@ggui-ai/artifact-manifest 0.2.0-alpha.4 → 0.3.0-rc.0

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.
package/README.md CHANGED
@@ -34,14 +34,14 @@ const artifact = parseArtifactManifest(json);
34
34
 
35
35
  ## Exports
36
36
 
37
- | Symbol | What it is |
38
- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
39
- | `gadgetManifestSchema`, `parseGadgetManifest`, `safeParseGadgetManifest`, `assertGadgetManifestValid` | Gadget manifest schema + parsers |
40
- | `blueprintManifestSchema`, `parseBlueprintManifest`, `safeParseBlueprintManifest`, `assertBlueprintManifestValid` | Blueprint manifest schema + parsers |
41
- | `artifactManifestSchema`, `parseArtifactManifest`, `safeParseArtifactManifest`, `assertArtifactManifestValid` | Discriminated union over both kinds |
42
- | `manifestToRegistryEntry` | Translate a manifest into a registry entry |
43
- | `GADGET_NAME_RE`, `BLUEPRINT_NAME_RE`, `ArtifactScopeSchema`, `ArtifactVersionSchema` | Shared name + version validators |
44
- | `GGUI_GADGET_JSON_FILENAME`, `GGUI_BLUEPRINT_JSON_FILENAME` | Canonical manifest filenames |
37
+ | Symbol | What it is |
38
+ | ------------------------------------------------------------------------------------- | ------------------------------------------ |
39
+ | `gadgetManifestSchema`, `parseGadgetManifest`, `safeParseGadgetManifest` | Gadget manifest schema + parsers |
40
+ | `blueprintManifestSchema`, `parseBlueprintManifest`, `safeParseBlueprintManifest` | Blueprint manifest schema + parsers |
41
+ | `artifactManifestSchema`, `parseArtifactManifest`, `safeParseArtifactManifest` | Discriminated union over both kinds |
42
+ | `manifestToRegistryEntry` | Translate a manifest into a registry entry |
43
+ | `GADGET_NAME_RE`, `BLUEPRINT_NAME_RE`, `ArtifactScopeSchema`, `ArtifactVersionSchema` | Shared name + version validators |
44
+ | `GGUI_GADGET_JSON_FILENAME`, `GGUI_BLUEPRINT_JSON_FILENAME` | Canonical manifest filenames |
45
45
 
46
46
  `GadgetManifest`, `BlueprintManifest`, and `ArtifactManifest` types are exported alongside their schemas.
47
47
 
@@ -89,6 +89,8 @@ export declare const artifactManifestSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
89
89
  contract: z.ZodOptional<z.ZodType<import("@ggui-ai/protocol").DataContract, unknown, z.core.$ZodTypeInternals<import("@ggui-ai/protocol").DataContract, unknown>>>;
90
90
  fixtureProps: z.ZodOptional<z.ZodUnknown>;
91
91
  variance: z.ZodOptional<z.ZodType<import("@ggui-ai/protocol").BlueprintVariance, unknown, z.core.$ZodTypeInternals<import("@ggui-ai/protocol").BlueprintVariance, unknown>>>;
92
+ generatorProtocolVersion: z.ZodOptional<z.ZodString>;
93
+ toolIdentityCatalogHash: z.ZodOptional<z.ZodString>;
92
94
  }, z.core.$strict>], "kind">;
93
95
  /**
94
96
  * Static TypeScript type derived from {@link artifactManifestSchema}.
@@ -104,11 +106,6 @@ export type ArtifactManifest = z.infer<typeof artifactManifestSchema>;
104
106
  * including unknown / missing `kind` discriminator at `path: ["kind"]`.
105
107
  */
106
108
  export declare function parseArtifactManifest(raw: unknown): ArtifactManifest;
107
- /**
108
- * Assertion helper — narrows `raw` to {@link ArtifactManifest} on
109
- * success, throws `ZodError` on failure.
110
- */
111
- export declare function assertArtifactManifestValid(raw: unknown): asserts raw is ArtifactManifest;
112
109
  /**
113
110
  * Safe-parse variant — returns a `z.safeParse` result. Prefer this
114
111
  * inside CLI tooling where you want to render the issue list without
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-manifest.d.ts","sourceRoot":"","sources":["../src/artifact-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAGjC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAatE;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,CAEpE;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,GAAG,IAAI,gBAAgB,CAEjC;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,OAAO,GACX,UAAU,CAAC,OAAO,sBAAsB,CAAC,SAAS,CAAC,CAErD"}
1
+ {"version":3,"file":"artifact-manifest.d.ts","sourceRoot":"","sources":["../src/artifact-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAGjC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAatE;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,CAEpE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,OAAO,GACX,UAAU,CAAC,OAAO,sBAAsB,CAAC,SAAS,CAAC,CAErD"}
@@ -52,13 +52,6 @@ void _artifactUnionTypeCheck;
52
52
  export function parseArtifactManifest(raw) {
53
53
  return artifactManifestSchema.parse(raw);
54
54
  }
55
- /**
56
- * Assertion helper — narrows `raw` to {@link ArtifactManifest} on
57
- * success, throws `ZodError` on failure.
58
- */
59
- export function assertArtifactManifestValid(raw) {
60
- artifactManifestSchema.parse(raw);
61
- }
62
55
  /**
63
56
  * Safe-parse variant — returns a `z.safeParse` result. Prefer this
64
57
  * inside CLI tooling where you want to render the issue list without
package/dist/base.d.ts CHANGED
@@ -52,17 +52,17 @@ export declare const BLUEPRINT_NAME_RE: RegExp;
52
52
  */
53
53
  export declare const ArtifactVersionSchema: z.ZodString;
