@foir/sdk 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CHANGELOG.md +135 -1
  2. package/README.md +9 -9
  3. package/dist/app/client.d.ts +90 -84
  4. package/dist/app/contract/proto/apps/v1/apps_pb.d.ts +14 -13
  5. package/dist/app/dispatch.d.ts +5 -5
  6. package/dist/app/errors.d.ts +11 -11
  7. package/dist/app/index.d.ts +4 -4
  8. package/dist/app/naming.d.ts +1 -1
  9. package/dist/app/ticket.d.ts +2 -2
  10. package/dist/app/vocabulary.generated.d.ts +2 -2
  11. package/dist/app-contract.js +3 -3
  12. package/dist/app.js +92 -90
  13. package/dist/auth/access.d.ts +19 -19
  14. package/dist/auth/auth.d.ts +216 -114
  15. package/dist/auth/hosted.d.ts +14 -14
  16. package/dist/auth/index.d.ts +7 -7
  17. package/dist/auth/operations.d.ts +128 -32
  18. package/dist/auth/ops.d.ts +39 -21
  19. package/dist/auth/session-client.d.ts +3 -3
  20. package/dist/auth-session.js +3 -3
  21. package/dist/auth.js +291 -146
  22. package/dist/client/platform-client.d.ts +1 -1
  23. package/dist/client.js +32 -5
  24. package/dist/codegen/index.js +1 -1
  25. package/dist/data/builtins.d.ts +41 -82
  26. package/dist/data/client.d.ts +2 -2
  27. package/dist/data/decimal.d.ts +1 -1
  28. package/dist/data/document.d.ts +14 -0
  29. package/dist/data/index.d.ts +2 -2
  30. package/dist/data/manifest.d.ts +1 -1
  31. package/dist/data/schema.d.ts +1 -1
  32. package/dist/data/transport.d.ts +33 -26
  33. package/dist/data/ws-transport.d.ts +1 -1
  34. package/dist/data.js +97 -19
  35. package/dist/graphql/content-client.d.ts +13 -13
  36. package/dist/index.js +24 -0
  37. package/dist/live/drift.d.ts +1 -1
  38. package/dist/media/screen-capture.d.ts +1 -1
  39. package/dist/next/index.d.ts +2 -2
  40. package/dist/next/session.d.ts +10 -10
  41. package/dist/next.js +121 -61
  42. package/dist/placement/index.d.ts +15 -32
  43. package/dist/placement.js +18 -20
  44. package/dist/push.js +113 -46
  45. package/dist/react/FoirFeedback.d.ts +2 -2
  46. package/dist/react/FoirProvider.d.ts +23 -23
  47. package/dist/react/SignIn.d.ts +4 -4
  48. package/dist/react/UserButton.d.ts +1 -1
  49. package/dist/react/feedback-notes.d.ts +4 -4
  50. package/dist/react/index.d.ts +3 -3
  51. package/dist/react.js +168 -105
  52. package/dist/realtime/index.d.ts +1 -1
  53. package/dist/server/callback-client.d.ts +4 -4
  54. package/dist/server/events-client.d.ts +18 -18
  55. package/dist/server/operation-types.d.ts +8 -8
  56. package/dist/server/require-scoped-token.d.ts +3 -3
  57. package/dist/server/server-client.d.ts +1 -1
  58. package/dist/server/types.d.ts +1 -1
  59. package/dist/server/verify-scoped-token.d.ts +4 -28
  60. package/dist/server.js +67 -112
  61. package/dist/transport/foir-http.d.ts +57 -18
  62. package/dist/transport/key-kind.d.ts +40 -0
  63. package/dist/types/index.d.ts +2 -2
  64. package/package.json +3 -3
  65. package/dist/server/older-claims.generated.d.ts +0 -8
package/dist/react.js CHANGED
@@ -14,6 +14,26 @@ import {
14
14
  // src/graphql/foir-request.ts
15
15
  import { print as print2 } from "graphql";
16
16
 
17
+ // src/transport/key-kind.ts
18
+ var KEY_PREFIXES = [
19
+ ["foir_pub_", "publishable"],
20
+ ["foir_srv_", "server"],
21
+ ["foir_adm_", "admin"],
22
+ ["pk_", "publishable"],
23
+ ["sk_", "older"],
24
+ ["tc_", "older"]
25
+ ];
26
+ function foirKeyKind(apiKey) {
27
+ if (typeof apiKey !== "string") return void 0;
28
+ for (const [prefix, kind] of KEY_PREFIXES) {
29
+ if (apiKey.startsWith(prefix)) return kind;
30
+ }
31
+ return void 0;
32
+ }
33
+ function isPublishableFoirKey(apiKey) {
34
+ return foirKeyKind(apiKey) === "publishable";
35
+ }
36
+
17
37
  // src/graphql/cdn-route.ts
18
38
  import { print } from "graphql";
19
39
 
@@ -117,6 +137,28 @@ function refuseCredentialHeaders(extra) {
117
137
  }
118
138
  }
