@foir/sdk 0.7.0 → 0.9.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +857 -4
  2. package/README.md +46 -15
  3. package/dist/auth/auth.d.ts +104 -1
  4. package/dist/auth/hosted.d.ts +22 -0
  5. package/dist/auth/index.d.ts +13 -7
  6. package/dist/auth/operations.d.ts +85 -64
  7. package/dist/auth/ops.d.ts +99 -0
  8. package/dist/auth.js +786 -106
  9. package/dist/chunk-IGNLWT3H.js +35 -0
  10. package/dist/chunk-OHYVKTGB.js +45 -0
  11. package/dist/chunk-TAL5H6VA.js +39 -0
  12. package/dist/client.js +25 -31
  13. package/dist/codegen/block-registry.d.ts +13 -19
  14. package/dist/codegen/block-registry.js +3 -31
  15. package/dist/codegen/block-scaffold.d.ts +12 -21
  16. package/dist/codegen/block-scaffold.js +3 -41
  17. package/dist/codegen/index.d.ts +9 -4
  18. package/dist/codegen/index.js +7 -11
  19. package/dist/codegen/item-registry.d.ts +28 -0
  20. package/dist/codegen/item-registry.js +7 -0
  21. package/dist/codegen/item-scaffold.d.ts +29 -0
  22. package/dist/codegen/item-scaffold.js +7 -0
  23. package/dist/codegen/preset.d.ts +14 -7
  24. package/dist/codegen/shared.d.ts +20 -9
  25. package/dist/content/content-renderer.d.ts +90 -24
  26. package/dist/content/index.d.ts +13 -7
  27. package/dist/content/richtext.d.ts +66 -18
  28. package/dist/content.js +227 -80
  29. package/dist/data/builtins.d.ts +369 -92
  30. package/dist/data/client.d.ts +97 -25
  31. package/dist/data/document.d.ts +251 -0
  32. package/dist/data/index.d.ts +38 -19
  33. package/dist/data/manifest.d.ts +290 -8
  34. package/dist/data/schema.d.ts +78 -8
  35. package/dist/data/selection.d.ts +231 -37
  36. package/dist/data/subjects.d.ts +221 -0
  37. package/dist/data/subscription-document.d.ts +75 -0
  38. package/dist/data/subscriptions.d.ts +181 -0
  39. package/dist/data/transport.d.ts +255 -37
  40. package/dist/data/ws-transport.d.ts +197 -0
  41. package/dist/data.js +1419 -45
  42. package/dist/graphql/cdn-route.d.ts +12 -28
  43. package/dist/media/index.d.ts +6 -2
  44. package/dist/media/media.d.ts +2 -2
  45. package/dist/media/screen-capture.d.ts +81 -0
  46. package/dist/media.js +97 -0
  47. package/dist/next.js +663 -182
  48. package/dist/push.js +700 -90
  49. package/dist/react/FoirFeedback.d.ts +62 -0
  50. package/dist/react/feedback-notes.d.ts +101 -0
  51. package/dist/react/index.d.ts +7 -1
  52. package/dist/react.js +1272 -194
  53. package/dist/realtime.js +1 -1
  54. package/dist/server/events-client.d.ts +279 -0
  55. package/dist/server/index.d.ts +4 -0
  56. package/dist/server.js +298 -0
  57. package/dist/transport/foir-http.d.ts +23 -6
  58. package/dist/transport/persisted-query.d.ts +68 -0
  59. package/dist/transport/retry.d.ts +1 -1
  60. package/package.json +13 -1
  61. package/dist/chunk-ADO5FJNM.js +0 -30
