@capacms/sdk 1.0.0-next.1 → 1.0.0-next.10

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 (92) hide show
  1. package/CHANGELOG.md +450 -0
  2. package/README.md +1698 -193
  3. package/bin/capa-codegen.js +192 -5
  4. package/bin/capa.js +235 -0
  5. package/bin/graphql-project.js +142 -0
  6. package/bin/project-env.js +58 -0
  7. package/dist/client.d.ts +5 -0
  8. package/dist/client.js +17 -0
  9. package/dist/codegen.d.ts +55 -0
  10. package/dist/codegen.js +320 -39
  11. package/dist/config.d.ts +5 -36
  12. package/dist/config.js +47 -1
  13. package/dist/esm/image/index.d.ts +120 -0
  14. package/dist/esm/image/index.js +250 -0
  15. package/dist/esm/image/shared-params.generated.d.ts +190 -0
  16. package/dist/esm/image/shared-params.generated.js +461 -0
  17. package/dist/esm/nextjs/image-loader.d.ts +60 -0
  18. package/dist/esm/nextjs/image-loader.js +67 -0
  19. package/dist/esm/nextjs/overlay.d.ts +30 -0
  20. package/dist/esm/nextjs/overlay.js +75 -0
  21. package/dist/esm/overlay/index.d.ts +32 -0
  22. package/dist/esm/overlay/index.js +576 -0
  23. package/dist/esm/overlay/protocol.d.ts +187 -0
  24. package/dist/esm/overlay/protocol.js +240 -0
  25. package/dist/esm/package.json +4 -0
  26. package/dist/graphql-codegen.d.ts +117 -0
  27. package/dist/graphql-codegen.js +705 -0
  28. package/dist/http.js +1 -1
  29. package/dist/image/index.d.ts +120 -0
  30. package/dist/image/index.js +257 -0
  31. package/dist/image/shared-params.generated.d.ts +190 -0
  32. package/dist/image/shared-params.generated.js +471 -0
  33. package/dist/index.d.ts +2 -2
  34. package/dist/index.js +2 -1
  35. package/dist/next/attrs.d.ts +84 -10
  36. package/dist/next/attrs.js +119 -2
  37. package/dist/next/client.d.ts +176 -32
  38. package/dist/next/client.js +212 -90
  39. package/dist/next/entry-fields.d.ts +162 -0
  40. package/dist/next/entry-fields.js +2 -0
  41. package/dist/next/errors.d.ts +136 -0
  42. package/dist/next/errors.js +214 -0
  43. package/dist/next/field-names.d.ts +37 -0
  44. package/dist/next/field-names.js +145 -0
  45. package/dist/next/graphql/build.d.ts +27 -0
  46. package/dist/next/graphql/build.js +98 -0
  47. package/dist/next/graphql/documents.d.ts +67 -0
  48. package/dist/next/graphql/documents.js +35 -0
  49. package/dist/next/graphql/edit-mode.d.ts +16 -0
  50. package/dist/next/graphql/edit-mode.js +93 -0
  51. package/dist/next/graphql/filter-values.d.ts +34 -0
  52. package/dist/next/graphql/filter-values.js +96 -0
  53. package/dist/next/graphql/introspection.d.ts +89 -0
  54. package/dist/next/graphql/introspection.js +102 -0
  55. package/dist/next/graphql/plan.d.ts +115 -0
  56. package/dist/next/graphql/plan.js +531 -0
  57. package/dist/next/graphql/request.d.ts +228 -0
  58. package/dist/next/graphql/request.js +283 -0
  59. package/dist/next/graphql/rest.d.ts +66 -0
  60. package/dist/next/graphql/rest.js +502 -0
  61. package/dist/next/graphql/selection.d.ts +55 -0
  62. package/dist/next/graphql/selection.js +212 -0
  63. package/dist/next/graphql/sha256.d.ts +13 -0
  64. package/dist/next/graphql/sha256.js +86 -0
  65. package/dist/next/graphql/summary.d.ts +83 -0
  66. package/dist/next/graphql/summary.js +151 -0
  67. package/dist/next/graphql/tree-layout.d.ts +36 -0
  68. package/dist/next/graphql/tree-layout.js +20 -0
  69. package/dist/next/graphql/tree.d.ts +171 -0
  70. package/dist/next/graphql/tree.js +249 -0
  71. package/dist/next/graphql/typed.d.ts +261 -0
  72. package/dist/next/graphql/typed.js +146 -0
  73. package/dist/next/index.d.ts +30 -5
  74. package/dist/next/index.js +32 -1
  75. package/dist/next/inflate.d.ts +51 -0
  76. package/dist/next/inflate.js +243 -0
  77. package/dist/next/key-family.d.ts +31 -0
  78. package/dist/next/key-family.js +66 -0
  79. package/dist/next/select-types.d.ts +58 -5
  80. package/dist/next/system-keys.d.ts +27 -0
  81. package/dist/next/system-keys.js +42 -0
  82. package/dist/nextjs/image-loader.d.ts +60 -0
  83. package/dist/nextjs/image-loader.js +71 -0
  84. package/dist/nextjs/index.d.ts +484 -5
  85. package/dist/nextjs/index.js +688 -6
  86. package/dist/nextjs/overlay.d.ts +30 -0
  87. package/dist/nextjs/overlay.js +78 -0
  88. package/dist/overlay/index.d.ts +14 -2
  89. package/dist/overlay/index.js +282 -43
  90. package/dist/overlay/protocol.d.ts +98 -2
  91. package/dist/overlay/protocol.js +151 -4
  92. package/package.json +63 -15
