@capacms/sdk 1.0.0-next.4 → 1.0.0-next.7

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 (69) hide show
  1. package/CHANGELOG.md +345 -0
  2. package/README.md +1069 -186
  3. package/bin/capa-codegen.js +192 -5
  4. package/bin/capa.js +208 -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/graphql-codegen.d.ts +117 -0
  14. package/dist/graphql-codegen.js +705 -0
  15. package/dist/http.js +1 -1
  16. package/dist/index.d.ts +2 -2
  17. package/dist/index.js +2 -1
  18. package/dist/next/attrs.d.ts +51 -12
  19. package/dist/next/attrs.js +74 -20
  20. package/dist/next/client.d.ts +112 -38
  21. package/dist/next/client.js +131 -83
  22. package/dist/next/entry-fields.d.ts +162 -0
  23. package/dist/next/entry-fields.js +2 -0
  24. package/dist/next/errors.d.ts +136 -0
  25. package/dist/next/errors.js +214 -0
  26. package/dist/next/field-names.d.ts +37 -0
  27. package/dist/next/field-names.js +145 -0
  28. package/dist/next/graphql/build.d.ts +27 -0
  29. package/dist/next/graphql/build.js +98 -0
  30. package/dist/next/graphql/documents.d.ts +67 -0
  31. package/dist/next/graphql/documents.js +35 -0
  32. package/dist/next/graphql/edit-mode.d.ts +16 -0
  33. package/dist/next/graphql/edit-mode.js +93 -0
  34. package/dist/next/graphql/filter-values.d.ts +34 -0
  35. package/dist/next/graphql/filter-values.js +96 -0
  36. package/dist/next/graphql/introspection.d.ts +89 -0
  37. package/dist/next/graphql/introspection.js +102 -0
  38. package/dist/next/graphql/plan.d.ts +115 -0
  39. package/dist/next/graphql/plan.js +531 -0
  40. package/dist/next/graphql/request.d.ts +228 -0
  41. package/dist/next/graphql/request.js +283 -0
  42. package/dist/next/graphql/rest.d.ts +66 -0
  43. package/dist/next/graphql/rest.js +502 -0
  44. package/dist/next/graphql/selection.d.ts +55 -0
  45. package/dist/next/graphql/selection.js +212 -0
  46. package/dist/next/graphql/sha256.d.ts +13 -0
  47. package/dist/next/graphql/sha256.js +86 -0
  48. package/dist/next/graphql/summary.d.ts +83 -0
  49. package/dist/next/graphql/summary.js +151 -0
  50. package/dist/next/graphql/tree-layout.d.ts +36 -0
  51. package/dist/next/graphql/tree-layout.js +20 -0
  52. package/dist/next/graphql/tree.d.ts +171 -0
  53. package/dist/next/graphql/tree.js +249 -0
  54. package/dist/next/graphql/typed.d.ts +261 -0
  55. package/dist/next/graphql/typed.js +146 -0
  56. package/dist/next/index.d.ts +28 -5
  57. package/dist/next/index.js +25 -1
  58. package/dist/next/inflate.d.ts +25 -7
  59. package/dist/next/inflate.js +46 -32
  60. package/dist/next/key-family.d.ts +34 -0
  61. package/dist/next/key-family.js +74 -0
  62. package/dist/next/select-types.d.ts +44 -8
  63. package/dist/next/system-keys.d.ts +27 -0
  64. package/dist/next/system-keys.js +42 -0
  65. package/dist/nextjs/index.d.ts +174 -12
  66. package/dist/nextjs/index.js +270 -23
  67. package/dist/nextjs/overlay.d.ts +5 -0
  68. package/dist/nextjs/overlay.js +35 -0
  69. package/package.json +31 -13
