@foir/sdk 0.30.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The finishing halves of signing in, and of a person's own account steps,
3
+ * each on the data API's own route.
4
+ *
5
+ * A step is begun by an auth op (asking for a password reset, for one) and
6
+ * finished with the proof the person brings back: the token the reset link
7
+ * carried. The finish is no op of its own. The data API takes it on the step's
8
+ * route for somebody who holds no session yet, and the proof decides whose
9
+ * step it finishes, so it is sent with no key and no session.
10
+ */
11
+ import { type FoirEnv } from '../transport/foir-http';
12
+ /**
13
+ * A code sign-in begun: {@link requestOTP} and {@link signUpWithPassword} answer one.
14
+ * The code the address was sent is brought back to it with
15
+ * {@link signInWithOTP}. Every address is answered a step alike, so having one
16
+ * says nothing of whether the address is anybody's.
17
+ */
18
+ export interface FoirSignInStep {
19
+ id: string;
20
+ /** Minted for this step alone; it is the credential the code goes back with. */
21
+ token: string;
22
+ /** The step's own route. */
23
+ endpoint: string;
24
+ /** When the step, and its code, lapse (RFC 3339). */
25
+ expiresAt: string;
26
+ }
27
+ /**
28
+ * A change to the calling user's own account begun: {@link addMyAddress}
29
+ * answers one. What it asks for (the code the address was sent) is brought
30
+ * back to it with its token in the body, with {@link proveMyAddress}. It
31
+ * finishes once, for the person who began it, and not once the session that
32
+ * began it has ended.
33
+ */
34
+ export interface FoirAccountStep {
35
+ id: string;
36
+ /** Minted for this step alone; it goes back in the body. */
37
+ token: string;
38
+ /** The step's own route. */
39
+ endpoint: string;
40
+ /** When the step lapses (RFC 3339). */
41
+ expiresAt: string;
42
+ }
43
+ /**
44
+ * Posts a step's proof to its route and answers the step as the platform gave
45
+ * it, with the step's token where the step has one. A refusal is thrown as a
46
+ * {@link FoirRequestError} carrying the HTTP status and the same error code a
47
+ * GraphQL refusal carries, so `isFoirUnauthenticated` and the rest read it
48
+ * alike.
49
+ */
50
+ export declare function postSignInStep<T>(env: FoirEnv, path: `/v1/${string}`, body: Record<string, unknown>, stepToken?: string): Promise<T>;
@@ -1,13 +1,13 @@
1
1
  // src/auth/session-client.ts
2
2
  var DEFAULT_SESSION_PATH = "/session/token";
3
- var DEFAULT_LOGOUT_PATH = "/session/logout";
3
+ var DEFAULT_SIGN_OUT_PATH = "/session/logout";
4
4
  var DEFAULT_REFRESH_SKEW_SECONDS = 60;
5
5
  var MIN_REFRESH_DELAY_MS = 5e3;
6
6
  var CSRF_HEADER = { "X-Foir-Session": "1" };
