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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/CHANGELOG.md +450 -0
  2. package/README.md +1698 -193
  3. package/bin/capa-codegen.js +192 -5
  4. package/bin/capa.js +235 -0
  5. package/bin/graphql-project.js +142 -0
  6. package/bin/project-env.js +58 -0
  7. package/dist/client.d.ts +5 -0
  8. package/dist/client.js +17 -0
  9. package/dist/codegen.d.ts +55 -0
  10. package/dist/codegen.js +320 -39
  11. package/dist/config.d.ts +5 -36
  12. package/dist/config.js +47 -1
  13. package/dist/esm/image/index.d.ts +120 -0
  14. package/dist/esm/image/index.js +250 -0
  15. package/dist/esm/image/shared-params.generated.d.ts +190 -0
  16. package/dist/esm/image/shared-params.generated.js +461 -0
  17. package/dist/esm/nextjs/image-loader.d.ts +60 -0
  18. package/dist/esm/nextjs/image-loader.js +67 -0
  19. package/dist/esm/nextjs/overlay.d.ts +30 -0
  20. package/dist/esm/nextjs/overlay.js +75 -0
  21. package/dist/esm/overlay/index.d.ts +32 -0
  22. package/dist/esm/overlay/index.js +576 -0
  23. package/dist/esm/overlay/protocol.d.ts +187 -0
  24. package/dist/esm/overlay/protocol.js +240 -0
  25. package/dist/esm/package.json +4 -0
  26. package/dist/graphql-codegen.d.ts +117 -0
  27. package/dist/graphql-codegen.js +705 -0
  28. package/dist/http.js +1 -1
  29. package/dist/image/index.d.ts +120 -0
  30. package/dist/image/index.js +257 -0
  31. package/dist/image/shared-params.generated.d.ts +190 -0
  32. package/dist/image/shared-params.generated.js +471 -0
  33. package/dist/index.d.ts +2 -2
  34. package/dist/index.js +2 -1
  35. package/dist/next/attrs.d.ts +84 -10
  36. package/dist/next/attrs.js +119 -2
  37. package/dist/next/client.d.ts +176 -32
  38. package/dist/next/client.js +212 -90
  39. package/dist/next/entry-fields.d.ts +162 -0
  40. package/dist/next/entry-fields.js +2 -0
  41. package/dist/next/errors.d.ts +136 -0
  42. package/dist/next/errors.js +214 -0
  43. package/dist/next/field-names.d.ts +37 -0
  44. package/dist/next/field-names.js +145 -0
  45. package/dist/next/graphql/build.d.ts +27 -0
  46. package/dist/next/graphql/build.js +98 -0
  47. package/dist/next/graphql/documents.d.ts +67 -0
  48. package/dist/next/graphql/documents.js +35 -0
  49. package/dist/next/graphql/edit-mode.d.ts +16 -0
  50. package/dist/next/graphql/edit-mode.js +93 -0
  51. package/dist/next/graphql/filter-values.d.ts +34 -0
  52. package/dist/next/graphql/filter-values.js +96 -0
  53. package/dist/next/graphql/introspection.d.ts +89 -0
  54. package/dist/next/graphql/introspection.js +102 -0
  55. package/dist/next/graphql/plan.d.ts +115 -0
  56. package/dist/next/graphql/plan.js +531 -0
  57. package/dist/next/graphql/request.d.ts +228 -0
  58. package/dist/next/graphql/request.js +283 -0
  59. package/dist/next/graphql/rest.d.ts +66 -0
  60. package/dist/next/graphql/rest.js +502 -0
  61. package/dist/next/graphql/selection.d.ts +55 -0
  62. package/dist/next/graphql/selection.js +212 -0
  63. package/dist/next/graphql/sha256.d.ts +13 -0
  64. package/dist/next/graphql/sha256.js +86 -0
  65. package/dist/next/graphql/summary.d.ts +83 -0
  66. package/dist/next/graphql/summary.js +151 -0
  67. package/dist/next/graphql/tree-layout.d.ts +36 -0
  68. package/dist/next/graphql/tree-layout.js +20 -0
  69. package/dist/next/graphql/tree.d.ts +171 -0
  70. package/dist/next/graphql/tree.js +249 -0
  71. package/dist/next/graphql/typed.d.ts +261 -0
  72. package/dist/next/graphql/typed.js +146 -0
  73. package/dist/next/index.d.ts +30 -5
  74. package/dist/next/index.js +32 -1
  75. package/dist/next/inflate.d.ts +51 -0
  76. package/dist/next/inflate.js +243 -0
  77. package/dist/next/key-family.d.ts +31 -0
  78. package/dist/next/key-family.js +66 -0
  79. package/dist/next/select-types.d.ts +58 -5
  80. package/dist/next/system-keys.d.ts +27 -0
  81. package/dist/next/system-keys.js +42 -0
  82. package/dist/nextjs/image-loader.d.ts +60 -0
  83. package/dist/nextjs/image-loader.js +71 -0
  84. package/dist/nextjs/index.d.ts +484 -5
  85. package/dist/nextjs/index.js +688 -6
  86. package/dist/nextjs/overlay.d.ts +30 -0
  87. package/dist/nextjs/overlay.js +78 -0
  88. package/dist/overlay/index.d.ts +14 -2
  89. package/dist/overlay/index.js +282 -43
  90. package/dist/overlay/protocol.d.ts +98 -2
  91. package/dist/overlay/protocol.js +151 -4
  92. package/package.json +63 -15
