@c1m-public/platform-auth 0.9.3 → 0.12.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
@@ -11,6 +11,7 @@ need — the boundary is the subpath.
11
11
  ```
12
12
  . session: token reads, handoff, proxy gate, refresh (Web Request/Response)
13
13
  ./next session, server-only guard (Next route handlers)
14
+ ./mcp-tokens self-service MCP PAT lifecycle (framework-neutral)
14
15
  ./access authorization: snapshot, keys, predicates (framework-neutral)
15
16
  ./access/next access loader: require / forbidden / invalidate (Next, server-only)
16
17
  ./access/react <Can>, useCan, AccessProvider (client)
@@ -19,6 +20,23 @@ need — the boundary is the subpath.
19
20
  `next` and `react` are **optional** peer dependencies: a BFF that only reads
20
21
  sessions never needs them.
21
22
 
23
+ ## `./mcp-tokens` — MCP personal access tokens
24
+
25
+ `createMCPTokenClient` lists, mints, and revokes the signed-in platform user's
26
+ own MCP tokens under `/api/v1/platform/auth/me/mcp-tokens`. The client resolves
27
+ the bearer on every request, never retries mint or revoke, and emits bounded
28
+ observations containing operation metadata but no URL, bearer, or PAT material.
29
+
30
+ The subpath also exports `MCP_ACCESS_PERMISSION`,
31
+ `MCP_TOKENS_MANAGE_PERMISSION`, `MCP_TOOL_PERMISSIONS`,
32
+ `MCP_WILDCARD_TOOL_PERMISSIONS`, the request/response types, and the structural
33
+ `MCPTokenAPIError` predicate. The permission ceiling `["*"]` follows future
34
+ read-only tool permissions; mutating permissions must always be named
35
+ explicitly. A minted `raw_token` is a one-time value: callers must keep it out
36
+ of URLs, logs, storage, and telemetry. A `recent_authentication_required` API
37
+ error is a step-up challenge, not an expired session; send the user through the
38
+ host application's re-authentication path before retrying the mint.
39
+
22
40
  ## `.` — session
23
41
 
24
42
  | Export | Purpose |
@@ -92,7 +110,7 @@ The resolved snapshot from `GET /api/v1/platform/access`.
92
110
  | `PLATFORM_PERMISSIONS`, `LEADBROKER_PERMISSIONS`, `WORKSPACE_PERMISSIONS`, `WORKSPACE_ROLES` + key types | Generated from the backend catalog — see the drift guard below. |
93
111
  | `parseAccessSnapshot`, `emptySnapshot`, `AccessSnapshot`, `AccessEntry` | Validate and shape the snapshot. |
94
112
  | `hasPermission`, `hasAnyPermission`, `hasAllPermissions`, `hasWorkspacePermission`, `isPlatformOwner`, `appScopes`, `permissionsFor` | Scope-aware predicates. |
95
- | `managedDashes`, `dashRole` | The dashes a subject runs, from the mirrored `dash.owner` / `dash.admin` bundle grants (`snapshot.dash_roles`). Admission only — gate an action with `hasPermission(snapshot, "dash.publish", { saasApp })`. Platform managers are not listed; admit them on `platform.tenants.manage`. |
113
+ | `managedDashes`, `dashRole` | The dashes a subject runs, from the mirrored `dash.owner` / `dash.admin` bundle grants (`snapshot.dash_roles`). Admission only — gate an action with `hasPermission(snapshot, "dash.publish", { dashId })`. Platform managers are not listed; admit them on `platform.tenants.manage`. |
96
114
  | `fetchAccessSnapshot` | Framework-neutral fetch. Pass `request` and it forwards client identity for you. |
97
115
  | `AccessSnapshotError`, `isAccessSnapshotError` | `unauthenticated` / `forbidden` / `unavailable` / `invalid_snapshot`. |
98
116
 
@@ -1 +1 @@
1
- export { a as AccessEntry, b as AccessErrorCode, c as AccessScopeType, A as AccessSnapshot, d as AccessSnapshotError, D as DASH_PERMISSIONS, e as DASH_ROLES, f as DEFAULT_ACCESS_ENDPOINT_PATH, g as DashPermissionKey, h as DashRole, F as FetchAccessSnapshotOptions, L as LEADBROKER_PERMISSIONS, i as LeadBrokerPermissionKey, j as PIPELINE_STAGES, k as PLATFORM_PERMISSIONS, P as PermissionCheckOptions, l as PermissionKey, m as PipelineStage, n as PlatformPermissionKey, W as WORKSPACE_PERMISSIONS, o as WORKSPACE_ROLES, p as WorkspacePermissionKey, q as WorkspaceRole, r as appScopes, s as dashRole, t as emptySnapshot, u as entryCoversApp, v as fetchAccessSnapshot, w as hasAllPermissions, x as hasAnyPermission, y as hasPermission, z as hasWorkspacePermission, B as isAccessSnapshotError, C as isPipelineStage, E as isPlatformOwner, G as managedDashes, H as parseAccessSnapshot, I as permissionsFor } from '../index-BcDlVbUd.js';
1
+ export { a as AccessEntry, b as AccessErrorCode, c as AccessScopeType, A as AccessSnapshot, d as AccessSnapshotError, D as DASH_PERMISSIONS, e as DASH_ROLES, f as DEFAULT_ACCESS_ENDPOINT_PATH, g as DashPermissionKey, h as DashRole, F as FetchAccessSnapshotOptions, L as LEADBROKER_PERMISSIONS, i as LeadBrokerPermissionKey, j as PIPELINE_STAGES, k as PLATFORM_PERMISSIONS, P as PermissionCheckOptions, l as PermissionKey, m as PipelineStage, n as PlatformPermissionKey, W as WORKSPACE_PERMISSIONS, o as WORKSPACE_ROLES, p as WorkspacePermissionKey, q as WorkspaceRole, r as appScopes, s as dashRole, t as emptySnapshot, u as entryCoversApp, v as fetchAccessSnapshot, w as hasAllPermissions, x as hasAnyPermission, y as hasPermission, z as hasWorkspacePermission, B as isAccessSnapshotError, C as isPipelineStage, E as isPlatformOwner, G as managedDashes, H as parseAccessSnapshot, I as permissionsFor } from '../index-D-cH_sfe.js';
@@ -13,20 +13,25 @@ var PLATFORM_PERMISSIONS = [
13
13
  "platform.audit.view",
14
14
  "platform.auth.manage",
15
15
  "platform.billing.manage",
16
+ "platform.billing.view",
16
17
  "platform.channels.manage",
17
18
  "platform.channels.view",
18
19
  "platform.config.manage",
19
20
  "platform.docs.manage",
20
21
  "platform.docs.view",
22
+ "platform.mcp.access",
23
+ "platform.mcp.tokens.manage",
21
24
  "platform.observability.manage",
22
25
  "platform.observability.view",
23
26
  "platform.offboarding.view",
24
27
  "platform.ops.manage",
28
+ "platform.ops.view",
25
29
  "platform.support.impersonate",
26
30
  "platform.support.sessions",
27
31
  "platform.tenants.archive",
28
32
  "platform.tenants.manage",
29
33
  "platform.tenants.restore",
34
+ "platform.tenants.view",
30
35
  "platform.users.deactivate",
31
36
  "platform.users.delete",
32
37
  "platform.users.invite",
@@ -37,16 +42,20 @@ var PLATFORM_PERMISSIONS = [
37
42
  var DASH_PERMISSIONS = [
38
43
  "dash.apps.manage",
39
44
  "dash.billing.manage",
45
+ "dash.billing.view",
40
46
  "dash.channels.manage",
41
47
  "dash.customers.manage",
42
48
  "dash.domains.manage",
49
+ "dash.domains.view",
43
50
  "dash.members.manage",
44
51
  "dash.ownership.transfer",
45
52
  "dash.plans.manage",
53
+ "dash.plans.view",
46
54
  "dash.publish",
47
55
  "dash.settings.manage",
48
56
  "dash.workspaces.admin",
49
- "dash.workspaces.manage"
57
+ "dash.workspaces.manage",
58
+ "dash.workspaces.view"
50
59
  ];
51
60
  var DASH_ROLES = [
52
61
  "dash.admin",
@@ -102,7 +111,7 @@ function isAccessSnapshotError(error, code) {
102
111
  }
103
112
 
104
113
  // src/access/snapshot.ts
105
- var SCOPE_TYPES = /* @__PURE__ */ new Set(["platform", "saas_app", "workspace"]);
114
+ var SCOPE_TYPES = /* @__PURE__ */ new Set(["platform", "dash_id", "workspace"]);
106
115
  function emptySnapshot(subjectId = "") {
107
116
  return {
108
117
  subject_id: subjectId,
@@ -135,7 +144,7 @@ function parseAccessSnapshot(input) {
135
144
  if (!isRecord(raw)) fail(`permissions[${i}]`, "is not an object");
136
145
  const { key, scope_type, scope_id } = raw;
137
146
  if (typeof key !== "string" || key === "") fail(`permissions[${i}].key`, "must be a non-empty string");
138
- if (typeof scope_type !== "string" || !SCOPE_TYPES.has(scope_type)) fail(`permissions[${i}].scope_type`, "must be platform|saas_app|workspace");
147
+ if (typeof scope_type !== "string" || !SCOPE_TYPES.has(scope_type)) fail(`permissions[${i}].scope_type`, "must be platform|dash_id|workspace");
139
148
  if (scope_id !== void 0 && scope_id !== null && typeof scope_id !== "string") fail(`permissions[${i}].scope_id`, "must be a string");
140
149
  return { key, scope_type, scope_id: typeof scope_id === "string" ? scope_id : "" };
141
150
  });
@@ -177,20 +186,20 @@ function parseAccessSnapshot(input) {
177
186
  }
178
187
 
179
188
  // src/access/predicates.ts
180
- function entryCoversApp(entry, saasApp) {
189
+ function entryCoversApp(entry, dashId) {
181
190
  switch (entry.scope_type) {
182
191
  case "platform":
183
192
  return true;
184
- case "saas_app":
185
- if (saasApp === void 0) return true;
186
- return entry.scope_id === "*" || entry.scope_id.toLowerCase() === saasApp.toLowerCase();
193
+ case "dash_id":
194
+ if (dashId === void 0) return true;
195
+ return entry.scope_id === "*" || entry.scope_id.toLowerCase() === dashId.toLowerCase();
187
196
  default:
188
197
  return false;
189
198
  }
190
199
  }
191
200
  function hasPermission(snapshot, key, opts = {}) {
192
201
  if (!snapshot.active) return false;
193
- return snapshot.permissions.some((entry) => entry.key === key && entryCoversApp(entry, opts.saasApp));
202
+ return snapshot.permissions.some((entry) => entry.key === key && entryCoversApp(entry, opts.dashId));
194
203
  }
195
204
  function hasAnyPermission(snapshot, keys, opts = {}) {
196
205
  return keys.some((key) => hasPermission(snapshot, key, opts));
@@ -205,11 +214,11 @@ function hasWorkspacePermission(snapshot, workspaceId, key) {
205
214
  }
206
215
  function managedDashes(snapshot) {
207
216
  if (!snapshot.active) return [];
208
- return Object.entries(snapshot.dash_roles).map(([saasApp, role]) => ({ saasApp, role })).sort((a, b) => a.saasApp.localeCompare(b.saasApp));
217
+ return Object.entries(snapshot.dash_roles).map(([dashId, role]) => ({ dashId, role })).sort((a, b) => a.dashId.localeCompare(b.dashId));
209
218
  }
210
- function dashRole(snapshot, saasApp) {
219
+ function dashRole(snapshot, dashId) {
211
220
  if (!snapshot.active) return "";
212
- return snapshot.dash_roles[saasApp] ?? "";
221
+ return snapshot.dash_roles[dashId] ?? "";
213
222
  }
214
223
  function isPlatformOwner(snapshot) {
215
224
  return snapshot.active && snapshot.is_owner;
@@ -220,7 +229,7 @@ function appScopes(snapshot, key) {
220
229
  for (const entry of snapshot.permissions) {
221
230
  if (entry.key !== key) continue;
222
231
  if (entry.scope_type === "platform") return { all: true, apps: [] };
223
- if (entry.scope_type === "saas_app") {
232
+ if (entry.scope_type === "dash_id") {
224
233
  if (entry.scope_id === "*") return { all: true, apps: [] };
225
234
  apps.add(entry.scope_id.toLowerCase());
226
235
  }
@@ -230,7 +239,7 @@ function appScopes(snapshot, key) {
230
239
  function permissionsFor(snapshot, opts = {}) {
231
240
  if (!snapshot.active) return [];
232
241
  const keys = /* @__PURE__ */ new Set();
233
- for (const entry of snapshot.permissions) if (entryCoversApp(entry, opts.saasApp)) keys.add(entry.key);
242
+ for (const entry of snapshot.permissions) if (entryCoversApp(entry, opts.dashId)) keys.add(entry.key);
234
243
  return [...keys].sort();
235
244
  }
236
245
 
@@ -257,6 +266,11 @@ function forwardedRequestHeaders(request, init) {
257
266
  return applyForwardedClientHeaders(request.headers, new Headers(init));
258
267
  }
259
268
 
269
+ // src/forwarding.ts
270
+ function forwardedRequestHeaders2(request, init) {
271
+ return forwardedRequestHeaders(request, init);
272
+ }
273
+
260
274
  // src/internal.ts
261
275
  function resolveValue(value) {
262
276
  return typeof value === "function" ? value() : value;
@@ -280,7 +294,7 @@ async function timedFetch(url, options = {}) {
280
294
  var DEFAULT_ACCESS_ENDPOINT_PATH = "/api/v1/platform/access";
281
295
  async function fetchAccessSnapshot(opts) {
282
296
  const url = `${resolveValue(opts.apiUrl).replace(/\/$/, "")}${opts.endpointPath ?? DEFAULT_ACCESS_ENDPOINT_PATH}`;
283
- const headers = opts.request ? forwardedRequestHeaders(opts.request, opts.headers) : new Headers(opts.headers);
297
+ const headers = opts.request ? forwardedRequestHeaders2(opts.request, opts.headers) : new Headers(opts.headers);
284
298
  headers.set("Authorization", `Bearer ${opts.accessToken}`);
285
299
  headers.set("Accept", "application/json");
286
300
  let response;
@@ -1,5 +1,5 @@
1
- import { A as AccessSnapshot, P as PermissionCheckOptions, R as Resolvable } from '../index-BcDlVbUd.js';
2
- export { a as AccessEntry, b as AccessErrorCode, c as AccessScopeType, d as AccessSnapshotError, D as DASH_PERMISSIONS, e as DASH_ROLES, f as DEFAULT_ACCESS_ENDPOINT_PATH, g as DashPermissionKey, h as DashRole, F as FetchAccessSnapshotOptions, L as LEADBROKER_PERMISSIONS, i as LeadBrokerPermissionKey, j as PIPELINE_STAGES, k as PLATFORM_PERMISSIONS, l as PermissionKey, m as PipelineStage, n as PlatformPermissionKey, W as WORKSPACE_PERMISSIONS, o as WORKSPACE_ROLES, p as WorkspacePermissionKey, q as WorkspaceRole, r as appScopes, s as dashRole, t as emptySnapshot, u as entryCoversApp, v as fetchAccessSnapshot, w as hasAllPermissions, x as hasAnyPermission, y as hasPermission, z as hasWorkspacePermission, B as isAccessSnapshotError, C as isPipelineStage, E as isPlatformOwner, G as managedDashes, H as parseAccessSnapshot, I as permissionsFor } from '../index-BcDlVbUd.js';
1
+ import { A as AccessSnapshot, P as PermissionCheckOptions, R as Resolvable } from '../index-D-cH_sfe.js';
2
+ export { a as AccessEntry, b as AccessErrorCode, c as AccessScopeType, d as AccessSnapshotError, D as DASH_PERMISSIONS, e as DASH_ROLES, f as DEFAULT_ACCESS_ENDPOINT_PATH, g as DashPermissionKey, h as DashRole, F as FetchAccessSnapshotOptions, L as LEADBROKER_PERMISSIONS, i as LeadBrokerPermissionKey, j as PIPELINE_STAGES, k as PLATFORM_PERMISSIONS, l as PermissionKey, m as PipelineStage, n as PlatformPermissionKey, W as WORKSPACE_PERMISSIONS, o as WORKSPACE_ROLES, p as WorkspacePermissionKey, q as WorkspaceRole, r as appScopes, s as dashRole, t as emptySnapshot, u as entryCoversApp, v as fetchAccessSnapshot, w as hasAllPermissions, x as hasAnyPermission, y as hasPermission, z as hasWorkspacePermission, B as isAccessSnapshotError, C as isPipelineStage, E as isPlatformOwner, G as managedDashes, H as parseAccessSnapshot, I as permissionsFor } from '../index-D-cH_sfe.js';
3
3
 
4
4
  /** Default cache tag for one subject's snapshot: `access:<subjectId>`. */
5
5
  declare function accessCacheTag(subjectId: string): string;
@@ -87,8 +87,13 @@ function forwardedRequestHeaders(request, init) {
87
87
  return applyForwardedClientHeaders(request.headers, new Headers(init));
88
88
  }
89
89
 
90
+ // src/forwarding.ts
91
+ function forwardedRequestHeaders2(request, init) {
92
+ return forwardedRequestHeaders(request, init);
93
+ }
94
+
90
95
  // src/access/snapshot.ts
91
- var SCOPE_TYPES = /* @__PURE__ */ new Set(["platform", "saas_app", "workspace"]);
96
+ var SCOPE_TYPES = /* @__PURE__ */ new Set(["platform", "dash_id", "workspace"]);
92
97
  function emptySnapshot(subjectId = "") {
93
98
  return {
94
99
  subject_id: subjectId,
@@ -121,7 +126,7 @@ function parseAccessSnapshot(input) {
121
126
  if (!isRecord(raw)) fail(`permissions[${i}]`, "is not an object");
122
127
  const { key, scope_type, scope_id } = raw;
123
128
  if (typeof key !== "string" || key === "") fail(`permissions[${i}].key`, "must be a non-empty string");
124
- if (typeof scope_type !== "string" || !SCOPE_TYPES.has(scope_type)) fail(`permissions[${i}].scope_type`, "must be platform|saas_app|workspace");
129
+ if (typeof scope_type !== "string" || !SCOPE_TYPES.has(scope_type)) fail(`permissions[${i}].scope_type`, "must be platform|dash_id|workspace");
125
130
  if (scope_id !== void 0 && scope_id !== null && typeof scope_id !== "string") fail(`permissions[${i}].scope_id`, "must be a string");
126
131
  return { key, scope_type, scope_id: typeof scope_id === "string" ? scope_id : "" };
127
132
  });
@@ -166,7 +171,7 @@ function parseAccessSnapshot(input) {
166
171
  var DEFAULT_ACCESS_ENDPOINT_PATH = "/api/v1/platform/access";
167
172
  async function fetchAccessSnapshot(opts) {
168
173
  const url = `${resolveValue(opts.apiUrl).replace(/\/$/, "")}${opts.endpointPath ?? DEFAULT_ACCESS_ENDPOINT_PATH}`;
169
- const headers = opts.request ? forwardedRequestHeaders(opts.request, opts.headers) : new Headers(opts.headers);
174
+ const headers = opts.request ? forwardedRequestHeaders2(opts.request, opts.headers) : new Headers(opts.headers);
170
175
  headers.set("Authorization", `Bearer ${opts.accessToken}`);
171
176
  headers.set("Accept", "application/json");
172
177
  let response;
@@ -192,20 +197,20 @@ async function fetchAccessSnapshot(opts) {
192
197
  }
193
198
 
194
199
  // src/access/predicates.ts
195
- function entryCoversApp(entry, saasApp) {
200
+ function entryCoversApp(entry, dashId) {
196
201
  switch (entry.scope_type) {
197
202
  case "platform":
198
203
  return true;
199
- case "saas_app":
200
- if (saasApp === void 0) return true;
201
- return entry.scope_id === "*" || entry.scope_id.toLowerCase() === saasApp.toLowerCase();
204
+ case "dash_id":
205
+ if (dashId === void 0) return true;
206
+ return entry.scope_id === "*" || entry.scope_id.toLowerCase() === dashId.toLowerCase();
202
207
  default:
203
208
  return false;
204
209
  }
205
210
  }
206
211
  function hasPermission(snapshot, key, opts = {}) {
207
212
  if (!snapshot.active) return false;
208
- return snapshot.permissions.some((entry) => entry.key === key && entryCoversApp(entry, opts.saasApp));
213
+ return snapshot.permissions.some((entry) => entry.key === key && entryCoversApp(entry, opts.dashId));
209
214
  }
210
215
  function hasAnyPermission(snapshot, keys, opts = {}) {
211
216
  return keys.some((key) => hasPermission(snapshot, key, opts));
@@ -220,11 +225,11 @@ function hasWorkspacePermission(snapshot, workspaceId, key) {
220
225
  }
221
226
  function managedDashes(snapshot) {
222
227
  if (!snapshot.active) return [];
223
- return Object.entries(snapshot.dash_roles).map(([saasApp, role]) => ({ saasApp, role })).sort((a, b) => a.saasApp.localeCompare(b.saasApp));
228
+ return Object.entries(snapshot.dash_roles).map(([dashId, role]) => ({ dashId, role })).sort((a, b) => a.dashId.localeCompare(b.dashId));
224
229
  }
225
- function dashRole(snapshot, saasApp) {
230
+ function dashRole(snapshot, dashId) {
226
231
  if (!snapshot.active) return "";
227
- return snapshot.dash_roles[saasApp] ?? "";
232
+ return snapshot.dash_roles[dashId] ?? "";
228
233
  }
229
234
  function isPlatformOwner(snapshot) {
230
235
  return snapshot.active && snapshot.is_owner;
@@ -235,7 +240,7 @@ function appScopes(snapshot, key) {
235
240
  for (const entry of snapshot.permissions) {
236
241
  if (entry.key !== key) continue;
237
242
  if (entry.scope_type === "platform") return { all: true, apps: [] };
238
- if (entry.scope_type === "saas_app") {
243
+ if (entry.scope_type === "dash_id") {
239
244
  if (entry.scope_id === "*") return { all: true, apps: [] };
240
245
  apps.add(entry.scope_id.toLowerCase());
241
246
  }
@@ -245,7 +250,7 @@ function appScopes(snapshot, key) {
245
250
  function permissionsFor(snapshot, opts = {}) {
246
251
  if (!snapshot.active) return [];
247
252
  const keys = /* @__PURE__ */ new Set();
248
- for (const entry of snapshot.permissions) if (entryCoversApp(entry, opts.saasApp)) keys.add(entry.key);
253
+ for (const entry of snapshot.permissions) if (entryCoversApp(entry, opts.dashId)) keys.add(entry.key);
249
254
  return [...keys].sort();
250
255
  }
251
256
 
@@ -264,20 +269,25 @@ var PLATFORM_PERMISSIONS = [
264
269
  "platform.audit.view",
265
270
  "platform.auth.manage",
266
271
  "platform.billing.manage",
272
+ "platform.billing.view",
267
273
  "platform.channels.manage",
268
274
  "platform.channels.view",
269
275
  "platform.config.manage",
270
276
  "platform.docs.manage",
271
277
  "platform.docs.view",
278
+ "platform.mcp.access",
279
+ "platform.mcp.tokens.manage",
272
280
  "platform.observability.manage",
273
281
  "platform.observability.view",
274
282
  "platform.offboarding.view",
275
283
  "platform.ops.manage",
284
+ "platform.ops.view",
276
285
  "platform.support.impersonate",
277
286
  "platform.support.sessions",
278
287
  "platform.tenants.archive",
279
288
  "platform.tenants.manage",
280
289
  "platform.tenants.restore",
290
+ "platform.tenants.view",
281
291
  "platform.users.deactivate",
282
292
  "platform.users.delete",
283
293
  "platform.users.invite",
@@ -288,16 +298,20 @@ var PLATFORM_PERMISSIONS = [
288
298
  var DASH_PERMISSIONS = [
289
299
  "dash.apps.manage",
290
300
  "dash.billing.manage",
301
+ "dash.billing.view",
291
302
  "dash.channels.manage",
292
303
  "dash.customers.manage",
293
304
  "dash.domains.manage",
305
+ "dash.domains.view",
294
306
  "dash.members.manage",
295
307
  "dash.ownership.transfer",
296
308
  "dash.plans.manage",
309
+ "dash.plans.view",
297
310
  "dash.publish",
298
311
  "dash.settings.manage",
299
312
  "dash.workspaces.admin",
300
- "dash.workspaces.manage"
313
+ "dash.workspaces.manage",
314
+ "dash.workspaces.view"
301
315
  ];
302
316
  var DASH_ROLES = [
303
317
  "dash.admin",
@@ -2,12 +2,12 @@ import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
 
4
4
  /** Scope a permission entry applies to. Mirrors c1m-server authz.Scope*. */
5
- type AccessScopeType = "platform" | "saas_app" | "workspace";
5
+ type AccessScopeType = "platform" | "dash_id" | "workspace";
6
6
  interface AccessEntry {
7
7
  /** Permission key, e.g. "platform.users.manage_access". */
8
8
  key: string;
9
9
  scope_type: AccessScopeType;
10
- /** "" for platform scope; saas_app slug or "*" for saas_app scope; workspace id for workspace scope. */
10
+ /** "" for platform scope; dash id or "*" for dash scope; workspace id for workspace scope. */
11
11
  scope_id: string;
12
12
  }
13
13
  /**
@@ -25,10 +25,10 @@ interface AccessSnapshot {
25
25
  platform_role: string;
26
26
  permissions: AccessEntry[];
27
27
  /**
28
- * Dash bundle (`dash.owner` / `dash.admin`) per saas_app id, mirrored from
28
+ * Dash bundle (`dash.owner` / `dash.admin`) per dash id, mirrored from
29
29
  * the subject's dash membership. This is the admission list for the dash
30
30
  * area: the dashes this subject runs. What they may *do* on one is a normal
31
- * `hasPermission(snapshot, key, { saasApp })` check — platform managers hold
31
+ * `hasPermission(snapshot, key, { dashId })` check — platform managers hold
32
32
  * their authority platform-wide and so appear here not at all.
33
33
  */
34
34
  dash_roles: Record<string, string>;
@@ -40,10 +40,10 @@ interface AccessSnapshot {
40
40
 
41
41
  interface PermissionCheckOptions {
42
42
  /**
43
- * SaaS app (dash) slug the check is about. Omit for "anywhere": platform
44
- * entries and any saas_app entry satisfy the check.
43
+ * Dash slug the check is about. Omit for "anywhere": platform
44
+ * entries and any dash-scoped entry satisfy the check.
45
45
  */
46
- saasApp?: string;
46
+ dashId?: string;
47
47
  }
48
48
 
49
49
  interface AccessProviderProps {
@@ -70,6 +70,6 @@ interface CanProps extends PermissionCheckOptions {
70
70
  children: ReactNode;
71
71
  }
72
72
  /** Render-gate. Presentation only — the backend remains the security boundary. */
73
- declare function Can({ permission, mode, workspaceId, saasApp, not, fallback, children }: CanProps): react.JSX.Element;
73
+ declare function Can({ permission, mode, workspaceId, dashId, not, fallback, children }: CanProps): react.JSX.Element;
74
74
 
75
75
  export { AccessProvider, type AccessProviderProps, Can, type CanProps, useAccess, useAccessOrEmpty, useCan, useCanWorkspace, useIsPlatformOwner };
@@ -4,20 +4,20 @@
4
4
  import { createContext, useContext, useMemo } from "react";
5
5
 
6
6
  // src/access/predicates.ts
7
- function entryCoversApp(entry, saasApp) {
7
+ function entryCoversApp(entry, dashId) {
8
8
  switch (entry.scope_type) {
9
9
  case "platform":
10
10
  return true;
11
- case "saas_app":
12
- if (saasApp === void 0) return true;
13
- return entry.scope_id === "*" || entry.scope_id.toLowerCase() === saasApp.toLowerCase();
11
+ case "dash_id":
12
+ if (dashId === void 0) return true;
13
+ return entry.scope_id === "*" || entry.scope_id.toLowerCase() === dashId.toLowerCase();
14
14
  default:
15
15
  return false;
16
16
  }
17
17
  }
18
18
  function hasPermission(snapshot, key, opts = {}) {
19
19
  if (!snapshot.active) return false;
20
- return snapshot.permissions.some((entry) => entry.key === key && entryCoversApp(entry, opts.saasApp));
20
+ return snapshot.permissions.some((entry) => entry.key === key && entryCoversApp(entry, opts.dashId));
21
21
  }
22
22
  function hasWorkspacePermission(snapshot, workspaceId, key) {
23
23
  if (!snapshot.active) return false;
@@ -69,10 +69,10 @@ function useCanWorkspace(workspaceId) {
69
69
  function useIsPlatformOwner() {
70
70
  return isPlatformOwner(useAccess());
71
71
  }
72
- function Can({ permission, mode = "all", workspaceId, saasApp, not = false, fallback = null, children }) {
72
+ function Can({ permission, mode = "all", workspaceId, dashId, not = false, fallback = null, children }) {
73
73
  const snapshot = useAccess();
74
74
  const keys = typeof permission === "string" ? [permission] : permission;
75
- const check = (key) => workspaceId !== void 0 ? hasWorkspacePermission(snapshot, workspaceId, key) : hasPermission(snapshot, key, { saasApp });
75
+ const check = (key) => workspaceId !== void 0 ? hasWorkspacePermission(snapshot, workspaceId, key) : hasPermission(snapshot, key, { dashId });
76
76
  const allowed = mode === "any" ? keys.some(check) : keys.every(check);
77
77
  return /* @__PURE__ */ jsx(Fragment, { children: allowed !== not ? children : fallback });
78
78
  }
@@ -1,8 +1,8 @@
1
1
  /** Platform-operator permission keys. */
2
- declare const PLATFORM_PERMISSIONS: readonly ["affiliates.enrollments.manage", "affiliates.finance.manage", "affiliates.partners.manage", "affiliates.programmes.manage", "affiliates.view", "linkservice.domains.manage", "linkservice.links.manage", "linkservice.qr.manage", "linkservice.view", "platform.admin.view", "platform.audit.view", "platform.auth.manage", "platform.billing.manage", "platform.channels.manage", "platform.channels.view", "platform.config.manage", "platform.docs.manage", "platform.docs.view", "platform.observability.manage", "platform.observability.view", "platform.offboarding.view", "platform.ops.manage", "platform.support.impersonate", "platform.support.sessions", "platform.tenants.archive", "platform.tenants.manage", "platform.tenants.restore", "platform.users.deactivate", "platform.users.delete", "platform.users.invite", "platform.users.manage_access", "platform.users.reactivate", "platform.users.view"];
2
+ declare const PLATFORM_PERMISSIONS: readonly ["affiliates.enrollments.manage", "affiliates.finance.manage", "affiliates.partners.manage", "affiliates.programmes.manage", "affiliates.view", "linkservice.domains.manage", "linkservice.links.manage", "linkservice.qr.manage", "linkservice.view", "platform.admin.view", "platform.audit.view", "platform.auth.manage", "platform.billing.manage", "platform.billing.view", "platform.channels.manage", "platform.channels.view", "platform.config.manage", "platform.docs.manage", "platform.docs.view", "platform.mcp.access", "platform.mcp.tokens.manage", "platform.observability.manage", "platform.observability.view", "platform.offboarding.view", "platform.ops.manage", "platform.ops.view", "platform.support.impersonate", "platform.support.sessions", "platform.tenants.archive", "platform.tenants.manage", "platform.tenants.restore", "platform.tenants.view", "platform.users.deactivate", "platform.users.delete", "platform.users.invite", "platform.users.manage_access", "platform.users.reactivate", "platform.users.view"];
3
3
  type PlatformPermissionKey = (typeof PLATFORM_PERMISSIONS)[number];
4
4
  /** Dash-owner permission keys (granted at dash scope, mirrored from the membership role). */
5
- declare const DASH_PERMISSIONS: readonly ["dash.apps.manage", "dash.billing.manage", "dash.channels.manage", "dash.customers.manage", "dash.domains.manage", "dash.members.manage", "dash.ownership.transfer", "dash.plans.manage", "dash.publish", "dash.settings.manage", "dash.workspaces.admin", "dash.workspaces.manage"];
5
+ declare const DASH_PERMISSIONS: readonly ["dash.apps.manage", "dash.billing.manage", "dash.billing.view", "dash.channels.manage", "dash.customers.manage", "dash.domains.manage", "dash.domains.view", "dash.members.manage", "dash.ownership.transfer", "dash.plans.manage", "dash.plans.view", "dash.publish", "dash.settings.manage", "dash.workspaces.admin", "dash.workspaces.manage", "dash.workspaces.view"];
6
6
  type DashPermissionKey = (typeof DASH_PERMISSIONS)[number];
7
7
  /** Membership-mirrored dash role bundles (grant keys at dash scope). */
8
8
  declare const DASH_ROLES: readonly ["dash.admin", "dash.owner"];
@@ -39,12 +39,12 @@ declare class AccessSnapshotError extends Error {
39
39
  declare function isAccessSnapshotError(error: unknown, code?: AccessErrorCode): error is AccessSnapshotError;
40
40
 
41
41
  /** Scope a permission entry applies to. Mirrors c1m-server authz.Scope*. */
42
- type AccessScopeType = "platform" | "saas_app" | "workspace";
42
+ type AccessScopeType = "platform" | "dash_id" | "workspace";
43
43
  interface AccessEntry {
44
44
  /** Permission key, e.g. "platform.users.manage_access". */
45
45
  key: string;
46
46
  scope_type: AccessScopeType;
47
- /** "" for platform scope; saas_app slug or "*" for saas_app scope; workspace id for workspace scope. */
47
+ /** "" for platform scope; dash id or "*" for dash scope; workspace id for workspace scope. */
48
48
  scope_id: string;
49
49
  }
50
50
  /**
@@ -62,10 +62,10 @@ interface AccessSnapshot {
62
62
  platform_role: string;
63
63
  permissions: AccessEntry[];
64
64
  /**
65
- * Dash bundle (`dash.owner` / `dash.admin`) per saas_app id, mirrored from
65
+ * Dash bundle (`dash.owner` / `dash.admin`) per dash id, mirrored from
66
66
  * the subject's dash membership. This is the admission list for the dash
67
67
  * area: the dashes this subject runs. What they may *do* on one is a normal
68
- * `hasPermission(snapshot, key, { saasApp })` check — platform managers hold
68
+ * `hasPermission(snapshot, key, { dashId })` check — platform managers hold
69
69
  * their authority platform-wide and so appear here not at all.
70
70
  */
71
71
  dash_roles: Record<string, string>;
@@ -80,17 +80,17 @@ declare function parseAccessSnapshot(input: unknown): AccessSnapshot;
80
80
 
81
81
  interface PermissionCheckOptions {
82
82
  /**
83
- * SaaS app (dash) slug the check is about. Omit for "anywhere": platform
84
- * entries and any saas_app entry satisfy the check.
83
+ * Dash slug the check is about. Omit for "anywhere": platform
84
+ * entries and any dash-scoped entry satisfy the check.
85
85
  */
86
- saasApp?: string;
86
+ dashId?: string;
87
87
  }
88
88
  /**
89
89
  * Mirrors c1m-server authz.entryCoversApp: platform scope covers every app;
90
- * saas_app scope covers "*" or a case-insensitive slug match; workspace-scoped
90
+ * Dash scope covers "*" or a case-insensitive dash-id match; workspace-scoped
91
91
  * entries never satisfy an app-level check.
92
92
  */
93
- declare function entryCoversApp(entry: AccessEntry, saasApp: string | undefined): boolean;
93
+ declare function entryCoversApp(entry: AccessEntry, dashId: string | undefined): boolean;
94
94
  /** True when the subject is active and holds `key` for the given app (or anywhere). */
95
95
  declare function hasPermission(snapshot: AccessSnapshot, key: string, opts?: PermissionCheckOptions): boolean;
96
96
  declare function hasAnyPermission(snapshot: AccessSnapshot, keys: readonly string[], opts?: PermissionCheckOptions): boolean;
@@ -98,7 +98,7 @@ declare function hasAllPermissions(snapshot: AccessSnapshot, keys: readonly stri
98
98
  /**
99
99
  * Workspace-staff check. Platform owners always pass (they own every
100
100
  * workspace); otherwise the workspace's effective permission list decides.
101
- * Platform/saas_app entries never confer workspace-staff permissions.
101
+ * Platform/dash entries never confer workspace-staff permissions.
102
102
  */
103
103
  declare function hasWorkspacePermission(snapshot: AccessSnapshot, workspaceId: string, key: string): boolean;
104
104
  /**
@@ -108,14 +108,14 @@ declare function hasWorkspacePermission(snapshot: AccessSnapshot, workspaceId: s
108
108
  * `hasPermission(snapshot, "platform.tenants.manage")` instead.
109
109
  */
110
110
  declare function managedDashes(snapshot: AccessSnapshot): Array<{
111
- saasApp: string;
111
+ dashId: string;
112
112
  role: string;
113
113
  }>;
114
114
  /** The dash bundle held on one dash, or "" when the subject holds none there. */
115
- declare function dashRole(snapshot: AccessSnapshot, saasApp: string): string;
115
+ declare function dashRole(snapshot: AccessSnapshot, dashId: string): string;
116
116
  declare function isPlatformOwner(snapshot: AccessSnapshot): boolean;
117
117
  /**
118
- * The saas_app scopes under which `key` is held. Returns `{ all: true }` when a
118
+ * The dash scopes under which `key` is held. Returns `{ all: true }` when a
119
119
  * platform-scoped or "*" entry grants it everywhere; otherwise the explicit
120
120
  * app slugs (empty = nowhere). Mirrors authz.AppPermissionScope.
121
121
  */
@@ -123,7 +123,7 @@ declare function appScopes(snapshot: AccessSnapshot, key: string): {
123
123
  all: boolean;
124
124
  apps: string[];
125
125
  };
126
- /** Distinct permission keys held for `saasApp` (or anywhere). Handy for nav/badges. */
126
+ /** Distinct permission keys held for `dashId` (or anywhere). Handy for nav/badges. */
127
127
  declare function permissionsFor(snapshot: AccessSnapshot, opts?: PermissionCheckOptions): string[];
128
128
 
129
129
  /** A value that may be fixed or resolved per call (env read at request time). */
@@ -1,5 +1,3 @@
1
- import '@c1m-public/transport';
2
-
3
1
  interface SessionUser {
4
2
  id: string;
5
3
  email: string;
@@ -59,6 +57,9 @@ declare function parseAuthResponse(value: unknown): AuthResponse | null;
59
57
  */
60
58
  declare function safeInternalPath(raw: string | null | undefined): string | null;
61
59
 
60
+ declare function applyForwardedClientHeaders(incoming: Headers, headers?: Headers): Headers;
61
+ declare function forwardedRequestHeaders(request: Request, init?: HeadersInit): Headers;
62
+
62
63
  interface CookieOptions {
63
64
  httpOnly?: boolean;
64
65
  secure?: boolean;
@@ -232,4 +233,4 @@ interface SessionGateInput {
232
233
  }
233
234
  declare function evaluateSessionGate(input: SessionGateInput): Promise<SessionGateDecision>;
234
235
 
235
- export { type AsyncResolvable as A, deleteCookie as B, type CookieOptions as C, type DeviceIdentity as D, evaluateSessionGate as E, handoffErrorMessage as F, hasSessionShape as G, HANDOFF_ERROR_FALLBACK as H, hasTokenAudience as I, isAuthErrorCode as J, isHandoffErrorCode as K, isTokenExpired as L, isTokenExpiringSoon as M, parseAuthResponse as N, parseRefreshEnvelope as O, readCookie as P, safeInternalPath as Q, type Resolvable as R, type SessionData as S, type TokenPayload as T, serializeCookie as U, setCookie as V, sourceStartPath as W, tokenMaxAgeSeconds as X, AUTH_ERROR_MESSAGES as a, type AuthResponse as b, type DeviceIdentityConfig as c, type DeviceIdentityStore as d, HANDOFF_ERROR_MESSAGES as e, type HandoffSource as f, type HandoffSourceConfig as g, type HandoffSourceTarget as h, type HandoffTarget as i, type HandoffTargetConfig as j, type RefreshedSession as k, SSO_ERROR_MESSAGES as l, type SessionGateDecision as m, type SessionGateInput as n, type SessionRefresher as o, type SessionRefresherConfig as p, type SessionUser as q, authErrorMessage as r, brokerPaths as s, createDeviceIdentity as t, createHandoffSource as u, createHandoffTarget as v, createSessionRefresher as w, decodeBase64Url as x, decodeDefaultSession as y, decodeTokenPayload as z };
236
+ export { type AsyncResolvable as A, decodeTokenPayload as B, type CookieOptions as C, type DeviceIdentity as D, deleteCookie as E, evaluateSessionGate as F, forwardedRequestHeaders as G, HANDOFF_ERROR_FALLBACK as H, handoffErrorMessage as I, hasSessionShape as J, hasTokenAudience as K, isAuthErrorCode as L, isHandoffErrorCode as M, isTokenExpired as N, isTokenExpiringSoon as O, parseAuthResponse as P, parseRefreshEnvelope as Q, type Resolvable as R, type SessionData as S, type TokenPayload as T, readCookie as U, safeInternalPath as V, serializeCookie as W, setCookie as X, sourceStartPath as Y, tokenMaxAgeSeconds as Z, AUTH_ERROR_MESSAGES as a, type AuthResponse as b, type DeviceIdentityConfig as c, type DeviceIdentityStore as d, HANDOFF_ERROR_MESSAGES as e, type HandoffSource as f, type HandoffSourceConfig as g, type HandoffSourceTarget as h, type HandoffTarget as i, type HandoffTargetConfig as j, type RefreshedSession as k, SSO_ERROR_MESSAGES as l, type SessionGateDecision as m, type SessionGateInput as n, type SessionRefresher as o, type SessionRefresherConfig as p, type SessionUser as q, applyForwardedClientHeaders as r, authErrorMessage as s, brokerPaths as t, createDeviceIdentity as u, createHandoffSource as v, createHandoffTarget as w, createSessionRefresher as x, decodeBase64Url as y, decodeDefaultSession as z };
package/dist/index.d.ts CHANGED
@@ -1,2 +1 @@
1
- export { a as AUTH_ERROR_MESSAGES, b as AuthResponse, C as CookieOptions, D as DeviceIdentity, c as DeviceIdentityConfig, d as DeviceIdentityStore, H as HANDOFF_ERROR_FALLBACK, e as HANDOFF_ERROR_MESSAGES, f as HandoffSource, g as HandoffSourceConfig, h as HandoffSourceTarget, i as HandoffTarget, j as HandoffTargetConfig, k as RefreshedSession, l as SSO_ERROR_MESSAGES, S as SessionData, m as SessionGateDecision, n as SessionGateInput, o as SessionRefresher, p as SessionRefresherConfig, q as SessionUser, T as TokenPayload, r as authErrorMessage, s as brokerPaths, t as createDeviceIdentity, u as createHandoffSource, v as createHandoffTarget, w as createSessionRefresher, x as decodeBase64Url, y as decodeDefaultSession, z as decodeTokenPayload, B as deleteCookie, E as evaluateSessionGate, F as handoffErrorMessage, G as hasSessionShape, I as hasTokenAudience, J as isAuthErrorCode, K as isHandoffErrorCode, L as isTokenExpired, M as isTokenExpiringSoon, N as parseAuthResponse, O as parseRefreshEnvelope, P as readCookie, Q as safeInternalPath, U as serializeCookie, V as setCookie, W as sourceStartPath, X as tokenMaxAgeSeconds } from './index-BnchfjP_.js';
2
- export { applyForwardedClientHeaders, forwardedRequestHeaders } from '@c1m-public/transport';
1
+ export { a as AUTH_ERROR_MESSAGES, b as AuthResponse, C as CookieOptions, D as DeviceIdentity, c as DeviceIdentityConfig, d as DeviceIdentityStore, H as HANDOFF_ERROR_FALLBACK, e as HANDOFF_ERROR_MESSAGES, f as HandoffSource, g as HandoffSourceConfig, h as HandoffSourceTarget, i as HandoffTarget, j as HandoffTargetConfig, k as RefreshedSession, l as SSO_ERROR_MESSAGES, S as SessionData, m as SessionGateDecision, n as SessionGateInput, o as SessionRefresher, p as SessionRefresherConfig, q as SessionUser, T as TokenPayload, r as applyForwardedClientHeaders, s as authErrorMessage, t as brokerPaths, u as createDeviceIdentity, v as createHandoffSource, w as createHandoffTarget, x as createSessionRefresher, y as decodeBase64Url, z as decodeDefaultSession, B as decodeTokenPayload, E as deleteCookie, F as evaluateSessionGate, G as forwardedRequestHeaders, I as handoffErrorMessage, J as hasSessionShape, K as hasTokenAudience, L as isAuthErrorCode, M as isHandoffErrorCode, N as isTokenExpired, O as isTokenExpiringSoon, P as parseAuthResponse, Q as parseRefreshEnvelope, U as readCookie, V as safeInternalPath, W as serializeCookie, X as setCookie, Y as sourceStartPath, Z as tokenMaxAgeSeconds } from './index-aKe58m6n.js';
package/dist/index.js CHANGED
@@ -123,6 +123,14 @@ function forwardedRequestHeaders(request, init) {
123
123
  return applyForwardedClientHeaders(request.headers, new Headers(init));
124
124
  }
125
125
 
126
+ // src/forwarding.ts
127
+ function applyForwardedClientHeaders2(incoming, headers = new Headers()) {
128
+ return applyForwardedClientHeaders(incoming, headers);
129
+ }
130
+ function forwardedRequestHeaders2(request, init) {
131
+ return forwardedRequestHeaders(request, init);
132
+ }
133
+
126
134
  // src/cookies.ts
127
135
  function readCookie(request, name) {
128
136
  const header = request.headers.get("cookie");
@@ -373,7 +381,7 @@ function createHandoffTarget(config) {
373
381
  const device = config.device.read(request);
374
382
  const respond = (response) => config.device.persist(response, device);
375
383
  try {
376
- const headers = forwardedRequestHeaders(request, {
384
+ const headers = forwardedRequestHeaders2(request, {
377
385
  "Content-Type": "application/json",
378
386
  "X-Client-Type": config.clientType,
379
387
  "X-Client-Device-ID": device.value
@@ -422,7 +430,7 @@ function createHandoffSource(config) {
422
430
  const token = await config.getAccessToken(request);
423
431
  if (!token) return sourceLogin();
424
432
  try {
425
- const headers = forwardedRequestHeaders(request, {
433
+ const headers = forwardedRequestHeaders2(request, {
426
434
  "Content-Type": "application/json",
427
435
  "X-Client-Type": config.clientType,
428
436
  Authorization: `Bearer ${token}`
@@ -549,4 +557,4 @@ async function evaluateSessionGate(input) {
549
557
  return { kind: "redirect_login" };
550
558
  }
551
559
 
552
- export { AUTH_ERROR_MESSAGES, HANDOFF_ERROR_FALLBACK, HANDOFF_ERROR_MESSAGES, SSO_ERROR_MESSAGES, applyForwardedClientHeaders, authErrorMessage, brokerPaths, createDeviceIdentity, createHandoffSource, createHandoffTarget, createSessionRefresher, decodeBase64Url, decodeDefaultSession, decodeTokenPayload, deleteCookie, evaluateSessionGate, forwardedRequestHeaders, handoffErrorMessage, hasSessionShape, hasTokenAudience, isAuthErrorCode, isHandoffErrorCode, isTokenExpired, isTokenExpiringSoon, parseAuthResponse, parseRefreshEnvelope, readCookie, safeInternalPath, serializeCookie, setCookie, sourceStartPath, tokenMaxAgeSeconds };
560
+ export { AUTH_ERROR_MESSAGES, HANDOFF_ERROR_FALLBACK, HANDOFF_ERROR_MESSAGES, SSO_ERROR_MESSAGES, applyForwardedClientHeaders2 as applyForwardedClientHeaders, authErrorMessage, brokerPaths, createDeviceIdentity, createHandoffSource, createHandoffTarget, createSessionRefresher, decodeBase64Url, decodeDefaultSession, decodeTokenPayload, deleteCookie, evaluateSessionGate, forwardedRequestHeaders2 as forwardedRequestHeaders, handoffErrorMessage, hasSessionShape, hasTokenAudience, isAuthErrorCode, isHandoffErrorCode, isTokenExpired, isTokenExpiringSoon, parseAuthResponse, parseRefreshEnvelope, readCookie, safeInternalPath, serializeCookie, setCookie, sourceStartPath, tokenMaxAgeSeconds };
@@ -0,0 +1,79 @@
1
+ declare const MCP_TOOL_PERMISSIONS: readonly ["dash.domains.view", "dash.workspaces.view", "platform.audit.view", "platform.ops.manage", "platform.ops.view", "platform.tenants.view"];
2
+ declare const MCP_WILDCARD_TOOL_PERMISSIONS: readonly ["dash.domains.view", "dash.workspaces.view", "platform.audit.view", "platform.ops.view", "platform.tenants.view"];
3
+ type MCPToolPermission = (typeof MCP_TOOL_PERMISSIONS)[number];
4
+
5
+ declare const MCP_ACCESS_PERMISSION: "platform.mcp.access";
6
+ declare const MCP_TOKENS_MANAGE_PERMISSION: "platform.mcp.tokens.manage";
7
+ declare const MCP_PERMISSION_WILDCARD: "*";
8
+ type MCPTokenPermission = typeof MCP_ACCESS_PERMISSION | typeof MCP_PERMISSION_WILDCARD | MCPToolPermission;
9
+ type MCPTokenOperation = "platform_user.auth.mcp_tokens.list" | "platform_user.auth.mcp_tokens.mint" | "platform_user.auth.mcp_tokens.revoke";
10
+ type MCPTokenRequestOutcome = "success" | "api_error" | "network_error" | "timeout" | "invalid_response" | "cancelled";
11
+ interface MCPTokenView {
12
+ token_id: string;
13
+ name: string;
14
+ /** Recorded ceilings may include permissions added by a newer server. */
15
+ permissions: string[];
16
+ app_allowlist: string[];
17
+ created_at: string;
18
+ expires_at: string;
19
+ last_used_at?: string;
20
+ revoked_at?: string;
21
+ }
22
+ interface MCPTokenPage {
23
+ items: MCPTokenView[];
24
+ next_cursor?: string;
25
+ has_more: boolean;
26
+ mcp_enabled: boolean;
27
+ }
28
+ interface MCPTokenListParams {
29
+ cursor?: string;
30
+ limit?: number;
31
+ }
32
+ interface MintMCPTokenInput {
33
+ name: string;
34
+ expires_in_days: number;
35
+ permissions: MCPTokenPermission[];
36
+ app_allowlist: string[];
37
+ }
38
+ interface MintMCPTokenResponse {
39
+ token: MCPTokenView;
40
+ raw_token: string;
41
+ }
42
+ interface MCPTokenRequestObservation {
43
+ operation: MCPTokenOperation;
44
+ method: string;
45
+ outcome: MCPTokenRequestOutcome;
46
+ status: number;
47
+ requestId: string;
48
+ durationMs: number;
49
+ attempts: number;
50
+ }
51
+ interface CreateMCPTokenClientOptions {
52
+ baseUrl: string;
53
+ getAccessToken: () => Promise<string | null | undefined> | string | null | undefined;
54
+ getHeaders?: () => Promise<HeadersInit | undefined> | HeadersInit | undefined;
55
+ fetch?: typeof globalThis.fetch;
56
+ /** Per attempt (default 10000). */
57
+ timeoutMs?: number;
58
+ /** Additional attempts for GET only (default 1). Mint and revoke are never retried. */
59
+ retryAttempts?: number;
60
+ /** Cap on one retry delay (default 2000). */
61
+ maxRetryDelayMs?: number;
62
+ observe?: (event: MCPTokenRequestObservation) => void;
63
+ signal?: AbortSignal;
64
+ }
65
+ declare class MCPTokenAPIError extends Error {
66
+ readonly status: number;
67
+ readonly code: string;
68
+ readonly requestId: string;
69
+ constructor(message: string, status: number, code: string, requestId: string);
70
+ }
71
+ declare function isMCPTokenAPIError(error: unknown): error is MCPTokenAPIError;
72
+ declare function createMCPTokenClient(options: CreateMCPTokenClientOptions): {
73
+ readonly list: (params?: MCPTokenListParams) => Promise<MCPTokenPage>;
74
+ readonly mint: (input: MintMCPTokenInput) => Promise<MintMCPTokenResponse>;
75
+ readonly revoke: (tokenId: string) => Promise<void>;
76
+ };
77
+ type MCPTokenClient = ReturnType<typeof createMCPTokenClient>;
78
+
79
+ export { type CreateMCPTokenClientOptions, MCPTokenAPIError, type MCPTokenClient, type MCPTokenListParams, type MCPTokenOperation, type MCPTokenPage, type MCPTokenPermission, type MCPTokenRequestObservation, type MCPTokenRequestOutcome, type MCPTokenView, type MCPToolPermission, MCP_ACCESS_PERMISSION, MCP_PERMISSION_WILDCARD, MCP_TOKENS_MANAGE_PERMISSION, MCP_TOOL_PERMISSIONS, MCP_WILDCARD_TOOL_PERMISSIONS, type MintMCPTokenInput, type MintMCPTokenResponse, createMCPTokenClient, isMCPTokenAPIError };
@@ -0,0 +1,357 @@
1
+ // ../transport/src/index.ts
2
+ var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([429, 502, 503, 504]);
3
+ var TransportError = class extends Error {
4
+ constructor(failure) {
5
+ super(failure.message || failure.outcome);
6
+ this.failure = failure;
7
+ this.name = "TransportError";
8
+ }
9
+ failure;
10
+ };
11
+ function isTransportError(error) {
12
+ return error instanceof TransportError || typeof error === "object" && error !== null && error.name === "TransportError";
13
+ }
14
+ function positiveNumber(value, label, fail) {
15
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) throw fail(`${label} must be a positive finite number`);
16
+ return value;
17
+ }
18
+ function nonNegativeInteger(value, label, fail) {
19
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw fail(`${label} must be a non-negative safe integer`);
20
+ return value;
21
+ }
22
+ function requiredString(value, label, fail) {
23
+ const normalized = typeof value === "string" ? value.trim() : "";
24
+ if (!normalized) throw fail(`${label} is required`);
25
+ return normalized;
26
+ }
27
+ function backoffDelay(attempt, maxDelayMs) {
28
+ const base = Math.min(250 * 2 ** Math.max(attempt, 0), maxDelayMs);
29
+ return Math.floor(Math.random() * base);
30
+ }
31
+ function retryDelay(response, attempt, maxDelayMs) {
32
+ const value = response.headers.get("Retry-After");
33
+ if (!value) return backoffDelay(attempt, maxDelayMs);
34
+ const seconds = Number(value);
35
+ if (Number.isFinite(seconds)) return Math.min(Math.max(seconds * 1e3, 0), maxDelayMs);
36
+ const date = Date.parse(value);
37
+ return Number.isNaN(date) ? backoffDelay(attempt, maxDelayMs) : Math.min(Math.max(date - Date.now(), 0), maxDelayMs);
38
+ }
39
+ function wait(ms) {
40
+ return ms <= 0 ? Promise.resolve() : new Promise((resolve) => setTimeout(resolve, ms));
41
+ }
42
+ function combineSignals(...signals) {
43
+ const active = signals.filter((signal) => Boolean(signal));
44
+ if (active.length === 0) return void 0;
45
+ if (active.length === 1) return active[0];
46
+ return AbortSignal.any(active);
47
+ }
48
+ function isRetryableRequest(method, headers, retry) {
49
+ if (method === "GET") return true;
50
+ return retry.idempotentWrites === true && headers.has("Idempotency-Key");
51
+ }
52
+ async function performRequest(transport, url, init, observe, decode) {
53
+ const method = (init.method ?? "GET").toUpperCase();
54
+ const headers = new Headers(init.headers);
55
+ const startedAt = Date.now();
56
+ const retryable = isRetryableRequest(method, headers, transport.retry);
57
+ const maxAttempts = retryable ? transport.retry.attempts : 0;
58
+ let attempts = 0;
59
+ let status = 0;
60
+ let requestId = "";
61
+ let outcome = "network_error";
62
+ const fail = (failure) => {
63
+ outcome = failure.outcome;
64
+ throw new TransportError({ requestId, ...failure });
65
+ };
66
+ try {
67
+ let response;
68
+ for (let attempt = 0; attempt <= maxAttempts; attempt += 1) {
69
+ attempts = attempt + 1;
70
+ const controller = new AbortController();
71
+ const timeout = setTimeout(() => controller.abort(), transport.timeoutMs);
72
+ try {
73
+ response = await transport.fetch(url, {
74
+ ...init,
75
+ method,
76
+ headers,
77
+ signal: combineSignals(transport.signal, init.signal, controller.signal)
78
+ });
79
+ } catch {
80
+ if (controller.signal.aborted) fail({ outcome: "timeout", status: 0, code: "", message: "" });
81
+ if (transport.signal?.aborted || init.signal?.aborted) fail({ outcome: "cancelled", status: 0, code: "", message: "" });
82
+ if (attempt < maxAttempts) {
83
+ await wait(backoffDelay(attempt, transport.retry.maxDelayMs));
84
+ continue;
85
+ }
86
+ fail({ outcome: "network_error", status: 0, code: "", message: "" });
87
+ } finally {
88
+ clearTimeout(timeout);
89
+ }
90
+ if (!RETRYABLE_STATUSES.has(response.status) || attempt === maxAttempts) break;
91
+ await wait(retryDelay(response, attempt, transport.retry.maxDelayMs));
92
+ }
93
+ if (!response) return fail({ outcome: "network_error", status: 0, code: "", message: "" });
94
+ status = response.status;
95
+ requestId = response.headers.get("X-Request-ID") ?? "";
96
+ if (!response.ok) {
97
+ const envelope = await response.json().catch(() => ({}));
98
+ if (typeof envelope.request_id === "string") requestId = envelope.request_id;
99
+ return fail({
100
+ outcome: "api_error",
101
+ status,
102
+ code: typeof envelope.code === "string" ? envelope.code : "",
103
+ message: typeof envelope.message === "string" ? envelope.message : "",
104
+ requestId
105
+ });
106
+ }
107
+ let payload;
108
+ try {
109
+ if (status === 204) {
110
+ payload = void 0;
111
+ } else {
112
+ const text = await response.text();
113
+ const parsed = text ? JSON.parse(text) : void 0;
114
+ payload = decode ? decode(parsed) : parsed;
115
+ }
116
+ } catch {
117
+ return fail({ outcome: "invalid_response", status, code: "", message: "", requestId });
118
+ }
119
+ outcome = "success";
120
+ return { payload, status, requestId };
121
+ } finally {
122
+ if (observe) {
123
+ try {
124
+ observe({ method, outcome, status, requestId, durationMs: Math.max(0, Date.now() - startedAt), attempts });
125
+ } catch {
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ // src/access/generated/mcp-tools.ts
132
+ var MCP_TOOL_PERMISSIONS = [
133
+ "dash.domains.view",
134
+ "dash.workspaces.view",
135
+ "platform.audit.view",
136
+ "platform.ops.manage",
137
+ "platform.ops.view",
138
+ "platform.tenants.view"
139
+ ];
140
+ var MCP_WILDCARD_TOOL_PERMISSIONS = [
141
+ "dash.domains.view",
142
+ "dash.workspaces.view",
143
+ "platform.audit.view",
144
+ "platform.ops.view",
145
+ "platform.tenants.view"
146
+ ];
147
+
148
+ // src/mcp-tokens.ts
149
+ var MCP_ACCESS_PERMISSION = "platform.mcp.access";
150
+ var MCP_TOKENS_MANAGE_PERMISSION = "platform.mcp.tokens.manage";
151
+ var MCP_PERMISSION_WILDCARD = "*";
152
+ var MCPTokenAPIError = class extends Error {
153
+ constructor(message, status, code, requestId) {
154
+ super(message);
155
+ this.status = status;
156
+ this.code = code;
157
+ this.requestId = requestId;
158
+ this.name = "MCPTokenAPIError";
159
+ }
160
+ status;
161
+ code;
162
+ requestId;
163
+ };
164
+ function isMCPTokenAPIError(error) {
165
+ return error instanceof MCPTokenAPIError || typeof error === "object" && error !== null && error.name === "MCPTokenAPIError" && typeof error.status === "number" && typeof error.code === "string" && typeof error.requestId === "string";
166
+ }
167
+ var configurationError = (message) => new Error(message);
168
+ var basePath = "/api/v1/platform/auth/me/mcp-tokens";
169
+ var tokenIDPattern = /^[0-9a-f]{32}$/;
170
+ var rawTokenPattern = /^sd_pat_([0-9a-f]{32})_[A-Za-z0-9_-]{43}$/;
171
+ var timestampPattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
172
+ function invalidResponse() {
173
+ throw new Error("invalid MCP token response");
174
+ }
175
+ function objectValue(value) {
176
+ if (typeof value !== "object" || value === null || Array.isArray(value)) invalidResponse();
177
+ return value;
178
+ }
179
+ function responseString(value, options = {}) {
180
+ if (value === void 0 && options.optional) return void 0;
181
+ if (typeof value !== "string" || value.length === 0) invalidResponse();
182
+ if (options.tokenID && !tokenIDPattern.test(value)) invalidResponse();
183
+ if (options.timestamp && (!timestampPattern.test(value) || !Number.isFinite(Date.parse(value)))) invalidResponse();
184
+ return value;
185
+ }
186
+ function responseStrings(value) {
187
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string" || entry.length === 0)) invalidResponse();
188
+ return [...value];
189
+ }
190
+ function parseMCPTokenView(value) {
191
+ const item = objectValue(value);
192
+ return {
193
+ token_id: responseString(item.token_id, { tokenID: true }),
194
+ name: responseString(item.name),
195
+ permissions: responseStrings(item.permissions),
196
+ app_allowlist: responseStrings(item.app_allowlist),
197
+ created_at: responseString(item.created_at, { timestamp: true }),
198
+ expires_at: responseString(item.expires_at, { timestamp: true }),
199
+ last_used_at: responseString(item.last_used_at, { optional: true, timestamp: true }),
200
+ revoked_at: responseString(item.revoked_at, { optional: true, timestamp: true })
201
+ };
202
+ }
203
+ function parseMCPTokenPage(value) {
204
+ const page = objectValue(value);
205
+ if (!Array.isArray(page.items) || typeof page.has_more !== "boolean" || typeof page.mcp_enabled !== "boolean") invalidResponse();
206
+ const nextCursor = responseString(page.next_cursor, { optional: true });
207
+ if (Boolean(nextCursor) !== page.has_more) invalidResponse();
208
+ return {
209
+ items: page.items.map(parseMCPTokenView),
210
+ next_cursor: nextCursor,
211
+ has_more: page.has_more,
212
+ mcp_enabled: page.mcp_enabled
213
+ };
214
+ }
215
+ function parseMintMCPTokenResponse(value) {
216
+ const response = objectValue(value);
217
+ const token = parseMCPTokenView(response.token);
218
+ const rawToken = responseString(response.raw_token);
219
+ const match = rawToken.match(rawTokenPattern);
220
+ if (!match || match[1] !== token.token_id) invalidResponse();
221
+ return { token, raw_token: rawToken };
222
+ }
223
+ function normalizedStrings(values, label, max) {
224
+ if (!Array.isArray(values)) throw configurationError(`${label} must be an array`);
225
+ const normalized = [...new Set(values.map((value) => requiredString(value, label, configurationError)))];
226
+ if (normalized.length > max) throw configurationError(`${label} must contain at most ${max} entries`);
227
+ return normalized;
228
+ }
229
+ function mintInput(value) {
230
+ const name = requiredString(value.name, "name", configurationError);
231
+ if (name.length > 64) throw configurationError("name must be 64 characters or fewer");
232
+ if (!Number.isSafeInteger(value.expires_in_days) || value.expires_in_days < 1 || value.expires_in_days > 90) {
233
+ throw configurationError("expires_in_days must be an integer from 1 to 90");
234
+ }
235
+ const permissions = normalizedStrings(value.permissions, "permissions", 32);
236
+ if (permissions.includes(MCP_PERMISSION_WILDCARD)) {
237
+ if (permissions.length !== 1) {
238
+ throw configurationError('permissions "*" must be the only entry');
239
+ }
240
+ } else {
241
+ if (!permissions.includes(MCP_ACCESS_PERMISSION)) throw configurationError(`permissions must include ${MCP_ACCESS_PERMISSION}`);
242
+ if (permissions.length < 2) throw configurationError("permissions must include at least one MCP tool permission");
243
+ const allowedPermissions = /* @__PURE__ */ new Set([MCP_ACCESS_PERMISSION, ...MCP_TOOL_PERMISSIONS]);
244
+ if (permissions.some((permission) => !allowedPermissions.has(permission))) {
245
+ throw configurationError("permissions contains a key that is not available to MCP tools");
246
+ }
247
+ }
248
+ const appAllowlist = normalizedStrings(value.app_allowlist, "app_allowlist", 32);
249
+ if (appAllowlist.includes("*") && appAllowlist.length !== 1) {
250
+ throw configurationError('app_allowlist "*" must be the only entry');
251
+ }
252
+ return {
253
+ name,
254
+ expires_in_days: value.expires_in_days,
255
+ permissions,
256
+ app_allowlist: appAllowlist
257
+ };
258
+ }
259
+ function tokenIDInput(value) {
260
+ const tokenID = requiredString(value, "tokenId", configurationError);
261
+ if (!tokenIDPattern.test(tokenID)) throw configurationError("tokenId must be a 32-character hexadecimal MCP token id");
262
+ return tokenID;
263
+ }
264
+ function createMCPTokenClient(options) {
265
+ const baseUrl = requiredString(options.baseUrl, "baseUrl", configurationError).replace(/\/+$/, "");
266
+ const transport = {
267
+ fetch: (input, init) => (options.fetch ?? globalThis.fetch)(input, init),
268
+ timeoutMs: positiveNumber(options.timeoutMs ?? 1e4, "timeoutMs", configurationError),
269
+ retry: {
270
+ attempts: nonNegativeInteger(options.retryAttempts ?? 1, "retryAttempts", configurationError),
271
+ maxDelayMs: positiveNumber(options.maxRetryDelayMs ?? 2e3, "maxRetryDelayMs", configurationError),
272
+ idempotentWrites: false
273
+ },
274
+ signal: options.signal
275
+ };
276
+ async function request(operation, path, decode, init = {}) {
277
+ const method = (init.method ?? "GET").toUpperCase();
278
+ const report = options.observe && ((event) => {
279
+ options.observe?.({ operation, ...event });
280
+ });
281
+ let headers;
282
+ try {
283
+ const accessToken = requiredString(await options.getAccessToken() ?? "", "access token", configurationError);
284
+ headers = new Headers(await options.getHeaders?.());
285
+ new Headers(init.headers).forEach((value, key) => headers.set(key, value));
286
+ headers.set("Authorization", `Bearer ${accessToken}`);
287
+ headers.set("Accept", "application/json");
288
+ if (init.body !== void 0) headers.set("Content-Type", "application/json");
289
+ } catch (error) {
290
+ try {
291
+ report?.({ method, outcome: "network_error", status: 0, requestId: "", durationMs: 0, attempts: 0 });
292
+ } catch {
293
+ }
294
+ throw error;
295
+ }
296
+ try {
297
+ const result = await performRequest(
298
+ transport,
299
+ `${baseUrl}${path}`,
300
+ { ...init, method, headers, cache: "no-store" },
301
+ report,
302
+ decode
303
+ );
304
+ return result.payload;
305
+ } catch (error) {
306
+ if (!isTransportError(error)) throw error;
307
+ const { outcome, status, code, message, requestId } = error.failure;
308
+ switch (outcome) {
309
+ case "timeout":
310
+ throw new MCPTokenAPIError("MCP token request timed out", 0, "mcp_token_request_timeout", "");
311
+ case "cancelled":
312
+ throw new MCPTokenAPIError("MCP token request was cancelled", 0, "mcp_token_request_cancelled", "");
313
+ case "network_error":
314
+ throw new MCPTokenAPIError("MCP token service is unavailable", 0, "mcp_token_service_unavailable", "");
315
+ case "invalid_response":
316
+ throw new MCPTokenAPIError("MCP token service returned an invalid response", status, "mcp_token_invalid_response", requestId);
317
+ case "api_error":
318
+ throw new MCPTokenAPIError(message || code || "MCP token request failed", status, code, requestId);
319
+ }
320
+ }
321
+ }
322
+ return {
323
+ list(params = {}) {
324
+ const query = new URLSearchParams();
325
+ const cursor = params.cursor?.trim();
326
+ if (cursor) query.set("cursor", cursor);
327
+ if (params.limit !== void 0) {
328
+ const limit = positiveNumber(params.limit, "limit", configurationError);
329
+ if (!Number.isSafeInteger(limit) || limit > 100) throw configurationError("limit must be an integer from 1 to 100");
330
+ query.set("limit", String(limit));
331
+ }
332
+ return request(
333
+ "platform_user.auth.mcp_tokens.list",
334
+ `${basePath}${query.size ? `?${query}` : ""}`,
335
+ parseMCPTokenPage
336
+ );
337
+ },
338
+ mint(input) {
339
+ return request("platform_user.auth.mcp_tokens.mint", basePath, parseMintMCPTokenResponse, {
340
+ method: "POST",
341
+ body: JSON.stringify(mintInput(input))
342
+ });
343
+ },
344
+ revoke(tokenId) {
345
+ return request(
346
+ "platform_user.auth.mcp_tokens.revoke",
347
+ `${basePath}/${tokenIDInput(tokenId)}`,
348
+ (payload) => {
349
+ if (payload !== void 0) invalidResponse();
350
+ },
351
+ { method: "DELETE" }
352
+ );
353
+ }
354
+ };
355
+ }
356
+
357
+ export { MCPTokenAPIError, MCP_ACCESS_PERMISSION, MCP_PERMISSION_WILDCARD, MCP_TOKENS_MANAGE_PERMISSION, MCP_TOOL_PERMISSIONS, MCP_WILDCARD_TOOL_PERMISSIONS, createMCPTokenClient, isMCPTokenAPIError };
package/dist/next.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { R as Resolvable, A as AsyncResolvable, S as SessionData, C as CookieOptions } from './index-BnchfjP_.js';
2
- export { a as AUTH_ERROR_MESSAGES, b as AuthResponse, D as DeviceIdentity, c as DeviceIdentityConfig, d as DeviceIdentityStore, H as HANDOFF_ERROR_FALLBACK, e as HANDOFF_ERROR_MESSAGES, f as HandoffSource, g as HandoffSourceConfig, h as HandoffSourceTarget, i as HandoffTarget, j as HandoffTargetConfig, k as RefreshedSession, l as SSO_ERROR_MESSAGES, m as SessionGateDecision, n as SessionGateInput, o as SessionRefresher, p as SessionRefresherConfig, q as SessionUser, T as TokenPayload, r as authErrorMessage, s as brokerPaths, t as createDeviceIdentity, u as createHandoffSource, v as createHandoffTarget, w as createSessionRefresher, x as decodeBase64Url, y as decodeDefaultSession, z as decodeTokenPayload, B as deleteCookie, E as evaluateSessionGate, F as handoffErrorMessage, G as hasSessionShape, I as hasTokenAudience, J as isAuthErrorCode, K as isHandoffErrorCode, L as isTokenExpired, M as isTokenExpiringSoon, N as parseAuthResponse, O as parseRefreshEnvelope, P as readCookie, Q as safeInternalPath, U as serializeCookie, V as setCookie, W as sourceStartPath, X as tokenMaxAgeSeconds } from './index-BnchfjP_.js';
3
- export { applyForwardedClientHeaders, forwardedRequestHeaders } from '@c1m-public/transport';
1
+ import { R as Resolvable, A as AsyncResolvable, S as SessionData, C as CookieOptions } from './index-aKe58m6n.js';
2
+ export { a as AUTH_ERROR_MESSAGES, b as AuthResponse, D as DeviceIdentity, c as DeviceIdentityConfig, d as DeviceIdentityStore, H as HANDOFF_ERROR_FALLBACK, e as HANDOFF_ERROR_MESSAGES, f as HandoffSource, g as HandoffSourceConfig, h as HandoffSourceTarget, i as HandoffTarget, j as HandoffTargetConfig, k as RefreshedSession, l as SSO_ERROR_MESSAGES, m as SessionGateDecision, n as SessionGateInput, o as SessionRefresher, p as SessionRefresherConfig, q as SessionUser, T as TokenPayload, r as applyForwardedClientHeaders, s as authErrorMessage, t as brokerPaths, u as createDeviceIdentity, v as createHandoffSource, w as createHandoffTarget, x as createSessionRefresher, y as decodeBase64Url, z as decodeDefaultSession, B as decodeTokenPayload, E as deleteCookie, F as evaluateSessionGate, G as forwardedRequestHeaders, I as handoffErrorMessage, J as hasSessionShape, K as hasTokenAudience, L as isAuthErrorCode, M as isHandoffErrorCode, N as isTokenExpired, O as isTokenExpiringSoon, P as parseAuthResponse, Q as parseRefreshEnvelope, U as readCookie, V as safeInternalPath, W as serializeCookie, X as setCookie, Y as sourceStartPath, Z as tokenMaxAgeSeconds } from './index-aKe58m6n.js';
4
3
 
5
4
  /**
6
5
  * The error vocabulary every first-party platform surface uses at its edge.
package/dist/next.js CHANGED
@@ -128,6 +128,14 @@ function forwardedRequestHeaders(request, init) {
128
128
  return applyForwardedClientHeaders(request.headers, new Headers(init));
129
129
  }
130
130
 
131
+ // src/forwarding.ts
132
+ function applyForwardedClientHeaders2(incoming, headers = new Headers()) {
133
+ return applyForwardedClientHeaders(incoming, headers);
134
+ }
135
+ function forwardedRequestHeaders2(request, init) {
136
+ return forwardedRequestHeaders(request, init);
137
+ }
138
+
131
139
  // src/cookies.ts
132
140
  function readCookie(request, name) {
133
141
  const header = request.headers.get("cookie");
@@ -378,7 +386,7 @@ function createHandoffTarget(config) {
378
386
  const device = config.device.read(request);
379
387
  const respond = (response) => config.device.persist(response, device);
380
388
  try {
381
- const headers = forwardedRequestHeaders(request, {
389
+ const headers = forwardedRequestHeaders2(request, {
382
390
  "Content-Type": "application/json",
383
391
  "X-Client-Type": config.clientType,
384
392
  "X-Client-Device-ID": device.value
@@ -427,7 +435,7 @@ function createHandoffSource(config) {
427
435
  const token = await config.getAccessToken(request);
428
436
  if (!token) return sourceLogin();
429
437
  try {
430
- const headers = forwardedRequestHeaders(request, {
438
+ const headers = forwardedRequestHeaders2(request, {
431
439
  "Content-Type": "application/json",
432
440
  "X-Client-Type": config.clientType,
433
441
  Authorization: `Bearer ${token}`
@@ -615,7 +623,7 @@ async function controlRequest(run) {
615
623
  async function buildForwardedRequestHeaders(initHeaders) {
616
624
  const headers$1 = new Headers(initHeaders);
617
625
  try {
618
- applyForwardedClientHeaders(await headers(), headers$1);
626
+ applyForwardedClientHeaders2(await headers(), headers$1);
619
627
  } catch {
620
628
  }
621
629
  return headers$1;
@@ -856,4 +864,4 @@ function createSessionStore(config) {
856
864
  };
857
865
  }
858
866
 
859
- export { AUTH_ERROR_MESSAGES, HANDOFF_ERROR_FALLBACK, HANDOFF_ERROR_MESSAGES, PlatformServerFetchError, RecentAuthenticationRequiredError, SSOReauthenticationRequiredError, SSO_ERROR_MESSAGES, SessionExpiredError, applyForwardedClientHeaders, authErrorMessage, authenticationErrorFor, brokerPaths, buildForwardedRequestHeaders, controlRequest, createDeviceIdentity, createHandoffSource, createHandoffTarget, createPlatformFetch, createSessionRefresher, createSessionStore, decodeBase64Url, decodeDefaultSession, decodeTokenPayload, deleteCookie, evaluateSessionGate, forwardedRequestHeaders, handoffErrorMessage, hasSessionShape, hasTokenAudience, isAuthErrorCode, isHandoffErrorCode, isPlatformServerFetchError, isRecentAuthenticationRequiredError, isSSOReauthenticationRequiredError, isSessionExpiredError, isTokenExpired, isTokenExpiringSoon, mapControlError, parseAuthResponse, parseRefreshEnvelope, readCookie, safeInternalPath, serializeCookie, setCookie, sourceStartPath, tokenMaxAgeSeconds };
867
+ export { AUTH_ERROR_MESSAGES, HANDOFF_ERROR_FALLBACK, HANDOFF_ERROR_MESSAGES, PlatformServerFetchError, RecentAuthenticationRequiredError, SSOReauthenticationRequiredError, SSO_ERROR_MESSAGES, SessionExpiredError, applyForwardedClientHeaders2 as applyForwardedClientHeaders, authErrorMessage, authenticationErrorFor, brokerPaths, buildForwardedRequestHeaders, controlRequest, createDeviceIdentity, createHandoffSource, createHandoffTarget, createPlatformFetch, createSessionRefresher, createSessionStore, decodeBase64Url, decodeDefaultSession, decodeTokenPayload, deleteCookie, evaluateSessionGate, forwardedRequestHeaders2 as forwardedRequestHeaders, handoffErrorMessage, hasSessionShape, hasTokenAudience, isAuthErrorCode, isHandoffErrorCode, isPlatformServerFetchError, isRecentAuthenticationRequiredError, isSSOReauthenticationRequiredError, isSessionExpiredError, isTokenExpired, isTokenExpiringSoon, mapControlError, parseAuthResponse, parseRefreshEnvelope, readCookie, safeInternalPath, serializeCookie, setCookie, sourceStartPath, tokenMaxAgeSeconds };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c1m-public/platform-auth",
3
- "version": "0.9.3",
3
+ "version": "0.12.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",
@@ -20,6 +20,10 @@
20
20
  "types": "./dist/next.d.ts",
21
21
  "default": "./dist/next.js"
22
22
  },
23
+ "./mcp-tokens": {
24
+ "types": "./dist/mcp-tokens.d.ts",
25
+ "default": "./dist/mcp-tokens.js"
26
+ },
23
27
  "./access": {
24
28
  "types": "./dist/access/index.d.ts",
25
29
  "default": "./dist/access/index.js"