54
54
  /**
55
- * Visibility — controls how the artifact is stored + distributed:
55
+ * Visibility — controls how the artifact is signed + distributed:
56
56
  *
57
- * - `public` — sigstore-signed, served from S3 `public/` prefix,
58
- * publicly listable via `/search`.
59
- * - `private` — Ed25519-signed, served from `private/<orgId>/`
60
- * with signed CloudFront URLs, only visible to the
61
- * publisher's Cognito org.
57
+ * - `public` — sigstore-signed, publicly listable via `/search`.
58
+ * - `private` — Ed25519-signed, scoped to the publisher's org;
59
+ * never publicly listable.
62
60
  *
63
61
  * Both paths land in the same registry stack; the visibility flag
64
- * picks the signing trust chain + S3 prefix at publish time. No
65
- * "internal" / "team" third option in MVP.
62
+ * picks the signing trust chain at publish time. How a registry
63
+ * implementation partitions storage or gates download URLs per
64
+ * visibility is the storage adapter's concern. No "internal" /
65
+ * "team" third option in MVP.
66
66
  */
67
67
  export declare const ArtifactVisibilitySchema: z.ZodEnum<{
68
68
  public: "public";
package/dist/base.js CHANGED
@@ -60,17 +60,17 @@ export const ArtifactVersionSchema = z
60
60
  message: 'version must be valid semver (MAJOR.MINOR.PATCH with optional `-pre` / `+build`).',
61
61
  });
62
62
  /**
63
- * Visibility — controls how the artifact is stored + distributed:
63
+ * Visibility — controls how the artifact is signed + distributed:
64
64
  *
65
- * - `public` — sigstore-signed, served from S3 `public/` prefix,
66
- * publicly listable via `/search`.
67
- * - `private` — Ed25519-signed, served from `private/<orgId>/`
68
- * with signed CloudFront URLs, only visible to the
69
- * publisher's Cognito org.
65
+ * - `public` — sigstore-signed, publicly listable via `/search`.
66
+ * - `private` — Ed25519-signed, scoped to the publisher's org;
67
+ * never publicly listable.
70
68
  *
71
69
  * Both paths land in the same registry stack; the visibility flag
72
- * picks the signing trust chain + S3 prefix at publish time. No
73
- * "internal" / "team" third option in MVP.
70
+ * picks the signing trust chain at publish time. How a registry
71
+ * implementation partitions storage or gates download URLs per
72
+ * visibility is the storage adapter's concern. No "internal" /
73
+ * "team" third option in MVP.
74
74
  */
75
75
  export const ArtifactVisibilitySchema = z.enum(['public', 'private']);
76
76
  /**
@@ -14,21 +14,24 @@
14
14
  * hints that drive the LLM-driven variant selector when multiple
15
15
  * blueprints share a `(appId, contractHash)` group.
16
16
  *
17
- * ## In-process counterpart
17
+ * ## Relation to `ggui_ops_register_blueprint`
18
18
  *
19
- * The in-process registration tool at
20
- * `cloud/ggui-protocol-pod/src/tools/register-blueprint.ts` accepts
21
- * `{source, contract?, fixtureProps?}` and a slug
22
- * `^[a-z0-9][a-z0-9_-]{0,63}$`. This manifest's `source` /
23
- * `contract` / `fixtureProps` fields mirror that envelope exactly
24
- * — round-tripping a blueprint through
25
- * `ggui_ops_register_blueprint` then exporting it back into a
26
- * `ggui.blueprint.json` must not require any field rewriting beyond
27
- * adding the marketplace identity (`scope`, `name`, `version`,
28
- * `kind`, `visibility`) and optional variance tags.
19
+ * The operator registration tool `ggui_ops_register_blueprint`
20
+ * (`@ggui-ai/mcp-server-handlers`) takes `{contract, componentCode,
21
+ * generator?, persona?, aesthetic?, context?, seedPrompt?,
22
+ * setAsOperatorDefault?}`. Mapping a manifest onto that envelope:
29
23
  *
30
- * The `name` regex matches the in-process slug rule
31
- * ({@link BLUEPRINT_NAME_RE}) — diverging would break round-trip.
24
+ * - `source` → `componentCode` (verbatim TSX body).
25
+ * - `contract` → `contract` (optional on the manifest,
26
+ * REQUIRED by the tool — a contract-less
27
+ * manifest cannot be registered as-is).
28
+ * - `variance` → the flat `persona` / `aesthetic` /
29
+ * `context` / `seedPrompt` fields.
30
+ * - `fixtureProps` → no counterpart. Conformance-gate-only:
31
+ * consumed by the registry's runtime probe,
32
+ * never sent on the register envelope.
33
+ * - marketplace identity (`scope`, `name`, `version`, `kind`,
34
+ * `visibility`) → no counterpart; registry-side only.
32
35
  *
33
36
  * ## Why no `matchers` field
34
37
  *
@@ -88,6 +91,8 @@ export declare const blueprintManifestSchema: z.ZodObject<{
88
91
  contract: z.ZodOptional<z.ZodType<DataContract, unknown, z.core.$ZodTypeInternals<DataContract, unknown>>>;
89
92
  fixtureProps: z.ZodOptional<z.ZodUnknown>;
90
93
  variance: z.ZodOptional<z.ZodType<BlueprintVariance, unknown, z.core.$ZodTypeInternals<BlueprintVariance, unknown>>>;
94
+ generatorProtocolVersion: z.ZodOptional<z.ZodString>;
95
+ toolIdentityCatalogHash: z.ZodOptional<z.ZodString>;
91
96
  }, z.core.$strict>;
92
97
  /**
93
98
  * Static TypeScript type derived from {@link blueprintManifestSchema}.
@@ -113,11 +118,6 @@ export declare const GGUI_BLUEPRINT_JSON_FILENAME = "ggui.blueprint.json";
113
118
  * decoded the JSON (`JSON.parse(source)`).
114
119
  */
115
120
  export declare function parseBlueprintManifest(raw: unknown): BlueprintManifest;
