@foir/sdk 0.21.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.
- package/CHANGELOG.md +84 -1
- package/README.md +9 -9
- package/dist/app/client.d.ts +90 -84
- package/dist/app/contract/proto/apps/v1/apps_pb.d.ts +14 -13
- package/dist/app/dispatch.d.ts +5 -5
- package/dist/app/errors.d.ts +11 -11
- package/dist/app/index.d.ts +4 -4
- package/dist/app/naming.d.ts +1 -1
- package/dist/app/ticket.d.ts +2 -2
- package/dist/app/vocabulary.generated.d.ts +2 -2
- package/dist/app-contract.js +3 -3
- package/dist/app.js +92 -90
- package/dist/auth/access.d.ts +19 -19
- package/dist/auth/auth.d.ts +216 -114
- package/dist/auth/hosted.d.ts +14 -14
- package/dist/auth/index.d.ts +7 -7
- package/dist/auth/operations.d.ts +128 -32
- package/dist/auth/ops.d.ts +39 -21
- package/dist/auth/session-client.d.ts +3 -3
- package/dist/auth-session.js +3 -3
- package/dist/auth.js +234 -135
- package/dist/client.js +4 -4
- package/dist/data/builtins.d.ts +26 -26
- package/dist/data/client.d.ts +2 -2
- package/dist/data/decimal.d.ts +1 -1
- package/dist/data/index.d.ts +1 -1
- package/dist/data/manifest.d.ts +1 -1
- package/dist/data/schema.d.ts +1 -1
- package/dist/data/transport.d.ts +10 -10
- package/dist/data/ws-transport.d.ts +1 -1
- package/dist/data.js +6 -6
- package/dist/graphql/content-client.d.ts +13 -13
- package/dist/live/drift.d.ts +1 -1
- package/dist/media/screen-capture.d.ts +1 -1
- package/dist/next/index.d.ts +2 -2
- package/dist/next/session.d.ts +10 -10
- package/dist/next.js +77 -56
- package/dist/placement/index.d.ts +13 -13
- package/dist/placement.js +9 -6
- package/dist/push.js +61 -40
- package/dist/react/FoirFeedback.d.ts +2 -2
- package/dist/react/FoirProvider.d.ts +23 -23
- package/dist/react/SignIn.d.ts +4 -4
- package/dist/react/UserButton.d.ts +1 -1
- package/dist/react/feedback-notes.d.ts +4 -4
- package/dist/react/index.d.ts +3 -3
- package/dist/react.js +119 -95
- package/dist/realtime/index.d.ts +1 -1
- package/dist/server/callback-client.d.ts +4 -4
- package/dist/server/events-client.d.ts +16 -16
- package/dist/server/operation-types.d.ts +8 -8
- package/dist/server/require-scoped-token.d.ts +3 -3
- package/dist/server/types.d.ts +1 -1
- package/dist/server/verify-scoped-token.d.ts +3 -3
- package/dist/server.js +16 -13
- package/dist/transport/foir-http.d.ts +13 -13
- package/dist/types/index.d.ts +2 -2
- package/package.json +3 -3
package/dist/data/builtins.d.ts
CHANGED
|
@@ -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 = '
|
|
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
|
|
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 `'
|
|
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
|
|
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
|
|
462
|
-
* note about either through a row policy no
|
|
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
|
|
465
|
-
* (see the file header) applies: a kind the platform opens to
|
|
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
|
-
*
|
|
467
|
+
* user writer could have produced.
|
|
468
468
|
*/
|
|
469
|
-
export type FoirNoteSubjectType = 'record' | 'file' | 'model' | 'operation' | 'schedule' | '
|
|
469
|
+
export type FoirNoteSubjectType = 'record' | 'file' | 'model' | 'operation' | 'schedule' | 'user';
|
|
470
470
|
/**
|
|
471
|
-
* One file the
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
550
|
-
* deliberately sent them. Never another
|
|
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<
|
|
553
|
+
export type FoirMyNotesResult = FoirConnection<FoirUserNote>;
|
|
554
554
|
/**
|
|
555
|
-
* `writeNote` arguments: the one note create, for a signed-in
|
|
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
|
|
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
|
|
588
|
-
*
|
|
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
|
-
*
|
|
600
|
+
* user. Use `writeNote` and {@link FoirWriteNoteArgs}.
|
|
601
601
|
*/
|
|
602
602
|
export interface FoirCreateMyNoteArgs {
|
|
603
603
|
subjectType: FoirNoteSubjectType;
|
package/dist/data/client.d.ts
CHANGED
|
@@ -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`, `
|
|
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
|
|
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
|
package/dist/data/decimal.d.ts
CHANGED
|
@@ -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
|
|
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
|
package/dist/data/index.d.ts
CHANGED
|
@@ -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,
|
|
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
|
package/dist/data/manifest.d.ts
CHANGED
|
@@ -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`, `
|
|
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.
|
package/dist/data/schema.d.ts
CHANGED
|
@@ -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`, `
|
|
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
|
*/
|
package/dist/data/transport.d.ts
CHANGED
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
* Where a call goes
|
|
6
6
|
* ---------------------------------------------------------------------------
|
|
7
7
|
*
|
|
8
|
-
* read + `pk_` key + no
|
|
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
|
|
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
|
|
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
|
|
186
|
+
* `sk_`, optionally for a signed-in user.
|
|
187
187
|
*/
|
|
188
188
|
export interface FoirKeyClientConfig<S extends FoirSchemaDefinition = FoirSchemaDefinition> {
|
|
189
189
|
/**
|
|
@@ -206,13 +206,13 @@ export interface FoirKeyClientConfig<S extends FoirSchemaDefinition = FoirSchema
|
|
|
206
206
|
*/
|
|
207
207
|
channel?: 'published' | 'draft';
|
|
208
208
|
/**
|
|
209
|
-
*
|
|
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
|
|
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
|
|
251
|
-
* unless that
|
|
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
|
*
|
|
@@ -527,7 +527,7 @@ export interface FoirKeyClientConfig<S extends FoirSchemaDefinition = FoirSchema
|
|
|
527
527
|
}
|
|
528
528
|
/**
|
|
529
529
|
* The options that belong to a key: the key itself, what it is presented with
|
|
530
|
-
* (a
|
|
530
|
+
* (a user bearer, an organization, a channel), and the subscription socket,
|
|
531
531
|
* which only a key can open.
|
|
532
532
|
*/
|
|
533
533
|
type FoirKeySideOption = 'apiKey' | 'dispatch' | 'channel' | 'bearerToken' | 'refreshBearer' | 'orgId' | 'orgUrl' | 'visitor' | 'wsUrl' | 'webSocketImpl' | 'reconnect' | 'connectionParams';
|
|
@@ -600,7 +600,7 @@ export interface FoirSchemaDrift {
|
|
|
600
600
|
* way, as paths into the manifest, sorted:
|
|
601
601
|
* `models.order.selection.status`, `models.order.ops.update`,
|
|
602
602
|
* `namespaces.search.ops.searchRecords.args.query`,
|
|
603
|
-
* `models.order.relations.
|
|
603
|
+
* `models.order.relations.user`, `selectionUnions.Block.HeroBlock.title`.
|
|
604
604
|
*
|
|
605
605
|
* `changed` says what moved; this says what BROKE. Empty when the surface
|
|
606
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,
|
|
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".
|
package/dist/data.js
CHANGED
|
@@ -166,8 +166,8 @@ var FoirAuthDowngradedError = class extends FoirRequestError {
|
|
|
166
166
|
downgrade;
|
|
167
167
|
constructor(downgrade) {
|
|
168
168
|
super(
|
|
169
|
-
`[foir] your
|
|
170
|
-
{ graphQLErrors: [{ message: "
|
|
169
|
+
`[foir] your user token was ${downgrade.userToken} (${downgrade.reason}), so the request was served as ${downgrade.servedAs}`,
|
|
170
|
+
{ graphQLErrors: [{ message: "user token rejected", extensions: { code: "AUTH_DOWNGRADED" } }] }
|
|
171
171
|
);
|
|
172
172
|
this.name = "FoirAuthDowngradedError";
|
|
173
173
|
this.downgrade = downgrade;
|
|
@@ -175,7 +175,7 @@ var FoirAuthDowngradedError = class extends FoirRequestError {
|
|
|
175
175
|
};
|
|
176
176
|
var FoirSessionExpiredError = class extends FoirRequestError {
|
|
177
177
|
constructor(options) {
|
|
178
|
-
super("[foir] the
|
|
178
|
+
super("[foir] the user session has expired and could not be refreshed: sign in again", {
|
|
179
179
|
cause: options?.cause,
|
|
180
180
|
graphQLErrors: [{ message: "session expired", extensions: { code: "SESSION_EXPIRED" } }]
|
|
181
181
|
});
|
|
@@ -192,7 +192,7 @@ function reportAuthDowngrade(envelope) {
|
|
|
192
192
|
if (warnedDowngrade === downgrade.reason) return;
|
|
193
193
|
warnedDowngrade = downgrade.reason;
|
|
194
194
|
console.warn(
|
|
195
|
-
`[foir] your
|
|
195
|
+
`[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.")
|
|
196
196
|
);
|
|
197
197
|
}
|
|
198
198
|
function refusePrunedDocument(json, options) {
|
|
@@ -383,7 +383,7 @@ function assertFoirCredential(config) {
|
|
|
383
383
|
].filter((name) => loose[name] !== void 0);
|
|
384
384
|
if (keySide.length > 0) {
|
|
385
385
|
throw new FoirRequestError(
|
|
386
|
-
`[foir] createFoirClient was given \`dispatch\` and ${keySide.map((n) => `\`${n}\``).join(", ")}. A dispatch token and an api key are different actors, and the dispatch token carries its own
|
|
386
|
+
`[foir] createFoirClient was given \`dispatch\` and ${keySide.map((n) => `\`${n}\``).join(", ")}. A dispatch token and an api key are different actors, and the dispatch token carries its own user, organization and channel. Pass one credential: \`dispatch\` inside an operation endpoint, \`apiKey\` everywhere else.`
|
|
387
387
|
);
|
|
388
388
|
}
|
|
389
389
|
const dispatch = loose.dispatch;
|
|
@@ -1411,7 +1411,7 @@ var FoirSocketTransport = class {
|
|
|
1411
1411
|
constructor(config) {
|
|
1412
1412
|
if (config.dispatch !== void 0) {
|
|
1413
1413
|
throw new FoirRequestError(
|
|
1414
|
-
"[foir] a client built from a dispatch token cannot subscribe. The subscription socket authenticates an api key,
|
|
1414
|
+
"[foir] a client built from a dispatch token cannot subscribe. The subscription socket authenticates an api key, a console token or a user bearer, and has no path for a dispatch token. Queries and mutations made as the operation go to /graphql and work as they are."
|
|
1415
1415
|
);
|
|
1416
1416
|
}
|
|
1417
1417
|
this.config = config;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Session-bound content client — forwards the
|
|
3
|
-
* when one is available, so auth/segment-targeted variants and
|
|
2
|
+
* Session-bound content client — forwards the user bearer on every read
|
|
3
|
+
* when one is available, so auth/segment-targeted variants and user-scoped
|
|
4
4
|
* records resolve out of the box, with no per-query wiring to forget.
|
|
5
5
|
*
|
|
6
6
|
* Resolution keys off the request's principal (see the platform's two-gate
|
|
7
7
|
* model): the `x-api-key` alone resolves the *anonymous baseline*
|
|
8
|
-
* (`context.authStatus = ""`); adding the
|
|
9
|
-
* as that
|
|
8
|
+
* (`context.authStatus = ""`); adding the user bearer resolves the request
|
|
9
|
+
* as that user (`context.authStatus = "authenticated"`, `user_id` set).
|
|
10
10
|
*
|
|
11
11
|
* Caching: an api-key-only read is identical for every anonymous visitor and is
|
|
12
|
-
* shared-cacheable; a bearer-bearing read resolves per-
|
|
13
|
-
* Because the bearer only exists once a
|
|
12
|
+
* shared-cacheable; a bearer-bearing read resolves per-user and is not.
|
|
13
|
+
* Because the bearer only exists once a user signs in, anonymous traffic
|
|
14
14
|
* keeps hitting the shared-cacheable baseline — only signed-in reads become
|
|
15
|
-
* per-
|
|
16
|
-
* apps, everywhere the
|
|
15
|
+
* per-user. Bind this client wherever content is personalized (for most
|
|
16
|
+
* apps, everywhere the user may be signed in) and use plain `foirRequest`
|
|
17
17
|
* for reads that must stay anonymous regardless of session.
|
|
18
18
|
*/
|
|
19
19
|
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
@@ -25,9 +25,9 @@ import type { FoirTokenProvider } from '../transport/foir-http';
|
|
|
25
25
|
export interface FoirContentClientConfig {
|
|
26
26
|
env: FoirEnv;
|
|
27
27
|
/**
|
|
28
|
-
* Resolves the current
|
|
28
|
+
* Resolves the current user bearer before every request. When it yields a
|
|
29
29
|
* token the token is forwarded, so `authStatus`/segment targeting and
|
|
30
|
-
*
|
|
30
|
+
* user-scoped records resolve as that user; when it yields
|
|
31
31
|
* null/undefined the read hits the anonymous baseline. Omit for a client that
|
|
32
32
|
* is always anonymous (equivalent to calling `foirRequest` directly).
|
|
33
33
|
*/
|
|
@@ -51,7 +51,7 @@ export interface FoirContentClientConfig {
|
|
|
51
51
|
}
|
|
52
52
|
export interface FoirContentClient {
|
|
53
53
|
/**
|
|
54
|
-
* Run a typed document, forwarding the bound
|
|
54
|
+
* Run a typed document, forwarding the bound user bearer when available.
|
|
55
55
|
* An explicit `options.bearerToken` still wins, so a single call can override
|
|
56
56
|
* the bound token (or force anonymous by passing `undefined` — the bound
|
|
57
57
|
* token only fills in when `options.bearerToken` is not supplied).
|
|
@@ -60,7 +60,7 @@ export interface FoirContentClient {
|
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
62
|
* Create a {@link FoirContentClient} bound to an env + token source. Every
|
|
63
|
-
* `request` forwards the
|
|
64
|
-
* that read from the anonymous baseline to the signed-in
|
|
63
|
+
* `request` forwards the user bearer when `getToken` yields one, upgrading
|
|
64
|
+
* that read from the anonymous baseline to the signed-in user.
|
|
65
65
|
*/
|
|
66
66
|
export declare function createFoirContentClient(config: FoirContentClientConfig): FoirContentClient;
|
package/dist/live/drift.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ import type { FoirSchemaDrift } from '../data/transport';
|
|
|
12
12
|
* Nothing else catches it. The dependency graph is about records, and no record
|
|
13
13
|
* changed. `seq` is about ordering, and nothing is out of order. The entry is
|
|
14
14
|
* fresh, correctly tagged, correctly stamped, and describes a schema that no
|
|
15
|
-
* longer exists — until the tab is reloaded, which on a long-lived
|
|
15
|
+
* longer exists — until the tab is reloaded, which on a long-lived console
|
|
16
16
|
* session can be days.
|
|
17
17
|
*
|
|
18
18
|
* The SDK already detects this: the data client compares the surface version
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* ---------------------------------------------------------------------------
|
|
7
7
|
*
|
|
8
8
|
* Two surfaces need the same picture: the console's own bug report, and the
|
|
9
|
-
* feedback widget a
|
|
9
|
+
* feedback widget a user's visitors use (`@foir/sdk/react`). One of those
|
|
10
10
|
* ships to npm and the other does not, so the shared half has to sit in the
|
|
11
11
|
* published package — a copy in each would be two answers to "how big is a
|
|
12
12
|
* screenshot", free to drift, and the drift would only show up as an upload the
|
package/dist/next/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `@foir/sdk/next` — server-side Foir
|
|
2
|
+
* `@foir/sdk/next` — server-side Foir user auth for the Next.js App Router
|
|
3
3
|
* (the BFF pattern): an HttpOnly-cookie session adapter, server-side session
|
|
4
4
|
* helpers, a provider-callback exchange, and a route-protection middleware.
|
|
5
5
|
*
|
|
@@ -18,5 +18,5 @@ export { readFoirCacheTags, foirCacheTags, createFoirTaggingFetch, foirTagsForRe
|
|
|
18
18
|
export type { FoirHeaderSource, FoirCacheTags, FoirCacheTagsOptions, FoirTaggingReport, FoirTaggingFetchOptions, FoirRecordChange, } from './cacheTags';
|
|
19
19
|
export { createFoirMiddleware } from './middleware';
|
|
20
20
|
export type { FoirMiddlewareConfig, FoirMiddlewareRequest } from './middleware';
|
|
21
|
-
export type {
|
|
21
|
+
export type { FoirUser, SessionAdapter } from '../auth';
|
|
22
22
|
export type { FoirEnv } from '../graphql/foir-request';
|
package/dist/next/session.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FoirUser } from '../auth';
|
|
2
2
|
import type { FoirEnv } from '../graphql/foir-request';
|
|
3
3
|
import type { CookieAdapterOptions, FoirCookieStore } from './cookieAdapter';
|
|
4
4
|
/**
|
|
@@ -6,14 +6,14 @@ import type { CookieAdapterOptions, FoirCookieStore } from './cookieAdapter';
|
|
|
6
6
|
* cookie store (`await cookies()` in a route handler / server action, or the
|
|
7
7
|
* read-only `cookies()` in a Server Component for reads).
|
|
8
8
|
*
|
|
9
|
-
* Note on "verification": the
|
|
9
|
+
* Note on "verification": the user access token is opaque to your app and
|
|
10
10
|
* validated by the Foir API on use, so `getFoirSession` returns the identity
|
|
11
11
|
* stored in the cookies rather than locally verifying a JWT. A rejected/expired
|
|
12
12
|
* bearer surfaces when you call the API (and `@foir/sdk/auth`'s `authedRequest`
|
|
13
13
|
* transparently refreshes it).
|
|
14
14
|
*/
|
|
15
|
-
/** The signed-in
|
|
16
|
-
export declare function getFoirSession(store: FoirCookieStore): Promise<
|
|
15
|
+
/** The signed-in user from the session cookies, or null. */
|
|
16
|
+
export declare function getFoirSession(store: FoirCookieStore): Promise<FoirUser | null>;
|
|
17
17
|
/** The current access token from the session cookies, or null. */
|
|
18
18
|
export declare function getFoirToken(store: FoirCookieStore): Promise<string | null>;
|
|
19
19
|
/** Clear the session cookies (sign out). */
|
|
@@ -26,9 +26,9 @@ interface PasswordArgs {
|
|
|
26
26
|
cookieOptions?: CookieAdapterOptions['cookieOptions'];
|
|
27
27
|
}
|
|
28
28
|
/** Password sign-in in a route handler; persists the session to cookies. */
|
|
29
|
-
export declare function foirSignInWithPassword({ env, store, email, password, cookieOptions, }: PasswordArgs): Promise<
|
|
30
|
-
/** Register a
|
|
31
|
-
export declare function foirRegisterWithPassword({ env, store, email, password, cookieOptions, }: PasswordArgs): Promise<
|
|
29
|
+
export declare function foirSignInWithPassword({ env, store, email, password, cookieOptions, }: PasswordArgs): Promise<FoirUser>;
|
|
30
|
+
/** Register a user in a route handler; persists the session to cookies. */
|
|
31
|
+
export declare function foirRegisterWithPassword({ env, store, email, password, cookieOptions, }: PasswordArgs): Promise<FoirUser>;
|
|
32
32
|
/** Complete an OTP sign-in in a route handler; persists the session to cookies. */
|
|
33
33
|
export declare function foirSignInWithOtp({ env, store, email, otp, cookieOptions, }: {
|
|
34
34
|
env: FoirEnv;
|
|
@@ -36,11 +36,11 @@ export declare function foirSignInWithOtp({ env, store, email, otp, cookieOption
|
|
|
36
36
|
email: string;
|
|
37
37
|
otp: string;
|
|
38
38
|
cookieOptions?: CookieAdapterOptions['cookieOptions'];
|
|
39
|
-
}): Promise<
|
|
39
|
+
}): Promise<FoirUser>;
|
|
40
40
|
/**
|
|
41
41
|
* Complete a provider (OAuth/OIDC) login in your callback route handler:
|
|
42
42
|
* exchange the `code` + `state` for tokens and persist them to the session
|
|
43
|
-
* cookies. Returns the
|
|
43
|
+
* cookies. Returns the user.
|
|
44
44
|
*/
|
|
45
45
|
export declare function completeFoirProviderLogin(opts: {
|
|
46
46
|
env: FoirEnv;
|
|
@@ -49,5 +49,5 @@ export declare function completeFoirProviderLogin(opts: {
|
|
|
49
49
|
code?: string;
|
|
50
50
|
state?: string;
|
|
51
51
|
cookieOptions?: CookieAdapterOptions['cookieOptions'];
|
|
52
|
-
}): Promise<
|
|
52
|
+
}): Promise<FoirUser>;
|
|
53
53
|
export {};
|