@gradial/aci 0.1.20-preview.3 → 0.1.20

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 (224) hide show
  1. package/README.md +48 -108
  2. package/bin/{aci → aci-darwin-arm64} +0 -0
  3. package/bin/aci.js +99 -6
  4. package/dist/assets/index.d.ts +3 -3
  5. package/dist/assets/index.js +3 -3
  6. package/dist/astro/index.d.ts +12 -3
  7. package/dist/astro/index.js +20 -5
  8. package/dist/content/assets.d.ts +17 -0
  9. package/dist/content/assets.js +65 -0
  10. package/dist/content/index.d.ts +1 -0
  11. package/dist/content/index.js +1 -0
  12. package/dist/define-component.d.ts +1 -2
  13. package/dist/define-component.js +73 -5
  14. package/dist/dev/content-watch.d.ts +37 -0
  15. package/dist/dev/content-watch.js +154 -0
  16. package/dist/dev/index.d.ts +24 -43
  17. package/dist/dev/index.js +4 -169
  18. package/dist/index.d.ts +14 -6
  19. package/dist/index.js +8 -9
  20. package/dist/next/asset-route.js +2 -2
  21. package/dist/next/config.d.ts +2 -2
  22. package/dist/next/config.js +5 -5
  23. package/dist/next/content-watch.js +6 -1
  24. package/dist/next/index.d.ts +2 -2
  25. package/dist/next/index.js +2 -2
  26. package/dist/next/middleware.d.ts +2 -2
  27. package/dist/next/middleware.js +6 -6
  28. package/dist/next/page.d.ts +1 -1
  29. package/dist/next/page.js +14 -12
  30. package/dist/next/render.d.ts +3 -3
  31. package/dist/next/render.js +11 -9
  32. package/dist/next/server.d.ts +12 -12
  33. package/dist/next/server.js +1 -1
  34. package/dist/react/Media.d.ts +24 -0
  35. package/dist/react/Media.js +30 -0
  36. package/dist/react/Picture.d.ts +12 -0
  37. package/dist/react/Picture.js +11 -0
  38. package/dist/react/VideoPlayer.d.ts +13 -0
  39. package/dist/react/{GradialVideoPlayer.js → VideoPlayer.js} +6 -5
  40. package/dist/react/index.d.ts +333 -3
  41. package/dist/react/index.js +89 -3
  42. package/dist/registry.d.ts +2 -2
  43. package/dist/registry.js +3 -3
  44. package/dist/types/block-ref.d.ts +26 -0
  45. package/dist/types/block-ref.js +28 -0
  46. package/dist/types/component.d.ts +36 -32
  47. package/dist/types/config.d.ts +1 -1
  48. package/dist/types/image.d.ts +33 -20
  49. package/dist/types/image.js +42 -50
  50. package/dist/types/index.d.ts +1 -0
  51. package/dist/types/index.js +1 -0
  52. package/dist/types/link.d.ts +38 -0
  53. package/dist/types/link.js +58 -0
  54. package/dist/types/media.d.ts +16 -35
  55. package/dist/types/media.js +15 -84
  56. package/dist/types/renderer.d.ts +1 -1
  57. package/dist/types/rich-text.d.ts +40 -0
  58. package/dist/types/rich-text.js +39 -0
  59. package/dist/types/video.d.ts +7 -13
  60. package/dist/types/video.js +3 -3
  61. package/package.json +28 -76
  62. package/src/cli/compile-registry.mjs +120 -63
  63. package/src/cli/validate-content.mjs +38 -75
  64. package/src/types/image.ts +79 -60
  65. package/templates/astro/template/.aci.yaml +27 -0
  66. package/templates/astro/template/.storybook/main.ts +79 -0
  67. package/templates/astro/template/.storybook/manager.ts +6 -0
  68. package/templates/astro/template/.storybook/preview.ts +33 -0
  69. package/templates/astro/template/astro.config.mjs +37 -0
  70. package/templates/astro/template/package.json.tmpl +41 -0
  71. package/templates/astro/template/src/cms/contracts/layouts/index.ts +18 -0
  72. package/templates/astro/template/src/cms/registry.ts +28 -0
  73. package/templates/astro/template/src/components/chrome/Footer.astro +107 -0
  74. package/templates/astro/template/src/components/chrome/Header.astro +94 -0
  75. package/templates/astro/template/src/components/elements/AtomicBlock.astro +15 -0
  76. package/templates/astro/template/src/components/elements/AtomicBlocks.astro +16 -0
  77. package/templates/astro/template/src/components/elements/Button.astro +51 -0
  78. package/templates/astro/template/src/components/elements/ButtonBlock.astro +25 -0
  79. package/templates/astro/template/src/components/elements/Container.astro +11 -0
  80. package/templates/astro/template/src/components/elements/Icon.astro +31 -0
  81. package/templates/astro/template/src/components/elements/Logo.astro +29 -0
  82. package/templates/astro/template/src/components/elements/RemoteImage.astro +41 -0
  83. package/templates/astro/template/src/components/sections/ContainerSection.astro +32 -0
  84. package/templates/astro/template/src/components/sections/FeatureCard.astro +23 -0
  85. package/templates/astro/template/src/components/sections/FeatureGrid.astro +35 -0
  86. package/templates/astro/template/src/components/sections/HomeHero.astro +51 -0
  87. package/templates/astro/template/src/components/sections/StatsBar.astro +33 -0
  88. package/templates/astro/template/src/design-system/styles.css +399 -0
  89. package/templates/astro/template/src/design-system/tokens/colors.css +60 -0
  90. package/templates/astro/template/src/design-system/tokens/components.css +69 -0
  91. package/templates/astro/template/src/design-system/tokens/index.css +6 -0
  92. package/templates/astro/template/src/design-system/tokens/radii.css +5 -0
  93. package/templates/astro/template/src/design-system/tokens/shadows.css +5 -0
  94. package/templates/astro/template/src/design-system/tokens/spacing.css +13 -0
  95. package/templates/astro/template/src/design-system/tokens/typography.css +24 -0
  96. package/templates/astro/template/src/env.d.ts +1 -0
  97. package/templates/astro/template/src/fixtures/atomicBlocks.ts +33 -0
  98. package/templates/astro/template/src/fixtures/composition.ts +31 -0
  99. package/templates/astro/template/src/fixtures/index.ts +17 -0
  100. package/templates/astro/template/src/fixtures/sections.ts +39 -0
  101. package/templates/astro/template/src/layouts/SiteLayout.astro +30 -0
  102. package/templates/astro/template/src/pages/[...slug].astro +61 -0
  103. package/templates/astro/template/src/render/RenderPage.astro +66 -0
  104. package/templates/astro/template/src/stories/CompositionStoryFrame.astro +15 -0
  105. package/templates/astro/template/src/stories/HomeHero.stories.ts +24 -0
  106. package/templates/astro/template/src/stories/SectionStoryFrame.astro +16 -0
  107. package/templates/astro/template/src/stories/StoryDocFrame.astro +31 -0
  108. package/templates/astro/template/tsconfig.json +11 -0
  109. package/templates/common/.agents/AGENTS.md +37 -0
  110. package/templates/common/.agents/skills/aci/SKILL.md +162 -0
  111. package/templates/common/.agents/skills/authoring/SKILL.md +590 -0
  112. package/templates/common/.agents/skills/authoring/references/block-registry.md +151 -0
  113. package/templates/common/.agents/skills/authoring/references/contracts.md +153 -0
  114. package/templates/common/.agents/skills/authoring/references/design-system.md +171 -0
  115. package/templates/common/.agents/skills/authoring/references/image-assets.md +73 -0
  116. package/templates/common/.agents/skills/authoring/references/repo-structure.md +157 -0
  117. package/templates/common/.agents/skills/migration/SKILL.md +160 -0
  118. package/templates/common/.agents/skills/migration/references/analyzing-source.md +215 -0
  119. package/templates/common/.agents/skills/migration/references/component-migration.md +200 -0
  120. package/templates/common/.agents/skills/migration/references/selector-map.md +31 -0
  121. package/templates/common/.content/.gradial-dam/blobs/sha256/7f/bf/7fbfc7fe230ff12688c496f660119e41d9725c4504d82e310c15665c73c09292 +0 -0
  122. package/templates/common/.content/.gradial-dam/blobs/sha256/a0/f5/a0f506689de9b15a7055f70103a3f02cd3ba105771ae2de6754df2ede1210d3a +0 -0
  123. package/templates/common/.content/.gradial-dam/blobs/sha256/dd/b7/ddb7e9642be08317bcd4b2bd26b58ba8d0d34dd7239e03e684a4f3634fa3845b +0 -0
  124. package/templates/common/.content/.gradial-dam/blobs/sha256/fb/32/fb3260e8286ea8231ea1c77b9c0be92d6edd9026565731eb14cfdcfd6b1b75b3 +0 -0
  125. package/templates/common/.content/config/site.json +192 -0
  126. package/templates/common/.content/dam/folders/seed/ast_site_about_hero/asset.json +9 -0
  127. package/templates/common/.content/dam/folders/seed/ast_site_about_hero/editorial.json +14 -0
  128. package/templates/common/.content/dam/folders/seed/ast_site_about_hero/governance.json +23 -0
  129. package/templates/common/.content/dam/folders/seed/ast_site_about_hero/versions/v0001.json +37 -0
  130. package/templates/common/.content/dam/folders/seed/ast_site_home_hero/asset.json +9 -0
  131. package/templates/common/.content/dam/folders/seed/ast_site_home_hero/editorial.json +14 -0
  132. package/templates/common/.content/dam/folders/seed/ast_site_home_hero/governance.json +23 -0
  133. package/templates/common/.content/dam/folders/seed/ast_site_home_hero/versions/v0001.json +37 -0
  134. package/templates/common/.content/fragments/navbar/_index.json +25 -0
  135. package/templates/common/.content/fragments/site-footer/_index.json +62 -0
  136. package/templates/common/.content/pages/about/_index.json +51 -0
  137. package/templates/common/.content/pages/home/_index.json +112 -0
  138. package/templates/common/.content/schemas/site.schema.json +123 -0
  139. package/templates/common/README.md.tmpl +45 -0
  140. package/templates/common/contracts/components/button.contract.ts +19 -0
  141. package/templates/common/contracts/components/container.contract.ts +19 -0
  142. package/templates/common/contracts/components/featureCard.contract.ts +15 -0
  143. package/templates/common/contracts/components/featureGrid.contract.ts +16 -0
  144. package/templates/common/contracts/components/homeHero.contract.ts +36 -0
  145. package/templates/common/contracts/components/index.ts +21 -0
  146. package/templates/common/contracts/components/siteFooter.contract.ts +45 -0
  147. package/templates/common/contracts/components/siteNavigation.contract.ts +30 -0
  148. package/templates/common/contracts/components/statsBar.contract.ts +19 -0
  149. package/templates/common/design-system/styles.css +346 -0
  150. package/templates/common/design-system/tokens/colors.css +110 -0
  151. package/templates/common/design-system/tokens/components.css +86 -0
  152. package/templates/common/design-system/tokens/index.css +6 -0
  153. package/templates/common/design-system/tokens/radii.css +5 -0
  154. package/templates/common/design-system/tokens/shadows.css +9 -0
  155. package/templates/common/design-system/tokens/spacing.css +26 -0
  156. package/templates/common/design-system/tokens/typography.css +32 -0
  157. package/templates/common/eslint-rules/no-raw-tailwind-values.js +127 -0
  158. package/templates/common/public/assets/Dwire-model.png +0 -0
  159. package/templates/common/public/assets/bare-metal-logo.png +0 -0
  160. package/templates/common/public/assets/meridian-logo.svg +8 -0
  161. package/templates/common/public/assets/seattle.avif +0 -0
  162. package/templates/nextjs/template/.aci.yaml +25 -0
  163. package/templates/nextjs/template/.storybook/main.ts +13 -0
  164. package/templates/nextjs/template/.storybook/preview.ts +34 -0
  165. package/templates/nextjs/template/eslint.config.mjs +36 -0
  166. package/templates/nextjs/template/next-env.d.ts +6 -0
  167. package/templates/nextjs/template/next.config.ts +8 -0
  168. package/templates/nextjs/template/package.json.tmpl +46 -0
  169. package/templates/nextjs/template/postcss.config.mjs +7 -0
  170. package/templates/nextjs/template/src/app/[[...slug]]/page.tsx +8 -0
  171. package/templates/nextjs/template/src/app/gradial/assets/[releaseId]/[...path]/route.ts +31 -0
  172. package/templates/nextjs/template/src/app/layout.tsx +29 -0
  173. package/templates/nextjs/template/src/cms/contracts/components/button.contract.ts +19 -0
  174. package/templates/nextjs/template/src/cms/contracts/components/container.contract.ts +20 -0
  175. package/templates/nextjs/template/src/cms/contracts/components/homeHero.contract.ts +36 -0
  176. package/templates/nextjs/template/src/cms/contracts/components/index.ts +15 -0
  177. package/templates/nextjs/template/src/cms/contracts/components/siteFooter.contract.ts +45 -0
  178. package/templates/nextjs/template/src/cms/contracts/components/siteNavigation.contract.ts +30 -0
  179. package/templates/nextjs/template/src/cms/contracts/layouts/index.ts +16 -0
  180. package/templates/nextjs/template/src/cms/registry.ts +28 -0
  181. package/templates/nextjs/template/src/components/chrome/Footer.tsx +86 -0
  182. package/templates/nextjs/template/src/components/chrome/Header.tsx +74 -0
  183. package/templates/nextjs/template/src/components/elements/AtomicBlock.tsx +13 -0
  184. package/templates/nextjs/template/src/components/elements/Button.tsx +40 -0
  185. package/templates/nextjs/template/src/components/elements/ButtonBlock.tsx +18 -0
  186. package/templates/nextjs/template/src/components/elements/Container.tsx +14 -0
  187. package/templates/nextjs/template/src/components/elements/Icon.tsx +29 -0
  188. package/templates/nextjs/template/src/components/elements/Logo.tsx +38 -0
  189. package/templates/nextjs/template/src/components/sections/ContainerSection.tsx +28 -0
  190. package/templates/nextjs/template/src/components/sections/FeatureCard.tsx +25 -0
  191. package/templates/nextjs/template/src/components/sections/FeatureGrid.tsx +36 -0
  192. package/templates/nextjs/template/src/components/sections/HomeHero.tsx +62 -0
  193. package/templates/nextjs/template/src/components/sections/StatsBar.tsx +30 -0
  194. package/templates/nextjs/template/src/middleware.ts +4 -0
  195. package/templates/nextjs/template/src/stories/Button.stories.tsx +38 -0
  196. package/templates/nextjs/template/src/stories/Header.stories.tsx +30 -0
  197. package/templates/nextjs/template/src/stories/HomeHero.stories.tsx +33 -0
  198. package/templates/nextjs/template/tsconfig.json +23 -0
  199. package/templates/nextjs/template/vercel.json +6 -0
  200. package/dist/content/contract.d.ts +0 -83
  201. package/dist/content/contract.js +0 -104
  202. package/dist/content/tailwind-validator.d.ts +0 -6
  203. package/dist/content/tailwind-validator.js +0 -31
  204. package/dist/content/validation.d.ts +0 -108
  205. package/dist/content/validation.js +0 -183
  206. package/dist/react/GradialMedia.d.ts +0 -24
  207. package/dist/react/GradialMedia.js +0 -31
  208. package/dist/react/GradialPicture.d.ts +0 -14
  209. package/dist/react/GradialPicture.js +0 -30
  210. package/dist/react/GradialVideoPlayer.d.ts +0 -13
  211. package/dist/sveltekit/index.d.ts +0 -25
  212. package/dist/sveltekit/index.js +0 -66
  213. package/dist/sveltekit/preview.d.ts +0 -5
  214. package/dist/sveltekit/preview.js +0 -33
  215. package/src/types/component.ts +0 -49
  216. package/src/types/config.ts +0 -37
  217. package/src/types/data.ts +0 -47
  218. package/src/types/index.ts +0 -10
  219. package/src/types/layout.ts +0 -29
  220. package/src/types/media.ts +0 -125
  221. package/src/types/page.ts +0 -47
  222. package/src/types/render-mode.ts +0 -10
  223. package/src/types/renderer.ts +0 -83
  224. package/src/types/video.ts +0 -66