116
- /**
117
- * Assertion helper — narrows `raw` to {@link BlueprintManifest} on
118
- * success, throws `ZodError` on failure.
119
- */
120
- export declare function assertBlueprintManifestValid(raw: unknown): asserts raw is BlueprintManifest;
121
121
  /**
122
122
  * Safe-parse variant — returns a discriminated `z.safeParse` result
123
123
  * (`{ success: true, data }` vs `{ success: false, error }`).
@@ -1 +1 @@
1
- {"version":3,"file":"blueprint-manifest.d.ts","sourceRoot":"","sources":["../src/blueprint-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,YAAY,EAGlB,MAAM,mBAAmB,CAAC;AAgC3B;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;kBAiDlC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAmBxE;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,wBAAwB,CAAC;AAElE;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,iBAAiB,CAEtE;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,GAAG,IAAI,iBAAiB,CAElC;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,OAAO,GACX,UAAU,CAAC,OAAO,uBAAuB,CAAC,SAAS,CAAC,CAEtD"}
1
+ {"version":3,"file":"blueprint-manifest.d.ts","sourceRoot":"","sources":["../src/blueprint-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,YAAY,EAGlB,MAAM,mBAAmB,CAAC;AA+B3B;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;kBAiElC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAmBxE;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,wBAAwB,CAAC;AAElE;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,iBAAiB,CAEtE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,OAAO,GACX,UAAU,CAAC,OAAO,uBAAuB,CAAC,SAAS,CAAC,CAEtD"}
@@ -14,21 +14,24 @@
14
14
  * hints that drive the LLM-driven variant selector when multiple
15
15
  * blueprints share a `(appId, contractHash)` group.
16
16
  *
17
- * ## In-process counterpart
17
+ * ## Relation to `ggui_ops_register_blueprint`
18
18
  *
19
- * The in-process registration tool at
20
- * `cloud/ggui-protocol-pod/src/tools/register-blueprint.ts` accepts
21
- * `{source, contract?, fixtureProps?}` and a slug
22
- * `^[a-z0-9][a-z0-9_-]{0,63}$`. This manifest's `source` /
23
- * `contract` / `fixtureProps` fields mirror that envelope exactly
24
- * — round-tripping a blueprint through
25
- * `ggui_ops_register_blueprint` then exporting it back into a
26
- * `ggui.blueprint.json` must not require any field rewriting beyond
27
- * adding the marketplace identity (`scope`, `name`, `version`,
28
- * `kind`, `visibility`) and optional variance tags.
19
+ * The operator registration tool `ggui_ops_register_blueprint`
20
+ * (`@ggui-ai/mcp-server-handlers`) takes `{contract, componentCode,
21
+ * generator?, persona?, aesthetic?, context?, seedPrompt?,
22
+ * setAsOperatorDefault?}`. Mapping a manifest onto that envelope:
29
23
  *
30
- * The `name` regex matches the in-process slug rule
31
- * ({@link BLUEPRINT_NAME_RE}) — diverging would break round-trip.
24
+ * - `source` → `componentCode` (verbatim TSX body).
25
+ * - `contract` → `contract` (optional on the manifest,
26
+ * REQUIRED by the tool — a contract-less
27
+ * manifest cannot be registered as-is).
28
+ * - `variance` → the flat `persona` / `aesthetic` /
29
+ * `context` / `seedPrompt` fields.
30
+ * - `fixtureProps` → no counterpart. Conformance-gate-only:
31
+ * consumed by the registry's runtime probe,
32
+ * never sent on the register envelope.
33
+ * - marketplace identity (`scope`, `name`, `version`, `kind`,
34
+ * `visibility`) → no counterpart; registry-side only.
32
35
  *
33
36
  * ## Why no `matchers` field
34
37
  *
@@ -70,8 +73,7 @@ const BlueprintNameSchema = z.string().min(2).max(64).regex(BLUEPRINT_NAME_RE, {
70
73
  * runtime probe round-trips it through `JSON.stringify` and feeds it
71
74
  * as `props` to the rendered TSX. Any JSON-safe shape rides through;
72
75
  * the blueprint's own `contract.propsSchema` (when present) is what
73
- * actually validates the shape at runtime probe time. Mirrors the
74
- * in-process register-blueprint's `fixtureProps: z.unknown().optional()`.
76
+ * actually validates the shape at runtime probe time.
75
77
  *
76
78
  * `z.unknown()` is permitted here (not `Record<string, unknown>`)
77
79
  * because the value is genuinely shape-unknown at THIS layer — only
@@ -94,13 +96,13 @@ export const blueprintManifestSchema = z.strictObject({
94
96
  .describe('Discriminator — picks the blueprint variant of the artifact-manifest union. MUST be the literal string `"blueprint"`.'),
95
97
  // ---- Identity (required) ----
96
98
  scope: ArtifactScopeSchema.describe('Blueprint scope. Must start with `@` (e.g. `@my-org`). Disambiguates the `<scope>/<name>` install identifier.'),
97
- name: BlueprintNameSchema.describe('Blueprint slug. 2-64 chars, `^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$` — kebab-case, no underscores, no single-character names. Unified with the gadget naming rule under LOCKED-25 (2026-05-18). The in-process `ggui_ops_register_blueprint` slug rule mirrors this for round-trip preservation.'),
99
+ name: BlueprintNameSchema.describe('Blueprint slug. 2-64 chars, `^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$` — kebab-case, no underscores, no single-character names. Unified with the gadget naming rule under LOCKED-25 (2026-05-18).'),
98
100
  version: ArtifactVersionSchema.describe('SemVer. `MAJOR.MINOR.PATCH` with optional `-pre` / `+build` suffixes. Per-version immutable once published.'),
99
101
  // ---- Core blueprint shape (required: source) ----
100
102
  source: z
101
103
  .string()
102
104
  .min(1)
103
- .describe('TSX source body with a default-exported React component. Mirrors the in-process register-blueprint `blueprint.source` field — the conformance gate compiles + runtime-probes this string before the registry accepts the upload.'),
105
+ .describe('TSX source body with a default-exported React component. Maps to `ggui_ops_register_blueprint`’s `componentCode` field; the conformance gate compiles + runtime-probes this string before the registry accepts the upload.'),
104
106
  visibility: ArtifactVisibilitySchema.describe('Storage + signing posture. `public` = sigstore-signed, listable; `private` = Ed25519-signed, visible only within publisher org.'),
105
107
  // ---- Optional core blueprint shape ----
106
108
  contract: dataContractSchema
@@ -112,6 +114,17 @@ export const blueprintManifestSchema = z.strictObject({
112
114
  variance: blueprintVarianceSchema
113
115
  .optional()
114
116
  .describe("Persona + aesthetic + context + seedPrompt hints that drive the LLM-driven variant selector when multiple blueprints share a `(appId, contractHash)` group. Mirrors `Blueprint.variance` in `@ggui-ai/protocol`."),
117
+ // ---- Persistence-contract stamps (mirrors `PortableBlueprint`) ----
118
+ generatorProtocolVersion: z
119
+ .string()
120
+ .min(1)
121
+ .optional()
122
+ .describe('PROTOCOL_VERSION of the toolchain that authored + signed this manifest. Import gates compare it against the importing deployment’s era before admitting the blueprint into a reuse pool — an era mismatch (or a missing stamp) drops the row loudly instead of serving code generated against a different protocol shape. Publishing tools stamp this automatically right before signing; deployments that consume installed blueprints into a matcher pool require it.'),
123
+ toolIdentityCatalogHash: z
124
+ .string()
125
+ .min(1)
126
+ .optional()
127
+ .describe('SHA256(16) of the tool-identity catalog used to canonicalize `contract` at authoring time. Importers re-canonicalize against their own catalog and recompute the key; a divergence means the same intent would mis-key and silently cold-gen, so it is rejected. Optional — most marketplace blueprints are authored without a live tool catalog, which leaves the import gate’s re-key check inert.'),
115
128
  // ---- Shared metadata ----
116
129
  ...sharedMetadataShape,
117
130
  });
@@ -143,13 +156,6 @@ export const GGUI_BLUEPRINT_JSON_FILENAME = 'ggui.blueprint.json';
143
156
  export function parseBlueprintManifest(raw) {
144
157
  return blueprintManifestSchema.parse(raw);
145
158
  }
146
- /**
147
- * Assertion helper — narrows `raw` to {@link BlueprintManifest} on
148
- * success, throws `ZodError` on failure.
149
- */
150
- export function assertBlueprintManifestValid(raw) {
151
- blueprintManifestSchema.parse(raw);
152
- }
153
159
  /**
154
160
  * Safe-parse variant — returns a discriminated `z.safeParse` result
155
161
  * (`{ success: true, data }` vs `{ success: false, error }`).
@@ -130,8 +130,8 @@ export declare const gadgetManifestSchema: z.ZodObject<{
130
130
  * 3. THIS field — gadget author's default
131
131
  * 4. spec default `registry.ggui.ai`
132
132
  *
133
- * Most wrappers omit this (they publish to the hosted registry, and
134
- * the spec default covers them). Set this only when the wrapper ships
133
+ * Most wrappers omit this (they publish to the default registry,
134
+ * and the spec default covers them). Set this only when the wrapper ships
135
135
  * via a non-default registry (private org registry, sandbox-only
136
136
  * fixture, …). The operator override remains the right knob for
137
137
  * sandbox-vs-prod swaps.
@@ -163,13 +163,6 @@ export declare const GGUI_GADGET_JSON_FILENAME = "ggui.gadget.json";
163
163
  * decoded the JSON (`JSON.parse(source)`).
164
164
  */
