@foir/sdk 0.7.0 → 0.8.0
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 +805 -4
- package/README.md +46 -15
- package/dist/auth/auth.d.ts +104 -1
- package/dist/auth/index.d.ts +12 -6
- package/dist/auth/operations.d.ts +85 -64
- package/dist/auth/ops.d.ts +99 -0
- package/dist/auth.js +775 -106
- package/dist/chunk-IGNLWT3H.js +35 -0
- package/dist/chunk-OHYVKTGB.js +45 -0
- package/dist/chunk-TAL5H6VA.js +39 -0
- package/dist/client.js +25 -31
- package/dist/codegen/block-registry.d.ts +13 -19
- package/dist/codegen/block-registry.js +3 -31
- package/dist/codegen/block-scaffold.d.ts +12 -21
- package/dist/codegen/block-scaffold.js +3 -41
- package/dist/codegen/index.d.ts +9 -4
- package/dist/codegen/index.js +7 -11
- package/dist/codegen/item-registry.d.ts +28 -0
- package/dist/codegen/item-registry.js +7 -0
- package/dist/codegen/item-scaffold.d.ts +29 -0
- package/dist/codegen/item-scaffold.js +7 -0
- package/dist/codegen/preset.d.ts +14 -7
- package/dist/codegen/shared.d.ts +20 -9
- package/dist/content/content-renderer.d.ts +90 -24
- package/dist/content/index.d.ts +13 -7
- package/dist/content/richtext.d.ts +66 -18
- package/dist/content.js +227 -80
- package/dist/data/builtins.d.ts +302 -92
- package/dist/data/client.d.ts +97 -25
- package/dist/data/document.d.ts +251 -0
- package/dist/data/index.d.ts +38 -19
- package/dist/data/manifest.d.ts +266 -3
- package/dist/data/schema.d.ts +78 -8
- package/dist/data/selection.d.ts +231 -37
- package/dist/data/subjects.d.ts +221 -0
- package/dist/data/subscription-document.d.ts +75 -0
- package/dist/data/subscriptions.d.ts +181 -0
- package/dist/data/transport.d.ts +255 -37
- package/dist/data/ws-transport.d.ts +197 -0
- package/dist/data.js +1419 -45
- package/dist/graphql/cdn-route.d.ts +12 -28
- package/dist/media/index.d.ts +6 -2
- package/dist/media/media.d.ts +2 -2
- package/dist/media/screen-capture.d.ts +81 -0
- package/dist/media.js +97 -0
- package/dist/next.js +663 -182
- package/dist/push.js +700 -90
- package/dist/react/FoirFeedback.d.ts +62 -0
- package/dist/react/feedback-notes.d.ts +101 -0
- package/dist/react/index.d.ts +7 -1
- package/dist/react.js +1272 -194
- package/dist/realtime.js +1 -1
- package/dist/server/events-client.d.ts +279 -0
- package/dist/server/index.d.ts +4 -0
- package/dist/server.js +298 -0
- package/dist/transport/foir-http.d.ts +23 -6
- package/dist/transport/persisted-query.d.ts +68 -0
- package/dist/transport/retry.d.ts +1 -1
- package/package.json +13 -1
- package/dist/chunk-ADO5FJNM.js +0 -30
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* From a resolved selection tree to a GraphQL document string.
|
|
3
|
+
*
|
|
4
|
+
* ---------------------------------------------------------------------------
|
|
5
|
+
* Why there is no `graphql` dependency here, and never can be
|
|
6
|
+
* ---------------------------------------------------------------------------
|
|
7
|
+
*
|
|
8
|
+
* The tree arrives PRE-RESOLVED. The server walked the built schema once per
|
|
9
|
+
* schema version — unions expanded per member, response-shape aliases assigned,
|
|
10
|
+
* cycles broken, the field budget counted — and published the answer on
|
|
11
|
+
* `GET /v1/manifest`: `models.<key>.selection` for a model's own tree, and
|
|
12
|
+
* `ops.<op>.payload` for the shape of what each op actually returns. What is
|
|
13
|
+
* left at runtime is a filter and a printer, which is string building. That is
|
|
14
|
+
* the whole reason this client shrinks rather than inheriting
|
|
15
|
+
* `query_compiler.go` in TypeScript.
|
|
16
|
+
*
|
|
17
|
+
* The rule that keeps it that way: **nothing below may need to know something
|
|
18
|
+
* about the schema that the manifest does not publish.** Every decision here is
|
|
19
|
+
* made from a flag the tree carries (`alias`, `model`, `union`, `relation`,
|
|
20
|
+
* `truncated`), from a payload's stated `kind`, or from a published argument
|
|
21
|
+
* type. There is no table of op names, no inferred wrapper shape, and no type
|
|
22
|
+
* guessed from a JavaScript value.
|
|
23
|
+
*
|
|
24
|
+
* ---------------------------------------------------------------------------
|
|
25
|
+
* Arguments are variables, not literals
|
|
26
|
+
* ---------------------------------------------------------------------------
|
|
27
|
+
*
|
|
28
|
+
* The manifest publishes each argument's declared GraphQL type
|
|
29
|
+
* (`ops.<op>.argTypes`), so an argument is emitted as a variable definition and
|
|
30
|
+
* its value travels in `variables`:
|
|
31
|
+
*
|
|
32
|
+
* query PageFindMany($orderBy: [PageOrderByInput]) { pages(orderBy: $orderBy) { … } }
|
|
33
|
+
*
|
|
34
|
+
* That is not a nicety. A printer working from argument NAMES alone has to
|
|
35
|
+
* infer each value's literal form from the JavaScript value it holds, which is
|
|
36
|
+
* exact for strings, numbers, booleans and objects and **ambiguous for enums**:
|
|
37
|
+
* `orderBy: { createdAt: DESC }` needs `DESC` unquoted and the client holds the
|
|
38
|
+
* string `'DESC'`, indistinguishable from `naturalKey: "DESC"`. Putting the
|
|
39
|
+
* value in `variables` does not resolve the ambiguity, it removes it — the
|
|
40
|
+
* executor coerces against the declared input type, which is the same path the
|
|
41
|
+
* server's own `compileArgs` took so that no caller byte is spliced into query
|
|
42
|
+
* text.
|
|
43
|
+
*
|
|
44
|
+
* The second-order win is that the document text no longer varies with the
|
|
45
|
+
* argument VALUE, so a persisted-query registry holds one entry per op instead
|
|
46
|
+
* of one per argument tuple. Argument names are emitted in sorted order for the
|
|
47
|
+
* same reason: two callers passing the same arguments in a different object
|
|
48
|
+
* literal order must hash to one entry.
|
|
49
|
+
*
|
|
50
|
+
* An argument the manifest publishes no type for is REFUSED. Falling back to
|
|
51
|
+
* inferring a literal would reinstate the defect above under a condition no
|
|
52
|
+
* caller can see.
|
|
53
|
+
*/
|
|
54
|
+
import type { FoirManifestOp, FoirManifestRelation, FoirManifestSelection, FoirManifestSelectionField, FoirManifestSelectionUnion } from './manifest';
|
|
55
|
+
/**
|
|
56
|
+
* One model, as the printer needs it.
|
|
57
|
+
*
|
|
58
|
+
* A structural subset of `FoirManifestModel`, deliberately — so the two ways of
|
|
59
|
+
* getting here are the same shape and there is one code path, not two:
|
|
60
|
+
*
|
|
61
|
+
* - `foir types` bakes it into `foirSelections`, the runtime half of the
|
|
62
|
+
* generated module, and the client never fetches anything.
|
|
63
|
+
* - the fallback fetches `GET /v1/manifest` at construction and passes
|
|
64
|
+
* `manifest.models` straight in, because a `FoirManifestModel` already
|
|
65
|
+
* satisfies this interface.
|
|
66
|
+
*/
|
|
67
|
+
export interface FoirSelectionModel {
|
|
68
|
+
/** GraphQL type name, e.g. `'Page'`. Used when a polymorphic relation needs fragments. */
|
|
69
|
+
typeName: string;
|
|
70
|
+
/** Op name → root field, argument types and the resolved shape of the result. */
|
|
71
|
+
ops?: Readonly<Record<string, FoirManifestOp>>;
|
|
72
|
+
/** The complete-by-default selection for this model's own record payload. */
|
|
73
|
+
selection?: FoirManifestSelection;
|
|
74
|
+
/** Relations a caller may `include`. Needed to resolve an include's target. */
|
|
75
|
+
relations?: readonly FoirManifestRelation[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* One namespace, as the printer needs it.
|
|
79
|
+
*
|
|
80
|
+
* A namespace op is a `FoirManifestOp` exactly as a model op is, which is what
|
|
81
|
+
* makes `foir.ns.search.searchRecords()` and `foir.page.findMany()` the same
|
|
82
|
+
* code path below rather than two printers that agree by inspection.
|
|
83
|
+
*/
|
|
84
|
+
export interface FoirSelectionNamespace {
|
|
85
|
+
/** Op token → root field, argument types and the resolved shape of the result. */
|
|
86
|
+
ops?: Readonly<Record<string, FoirManifestOp>>;
|
|
87
|
+
}
|
|
88
|
+
/** Model key → its selection. What `foir types` emits as `foirSelections`. */
|
|
89
|
+
export type FoirSelections = Readonly<Record<string, FoirSelectionModel>>;
|
|
90
|
+
/** Namespace name → its ops. What `foir types` emits as `foirNamespaceSelections`. */
|
|
91
|
+
export type FoirNamespaceSelections = Readonly<Record<string, FoirSelectionNamespace>>;
|
|
92
|
+
/** Union type name → its expansion. What `foir types` emits as `foirSelectionUnions`. */
|
|
93
|
+
export type FoirSelectionUnions = Readonly<Record<string, FoirManifestSelectionUnion>>;
|
|
94
|
+
/** Everything the printer reads. `FoirManifest` satisfies it as-is. */
|
|
95
|
+
export interface FoirSelectionSource {
|
|
96
|
+
models: FoirSelections;
|
|
97
|
+
namespaces?: FoirNamespaceSelections;
|
|
98
|
+
selectionUnions?: FoirSelectionUnions;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* `_id` is emitted whatever the caller asked for — the server's own
|
|
102
|
+
* `protectedSelectionFields` does the same, and a record you cannot address is
|
|
103
|
+
* not a useful answer. Named here so `pick` adds it back and `omit` refuses it.
|
|
104
|
+
*
|
|
105
|
+
* Exported because the subject registry reads it back off the response: every
|
|
106
|
+
* record in a response carries this key precisely because no narrowing can
|
|
107
|
+
* remove it, and that guarantee is this constant's, not the registry's.
|
|
108
|
+
*/
|
|
109
|
+
export declare const PROTECTED_ROOT_FIELD = "_id";
|
|
110
|
+
/**
|
|
111
|
+
* Print a complete selection body from a resolved tree, with no narrowing.
|
|
112
|
+
*
|
|
113
|
+
* The one entry point for a caller that has a `ManifestSelection` and wants the
|
|
114
|
+
* whole of it — today, the subscription transport, whose payload trees the
|
|
115
|
+
* manifest publishes exactly as it publishes a model's.
|
|
116
|
+
*
|
|
117
|
+
* It exists so there is ONE implementation of "walk a resolved tree and emit
|
|
118
|
+
* braces". Every rule a reader would otherwise have to re-derive lives in
|
|
119
|
+
* `printFields`: relations are include-governed and skipped, a `truncated` field
|
|
120
|
+
* degrades to `__typename` rather than an illegal empty body, a union emits
|
|
121
|
+
* `__typename` plus one inline fragment per member, a `model` reference expands
|
|
122
|
+
* to that model's published tree, and an alias prints as `alias: key`. A second
|
|
123
|
+
* walk elsewhere in this package would be correct on the day it was written and
|
|
124
|
+
* wrong on the day any of those changed.
|
|
125
|
+
*
|
|
126
|
+
* `isRoot` is false: the `_id` protection is a property of a MODEL's root
|
|
127
|
+
* selection, and an event payload has no records in it to address.
|
|
128
|
+
*/
|
|
129
|
+
export declare function printFoirSelectionBody(fields: readonly FoirManifestSelectionField[], unions: FoirSelectionUnions, models?: FoirSelections): string;
|
|
130
|
+
/**
|
|
131
|
+
* Where a payload puts a record, and which model it is.
|
|
132
|
+
*
|
|
133
|
+
* `record` names one outright, AT THE PAYLOAD ROOT — an empty path. An `object`
|
|
134
|
+
* payload reaches one through a `model` reference at some depth (`edges.node`,
|
|
135
|
+
* `record`), and the path is the RESPONSE keys to it, so an aliased field
|
|
136
|
+
* contributes its alias rather than its key.
|
|
137
|
+
*
|
|
138
|
+
* The empty path is therefore not merely a position: it is the manifest saying
|
|
139
|
+
* this op's result IS one record, which is what the subject registry reads as
|
|
140
|
+
* "the caller addressed this record by name".
|
|
141
|
+
*/
|
|
142
|
+
export interface FoirRecordPath {
|
|
143
|
+
/** Response keys from the root field's value down to the record. */
|
|
144
|
+
path: readonly string[];
|
|
145
|
+
/** Model key whose published `selection` is printed at that position. */
|
|
146
|
+
modelKey: string;
|
|
147
|
+
}
|
|
148
|
+
/** One printed operation, and what the transport needs to route it. */
|
|
149
|
+
export interface FoirDocumentPlan {
|
|
150
|
+
/** The document text. Also the thing that gets hashed for APQ. */
|
|
151
|
+
document: string;
|
|
152
|
+
/** The argument values, sent beside the document. Empty when the op takes none. */
|
|
153
|
+
variables: Record<string, unknown>;
|
|
154
|
+
/** True when the op lives on the Mutation root. Decides the route and the keyword. */
|
|
155
|
+
mutation: boolean;
|
|
156
|
+
/** The single root field the response is keyed by. */
|
|
157
|
+
rootField: string;
|
|
158
|
+
/**
|
|
159
|
+
* Fields this document selects, in the unit the server's complexity ceiling is
|
|
160
|
+
* denominated in — the same number `CompiledQuery.Fields` carries on the
|
|
161
|
+
* server side.
|
|
162
|
+
*
|
|
163
|
+
* Measured while printing rather than derived afterwards, and exposed rather
|
|
164
|
+
* than kept private so it is TESTABLE against the document it describes: a
|
|
165
|
+
* counter nobody can compare to the artefact is a counter that drifts from it.
|
|
166
|
+
*
|
|
167
|
+
* OPTIONAL because a plan is not only something this file returns — a
|
|
168
|
+
* hand-built one is a real pattern for executing a document the printer did
|
|
169
|
+
* not produce, and requiring the count there would mean requiring a caller to
|
|
170
|
+
* invent a number about a document this code never measured. Everything
|
|
171
|
+
* `planFoirModelCall` / `planFoirNamespaceCall` return sets it.
|
|
172
|
+
*/
|
|
173
|
+
fields?: number;
|
|
174
|
+
/**
|
|
175
|
+
* Where the records this document selects sit in the response, and which
|
|
176
|
+
* model each one is.
|
|
177
|
+
*
|
|
178
|
+
* Read by the subject registry (`subjects.ts`) to answer "what did this page
|
|
179
|
+
* fetch" without inspecting the response's shape — the manifest already said
|
|
180
|
+
* where the records would be, so hunting for objects carrying an `_id` would
|
|
181
|
+
* be re-deriving something published.
|
|
182
|
+
*
|
|
183
|
+
* OPTIONAL for the same reason `fields` is: a hand-built plan for a document
|
|
184
|
+
* this printer never produced has no published payload to read positions off,
|
|
185
|
+
* and inventing them would put subjects against records nobody can vouch for.
|
|
186
|
+
* Absent means "this call records nothing", never "this call fetched nothing".
|
|
187
|
+
*/
|
|
188
|
+
records?: readonly FoirRecordPath[];
|
|
189
|
+
}
|
|
190
|
+
/** What a model call carries, already split out of the caller's flat query object. */
|
|
191
|
+
export interface FoirCall {
|
|
192
|
+
model: string;
|
|
193
|
+
op: string;
|
|
194
|
+
args: Record<string, unknown>;
|
|
195
|
+
include?: Record<string, unknown>;
|
|
196
|
+
omit?: readonly string[];
|
|
197
|
+
pick?: readonly string[];
|
|
198
|
+
/** Union levels to expand. See `FoirNamespaceCall.depth`. */
|
|
199
|
+
depth?: number;
|
|
200
|
+
}
|
|
201
|
+
/** What a namespace call carries. Same shape, addressed by namespace. */
|
|
202
|
+
export interface FoirNamespaceCall {
|
|
203
|
+
namespace: string;
|
|
204
|
+
op: string;
|
|
205
|
+
args: Record<string, unknown>;
|
|
206
|
+
include?: Record<string, unknown>;
|
|
207
|
+
omit?: readonly string[];
|
|
208
|
+
pick?: readonly string[];
|
|
209
|
+
/**
|
|
210
|
+
* How many union levels to expand, default `1`.
|
|
211
|
+
*
|
|
212
|
+
* A block union's members can themselves carry block unions, and the server
|
|
213
|
+
* refuses to expand a union already on the current path — so the complete
|
|
214
|
+
* document stops one level in and says so, publishing the union name it
|
|
215
|
+
* stopped in front of. Each level above 1 spends one of those stopping points.
|
|
216
|
+
*
|
|
217
|
+
* It is a BUDGET rather than a setting, though a much larger one since
|
|
218
|
+
* TTS-1448: on a real project the same op measures 318 fields at level 1, 468
|
|
219
|
+
* at level 2 and 618 at level 3, against a server ceiling of 10,000. Those
|
|
220
|
+
* were 837 / 3,513 / 14,217 while a union position was charged every member it
|
|
221
|
+
* could hold rather than the one a value can be.
|
|
222
|
+
*
|
|
223
|
+
* What a level costs is one more expansion at each STOPPING POINT inside the
|
|
224
|
+
* expansion, so it still compounds where a member carries several union-typed
|
|
225
|
+
* fields — and it no longer grows at all with how many members the union has.
|
|
226
|
+
* Where a level does cross the ceiling, `planCall` refuses and names the
|
|
227
|
+
* count, rather than letting the server answer with a number the caller
|
|
228
|
+
* cannot act on.
|
|
229
|
+
*/
|
|
230
|
+
depth?: number;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Turn a model call into a document.
|
|
234
|
+
*
|
|
235
|
+
* Every op is printable or REFUSED. There is no third answer: an op the
|
|
236
|
+
* manifest describes no payload for is one this client would have to invent a
|
|
237
|
+
* shape for, and inventing one is what this design exists to stop.
|
|
238
|
+
*/
|
|
239
|
+
export declare function planFoirModelCall(source: FoirSelectionSource, call: FoirCall): FoirDocumentPlan;
|
|
240
|
+
/**
|
|
241
|
+
* Turn a namespace call into a document.
|
|
242
|
+
*
|
|
243
|
+
* Identical to `planFoirModelCall` below the addressing, and deliberately the
|
|
244
|
+
* same function underneath: a namespace op is a `FoirManifestOp` carrying a
|
|
245
|
+
* payload exactly as a model op is, so `foir.ns.search.searchRecords()` is
|
|
246
|
+
* printed by the code that prints `foir.page.findMany()` rather than by a
|
|
247
|
+
* second printer that agrees with it by inspection.
|
|
248
|
+
*/
|
|
249
|
+
export declare function planFoirNamespaceCall(source: FoirSelectionSource, call: FoirNamespaceCall): FoirDocumentPlan;
|
|
250
|
+
/** True when a hand-written document is a mutation, so it never takes the shared lane. */
|
|
251
|
+
export declare function isFoirMutationDocument(documentText: string): boolean;
|
package/dist/data/index.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@foir/sdk/data` — the typed data client.
|
|
3
3
|
*
|
|
4
|
-
* A
|
|
5
|
-
* shaped by the credential you hand it.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
4
|
+
* A typed client over the same GraphQL endpoint `@foir/sdk/client` posts to,
|
|
5
|
+
* shaped by the credential you hand it. It sends a GraphQL document like every
|
|
6
|
+
* other consumer — one execution surface, the same executor, the same scope
|
|
7
|
+
* checks, the same response cache — but you never write one: the document is
|
|
8
|
+
* printed from the selection tree the manifest publishes for that op.
|
|
9
|
+
*
|
|
10
|
+
* What you get over the hand-written GraphQL path: no `.graphql` documents, no
|
|
11
|
+
* `graphql-codegen` step, and **no `graphql` dependency at all**. Printing a
|
|
12
|
+
* pre-resolved tree is string building. This subpath imports neither `graphql`
|
|
13
|
+
* nor `@graphql-typed-document-node/core`; the import graph is asserted
|
|
14
|
+
* graphql-free by `__tests__/data.test.ts`
|
|
15
15
|
* ("`@foir/sdk/data` has zero graphql dependency").
|
|
16
16
|
*
|
|
17
17
|
* `./data` and not `./client` because `./client` is the editor-iframe/GraphQL
|
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
*
|
|
20
20
|
* ```ts
|
|
21
21
|
* import { createFoirClient } from '@foir/sdk/data';
|
|
22
|
-
* import
|
|
22
|
+
* import * as generated from './foir.generated';
|
|
23
23
|
*
|
|
24
|
-
* const foir = createFoirClient
|
|
24
|
+
* const foir = createFoirClient({
|
|
25
25
|
* apiUrl: 'https://api.foir.dev',
|
|
26
26
|
* apiKey: process.env.PLATFORM_API_KEY!,
|
|
27
|
-
*
|
|
27
|
+
* generated,
|
|
28
28
|
* });
|
|
29
29
|
*
|
|
30
30
|
* const page = await foir.page.findUnique({
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
* });
|
|
35
35
|
*
|
|
36
36
|
* const results = await foir.ns.search.searchRecords({ query: 'shoes' });
|
|
37
|
-
* const anything = await foir.raw({
|
|
37
|
+
* const anything = await foir.raw('{ designTokens { name value } }');
|
|
38
38
|
* ```
|
|
39
39
|
*
|
|
40
40
|
* `FoirSchema` comes from `foir types` (TTS-875). The contract it generates
|
|
@@ -44,10 +44,29 @@
|
|
|
44
44
|
export { createFoirClient, createFoirClientFromEnv } from './client';
|
|
45
45
|
export type { FoirClient, FoirClientCore, FoirModelClient, FoirNamespaceClient } from './client';
|
|
46
46
|
export { fetchFoirManifest } from './manifest';
|
|
47
|
-
export type { FoirManifest, FoirManifestComposite, FoirManifestModel, FoirManifestNamespace, FoirManifestOp, FoirManifestRelation, FoirManifestScalar, FoirManifestUnclassifiedField, } from './manifest';
|
|
48
|
-
export
|
|
49
|
-
export {
|
|
50
|
-
export
|
|
47
|
+
export type { FoirManifest, FoirManifestComposite, FoirManifestModel, FoirManifestNamespace, FoirManifestOp, FoirManifestOpPayload, FoirManifestRelation, FoirManifestScalar, FoirManifestSelection, FoirManifestSelectionField, FoirManifestSelectionMember, FoirManifestSelectionUnion, FoirManifestSubscription, FoirManifestSubscriptionArgScope, FoirManifestUnclassifiedField, } from './manifest';
|
|
48
|
+
export { planFoirModelCall, planFoirNamespaceCall } from './document';
|
|
49
|
+
export type { FoirCall, FoirDocumentPlan, FoirNamespaceCall, FoirNamespaceSelections, FoirRecordPath, FoirSelectionModel, FoirSelectionNamespace, FoirSelections, FoirSelectionSource, FoirSelectionUnions, } from './document';
|
|
50
|
+
export { createFoirSubjectRegistry, recordFoirSubjects } from './subjects';
|
|
51
|
+
export type { FoirSubject, FoirSubjectEntry, FoirSubjectOptions, FoirSubjectOrigin, FoirSubjectRegistry, } from './subjects';
|
|
52
|
+
export type { CollabInfo, FileValue, FoirAccessGrant, FoirAccessLevel, FoirAccessSource, FoirAccessor, FoirCreateMyNoteArgs, FoirCustomerNote, FoirCustomerNoteAttachment, FoirDegraded, FoirDepthBelow, FoirDepthLevel, FoirDeviceType, FoirGranteeKind, FoirJsonValue, FoirMyAccess, FoirMyNotesArgs, FoirMyNotesResult, FoirNoteConfig, FoirNoteSubjectType, FoirPlatformType, FoirResolveContext, FoirResourceAccess, FoirUnexpandedRecord, FoirUpdateManyPayload, FoirVisibility, GeoPoint, Image, ImageFormat, ImageVariant, ImageVariantSet, MediaValue, Reference, Richtext, Video, } from './builtins';
|
|
53
|
+
/**
|
|
54
|
+
* Pre-TTS-1391 spellings. The `<Name>Block` wrappers and the `<Name>Value`
|
|
55
|
+
* split are the same thing as the types above — an item IS its value — so each
|
|
56
|
+
* of these is an alias, not a separate shape.
|
|
57
|
+
*
|
|
58
|
+
* `MediaBlock`, `TextBlock`, `FlexibleBlock` and `FoirBlockMeta` are NOT here:
|
|
59
|
+
* they described a wrapper, a member and an envelope the platform no longer
|
|
60
|
+
* emits, so there is nothing for them to alias. See `builtins.ts`.
|
|
61
|
+
*/
|
|
62
|
+
export type { FileBlock, GeoPointValue, ImageBlock, ImageValue, ReferenceBlock, ReferenceValue, RichtextBlock, RichtextValue, VideoBlock, VideoValue, } from './builtins';
|
|
63
|
+
export { foirDataEndpoint, foirRoute } from './transport';
|
|
64
|
+
export type { FoirClientConfig, FoirGeneratedModule, FoirLane, FoirLaneReason, FoirRouteDecision, FoirRouteInput, FoirSchemaDrift, } from './transport';
|
|
65
|
+
export { foirSocketEndpoint, FoirSocketTransport } from './ws-transport';
|
|
66
|
+
export type { FoirReconnectPolicy, FoirSubscribeRequest, FoirSubscription, FoirSubscriptionHandlers, FoirWebSocketFactory, FoirWebSocketLike, } from './ws-transport';
|
|
67
|
+
export { printSubscriptionDocument } from './subscription-document';
|
|
68
|
+
export type { FoirSubscriptionArgument, PrintSubscriptionDocumentInput, } from './subscription-document';
|
|
69
|
+
export type { FoirExecutionSubscribeOptions, FoirJobProgressEvent, FoirModelSubscriptions, FoirNamespaceSubscriptions, FoirNotificationEvent, FoirOperationExecutionEvent, FoirRecordChangedEvent, } from './subscriptions';
|
|
51
70
|
export type { FoirConnection, FoirFieldsShape, FoirModelDefinition, FoirNamespaceDefinition, FoirNamespaceOpDefinition, FoirOpDefinition, FoirRelationDefinition, FoirReturnDefinition, FoirSchemaDefinition, } from './schema';
|
|
52
71
|
export type { FoirInclude, FoirModelOperation, FoirNamespaceOperation, FoirOmittableKey, FoirOpResult, FoirQuery, FoirRecordResult, } from './selection';
|
|
53
72
|
export { FoirRequestError } from '../transport/foir-http';
|
package/dist/data/manifest.d.ts
CHANGED
|
@@ -20,9 +20,9 @@ export interface FoirManifestScalar {
|
|
|
20
20
|
/**
|
|
21
21
|
* GraphQL named type: a scalar (`String`, `Float`, `Boolean`, `ID`,
|
|
22
22
|
* `DateTime`, `JSON`), a generated enum (then `enumValues` is set), or one of
|
|
23
|
-
* the closed set of platform-owned value objects (`
|
|
24
|
-
* `FileValue`, `MediaValue`, `
|
|
25
|
-
* `
|
|
23
|
+
* the closed set of platform-owned value objects (`Image`, `Video`,
|
|
24
|
+
* `FileValue`, `MediaValue`, `Richtext`, `GeoPoint`,
|
|
25
|
+
* `Reference`, `CollabInfo`) — see `builtins.ts`.
|
|
26
26
|
*/
|
|
27
27
|
type: string;
|
|
28
28
|
/**
|
|
@@ -72,8 +72,72 @@ export interface FoirManifestOp {
|
|
|
72
72
|
/** GraphQL root field this op compiles to, e.g. `tillyBlocks`. */
|
|
73
73
|
field: string;
|
|
74
74
|
args?: string[];
|
|
75
|
+
/**
|
|
76
|
+
* Each name in `args` mapped to the GraphQL type the root field declares for
|
|
77
|
+
* it — `'String!'`, `'[PageOrderByInput]'`, `'SortDirection'` — spelled
|
|
78
|
+
* exactly as a variable definition needs it.
|
|
79
|
+
*
|
|
80
|
+
* This is what lets the printer emit `query FoirQuery($orderBy: [PageOrderByInput])`
|
|
81
|
+
* and put the value in `variables`, where the executor coerces it. Without
|
|
82
|
+
* the type a printer has to infer a LITERAL from the JavaScript value, which
|
|
83
|
+
* is exact for strings, numbers, booleans and objects and ambiguous for
|
|
84
|
+
* enums — the client holds the string `'DESC'` and `orderBy: { createdAt: DESC }`
|
|
85
|
+
* needs it unquoted.
|
|
86
|
+
*
|
|
87
|
+
* An argument named in `args` with no entry here has no type this projection
|
|
88
|
+
* could read. The printer REFUSES such a call: inferring the literal form
|
|
89
|
+
* from the value is the defect this field exists to remove, so falling back
|
|
90
|
+
* to it would reintroduce it under a condition nobody can see.
|
|
91
|
+
*/
|
|
92
|
+
argTypes?: Record<string, string>;
|
|
75
93
|
/** True when the field lives on the Mutation root. */
|
|
76
94
|
mutation?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* The resolved shape of this op's RESULT.
|
|
97
|
+
*
|
|
98
|
+
* The model's own `selection` answers for `findUnique` and for nothing else:
|
|
99
|
+
* `findMany` returns a connection OVER the model, `search` returns a wrapper
|
|
100
|
+
* CARRYING it, `delete` returns `Boolean!`, and `myAccess` returns a payload
|
|
101
|
+
* that is not the model in any sense. A consumer that bridged that gap by
|
|
102
|
+
* knowing from the OP NAME which shape to print was carrying a schema under
|
|
103
|
+
* another name.
|
|
104
|
+
*
|
|
105
|
+
* Absent is not "no selection". A consumer must refuse the op rather than
|
|
106
|
+
* synthesise a shape for it.
|
|
107
|
+
*/
|
|
108
|
+
payload?: FoirManifestOpPayload;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The resolved shape of one op's result — four kinds, and the printer handles
|
|
112
|
+
* all four rather than defaulting.
|
|
113
|
+
*/
|
|
114
|
+
export interface FoirManifestOpPayload {
|
|
115
|
+
/**
|
|
116
|
+
* - `record` — the payload IS the model named by `model`; print that model's
|
|
117
|
+
* published `selection` as the root field's selection set.
|
|
118
|
+
* - `object` — `fields` is the resolved selection set. A field carrying
|
|
119
|
+
* `model` expands to that model's `selection`, which is how the connection
|
|
120
|
+
* and search-result wrappers keep the record's tree in one place instead of
|
|
121
|
+
* copying it per op.
|
|
122
|
+
* - `union` — print one inline fragment per member of `selectionUnions[union]`.
|
|
123
|
+
* - `leaf` — `Boolean!`, `Int`, an enum. NO selection set: emitting `{}` is a
|
|
124
|
+
* parse error, which is why this is a stated kind rather than empty `fields`.
|
|
125
|
+
*/
|
|
126
|
+
kind: 'record' | 'object' | 'union' | 'leaf';
|
|
127
|
+
/** Model key, for kind `record`. */
|
|
128
|
+
model?: string;
|
|
129
|
+
/** `selectionUnions` key, for kind `union`. */
|
|
130
|
+
union?: string;
|
|
131
|
+
/** The resolved selection, for kind `object`. */
|
|
132
|
+
fields?: FoirManifestSelectionField[];
|
|
133
|
+
/** What this payload emits when printed whole, in `FoirManifestSelection.cost`'s unit. */
|
|
134
|
+
cost?: number;
|
|
135
|
+
/**
|
|
136
|
+
* Why this payload could not be resolved. Set INSTEAD of the shape fields,
|
|
137
|
+
* never beside them — an op carrying an error has no printable shape and a
|
|
138
|
+
* consumer must refuse it.
|
|
139
|
+
*/
|
|
140
|
+
error?: string;
|
|
77
141
|
}
|
|
78
142
|
/** A built field the projection has no bucket for. Reported rather than dropped. */
|
|
79
143
|
export interface FoirManifestUnclassifiedField {
|
|
@@ -95,6 +159,16 @@ export interface FoirManifestModel {
|
|
|
95
159
|
* survived pruning — hence optional, not `{}`.
|
|
96
160
|
*/
|
|
97
161
|
ops?: Record<string, FoirManifestOp>;
|
|
162
|
+
/**
|
|
163
|
+
* The resolved complete-by-default selection for this model. Present on a
|
|
164
|
+
* server that publishes selection trees; absent otherwise.
|
|
165
|
+
*
|
|
166
|
+
* It hangs off the MODEL rather than each op because every op whose payload
|
|
167
|
+
* is this model shares one selection root.
|
|
168
|
+
*/
|
|
169
|
+
selection?: FoirManifestSelection;
|
|
170
|
+
/** Why `selection` is absent, when the server could not resolve one. */
|
|
171
|
+
selectionError?: string;
|
|
98
172
|
scalars: FoirManifestScalar[];
|
|
99
173
|
relations: FoirManifestRelation[];
|
|
100
174
|
composites: FoirManifestComposite[];
|
|
@@ -108,6 +182,37 @@ export interface FoirManifestModel {
|
|
|
108
182
|
unions?: Record<string, string[]>;
|
|
109
183
|
/** Op names of this model's typed lookups. Each also appears in `ops`. */
|
|
110
184
|
lookups?: string[];
|
|
185
|
+
/**
|
|
186
|
+
* The model's `<Type>OrderByInput`, projected — the vocabulary of the
|
|
187
|
+
* `orderBy` argument.
|
|
188
|
+
*
|
|
189
|
+
* `fields` are the entry keys a sort element may carry; `directions` are the
|
|
190
|
+
* value names of the enum those entries are typed as (`ASC` / `DESC`). Both
|
|
191
|
+
* are read off the built input object server-side, so neither can disagree
|
|
192
|
+
* with what the executor coerces a caller's `orderBy` against.
|
|
193
|
+
*
|
|
194
|
+
* IT IS PUBLISHED BECAUSE NOTHING ELSE HERE ANSWERS FOR IT, and `scalars` —
|
|
195
|
+
* the field that looks like it should — is wrong in both directions at once:
|
|
196
|
+
*
|
|
197
|
+
* - wrong SET: `hero` (`Image`), `body` (`Richtext`), `_segments`
|
|
198
|
+
* (`JSON`) and every soft-deleted field are scalars and none is sortable;
|
|
199
|
+
* - wrong NAMES: the platform-managed columns are `_id` / `_createdAt` /
|
|
200
|
+
* `_updatedAt` / `_naturalKey` on the record type and `id` / `createdAt` /
|
|
201
|
+
* `updatedAt` / `naturalKey` in `OrderByInput`. A consumer deriving sort
|
|
202
|
+
* keys from the scalar list emits `_createdAt`, which the server refuses.
|
|
203
|
+
*
|
|
204
|
+
* `ops[op].argTypes.orderBy` names the input type (`[PageOrderByInput]`) and
|
|
205
|
+
* stops there: enough to print a variable definition, not enough to type a
|
|
206
|
+
* call site.
|
|
207
|
+
*
|
|
208
|
+
* ABSENT means "this projection has nothing to say" — an embedded model, or a
|
|
209
|
+
* server that predates the field. A consumer must WIDEN on absent, never read
|
|
210
|
+
* it as "nothing is sortable".
|
|
211
|
+
*/
|
|
212
|
+
orderBy?: {
|
|
213
|
+
fields: string[];
|
|
214
|
+
directions: string[];
|
|
215
|
+
};
|
|
111
216
|
unclassifiedFields?: FoirManifestUnclassifiedField[];
|
|
112
217
|
cacheControl?: {
|
|
113
218
|
scope: string;
|
|
@@ -133,6 +238,20 @@ export interface FoirManifestNamespace {
|
|
|
133
238
|
execute?: string[];
|
|
134
239
|
/** `operations` only: operation keys reachable as `query.<key>`. */
|
|
135
240
|
query?: string[];
|
|
241
|
+
/**
|
|
242
|
+
* Each of those root fields described the way a model op is described:
|
|
243
|
+
* arguments with their types, and the resolved shape of the result.
|
|
244
|
+
*
|
|
245
|
+
* Keyed by the token the op is ADDRESSED by — the root field name for every
|
|
246
|
+
* namespace but `operations`, where it is `execute.<key>` / `query.<key>` for
|
|
247
|
+
* the per-operation surfaces and the plain field name for the bookkeeping
|
|
248
|
+
* ones. The lists above stay authoritative for REACHABILITY; this is the
|
|
249
|
+
* description of what those names do.
|
|
250
|
+
*
|
|
251
|
+
* Because an entry is a `FoirManifestOp`, whatever prints a model op prints a
|
|
252
|
+
* namespace op — one code path, not two.
|
|
253
|
+
*/
|
|
254
|
+
ops?: Record<string, FoirManifestOp>;
|
|
136
255
|
}
|
|
137
256
|
export interface FoirManifest {
|
|
138
257
|
schemaVersion: number;
|
|
@@ -149,7 +268,151 @@ export interface FoirManifest {
|
|
|
149
268
|
unclassified?: {
|
|
150
269
|
queries?: string[];
|
|
151
270
|
mutations?: string[];
|
|
271
|
+
/**
|
|
272
|
+
* Subscription root fields the server declined to state the reachability
|
|
273
|
+
* of — today only `events`, whose scope is charged against the resolved
|
|
274
|
+
* data-plane authority rather than the api key's own scope set. Reported so
|
|
275
|
+
* the gap is visible; nothing is generated from it.
|
|
276
|
+
*/
|
|
277
|
+
subscriptions?: string[];
|
|
152
278
|
};
|
|
279
|
+
/**
|
|
280
|
+
* Each union's expansion, once, keyed by union type name. A selection field
|
|
281
|
+
* references one by name rather than inlining it — seven models reaching one
|
|
282
|
+
* 56-member block union inlined it seven times and made the manifest 6.9x
|
|
283
|
+
* larger, 85% of it duplication.
|
|
284
|
+
*
|
|
285
|
+
* Absent on a server that predates selection trees, which is why every
|
|
286
|
+
* consumer must treat it as optional rather than assume the shape.
|
|
287
|
+
*/
|
|
288
|
+
selectionUnions?: Record<string, FoirManifestSelectionUnion>;
|
|
289
|
+
/**
|
|
290
|
+
* Subscription root fields this credential may open over `/graphql/ws`.
|
|
291
|
+
*
|
|
292
|
+
* Unlike `models[].ops`, this list is NOT derived from the caller's schema
|
|
293
|
+
* variant: the server copies the whole Subscription root into every variant
|
|
294
|
+
* (the transport is out of band), so the variant admits all of them to
|
|
295
|
+
* everybody. The list is projected from the same table the socket charges at
|
|
296
|
+
* subscribe time, which is what makes it safe to generate against — a field
|
|
297
|
+
* that is here will be accepted, and one that is absent will be refused.
|
|
298
|
+
*/
|
|
299
|
+
subscriptions?: FoirManifestSubscription[];
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* One subscription root field, with the tree a document is printed from.
|
|
303
|
+
*/
|
|
304
|
+
export interface FoirManifestSubscription {
|
|
305
|
+
/** The Subscription root field name. */
|
|
306
|
+
field: string;
|
|
307
|
+
/** Argument names, sorted. */
|
|
308
|
+
args?: string[];
|
|
309
|
+
/**
|
|
310
|
+
* Each name in `args` mapped to the GraphQL type the field declares for it —
|
|
311
|
+
* `'String!'` — spelled exactly as a variable definition needs it, and for
|
|
312
|
+
* the same reason `FoirManifestOp.argTypes` exists: a subscribe frame carries
|
|
313
|
+
* a `variables` object like any other operation, so without the type a
|
|
314
|
+
* consumer would have to infer a literal form from the value it holds.
|
|
315
|
+
*
|
|
316
|
+
* It also decides the variable NAME. The socket resolves an argument-gated
|
|
317
|
+
* subscription's scope by reading `variables[<arg>]` BY NAME, so
|
|
318
|
+
* `subscription S($m: String!) { recordChanged(modelKey: $m) … }` opens and is
|
|
319
|
+
* then refused for a scope it cannot complete. Declaring `$<arg>` — which is
|
|
320
|
+
* what a printer driven by this map does — is what keeps the two in step.
|
|
321
|
+
*/
|
|
322
|
+
argTypes?: Record<string, string>;
|
|
323
|
+
/** GraphQL named type of the event payload. */
|
|
324
|
+
type: string;
|
|
325
|
+
/**
|
|
326
|
+
* The scope the socket charges. Empty exactly when `argScope` is set. Carried
|
|
327
|
+
* so a client can say WHICH capability a refusal was about instead of
|
|
328
|
+
* reporting a bare failure.
|
|
329
|
+
*/
|
|
330
|
+
scope?: string;
|
|
331
|
+
/** Set when the required scope is completed by a subscribe argument. */
|
|
332
|
+
argScope?: FoirManifestSubscriptionArgScope;
|
|
333
|
+
/** Resolved complete-by-default selection for the payload type. */
|
|
334
|
+
selection?: FoirManifestSelection;
|
|
335
|
+
/** Why `selection` is absent. Absent is not "no fields". */
|
|
336
|
+
selectionError?: string;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* A subscription whose authorization depends on a value supplied at subscribe
|
|
340
|
+
* time.
|
|
341
|
+
*
|
|
342
|
+
* `recordChanged` is the one instance: the socket charges
|
|
343
|
+
* `records:read:<modelKey>` against the `modelKey` variable, so the field has
|
|
344
|
+
* no static yes/no. What is statically true is which values this credential's
|
|
345
|
+
* scopes admit, and that is what `values` carries.
|
|
346
|
+
*/
|
|
347
|
+
export interface FoirManifestSubscriptionArgScope {
|
|
348
|
+
/** The subscribe argument whose value completes the scope. */
|
|
349
|
+
arg: string;
|
|
350
|
+
/** What the argument's value is appended to. */
|
|
351
|
+
prefix: string;
|
|
352
|
+
/**
|
|
353
|
+
* The argument values this credential admits, sorted. The ADDRESSABLE set,
|
|
354
|
+
* not a proof of exhaustiveness — a key holding the two-part `records:read`
|
|
355
|
+
* satisfies the socket for any string at all.
|
|
356
|
+
*/
|
|
357
|
+
values: string[];
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* A resolved complete-by-default selection: what to ask for, already expanded.
|
|
361
|
+
*
|
|
362
|
+
* The server resolves this once per schema version — unions expanded per
|
|
363
|
+
* member, response-shape aliases assigned, cycles broken, field budget
|
|
364
|
+
* counted — so printing a document is string building rather than a schema
|
|
365
|
+
* walk. Nothing here requires the consumer to know a field's GraphQL type.
|
|
366
|
+
*/
|
|
367
|
+
export interface FoirManifestSelection {
|
|
368
|
+
fields: FoirManifestSelectionField[];
|
|
369
|
+
/**
|
|
370
|
+
* Fields this tree emits when printed whole, relations excluded. Same unit
|
|
371
|
+
* the executor's complexity budget is denominated in.
|
|
372
|
+
*/
|
|
373
|
+
cost: number;
|
|
374
|
+
}
|
|
375
|
+
export interface FoirManifestSelectionField {
|
|
376
|
+
key: string;
|
|
377
|
+
/**
|
|
378
|
+
* The response key to emit instead of `key`, set only where a union member's
|
|
379
|
+
* field name collides with an incompatible shape on another member. A
|
|
380
|
+
* consumer prints `alias: key` and types the result under `alias`.
|
|
381
|
+
*/
|
|
382
|
+
alias?: string;
|
|
383
|
+
/** Nested selection for a composite or a builtin value object. */
|
|
384
|
+
fields?: FoirManifestSelectionField[];
|
|
385
|
+
/**
|
|
386
|
+
* Names a model whose published `selection` IS this field's selection.
|
|
387
|
+
*
|
|
388
|
+
* It appears where a record turns up inside a payload the caller did not
|
|
389
|
+
* address the record through: a connection's `node`, a search result's
|
|
390
|
+
* `record`. A REFERENCE rather than an inlined copy, so seven ops over one
|
|
391
|
+
* model do not carry seven copies of its tree — and so a caller's `omit`
|
|
392
|
+
* reaches the same tree whichever op it came through.
|
|
393
|
+
*/
|
|
394
|
+
model?: string;
|
|
395
|
+
/** Names an entry in `FoirManifest.selectionUnions`. */
|
|
396
|
+
union?: string;
|
|
397
|
+
/**
|
|
398
|
+
* `include` governs this field, so it is NOT part of the default document.
|
|
399
|
+
* Emit it only when the caller asks for it.
|
|
400
|
+
*/
|
|
401
|
+
relation?: boolean;
|
|
402
|
+
/**
|
|
403
|
+
* The cycle or depth rule stopped expansion here. Still selectable, but only
|
|
404
|
+
* as `__typename` — print that rather than an empty body, which is a parse
|
|
405
|
+
* error.
|
|
406
|
+
*/
|
|
407
|
+
truncated?: boolean;
|
|
408
|
+
}
|
|
409
|
+
export interface FoirManifestSelectionUnion {
|
|
410
|
+
/** Sorted by type name, so the expansion is stable across runs. */
|
|
411
|
+
members: FoirManifestSelectionMember[];
|
|
412
|
+
}
|
|
413
|
+
export interface FoirManifestSelectionMember {
|
|
414
|
+
typeName: string;
|
|
415
|
+
fields: FoirManifestSelectionField[];
|
|
153
416
|
}
|
|
154
417
|
/**
|
|
155
418
|
* Fetch the manifest for the credential in `config`.
|