package/README.md CHANGED
@@ -1,147 +1,87 @@
1
1
  # Agentic Content Infrastructure SDK
2
2
 
3
- Agentic Content Infrastructure (ACI) sites implement the frontend contract by
4
- installing `@gradial/aci`, Zod 4, and TypeScript tooling. The
5
- SDK exposes component and layout helpers, renderer types, compiler tooling,
6
- content provider helpers, and framework-specific subpaths from one package.
3
+ `@gradial/aci` `0.1.20` is a pre-1.0 public-surface reset for the ACI
4
+ client SDK. Breaking changes from the old `0.1.x` accidental surface are
5
+ intentional: the root import is framework-neutral, framework runtime behavior is
6
+ behind explicit subpaths, and the first required customer path is React/Next.
7
7
 
8
- ## Getting Started
9
-
10
- The fastest way to create a new ACI site is via the scaffolding script:
8
+ ## Install
11
9
 
12
10
  ```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
11
+ npm install @gradial/aci@0.1.20 zod@^4
16
12
  ```
17
13
 
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
-
30
- ```bash
31
- pnpm add @gradial/aci zod@^4
32
- pnpm add -D typescript tsx
33
- ```
14
+ ## Root Import
34
15
 
35
- Common imports:
16
+ The root import is for framework-neutral contracts and value types only:
36
17
 
