@foir/sdk 0.5.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.
Files changed (107) hide show
  1. package/CHANGELOG.md +1126 -0
  2. package/README.md +94 -0
  3. package/dist/auth/auth.d.ts +243 -0
  4. package/dist/auth/hosted.d.ts +40 -0
  5. package/dist/auth/index.d.ts +21 -0
  6. package/dist/auth/operations.d.ts +144 -0
  7. package/dist/auth/ops.d.ts +99 -0
  8. package/dist/auth/session-client.d.ts +76 -0
  9. package/dist/auth-session.js +137 -0
  10. package/dist/auth.js +973 -92
  11. package/dist/chunk-IGNLWT3H.js +35 -0
  12. package/dist/chunk-OHYVKTGB.js +45 -0
  13. package/dist/chunk-TAL5H6VA.js +39 -0
  14. package/dist/client/platform-client.d.ts +29 -0
  15. package/dist/client.js +275 -37
  16. package/dist/codegen/block-registry.d.ts +13 -23
  17. package/dist/codegen/block-registry.js +3 -31
  18. package/dist/codegen/block-scaffold.d.ts +12 -25
  19. package/dist/codegen/block-scaffold.js +3 -41
  20. package/dist/codegen/index.d.ts +12 -61
  21. package/dist/codegen/index.js +7 -11
  22. package/dist/codegen/item-registry.d.ts +28 -0
  23. package/dist/codegen/item-registry.js +7 -0
  24. package/dist/codegen/item-scaffold.d.ts +29 -0
  25. package/dist/codegen/item-scaffold.js +7 -0
  26. package/dist/codegen/preset.d.ts +67 -0
  27. package/dist/codegen/shared.d.ts +36 -0
  28. package/dist/components/EditorProvider.d.ts +36 -0
  29. package/dist/content/content-renderer.d.ts +113 -0
  30. package/dist/content/index.d.ts +18 -0
  31. package/dist/content/richtext.d.ts +118 -0
  32. package/dist/content.js +227 -80
  33. package/dist/data/builtins.d.ts +506 -0
  34. package/dist/data/client.d.ts +166 -0
  35. package/dist/data/document.d.ts +251 -0
  36. package/dist/data/index.d.ts +73 -0
  37. package/dist/data/manifest.d.ts +424 -0
  38. package/dist/data/schema.d.ts +313 -0
  39. package/dist/data/selection.d.ts +524 -0
  40. package/dist/data/subjects.d.ts +221 -0
  41. package/dist/data/subscription-document.d.ts +75 -0
  42. package/dist/data/subscriptions.d.ts +181 -0
  43. package/dist/data/transport.d.ts +325 -0
  44. package/dist/data/ws-transport.d.ts +197 -0
  45. package/dist/data.js +1683 -0
  46. package/dist/graphql/cdn-route.d.ts +26 -0
  47. package/dist/graphql/client.d.ts +30 -0
  48. package/dist/graphql/content-client.d.ts +66 -0
  49. package/dist/graphql/foir-request.d.ts +47 -0
  50. package/dist/hooks/useAutoResize.d.ts +22 -0
  51. package/dist/hooks/useEditor.d.ts +16 -0
  52. package/dist/index.d.ts +10 -394
  53. package/dist/media/BlurhashCanvas.d.ts +10 -0
  54. package/dist/media/ProgressiveMedia.d.ts +56 -0
  55. package/dist/media/index.d.ts +18 -0
  56. package/dist/media/media.d.ts +139 -0
  57. package/dist/media/screen-capture.d.ts +81 -0
  58. package/dist/media/useProgressiveLoad.d.ts +23 -0
  59. package/dist/media.js +102 -0
  60. package/dist/next/cookieAdapter.d.ts +26 -0
  61. package/dist/next/index.d.ts +15 -0
  62. package/dist/next/middleware.d.ts +49 -0
  63. package/dist/next/session.d.ts +53 -0
  64. package/dist/next.js +763 -78
  65. package/dist/protocol/constants.d.ts +6 -0
  66. package/dist/protocol/messages.d.ts +155 -0
  67. package/dist/protocol/validation.d.ts +8 -0
  68. package/dist/push/index.d.ts +14 -0
  69. package/dist/push/operations.d.ts +22 -0
  70. package/dist/push/web-push.d.ts +39 -0
  71. package/dist/push.js +892 -78
  72. package/dist/react/FoirFeedback.d.ts +62 -0
  73. package/dist/react/FoirProvider.d.ts +116 -0
  74. package/dist/react/OAuthButtons.d.ts +20 -0
  75. package/dist/react/SignIn.d.ts +22 -0
  76. package/dist/react/UserButton.d.ts +13 -0
  77. package/dist/react/feedback-notes.d.ts +101 -0
  78. package/dist/react/index.d.ts +25 -0
  79. package/dist/react/localStorageAdapter.d.ts +10 -0
  80. package/dist/react.js +1373 -91
  81. package/dist/{realtime.d.ts → realtime/index.d.ts} +35 -16
  82. package/dist/realtime.js +1 -1
  83. package/dist/server/callback-client.d.ts +92 -0
  84. package/dist/server/events-client.d.ts +279 -0
  85. package/dist/server/index.d.ts +12 -0
  86. package/dist/server/operation-types.d.ts +134 -0
  87. package/dist/server/require-scoped-token.d.ts +76 -0
  88. package/dist/server/server-client.d.ts +34 -0
  89. package/dist/server/types.d.ts +54 -0
  90. package/dist/server/verify-scoped-token.d.ts +100 -0
  91. package/dist/server/webhook-helpers.d.ts +36 -0
  92. package/dist/server.js +298 -0
  93. package/dist/transport/foir-http.d.ts +234 -0
  94. package/dist/transport/persisted-query.d.ts +68 -0
  95. package/dist/transport/retry.d.ts +61 -0
  96. package/dist/types/index.d.ts +124 -0
  97. package/package.json +35 -13
  98. package/dist/auth.d.ts +0 -382
  99. package/dist/chunk-ADO5FJNM.js +0 -30
  100. package/dist/client.d.ts +0 -135
  101. package/dist/content.d.ts +0 -96
  102. package/dist/media.d.ts +0 -234
  103. package/dist/next.d.ts +0 -178
  104. package/dist/push.d.ts +0 -109
  105. package/dist/react.d.ts +0 -319
  106. package/dist/server.d.ts +0 -534
  107. package/dist/shared-DkWlEd2Z.d.ts +0 -18