@@ -0,0 +1,35 @@
1
+ import {
2
+ DEFAULT_GRAPHQL_IMPORT,
3
+ DEFAULT_SDK_IMPORT,
4
+ collectItemMembers
5
+ } from "./chunk-TAL5H6VA.js";
6
+
7
+ // src/codegen/item-registry.ts
8
+ var plugin = (schema, _documents, config = {}) => {
9
+ const members = collectItemMembers(schema, config.unions);
10
+ const graphqlImport = config.graphqlImport ?? DEFAULT_GRAPHQL_IMPORT;
11
+ const sdkImport = config.sdkImport ?? DEFAULT_SDK_IMPORT;
12
+ const registryName = config.registryName ?? "ItemRegistry";
13
+ return [
14
+ "/* eslint-disable */",
15
+ "// Generated by @foir/sdk/codegen/item-registry. Do not edit by hand.",
16
+ "// Regenerated on every codegen run \u2014 omitting an item type is a compile error.",
17
+ `import type { ItemComponent } from '${sdkImport}';`,
18
+ `import type {`,
19
+ ...members.map((m) => ` ${m},`),
20
+ `} from '${graphqlImport}';`,
21
+ "",
22
+ `/**`,
23
+ ` * Exhaustive map of every item \`__typename\` in the project schema to the`,
24
+ ` * component that renders it. Pass an instance to \`createContentRenderer\`.`,
25
+ ` */`,
26
+ `export type ${registryName}<Ctx = unknown> = {`,
27
+ ...members.map((m) => ` ${m}: ItemComponent<${m}, Ctx>;`),
28
+ `};`,
29
+ ""
30
+ ].join("\n");
31
+ };
32
+
33
+ export {
34
+ plugin
35
+ };
@@ -0,0 +1,45 @@
1
+ import {
2
+ DEFAULT_GRAPHQL_IMPORT,
3
+ DEFAULT_SDK_IMPORT,
4
+ collectItemMembers
5
+ } from "./chunk-TAL5H6VA.js";
6
+
7
+ // src/codegen/item-scaffold.ts
8
+ var plugin = (schema, _documents, config = {}) => {
9
+ const members = collectItemMembers(schema, config.unions);
10
+ const graphqlImport = config.graphqlImport ?? DEFAULT_GRAPHQL_IMPORT;
11
+ const sdkImport = config.sdkImport ?? DEFAULT_SDK_IMPORT;
12
+ const registryImport = config.registryImport ?? "./item-registry";
13
+ const ctx = config.ctxType ?? "unknown";
14
+ const stub = (m) => [
15
+ `function ${m}View(props: ItemComponentProps<${m}, ${ctx}>) {`,
16
+ ` // TODO: render ${m} from props.item (props.ctx, props.priority available)`,
17
+ ` void props;`,
18
+ ` return null;`,
19
+ `}`
20
+ ].join("\n");
21
+ return [
22
+ "/* eslint-disable */",
23
+ "// Scaffolded once by @foir/sdk/codegen/item-scaffold \u2014 you own this file.",
24
+ "// Implement each stub; the build stays green until you do.",
25
+ `import { createContentRenderer, type ItemComponentProps } from '${sdkImport}';`,
26
+ `import type { ItemRegistry } from '${registryImport}';`,
27
+ `import type {`,
28
+ ...members.map((m) => ` ${m},`),
29
+ `} from '${graphqlImport}';`,
30
+ ...config.ctxImport ? ["", config.ctxImport] : [],
31
+ "",
32
+ ...members.map(stub),
33
+ "",
34
+ `export const itemRegistry: ItemRegistry<${ctx}> = {`,
35
+ ...members.map((m) => ` ${m}: ${m}View,`),
36
+ `};`,
37
+ "",
38
+ `export const ContentRenderer = createContentRenderer<${ctx}>(itemRegistry);`,
39
+ ""
40
+ ].join("\n");
41
+ };
42
+
43
+ export {
44
+ plugin
45
+ };
@@ -0,0 +1,39 @@
1
+ // src/codegen/shared.ts
2
+ import { isUnionType } from "graphql";
3
+ var DEFAULT_GRAPHQL_IMPORT = "./graphql";
4
+ var DEFAULT_SDK_IMPORT = "@foir/sdk/content";
5
+ var PASSAGE = "Passage";
6
+ function collectItemMembers(schema, unionNames) {
7
+ const members = /* @__PURE__ */ new Set();
8
+ const missing = [];
9
+ if (unionNames && unionNames.length > 0) {
10
+ for (const name of unionNames) {
11
+ const type = schema.getType(name);
12
+ if (!type || !isUnionType(type)) {
13
+ missing.push(name);
14
+ continue;
15
+ }
16
+ for (const member of type.getTypes()) members.add(member.name);
17
+ }
18
+ } else {
19
+ for (const type of Object.values(schema.getTypeMap())) {
20
+ if (!isUnionType(type)) continue;
21
+ const names = type.getTypes().map((m) => m.name);
22
+ if (!names.includes(PASSAGE)) continue;
23
+ for (const name of names) members.add(name);
24
+ }
25
+ }
26
+ members.delete(PASSAGE);
27
+ if (members.size === 0) {
28
+ throw new Error(
29
+ `[foir codegen] no item members found. ` + (unionNames && unionNames.length > 0 ? `Looked for union(s): ${unionNames.join(", ")}` + (missing.length ? ` (not found or not a union: ${missing.join(", ")})` : "") : `No prose entries union (a union containing Passage) exists in the schema`) + `. Run \`foir push\`, then confirm the schema has a prose field that places models \u2014 a prose field's entries union is named by its materialised member set.`
30
+ );
31
+ }
32
+ return [...members].sort();
33
+ }
34
+
35
+ export {
36
+ DEFAULT_GRAPHQL_IMPORT,
37
+ DEFAULT_SDK_IMPORT,
38
+ collectItemMembers
39
+ };
package/dist/client.js CHANGED
@@ -129,18 +129,14 @@ function readFoirEnvelope(json) {
129
129
  return json.data;
130
130
  }