37
18
  ```ts
38
- import { defineComponentContract, defineLayoutContract, slot } from '@gradial/aci';
39
- import type { GradialRenderer } from '@gradial/aci';
40
- import type { KernelPage, KernelSiteConfig } from '@gradial/aci/content';
41
- import { createContentSchemas, stringField } from '@gradial/aci/content';
42
- import { FileContentProvider } from '@gradial/aci/providers/file';
19
+ import {
20
+ ImageSchema,
21
+ HeadingSchema,
22
+ LinkSchema,
23
+ RichTextValueSchema,
24
+ defineComponentContract,
25
+ type Image,
26
+ type Heading,
27
+ type Link,
28
+ type RichTextValue,
29
+ } from '@gradial/aci';
43
30
  ```
44
31
 
45
- Content contract helpers are also available through focused subpaths:
46
- `@gradial/aci/content/contract`, `@gradial/aci/content/validation`, and
47
- `@gradial/aci/content/tailwind-validator`.
48
-
49
- Framework helpers live under `@gradial/aci/astro`,
50
- `@gradial/aci/next/server`, `@gradial/aci/next/middleware`,
51
- `@gradial/aci/next/dev-refresh`, and `@gradial/aci/sveltekit`.
52
-
53
- ## Component Contracts vs Runtime Components
32
+ The root import does not load React, Next, Vite, Webpack, browser-only code, or
33
+ server providers.
54
34
 
