@foir/sdk 0.22.0 → 0.24.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/dist/react.js CHANGED
@@ -18,10 +18,7 @@ import { print as print2 } from "graphql";
18
18
  var KEY_PREFIXES = [
19
19
  ["foir_pub_", "publishable"],
20
20
  ["foir_srv_", "server"],
21
- ["foir_adm_", "admin"],
22
- ["pk_", "publishable"],
23
- ["sk_", "older"],
24
- ["tc_", "older"]
21
+ ["foir_adm_", "admin"]
25
22
  ];
26
23
  function foirKeyKind(apiKey) {
27
24
  if (typeof apiKey !== "string") return void 0;
@@ -970,7 +967,6 @@ var AUTH_OPS = {
970
967
  requestPasswordReset: "requestPasswordReset",
971
968
  resetPassword: "resetPassword",
972
969
  updatePassword: "updatePassword",
973
- verifyEmail: "verifyEmail",
974
970
  deleteMyAccount: "deleteMyAccount",
975
971
  // The user's own profile, and the apps they have agreed may act for them.
976
972
  updateMyProfile: "updateMyProfile",
@@ -1200,125 +1196,125 @@ async function authedOp(adapter, env, op, args) {
1200
1196
 
1201
1197
  // src/auth/grant-table.generated.ts
1202
1198
  var GRANT_TABLE = [
1203
- ["records:read", true, ["own", "all"], []],
1204
- ["records:create", true, [], []],
1205
- ["records:write", true, ["own", "all"], []],
1206
- ["records:delete", true, ["own", "all"], []],
1207
- ["records:publish", true, ["own", "all"], []],
1208
- ["records:attribute", true, [], []],
1209
- ["search:read", true, [], []],
1210
- ["embeddings:read", false, [], []],
1211
- ["embeddings:write", false, [], []],
1212
- ["schemas:read", false, [], []],
1213
- ["drafts:read", false, [], []],
1214
- ["files:read", false, ["own", "all"], []],
1215
- ["files:write", false, ["own", "all"], []],
1216
- ["files:delete", false, ["own", "all"], []],
1217
- ["notifications:read", false, ["own", "all"], []],
1218
- ["notifications:write", false, ["own", "named", "all"], []],
1219
- ["notifications:consent", false, [], []],
1220
- ["pushcredentials:read", false, [], []],
1221
- ["pushcredentials:write", false, [], []],
1222
- ["notes:read", false, ["own", "all"], []],
1223
- ["notes:write", false, ["own", "all"], []],
1224
- ["notes:create", false, [], []],
1225
- ["approvals:read", false, [], []],
1226
- ["approvals:write", false, [], []],
1227
- ["rooms:read", true, [], []],
1228
- ["rooms:write", true, [], []],
1229
- ["presence:read", true, [], []],
1230
- ["operations:read", false, [], []],
1231
- ["operations:execute", true, [], []],
1232
- ["operations:write", false, [], []],
1233
- ["operations:complete", false, [], []],
1234
- ["status:write", false, [], []],
1235
- ["appconfig:read", false, [], []],
1236
- ["schedules:read", false, [], []],
1237
- ["schedules:write", false, [], []],
1238
- ["hooks:read", false, [], []],
1239
- ["hooks:write", false, [], []],
1240
- ["relyingparties:read", false, [], []],
1241
- ["relyingparties:write", false, [], []],
1242
- ["domains:read", false, [], []],
1243
- ["domains:write", false, [], []],
1244
- ["secrets:read", false, [], []],
1245
- ["secrets:list", false, [], []],
1246
- ["secrets:put", false, [], []],
1247
- ["secrets:delete", false, [], []],
1248
- ["appsecrets:read", false, [], []],
1249
- ["appsecrets:list", false, [], []],
1250
- ["appsecrets:put", false, [], []],
1251
- ["appsecrets:delete", false, [], []],
1252
- ["opsecrets:read", false, [], []],
1253
- ["opsecrets:write", false, [], []],
1254
- ["settings:read", false, [], []],
1255
- ["settings:write", false, [], []],
1256
- ["designtokens:read", false, [], []],
1257
- ["designtokens:write", false, [], []],
1258
- ["models:read", false, [], []],
1259
- ["models:write", false, [], []],
1260
- ["configs:read", false, [], []],
1261
- ["configs:write", false, [], []],
1262
- ["apps:read", false, [], []],
1263
- ["apps:write", false, [], []],
1264
- ["events:read", false, [], []],
1265
- ["targeting:debug", false, [], []],
1266
- ["visitors:forward", false, [], []],
1267
- ["apikeys:read", false, [], []],
1268
- ["apikeys:write", false, [], []],
1269
- ["organizations:read", false, [], []],
1270
- ["organizations:write", false, [], []],
1271
- ["organizations:create", false, [], []],
1272
- ["organizations:delete", false, [], []],
1273
- ["organizations:reach", false, [], []],
1274
- ["members:read", false, [], []],
1275
- ["members:write", false, [], []],
1276
- ["roles:read", false, [], []],
1277
- ["roles:write", false, [], []],
1278
- ["projects:read", false, [], []],
1279
- ["projects:write", false, [], []],
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"]],
1282
- ["projects:create", false, [], []],
1283
- ["projects:delete", false, [], []],
1284
- ["tenants:read", false, [], []],
1285
- ["tenants:write", false, [], []],
1286
- ["tenants:delete", false, [], []],
1287
- ["audit:read", false, [], []],
1288
- ["export:run", false, [], []],
1289
- ["billing:read", false, [], []],
1290
- ["billing:manage", false, [], []],
1291
- ["usage:read", false, [], []],
1292
- ["controlkeys:read", false, [], []],
1293
- ["controlkeys:write", false, [], []],
1294
- ["tenantsigninproviders:read", false, [], []],
1295
- ["tenantsigninproviders:write", false, [], []],
1296
- ["tenanthooks:read", false, [], []],
1297
- ["tenanthooks:write", false, [], []],
1298
- ["apps:install", false, [], []],
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"]],
1300
- ["platform:read", false, [], []],
1301
- ["platform:manage", false, [], ["tenant:manage", "platform:read", "platform:create_workspace"]],
1302
- ["platform:create_workspace", false, [], []],
1303
- ["users:read", false, ["own", "named", "all"], []],
1304
- ["users:write", false, ["own", "all"], []],
1305
- ["users:setup", false, [], []],
1306
- ["users:delete", false, ["own", "all"], []],
1307
- ["users:create", false, [], []],
1308
- ["identities:read", false, [], []],
1309
- ["identities:delete", false, [], []],
1310
- ["usersecrets:read", false, [], []],
1311
- ["usersecrets:list", false, [], []],
1312
- ["usersecrets:put", false, [], []],
1313
- ["usersecrets:delete", false, [], []],
1314
- ["auth:login_with_foir", false, [], []],
1315
- ["signinproviders:read", false, [], []],
1316
- ["signinproviders:write", false, [], []]
1199
+ ["records:read", "model", ["own", "all"], []],
1200
+ ["records:create", "model", [], []],
1201
+ ["records:write", "model", ["own", "all"], []],
1202
+ ["records:delete", "model", ["own", "all"], []],
1203
+ ["records:publish", "model", ["own", "all"], []],
1204
+ ["records:attribute", "model", [], []],
1205
+ ["search:read", "model", [], []],
1206
+ ["embeddings:read", "none", [], []],
1207
+ ["embeddings:write", "none", [], []],
1208
+ ["schemas:read", "none", [], []],
1209
+ ["drafts:read", "none", [], []],
1210
+ ["files:read", "none", ["own", "all"], []],
1211
+ ["files:write", "none", ["own", "all"], []],
1212
+ ["files:delete", "none", ["own", "all"], []],
1213
+ ["notifications:read", "none", ["own", "all"], []],
1214
+ ["notifications:write", "none", ["own", "named", "all"], []],
1215
+ ["notifications:consent", "none", [], []],
1216
+ ["pushcredentials:read", "none", [], []],
1217
+ ["pushcredentials:write", "none", [], []],
1218
+ ["notes:read", "none", ["own", "all"], []],
1219
+ ["notes:write", "none", ["own", "all"], []],
1220
+ ["notes:create", "none", [], []],
1221
+ ["approvals:read", "none", [], []],
1222
+ ["approvals:write", "none", [], []],
1223
+ ["rooms:read", "model", [], []],
1224
+ ["rooms:write", "model", [], []],
1225
+ ["presence:read", "model", [], []],
1226
+ ["operations:read", "none", [], []],
1227
+ ["operations:execute", "operation", [], []],
1228
+ ["operations:write", "none", [], []],
1229
+ ["operations:complete", "none", [], []],
1230
+ ["status:write", "none", [], []],
1231
+ ["appconfig:read", "none", [], []],
1232
+ ["schedules:read", "none", [], []],
1233
+ ["schedules:write", "none", [], []],
1234
+ ["hooks:read", "none", [], []],
1235
+ ["hooks:write", "none", [], []],
1236
+ ["authclients:read", "none", [], []],
1237
+ ["authclients:write", "none", [], []],
1238
+ ["domains:read", "none", [], []],
1239
+ ["domains:write", "none", [], []],
1240
+ ["secrets:read", "none", [], []],
1241
+ ["secrets:list", "none", [], []],
1242
+ ["secrets:put", "none", [], []],
1243
+ ["secrets:delete", "none", [], []],
1244
+ ["appsecrets:read", "none", [], []],
1245
+ ["appsecrets:list", "none", [], []],
1246
+ ["appsecrets:put", "none", [], []],
1247
+ ["appsecrets:delete", "none", [], []],
1248
+ ["opsecrets:read", "none", [], []],
1249
+ ["opsecrets:write", "none", [], []],
1250
+ ["settings:read", "none", [], []],
1251
+ ["settings:write", "none", [], []],
1252
+ ["designtokens:read", "none", [], []],
1253
+ ["designtokens:write", "none", [], []],
1254
+ ["models:read", "none", [], []],
1255
+ ["models:write", "none", [], []],
1256
+ ["configs:read", "none", [], []],
1257
+ ["configs:write", "none", [], []],
1258
+ ["apps:read", "none", [], []],
1259
+ ["apps:write", "none", [], []],
1260
+ ["events:read", "none", [], []],
1261
+ ["targeting:debug", "none", [], []],
1262
+ ["visitors:forward", "none", [], []],
1263
+ ["apikeys:read", "none", [], []],
1264
+ ["apikeys:write", "none", [], []],
1265
+ ["organizations:read", "none", [], []],
1266
+ ["organizations:write", "none", [], []],
1267
+ ["organizations:create", "none", [], []],
1268
+ ["organizations:delete", "none", [], []],
1269
+ ["organizations:reach", "none", [], []],
1270
+ ["members:read", "none", [], []],
1271
+ ["members:write", "none", [], []],
1272
+ ["roles:read", "none", [], []],
1273
+ ["roles:write", "none", [], []],
1274
+ ["projects:read", "none", [], []],
1275
+ ["projects:write", "none", [], []],
1276
+ ["project:stand", "none", [], []],
1277
+ ["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"]],
1278
+ ["projects:create", "none", [], []],
1279
+ ["projects:delete", "none", [], []],
1280
+ ["tenants:read", "none", [], []],
1281
+ ["tenants:write", "none", [], []],
1282
+ ["tenants:delete", "none", [], []],
1283
+ ["audit:read", "none", [], []],
1284
+ ["export:run", "none", [], []],
1285
+ ["billing:read", "none", [], []],
1286
+ ["billing:manage", "none", [], []],
1287
+ ["usage:read", "none", [], []],
1288
+ ["controlkeys:read", "none", [], []],
1289
+ ["controlkeys:write", "none", [], []],
1290
+ ["tenanthooks:read", "none", [], []],
1291
+ ["tenanthooks:write", "none", [], []],
1292
+ ["apps:install", "none", [], []],
1293
+ ["tenant:manage", "none", [], ["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"]],
1294
+ ["platform:read", "none", [], []],
1295
+ ["platform:manage", "none", [], ["tenant:manage", "platform:read", "platform:create_workspace"]],
1296
+ ["platform:create_workspace", "none", [], []],
1297
+ ["users:read", "none", ["own", "named", "all"], []],
1298
+ ["users:write", "none", ["own", "all"], []],
1299
+ ["users:setup", "none", [], []],
1300
+ ["users:delete", "none", ["own", "all"], []],
1301
+ ["users:create", "none", [], []],
1302
+ ["identities:read", "none", [], []],
1303
+ ["identities:delete", "none", [], []],
1304
+ ["usersecrets:read", "none", [], []],
1305
+ ["usersecrets:list", "none", [], []],
1306
+ ["usersecrets:put", "none", [], []],
1307
+ ["usersecrets:delete", "none", [], []],
1308
+ ["auth:login_with_foir", "none", [], []],
1309
+ ["signinproviders:read", "none", [], []],
1310
+ ["signinproviders:write", "none", [], []]
1317
1311
  ];
1318
1312
 
1319
1313
  // src/auth/grants.ts
1320
1314
  var WILDCARD = "*";
1321
1315
  var RESOURCE_WILDCARD = ":*";
1316
+ var FIELD_PERMISSIONS = ["records:read", "records:write"];
1317
+ var FIELD_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
1322
1318
  var index;
1323
1319
  function catalogue() {
1324
1320
  if (!index) {
@@ -1359,15 +1355,23 @@ function parseGrant(s) {
1359
1355
  let target = "";
1360
1356
  if (rest.startsWith(":")) {
1361
1357
  target = rest.slice(1);
1362
- if (!permission[1]) return null;
1358
+ if (permission[1] === "none") return null;
1363
1359
  if (target === "" || /[: \t\n*]/.test(target)) return null;
1360
+ const dot = target.indexOf(".");
1361
+ if (permission[1] === "model" && dot >= 0) {
1362
+ if (!FIELD_PERMISSIONS.includes(name) || dot === 0 || !FIELD_KEY.test(target.slice(dot + 1))) return null;
1363
+ }
1364
1364
  }
1365
1365
  return { permission, reach, target };
1366
1366
  }
1367
1367
  return null;
1368
1368
  }
1369
1369
  function covers(held, required) {
1370
- return held.permission === required.permission && reachRank[held.reach] >= reachRank[required.reach] && (held.target === "" || held.target === required.target);
1370
+ if (held.permission !== required.permission || reachRank[held.reach] < reachRank[required.reach]) return false;
1371
+ if (required.permission[1] === "model" && required.target.includes(".")) {
1372
+ return held.target === required.target || held.target === "" && held.reach === "all";
1373
+ }
1374
+ return held.target === "" || held.target === required.target;
1371
1375
  }
1372
1376
  function resourceWildcard(held) {
1373
1377
  if (!held.endsWith(RESOURCE_WILDCARD)) return null;
@@ -1426,8 +1430,9 @@ var DEFAULT_REFRESH_SKEW_SECONDS = 60;
1426
1430
  var MIN_REFRESH_DELAY_MS = 5e3;
1427
1431
  var CSRF_HEADER = { "X-Foir-Session": "1" };
1428
1432
  function createFoirSessionClient(config) {
1429
- const sessionUrl = `${trimSlash(config.loginOrigin)}${config.sessionPath ?? DEFAULT_SESSION_PATH}`;
1430
- const logoutUrl = `${trimSlash(config.loginOrigin)}${config.logoutPath ?? DEFAULT_LOGOUT_PATH}`;
1433
+ const forApp = config.clientId ? `?client_id=${encodeURIComponent(config.clientId)}` : "";
1434
+ const sessionUrl = `${trimSlash(config.loginOrigin)}${config.sessionPath ?? DEFAULT_SESSION_PATH}${forApp}`;
1435
+ const logoutUrl = `${trimSlash(config.loginOrigin)}${config.logoutPath ?? DEFAULT_LOGOUT_PATH}${forApp}`;
1431
1436
  const skewMs = (config.refreshSkewSeconds ?? DEFAULT_REFRESH_SKEW_SECONDS) * 1e3;
1432
1437
  let cached = null;
1433
1438
  let inflight = null;
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * const events = createEventsClient({
9
9
  * apiUrl: process.env.PLATFORM_API_URL!,
10
- * apiKey: process.env.FOIR_SECRET_KEY!, // sk_…, holding events:read
10
+ * apiKey: process.env.FOIR_SECRET_KEY!, // an admin key, holding events:read
11
11
  * });
12
12
  *
13
13
  * const page = await events.list({ after: lastSeq, limit: 500 });
@@ -21,15 +21,15 @@
21
21
  * PROJECT SURFACE. Your app's users do not reach it.
22
22
  * ---------------------------------------------------------------------------
23
23
  *
24
- * DECIDED 2026-08-04. The event log is reachable by an `sk_` api key
24
+ * DECIDED 2026-08-04. The event log is reachable by an admin key
25
25
  * and by a console session. It is NOT reachable by a user token, there is no
26
- * user lane for it on api-public, and a `pk_` key can never be minted
26
+ * user lane for it on api-public, and a publishable key can never be minted
27
27
  * holding `events:read` at all.
28
28
  *
29
29
  * The reason is a predicate asymmetry rather than a policy preference.
30
30
  * `events.view` is plain tenant+project containment; `record.view` carries
31
- * owner, admin_owner, access_mode, grantee, comp_parent, read_borrow and
32
- * slice_parent terms on top of it. A containment-only read over the log
31
+ * ownership, access-mode, grantee, composition, read-borrow and slice terms
32
+ * on top of it. A containment-only read over the log
33
33
  * therefore describes rows whose underlying records the same caller could not
34
34
  * read — and every row carries `actor`, naming which OTHER user acted. In a
35
35
  * project with owner confinement that is a per-record activity feed of other
@@ -39,19 +39,19 @@
39
39
  *
40
40
  * 1. **It lives on `@foir/sdk/server` and nowhere else.** Not `./data`, not
41
41
  * `./client`, not `./react`. Those subpaths are the ones a storefront
42
- * bundles, and `./data` in particular is routinely constructed with a `pk_`
42
+ * bundles, and `./data` in particular is routinely constructed with a publishable key
43
43
  * key in browser-reachable code. `src/server/__tests__/events-client.test.ts`
44
44
  * walks the import graph of every published subpath and fails if this
45
45
  * module becomes reachable from one that ships to a browser — because
46
46
  * "we only documented it on the server" is not a property anything checks.
47
47
  *
48
- * 2. **A `pk_` key is refused at construction**, before a request is made. The
48
+ * 2. **A publishable key is refused at construction**, before a request is made. The
49
49
  * server would refuse it anyway (403), but a 403 at 3am in a deploy log is
50
50
  * a worse teacher than a thrown error naming the key type at the line that
51
51
  * built the client.
52
52
  *
53
53
  * 3. **There is no `bearerToken` option, and an `Authorization` header is
54
- * refused.** On api-public a request presenting `sk_` plus a user
54
+ * refused.** On api-public a request presenting an admin key plus a user
55
55
  * bearer resolves the USER as the authority, and `events` is stripped
56
56
  * from every user authority upstream — so attaching a signed-in
57
57
  * shopper's token to a project read turns a working call into a 403 that
@@ -77,7 +77,7 @@ import { type FoirReconnectPolicy, type FoirSubscription, type FoirSubscriptionH
77
77
  /** The path `GET /v1/events` is mounted on, inside api-public's api-key group. */
78
78
  export declare const FOIR_EVENTS_PATH = "/v1/events";
79
79
  /**
80
- * The scope an `sk_` key must hold. Never mintable on a `pk_` — `events` is
80
+ * The scope an admin key must hold. Never mintable on a publishable key: `events` is
81
81
  * absent from the platform's `publicSafeScopeResources` — and never present in a
82
82
  * user's resolved authority.
83
83
  */
@@ -7,7 +7,7 @@
7
7
  export interface ServerClientOptions {
8
8
  /** Base URL for the platform API (e.g., 'https://api.example.com'). */
9
9
  baseUrl: string;
10
- /** Project-scoped API key (sk_* format). */
10
+ /** A project's admin key (foir_adm_). */
11
11
  apiKey: string;
12
12
  /**
13
13
  * Optional config key. Retained for backwards compatibility with older