131
131
 
132
- // src/graphql/cdn-route.ts
133
- var CDN_PATH = "/cdn/graphql";
134
- function isCdnEligible(env, documentText, bearerToken) {
135
- if (bearerToken) return false;
136
- if (isFoirPreview(env)) return false;
137
- const apiKey = resolveFoirApiKey(env);
138
- if (!apiKey?.startsWith("pk_")) return false;
139
- return !/\bmutation\b/.test(documentText);
132
+ // src/transport/persisted-query.ts
133
+ var FOIR_CDN_GRAPHQL_PATH = "/cdn/graphql";
134
+ function persistedQueryExtension(hash) {
135
+ return { persistedQuery: { version: 1, sha256Hash: hash } };
140
136
  }
141
137
  function buildCdnUrl(endpoint, apiKey, hash, variables) {
142
138
  const url = new URL(endpoint);
143
- url.pathname = url.pathname.replace(/\/graphql\/?$/, "") + CDN_PATH;
139
+ url.pathname = url.pathname.replace(/\/graphql\/?$/, "") + FOIR_CDN_GRAPHQL_PATH;
144
140
  url.searchParams.set("key", apiKey);
145
141
  url.searchParams.set("extensions", JSON.stringify(persistedQueryExtension(hash)));
146
142
  if (variables && Object.keys(variables).length > 0) {
@@ -148,18 +144,29 @@ function buildCdnUrl(endpoint, apiKey, hash, variables) {
148
144
  }
149
145
  return url.toString();
150
146
  }
151
- function persistedQueryExtension(hash) {
152
- return { persistedQuery: { version: 1, sha256Hash: hash } };
153
- }
154
147
  async function documentHash(documentText) {
155
- const digest = await crypto.subtle.digest(
156
- "SHA-256",
157
- new TextEncoder().encode(documentText)
158
- );
148
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(documentText));
159
149
  return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
160
150
  }
161
151
  var PERSISTED_QUERY_NOT_FOUND = "PERSISTED_QUERY_NOT_FOUND";
162
152
  var NOT_SHAREABLE = "NOT_SHAREABLE";
153
+ async function hasFoirErrorCode(res, ...codes) {
154
+ try {
155
+ const body = await res.clone().json();
156
+ return body.errors?.some((e) => e.extensions?.code !== void 0 && codes.includes(e.extensions.code)) ?? false;
157
+ } catch {
158
+ return false;
159
+ }
160
+ }
161
+
162
+ // src/graphql/cdn-route.ts
163
+ function isCdnEligible(env, documentText, bearerToken) {
164
+ if (bearerToken) return false;
165
+ if (isFoirPreview(env)) return false;
166
+ const apiKey = resolveFoirApiKey(env);
167
+ if (!apiKey?.startsWith("pk_")) return false;
168
+ return !/\bmutation\b/.test(documentText);
169
+ }
163
170
 
164
171
  // src/transport/retry.ts
165
172
  var DEFAULT_ATTEMPTS = 3;
@@ -288,23 +295,10 @@ async function readErrorEnvelope(res) {
288
295
  return errors;
289
296
  }
290
297
  async function isSharedRefusal(res) {
291
- if (res.ok) return false;
292
- try {
293
- const body = await res.clone().json();
294
- return body.errors?.some((e) => e.extensions?.code === NOT_SHAREABLE) ?? false;
295
- } catch {
296
- return false;
297
- }
298
+ return hasFoirErrorCode(res, NOT_SHAREABLE);
298
299
  }
299
300
  async function isPersistedQueryMiss(res) {
300
- try {
301
- const body = await res.clone().json();
302
- return body.errors?.some(
303
- (e) => e.extensions?.code === PERSISTED_QUERY_NOT_FOUND
304
- ) ?? false;
305
- } catch {
306
- return false;
307
- }
301
+ return hasFoirErrorCode(res, PERSISTED_QUERY_NOT_FOUND);
308
302
  }
309
303
 
310
304
  // src/graphql/content-client.ts
@@ -1,23 +1,17 @@
1
1
  /**
2
- * `@foir/sdk/codegen/block-registry` — a graphql-codegen plugin.
2
+ * `@foir/sdk/codegen/block-registry` — DEPRECATED alias.
3
3
  *
4
- * Introspects the project's public schema, collects every member of the block
5
- * union(s), and emits an EXHAUSTIVE `BlockRegistry` type — one key per block
6
- * `__typename`, each typed `BlockComponent<ThatBlock, Ctx>`. Because the type
7
- * requires every key, a project that adds an inline model (→ a new block
8
- * `__typename`) breaks the consumer's build until the new component is wired:
9
- * exhaustiveness by construction, replacing the hand-synced switch the
10
- * storefront's `BlockDigester` used to carry.
4
+ * `block` was one project's name for a flexible field, never a platform
5
+ * concept (TTS-1391). The plugin moved to `@foir/sdk/codegen/item-registry`;
6
+ * this path re-exports it unchanged so an existing `codegen.ts` keeps working.
7
+ * Repoint the `plugins:` entry when convenient — this will be removed in a
8
+ * future major.
11
9
  *
12
- * Wired automatically by `foirCodegen()`. The generated file imports the block
13
- * types from the codegen output (`./graphql`) and `BlockComponent` from
14
- * `@foir/sdk/content`, so it pairs directly with `createContentRenderer`.
10
+ * Note that the emitted type is now named `ItemRegistry` by default and its
11
+ * components are typed `ItemComponent`. If you import the generated
12
+ * `BlockRegistry` by name, either pass `registryName: 'BlockRegistry'` or
13
+ * update the import; `@foir/sdk/content` still exports `BlockRegistry` as a
14
+ * deprecated alias of `ItemRegistry`, so the types remain compatible.
15
15
  */
16
- import type { GraphQLSchema } from 'graphql';
17
- import { type BlockPluginConfig } from './shared';
18
- export interface BlockRegistryConfig extends BlockPluginConfig {
19
- /** Name of the generated registry type. Default `BlockRegistry`. */
20
- registryName?: string;
21
- }
22
- /** graphql-codegen plugin entrypoint. */
23
- export declare const plugin: (schema: GraphQLSchema, _documents: unknown, config?: BlockRegistryConfig) => string;
16
+ export { plugin } from './item-registry';
17
+ export type { ItemRegistryConfig, BlockRegistryConfig, } from './item-registry';
@@ -1,35 +1,7 @@
1
1
  import {
2
- DEFAULT_GRAPHQL_IMPORT,
3
- DEFAULT_SDK_IMPORT,
4
- DEFAULT_UNIONS,
5
- collectBlockMembers
6
- } from "../chunk-ADO5FJNM.js";
7
-
8
- // src/codegen/block-registry.ts
9
- var plugin = (schema, _documents, config = {}) => {
10
- const members = collectBlockMembers(schema, config.unions ?? DEFAULT_UNIONS);
11
- const graphqlImport = config.graphqlImport ?? DEFAULT_GRAPHQL_IMPORT;
12
- const sdkImport = config.sdkImport ?? DEFAULT_SDK_IMPORT;
13
- const registryName = config.registryName ?? "BlockRegistry";
14
- return [
15
- "/* eslint-disable */",
16
- "// Generated by @foir/sdk/codegen/block-registry. Do not edit by hand.",
17
- "// Regenerated on every codegen run \u2014 omitting a block type is a compile error.",
18
- `import type { BlockComponent } from '${sdkImport}';`,
19
- `import type {`,
20
- ...members.map((m) => ` ${m},`),
21
- `} from '${graphqlImport}';`,
22
- "",
23
- `/**`,
24
- ` * Exhaustive map of every block \`__typename\` in the project schema to the`,
25
- ` * component that renders it. Pass an instance to \`createContentRenderer\`.`,
26
- ` */`,
27
- `export type ${registryName}<Ctx = unknown> = {`,
28
- ...members.map((m) => ` ${m}: BlockComponent<${m}, Ctx>;`),
29
- `};`,
30
- ""
31
- ].join("\n");
32
- };
2
+ plugin
3
+ } from "../chunk-IGNLWT3H.js";
4
+ import "../chunk-TAL5H6VA.js";
33
5
  export {
34
6
  plugin
35
7
  };
