@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.
Files changed (58) hide show
  1. package/CHANGELOG.md +84 -1
  2. package/README.md +9 -9
  3. package/dist/app/client.d.ts +90 -84
  4. package/dist/app/contract/proto/apps/v1/apps_pb.d.ts +14 -13
  5. package/dist/app/dispatch.d.ts +5 -5
  6. package/dist/app/errors.d.ts +11 -11
  7. package/dist/app/index.d.ts +4 -4
  8. package/dist/app/naming.d.ts +1 -1
  9. package/dist/app/ticket.d.ts +2 -2
  10. package/dist/app/vocabulary.generated.d.ts +2 -2
  11. package/dist/app-contract.js +3 -3
  12. package/dist/app.js +92 -90
  13. package/dist/auth/access.d.ts +19 -19
  14. package/dist/auth/auth.d.ts +216 -114
  15. package/dist/auth/hosted.d.ts +14 -14
  16. package/dist/auth/index.d.ts +7 -7
  17. package/dist/auth/operations.d.ts +128 -32
  18. package/dist/auth/ops.d.ts +39 -21
  19. package/dist/auth/session-client.d.ts +3 -3
  20. package/dist/auth-session.js +3 -3
  21. package/dist/auth.js +234 -135
  22. package/dist/client.js +4 -4
  23. package/dist/data/builtins.d.ts +26 -26
  24. package/dist/data/client.d.ts +2 -2
  25. package/dist/data/decimal.d.ts +1 -1
  26. package/dist/data/index.d.ts +1 -1
  27. package/dist/data/manifest.d.ts +1 -1
  28. package/dist/data/schema.d.ts +1 -1
  29. package/dist/data/transport.d.ts +10 -10
  30. package/dist/data/ws-transport.d.ts +1 -1
  31. package/dist/data.js +6 -6
  32. package/dist/graphql/content-client.d.ts +13 -13
  33. package/dist/live/drift.d.ts +1 -1
  34. package/dist/media/screen-capture.d.ts +1 -1
  35. package/dist/next/index.d.ts +2 -2
  36. package/dist/next/session.d.ts +10 -10
  37. package/dist/next.js +77 -56
  38. package/dist/placement/index.d.ts +13 -13
  39. package/dist/placement.js +9 -6
  40. package/dist/push.js +61 -40
  41. package/dist/react/FoirFeedback.d.ts +2 -2
  42. package/dist/react/FoirProvider.d.ts +23 -23
  43. package/dist/react/SignIn.d.ts +4 -4
  44. package/dist/react/UserButton.d.ts +1 -1
  45. package/dist/react/feedback-notes.d.ts +4 -4
  46. package/dist/react/index.d.ts +3 -3
  47. package/dist/react.js +119 -95
  48. package/dist/realtime/index.d.ts +1 -1
  49. package/dist/server/callback-client.d.ts +4 -4
  50. package/dist/server/events-client.d.ts +16 -16
  51. package/dist/server/operation-types.d.ts +8 -8
  52. package/dist/server/require-scoped-token.d.ts +3 -3
  53. package/dist/server/types.d.ts +1 -1
  54. package/dist/server/verify-scoped-token.d.ts +3 -3
  55. package/dist/server.js +16 -13
  56. package/dist/transport/foir-http.d.ts +13 -13
  57. package/dist/types/index.d.ts +2 -2
  58. package/package.json +3 -3
@@ -120,12 +120,12 @@ export interface ScopedTokenIngress {
120
120
  */
121
121
  orgId: string | null;
122
122
  /**
123
- * The customer the run acts for, when it acts for one: the signed-in
124
- * customer who ran the operation, or the owner of the record whose event
123
+ * The user the run acts for, when it acts for one: the signed-in
124
+ * user who ran the operation, or the owner of the record whose event
125
125
  * fired it. Verified with the rest of the token, so it is the one to trust
126
126
  * over anything in the input.
127
127
  */
128
- customerId?: string;
128
+ userId?: string;
129
129
  /** When the token stops being accepted. There is no refresh: finish, or report, before it. */
130
130
  expiresAt: Date;
131
131
  /** The token's own id (`jti`). The run's id on a dispatch that carries no other. */
@@ -16,7 +16,7 @@ export interface ServerClientOptions {
16
16
  configKey?: string;
17
17
  }
18
18
  /**
19
- * Where an editor iframe should appear in the admin record editor.
19
+ * Where an editor iframe should appear in the console's record editor.
20
20
  */
21
21
  export interface EditorPlacement {
22
22
  /** 'main-editor' replaces / augments the content tab; 'sidebar' renders in the sidebar. */
@@ -38,9 +38,9 @@ export interface ScopedTokenClaims {
38
38
  iat: number;
39
39
  ctx?: Record<string, string>;
40
40
  /**
41
- * The customer the token acts for, when it acts for one: the signed-in
42
- * customer who ran the operation, or the owner of the record whose event
43
- * fired it. `requireScopedToken` answers it as `customerId`.
41
+ * The user the token acts for, when it acts for one: the signed-in
42
+ * user who ran the operation, or the owner of the record whose event
43
+ * fired it. `requireScopedToken` answers it as `userId`.
44
44
  */
45
45
  cid?: string;
46
46
  }
package/dist/server.js CHANGED
@@ -151,7 +151,8 @@ var GRANT_TABLE = [
151
151
  ["roles:write", false, [], []],
152
152
  ["projects:read", false, [], []],
153
153
  ["projects:write", false, [], []],
154
- ["project:manage", false, [], ["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: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", "relyingparties:read", "relyingparties: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"]],
154
+ ["project:stand", false, [], []],
155
+ ["project:manage", false, [], ["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", "relyingparties:read", "relyingparties: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"]],
155
156
  ["projects:create", false, [], []],
156
157
  ["projects:delete", false, [], []],
157
158
  ["tenants:read", false, [], []],
@@ -164,12 +165,14 @@ var GRANT_TABLE = [
164
165
  ["usage:read", false, [], []],
165
166
  ["controlkeys:read", false, [], []],
166
167
  ["controlkeys:write", false, [], []],
168
+ ["tenantsigninproviders:read", false, [], []],
169
+ ["tenantsigninproviders:write", false, [], []],
167
170
  ["tenanthooks:read", false, [], []],
168
171
  ["tenanthooks:write", false, [], []],
169
172
  ["apps:install", false, [], []],
170
- ["tenant:manage", false, [], ["project:manage", "projects:create", "projects:delete", "tenants:read", "tenants:write", "tenants:delete", "export:run", "billing:read", "billing:manage", "usage:read", "controlkeys:read", "controlkeys:write", "tenanthooks:read", "tenanthooks:write", "apps:install"]],
173
+ ["tenant:manage", false, [], ["project:manage", "projects:create", "projects:delete", "tenants:read", "tenants:write", "tenants:delete", "export:run", "billing:read", "billing:manage", "usage:read", "controlkeys:read", "controlkeys:write", "tenanthooks:read", "tenanthooks:write", "tenantsigninproviders:read", "tenantsigninproviders:write", "apps:install"]],
171
174
  ["platform:read", false, [], []],
172
- ["platform:manage", false, [], ["tenant:manage", "platform:read", "platform:create_workspace", "users:setup"]],
175
+ ["platform:manage", false, [], ["tenant:manage", "platform:read", "platform:create_workspace"]],
173
176
  ["platform:create_workspace", false, [], []],
174
177
  ["users:read", false, ["own", "named", "all"], []],
175
178
  ["users:write", false, ["own", "all"], []],
@@ -577,7 +580,7 @@ async function requireScopedToken(request, options) {
577
580
  // header, so the client presents exactly what this guard accepted.
578
581
  dispatch: { token: () => token, context: rawContext },
579
582
  orgId: typeof level === "string" ? level : null,
580
- ...typeof claims.cid === "string" && claims.cid !== "" ? { customerId: claims.cid } : {},
583
+ ...typeof claims.cid === "string" && claims.cid !== "" ? { userId: claims.cid } : {},
581
584
  expiresAt: new Date(claims.exp * 1e3),
582
585
  tokenId: claims.jti
583
586
  };
@@ -639,9 +642,9 @@ async function readDispatch(request) {
639
642
  if (!isObject(context)) refuse(`body.context is ${describe(context)}, expected an object`);
640
643
  requireString(context, "tenantId", "body.context");
641
644
  requireString(context, "projectId", "body.context");
642
- requireString(context, "userId", "body.context", true);
645
+ requireString(context, "actorId", "body.context", true);
643
646
  requireString(context, "timestamp", "body.context");
644
- if (context.customerId !== void 0) requireString(context, "customerId", "body.context");
647
+ if (context.userId !== void 0) requireString(context, "userId", "body.context");
645
648
  const input = body.input;
646
649
  if (input !== null && !isObject(input)) {
647
650
  refuse(`body.input is ${describe(input)}, expected an object`);
@@ -862,8 +865,8 @@ var FoirAuthDowngradedError = class extends FoirRequestError {
862
865
  downgrade;
863
866
  constructor(downgrade) {
864
867
  super(
865
- `[foir] your customer token was ${downgrade.customerToken} (${downgrade.reason}), so the request was served as ${downgrade.servedAs}`,
866
- { graphQLErrors: [{ message: "customer token rejected", extensions: { code: "AUTH_DOWNGRADED" } }] }
868
+ `[foir] your user token was ${downgrade.userToken} (${downgrade.reason}), so the request was served as ${downgrade.servedAs}`,
869
+ { graphQLErrors: [{ message: "user token rejected", extensions: { code: "AUTH_DOWNGRADED" } }] }
867
870
  );
868
871
  this.name = "FoirAuthDowngradedError";
869
872
  this.downgrade = downgrade;
@@ -871,7 +874,7 @@ var FoirAuthDowngradedError = class extends FoirRequestError {
871
874
  };
872
875
  var FoirSessionExpiredError = class extends FoirRequestError {
873
876
  constructor(options) {
874
- super("[foir] the customer session has expired and could not be refreshed: sign in again", {
877
+ super("[foir] the user session has expired and could not be refreshed: sign in again", {
875
878
  cause: options?.cause,
876
879
  graphQLErrors: [{ message: "session expired", extensions: { code: "SESSION_EXPIRED" } }]
877
880
  });
@@ -1131,7 +1134,7 @@ var FoirSocketTransport = class {
1131
1134
  constructor(config) {
1132
1135
  if (config.dispatch !== void 0) {
1133
1136
  throw new FoirRequestError(
1134
- "[foir] a client built from a dispatch token cannot subscribe. The subscription socket authenticates an api key, an admin token or a customer bearer, and has no path for a dispatch token. Queries and mutations made as the operation go to /graphql and work as they are."
1137
+ "[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."
1135
1138
  );
1136
1139
  }
1137
1140
  this.config = config;
@@ -1495,12 +1498,12 @@ function assertOperatorKey(apiKey) {
1495
1498
  const kind = foirKeyKind(key);
1496
1499
  if (kind === "publishable" || kind === "server") {
1497
1500
  throw new FoirRequestError(
1498
- `[foir] createEventsClient: the event log is an OPERATOR surface and a ${kind} key can never hold ${FOIR_EVENTS_SCOPE}: it is not mintable on an app's key. Use an admin key from a machine of your own. The log names which customer acted on records that whoever reads an app's key cannot themselves read.`
1501
+ `[foir] createEventsClient: the event log is a project surface and a ${kind} key can never hold ${FOIR_EVENTS_SCOPE}: it is not mintable on an app's key. Use an admin key from a machine of your own. The log names which user acted on records that whoever reads an app's key cannot themselves read.`
1499
1502
  );
1500
1503
  }
1501
1504
  if (kind === void 0) {
1502
1505
  throw new FoirRequestError(
1503
- `[foir] createEventsClient: apiKey must be an admin key, got a key starting "${key.slice(0, 4)}". The event log is reachable by an admin key or an admin session only.`
1506
+ `[foir] createEventsClient: apiKey must be an admin key, got a key starting "${key.slice(0, 4)}". The event log is reachable by an admin key or a console session only.`
1504
1507
  );
1505
1508
  }
1506
1509
  return key;
@@ -1510,7 +1513,7 @@ function assertNoBearer(headers) {
1510
1513
  for (const name of Object.keys(headers)) {
1511
1514
  if (name.toLowerCase() === "authorization") {
1512
1515
  throw new FoirRequestError(
1513
- `[foir] createEventsClient: an Authorization header is not accepted. A customer bearer makes the customer the resolved authority on api-public, and no customer authority can contain ${FOIR_EVENTS_SCOPE}. The sk_ key alone is the credential for this surface.`
1516
+ `[foir] createEventsClient: an Authorization header is not accepted. A user bearer makes the user the resolved authority on api-public, and no user authority can contain ${FOIR_EVENTS_SCOPE}. The sk_ key alone is the credential for this surface.`
1514
1517
  );
1515
1518
  }
1516
1519
  }
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * The split exists so the second one is possible. The Foir-specific transport
13
13
  * concerns — which api key is in play, the preview schema channel header, the
14
- * optional customer bearer, and the `FoirRequestError` shape — are identical on
14
+ * optional user bearer, and the `FoirRequestError` shape — are identical on
15
15
  * both, and duplicating them is exactly how the two surfaces would drift. So
16
16
  * they live here once and `foir-request.ts` re-exports them unchanged; the only
17
17
  * thing that stayed behind is the part that needs `print`.
@@ -206,8 +206,8 @@ export declare function readFoirRateLimit(headers: Headers): FoirRateLimitSnapsh
206
206
  export declare function readFoirRetryAfterMs(headers: Headers): number | undefined;
207
207
  export interface FoirRequestOptions {
208
208
  /**
209
- * Customer bearer token. api-public still needs the `x-api-key` to resolve
210
- * the project; the bearer adds the customer identity for self-scoped reads
209
+ * User bearer token. api-public still needs the `x-api-key` to resolve
210
+ * the project; the bearer adds the user identity for self-scoped reads
211
211
  * (e.g. `myProfile`). Used by `@foir/sdk/auth`'s post-login profile fetch.
212
212
  */
213
213
  bearerToken?: string;
@@ -256,7 +256,7 @@ export interface FoirRequestOptions {
256
256
  onRateLimit?: (snapshot: FoirRateLimitSnapshot | undefined) => void;
257
257
  }
258
258
  /**
259
- * Supplies the current customer bearer. Sync or async so consumers can read a
259
+ * Supplies the current user bearer. Sync or async so consumers can read a
260
260
  * cookie session (Hydrogen/Remix), a KV store, an in-memory value, etc. Returns
261
261
  * the token when signed in, or `null`/`undefined` when signed out.
262
262
  *
@@ -265,7 +265,7 @@ export interface FoirRequestOptions {
265
265
  * they would end up accepting subtly different things.
266
266
  */
267
267
  export type FoirTokenProvider = () => string | null | undefined | Promise<string | null | undefined>;
268
- /** A request made with an api key, optionally for a signed-in customer. */
268
+ /** A request made with an api key, optionally for a signed-in user. */
269
269
  export interface FoirKeyHeaderInput {
270
270
  apiKey: string;
271
271
  /**
@@ -305,7 +305,7 @@ export interface FoirKeyHeaderInput {
305
305
  *
306
306
  * The token is the whole credential. api-public takes the scoped path when
307
307
  * `X-Foir-Token` is present and never reads `x-api-key` on it, and the
308
- * organization, the customer and the schema channel all come from the token's
308
+ * organization, the user and the schema channel all come from the token's
309
309
  * own claims, so none of the key-side inputs has anything to say here.
310
310
  */
311
311
  export interface FoirDispatchHeaderInput {
@@ -337,7 +337,7 @@ export declare function refuseCredentialHeaders(extra: Readonly<Record<string, s
337
337
  * authorization difference nobody would notice until it mattered.
338
338
  *
339
339
  * Two credentials, and a request carries exactly one: an api key (with its
340
- * optional customer bearer, organization and channel), or an operation's
340
+ * optional user bearer, organization and channel), or an operation's
341
341
  * dispatch token. A dispatch request never writes `x-api-key`.
342
342
  */
343
343
  /** The header a server names the visitor it calls for in. */
@@ -412,7 +412,7 @@ export declare function foirApiEndpoint(apiUrl: string, path: `/${string}`): str
412
412
  /**
413
413
  * Foir DISCARDED a credential you sent, and served the request without it.
414
414
  *
415
- * A customer JWT is optional: if it fails to verify, the read is served as an
415
+ * A user JWT is optional: if it fails to verify, the read is served as an
416
416
  * ordinary anonymous one rather than refused, because plenty of reads
417
417
  * legitimately have nobody signed in. That is the right behaviour and it has a
418
418
  * sharp edge — a lapsed token and a genuinely anonymous request produce the
@@ -424,9 +424,9 @@ export declare function foirApiEndpoint(apiUrl: string, path: `/${string}`): str
424
424
  */
425
425
  export interface FoirAuthDowngrade {
426
426
  /** Always `"rejected"`. */
427
- customerToken: string;
427
+ userToken: string;
428
428
  /**
429
- * `expired` — re-exchange and retry. `invalid` — not a customer token for
429
+ * `expired` — re-exchange and retry. `invalid` — not a user token for
430
430
  * this environment. `wrong_project` — the token and the api-key name
431
431
  * different projects.
432
432
  */
@@ -435,7 +435,7 @@ export interface FoirAuthDowngrade {
435
435
  servedAs: string;
436
436
  }
437
437
  /**
438
- * A request that sent a customer token was served without it.
438
+ * A request that sent a user token was served without it.
439
439
  *
440
440
  * Thrown only to a caller that asked (`rejectDowngrade`): one that sent the
441
441
  * token because it wants the signed-in answer, and would otherwise be handed the
@@ -448,9 +448,9 @@ export declare class FoirAuthDowngradedError extends FoirRequestError {
448
448
  constructor(downgrade: FoirAuthDowngrade);
449
449
  }
450
450
  /**
451
- * The customer's session is over: its token was rejected and could not be
451
+ * The user's session is over: its token was rejected and could not be
452
452
  * refreshed. It is what a signed-in request gets in place of the anonymous
453
- * answer. Send the customer to sign in again.
453
+ * answer. Send the user to sign in again.
454
454
  */
455
455
  export declare class FoirSessionExpiredError extends FoirRequestError {
456
456
  constructor(options?: {
@@ -21,7 +21,7 @@ export interface EditorInit {
21
21
  apiUrl: string;
22
22
  /** Config connection domain (e.g. my-store.myshopify.com) */
23
23
  connectionDomain?: string;
24
- /** How this editor is rendered in the admin UI. */
24
+ /** How this editor is rendered in the console. */
25
25
  configMode?: 'editor' | 'sidebar';
26
26
  /** Currently selected field keys (sidebar mode). */
27
27
  selectedFieldKeys?: string[];
@@ -67,7 +67,7 @@ export interface EditorContextValue {
67
67
  resize: (height: number) => void;
68
68
  /** Report dirty state (unsaved changes). */
69
69
  setDirty: (isDirty: boolean) => void;
70
- /** Request the host to navigate to an admin path. */
70
+ /** Request the host to navigate to a console path. */
71
71
  requestNavigate: (path: string) => void;
72
72
  /** Request the host to execute a platform operation. Returns the result.
73
73
  * `mode` controls whether the platform waits for the operation to complete
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foir/sdk",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Official Foir SDK — editor iframe client + server-side platform helpers",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -177,8 +177,8 @@
177
177
  "ws": "^8.18.0",
178
178
  "y-websocket": "^3.0.0",
179
179
  "yjs": "^13.6.30",
180
- "@foir/access-vocab": "0.0.0",
181
- "@foir/proto-ts": "0.109.0"
180
+ "@foir/proto-ts": "0.109.0",
181
+ "@foir/access-vocab": "0.0.0"
182
182
  },
183
183
  "engines": {
184
184
  "node": ">=18.0.0"