165
165
  export declare function parseGadgetManifest(raw: unknown): GadgetManifest;
166
- /**
167
- * Assertion helper — narrows `raw` to {@link GadgetManifest} on
168
- * success, throws `ZodError` on failure. Useful when the caller wants
169
- * to keep the original reference (rather than the parsed copy
170
- * `parseGadgetManifest` returns).
171
- */
172
- export declare function assertGadgetManifestValid(raw: unknown): asserts raw is GadgetManifest;
173
166
  /**
174
167
  * Safe-parse variant — returns a discriminated `z.safeParse` result
175
168
  * (`{ success: true, data }` vs `{ success: false, error }`). Prefer
@@ -1 +1 @@
1
- {"version":3,"file":"gadget-manifest.d.ts","sourceRoot":"","sources":["../src/gadget-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAsFxB;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;oBAwB7B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4D/B;;;;;OAKG;;;IAcH;;;;;;;;;;;;;;;;;OAiBG;;kBAwBH,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,qBAAqB,CAAC;AAE5D;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,GAAG,IAAI,cAAc,CAE/B;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,OAAO,GACX,UAAU,CAAC,OAAO,oBAAoB,CAAC,SAAS,CAAC,CAEnD"}
1
+ {"version":3,"file":"gadget-manifest.d.ts","sourceRoot":"","sources":["../src/gadget-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAsFxB;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;oBAwB7B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4D/B;;;;;OAKG;;;IAcH;;;;;;;;;;;;;;;;;OAiBG;;kBAwBH,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,qBAAqB,CAAC;AAE5D;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,OAAO,GACX,UAAU,CAAC,OAAO,oBAAoB,CAAC,SAAS,CAAC,CAEnD"}
@@ -207,8 +207,8 @@ export const gadgetManifestSchema = z.strictObject({
207
207
  * 3. THIS field — gadget author's default
208
208
  * 4. spec default `registry.ggui.ai`
209
209
  *
210
- * Most wrappers omit this (they publish to the hosted registry, and
211
- * the spec default covers them). Set this only when the wrapper ships
210
+ * Most wrappers omit this (they publish to the default registry,
211
+ * and the spec default covers them). Set this only when the wrapper ships
212
212
  * via a non-default registry (private org registry, sandbox-only
213
213
  * fixture, …). The operator override remains the right knob for
214
214
  * sandbox-vs-prod swaps.
@@ -250,15 +250,6 @@ export const GGUI_GADGET_JSON_FILENAME = 'ggui.gadget.json';
250
250
  export function parseGadgetManifest(raw) {
251
251
  return gadgetManifestSchema.parse(raw);
252
252
  }
253
- /**
254
- * Assertion helper — narrows `raw` to {@link GadgetManifest} on
255
- * success, throws `ZodError` on failure. Useful when the caller wants
256
- * to keep the original reference (rather than the parsed copy
257
- * `parseGadgetManifest` returns).
258
- */
259
- export function assertGadgetManifestValid(raw) {
260
- gadgetManifestSchema.parse(raw);
261
- }
262
253
  /**
263
254
  * Safe-parse variant — returns a discriminated `z.safeParse` result
264
255
  * (`{ success: true, data }` vs `{ success: false, error }`). Prefer
package/dist/index.d.ts CHANGED
@@ -11,14 +11,19 @@
11
11
  * kinds for tooling that handles them generically (signing, registry
12
12
  * upload, search-index ingestion).
13
13
  *
14
+ * Also the single owner of the seed-pool wrapper-artifact format
15
+ * (`pool-artifact.ts`) — the `manifest.json` + `codes/` directory
16
+ * layout that pool exporters write and seed-pool readers consume.
17
+ *
14
18
  * Browser-safe (no Node dependencies) — pure schema + parsers.
15
19
  */