@@ -1,24 +1,15 @@
1
1
  /**
2
- * `@foir/sdk/codegen/block-scaffold` — a one-shot graphql-codegen plugin.
2
+ * `@foir/sdk/codegen/block-scaffold` — DEPRECATED alias.
3
3
  *
4
- * Emits a ContentRenderer shell: a stub component per block `__typename`, a
5
- * `blockRegistry` of the (exhaustive) `BlockRegistry` type, and a
6
- * `createContentRenderer` wiring. Unlike the block-registry plugin (which
7
- * regenerates every run), this is a STARTING POINT the dev then owns — run it
8
- * once via `foirScaffold()`, then implement each stub. It compiles out of the
9
- * box (each stub is a typed no-op) so the build stays green while you fill them
10
- * in. Adding a new block type later surfaces as a compile error on
11
- * `blockRegistry` (via the regenerated `BlockRegistry` type), not here.
4
+ * `block` was one project's name for a flexible field, never a platform
5
+ * concept (TTS-1391). The plugin moved to `@foir/sdk/codegen/item-scaffold`;
6
+ * this path re-exports it unchanged so an existing `codegen.ts` keeps working.
7
+ * Repoint the `plugins:` entry when convenient — this will be removed in a
8
+ * future major.
9
+ *
10
+ * The scaffold is a one-shot generator, so a file scaffolded under the old name
11
+ * is yours and is untouched by this. Newly scaffolded files export
12
+ * `itemRegistry` rather than `blockRegistry` and take `props.item`.
12
13
  */