55
- Keep compile-time CMS contracts separate from runtime component implementation.
56
- The ACI compiler imports only contract files, so those files must not import
57
- React, framework components, CSS, or browser-only code.
35
+ ## React/Next
58
36
 
59
- Recommended shape:
37
+ React renderers and bindings live under `@gradial/aci/react`:
60
38
 
61
- ```txt
62
- src/cms/contracts/components/hero.contract.ts
63
- src/cms/contracts/components/index.ts
64
- src/cms/contracts/layouts/index.ts
65
- src/components/Hero.tsx
66
- src/cms/renderBlock.tsx
39
+ ```tsx
40
+ import { Image, Link, Heading, RichText, bindReactComponent } from '@gradial/aci/react';
67
41
  ```
68
42
 
69
- Contract files own names, schemas, render modes, image slots, and other metadata:
43
+ Next integration helpers live under explicit Next subpaths:
70
44
 
71
45
  ```ts
72
- import { defineComponentContract, GradialImageSchema } from '@gradial/aci';
73
- import { z } from 'zod';
74
-
75
- export const heroContract = defineComponentContract({
76
- name: 'hero',
77
- schema: z.object({
78
- headline: z.string(),
79
- image: GradialImageSchema,
80
- }),
81
- });
82
-
83
- export type HeroProps = z.infer<typeof heroContract.schema>;
46
+ import { createPage, withAci } from '@gradial/aci/next';
47
+ import { createMiddleware } from '@gradial/aci/next/middleware';
48
+ import { DevRefresh } from '@gradial/aci/next/dev-refresh';
84
49
  ```
85
50
 
86
- Runtime components may import the contract for types, but contract files should
87
- never import runtime components:
51
+ Astro public subpath is `@gradial/aci/astro`.
88
52
 
89
- ```tsx
90
- import type { HeroProps } from '../cms/contracts/components/hero.contract';
53
+ ## Server-Side Content Providers
91
54
 
92
- export function Hero(props: HeroProps) {
93
- return <section>{props.headline}</section>;
94
- }
95
- ```
96
-
97
- Testing helpers live under `@gradial/aci/testing`:
55
+ File and S3 providers are public server-only APIs for custom server composition,
56
+ such as blogs, events, product detail pages, and route-specific loaders:
98
57
 
99
58
  ```ts
100
- import { FixtureContentProvider } from '@gradial/aci/testing';
101
-
102
- const content = new FixtureContentProvider({
103
- pages: {
104
- '/': {
105
- id: 'home',
106
- $type: 'page',
107
- status: 'published',
108
- layout: 'marketing',
109
- metadata: { title: 'Test Home' },
110
- regions: { main: [] }
111
- }
112
- }
113
- });
114
-
115
- const input = await content.loadRenderInput('/');
59
+ import { FileContentProvider } from '@gradial/aci/providers/file';
60
+ import { S3ContentProvider } from '@gradial/aci/providers/s3';
116
61
  ```
117
62
 
118
- Use this in unit tests when you want the same provider API as
119
- `FileContentProvider` without creating `.content` fixture files.
63
+ These providers are not browser/client-side fetch APIs. Client-side fetch should
64
+ go through an app-owned HTTP endpoint backed server-side by a `ContentProvider`.
120
65
 
121
- Publish from this package directory:
66
+ ## Scaffold
67
+
68
+ The first RC scaffold path is Next:
122
69
 
123
70
  ```bash
