@foir/sdk 0.23.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.
@@ -10,7 +10,7 @@
10
10
  * the caller's own manifest advertises, through the same op transport
11
11
  * `@foir/sdk/data` uses, so `graphql` is not on this module's path at all.
12
12
  */
13
- export { login, register, requestOTP, loginWithOTP, refreshTokens, loginWithProvider, providerCallback, providerVerifyOTP, providerSignInRefusalOf, signInRefusalOf, confirmProviderLink, resendProviderLinkCode, getAuthProviders, getAuthConfig, getDefaultAuthProvider, signupContext, joinWaitlist, requestPasswordReset, resetPassword, updatePassword, verifyEmail, currentUser, myProviderToken, logout, deleteMyAccount, updateMyProfile, myAuthorizedApps, revokeAuthorizedApp, mySessions, endMySession, signOutEverywhere, createPersonalAccessToken, mySignInMethods, connectSignInMethod, disconnectSignInMethod, myFactors, beginStepUp, completeStepUp, beginFactorEnrollment, completeFactorEnrollment, removeFactor, makeRecoveryCodes, myOrganizations, registerOrganization, saveSession, clearSession, getSessionToken, getSessionUser, signInWithPassword, signUpWithPassword, signInWithOTP, resetPasswordAndSignIn, refreshSession, refreshSessionOnce, signOut, authedRequest, authedOp, requireAuth, } from './auth';
13
+ export { login, register, requestOTP, loginWithOTP, refreshTokens, loginWithProvider, providerCallback, providerVerifyOTP, providerSignInRefusalOf, signInRefusalOf, confirmProviderLink, resendProviderLinkCode, getAuthProviders, getAuthConfig, getDefaultAuthProvider, signupContext, joinWaitlist, requestPasswordReset, resetPassword, updatePassword, currentUser, myProviderToken, logout, deleteMyAccount, updateMyProfile, myAuthorizedApps, revokeAuthorizedApp, mySessions, endMySession, signOutEverywhere, createPersonalAccessToken, mySignInMethods, connectSignInMethod, disconnectSignInMethod, myFactors, beginStepUp, completeStepUp, beginFactorEnrollment, completeFactorEnrollment, removeFactor, makeRecoveryCodes, myOrganizations, registerOrganization, saveSession, clearSession, getSessionToken, getSessionUser, signInWithPassword, signUpWithPassword, signInWithOTP, resetPasswordAndSignIn, refreshSession, refreshSessionOnce, signOut, authedRequest, authedOp, requireAuth, } from './auth';
14
14
  export type { FoirAuthTokens, FoirUser, SessionAdapter, RequireAuthOptions, } from './auth';
15
15
  export { userAccess, getSessionAccess, hasRole, hasScope, requireRole, requireScope, FoirAccessDeniedError, } from './access';
16
16
  export type { FoirAccess, FoirAccessDenial } from './access';