13
- import type { GraphQLSchema } from 'graphql';
14
- import { type BlockPluginConfig } from './shared';
15
- export interface BlockScaffoldConfig extends BlockPluginConfig {
16
- /** Import path for the generated registry type. Default `./block-registry`. */
17
- registryImport?: string;
18
- /** Render-context type name threaded to every component. Default `unknown`. */
19
- ctxType?: string;
20
- /** Optional import line for the ctx type, e.g. `import type { Ctx } from '~/ctx'`. */
21
- ctxImport?: string;
22
- }
23
- /** graphql-codegen plugin entrypoint. */
24
- export declare const plugin: (schema: GraphQLSchema, _documents: unknown, config?: BlockScaffoldConfig) => string;
14
+ export { plugin } from './item-scaffold';
15
+ export type { ItemScaffoldConfig, BlockScaffoldConfig, } from './item-scaffold';
@@ -1,45 +1,7 @@
1
1
  import {
2
- DEFAULT_GRAPHQL_IMPORT,
3
- DEFAULT_SDK_IMPORT,
4
- DEFAULT_UNIONS,
5
- collectBlockMembers
6
- } from "../chunk-ADO5FJNM.js";
7
-
8
- // src/codegen/block-scaffold.ts
9
- var plugin = (schema, _documents, config = {}) => {
10
- const members = collectBlockMembers(schema, config.unions ?? DEFAULT_UNIONS);
11
- const graphqlImport = config.graphqlImport ?? DEFAULT_GRAPHQL_IMPORT;
12
- const sdkImport = config.sdkImport ?? DEFAULT_SDK_IMPORT;
13
- const registryImport = config.registryImport ?? "./block-registry";
14
- const ctx = config.ctxType ?? "unknown";
15
- const stub = (m) => [
16
- `function ${m}View(props: BlockComponentProps<${m}, ${ctx}>) {`,
17
- ` // TODO: render ${m} from props.block (props.ctx, props.priority available)`,
18
- ` void props;`,
19
- ` return null;`,
20
- `}`
21
- ].join("\n");
22
- return [
23
- "/* eslint-disable */",
24
- "// Scaffolded once by @foir/sdk/codegen/block-scaffold \u2014 you own this file.",
25
- "// Implement each stub; the build stays green until you do.",
26
- `import { createContentRenderer, type BlockComponentProps } from '${sdkImport}';`,
27
- `import type { BlockRegistry } from '${registryImport}';`,
28
- `import type {`,
29
- ...members.map((m) => ` ${m},`),
30
- `} from '${graphqlImport}';`,
31
- ...config.ctxImport ? ["", config.ctxImport] : [],
32
- "",
33
- ...members.map(stub),
34
- "",
35
- `export const blockRegistry: BlockRegistry<${ctx}> = {`,
36
- ...members.map((m) => ` ${m}: ${m}View,`),
37
- `};`,
38
- "",
39
- `export const ContentRenderer = createContentRenderer<${ctx}>(blockRegistry);`,
40
- ""
41
- ].join("\n");
42
- };
2
+ plugin
3
+ } from "../chunk-OHYVKTGB.js";
4
+ import "../chunk-TAL5H6VA.js";
43
5
  export {
44
6
  plugin
45
7
  };