package/CHANGELOG.md ADDED
@@ -0,0 +1,345 @@
1
+ # @capacms/sdk changelog
2
+
3
+ ## Unreleased
4
+
5
+ - 1.0.0-next.7. Browsers: the `/api/` and legacy clients called the platform `fetch` as a
6
+ method of their config, which a browser refuses ("Failed to execute 'fetch'
7
+ on 'Window': Illegal invocation"), so every read from a browser failed unless
8
+ `fetch` was passed in. The default fetch is now called through `globalThis`
9
+ on each request, which also picks up a fetch a framework patches in later.
10
+ - `next` is no longer a peer dependency. No range matches every Next canary,
11
+ so a site on `next@16.3.0-canary.39` could not `npm install` the SDK without
12
+ `--legacy-peer-deps`. `@capacms/sdk/nextjs/overlay` still imports `next`,
13
+ which only a Next site loads.
14
+ - Docs: the edit mark is dropped wherever an entry is serialized to the
15
+ browser (Pages Router props, SvelteKit and Remix loaders, Nuxt payload);
16
+ pass the edit flag to `capaAttrs` there. Found testing preview on nine stacks.
17
+ - Next.js: a GraphQL read that gives neither `tags` nor `revalidate`, through
18
+ `getCapaClient().graphql()`, its builder or `graphql()`, is no longer kept
19
+ in Next's data cache. It is sent as `entries.list` and `entries.get` send
20
+ theirs, with no `cache` and no `next`, so a publish shows on the next render
21
+ whether the page reads by REST or by GraphQL. It used to be kept under
22
+ `capa:graphql` until a webhook revalidated it, so a site with no webhook
23
+ route kept serving the old answer by GraphQL while REST showed the new one.
24
+ A read that gives `tags` or a `revalidate` is kept as before. To keep a read
25
+ with no tags as it was kept, pass `revalidate: false`, which keeps it under
26
+ `capa:graphql` until the next publish. `tags: []` now counts as no tags.
27
+ - 1.0.0-next.6. GraphQL, on `@capacms/sdk/next` and `@capacms/sdk/nextjs`,
28
+ and two commands, `capa-codegen --graphql` and `capa persist`. Additive:
29
+ every call that existed behaves as before. `graphql` is an optional peer
30
+ dependency that only the two commands load. The package's types now need
31
+ TypeScript 5.0 or later, with `strict` on or off.
32
+
33
+ Calls and errors. `client.graphql(document, variables?, options?)` runs a
34
+ query against `/api/graphql` and resolves with
35
+ `{ data, errors, extensions, cacheTags }` once the API has run it, even
36
+ when `errors` is not empty: a root field that failed is `null` and the
37
+ others keep their data. A request the API refuses as a whole, `errors` and
38
+ no `data`, throws `CapaError` whatever its status: a 4xx, or the 200 that
39
+ GraphQL over HTTP sends on `application/json`, thrown with `status` 400.
40
+ 401, 402, 403, 404, 405 and 429 keep their own. `CapaError` carries every
41
+ error of the refusal in `graphqlErrors`. Each error is a
42
+ `CapaGraphQLError`, a plain object: `message`, `locations`, `path` and
43
+ `extensions` as the spec writes them, with `code`, `hint`, `docs`, `param`
44
+ and `type` lifted out, so `Response.json(result)` and a client component's
45
+ props keep every field. `isCapaGraphQLError` checks one by its shape.
46
+ Where GraphQL is switched off (`CAPA_API_GRAPHQL=off`) the call throws
47
+ "This Capa deployment does not serve GraphQL." with a hint to read over
48
+ REST meanwhile. `extensions.cost` (`requestedQueryCost`,
49
+ `actualQueryCost`, and `budget`, whose `counted` is what the 5,000-entry
50
+ limit checks) and `extensions.deprecations` (`{ coordinate, reason }` for
51
+ each deprecated member a document used) are typed.
52
+
53
+ Sending. A read is a GET whenever its URL fits the API's 8,192-byte limit,
54
+ so a production key's read is cached by the CDN and the API with no option
55
+ set, and a POST when it does not; no document is refused for its length.
56
+ `method: "POST"` always sends a POST. A host that serves GraphQL by POST
57
+ only (the admin host) answers a GET as a path it does not serve; the read
58
+ is repeated as a POST, and that host is read by POST for five minutes. A
59
+ 429 (over the API's read limits: 4 running per project, 3 of them per
60
+ client, and 64 waiting per client or 256 per key, with `/api/entries`
61
+ reads counted in the same limits) is sent again after its `Retry-After`
62
+ plus up to 250 ms, up to 3 times; `retries: 0` throws it, and a thrown 429
63
+ carries `retryAfter` in seconds, on REST calls too. `createClient` takes the legacy key a site holds for
64
+ every read, `pk_`, `sk_` or unprefixed as older tenants were minted, and
65
+ warns once per process without printing any of it; `preview()` and draft
66
+ reads (`draftClient`, `CAPA_DRAFT_KEY`) take a `cap_` key only.
67
+
68
+ Persisted queries. `persisted: true` sends the document's sha256 as a
69
+ cacheable GET (a POST when the variables are too long for a URL), and on
70
+ `PersistedQueryNotFound` one POST with the document. The API stores a
71
+ document only for a development key; a hash a host declined is
72
+ remembered for five minutes and sent by POST meanwhile. `capa persist`
73
+ registers a project's documents at build time, with the development key
74
+ in `CAPA_DRAFT_KEY`, on `CAPA_API_URL` (`CAPA_ADMIN_URL` for a self-hosted
75
+ stack whose read host stores nothing), and refuses a production key
76
+ before it sends anything. Every document is pinned (`Capa-Persist: pin`),
77
+ so documents registered in the Explorer or a preview never evict it, and
78
+ one stored without its pin fails the run. A refusal is reported with its
79
+ code. `--release` and `--env` name the build its pins belong to
80
+ (`Capa-Persist: pin; release=<id>; env=<env>`), read from Vercel's and
81
+ Netlify's build variables when not given, so the API keeps the latest
82
+ production releases' documents before a preview's.
83
+
84
+ Typed documents. `capa-codegen --graphql` checks the project's `.graphql`
85
+ files and its `#graphql`, `/* capa */` and gql`` literals against the
86
+ key's schema, and writes one module: the schema's types, `CapaQuery`, a
87
+ `TypedDocument` per operation with `<Name>Models`, the models it reads,
88
+ beside it, a `<Name>Fragment` per fragment and `capaTreeLayout`.
89
+ `tagsFor({ namespace: <Name>Models })` tags a Next.js read with every model
90
+ its query reads, relations and filters through them included, so no model
91
+ is left out by hand, and with `capa:media`, which `revalidateFromWebhook`
92
+ revalidates when a file in the media library is edited. `client.graphql(doc, vars)` then infers data and
93
+ variables with no cast, a literal is typed by its own text, and a
94
+ document's required variables are required in the call. A literal codegen
95
+ has not read yet does not compile (`RunCapaCodegen`). A fragment in a
96
+ literal of its own, spread with `${FRAGMENT}` into a query kept
97
+ `as const`, works as in Hydrogen. A field, argument or value a later
98
+ `Capa-Version` phases out is `@deprecated`, and each use is printed with
99
+ its file, line and reason. `--watch`, `--check`, `--save-schema` and
100
+ `--schema` are supported. Both commands read `CAPA_API_URL` and `CAPA_KEY`
101
+ (`CAPA_BASE_URL` and `CAPA_API_KEY` still work) from the shell or the
102
+ project's `.env` files, as `next dev` does.
103
+
104
+ REST types. `capa-codegen` without `--graphql` takes a `cap_` key: it
105
+ writes the model interfaces the `/v2` schema gives a legacy key from the
106
+ key's GraphQL schema, keyed by namespace, with no tenant id, and from a
107
+ saved schema with `--schema`. Every field is optional there, an enum is a
108
+ `string` and a field GraphQL leaves out is `unknown`, since GraphQL does
109
+ not say more; no `CAPA_SCHEMA_CHECKSUM` is written. Whichever key reads
110
+ it, the module now parses for any namespace: a field that is not an
111
+ identifier is quoted (`"am/pm_indicator"?: string;`), a model whose
112
+ PascalCase name is not one is named as GraphQL names it (`2024_events` is
113
+ `_2024Events`, its references and `Select` and `Attrs` aliases too), and an
114
+ enum's values are escaped. A read's `fields` is typed as the API returns
115
+ it: `entries.list<Articles, typeof select>` types exactly the fields the
116
+ select names, each always there and `null` when it was never filled, an
117
+ expanded relation as the entry (with `fields`) or
118
+ `{ id, model, missing: true }`, one it does not expand as `{ id, model }`,
119
+ a relation list as `{ items, pageInfo }` and media as
120
+ `{ id, url, alt, type, width, height }` (`EntryFields`). A select the
121
+ compiler cannot read, a string or one typed `Select<T>`, types every field
122
+ and each relation as any of the three. A flat read's relations are
123
+ references, `included` holds partial entries, and `inflate` returns the
124
+ tree read's type. BREAKING for code that compiled against the stored
125
+ shape (`fields.author.name`, `fields.coauthors[0]`), which read
126
+ `undefined` or threw at run time. A relation may be named alone in a
127
+ typed select, as a reference.
128
+
129
+ The typed builder. `client.graphql.query(selection)` builds the document
130
+ from an object and, with `createClient<CapaQuery>()`, types the result from
131
+ exactly what was selected. A misspelled field, argument, filter field or
132
+ operator, an argument of the wrong type, a sort value outside the enum
133
+ and a missing required argument (`article` without `args: { id }`) do not
134
+ compile, and the compiler's error names the key and where it was written
135
+ (`SelectionError<"titel is not a field of articles.nodes">`).
136
+ `NodeOf<CapaQuery, typeof selection, "articles">` is one entry of a read,
137
+ for a component's props, and `QueryResult` the whole of its `data`. An alias reads a field again in the same request:
138
+ `{ latest: { __aliasFor: "articles", args, nodes } }` is sent as
139
+ `latest: articles(...)`, and typed and checked as `articles`. A `Date` in
140
+ `args` is sent as its ISO text. `selectionToDocument` returns the text a
141
+ selection sends. It takes no `persisted`, and throws a `TypeError` for it
142
+ before any request: its document is printed when it runs, so `capa persist`
143
+ never stored it, and it is already a cacheable GET.
144
+
145
+ Paging, tags and descriptions. The builders page back as the API does:
146
+ REST's `before` with a `limit` is sent as `last` with `before`, and
147
+ `before=end` as `last` alone, the end of the list. A model's filter takes
148
+ `_tags`, as REST's `where` takes `$tags`, with the operators the key's
149
+ schema declares for it. `graphqlSchema()`, the builders and codegen read a
150
+ field's `Capa field ...` tag from the last line of its description, after
151
+ the field's label, which is where the API writes it.
152
+
153
+ REST's shape. `toTree(data, selection, layout)` turns a builder result into
154
+ REST's `shape=tree` data for the same read, typed from the selection:
155
+ system keys beside `fields`, each field under its namespace, media values
156
+ in REST's public shape and order (`id`, `url`, `alt`, `type`, `width`,
157
+ `height`), and each entry's `model` from the layout. A relation list
158
+ without `pageInfo` selected is `{ items }`, and a missing item of one is
159
+ left out, where REST keeps a `{ id, model, missing: true }` slot. The layout
160
+ is the `capaTreeLayout` constant codegen writes, so a server reads no schema
161
+ for it, or a schema read with `client.graphqlSchema()`. A root alias
162
+ converts as the field it names; an alias below a root is refused, since
163
+ REST reads each field once. `selectToSelection` writes a REST read as a
164
+ builder selection, and `graphqlToSelect` takes a selection back to REST
165
+ as it takes a tool spec.
166
+
167
+ The tool spec. `buildGraphQLQuery`, `graphqlToSelect` and `selectToGraphQL`
168
+ move between the spec the Explorer and `@capa/mcp` share, GraphQL text and
169
+ the equal REST request, written exactly as the API writes it in
170
+ `extensions.capa.rest`: the filter as `where` JSON, and a system key a
171
+ field shadows as `$tags`, `$createdAt` or `author.$id`. They nest at most 4
172
+ relations below the root entry, which is the API's 5 levels of entries,
173
+ and send each filter value as the type its filter input declares, so
174
+ `has: "true"` on a list of true/false values goes as `true`. They check a
175
+ filter's names through `and`, `or`, `not` and one hop, refuse a system
176
+ field GraphQL does not filter (`_version`) and a hop through a relation the
177
+ key cannot read without naming the hidden model, and refuse a key a spec
178
+ does not take (`frist`) with the keys it does. `selectToGraphQL` selects
179
+ what REST returns: all six media fields, and for `*` or no select the
180
+ system keys, every field and each relation list as a connection of ids.
181
+ `inflate` and `Select<T>` read `$tags`, `$createdAt` and the other `$`
182
+ names as system keys (`SystemKey`). The schema summary lists the models
183
+ GraphQL leaves out in `restOnly`, and the builder refuses one by naming
184
+ its REST read, never as an unknown model with another model suggested.
185
+ A read of one entry pages a relation list from a cursor: `after` on the
186
+ relation's spec, `after:` in a select, `args.after` in a selection. A list
187
+ read refuses it, as the API does. `sort` takes one value or a list, at the
188
+ root too. A spec written as REST writes a read (`author.name`,
189
+ `author(name)`, `*`, a sort of `-publishedAt`) throws with what to write
190
+ instead.
191
+
192
+ Next.js. `graphql()` on `@capacms/sdk/nextjs` reads `CAPA_API_URL`,
193
+ `CAPA_KEY` and `CAPA_API_VERSION` (a setting in `config` wins), works out
194
+ draft and edit mode from `{ draftMode, headers }` as `getCapaClient` does,
195
+ and keeps a published read that answered with no `errors` in Next's data
196
+ cache, through `unstable_cache`, under its `tags`: until one of them is
197
+ revalidated, or for `revalidate` seconds. A read with no `tags` is tagged
198
+ `capa:graphql` (`GRAPHQL_TAG`), which `revalidateFromWebhook` revalidates
199
+ on every content and media event; `tagsFor({ namespace })` tags a read by
200
+ the models it reads. Drafts are read uncached, by GET. It is not
201
+ persisted by default. `draftClient`, `getCapaClient` and
202
+ `getPublishedClient` take `CapaQuery` like `createClient`, and
203
+ `getCapaClient` keeps its GraphQL reads, a document or the typed builder,
204
+ in Next's data cache the same way, under the `tags` and `revalidate` each
205
+ call gives.
206
+
207
+ The package root. `createClient` from `@capacms/sdk`, the legacy `/v2/api`
208
+ client, refuses a `cap_` key with a `TypeError` that names
209
+ `@capacms/sdk/next`, before it asks for a tenant id or sends anything,
210
+ where every read failed as a 401 "Invalid API key". Its `CapaError`
211
+ message joins the body with a colon. The README opens with which import is
212
+ which and links the API reference, and `homepage` is
213
+ https://docs.capacms.com/api.
214
+
215
+ Edit mode. A GraphQL read in edit mode is marked like a REST read: each
216
+ object that selected `id` and `model` is an entry, and
217
+ `capaAttrs(node, field)` and `fieldAttrs(node)` tag a field GraphQL renamed
218
+ by its namespace. To know which fields those are, the client reads the
219
+ key's type and field names once a minute, beside the page's read rather
220
+ than after it; a document that never says `model` reads none. `toTree`
221
+ keeps the mark, and `markGraphQLEntries` is exported. With next.5's
222
+ `FieldAttrs<T>`: `fieldAttrs` also takes a GraphQL node and, for a REST
223
+ entry typed with `Model`, still returns exactly `FieldAttrs<Model>`, so the
224
+ `<Model>Attrs` aliases codegen writes keep working. `TaggableField<E>` is
225
+ exported beside it.
226
+
227
+ - 1.0.0-next.5. `<CapaOverlay adminOrigins={[...]} />` from the new entry
228
+ point `@capacms/sdk/nextjs/overlay`: the live preview overlay as one Next.js
229
+ client component, refreshing with `router.refresh()` on save (M6). `react`
230
+ and `next` are optional peer dependencies, needed only for that entry. The
231
+ `FieldAttrs<T>` type is exported from `@capacms/sdk/next`, and `capa-codegen`
232
+ writes a `<Model>Attrs` alias beside each `<Model>Select`, so
233
+ `const a: ArticleAttrs = fieldAttrs(entry)` catches a wrong field name at
234
+ compile time (M5).
235
+ - 1.0.0-next.4. Edit mode. BREAKING for sites that call `capaAttrs(entry,
236
+ field)` with no third argument: it now tags only entries read in edit mode, so
237
+ a published page ships no `data-capa-` attributes. Create the client with
238
+ `editMode: true` (work it out with `editMode({ draftMode, headers })` from
239
+ `@capacms/sdk/nextjs`) and every entry it reads, related entries included, is
240
+ marked. Sites that pass a flag keep working unchanged. New in
241
+ `@capacms/sdk/nextjs`: `editMode`, `resolveEditRequest` for middleware (checks
242
+ a `capa-edit` token with Capa, strips a forged `x-capa-edit`, returns the
243
+ `private, no-store` Cache-Control to set), and the constants `EDIT_PARAM`,
244
+ `EDIT_HEADER`, `DRAFT_COOKIE`, `EDIT_CACHE_CONTROL`. New on the client: a
245
+ `path` option (config and per call) sent as `Capa-Path` beside `Capa-Page`, so
246
+ Capa can list the concrete URLs an entry appears on. `markEditEntries`,
247
+ `isEditEntry` and `CAPA_EDIT` are exported from `@capacms/sdk/next`.
248
+ Five-minute integration (M6) in `@capacms/sdk/nextjs`: `getCapaClient`
249
+ (keys and edit mode from env), `getPublishedClient`, `createPreviewRoute`,
250
+ `exitPreviewRoute` and `capaMiddleware` (preview links, the Published view,
251
+ edit mode and `no-store` in one line). Typed `fieldAttrs(entry).title` on
252
+ `@capacms/sdk/next` (M5): a wrong field name is a compile error.
253
+ Flat responses: `entries.list` and `entries.get` take `shape: "flat"`, which
254
+ sends `?shape=flat` and returns every relation as a `{ id, model }`
255
+ reference with each expanded entry once in `included`, typed by the select.
256
+ The result carries the select it sent. `inflate(result)` turns it back into
257
+ the tree result, deep-equal to a `shape=tree` read of the same request; it
258
+ returns copies and stops where the select stops, so cycles end. New types:
259
+ `FlatPage`, `FlatSingle`, `FlatListOptions`, `FlatGetOptions`, `Included`,
260
+ `ExpandedTargets`, `ResponseShape`, `FlatResponse`. Additive: a read without
261
+ `shape` sends the same URL and returns the same result as before.
262
+ - 1.0.0-next.3. Reads made from a layout are no longer charged to `/`.
263
+ `routeOf` returned the route a file sits at, so `app/layout.tsx` came out as
264
+ `/` and every Site singleton or nav read in a root layout was recorded as a
265
+ read of the home page, on every page of the site. `routeOf` now returns
266
+ `"(layout)"` (exported as `LAYOUT_PAGE` from `@capacms/sdk/next` and
267
+ `@capacms/sdk/nextjs`) for an app-router `layout.*` or `template.*`, and a
268
+ read whose page is `"(layout)"` sends no `Capa-Page`, even when the client was
269
+ created with a `page`. The return type is still `string`, so layout code that
270
+ already passes `routeOf(import.meta.url)` needs no change: upgrading fixes it.
271
+ No API change: the API already records nothing for a read without the
272
+ header. In the pages router, `pages/layout.tsx` is now the page `/layout`
273
+ rather than `/`.
274
+ - 1.0.0-next.2. The overlay reports `visible { entryId, field }`, the tagged
275
+ element at the centre of the viewport, while the page scrolls: at most every
276
+ 150ms and only when it changes (the topmost visible element at the very top
277
+ of a page, the bottommost at the very bottom). The Capa editor's "Follow the
278
+ page" scrolls the form to match. Additive and still protocol `v: 1`, so an older admin
279
+ ignores it and an older overlay simply never sends it. `pickCentred` and
280
+ `scrollEdge`, the pure choice behind it, and `visibleMessage` are exported
281
+ for tests.
282
+ - 1.0.0-next.1. Live preview. `capaAttrs(entry, field, enabled)` on
283
+ `@capacms/sdk/next` tags an element with the entry and field it renders,
284
+ typed so `field` is one of the entry's data keys. The new entry point
285
+ `@capacms/sdk/overlay` exports `startOverlay({ adminOrigins, onRefresh })`,
286
+ which, inside the Capa editor's preview frame, outlines the field being
287
+ edited, reports clicks on tagged elements back to the editor and re-renders
288
+ the draft after a save. It does nothing outside a frame and has no
289
+ dependencies. `acceptMessage` is exported for tests. See "Live preview" in
290
+ the README.
291
+ - `routeOf(import.meta.url)` now decodes the file URL. A real `import.meta.url`
292
+ percent-encodes brackets, so a dynamic route such as `app/blog/[slug]/page.tsx`
293
+ came out as `/blog/%5Bslug%5D` and every read with that `page` threw a
294
+ `TypeError`.
295
+ - The package is published as `@capacms/sdk`. The `capa` scope on npm was
296
+ already taken, so the org is `capacms`; entry points are `@capacms/sdk`
297
+ (legacy `/v2` client), `@capacms/sdk/next` and `@capacms/sdk/nextjs`.
298
+ Nothing else about the package changed. Earlier notes below that named
299
+ `@capa/sdk` were written before the first publish and mean this package.
300
+ - Added `page` to `CapaNextConfig` and to every call's options, sending the
301
+ `Capa-Page` header so Capa can report which of a site's pages read which
302
+ entries. Telemetry only: it does not change a response, a cache key or an
303
+ `ETag`. A malformed value throws a `TypeError`, because the API ignores a
304
+ header it cannot store and a typo should surface where it is written.
305
+ - Added `client.pages.list()` and `client.pages.get(page)` for the page list and
306
+ one page's detail. `list({ entry })` narrows to the pages that read one entry
307
+ and adds `entryReads` to each row; `get` returns `null` for an unknown page.
308
+ - Added `client.preview(token)`, which verifies a preview token minted by the
309
+ Capa admin and returns the claim, or `null` when the token is invalid or
310
+ expired. Every other failure throws.
311
+ - Added `schemaChecksum` to `CapaNextConfig`, sending the `Capa-Schema` header on
312
+ every call so Capa can tell a site built against the current models from one
313
+ built against an older set. Telemetry only, like `page`: it changes no
314
+ response, cache key or `ETag`. A malformed value throws a `TypeError`, because
315
+ a stamp the API drops in silence looks exactly like a site that is up to date.
316
+ - `capa-codegen` now writes `export const CAPA_SCHEMA_CHECKSUM` beside the
317
+ checksum comment it already wrote, so the value can be imported and handed to
318
+ `createClient`. That constant is the only new byte in the generated file.
319
+ - `client.pages.get(page)` now carries `insights`, the suggestions Capa draws
320
+ from that page's own reads (`overfetch`, `fanout`, `cache`, `drift`), each
321
+ with the numbers behind it and a copyable rewrite where there is one, and
322
+ every `queries[]` row carries `selection`, the parsed Selection IR of its
323
+ `select`, or `selectionError` when it no longer parses.
324
+ - Every `queries[]` row on `client.pages.get(page)` also carries `url`, the
325
+ request that group most often made, so a caller can print the real call with
326
+ its filters, sort and limit instead of reconstructing one from `select`. It is
327
+ `null` once the group has been folded into the daily rollup, which keeps
328
+ counts rather than requests. The detail itself gains `lastReadAt`.
329
+ - `client.pages.list()` now carries `meta.insights`, the tenant-wide `unused`
330
+ rows: entries no page has read in 30 days and nobody has edited in 90.
331
+ - Added `routeOf(file)`, `preview(token, client)` and `pagesFor(client)` to
332
+ `@capacms/sdk/nextjs`. `routeOf` turns a Next route file into a page string,
333
+ dropping route groups, parallel slots, leaf file names and extensions, and
334
+ throws rather than guessing for files Next does not route.
335
+
336
+ ## 1.0.0-next.0
337
+
338
+ - Added `@capacms/sdk/next`, the dependency-free `/api/` read client for `cap_`
339
+ keys, typed selects, cursor iteration, structured `/api/` errors, and
340
+ surrogate cache tags.
341
+ - Added `@capacms/sdk/nextjs` helpers for Next fetch caching, surrogate tag
342
+ construction, webhook revalidation, and server-only draft client selection.
343
+ - Kept the legacy `/v2/api` client as the root export.
344
+ - Added relation-aware `capa-codegen` output while preserving byte-identical
345
+ output for schemas without relations.