Skip to content

refactor: outputs built templates into separate files for summary and templates#2643

Merged
stalniy merged 4 commits intomainfrom
refactor/templates-per-file
Feb 2, 2026
Merged

refactor: outputs built templates into separate files for summary and templates#2643
stalniy merged 4 commits intomainfrom
refactor/templates-per-file

Conversation

@stalniy
Copy link
Contributor

@stalniy stalniy commented Feb 2, 2026

Why

To make the format compatible with what we will publish to cloudflare pages.

What

  1. refactor templates cache structure + optimizations
  2. added gha workflow to build and publish templates everyday
  3. adjusts deploy-web/http-sdk to fetch templates from cloudflare pages (currently from here -> https://akash-templates.pages.dev/v1/templates-list.json but will need to move it to org pages, don't have permissions)
  4. replaces volta action with standard actions/setup-node which supports volta field in package.json

Summary by CodeRabbit

Release Notes

  • New Features

    • Templates are now published and served from a dedicated Cloudflare Pages deployment (Akash Templates) for improved performance and reliability.
    • Enhanced template retrieval with optimized caching for faster access.
  • Chores

    • Added automated daily workflow for template publishing.
    • Updated GitHub Actions dependency setup process.

@stalniy stalniy requested a review from a team as a code owner February 2, 2026 01:57
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

📝 Walkthrough

Walkthrough

This PR refactors template caching from in-memory to disk-backed storage with per-template JSON files, adds a new automated Cloudflare Pages deployment workflow, updates HTTP client architecture to use dedicated baseURL configuration, introduces legacy .json route redirects, and adds environment-specific header handling for cross-origin requests.

Changes

Cohort / File(s) Summary
GitHub Actions Configuration
.github/actions/setup-app-deps/action.yml, .github/workflows/akash-templates-publisher.yml
Updates Node.js setup action from volta to actions/setup-node@v6. Adds new daily-scheduled workflow that builds Akash templates via npm, cleans generated files, and deploys to Cloudflare Pages using wrangler with GITHUB_PAT and CLOUDFLARE credentials.
Template Controller & Router
apps/api/src/template/controllers/template/template.controller.ts, apps/api/src/template/routes/templates/templates.router.ts
Renames getTemplatesList() to getTemplatesListJson() returning Buffer instead of string. Updates router to call new method and construct Response with Content-Type application/json header.
Template Gallery Service
apps/api/src/template/services/template-gallery/template-gallery.service.ts, apps/api/src/template/services/template-gallery/template-gallery.service.spec.ts
Migrates from in-memory aggregated cache to disk-backed per-template JSON files with LRUCache and PromisePool. Replaces getCachedTemplateGallery() with getGallerySummaryBuffer(). Changes buildTemplateGalleryCache to return void. Updates tests to verify file-based caching and buffer reads.
Legacy Routes & Package Updates
apps/api/src/routers/legacyRouter.ts, package.json
Adds redirect routes for /v1/templates-list.json and /v1/templates/:id.json endpoints. Updates package.json dependencies/scripts.
Deploy-web Configuration
apps/deploy-web/env/.env, apps/deploy-web/src/config/browser-env.config.ts, apps/deploy-web/src/config/env-config.schema.ts
Introduces NEXT_PUBLIC_BASE_TEMPLATES_URL environment variable with value https://akash-templates.pages.dev. Adds URL to browser config object and schema with validation.
Template Service DI & HTTP Client
apps/deploy-web/src/services/app-di-container/app-di-container.ts, packages/http-sdk/src/template/template-http.service.ts
Refactors template service wiring to create dedicated Axios instance with baseURL from NEXT_PUBLIC_BASE_TEMPLATES_URL, conditionally removes headers in browser environment. Changes TemplateHttpService from extending ApiHttpService to composing HttpClient, updates endpoints to /v1/templates/{id}.json and /v1/templates-list.json.
Template Processor
apps/api/src/template/services/template-processor/template-processor.service.ts, apps/api/src/template/services/template-processor/template-processor.service.spec.ts
Sanitizes template IDs by replacing slashes with hyphens. Updates test expectation from "test-owner-test-repo-templates/app" to "test-owner-test-repo-templates-app".

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant TemplateController
    participant TemplateGalleryService
    participant FileSystem as File System<br/>(disk cache)
    participant LRUCache

    rect rgba(100, 150, 200, 0.5)
    Note over Client,LRUCache: New Disk-Backed Template Retrieval Flow
    end

    Client->>TemplateController: GET /v1/templates-list
    TemplateController->>TemplateGalleryService: getGallerySummaryBuffer()
    
    alt Cache hit (in-memory)
        TemplateGalleryService->>LRUCache: Check `#templatesSummaryCache`
        LRUCache-->>TemplateGalleryService: Return Buffer
    else Cache miss
        TemplateGalleryService->>FileSystem: Read /data/templates/v1/templates-list.json
        FileSystem-->>TemplateGalleryService: Buffer content
        TemplateGalleryService->>LRUCache: Store Buffer in `#templatesSummaryCache`
    end
    
    TemplateGalleryService-->>TemplateController: Buffer
    TemplateController->>Client: Response (Content-Type: application/json)
Loading
sequenceDiagram
    participant GithubScheduler as GitHub Scheduler
    participant GithubActions as GitHub Actions
    participant NPM
    participant FileSystem as File System
    participant Cloudflare as Cloudflare Pages
    participant Wrangler

    rect rgba(100, 150, 200, 0.5)
    Note over GithubScheduler,Wrangler: Automated Template Build & Deploy Workflow
    end

    GithubScheduler->>GithubActions: Trigger daily at 15:00 UTC
    GithubActions->>GithubActions: Checkout repository
    GithubActions->>GithubActions: Setup Node.js via actions/setup-node@v6
    
    GithubActions->>NPM: npm run build:akash-templates --workspace=apps/api
    NPM->>FileSystem: Generate template files in apps/api/dist/.data/templates
    
    GithubActions->>FileSystem: Delete generated files (excluding v1)
    GithubActions->>FileSystem: Write _headers file
    
    GithubActions->>Wrangler: wrangler pages deploy dist/.data/templates/
    Wrangler->>Cloudflare: Deploy to akash-templates project
    Cloudflare-->>Wrangler: Deployment confirmed
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • baktun14
  • ygrishajev

🐰 Hop! Hop! Templates hop away,
From memory to disk they'll stay,
Cloudflare Pages, so shiny and new,
With HTTP clients refreshed through and through! 🚀

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main refactoring objective: restructuring templates to output separate files for summary and individual templates, which aligns with the primary code changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/templates-per-file

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@apps/api/src/template/services/template-gallery/template-gallery.service.ts`:
- Around line 57-60: The refreshCache method currently rebuilds the gallery and
clears `#parsedTemplates` and templateFetcher archive cache but does not
invalidate `#templatesSummaryCache`, so getGallerySummaryBuffer() may return stale
data; update the refreshCache implementation (the async refreshCache that calls
buildTemplateGalleryCache) to also clear or reset `#templatesSummaryCache` after
buildTemplateGalleryCache completes (alongside this.#parsedTemplates.clear() and
this.templateFetcher?.clearArchiveCache()) so the summary buffer is regenerated
on next getGallerySummaryBuffer() call.
- Around line 81-87: The `#templateCachePath` function is interpolating templateId
directly into a filesystem path, allowing IDs with "/" or ".." to escape the
by-id directory; fix by validating or canonicalizing templateId inside
`#templateCachePath`: reject or sanitize any IDs containing path separators or
parent-segment tokens (e.g., disallow "/" and ".."), or encode the ID into a
safe form (URL-encode, base64/url-safe, or replace non-allowed chars with safe
tokens) before building `${this.#galleriesCachePath}/by-id/${...}.json`; keep
`#summaryCachePath` unchanged but ensure callers of `#templateCachePath` pass
validated IDs.
- Around line 52-55: getGallerySummaryBuffer currently assigns a pending Promise
to the private field `#templatesSummaryCache` using this.#fs.readFile(...), which
if it rejects will cache a rejected Promise and never retry; change the logic so
you await the read and on failure clear the cache before rethrowing or returning
a fallback. Concretely, replace the direct assignment with code that sets
`#templatesSummaryCache` to the read Promise only while awaiting it (or use a
.catch handler on the Promise from this.#fs.readFile(this.#summaryCachePath())
that sets this.#templatesSummaryCache = undefined and then throws the error), so
subsequent calls can attempt to reload the file; refer to the
getGallerySummaryBuffer method, the `#templatesSummaryCache` field, the
`#fs.readFile` call and `#summaryCachePath` to locate where to apply the change.
- Around line 134-140: The code currently assigns JSON.parse result to
`template` (implicitly any) and caches it in `#parsedTemplates`; replace this by
parsing then validating against a typed schema (e.g., a Zod schema or a
TypeScript type guard) for the Template shape before caching and returning.
Specifically, create/inline a `Template` schema or guard (or import one), call
`JSON.parse` into an untyped value, run schema.parse/validate or guard(value) to
assert the shape, throw or log and propagate an error if validation fails, and
only `this.#parsedTemplates.set(id, validatedTemplate)` and return the
strongly-typed `Template` when validation succeeds; update the method’s return
type to `Template` (or Promise<Template>) accordingly. In TypeScript, prefer
runtime validation libraries like Zod or explicit type guard functions to
validate JSON.parse results rather than casting to `any`.

@stalniy stalniy force-pushed the refactor/templates-per-file branch 2 times, most recently from ae2b268 to 49517e3 Compare February 2, 2026 02:10
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@apps/api/src/template/services/template-gallery/template-gallery.service.ts`:
- Around line 63-79: The PromisePool call in buildTemplateGalleryCache can
swallow write errors because PromisePool.process() returns a result object with
an errors array instead of throwing; change the PromisePool invocation to
capture its return (e.g., const result = await
PromisePool.for(allTemplates).withConcurrency(100).process(...)) and then check
result.errors (or result.hasErrors) and surface them—either throw an aggregated
Error or log and rethrow—so failed `#fs.writeFile` operations for each template.id
are not silently ignored; ensure the method returns/throws appropriately after
inspecting result.errors.
🧹 Nitpick comments (1)
apps/api/src/template/services/template-gallery/template-gallery.service.spec.ts (1)

262-289: Align the setup helper with test guidelines.
setup should be the last helper in the root describe and accept a single parameter with inline type definition. Consider moving it below createAsyncGenerator / createCategory, and adding an options param (even if unused).

🧩 Example signature tweak
-function setup() {
+function setup({ dataFolderPath = "/data" }: { dataFolderPath?: string } = {}) {
   const logger = mock<LoggerService>();
   const fsMock = mock<FileSystemApi>({
     access: jest.fn(() => Promise.reject(new Error("File not found")))
   });
-  const dataFolderPath = "/data";
As per coding guidelines "Use `setup` function instead of `beforeEach` in test files. The `setup` function must be at the bottom of the root `describe` block, should create an object under test and return it, accept a single parameter with inline type definition, avoid shared state, and not have a specified return type."

@codecov
Copy link

codecov bot commented Feb 2, 2026

Codecov Report

❌ Patch coverage is 78.26087% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 51.34%. Comparing base (19808cd) to head (ca185bf).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
apps/api/src/routers/legacyRouter.ts 40.00% 3 Missing ⚠️
...vices/template-gallery/template-gallery.service.ts 90.32% 3 Missing ⚠️
...mplate/controllers/template/template.controller.ts 0.00% 2 Missing ⚠️
.../src/services/app-di-container/app-di-container.ts 66.66% 2 Missing ⚠️

❌ Your patch status has failed because the patch coverage (79.48%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2643      +/-   ##
==========================================
- Coverage   51.37%   51.34%   -0.03%     
==========================================
  Files        1053     1053              
  Lines       29593    29578      -15     
  Branches     6659     6651       -8     
==========================================
- Hits        15204    15188      -16     
+ Misses      14154    14003     -151     
- Partials      235      387     +152     
Flag Coverage Δ *Carryforward flag
api 78.24% <79.48%> (-0.06%) ⬇️
deploy-web 32.76% <71.42%> (+0.01%) ⬆️
log-collector 75.35% <ø> (ø)
notifications 87.94% <ø> (ø)
provider-console 81.48% <ø> (ø) Carriedforward from 19808cd
provider-proxy 84.35% <ø> (ø) Carriedforward from 19808cd
tx-signer 79.25% <ø> (ø)

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
...s/template-processor/template-processor.service.ts 100.00% <100.00%> (ø)
apps/deploy-web/src/config/browser-env.config.ts 100.00% <ø> (ø)
apps/deploy-web/src/config/env-config.schema.ts 71.42% <100.00%> (ø)
...mplate/controllers/template/template.controller.ts 41.66% <0.00%> (+3.20%) ⬆️
.../src/services/app-di-container/app-di-container.ts 75.59% <66.66%> (+0.18%) ⬆️
apps/api/src/routers/legacyRouter.ts 35.39% <40.00%> (+0.21%) ⬆️
...vices/template-gallery/template-gallery.service.ts 95.78% <90.32%> (+0.83%) ⬆️

... and 86 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@stalniy stalniy changed the title Refactor/templates per file refactor: makes templates to output separate files for summary and templates Feb 2, 2026
@stalniy stalniy force-pushed the refactor/templates-per-file branch from 3d18cdf to 6f1f66c Compare February 2, 2026 03:50
ygrishajev
ygrishajev previously approved these changes Feb 2, 2026
@stalniy stalniy force-pushed the refactor/templates-per-file branch from 6f1f66c to ca185bf Compare February 2, 2026 09:24
@stalniy stalniy changed the title refactor: makes templates to output separate files for summary and templates refactor: outputs built templates into separate files for summary and templates Feb 2, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/deploy-web/src/services/app-di-container/app-di-container.ts`:
- Around line 71-81: The Content-Type deletion is targeting the wrong place and
is a no-op; update the template factory (the template: () => { ... } block that
creates httpClient via container.createAxios and returns new
TemplateHttpService) to remove the header from the correct locations: delete
httpClient.defaults.headers.common['Content-Type'] and also remove
'Content-Type' from any per-method header objects (e.g.
httpClient.defaults.headers.post/put/patch/delete or by iterating all keys of
httpClient.defaults.headers except 'common' and deleting ['Content-Type'] on
each). Keep the existing removal of Accept on defaults.headers.common. Ensure
these deletions occur only when config.runtimeEnv === "browser" before
constructing TemplateHttpService.

In `@packages/http-sdk/src/template/template-http.service.ts`:
- Around line 41-42: The findById method interpolates raw id into the request
path which can produce malformed URLs or path traversal; URL-encode the id
before interpolation (use encodeURIComponent on the id passed to
TemplateHttpService.findById) so the call to
this.#httpClient.get<TemplateOutput>(`/v1/templates/${...}.json`) uses the
encoded value when building the URL.

@stalniy stalniy merged commit 3bdb346 into main Feb 2, 2026
76 of 77 checks passed
@stalniy stalniy deleted the refactor/templates-per-file branch February 2, 2026 09:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments