@foir/sdk 0.25.0 → 0.27.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 -0
- package/dist/app/client.d.ts +82 -14
- package/dist/app/index.d.ts +1 -1
- package/dist/app/vocabulary.generated.d.ts +1 -1
- package/dist/app.js +24 -6
- package/dist/auth/auth.d.ts +10 -1
- package/dist/auth/hosted.d.ts +14 -3
- package/dist/auth/index.d.ts +3 -3
- package/dist/auth/operations.d.ts +32 -0
- package/dist/auth/ops.d.ts +1 -0
- package/dist/auth/session-client.d.ts +7 -2
- package/dist/auth-session.js +2 -1
- package/dist/auth.js +16 -3
- package/dist/data/builtins.d.ts +38 -13
- package/dist/data/index.d.ts +3 -3
- package/dist/data.js +11 -1
- package/dist/next.js +3 -0
- package/dist/placement/index.d.ts +17 -0
- package/dist/placement.js +16 -3
- package/dist/push.js +3 -0
- package/dist/react/FoirFeedback.d.ts +12 -5
- package/dist/react/FoirProvider.d.ts +5 -4
- package/dist/react/feedback-notes.d.ts +38 -4
- package/dist/react.js +116 -23
- package/dist/server/index.d.ts +1 -1
- package/dist/server.js +13 -1
- package/dist/transport/foir-http.d.ts +17 -1
- package/package.json +2 -2
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, 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';
|
|
62
|
+
export type { CollabInfo, FileValue, FoirAccessGrant, FoirAccessLevel, FoirAccessSource, FoirAccessor, FoirCreateMyNoteArgs, FoirWriteNoteArgs, FoirUserNote, FoirUserNoteAttachment, FoirDegraded, FoirDepthBelow, FoirDepthLevel, FoirDeviceType, FoirGranteeKind, FoirJsonValue, FoirMyAccess, FoirMyNotesArgs, FoirMyNotesResult, 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
|
|
@@ -81,5 +81,5 @@ export type { FoirConnection, FoirFieldsShape, FoirModelDefinition, FoirNamespac
|
|
|
81
81
|
export type { FoirInclude, FoirModelOperation, FoirNamespaceOperation, FoirOmittableKey, FoirOpResult, FoirQuery, FoirRecordResult, FoirWriteResult, } from './selection';
|
|
82
82
|
export { FoirDecimal, decimal } from './decimal';
|
|
83
83
|
export type { FoirDecimalDivOptions, FoirDecimalInput, FoirDecimalRounding, } from './decimal';
|
|
84
|
-
export { FoirRequestError, FoirAuthDowngradedError, FoirSessionExpiredError, FOIR_VISITOR_IP_HEADER, } from '../transport/foir-http';
|
|
85
|
-
export type { FoirEnv, FoirGraphQLErrorItem, FoirTokenProvider, FoirAuthDowngrade, FoirVisitor, FoirVisitorSource, } from '../transport/foir-http';
|
|
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';
|
package/dist/data.js
CHANGED
|
@@ -10,6 +10,15 @@ var MALFORMED_PRUNE_REASONS = /* @__PURE__ */ new Set([
|
|
|
10
10
|
"subselections_on_scalar",
|
|
11
11
|
"missing_subselections"
|
|
12
12
|
]);
|
|
13
|
+
function stepUpRequired(error) {
|
|
14
|
+
if (!(error instanceof FoirRequestError)) return null;
|
|
15
|
+
for (const item of error.graphQLErrors ?? []) {
|
|
16
|
+
if (item.extensions?.code !== "STEP_UP_REQUIRED") continue;
|
|
17
|
+
const asked = item.extensions.stepUp;
|
|
18
|
+
if (asked === "second_factor" || asked === "sign_in_method") return asked;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
13
22
|
var FoirRequestError = class extends Error {
|
|
14
23
|
/** HTTP status code, when the request failed at the HTTP layer. */
|
|
15
24
|
status;
|
|
@@ -2686,5 +2695,6 @@ export {
|
|
|
2686
2695
|
planFoirModelCall,
|
|
2687
2696
|
planFoirNamespaceCall,
|
|
2688
2697
|
printSubscriptionDocument,
|
|
2689
|
-
recordFoirSubjects
|
|
2698
|
+
recordFoirSubjects,
|
|
2699
|
+
stepUpRequired
|
|
2690
2700
|
};
|
package/dist/next.js
CHANGED
|
@@ -1010,6 +1010,9 @@ var AUTH_OPS = {
|
|
|
1010
1010
|
// names the organization it acts in (`orgId` or `orgUrl` below), and the
|
|
1011
1011
|
// platform checks the caller stands there every time.
|
|
1012
1012
|
myOrganizations: "myOrganizations",
|
|
1013
|
+
// Where they may go: the organizations they are a member of, are invited
|
|
1014
|
+
// to, may join, or asked to join. An organization switcher's choices.
|
|
1015
|
+
myOrganizationChoices: "myOrganizationChoices",
|
|
1013
1016
|
// Founding one. Present in a manifest only when the project opted in.
|
|
1014
1017
|
registerOrganization: "registerOrganization",
|
|
1015
1018
|
// External identity providers.
|
|
@@ -113,6 +113,23 @@ export declare function placementFrameAncestors(origins: readonly string[]): str
|
|
|
113
113
|
export declare class PlacementRefused extends Error {
|
|
114
114
|
constructor(reason: string);
|
|
115
115
|
}
|
|
116
|
+
/** One error of a GraphQL answer, as Foir's API sends it. */
|
|
117
|
+
export interface PlacementRequestError {
|
|
118
|
+
message: string;
|
|
119
|
+
path?: (string | number)[];
|
|
120
|
+
extensions?: Record<string, unknown>;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* A request the page made on its token that Foir's API refused or failed.
|
|
124
|
+
* The message says each distinct refusal once: a read refused on a field is
|
|
125
|
+
* answered once per row, and one missing grant over five hundred rows would
|
|
126
|
+
* otherwise read five hundred times. `errors` keeps every one, with its path.
|
|
127
|
+
*/
|
|
128
|
+
export declare class PlacementRequestFailed extends Error {
|
|
129
|
+
readonly errors: PlacementRequestError[];
|
|
130
|
+
readonly status: number;
|
|
131
|
+
constructor(errors: PlacementRequestError[], status: number);
|
|
132
|
+
}
|
|
116
133
|
export interface ConnectPlacementOptions {
|
|
117
134
|
/** Foir's API, e.g. `https://api.foir.dev`. */
|
|
118
135
|
apiUrl: string;
|
package/dist/placement.js
CHANGED
|
@@ -41,6 +41,8 @@ var GRANT_TABLE = [
|
|
|
41
41
|
["authclients:write", "none", [], []],
|
|
42
42
|
["domains:read", "none", [], []],
|
|
43
43
|
["domains:write", "none", [], []],
|
|
44
|
+
["loginpages:read", "none", [], []],
|
|
45
|
+
["loginpages:write", "none", [], []],
|
|
44
46
|
["secrets:read", "none", [], []],
|
|
45
47
|
["secrets:list", "none", [], []],
|
|
46
48
|
["secrets:put", "none", [], []],
|
|
@@ -78,7 +80,7 @@ var GRANT_TABLE = [
|
|
|
78
80
|
["projects:read", "none", [], []],
|
|
79
81
|
["projects:write", "none", [], []],
|
|
80
82
|
["project:stand", "none", [], []],
|
|
81
|
-
["project:manage", "none", [], ["project:stand", "records:read.all", "records:create", "records:write.all", "records:delete.all", "records:publish.all", "records:attribute", "search:read", "embeddings:read", "embeddings:write", "schemas:read", "drafts:read", "files:read.all", "files:write.all", "files:delete.all", "users:read.all", "identities:read", "users:create", "identities:delete", "users:write.all", "users:setup", "users:delete.all", "notifications:read.all", "notifications:write.all", "notifications:consent", "pushcredentials:read", "pushcredentials:write", "notes:read.all", "notes:write.all", "notes:create", "approvals:read", "approvals:write", "rooms:read", "rooms:write", "presence:read", "operations:read", "operations:execute", "operations:write", "appconfig:read", "schedules:read", "schedules:write", "hooks:read", "hooks:write", "auth:login_with_foir", "authclients:read", "authclients:write", "domains:read", "domains:write", "secrets:read", "secrets:list", "secrets:put", "secrets:delete", "appsecrets:read", "appsecrets:list", "appsecrets:put", "appsecrets:delete", "usersecrets:read", "usersecrets:list", "usersecrets:put", "usersecrets:delete", "opsecrets:read", "opsecrets:write", "settings:read", "settings:write", "designtokens:read", "designtokens:write", "models:read", "models:write", "configs:read", "configs:write", "signinproviders:read", "signinproviders:write", "apps:read", "apps:write", "events:read", "targeting:debug", "visitors:forward", "apikeys:read", "apikeys:write", "organizations:read", "organizations:create", "organizations:delete", "organizations:write", "organizations:reach", "members:read", "members:write", "roles:read", "roles:write", "projects:read", "projects:write", "audit:read"]],
|
|
83
|
+
["project:manage", "none", [], ["project:stand", "records:read.all", "records:create", "records:write.all", "records:delete.all", "records:publish.all", "records:attribute", "search:read", "embeddings:read", "embeddings:write", "schemas:read", "drafts:read", "files:read.all", "files:write.all", "files:delete.all", "users:read.all", "identities:read", "users:create", "identities:delete", "users:write.all", "users:setup", "users:delete.all", "notifications:read.all", "notifications:write.all", "notifications:consent", "pushcredentials:read", "pushcredentials:write", "notes:read.all", "notes:write.all", "notes:create", "approvals:read", "approvals:write", "rooms:read", "rooms:write", "presence:read", "operations:read", "operations:execute", "operations:write", "appconfig:read", "schedules:read", "schedules:write", "hooks:read", "hooks:write", "auth:login_with_foir", "authclients:read", "authclients:write", "domains:read", "domains:write", "loginpages:read", "loginpages:write", "secrets:read", "secrets:list", "secrets:put", "secrets:delete", "appsecrets:read", "appsecrets:list", "appsecrets:put", "appsecrets:delete", "usersecrets:read", "usersecrets:list", "usersecrets:put", "usersecrets:delete", "opsecrets:read", "opsecrets:write", "settings:read", "settings:write", "designtokens:read", "designtokens:write", "models:read", "models:write", "configs:read", "configs:write", "signinproviders:read", "signinproviders:write", "apps:read", "apps:write", "events:read", "targeting:debug", "visitors:forward", "apikeys:read", "apikeys:write", "organizations:read", "organizations:create", "organizations:delete", "organizations:write", "organizations:reach", "members:read", "members:write", "roles:read", "roles:write", "projects:read", "projects:write", "audit:read"]],
|
|
82
84
|
["projects:create", "none", [], []],
|
|
83
85
|
["projects:delete", "none", [], []],
|
|
84
86
|
["tenants:read", "none", [], []],
|
|
@@ -266,6 +268,17 @@ var PlacementRefused = class extends Error {
|
|
|
266
268
|
this.name = "PlacementRefused";
|
|
267
269
|
}
|
|
268
270
|
};
|
|
271
|
+
var PlacementRequestFailed = class extends Error {
|
|
272
|
+
errors;
|
|
273
|
+
status;
|
|
274
|
+
constructor(errors, status) {
|
|
275
|
+
const said = [...new Set(errors.map((e) => e.message))];
|
|
276
|
+
super(`[foir] placement request failed: ${said.length > 0 ? said.join("; ") : `HTTP ${status}`}`);
|
|
277
|
+
this.name = "PlacementRequestFailed";
|
|
278
|
+
this.errors = errors;
|
|
279
|
+
this.status = status;
|
|
280
|
+
}
|
|
281
|
+
};
|
|
269
282
|
function isHostMessage(data) {
|
|
270
283
|
if (typeof data !== "object" || data === null) return false;
|
|
271
284
|
const t = data.type;
|
|
@@ -325,8 +338,7 @@ function connectPlacement(options) {
|
|
|
325
338
|
});
|
|
326
339
|
const body = await res.json().catch(() => ({}));
|
|
327
340
|
if (!res.ok || body.errors && body.errors.length > 0) {
|
|
328
|
-
|
|
329
|
-
throw new Error(`[foir] placement request failed: ${messages}`);
|
|
341
|
+
throw new PlacementRequestFailed(body.errors ?? [], res.status);
|
|
330
342
|
}
|
|
331
343
|
return body.data;
|
|
332
344
|
},
|
|
@@ -381,6 +393,7 @@ export {
|
|
|
381
393
|
FOIR_CONSOLE_ORIGINS,
|
|
382
394
|
PLACEMENT_MESSAGE,
|
|
383
395
|
PlacementRefused,
|
|
396
|
+
PlacementRequestFailed,
|
|
384
397
|
connectPlacement,
|
|
385
398
|
placementFrameAncestors
|
|
386
399
|
};
|
package/dist/push.js
CHANGED
|
@@ -1130,6 +1130,9 @@ var AUTH_OPS = {
|
|
|
1130
1130
|
// names the organization it acts in (`orgId` or `orgUrl` below), and the
|
|
1131
1131
|
// platform checks the caller stands there every time.
|
|
1132
1132
|
myOrganizations: "myOrganizations",
|
|
1133
|
+
// Where they may go: the organizations they are a member of, are invited
|
|
1134
|
+
// to, may join, or asked to join. An organization switcher's choices.
|
|
1135
|
+
myOrganizationChoices: "myOrganizationChoices",
|
|
1133
1136
|
// Founding one. Present in a manifest only when the project opted in.
|
|
1134
1137
|
registerOrganization: "registerOrganization",
|
|
1135
1138
|
// External identity providers.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FoirUserNote, FoirSubject, FoirSubjectRegistry } from '../data';
|
|
1
|
+
import type { FoirNoteReceipt, FoirUserNote, FoirSubject, FoirSubjectRegistry } from '../data';
|
|
2
2
|
import { type FoirFeedbackClient } from './feedback-notes';
|
|
3
3
|
export type { FoirFeedbackClient } from './feedback-notes';
|
|
4
4
|
export interface FoirFeedbackProps {
|
|
@@ -41,12 +41,19 @@ export interface FoirFeedbackProps {
|
|
|
41
41
|
/** Start with the panel open. Default false. */
|
|
42
42
|
defaultOpen?: boolean;
|
|
43
43
|
/**
|
|
44
|
-
* Called when the visitor has to sign in first
|
|
45
|
-
*
|
|
44
|
+
* Called when the visitor has to sign in first: the project takes no notes
|
|
45
|
+
* from visitors who are not signed in. Given a handler, the widget renders a
|
|
46
|
+
* button that calls it; given none, it says so and stops.
|
|
46
47
|
*/
|
|
47
48
|
onSignIn?: () => void;
|
|
48
|
-
/** Called with
|
|
49
|
+
/** Called with a signed-in user's note once it is written. */
|
|
49
50
|
onSubmitted?: (note: FoirUserNote) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Called with the receipt once a visitor who is not signed in has sent a
|
|
53
|
+
* note: its id and when it was written, which is all a visitor's note
|
|
54
|
+
* answers with.
|
|
55
|
+
*/
|
|
56
|
+
onVisitorSubmitted?: (receipt: FoirNoteReceipt) => void;
|
|
50
57
|
/**
|
|
51
58
|
* Called with anything that failed. The widget also logs it — this is for
|
|
52
59
|
* routing it into your own error reporting, not for making it visible.
|
|
@@ -59,4 +66,4 @@ export interface FoirFeedbackProps {
|
|
|
59
66
|
*/
|
|
60
67
|
className?: string;
|
|
61
68
|
}
|
|
62
|
-
export declare function FoirFeedback({ client, subjects, subject, label, triggerLabel, title, placeholder, defaultOpen, onSignIn, onSubmitted, onError, className, }: FoirFeedbackProps): import("react/jsx-runtime").JSX.Element;
|
|
69
|
+
export declare function FoirFeedback({ client, subjects, subject, label, triggerLabel, title, placeholder, defaultOpen, onSignIn, onSubmitted, onVisitorSubmitted, onError, className, }: FoirFeedbackProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
import type { AuthProviderPublic, FoirAccess, FoirUser, FoirSessionConfig, SessionAdapter } from '../auth';
|
|
2
|
+
import type { AuthProviderPublic, FoirAccess, FoirUser, FoirSessionConfig, HostedLoginOptions, SessionAdapter } from '../auth';
|
|
3
3
|
import type { ProviderCallbackInput, ProviderLoginInput } from '../auth';
|
|
4
4
|
import type { FoirEnv } from '../graphql/foir-request';
|
|
5
5
|
/** Where the session hydration stands. */
|
|
@@ -53,9 +53,10 @@ export interface FoirContextValue {
|
|
|
53
53
|
/**
|
|
54
54
|
* In `hostedSession` mode, where to send the browser to sign in — sign-in is a
|
|
55
55
|
* redirect to your Foir login domain, not an in-page form. Null in token mode,
|
|
56
|
-
* where you call {@link FoirContextValue.signIn} instead.
|
|
56
|
+
* where you call {@link FoirContextValue.signIn} instead. `options.org` names
|
|
57
|
+
* the organization the sign-in is for.
|
|
57
58
|
*/
|
|
58
|
-
hostedSignInUrl: ((returnTo?: string) => string) | null;
|
|
59
|
+
hostedSignInUrl: ((returnTo?: string, options?: HostedLoginOptions) => string) | null;
|
|
59
60
|
}
|
|
60
61
|
export interface FoirProviderProps {
|
|
61
62
|
/** API config: `{ PLATFORM_API_URL, PLATFORM_API_KEY }` (a publishable key). */
|
|
@@ -151,5 +152,5 @@ export declare function useFoirAuth(): {
|
|
|
151
152
|
refresh: () => Promise<boolean>;
|
|
152
153
|
getToken: () => Promise<string | null>;
|
|
153
154
|
getProviders: () => Promise<AuthProviderPublic[]>;
|
|
154
|
-
hostedSignInUrl: ((returnTo?: string) => string) | null;
|
|
155
|
+
hostedSignInUrl: ((returnTo?: string, options?: HostedLoginOptions) => string) | null;
|
|
155
156
|
};
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* shape (see `data/selection.ts`) — so every response here has to be read rather
|
|
8
8
|
* than cast, and reading is the part worth testing on its own.
|
|
9
9
|
*/
|
|
10
|
-
import type { FoirUserNote, FoirNoteConfig, FoirSubject } from '../data';
|
|
10
|
+
import type { FoirUserNote, FoirNoteConfig, FoirNoteReceipt, FoirSubject } from '../data';
|
|
11
11
|
import type { FoirScreenCapture } from '../media/screen-capture';
|
|
12
12
|
/**
|
|
13
13
|
* The client the widget needs, and no more of it.
|
|
@@ -15,9 +15,9 @@ import type { FoirScreenCapture } from '../media/screen-capture';
|
|
|
15
15
|
* Structural rather than `FoirClient<S>`, for two reasons. `FoirClient` is
|
|
16
16
|
* generic in the caller's generated schema, so naming it here would force the
|
|
17
17
|
* component's props to be generic in a parameter nothing else reads. And what
|
|
18
|
-
* the widget actually depends on is
|
|
19
|
-
* a client whose key cannot reach `files` still satisfies this type, which
|
|
20
|
-
* the honest shape: a project with screenshots off never uploads anything.
|
|
18
|
+
* the widget actually depends on is a handful of root fields — narrowing to them
|
|
19
|
+
* means a client whose key cannot reach `files` still satisfies this type, which
|
|
20
|
+
* is the honest shape: a project with screenshots off never uploads anything.
|
|
21
21
|
*
|
|
22
22
|
* The signatures are the ones `foir types` emits for every namespace op —
|
|
23
23
|
* `Record<string, unknown>` in, `unknown` out — so a real generated client
|
|
@@ -27,6 +27,14 @@ export interface FoirFeedbackClient {
|
|
|
27
27
|
readonly ns: {
|
|
28
28
|
readonly notes: {
|
|
29
29
|
noteConfig(args?: Record<string, unknown>): Promise<unknown>;
|
|
30
|
+
/**
|
|
31
|
+
* The one note create, for a signed-in user and a visitor alike. Optional
|
|
32
|
+
* so a client typed before it still satisfies this; without it a
|
|
33
|
+
* signed-in user's note goes through `createMyNote`, and a visitor's
|
|
34
|
+
* cannot be sent.
|
|
35
|
+
*/
|
|
36
|
+
writeNote?(args?: Record<string, unknown>): Promise<unknown>;
|
|
37
|
+
/** The older name of `writeNote` for a signed-in user. */
|
|
30
38
|
createMyNote(args?: Record<string, unknown>): Promise<unknown>;
|
|
31
39
|
};
|
|
32
40
|
/**
|
|
@@ -77,6 +85,12 @@ export declare function classifyNotesFault(err: unknown): FoirFeedbackFault;
|
|
|
77
85
|
* `screenshotsEnabled` to false. Defaulting would be the quiet version of a
|
|
78
86
|
* project's setting being ignored: the offer would disappear from every surface
|
|
79
87
|
* at once and the only symptom would be a missing button.
|
|
88
|
+
*
|
|
89
|
+
* `signedIn` and `anonymousAccepted` are read as the older contract when they
|
|
90
|
+
* are absent, which is not a guess: a data API without them answers only a
|
|
91
|
+
* signed-in user, and refuses everyone else. A generated module that predates
|
|
92
|
+
* them selects neither from a data API that has both, and the client's drift
|
|
93
|
+
* check names that module as the thing to regenerate.
|
|
80
94
|
*/
|
|
81
95
|
export declare function readNoteConfig(client: FoirFeedbackClient): Promise<FoirNoteConfig>;
|
|
82
96
|
/** What one submission carries. */
|
|
@@ -101,3 +115,23 @@ export interface FoirFeedbackSubmission {
|
|
|
101
115
|
* they wrote ("as you can see in the screenshot") stops making sense.
|
|
102
116
|
*/
|
|
103
117
|
export declare function submitFeedbackNote(client: FoirFeedbackClient, submission: FoirFeedbackSubmission): Promise<FoirUserNote>;
|
|
118
|
+
/** What a visitor's submission carries. */
|
|
119
|
+
export interface FoirVisitorSubmission {
|
|
120
|
+
/** What the note is about, as for a signed-in user's. */
|
|
121
|
+
subject: FoirSubject;
|
|
122
|
+
body: string;
|
|
123
|
+
/**
|
|
124
|
+
* Where the project's team may reply, as the visitor typed it. Sent only
|
|
125
|
+
* when it is not blank, and never verified by anyone.
|
|
126
|
+
*/
|
|
127
|
+
contactEmail?: string;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Write a visitor's note, and hand back its receipt.
|
|
131
|
+
*
|
|
132
|
+
* It asks for the note's `id` and `createdAt` and nothing else, because that is
|
|
133
|
+
* all a visitor's note answers with: asked for more, the data API refuses the
|
|
134
|
+
* write before anything is written. And it takes no attachment, which a
|
|
135
|
+
* visitor's note cannot carry.
|
|
136
|
+
*/
|
|
137
|
+
export declare function submitVisitorNote(client: FoirFeedbackClient, submission: FoirVisitorSubmission): Promise<FoirNoteReceipt>;
|
package/dist/react.js
CHANGED
|
@@ -1004,6 +1004,9 @@ var AUTH_OPS = {
|
|
|
1004
1004
|
// names the organization it acts in (`orgId` or `orgUrl` below), and the
|
|
1005
1005
|
// platform checks the caller stands there every time.
|
|
1006
1006
|
myOrganizations: "myOrganizations",
|
|
1007
|
+
// Where they may go: the organizations they are a member of, are invited
|
|
1008
|
+
// to, may join, or asked to join. An organization switcher's choices.
|
|
1009
|
+
myOrganizationChoices: "myOrganizationChoices",
|
|
1007
1010
|
// Founding one. Present in a manifest only when the project opted in.
|
|
1008
1011
|
registerOrganization: "registerOrganization",
|
|
1009
1012
|
// External identity providers.
|
|
@@ -1248,6 +1251,8 @@ var GRANT_TABLE = [
|
|
|
1248
1251
|
["authclients:write", "none", [], []],
|
|
1249
1252
|
["domains:read", "none", [], []],
|
|
1250
1253
|
["domains:write", "none", [], []],
|
|
1254
|
+
["loginpages:read", "none", [], []],
|
|
1255
|
+
["loginpages:write", "none", [], []],
|
|
1251
1256
|
["secrets:read", "none", [], []],
|
|
1252
1257
|
["secrets:list", "none", [], []],
|
|
1253
1258
|
["secrets:put", "none", [], []],
|
|
@@ -1285,7 +1290,7 @@ var GRANT_TABLE = [
|
|
|
1285
1290
|
["projects:read", "none", [], []],
|
|
1286
1291
|
["projects:write", "none", [], []],
|
|
1287
1292
|
["project:stand", "none", [], []],
|
|
1288
|
-
["project:manage", "none", [], ["project:stand", "records:read.all", "records:create", "records:write.all", "records:delete.all", "records:publish.all", "records:attribute", "search:read", "embeddings:read", "embeddings:write", "schemas:read", "drafts:read", "files:read.all", "files:write.all", "files:delete.all", "users:read.all", "identities:read", "users:create", "identities:delete", "users:write.all", "users:setup", "users:delete.all", "notifications:read.all", "notifications:write.all", "notifications:consent", "pushcredentials:read", "pushcredentials:write", "notes:read.all", "notes:write.all", "notes:create", "approvals:read", "approvals:write", "rooms:read", "rooms:write", "presence:read", "operations:read", "operations:execute", "operations:write", "appconfig:read", "schedules:read", "schedules:write", "hooks:read", "hooks:write", "auth:login_with_foir", "authclients:read", "authclients:write", "domains:read", "domains:write", "secrets:read", "secrets:list", "secrets:put", "secrets:delete", "appsecrets:read", "appsecrets:list", "appsecrets:put", "appsecrets:delete", "usersecrets:read", "usersecrets:list", "usersecrets:put", "usersecrets:delete", "opsecrets:read", "opsecrets:write", "settings:read", "settings:write", "designtokens:read", "designtokens:write", "models:read", "models:write", "configs:read", "configs:write", "signinproviders:read", "signinproviders:write", "apps:read", "apps:write", "events:read", "targeting:debug", "visitors:forward", "apikeys:read", "apikeys:write", "organizations:read", "organizations:create", "organizations:delete", "organizations:write", "organizations:reach", "members:read", "members:write", "roles:read", "roles:write", "projects:read", "projects:write", "audit:read"]],
|
|
1293
|
+
["project:manage", "none", [], ["project:stand", "records:read.all", "records:create", "records:write.all", "records:delete.all", "records:publish.all", "records:attribute", "search:read", "embeddings:read", "embeddings:write", "schemas:read", "drafts:read", "files:read.all", "files:write.all", "files:delete.all", "users:read.all", "identities:read", "users:create", "identities:delete", "users:write.all", "users:setup", "users:delete.all", "notifications:read.all", "notifications:write.all", "notifications:consent", "pushcredentials:read", "pushcredentials:write", "notes:read.all", "notes:write.all", "notes:create", "approvals:read", "approvals:write", "rooms:read", "rooms:write", "presence:read", "operations:read", "operations:execute", "operations:write", "appconfig:read", "schedules:read", "schedules:write", "hooks:read", "hooks:write", "auth:login_with_foir", "authclients:read", "authclients:write", "domains:read", "domains:write", "loginpages:read", "loginpages:write", "secrets:read", "secrets:list", "secrets:put", "secrets:delete", "appsecrets:read", "appsecrets:list", "appsecrets:put", "appsecrets:delete", "usersecrets:read", "usersecrets:list", "usersecrets:put", "usersecrets:delete", "opsecrets:read", "opsecrets:write", "settings:read", "settings:write", "designtokens:read", "designtokens:write", "models:read", "models:write", "configs:read", "configs:write", "signinproviders:read", "signinproviders:write", "apps:read", "apps:write", "events:read", "targeting:debug", "visitors:forward", "apikeys:read", "apikeys:write", "organizations:read", "organizations:create", "organizations:delete", "organizations:write", "organizations:reach", "members:read", "members:write", "roles:read", "roles:write", "projects:read", "projects:write", "audit:read"]],
|
|
1289
1294
|
["projects:create", "none", [], []],
|
|
1290
1295
|
["projects:delete", "none", [], []],
|
|
1291
1296
|
["tenants:read", "none", [], []],
|
|
@@ -1549,10 +1554,11 @@ function createFoirSessionClient(config) {
|
|
|
1549
1554
|
forget();
|
|
1550
1555
|
config.onSignOut?.();
|
|
1551
1556
|
},
|
|
1552
|
-
signInUrl(returnTo) {
|
|
1557
|
+
signInUrl(returnTo, options = {}) {
|
|
1553
1558
|
const dest = new URL(trimSlash(config.loginOrigin));
|
|
1554
1559
|
const target = returnTo ?? (typeof window !== "undefined" ? window.location.href : void 0);
|
|
1555
1560
|
if (target && target !== "/") dest.searchParams.set("returnTo", target);
|
|
1561
|
+
if (options.org) dest.searchParams.set("org", options.org);
|
|
1556
1562
|
return dest.toString();
|
|
1557
1563
|
},
|
|
1558
1564
|
subscribe(listener) {
|
|
@@ -1779,7 +1785,7 @@ function FoirProvider({
|
|
|
1779
1785
|
}, [refresh, loadAccess, accessWasRead]);
|
|
1780
1786
|
const getProviders = useCallback(() => getAuthProviders(envRef.current), []);
|
|
1781
1787
|
const hostedSignInUrl = useMemo(
|
|
1782
|
-
() => hosted ? (returnTo) => hosted.signInUrl(returnTo) : null,
|
|
1788
|
+
() => hosted ? (returnTo, options) => hosted.signInUrl(returnTo, options) : null,
|
|
1783
1789
|
[hosted]
|
|
1784
1790
|
);
|
|
1785
1791
|
const value = useMemo(
|
|
@@ -2243,7 +2249,14 @@ async function readNoteConfig(client) {
|
|
|
2243
2249
|
"[foir] noteConfig answered without a boolean `screenshotsEnabled`. The widget reads it to decide whether to offer screenshot capture, and will not guess."
|
|
2244
2250
|
);
|
|
2245
2251
|
}
|
|
2246
|
-
|
|
2252
|
+
const signedIn = result?.signedIn ?? true;
|
|
2253
|
+
const anonymousAccepted = result?.anonymousAccepted ?? false;
|
|
2254
|
+
if (typeof signedIn !== "boolean" || typeof anonymousAccepted !== "boolean") {
|
|
2255
|
+
throw new Error(
|
|
2256
|
+
"[foir] noteConfig answered `signedIn` or `anonymousAccepted` with something other than a boolean. The widget reads them to decide whether this visitor writes as themselves, and will not guess."
|
|
2257
|
+
);
|
|
2258
|
+
}
|
|
2259
|
+
return { screenshotsEnabled, anonymousAccepted, signedIn };
|
|
2247
2260
|
}
|
|
2248
2261
|
async function submitFeedbackNote(client, submission) {
|
|
2249
2262
|
const attachmentFileIds = [];
|
|
@@ -2252,14 +2265,42 @@ async function submitFeedbackNote(client, submission) {
|
|
|
2252
2265
|
await uploadFeedbackAttachment(client, submission.screenshot, submission.fetch)
|
|
2253
2266
|
);
|
|
2254
2267
|
}
|
|
2255
|
-
const args =
|
|
2268
|
+
const args = noteArgs(submission.subject, submission.body);
|
|
2269
|
+
if (attachmentFileIds.length > 0) args.attachmentFileIds = attachmentFileIds;
|
|
2270
|
+
const { notes } = client.ns;
|
|
2271
|
+
return readCreatedNote(
|
|
2272
|
+
await (notes.writeNote ? notes.writeNote(args) : notes.createMyNote(args))
|
|
2273
|
+
);
|
|
2274
|
+
}
|
|
2275
|
+
async function submitVisitorNote(client, submission) {
|
|
2276
|
+
const { notes } = client.ns;
|
|
2277
|
+
if (!notes.writeNote) {
|
|
2278
|
+
throw new Error(
|
|
2279
|
+
"[foir] this client has no `notes.writeNote`, which is the only create that takes a note from a visitor who is not signed in. Re-run `foir types`."
|
|
2280
|
+
);
|
|
2281
|
+
}
|
|
2282
|
+
const args = noteArgs(submission.subject, submission.body);
|
|
2283
|
+
const contactEmail = submission.contactEmail?.trim();
|
|
2284
|
+
if (contactEmail) args.contactEmail = contactEmail;
|
|
2285
|
+
args.pick = ["id", "createdAt"];
|
|
2286
|
+
const result = await notes.writeNote(args);
|
|
2287
|
+
if (!result || typeof result.id !== "string" || result.id === "") {
|
|
2288
|
+
throw new Error(
|
|
2289
|
+
"[foir] writeNote answered a visitor with no receipt. Nothing was saved \u2014 if it had been, the surface would have returned its id."
|
|
2290
|
+
);
|
|
2291
|
+
}
|
|
2292
|
+
return {
|
|
2293
|
+
id: result.id,
|
|
2294
|
+
createdAt: typeof result.createdAt === "string" ? result.createdAt : ""
|
|
2295
|
+
};
|
|
2296
|
+
}
|
|
2297
|
+
function noteArgs(subject, body) {
|
|
2298
|
+
return {
|
|
2256
2299
|
subjectType: "record",
|
|
2257
|
-
subjectId:
|
|
2258
|
-
subjectModelKey:
|
|
2259
|
-
body
|
|
2300
|
+
subjectId: subject.recordId,
|
|
2301
|
+
subjectModelKey: subject.modelKey,
|
|
2302
|
+
body
|
|
2260
2303
|
};
|
|
2261
|
-
if (attachmentFileIds.length > 0) args.attachmentFileIds = attachmentFileIds;
|
|
2262
|
-
return readCreatedNote(await client.ns.notes.createMyNote(args));
|
|
2263
2304
|
}
|
|
2264
2305
|
async function uploadFeedbackAttachment(client, screenshot, fetchImpl = globalThis.fetch) {
|
|
2265
2306
|
const files = client.ns.files;
|
|
@@ -2311,7 +2352,7 @@ function readCreatedNote(result) {
|
|
|
2311
2352
|
const note = result;
|
|
2312
2353
|
if (!note || typeof note.id !== "string" || note.id === "") {
|
|
2313
2354
|
throw new Error(
|
|
2314
|
-
"[foir]
|
|
2355
|
+
"[foir] writeNote answered with no note. Nothing was saved \u2014 if it had been, the surface would have returned it."
|
|
2315
2356
|
);
|
|
2316
2357
|
}
|
|
2317
2358
|
return {
|
|
@@ -2361,6 +2402,8 @@ var COPY = {
|
|
|
2361
2402
|
loading: "One moment\u2026",
|
|
2362
2403
|
sendFailed: "Your feedback could not be sent. Please try again.",
|
|
2363
2404
|
sent: "Thanks. Your feedback has been sent.",
|
|
2405
|
+
reference: "Reference",
|
|
2406
|
+
contactEmail: "Your email, if you would like a reply (optional)",
|
|
2364
2407
|
send: "Send feedback",
|
|
2365
2408
|
sending: "Sending\u2026",
|
|
2366
2409
|
capture: "Add a screenshot",
|
|
@@ -2397,6 +2440,13 @@ var textareaStyle = {
|
|
|
2397
2440
|
minHeight: 96,
|
|
2398
2441
|
resize: "vertical"
|
|
2399
2442
|
};
|
|
2443
|
+
var inputStyle2 = {
|
|
2444
|
+
padding: "8px 10px",
|
|
2445
|
+
borderRadius: 6,
|
|
2446
|
+
border: "1px solid currentColor",
|
|
2447
|
+
background: "transparent",
|
|
2448
|
+
font: "inherit"
|
|
2449
|
+
};
|
|
2400
2450
|
var headingStyle = { margin: 0, fontSize: 15, fontWeight: 600 };
|
|
2401
2451
|
var subjectStyle = { margin: 0, fontSize: 13, opacity: 0.75 };
|
|
2402
2452
|
var noteStyle = { margin: 0, fontSize: 13 };
|
|
@@ -2421,12 +2471,15 @@ function FoirFeedback({
|
|
|
2421
2471
|
defaultOpen = false,
|
|
2422
2472
|
onSignIn,
|
|
2423
2473
|
onSubmitted,
|
|
2474
|
+
onVisitorSubmitted,
|
|
2424
2475
|
onError,
|
|
2425
2476
|
className
|
|
2426
2477
|
}) {
|
|
2427
2478
|
const [open, setOpen] = useState4(defaultOpen);
|
|
2428
2479
|
const [probe, setProbe] = useState4({ status: "loading" });
|
|
2429
2480
|
const [body, setBody] = useState4("");
|
|
2481
|
+
const [contactEmail, setContactEmail] = useState4("");
|
|
2482
|
+
const [receipt, setReceipt] = useState4(null);
|
|
2430
2483
|
const [screenshot, setScreenshot] = useState4(null);
|
|
2431
2484
|
const [capturing, setCapturing] = useState4(false);
|
|
2432
2485
|
const [busy, setBusy] = useState4(false);
|
|
@@ -2445,7 +2498,11 @@ function FoirFeedback({
|
|
|
2445
2498
|
try {
|
|
2446
2499
|
const config = await readNoteConfig(client);
|
|
2447
2500
|
if (!cancelled) {
|
|
2448
|
-
setProbe({
|
|
2501
|
+
setProbe({
|
|
2502
|
+
status: "ready",
|
|
2503
|
+
screenshotsEnabled: config.screenshotsEnabled,
|
|
2504
|
+
signedIn: config.signedIn
|
|
2505
|
+
});
|
|
2449
2506
|
}
|
|
2450
2507
|
} catch (err) {
|
|
2451
2508
|
if (cancelled) return;
|
|
@@ -2476,19 +2533,32 @@ function FoirFeedback({
|
|
|
2476
2533
|
const onSubmit = async (event) => {
|
|
2477
2534
|
event.preventDefault();
|
|
2478
2535
|
const prose = body.trim();
|
|
2479
|
-
if (!resolved || !prose || busy) return;
|
|
2536
|
+
if (!resolved || !prose || busy || probe.status !== "ready") return;
|
|
2480
2537
|
setBusy(true);
|
|
2481
2538
|
setFailure(null);
|
|
2482
2539
|
try {
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2540
|
+
if (probe.signedIn) {
|
|
2541
|
+
const note = await submitFeedbackNote(client, {
|
|
2542
|
+
subject: resolved,
|
|
2543
|
+
body: prose,
|
|
2544
|
+
screenshot
|
|
2545
|
+
});
|
|
2546
|
+
setBody("");
|
|
2547
|
+
setScreenshot(null);
|
|
2548
|
+
setSent(true);
|
|
2549
|
+
onSubmitted?.(note);
|
|
2550
|
+
} else {
|
|
2551
|
+
const written = await submitVisitorNote(client, {
|
|
2552
|
+
subject: resolved,
|
|
2553
|
+
body: prose,
|
|
2554
|
+
contactEmail
|
|
2555
|
+
});
|
|
2556
|
+
setBody("");
|
|
2557
|
+
setContactEmail("");
|
|
2558
|
+
setReceipt(written);
|
|
2559
|
+
setSent(true);
|
|
2560
|
+
onVisitorSubmitted?.(written);
|
|
2561
|
+
}
|
|
2492
2562
|
} catch (err) {
|
|
2493
2563
|
const fault = classifyNotesFault(err);
|
|
2494
2564
|
reportFault(fault, err, "sending feedback failed");
|
|
@@ -2504,6 +2574,7 @@ function FoirFeedback({
|
|
|
2504
2574
|
return;
|
|
2505
2575
|
}
|
|
2506
2576
|
setSent(false);
|
|
2577
|
+
setReceipt(null);
|
|
2507
2578
|
setFailure(null);
|
|
2508
2579
|
setOpen(true);
|
|
2509
2580
|
};
|
|
@@ -2564,11 +2635,28 @@ function FoirFeedback({
|
|
|
2564
2635
|
disabled: busy,
|
|
2565
2636
|
onChange: (event) => {
|
|
2566
2637
|
setBody(event.target.value);
|
|
2567
|
-
if (sent)
|
|
2638
|
+
if (sent) {
|
|
2639
|
+
setSent(false);
|
|
2640
|
+
setReceipt(null);
|
|
2641
|
+
}
|
|
2568
2642
|
},
|
|
2569
2643
|
style: styled ? textareaStyle : void 0
|
|
2570
2644
|
}
|
|
2571
2645
|
),
|
|
2646
|
+
!probe.signedIn && /* @__PURE__ */ jsx5(
|
|
2647
|
+
"input",
|
|
2648
|
+
{
|
|
2649
|
+
type: "email",
|
|
2650
|
+
"data-foir-feedback-contact": true,
|
|
2651
|
+
"aria-label": COPY.contactEmail,
|
|
2652
|
+
placeholder: COPY.contactEmail,
|
|
2653
|
+
autoComplete: "email",
|
|
2654
|
+
value: contactEmail,
|
|
2655
|
+
disabled: busy,
|
|
2656
|
+
onChange: (event) => setContactEmail(event.target.value),
|
|
2657
|
+
style: styled ? inputStyle2 : void 0
|
|
2658
|
+
}
|
|
2659
|
+
),
|
|
2572
2660
|
probe.screenshotsEnabled && isFoirScreenCaptureSupported() && /* @__PURE__ */ jsx5(Fragment2, { children: screenshot ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
2573
2661
|
/* @__PURE__ */ jsx5(
|
|
2574
2662
|
"img",
|
|
@@ -2611,6 +2699,11 @@ function FoirFeedback({
|
|
|
2611
2699
|
children: COPY.sent
|
|
2612
2700
|
}
|
|
2613
2701
|
),
|
|
2702
|
+
sent && !failure && receipt && /* @__PURE__ */ jsxs4("p", { "data-foir-feedback-receipt": true, style: styled ? subjectStyle : void 0, children: [
|
|
2703
|
+
COPY.reference,
|
|
2704
|
+
": ",
|
|
2705
|
+
receipt.id
|
|
2706
|
+
] }),
|
|
2614
2707
|
/* @__PURE__ */ jsx5(
|
|
2615
2708
|
"button",
|
|
2616
2709
|
{
|
package/dist/server/index.d.ts
CHANGED
|
@@ -12,5 +12,5 @@ export type { CallbackClient, CallbackResult } from './callback-client';
|
|
|
12
12
|
export { createEventsClient, FoirEventCursorExpiredError, isFoirEventCursorExpired, FOIR_EVENTS_PATH, FOIR_EVENTS_SCOPE, FOIR_EVENTS_RETENTION_DAYS, } from './events-client';
|
|
13
13
|
export type { FoirEvent, FoirEventActor, FoirEventPage, FoirEventRetention, FoirEventsClient, FoirEventsClientConfig, FoirEventsListParams, FoirEventsStreamParams, FoirEventsSubscribeParams, } from './events-client';
|
|
14
14
|
export type { FoirSubscription, FoirSubscriptionHandlers } from '../data/ws-transport';
|
|
15
|
-
export { FoirRequestError, FoirAuthDowngradedError, FoirSessionExpiredError, isFoirForbidden, isFoirNotFound, isFoirRateLimited, isFoirUnauthenticated, } from '../transport/foir-http';
|
|
15
|
+
export { FoirRequestError, FoirAuthDowngradedError, FoirSessionExpiredError, isFoirForbidden, isFoirNotFound, isFoirRateLimited, isFoirUnauthenticated, stepUpRequired, } from '../transport/foir-http';
|
|
16
16
|
export type { FoirErrorCode, FoirErrorExtensions, FoirGraphQLErrorItem, FoirAuthDowngrade, } from '../transport/foir-http';
|
package/dist/server.js
CHANGED
|
@@ -115,6 +115,8 @@ var GRANT_TABLE = [
|
|
|
115
115
|
["authclients:write", "none", [], []],
|
|
116
116
|
["domains:read", "none", [], []],
|
|
117
117
|
["domains:write", "none", [], []],
|
|
118
|
+
["loginpages:read", "none", [], []],
|
|
119
|
+
["loginpages:write", "none", [], []],
|
|
118
120
|
["secrets:read", "none", [], []],
|
|
119
121
|
["secrets:list", "none", [], []],
|
|
120
122
|
["secrets:put", "none", [], []],
|
|
@@ -152,7 +154,7 @@ var GRANT_TABLE = [
|
|
|
152
154
|
["projects:read", "none", [], []],
|
|
153
155
|
["projects:write", "none", [], []],
|
|
154
156
|
["project:stand", "none", [], []],
|
|
155
|
-
["project:manage", "none", [], ["project:stand", "records:read.all", "records:create", "records:write.all", "records:delete.all", "records:publish.all", "records:attribute", "search:read", "embeddings:read", "embeddings:write", "schemas:read", "drafts:read", "files:read.all", "files:write.all", "files:delete.all", "users:read.all", "identities:read", "users:create", "identities:delete", "users:write.all", "users:setup", "users:delete.all", "notifications:read.all", "notifications:write.all", "notifications:consent", "pushcredentials:read", "pushcredentials:write", "notes:read.all", "notes:write.all", "notes:create", "approvals:read", "approvals:write", "rooms:read", "rooms:write", "presence:read", "operations:read", "operations:execute", "operations:write", "appconfig:read", "schedules:read", "schedules:write", "hooks:read", "hooks:write", "auth:login_with_foir", "authclients:read", "authclients:write", "domains:read", "domains:write", "secrets:read", "secrets:list", "secrets:put", "secrets:delete", "appsecrets:read", "appsecrets:list", "appsecrets:put", "appsecrets:delete", "usersecrets:read", "usersecrets:list", "usersecrets:put", "usersecrets:delete", "opsecrets:read", "opsecrets:write", "settings:read", "settings:write", "designtokens:read", "designtokens:write", "models:read", "models:write", "configs:read", "configs:write", "signinproviders:read", "signinproviders:write", "apps:read", "apps:write", "events:read", "targeting:debug", "visitors:forward", "apikeys:read", "apikeys:write", "organizations:read", "organizations:create", "organizations:delete", "organizations:write", "organizations:reach", "members:read", "members:write", "roles:read", "roles:write", "projects:read", "projects:write", "audit:read"]],
|
|
157
|
+
["project:manage", "none", [], ["project:stand", "records:read.all", "records:create", "records:write.all", "records:delete.all", "records:publish.all", "records:attribute", "search:read", "embeddings:read", "embeddings:write", "schemas:read", "drafts:read", "files:read.all", "files:write.all", "files:delete.all", "users:read.all", "identities:read", "users:create", "identities:delete", "users:write.all", "users:setup", "users:delete.all", "notifications:read.all", "notifications:write.all", "notifications:consent", "pushcredentials:read", "pushcredentials:write", "notes:read.all", "notes:write.all", "notes:create", "approvals:read", "approvals:write", "rooms:read", "rooms:write", "presence:read", "operations:read", "operations:execute", "operations:write", "appconfig:read", "schedules:read", "schedules:write", "hooks:read", "hooks:write", "auth:login_with_foir", "authclients:read", "authclients:write", "domains:read", "domains:write", "loginpages:read", "loginpages:write", "secrets:read", "secrets:list", "secrets:put", "secrets:delete", "appsecrets:read", "appsecrets:list", "appsecrets:put", "appsecrets:delete", "usersecrets:read", "usersecrets:list", "usersecrets:put", "usersecrets:delete", "opsecrets:read", "opsecrets:write", "settings:read", "settings:write", "designtokens:read", "designtokens:write", "models:read", "models:write", "configs:read", "configs:write", "signinproviders:read", "signinproviders:write", "apps:read", "apps:write", "events:read", "targeting:debug", "visitors:forward", "apikeys:read", "apikeys:write", "organizations:read", "organizations:create", "organizations:delete", "organizations:write", "organizations:reach", "members:read", "members:write", "roles:read", "roles:write", "projects:read", "projects:write", "audit:read"]],
|
|
156
158
|
["projects:create", "none", [], []],
|
|
157
159
|
["projects:delete", "none", [], []],
|
|
158
160
|
["tenants:read", "none", [], []],
|
|
@@ -697,6 +699,15 @@ function continueRun(continuation) {
|
|
|
697
699
|
}
|
|
698
700
|
|
|
699
701
|
// src/transport/foir-http.ts
|
|
702
|
+
function stepUpRequired(error) {
|
|
703
|
+
if (!(error instanceof FoirRequestError)) return null;
|
|
704
|
+
for (const item of error.graphQLErrors ?? []) {
|
|
705
|
+
if (item.extensions?.code !== "STEP_UP_REQUIRED") continue;
|
|
706
|
+
const asked = item.extensions.stepUp;
|
|
707
|
+
if (asked === "second_factor" || asked === "sign_in_method") return asked;
|
|
708
|
+
}
|
|
709
|
+
return null;
|
|
710
|
+
}
|
|
700
711
|
var FoirRequestError = class extends Error {
|
|
701
712
|
/** HTTP status code, when the request failed at the HTTP layer. */
|
|
702
713
|
status;
|
|
@@ -1750,6 +1761,7 @@ export {
|
|
|
1750
1761
|
recordsReadModels,
|
|
1751
1762
|
recordsWriteModels,
|
|
1752
1763
|
requireScopedToken,
|
|
1764
|
+
stepUpRequired,
|
|
1753
1765
|
verifyScopedToken,
|
|
1754
1766
|
verifyWebhookSignature
|
|
1755
1767
|
};
|