@c1m-public/platform-auth 0.8.3 → 0.9.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/README.md CHANGED
@@ -116,6 +116,14 @@ await access.requireAccess("platform.tenants.manage");
116
116
  Omit `getSubjectId` and the loader derives the cache-tag subject from the access
117
117
  token, so per-user tagging cannot silently collapse to one shared tag.
118
118
 
119
+ ### Pipeline stages
120
+
121
+ `PIPELINE_STAGES` / `PipelineStage` / `isPipelineStage` under `./access` are
122
+ the onboarding funnel strings in order (`created`, `awaiting_payment`,
123
+ `provisioning`, `attention`, `active`), generated from the backend's
124
+ `schemas/api/pipeline-stages.json` the same way the permission keys are.
125
+ Labels and descriptions stay with the app; the strings are the backend's.
126
+
119
127
  ## Keys drift guard
120
128
 
121
129
  `src/access/generated/keys.ts` is generated from the backend authz catalog
@@ -21,6 +21,11 @@ type WorkspaceRole = (typeof WORKSPACE_ROLES)[number];
21
21
  /** Every permission key the backend can grant, across all scopes. */
22
22
  type PermissionKey = PlatformPermissionKey | DashPermissionKey | LeadBrokerPermissionKey | WorkspacePermissionKey;
23
23
 
24
+ /** Onboarding pipeline stages, in funnel order. Labels and copy stay with the app; the strings are the backend's. */
25
+ declare const PIPELINE_STAGES: readonly ["created", "awaiting_payment", "provisioning", "attention", "active"];
26
+ type PipelineStage = (typeof PIPELINE_STAGES)[number];
27
+ declare function isPipelineStage(value: unknown): value is PipelineStage;
28
+
24
29
  type AccessErrorCode = "unauthenticated" | "forbidden" | "unavailable" | "invalid_snapshot";
25
30
  /**
26
31
  * Typed failure for loading or validating an access snapshot. `unauthenticated`
@@ -145,4 +150,4 @@ interface FetchAccessSnapshotOptions {
145
150
  */
146
151
  declare function fetchAccessSnapshot(opts: FetchAccessSnapshotOptions): Promise<AccessSnapshot>;
147
152
 
148
- export { type AccessEntry, type AccessErrorCode, type AccessScopeType, type AccessSnapshot, AccessSnapshotError, DASH_PERMISSIONS, DASH_ROLES, DEFAULT_ACCESS_ENDPOINT_PATH, type DashPermissionKey, type DashRole, type FetchAccessSnapshotOptions, LEADBROKER_PERMISSIONS, type LeadBrokerPermissionKey, PLATFORM_PERMISSIONS, type PermissionCheckOptions, type PermissionKey, type PlatformPermissionKey, WORKSPACE_PERMISSIONS, WORKSPACE_ROLES, type WorkspacePermissionKey, type WorkspaceRole, appScopes, dashRole, emptySnapshot, entryCoversApp, fetchAccessSnapshot, hasAllPermissions, hasAnyPermission, hasPermission, hasWorkspacePermission, isAccessSnapshotError, isPlatformOwner, managedDashes, parseAccessSnapshot, permissionsFor };
153
+ export { type AccessEntry, type AccessErrorCode, type AccessScopeType, type AccessSnapshot, AccessSnapshotError, DASH_PERMISSIONS, DASH_ROLES, DEFAULT_ACCESS_ENDPOINT_PATH, type DashPermissionKey, type DashRole, type FetchAccessSnapshotOptions, LEADBROKER_PERMISSIONS, type LeadBrokerPermissionKey, PIPELINE_STAGES, PLATFORM_PERMISSIONS, type PermissionCheckOptions, type PermissionKey, type PipelineStage, type PlatformPermissionKey, WORKSPACE_PERMISSIONS, WORKSPACE_ROLES, type WorkspacePermissionKey, type WorkspaceRole, appScopes, dashRole, emptySnapshot, entryCoversApp, fetchAccessSnapshot, hasAllPermissions, hasAnyPermission, hasPermission, hasWorkspacePermission, isAccessSnapshotError, isPipelineStage, isPlatformOwner, managedDashes, parseAccessSnapshot, permissionsFor };
@@ -1,2 +1,2 @@
1
- export { AccessSnapshotError, DASH_PERMISSIONS, DASH_ROLES, DEFAULT_ACCESS_ENDPOINT_PATH, LEADBROKER_PERMISSIONS, PLATFORM_PERMISSIONS, WORKSPACE_PERMISSIONS, WORKSPACE_ROLES, appScopes, dashRole, emptySnapshot, entryCoversApp, fetchAccessSnapshot, hasAllPermissions, hasAnyPermission, hasPermission, hasWorkspacePermission, isAccessSnapshotError, isPlatformOwner, managedDashes, parseAccessSnapshot, permissionsFor } from '../chunk-73ZH67GM.js';
1
+ export { AccessSnapshotError, DASH_PERMISSIONS, DASH_ROLES, DEFAULT_ACCESS_ENDPOINT_PATH, LEADBROKER_PERMISSIONS, PIPELINE_STAGES, PLATFORM_PERMISSIONS, WORKSPACE_PERMISSIONS, WORKSPACE_ROLES, appScopes, dashRole, emptySnapshot, entryCoversApp, fetchAccessSnapshot, hasAllPermissions, hasAnyPermission, hasPermission, hasWorkspacePermission, isAccessSnapshotError, isPipelineStage, isPlatformOwner, managedDashes, parseAccessSnapshot, permissionsFor } from '../chunk-U67NBJND.js';
2
2
  import '../chunk-ZWSJVE5S.js';