16
- export { GGUI_GADGET_JSON_FILENAME, assertGadgetManifestValid, parseGadgetManifest, gadgetManifestSchema, gadgetExportSchema, safeParseGadgetManifest, } from './gadget-manifest.js';
20
+ export { GGUI_GADGET_JSON_FILENAME, parseGadgetManifest, gadgetManifestSchema, gadgetExportSchema, safeParseGadgetManifest, } from './gadget-manifest.js';
17
21
  export type { GadgetManifest } from './gadget-manifest.js';
18
- export { GGUI_BLUEPRINT_JSON_FILENAME, assertBlueprintManifestValid, blueprintManifestSchema, parseBlueprintManifest, safeParseBlueprintManifest, } from './blueprint-manifest.js';
22
+ export { GGUI_BLUEPRINT_JSON_FILENAME, blueprintManifestSchema, parseBlueprintManifest, safeParseBlueprintManifest, } from './blueprint-manifest.js';
19
23
  export type { BlueprintManifest } from './blueprint-manifest.js';
20
- export { artifactManifestSchema, assertArtifactManifestValid, parseArtifactManifest, safeParseArtifactManifest, } from './artifact-manifest.js';
24
+ export { artifactManifestSchema, parseArtifactManifest, safeParseArtifactManifest, } from './artifact-manifest.js';
21
25
  export type { ArtifactManifest } from './artifact-manifest.js';
22
26
  export { GADGET_NAME_RE, BLUEPRINT_NAME_RE, ArtifactScopeSchema, ArtifactVersionSchema, } from './base.js';
23
27
  export { manifestToRegistryEntry, type ManifestToRegistryEntryFields, } from './manifest-to-registry-entry.js';
28
+ export { POOL_ARTIFACT_CODES_DIR, POOL_ARTIFACT_CODE_REF_PATTERN, POOL_ARTIFACT_MANIFEST_FILENAME, POOL_ARTIFACT_SCHEMA_VERSION, POOL_ARTIFACT_V1_REJECTION, buildPoolArtifactManifest, parsePoolArtifactManifest, poolArtifactCodeRef, serializePoolArtifactManifest, type ParsePoolArtifactManifestResult, type PoolArtifactManifest, type PoolArtifactManifestEntry, } from './pool-artifact.js';
24
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EACL,yBAAyB,EACzB,yBAAyB,EACzB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,EACL,4BAA4B,EAC5B,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGjE,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAS/D,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,WAAW,CAAC;AAMnB,OAAO,EACL,uBAAuB,EACvB,KAAK,6BAA6B,GACnC,MAAM,iCAAiC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGjE,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAS/D,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,WAAW,CAAC;AAMnB,OAAO,EACL,uBAAuB,EACvB,KAAK,6BAA6B,GACnC,MAAM,iCAAiC,CAAC;AAMzC,OAAO,EACL,uBAAuB,EACvB,8BAA8B,EAC9B,+BAA+B,EAC/B,4BAA4B,EAC5B,0BAA0B,EAC1B,yBAAyB,EACzB,yBAAyB,EACzB,mBAAmB,EACnB,6BAA6B,EAC7B,KAAK,+BAA+B,EACpC,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,GAC/B,MAAM,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -11,14 +11,18 @@
11
11
  * kinds for tooling that handles them generically (signing, registry
12
12
  * upload, search-index ingestion).
13
13
  *
14
+ * Also the single owner of the seed-pool wrapper-artifact format
15
+ * (`pool-artifact.ts`) — the `manifest.json` + `codes/` directory
16
+ * layout that pool exporters write and seed-pool readers consume.
17
+ *
14
18
  * Browser-safe (no Node dependencies) — pure schema + parsers.
15
19
  */
16
20
  // Gadget manifest — narrow surface.
17
- export { GGUI_GADGET_JSON_FILENAME, assertGadgetManifestValid, parseGadgetManifest, gadgetManifestSchema, gadgetExportSchema, safeParseGadgetManifest, } from './gadget-manifest.js';
21
+ export { GGUI_GADGET_JSON_FILENAME, parseGadgetManifest, gadgetManifestSchema, gadgetExportSchema, safeParseGadgetManifest, } from './gadget-manifest.js';
18
22
  // Blueprint manifest — narrow surface.