@@ -1,8 +1,125 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CAPA_EDIT = void 0;
4
+ exports.isEditEntry = isEditEntry;
5
+ exports.markEditEntries = markEditEntries;
6
+ exports.markGraphQLEntries = markGraphQLEntries;
7
+ exports.hasGraphQLEntry = hasGraphQLEntry;
8
+ exports.carryEditMark = carryEditMark;
3
9
  exports.capaAttrs = capaAttrs;
4
- function capaAttrs(entry, field, enabled = true) {
10
+ exports.fieldAttrs = fieldAttrs;
11
+ /** `Symbol.for`, so two copies of the SDK in one bundle agree on the mark. */
12
+ exports.CAPA_EDIT = Symbol.for("capacms.edit");
13
+ /** Whether an entry was read in edit mode. */
14
+ function isEditEntry(entry) {
15
+ return (typeof entry === "object" &&
16
+ entry !== null &&
17
+ entry[exports.CAPA_EDIT] === true);
18
+ }
19
+ /**
20
+ * Where a GraphQL node read in edit mode keeps the namespaces of the fields
21
+ * GraphQL renamed, by GraphQL name. Hidden like the mark itself.
22
+ */
23
+ const CAPA_EDIT_NAMESPACES = Symbol.for("capacms.edit.namespaces");
24
+ /** A REST entry: an id beside `fields`. */
25
+ function looksLikeEntry(value) {
26
+ return typeof value.id === "string" && typeof value.fields === "object" && value.fields !== null;
27
+ }
28
+ /** A GraphQL entry: the `Entry` interface's `id` and `model`, which every model type has. */
29
+ function looksLikeGraphQLEntry(value) {
30
+ return typeof value.id === "string" && typeof value.model === "string";
31
+ }
32
+ /** Define a hidden property: absent from JSON, keys and spreads. */
33
+ function hide(record, key, value) {
34
+ Object.defineProperty(record, key, { value, enumerable: false, configurable: true });
35
+ }
36
+ /** Visit every plain object and array inside `value` once, cycles included. */
37
+ function eachObject(value, visit) {
38
+ const seen = new Set();
39
+ const walk = (node) => {
40
+ if (typeof node !== "object" || node === null || seen.has(node))
41
+ return;
42
+ seen.add(node);
43
+ if (Array.isArray(node)) {
44
+ for (const item of node)
45
+ walk(item);
46
+ return;
47
+ }
48
+ const record = node;
49
+ visit(record);
50
+ for (const key of Object.keys(record))
51
+ walk(record[key]);
52
+ };
53
+ walk(value);
54
+ }
55
+ /**
56
+ * Mark every entry inside `value`, related entries included, so a click on an
57
+ * author inside an article opens the author. Walks arrays and plain objects,
58
+ * never the same object twice. Returns `value` for chaining.
59
+ */
60
+ function markEditEntries(value) {
61
+ eachObject(value, (record) => {
62
+ if (looksLikeEntry(record) && Object.isExtensible(record))
63
+ hide(record, exports.CAPA_EDIT, true);
64
+ });
65
+ return value;
66
+ }
67
+ /**
68
+ * Mark every entry inside a GraphQL result's `data`: each object that
69
+ * selected `id` and `model`, related entries included. `renamed(model)` gives
70
+ * that model's fields whose GraphQL name is not their namespace, by GraphQL
71
+ * name, so `capaAttrs` tags those by namespace. Returns `data`.
72
+ */
73
+ function markGraphQLEntries(data, renamed = () => undefined) {
74
+ eachObject(data, (record) => {
75
+ if (!looksLikeGraphQLEntry(record) || !Object.isExtensible(record))
76
+ return;
77
+ hide(record, exports.CAPA_EDIT, true);
78
+ const namespaces = renamed(record.model);
79
+ if (namespaces)
80
+ hide(record, CAPA_EDIT_NAMESPACES, namespaces);
81
+ });
82
+ return data;
83
+ }
84
+ /** Whether a GraphQL result's `data` holds any entry `markGraphQLEntries` would mark. */
85
+ function hasGraphQLEntry(data) {
86
+ let found = false;
87
+ eachObject(data, (record) => {
88
+ found ||= looksLikeGraphQLEntry(record);
89
+ });
90
+ return found;
91
+ }
92
+ /** Keep `from`'s edit mark on `to`, for a copy of an entry in another shape (`toTree`). */
93
+ function carryEditMark(from, to) {
94
+ if (isEditEntry(from) && Object.isExtensible(to))
95
+ hide(to, exports.CAPA_EDIT, true);
96
+ return to;
97
+ }
98
+ /** The namespace a field of `entry` is tagged with: a renamed GraphQL field's own, else the name given. */
99
+ function namespaceOf(entry, field) {
100
+ const namespaces = entry[CAPA_EDIT_NAMESPACES];
101
+ return namespaces?.[field] ?? field;
102
+ }
103
+ function capaAttrs(entry, field, enabled = isEditEntry(entry)) {
5
104
  if (!enabled)
6
105
  return {};
7
- return { "data-capa-entry": entry.id, "data-capa-field": field };
106
+ return { "data-capa-entry": entry.id, "data-capa-field": namespaceOf(entry, field) };
107
+ }
108
+ /**
109
+ * Typed attributes for every field of one entry (M5), or of one GraphQL node:
110
+ *
111
+ * const a = fieldAttrs(article);
112
+ * <h1 {...a.title}>…</h1> // a.titel is a compile error
113
+ *
114
+ * Same rule as `capaAttrs`: empty unless the entry was read in edit mode, or
115
+ * `enabled` says otherwise.
116
+ */
117
+ function fieldAttrs(entry, enabled = isEditEntry(entry)) {
118
+ return new Proxy({}, {
119
+ get(_target, key) {
120
+ if (typeof key !== "string")
121
+ return undefined;
122
+ return enabled ? { "data-capa-entry": entry.id, "data-capa-field": namespaceOf(entry, key) } : {};
123
+ },
124
+ });
8
125
  }
@@ -1,6 +1,18 @@
1
- import type { Select } from "./select-types";
1
+ import type { CapaDocumentResult, CapaDocuments, CapaDocumentVariables, NotARecordedDocument } from "./graphql/documents";
2
+ import { type GraphQLCallOptions, type GraphQLResult, type TypedDocument, type VariablesThenOptions } from "./graphql/request";
3
+ import { type GraphQLSchemaSummary } from "./graphql/summary";
4
+ import { type ExactSelection, type QueryResult, type QuerySelection, type UntypedQuery } from "./graphql/typed";
5
+ export { CapaError, isCapaError } from "./errors";
6
+ import type { EntryFields, FlatFields, FlatRead, IncludedFields } from "./entry-fields";
7
+ import type { ExpandedTargets, Select } from "./select-types";
2
8
  export interface CapaNextConfig {
3
9
  baseUrl: string;
10
+ /**
11
+ * A `cap_` key, or the legacy key a site already holds: `pk_`, `sk_`, or
12
+ * an older key with no prefix. A legacy key reads through every read call,
13
+ * `preview()` included, and warns once per process; the draft clients of
14
+ * `@capacms/sdk/nextjs` take a `cap_` key only.
15
+ */
4
16
  apiKey: string;
5
17
  version: string;
6
18
  contract?: 1;
@@ -34,6 +46,23 @@ export interface CapaNextConfig {
34
46
  * Config only, never per call: one build has one schema.
35
47
  */
36
48
  schemaChecksum?: string;
49
+ /**
50
+ * Read in edit mode: every entry this client returns carries the hidden edit
51
+ * mark, so `capaAttrs` tags it for the Capa editor. Leave it off for visitors
52
+ * and a published page ships no entry ids. `@capacms/sdk/nextjs` works it out
53
+ * per request with `editMode()`.
54
+ *
55
+ * The same request is sent either way. A GraphQL read marks each object
56
+ * that selected `id` and `model`, and to tag a field GraphQL renamed by its
57
+ * namespace, it also reads the key's schema, once a minute.
58
+ */
59
+ editMode?: boolean;
60
+ /**
61
+ * The concrete path being rendered (`/blog/hello`), sent as `Capa-Path`
62
+ * beside `Capa-Page` (`/blog/[slug]`). Telemetry only, like `page`: it is how
63
+ * Capa lists every real URL an entry appears on. Usually set per call.
64
+ */
65
+ path?: string;
37
66
  /** Injected for tests, non-standard runtimes, and framework fetch wrappers. */
38
67
  fetch?: typeof fetch;
39
68
  }
@@ -53,7 +82,18 @@ export interface CallOptions {
53
82
  * writing the code.
54
83
  */
55
84
  page?: string;
85
+ /**
86
+ * The concrete path THIS read renders (`/blog/hello`). Overrides `path` on the
87
+ * config. Sent as `Capa-Path` only alongside a `Capa-Page`, since a path with
88
+ * no page says nothing Capa can group.
89
+ */
90
+ path?: string;
56
91
  }
92
+ /**
93
+ * One entry as `/api/entries` returns it: the system keys, and `fields`. A read
94
+ * types `fields` from its model and select (`EntryFields`), so a relation is a
95
+ * reference or the related entry, and a relation list is `{ items, pageInfo }`.
96
+ */
57
97
  export interface Entry<T = Record<string, unknown>> {
58
98
  id: string;
59
99
  model: string;
@@ -97,29 +137,80 @@ export type FilterOperator = "eq" | "ne" | "in" | "nin" | "lt" | "lte" | "gt" |
97
137
  export type FilterScalar = string | number | boolean | null;
98
138
  export type FilterValue = FilterScalar | readonly FilterScalar[];
99
139
  export type Filter = Record<string, Partial<Record<FilterOperator, FilterValue>>>;
100
- export interface ListOptions<T = Record<string, unknown>> extends CallOptions {
101
- select?: Select<T> | string;
140
+ /**
141
+ * How expanded relations come back (`?shape=`). `tree`, the default, nests each
142
+ * one inline where it was selected. `flat` answers every relation as a
143
+ * `{ id, model }` reference and every expanded entry ONCE, in `included`, so
144
+ * twenty articles by one author carry that author once. `inflate(result)`
145
+ * turns a flat result back into the tree one.
146
+ */
147
+ export type ResponseShape = "tree" | "flat";
148
+ export interface ListOptions<T = Record<string, unknown>, S extends Select<T> | string = Select<T> | string> extends CallOptions {
149
+ select?: S;
150
+ shape?: "tree";
102
151
  filter?: Filter;
103
152
  where?: Record<string, unknown>;
104
153
  sort?: readonly string[];
105
154
  limit?: number;
106
155
  count?: boolean;
156
+ /** `page.next`: the page after it. */
107
157
  after?: string;
158
+ /** `page.prev`: the page before it. Or `"end"`: the last `limit` entries of the list. */
108
159
  before?: string;
109
160
  }
110
- export interface GetOptions<T = Record<string, unknown>> extends CallOptions {
111
- select?: Select<T> | string;
161
+ export interface GetOptions<T = Record<string, unknown>, S extends Select<T> | string = Select<T> | string> extends CallOptions {
162
+ select?: S;
163
+ shape?: "tree";
164
+ }
165
+ /** `list` with `shape: "flat"`. `S` is the select, which types `included`. */
166
+ export type FlatListOptions<T, S extends Select<T> | string = Select<T>> = Omit<ListOptions<T>, "select" | "shape"> & {
167
+ select?: S;
168
+ shape: "flat";
169
+ };
170
+ /** `get` with `shape: "flat"`. */
171
+ export type FlatGetOptions<T, S extends Select<T> | string = Select<T>> = Omit<GetOptions<T>, "select" | "shape"> & {
172
+ select?: S;
173
+ shape: "flat";
174
+ };
175
+ /**
176
+ * `included` of a flat read: model namespace, then entry id, then the entry.
177
+ * Typed by the select: the union of every entry type it expands, each field
178
+ * of which may be absent, and every relation in it a reference.
179
+ */
180
+ export type Included<I> = Record<string, Record<string, Entry<IncludedFields<I>>>>;
181
+ interface FlatExtras<T, S> extends FlatRead<T, S> {
182
+ included: Included<[ExpandedTargets<T, S>] extends [never] ? never : ExpandedTargets<T, S>>;
183
+ /** The select this read sent, which is what `inflate` walks. Absent when none was sent. */
184
+ select?: string;
112
185
  }
186
+ /** A `shape=flat` list: every relation in `data` a reference, each expanded entry once in `included`. */
187
+ export type FlatPage<T, S = Select<T>> = Page<Entry<FlatFields<T, S>>> & FlatExtras<T, S>;
188
+ export type FlatSingle<T, S = Select<T>> = Single<Entry<FlatFields<T, S>>> & FlatExtras<T, S>;
189
+ /**
190
+ * `T` as given, never inferred from the options: a read's model type is
191
+ * written (`list<Article>`), and without one the read is untyped whatever its
192
+ * select names. Inferred from a select's names, `T` would be `{ title: any }`,
193
+ * which refuses the relations the same select expands.
194
+ */
195
+ type Given<T> = [T][T extends unknown ? 0 : never];
196
+ /**
197
+ * Reads of `/api/entries`. `T` is the model type (`list<Articles>`), and `S`
198
+ * the select's own type, for `fields` typed exactly as the read returns them
199
+ * (`list<Articles, typeof select>`); see `EntryFields`.
200
+ */
113
201
  export interface EntriesResource {
114
- list<T = Record<string, unknown>>(namespace: string, options?: ListOptions<T>): Promise<Page<Entry<T>>>;
115
- get<T = Record<string, unknown>>(namespace: string, id: string, options?: GetOptions<T>): Promise<Single<Entry<T>> | null>;
116
- iterate<T = Record<string, unknown>>(namespace: string, options?: ListOptions<T>): AsyncGenerator<Entry<T>, void, undefined>;
202
+ list<T = Record<string, unknown>, S extends Select<T> | string = Select<T>>(namespace: string, options: FlatListOptions<Given<T>, S>): Promise<FlatPage<T, S>>;
203
+ list<T = Record<string, unknown>, S extends Select<T> | string = Select<T> | string>(namespace: string, options?: ListOptions<Given<T>, S>): Promise<Page<Entry<EntryFields<T, S>>>>;
204
+ get<T = Record<string, unknown>, S extends Select<T> | string = Select<T>>(namespace: string, id: string, options: FlatGetOptions<Given<T>, S>): Promise<FlatSingle<T, S> | null>;
205
+ get<T = Record<string, unknown>, S extends Select<T> | string = Select<T> | string>(namespace: string, id: string, options?: GetOptions<Given<T>, S>): Promise<Single<Entry<EntryFields<T, S>>> | null>;
206
+ /** Tree only: it yields entries one at a time, which is what `included` exists to avoid. */
207
+ iterate<T = Record<string, unknown>, S extends Select<T> | string = Select<T> | string>(namespace: string, options?: ListOptions<Given<T>, S>): AsyncGenerator<Entry<EntryFields<T, S>>, void, undefined>;
117
208
  }
118
209
  /**
119
210
  * One suggestion drawn from a page's own reads.
120
211
  *
121
212
  * Computed on the API, never here. Three clients want this answer (this SDK,
122
- * the Capa admin and `@capa/mcp`), and a second implementation of "this page
213
+ * the Capa admin and `@capacms/mcp`), and a second implementation of "this page
123
214
  * over-fetches" would drift from the first the moment a threshold moved.
124
215
  */
125
216
  export interface PageInsight {
@@ -252,7 +343,56 @@ export interface PreviewClaim {
252
343
  path: string | null;
253
344
  expiresAt: string;
254
345
  }
255
- export interface CapaNextClient {
346
+ /**
347
+ * `client.graphql`: run a document, or build one from a typed selection with
348
+ * `client.graphql.query()`. `Q` is the `CapaQuery` type `capa-codegen
349
+ * --graphql` writes; without it selections and results are untyped. `O` is
350
+ * what a call takes: `getCapaClient` from `/nextjs` adds Next's cache `tags`
351
+ * and `revalidate`.
352
+ */
353
+ export interface GraphQLClient<Q = UntypedQuery, O extends GraphQLCallOptions = GraphQLCallOptions> {
354
+ /**
355
+ * Run a document written as a literal (`#graphql`, `/* capa *\/` or
356
+ * gql(`...`)) that `capa-codegen --graphql` has checked: its text is looked
357
+ * up in `CapaDocuments`, so `data` and `variables` are typed with no cast.
358
+ *
359
+ * Resolves once the API ran the document, even when `errors` is not empty,
360
+ * because the root fields that worked still carry data. Throws `CapaError`
361
+ * when the API refused the request as a whole, with `graphqlErrors` holding
362
+ * every error it sent: `errors` and no `data`, whether sent as a 4xx or, as
363
+ * GraphQL over HTTP sends it on `application/json`, as a 200.
364
+ */
365
+ <D extends keyof CapaDocuments>(document: D, ...rest: VariablesThenOptions<CapaDocumentVariables<D>, O>): Promise<GraphQLResult<CapaDocumentResult<D>>>;
366
+ /**
367
+ * Run a GraphQL document. A `<Name>Document` from `capa-codegen --graphql`
368
+ * types `data` and `variables` by itself; for any other string, pass the
369
+ * data type: `capa.graphql<{ articles: ... }>(query, variables)`.
370
+ */
371
+ <TData = Record<string, unknown>, TVariables = Record<string, unknown>, D extends string = string>(document: NotARecordedDocument<D, TypedDocument<TData, TVariables> | D>, ...rest: VariablesThenOptions<TVariables, O>): Promise<GraphQLResult<TData>>;
372
+ /**
373
+ * Build the document from a selection object and run it. See "Typed
374
+ * builder" in the README. It takes no `persisted`: see `BuilderCallOptions`.
375
+ */
376
+ query<const S extends QuerySelection<Q>>(selection: S & ExactSelection<S, Q>, options?: BuilderCallOptions<O>): Promise<GraphQLResult<QueryResult<Q, S>>>;
377
+ }
378
+ /**
379
+ * What `graphql.query()` takes: a call's options without `persisted`. The
380
+ * builder prints its document when it runs, so `capa persist`, which stores
381
+ * the documents written in a project, never stored it, and a production key
382
+ * never registers one: every read would miss its hash and fall back to a POST,
383
+ * which is never cached. Unpersisted, a builder read is already a GET the API
384
+ * and the CDN cache. To persist a read, write it as a `#graphql` literal.
385
+ */
386
+ export type BuilderCallOptions<O extends GraphQLCallOptions = GraphQLCallOptions> = Omit<O, "persisted">;
387
+ /**
388
+ * `client.graphql` over one way of reading a document: called with a
389
+ * document, and `query()` printing a selection's document for it. `createClient`
390
+ * reads straight from the API, and `getCapaClient` from `/nextjs` the same way
391
+ * unless a call gives `tags` or `revalidate`, then through Next's data cache,
392
+ * with the same refusals.
393
+ */
394
+ export declare function graphqlClient<Q, O extends GraphQLCallOptions>(read: (document: string, variables: Record<string, unknown> | undefined, options: O | undefined) => Promise<GraphQLResult<unknown>>): GraphQLClient<Q, O>;
395
+ export interface CapaNextClient<Q = UntypedQuery, O extends GraphQLCallOptions = GraphQLCallOptions> {
256
396
  entries: EntriesResource;
257
397
  pages: PagesResource;
258
398
  /**
@@ -261,34 +401,38 @@ export interface CapaNextClient {
261
401
  * Returns the claim, or NULL when the token is invalid or expired, because
262
402
  * both mean the same thing to a preview route: do not enable draft mode.
263
403
  * Every other failure throws, so a Capa outage does not look like a bad link.
404
+ * Takes any key the site holds, a legacy `pk_`, `sk_` or unprefixed key
405
+ * included: Capa answers a token minted for another tenant as invalid.
264
406
  */
265
407
  preview(token: string, options?: CallOptions): Promise<PreviewClaim | null>;
266
408
  me<T = Record<string, unknown>>(options?: CallOptions): Promise<T>;
267
409
  versions<T = Record<string, unknown>>(options?: CallOptions): Promise<T>;
410
+ graphql: GraphQLClient<Q, O>;
411
+ /**
412
+ * Every model this key can read over GraphQL, with its root fields, fields,
413
+ * filter operators and sort values, read from one introspection request.
414
+ * What `buildGraphQLQuery`, `graphqlToSelect` and `toTree` take.
415
+ */
416
+ graphqlSchema(options?: {
417
+ signal?: AbortSignal;
418
+ }): Promise<GraphQLSchemaSummary<Q>>;
268
419
  }
269
- export declare class CapaError extends Error {
270
- readonly status: number;
271
- readonly type: string;
272
- readonly code: string;
273
- readonly param?: string;
274
- readonly hint?: string;
275
- readonly requestId: string;
276
- readonly docs: string;
277
- constructor(input: {
278
- status: number;
279
- type: string;
280
- code: string;
281
- message: string;
282
- param?: string;
283
- hint?: string;
284
- requestId: string;
285
- docs: string;
286
- });
287
- }
288
- export declare function isCapaError(error: unknown): error is CapaError;
289
420
  export declare function resolveNextConfig(config: CapaNextConfig): ResolvedNextConfig;
421
+ /**
422
+ * The page a layout (or template) reads for: none.
423
+ *
424
+ * A root layout renders around every page on the site, so charging its reads
425
+ * to `/`, the route its file sits at, made the home page look as if it read
426
+ * every Site singleton and nav on the site. `routeOf` returns this for a
427
+ * `layout.*` or `template.*` file, and a read that names it sends NO
428
+ * `Capa-Page` at all, even when the client was built with a `page`.
429
+ *
430
+ * Not sent as a value, because the API would drop it anyway: it is not a
431
+ * `PAGE_ID`, and the API ignores what it cannot store. Staying absent keeps a
432
+ * layout read byte-identical to one from a client that never named a page.
433
+ */
434
+ export declare const LAYOUT_PAGE = "(layout)";
290
435
  type SelectInput = string | ReadonlyArray<unknown>;
291
436
  /** Serialize the SDK object form into the canonical `/api/entries` grammar. */
292
437
  export declare function serializeSelect(select: SelectInput): string;
293
- export declare function createClient(config: CapaNextConfig): CapaNextClient;
294
- export {};
438
+ export declare function createClient<Q = UntypedQuery>(config: CapaNextConfig): CapaNextClient<Q>;