@@ -1,6 +1,6 @@
1
1
  import { R as Resolvable } from '../internal-D6RafCm2.js';
2
2
  import { AccessSnapshot, PermissionCheckOptions } from './index.js';
3
- export { AccessEntry, AccessErrorCode, AccessScopeType, AccessSnapshotError, DASH_PERMISSIONS, DASH_ROLES, DEFAULT_ACCESS_ENDPOINT_PATH, DashPermissionKey, DashRole, FetchAccessSnapshotOptions, LEADBROKER_PERMISSIONS, LeadBrokerPermissionKey, PLATFORM_PERMISSIONS, PermissionKey, PlatformPermissionKey, WORKSPACE_PERMISSIONS, WORKSPACE_ROLES, WorkspacePermissionKey, WorkspaceRole, appScopes, dashRole, emptySnapshot, entryCoversApp, fetchAccessSnapshot, hasAllPermissions, hasAnyPermission, hasPermission, hasWorkspacePermission, isAccessSnapshotError, isPlatformOwner, managedDashes, parseAccessSnapshot, permissionsFor } from './index.js';
3
+ export { AccessEntry, AccessErrorCode, AccessScopeType, AccessSnapshotError, DASH_PERMISSIONS, DASH_ROLES, DEFAULT_ACCESS_ENDPOINT_PATH, DashPermissionKey, DashRole, FetchAccessSnapshotOptions, LEADBROKER_PERMISSIONS, LeadBrokerPermissionKey, PIPELINE_STAGES, PLATFORM_PERMISSIONS, PermissionKey, PipelineStage, PlatformPermissionKey, WORKSPACE_PERMISSIONS, WORKSPACE_ROLES, WorkspacePermissionKey, WorkspaceRole, appScopes, dashRole, emptySnapshot, entryCoversApp, fetchAccessSnapshot, hasAllPermissions, hasAnyPermission, hasPermission, hasWorkspacePermission, isAccessSnapshotError, isPipelineStage, isPlatformOwner, managedDashes, parseAccessSnapshot, permissionsFor } from './index.js';
4
4
 
5
5
  /** Default cache tag for one subject's snapshot: `access:<subjectId>`. */
6
6
  declare function accessCacheTag(subjectId: string): string;
@@ -1,6 +1,6 @@
1
1
  import { decodeTokenPayload } from '../chunk-FBC2NUH7.js';
