@foir/sdk 0.20.0 → 0.22.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 (65) hide show
  1. package/CHANGELOG.md +135 -1
  2. package/README.md +9 -9
  3. package/dist/app/client.d.ts +90 -84
  4. package/dist/app/contract/proto/apps/v1/apps_pb.d.ts +14 -13
  5. package/dist/app/dispatch.d.ts +5 -5
  6. package/dist/app/errors.d.ts +11 -11
  7. package/dist/app/index.d.ts +4 -4
  8. package/dist/app/naming.d.ts +1 -1
  9. package/dist/app/ticket.d.ts +2 -2
  10. package/dist/app/vocabulary.generated.d.ts +2 -2
  11. package/dist/app-contract.js +3 -3
  12. package/dist/app.js +92 -90
  13. package/dist/auth/access.d.ts +19 -19
  14. package/dist/auth/auth.d.ts +216 -114
  15. package/dist/auth/hosted.d.ts +14 -14
  16. package/dist/auth/index.d.ts +7 -7
  17. package/dist/auth/operations.d.ts +128 -32
  18. package/dist/auth/ops.d.ts +39 -21
  19. package/dist/auth/session-client.d.ts +3 -3
  20. package/dist/auth-session.js +3 -3
  21. package/dist/auth.js +291 -146
  22. package/dist/client/platform-client.d.ts +1 -1
  23. package/dist/client.js +32 -5
  24. package/dist/codegen/index.js +1 -1
  25. package/dist/data/builtins.d.ts +41 -82
  26. package/dist/data/client.d.ts +2 -2
  27. package/dist/data/decimal.d.ts +1 -1
  28. package/dist/data/document.d.ts +14 -0
  29. package/dist/data/index.d.ts +2 -2
  30. package/dist/data/manifest.d.ts +1 -1
  31. package/dist/data/schema.d.ts +1 -1
  32. package/dist/data/transport.d.ts +33 -26
  33. package/dist/data/ws-transport.d.ts +1 -1
  34. package/dist/data.js +97 -19
  35. package/dist/graphql/content-client.d.ts +13 -13
  36. package/dist/index.js +24 -0
  37. package/dist/live/drift.d.ts +1 -1
  38. package/dist/media/screen-capture.d.ts +1 -1
  39. package/dist/next/index.d.ts +2 -2
  40. package/dist/next/session.d.ts +10 -10
  41. package/dist/next.js +121 -61
  42. package/dist/placement/index.d.ts +15 -32
  43. package/dist/placement.js +18 -20
  44. package/dist/push.js +113 -46
  45. package/dist/react/FoirFeedback.d.ts +2 -2
  46. package/dist/react/FoirProvider.d.ts +23 -23
  47. package/dist/react/SignIn.d.ts +4 -4
  48. package/dist/react/UserButton.d.ts +1 -1
  49. package/dist/react/feedback-notes.d.ts +4 -4
  50. package/dist/react/index.d.ts +3 -3
  51. package/dist/react.js +168 -105
  52. package/dist/realtime/index.d.ts +1 -1
  53. package/dist/server/callback-client.d.ts +4 -4
  54. package/dist/server/events-client.d.ts +18 -18
  55. package/dist/server/operation-types.d.ts +8 -8
  56. package/dist/server/require-scoped-token.d.ts +3 -3
  57. package/dist/server/server-client.d.ts +1 -1
  58. package/dist/server/types.d.ts +1 -1
  59. package/dist/server/verify-scoped-token.d.ts +4 -28
  60. package/dist/server.js +67 -112
  61. package/dist/transport/foir-http.d.ts +57 -18
  62. package/dist/transport/key-kind.d.ts +40 -0
  63. package/dist/types/index.d.ts +2 -2
  64. package/package.json +3 -3
  65. package/dist/server/older-claims.generated.d.ts +0 -8
