@foir/sdk 0.30.1 → 0.31.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 +14 -0
- package/README.md +1 -1
- package/dist/ai/index.d.ts +8 -9
- package/dist/ai.js +162 -7
- package/dist/app/client.d.ts +9 -5
- package/dist/app.js +12 -13
- package/dist/auth/auth.d.ts +80 -101
- package/dist/auth/hosted.d.ts +12 -12
- package/dist/auth/index.d.ts +11 -7
- package/dist/auth/operations.d.ts +17 -32
- package/dist/auth/ops.d.ts +4 -13
- package/dist/auth/session-client.d.ts +4 -4
- package/dist/auth/steps.d.ts +50 -0
- package/dist/auth-session.js +3 -3
- package/dist/auth.js +157 -75
- package/dist/content/content-renderer.d.ts +2 -2
- package/dist/content/richtext.d.ts +2 -2
- package/dist/content.js +7 -7
- package/dist/data/builtins.d.ts +64 -33
- package/dist/data/index.d.ts +2 -2
- package/dist/data/manifest.d.ts +1 -1
- package/dist/data/schema.d.ts +1 -1
- package/dist/data/selection.d.ts +3 -3
- package/dist/data.js +5 -2
- package/dist/next/index.d.ts +1 -1
- package/dist/next/session.d.ts +27 -11
- package/dist/next.js +98 -40
- package/dist/push.js +9 -19
- package/dist/react/FoirProvider.d.ts +18 -16
- package/dist/react/feedback-notes.d.ts +1 -2
- package/dist/react.js +167 -84
- package/dist/runs/step-reply.d.ts +81 -0
- package/dist/server/callback-client.d.ts +11 -16
- package/dist/server/index.d.ts +2 -0
- package/dist/server/operation-types.d.ts +6 -13
- package/dist/server.js +76 -107
- package/dist/transport/foir-http.d.ts +20 -6
- package/package.json +1 -1
package/dist/data/builtins.d.ts
CHANGED
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
* against `api-public/internal/schema/field_mapping.go`.
|
|
47
47
|
*/
|
|
48
48
|
import type { FoirConnection } from './schema';
|
|
49
|
+
import type { StepReply } from '../runs/step-reply';
|
|
49
50
|
/** A `JSON` scalar. Deliberately not `any`: reading through it needs a check. */
|
|
50
51
|
export type FoirJsonValue = string | number | boolean | null | FoirJsonValue[] | {
|
|
51
52
|
[key: string]: FoirJsonValue;
|
|
@@ -84,6 +85,8 @@ export interface Image {
|
|
|
84
85
|
* `url: String` — so this follows.
|
|
85
86
|
*/
|
|
86
87
|
__typename?: 'Image';
|
|
88
|
+
/** The item's own id when this is an item of a list or an entry of a prose field; null on a plain field's value. */
|
|
89
|
+
_id: string | null;
|
|
87
90
|
url: string | null;
|
|
88
91
|
width: number | null;
|
|
89
92
|
height: number | null;
|
|
@@ -102,6 +105,8 @@ export interface Image {
|
|
|
102
105
|
}
|
|
103
106
|
export interface Video {
|
|
104
107
|
__typename?: 'Video';
|
|
108
|
+
/** The item's own id when this is an item of a list or an entry of a prose field; null on a plain field's value. */
|
|
109
|
+
_id: string | null;
|
|
105
110
|
url: string | null;
|
|
106
111
|
thumbnailUrl: string | null;
|
|
107
112
|
previewUrl: string | null;
|
|
@@ -116,6 +121,8 @@ export interface Video {
|
|
|
116
121
|
}
|
|
117
122
|
export interface FileValue {
|
|
118
123
|
__typename?: 'FileValue';
|
|
124
|
+
/** The item's own id when this is an item of a list or an entry of a prose field; null on a plain field's value. */
|
|
125
|
+
_id: string | null;
|
|
119
126
|
url: string | null;
|
|
120
127
|
filename: string | null;
|
|
121
128
|
mimeType: string | null;
|
|
@@ -123,6 +130,8 @@ export interface FileValue {
|
|
|
123
130
|
}
|
|
124
131
|
export interface GeoPoint {
|
|
125
132
|
__typename?: 'GeoPoint';
|
|
133
|
+
/** The item's own id when this is an item of a list or an entry of a prose field; null on a plain field's value. */
|
|
134
|
+
_id: string | null;
|
|
126
135
|
lat: number | null;
|
|
127
136
|
lng: number | null;
|
|
128
137
|
}
|
|
@@ -157,7 +166,8 @@ export interface ProseSpan {
|
|
|
157
166
|
*/
|
|
158
167
|
export interface Passage {
|
|
159
168
|
__typename?: 'Passage';
|
|
160
|
-
|
|
169
|
+
/** The passage's own id: minted once, never changed, unique within its record. */
|
|
170
|
+
_id: string | null;
|
|
161
171
|
kind: string | null;
|
|
162
172
|
token: string | null;
|
|
163
173
|
align: string | null;
|
|
@@ -209,30 +219,25 @@ export interface RecordAncestor {
|
|
|
209
219
|
*
|
|
210
220
|
* # What makes it followable
|
|
211
221
|
*
|
|
212
|
-
* `_targetModelKey` names the model and `_targetId`
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
* rather than an omission. They were the wrapper's own metadata: `_id` was the
|
|
220
|
-
* ITEM's id (never the target's, which is why `_targetId` exists separately) and
|
|
221
|
-
* `_type` was the union discriminator, reading `"reference"` on every reference
|
|
222
|
-
* ever stored. The wrapper is gone, so neither field is in the schema, and a
|
|
223
|
-
* consumer selecting them got `undefined` while the types promised a string.
|
|
222
|
+
* `_targetModelKey` names the model and `_targetId` the row within it:
|
|
223
|
+
* `foir[_targetModelKey].findUnique({ where: { _id: _targetId } })`. A reference
|
|
224
|
+
* names its target by id and nothing else.
|
|
225
|
+
*
|
|
226
|
+
* `_id` is the entry's own id, never the target's, which is why `_targetId`
|
|
227
|
+
* exists separately. It is null on a reference field's value, which is not an
|
|
228
|
+
* entry.
|
|
224
229
|
*/
|
|
225
230
|
export interface Reference<TRecord = FoirUnexpandedRecord> {
|
|
226
231
|
__typename?: 'Reference';
|
|
232
|
+
/** The entry's own id, when the reference is an entry of a prose field. */
|
|
233
|
+
_id: string | null;
|
|
227
234
|
/** The model to fetch the target from. Null when the target no longer exists. */
|
|
228
235
|
_targetModelKey: string | null;
|
|
229
|
-
/** The target's id
|
|
236
|
+
/** The target's id. */
|
|
230
237
|
_targetId: string | null;
|
|
231
|
-
/** The target's natural key, when the reference names its target that way. */
|
|
232
|
-
_targetNaturalKey: string | null;
|
|
233
238
|
/**
|
|
234
239
|
* The resolved target, over the project's `Record` union — every model in the
|
|
235
|
-
* project. Left as a type parameter so the generated file can name that
|
|
240
|
+
* project that bears records. Left as a type parameter so the generated file can name that
|
|
236
241
|
* union; the default is the honest answer for a consumer who has not narrowed
|
|
237
242
|
* it.
|
|
238
243
|
*/
|
|
@@ -397,13 +402,8 @@ export type FoirUnexpandedRecord = FoirDegraded;
|
|
|
397
402
|
*/
|
|
398
403
|
export type FoirVisibility = 'PRIVATE' | 'PUBLIC';
|
|
399
404
|
export type FoirAccessLevel = 'READ' | 'WRITE' | 'DELETE';
|
|
400
|
-
export type FoirAccessSource = '
|
|
405
|
+
export type FoirAccessSource = 'OWNER' | 'GRANT' | 'ROLE';
|
|
401
406
|
export type FoirGranteeKind = 'USER';
|
|
402
|
-
/** `myAccess` — this principal's effective access to one record. */
|
|
403
|
-
export interface FoirMyAccess {
|
|
404
|
-
access: FoirAccessLevel;
|
|
405
|
-
source: FoirAccessSource;
|
|
406
|
-
}
|
|
407
407
|
export interface FoirAccessGrant {
|
|
408
408
|
access: FoirAccessLevel;
|
|
409
409
|
createdAt: string;
|
|
@@ -416,7 +416,7 @@ export interface FoirAccessor {
|
|
|
416
416
|
granteeKind: FoirGranteeKind;
|
|
417
417
|
source: FoirAccessSource;
|
|
418
418
|
}
|
|
419
|
-
/** `access` —
|
|
419
|
+
/** `access` — who can reach one record, or one user's access to it. */
|
|
420
420
|
export interface FoirResourceAccess {
|
|
421
421
|
accessors: FoirAccessor[];
|
|
422
422
|
grants: FoirAccessGrant[];
|
|
@@ -592,14 +592,17 @@ export interface FoirWriteNoteArgs {
|
|
|
592
592
|
/** A visitor may write about a record and nothing else. */
|
|
593
593
|
subjectType: FoirNoteSubjectType;
|
|
594
594
|
subjectId: string;
|
|
595
|
-
/**
|
|
595
|
+
/**
|
|
596
|
+
* @deprecated Not read: a note on a record takes the record's own model.
|
|
597
|
+
* Still accepted so code that sends it keeps working.
|
|
598
|
+
*/
|
|
596
599
|
subjectModelKey?: string;
|
|
597
600
|
body: string;
|
|
598
601
|
/** Reply within an existing thread. Refused where nobody is signed in. */
|
|
599
602
|
parentNoteId?: string;
|
|
600
603
|
/**
|
|
601
|
-
* Files to submit with this note, already uploaded through
|
|
602
|
-
*
|
|
604
|
+
* Files to submit with this note, already uploaded through `uploadFile`.
|
|
605
|
+
* Refused where nobody is signed in.
|
|
603
606
|
*
|
|
604
607
|
* A file this caller cannot read is REFUSED and the note is not written. That
|
|
605
608
|
* is not a rough edge to code around: a create that accepted the note and
|
|
@@ -626,14 +629,16 @@ export interface FoirWriteNoteArgs {
|
|
|
626
629
|
export interface FoirCreateMyNoteArgs {
|
|
627
630
|
subjectType: FoirNoteSubjectType;
|
|
628
631
|
subjectId: string;
|
|
629
|
-
/**
|
|
632
|
+
/**
|
|
633
|
+
* @deprecated Not read: a note on a record takes the record's own model.
|
|
634
|
+
* Still accepted so code that sends it keeps working.
|
|
635
|
+
*/
|
|
630
636
|
subjectModelKey?: string;
|
|
631
637
|
body: string;
|
|
632
638
|
/** Reply within an existing thread. */
|
|
633
639
|
parentNoteId?: string;
|
|
634
640
|
/**
|
|
635
|
-
* Files to submit with this note, already uploaded through
|
|
636
|
-
* `createFileUpload` / `confirmFileUpload`.
|
|
641
|
+
* Files to submit with this note, already uploaded through `uploadFile`.
|
|
637
642
|
*
|
|
638
643
|
* A file this caller cannot read is REFUSED and the note is not written. That
|
|
639
644
|
* is not a rough edge to code around: a create that accepted the note and
|
|
@@ -693,14 +698,35 @@ export interface FoirAgentApproval {
|
|
|
693
698
|
decision: 'PENDING' | 'APPROVED' | 'DENIED' | 'EXPIRED';
|
|
694
699
|
reason?: string | null;
|
|
695
700
|
}
|
|
701
|
+
/**
|
|
702
|
+
* An act held for a decision: a step a run holds, or an act proposed on a
|
|
703
|
+
* note. `myAgentApprovals` lists them and `decideAgentApproval` decides one.
|
|
704
|
+
*/
|
|
705
|
+
export interface FoirAgentHeldAct {
|
|
706
|
+
/** Pass it to `decideAgentApproval`. */
|
|
707
|
+
id: string;
|
|
708
|
+
heldIn: 'RUN' | 'NOTE';
|
|
709
|
+
/** RUN: the run that holds it. */
|
|
710
|
+
runId?: string | null;
|
|
711
|
+
/** NOTE: the note it is held on. */
|
|
712
|
+
noteId?: string | null;
|
|
713
|
+
/** The tool, operation or agent it would call, by its name. */
|
|
714
|
+
action: string;
|
|
715
|
+
/** What it would be called with. */
|
|
716
|
+
input?: unknown;
|
|
717
|
+
approval?: FoirAgentApproval | null;
|
|
718
|
+
requestedBy?: string | null;
|
|
719
|
+
/** ISO-8601. */
|
|
720
|
+
createdAt?: string | null;
|
|
721
|
+
}
|
|
696
722
|
/** One step of a run: a model turn, a tool call, a check, or a child agent. */
|
|
697
723
|
export interface FoirAgentRunNode {
|
|
698
724
|
id: string;
|
|
699
725
|
parentId?: string | null;
|
|
700
726
|
/**
|
|
701
727
|
* PAGE_TOOL is a call to a tool the caller's page offered with the message,
|
|
702
|
-
* HELD until the page answers it with `
|
|
703
|
-
*
|
|
728
|
+
* HELD until the page answers it with its `reply`; DATA is data sent to the
|
|
729
|
+
* app's components, delivered as a DATA event.
|
|
704
730
|
*/
|
|
705
731
|
kind: 'AGENT' | 'OPERATION' | 'VERB' | 'MCP_TOOL' | 'MODEL_TURN' | 'CHECK' | 'PAGE_TOOL' | 'DATA';
|
|
706
732
|
/** The tool, operation or agent the step is, by its key. */
|
|
@@ -714,6 +740,11 @@ export interface FoirAgentRunNode {
|
|
|
714
740
|
startedAt?: string | null;
|
|
715
741
|
/** ISO-8601. */
|
|
716
742
|
completedAt?: string | null;
|
|
743
|
+
/**
|
|
744
|
+
* A HELD PAGE_TOOL step, for the run's own caller: how the page answers it,
|
|
745
|
+
* with `replyToStep`. Nobody else is handed one.
|
|
746
|
+
*/
|
|
747
|
+
reply?: StepReply | null;
|
|
717
748
|
}
|
|
718
749
|
/**
|
|
719
750
|
* A run of an agent: its answer, once given, and every step it took. A refusal
|
|
@@ -793,7 +824,7 @@ export interface FoirStartAgentRunArgs {
|
|
|
793
824
|
/**
|
|
794
825
|
* Tools of the caller's own page the agent may call during this run, for
|
|
795
826
|
* an agent that allows the page's tools. A call is HELD until the page
|
|
796
|
-
* answers it with `
|
|
827
|
+
* answers it with its `reply`. At most 20. `foirChatTransport`'s
|
|
797
828
|
* `pageTools` sends these and answers the calls for you.
|
|
798
829
|
*/
|
|
799
830
|
pageTools?: FoirPageToolOffer[];
|
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 { FoirFieldMark, FoirFieldMarkAttributes, FoirSubject, FoirSubjectEntry, FoirSubjectOptions, FoirSubjectOrigin, FoirSubjectRegistry, } from './subjects';
|
|
62
|
-
export type { CollabInfo, FileValue, FoirAccessGrant, FoirAccessLevel, FoirAccessSource, FoirAccessor, FoirCreateMyNoteArgs, FoirWriteNoteArgs, FoirUserNote, FoirUserNoteAttachment, FoirDegraded, FoirDepthBelow, FoirDepthLevel, FoirDeviceType, FoirGranteeKind, FoirJsonValue,
|
|
62
|
+
export type { CollabInfo, FileValue, FoirAccessGrant, FoirAccessLevel, FoirAccessSource, FoirAccessor, FoirCreateMyNoteArgs, FoirWriteNoteArgs, FoirUserNote, FoirUserNoteAttachment, FoirDegraded, FoirDepthBelow, FoirDepthLevel, FoirDeviceType, FoirGranteeKind, FoirJsonValue, FoirMyNotesArgs, FoirMyNotesResult, FoirAgentApproval, FoirAgentAttachment, FoirAgentAttachmentUpload, FoirAgentRun, FoirAgentHeldAct, FoirAgentRunNode, FoirAgentRunStatus, FoirAgentThread, FoirAgentThreadMessage, FoirAgentThreadsResult, FoirMcpConnection, FoirStartAgentRunArgs, FoirPageToolOffer, FoirCreateAgentAttachmentArgs, FoirMessageTag, FoirMessageTagKind, FoirNoteConfig, FoirNoteReceipt, 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,6 +82,6 @@ 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, stepUpRequired, } from '../transport/foir-http';
|
|
85
|
-
export type { FoirEnv, FoirGraphQLErrorItem, FoirTokenProvider, FoirAuthDowngrade, FoirStepUp, FoirVisitor, FoirVisitorSource, } from '../transport/foir-http';
|
|
85
|
+
export type { FoirEnv, FoirGraphQLErrorItem, FoirTokenProvider, FoirAuthDowngrade, FoirStepUp, FoirStepUpAsk, FoirVisitor, FoirVisitorSource, } from '../transport/foir-http';
|
|
86
86
|
export { askAgent, uploadAgentFile, visitorToken } from './agents';
|
|
87
87
|
export type { AgentReply, AskAgentOptions, FoirAgentFile, FoirAgentFilesClient, FoirAgentsClient } from './agents';
|
package/dist/data/manifest.d.ts
CHANGED
|
@@ -97,7 +97,7 @@ export interface FoirManifestOp {
|
|
|
97
97
|
*
|
|
98
98
|
* The model's own `selection` answers for `findUnique` and for nothing else:
|
|
99
99
|
* `findMany` returns a connection OVER the model, `search` returns a wrapper
|
|
100
|
-
* CARRYING it, `delete` returns `Boolean!`, and `
|
|
100
|
+
* CARRYING it, `delete` returns `Boolean!`, and `access` returns a payload
|
|
101
101
|
* that is not the model in any sense. A consumer that bridged that gap by
|
|
102
102
|
* knowing from the OP NAME which shape to print was carrying a schema under
|
|
103
103
|
* another name.
|
package/dist/data/schema.d.ts
CHANGED
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
* (`findUnique`, `findMine`).
|
|
152
152
|
* - `connection` — a Relay connection over the model (`findMany`).
|
|
153
153
|
* - `list` — a plain array of the model.
|
|
154
|
-
* - `opaque` — the op does not return the model at all (`
|
|
154
|
+
* - `opaque` — the op does not return the model at all (`access`). Its
|
|
155
155
|
* `type` is used verbatim and `include`/`omit` are not offered.
|
|
156
156
|
*
|
|
157
157
|
* 7. **Unions are emitted statically.** A polymorphic field's type is written
|
package/dist/data/selection.d.ts
CHANGED
|
@@ -274,9 +274,9 @@ type MemberOf<U, T> = Extract<U, {
|
|
|
274
274
|
*
|
|
275
275
|
* `__typename` is excluded because it is not optional: the printer emits it at
|
|
276
276
|
* the union level whatever the selection says, so offering it would suggest a
|
|
277
|
-
* choice that does not exist.
|
|
278
|
-
*
|
|
279
|
-
*
|
|
277
|
+
* choice that does not exist. An entry's own `_id` IS offered — unlike a
|
|
278
|
+
* record's `_id` the server does not force it inside a fragment, so naming it is
|
|
279
|
+
* the only way to keep it.
|
|
280
280
|
*/
|
|
281
281
|
type MemberKeys<U, T> = Exclude<Extract<keyof MemberOf<U, T>, string>, '__typename'>;
|
|
282
282
|
/**
|
package/dist/data.js
CHANGED
|
@@ -14,8 +14,11 @@ function stepUpRequired(error) {
|
|
|
14
14
|
if (!(error instanceof FoirRequestError)) return null;
|
|
15
15
|
for (const item of error.graphQLErrors ?? []) {
|
|
16
16
|
if (item.extensions?.code !== "STEP_UP_REQUIRED") continue;
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
17
|
+
const kind = item.extensions.stepUp;
|
|
18
|
+
if (kind === "proof" || kind === "second_factor" || kind === "sign_in_method") {
|
|
19
|
+
const url = item.extensions.stepUpUrl;
|
|
20
|
+
return { kind, url: typeof url === "string" && url !== "" ? url : null };
|
|
21
|
+
}
|
|
19
22
|
}
|
|
20
23
|
return null;
|
|
21
24
|
}
|
package/dist/next/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
export { createFoirCookieAdapter, foirCookieName, } from './cookieAdapter';
|
|
15
15
|
export type { FoirCookieStore, CookieAdapterOptions } from './cookieAdapter';
|
|
16
|
-
export { getFoirSession, getFoirToken, foirSignOut, foirSignInWithPassword,
|
|
16
|
+
export { getFoirSession, getFoirToken, foirSignOut, foirSignInWithPassword, foirSignUpWithPassword, foirSignInWithOtp, startFoirProviderSignIn, finishFoirProviderSignIn, } from './session';
|
|
17
17
|
export { readFoirCacheTags, foirCacheTags, createFoirTaggingFetch, foirTagsForRecordEvent, revalidateFoirRecordEvent, FOIR_SURROGATE_KEY_HEADER, FOIR_NEXT_TAG_MAX_ITEMS, FOIR_NEXT_TAG_MAX_LENGTH, FOIR_UNTAGGED_TAG, } from './cacheTags';
|
|
18
18
|
export type { FoirHeaderSource, FoirCacheTags, FoirCacheTagsOptions, FoirTaggingReport, FoirTaggingFetchOptions, FoirRecordChange, } from './cacheTags';
|
|
19
19
|
export { createFoirMiddleware } from './middleware';
|
package/dist/next/session.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FoirUser } from '../auth';
|
|
1
|
+
import type { FoirSignInStep, FoirUser, ProviderSignInInput } from '../auth';
|
|
2
2
|
import type { FoirEnv } from '../graphql/foir-request';
|
|
3
3
|
import type { CookieAdapterOptions, FoirCookieStore } from './cookieAdapter';
|
|
4
4
|
/**
|
|
@@ -28,25 +28,41 @@ interface PasswordArgs {
|
|
|
28
28
|
/** Password sign-in in a route handler; persists the session to cookies. */
|
|
29
29
|
export declare function foirSignInWithPassword({ env, store, email, password, cookieOptions, }: PasswordArgs): Promise<FoirUser>;
|
|
30
30
|
/**
|
|
31
|
-
* Start a sign-up in a route handler: the address is mailed a code
|
|
32
|
-
*
|
|
31
|
+
* Start a sign-up in a route handler: the address is mailed a code. Keep the
|
|
32
|
+
* step this answers (in the form, or a cookie) for {@link foirSignInWithOtp},
|
|
33
|
+
* which brings the code back to it, finishes the account and persists the
|
|
33
34
|
* session to cookies.
|
|
34
35
|
*/
|
|
35
|
-
export declare function
|
|
36
|
-
/**
|
|
37
|
-
|
|
36
|
+
export declare function foirSignUpWithPassword({ env, email, password, }: Pick<PasswordArgs, 'env' | 'email' | 'password'>): Promise<FoirSignInStep>;
|
|
37
|
+
/**
|
|
38
|
+
* Complete a code sign-in in a route handler: bring the code back to the step
|
|
39
|
+
* `requestOTP` or {@link foirSignUpWithPassword} answered. Persists the
|
|
40
|
+
* session to cookies.
|
|
41
|
+
*/
|
|
42
|
+
export declare function foirSignInWithOtp({ env, store, step, otp, cookieOptions, }: {
|
|
38
43
|
env: FoirEnv;
|
|
39
44
|
store: FoirCookieStore;
|
|
40
|
-
|
|
45
|
+
step: FoirSignInStep;
|
|
41
46
|
otp: string;
|
|
42
47
|
cookieOptions?: CookieAdapterOptions['cookieOptions'];
|
|
43
48
|
}): Promise<FoirUser>;
|
|
44
49
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* cookies
|
|
50
|
+
* Start a provider (OAuth/OIDC) sign-in in a route handler: answers where to
|
|
51
|
+
* send the browser, and keeps the step its finish is brought back to in the
|
|
52
|
+
* session cookies for {@link finishFoirProviderSignIn}.
|
|
53
|
+
*/
|
|
54
|
+
export declare function startFoirProviderSignIn(opts: {
|
|
55
|
+
env: FoirEnv;
|
|
56
|
+
store: FoirCookieStore;
|
|
57
|
+
input: ProviderSignInInput;
|
|
58
|
+
cookieOptions?: CookieAdapterOptions['cookieOptions'];
|
|
59
|
+
}): Promise<string | null>;
|
|
60
|
+
/**
|
|
61
|
+
* Finish a provider (OAuth/OIDC) sign-in in your callback route handler:
|
|
62
|
+
* bring the `code` + `state` back to the step {@link startFoirProviderSignIn}
|
|
63
|
+
* kept, and persist the session to cookies. Returns the user.
|
|
48
64
|
*/
|
|
49
|
-
export declare function
|
|
65
|
+
export declare function finishFoirProviderSignIn(opts: {
|
|
50
66
|
env: FoirEnv;
|
|
51
67
|
store: FoirCookieStore;
|
|
52
68
|
providerKey: string;
|
package/dist/next.js
CHANGED
|
@@ -949,7 +949,7 @@ async function fetchFoirManifest(config, options = {}) {
|
|
|
949
949
|
|
|
950
950
|
// src/auth/ops.ts
|
|
951
951
|
var AUTH_OPS = {
|
|
952
|
-
// Pre-credential reads a
|
|
952
|
+
// Pre-credential reads a sign-in screen renders itself from.
|
|
953
953
|
authConfig: "authConfig",
|
|
954
954
|
authProviders: "authProviders",
|
|
955
955
|
defaultAuthProvider: "defaultAuthProvider",
|
|
@@ -961,17 +961,15 @@ var AUTH_OPS = {
|
|
|
961
961
|
// they hold. `./access` reads it.
|
|
962
962
|
whoami: "whoami",
|
|
963
963
|
// Methods.
|
|
964
|
-
|
|
964
|
+
signIn: "signIn",
|
|
965
965
|
register: "register",
|
|
966
966
|
requestOTP: "requestOTP",
|
|
967
|
-
loginWithOTP: "loginWithOTP",
|
|
968
967
|
// Session lifecycle.
|
|
969
968
|
refreshToken: "refreshToken",
|
|
970
|
-
|
|
969
|
+
signOut: "signOut",
|
|
971
970
|
joinWaitlist: "joinWaitlist",
|
|
972
971
|
// Password management and account lifecycle.
|
|
973
972
|
requestPasswordReset: "requestPasswordReset",
|
|
974
|
-
resetPassword: "resetPassword",
|
|
975
973
|
updatePassword: "updatePassword",
|
|
976
974
|
deleteMyAccount: "deleteMyAccount",
|
|
977
975
|
// Ending their own membership where the request stands.
|
|
@@ -985,10 +983,10 @@ var AUTH_OPS = {
|
|
|
985
983
|
mySessions: "mySessions",
|
|
986
984
|
endMySession: "endMySession",
|
|
987
985
|
signOutEverywhere: "signOutEverywhere",
|
|
988
|
-
// Their email addresses: one added is kept once the code it was sent
|
|
986
|
+
// Their email addresses: one added is kept once the code it was sent comes
|
|
987
|
+
// back on the step addMyAddress answers, on its own route (proveMyAddress).
|
|
989
988
|
myAddresses: "myAddresses",
|
|
990
989
|
addMyAddress: "addMyAddress",
|
|
991
|
-
proveMyAddress: "proveMyAddress",
|
|
992
990
|
makeMyAddressPrimary: "makeMyAddressPrimary",
|
|
993
991
|
removeMyAddress: "removeMyAddress",
|
|
994
992
|
// A copy of their own data.
|
|
@@ -999,10 +997,8 @@ var AUTH_OPS = {
|
|
|
999
997
|
disconnectSignInMethod: "disconnectSignInMethod",
|
|
1000
998
|
// Their second factors. A change needs one proven first, by a step-up.
|
|
1001
999
|
myFactors: "myFactors",
|
|
1002
|
-
|
|
1003
|
-
completeStepUp: "completeStepUp",
|
|
1000
|
+
stepUp: "stepUp",
|
|
1004
1001
|
beginFactorEnrollment: "beginFactorEnrollment",
|
|
1005
|
-
completeFactorEnrollment: "completeFactorEnrollment",
|
|
1006
1002
|
removeFactor: "removeFactor",
|
|
1007
1003
|
renameFactor: "renameFactor",
|
|
1008
1004
|
makeRecoveryCodes: "makeRecoveryCodes",
|
|
@@ -1016,13 +1012,7 @@ var AUTH_OPS = {
|
|
|
1016
1012
|
// Founding one. Present in a manifest only when the project opted in.
|
|
1017
1013
|
registerOrganization: "registerOrganization",
|
|
1018
1014
|
// External identity providers.
|
|
1019
|
-
|
|
1020
|
-
providerCallback: "providerCallback",
|
|
1021
|
-
providerVerifyOTP: "providerVerifyOTP",
|
|
1022
|
-
// A provider sign-in that names an address somebody already holds, waiting
|
|
1023
|
-
// for the code sent to it.
|
|
1024
|
-
confirmProviderLink: "confirmProviderLink",
|
|
1025
|
-
resendProviderLinkCode: "resendProviderLinkCode"
|
|
1015
|
+
signInWithProvider: "signInWithProvider"
|
|
1026
1016
|
};
|
|
1027
1017
|
function authClientConfig(env, options) {
|
|
1028
1018
|
const apiKey = resolveFoirApiKey(env);
|
|
@@ -1082,22 +1072,88 @@ function stripUndefined(args) {
|
|
|
1082
1072
|
return out;
|
|
1083
1073
|
}
|
|
1084
1074
|
|
|
1075
|
+
// src/auth/steps.ts
|
|
1076
|
+
async function postSignInStep(env, path, body, stepToken) {
|
|
1077
|
+
const apiUrl = env.PLATFORM_API_URL;
|
|
1078
|
+
if (!apiUrl) {
|
|
1079
|
+
throw new FoirRequestError("[foir] no api url configured: set PLATFORM_API_URL");
|
|
1080
|
+
}
|
|
1081
|
+
const headers = { "Content-Type": "application/json" };
|
|
1082
|
+
if (stepToken) headers["X-Foir-Token"] = stepToken;
|
|
1083
|
+
const res = await fetch(foirApiEndpoint(apiUrl, path), {
|
|
1084
|
+
method: "POST",
|
|
1085
|
+
headers,
|
|
1086
|
+
body: JSON.stringify(body)
|
|
1087
|
+
});
|
|
1088
|
+
const data = await res.json().catch(() => ({}));
|
|
1089
|
+
if (!res.ok) {
|
|
1090
|
+
const message = typeof data.error === "string" ? data.error : `[foir] POST ${path} failed: HTTP ${res.status}`;
|
|
1091
|
+
const code = typeof data.code === "string" ? data.code : void 0;
|
|
1092
|
+
const extensions = {};
|
|
1093
|
+
if (code) extensions.code = code;
|
|
1094
|
+
if (data.signIn && typeof data.signIn === "object") extensions.signIn = data.signIn;
|
|
1095
|
+
if (data.providerSignIn && typeof data.providerSignIn === "object") extensions.providerSignIn = data.providerSignIn;
|
|
1096
|
+
throw new FoirRequestError(message, {
|
|
1097
|
+
status: res.status,
|
|
1098
|
+
graphQLErrors: Object.keys(extensions).length > 0 ? [{ message, extensions }] : void 0
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
return data;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1085
1104
|
// src/auth/auth.ts
|
|
1086
1105
|
var TOKEN_KEY = "foir:token";
|
|
1087
1106
|
var REFRESH_KEY = "foir:refreshToken";
|
|
1088
1107
|
var USER_ID_KEY = "foir:userId";
|
|
1089
1108
|
var EMAIL_KEY = "foir:email";
|
|
1090
|
-
async function
|
|
1091
|
-
|
|
1109
|
+
async function codeSignIn(env, vars) {
|
|
1110
|
+
const signedIn = await postSignInStep(env, `/v1/sign-ins/${encodeURIComponent(vars.step.id)}/code`, { code: vars.otp }, vars.step.token);
|
|
1111
|
+
return {
|
|
1112
|
+
token: signedIn.accessToken ?? "",
|
|
1113
|
+
refreshToken: signedIn.refreshToken ?? "",
|
|
1114
|
+
userId: signedIn.user?.id ?? "",
|
|
1115
|
+
email: signedIn.user?.email ?? ""
|
|
1116
|
+
};
|
|
1092
1117
|
}
|
|
1093
|
-
async function
|
|
1094
|
-
|
|
1118
|
+
async function signInWithProvider(adapter, env, input) {
|
|
1119
|
+
const started = await authOp(
|
|
1120
|
+
env,
|
|
1121
|
+
AUTH_OPS.signInWithProvider,
|
|
1122
|
+
{ input }
|
|
1123
|
+
);
|
|
1124
|
+
if (started.step) await adapter.set(PROVIDER_STEP_KEY, JSON.stringify(started.step));
|
|
1125
|
+
else await adapter.unset(PROVIDER_STEP_KEY);
|
|
1126
|
+
return { redirectUrl: started.redirectUrl ?? null };
|
|
1127
|
+
}
|
|
1128
|
+
async function finishProviderSignIn(adapter, env, input) {
|
|
1129
|
+
const step = await keptProviderStep(adapter, "no provider sign-in was started here: start one before finishing it");
|
|
1130
|
+
return signedInOnStep(adapter, env, step, "provider", {
|
|
1131
|
+
providerKey: input.providerKey,
|
|
1132
|
+
code: input.code,
|
|
1133
|
+
state: input.state
|
|
1134
|
+
});
|
|
1095
1135
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1136
|
+
var PROVIDER_STEP_KEY = "foir:providerStep";
|
|
1137
|
+
async function keptProviderStep(adapter, missing) {
|
|
1138
|
+
const raw = await adapter.get(PROVIDER_STEP_KEY);
|
|
1139
|
+
if (raw) {
|
|
1140
|
+
try {
|
|
1141
|
+
const step = JSON.parse(raw);
|
|
1142
|
+
if (typeof step.id === "string" && typeof step.token === "string") return step;
|
|
1143
|
+
} catch {
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
throw new Error(`[foir] ${missing}`);
|
|
1098
1147
|
}
|
|
1099
|
-
async function
|
|
1100
|
-
|
|
1148
|
+
async function signedInOnStep(adapter, env, step, route, body) {
|
|
1149
|
+
const signedIn = await postSignInStep(env, `/v1/sign-ins/${encodeURIComponent(step.id)}/${route}`, body, step.token);
|
|
1150
|
+
await adapter.unset(PROVIDER_STEP_KEY);
|
|
1151
|
+
return saveSession(adapter, {
|
|
1152
|
+
token: signedIn.accessToken ?? "",
|
|
1153
|
+
refreshToken: signedIn.refreshToken ?? "",
|
|
1154
|
+
userId: signedIn.userId ?? "",
|
|
1155
|
+
email: signedIn.email ?? ""
|
|
1156
|
+
});
|
|
1101
1157
|
}
|
|
1102
1158
|
async function saveSession(adapter, result) {
|
|
1103
1159
|
await adapter.set(TOKEN_KEY, result.token);
|
|
@@ -1125,13 +1181,13 @@ async function getSessionUser(adapter) {
|
|
|
1125
1181
|
return { id, email: email ?? "" };
|
|
1126
1182
|
}
|
|
1127
1183
|
async function signInWithPassword(adapter, env, vars) {
|
|
1128
|
-
return saveSession(adapter, await
|
|
1184
|
+
return saveSession(adapter, await authOp(env, AUTH_OPS.signIn, vars));
|
|
1129
1185
|
}
|
|
1130
1186
|
async function signUpWithPassword(env, vars) {
|
|
1131
|
-
|
|
1187
|
+
return authOp(env, AUTH_OPS.register, vars);
|
|
1132
1188
|
}
|
|
1133
1189
|
async function signInWithOTP(adapter, env, vars) {
|
|
1134
|
-
return saveSession(adapter, await
|
|
1190
|
+
return saveSession(adapter, await codeSignIn(env, vars));
|
|
1135
1191
|
}
|
|
1136
1192
|
|
|
1137
1193
|
// src/next/session.ts
|
|
@@ -1156,7 +1212,7 @@ function foirSignInWithPassword({
|
|
|
1156
1212
|
password
|
|
1157
1213
|
});
|
|
1158
1214
|
}
|
|
1159
|
-
function
|
|
1215
|
+
function foirSignUpWithPassword({
|
|
1160
1216
|
env,
|
|
1161
1217
|
email,
|
|
1162
1218
|
password
|
|
@@ -1166,25 +1222,26 @@ function foirRegisterWithPassword({
|
|
|
1166
1222
|
function foirSignInWithOtp({
|
|
1167
1223
|
env,
|
|
1168
1224
|
store,
|
|
1169
|
-
|
|
1225
|
+
step,
|
|
1170
1226
|
otp,
|
|
1171
1227
|
cookieOptions
|
|
1172
1228
|
}) {
|
|
1173
1229
|
return signInWithOTP(createFoirCookieAdapter(store, { cookieOptions }), env, {
|
|
1174
|
-
|
|
1230
|
+
step,
|
|
1175
1231
|
otp
|
|
1176
1232
|
});
|
|
1177
1233
|
}
|
|
1178
|
-
async function
|
|
1179
|
-
const
|
|
1234
|
+
async function startFoirProviderSignIn(opts) {
|
|
1235
|
+
const adapter = createFoirCookieAdapter(opts.store, { cookieOptions: opts.cookieOptions });
|
|
1236
|
+
return (await signInWithProvider(adapter, opts.env, opts.input)).redirectUrl;
|
|
1237
|
+
}
|
|
1238
|
+
async function finishFoirProviderSignIn(opts) {
|
|
1239
|
+
const adapter = createFoirCookieAdapter(opts.store, { cookieOptions: opts.cookieOptions });
|
|
1240
|
+
return finishProviderSignIn(adapter, opts.env, {
|
|
1180
1241
|
providerKey: opts.providerKey,
|
|
1181
1242
|
code: opts.code,
|
|
1182
1243
|
state: opts.state
|
|
1183
1244
|
});
|
|
1184
|
-
return saveSession(
|
|
1185
|
-
createFoirCookieAdapter(opts.store, { cookieOptions: opts.cookieOptions }),
|
|
1186
|
-
result
|
|
1187
|
-
);
|
|
1188
1245
|
}
|
|
1189
1246
|
|
|
1190
1247
|
// src/live/events.ts
|
|
@@ -1304,19 +1361,20 @@ export {
|
|
|
1304
1361
|
FOIR_NEXT_TAG_MAX_LENGTH,
|
|
1305
1362
|
FOIR_SURROGATE_KEY_HEADER,
|
|
1306
1363
|
FOIR_UNTAGGED_TAG,
|
|
1307
|
-
completeFoirProviderLogin,
|
|
1308
1364
|
createFoirCookieAdapter,
|
|
1309
1365
|
createFoirMiddleware,
|
|
1310
1366
|
createFoirTaggingFetch,
|
|
1367
|
+
finishFoirProviderSignIn,
|
|
1311
1368
|
foirCacheTags,
|
|
1312
1369
|
foirCookieName,
|
|
1313
|
-
foirRegisterWithPassword,
|
|
1314
1370
|
foirSignInWithOtp,
|
|
1315
1371
|
foirSignInWithPassword,
|
|
1316
1372
|
foirSignOut,
|
|
1373
|
+
foirSignUpWithPassword,
|
|
1317
1374
|
foirTagsForRecordEvent,
|
|
1318
1375
|
getFoirSession,
|
|
1319
1376
|
getFoirToken,
|
|
1320
1377
|
readFoirCacheTags,
|
|
1321
|
-
revalidateFoirRecordEvent
|
|
1378
|
+
revalidateFoirRecordEvent,
|
|
1379
|
+
startFoirProviderSignIn
|
|
1322
1380
|
};
|