119
139
  var FOIR_VISITOR_IP_HEADER = "X-Foir-Visitor-IP";
140
+ function sentCoordinate(value) {
141
+ return Math.round(value * 100) / 100;
142
+ }
143
+ async function resolveFoirVisitor(source) {
144
+ const value = typeof source === "function" ? await source() : source;
145
+ if (value === null || value === void 0) return { place: {} };
146
+ if (typeof value === "string") {
147
+ const address2 = value.trim();
148
+ return { address: address2 || void 0, place: {} };
149
+ }
150
+ const address = value.address?.trim();
151
+ const country = value.country?.trim();
152
+ const place = {};
153
+ if (country) place.country = country;
154
+ if (Number.isFinite(value.latitude) && Number.isFinite(value.longitude)) {
155
+ place.location = {
156
+ latitude: sentCoordinate(value.latitude),
157
+ longitude: sentCoordinate(value.longitude)
158
+ };
159
+ }
160
+ return { address: address || void 0, place };
161
+ }
120
162
  function buildFoirHeaders(input) {
121
163
  const headers = {
122
164
  "Content-Type": "application/json"
@@ -163,8 +205,8 @@ var FoirAuthDowngradedError = class extends FoirRequestError {
163
205
  downgrade;
164
206
  constructor(downgrade) {
165
207
  super(
166
- `[foir] your customer token was ${downgrade.customerToken} (${downgrade.reason}), so the request was served as ${downgrade.servedAs}`,
167
- { graphQLErrors: [{ message: "customer token rejected", extensions: { code: "AUTH_DOWNGRADED" } }] }
208
+ `[foir] your user token was ${downgrade.userToken} (${downgrade.reason}), so the request was served as ${downgrade.servedAs}`,
209
+ { graphQLErrors: [{ message: "user token rejected", extensions: { code: "AUTH_DOWNGRADED" } }] }
168
210
  );
169
211
  this.name = "FoirAuthDowngradedError";
170
212
  this.downgrade = downgrade;
@@ -172,7 +214,7 @@ var FoirAuthDowngradedError = class extends FoirRequestError {
172
214
  };
173
215
  var FoirSessionExpiredError = class extends FoirRequestError {
174
216
  constructor(options) {
175
- super("[foir] the customer session has expired and could not be refreshed: sign in again", {
217
+ super("[foir] the user session has expired and could not be refreshed: sign in again", {
176
218
  cause: options?.cause,
177
219
  graphQLErrors: [{ message: "session expired", extensions: { code: "SESSION_EXPIRED" } }]
178
220
  });
@@ -189,7 +231,7 @@ function reportAuthDowngrade(envelope) {
189
231
  if (warnedDowngrade === downgrade.reason) return;
190
232
  warnedDowngrade = downgrade.reason;
191
233
  console.warn(
192
- `[foir] your customer token was ${downgrade.customerToken} (${downgrade.reason}) \u2014 this request was served as ${downgrade.servedAs}, so auth-targeted content resolved to its anonymous variant. ` + (downgrade.reason === "expired" ? "Re-exchange the token and retry." : "Check which credential you are sending.")
234
+ `[foir] your user token was ${downgrade.userToken} (${downgrade.reason}) \u2014 this request was served as ${downgrade.servedAs}, so auth-targeted content resolved to its anonymous variant. ` + (downgrade.reason === "expired" ? "Re-exchange the token and retry." : "Check which credential you are sending.")
193
235
  );
194
236
  }
195
237
  function refusePrunedDocument(json, options) {
@@ -733,10 +775,7 @@ function foirDataEndpoint(apiUrl, path) {
733
775
  return foirApiEndpoint(apiUrl, path);
734
776
  }
735
777
  async function resolveVisitorAddress(config) {
736
- const source = config.visitor;
737
- const value = typeof source === "function" ? await source() : source;
738
- const address = value?.trim();
739
- return address ? address : void 0;
778
+ return (await resolveFoirVisitor(config.visitor)).address;
740
779
  }
741
780
  async function resolveBearerToken(config) {
742
781
  const source = config.bearerToken;
@@ -777,7 +816,7 @@ async function resolveFoirAuth(config) {
777
816
  };
778
817
  }
779
818
  function foirRoute(input) {
780
- if (!input.apiKey.startsWith("pk_")) return { lane: "origin", reason: "key" };
819
+ if (!isPublishableFoirKey(input.apiKey)) return { lane: "origin", reason: "key" };
781
820
  if (input.bearerToken) return { lane: "origin", reason: "bearer" };
782
821
  if (input.orgId || input.orgUrl) return { lane: "origin", reason: "org" };
783
822
  if (input.mutation) return { lane: "origin", reason: "operation" };
@@ -911,42 +950,63 @@ var AUTH_OPS = {
911
950
  authConfig: "authConfig",
912
951
  authProviders: "authProviders",
913
952
  defaultAuthProvider: "defaultAuthProvider",
914
- customerSignupContext: "customerSignupContext",
953
+ signupContext: "signupContext",
915
954
  // Post-credential self reads.
916
955
  currentUser: "currentUser",
917
956
  myProviderToken: "myProviderToken",
918
- // What the calling credential may do, and for a signed-in customer the roles
957
+ // What the calling credential may do, and for a signed-in user the roles
919
958
  // they hold. `./access` reads it.
920
959
  whoami: "whoami",
921
960
  // Methods.
922
- customerLogin: "customerLogin",
923
- customerRegister: "customerRegister",
924
- customerRequestOTP: "customerRequestOTP",
925
- customerLoginOTP: "customerLoginOTP",
961
+ login: "login",
962
+ register: "register",
963
+ requestOTP: "requestOTP",
964
+ loginWithOTP: "loginWithOTP",
926
965
  // Session lifecycle.
927
- customerRefreshToken: "customerRefreshToken",
928
- customerLogout: "customerLogout",
929
- customerJoinWaitlist: "customerJoinWaitlist",
930
- // Password management and account lifecycle — the block that had no path.
931
- customerRequestPasswordReset: "customerRequestPasswordReset",
932
- customerResetPassword: "customerResetPassword",
933
- customerUpdatePassword: "customerUpdatePassword",
934
- customerVerifyEmail: "customerVerifyEmail",
966
+ refreshToken: "refreshToken",
967
+ logout: "logout",
968
+ joinWaitlist: "joinWaitlist",
969
+ // Password management and account lifecycle.
970
+ requestPasswordReset: "requestPasswordReset",
971
+ resetPassword: "resetPassword",
972
+ updatePassword: "updatePassword",
973
+ verifyEmail: "verifyEmail",
935
974
  deleteMyAccount: "deleteMyAccount",
936
- // The operator's organization context. TWO ops and no third: one to read
937
- // which organizations the caller may stand in, one to say which. There is
938
- // deliberately no per-call org argument anywhere in this SDK — the claim the
939
- // row layer reads is resolved from the caller's own membership row on every
940
- // request, so an application that never names an org cannot name the wrong
941
- // one.
975
+ // The user's own profile, and the apps they have agreed may act for them.
976
+ updateMyProfile: "updateMyProfile",
977
+ myAuthorizedApps: "myAuthorizedApps",
978
+ revokeAuthorizedApp: "revokeAuthorizedApp",
979
+ // Where they are signed in, their personal access tokens, and the
980
+ // providers they sign in with.
981
+ mySessions: "mySessions",
982
+ endMySession: "endMySession",
983
+ signOutEverywhere: "signOutEverywhere",
984
+ createPersonalAccessToken: "createPersonalAccessToken",
985
+ mySignInMethods: "mySignInMethods",
986
+ connectSignInMethod: "connectSignInMethod",
987
+ disconnectSignInMethod: "disconnectSignInMethod",
988
+ // Their second factors. A change needs one proven first, by a step-up.
989
+ myFactors: "myFactors",
990
+ beginStepUp: "beginStepUp",
991
+ completeStepUp: "completeStepUp",
992
+ beginFactorEnrollment: "beginFactorEnrollment",
993
+ completeFactorEnrollment: "completeFactorEnrollment",
994
+ removeFactor: "removeFactor",
995
+ makeRecoveryCodes: "makeRecoveryCodes",
996
+ // The organizations the caller may stand in. Nothing selects one: a request
997
+ // names the organization it acts in (`orgId` or `orgUrl` below), and the
998
+ // platform checks the caller stands there every time.
942
999
  myOrganizations: "myOrganizations",
943
- selectMyOrganization: "selectMyOrganization",
944
1000
  // Founding one. Present in a manifest only when the project opted in.
945
- registerOperatorOrganization: "registerOperatorOrganization",
1001
+ registerOrganization: "registerOrganization",
946
1002
  // External identity providers.
947
- customerLoginWithProvider: "customerLoginWithProvider",
948
- customerProviderCallback: "customerProviderCallback",
949
- customerProviderVerifyOTP: "customerProviderVerifyOTP"
1003
+ loginWithProvider: "loginWithProvider",
1004
+ providerCallback: "providerCallback",
1005
+ providerVerifyOTP: "providerVerifyOTP",
1006
+ // A provider sign-in that names an address somebody already holds, waiting
1007
+ // for the code sent to it.
1008
+ confirmProviderLink: "confirmProviderLink",
1009
+ resendProviderLinkCode: "resendProviderLinkCode"
950
1010
  };
951
1011
  function authClientConfig(env, options) {
952
1012
  const apiKey = resolveFoirApiKey(env);
@@ -1009,28 +1069,28 @@ function stripUndefined(args) {
1009
1069
  // src/auth/auth.ts
1010
1070
  var TOKEN_KEY = "foir:token";
1011
1071
  var REFRESH_KEY = "foir:refreshToken";
1012
- var CUSTOMER_ID_KEY = "foir:customerId";
1072
+ var USER_ID_KEY = "foir:userId";
1013
1073
  var EMAIL_KEY = "foir:email";
1014
- async function customerLogin(env, vars) {
1015
- return authOp(env, AUTH_OPS.customerLogin, vars);
1074
+ async function login(env, vars) {
1075
+ return authOp(env, AUTH_OPS.login, vars);
1016
1076
  }
1017
- async function customerRegister(env, vars) {
1018
- return authOp(env, AUTH_OPS.customerRegister, vars);
1077
+ async function register(env, vars) {
1078
+ return authOp(env, AUTH_OPS.register, vars);
1019
1079
  }
1020
- async function customerRequestOTP(env, email) {
1021
- return authOp(env, AUTH_OPS.customerRequestOTP, { email });
1080
+ async function requestOTP(env, email) {
1081
+ return authOp(env, AUTH_OPS.requestOTP, { email });
1022
1082
  }
1023
- async function customerLoginOTP(env, vars) {
1024
- return authOp(env, AUTH_OPS.customerLoginOTP, vars);
1083
+ async function loginWithOTP(env, vars) {
1084
+ return authOp(env, AUTH_OPS.loginWithOTP, vars);
1025
1085
  }
1026
- async function customerRefreshToken(env, refreshToken) {
1027
- return authOp(env, AUTH_OPS.customerRefreshToken, { refreshToken });
1086
+ async function refreshTokens(env, refreshToken) {
1087
+ return authOp(env, AUTH_OPS.refreshToken, { refreshToken });
1028
1088
  }
1029
- async function customerLoginWithProvider(env, input) {
1030
- return authOp(env, AUTH_OPS.customerLoginWithProvider, { input });
1089
+ async function loginWithProvider(env, input) {
1090
+ return authOp(env, AUTH_OPS.loginWithProvider, { input });
1031
1091
  }
1032
- async function customerProviderCallback(env, input) {
1033
- return authOp(env, AUTH_OPS.customerProviderCallback, { input });
1092
+ async function providerCallback(env, input) {
1093
+ return authOp(env, AUTH_OPS.providerCallback, { input });
1034
1094
  }
1035
1095
  async function getAuthProviders(env) {
1036
1096
  return authOp(env, AUTH_OPS.authProviders);
@@ -1038,42 +1098,42 @@ async function getAuthProviders(env) {
1038
1098
  async function saveSession(adapter, result) {
1039
1099
  await adapter.set(TOKEN_KEY, result.token);
1040
1100
  await adapter.set(REFRESH_KEY, result.refreshToken);
1041
- if (!result.customerId) {
1042
- return await getSessionCustomer(adapter) ?? { id: "", email: "" };
1101
+ if (!result.userId) {
1102
+ return await getSessionUser(adapter) ?? { id: "", email: "" };
1043
1103
  }
1044
- await adapter.set(CUSTOMER_ID_KEY, result.customerId);
1104
+ await adapter.set(USER_ID_KEY, result.userId);
1045
1105
  await adapter.set(EMAIL_KEY, result.email);
1046
- return { id: result.customerId, email: result.email };
1106
+ return { id: result.userId, email: result.email };
1047
1107
  }
1048
1108
  async function clearSession(adapter) {
1049
1109
  await adapter.unset(TOKEN_KEY);
1050
1110
  await adapter.unset(REFRESH_KEY);
1051
- await adapter.unset(CUSTOMER_ID_KEY);
1111
+ await adapter.unset(USER_ID_KEY);
1052
1112
  await adapter.unset(EMAIL_KEY);
1053
1113
  }
1054
1114
  async function getSessionToken(adapter) {
1055
1115
  return await adapter.get(TOKEN_KEY) ?? null;
1056
1116
  }
1057
- async function getSessionCustomer(adapter) {
1058
- const id = await adapter.get(CUSTOMER_ID_KEY) ?? null;
1117
+ async function getSessionUser(adapter) {
1118
+ const id = await adapter.get(USER_ID_KEY) ?? null;
1059
1119
  const email = await adapter.get(EMAIL_KEY) ?? null;
1060
1120
  if (!id) return null;
1061
1121
  return { id, email: email ?? "" };
1062
1122
  }
1063
- async function loginWithPassword(adapter, env, vars) {
1064
- return saveSession(adapter, await customerLogin(env, vars));
1123
+ async function signInWithPassword(adapter, env, vars) {
1124
+ return saveSession(adapter, await login(env, vars));
1065
1125
  }
1066
- async function registerWithPassword(adapter, env, vars) {
1067
- return saveSession(adapter, await customerRegister(env, vars));
1126
+ async function signUpWithPassword(adapter, env, vars) {
1127
+ return saveSession(adapter, await register(env, vars));
1068
1128
  }
1069
- async function loginWithOTP(adapter, env, vars) {
1070
- return saveSession(adapter, await customerLoginOTP(env, vars));
1129
+ async function signInWithOTP(adapter, env, vars) {
1130
+ return saveSession(adapter, await loginWithOTP(env, vars));
1071
1131
  }
1072
1132
  async function refreshSession(adapter, env) {
1073
1133
  const refreshToken = await adapter.get(REFRESH_KEY) ?? null;
1074
1134
  if (!refreshToken) return null;
1075
1135
  try {
1076
- const result = await customerRefreshToken(env, refreshToken);
1136
+ const result = await refreshTokens(env, refreshToken);
1077
1137
  await saveSession(adapter, result);
1078
1138
  return { token: result.token, refreshToken: result.refreshToken };
1079
1139
  } catch {
@@ -1140,10 +1200,10 @@ async function authedOp(adapter, env, op, args) {
1140
1200
 
1141
1201
  // src/auth/grant-table.generated.ts
1142
1202
  var GRANT_TABLE = [
1143
- ["records:read", true, ["own", "named", "all"], []],
1203
+ ["records:read", true, ["own", "all"], []],
1144
1204
  ["records:create", true, [], []],
1145
- ["records:write", true, ["own", "named", "all"], []],
1146
- ["records:delete", true, ["own", "named", "all"], []],
1205
+ ["records:write", true, ["own", "all"], []],
1206
+ ["records:delete", true, ["own", "all"], []],
1147
1207
  ["records:publish", true, ["own", "all"], []],
1148
1208
  ["records:attribute", true, [], []],
1149
1209
  ["search:read", true, [], []],
@@ -1159,8 +1219,8 @@ var GRANT_TABLE = [
1159
1219
  ["notifications:consent", false, [], []],
1160
1220
  ["pushcredentials:read", false, [], []],
1161
1221
  ["pushcredentials:write", false, [], []],
1162
- ["notes:read", false, [], []],
1163
- ["notes:write", false, [], []],
1222
+ ["notes:read", false, ["own", "all"], []],
1223
+ ["notes:write", false, ["own", "all"], []],
1164
1224
  ["notes:create", false, [], []],
1165
1225
  ["approvals:read", false, [], []],
1166
1226
  ["approvals:write", false, [], []],
@@ -1217,7 +1277,8 @@ var GRANT_TABLE = [
1217
1277
  ["roles:write", false, [], []],
1218
1278
  ["projects:read", false, [], []],
1219
1279
  ["projects:write", false, [], []],
1220
- ["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", "notes:write", "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"]],
1280
+ ["project:stand", false, [], []],
1281
+ ["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"]],
1221
1282
  ["projects:create", false, [], []],
1222
1283
  ["projects:delete", false, [], []],
1223
1284
  ["tenants:read", false, [], []],
@@ -1230,12 +1291,14 @@ var GRANT_TABLE = [
1230
1291
  ["usage:read", false, [], []],
1231
1292
  ["controlkeys:read", false, [], []],
1232
1293
  ["controlkeys:write", false, [], []],
1294
+ ["tenantsigninproviders:read", false, [], []],
1295
+ ["tenantsigninproviders:write", false, [], []],
1233
1296
  ["tenanthooks:read", false, [], []],
1234
1297
  ["tenanthooks:write", false, [], []],
1235
1298
  ["apps:install", false, [], []],
1236
- ["tenant:manage", false, [], ["project:manage", "projects:create", "projects:delete", "tenants:read", "tenants:write", "tenants:delete", "audit:read", "export:run", "billing:read", "billing:manage", "usage:read", "controlkeys:read", "controlkeys:write", "tenanthooks:read", "tenanthooks:write", "apps:install"]],
1299
+ ["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"]],
1237
1300
  ["platform:read", false, [], []],
1238
- ["platform:manage", false, [], ["tenant:manage", "platform:read", "platform:create_workspace", "users:setup"]],
1301
+ ["platform:manage", false, [], ["tenant:manage", "platform:read", "platform:create_workspace"]],
1239
1302
  ["platform:create_workspace", false, [], []],
1240
1303
  ["users:read", false, ["own", "named", "all"], []],
1241
1304
  ["users:write", false, ["own", "all"], []],
@@ -1334,15 +1397,15 @@ function holds(held, required) {
1334
1397
 
1335
1398
  // src/auth/access.ts
1336
1399
  function accessFrom(who) {
1337
- const customer = who?.credential?.customer;
1338
- if (!customer?.id) return null;
1400
+ const user = who?.credential?.user;
1401
+ if (!user?.id) return null;
1339
1402
  return {
1340
- customerId: customer.id,
1341
- roles: Array.isArray(customer.roles) ? [...customer.roles] : null,
1403
+ userId: user.id,
1404
+ roles: Array.isArray(user.roles) ? [...user.roles] : null,
1342
1405
  scopes: [...who?.authority?.effective ?? []]
1343
1406
  };
1344
1407
  }
1345
- async function customerAccess(env, options) {
1408
+ async function userAccess(env, options) {
1346
1409
  return accessFrom(await authOp(env, AUTH_OPS.whoami, void 0, options));
1347
1410
  }
1348
1411
  async function getSessionAccess(adapter, env) {
@@ -1422,14 +1485,14 @@ function createFoirSessionClient(config) {
1422
1485
  } catch {
1423
1486
  return cached;
1424
1487
  }
1425
- if (!json.access_token || !json.customer_id) return cached;
1488
+ if (!json.access_token || !json.user_id) return cached;
1426
1489
  const expiresIn = typeof json.expires_in === "number" ? json.expires_in : 0;
1427
1490
  const next = {
1428
1491
  token: json.access_token,
1429
1492
  expiresAt: Date.now() + expiresIn * 1e3,
1430
- user: { customerId: json.customer_id, email: json.email ?? "" }
1493
+ user: { userId: json.user_id, email: json.email ?? "" }
1431
1494
  };
1432
- const changed = cached?.user.customerId !== next.user.customerId;
1495
+ const changed = cached?.user.userId !== next.user.userId;
1433
1496
  cached = next;
1434
1497
  scheduleRefresh(next.expiresAt);
1435
1498
  if (changed) emit(next.user);
@@ -1530,13 +1593,13 @@ function FoirProvider({
1530
1593
  const adapterRef = useRef(adapter ?? createLocalStorageAdapter());
1531
1594
  if (adapter && adapter !== adapterRef.current) adapterRef.current = adapter;
1532
1595
  const [status, setStatus] = useState("loading");
1533
- const [customer, setCustomer] = useState(null);
1596
+ const [user, setUser] = useState(null);
1534
1597
  const [access, setAccess] = useState(null);
1535
1598
  const [accessStatus, setAccessStatus] = useState("idle");
1536
1599
  const accessRead = useRef(0);
1537
1600
  const accessPending = useRef(null);
1538
1601
  const apply = useCallback((c) => {
1539
- setCustomer(c);
1602
+ setUser(c);
1540
1603
  setStatus(c ? "authenticated" : "unauthenticated");
1541
1604
  accessRead.current += 1;
1542
1605
  setAccess(null);
@@ -1561,10 +1624,10 @@ function FoirProvider({
1561
1624
  void (async () => {
1562
1625
  if (hosted) {
1563
1626
  const u = await hosted.getUser();
1564
- if (!cancelled) apply(u ? { id: u.customerId, email: u.email } : null);
1627
+ if (!cancelled) apply(u ? { id: u.userId, email: u.email } : null);
1565
1628
  return;
1566
1629
  }
1567
- const c = await getSessionCustomer(adapterRef.current);
1630
+ const c = await getSessionUser(adapterRef.current);
1568
1631
  if (!cancelled) apply(c);
1569
1632
  })();
1570
1633
  return () => {
@@ -1579,7 +1642,7 @@ function FoirProvider({
1579
1642
  (action) => {
1580
1643
  if (hosted) {
1581
1644
  throw new Error(
1582
- `[foir] ${action}() is not available in hostedSession mode \u2014 the customer signs in at your Foir login domain. Redirect to hostedSignInUrl() instead.`
1645
+ `[foir] ${action}() is not available in hostedSession mode \u2014 the user signs in at your Foir login domain. Redirect to hostedSignInUrl() instead.`
1583
1646
  );
1584
1647
  }
1585
1648
  },
@@ -1588,16 +1651,16 @@ function FoirProvider({
1588
1651
  const signIn = useCallback(
1589
1652
  async (vars) => {
1590
1653
  assertTokenMode("signIn");
1591
- const c = await loginWithPassword(adapterRef.current, envRef.current, vars);
1654
+ const c = await signInWithPassword(adapterRef.current, envRef.current, vars);
1592
1655
  apply(c);
1593
1656
  return c;
1594
1657
  },
1595
1658
  [apply, assertTokenMode]
1596
1659
  );
1597
- const register = useCallback(
1660
+ const register2 = useCallback(
1598
1661
  async (vars) => {
1599
1662
  assertTokenMode("register");
1600
- const c = await registerWithPassword(adapterRef.current, envRef.current, vars);
1663
+ const c = await signUpWithPassword(adapterRef.current, envRef.current, vars);
1601
1664
  apply(c);
1602
1665
  return c;
1603
1666
  },
@@ -1606,14 +1669,14 @@ function FoirProvider({
1606
1669
  const requestOtp = useCallback(
1607
1670
  (email) => {
1608
1671
  assertTokenMode("requestOtp");
1609
- return customerRequestOTP(envRef.current, email);
1672
+ return requestOTP(envRef.current, email);
1610
1673
  },
1611
1674
  [assertTokenMode]
1612
1675
  );
1613
1676
  const signInWithOtp = useCallback(
1614
1677
  async (vars) => {
1615
1678
  assertTokenMode("signInWithOtp");
1616
- const c = await loginWithOTP(adapterRef.current, envRef.current, vars);
1679
+ const c = await signInWithOTP(adapterRef.current, envRef.current, vars);
1617
1680
  apply(c);
1618
1681
  return c;
1619
1682
  },
@@ -1622,7 +1685,7 @@ function FoirProvider({
1622
1685
  const signInWithProvider = useCallback(
1623
1686
  async (providerKey, opts) => {
1624
1687
  assertTokenMode("signInWithProvider");
1625
- const res = await customerLoginWithProvider(envRef.current, {
1688
+ const res = await loginWithProvider(envRef.current, {
1626
1689
  providerKey,
1627
1690
  ...opts
1628
1691
  });
@@ -1635,7 +1698,7 @@ function FoirProvider({
1635
1698
  const completeProviderLogin = useCallback(
1636
1699
  async (input) => {
1637
1700
  assertTokenMode("completeProviderLogin");
1638
- const result = await customerProviderCallback(envRef.current, input);
1701
+ const result = await providerCallback(envRef.current, input);
1639
1702
  const c = await saveSession(adapterRef.current, result);
1640
1703
  apply(c);
1641
1704
  return c;
@@ -1671,7 +1734,7 @@ function FoirProvider({
1671
1734
  const pending = (async () => {
1672
1735
  try {
1673
1736
  const next = hosted ? await hosted.getToken().then(
1674
- (bearerToken) => bearerToken ? customerAccess(envRef.current, { bearerToken }) : null
1737
+ (bearerToken) => bearerToken ? userAccess(envRef.current, { bearerToken }) : null
1675
1738
  ) : await getSessionAccess(adapterRef.current, envRef.current);
1676
1739
  if (accessRead.current !== read) return;
1677
1740
  setAccess(next);
@@ -1706,7 +1769,7 @@ function FoirProvider({
1706
1769
  const value = useMemo(
1707
1770
  () => ({
1708
1771
  status,
1709
- customer,
1772
+ user,
1710
1773
  access,
1711
1774
  accessStatus,
1712
1775
  loadAccess,
@@ -1714,7 +1777,7 @@ function FoirProvider({
1714
1777
  env,
1715
1778
  adapter: adapterRef.current,
1716
1779
  signIn,
1717
- register,
1780
+ register: register2,
1718
1781
  requestOtp,
1719
1782
  signInWithOtp,
1720
1783
  signInWithProvider,
@@ -1727,14 +1790,14 @@ function FoirProvider({
1727
1790
  }),
1728
1791
  [
1729
1792
  status,
1730
- customer,
1793
+ user,
1731
1794
  access,
1732
1795
  accessStatus,
1733
1796
  loadAccess,
1734
1797
  ensureAccess,
1735
1798
  env,
1736
1799
  signIn,
1737
- register,
1800
+ register2,
1738
1801
  requestOtp,
1739
1802
  signInWithOtp,
1740
1803
  signInWithProvider,
@@ -1756,16 +1819,16 @@ function useFoirContext() {
1756
1819
  return ctx;
1757
1820
  }
1758
1821
  function useFoirSession() {
1759
- const { status, customer } = useFoirContext();
1822
+ const { status, user } = useFoirContext();
1760
1823
  return {
1761
1824
  status,
1762
- customer,
1825
+ user,
1763
1826
  isLoading: status === "loading",
1764
1827
  isAuthenticated: status === "authenticated"
1765
1828
  };
1766
1829
  }
1767
1830
  function useFoirUser() {
1768
- return useFoirContext().customer;
1831
+ return useFoirContext().user;
1769
1832
  }
1770
1833
  function useFoirAccess() {
1771
1834
  const { status, access, accessStatus, loadAccess, ensureAccess } = useFoirContext();
@@ -1788,7 +1851,7 @@ function useFoirAccess() {
1788
1851
  function useFoirAuth() {
1789
1852
  const {
1790
1853
  signIn,
1791
- register,
1854
+ register: register2,
1792
1855
  requestOtp,
1793
1856
  signInWithOtp,
1794
1857
  signInWithProvider,
@@ -1801,7 +1864,7 @@ function useFoirAuth() {
1801
1864
  } = useFoirContext();
1802
1865
  return {
1803
1866
  signIn,
1804
- register,
1867
+ register: register2,
1805
1868
  requestOtp,
1806
1869
  signInWithOtp,
1807
1870
  signInWithProvider,
@@ -1909,8 +1972,8 @@ function SignIn({
1909
1972
  if (hostedUrl) {
1910
1973
  return /* @__PURE__ */ jsx3("div", { className, "data-foir-signin": true, children: /* @__PURE__ */ jsx3("a", { href: hostedUrl, "data-foir-hosted-login": true, style: styled ? submitStyle : void 0, children: "Sign in" }) });
1911
1974
  }
1912
- const finish = (customer) => {
1913
- onSignIn?.(customer);
1975
+ const finish = (user) => {
1976
+ onSignIn?.(user);
1914
1977
  if (afterSignInUrl && typeof window !== "undefined") {
1915
1978
  window.location.assign(afterSignInUrl);
1916
1979
  }
@@ -2186,7 +2249,7 @@ async function uploadFeedbackAttachment(client, screenshot, fetchImpl = globalTh
2186
2249
  const files = client.ns.files;
2187
2250
  if (!files) {
2188
2251
  throw new Error(
2189
- "[foir] this client cannot reach the files namespace, so a screenshot cannot be uploaded. Attaching one needs `files:write` on the key and on the signed-in customer's role."
2252
+ "[foir] this client cannot reach the files namespace, so a screenshot cannot be uploaded. Attaching one needs `files:write` on the key and on the signed-in user's role."
2190
2253
  );
2191
2254
  }
2192
2255
  const ticket = readUploadTicket(
@@ -2578,7 +2641,7 @@ function failureCopy(fault) {
2578
2641
  function reportFault(fault, err, action) {
2579
2642
  if (fault.kind === "scope") {
2580
2643
  console.error(
2581
- `[foir] <FoirFeedback>: the API refused with "missing required scope: ${fault.scope}". This is not a bad API key: the key reached the surface. The signed-in CUSTOMER's role does not grant ${fault.scope}, and a new project's default customer role does not carry the notes scopes. Add it to the role that customer holds, or to the project's default customer role, and this works with no code change.`,
2644
+ `[foir] <FoirFeedback>: the API refused with "missing required scope: ${fault.scope}". This is not a bad API key: the key reached the surface. The signed-in USER's role does not grant ${fault.scope}, and a new project's default user role does not carry the notes scopes. Add it to the role that user holds, or to the project's default user role, and this works with no code change.`,
2582
2645
  err
2583
2646
  );
2584
2647
  return;
@@ -11,7 +11,7 @@
11
11
  * provider's url params current for whenever it next reconnects.
12
12
  *
13
13
  * Agnostic by design: token-agnostic (caller supplies `getToken` — an internal
14
- * mint for admin, a customer access token for an app), persistence-agnostic
14
+ * mint for the console, a user access token for an app), persistence-agnostic
15
15
  * (never persists), doc-schema-agnostic (caller owns the `Y.Doc` + shared types).
16
16
  *
17
17
  * `yjs` + `y-websocket` are OPTIONAL peer deps gated to this subpath, so a
@@ -12,8 +12,8 @@
12
12
  * pushes a DLQ entry.
13
13
  * - `progress({pct, message, metadata})` — non-terminal update; the
14
14
  * monotonic guard at the platform DB layer drops out-of-order packets.
15
- * - `cancel()` — extension self-cancels (rare; admins normally drive
16
- * cancel via the admin app's ConnectRPC path).
15
+ * - `cancel()`: the extension cancels itself (rare; a run is normally
16
+ * cancelled from the console).
17
17
  *
18
18
  * Each call carries:
19
19
  * - `Authorization: Bearer <callback.token>` — Ed25519 scoped token.
@@ -42,7 +42,7 @@ export interface CallbackResult {
42
42
  */
43
43
  status: string;
44
44
  /**
45
- * True when the admin cancelled the execution while the extension was
45
+ * True when someone cancelled the execution while the extension was
46
46
  * processing — the platform refused to overwrite the cancelled state.
47
47
  * Extensions should stop work and (optionally) call `fail('CANCELLED')`.
48
48
  */
@@ -66,7 +66,7 @@ export interface CallbackClient<TResult = unknown> {
66
66
  details?: Record<string, unknown>;
67
67
  }): Promise<CallbackResult>;
68
68
  /**
69
- * Returns `{cancelled: true}` when the admin has cancelled — extension
69
+ * Returns `{cancelled: true}` when someone has cancelled it: the extension
70
70
  * must stop work. `applied: false` means the monotonic guard dropped
71
71
  * the update because pct was lower than the persisted value.
72
72
  */