@@ -0,0 +1,187 @@
1
+ /**
2
+ * The live preview protocol, site side. Pure: no DOM, no globals, so it can be
3
+ * tested under plain `node --test`.
4
+ *
5
+ * The Capa admin frames the site and the two talk over `postMessage`. Every
6
+ * message is a plain object `{ source, v: 1, type, ...fields }`:
7
+ *
8
+ * admin -> site (source "capa-admin")
9
+ * hello {} sent on the frame's load
10
+ * highlight { entryId, field: string | null } entryId "" clears
11
+ * outline { on: boolean } outline every tagged element
12
+ * refresh {} re-render the draft
13
+ * patch { entryId, fields: [{ field, value, saved }] }
14
+ * unsaved text, as the editor types it
15
+ *
16
+ * site -> admin (source "capa")
17
+ * ready { path, entries, features } after hello, and after every navigation.
18
+ * `features`: what this overlay can do
19
+ * beyond v1 (`SITE_FEATURES`)
20
+ * select { entryId, field } a tagged element was clicked
21
+ * hover { entryId, field } | { entryId: "", field: null }
22
+ * visible { entryId, field } the tagged element at the centre of the
23
+ * viewport changed (throttled, on scroll)
24
+ *
25
+ * `visible` arrived in 1.0.0-next.2 and is OPTIONAL: it is still `v: 1`,
26
+ * because an admin that does not know it drops an unknown type, and an older
27
+ * overlay simply never sends it. Additive messages keep the version; only a
28
+ * change to an existing shape would move it. `patch` and `features` are the
29
+ * same kind of addition: an admin sends `patch` only to an overlay whose
30
+ * `ready` lists "patch", and an older admin never reads `features`.
31
+ *
32
+ * A PATCH IS TEXT ONLY, and only where the page shows the field verbatim. The
33
+ * overlay changes a tagged element's text while it reads exactly `saved` (the
34
+ * value the page was rendered from) or what this page last patched it to, so
35
+ * a field the site formats (a price, a date, Markdown) is left alone until the
36
+ * save re-renders it (`patchedText`).
37
+ *
38
+ * The admin keeps its own copy of these shapes (`apps/admin`, no dependency on
39
+ * this package). If you change one side, change the other.
40
+ */
41
+ export declare const PROTOCOL_VERSION = 1;
42
+ export declare const ADMIN_SOURCE = "capa-admin";
43
+ export declare const SITE_SOURCE = "capa";
44
+ /** What this overlay can do beyond v1, listed in its `ready`. */
45
+ export declare const SITE_FEATURES: readonly string[];
46
+ /** One field of a `patch`: the text being typed, and the saved value the page was rendered from. */
47
+ export interface PatchField {
48
+ field: string;
49
+ value: string;
50
+ saved: string;
51
+ }
52
+ /** A `patch` past these is refused whole: no form has that many text fields, or that much text in one. */
53
+ export declare const PATCH_MAX_FIELDS = 500;
54
+ export declare const PATCH_MAX_LENGTH = 100000;
55
+ export type AdminMessage = {
56
+ source: typeof ADMIN_SOURCE;
57
+ v: 1;
58
+ type: "hello";
59
+ } | {
60
+ source: typeof ADMIN_SOURCE;
61
+ v: 1;
62
+ type: "highlight";
63
+ entryId: string;
64
+ field: string | null;
65
+ } | {
66
+ source: typeof ADMIN_SOURCE;
67
+ v: 1;
68
+ type: "outline";
69
+ on: boolean;
70
+ } | {
71
+ source: typeof ADMIN_SOURCE;
72
+ v: 1;
73
+ type: "refresh";
74
+ } | {
75
+ source: typeof ADMIN_SOURCE;
76
+ v: 1;
77
+ type: "patch";
78
+ entryId: string;
79
+ fields: PatchField[];
80
+ };
81
+ export type SiteMessage = {
82
+ source: typeof SITE_SOURCE;
83
+ v: 1;
84
+ type: "ready";
85
+ path: string;
86
+ entries: string[];
87
+ features?: string[];
88
+ } | {
89
+ source: typeof SITE_SOURCE;
90
+ v: 1;
91
+ type: "select";
92
+ entryId: string;
93
+ field: string;
94
+ } | {
95
+ source: typeof SITE_SOURCE;
96
+ v: 1;
97
+ type: "hover";
98
+ entryId: string;
99
+ field: string | null;
100
+ } | {
101
+ source: typeof SITE_SOURCE;
102
+ v: 1;
103
+ type: "visible";
104
+ entryId: string;
105
+ field: string;
106
+ };
107
+ /** The parts of a `MessageEvent` the filter reads, so a test can hand in a literal. */
108
+ export interface MessageLike {
109
+ origin: string;
110
+ source: unknown;
111
+ data: unknown;
112
+ }
113
+ /**
114
+ * `https://admin.example.com/` and `https://admin.example.com` are one origin,
115
+ * and a configured value that is not a URL at all is dropped rather than
116
+ * compared as a string, because `"*"` must never mean "anyone".
117
+ */
118
+ export declare function normaliseOrigins(origins: readonly string[]): string[];
119
+ /**
120
+ * The one gate every incoming message goes through. A message is accepted only
121
+ * when all of these hold, and is `null` otherwise:
122
+ *
123
+ * - it came from the window that framed this page (`parent`), not from a
124
+ * popup, a sibling frame or this page itself
125
+ * - its origin is one the site configured as its admin
126
+ * - it says it is from the admin, speaks version 1, and has a known type
127
+ * whose fields have the right shapes
128
+ *
129
+ * `allowedOrigins` is expected already normalised (`normaliseOrigins`).
130
+ */
131
+ export declare function acceptMessage(event: MessageLike, allowedOrigins: readonly string[], parent: unknown): AdminMessage | null;
132
+ /**
133
+ * The text a node should read after a patch, or null to leave it alone.
134
+ *
135
+ * Only while its text (trimmed) is the saved value or what this page last
136
+ * patched it to, so text the site formats is never touched. The whitespace a
137
+ * template put around it stays. Null too when there is nothing to change.
138
+ */
139
+ export declare function patchedText(current: string, change: {
140
+ value: string;
141
+ saved: string;
142
+ }, lastPatched: string | null, around?: {
143
+ lead: string;
144
+ trail: string;
145
+ }): string | null;
146
+ /**
147
+ * The whitespace around a node's text, which a patch keeps. A node that is
148
+ * only whitespace keeps it in front. The overlay remembers this from the
149
+ * first patch, so text typed away to nothing and back lands where it was.
150
+ */
151
+ export declare function textAround(current: string): {
152
+ lead: string;
153
+ trail: string;
154
+ };
155
+ export declare function readyMessage(path: string, entries: string[], features?: readonly string[]): SiteMessage;
156
+ export declare function selectMessage(entryId: string, field: string): SiteMessage;
157
+ export declare function hoverMessage(entryId: string, field: string | null): SiteMessage;
158
+ export declare function visibleMessage(entryId: string, field: string): SiteMessage;
159
+ /** The part of a tagged element `pickCentred` reads, so a test can hand in literals. */
160
+ export interface TaggedBox {
161
+ entryId: string;
162
+ field: string;
163
+ /** `getBoundingClientRect()`, viewport coordinates. */
164
+ top: number;
165
+ bottom: number;
166
+ }
167
+ /**
168
+ * The tagged element a reader is looking at: the one that contains the
169
+ * viewport's horizontal centre line, and when several do (a field inside a
170
+ * card that is also tagged) the SMALLEST, because the innermost element is
171
+ * the specific one. When none crosses the line, the nearest one that is at
172
+ * least partly on screen. Null when nothing tagged is on screen at all.
173
+ *
174
+ * `edge` is where the page is scrolled to. A heading near the top of a page
175
+ * can never reach the centre line, because the page cannot scroll above its
176
+ * top; at the top the topmost visible element is the one being read, and at
177
+ * the bottom the bottommost. The same rule a table of contents' scroll spy
178
+ * uses.
179
+ *
180
+ * Pure, so the admin's "follow the page" can be tested without a DOM.
181
+ */
182
+ export declare function pickCentred(boxes: readonly TaggedBox[], viewportHeight: number, edge?: "top" | "bottom" | null): TaggedBox | null;
183
+ /**
184
+ * Which edge a scroll position is at, for `pickCentred`. A page that does not
185
+ * scroll at all is at neither: nothing moves, and the centre rule stands.
186
+ */
187
+ export declare function scrollEdge(scrollY: number, viewportHeight: number, scrollHeight: number): "top" | "bottom" | null;
@@ -0,0 +1,240 @@
1
+ /**
2
+ * The live preview protocol, site side. Pure: no DOM, no globals, so it can be
3
+ * tested under plain `node --test`.
4
+ *
5
+ * The Capa admin frames the site and the two talk over `postMessage`. Every
6
+ * message is a plain object `{ source, v: 1, type, ...fields }`:
7
+ *
8
+ * admin -> site (source "capa-admin")
9
+ * hello {} sent on the frame's load
10
+ * highlight { entryId, field: string | null } entryId "" clears
11
+ * outline { on: boolean } outline every tagged element
12
+ * refresh {} re-render the draft
13
+ * patch { entryId, fields: [{ field, value, saved }] }
14
+ * unsaved text, as the editor types it
15
+ *
16
+ * site -> admin (source "capa")
17
+ * ready { path, entries, features } after hello, and after every navigation.
18
+ * `features`: what this overlay can do
19
+ * beyond v1 (`SITE_FEATURES`)
20
+ * select { entryId, field } a tagged element was clicked
21
+ * hover { entryId, field } | { entryId: "", field: null }
22
+ * visible { entryId, field } the tagged element at the centre of the
23
+ * viewport changed (throttled, on scroll)
24
+ *
25
+ * `visible` arrived in 1.0.0-next.2 and is OPTIONAL: it is still `v: 1`,
26
+ * because an admin that does not know it drops an unknown type, and an older
27
+ * overlay simply never sends it. Additive messages keep the version; only a
28
+ * change to an existing shape would move it. `patch` and `features` are the
29
+ * same kind of addition: an admin sends `patch` only to an overlay whose
30
+ * `ready` lists "patch", and an older admin never reads `features`.
31
+ *
32
+ * A PATCH IS TEXT ONLY, and only where the page shows the field verbatim. The
33
+ * overlay changes a tagged element's text while it reads exactly `saved` (the
34
+ * value the page was rendered from) or what this page last patched it to, so
35
+ * a field the site formats (a price, a date, Markdown) is left alone until the
36
+ * save re-renders it (`patchedText`).
37
+ *
38
+ * The admin keeps its own copy of these shapes (`apps/admin`, no dependency on
39
+ * this package). If you change one side, change the other.
40
+ */
41
+ export const PROTOCOL_VERSION = 1;
42
+ export const ADMIN_SOURCE = "capa-admin";
43
+ export const SITE_SOURCE = "capa";
44
+ /** What this overlay can do beyond v1, listed in its `ready`. */
45
+ export const SITE_FEATURES = ["patch"];
46
+ /** A `patch` past these is refused whole: no form has that many text fields, or that much text in one. */
47
+ export const PATCH_MAX_FIELDS = 500;
48
+ export const PATCH_MAX_LENGTH = 100_000;
49
+ /**
50
+ * `https://admin.example.com/` and `https://admin.example.com` are one origin,
51
+ * and a configured value that is not a URL at all is dropped rather than
52
+ * compared as a string, because `"*"` must never mean "anyone".
53
+ */
54
+ export function normaliseOrigins(origins) {
55
+ const out = [];
56
+ for (const raw of origins) {
57
+ if (typeof raw !== "string" || raw.trim() === "")
58
+ continue;
59
+ try {
60
+ const origin = new URL(raw.trim()).origin;
61
+ if (origin !== "null" && !out.includes(origin))
62
+ out.push(origin);
63
+ }
64
+ catch {
65
+ // Not a URL: never an origin anybody can send from.
66
+ }
67
+ }
68
+ return out;
69
+ }
70
+ /**
71
+ * The one gate every incoming message goes through. A message is accepted only
72
+ * when all of these hold, and is `null` otherwise:
73
+ *
74
+ * - it came from the window that framed this page (`parent`), not from a
75
+ * popup, a sibling frame or this page itself
76
+ * - its origin is one the site configured as its admin
77
+ * - it says it is from the admin, speaks version 1, and has a known type
78
+ * whose fields have the right shapes
79
+ *
80
+ * `allowedOrigins` is expected already normalised (`normaliseOrigins`).
81
+ */
82
+ export function acceptMessage(event, allowedOrigins, parent) {
83
+ if (!event || event.source !== parent || parent == null)
84
+ return null;
85
+ if (typeof event.origin !== "string" || !allowedOrigins.includes(event.origin))
86
+ return null;
87
+ const data = event.data;
88
+ if (typeof data !== "object" || data === null || Array.isArray(data))
89
+ return null;
90
+ const m = data;
91
+ if (m.source !== ADMIN_SOURCE || m.v !== PROTOCOL_VERSION)
92
+ return null;
93
+ switch (m.type) {
94
+ case "hello":
95
+ return { source: ADMIN_SOURCE, v: 1, type: "hello" };
96
+ case "refresh":
97
+ return { source: ADMIN_SOURCE, v: 1, type: "refresh" };
98
+ case "outline":
99
+ if (typeof m.on !== "boolean")
100
+ return null;
101
+ return { source: ADMIN_SOURCE, v: 1, type: "outline", on: m.on };
102
+ case "highlight":
103
+ if (typeof m.entryId !== "string")
104
+ return null;
105
+ if (m.field !== null && typeof m.field !== "string")
106
+ return null;
107
+ return { source: ADMIN_SOURCE, v: 1, type: "highlight", entryId: m.entryId, field: m.field };
108
+ case "patch": {
109
+ if (typeof m.entryId !== "string" || m.entryId === "")
110
+ return null;
111
+ if (!Array.isArray(m.fields) || m.fields.length > PATCH_MAX_FIELDS)
112
+ return null;
113
+ const fields = [];
114
+ for (const raw of m.fields) {
115
+ if (typeof raw !== "object" || raw === null)
116
+ return null;
117
+ const f = raw;
118
+ if (typeof f.field !== "string" || f.field === "")
119
+ return null;
120
+ if (typeof f.value !== "string" || typeof f.saved !== "string")
121
+ return null;
122
+ if (f.value.length > PATCH_MAX_LENGTH || f.saved.length > PATCH_MAX_LENGTH)
123
+ return null;
124
+ fields.push({ field: f.field, value: f.value, saved: f.saved });
125
+ }
126
+ return { source: ADMIN_SOURCE, v: 1, type: "patch", entryId: m.entryId, fields };
127
+ }
128
+ default:
129
+ return null;
130
+ }
131
+ }
132
+ /**
133
+ * The text a node should read after a patch, or null to leave it alone.
134
+ *
135
+ * Only while its text (trimmed) is the saved value or what this page last
136
+ * patched it to, so text the site formats is never touched. The whitespace a
137
+ * template put around it stays. Null too when there is nothing to change.
138
+ */
139
+ export function patchedText(current, change, lastPatched, around = textAround(current)) {
140
+ const text = current.trim();
141
+ const ours = text === change.saved.trim() || (lastPatched !== null && text === lastPatched.trim());
142
+ if (!ours || text === change.value.trim())
143
+ return null;
144
+ return `${around.lead}${change.value}${around.trail}`;
145
+ }
146
+ /**
147
+ * The whitespace around a node's text, which a patch keeps. A node that is
148
+ * only whitespace keeps it in front. The overlay remembers this from the
149
+ * first patch, so text typed away to nothing and back lands where it was.
150
+ */
151
+ export function textAround(current) {
152
+ const text = current.trim();
153
+ if (text === "")
154
+ return { lead: current, trail: "" };
155
+ return {
156
+ lead: current.slice(0, current.length - current.trimStart().length),
157
+ trail: current.slice(current.trimEnd().length),
158
+ };
159
+ }
160
+ export function readyMessage(path, entries, features) {
161
+ return features
162
+ ? { source: SITE_SOURCE, v: 1, type: "ready", path, entries, features: [...features] }
163
+ : { source: SITE_SOURCE, v: 1, type: "ready", path, entries };
164
+ }
165
+ export function selectMessage(entryId, field) {
166
+ return { source: SITE_SOURCE, v: 1, type: "select", entryId, field };
167
+ }
168
+ export function hoverMessage(entryId, field) {
169
+ return entryId === ""
170
+ ? { source: SITE_SOURCE, v: 1, type: "hover", entryId: "", field: null }
171
+ : { source: SITE_SOURCE, v: 1, type: "hover", entryId, field };
172
+ }
173
+ export function visibleMessage(entryId, field) {
174
+ return { source: SITE_SOURCE, v: 1, type: "visible", entryId, field };
175
+ }
176
+ /** Above any element height, so a box that misses the centre line never outranks one that crosses it. */
177
+ const MISS_FLOOR = 1e9;
178
+ /**
179
+ * The tagged element a reader is looking at: the one that contains the
180
+ * viewport's horizontal centre line, and when several do (a field inside a
181
+ * card that is also tagged) the SMALLEST, because the innermost element is
182
+ * the specific one. When none crosses the line, the nearest one that is at
183
+ * least partly on screen. Null when nothing tagged is on screen at all.
184
+ *
185
+ * `edge` is where the page is scrolled to. A heading near the top of a page
186
+ * can never reach the centre line, because the page cannot scroll above its
187
+ * top; at the top the topmost visible element is the one being read, and at
188
+ * the bottom the bottommost. The same rule a table of contents' scroll spy
189
+ * uses.
190
+ *
191
+ * Pure, so the admin's "follow the page" can be tested without a DOM.
192
+ */
193
+ export function pickCentred(boxes, viewportHeight, edge = null) {
194
+ const centre = viewportHeight / 2;
195
+ let best = null;
196
+ let bestScore = Infinity;
197
+ for (const b of boxes) {
198
+ if (!b.entryId || !b.field)
199
+ continue;
200
+ if (b.bottom <= 0 || b.top >= viewportHeight || b.bottom <= b.top)
201
+ continue;
202
+ const height = b.bottom - b.top;
203
+ let score;
204
+ if (edge === "top") {
205
+ // Topmost first; of two that start together, the smaller (inner) one.
206
+ score = b.top * MISS_FLOOR + height;
207
+ }
208
+ else if (edge === "bottom") {
209
+ score = (viewportHeight - b.bottom) * MISS_FLOOR + height;
210
+ }
211
+ else {
212
+ // Crossing the line scores by height (smaller wins) and always beats a
213
+ // box that misses it, which scores by its distance from the line on top
214
+ // of a floor no height can reach.
215
+ score =
216
+ b.top <= centre && b.bottom >= centre
217
+ ? height
218
+ : MISS_FLOOR + Math.min(Math.abs(b.top - centre), Math.abs(b.bottom - centre));
219
+ }
220
+ if (score < bestScore) {
221
+ best = b;
222
+ bestScore = score;
223
+ }
224
+ }
225
+ return best;
226
+ }
227
+ /**
228
+ * Which edge a scroll position is at, for `pickCentred`. A page that does not
229
+ * scroll at all is at neither: nothing moves, and the centre rule stands.
230
+ */
231
+ export function scrollEdge(scrollY, viewportHeight, scrollHeight) {
232
+ const max = scrollHeight - viewportHeight;
233
+ if (max <= 1)
234
+ return null;
235
+ if (scrollY <= 1)
236
+ return "top";
237
+ if (scrollY >= max - 1)
238
+ return "bottom";
239
+ return null;
240
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "module",
3
+ "sideEffects": false
4
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * graphql-codegen.ts — `capa-codegen --graphql` and `capa persist`, the pure half.
3
+ *
4
+ * Reads a key's schema (introspection JSON) and a project's GraphQL documents,
5
+ * validates every document against that schema, and writes ONE TypeScript
6
+ * module holding:
7
+ *
8
+ * - the schema as types, for `createClient<CapaQuery>()` and the typed
9
+ * builder (`client.graphql.query`);
10
+ * - one `TypedDocument` constant per named operation, so
11
+ * `client.graphql(ArticlesPageDocument, vars)` infers the result and the
12
+ * variables with no cast, and beside it `<Name>Models`, the models it
13
+ * reads, for its Next.js cache tags;
14
+ * - for each document written as a literal (`#graphql`, `/* capa *\/` or
15
+ * gql(`...`)), an entry in `CapaDocuments` keyed by its exact text, so
16
+ * `client.graphql(LITERAL, vars)` infers them too, with no import;
17
+ * - `capaTreeLayout`, what `toTree` reads of the schema, so a server lays a
18
+ * builder result out in REST's shape without reading the schema first.
19
+ *
20
+ * The file walk and the network live in `bin/`; everything here is a function
21
+ * of its inputs, so it is tested without either.
22
+ *
23
+ * `graphql` (graphql-js) is loaded on first use, never at import: it is an
24
+ * optional peer dependency that only these commands need, and a site that
25
+ * only calls `client.graphql()` must not pay for it.
26
+ */
27
+ import type * as GraphQLJs from "graphql";
28
+ import type { CapaIntrospection } from "./next/graphql/introspection";
29
+ /** graphql-js, or an error that says how to get it. */
30
+ export declare function loadGraphQL(): typeof GraphQLJs;
31
+ /** One GraphQL document found in a project, with where it came from. */
32
+ export interface DocumentSource {
33
+ file: string;
34
+ /** 1-based line of the document's first character in `file`. */
35
+ line: number;
36
+ /** The document's text as the program holds it at run time: a template's escapes are applied. */
37
+ text: string;
38
+ /**
39
+ * True for a literal whose type is its text (`#graphql`, `/* capa *\/`,
40
+ * gql(`...`)): it is sent exactly as written, and codegen keys its types by
41
+ * that text.
42
+ */
43
+ literal?: true;
44
+ /** The variable a literal is assigned to (`const CARD = ...`), which another literal's `${CARD}` names. */
45
+ name?: string;
46
+ /**
47
+ * For a literal with `${NAME}` in it: the text around each `${}` and the
48
+ * names in them, resolved against the project's other literals before the
49
+ * literal is read. `text` holds the template with its `${NAME}`s meanwhile.
50
+ */
51
+ template?: {
52
+ segments: string[];
53
+ names: string[];
54
+ asConst: boolean;
55
+ };
56
+ }
57
+ /** A template codegen does not read, and why: the CLI prints each one, so none is dropped in silence. */
58
+ export interface SkippedDocument extends DocumentSource {
59
+ reason: string;
60
+ }
61
+ /** A template's text at run time, from its source text: line ends as LF, escapes applied. */
62
+ export declare function cookTemplate(raw: string): string;
63
+ /**
64
+ * The GraphQL documents in one file: the whole file for `.graphql` and `.gql`,
65
+ * and elsewhere every template that is marked as one: a `#graphql` first
66
+ * line, a `/* capa *\/` comment before it, or `gql` as a tag or a function.
67
+ * One on a comment line is an example, not a document.
68
+ *
69
+ * `skipped` names every template codegen will not read that looks meant for
70
+ * it, with the reason: one with `${}` inside (its text is only known at run
71
+ * time, so it cannot be validated or hashed ahead of it), a named operation
72
+ * left unmarked, and `/nextjs`'s `graphql` used as a tag.
73
+ */
74
+ export declare function extractDocuments(file: string, text: string): {
75
+ documents: DocumentSource[];
76
+ skipped: SkippedDocument[];
77
+ };
78
+ export interface CodegenProblem {
79
+ file: string;
80
+ line: number;
81
+ column: number;
82
+ message: string;
83
+ }
84
+ export interface GeneratedOperation {
85
+ name: string;
86
+ /** The exact text of its `<Name>Document`, and hashed for persisted queries. */
87
+ document: string;
88
+ sha256: string;
89
+ /** The namespaces of the models it reads, written as `<Name>Models` for its cache tags. */
90
+ models: string[];
91
+ /** For a document written as a literal: the literal's text, which is what a call with it sends, and its hash. */
92
+ literal?: {
93
+ document: string;
94
+ sha256: string;
95
+ };
96
+ }
97
+ export interface GraphQLCodegenResult {
98
+ /** The module to write. Null when a document failed. */
99
+ source: string | null;
100
+ operations: GeneratedOperation[];
101
+ problems: CodegenProblem[];
102
+ /**
103
+ * Each use of a deprecated field, argument, input field or enum value, with
104
+ * the reason the schema gives: it still works, and a later Capa-Version
105
+ * removes it.
106
+ */
107
+ warnings: CodegenProblem[];
108
+ /** Literals with a `${}` that names no literal of the project, so their text is only known at run time. */
109
+ skipped: SkippedDocument[];
110
+ }
111
+ /**
112
+ * The generated module for a schema and a project's documents. Problems (a
113
+ * syntax error, a field the key cannot read, an unnamed operation, a name used
114
+ * twice) are returned with their file and line, and no module is produced
115
+ * while any remain.
116
+ */
117
+ export declare function generateGraphQLModule(introspection: CapaIntrospection, sources: DocumentSource[]): GraphQLCodegenResult;