2
- import { AccessSnapshotError, fetchAccessSnapshot, isAccessSnapshotError, hasAnyPermission, hasAllPermissions, hasWorkspacePermission } from '../chunk-73ZH67GM.js';
3
- export { AccessSnapshotError, DASH_PERMISSIONS, DASH_ROLES, DEFAULT_ACCESS_ENDPOINT_PATH, LEADBROKER_PERMISSIONS, PLATFORM_PERMISSIONS, WORKSPACE_PERMISSIONS, WORKSPACE_ROLES, appScopes, dashRole, emptySnapshot, entryCoversApp, fetchAccessSnapshot, hasAllPermissions, hasAnyPermission, hasPermission, hasWorkspacePermission, isAccessSnapshotError, isPlatformOwner, managedDashes, parseAccessSnapshot, permissionsFor } from '../chunk-73ZH67GM.js';
2
+ import { AccessSnapshotError, fetchAccessSnapshot, isAccessSnapshotError, hasAnyPermission, hasAllPermissions, hasWorkspacePermission } from '../chunk-U67NBJND.js';
3
+ export { AccessSnapshotError, DASH_PERMISSIONS, DASH_ROLES, DEFAULT_ACCESS_ENDPOINT_PATH, LEADBROKER_PERMISSIONS, PIPELINE_STAGES, PLATFORM_PERMISSIONS, WORKSPACE_PERMISSIONS, WORKSPACE_ROLES, appScopes, dashRole, emptySnapshot, entryCoversApp, fetchAccessSnapshot, hasAllPermissions, hasAnyPermission, hasPermission, hasWorkspacePermission, isAccessSnapshotError, isPipelineStage, isPlatformOwner, managedDashes, parseAccessSnapshot, permissionsFor } from '../chunk-U67NBJND.js';
4
4
  import { resolveValue } from '../chunk-ZWSJVE5S.js';
5
5
  import 'server-only';
6
6
  import { cache } from 'react';
@@ -81,6 +81,12 @@ var WORKSPACE_ROLES = [
81
81
  "workspace.manager"
82
82
  ];
83
83
 
84
+ // src/access/generated/stages.ts
85
+ var PIPELINE_STAGES = ["created", "awaiting_payment", "provisioning", "attention", "active"];
86
+ function isPipelineStage(value) {
87
+ return typeof value === "string" && PIPELINE_STAGES.includes(value);
88
+ }
89
+
84
90
  // src/access/errors.ts
