@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.
- package/CHANGELOG.md +345 -0
- package/README.md +1069 -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 -36
- package/dist/config.js +47 -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 +112 -38
- package/dist/next/client.js +131 -83
- 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 +174 -12
- package/dist/nextjs/index.js +270 -23
- package/dist/nextjs/overlay.d.ts +5 -0
- package/dist/nextjs/overlay.js +35 -0
- package/package.json +31 -13
package/dist/http.js
CHANGED
|
@@ -10,7 +10,7 @@ class CapaError extends Error {
|
|
|
10
10
|
status;
|
|
11
11
|
path;
|
|
12
12
|
constructor(status, path, body) {
|
|
13
|
-
super(`Capa API ${status} on ${path}${body ?
|
|
13
|
+
super(`Capa API ${status} on ${path}${body ? `: ${body.slice(0, 200)}` : ""}`);
|
|
14
14
|
this.name = "CapaError";
|
|
15
15
|
this.status = status;
|
|
16
16
|
this.path = path;
|
package/dist/index.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export { WEBHOOKS_NEED_ACCESS_TOKEN } from "./webhooks";
|
|
|
6
6
|
export type { CreateWebhookEndpointInput, ListWebhookDeliveriesOptions, ResumeWebhookEndpointOptions, ResumeWebhookEndpointResult, UpdateWebhookEndpointInput, WebhookDeliveriesPage, WebhookDeliveriesResource, WebhookDelivery, WebhookDeliveryDetail, WebhookDeliveryStatus, WebhookDisabledReason, WebhookEndpoint, WebhookEndpointDetail, WebhookEndpointsResource, WebhookEndpointWithSecret, WebhookEventCatalogueEntry, WebhookEventGroup, WebhookPagination, WebhooksResource, } from "./webhooks";
|
|
7
7
|
export { DEFAULT_WEBHOOK_TOLERANCE_SECONDS, parseWebhookSignatureHeader, signWebhookPayload, verifyWebhookSignature, WEBHOOK_SIGNATURE_HEADER, } from "./webhook-signature";
|
|
8
8
|
export type { ParsedWebhookSignature, VerifyWebhookSignatureInput, } from "./webhook-signature";
|
|
9
|
-
export { generate, normalizeTypes, readStampedChecksum, typeNames } from "./codegen";
|
|
10
|
-
export type { CodegenResult } from "./codegen";
|
|
9
|
+
export { generate, normalizeTypes, readStampedChecksum, restTypesFromIntrospection, typeNames } from "./codegen";
|
|
10
|
+
export type { CodegenResult, RestTypesResult } from "./codegen";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.typeNames = exports.readStampedChecksum = exports.normalizeTypes = exports.generate = exports.WEBHOOK_SIGNATURE_HEADER = exports.verifyWebhookSignature = exports.signWebhookPayload = exports.parseWebhookSignatureHeader = exports.DEFAULT_WEBHOOK_TOLERANCE_SECONDS = exports.WEBHOOKS_NEED_ACCESS_TOKEN = exports.CapaError = exports.instanceIdOf = exports.createClient = void 0;
|
|
3
|
+
exports.typeNames = exports.restTypesFromIntrospection = exports.readStampedChecksum = exports.normalizeTypes = exports.generate = exports.WEBHOOK_SIGNATURE_HEADER = exports.verifyWebhookSignature = exports.signWebhookPayload = exports.parseWebhookSignatureHeader = exports.DEFAULT_WEBHOOK_TOLERANCE_SECONDS = exports.WEBHOOKS_NEED_ACCESS_TOKEN = exports.CapaError = exports.instanceIdOf = exports.createClient = void 0;
|
|
4
4
|
var client_1 = require("./client");
|
|
5
5
|
Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return client_1.createClient; } });
|
|
6
6
|
Object.defineProperty(exports, "instanceIdOf", { enumerable: true, get: function () { return client_1.instanceIdOf; } });
|
|
@@ -18,4 +18,5 @@ var codegen_1 = require("./codegen");
|
|
|
18
18
|
Object.defineProperty(exports, "generate", { enumerable: true, get: function () { return codegen_1.generate; } });
|
|
19
19
|
Object.defineProperty(exports, "normalizeTypes", { enumerable: true, get: function () { return codegen_1.normalizeTypes; } });
|
|
20
20
|
Object.defineProperty(exports, "readStampedChecksum", { enumerable: true, get: function () { return codegen_1.readStampedChecksum; } });
|
|
21
|
+
Object.defineProperty(exports, "restTypesFromIntrospection", { enumerable: true, get: function () { return codegen_1.restTypesFromIntrospection; } });
|
|
21
22
|
Object.defineProperty(exports, "typeNames", { enumerable: true, get: function () { return codegen_1.typeNames; } });
|
package/dist/next/attrs.d.ts
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
* The attributes that make a rendered field clickable in Capa's live preview.
|
|
3
3
|
*
|
|
4
4
|
* <h1 {...capaAttrs(entry, "title")}>{entry.fields.title}</h1>
|
|
5
|
+
* <h1 {...capaAttrs(node, "title")}>{node.title}</h1> // a GraphQL node
|
|
5
6
|
*
|
|
6
|
-
* `field` is the field's namespace, which is the key it has
|
|
7
|
-
* the API renders every field under its namespace, and the
|
|
8
|
-
* each field row with that same namespace, so one string
|
|
9
|
-
* both sides of the preview frame.
|
|
7
|
+
* For a REST entry, `field` is the field's namespace, which is the key it has
|
|
8
|
+
* in `entry.fields`: the API renders every field under its namespace, and the
|
|
9
|
+
* Capa editor tags each field row with that same namespace, so one string
|
|
10
|
+
* names the field on both sides of the preview frame.
|
|
11
|
+
*
|
|
12
|
+
* For a GraphQL node (an object that selected `id` and `model`), `field` is
|
|
13
|
+
* the field as selected. A field GraphQL renamed (`hero_image` for
|
|
14
|
+
* `hero-image`, `status_field` for `status`) is tagged by its namespace: a
|
|
15
|
+
* client in edit mode reads the key's schema to know which those are.
|
|
10
16
|
*
|
|
11
17
|
* EDIT MODE DECIDES, NOT THE CALLER. An entry read by a client created with
|
|
12
18
|
* `editMode: true` carries a hidden edit mark (`markEditEntries`), and
|
|
@@ -38,12 +44,45 @@ export declare function isEditEntry(entry: unknown): boolean;
|
|
|
38
44
|
* never the same object twice. Returns `value` for chaining.
|
|
39
45
|
*/
|
|
40
46
|
export declare function markEditEntries<T>(value: T): T;
|
|
41
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Mark every entry inside a GraphQL result's `data`: each object that
|
|
49
|
+
* selected `id` and `model`, related entries included. `renamed(model)` gives
|
|
50
|
+
* that model's fields whose GraphQL name is not their namespace, by GraphQL
|
|
51
|
+
* name, so `capaAttrs` tags those by namespace. Returns `data`.
|
|
52
|
+
*/
|
|
53
|
+
export declare function markGraphQLEntries<T>(data: T, renamed?: (model: string) => Readonly<Record<string, string>> | undefined): T;
|
|
54
|
+
/** Whether a GraphQL result's `data` holds any entry `markGraphQLEntries` would mark. */
|
|
55
|
+
export declare function hasGraphQLEntry(data: unknown): boolean;
|
|
56
|
+
/** Keep `from`'s edit mark on `to`, for a copy of an entry in another shape (`toTree`). */
|
|
57
|
+
export declare function carryEditMark<T extends object>(from: unknown, to: T): T;
|
|
58
|
+
/** GraphQL's system fields, which name the entry rather than one of its fields. */
|
|
59
|
+
type GraphQLSystemField = "id" | "model" | "status" | "createdAt" | "updatedAt" | "publishedAt" | "_version" | "_tags" | "_folder" | "__typename";
|
|
60
|
+
/**
|
|
61
|
+
* The `field` `capaAttrs` takes for `E`: a key of `fields` for a REST entry;
|
|
62
|
+
* a field as selected for a GraphQL node, which selected `id` and `model`;
|
|
63
|
+
* any name for a bare `{ id }`. A GraphQL node without `model` takes none,
|
|
64
|
+
* and the compiler says why.
|
|
65
|
+
*/
|
|
66
|
+
export type TaggableField<E> = unknown extends FieldsOf<E> ? E extends {
|
|
67
|
+
model: string;
|
|
68
|
+
} ? Exclude<Extract<keyof E, string>, GraphQLSystemField> : [Exclude<keyof E, "id">] extends [never] ? string : "select model on this node: capaAttrs tags an entry that selected id and model" : Extract<keyof NonNullable<FieldsOf<E>>, string>;
|
|
69
|
+
/** A REST entry's `fields` type; `unknown` for anything without one (a GraphQL node, a bare `{ id }`). */
|
|
70
|
+
type FieldsOf<E> = "fields" extends keyof E ? E["fields" & keyof E] : unknown;
|
|
71
|
+
export declare function capaAttrs<E extends {
|
|
42
72
|
id: string;
|
|
43
|
-
|
|
44
|
-
}, field: Extract<keyof T, string>, enabled?: boolean): CapaAttrs;
|
|
73
|
+
}>(entry: E, field: TaggableField<E>, enabled?: boolean): CapaAttrs;
|
|
45
74
|
/**
|
|
46
|
-
*
|
|
75
|
+
* The attributes for every field of `T`, one `CapaAttrs` per field name.
|
|
76
|
+
* `capa-codegen` writes `<Model>Attrs = FieldAttrs<Model>` beside each
|
|
77
|
+
* `<Model>Select`, so `const a: ArticleAttrs = fieldAttrs(entry)` fails to
|
|
78
|
+
* compile on a wrong field name (M5). `fieldAttrs` of a REST entry typed with
|
|
79
|
+
* `Model` returns exactly this type.
|
|
80
|
+
*/
|
|
81
|
+
export type FieldAttrs<T> = {
|
|
82
|
+
readonly [K in Extract<keyof T, string>]: CapaAttrs;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Typed attributes for every field of one entry (M5), or of one GraphQL node:
|
|
47
86
|
*
|
|
48
87
|
* const a = fieldAttrs(article);
|
|
49
88
|
* <h1 {...a.title}>…</h1> // a.titel is a compile error
|
|
@@ -51,9 +90,9 @@ export declare function capaAttrs<T = Record<string, unknown>>(entry: {
|
|
|
51
90
|
* Same rule as `capaAttrs`: empty unless the entry was read in edit mode, or
|
|
52
91
|
* `enabled` says otherwise.
|
|
53
92
|
*/
|
|
54
|
-
export declare function fieldAttrs<
|
|
93
|
+
export declare function fieldAttrs<E extends {
|
|
55
94
|
id: string;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
readonly [K in Extract<keyof T, string>]: CapaAttrs;
|
|
95
|
+
}>(entry: E, enabled?: boolean): {
|
|
96
|
+
readonly [K in TaggableField<E>]: CapaAttrs;
|
|
59
97
|
};
|
|
98
|
+
export {};
|
package/dist/next/attrs.js
CHANGED
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.CAPA_EDIT = void 0;
|
|
4
4
|
exports.isEditEntry = isEditEntry;
|
|
5
5
|
exports.markEditEntries = markEditEntries;
|
|
6
|
+
exports.markGraphQLEntries = markGraphQLEntries;
|
|
7
|
+
exports.hasGraphQLEntry = hasGraphQLEntry;
|
|
8
|
+
exports.carryEditMark = carryEditMark;
|
|
6
9
|
exports.capaAttrs = capaAttrs;
|
|
7
10
|
exports.fieldAttrs = fieldAttrs;
|
|
8
11
|
/** `Symbol.for`, so two copies of the SDK in one bundle agree on the mark. */
|
|
@@ -13,46 +16,97 @@ function isEditEntry(entry) {
|
|
|
13
16
|
entry !== null &&
|
|
14
17
|
entry[exports.CAPA_EDIT] === true);
|
|
15
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`. */
|
|
16
25
|
function looksLikeEntry(value) {
|
|
17
26
|
return typeof value.id === "string" && typeof value.fields === "object" && value.fields !== null;
|
|
18
27
|
}
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*/
|
|
24
|
-
function
|
|
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) {
|
|
25
38
|
const seen = new Set();
|
|
26
|
-
const
|
|
39
|
+
const walk = (node) => {
|
|
27
40
|
if (typeof node !== "object" || node === null || seen.has(node))
|
|
28
41
|
return;
|
|
29
42
|
seen.add(node);
|
|
30
43
|
if (Array.isArray(node)) {
|
|
31
44
|
for (const item of node)
|
|
32
|
-
|
|
45
|
+
walk(item);
|
|
33
46
|
return;
|
|
34
47
|
}
|
|
35
48
|
const record = node;
|
|
36
|
-
|
|
37
|
-
Object.defineProperty(record, exports.CAPA_EDIT, {
|
|
38
|
-
value: true,
|
|
39
|
-
enumerable: false,
|
|
40
|
-
configurable: true,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
49
|
+
visit(record);
|
|
43
50
|
for (const key of Object.keys(record))
|
|
44
|
-
|
|
51
|
+
walk(record[key]);
|
|
45
52
|
};
|
|
46
|
-
|
|
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
|
+
});
|
|
47
65
|
return value;
|
|
48
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
|
+
}
|
|
49
103
|
function capaAttrs(entry, field, enabled = isEditEntry(entry)) {
|
|
50
104
|
if (!enabled)
|
|
51
105
|
return {};
|
|
52
|
-
return { "data-capa-entry": entry.id, "data-capa-field": field };
|
|
106
|
+
return { "data-capa-entry": entry.id, "data-capa-field": namespaceOf(entry, field) };
|
|
53
107
|
}
|
|
54
108
|
/**
|
|
55
|
-
* Typed attributes for every field of one entry (M5):
|
|
109
|
+
* Typed attributes for every field of one entry (M5), or of one GraphQL node:
|
|
56
110
|
*
|
|
57
111
|
* const a = fieldAttrs(article);
|
|
58
112
|
* <h1 {...a.title}>…</h1> // a.titel is a compile error
|
|
@@ -65,7 +119,7 @@ function fieldAttrs(entry, enabled = isEditEntry(entry)) {
|
|
|
65
119
|
get(_target, key) {
|
|
66
120
|
if (typeof key !== "string")
|
|
67
121
|
return undefined;
|
|
68
|
-
return enabled ? { "data-capa-entry": entry.id, "data-capa-field": key } : {};
|
|
122
|
+
return enabled ? { "data-capa-entry": entry.id, "data-capa-field": namespaceOf(entry, key) } : {};
|
|
69
123
|
},
|
|
70
124
|
});
|
|
71
125
|
}
|
package/dist/next/client.d.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
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";
|
|
1
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
|
+
* and warns once per process; `preview()` and draft reads take a `cap_` key
|
|
14
|
+
* only.
|
|
15
|
+
*/
|
|
4
16
|
apiKey: string;
|
|
5
17
|
version: string;
|
|
6
18
|
contract?: 1;
|
|
@@ -40,7 +52,9 @@ export interface CapaNextConfig {
|
|
|
40
52
|
* and a published page ships no entry ids. `@capacms/sdk/nextjs` works it out
|
|
41
53
|
* per request with `editMode()`.
|
|
42
54
|
*
|
|
43
|
-
*
|
|
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.
|
|
44
58
|
*/
|
|
45
59
|
editMode?: boolean;
|
|
46
60
|
/**
|
|
@@ -75,6 +89,11 @@ export interface CallOptions {
|
|
|
75
89
|
*/
|
|
76
90
|
path?: string;
|
|
77
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
|
+
*/
|
|
78
97
|
export interface Entry<T = Record<string, unknown>> {
|
|
79
98
|
id: string;
|
|
80
99
|
model: string;
|
|
@@ -126,19 +145,21 @@ export type Filter = Record<string, Partial<Record<FilterOperator, FilterValue>>
|
|
|
126
145
|
* turns a flat result back into the tree one.
|
|
127
146
|
*/
|
|
128
147
|
export type ResponseShape = "tree" | "flat";
|
|
129
|
-
export interface ListOptions<T = Record<string, unknown
|
|
130
|
-
select?:
|
|
148
|
+
export interface ListOptions<T = Record<string, unknown>, S extends Select<T> | string = Select<T> | string> extends CallOptions {
|
|
149
|
+
select?: S;
|
|
131
150
|
shape?: "tree";
|
|
132
151
|
filter?: Filter;
|
|
133
152
|
where?: Record<string, unknown>;
|
|
134
153
|
sort?: readonly string[];
|
|
135
154
|
limit?: number;
|
|
136
155
|
count?: boolean;
|
|
156
|
+
/** `page.next`: the page after it. */
|
|
137
157
|
after?: string;
|
|
158
|
+
/** `page.prev`: the page before it. Or `"end"`: the last `limit` entries of the list. */
|
|
138
159
|
before?: string;
|
|
139
160
|
}
|
|
140
|
-
export interface GetOptions<T = Record<string, unknown
|
|
141
|
-
select?:
|
|
161
|
+
export interface GetOptions<T = Record<string, unknown>, S extends Select<T> | string = Select<T> | string> extends CallOptions {
|
|
162
|
+
select?: S;
|
|
142
163
|
shape?: "tree";
|
|
143
164
|
}
|
|
144
165
|
/** `list` with `shape: "flat"`. `S` is the select, which types `included`. */
|
|
@@ -153,23 +174,37 @@ export type FlatGetOptions<T, S extends Select<T> | string = Select<T>> = Omit<G
|
|
|
153
174
|
};
|
|
154
175
|
/**
|
|
155
176
|
* `included` of a flat read: model namespace, then entry id, then the entry.
|
|
156
|
-
* Typed by the select: the union of every entry type it expands
|
|
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.
|
|
157
179
|
*/
|
|
158
|
-
export type Included<I> = Record<string, Record<string, Entry<I
|
|
159
|
-
interface FlatExtras<T, S> {
|
|
180
|
+
export type Included<I> = Record<string, Record<string, Entry<IncludedFields<I>>>>;
|
|
181
|
+
interface FlatExtras<T, S> extends FlatRead<T, S> {
|
|
160
182
|
included: Included<[ExpandedTargets<T, S>] extends [never] ? never : ExpandedTargets<T, S>>;
|
|
161
183
|
/** The select this read sent, which is what `inflate` walks. Absent when none was sent. */
|
|
162
184
|
select?: string;
|
|
163
185
|
}
|
|
164
|
-
|
|
165
|
-
export type
|
|
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
|
+
*/
|
|
166
201
|
export interface EntriesResource {
|
|
167
|
-
list<T = Record<string, unknown>, S extends Select<T> | string = Select<T>>(namespace: string, options: FlatListOptions<T
|
|
168
|
-
list<T = Record<string, unknown
|
|
169
|
-
get<T = Record<string, unknown>, S extends Select<T> | string = Select<T>>(namespace: string, id: string, options: FlatGetOptions<T
|
|
170
|
-
get<T = Record<string, unknown
|
|
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>;
|
|
171
206
|
/** Tree only: it yields entries one at a time, which is what `included` exists to avoid. */
|
|
172
|
-
iterate<T = Record<string, unknown
|
|
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>;
|
|
173
208
|
}
|
|
174
209
|
/**
|
|
175
210
|
* One suggestion drawn from a page's own reads.
|
|
@@ -308,7 +343,56 @@ export interface PreviewClaim {
|
|
|
308
343
|
path: string | null;
|
|
309
344
|
expiresAt: string;
|
|
310
345
|
}
|
|
311
|
-
|
|
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> {
|
|
312
396
|
entries: EntriesResource;
|
|
313
397
|
pages: PagesResource;
|
|
314
398
|
/**
|
|
@@ -317,31 +401,22 @@ export interface CapaNextClient {
|
|
|
317
401
|
* Returns the claim, or NULL when the token is invalid or expired, because
|
|
318
402
|
* both mean the same thing to a preview route: do not enable draft mode.
|
|
319
403
|
* Every other failure throws, so a Capa outage does not look like a bad link.
|
|
404
|
+
* Needs a `cap_` key: a client built with a legacy key throws a
|
|
405
|
+
* `TypeError` here before any request.
|
|
320
406
|
*/
|
|
321
407
|
preview(token: string, options?: CallOptions): Promise<PreviewClaim | null>;
|
|
322
408
|
me<T = Record<string, unknown>>(options?: CallOptions): Promise<T>;
|
|
323
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>>;
|
|
324
419
|
}
|
|
325
|
-
export declare class CapaError extends Error {
|
|
326
|
-
readonly status: number;
|
|
327
|
-
readonly type: string;
|
|
328
|
-
readonly code: string;
|
|
329
|
-
readonly param?: string;
|
|
330
|
-
readonly hint?: string;
|
|
331
|
-
readonly requestId: string;
|
|
332
|
-
readonly docs: string;
|
|
333
|
-
constructor(input: {
|
|
334
|
-
status: number;
|
|
335
|
-
type: string;
|
|
336
|
-
code: string;
|
|
337
|
-
message: string;
|
|
338
|
-
param?: string;
|
|
339
|
-
hint?: string;
|
|
340
|
-
requestId: string;
|
|
341
|
-
docs: string;
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
export declare function isCapaError(error: unknown): error is CapaError;
|
|
345
420
|
export declare function resolveNextConfig(config: CapaNextConfig): ResolvedNextConfig;
|
|
346
421
|
/**
|
|
347
422
|
* The page a layout (or template) reads for: none.
|
|
@@ -360,5 +435,4 @@ export declare const LAYOUT_PAGE = "(layout)";
|
|
|
360
435
|
type SelectInput = string | ReadonlyArray<unknown>;
|
|
361
436
|
/** Serialize the SDK object form into the canonical `/api/entries` grammar. */
|
|
362
437
|
export declare function serializeSelect(select: SelectInput): string;
|
|
363
|
-
export declare function createClient(config: CapaNextConfig): CapaNextClient
|
|
364
|
-
export {};
|
|
438
|
+
export declare function createClient<Q = UntypedQuery>(config: CapaNextConfig): CapaNextClient<Q>;
|