@gradial/aci 0.1.19 → 0.1.20-preview.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +28 -8
  2. package/bin/aci +0 -0
  3. package/dist/astro/index.d.ts +4 -2
  4. package/dist/astro/index.js +9 -1
  5. package/dist/astro/preview.d.ts +5 -0
  6. package/dist/astro/preview.js +33 -0
  7. package/dist/content/index.d.ts +1 -0
  8. package/dist/content/index.js +1 -0
  9. package/dist/content/provider.d.ts +19 -0
  10. package/dist/content/provider.js +7 -0
  11. package/dist/content/resolve-slots.d.ts +9 -0
  12. package/dist/content/resolve-slots.js +24 -0
  13. package/dist/content/types.d.ts +1 -1
  14. package/dist/content/validation.js +0 -1
  15. package/dist/define-component.js +0 -6
  16. package/dist/define-data-model.d.ts +2 -0
  17. package/dist/define-data-model.js +3 -0
  18. package/dist/define-layout.d.ts +2 -0
  19. package/dist/define-layout.js +3 -0
  20. package/dist/dev/index.d.ts +12 -0
  21. package/dist/dev/index.js +84 -9
  22. package/dist/index.d.ts +2 -0
  23. package/dist/index.js +2 -0
  24. package/dist/next/asset-route.d.ts +2 -0
  25. package/dist/next/asset-route.js +10 -2
  26. package/dist/next/config.d.ts +1 -1
  27. package/dist/next/config.js +14 -2
  28. package/dist/next/content-watch.d.ts +11 -0
  29. package/dist/next/content-watch.js +106 -0
  30. package/dist/next/index.d.ts +2 -2
  31. package/dist/next/index.js +2 -2
  32. package/dist/next/middleware.d.ts +6 -2
  33. package/dist/next/middleware.js +40 -51
  34. package/dist/next/page.d.ts +41 -0
  35. package/dist/next/page.js +77 -0
  36. package/dist/next/preview-mode.js +4 -8
  37. package/dist/next/render.d.ts +5 -0
  38. package/dist/next/render.js +15 -0
  39. package/dist/next/root-layout.d.ts +4 -0
  40. package/dist/next/root-layout.js +5 -0
  41. package/dist/next/server.d.ts +3 -2
  42. package/dist/next/server.js +12 -8
  43. package/dist/preview/core.d.ts +41 -0
  44. package/dist/preview/core.js +116 -0
  45. package/dist/providers/file.d.ts +2 -0
  46. package/dist/providers/file.js +61 -1
  47. package/dist/providers/s3.d.ts +1 -0
  48. package/dist/providers/s3.js +14 -1
  49. package/dist/registry.d.ts +15 -0
  50. package/dist/registry.js +10 -0
  51. package/dist/sveltekit/index.d.ts +4 -1
  52. package/dist/sveltekit/index.js +9 -1
  53. package/dist/sveltekit/preview.d.ts +5 -0
  54. package/dist/sveltekit/preview.js +33 -0
  55. package/dist/testing/index.d.ts +3 -0
  56. package/dist/testing/index.js +15 -2
  57. package/dist/types/component.d.ts +0 -9
  58. package/dist/types/config.d.ts +1 -1
  59. package/dist/types/data.d.ts +19 -0
  60. package/dist/types/data.js +11 -0
  61. package/dist/types/image.d.ts +1 -1
  62. package/dist/types/image.js +1 -1
  63. package/dist/types/index.d.ts +1 -0
  64. package/dist/types/index.js +1 -0
  65. package/dist/types/page.d.ts +1 -2
  66. package/dist/types/render-mode.d.ts +0 -1
  67. package/package.json +40 -6
  68. package/src/cli/compile-registry.mjs +167 -19
  69. package/src/types/component.ts +0 -10
  70. package/src/types/config.ts +1 -1
  71. package/src/types/data.ts +47 -0
  72. package/src/types/image.ts +2 -2
  73. package/src/types/index.ts +1 -0
  74. package/src/types/page.ts +1 -2
  75. package/src/types/render-mode.ts +0 -8
  76. package/dist/next/preview-banner.d.ts +0 -4
  77. package/dist/next/preview-banner.js +0 -51
  78. package/dist/next/preview.d.ts +0 -7
  79. package/dist/next/preview.js +0 -37
  80. package/dist/render.d.ts +0 -14
  81. package/dist/render.js +0 -33
  82. package/src/cli/verify-renderer.mjs +0 -73