85
91
  var AccessSnapshotError = class extends Error {
86
92
  code;
@@ -258,4 +264,4 @@ async function fetchAccessSnapshot(opts) {
258
264
  return parseAccessSnapshot(body);
259
265
  }
260
266
 
261
- export { AccessSnapshotError, DASH_PERMISSIONS, DASH_ROLES, DEFAULT_ACCESS_ENDPOINT_PATH, LEADBROKER_PERMISSIONS, PLATFORM_PERMISSIONS, WORKSPACE_PERMISSIONS, WORKSPACE_ROLES, appScopes, dashRole, emptySnapshot, entryCoversApp, fetchAccessSnapshot, hasAllPermissions, hasAnyPermission, hasPermission, hasWorkspacePermission, isAccessSnapshotError, isPlatformOwner, managedDashes, parseAccessSnapshot, permissionsFor };
267
+ export { AccessSnapshotError, DASH_PERMISSIONS, DASH_ROLES, DEFAULT_ACCESS_ENDPOINT_PATH, LEADBROKER_PERMISSIONS, PIPELINE_STAGES, PLATFORM_PERMISSIONS, WORKSPACE_PERMISSIONS, WORKSPACE_ROLES, appScopes, dashRole, emptySnapshot, entryCoversApp, fetchAccessSnapshot, hasAllPermissions, hasAnyPermission, hasPermission, hasWorkspacePermission, isAccessSnapshotError, isPipelineStage, isPlatformOwner, managedDashes, parseAccessSnapshot, permissionsFor };
package/dist/next.d.ts CHANGED
@@ -128,6 +128,11 @@ interface SessionStoreConfig {
128
128
  /** Called when a cookie read/write fails outside a request (prerender); default swallows. */
129
129
  onError?: (error: unknown, operation: string) => void;
130
130
  }
131
+ /** Per-call overrides: a multi-host surface picks the cookie domain per request. */
132
+ interface SessionWriteOptions {
133
+ /** Ignored for `__Host-` names, which forbid Domain. */
134
+ cookieDomain?: string;
135
+ }
131
136
  /**
132
137
  * Session cookies for a first-party Next.js platform surface, written once.
133
138
  *
@@ -148,24 +153,24 @@ interface SessionStoreConfig {
148
153
  declare function createSessionStore(config: SessionStoreConfig): {
149
154
  audience: string;
150
155
  cookieNames: SessionCookieNames;
151
- cookieOptions: (rememberMe: boolean, token?: string) => CookieOptions & {
156
+ cookieOptions: (rememberMe: boolean, token?: string, options?: SessionWriteOptions) => CookieOptions & {
152
157
  httpOnly: true;
153
158
  sameSite: "lax";
154
159
  path: "/";
155
160
  };
156
- createSession: (accessToken: string, refreshToken?: string, rememberMe?: boolean) => Promise<void>;
161
+ createSession: (accessToken: string, refreshToken?: string, rememberMe?: boolean, options?: SessionWriteOptions) => Promise<void>;
157
162
  writeSessionCookies: (response: Response, accessToken: string, refreshToken?: string, rememberMe?: boolean) => Response;
158
163
  getAccessToken: () => Promise<string | null>;
159
164
  getRefreshToken: () => Promise<string | null>;
160
165
  getSession: () => Promise<SessionData | null>;
161
166
  getSessionWithRefresh: () => Promise<SessionData | null>;
162
167
  isRememberMe: () => Promise<boolean>;
163
- updateAccessToken: (accessToken: string, refreshToken?: string) => Promise<void>;
164
- destroySession: () => Promise<void>;
168
+ updateAccessToken: (accessToken: string, refreshToken?: string, options?: SessionWriteOptions) => Promise<void>;
169
+ destroySession: (options?: SessionWriteOptions) => Promise<void>;
165
170
  clearSessionCookies: (response: Response) => Response;
166
171
  requireSession: () => Promise<SessionData>;
167
172
  isAuthenticated(): Promise<boolean>;
168
173
  };
169
174
  type SessionStore = ReturnType<typeof createSessionStore>;
170
175
 
171
- export { CookieOptions, type PlatformFetch, type PlatformFetchConfig, type PlatformFetchTimeouts, PlatformServerFetchError, RecentAuthenticationRequiredError, SSOReauthenticationRequiredError, type SessionCookieNames, SessionData, SessionExpiredError, type SessionStore, type SessionStoreConfig, type SessionStoreRefreshConfig, authenticationErrorFor, buildForwardedRequestHeaders, controlRequest, createPlatformFetch, createSessionStore, isPlatformServerFetchError, isRecentAuthenticationRequiredError, isSSOReauthenticationRequiredError, isSessionExpiredError, mapControlError };
176
+ export { CookieOptions, type PlatformFetch, type PlatformFetchConfig, type PlatformFetchTimeouts, PlatformServerFetchError, RecentAuthenticationRequiredError, SSOReauthenticationRequiredError, type SessionCookieNames, SessionData, SessionExpiredError, type SessionStore, type SessionStoreConfig, type SessionStoreRefreshConfig, type SessionWriteOptions, authenticationErrorFor, buildForwardedRequestHeaders, controlRequest, createPlatformFetch, createSessionStore, isPlatformServerFetchError, isRecentAuthenticationRequiredError, isSSOReauthenticationRequiredError, isSessionExpiredError, mapControlError };
package/dist/next.js CHANGED
@@ -176,15 +176,16 @@ function createSessionStore(config) {
176
176
  timeoutMs: config.refresh.timeoutMs,
177
177
  fetch: config.refresh.fetch
178
178
  }) : void 0;
179
- function cookieOptions(rememberMe, token) {
179
+ function cookieOptions(rememberMe, token, options) {
180
180
  const maxAge = token ? tokenMaxAgeSeconds(token, maxAgeCap) : maxAgeCap;
181
+ const effectiveDomain = hostPrefixed ? void 0 : options?.cookieDomain ?? domain;
181
182
  return {
182
183
  httpOnly: true,
183
184
  secure,
184
185
  sameSite: "lax",
185
186
  path: "/",
186
187
  ...rememberMe ? { maxAge } : {},
187
- ...domain ? { domain } : {}
188
+ ...effectiveDomain ? { domain: effectiveDomain } : {}
188
189
  };
189
190
  }
190
191
  function assertAudience(token) {
@@ -207,13 +208,13 @@ function createSessionStore(config) {
207
208
  function rememberedIn(store) {
208
209
  return store?.get(names.rememberMe)?.value === "true";
209
210
  }
210
- async function createSession(accessToken, refreshToken, rememberMe = config.defaultRememberMe ?? true) {
211
+ async function createSession(accessToken, refreshToken, rememberMe = config.defaultRememberMe ?? true, options) {
211
212
  assertAudience(accessToken);
212
213
  const store = await jar("createSession");
213
214
  if (!store) throw new Error("Cannot create a session outside a request");
214
- store.set(names.session, accessToken, cookieOptions(rememberMe, accessToken));
215
- if (refreshToken) store.set(names.refreshToken, refreshToken, cookieOptions(rememberMe, refreshToken));
216
- store.set(names.rememberMe, rememberMe ? "true" : "false", cookieOptions(rememberMe));
215
+ store.set(names.session, accessToken, cookieOptions(rememberMe, accessToken, options));
216
+ if (refreshToken) store.set(names.refreshToken, refreshToken, cookieOptions(rememberMe, refreshToken, options));
217
+ store.set(names.rememberMe, rememberMe ? "true" : "false", cookieOptions(rememberMe, void 0, options));
217
218
  }
218
219
  function writeSessionCookies(response, accessToken, refreshToken, rememberMe = config.defaultRememberMe ?? true) {
219
220
  assertAudience(accessToken);
@@ -238,13 +239,13 @@ function createSessionStore(config) {
238
239
  async function isRememberMe() {
239
240
  return rememberedIn(await jar("isRememberMe"));
240
241
  }
241
- async function updateAccessToken(accessToken, refreshToken) {
242
+ async function updateAccessToken(accessToken, refreshToken, options) {
242
243
  assertAudience(accessToken);
243
244
  const store = await jar("updateAccessToken");
244
245
  if (!store) throw new Error("Cannot update a session outside a request");
245
246
  const rememberMe = rememberedIn(store);
246
- store.set(names.session, accessToken, cookieOptions(rememberMe, accessToken));
247
- if (refreshToken) store.set(names.refreshToken, refreshToken, cookieOptions(rememberMe, refreshToken));
247
+ store.set(names.session, accessToken, cookieOptions(rememberMe, accessToken, options));
248
+ if (refreshToken) store.set(names.refreshToken, refreshToken, cookieOptions(rememberMe, refreshToken, options));
248
249
  }
249
250
  async function getSessionWithRefresh() {
250
251
  const store = await jar("getSessionWithRefresh");
@@ -264,12 +265,12 @@ function createSessionStore(config) {
264
265
  function clearOptions() {
265
266
  return { path: "/", secure };
266
267
  }
267
- async function destroySession() {
268
+ async function destroySession(options) {
268
269
  const store = await jar("destroySession");
269
270
  if (!store) return;
270
271
  try {
271
- const options = cookieOptions(false);
272
- for (const name of [names.session, names.refreshToken, names.rememberMe]) store.delete({ name, ...options });
272
+ const attributes = cookieOptions(false, void 0, options);
273
+ for (const name of [names.session, names.refreshToken, names.rememberMe]) store.delete({ name, ...attributes });
273
274
  } catch (error) {
274
275
  onError(error, "destroySession");
275
276
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c1m-public/platform-auth",
3
- "version": "0.8.3",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Session and authorization helpers for C1M platform surfaces. The root is runtime-neutral (Web Request/Response): token/session reads, the first-party handoff (PKCE target + source), proxy session gate and coalesced refresh; ./next adds the server-only guard; ./access carries the resolved access snapshot, typed permission keys, predicates, a Next loader and React bindings",