124
- pnpm publish --access public
71
+ npx @gradial/aci@0.1.20 init my-site --template next-starter
125
72
  ```
126
73
 
127
- The package includes a `prepack` script that builds `dist` before packing or
128
- publishing.
74
+ List available templates:
129
75
 
130
- ## Verify the Published Shape Locally
76
+ ```bash
77
+ npx @gradial/aci@0.1.20 init --list
78
+ ```
131
79
 
132
- Before publishing, inspect the exact tarball pnpm will upload. This catches
133
- package `files` mistakes where local source imports work from the repo but fail
134
- after pnpm filters the packed files.
80
+ ## Verify Locally
135
81
 
136
82
  From `packages/sdk`:
137
83
 
138
84
  ```bash
139
- tmpdir="$(mktemp -d /tmp/gradial-aci-pack.XXXXXX)"
140
- filename="$(pnpm pack --pack-destination "$tmpdir" | tail -n 1)"
141
- tar -tzf "$tmpdir/$filename" | sort | rg '^(package/src/cli/|package/src/types/|package/dist/types/)'
142
- echo "tarball=$tmpdir/$filename"
85
+ pnpm run build
86
+ pnpm run generate-starters
143
87
  ```
144
-
145
- If a shipped source CLI imports another source file, make sure both paths appear
146
- in the tarball. For example, `src/cli/compile-registry.mjs` imports
147
- `src/types/image.ts`, so both files must be included by `package.json#files`.
Binary file
package/bin/aci.js CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawn } from 'node:child_process';
3
3
  import { existsSync } from 'node:fs';
4
+ import { cp, mkdir, readdir, readFile, rename, stat, writeFile } from 'node:fs/promises';
4
5
  import { createRequire } from 'node:module';
5
- import { dirname, join, resolve } from 'node:path';
6
+ import { basename, dirname, join, relative, resolve } from 'node:path';
6
7
  import { fileURLToPath } from 'node:url';
7
8
 
8
9
  const require = createRequire(import.meta.url);
@@ -14,6 +15,7 @@ const platformPackages = {
14
15
  'darwin-x64': '@gradial/aci-cli-darwin-x64',
15
16
  'linux-arm64': '@gradial/aci-cli-linux-arm64',
16
17
  'linux-x64': '@gradial/aci-cli-linux-x64',
18
+ 'win32-arm64': '@gradial/aci-cli-win32-arm64',
17
19
  'win32-x64': '@gradial/aci-cli-win32-x64',
18
20
  };
19
21
 
@@ -21,7 +23,7 @@ const platformKey = `${process.platform}-${process.arch}`;
21
23
  const packageName = platformPackages[platformKey];
22
24
 
23
25
  if (!packageName) {
24
- console.error(`Unsupported platform for aci: ${platformKey}`);
26
+ console.error(`Unsupported platform for gradial-aci: ${platformKey}`);
25
27
  process.exit(1);
26
28
  }
27
29
 
@@ -29,9 +31,17 @@ const binName = process.platform === 'win32' ? 'aci.exe' : 'aci';
29
31
  const shimDir = dirname(fileURLToPath(import.meta.url));
30
32
  const repoRoot = resolve(shimDir, '../../..');
31
33
 
34
+ if (argv[0] === 'init') {
35
+ await runInit(argv.slice(1));
36
+ process.exit(0);
37
+ }
38
+
32
39
  function resolveBundledBinary() {
33
- const binaryPath = join(shimDir, binName);
34
- return existsSync(binaryPath) ? binaryPath : null;
40
+ const binaryPath = join(shimDir, `aci-${platformKey}${process.platform === 'win32' ? '.exe' : ''}`);
41
+ if (existsSync(binaryPath)) return binaryPath;
42
+ // Local development fallback for packages built before platform-suffixed bins.
43
+ const legacyPath = join(shimDir, binName);
44
+ return existsSync(legacyPath) ? legacyPath : null;
35
45
  }
36
46
 