@@ -21,4 +21,4 @@ export { hostedLoginUrl, hostedLogoutUrl, fetchHostedSession, hostedSignInNotice
21
21
  export type { HostedLoginConfig, HostedSession, HostedSessionResult, HostedSignInNotice } from './hosted';
22
22
  export { createFoirSessionClient } from './session-client';
23
23
  export type { FoirSessionClient, FoirSessionConfig, FoirSessionUser, } from './session-client';
24
- export type { AuthResult, ProviderLoginResult, AuthProviderPublic, ProviderLoginInput, ProviderCallbackInput, ProviderOTPVerifyInput, SignupContext, SignupMode, WaitlistJoinResult, AuthConfig, AuthConfigProvider, DefaultAuthProvider, CurrentUser, ProviderToken, ProviderTokenRefresh, DeleteAccountResult, MyOrganization, MyProfile, MyProfileChange, AuthorizedApp, MySession, NewPersonalAccessToken, MySignInMethod, MyFactor, StepUp, FactorEnrollment, } from './operations';
24
+ export type { AuthResult, ProviderLoginResult, AuthProviderPublic, ProviderLoginInput, ProviderCallbackInput, ProviderOTPVerifyInput, SignupContext, SignupMode, AuthConfig, AuthConfigProvider, DefaultAuthProvider, CurrentUser, ProviderToken, ProviderTokenRefresh, DeleteAccountResult, MyOrganization, MyProfile, MyProfileChange, AuthorizedApp, MySession, NewPersonalAccessToken, MySignInMethod, MyFactor, StepUp, FactorEnrollment, } from './operations';
@@ -76,13 +76,6 @@ export type SignupMode = 'PUBLIC' | 'RESTRICTED' | 'WAITLIST' | 'CLOSED';
76
76
  export interface SignupContext {
77
77
  signupMode: SignupMode;
78
78
  }
79
- /** The queued (or existing pending) entry a waitlist join returns. */
80
- export interface WaitlistJoinResult {
81
- id: string;
82
- email: string;
83
- /** Waitlist lifecycle status; PENDING on a fresh join. */
84
- status: string;
85
- }
86
79
  /** One provider as it appears inside {@link AuthConfig}. */
87
80
  export interface AuthConfigProvider {
88
81
  key: string;
@@ -126,13 +119,15 @@ export interface CurrentUser {
126
119
  /** What a provider token read did about the token's freshness. */
127
120
  export type ProviderTokenRefresh = 'NOT_ATTEMPTED' | 'REFRESHED' | 'FAILED' | 'HELD_BACK';
128
121
  /**
129
- * A stored upstream provider token for the calling user. `myProviderToken`
130
- * answers `null` when there is no user token on the request, and
131
- * `linked: false` when the user has none stored for that provider.
122
+ * The token of the provider the calling user signed in through. It belongs to
123
+ * the sign-in that obtained it: a sign-in on another device keeps its own, and
124
+ * signing out ends it. `myProviderToken` answers `null` when there is no user
125
+ * token on the request, and `linked: false` with `reauthenticate: true` when
126
+ * nothing is kept for this sign-in.
132
127
  */
133
128
  export interface ProviderToken {
134
129
  providerKey: string;
135
- /** False when the user has no token for the provider; every token field is then null. */
130
+ /** False when nothing is kept for the sign-in the request belongs to; every token field is then null. */
136
131
  linked: boolean;
137
132
  accessToken: string | null;
138
133
  refreshToken: string | null;
@@ -148,7 +143,11 @@ export interface ProviderToken {
148
143
  refresh: ProviderTokenRefresh | null;
149
144
  /** Where a failed refresh failed, such as `"refresh grant"`. */
150
145
  refreshFailure: string | null;
151
- /** Only the user signing in with the provider again mends the connection. */
146
+ /**
147
+ * Only the user signing in with the provider again mends the connection:
148
+ * nothing is kept for this sign-in, or the provider will not renew it. Show
149
+ * them the way to sign in through the provider, not an empty page.
150
+ */
152
151
  reauthenticate: boolean;
153
152
  }
154
153
  /** What a self-serve account deletion removed. */
@@ -55,7 +55,6 @@ export declare const AUTH_OPS: {
55
55
  readonly requestPasswordReset: "requestPasswordReset";
56
56
  readonly resetPassword: "resetPassword";
57
57
  readonly updatePassword: "updatePassword";
58
- readonly verifyEmail: "verifyEmail";
59
58
  readonly deleteMyAccount: "deleteMyAccount";
60
59
  readonly updateMyProfile: "updateMyProfile";
61
60
  readonly myAuthorizedApps: "myAuthorizedApps";
@@ -37,6 +37,11 @@ export interface FoirSessionConfig {
37
37
  sessionPath?: string;
38
38
  /** Logout path. Default `/session/logout`. */
39
39
  logoutPath?: string;
40
+ /**
41
+ * The app the bearer is for, when it is not the app the login domain fronts.
42
+ * Default: the domain's own app.
43
+ */
44
+ clientId?: string;
40
45
  /** Seconds before expiry to re-exchange. Default 60. */
41
46
  refreshSkewSeconds?: number;
42
47
  /**
@@ -5,8 +5,9 @@ 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
- const sessionUrl = `${trimSlash(config.loginOrigin)}${config.sessionPath ?? DEFAULT_SESSION_PATH}`;
9
- const logoutUrl = `${trimSlash(config.loginOrigin)}${config.logoutPath ?? DEFAULT_LOGOUT_PATH}`;
8
+ const forApp = config.clientId ? `?client_id=${encodeURIComponent(config.clientId)}` : "";
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
11
  const skewMs = (config.refreshSkewSeconds ?? DEFAULT_REFRESH_SKEW_SECONDS) * 1e3;
11
12
  let cached = null;
12
13
  let inflight = null;
package/dist/auth.js CHANGED
@@ -1093,7 +1093,6 @@ var AUTH_OPS = {
1093
1093
  requestPasswordReset: "requestPasswordReset",
1094
1094
  resetPassword: "resetPassword",
1095
1095
  updatePassword: "updatePassword",
1096
- verifyEmail: "verifyEmail",
1097
1096
  deleteMyAccount: "deleteMyAccount",
1098
1097
  // The user's own profile, and the apps they have agreed may act for them.
1099
1098
  updateMyProfile: "updateMyProfile",
@@ -1266,9 +1265,6 @@ async function requestPasswordReset(env, email, options) {
1266
1265
  async function resetPassword(env, vars) {
1267
1266
  return authOp(env, AUTH_OPS.resetPassword, vars);
1268
1267
  }
1269
- async function verifyEmail(env, token) {
1270
- return authOp(env, AUTH_OPS.verifyEmail, { token });
1271
- }
1272
1268
  async function updatePassword(env, vars, options) {
1273
1269
  return authOp(env, AUTH_OPS.updatePassword, vars, options);
1274
1270
  }
@@ -1792,7 +1788,7 @@ async function fetchHostedSession(request, config) {
1792
1788
  if (!match) return { outcome: "signed-out", reason: "no-cookie" };
1793
1789
  let res;
1794
1790
  try {
1795
- res = await fetch(`${config.loginOrigin}${sessionPath}`, {
1791
+ res = await fetch(`${config.loginOrigin}${sessionPath}${forApp(config.clientId)}`, {
1796
1792
  headers: {
1797
1793
  Cookie: `${cookieName}=${match[1]}`,
1798
1794
  "X-Foir-Session": "1"
@@ -1867,6 +1863,9 @@ var REFUSAL_MESSAGES = {
1867
1863
  function refusalMessage(code) {
1868
1864
  return REFUSAL_MESSAGES[code] ?? "The sign-in couldn\u2019t be finished. Try again.";
1869
1865
  }
1866
+ function forApp(clientId) {
1867
+ return clientId ? `?client_id=${encodeURIComponent(clientId)}` : "";
1868
+ }
1870
1869
 
1871
1870
  // src/auth/session-client.ts
1872
1871
  var DEFAULT_SESSION_PATH2 = "/session/token";
@@ -1875,8 +1874,9 @@ var DEFAULT_REFRESH_SKEW_SECONDS = 60;
1875
1874
  var MIN_REFRESH_DELAY_MS = 5e3;
1876
1875
  var CSRF_HEADER = { "X-Foir-Session": "1" };
1877
1876
  function createFoirSessionClient(config) {
1878
- const sessionUrl = `${trimSlash(config.loginOrigin)}${config.sessionPath ?? DEFAULT_SESSION_PATH2}`;
1879
- const logoutUrl = `${trimSlash(config.loginOrigin)}${config.logoutPath ?? DEFAULT_LOGOUT_PATH}`;
1877
+ const forApp2 = config.clientId ? `?client_id=${encodeURIComponent(config.clientId)}` : "";
1878
+ const sessionUrl = `${trimSlash(config.loginOrigin)}${config.sessionPath ?? DEFAULT_SESSION_PATH2}${forApp2}`;
1879
+ const logoutUrl = `${trimSlash(config.loginOrigin)}${config.logoutPath ?? DEFAULT_LOGOUT_PATH}${forApp2}`;
1880
1880
  const skewMs = (config.refreshSkewSeconds ?? DEFAULT_REFRESH_SKEW_SECONDS) * 1e3;
1881
1881
  let cached = null;
1882
1882
  let inflight = null;
@@ -2074,6 +2074,5 @@ export {
2074
2074
  signupContext,
2075
2075
  updateMyProfile,
2076
2076
  updatePassword,
2077
- userAccess,
2078
- verifyEmail
2077
+ userAccess
2079
2078
  };
@@ -11,7 +11,7 @@ export interface EditorProviderProps {
11
11
  children: ReactNode;
12
12
  /**
13
13
  * Parent window origin for postMessage validation.
14
- * Must be an explicit origin (e.g., 'https://admin.example.com').
14
+ * Must be an explicit origin (e.g., 'https://console.example.com').
15
15
  * Falls back to VITE_PARENT_ORIGIN or NEXT_PUBLIC_PARENT_ORIGIN env var.
16
16
  */
17
17
  parentOrigin?: string;
package/dist/next.js CHANGED
@@ -973,7 +973,6 @@ var AUTH_OPS = {
973
973
  requestPasswordReset: "requestPasswordReset",
974
974
  resetPassword: "resetPassword",
975
975
  updatePassword: "updatePassword",
976
- verifyEmail: "verifyEmail",
977
976
  deleteMyAccount: "deleteMyAccount",
978
977
  // The user's own profile, and the apps they have agreed may act for them.
979
978
  updateMyProfile: "updateMyProfile",
package/dist/push.js CHANGED
@@ -1093,7 +1093,6 @@ var AUTH_OPS = {
1093
1093
  requestPasswordReset: "requestPasswordReset",
1094
1094
  resetPassword: "resetPassword",
1095
1095
  updatePassword: "updatePassword",
1096
- verifyEmail: "verifyEmail",
1097
1096
  deleteMyAccount: "deleteMyAccount",
1098
1097
  // The user's own profile, and the apps they have agreed may act for them.
1099
1098
  updateMyProfile: "updateMyProfile",
package/dist/react.js CHANGED
@@ -967,7 +967,6 @@ var AUTH_OPS = {
967
967
  requestPasswordReset: "requestPasswordReset",
968
968
  resetPassword: "resetPassword",
969
969
  updatePassword: "updatePassword",
970
- verifyEmail: "verifyEmail",
971
970
  deleteMyAccount: "deleteMyAccount",
972
971
  // The user's own profile, and the apps they have agreed may act for them.
973
972
  updateMyProfile: "updateMyProfile",
@@ -1431,8 +1430,9 @@ var DEFAULT_REFRESH_SKEW_SECONDS = 60;
1431
1430
  var MIN_REFRESH_DELAY_MS = 5e3;
1432
1431
  var CSRF_HEADER = { "X-Foir-Session": "1" };
1433
1432
  function createFoirSessionClient(config) {
1434
- const sessionUrl = `${trimSlash(config.loginOrigin)}${config.sessionPath ?? DEFAULT_SESSION_PATH}`;
1435
- 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}`;
1436
1436
  const skewMs = (config.refreshSkewSeconds ?? DEFAULT_REFRESH_SKEW_SECONDS) * 1e3;
1437
1437
  let cached = null;
1438
1438
  let inflight = null;
@@ -28,8 +28,8 @@
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
package/dist/server.js CHANGED
@@ -1489,7 +1489,7 @@ function parseResumeFrom(message) {
1489
1489
  const n = Number(m[1]);
1490
1490
  return Number.isSafeInteger(n) ? n : void 0;
1491
1491
  }
1492
- function assertOperatorKey(apiKey) {
1492
+ function assertAdminKey(apiKey) {
1493
1493
  const key = apiKey?.trim() ?? "";
1494
1494
  if (!key) {
1495
1495
  throw new FoirRequestError(
@@ -1576,7 +1576,7 @@ async function readErrorMessage(res) {
1576
1576
  }
1577
1577
  }
1578
1578
  function createEventsClient(config) {
1579
- const apiKey = assertOperatorKey(config.apiKey);
1579
+ const apiKey = assertAdminKey(config.apiKey);
1580
1580
  assertNoBearer(config.headers);
1581
1581
  const url = foirApiEndpoint(config.apiUrl, FOIR_EVENTS_PATH);
1582
1582
  async function list(params = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foir/sdk",
3
- "version": "0.23.0",
3
+ "version": "0.24.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"