@@ -1,11 +1,16 @@
1
1
  /**
2
- * `@foir/sdk/codegen` — Foir graphql-codegen preset + block-registry plugin.
2
+ * `@foir/sdk/codegen` — Foir graphql-codegen preset + item-registry plugin.
3
3
  *
4
4
  * Build-time only. `@graphql-codegen/cli` + `@graphql-codegen/client-preset`
5
- * are optional peer dependencies (the consumer's devDeps). The block-registry
6
- * and block-scaffold plugins are wired by the preset and also available at
7
- * `@foir/sdk/codegen/block-registry` / `@foir/sdk/codegen/block-scaffold`.
5
+ * are optional peer dependencies (the consumer's devDeps). The item-registry
6
+ * and item-scaffold plugins are wired by the preset and also available at
7
+ * `@foir/sdk/codegen/item-registry` / `@foir/sdk/codegen/item-scaffold`.
8
+ *
9
+ * The pre-TTS-1391 paths `@foir/sdk/codegen/block-registry` and
10
+ * `/block-scaffold` still resolve, re-exporting those modules unchanged.
8
11
  */
9
12
  export { foirCodegen, foirScaffold } from './preset';
10
13
  export type { FoirCodegenOptions, FoirScaffoldOptions } from './preset';
14
+ export type { ItemPluginConfig } from './shared';
15
+ /** @deprecated Renamed to `ItemPluginConfig`. */
11
16
  export type { BlockPluginConfig } from './shared';
@@ -1,7 +1,3 @@
1
- import {
2
- DEFAULT_UNIONS
3
- } from "../chunk-ADO5FJNM.js";
4
-
5
1
  // src/codegen/preset.ts
6
2
  var DEFAULT_OUTPUT_DIR = "./app/gql/foir/";
7
3
  var DEFAULT_DOCUMENTS = "app/graphql/foir/**/*.graphql";
@@ -30,8 +26,8 @@ function foirCodegen(options) {
30
26
  const previewKey = options.previewKey ?? options.apiKey;
31
27
  const outputDir = normalizeDir(options.outputDir ?? DEFAULT_OUTPUT_DIR);
32
28
  const documents = options.documents ?? DEFAULT_DOCUMENTS;
33
- const blockUnions = options.blockUnions ?? DEFAULT_UNIONS;
34
- const registryFile = options.registryFile ?? `${outputDir}block-registry.ts`;
29
+ const unions = options.itemUnions ?? options.blockUnions;
30
+ const registryFile = options.registryFile ?? `${outputDir}item-registry.ts`;
35
31
  return {
36
32
  schema: schemaEntry(options.apiUrl, previewKey),
37
33
  documents,
@@ -47,8 +43,8 @@ function foirCodegen(options) {
47
43
  }
48
44
  },
49
45
  [registryFile]: {
50
- plugins: ["@foir/sdk/codegen/block-registry"],
51
- config: { unions: blockUnions }
46
+ plugins: ["@foir/sdk/codegen/item-registry"],
47
+ config: { unions }
52
48
  }
53
49
  }
54
50
  };