37
47
  function resolvePackagedBinary() {
@@ -65,14 +75,24 @@ if (!binaryPath && !fallback) {
65
75
  }
66
76
 
67
77
  const child = binaryPath
68
- ? spawn(binaryPath, argv, { stdio: 'inherit' })
78
+ ? spawn(binaryPath, argv, {
79
+ env: {
80
+ ...process.env,
81
+ ACI_PACKAGE_ROOT: resolve(shimDir, '..'),
82
+ },
83
+ stdio: 'inherit',
84
+ })
69
85
  : spawn(fallback.command, fallback.args, {
70
86
  cwd: fallback.cwd,
87
+ env: {
88
+ ...process.env,
89
+ ACI_PACKAGE_ROOT: resolve(shimDir, '..'),
90
+ },
71
91
  stdio: 'inherit',
72
92
  });
73
93
 
74
94
  child.on('error', (error) => {
75
- console.error(`Failed to run aci: ${error.message}`);
95
+ console.error(`Failed to run gradial-aci: ${error.message}`);
76
96
  process.exit(1);
77
97
  });
78
98
 
@@ -155,3 +175,76 @@ function normalizePathArg(value) {
155
175
  function isAbsolutePath(value) {
156
176
  return value.startsWith('/') || /^[A-Za-z]:[\\/]/.test(value);
157
177
  }
178
+
179
+ async function runInit(args) {
180
+ if (args.includes('--list')) {
181
+ console.log('next-starter');
182
+ return;
183
+ }
184
+
185
+ const target = args.find((arg) => !arg.startsWith('-'));
186
+ const template = optionValue(args, '--template') || 'next-starter';
187
+ if (!target) {
188
+ throw new Error('usage: aci init <target> --template next-starter');
189
+ }
190
+ if (template !== 'next-starter') {
191
+ throw new Error(`unknown template "${template}". Available templates: next-starter`);
192
+ }
193
+
194
+ const targetDir = resolve(callerCwd, target);
195
+ await assertEmptyTarget(targetDir);
196
+ await mkdir(targetDir, { recursive: true });
197
+
198
+ const packageRoot = resolve(shimDir, '..');
199
+ await cp(join(packageRoot, 'templates', 'common'), targetDir, { recursive: true });
200
+ await cp(join(packageRoot, 'templates', 'nextjs', 'template'), targetDir, { recursive: true });
201
+ await renderTemplates(targetDir, {
202
+ siteName: basename(targetDir),
203
+ version: '0.1.0',
204
+ });
205
+ console.log(`Created ${relative(callerCwd, targetDir) || '.'} from next-starter`);
206
+ }
207
+
208
+ function optionValue(args, name) {
209
+ for (let index = 0; index < args.length; index += 1) {
210
+ const arg = args[index];
211
+ if (arg === name) return args[index + 1] || '';
212
+ if (arg.startsWith(`${name}=`)) return arg.slice(name.length + 1);
213
+ }
214
+ return '';
215
+ }
216
+
217
+ async function assertEmptyTarget(targetDir) {
218
+ try {
219
+ const info = await stat(targetDir);
220
+ if (!info.isDirectory()) {
221
+ throw new Error(`target exists and is not a directory: ${targetDir}`);
222
+ }
223
+ const entries = await readdir(targetDir);
224
+ if (entries.length > 0) {
225
+ throw new Error(`target directory is not empty: ${targetDir}`);
226
+ }
227
+ } catch (error) {
228
+ if (error?.code === 'ENOENT') return;
229
+ throw error;
230
+ }
231
+ }
232
+
233
+ async function renderTemplates(root, values) {
234
+ const entries = await readdir(root, { withFileTypes: true });
235
+ for (const entry of entries) {
236
+ const fullPath = join(root, entry.name);
237
+ if (entry.isDirectory()) {
238
+ await renderTemplates(fullPath, values);
239
+ continue;
240
+ }
241
+ if (!entry.name.endsWith('.tmpl')) {
242
+ continue;
243
+ }
244
+ const raw = await readFile(fullPath, 'utf-8');
245
+ const rendered = raw.replace(/\{\{\s*([A-Za-z0-9_]+)\s*\}\}/g, (_match, key) => values[key] ?? '');
246
+ const nextPath = fullPath.slice(0, -'.tmpl'.length);
247
+ await writeFile(fullPath, rendered);
248
+ await rename(fullPath, nextPath);
249
+ }
250
+ }
@@ -1,3 +1,3 @@
1
- export { type GradialImage, type ImageSource, type PictureSource, type ImageSlotContract, type SlotOutput, type ImageHTMLAttributes, GradialImageSchema, renderImageHTML, } from '../types/image.js';
2
- export { type GradialVideo, type VideoSource, GradialVideoSchema, VideoSourceSchema, } from '../types/video.js';
3
- export { type GradialAsset, GradialAssetSchema, isGradialImage, isGradialVideo, isGradialAsset, renderVideoHTML, renderAssetHTML, } from '../types/media.js';
1
+ export { type Image, type ImageSource, type ImageAttrs, ImageSchema, imageAttrs, primaryImageSource, } from '../types/image.js';
2
+ export { type Video, type VideoSource, VideoSchema, VideoSourceSchema, } from '../types/video.js';
3
+ export { type Asset, AssetSchema, isImage, isVideo, isAsset, } from '../types/media.js';
@@ -1,3 +1,3 @@
1
- export { GradialImageSchema, renderImageHTML, } from '../types/image.js';
2
- export { GradialVideoSchema, VideoSourceSchema, } from '../types/video.js';
3
- export { GradialAssetSchema, isGradialImage, isGradialVideo, isGradialAsset, renderVideoHTML, renderAssetHTML, } from '../types/media.js';
1
+ export { ImageSchema, imageAttrs, primaryImageSource, } from '../types/image.js';
2
+ export { VideoSchema, VideoSourceSchema, } from '../types/video.js';
3
+ export { AssetSchema, isImage, isVideo, isAsset, } from '../types/media.js';
@@ -1,5 +1,7 @@
1
1
  import type { RenderInput } from '../content/types.js';
2
- import { type GradialContentWatchOptions } from '../dev/index.js';
2
+ import { type ContentWatchOptions } from '../dev/content-watch.js';
3
+ import type { Registry, AnyComponent } from '../registry.js';
4
+ import type { BlockRef } from '../types/block-ref.js';
3
5
  interface AstroConfigSetupParams {
4
6
  injectScript(stage: 'head-inline' | 'page' | 'page-ssr', content: string): void;
5
7
  updateConfig(config: {
@@ -35,9 +37,16 @@ export declare function getGradialStaticPaths(): Promise<Array<{
35
37
  export declare function getPageRuntimeRenderInput(request: Request): RenderInput | null;
36
38
  export { createRegistry, registryLookup } from '../registry.js';
37
39
  export type { Registry, RegistryEntry, AnyComponent } from '../registry.js';
40
+ export type { BlockRef } from '../types/block-ref.js';
41
+ export interface RenderableBlock {
42
+ Component: AnyComponent | undefined;
43
+ props: Record<string, unknown>;
44
+ }
45
+ export type RenderChildren = (blocks: readonly BlockRef[]) => RenderableBlock[];
46
+ export declare function createRenderChildren(registry: Registry): RenderChildren;
38
47
  export { getPreviewMode, createPreviewBannerHTML, createPreviewCookies, type PreviewContext, type PreviewCookie, } from './preview.js';
39
- export interface GradialAstroOptions extends GradialContentWatchOptions {
48
+ export interface AstroOptions extends ContentWatchOptions {
40
49
  /** Path to compiled content root. Defaults to ACI_CONTENT_ROOT env or '.aci/compiled' */
41
50
  compiledRoot?: string;
42
51
  }
43
- export declare function withGradialAci(options?: GradialAstroOptions): AstroIntegrationLike;
52
+ export declare function withAci(options?: AstroOptions): AstroIntegrationLike;
@@ -1,7 +1,8 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { getPendingRenderInputFromHeaders } from '../runtime/page.js';
4
- import { gradialContentWatchPlugin, gradialDamAssetPlugin, devRefreshPort, devRefreshScript, } from '../dev/index.js';
4
+ import { contentWatchPlugin, damAssetPlugin, devRefreshPort, } from '../dev/content-watch.js';
5
+ import { createDevRefreshBrowserScript } from '../dev/index.js';
5
6
  // ---------------------------------------------------------------------------
6
7
  // Static paths helper — for Astro SSG
7
8
  // ---------------------------------------------------------------------------
@@ -35,24 +36,38 @@ export function getPageRuntimeRenderInput(request) {
35
36
  // Registry helpers
36
37
  // ---------------------------------------------------------------------------
37
38
  export { createRegistry, registryLookup } from '../registry.js';
39
+ export function createRenderChildren(registry) {
40
+ function renderChildren(blocks) {
41
+ return blocks.map((block) => {
42
+ const entry = registry.find((r) => r.id === block.component);
43
+ const hasBlockSlots = !!entry?.contract.blockSlots;
44
+ const props = { ...block.props };
45
+ if (hasBlockSlots) {
46
+ props.renderChildren = renderChildren;
47
+ }
48
+ return { Component: entry?.component, props };
49
+ });
50
+ }
51
+ return renderChildren;
52
+ }
38
53
  // ---------------------------------------------------------------------------
39
54
  // Preview support
40
55
  // ---------------------------------------------------------------------------
41
56
  export { getPreviewMode, createPreviewBannerHTML, createPreviewCookies, } from './preview.js';
42
- export function withGradialAci(options = {}) {
57
+ export function withAci(options = {}) {
43
58
  return {
44
- name: 'gradial-astro',
59
+ name: 'aci-astro',
45
60
  hooks: {
46
61
  'astro:config:setup'({ injectScript, updateConfig }) {
47
62
  if (process.env.NODE_ENV === 'production') {
48
63
  return;
49
64
  }
50
65
  if (devRefreshPort(options) > 0) {
51
- injectScript('page', devRefreshScript(options));
66
+ injectScript('page', createDevRefreshBrowserScript(options));
52
67
  }
53
68
  updateConfig({
54
69
  vite: {
55
- plugins: [gradialDamAssetPlugin(options), gradialContentWatchPlugin(options)],
70
+ plugins: [damAssetPlugin(options), contentWatchPlugin(options)],
56
71
  },
57
72
  });
58
73
  },
@@ -0,0 +1,17 @@
1
+ export interface ReleaseAssetConfig {
2
+ bucket?: string;
3
+ keyPrefix?: string;
4
+ region?: string;
5
+ accessKeyId?: string;
6
+ secretAccessKey?: string;
7
+ sessionToken?: string;
8
+ endpoint?: string;
9
+ }
10
+ export declare class ReleaseAssetNotFoundError extends Error {
11
+ constructor(releaseId: string, assetPath: string, cause?: unknown);
12
+ }
13
+ export declare function getReleaseAssetResponse(input: {
14
+ releaseId: string;
15
+ assetPath: string;
16
+ config?: ReleaseAssetConfig;
17
+ }): Promise<Response>;
@@ -0,0 +1,65 @@
1
+ import { S3ContentProvider } from '../providers/s3.js';
2
+ export class ReleaseAssetNotFoundError extends Error {
3
+ constructor(releaseId, assetPath, cause) {
4
+ super(`ACI release asset not found: ${releaseId}/${assetPath}`);
5
+ this.name = 'ReleaseAssetNotFoundError';
6
+ this.cause = cause;
7
+ }
8
+ }
9
+ export async function getReleaseAssetResponse(input) {
10
+ const clean = cleanAssetPath(input.assetPath);
11
+ if (!input.releaseId || !clean) {
12
+ throw new ReleaseAssetNotFoundError(input.releaseId, input.assetPath);
13
+ }
14
+ const config = input.config ?? {};
15
+ const provider = new S3ContentProvider({
16
+ bucket: config.bucket,
17
+ keyPrefix: releaseKey(config, input.releaseId),
18
+ region: config.region,
19
+ accessKeyId: config.accessKeyId,
20
+ secretAccessKey: config.secretAccessKey,
21
+ sessionToken: config.sessionToken,
22
+ endpoint: config.endpoint,
23
+ });
24
+ const key = joinKey(provider.config.keyPrefix, 'assets', clean);
25
+ const res = await provider.fetchRaw(key);
26
+ if (!res.ok || !res.body) {
27
+ throw new ReleaseAssetNotFoundError(input.releaseId, clean, await safeResponseText(res));
28
+ }
29
+ const headers = new Headers();
30
+ copyHeader(res.headers, headers, 'content-type');
31
+ copyHeader(res.headers, headers, 'content-length');
32
+ copyHeader(res.headers, headers, 'etag');
33
+ copyHeader(res.headers, headers, 'last-modified');
34
+ headers.set('cache-control', 'public, max-age=31536000, immutable');
35
+ return new Response(res.body, { status: 200, headers });
36
+ }
37
+ function cleanAssetPath(value) {
38
+ const clean = value.replace(/^\/+|\/+$/g, '').replace(/\/+/g, '/');
39
+ if (!clean || clean.split('/').some((segment) => segment === '..' || segment === '.'))
40
+ return '';
41
+ return clean;
42
+ }
43
+ function copyHeader(from, to, name) {
44
+ const value = from.get(name);
45
+ if (value)
46
+ to.set(name, value);
47
+ }
48
+ async function safeResponseText(res) {
49
+ try {
50
+ return await res.text();
51
+ }
52
+ catch {
53
+ return '';
54
+ }
55
+ }
56
+ function releaseKey(config, releaseId) {
57
+ return joinKey(config.keyPrefix || process.env.ACI_S3_KEY_PREFIX || '', 'releases', releaseId);
58
+ }
59
+ function joinKey(...parts) {
60
+ return parts
61
+ .filter(Boolean)
62
+ .map((part) => part.replace(/^\/+|\/+$/g, ''))
63
+ .filter(Boolean)
64
+ .join('/');
65
+ }
@@ -3,3 +3,4 @@ export * from './routes.js';
3
3
  export * from './types.js';
4
4
  export * from './cache.js';
5
5
  export * from './resolve-slots.js';
6
+ export * from './assets.js';
@@ -3,3 +3,4 @@ export * from './routes.js';
3
3
  export * from './types.js';
4
4
  export * from './cache.js';
5
5
  export * from './resolve-slots.js';
6
+ export * from './assets.js';
@@ -1,3 +1,2 @@
1
1
  import type { ComponentContract, ComponentDefinition } from './types/component.js';
2
- export declare function defineComponent<TSchema = unknown>(definition: ComponentDefinition<TSchema>): ComponentContract<TSchema>;
3
- export declare const defineComponentContract: typeof defineComponent;
2
+ export declare function defineComponentContract<const TId extends string, TSchema = unknown>(definition: ComponentDefinition<TId, TSchema>): ComponentContract<TId, TSchema>;
@@ -1,8 +1,76 @@
1
- export function defineComponent(definition) {
1
+ import { getBlockRefMeta } from './types/block-ref.js';
2
+ export function defineComponentContract(definition) {
2
3
  return {
3
- ...definition,
4
- varyDimensions: definition.varyDimensions ?? definition.vary,
5
- vary: definition.vary ?? definition.varyDimensions,
4
+ id: definition.id,
5
+ ...(definition.displayName ? { displayName: definition.displayName } : {}),
6
+ props: definition.props,
7
+ ...scanBlockSlots(definition.props),
8
+ ...(definition.imageSlots ? { imageSlots: definition.imageSlots } : {}),
9
+ validate: definition.validate ?? [],
6
10
  };
7
11
  }
8
- export const defineComponentContract = defineComponent;
12
+ function scanBlockSlots(schema) {
13
+ const slots = {};
14
+ const shape = getSchemaShape(schema);
15
+ if (!shape)
16
+ return {};
17
+ for (const [key, fieldSchema] of Object.entries(shape)) {
18
+ const unwrapped = unwrapOptional(fieldSchema);
19
+ const meta = getBlockRefMeta(unwrapped) ?? getBlockRefMeta(unwrapArray(unwrapped));
20
+ if (meta) {
21
+ slots[key] = meta;
22
+ }
23
+ }
24
+ return Object.keys(slots).length ? { blockSlots: slots } : {};
25
+ }
26
+ function unwrapOptional(schema) {
27
+ let current = schema;
28
+ const seen = new Set();
29
+ while (current && typeof current === 'object' && !seen.has(current)) {
30
+ seen.add(current);
31
+ const def = current._def;
32
+ if (!def || typeof def !== 'object')
33
+ break;
34
+ const type = def.type;
35
+ const typeName = def.typeName;
36
+ if (type === 'optional' || type === 'nullable' || type === 'default' ||
37
+ typeName === 'ZodOptional' || typeName === 'ZodNullable' || typeName === 'ZodDefault') {
38
+ const inner = def.innerType ?? def.schema;
39
+ if (inner) {
40
+ current = inner;
41
+ continue;
42
+ }
43
+ }
44
+ break;
45
+ }
46
+ return current;
47
+ }
48
+ function getSchemaShape(schema) {
49
+ if (!schema || typeof schema !== 'object')
50
+ return null;
51
+ const def = schema._def;
52
+ if (!def || typeof def !== 'object')
53
+ return null;
54
+ const shape = def.shape;
55
+ if (typeof shape === 'function') {
56
+ return shape.call(def);
57
+ }
58
+ if (shape && typeof shape === 'object') {
59
+ return shape;
60
+ }
61
+ return null;
62
+ }
63
+ function unwrapArray(schema) {
64
+ if (!schema || typeof schema !== 'object')
65
+ return null;
66
+ const def = schema._def;
67
+ if (!def || typeof def !== 'object')
68
+ return null;
69
+ const type = def.type;
70
+ const typeName = def.typeName;
71
+ if (type === 'array' && def.element)
72
+ return def.element;
73
+ if (typeName === 'ZodArray' && def.type)
74
+ return def.type;
75
+ return null;
76
+ }