@@ -17,7 +17,7 @@ export declare class PlatformClientError extends Error {
17
17
  * ```ts
18
18
  * const client = createPlatformClient({
19
19
  * apiUrl: 'https://api.example.com/graphql',
20
- * apiKey: 'sk_test_...',
20
+ * apiKey: 'foir_pub_...', // runs in the browser: a publishable key only
21
21
  * });
22
22
  *
23
23
  * const { data } = await client.query(
package/dist/client.js CHANGED
@@ -1,6 +1,30 @@
1
1
  // src/graphql/foir-request.ts
2
2
  import { print as print2 } from "graphql";
3
3
 
4
+ // src/transport/key-kind.ts
5
+ var KEY_PREFIXES = [
6
+ ["foir_pub_", "publishable"],
7
+ ["foir_srv_", "server"],
8
+ ["foir_adm_", "admin"],
9
+ ["pk_", "publishable"],
10
+ ["sk_", "older"],
11
+ ["tc_", "older"]
12
+ ];
13
+ var FOIR_CREDENTIALS_DOC = "https://docs.foir.dev/credentials";
14
+ function foirKeyKind(apiKey) {
15
+ if (typeof apiKey !== "string") return void 0;
16
+ for (const [prefix, kind] of KEY_PREFIXES) {
17
+ if (apiKey.startsWith(prefix)) return kind;
18
+ }
19
+ return void 0;
20
+ }
21
+ function adminKeyRefusal(client) {
22
+ return `[foir] ${client} was given an admin key. An admin key is a machine's own: nobody signs in through it, and an app never holds one. Build this client from your publishable key, or from your server key on the server that renders your pages. A machine that acts for itself uses createServerClient from @foir/sdk/server. See ${FOIR_CREDENTIALS_DOC}`;
23
+ }
24
+ function isPublishableFoirKey(apiKey) {
25
+ return foirKeyKind(apiKey) === "publishable";
26
+ }
27
+
4
28
  // src/graphql/cdn-route.ts
5
29
  import { print } from "graphql";
6
30
 