7
7
  function createFoirSessionClient(config) {
8
8
  const forApp = config.clientId ? `?client_id=${encodeURIComponent(config.clientId)}` : "";
9
9
  const sessionUrl = `${trimSlash(config.loginOrigin)}${config.sessionPath ?? DEFAULT_SESSION_PATH}${forApp}`;
10
- const logoutUrl = `${trimSlash(config.loginOrigin)}${config.logoutPath ?? DEFAULT_LOGOUT_PATH}${forApp}`;
10
+ const signOutUrl = `${trimSlash(config.loginOrigin)}${config.signOutPath ?? DEFAULT_SIGN_OUT_PATH}${forApp}`;
11
11
  const skewMs = (config.refreshSkewSeconds ?? DEFAULT_REFRESH_SKEW_SECONDS) * 1e3;
12
12
  let cached = null;
13
13
  let inflight = null;
@@ -103,7 +103,7 @@ function createFoirSessionClient(config) {
103
103
  },
104
104
  async signOut() {
105
105
  try {
106
- await fetch(logoutUrl, {
106
+ await fetch(signOutUrl, {
107
107
  method: "POST",
108
108
  credentials: "include",
109
109
  headers: { ...CSRF_HEADER }
package/dist/auth.js CHANGED
@@ -37,6 +37,18 @@ var MALFORMED_PRUNE_REASONS = /* @__PURE__ */ new Set([
37
37
  "subselections_on_scalar",
38
38
  "missing_subselections"
39
39
  ]);
40
+ function stepUpRequired(error) {
41
+ if (!(error instanceof FoirRequestError)) return null;
42
+ for (const item of error.graphQLErrors ?? []) {
43
+ if (item.extensions?.code !== "STEP_UP_REQUIRED") continue;
44
+ const kind = item.extensions.stepUp;
45
+ if (kind === "proof" || kind === "second_factor" || kind === "sign_in_method") {
46
+ const url = item.extensions.stepUpUrl;
47
+ return { kind, url: typeof url === "string" && url !== "" ? url : null };
48
+ }
49
+ }
50
+ return null;
51
+ }
40
52
  var FoirRequestError = class extends Error {
41
53
  /** HTTP status code, when the request failed at the HTTP layer. */
42
54
  status;
@@ -1069,7 +1081,7 @@ async function fetchFoirManifest(config, options = {}) {
1069
1081
 
1070
1082
  // src/auth/ops.ts
1071
1083
  var AUTH_OPS = {
1072
- // Pre-credential reads a login screen renders itself from.
1084
+ // Pre-credential reads a sign-in screen renders itself from.
1073
1085
  authConfig: "authConfig",
1074
1086
  authProviders: "authProviders",
1075
1087
  defaultAuthProvider: "defaultAuthProvider",
@@ -1081,17 +1093,15 @@ var AUTH_OPS = {
1081
1093
  // they hold. `./access` reads it.
1082
1094
  whoami: "whoami",
1083
1095
  // Methods.
1084
- login: "login",
1096
+ signIn: "signIn",
1085
1097
  register: "register",
1086
1098
  requestOTP: "requestOTP",
1087
- loginWithOTP: "loginWithOTP",
1088
1099
  // Session lifecycle.
1089
1100
  refreshToken: "refreshToken",
1090
- logout: "logout",
1101
+ signOut: "signOut",
1091
1102
  joinWaitlist: "joinWaitlist",
1092
1103
  // Password management and account lifecycle.
1093
1104
  requestPasswordReset: "requestPasswordReset",
1094
- resetPassword: "resetPassword",
1095
1105
  updatePassword: "updatePassword",
1096
1106
  deleteMyAccount: "deleteMyAccount",
1097
1107
  // Ending their own membership where the request stands.
@@ -1105,10 +1115,10 @@ var AUTH_OPS = {
1105
1115
  mySessions: "mySessions",
1106
1116
  endMySession: "endMySession",
1107
1117
  signOutEverywhere: "signOutEverywhere",
1108
- // Their email addresses: one added is kept once the code it was sent proves it.
1118
+ // Their email addresses: one added is kept once the code it was sent comes
1119
+ // back on the step addMyAddress answers, on its own route (proveMyAddress).
1109
1120
  myAddresses: "myAddresses",
1110
1121
  addMyAddress: "addMyAddress",
1111
- proveMyAddress: "proveMyAddress",
1112
1122
  makeMyAddressPrimary: "makeMyAddressPrimary",
1113
1123
  removeMyAddress: "removeMyAddress",
1114
1124
  // A copy of their own data.
@@ -1119,10 +1129,8 @@ var AUTH_OPS = {
1119
1129
  disconnectSignInMethod: "disconnectSignInMethod",
1120
1130
  // Their second factors. A change needs one proven first, by a step-up.
1121
1131
  myFactors: "myFactors",
1122
- beginStepUp: "beginStepUp",
1123
- completeStepUp: "completeStepUp",
1132
+ stepUp: "stepUp",
1124
1133
  beginFactorEnrollment: "beginFactorEnrollment",
1125
- completeFactorEnrollment: "completeFactorEnrollment",
1126
1134
  removeFactor: "removeFactor",
1127
1135
  renameFactor: "renameFactor",
1128
1136
  makeRecoveryCodes: "makeRecoveryCodes",
@@ -1136,13 +1144,7 @@ var AUTH_OPS = {
1136
1144
  // Founding one. Present in a manifest only when the project opted in.
1137
1145
  registerOrganization: "registerOrganization",
1138
1146
  // External identity providers.
1139
- loginWithProvider: "loginWithProvider",
1140
- providerCallback: "providerCallback",
1141
- providerVerifyOTP: "providerVerifyOTP",
1142
- // A provider sign-in that names an address somebody already holds, waiting
1143
- // for the code sent to it.
1144
- confirmProviderLink: "confirmProviderLink",
1145
- resendProviderLinkCode: "resendProviderLinkCode"
1147
+ signInWithProvider: "signInWithProvider"
1146
1148
  };
1147
1149
  function authClientConfig(env, options) {
1148
1150
  const apiKey = resolveFoirApiKey(env);
@@ -1202,34 +1204,94 @@ function stripUndefined(args) {
1202
1204
  return out;
1203
1205
  }
1204
1206
 
1207
+ // src/auth/steps.ts
1208
+ async function postSignInStep(env, path, body, stepToken) {
1209
+ const apiUrl = env.PLATFORM_API_URL;
1210
+ if (!apiUrl) {
1211
+ throw new FoirRequestError("[foir] no api url configured: set PLATFORM_API_URL");
1212
+ }
1213
+ const headers = { "Content-Type": "application/json" };
1214
+ if (stepToken) headers["X-Foir-Token"] = stepToken;
1215
+ const res = await fetch(foirApiEndpoint(apiUrl, path), {
1216
+ method: "POST",
1217
+ headers,
1218
+ body: JSON.stringify(body)
1219
+ });
1220
+ const data = await res.json().catch(() => ({}));
1221
+ if (!res.ok) {
1222
+ const message = typeof data.error === "string" ? data.error : `[foir] POST ${path} failed: HTTP ${res.status}`;
1223
+ const code = typeof data.code === "string" ? data.code : void 0;
1224
+ const extensions = {};
1225
+ if (code) extensions.code = code;
1226
+ if (data.signIn && typeof data.signIn === "object") extensions.signIn = data.signIn;
1227
+ if (data.providerSignIn && typeof data.providerSignIn === "object") extensions.providerSignIn = data.providerSignIn;
1228
+ throw new FoirRequestError(message, {
1229
+ status: res.status,
1230
+ graphQLErrors: Object.keys(extensions).length > 0 ? [{ message, extensions }] : void 0
1231
+ });
1232
+ }
1233
+ return data;
1234
+ }
1235
+
1205
1236
  // src/auth/auth.ts
1206
1237
  var TOKEN_KEY = "foir:token";
1207
1238
  var REFRESH_KEY = "foir:refreshToken";
1208
1239
  var USER_ID_KEY = "foir:userId";
1209
1240
  var EMAIL_KEY = "foir:email";
1210
- async function login(env, vars) {
1211
- return authOp(env, AUTH_OPS.login, vars);
1212
- }
1213
- async function register(env, vars) {
1214
- return authOp(env, AUTH_OPS.register, vars);
1215
- }
1216
1241
  async function requestOTP(env, email) {
1217
1242
  return authOp(env, AUTH_OPS.requestOTP, { email });
1218
1243
  }
1219
- async function loginWithOTP(env, vars) {
1220
- return authOp(env, AUTH_OPS.loginWithOTP, vars);
1244
+ async function codeSignIn(env, vars) {
1245
+ const signedIn = await postSignInStep(env, `/v1/sign-ins/${encodeURIComponent(vars.step.id)}/code`, { code: vars.otp }, vars.step.token);
1246
+ return {
1247
+ token: signedIn.accessToken ?? "",
1248
+ refreshToken: signedIn.refreshToken ?? "",
1249
+ userId: signedIn.user?.id ?? "",
1250
+ email: signedIn.user?.email ?? ""
1251
+ };
1221
1252
  }
1222
- async function refreshTokens(env, refreshToken) {
1253
+ async function rotateTokens(env, refreshToken) {
1223
1254
  return authOp(env, AUTH_OPS.refreshToken, { refreshToken });
1224
1255
  }
1225
- async function loginWithProvider(env, input) {
1226
- return authOp(env, AUTH_OPS.loginWithProvider, { input });
1256
+ async function signInWithProvider(adapter, env, input) {
1257
+ const started = await authOp(
1258
+ env,
1259
+ AUTH_OPS.signInWithProvider,
1260
+ { input }
1261
+ );
1262
+ if (started.step) await adapter.set(PROVIDER_STEP_KEY, JSON.stringify(started.step));
1263
+ else await adapter.unset(PROVIDER_STEP_KEY);
1264
+ return { redirectUrl: started.redirectUrl ?? null };
1265
+ }
1266
+ async function finishProviderSignIn(adapter, env, input) {
1267
+ const step = await keptProviderStep(adapter, "no provider sign-in was started here: start one before finishing it");
1268
+ return signedInOnStep(adapter, env, step, "provider", {
1269
+ providerKey: input.providerKey,
1270
+ code: input.code,
1271
+ state: input.state
1272
+ });
1227
1273
  }
1228
- async function providerCallback(env, input) {
1229
- return authOp(env, AUTH_OPS.providerCallback, { input });
1274
+ var PROVIDER_STEP_KEY = "foir:providerStep";
1275
+ async function keptProviderStep(adapter, missing) {
1276
+ const raw = await adapter.get(PROVIDER_STEP_KEY);
1277
+ if (raw) {
1278
+ try {
1279
+ const step = JSON.parse(raw);
1280
+ if (typeof step.id === "string" && typeof step.token === "string") return step;
1281
+ } catch {
1282
+ }
1283
+ }
1284
+ throw new Error(`[foir] ${missing}`);
1230
1285
  }
1231
- async function providerVerifyOTP(env, input) {
1232
- return authOp(env, AUTH_OPS.providerVerifyOTP, { input });
1286
+ async function signedInOnStep(adapter, env, step, route, body) {
1287
+ const signedIn = await postSignInStep(env, `/v1/sign-ins/${encodeURIComponent(step.id)}/${route}`, body, step.token);
1288
+ await adapter.unset(PROVIDER_STEP_KEY);
1289
+ return saveSession(adapter, {
1290
+ token: signedIn.accessToken ?? "",
1291
+ refreshToken: signedIn.refreshToken ?? "",
1292
+ userId: signedIn.userId ?? "",
1293
+ email: signedIn.email ?? ""
1294
+ });
1233
1295
  }
1234
1296
  function providerSignInRefusalOf(error) {
1235
1297
  if (!(error instanceof FoirRequestError)) return null;
@@ -1252,11 +1314,19 @@ function signInRefusalOf(error) {
1252
1314
  }
1253
1315
  return null;
1254
1316
  }
1255
- async function confirmProviderLink(env, input) {
1256
- return authOp(env, AUTH_OPS.confirmProviderLink, { input });
1317
+ async function confirmProviderLink(adapter, env, input) {
1318
+ const step = await keptProviderStep(adapter, "no provider sign-in is waiting for a code here");
1319
+ return signedInOnStep(adapter, env, step, "link", { pending: input.pending, code: input.code });
1257
1320
  }
1258
- async function resendProviderLinkCode(env, input) {
1259
- return authOp(env, AUTH_OPS.resendProviderLinkCode, { input });
1321
+ async function resendProviderLinkCode(adapter, env, input) {
1322
+ const step = await keptProviderStep(adapter, "no provider sign-in is waiting for a code here");
1323
+ const resent = await postSignInStep(
1324
+ env,
1325
+ `/v1/sign-ins/${encodeURIComponent(step.id)}/link/resend`,
1326
+ { pending: input.pending },
1327
+ step.token
1328
+ );
1329
+ return { pending: resent.pending ?? "" };
1260
1330
  }
1261
1331
  async function getAuthProviders(env) {
1262
1332
  return authOp(env, AUTH_OPS.authProviders);
@@ -1276,8 +1346,14 @@ async function joinWaitlist(env, email) {
1276
1346
  async function requestPasswordReset(env, email, options) {
1277
1347
  return authOp(env, AUTH_OPS.requestPasswordReset, { email, clientId: options?.clientId });
1278
1348
  }
1279
- async function resetPassword(env, vars) {
1280
- return authOp(env, AUTH_OPS.resetPassword, vars);
1349
+ async function redeemPasswordReset(env, vars) {
1350
+ const reset = await postSignInStep(env, "/v1/password-resets/redeem", { token: vars.token, newPassword: vars.newPassword });
1351
+ return {
1352
+ token: reset.accessToken ?? "",
1353
+ refreshToken: reset.refreshToken ?? "",
1354
+ userId: reset.user?.id ?? "",
1355
+ email: reset.user?.email ?? ""
1356
+ };
1281
1357
  }
1282
1358
  async function updatePassword(env, vars, options) {
1283
1359
  return authOp(env, AUTH_OPS.updatePassword, vars, options);
@@ -1290,8 +1366,8 @@ async function myProviderToken(env, providerKey, options) {
1290
1366
  const vars = forceRefresh ? { providerKey, forceRefresh: true } : { providerKey };
1291
1367
  return authOp(env, AUTH_OPS.myProviderToken, vars, rest);
1292
1368
  }
1293
- async function logout(env, options) {
1294
- return authOp(env, AUTH_OPS.logout, void 0, options);
1369
+ async function endSignIn(env, options) {
1370
+ return authOp(env, AUTH_OPS.signOut, void 0, options);
1295
1371
  }
1296
1372
  async function deleteMyAccount(env, vars, options) {
1297
1373
  return authOp(env, AUTH_OPS.deleteMyAccount, vars, options);
@@ -1326,8 +1402,14 @@ async function myAddresses(env, options) {
1326
1402
  async function addMyAddress(env, vars, options) {
1327
1403
  return authOp(env, AUTH_OPS.addMyAddress, vars, options);
1328
1404
  }
1329
- async function proveMyAddress(env, vars, options) {
1330
- return authOp(env, AUTH_OPS.proveMyAddress, vars, options);
1405
+ async function proveMyAddress(env, vars) {
1406
+ const kept = await postSignInStep(env, `/v1/address-proofs/${encodeURIComponent(vars.step.id)}`, { token: vars.step.token, code: vars.code });
1407
+ return {
1408
+ email: kept.address?.email ?? "",
1409
+ primary: kept.address?.primary ?? false,
1410
+ proven: kept.address?.proven ?? false,
1411
+ addedAt: kept.address?.addedAt ?? null
1412
+ };
1331
1413
  }
1332
1414
  async function makeMyAddressPrimary(env, email, options) {
1333
1415
  return authOp(env, AUTH_OPS.makeMyAddressPrimary, { email }, options);
@@ -1350,17 +1432,24 @@ async function disconnectSignInMethod(env, provider, options) {
1350
1432
  async function myFactors(env, options) {
1351
1433
  return authOp(env, AUTH_OPS.myFactors, void 0, options);
1352
1434
  }
1353
- async function beginStepUp(env, password, options) {
1354
- return authOp(env, AUTH_OPS.beginStepUp, { password }, options);
1355
- }
1356
- async function completeStepUp(env, vars, options) {
1357
- return authOp(env, AUTH_OPS.completeStepUp, vars, options);
1435
+ async function stepUp(env, options) {
1436
+ return authOp(env, AUTH_OPS.stepUp, void 0, options);
1358
1437
  }
1359
1438
  async function beginFactorEnrollment(env, vars, options) {
1360
1439
  return authOp(env, AUTH_OPS.beginFactorEnrollment, vars, options);
1361
1440
  }
1362
- async function completeFactorEnrollment(env, vars, options) {
1363
- return authOp(env, AUTH_OPS.completeFactorEnrollment, vars, options);
1441
+ async function completeFactorEnrollment(env, vars) {
1442
+ const done = await postSignInStep(
1443
+ env,
1444
+ `/v1/factor-enrollments/${encodeURIComponent(vars.step.id)}`,
1445
+ {
1446
+ token: vars.step.token,
1447
+ webauthnAttestationJson: vars.webauthnAttestationJson,
1448
+ totpCode: vars.totpCode,
1449
+ displayName: vars.name
1450
+ }
1451
+ );
1452
+ return done.enrolled === true;
1364
1453
  }
1365
1454
  async function removeFactor(env, vars, options) {
1366
1455
  return authOp(env, AUTH_OPS.removeFactor, vars, options);
@@ -1368,8 +1457,8 @@ async function removeFactor(env, vars, options) {
1368
1457
  async function renameFactor(env, vars, options) {
1369
1458
  return authOp(env, AUTH_OPS.renameFactor, vars, options);
1370
1459
  }
1371
- async function makeRecoveryCodes(env, elevatedHandle, options) {
1372
- return authOp(env, AUTH_OPS.makeRecoveryCodes, { elevatedHandle }, options);
1460
+ async function makeRecoveryCodes(env, options) {
1461
+ return authOp(env, AUTH_OPS.makeRecoveryCodes, void 0, options);
1373
1462
  }
1374
1463
  async function myOrganizations(env, vars, options) {
1375
1464
  return authOp(env, AUTH_OPS.myOrganizations, vars ?? {}, options);
@@ -1406,16 +1495,16 @@ async function getSessionUser(adapter) {
1406
1495
  return { id, email: email ?? "" };
1407
1496
  }
1408
1497
  async function signInWithPassword(adapter, env, vars) {
1409
- return saveSession(adapter, await login(env, vars));
1498
+ return saveSession(adapter, await authOp(env, AUTH_OPS.signIn, vars));
1410
1499
  }
1411
1500
  async function signUpWithPassword(env, vars) {
1412
- await register(env, vars);
1501
+ return authOp(env, AUTH_OPS.register, vars);
1413
1502
  }
1414
1503
  async function signInWithOTP(adapter, env, vars) {
1415
- return saveSession(adapter, await loginWithOTP(env, vars));
1504
+ return saveSession(adapter, await codeSignIn(env, vars));
1416
1505
  }
1417
1506
  async function resetPasswordAndSignIn(adapter, env, vars) {
1418
- return saveSession(adapter, await resetPassword(env, vars));
1507
+ return saveSession(adapter, await redeemPasswordReset(env, vars));
1419
1508
  }
1420
1509
  async function deleteMyAccountAndSignOut(adapter, env, vars) {
1421
1510
  const result = await authedOp(adapter, env, AUTH_OPS.deleteMyAccount, vars);
@@ -1426,7 +1515,7 @@ async function signOut(adapter, env) {
1426
1515
  const token = await getSessionToken(adapter);
1427
1516
  if (token) {
1428
1517
  try {
1429
- await logout(env, { bearerToken: token });
1518
+ await endSignIn(env, { bearerToken: token });
1430
1519
  } catch {
1431
1520
  }
1432
1521
  }
@@ -1436,7 +1525,7 @@ async function refreshSession(adapter, env) {
1436
1525
  const refreshToken = await adapter.get(REFRESH_KEY) ?? null;
1437
1526
  if (!refreshToken) return null;
1438
1527
  try {
1439
- const result = await refreshTokens(env, refreshToken);
1528
+ const result = await rotateTokens(env, refreshToken);
1440
1529
  await saveSession(adapter, result);
1441
1530
  return { token: result.token, refreshToken: result.refreshToken };
1442
1531
  } catch {
@@ -1816,7 +1905,7 @@ async function requireScope(adapter, env, scope) {
1816
1905
  var DEFAULT_COOKIE_NAME = "foir_session";
1817
1906
  var DEFAULT_SESSION_PATH = "/session/token";
1818
1907
  var DEFAULT_END_SESSION_PATH = "/session/end-session";
1819
- function hostedLoginUrl(config, returnTo, options = {}) {
1908
+ function hostedSignInUrl(config, returnTo, options = {}) {
1820
1909
  const dest = new URL(config.loginOrigin);
1821
1910
  if (options.signUp) {
1822
1911
  dest.pathname = `${dest.pathname.replace(/\/+$/, "")}/signup`;
@@ -1829,7 +1918,7 @@ function hostedLoginUrl(config, returnTo, options = {}) {
1829
1918
  }
1830
1919
  return dest.toString();
1831
1920
  }
1832
- function hostedLogoutUrl(config, clientId, returnTo) {
1921
+ function hostedSignOutUrl(config, clientId, returnTo) {
1833
1922
  const path = config.endSessionPath ?? DEFAULT_END_SESSION_PATH;
1834
1923
  const dest = new URL(path, config.loginOrigin);
1835
1924
  dest.searchParams.set("client_id", clientId);
@@ -2092,14 +2181,14 @@ async function completeSignIn(config, callback, pending) {
2092
2181
 
2093
2182
  // src/auth/session-client.ts
2094
2183
  var DEFAULT_SESSION_PATH2 = "/session/token";
2095
- var DEFAULT_LOGOUT_PATH = "/session/logout";
2184
+ var DEFAULT_SIGN_OUT_PATH = "/session/logout";
2096
2185
  var DEFAULT_REFRESH_SKEW_SECONDS = 60;
2097
2186
  var MIN_REFRESH_DELAY_MS = 5e3;
2098
2187
  var CSRF_HEADER = { "X-Foir-Session": "1" };
2099
2188
  function createFoirSessionClient(config) {
2100
2189
  const forApp2 = config.clientId ? `?client_id=${encodeURIComponent(config.clientId)}` : "";
2101
2190
  const sessionUrl = `${trimSlash2(config.loginOrigin)}${config.sessionPath ?? DEFAULT_SESSION_PATH2}${forApp2}`;
2102
- const logoutUrl = `${trimSlash2(config.loginOrigin)}${config.logoutPath ?? DEFAULT_LOGOUT_PATH}${forApp2}`;
2191
+ const signOutUrl = `${trimSlash2(config.loginOrigin)}${config.signOutPath ?? DEFAULT_SIGN_OUT_PATH}${forApp2}`;
2103
2192
  const skewMs = (config.refreshSkewSeconds ?? DEFAULT_REFRESH_SKEW_SECONDS) * 1e3;
2104
2193
  let cached = null;
2105
2194
  let inflight = null;
@@ -2195,7 +2284,7 @@ function createFoirSessionClient(config) {
2195
2284
  },
2196
2285
  async signOut() {
2197
2286
  try {
2198
- await fetch(logoutUrl, {
2287
+ await fetch(signOutUrl, {
2199
2288
  method: "POST",
2200
2289
  credentials: "include",
2201
2290
  headers: { ...CSRF_HEADER }
@@ -2237,11 +2326,9 @@ export {
2237
2326
  authedRequest,
2238
2327
  beginFactorEnrollment,
2239
2328
  beginSignIn,
2240
- beginStepUp,
2241
2329
  clearSession,
2242
2330
  completeFactorEnrollment,
2243
2331
  completeSignIn,
2244
- completeStepUp,
2245
2332
  confirmProviderLink,
2246
2333
  connectSignInMethod,
2247
2334
  createFoirSessionClient,
@@ -2253,6 +2340,7 @@ export {
2253
2340
  endMySession,
2254
2341
  exportMyData,
2255
2342
  fetchHostedSession,
2343
+ finishProviderSignIn,
2256
2344
  getAuthConfig,
2257
2345
  getAuthProviders,
2258
2346
  getDefaultAuthProvider,
@@ -2261,15 +2349,11 @@ export {
2261
2349
  getSessionUser,
2262
2350
  hasRole,
2263
2351
  hasScope,
2264
- hostedLoginUrl,
2265
- hostedLogoutUrl,
2266
2352
  hostedSignInNoticeOf,
2353
+ hostedSignInUrl,
2354
+ hostedSignOutUrl,
2267
2355
  joinWaitlist,
2268
2356
  leaveMembership,
2269
- login,
2270
- loginWithOTP,
2271
- loginWithProvider,
2272
- logout,
2273
2357
  makeMyAddressPrimary,
2274
2358
  makeRecoveryCodes,
2275
2359
  myAddresses,
@@ -2281,13 +2365,9 @@ export {
2281
2365
  mySessions,
2282
2366
  mySignInMethods,
2283
2367
  proveMyAddress,
2284
- providerCallback,
2285
2368
  providerSignInRefusalOf,
2286
- providerVerifyOTP,
2287
2369
  refreshSession,
2288
2370
  refreshSessionOnce,
2289
- refreshTokens,
2290
- register,
2291
2371
  registerOrganization,
2292
2372
  removeFactor,
2293
2373
  removeMyAddress,
@@ -2298,17 +2378,19 @@ export {
2298
2378
  requireRole,
2299
2379
  requireScope,
2300
2380
  resendProviderLinkCode,
2301
- resetPassword,
2302
2381
  resetPasswordAndSignIn,
2303
2382
  revokeAuthorizedApp,
2304
2383
  saveSession,
2305
2384
  signInRefusalOf,
2306
2385
  signInWithOTP,
2307
2386
  signInWithPassword,
2387
+ signInWithProvider,
2308
2388
  signOut,
2309
2389
  signOutEverywhere,
2310
2390
  signUpWithPassword,
2311
2391
  signupContext,
2392
+ stepUp,
2393
+ stepUpRequired,
2312
2394
  updateMyProfile,
2313
2395
  updatePassword,
2314
2396
  userAccess
@@ -4,7 +4,7 @@
4
4
  * It does NOT know any concrete item types. Given a registry that maps each
5
5
  * entry `__typename` to a component, it renders a prose flow's entries (or a
6
6
  * plain item array): looks each entry up by `__typename`, renders unknown
7
- * types as null, keys by the entry `_key`/`_id` where one is present, assigns
7
+ * types as null, keys by the entry `_id` where one is present, assigns
8
8
  * LCP `priority` to the first entry that actually renders, and threads a
9
9
  * consumer-defined `Ctx` to every component.
10
10
  *
@@ -31,8 +31,8 @@ import { type PassageLike } from './richtext';
31
31
  /** Minimal shape every entry in a prose flow carries. */
32
32
  export interface ItemLike {
33
33
  __typename: string;
34
+ /** The entry's own id. */
34
35
  _id?: string | null;
35
- _key?: string | null;
36
36
  }
37
37
  /** Props an item component receives from the content renderer. */
38
38
  export interface ItemComponentProps<TItem, TCtx = unknown> {
@@ -17,7 +17,7 @@
17
17
  * - `list` + `level` flatten list membership onto the passage; consecutive
18
18
  * list passages regroup into <ul>/<ol> with nesting rebuilt from `level`.
19
19
  * - Span marks are the eight decorations (bold, italic, underline,
20
- * strikethrough, code, subscript, superscript, highlight) or the `_key`
20
+ * strikethrough, code, subscript, superscript, highlight) or the `_id`
21
21
  * of a markDef on the same passage (links, scheme-checked through
22
22
  * `safeHref`).
23
23
  * - A soft line break is `"\n"` inside a span's text.
@@ -64,7 +64,7 @@ export interface ProseSpanLike {
64
64
  export interface PassageLike {
65
65
  __typename?: string;
66
66
  _type?: string;
67
- _key?: string | null;
67
+ _id?: string | null;
68
68
  kind?: string | null;
69
69
  token?: string | null;
70
70
  align?: string | null;
package/dist/content.js CHANGED
@@ -108,12 +108,12 @@ function PassageList({
108
108
  level: minLevel(run),
109
109
  tokens: tokenMap
110
110
  },
111
- run[0]._key ?? `list-${out.length}`
111
+ run[0]._id ?? `list-${out.length}`
112
112
  )
113
113
  );
114
114
  continue;
115
115
  }
116
- out.push(renderPassage(passage, passage._key ?? i, tokenMap, fallbackTag));
116
+ out.push(renderPassage(passage, passage._id ?? i, tokenMap, fallbackTag));
117
117
  i++;
118
118
  }
119
119
  return /* @__PURE__ */ jsx(Fragment, { children: out });
@@ -144,7 +144,7 @@ function ListRun({
144
144
  prev.nested = nested;
145
145
  } else {
146
146
  items.push({
147
- key: deep[0]._key ?? `d${items.length}`,
147
+ key: deep[0]._id ?? `d${items.length}`,
148
148
  content: null,
149
149
  nested,
150
150
  type: deep[0].list ?? "bullet"
@@ -154,7 +154,7 @@ function ListRun({
154
154
  }
155
155
  const token = passage.token ? tokens.get(passage.token) ?? null : null;
156
156
  items.push({
157
- key: passage._key ?? `li${items.length}`,
157
+ key: passage._id ?? `li${items.length}`,
158
158
  content: /* @__PURE__ */ jsx("span", { style: tokenToCss(token, passage.align), children: renderSpans(passage) }),
159
159
  nested: null,
160
160
  type: passage.list ?? "bullet"
@@ -216,7 +216,7 @@ function renderSpan(span, key, markDefs) {
216
216
  el = createElement(decorationTag, null, el);
217
217
  continue;
218
218
  }
219
- const def = markDefs.find((d) => d._key === mark);
219
+ const def = markDefs.find((d) => d._id === mark);
220
220
  if (def?.type === "link" && def.href) link = def;
221
221
  }
222
222
  if (link?.href) {
@@ -273,7 +273,7 @@ function createContentRenderer(registry, options) {
273
273
  const priority = !priorityAssigned;
274
274
  priorityAssigned = true;
275
275
  out.push(
276
- /* @__PURE__ */ jsx2(Fragment2, { children: /* @__PURE__ */ jsx2(PassageRun, { passages: run, ctx, priority }) }, run[0]._key ?? `run-${out.length}`)
276
+ /* @__PURE__ */ jsx2(Fragment2, { children: /* @__PURE__ */ jsx2(PassageRun, { passages: run, ctx, priority }) }, run[0]._id ?? `run-${out.length}`)
277
277
  );
278
278
  run = [];
279
279
  };
@@ -289,7 +289,7 @@ function createContentRenderer(registry, options) {
289
289
  const priority = !priorityAssigned;
290
290
  priorityAssigned = true;
291
291
  out.push(
292
- /* @__PURE__ */ jsx2(Fragment2, { children: /* @__PURE__ */ jsx2(Component, { item, block: item, ctx, priority }) }, item._key ?? item._id ?? i)
292
+ /* @__PURE__ */ jsx2(Fragment2, { children: /* @__PURE__ */ jsx2(Component, { item, block: item, ctx, priority }) }, item._id ?? i)
293
293
  );
294
294
  });
295
295
  flushRun();