@@ -0,0 +1,313 @@
1
+ /**
2
+ * THE `FoirSchema` CONTRACT.
3
+ *
4
+ * `createFoirClient<FoirSchema>()` is parameterised by a type that `foir types`
5
+ * (TTS-875) emits from `GET /v1/manifest`. This file is that contract: the
6
+ * shape the generator writes and the shape the client reads. It is the only
7
+ * coupling between the two, so it is written down here rather than living in
8
+ * the generator's head.
9
+ *
10
+ * ---------------------------------------------------------------------------
11
+ * What the generator emits
12
+ * ---------------------------------------------------------------------------
13
+ *
14
+ * A single module, `foir.generated.ts`, PASSED WHOLE:
15
+ *
16
+ * ```ts
17
+ * import * as generated from './foir.generated';
18
+ * const foir = createFoirClient({ apiUrl, apiKey, generated });
19
+ * ```
20
+ *
21
+ * A `.ts` and not a `.d.ts` because the file has a runtime half — the selection
22
+ * trees, `foirSchemaVersion`, and `foirSchemaType`, which is what carries
23
+ * `FoirSchema` across the type/value boundary so the client can infer it (a
24
+ * namespace import carries values; an interface erases). `FoirGeneratedModule`
25
+ * in `transport.ts` is the shape those exports have to satisfy, and it requires
26
+ * all of them: there is no case where a subset is wanted, and accepting one
27
+ * quietly meant a client that fetched the manifest on every cold start instead.
28
+ *
29
+ * ```ts
30
+ * // foir.generated.ts — DO NOT EDIT. Generated by `foir types`.
31
+ * import type { FoirSchemaDefinition } from '@foir/sdk/data';
32
+ *
33
+ * /** `schemaVersion` from the manifest these types were generated from. *\/
34
+ * export const foirSchemaVersion = 317;
35
+ * export const foirSchemaChannel = 'published';
36
+ *
37
+ * // `<D>` ONLY on the types between the record and a union stopping point —
38
+ * // see rule 10. Everything else is emitted without it.
39
+ * export interface TillyBlock<D extends FoirDepthLevel = 1> {
40
+ * _id: string;
41
+ * _createdAt: string;
42
+ * text: string | null;
43
+ * // Composite/polymorphic fields are emitted as a STATIC discriminated
44
+ * // union on `__typename`. The client never infers these; it only has to
45
+ * // avoid destroying them. See `selection.ts`.
46
+ * body: Array<HeroBlock<D> | TextBlock> | null;
47
+ * }
48
+ *
49
+ * export interface HeroBlock<D extends FoirDepthLevel = 1> {
50
+ * __typename: 'HeroBlock';
51
+ * headline: string;
52
+ * // The stopping point: a union reached from inside a union member is
53
+ * // already on the op compiler's path, so it degrades — unless the caller
54
+ * // bought a level. Mirrors the printer's `depth - 1` at this position.
55
+ * body: Array<(D extends 1 ? TillyBlockBodyDegraded
56
+ * : TillyBlockBody<FoirDepthBelow[D]>) | null> | null;
57
+ * }
58
+ *
59
+ * export interface TillyBlockFindUniqueArgs {
60
+ * id?: string;
61
+ * naturalKey?: string;
62
+ * locale?: string;
63
+ * preview?: boolean;
64
+ * // NOT a list, despite the plural: `ResolveContextInput`, an object of four
65
+ * // optional fields. This sketch said `ReadonlyArray<string>` until 2026-07-28,
66
+ * // when the docs lane caught it by RUNNING the call. A wrong argument type
67
+ * // compiles at every call site and fails at the server, which is the exact
68
+ * // lie generated types exist to remove — so `foir types` imports the shape
69
+ * // from `builtins.ts` rather than restating it.
70
+ * contexts?: FoirResolveContext;
71
+ * }
72
+ *
73
+ * export interface FoirSchema extends FoirSchemaDefinition {
74
+ * schemaVersion: typeof foirSchemaVersion;
75
+ * channel: 'published';
76
+ * models: {
77
+ * tilly_block: {
78
+ * typeName: 'TillyBlock';
79
+ * fields: TillyBlock;
80
+ * // Rule 10. Absent on a model with no stopping point, which is most.
81
+ * atDepth: { 2: TillyBlock<2>; 3: TillyBlock<3>; 4: TillyBlock<4> };
82
+ * relations: {
83
+ * parentBlockId: { target: 'tilly_block'; list: false; nullable: true };
84
+ * };
85
+ * ops: {
86
+ * findUnique: {
87
+ * args: TillyBlockFindUniqueArgs;
88
+ * returns: { kind: 'record'; nullable: true };
89
+ * };
90
+ * findMany: {
91
+ * args: TillyBlockFindManyArgs;
92
+ * returns: { kind: 'connection' };
93
+ * };
94
+ * };
95
+ * };
96
+ * };
97
+ * namespaces: {
98
+ * search: {
99
+ * ops: {
100
+ * searchRecords: {
101
+ * args: SearchRecordsArgs;
102
+ * result: SearchRecordsResult;
103
+ * };
104
+ * };
105
+ * };
106
+ * };
107
+ * }
108
+ *
109
+ * // The type carrier. `FoirSchema` is an interface and erases, so this is the
110
+ * // only thing a namespace import can infer it from. Runtime value: undefined.
111
+ * export const foirSchemaType = undefined as unknown as FoirSchema;
112
+ * ```
113
+ *
114
+ * ---------------------------------------------------------------------------
115
+ * Rules the generator must hold to
116
+ * ---------------------------------------------------------------------------
117
+ *
118
+ * 1. **Model keys are the manifest's model keys verbatim** (`tilly_block`, not
119
+ * `tillyBlock`). They are the key the client looks the model's selection
120
+ * tree up by, and the key a refusal names when there is no tree to look up.
121
+ * Renaming them for aesthetics breaks the lookup.
122
+ *
123
+ * 2. **Op names are the manifest's op names verbatim** (`findUnique`,
124
+ * `findMany`, `search`, …) — the canonical names, NOT the GraphQL root
125
+ * field (`tillyBlock`, `tillyBlocks`). Same reason: they go on the wire.
126
+ * For namespaces the op name IS the root field name, as the manifest lists
127
+ * it, because that is what the server matches on.
128
+ *
129
+ * 3. **Emit only what the manifest returned.** The manifest is already the
130
+ * per-caller projection of `SchemaForCaller(scopes)`, so "only the ops this
131
+ * credential can perform" needs no extra filtering — it is what arrives. A
132
+ * `pk_` key's generated schema simply has no `create`, and
133
+ * `foir.tilly_block.create(...)` is then a compile error, which is the
134
+ * entire point of per-key shaping.
135
+ *
136
+ * 4. **`fields` is the COMPLETE scalar shape**, every scalar the manifest
137
+ * lists, none optional. This is what makes the model type unconditionally
138
+ * true: the server always returns every scalar (the selection model is
139
+ * complete-by-default), so no field can be typed present and arrive
140
+ * `undefined`. Nullable scalars are `T | null`, never `T | undefined` and
141
+ * never `?:`.
142
+ *
143
+ * 5. **Relations are NOT in `fields`.** A relation key only exists on the
144
+ * result when the caller asked for it via `include`. Putting it in `fields`
145
+ * would type it as always-present, which is the exact footgun rule 4 is
146
+ * there to remove.
147
+ *
148
+ * 6. **`returns.kind` classifies the wrapper, not the model.**
149
+ * - `record` — the model itself; `nullable` when the field can resolve null
150
+ * (`findUnique`, `findMine`).
151
+ * - `connection` — a Relay connection over the model (`findMany`).
152
+ * - `list` — a plain array of the model.
153
+ * - `opaque` — the op does not return the model at all (`myAccess`). Its
154
+ * `type` is used verbatim and `include`/`omit` are not offered.
155
+ *
156
+ * 7. **Unions are emitted statically.** A polymorphic field's type is written
157
+ * out as a discriminated union on `__typename` by the generator. There is
158
+ * no inference step, so there is nothing for the client to get wrong — see
159
+ * `selection.ts` for why the selection machinery cannot flatten it.
160
+ *
161
+ * 8. **`raw` and `ns` are reserved top-level names.** They are the escape hatch
162
+ * and the namespace accessor on the client object. A model whose key is
163
+ * `raw` or `ns` would collide; the server should reject those model keys at
164
+ * create time (noted in TTS-868's "Known limits").
165
+ *
166
+ * 9. **`models` and `namespaces` must be object type LITERALS, not named
167
+ * `interface`s.** TypeScript gives an implicit index signature to object
168
+ * type literals and to `type` aliases of them, but never to an interface. So
169
+ * `models: { tilly_block: {…} }` written inline satisfies
170
+ * `Readonly<Record<string, FoirModelDefinition>>`, and
171
+ * `interface Models { tilly_block: {…} }` + `models: Models` does not — it
172
+ * fails with "Index signature for type 'string' is missing". Emitting inline
173
+ * (as the sketch above does) is the safe shape; if the generator ever
174
+ * factors these out for readability, they have to be `type X = {…}`.
175
+ * `__tests__/fixture-schema.ts` is the compiling reference.
176
+ *
177
+ * 10. **The `<D>` level parameter goes on the path to a stopping point, and
178
+ * nowhere else.** A union reached from inside a union member is already on
179
+ * the op compiler's path, so it degrades to `__typename` — and `depth: 2`
180
+ * buys one such level back, on the wire AND in the type. The parameter is
181
+ * what carries the caller's level from the record down to that position,
182
+ * so it belongs on exactly the interfaces, union aliases and member
183
+ * projections between the two, and the model names its shape at each level
184
+ * under `atDepth`.
185
+ *
186
+ * Both halves of "and nowhere else" matter. A parameter on a type that
187
+ * reaches no stopping point is a generic instantiation at every reference
188
+ * that can only ever resolve to the default — measured at 7 interfaces of
189
+ * 50 on the live dev project, which is why the change costs +1.6% types
190
+ * rather than a multiple. And `= 1` on every one of them is what makes a
191
+ * call passing no `depth` resolve to the type it always did; a parameter
192
+ * without a default would be a breaking change to every generated name.
193
+ *
194
+ * The generator computes the set (`depthReach`); it is not a judgement
195
+ * call. See `builtins.ts` for `FoirDepthLevel` / `FoirDepthBelow`, and
196
+ * `selection.ts` for the single lookup that reads `atDepth`.
197
+ */
198
+ /**
199
+ * A model's complete scalar shape. Deliberately loose — the generator writes a
200
+ * real interface here and the client only ever `Omit`s from it or reads its
201
+ * keys, so constraining it further buys nothing and makes generated interfaces
202
+ * with index signatures or unusual key types fail to assign.
203
+ */
204
+ export type FoirFieldsShape = object;
205
+ /** One relation the caller may `include`. */
206
+ export interface FoirRelationDefinition {
207
+ /** Key in `FoirSchemaDefinition['models']` this relation resolves to. */
208
+ readonly target: string;
209
+ /** True when the relation resolves to a list of the target model. */
210
+ readonly list: boolean;
211
+ /** True when the relation itself can resolve null. */
212
+ readonly nullable: boolean;
213
+ }
214
+ /** How an op's result wraps (or does not wrap) the model. */
215
+ export type FoirReturnDefinition = {
216
+ readonly kind: 'record';
217
+ readonly nullable: boolean;
218
+ } | {
219
+ readonly kind: 'connection';
220
+ } | {
221
+ readonly kind: 'list';
222
+ readonly nullable: boolean;
223
+ } | {
224
+ readonly kind: 'opaque';
225
+ readonly type: unknown;
226
+ };
227
+ /** One operation available on a model for this credential. */
228
+ export interface FoirOpDefinition {
229
+ /**
230
+ * The op's arguments, as an object type. These are spread at the CALL SITE
231
+ * alongside `include`/`omit` (`{ where, first, include }`) and split back out
232
+ * into the wire's `args` object by the client — `include`/`omit` are
233
+ * selection, not arguments, and the server takes them as siblings of `args`.
234
+ */
235
+ readonly args: object;
236
+ readonly returns: FoirReturnDefinition;
237
+ }
238
+ /** A model as the per-caller manifest describes it. */
239
+ export interface FoirModelDefinition {
240
+ /** GraphQL type name, e.g. `'TillyBlock'`. Documentation + tooling. */
241
+ readonly typeName: string;
242
+ /** Complete scalar shape. See contract rule 4. */
243
+ readonly fields: FoirFieldsShape;
244
+ /**
245
+ * The same shape at a depth ABOVE the default, keyed by the level a caller
246
+ * would pass as `depth`.
247
+ *
248
+ * Present only on models whose tree reaches a union stopping point — a
249
+ * position the op compiler refuses to expand because the union is already on
250
+ * its path. `depth: 2` expands one such level on the wire, and the entry
251
+ * under `2` is the model type describing what then arrives.
252
+ *
253
+ * OPTIONAL, and absent is the common case. A model with no stopping point
254
+ * reads identically at every depth, so generating an entry for it would emit
255
+ * a second name for one type. A LEVEL with no entry — a depth past what the
256
+ * generator emitted, or a `depth` that is not a literal at the call site —
257
+ * falls back to `fields`, which under-promises: the caller gets the values
258
+ * and narrows by hand, exactly as they did before this key existed. That is
259
+ * the safe direction, and the reason absence never has to be an error.
260
+ *
261
+ * Contract rule 9 applies: emit it as an object type LITERAL.
262
+ */
263
+ readonly atDepth?: Readonly<Record<number, FoirFieldsShape>>;
264
+ readonly relations: Readonly<Record<string, FoirRelationDefinition>>;
265
+ readonly ops: Readonly<Record<string, FoirOpDefinition>>;
266
+ }
267
+ /**
268
+ * One op on a non-model namespace (`search`, `customers`, `notifications`).
269
+ * Namespaces have no model behind them, so there is no `include`/`omit` and
270
+ * the result type is used verbatim.
271
+ */
272
+ export interface FoirNamespaceOpDefinition {
273
+ readonly args: object;
274
+ readonly result: unknown;
275
+ }
276
+ export interface FoirNamespaceDefinition {
277
+ readonly ops: Readonly<Record<string, FoirNamespaceOpDefinition>>;
278
+ }
279
+ /**
280
+ * The type `createFoirClient` is parameterised by. `foir types` emits an
281
+ * interface extending this; everything above documents what goes in it.
282
+ */
283
+ export interface FoirSchemaDefinition {
284
+ /**
285
+ * `schemaVersion` from the manifest these types were generated from. Kept as
286
+ * a literal so a human reading the generated file sees it, and mirrored by a
287
+ * runtime `foirSchemaVersion` const for drift detection — the type cannot be
288
+ * read at runtime.
289
+ */
290
+ readonly schemaVersion: number;
291
+ readonly channel: 'published' | 'draft';
292
+ readonly models: Readonly<Record<string, FoirModelDefinition>>;
293
+ readonly namespaces: Readonly<Record<string, FoirNamespaceDefinition>>;
294
+ }
295
+ /**
296
+ * A Relay connection, as `findMany` returns it. Not flattened to an array on
297
+ * purpose: the compiled document is still the wire format, and hiding
298
+ * `pageInfo` behind a convenience array would make pagination unreachable
299
+ * without dropping to `raw`.
300
+ */
301
+ export interface FoirConnection<TNode> {
302
+ edges: Array<{
303
+ cursor: string;
304
+ node: TNode;
305
+ }>;
306
+ pageInfo: {
307
+ hasNextPage: boolean;
308
+ hasPreviousPage: boolean;
309
+ startCursor: string | null;
310
+ endCursor: string | null;
311
+ };
312
+ totalCount: number;
313
+ }