package/README.md CHANGED
@@ -5,9 +5,31 @@ installing `@gradial/aci`, Zod 4, and TypeScript tooling. The
5
5
  SDK exposes component and layout helpers, renderer types, compiler tooling,
6
6
  content provider helpers, and framework-specific subpaths from one package.
7
7
 
8
+ ## Getting Started
9
+
10
+ The fastest way to create a new ACI site is via the scaffolding script:
11
+
12
+ ```bash
13
+ pnpm exec tsx scripts/create-site.ts --framework astro --name my-site --dir ./my-site
14
+ cd my-site
15
+ pnpm run dev
16
+ ```
17
+
18
+ Available frameworks: `astro`, `nextjs`, `sveltekit`.
19
+
20
+ Generated starters include:
21
+ - `.aci/docs/` — Understanding ACI, running, and testing guides
22
+ - `.aci/guides/` — Component development, design system, content authoring
23
+ - `.aci/migration/` — Migrating existing sites to ACI
24
+ - Design system tokens, ESLint rules, and demo content
25
+
26
+ See the [templates directory](templates/) for the canonical starter source.
27
+
28
+ ## Installation
29
+
8
30
  ```bash
9
- npm install @gradial/aci zod@^4
10
- npm install -D typescript tsx
31
+ pnpm add @gradial/aci zod@^4
32
+ pnpm add -D typescript tsx
11
33
  ```
12
34
 
13
35
  Common imports:
@@ -56,7 +78,6 @@ export const heroContract = defineComponentContract({
56
78
  headline: z.string(),
57
79
  image: GradialImageSchema,
58
80
  }),
59
- renderModes: { canStatic: true, canSSR: true, canClientIsland: false },
60
81
  });
61
82
 
62
83
  export type HeroProps = z.infer<typeof heroContract.schema>;
@@ -85,7 +106,6 @@ const content = new FixtureContentProvider({
85
106
  $type: 'page',
86
107
  status: 'published',
87
108
  layout: 'marketing',
88
- renderMode: 'static',
89
109
  metadata: { title: 'Test Home' },
90
110
  regions: { main: [] }
91
111
  }
@@ -101,7 +121,7 @@ Use this in unit tests when you want the same provider API as
101
121
  Publish from this package directory:
102
122
 
103
123
  ```bash
104
- npm publish --access public
124
+ pnpm publish --access public
105
125
  ```
106
126
 
107
127
  The package includes a `prepack` script that builds `dist` before packing or
@@ -109,15 +129,15 @@ publishing.
109
129
 
110
130
  ## Verify the Published Shape Locally
111
131
 
112
- Before publishing, inspect the exact tarball npm will upload. This catches
132
+ Before publishing, inspect the exact tarball pnpm will upload. This catches
113
133
  package `files` mistakes where local source imports work from the repo but fail
114
- after npm filters the packed files.
134
+ after pnpm filters the packed files.
115
135
 
116
136
  From `packages/sdk`:
117
137
 
118
138
  ```bash
119
139
  tmpdir="$(mktemp -d /tmp/gradial-aci-pack.XXXXXX)"
120
- filename="$(npm pack --pack-destination "$tmpdir" | tail -n 1)"
140
+ filename="$(pnpm pack --pack-destination "$tmpdir" | tail -n 1)"
121
141
  tar -tzf "$tmpdir/$filename" | sort | rg '^(package/src/cli/|package/src/types/|package/dist/types/)'
122
142
  echo "tarball=$tmpdir/$filename"
123
143
  ```
package/bin/aci CHANGED
Binary file
@@ -33,9 +33,11 @@ export declare function getGradialStaticPaths(): Promise<Array<{
33
33
  };
34
34
  }>>;
35
35
  export declare function getPageRuntimeRenderInput(request: Request): RenderInput | null;
36
+ export { createRegistry, registryLookup } from '../registry.js';
37
+ export type { Registry, RegistryEntry, AnyComponent } from '../registry.js';
38
+ export { getPreviewMode, createPreviewBannerHTML, createPreviewCookies, type PreviewContext, type PreviewCookie, } from './preview.js';
36
39
  export interface GradialAstroOptions extends GradialContentWatchOptions {
37
40
  /** Path to compiled content root. Defaults to ACI_CONTENT_ROOT env or '.aci/compiled' */
38
41
  compiledRoot?: string;
39
42
  }
