@capacms/sdk 1.0.0-next.2 → 1.0.0-next.3
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 +13 -0
- package/dist/next/client.d.ts +14 -0
- package/dist/next/client.js +19 -1
- package/dist/next/index.d.ts +1 -1
- package/dist/next/index.js +2 -1
- package/dist/nextjs/index.d.ts +2 -1
- package/dist/nextjs/index.js +19 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -199,6 +199,19 @@ so that moving a folder cannot silently split one page's telemetry in two. Set
|
|
|
199
199
|
`page` on the config instead when a client serves exactly one page; a value on
|
|
200
200
|
the call wins over one on the config.
|
|
201
201
|
|
|
202
|
+
A layout is not a page. `app/layout.tsx` (and any nested `layout.*` or
|
|
203
|
+
`template.*`) renders around every page below it, and Next does not tell it
|
|
204
|
+
which one, so its reads cannot be charged to the page being rendered. `routeOf`
|
|
205
|
+
returns `"(layout)"` for these files, exported as `LAYOUT_PAGE`, and a read that
|
|
206
|
+
names it sends no `Capa-Page` header at all, even when the client was created
|
|
207
|
+
with a `page`. So a Site singleton or a nav read in your root layout is simply
|
|
208
|
+
not attributed, instead of making `/` look as if it read everything:
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
// In app/layout.tsx: same call as in a page, and no page is recorded.
|
|
212
|
+
const site = await capa.entries.list("site", { page: routeOf(import.meta.url) });
|
|
213
|
+
```
|
|
214
|
+
|
|
202
215
|
A malformed value throws a `TypeError`. Capa itself ignores a header it cannot
|
|
203
216
|
store, because a mangled page identity must never take a blog down, so the SDK
|
|
204
217
|
is the place a typo surfaces.
|
package/dist/next/client.d.ts
CHANGED
|
@@ -287,6 +287,20 @@ export declare class CapaError extends Error {
|
|
|
287
287
|
}
|
|
288
288
|
export declare function isCapaError(error: unknown): error is CapaError;
|
|
289
289
|
export declare function resolveNextConfig(config: CapaNextConfig): ResolvedNextConfig;
|
|
290
|
+
/**
|
|
291
|
+
* The page a layout (or template) reads for: none.
|
|
292
|
+
*
|
|
293
|
+
* A root layout renders around every page on the site, so charging its reads
|
|
294
|
+
* to `/`, the route its file sits at, made the home page look as if it read
|
|
295
|
+
* every Site singleton and nav on the site. `routeOf` returns this for a
|
|
296
|
+
* `layout.*` or `template.*` file, and a read that names it sends NO
|
|
297
|
+
* `Capa-Page` at all, even when the client was built with a `page`.
|
|
298
|
+
*
|
|
299
|
+
* Not sent as a value, because the API would drop it anyway: it is not a
|
|
300
|
+
* `PAGE_ID`, and the API ignores what it cannot store. Staying absent keeps a
|
|
301
|
+
* layout read byte-identical to one from a client that never named a page.
|
|
302
|
+
*/
|
|
303
|
+
export declare const LAYOUT_PAGE = "(layout)";
|
|
290
304
|
type SelectInput = string | ReadonlyArray<unknown>;
|
|
291
305
|
/** Serialize the SDK object form into the canonical `/api/entries` grammar. */
|
|
292
306
|
export declare function serializeSelect(select: SelectInput): string;
|
package/dist/next/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CapaError = void 0;
|
|
3
|
+
exports.LAYOUT_PAGE = exports.CapaError = void 0;
|
|
4
4
|
exports.isCapaError = isCapaError;
|
|
5
5
|
exports.resolveNextConfig = resolveNextConfig;
|
|
6
6
|
exports.serializeSelect = serializeSelect;
|
|
@@ -85,6 +85,20 @@ function resolveNextConfig(config) {
|
|
|
85
85
|
* quietly stops arriving rather than as an error.
|
|
86
86
|
*/
|
|
87
87
|
const PAGE_ID = /^\/[A-Za-z0-9._\-[\]/]{0,199}$/;
|
|
88
|
+
/**
|
|
89
|
+
* The page a layout (or template) reads for: none.
|
|
90
|
+
*
|
|
91
|
+
* A root layout renders around every page on the site, so charging its reads
|
|
92
|
+
* to `/`, the route its file sits at, made the home page look as if it read
|
|
93
|
+
* every Site singleton and nav on the site. `routeOf` returns this for a
|
|
94
|
+
* `layout.*` or `template.*` file, and a read that names it sends NO
|
|
95
|
+
* `Capa-Page` at all, even when the client was built with a `page`.
|
|
96
|
+
*
|
|
97
|
+
* Not sent as a value, because the API would drop it anyway: it is not a
|
|
98
|
+
* `PAGE_ID`, and the API ignores what it cannot store. Staying absent keeps a
|
|
99
|
+
* layout read byte-identical to one from a client that never named a page.
|
|
100
|
+
*/
|
|
101
|
+
exports.LAYOUT_PAGE = "(layout)";
|
|
88
102
|
/**
|
|
89
103
|
* The page for one call: the call's own value, else the client's, else none.
|
|
90
104
|
*
|
|
@@ -97,6 +111,10 @@ function resolvePage(configPage, callPage) {
|
|
|
97
111
|
const value = callPage !== undefined ? callPage : configPage;
|
|
98
112
|
if (value === undefined || value === null)
|
|
99
113
|
return undefined;
|
|
114
|
+
// A layout's read, named on purpose: no header, and the config's page does
|
|
115
|
+
// not stand in for it either.
|
|
116
|
+
if (value === exports.LAYOUT_PAGE)
|
|
117
|
+
return undefined;
|
|
100
118
|
if (typeof value !== "string" || !PAGE_ID.test(value)) {
|
|
101
119
|
throw new TypeError(`@capacms/sdk/next: page must be a path such as "/blog/[slug]" or "/blog/hello". Got ${JSON.stringify(value)}.`);
|
|
102
120
|
}
|
package/dist/next/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { CapaError, createClient, isCapaError, resolveNextConfig, serializeSelect, } from "./client";
|
|
1
|
+
export { CapaError, createClient, isCapaError, LAYOUT_PAGE, resolveNextConfig, serializeSelect, } from "./client";
|
|
2
2
|
export { capaAttrs } from "./attrs";
|
|
3
3
|
export type { CapaAttrs } from "./attrs";
|
|
4
4
|
export type { CallOptions, CapaNextClient, CapaNextConfig, EntriesResource, Entry, Filter, FilterOperator, FilterScalar, FilterValue, GetOptions, ListOptions, Page, PageDetail, PageInfo, PageSummary, PagesListOptions, PagesResource, PreviewClaim, ResponseMeta, Single, } from "./client";
|
package/dist/next/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.capaAttrs = exports.serializeSelect = exports.resolveNextConfig = exports.isCapaError = exports.createClient = exports.CapaError = void 0;
|
|
3
|
+
exports.capaAttrs = exports.serializeSelect = exports.resolveNextConfig = exports.LAYOUT_PAGE = exports.isCapaError = exports.createClient = exports.CapaError = void 0;
|
|
4
4
|
var client_1 = require("./client");
|
|
5
5
|
Object.defineProperty(exports, "CapaError", { enumerable: true, get: function () { return client_1.CapaError; } });
|
|
6
6
|
Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return client_1.createClient; } });
|
|
7
7
|
Object.defineProperty(exports, "isCapaError", { enumerable: true, get: function () { return client_1.isCapaError; } });
|
|
8
|
+
Object.defineProperty(exports, "LAYOUT_PAGE", { enumerable: true, get: function () { return client_1.LAYOUT_PAGE; } });
|
|
8
9
|
Object.defineProperty(exports, "resolveNextConfig", { enumerable: true, get: function () { return client_1.resolveNextConfig; } });
|
|
9
10
|
Object.defineProperty(exports, "serializeSelect", { enumerable: true, get: function () { return client_1.serializeSelect; } });
|
|
10
11
|
var attrs_1 = require("./attrs");
|
package/dist/nextjs/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CapaNextClient, type CapaNextConfig, type PagesResource, type PreviewClaim } from "../next";
|
|
1
|
+
import { LAYOUT_PAGE, type CapaNextClient, type CapaNextConfig, type PagesResource, type PreviewClaim } from "../next";
|
|
2
2
|
export interface CacheOptions {
|
|
3
3
|
tags?: string[];
|
|
4
4
|
revalidate?: number | false;
|
|
@@ -50,4 +50,5 @@ export declare function preview(token: string, client: CapaNextClient): Promise<
|
|
|
50
50
|
* this and never hold the whole client.
|
|
51
51
|
*/
|
|
52
52
|
export declare function pagesFor(client: CapaNextClient): PagesResource;
|
|
53
|
+
export { LAYOUT_PAGE };
|
|
53
54
|
export type { PreviewClaim };
|
package/dist/nextjs/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LAYOUT_PAGE = void 0;
|
|
3
4
|
exports.withCache = withCache;
|
|
4
5
|
exports.tagsFor = tagsFor;
|
|
5
6
|
exports.revalidateFromWebhook = revalidateFromWebhook;
|
|
@@ -8,6 +9,7 @@ exports.routeOf = routeOf;
|
|
|
8
9
|
exports.preview = preview;
|
|
9
10
|
exports.pagesFor = pagesFor;
|
|
10
11
|
const next_1 = require("../next");
|
|
12
|
+
Object.defineProperty(exports, "LAYOUT_PAGE", { enumerable: true, get: function () { return next_1.LAYOUT_PAGE; } });
|
|
11
13
|
/** Add Next.js fetch-cache options without importing `next/*`. */
|
|
12
14
|
function withCache(fetchImpl, options) {
|
|
13
15
|
return (async (input, init = {}) => {
|
|
@@ -64,6 +66,16 @@ async function draftClient(input) {
|
|
|
64
66
|
* src/app/(marketing)/pricing/page.tsx -> /pricing
|
|
65
67
|
* pages/blog/[slug].tsx -> /blog/[slug]
|
|
66
68
|
* app/page.tsx -> /
|
|
69
|
+
* app/layout.tsx, app/blog/template.tsx -> (layout)
|
|
70
|
+
*
|
|
71
|
+
* A LAYOUT IS NOT A PAGE. `layout.*` and `template.*` render around every page
|
|
72
|
+
* below them, and a layout is not told which one: Next hands it no pathname.
|
|
73
|
+
* So its reads cannot be charged to the page being rendered, and charging them
|
|
74
|
+
* to the route its own file sits at is wrong: a root layout's Site singleton
|
|
75
|
+
* and nav would all be recorded as reads of `/`. `routeOf` returns
|
|
76
|
+
* `LAYOUT_PAGE` (`"(layout)"`) for these files instead, and a read that names
|
|
77
|
+
* it sends no `Capa-Page` at all. Pass `routeOf(import.meta.url)` from a layout
|
|
78
|
+
* exactly as from a page and it does the right thing.
|
|
67
79
|
*
|
|
68
80
|
* WHAT IS DROPPED, and why each one:
|
|
69
81
|
*
|
|
@@ -74,8 +86,7 @@ async function draftClient(input) {
|
|
|
74
86
|
* parallel slots `@modal` the same
|
|
75
87
|
* the `(.)` intercept marker an intercepting route at the SAME
|
|
76
88
|
* level renders the segment beside it
|
|
77
|
-
* `page.*`, `
|
|
78
|
-
* `default.*`, `template.*`
|
|
89
|
+
* `page.*`, `route.*`, `default.*` leaf files, not segments
|
|
79
90
|
* `index` in the pages router the folder IS the route
|
|
80
91
|
* the extension never in a URL
|
|
81
92
|
*
|
|
@@ -87,7 +98,9 @@ async function draftClient(input) {
|
|
|
87
98
|
* case the message says to pass the page string yourself.
|
|
88
99
|
*/
|
|
89
100
|
const ROUTER_ROOTS = new Set(["app", "pages"]);
|
|
90
|
-
const LEAF_FILES = new Set(["page", "
|
|
101
|
+
const LEAF_FILES = new Set(["page", "route", "default"]);
|
|
102
|
+
/** Files that render around many routes, so they name none. */
|
|
103
|
+
const LAYOUT_FILES = new Set(["layout", "template"]);
|
|
91
104
|
/** `(..)photo`, `(..)(..)photo`, `(...)photo`: the URL is not here. */
|
|
92
105
|
const OUTER_INTERCEPT = /^(\(\.\.\.\)|(\(\.\.\))+)/;
|
|
93
106
|
function routeOf(file) {
|
|
@@ -131,6 +144,9 @@ function routeOf(file) {
|
|
|
131
144
|
const dot = part.lastIndexOf(".");
|
|
132
145
|
if (dot > 0)
|
|
133
146
|
part = part.slice(0, dot);
|
|
147
|
+
// Only in the app router: `pages/layout.tsx` is a page at `/layout`.
|
|
148
|
+
if (parts[rootIndex] === "app" && LAYOUT_FILES.has(part))
|
|
149
|
+
return next_1.LAYOUT_PAGE;
|
|
134
150
|
if (LEAF_FILES.has(part))
|
|
135
151
|
continue;
|
|
136
152
|
// The pages router: `pages/blog/index.tsx` is `/blog`.
|