19
- export { GGUI_BLUEPRINT_JSON_FILENAME, assertBlueprintManifestValid, blueprintManifestSchema, parseBlueprintManifest, safeParseBlueprintManifest, } from './blueprint-manifest.js';
23
+ export { GGUI_BLUEPRINT_JSON_FILENAME, blueprintManifestSchema, parseBlueprintManifest, safeParseBlueprintManifest, } from './blueprint-manifest.js';
20
24
  // Discriminated union — top-level surface.
21
- export { artifactManifestSchema, assertArtifactManifestValid, parseArtifactManifest, safeParseArtifactManifest, } from './artifact-manifest.js';
25
+ export { artifactManifestSchema, parseArtifactManifest, safeParseArtifactManifest, } from './artifact-manifest.js';
22
26
  // Shared name regexes — a single kebab-case rule unified across
23
27
  // gadget and blueprint kinds. External callers (registry tooling,
24
28
  // ops tools) import these instead of re-defining the regex inline so
@@ -32,3 +36,8 @@ export { GADGET_NAME_RE, BLUEPRINT_NAME_RE, ArtifactScopeSchema, ArtifactVersion
32
36
  // through this one function. Round-trip validated in the companion
33
37
  // test file.
34
38
  export { manifestToRegistryEntry, } from './manifest-to-registry-entry.js';
39
+ // Seed-pool wrapper-artifact codec — single owner of the artifact
40
+ // byte format (version literal, layout names, codeRef shape,
41
+ // rejection messages). Pool writers and seed-pool readers both
42
+ // import from here; they own only their IO.
43
+ export { POOL_ARTIFACT_CODES_DIR, POOL_ARTIFACT_CODE_REF_PATTERN, POOL_ARTIFACT_MANIFEST_FILENAME, POOL_ARTIFACT_SCHEMA_VERSION, POOL_ARTIFACT_V1_REJECTION, buildPoolArtifactManifest, parsePoolArtifactManifest, poolArtifactCodeRef, serializePoolArtifactManifest, } from './pool-artifact.js';
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Pool-artifact wrapper codec — the SINGLE owner of the seed-pool
3
+ * artifact byte format (schemaVersion 2).
4
+ *
5
+ * A seed-pool artifact is a directory-shaped bundle of exported
6
+ * blueprints that one deployment writes and another reads:
7
+ *
8
+ * - `manifest.json` — `{ schemaVersion: 2, blueprints: [{ record:
9
+ * <PortableBlueprint minus componentCode>, codeRef:
10
+ * "<sha256hex>.tsx" }] }`, UTF-8.
11
+ * - `codes/<codeRef>` — raw UTF-8 component-code body (NOT
12
+ * JSON-wrapped). Readers reconstruct each record as
13
+ * `{ ...entry.record, componentCode }`.
14
+ *
15
+ * This module owns everything FORMAT: the schema-version literal, the
16
+ * layout names (`manifest.json`, `codes/`), the codeRef filename
17
+ * shape, the manifest types, the (de)serializers, and the canonical
18
+ * rejection/issue messages. Writers and readers — whatever transport
19
+ * they sit on (local filesystem, object storage) — import from here
20
+ * and own ONLY their IO: byte fetch/store and code-body splice. A
21
+ * future schemaVersion bump is therefore a single-point change; a
22
+ * writer and a reader can never disagree on the format.
23
+ *
24
+ * Records stay UNVALIDATED here (`record: object`): artifact bytes are
25
+ * an untrusted input, and the trust boundary for record shape is the
26
+ * protocol's `fromPortableBlueprint` inside the seed-pool builder
27
+ * (skip-with-log on rejection — a rejected seed entry is just a
28
+ * cold-gen). This codec validates only the wrapper: version, layout,
29
+ * entry shape, codeRef shape.
30
+ *
31
+ * Versioning: the wrapper version is bumped in lockstep with the
32
+ * record schema (`PORTABLE_BLUEPRINT_SCHEMA_VERSION`). v1 artifacts
33
+ * are rejected on read with {@link POOL_ARTIFACT_V1_REJECTION} — a
34
+ * blueprint pool is a cache, so the fix is a re-export, never a
35
+ * migration shim.
36
+ */
37
+ /**
38
+ * Wrapper-artifact schema version. Bumped 1 → 2 in lockstep with
39
+ * PortableBlueprint v2 (records now carry required provenance).
40
+ */
41
+ export declare const POOL_ARTIFACT_SCHEMA_VERSION = 2;
42
+ /** Manifest filename inside the artifact directory/prefix. */
43
+ export declare const POOL_ARTIFACT_MANIFEST_FILENAME = "manifest.json";
44
+ /** Code-body directory name inside the artifact directory/prefix. */
45
+ export declare const POOL_ARTIFACT_CODES_DIR = "codes";
46
+ /**
47
+ * The codec's code-body filename shape: `<sha256 hex>.tsx`. Readers
48
+ * MUST honour only refs matching this pattern so a crafted manifest
49
+ * value like `../../etc/passwd` can never escape `codes/`.
50
+ */
51
+ export declare const POOL_ARTIFACT_CODE_REF_PATTERN: RegExp;
52
+ /** Rejection message for schemaVersion-1 wrapper artifacts. */
53
+ export declare const POOL_ARTIFACT_V1_REJECTION = "re-export the pool: artifact schemaVersion 2 records carry complete provenance (PortableBlueprint v2)";
54
+ /**
55
+ * One manifest entry. `record` is deliberately untyped beyond "an
56
+ * object": the inner record is untrusted artifact bytes readers
57
+ * forward verbatim; `fromPortableBlueprint` at the pool builder is
58
+ * the validating narrower.
59
+ */
60
+ export interface PoolArtifactManifestEntry {
61
+ readonly record: object;
62
+ readonly codeRef: string;
63
+ }
64
+ export interface PoolArtifactManifest {
65
+ readonly schemaVersion: typeof POOL_ARTIFACT_SCHEMA_VERSION;
66
+ readonly blueprints: readonly PoolArtifactManifestEntry[];
67
+ }
68
+ /**
69
+ * Build the codeRef filename for a code body's sha256 hex digest.
70
+ * Throws when the input is not a 64-char lowercase hex digest — a
71
+ * writer must never produce a ref its own reader would reject.
72
+ */
73
+ export declare function poolArtifactCodeRef(sha256Hex: string): string;
74
+ /** Stamp the current schema version onto a manifest. Writer-side. */
75
+ export declare function buildPoolArtifactManifest(blueprints: readonly PoolArtifactManifestEntry[]): PoolArtifactManifest;
76
+ /** Canonical manifest bytes (pretty-printed JSON + trailing newline). */
77
+ export declare function serializePoolArtifactManifest(manifest: PoolArtifactManifest): string;
78
+ /**
79
+ * Parse + validate raw manifest bytes.
80
+ *
81
+ * Failure modes (the codec's contract, shared by every reader):
82
+ * - Manifest-level problems — invalid JSON, non-object root, an
83
+ * unsupported `schemaVersion` (v1 included), a missing/non-array
84
+ * `blueprints` — return `{ok: false, reason}`. Readers THROW,
85
+ * prefixing their transport context.
86
+ * - Entry-level problems — a malformed entry or a codeRef failing
87
+ * {@link POOL_ARTIFACT_CODE_REF_PATTERN} — DROP the entry and
88
+ * append a canonical message to `issues`. Readers surface issues
89
+ * (warn/collect), never throw on them: a single bad row is a
90
+ * skipped blueprint, not a dead pool.
91
+ */
92
+ export type ParsePoolArtifactManifestResult = {
93
+ readonly ok: true;
94
+ readonly manifest: PoolArtifactManifest;
95
+ readonly issues: readonly string[];
96
+ } | {
97
+ readonly ok: false;
98
+ readonly reason: string;
99
+ };
100
+ export declare function parsePoolArtifactManifest(raw: string): ParsePoolArtifactManifestResult;
101
+ //# sourceMappingURL=pool-artifact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pool-artifact.d.ts","sourceRoot":"","sources":["../src/pool-artifact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH;;;GAGG;AACH,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,8DAA8D;AAC9D,eAAO,MAAM,+BAA+B,kBAAkB,CAAC;AAE/D,qEAAqE;AACrE,eAAO,MAAM,uBAAuB,UAAU,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,QAAwB,CAAC;AAEpE,+DAA+D;AAC/D,eAAO,MAAM,0BAA0B,0GACkE,CAAC;AAE1G;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,aAAa,EAAE,OAAO,4BAA4B,CAAC;IAC5D,QAAQ,CAAC,UAAU,EAAE,SAAS,yBAAyB,EAAE,CAAC;CAC3D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQ7D;AAED,qEAAqE;AACrE,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,SAAS,yBAAyB,EAAE,GAC/C,oBAAoB,CAEtB;AAED,yEAAyE;AACzE,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,oBAAoB,GAC7B,MAAM,CAER;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,+BAA+B,GACvC;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC,GACD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,GACV,+BAA+B,CAwDjC"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Pool-artifact wrapper codec — the SINGLE owner of the seed-pool
3
+ * artifact byte format (schemaVersion 2).
4
+ *
5
+ * A seed-pool artifact is a directory-shaped bundle of exported
6
+ * blueprints that one deployment writes and another reads:
7
+ *
8
+ * - `manifest.json` — `{ schemaVersion: 2, blueprints: [{ record:
9
+ * <PortableBlueprint minus componentCode>, codeRef:
10
+ * "<sha256hex>.tsx" }] }`, UTF-8.
11
+ * - `codes/<codeRef>` — raw UTF-8 component-code body (NOT
12
+ * JSON-wrapped). Readers reconstruct each record as
13
+ * `{ ...entry.record, componentCode }`.
14
+ *
15
+ * This module owns everything FORMAT: the schema-version literal, the
16
+ * layout names (`manifest.json`, `codes/`), the codeRef filename
17
+ * shape, the manifest types, the (de)serializers, and the canonical
18
+ * rejection/issue messages. Writers and readers — whatever transport
19
+ * they sit on (local filesystem, object storage) — import from here
20
+ * and own ONLY their IO: byte fetch/store and code-body splice. A
21
+ * future schemaVersion bump is therefore a single-point change; a
22
+ * writer and a reader can never disagree on the format.
23
+ *
24
+ * Records stay UNVALIDATED here (`record: object`): artifact bytes are
25
+ * an untrusted input, and the trust boundary for record shape is the
26
+ * protocol's `fromPortableBlueprint` inside the seed-pool builder
27
+ * (skip-with-log on rejection — a rejected seed entry is just a
28
+ * cold-gen). This codec validates only the wrapper: version, layout,
29
+ * entry shape, codeRef shape.
30
+ *
31
+ * Versioning: the wrapper version is bumped in lockstep with the
32
+ * record schema (`PORTABLE_BLUEPRINT_SCHEMA_VERSION`). v1 artifacts
33
+ * are rejected on read with {@link POOL_ARTIFACT_V1_REJECTION} — a
34
+ * blueprint pool is a cache, so the fix is a re-export, never a
35
+ * migration shim.
36
+ */
37
+ /**
38
+ * Wrapper-artifact schema version. Bumped 1 → 2 in lockstep with
39
+ * PortableBlueprint v2 (records now carry required provenance).
40
+ */
41
+ export const POOL_ARTIFACT_SCHEMA_VERSION = 2;
42
+ /** Manifest filename inside the artifact directory/prefix. */
43
+ export const POOL_ARTIFACT_MANIFEST_FILENAME = 'manifest.json';
44
+ /** Code-body directory name inside the artifact directory/prefix. */
45
+ export const POOL_ARTIFACT_CODES_DIR = 'codes';
46
+ /**
47
+ * The codec's code-body filename shape: `<sha256 hex>.tsx`. Readers
48
+ * MUST honour only refs matching this pattern so a crafted manifest
49
+ * value like `../../etc/passwd` can never escape `codes/`.
50
+ */
51
+ export const POOL_ARTIFACT_CODE_REF_PATTERN = /^[0-9a-f]{64}\.tsx$/;
52
+ /** Rejection message for schemaVersion-1 wrapper artifacts. */
53
+ export const POOL_ARTIFACT_V1_REJECTION = 're-export the pool: artifact schemaVersion 2 records carry complete provenance (PortableBlueprint v2)';
54
+ /**
55
+ * Build the codeRef filename for a code body's sha256 hex digest.
56
+ * Throws when the input is not a 64-char lowercase hex digest — a
57
+ * writer must never produce a ref its own reader would reject.
58
+ */
59
+ export function poolArtifactCodeRef(sha256Hex) {
60
+ const ref = `${sha256Hex}.tsx`;
61
+ if (!POOL_ARTIFACT_CODE_REF_PATTERN.test(ref)) {
62
+ throw new Error(`pool artifact: codeRef input is not a sha256 hex digest: ${sha256Hex}`);
63
+ }
64
+ return ref;
65
+ }
66
+ /** Stamp the current schema version onto a manifest. Writer-side. */
67
+ export function buildPoolArtifactManifest(blueprints) {
68
+ return { schemaVersion: POOL_ARTIFACT_SCHEMA_VERSION, blueprints };
69
+ }
70
+ /** Canonical manifest bytes (pretty-printed JSON + trailing newline). */
71
+ export function serializePoolArtifactManifest(manifest) {
72
+ return `${JSON.stringify(manifest, null, 2)}\n`;
73
+ }
74
+ export function parsePoolArtifactManifest(raw) {
75
+ let parsed;
76
+ try {
77
+ parsed = JSON.parse(raw);
78
+ }
79
+ catch (cause) {
80
+ return {
81
+ ok: false,
82
+ reason: `${POOL_ARTIFACT_MANIFEST_FILENAME} is not valid JSON: ${cause instanceof Error ? cause.message : String(cause)}`,
83
+ };
84
+ }
85
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
86
+ return {
87
+ ok: false,
88
+ reason: `${POOL_ARTIFACT_MANIFEST_FILENAME} is not an object`,
89
+ };
90
+ }
91
+ const m = parsed;
92
+ if (m.schemaVersion !== POOL_ARTIFACT_SCHEMA_VERSION) {
93
+ if (m.schemaVersion === 1) {
94
+ return { ok: false, reason: POOL_ARTIFACT_V1_REJECTION };
95
+ }
96
+ return {
97
+ ok: false,
98
+ reason: `unsupported manifest schemaVersion ${String(m.schemaVersion)} (expected ${POOL_ARTIFACT_SCHEMA_VERSION})`,
99
+ };
100
+ }
101
+ if (!Array.isArray(m.blueprints)) {
102
+ return {
103
+ ok: false,
104
+ reason: 'manifest.blueprints is missing or not an array',
105
+ };
106
+ }
107
+ const blueprints = [];
108
+ const issues = [];
109
+ for (const entry of m.blueprints) {
110
+ if (!isPoolArtifactManifestEntry(entry)) {
111
+ issues.push('malformed manifest entry (missing record/codeRef); skipping blueprint');
112
+ continue;
113
+ }
114
+ if (!POOL_ARTIFACT_CODE_REF_PATTERN.test(entry.codeRef)) {
115
+ issues.push(`invalid code reference ${entry.codeRef}; skipping blueprint`);
116
+ continue;
117
+ }
118
+ blueprints.push(entry);
119
+ }
120
+ return {
121
+ ok: true,
122
+ manifest: { schemaVersion: POOL_ARTIFACT_SCHEMA_VERSION, blueprints },
123
+ issues,
124
+ };
125
+ }
126
+ /**
127
+ * Structural guard for a manifest entry: `codeRef` is a string and
128
+ * `record` is an object readers can splice `componentCode` back into.
129
+ * The record's inner fields are deliberately NOT validated here — see
130
+ * the module docstring's trust-boundary note.
131
+ */
132
+ function isPoolArtifactManifestEntry(value) {
133
+ if (typeof value !== 'object' || value === null)
134
+ return false;
135
+ if (!('codeRef' in value) || typeof value.codeRef !== 'string')
136
+ return false;
137
+ if (!('record' in value) ||
138
+ typeof value.record !== 'object' ||
139
+ value.record === null ||
140
+ Array.isArray(value.record)) {
141
+ return false;
142
+ }
143
+ return true;
144
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggui-ai/artifact-manifest",
3
- "version": "0.2.0-alpha.4",
3
+ "version": "0.3.0-rc.0",
4
4
  "description": "Strict zod schemas + parsers for ggui marketplace artifact manifests — ggui.gadget.json (gadget bundles) and ggui.blueprint.json (cached UI blueprints).",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "zod": "^4.3.6",
30
- "@ggui-ai/protocol": "0.2.0-alpha.4"
30
+ "@ggui-ai/protocol": "0.3.0-rc.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "typescript": "^5.0.0",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "author": "ggui contributors <hello@ggui.ai>",
52
52
  "scripts": {
53
- "build": "tsc -p tsconfig.build.json",
53
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
54
54
  "dev": "tsc --watch",
55
55
  "typecheck": "tsc --noEmit",
56
56
  "test": "vitest run",