@@ -176,8 +200,8 @@ var FoirAuthDowngradedError = class extends FoirRequestError {
176
200
  downgrade;
177
201
  constructor(downgrade) {
178
202
  super(
179
- `[foir] your customer token was ${downgrade.customerToken} (${downgrade.reason}), so the request was served as ${downgrade.servedAs}`,
180
- { graphQLErrors: [{ message: "customer token rejected", extensions: { code: "AUTH_DOWNGRADED" } }] }
203
+ `[foir] your user token was ${downgrade.userToken} (${downgrade.reason}), so the request was served as ${downgrade.servedAs}`,
204
+ { graphQLErrors: [{ message: "user token rejected", extensions: { code: "AUTH_DOWNGRADED" } }] }
181
205
  );
182
206
  this.name = "FoirAuthDowngradedError";
183
207
  this.downgrade = downgrade;
@@ -185,7 +209,7 @@ var FoirAuthDowngradedError = class extends FoirRequestError {
185
209
  };
186
210
  var FoirSessionExpiredError = class extends FoirRequestError {
187
211
  constructor(options) {
188
- super("[foir] the customer session has expired and could not be refreshed: sign in again", {
212
+ super("[foir] the user session has expired and could not be refreshed: sign in again", {
189
213
  cause: options?.cause,
190
214
  graphQLErrors: [{ message: "session expired", extensions: { code: "SESSION_EXPIRED" } }]
191
215
  });
@@ -202,7 +226,7 @@ function reportAuthDowngrade(envelope) {
202
226
  if (warnedDowngrade === downgrade.reason) return;
203
227
  warnedDowngrade = downgrade.reason;
204
228
  console.warn(
205
- `[foir] your customer token was ${downgrade.customerToken} (${downgrade.reason}) \u2014 this request was served as ${downgrade.servedAs}, so auth-targeted content resolved to its anonymous variant. ` + (downgrade.reason === "expired" ? "Re-exchange the token and retry." : "Check which credential you are sending.")
229
+ `[foir] your user token was ${downgrade.userToken} (${downgrade.reason}) \u2014 this request was served as ${downgrade.servedAs}, so auth-targeted content resolved to its anonymous variant. ` + (downgrade.reason === "expired" ? "Re-exchange the token and retry." : "Check which credential you are sending.")
206
230
  );
207
231
  }
208
232
  function refusePrunedDocument(json, options) {
@@ -282,7 +306,7 @@ function isCdnEligible(env, documentText, bearerToken, orgId) {
282
306
  if (orgId) return false;
283
307
  if (isFoirPreview(env)) return false;
284
308
  const apiKey = resolveFoirApiKey(env);
285
- if (!apiKey?.startsWith("pk_")) return false;
309
+ if (!isPublishableFoirKey(apiKey)) return false;
286
310
  return !/\bmutation\b/.test(documentText);
287
311
  }
288
312
 
@@ -329,6 +353,9 @@ async function foirRequest(env, document, variables, options) {
329
353
  "[foir] PLATFORM_API_URL or PLATFORM_API_KEY is not set \u2014 add them to .env"
330
354
  );
331
355
  }
356
+ if (foirKeyKind(apiKey) === "admin") {
357
+ throw new FoirRequestError(adminKeyRefusal("foirRequest"));
358
+ }
332
359
  const headers = buildFoirHeaders({
333
360
  apiKey,
334
361
  draftChannel: isFoirPreview(env),
@@ -15,7 +15,7 @@ function schemaEntry(apiUrl, key) {
15
15
  headers: {
16
16
  "x-api-key": key ?? "",
17
17
  // Read the draft channel so freshly pushed changes are visible
18
- // (silently ignored by public keys, which can't see drafts).
18
+ // (ignored by an app's key that does not hold drafts:read).
19
19
  "X-Foir-Schema-Channel": "draft"
20
20
  }
21
21
  }
@@ -398,7 +398,7 @@ export type FoirUnexpandedRecord = FoirDegraded;
398
398
  export type FoirVisibility = 'PRIVATE' | 'PUBLIC';
399
399
  export type FoirAccessLevel = 'READ' | 'WRITE' | 'DELETE';
400
400
  export type FoirAccessSource = 'PUBLIC' | 'OWNER' | 'GRANT' | 'ROLE';
401
- export type FoirGranteeKind = 'CUSTOMER' | 'ADMIN';
401
+ export type FoirGranteeKind = 'USER';
402
402
  /** `myAccess` — this principal's effective access to one record. */
403
403
  export interface FoirMyAccess {
404
404
  access: FoirAccessLevel;
@@ -435,9 +435,9 @@ export interface FoirUpdateManyPayload {
435
435
  }
436
436
  /**
437
437
  * `setOwner`: who the record belongs to after an operation handed it to
438
- * another customer. It carries the owner and not the record, because the
438
+ * another user. It carries the owner and not the record, because the
439
439
  * operation may have been acting for the previous holder, who can no longer
440
- * read it. `ownerKind` is always `'customer'` from this op.
440
+ * read it. `ownerKind` is always `'user'` from this op.
441
441
  */
442
442
  export interface FoirRecordOwner {
443
443
  id: string;
@@ -445,7 +445,7 @@ export interface FoirRecordOwner {
445
445
  ownerKind: string;
446
446
  }
447
447
  /**
448
- * What a customer's note can be ABOUT: the customer-plane subset of the closed
448
+ * What a user's note can be ABOUT: the user-plane subset of the closed
449
449
  * set the platform's write path enforces.
450
450
  *
451
451
  * On the wire it is `String!`, not a GraphQL enum, so the manifest publishes no
@@ -458,23 +458,23 @@ export interface FoirRecordOwner {
458
458
  * record is `'record'` plus the model key on `subjectModelKey`.
459
459
  *
460
460
  * The platform set also holds `project` and `organization`, and this union
461
- * deliberately does not. Both are operator constructs: the platform answers a
462
- * note about either through a row policy no customer claim passes, so no note
461
+ * deliberately does not. Both are the project's own constructs: the platform answers a
462
+ * note about either through a row policy no user claim passes, so no note
463
463
  * this surface reads or writes can carry them. This mirrors the part of the
464
- * platform set a customer can reach, and the obligation that comes with a mirror
465
- * (see the file header) applies: a kind the platform opens to customers widens
464
+ * platform set a user can reach, and the obligation that comes with a mirror
465
+ * (see the file header) applies: a kind the platform opens to users widens
466
466
  * this union in a minor release, and until then a value outside it is a row no
467
- * customer writer could have produced.
467
+ * user writer could have produced.
468
468
  */
469
- export type FoirNoteSubjectType = 'record' | 'file' | 'model' | 'operation' | 'schedule' | 'customer';
469
+ export type FoirNoteSubjectType = 'record' | 'file' | 'model' | 'operation' | 'schedule' | 'user';
470
470
  /**
471
- * One file the customer submitted with their note.
471
+ * One file the user submitted with their note.
472
472
  *
473
473
  * The file's own facts, and nothing about the platform's handling of it: when
474
474
  * the link row was written and which retention clock it starts are not the
475
475
  * author's business. What is here is enough to render "you sent this".
476
476
  */
477
- export interface FoirCustomerNoteAttachment {
477
+ export interface FoirUserNoteAttachment {
478
478
  /** The file's id — the same one `createMyNote` was given. */
479
479
  fileId: string;
480
480
  filename: string;
@@ -484,15 +484,15 @@ export interface FoirCustomerNoteAttachment {
484
484
  url: string;
485
485
  }
486
486
  /**
487
- * One note on the customer plane — `foir.ns.notes.myNotes` and
487
+ * One note on the user plane — `foir.ns.notes.myNotes` and
488
488
  * `foir.ns.notes.createMyNote`.
489
489
  *
490
490
  * Deliberately narrower than the note your team sees in the dashboard. There is
491
491
  * no visibility, no resolution note, no mentions and no metadata: those are the
492
- * project's view of a thread, not the author's, and the customer-facing type
492
+ * project's view of a thread, not the author's, and the user-facing type
493
493
  * does not merely omit them from the document — the surface does not carry them.
494
494
  */
495
- export interface FoirCustomerNote {
495
+ export interface FoirUserNote {
496
496
  id: string;
497
497
  /** The note's prose. */
498
498
  body: string | null;
@@ -507,12 +507,12 @@ export interface FoirCustomerNote {
507
507
  /**
508
508
  * The files submitted with this note. Empty when there are none.
509
509
  *
510
- * The one place the customer surface is WIDER than "the author's own prose",
510
+ * The one place the user surface is WIDER than "the author's own prose",
511
511
  * and deliberately: an author who attached a screenshot has to be able to see
512
512
  * that it arrived, or the only readings left to them are that it failed
513
513
  * silently or that it was taken away.
514
514
  */
515
- attachments: FoirCustomerNoteAttachment[];
515
+ attachments: FoirUserNoteAttachment[];
516
516
  /** ISO-8601. */
517
517
  createdAt: string;
518
518
  }
@@ -521,7 +521,7 @@ export interface FoirCustomerNote {
521
521
  * — `foir.ns.notes.noteConfig`.
522
522
  *
523
523
  * Charged `notes:create` rather than `notes:read`, and refused to a caller with
524
- * no customer session, because the only caller it is useful to is one that can
524
+ * no user session, because the only caller it is useful to is one that can
525
525
  * submit. So a composer can read it as its single readiness probe: an answer
526
526
  * means this visitor may write, and a refusal names which half is missing.
527
527
  */
@@ -546,16 +546,16 @@ export interface FoirMyNotesArgs {
546
546
  threadRootId?: string;
547
547
  }
548
548
  /**
549
- * `myNotes` — the notes this customer wrote, plus the replies your team
550
- * deliberately sent them. Never another customer's, and never an operator's
549
+ * `myNotes` — the notes this user wrote, plus the replies your team
550
+ * deliberately sent them. Never another user's, and never your team's
551
551
  * internal ones.
552
552
  */
553
- export type FoirMyNotesResult = FoirConnection<FoirCustomerNote>;
553
+ export type FoirMyNotesResult = FoirConnection<FoirUserNote>;
554
554
  /**
555
- * `writeNote` arguments: the one note create, for a signed-in customer and for
555
+ * `writeNote` arguments: the one note create, for a signed-in user and for
556
556
  * a visitor alike. It asks `notes:create` of both.
557
557
  *
558
- * A signed-in customer's note is theirs and comes back in `myNotes`. A
558
+ * A signed-in user's note is theirs and comes back in `myNotes`. A
559
559
  * visitor's, through a key that gives `notes:create` to whoever comes through
560
560
  * it, on a project that takes visitors' notes, is nobody's: ask for its `id`
561
561
  * and `createdAt` and nothing else, because nothing reads it back.
@@ -584,8 +584,8 @@ export interface FoirWriteNoteArgs {
584
584
  */
585
585
  attachmentFileIds?: string[];
586
586
  /**
587
- * Where the operators may reply to a visitor. Refused from a signed-in
588
- * customer, whose note has an author.
587
+ * Where your team may reply to a visitor. Refused from a signed-in
588
+ * user, whose note has an author.
589
589
  *
590
590
  * Captured as typed and NEVER verified: it is not treated as proof of who
591
591
  * wrote the note, and nothing is sent to it to confirm it. Do not build a
@@ -597,7 +597,7 @@ export interface FoirWriteNoteArgs {
597
597
  * `createMyNote` arguments.
598
598
  *
599
599
  * @deprecated `createMyNote` is the older name of `writeNote` for a signed-in
600
- * customer. Use `writeNote` and {@link FoirWriteNoteArgs}.
600
+ * user. Use `writeNote` and {@link FoirWriteNoteArgs}.
601
601
  */
602
602
  export interface FoirCreateMyNoteArgs {
603
603
  subjectType: FoirNoteSubjectType;
@@ -618,62 +618,6 @@ export interface FoirCreateMyNoteArgs {
618
618
  */
619
619
  attachmentFileIds?: string[];
620
620
  }
621
- /**
622
- * `submitAnonymousNote` arguments — feedback from a visitor with no account.
623
- *
624
- * Present on the project's schema only while the project has opted in
625
- * (Notes settings → "Accept anonymous notes"). The feedback widget does NOT
626
- * use this: a signed-out visitor there is still asked to sign in, so this
627
- * mutation is the only path a visitor's note can take.
628
- *
629
- * WRITE-ONLY. Nothing reads an anonymous note back on the public plane, which
630
- * is why the result is a receipt rather than the note.
631
- *
632
- * @deprecated `submitAnonymousNote` is the older name of `writeNote` for a
633
- * visitor. Use `writeNote` and {@link FoirWriteNoteArgs}, asking for `id` and
634
- * `createdAt`.
635
- */
636
- export interface FoirSubmitAnonymousNoteArgs {
637
- /**
638
- * Must be `'record'` — the only thing a visitor may write a note about.
639
- * Narrower than `FoirCreateMyNoteArgs`, where a customer may also address a
640
- * file or a model.
641
- */
642
- subjectType: 'record';
643
- subjectId: string;
644
- /**
645
- * The record's model key. REQUIRED here, unlike on `createMyNote` where it is
646
- * conditional: the subject is always a record on this lane, so the condition
647
- * is always met.
648
- */
649
- subjectModelKey: string;
650
- body: string;
651
- /**
652
- * Optional. Where the operators may reply.
653
- *
654
- * Captured as typed and NEVER verified — it is not treated as proof of who
655
- * wrote the note, and nothing is sent to it to confirm it. Do not build a
656
- * flow that assumes the address is reachable.
657
- */
658
- contactEmail?: string;
659
- }
660
- /**
661
- * What `submitAnonymousNote` returns.
662
- *
663
- * @deprecated With the field it answers. `writeNote` answers a visitor with
664
- * the note's `id` and `createdAt`.
665
- */
666
- export interface FoirAnonymousNoteReceipt {
667
- /**
668
- * A reference for this submission, to quote when following it up.
669
- *
670
- * NOT a handle: there is no read that takes it. Showing it to the visitor is
671
- * the whole of its purpose.
672
- */
673
- reference: string;
674
- /** When the platform recorded the submission. */
675
- submittedAt: string;
676
- }
677
621
  export type FoirDeviceType = 'DESKTOP' | 'MOBILE' | 'TABLET';
678
622
  export type FoirPlatformType = 'IOS' | 'ANDROID' | 'WEB';
679
623
  /**
@@ -694,4 +638,19 @@ export interface FoirResolveContext {
694
638
  locale?: string | null;
695
639
  platform?: FoirPlatformType | null;
696
640
  preview?: boolean | null;
641
+ /**
642
+ * The country of the visitor a server is calling for, as an ISO 3166-1
643
+ * alpha-2 code. Only a key holding `visitors:forward` may say it, and a
644
+ * client given a `visitor` attaches it to every read, so there is rarely a
645
+ * reason to write it on one.
646
+ */
647
+ country?: string | null;
648
+ /**
649
+ * Where the visitor a server is calling for is, in decimal degrees. Only a
650
+ * key holding `visitors:forward` may say it.
651
+ */
652
+ location?: {
653
+ latitude: number;
654
+ longitude: number;
655
+ } | null;
697
656
  }
@@ -166,7 +166,7 @@ export interface FoirRawOptions {
166
166
  }
167
167
  export interface FoirClientCore<S extends FoirSchemaDefinition> {
168
168
  /**
169
- * Non-model root namespaces (`search`, `customers`, `notifications`).
169
+ * Non-model root namespaces (`search`, `users`, `notifications`).
170
170
  * Separate accessor because the addressing has to distinguish a model from a
171
171
  * namespace and the client has no runtime schema to disambiguate with.
172
172
  */
@@ -181,7 +181,7 @@ export interface FoirClientCore<S extends FoirSchemaDefinition> {
181
181
  * hatch that could only say what the JSON op could say would be an escape from
182
182
  * nothing. As a document it reaches everything the credential can reach —
183
183
  * including the root fields no model or namespace claims (`designTokens`,
184
- * `record`, `locales`, `resolvedLocale`, the whole customer-auth mutation
184
+ * `record`, `locales`, `resolvedLocale`, the whole user-auth mutation
185
185
  * set), which the JSON op could not address at all.
186
186
  *
187
187
  * Returns the whole `data` object rather than a single root field, because a
@@ -53,7 +53,7 @@
53
53
  *
54
54
  * TypeScript already rejects `price + tax` at compile time. The throw is for
55
55
  * JavaScript callers and for anything that reaches this through `any`, where a
56
- * silent `"19.992.00"` would otherwise reach a customer. Loud beats quiet: the
56
+ * silent `"19.992.00"` would otherwise reach a user. Loud beats quiet: the
57
57
  * whole reason this type exists is that the float bug was silent.
58
58
  *
59
59
  * `JSON.stringify` is answered by `toJSON`, so a decimal serialises back to the
@@ -51,6 +51,7 @@
51
51
  * inferring a literal would reinstate the defect above under a condition no
52
52
  * caller can see.
53
53
  */
54
+ import { type FoirVisitorPlace } from '../transport/foir-http';
54
55
  import type { FoirManifestOp, FoirManifestOpPayload, FoirManifestRelation, FoirManifestSelection, FoirManifestSelectionField, FoirManifestSelectionUnion } from './manifest';
55
56
  /**
56
57
  * One model, as the printer needs it.
@@ -260,6 +261,19 @@ export declare function planFoirModelCall(source: FoirSelectionSource, call: Foi
260
261
  * choose, since only the caller knows which calls are the same one.
261
262
  */
262
263
  export declare function withCreateIdempotencyKey(source: FoirSelectionSource, model: string, op: string, args: Record<string, unknown>): Record<string, unknown>;
264
+ /**
265
+ * A read's arguments with where its stated visitor is, when the op takes
266
+ * `contexts` and the client was given a visitor with a place.
267
+ *
268
+ * It is attached here, to every read, and not left to each call: a page
269
+ * renders with many reads, and one that forgot would be answered as a visitor
270
+ * nobody could place while the read beside it was not.
271
+ *
272
+ * What a call says of the place itself wins, part by part: a caller that
273
+ * passes `contexts.country` for one read has said something more exact than
274
+ * the client's visitor.
275
+ */
276
+ export declare function withStatedVisitor(op: FoirManifestOp | undefined, args: Record<string, unknown>, place: FoirVisitorPlace): Record<string, unknown>;
263
277
  /**
264
278
  * Turn a namespace call into a document.
265
279
  *
@@ -59,7 +59,7 @@ export { planFoirModelCall, planFoirNamespaceCall } from './document';
59
59
  export type { FoirCall, FoirDocumentPlan, FoirNamespaceCall, FoirNamespaceSelections, FoirRecordPath, FoirSelectionModel, FoirSelectionNamespace, FoirSelections, FoirSelectionSource, FoirSelectionUnions, } from './document';
60
60
  export { createFoirSubjectRegistry, recordFoirSubjects } from './subjects';
61
61
  export type { FoirSubject, FoirSubjectEntry, FoirSubjectOptions, FoirSubjectOrigin, FoirSubjectRegistry, } from './subjects';
62
- export type { CollabInfo, FileValue, FoirAccessGrant, FoirAccessLevel, FoirAccessSource, FoirAccessor, FoirCreateMyNoteArgs, FoirWriteNoteArgs, FoirSubmitAnonymousNoteArgs, FoirAnonymousNoteReceipt, FoirCustomerNote, FoirCustomerNoteAttachment, FoirDegraded, FoirDepthBelow, FoirDepthLevel, FoirDeviceType, FoirGranteeKind, FoirJsonValue, FoirMyAccess, FoirMyNotesArgs, FoirMyNotesResult, FoirNoteConfig, FoirNoteSubjectType, FoirPlatformType, FoirRecordOwner, FoirResolveContext, FoirResourceAccess, FoirUnexpandedRecord, FoirUpdateManyPayload, FoirVisibility, GeoPoint, Image, ImageFormat, ImageVariant, ImageVariantSet, MediaValue, Passage, Prose, ProseSpan, RecordAncestor, Reference, Richtext, Video, } from './builtins';
62
+ export type { CollabInfo, FileValue, FoirAccessGrant, FoirAccessLevel, FoirAccessSource, FoirAccessor, FoirCreateMyNoteArgs, FoirWriteNoteArgs, FoirUserNote, FoirUserNoteAttachment, FoirDegraded, FoirDepthBelow, FoirDepthLevel, FoirDeviceType, FoirGranteeKind, FoirJsonValue, FoirMyAccess, FoirMyNotesArgs, FoirMyNotesResult, FoirNoteConfig, FoirNoteSubjectType, FoirPlatformType, FoirRecordOwner, FoirResolveContext, FoirResourceAccess, FoirUnexpandedRecord, FoirUpdateManyPayload, FoirVisibility, GeoPoint, Image, ImageFormat, ImageVariant, ImageVariantSet, MediaValue, Passage, Prose, ProseSpan, RecordAncestor, Reference, Richtext, Video, } from './builtins';
63
63
  /**
64
64
  * Pre-rename spellings. The `<Name>Block` wrappers and the `<Name>Value`
65
65
  * split are the same thing as the types above — an item IS its value — so each
@@ -82,4 +82,4 @@ export type { FoirInclude, FoirModelOperation, FoirNamespaceOperation, FoirOmitt
82
82
  export { FoirDecimal, decimal } from './decimal';
83
83
  export type { FoirDecimalDivOptions, FoirDecimalInput, FoirDecimalRounding, } from './decimal';
84
84
  export { FoirRequestError, FoirAuthDowngradedError, FoirSessionExpiredError, FOIR_VISITOR_IP_HEADER, } from '../transport/foir-http';
85
- export type { FoirEnv, FoirGraphQLErrorItem, FoirTokenProvider, FoirAuthDowngrade, FoirVisitorSource, } from '../transport/foir-http';
85
+ export type { FoirEnv, FoirGraphQLErrorItem, FoirTokenProvider, FoirAuthDowngrade, FoirVisitor, FoirVisitorSource, } from '../transport/foir-http';
@@ -303,7 +303,7 @@ export interface FoirManifest {
303
303
  composedFor?: string;
304
304
  models: Record<string, FoirManifestModel>;
305
305
  /**
306
- * Keyed by namespace name (`auth`, `customers`, `files`, `notifications`,
306
+ * Keyed by namespace name (`auth`, `users`, `files`, `notifications`,
307
307
  * `operations`, `schedules`, `search`, `secrets`). Deliberately an open
308
308
  * record rather than the eight names: a namespace the platform adds must
309
309
  * reach the generator, and a closed union would silently drop it.
@@ -272,7 +272,7 @@ export interface FoirModelDefinition {
272
272
  readonly ops: Readonly<Record<string, FoirOpDefinition>>;
273
273
  }
274
274
  /**
275
- * One op on a non-model namespace (`search`, `customers`, `notifications`).
275
+ * One op on a non-model namespace (`search`, `users`, `notifications`).
276
276
  * Namespaces have no model behind them, so there is no `include`/`omit` and
277
277
  * the result type is used verbatim.
278
278
  */
@@ -5,12 +5,12 @@
5
5
  * Where a call goes
6
6
  * ---------------------------------------------------------------------------
7
7
  *
8
- * read + `pk_` key + no customer bearer + published channel
8
+ * read + `pk_` key + no user bearer + published channel
9
9
  * → `GET /cdn/graphql?key=pk_…&extensions={"persistedQuery":{"sha256Hash":…}}`
10
10
  * A shared cache in front of the caller stores the response, because the
11
11
  * request is a GET and the credential is in the URL.
12
12
  *
13
- * anything else — `sk_`, a customer bearer, a mutation, the draft channel
13
+ * anything else — `sk_`, a user bearer, a mutation, the draft channel
14
14
  * → `POST /graphql` with the `x-api-key` header and the APQ body.
15
15
  *
16
16
  * a call made AS an operation, with its dispatch token
@@ -158,7 +158,7 @@ export type FoirOperationGeneratedModule<S extends FoirSchemaDefinition = FoirSc
158
158
  * The endpoint calls Foir AS the operation, with the grants the operation
159
159
  * declared, and holds no key of its own. api-public accepts the token as a
160
160
  * caller in its own right: it builds the schema overlay from the token's
161
- * grants, and it reads the organization and the customer from the
161
+ * grants, and it reads the organization and the user from the
162
162
  * token's claims. So nothing a key client configures beside its key
163
163
  * (`bearerToken`, `orgId`, `channel`) means anything here, and none of it is
164
164
  * accepted.
@@ -183,7 +183,7 @@ export interface FoirDispatchCredential {
183
183
  }
184
184
  /**
185
185
  * A client that calls Foir with an api key: a storefront's `pk_`, a server's
186
- * `sk_`, optionally for a signed-in customer.
186
+ * `sk_`, optionally for a signed-in user.
187
187
  */
188
188
  export interface FoirKeyClientConfig<S extends FoirSchemaDefinition = FoirSchemaDefinition> {
189
189
  /**
@@ -200,19 +200,19 @@ export interface FoirKeyClientConfig<S extends FoirSchemaDefinition = FoirSchema
200
200
  dispatch?: never;
201
201
  /**
202
202
  * Read the draft schema channel (`X-Foir-Schema-Channel: draft`). Needs a key
203
- * holding `drafts:read`: a preview environment's own `pk_`, or an `sk_`. A
204
- * public key without it is served the published copy; a secret key without
205
- * it is refused. Defaults to `'published'`.
203
+ * holding `drafts:read`: a preview environment's own key. A publishable or
204
+ * a server key without it is served the published copy. Defaults to
205
+ * `'published'`.
206
206
  */
207
207
  channel?: 'published' | 'draft';
208
208
  /**
209
- * Customer bearer for self-scoped reads (`myProfile`, `myTillyNotes`). A
209
+ * User bearer for self-scoped reads (`myProfile`, `myTillyNotes`). A
210
210
  * function is resolved before every request so a cookie session can be read
211
211
  * per-request; a bare string is used as-is.
212
212
  */
213
213
  bearerToken?: string | FoirTokenProvider;
214
214
  /**
215
- * Renew the customer bearer when an answer comes back served without it
215
+ * Renew the user bearer when an answer comes back served without it
216
216
  * because it expired. Resolve the new token, or null when the session is
217
217
  * over. It is called at most once per request, and one call is shared by the
218
218
  * client's requests that find the bearer lapsed at the same time.
@@ -247,8 +247,8 @@ export interface FoirKeyClientConfig<S extends FoirSchemaDefinition = FoirSchema
247
247
  *
248
248
  * A credential already confined to an organization may only name its own
249
249
  * (`PERMISSION_DENIED` otherwise), so this cannot steer an organization key
250
- * elsewhere. And a request that also carries a customer bearer is refused
251
- * unless that customer stands in the named organization. The storefront
250
+ * elsewhere. And a request that also carries a user bearer is refused
251
+ * unless that user stands in the named organization. The storefront
252
252
  * pattern is still the confined credential, one per organization; this is
253
253
  * for the side of the product that holds the project key and has to choose.
254
254
  *
@@ -259,21 +259,28 @@ export interface FoirKeyClientConfig<S extends FoirSchemaDefinition = FoirSchema
259
259
  */
260
260
  orgId?: string;
261
261
  /**
262
- * The address of the visitor a server rendering pages is calling for, or a
263
- * function resolving it for each request, sent as `X-Foir-Visitor-IP`. The
264
- * public API's per-visitor limit then applies to that visitor rather than to
265
- * your server, which otherwise counts as one visitor for every page it
266
- * renders.
262
+ * The visitor a server rendering pages is calling for, or a function
263
+ * resolving them for each request: their address, and where they are.
267
264
  *
268
- * Give it the address your host guarantees: the one its edge sets and a
269
- * visitor cannot. A header a visitor can write lets them name a fresh address
270
- * per request, which is exactly what the limit exists to stop. The docs list
271
- * the value for each common host.
265
+ * The address is sent as `X-Foir-Visitor-IP`. The public API's per-visitor
266
+ * limit then applies to that visitor rather than to your server, which
267
+ * otherwise counts as one visitor for every page it renders. A string is the
268
+ * address alone.
272
269
  *
273
- * A secret key only, and one holding `visitors:forward`: the API refuses the
274
- * header, naming the permission, from any other. A client built from a public
275
- * key is refused `visitor` here, because a browser already calls as its own
276
- * visitor and a public key cannot hold the permission.
270
+ * The country and the coordinates are attached to every read, in its
271
+ * `contexts`, so that location targeting is decided by where the visitor is.
272
+ * Through a key holding `visitors:forward` the API never uses where the
273
+ * caller is: a read that says no place is a visitor nobody could place.
274
+ *
275
+ * Give it what your host guarantees: the values its edge sets and a visitor
276
+ * cannot. A header a visitor can write lets them name a fresh address per
277
+ * request, which is exactly what the limit exists to stop. The docs list
278
+ * the values for each common host.
279
+ *
280
+ * A server key only, and one holding `visitors:forward`: the API refuses the
281
+ * header, naming the permission, from any other. A client built from a
282
+ * publishable key is refused `visitor` here, because a browser already calls
283
+ * as its own visitor and a publishable key cannot hold the permission.
277
284
  */
278
285
  visitor?: FoirVisitorSource;
279
286
  /**
@@ -520,7 +527,7 @@ export interface FoirKeyClientConfig<S extends FoirSchemaDefinition = FoirSchema
520
527
  }
521
528
  /**
522
529
  * The options that belong to a key: the key itself, what it is presented with
523
- * (a customer bearer, an organization, a channel), and the subscription socket,
530
+ * (a user bearer, an organization, a channel), and the subscription socket,
524
531
  * which only a key can open.
525
532
  */
526
533
  type FoirKeySideOption = 'apiKey' | 'dispatch' | 'channel' | 'bearerToken' | 'refreshBearer' | 'orgId' | 'orgUrl' | 'visitor' | 'wsUrl' | 'webSocketImpl' | 'reconnect' | 'connectionParams';
@@ -593,7 +600,7 @@ export interface FoirSchemaDrift {
593
600
  * way, as paths into the manifest, sorted:
594
601
  * `models.order.selection.status`, `models.order.ops.update`,
595
602
  * `namespaces.search.ops.searchRecords.args.query`,
596
- * `models.order.relations.customer`, `selectionUnions.Block.HeroBlock.title`.
603
+ * `models.order.relations.user`, `selectionUnions.Block.HeroBlock.title`.
597
604
  *
598
605
  * `changed` says what moved; this says what BROKE. Empty when the surface
599
606
  * only grew, which is the usual drift, and then no typed call is refused.
@@ -43,7 +43,7 @@
43
43
  * being replayed after it expired.
44
44
  *
45
45
  * An operation's dispatch token is not one of them. The server's
46
- * `connection_init` authenticates a key, an admin token or a customer bearer
46
+ * `connection_init` authenticates a key, a console token or a user bearer
47
47
  * and has no path for a dispatch token, so a client built from one is refused
48
48
  * here, by name, rather than opening a socket the server will close as "Not
49
49
  * authenticated".