@@ -57,15 +53,15 @@ function foirScaffold(options) {
57
53
  const previewKey = options.previewKey ?? options.apiKey;
58
54
  const outputDir = normalizeDir(options.outputDir ?? DEFAULT_OUTPUT_DIR);
59
55
  const scaffoldFile = options.scaffoldFile ?? `${outputDir}ContentRenderer.tsx`;
60
- const blockUnions = options.blockUnions ?? DEFAULT_UNIONS;
56
+ const unions = options.itemUnions ?? options.blockUnions;
61
57
  return {
62
58
  schema: schemaEntry(options.apiUrl, previewKey),
63
59
  ignoreNoDocuments: true,
64
60
  generates: {
65
61
  [scaffoldFile]: {
66
- plugins: ["@foir/sdk/codegen/block-scaffold"],
62
+ plugins: ["@foir/sdk/codegen/item-scaffold"],
67
63
  config: {
68
- unions: blockUnions,
64
+ unions,
69
65
  ctxType: options.ctxType,
70
66
  ctxImport: options.ctxImport,
71
67
  registryImport: options.registryImport
@@ -0,0 +1,28 @@
1
+ /**
2
+ * `@foir/sdk/codegen/item-registry` — a graphql-codegen plugin.
3
+ *
4
+ * Introspects the project's public schema, collects every member of the
5
+ * flexible union(s), and emits an EXHAUSTIVE `ItemRegistry` type — one key per
6
+ * item `__typename`, each typed `ItemComponent<ThatItem, Ctx>`. Because the
7
+ * type requires every key, a project that adds an inline model (→ a new item
8
+ * `__typename`) breaks the consumer's build until the new component is wired:
9
+ * exhaustiveness by construction, replacing the hand-synced switch a storefront
10
+ * would otherwise carry.
11
+ *
12
+ * Wired automatically by `foirCodegen()`. The generated file imports the item
13
+ * types from the codegen output (`./graphql`) and `ItemComponent` from
14
+ * `@foir/sdk/content`, so it pairs directly with `createContentRenderer`.
15
+ *
16
+ * Reachable at the pre-TTS-1391 path `@foir/sdk/codegen/block-registry` too,
17
+ * which re-exports this module unchanged.
18
+ */
19
+ import type { GraphQLSchema } from 'graphql';
20
+ import { type ItemPluginConfig } from './shared';
21
+ export interface ItemRegistryConfig extends ItemPluginConfig {
22
+ /** Name of the generated registry type. Default `ItemRegistry`. */
23
+ registryName?: string;
24
+ }
25
+ /** @deprecated Renamed to {@link ItemRegistryConfig}. */
26
+ export type BlockRegistryConfig = ItemRegistryConfig;
27
+ /** graphql-codegen plugin entrypoint. */
28
+ export declare const plugin: (schema: GraphQLSchema, _documents: unknown, config?: ItemRegistryConfig) => string;
@@ -0,0 +1,7 @@
1
+ import {
2
+ plugin
3
+ } from "../chunk-IGNLWT3H.js";
4
+ import "../chunk-TAL5H6VA.js";
5
+ export {
6
+ plugin
7
+ };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * `@foir/sdk/codegen/item-scaffold` — a one-shot graphql-codegen plugin.
3
+ *
4
+ * Emits a ContentRenderer shell: a stub component per item `__typename`, an
5
+ * `itemRegistry` of the (exhaustive) `ItemRegistry` type, and a
6
+ * `createContentRenderer` wiring. Unlike the item-registry plugin (which
7
+ * regenerates every run), this is a STARTING POINT the dev then owns — run it
8
+ * once via `foirScaffold()`, then implement each stub. It compiles out of the
9
+ * box (each stub is a typed no-op) so the build stays green while you fill them
10
+ * in. Adding a new item type later surfaces as a compile error on
11
+ * `itemRegistry` (via the regenerated `ItemRegistry` type), not here.
12
+ *
13
+ * Reachable at the pre-TTS-1391 path `@foir/sdk/codegen/block-scaffold` too,
14
+ * which re-exports this module unchanged.
15
+ */
16
+ import type { GraphQLSchema } from 'graphql';
17
+ import { type ItemPluginConfig } from './shared';
18
+ export interface ItemScaffoldConfig extends ItemPluginConfig {
19
+ /** Import path for the generated registry type. Default `./item-registry`. */
20
+ registryImport?: string;
21
+ /** Render-context type name threaded to every component. Default `unknown`. */
22
+ ctxType?: string;
23
+ /** Optional import line for the ctx type, e.g. `import type { Ctx } from '~/ctx'`. */
24
+ ctxImport?: string;
25
+ }
26
+ /** @deprecated Renamed to {@link ItemScaffoldConfig}. */
27
+ export type BlockScaffoldConfig = ItemScaffoldConfig;
28
+ /** graphql-codegen plugin entrypoint. */
29
+ export declare const plugin: (schema: GraphQLSchema, _documents: unknown, config?: ItemScaffoldConfig) => string;
@@ -0,0 +1,7 @@
1
+ import {
2
+ plugin
3
+ } from "../chunk-OHYVKTGB.js";
4
+ import "../chunk-TAL5H6VA.js";
5
+ export {
6
+ plugin
7
+ };
@@ -5,7 +5,7 @@
5
5
  * a consumer's `codegen.ts` is ~3 lines instead of the ~109 every storefront
6
6
  * hand-copies. It standardizes the Foir conventions (custom scalars,
7
7
  * `enumValues: 'keep'`, the `X-Foir-Schema-Channel: draft` introspection header)
8
- * AND wires the block-registry plugin so the exhaustive `BlockRegistry` type is
8
+ * AND wires the item-registry plugin so the exhaustive `ItemRegistry` type is
9
9
  * regenerated alongside the typed documents.
10
10
  *
11
11
  * `foirScaffold()` is the separate one-shot that writes the ContentRenderer
@@ -30,31 +30,38 @@ export interface FoirCodegenOptions {
30
30
  outputDir?: string;
31
31
  /** Operation document glob(s). Default `app/graphql/foir/**\/*.graphql`. */
32
32
  documents?: string | string[];
33
- /** Block union name(s) for the registry. Default `['Block']`. */
33
+ /**
34
+ * Entries union name(s) for the registry. When unset, every prose
35
+ * entries union in the schema (the unions carrying `Passage`) is
36
+ * discovered at introspection time. Set explicitly to narrow the
37
+ * registry to specific fields' unions.
38
+ */
39
+ itemUnions?: string[];
40
+ /** @deprecated Renamed to `itemUnions`. Honoured when `itemUnions` is unset. */
34
41
  blockUnions?: string[];
35
- /** Generated registry file path. Default `<outputDir>block-registry.ts`. */
42
+ /** Generated registry file path. Default `<outputDir>item-registry.ts`. */
36
43
  registryFile?: string;
37
44
  /** Extra/override custom scalars merged onto the Foir defaults. */
38
45
  scalars?: Record<string, unknown>;
39
46
  }
40
47
  /**
41
48
  * Build the continuous Foir codegen config: typed documents + the exhaustive
42
- * block registry. Drop it into `codegen.ts` and run `graphql-codegen`.
49
+ * item registry. Drop it into `codegen.ts` and run `graphql-codegen`.
43
50
  */
44
51
  export declare function foirCodegen(options: FoirCodegenOptions): CodegenConfig;
45
52
  export interface FoirScaffoldOptions extends FoirCodegenOptions {
46
53
  /** Output path for the scaffold. Default `<outputDir>ContentRenderer.tsx`. */
47
54
  scaffoldFile?: string;
48
- /** Render-context type threaded to every block component. Default `unknown`. */
55
+ /** Render-context type threaded to every item component. Default `unknown`. */
49
56
  ctxType?: string;
50
57
  /** Optional ctx-type import line, e.g. `import type { Ctx } from '~/ctx'`. */
51
58
  ctxImport?: string;
52
- /** Import path for the generated registry type. Default `./block-registry`. */
59
+ /** Import path for the generated registry type. Default `./item-registry`. */
53
60
  registryImport?: string;
54
61
  }
55
62
  /**
56
63
  * Build the one-shot scaffold config — writes a ContentRenderer shell with a
57
- * typed stub per block type. Run once (`graphql-codegen --config scaffold.ts`),
64
+ * typed stub per item type. Run once (`graphql-codegen --config scaffold.ts`),
58
65
  * then own and implement the output.
59
66
  */
60
67
  export declare function foirScaffold(options: FoirScaffoldOptions): CodegenConfig;
@@ -2,11 +2,14 @@
2
2
  * Shared introspection helpers for the Foir codegen plugins.
3
3
  */
4
4
  import { type GraphQLSchema } from 'graphql';
5
- export interface BlockPluginConfig {
5
+ export interface ItemPluginConfig {
6
6
  /**
7
- * Union type name(s) to collect block members from. Defaults to `['Block']`
8
- * (the canonical Foir block union). A project with a distinct content-field
9
- * segment union lists it here too.
7
+ * Union type name(s) to collect item members from. When unset, the
8
+ * plugins DISCOVER the project's prose entries unions: every union whose
9
+ * member set includes `Passage` (each prose field's entries union is
10
+ * named by its materialised member set, so there is no single fixed
11
+ * name to configure). Set explicitly to narrow the registry to specific
12
+ * fields' unions.
10
13
  */
11
14
  unions?: string[];
12
15
  /** Import path for the codegen-generated types. Default `./graphql`. */
@@ -14,12 +17,20 @@ export interface BlockPluginConfig {
14
17
  /** Import path for the SDK content primitives. Default `@foir/sdk/content`. */
15
18
  sdkImport?: string;
16
19
  }
17
- export declare const DEFAULT_UNIONS: string[];
20
+ /** @deprecated Renamed to {@link ItemPluginConfig}. */
21
+ export type BlockPluginConfig = ItemPluginConfig;
18
22
  export declare const DEFAULT_GRAPHQL_IMPORT = "./graphql";
19
23
  export declare const DEFAULT_SDK_IMPORT = "@foir/sdk/content";
20
24
  /**
21
- * Collect the deduped, sorted set of object-type member names across the named
22
- * union(s). Throws when none of the unions resolve to members — that almost
23
- * always means a misconfigured union name or a schema that hasn't been pushed.
25
+ * Collect the deduped, sorted set of object-type member names across the
26
+ * named union(s) — or, when no names are given, across every prose entries
27
+ * union in the schema (the unions whose members include `Passage`).
28
+ * `Passage` itself is excluded: the content renderer owns passage
29
+ * rendering, so no registry component exists for it.
30
+ *
31
+ * Throws when nothing resolves — that almost always means a misconfigured
32
+ * union name, or a schema with no prose fields that place models.
24
33
  */
25
- export declare function collectBlockMembers(schema: GraphQLSchema, unionNames: string[]): string[];
34
+ export declare function collectItemMembers(schema: GraphQLSchema, unionNames?: string[]): string[];
35
+ /** @deprecated Renamed to {@link collectItemMembers}. */
36
+ export declare const collectBlockMembers: typeof collectItemMembers;