@capacms/sdk 1.0.0-next.4 → 1.0.0-next.6
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/CHANGELOG.md +323 -0
- package/README.md +1043 -186
- package/bin/capa-codegen.js +192 -5
- package/bin/capa.js +208 -0
- package/bin/graphql-project.js +142 -0
- package/bin/project-env.js +58 -0
- package/dist/client.d.ts +5 -0
- package/dist/client.js +17 -0
- package/dist/codegen.d.ts +55 -0
- package/dist/codegen.js +320 -39
- package/dist/config.d.ts +5 -1
- package/dist/graphql-codegen.d.ts +117 -0
- package/dist/graphql-codegen.js +705 -0
- package/dist/http.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/dist/next/attrs.d.ts +51 -12
- package/dist/next/attrs.js +74 -20
- package/dist/next/client.d.ts +111 -38
- package/dist/next/client.js +116 -82
- package/dist/next/entry-fields.d.ts +162 -0
- package/dist/next/entry-fields.js +2 -0
- package/dist/next/errors.d.ts +136 -0
- package/dist/next/errors.js +214 -0
- package/dist/next/field-names.d.ts +37 -0
- package/dist/next/field-names.js +145 -0
- package/dist/next/graphql/build.d.ts +27 -0
- package/dist/next/graphql/build.js +98 -0
- package/dist/next/graphql/documents.d.ts +67 -0
- package/dist/next/graphql/documents.js +35 -0
- package/dist/next/graphql/edit-mode.d.ts +16 -0
- package/dist/next/graphql/edit-mode.js +93 -0
- package/dist/next/graphql/filter-values.d.ts +34 -0
- package/dist/next/graphql/filter-values.js +96 -0
- package/dist/next/graphql/introspection.d.ts +89 -0
- package/dist/next/graphql/introspection.js +102 -0
- package/dist/next/graphql/plan.d.ts +115 -0
- package/dist/next/graphql/plan.js +531 -0
- package/dist/next/graphql/request.d.ts +228 -0
- package/dist/next/graphql/request.js +283 -0
- package/dist/next/graphql/rest.d.ts +66 -0
- package/dist/next/graphql/rest.js +502 -0
- package/dist/next/graphql/selection.d.ts +55 -0
- package/dist/next/graphql/selection.js +212 -0
- package/dist/next/graphql/sha256.d.ts +13 -0
- package/dist/next/graphql/sha256.js +86 -0
- package/dist/next/graphql/summary.d.ts +83 -0
- package/dist/next/graphql/summary.js +151 -0
- package/dist/next/graphql/tree-layout.d.ts +36 -0
- package/dist/next/graphql/tree-layout.js +20 -0
- package/dist/next/graphql/tree.d.ts +171 -0
- package/dist/next/graphql/tree.js +249 -0
- package/dist/next/graphql/typed.d.ts +261 -0
- package/dist/next/graphql/typed.js +146 -0
- package/dist/next/index.d.ts +28 -5
- package/dist/next/index.js +25 -1
- package/dist/next/inflate.d.ts +25 -7
- package/dist/next/inflate.js +46 -32
- package/dist/next/key-family.d.ts +34 -0
- package/dist/next/key-family.js +74 -0
- package/dist/next/select-types.d.ts +44 -8
- package/dist/next/system-keys.d.ts +27 -0
- package/dist/next/system-keys.js +42 -0
- package/dist/nextjs/index.d.ts +165 -12
- package/dist/nextjs/index.js +247 -23
- package/dist/nextjs/overlay.d.ts +5 -0
- package/dist/nextjs/overlay.js +35 -0
- package/package.json +35 -13
package/dist/nextjs/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_API_VERSION = exports.CAPA_ENV = exports.EDIT_CACHE_CONTROL = exports.DRAFT_COOKIE = exports.EDIT_HEADER = exports.EDIT_PARAM = exports.LAYOUT_PAGE = void 0;
|
|
3
|
+
exports.DEFAULT_API_VERSION = exports.CAPA_ENV_ALIASES = exports.CAPA_ENV = exports.EDIT_CACHE_CONTROL = exports.DRAFT_COOKIE = exports.EDIT_HEADER = exports.EDIT_PARAM = exports.LAYOUT_PAGE = exports.gql = exports.MEDIA_TAG = exports.GRAPHQL_TAG = void 0;
|
|
4
4
|
exports.withCache = withCache;
|
|
5
|
+
exports.modelTag = modelTag;
|
|
5
6
|
exports.tagsFor = tagsFor;
|
|
6
7
|
exports.revalidateFromWebhook = revalidateFromWebhook;
|
|
7
8
|
exports.draftClient = draftClient;
|
|
@@ -12,12 +13,17 @@ exports.editMode = editMode;
|
|
|
12
13
|
exports.resolveEditRequest = resolveEditRequest;
|
|
13
14
|
exports.getPublishedClient = getPublishedClient;
|
|
14
15
|
exports.getCapaClient = getCapaClient;
|
|
16
|
+
exports.graphql = graphql;
|
|
15
17
|
exports.safeSitePath = safeSitePath;
|
|
16
18
|
exports.createPreviewRoute = createPreviewRoute;
|
|
17
19
|
exports.exitPreviewRoute = exitPreviewRoute;
|
|
18
20
|
exports.capaMiddleware = capaMiddleware;
|
|
19
21
|
const next_1 = require("../next");
|
|
22
|
+
Object.defineProperty(exports, "gql", { enumerable: true, get: function () { return next_1.gql; } });
|
|
20
23
|
Object.defineProperty(exports, "LAYOUT_PAGE", { enumerable: true, get: function () { return next_1.LAYOUT_PAGE; } });
|
|
24
|
+
const client_1 = require("../next/client");
|
|
25
|
+
const sha256_1 = require("../next/graphql/sha256");
|
|
26
|
+
const key_family_1 = require("../next/key-family");
|
|
21
27
|
/** Add Next.js fetch-cache options without importing `next/*`. */
|
|
22
28
|
function withCache(fetchImpl, options) {
|
|
23
29
|
return (async (input, init = {}) => {
|
|
@@ -31,6 +37,38 @@ function withCache(fetchImpl, options) {
|
|
|
31
37
|
return fetchImpl(input, { ...init, next });
|
|
32
38
|
});
|
|
33
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* The Next.js cache tag for every read of a model, by its namespace. A GraphQL
|
|
42
|
+
* query names its models by namespace (`articles`), not by id, so this is the
|
|
43
|
+
* tag a GraphQL read is cached under, and `revalidateFromWebhook` revalidates
|
|
44
|
+
* it when an entry of that model changes.
|
|
45
|
+
*/
|
|
46
|
+
function modelTag(namespace) {
|
|
47
|
+
return `capa:model:${namespace}`;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The tag `graphql()` gives a read that names no `tags`, and that
|
|
51
|
+
* `revalidateFromWebhook` revalidates on every content change: such a page is
|
|
52
|
+
* never stale after a publish, at the price of refreshing on any publish.
|
|
53
|
+
* Name the models it reads with `tagsFor({ namespace })` to refresh it only
|
|
54
|
+
* when one of those changes.
|
|
55
|
+
*/
|
|
56
|
+
exports.GRAPHQL_TAG = "capa:graphql";
|
|
57
|
+
/**
|
|
58
|
+
* The tag `tagsFor({ namespace })` adds beside its model tags, and that
|
|
59
|
+
* `revalidateFromWebhook` revalidates on a media event: a GraphQL read shows
|
|
60
|
+
* a file's URL and alt text whichever models it names, so editing a file in
|
|
61
|
+
* the media library refreshes it.
|
|
62
|
+
*/
|
|
63
|
+
exports.MEDIA_TAG = "capa:media";
|
|
64
|
+
/**
|
|
65
|
+
* Next.js cache tags for a read. `model`, `entry`, `key` and `tenant` are the
|
|
66
|
+
* API's surrogate keys (`m:`, `e:`, `k:`, `t:`), by id; `namespace` is one
|
|
67
|
+
* `capa:model:<namespace>` tag per model a GraphQL query reads, which
|
|
68
|
+
* `capa-codegen --graphql` lists as `<Name>Models`, and `MEDIA_TAG`, since
|
|
69
|
+
* the query may show a file from the media library. Each pairs with
|
|
70
|
+
* `revalidateFromWebhook`.
|
|
71
|
+
*/
|
|
34
72
|
function tagsFor(input) {
|
|
35
73
|
const tags = [];
|
|
36
74
|
if (input.model)
|
|
@@ -41,9 +79,26 @@ function tagsFor(input) {
|
|
|
41
79
|
tags.push(`k:${input.key}`);
|
|
42
80
|
if (input.tenant)
|
|
43
81
|
tags.push(`t:${input.tenant}`);
|
|
82
|
+
const namespaces = typeof input.namespace === "string" ? [input.namespace] : (input.namespace ?? []);
|
|
83
|
+
for (const namespace of namespaces)
|
|
84
|
+
if (namespace)
|
|
85
|
+
tags.push(modelTag(namespace));
|
|
86
|
+
if (namespaces.some(Boolean))
|
|
87
|
+
tags.push(exports.MEDIA_TAG);
|
|
44
88
|
return tags;
|
|
45
89
|
}
|
|
46
|
-
/**
|
|
90
|
+
/**
|
|
91
|
+
* Revalidate every tag a webhook's entry and model can be cached under: the
|
|
92
|
+
* entry (`e:`), the model by id (`m:`) and by namespace (`capa:model:`, the
|
|
93
|
+
* tag a GraphQL read uses). The namespace is `data.modelNamespace` on
|
|
94
|
+
* `instance.published`, `instance.unpublished` and `model.published`, and
|
|
95
|
+
* `data.namespace` on the other events (docs/WEBHOOKS.md). Any of those, and
|
|
96
|
+
* a `media.` event, also revalidates `GRAPHQL_TAG`, the tag of a `graphql()`
|
|
97
|
+
* read that named no tags. A `media.` event (a file's alt text, name or
|
|
98
|
+
* visibility changed, or the file went) revalidates the file's own key
|
|
99
|
+
* (`f:<fileId>`, as REST's `Surrogate-Key` names it) and `MEDIA_TAG`, which
|
|
100
|
+
* every read tagged by namespace carries, since it may show that file.
|
|
101
|
+
*/
|
|
47
102
|
async function revalidateFromWebhook(input) {
|
|
48
103
|
const data = input.payload?.data ?? input.payload;
|
|
49
104
|
const tags = [];
|
|
@@ -52,14 +107,34 @@ async function revalidateFromWebhook(input) {
|
|
|
52
107
|
tags.push(`e:${entryId}`);
|
|
53
108
|
if (typeof data?.modelId === "string" && data.modelId)
|
|
54
109
|
tags.push(`m:${data.modelId}`);
|
|
110
|
+
const namespace = data?.modelNamespace ?? data?.namespace;
|
|
111
|
+
if (typeof namespace === "string" && namespace)
|
|
112
|
+
tags.push(modelTag(namespace));
|
|
113
|
+
const media = typeof input.payload?.type === "string" && input.payload.type.startsWith("media.");
|
|
114
|
+
if (media) {
|
|
115
|
+
if (typeof data?.fileId === "string" && data.fileId)
|
|
116
|
+
tags.push(`f:${data.fileId}`);
|
|
117
|
+
tags.push(exports.MEDIA_TAG);
|
|
118
|
+
}
|
|
119
|
+
if (tags.length > 0 || media)
|
|
120
|
+
tags.push(exports.GRAPHQL_TAG);
|
|
55
121
|
const unique = [...new Set(tags)];
|
|
56
122
|
for (const tag of unique)
|
|
57
123
|
await input.revalidateTag(tag);
|
|
58
124
|
return unique;
|
|
59
125
|
}
|
|
60
|
-
/**
|
|
126
|
+
/**
|
|
127
|
+
* Select a client using server-only draft state supplied by the caller. Pass
|
|
128
|
+
* codegen's `CapaQuery` to type the builder, as with `createClient`:
|
|
129
|
+
* `draftClient<CapaQuery>({ ... })`. `production` may hold the legacy key a
|
|
130
|
+
* site already has; `draft` needs a `cap_` key, and a legacy one throws a
|
|
131
|
+
* `TypeError` when draft mode selects it.
|
|
132
|
+
*/
|
|
61
133
|
async function draftClient(input) {
|
|
62
|
-
|
|
134
|
+
if (!(await input.isDraft()))
|
|
135
|
+
return (0, next_1.createClient)(input.production);
|
|
136
|
+
(0, key_family_1.requireDraftKey)(input.draft?.apiKey, "the draft config");
|
|
137
|
+
return (0, next_1.createClient)(input.draft);
|
|
63
138
|
}
|
|
64
139
|
// ------------------------------------------------------------------ pages ---
|
|
65
140
|
/**
|
|
@@ -233,7 +308,11 @@ exports.EDIT_CACHE_CONTROL = "private, no-store";
|
|
|
233
308
|
*/
|
|
234
309
|
async function editMode(input) {
|
|
235
310
|
const [draft, headers] = await Promise.all([input.draftMode(), input.headers()]);
|
|
236
|
-
return draft.isEnabled === true || headers
|
|
311
|
+
return draft.isEnabled === true || verifiedEdit(headers);
|
|
312
|
+
}
|
|
313
|
+
/** Whether `resolveEditRequest` verified a `capa-edit` token for this request. */
|
|
314
|
+
function verifiedEdit(headers) {
|
|
315
|
+
return headers.get(exports.EDIT_HEADER) === "1";
|
|
237
316
|
}
|
|
238
317
|
/**
|
|
239
318
|
* The middleware half of edit mode.
|
|
@@ -271,51 +350,196 @@ async function resolveEditRequest(request, client) {
|
|
|
271
350
|
return { edit, verified, headers, cacheControl: edit ? exports.EDIT_CACHE_CONTROL : null };
|
|
272
351
|
}
|
|
273
352
|
// ------------------------------------------------- five-minute integration ---
|
|
274
|
-
/**
|
|
353
|
+
/**
|
|
354
|
+
* Where the env-driven helpers read their settings (M6): the one pair of
|
|
355
|
+
* names the whole product uses (the MCP server, `capa-codegen`, `capa
|
|
356
|
+
* persist`, every curl example in the API docs).
|
|
357
|
+
*/
|
|
275
358
|
exports.CAPA_ENV = {
|
|
276
359
|
baseUrl: "CAPA_API_URL",
|
|
277
360
|
apiKey: "CAPA_KEY",
|
|
278
361
|
draftKey: "CAPA_DRAFT_KEY",
|
|
279
362
|
version: "CAPA_API_VERSION",
|
|
280
363
|
};
|
|
364
|
+
/** Older names that still work, read only when the name above is unset. */
|
|
365
|
+
exports.CAPA_ENV_ALIASES = {
|
|
366
|
+
CAPA_API_URL: "CAPA_BASE_URL",
|
|
367
|
+
CAPA_KEY: "CAPA_API_KEY",
|
|
368
|
+
};
|
|
281
369
|
exports.DEFAULT_API_VERSION = "2026-10-01";
|
|
282
|
-
function
|
|
370
|
+
function readOne(name) {
|
|
283
371
|
const env = globalThis.process?.env;
|
|
284
372
|
const value = env?.[name];
|
|
285
373
|
return value === undefined || value === "" ? undefined : value;
|
|
286
374
|
}
|
|
375
|
+
function readEnv(name) {
|
|
376
|
+
const alias = exports.CAPA_ENV_ALIASES[name];
|
|
377
|
+
return readOne(name) ?? (alias ? readOne(alias) : undefined);
|
|
378
|
+
}
|
|
287
379
|
function requireEnv(name) {
|
|
288
380
|
const value = readEnv(name);
|
|
289
|
-
if (
|
|
290
|
-
|
|
291
|
-
|
|
381
|
+
if (value)
|
|
382
|
+
return value;
|
|
383
|
+
const alias = exports.CAPA_ENV_ALIASES[name];
|
|
384
|
+
throw new Error(`@capacms/sdk/nextjs: ${name} is not set${alias ? ` (${alias} also works)` : ""}.`);
|
|
292
385
|
}
|
|
293
|
-
/**
|
|
386
|
+
/**
|
|
387
|
+
* A client config from env, `key` naming the env var for the key. A setting
|
|
388
|
+
* `config` gives is used as given and its env var is never read, so a full
|
|
389
|
+
* `config` needs no env at all.
|
|
390
|
+
*/
|
|
391
|
+
function envConfig(config, key) {
|
|
392
|
+
return {
|
|
393
|
+
...config,
|
|
394
|
+
baseUrl: config?.baseUrl ?? requireEnv(exports.CAPA_ENV.baseUrl),
|
|
395
|
+
apiKey: config?.apiKey ?? requireEnv(key),
|
|
396
|
+
version: config?.version ?? readEnv(exports.CAPA_ENV.version) ?? exports.DEFAULT_API_VERSION,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
/** The published or the draft config from env; the draft key must be a `cap_` key. */
|
|
400
|
+
function modeConfig(config, draft) {
|
|
401
|
+
if (!draft)
|
|
402
|
+
return envConfig(config, exports.CAPA_ENV.apiKey);
|
|
403
|
+
const settings = envConfig(config, exports.CAPA_ENV.draftKey);
|
|
404
|
+
(0, key_family_1.requireDraftKey)(settings.apiKey, config?.apiKey !== undefined ? "config.apiKey" : exports.CAPA_ENV.draftKey);
|
|
405
|
+
return settings;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* The published-key client from env: what verifying a token needs. `overrides`
|
|
409
|
+
* win over env, and pass codegen's `CapaQuery` to type the builder:
|
|
410
|
+
* `getPublishedClient<CapaQuery>()`.
|
|
411
|
+
*/
|
|
294
412
|
function getPublishedClient(overrides = {}) {
|
|
295
|
-
return (0, next_1.createClient)(
|
|
296
|
-
baseUrl: requireEnv(exports.CAPA_ENV.baseUrl),
|
|
297
|
-
apiKey: requireEnv(exports.CAPA_ENV.apiKey),
|
|
298
|
-
version: readEnv(exports.CAPA_ENV.version) ?? exports.DEFAULT_API_VERSION,
|
|
299
|
-
...overrides,
|
|
300
|
-
});
|
|
413
|
+
return (0, next_1.createClient)(envConfig(overrides, exports.CAPA_ENV.apiKey));
|
|
301
414
|
}
|
|
302
415
|
/**
|
|
303
416
|
* The client for this request, from env: the draft key under draft mode,
|
|
304
417
|
* otherwise the published key, and `editMode` worked out for you.
|
|
305
418
|
*
|
|
306
419
|
* import { draftMode, headers } from "next/headers";
|
|
307
|
-
* const capa = await getCapaClient({ draftMode, headers });
|
|
420
|
+
* const capa = await getCapaClient<CapaQuery>({ draftMode, headers });
|
|
421
|
+
* const { data } = await capa.graphql.query(selection, { tags: tagsFor({ namespace: "articles" }) });
|
|
422
|
+
*
|
|
423
|
+
* `CapaQuery` (from `capa-codegen --graphql`) types the builder, as with
|
|
424
|
+
* `createClient`; leave it out for an untyped client. `config` wins over env.
|
|
425
|
+
*
|
|
426
|
+
* Its GraphQL reads, a document or the builder, are kept in Next's data cache
|
|
427
|
+
* exactly as `graphql()` keeps them, each under the `tags` and `revalidate`
|
|
428
|
+
* it is called with: a published read with no errors, never a draft or an
|
|
429
|
+
* edit-mode page. Its REST reads are sent as `createClient` sends them.
|
|
308
430
|
*/
|
|
309
431
|
async function getCapaClient(input) {
|
|
310
432
|
const draft = (await input.draftMode()).isEnabled === true;
|
|
311
433
|
const edit = await editMode({ draftMode: input.draftMode, headers: input.headers });
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
434
|
+
const settings = modeConfig(input.config, draft);
|
|
435
|
+
const client = (0, next_1.createClient)({ editMode: edit, ...settings });
|
|
436
|
+
const read = { draft, edit, settings, given: input.unstable_cache };
|
|
437
|
+
const graphql = (0, client_1.graphqlClient)((document, variables, options = {}) => {
|
|
438
|
+
const { tags, revalidate, ...call } = options;
|
|
439
|
+
return readInNext(read, document, variables, call, { tags, revalidate });
|
|
440
|
+
});
|
|
441
|
+
return { ...client, graphql };
|
|
442
|
+
}
|
|
443
|
+
let loadedUnstableCache;
|
|
444
|
+
/**
|
|
445
|
+
* Next's own `unstable_cache`, loaded on first use, or null where `next/cache`
|
|
446
|
+
* cannot be loaded (Next not installed). The package never imports `next/*`
|
|
447
|
+
* at the top, so a Node script can import this file without Next.
|
|
448
|
+
*/
|
|
449
|
+
function nextUnstableCache() {
|
|
450
|
+
if (loadedUnstableCache === undefined) {
|
|
451
|
+
try {
|
|
452
|
+
loadedUnstableCache = require("next/cache").unstable_cache ?? null;
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
loadedUnstableCache = null;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return loadedUnstableCache;
|
|
459
|
+
}
|
|
460
|
+
/** Thrown inside `unstable_cache` so that a result with errors is never stored; caught at once. */
|
|
461
|
+
class NotCached extends Error {
|
|
462
|
+
result;
|
|
463
|
+
constructor(result) {
|
|
464
|
+
super(`@capacms/sdk/nextjs: this GraphQL read answered with errors, so it was not cached: ${result.errors[0]?.message ?? "unknown error"}`);
|
|
465
|
+
this.result = result;
|
|
466
|
+
this.name = "NotCached";
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* What a cached read is keyed by: everything that changes its answer. The key
|
|
471
|
+
* is hashed, so the API key never reaches the cache's index.
|
|
472
|
+
*/
|
|
473
|
+
async function cacheKeyOf(settings, document, variables, call) {
|
|
474
|
+
return [
|
|
475
|
+
"@capacms/sdk/nextjs graphql",
|
|
476
|
+
settings.baseUrl,
|
|
477
|
+
await (0, sha256_1.sha256Hex)(settings.apiKey),
|
|
478
|
+
settings.version ?? "",
|
|
479
|
+
String(settings.contract ?? ""),
|
|
480
|
+
settings.schemaChecksum ?? "",
|
|
481
|
+
document,
|
|
482
|
+
JSON.stringify(variables ?? null),
|
|
483
|
+
call.operationName ?? "",
|
|
484
|
+
call.persisted ? "persisted" : "",
|
|
485
|
+
call.method ?? "",
|
|
486
|
+
];
|
|
487
|
+
}
|
|
488
|
+
async function graphql(document, variables, options = {}) {
|
|
489
|
+
const { tags, revalidate, draft: draftOption, draftMode, headers, config, unstable_cache: given, ...call } = options;
|
|
490
|
+
const draft = draftOption ?? (draftMode ? (await draftMode()).isEnabled === true : false);
|
|
491
|
+
const edit = draft || (headers ? verifiedEdit(await headers()) : false);
|
|
492
|
+
const read = { draft, edit, settings: modeConfig(config, draft), given };
|
|
493
|
+
return readInNext(read, document, variables, call, { tags, revalidate });
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* One GraphQL read in Next, for `graphql()` and `getCapaClient`. Next's data
|
|
497
|
+
* cache holds only a published read with no errors, and the fetch under it is
|
|
498
|
+
* never cached. A draft, an edit-mode read (its entries carry marks a cached
|
|
499
|
+
* copy would lose) and `revalidate: 0` are not cached.
|
|
500
|
+
*/
|
|
501
|
+
async function readInNext(read, document, variables, call, { tags, revalidate }) {
|
|
502
|
+
const { draft, edit, settings, given } = read;
|
|
503
|
+
const baseFetch = settings.fetch ?? globalThis.fetch;
|
|
504
|
+
const cache = given ?? nextUnstableCache();
|
|
505
|
+
if (cache && !draft) {
|
|
506
|
+
if (edit || revalidate === 0) {
|
|
507
|
+
return (0, next_1.createClient)({ editMode: edit, ...settings, fetch: withCache(baseFetch, { revalidate: 0 }) }).graphql(document, variables, call);
|
|
508
|
+
}
|
|
509
|
+
const client = (0, next_1.createClient)({ editMode: false, ...settings, fetch: baseFetch });
|
|
510
|
+
let sent = false;
|
|
511
|
+
const send = async () => {
|
|
512
|
+
sent = true;
|
|
513
|
+
const result = await client.graphql(document, variables, call);
|
|
514
|
+
if (result.errors.length > 0)
|
|
515
|
+
throw new NotCached(result);
|
|
516
|
+
return result;
|
|
517
|
+
};
|
|
518
|
+
const keyParts = await cacheKeyOf(settings, document, variables, call);
|
|
519
|
+
const cacheOptions = { tags: tags ?? [exports.GRAPHQL_TAG] };
|
|
520
|
+
if (revalidate !== undefined)
|
|
521
|
+
cacheOptions.revalidate = revalidate;
|
|
522
|
+
try {
|
|
523
|
+
return await cache(send, keyParts, cacheOptions)();
|
|
524
|
+
}
|
|
525
|
+
catch (error) {
|
|
526
|
+
if (error instanceof NotCached)
|
|
527
|
+
return error.result;
|
|
528
|
+
// Next's own `unstable_cache` throws before it reads anything outside a
|
|
529
|
+
// Next request (a script, a test, a build step with no cache): the read
|
|
530
|
+
// is then sent as below. One passed in throws as it did.
|
|
531
|
+
if (given || sent)
|
|
532
|
+
throw error;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
const client = (0, next_1.createClient)({
|
|
316
536
|
editMode: edit,
|
|
317
|
-
...
|
|
537
|
+
...settings,
|
|
538
|
+
fetch: draft
|
|
539
|
+
? withCache(baseFetch, { revalidate: 0 })
|
|
540
|
+
: withCache(baseFetch, { tags: tags ?? [exports.GRAPHQL_TAG], revalidate }),
|
|
318
541
|
});
|
|
542
|
+
return client.graphql(document, variables, call);
|
|
319
543
|
}
|
|
320
544
|
/** Only a path on this site: never `//elsewhere.example` or a full URL. */
|
|
321
545
|
function safeSitePath(value) {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.CapaOverlay = CapaOverlay;
|
|
5
|
+
/**
|
|
6
|
+
* `<CapaOverlay />`: Capa's live preview overlay as one Next.js client
|
|
7
|
+
* component (M6).
|
|
8
|
+
*
|
|
9
|
+
* // app/layout.tsx (a server component)
|
|
10
|
+
* import { CapaOverlay } from "@capacms/sdk/nextjs/overlay";
|
|
11
|
+
* {edit ? <CapaOverlay adminOrigins={["https://app.capacms.com"]} /> : null}
|
|
12
|
+
*
|
|
13
|
+
* Render it only in edit mode (`editMode()` from `@capacms/sdk/nextjs`), so a
|
|
14
|
+
* visitor never downloads it. Inside the Capa editor it outlines the focused
|
|
15
|
+
* field, reports clicks back, and on a save re-renders the page with
|
|
16
|
+
* `router.refresh()`, keeping the scroll position. Outside a Capa frame it does
|
|
17
|
+
* nothing at all.
|
|
18
|
+
*
|
|
19
|
+
* Its own entry point, apart from `@capacms/sdk/nextjs`, because it imports
|
|
20
|
+
* `react` and `next/navigation` and is a client module: the server helpers must
|
|
21
|
+
* stay free of both.
|
|
22
|
+
*/
|
|
23
|
+
const react_1 = require("react");
|
|
24
|
+
const navigation_1 = require("next/navigation");
|
|
25
|
+
const overlay_1 = require("../overlay");
|
|
26
|
+
function CapaOverlay({ adminOrigins }) {
|
|
27
|
+
const router = (0, navigation_1.useRouter)();
|
|
28
|
+
// A string, so a new array with the same origins does not restart it.
|
|
29
|
+
const origins = adminOrigins.join(",");
|
|
30
|
+
(0, react_1.useEffect)(() => (0, overlay_1.startOverlay)({
|
|
31
|
+
adminOrigins: origins.split(",").filter(Boolean),
|
|
32
|
+
onRefresh: () => router.refresh(),
|
|
33
|
+
}), [origins, router]);
|
|
34
|
+
return null;
|
|
35
|
+
}
|
package/package.json
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capacms/sdk",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.6",
|
|
4
|
+
"description": "The TypeScript SDK for Capa's content API: REST and GraphQL reads typed from your models, Next.js caching and live preview, and codegen.",
|
|
4
5
|
"license": "UNLICENSED",
|
|
5
|
-
"
|
|
6
|
-
"type": "git",
|
|
7
|
-
"url": "git+https://github.com/ZVN-DEV/capa-cms-future.git",
|
|
8
|
-
"directory": "packages/sdk"
|
|
9
|
-
},
|
|
10
|
-
"homepage": "https://github.com/ZVN-DEV/capa-cms-future/tree/main/packages/sdk#readme",
|
|
11
|
-
"bugs": {
|
|
12
|
-
"url": "https://github.com/ZVN-DEV/capa-cms-future/issues"
|
|
13
|
-
},
|
|
6
|
+
"homepage": "https://docs.capacms.com/api",
|
|
14
7
|
"engines": {
|
|
15
8
|
"node": ">=18"
|
|
16
9
|
},
|
|
@@ -18,7 +11,8 @@
|
|
|
18
11
|
"files": [
|
|
19
12
|
"dist",
|
|
20
13
|
"bin",
|
|
21
|
-
"README.md"
|
|
14
|
+
"README.md",
|
|
15
|
+
"CHANGELOG.md"
|
|
22
16
|
],
|
|
23
17
|
"publishConfig": {
|
|
24
18
|
"access": "public",
|
|
@@ -43,7 +37,11 @@
|
|
|
43
37
|
"types": "./dist/overlay/index.d.ts",
|
|
44
38
|
"default": "./dist/overlay/index.js"
|
|
45
39
|
},
|
|
46
|
-
"./package.json": "./package.json"
|
|
40
|
+
"./package.json": "./package.json",
|
|
41
|
+
"./nextjs/overlay": {
|
|
42
|
+
"types": "./dist/nextjs/overlay.d.ts",
|
|
43
|
+
"default": "./dist/nextjs/overlay.js"
|
|
44
|
+
}
|
|
47
45
|
},
|
|
48
46
|
"typesVersions": {
|
|
49
47
|
"*": {
|
|
@@ -56,21 +54,45 @@
|
|
|
56
54
|
"overlay": [
|
|
57
55
|
"dist/overlay/index.d.ts"
|
|
58
56
|
],
|
|
57
|
+
"nextjs/overlay": [
|
|
58
|
+
"dist/nextjs/overlay.d.ts"
|
|
59
|
+
],
|
|
59
60
|
"*": [
|
|
60
61
|
"dist/index.d.ts"
|
|
61
62
|
]
|
|
62
63
|
}
|
|
63
64
|
},
|
|
64
65
|
"bin": {
|
|
66
|
+
"capa": "bin/capa.js",
|
|
65
67
|
"capa-codegen": "bin/capa-codegen.js"
|
|
66
68
|
},
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"graphql": "^16.9.0",
|
|
71
|
+
"next": ">=14",
|
|
72
|
+
"react": ">=18"
|
|
73
|
+
},
|
|
74
|
+
"peerDependenciesMeta": {
|
|
75
|
+
"graphql": {
|
|
76
|
+
"optional": true
|
|
77
|
+
},
|
|
78
|
+
"next": {
|
|
79
|
+
"optional": true
|
|
80
|
+
},
|
|
81
|
+
"react": {
|
|
82
|
+
"optional": true
|
|
83
|
+
}
|
|
84
|
+
},
|
|
67
85
|
"devDependencies": {
|
|
86
|
+
"graphql": "^16.9.0",
|
|
68
87
|
"typescript": "^5.5.0",
|
|
88
|
+
"@types/react": "19.0.1",
|
|
89
|
+
"next": "15.5.9",
|
|
90
|
+
"react": "19.2.8",
|
|
69
91
|
"@capa/shared": "0.1.0"
|
|
70
92
|
},
|
|
71
93
|
"scripts": {
|
|
72
94
|
"build": "tsc -p tsconfig.json",
|
|
73
95
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
74
|
-
"test": "tsc -p tsconfig.json && node --test test/codegen.test.js test/client.test.js test/next-client.test.js test/nextjs.test.js test/webhooks.test.js test/attrs.test.js test/overlay.test.js test/inflate.test.js && tsc -p test/types/tsconfig.consumer.json --noEmit"
|
|
96
|
+
"test": "tsc -p tsconfig.json && node --test test/comments.test.js test/codegen.test.js test/client.test.js test/next-client.test.js test/nextjs.test.js test/webhooks.test.js test/attrs.test.js test/overlay.test.js test/inflate.test.js test/field-names.test.js test/next-graphql.test.js test/graphql-codegen.test.js test/graphql-contract.test.js test/readme-snippets.test.js test/nextjs-app.test.js test/package-json.test.js test/changelog.test.js test/published-docs.test.js test/builder-messages.test.js && tsc -p test/types/tsconfig.consumer.json --noEmit && tsc -p test/types/tsconfig.nonstrict.json --noEmit"
|
|
75
97
|
}
|
|
76
98
|
}
|