40
- export declare function gradialAstro(options?: GradialAstroOptions): AstroIntegrationLike;
41
- export {};
43
+ export declare function withGradialAci(options?: GradialAstroOptions): AstroIntegrationLike;
@@ -31,7 +31,15 @@ export async function getGradialStaticPaths() {
31
31
  export function getPageRuntimeRenderInput(request) {
32
32
  return getPendingRenderInputFromHeaders(request.headers);
33
33
  }
34
- export function gradialAstro(options = {}) {
34
+ // ---------------------------------------------------------------------------
35
+ // Registry helpers
36
+ // ---------------------------------------------------------------------------
37
+ export { createRegistry, registryLookup } from '../registry.js';
38
+ // ---------------------------------------------------------------------------
39
+ // Preview support
40
+ // ---------------------------------------------------------------------------
41
+ export { getPreviewMode, createPreviewBannerHTML, createPreviewCookies, } from './preview.js';
42
+ export function withGradialAci(options = {}) {
35
43
  return {
36
44
  name: 'gradial-astro',
37
45
  hooks: {
@@ -0,0 +1,5 @@
1
+ import { type PreviewContext, type PreviewCookie } from '../preview/core.js';
2
+ export declare function getPreviewMode(request: Request, siteId: string): Promise<PreviewContext>;
3
+ export declare function createPreviewBannerHTML(releaseId: string): string;
4
+ export declare function createPreviewCookies(token: string, releaseId: string): PreviewCookie[];
5
+ export type { PreviewContext, PreviewCookie };
@@ -0,0 +1,33 @@
1
+ import { extractPreviewToken, resolvePreviewContext, createPreviewBannerHTML as coreCreatePreviewBannerHTML, createPreviewCookies as coreCreatePreviewCookies, previewSignKey, } from '../preview/core.js';
2
+ export async function getPreviewMode(request, siteId) {
3
+ const url = new URL(request.url);
4
+ const token = extractPreviewToken({
5
+ query: url.searchParams,
6
+ cookies: parseCookieHeader(request.headers.get('cookie') || ''),
7
+ authorization: request.headers.get('authorization') || undefined,
8
+ });
9
+ if (!token)
10
+ return { isPreview: false };
11
+ return resolvePreviewContext({ token, siteId, signKey: previewSignKey() });
12
+ }
13
+ export function createPreviewBannerHTML(releaseId) {
14
+ return coreCreatePreviewBannerHTML(releaseId);
15
+ }
16
+ export function createPreviewCookies(token, releaseId) {
17
+ return coreCreatePreviewCookies(token, releaseId);
18
+ }
19
+ function parseCookieHeader(header) {
20
+ const cookies = new Map();
21
+ for (const part of header.split(';')) {
22
+ const trimmed = part.trim();
23
+ if (!trimmed)
24
+ continue;
25
+ const idx = trimmed.indexOf('=');
26
+ if (idx < 0)
27
+ continue;
28
+ const name = trimmed.slice(0, idx).trim();
29
+ const value = trimmed.slice(idx + 1).trim();
30
+ cookies.set(name, decodeURIComponent(value));
31
+ }
32
+ return cookies;
33
+ }
@@ -2,3 +2,4 @@ export * from './provider.js';
2
2
  export * from './routes.js';
3
3
  export * from './types.js';
4
4
  export * from './cache.js';
5
+ export * from './resolve-slots.js';
@@ -2,3 +2,4 @@ export * from './provider.js';
2
2
  export * from './routes.js';
3
3
  export * from './types.js';
4
4
  export * from './cache.js';
5
+ export * from './resolve-slots.js';
@@ -12,17 +12,33 @@ export interface FragmentEntry {
12
12
  digest: string;
13
13
  fragmentRefs?: string[];
14
14
  }
15
+ export interface LayoutEntry {
16
+ name: string;
17
+ slots: LayoutSlot[];
18
+ defaults?: Record<string, FragmentRef[]>;
19
+ }
20
+ export interface LayoutSlot {
21
+ name: string;
22
+ required: boolean;
23
+ }
24
+ export interface FragmentRef {
25
+ kind: string;
26
+ fragmentId: string;
27
+ inline: boolean;
28
+ }
15
29
  export interface CompiledManifest {
16
30
  manifestVersion: string;
17
31
  buildDigest: string;
18
32
  siteConfigRef: string;
19
33
  routes: Record<string, RouteEntry>;
20
34
  fragments: Record<string, FragmentEntry>;
35
+ layouts?: Record<string, LayoutEntry>;
21
36
  }
22
37
  export interface ContentProvider {
23
38
  getSiteConfig<T = unknown>(): Promise<T>;
24
39
  getPage<T = unknown>(route: string): Promise<T>;
25
40
  getFragment<T = unknown>(id: string): Promise<T>;
41
+ getLayout<T = unknown>(name: string): Promise<T>;
26
42
  listRoutes(): Promise<RouteEntry[]>;
27
43
  }
28
44
  export declare class PageNotFoundError extends Error {
@@ -31,6 +47,9 @@ export declare class PageNotFoundError extends Error {
31
47
  export declare class FragmentNotFoundError extends Error {
32
48
  constructor(id: string, cause?: unknown);
33
49
  }
50
+ export declare class LayoutNotFoundError extends Error {
51
+ constructor(name: string, cause?: unknown);
52
+ }
34
53
  export interface RenderInputOptions {
35
54
  domain?: string;
36
55
  locale?: string;
@@ -16,6 +16,13 @@ export class FragmentNotFoundError extends Error {
16
16
  this.cause = cause;
17
17
  }
18
18
  }
19
+ export class LayoutNotFoundError extends Error {
20
+ constructor(name, cause) {
21
+ super(`Layout not found: ${name}`);
22
+ this.name = 'LayoutNotFoundError';
23
+ this.cause = cause;
24
+ }
25
+ }
19
26
  import { getCachedSiteConfig } from './cache.js';
20
27
  export async function loadRenderInput(provider, route = '/', options = {}) {
21
28
  const normalized = normalizeRoute(route);
@@ -0,0 +1,9 @@
1
+ import type { LayoutEntry } from './provider.js';
2
+ import type { KernelPageBlock } from './types.js';
3
+ export interface FragmentData {
4
+ id: string;
5
+ component: string;
6
+ props?: Record<string, unknown>;
7
+ }
8
+ export type FragmentLoader = (id: string) => Promise<FragmentData>;
9
+ export declare function resolveSlots(layout: LayoutEntry, pageRegions: Record<string, KernelPageBlock[]>, getFragment: FragmentLoader): Promise<Record<string, KernelPageBlock[]>>;
@@ -0,0 +1,24 @@
1
+ export async function resolveSlots(layout, pageRegions, getFragment) {
2
+ const resolved = {};
3
+ for (const slot of layout.slots) {
4
+ const pageBlocks = pageRegions[slot.name];
5
+ if (pageBlocks && pageBlocks.length > 0) {
6
+ resolved[slot.name] = pageBlocks;
7
+ continue;
8
+ }
9
+ const defaults = layout.defaults?.[slot.name];
10
+ if (defaults?.length) {
11
+ const blocks = [];
12
+ for (const ref of defaults) {
13
+ const fragment = await getFragment(ref.fragmentId);
14
+ blocks.push({
15
+ id: fragment.id,
16
+ component: fragment.component,
17
+ props: fragment.props || {},
18
+ });
19
+ }
20
+ resolved[slot.name] = blocks;
21
+ }
22
+ }
23
+ return resolved;
24
+ }
@@ -55,7 +55,6 @@ export interface KernelPage {
55
55
  $type: 'page';
56
56
  status: string;
57
57
  layout: string;
58
- renderMode: string;
59
58
  metadata: KernelPageSeo;
60
59
  regions: Record<string, KernelPageBlock[]>;
61
60
  }
@@ -93,6 +92,7 @@ export interface RenderInput<TPage extends KernelPage = KernelPage, TSiteConfig
93
92
  siteConfig: TSiteConfig;
94
93
  page: TPage | null;
95
94
  fragments?: Record<string, unknown>;
95
+ layouts?: Record<string, unknown>;
96
96
  }
97
97
  export interface RenderOutput {
98
98
  route: string;
@@ -121,7 +121,6 @@ export function createContentSchemas(contracts = {}) {
121
121
  $type: z.literal('page'),
122
122
  status: z.string().min(1),
123
123
  layout: z.string().min(1),
124
- renderMode: z.string().min(1),
125
124
  metadata: z.looseObject({
126
125
  title: z.string().optional(),
127
126
  description: z.string().optional(),
@@ -1,12 +1,6 @@
1
1
  export function defineComponent(definition) {
2
- const renderModes = definition.renderModes ?? definition.render;
3
- if (!renderModes) {
4
- throw new Error(`component ${definition.name} must define renderModes`);
5
- }
6
2
  return {
7
3
  ...definition,
8
- renderModes,
9
- render: renderModes,
10
4
  varyDimensions: definition.varyDimensions ?? definition.vary,
11
5
  vary: definition.vary ?? definition.varyDimensions,
12
6
  };
@@ -0,0 +1,2 @@
1
+ import type { DataModelContract, DataModelDefinition } from './types/data.js';
2
+ export declare function defineDataModel<TSchema = unknown, TType extends string = string>(definition: DataModelDefinition<TSchema, TType>): DataModelContract<TSchema, TType>;
@@ -0,0 +1,3 @@
1
+ export function defineDataModel(definition) {
2
+ return { ...definition };
3
+ }
@@ -1,4 +1,6 @@
1
1
  import type { LayoutContract, LayoutDefinition, LayoutSlot } from './types/layout.js';
2
+ import type { FragmentRefNode } from './types/page.js';
2
3
  export declare function defineLayout(definition: LayoutDefinition): LayoutContract;
3
4
  export declare const defineLayoutContract: typeof defineLayout;
4
5
  export declare function slot(name: string, required?: boolean): LayoutSlot;
6
+ export declare function fragmentDefault(fragmentId: string): FragmentRefNode;
@@ -9,3 +9,6 @@ export const defineLayoutContract = defineLayout;
9
9
  export function slot(name, required = false) {
10
10
  return { name, required };
11
11
  }
12
+ export function fragmentDefault(fragmentId) {
13
+ return { kind: 'fragment-ref', fragmentId, inline: true };
14
+ }
@@ -7,10 +7,21 @@ declare global {
7
7
  }
8
8
  }
9
9
  export interface GradialContentWatchOptions extends DevRefreshOptions {
10
+ /** Source content root to watch. Defaults to ACI_CONTENT_SOURCE env or '.content' */
10
11
  contentRoot?: string;
12
+ /** Compiled content output root. Defaults to ACI_CONTENT_ROOT env or '.aci/compiled' */
11
13
  compiledRoot?: string;
14
+ /** Path to the ACI CLI binary. Defaults to ACI_BIN env or 'aci' */
15
+ aciBin?: string;
16
+ /** Disable content watching entirely. Defaults to ACI_DISABLE_CONTENT_WATCH env */
12
17
  enabled?: boolean;
13
18
  }
19
+ interface ViteModuleGraph {
20
+ idToModuleMap: Map<unknown, {
21
+ id: string | null;
22
+ }>;
23
+ invalidateModule(mod: unknown): void;
24
+ }
14
25
  interface ViteDevServerLike {
15
26
  middlewares?: {
16
27
  use(path: string, handler: (req: IncomingMessage, res: ServerResponse, next: () => void) => void): void;
@@ -22,6 +33,7 @@ interface ViteDevServerLike {
22
33
  ws: {
23
34
  send(payload: unknown): void;
24
35
  };
36
+ moduleGraph?: ViteModuleGraph;
25
37
  }
26
38
  export interface VitePluginLike {
27
39
  name: string;
package/dist/dev/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import fs from 'node:fs/promises';
2
+ import { spawnSync } from 'node:child_process';
2
3
  import path from 'node:path';
3
4
  import { compiledContentRoot } from '../content/routes.js';
4
5
  import { DEFAULT_DEV_REFRESH_PATH, DEFAULT_DEV_REFRESH_PORT, } from './browser.js';
@@ -48,23 +49,97 @@ export function devRefreshScript(options = {}) {
48
49
  export function devRefreshScriptTag(options = {}) {
49
50
  return `<script>${devRefreshScript(options)}</script>`;
50
51
  }
52
+ function sourceContentRoot(options) {
53
+ return path.resolve(options.contentRoot ||
54
+ process.env.ACI_CONTENT_SOURCE ||
55
+ './.content');
56
+ }
57
+ function resolveAciBin(options) {
58
+ return options.aciBin || process.env.ACI_BIN || 'aci';
59
+ }
60
+ function recompileContent(options, reason) {
61
+ const siteDir = process.cwd();
62
+ const src = sourceContentRoot(options);
63
+ const out = path.resolve(options.compiledRoot ||
64
+ process.env.ACI_CONTENT_ROOT ||
65
+ '.aci/compiled');
66
+ const bin = resolveAciBin(options);
67
+ console.log(`[aci] compiling content (${reason})`);
68
+ const result = spawnSync(bin, [
69
+ '-s', siteDir,
70
+ 'build',
71
+ '--content', src,
72
+ '--out', out,
73
+ '--skip-code',
74
+ ], {
75
+ cwd: siteDir,
76
+ stdio: 'inherit',
77
+ env: process.env,
78
+ });
79
+ if (result.status !== 0) {
80
+ console.error(`[aci] content compile failed with exit code ${result.status ?? 'unknown'}`);
81
+ return false;
82
+ }
83
+ return true;
84
+ }
51
85
  export function gradialContentWatchPlugin(options = {}) {
52
86
  const enabled = options.enabled ?? process.env.ACI_DISABLE_CONTENT_WATCH !== '1';
87
+ if (!enabled) {
88
+ return {
89
+ name: 'gradial-content-watch-disabled',
90
+ apply: 'serve',
91
+ };
92
+ }
93
+ let timer;
94
+ let running = false;
95
+ let queued = false;
96
+ function rebuild(server, reason) {
97
+ if (running) {
98
+ queued = true;
99
+ return;
100
+ }
101
+ running = true;
102
+ const success = recompileContent(options, reason);
103
+ running = false;
104
+ if (success) {
105
+ if (server.moduleGraph) {
106
+ for (const mod of server.moduleGraph.idToModuleMap.values()) {
107
+ server.moduleGraph.invalidateModule(mod);
108
+ }
109
+ }
110
+ server.ws.send({ type: 'full-reload' });
111
+ }
112
+ if (queued) {
113
+ queued = false;
114
+ rebuild(server, 'queued change');
115
+ }
116
+ }
53
117
  return {
54
118
  name: 'gradial-content-watch',
55
119
  apply: 'serve',
56
120
  configureServer(server) {
57
- if (!enabled) {
58
- return;
59
- }
60
- const root = path.resolve(options.contentRoot || compiledContentRoot());
61
- server.watcher.add(root);
62
- server.watcher.on('all', (_eventName, filePath) => {
121
+ const src = sourceContentRoot(options);
122
+ const compiled = path.resolve(options.compiledRoot ||
123
+ process.env.ACI_CONTENT_ROOT ||
124
+ compiledContentRoot());
125
+ server.watcher.add(src);
126
+ server.watcher.add(compiled);
127
+ rebuild(server, 'startup');
128
+ server.watcher.on('all', (_event, filePath) => {
63
129
  const changed = path.resolve(filePath);
64
- const relative = path.relative(root, changed);
65
- if (relative && !relative.startsWith('..') && !path.isAbsolute(relative)) {
66
- server.ws.send({ type: 'full-reload', path: '*' });
130
+ const isSource = changed.startsWith(src + path.sep);
131
+ const isCompiled = changed.startsWith(compiled + path.sep);
132
+ if (!isSource && !isCompiled)
133
+ return;
134
+ if (isCompiled) {
135
+ server.ws.send({ type: 'full-reload' });
136
+ return;
67
137
  }
138
+ clearTimeout(timer);
139
+ timer = setTimeout(() => {
140
+ const relative = path.relative(src, changed);
141
+ rebuild(server, relative);
142
+ }, 100);
68
143
  });
69
144
  },
70
145
  };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from './block-ref.js';
2
2
  export * from './define-component.js';
3
+ export * from './define-data-model.js';
3
4
  export * from './define-layout.js';
5
+ export * from './registry.js';
4
6
  export * from './types/index.js';
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  export * from './block-ref.js';
2
2
  export * from './define-component.js';
3
+ export * from './define-data-model.js';
3
4
  export * from './define-layout.js';
5
+ export * from './registry.js';
4
6
  export * from './types/index.js';
5
7
  // Note: content/ is NOT re-exported here because it imports node:path,
6
8
  // making it incompatible with client-side bundlers. Import server-only
@@ -5,5 +5,7 @@ type AssetRouteParams = {
5
5
  releaseId?: string;
6
6
  path?: string[];
7
7
  };
8
+ export declare const runtime = "nodejs";
9
+ export declare const dynamic = "force-dynamic";
8
10
  export declare function GET(_request: Request, { params }: AssetRouteContext): Promise<Response>;
9
11
  export {};
@@ -1,11 +1,19 @@
1
+ import { FileContentProvider } from '../providers/file.js';
1
2
  import { getReleaseAssetResponse } from './server.js';
3
+ const LOCAL_RELEASE_ID = 'local';
4
+ export const runtime = 'nodejs';
5
+ export const dynamic = 'force-dynamic';
2
6
  export async function GET(_request, { params }) {
3
7
  const resolvedParams = await params;
4
8
  const releaseId = resolvedParams.releaseId || '';
5
- const assetPath = (resolvedParams.path || []).join('/');
6
- if (!releaseId || !assetPath) {
9
+ const assetPath = '/' + (resolvedParams.path || []).join('/');
10
+ if (!releaseId || assetPath === '/') {
7
11
  return new Response('asset not found', { status: 404 });
8
12
  }
13
+ if (releaseId === LOCAL_RELEASE_ID) {
14
+ const provider = new FileContentProvider();
15
+ return provider.fetchRaw(assetPath);
16
+ }
9
17
  try {
10
18
  return await getReleaseAssetResponse(releaseId, assetPath);
11
19
  }
@@ -3,4 +3,4 @@ export interface WithGradialOptions {
3
3
  /** Asset rewrite prefix. Defaults to '/.gradial-dam' */
4
4
  assetPrefix?: string;
5
5
  }
6
- export declare function withGradial(nextConfig?: NextConfig, options?: WithGradialOptions): NextConfig;
6
+ export declare function withGradialAci(nextConfig?: NextConfig, options?: WithGradialOptions): NextConfig;
@@ -1,13 +1,15 @@
1
- export function withGradial(nextConfig = {}, options = {}) {
1
+ import { createContentWatchWebpackPlugin } from './content-watch.js';
2
+ export function withGradialAci(nextConfig = {}, options = {}) {
2
3
  const assetPrefix = options.assetPrefix || '/.gradial-dam';
3
4
  const userRewrites = nextConfig.rewrites;
5
+ const userWebpack = nextConfig.webpack;
4
6
  return {
5
7
  ...nextConfig,
6
8
  rewrites: async () => {
7
9
  const gradialRewrites = [
8
10
  {
9
11
  source: `${assetPrefix}/:path*`,
10
- destination: `/api/aci-assets${assetPrefix}/:path*`,
12
+ destination: `/gradial/assets/local${assetPrefix}/:path*`,
11
13
  },
12
14
  ];
13
15
  if (!userRewrites)
@@ -21,5 +23,15 @@ export function withGradial(nextConfig = {}, options = {}) {
21
23
  beforeFiles: [...gradialRewrites, ...(userResult.beforeFiles ?? [])],
22
24
  };
23
25
  },
26
+ webpack: (config, context) => {
27
+ if (context?.isServer && process.env.NODE_ENV !== 'production') {
28
+ if (!config.plugins)
29
+ config.plugins = [];
30
+ config.plugins.push(createContentWatchWebpackPlugin());
31
+ }
32
+ return typeof userWebpack === 'function'
33
+ ? userWebpack(config, context)
34
+ : config;
35
+ },
24
36
  };
25
37
  }
@@ -0,0 +1,11 @@
1
+ interface ContentWatchWebpackPlugin {
2
+ apply(compiler: {
3
+ hooks: {
4
+ [key: string]: {
5
+ tap: (name: string, fn: () => void) => void;
6
+ };
7
+ };
8
+ }): void;
9
+ }
10
+ export declare function createContentWatchWebpackPlugin(): ContentWatchWebpackPlugin;
11
+ export {};