@c1m-public/platform-auth 0.9.0 → 0.9.1

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.
@@ -1,153 +1 @@
1
- import { R as Resolvable } from '../internal-D6RafCm2.js';
2
-
3
- /** Platform-operator permission keys. */
4
- declare const PLATFORM_PERMISSIONS: readonly ["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"];
5
- type PlatformPermissionKey = (typeof PLATFORM_PERMISSIONS)[number];
6
- /** Dash-owner permission keys (granted at dash scope, mirrored from the membership role). */
7
- 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"];
8
- type DashPermissionKey = (typeof DASH_PERMISSIONS)[number];
9
- /** Membership-mirrored dash role bundles (grant keys at dash scope). */
10
- declare const DASH_ROLES: readonly ["dash.admin", "dash.owner"];
11
- type DashRole = (typeof DASH_ROLES)[number];
12
- /** Lead-broker workload permission keys. */
13
- declare const LEADBROKER_PERMISSIONS: readonly ["leadbroker.finance.manage", "leadbroker.leads.dispatch", "leadbroker.leads.review", "leadbroker.leads.view", "leadbroker.policy.manage"];
14
- type LeadBrokerPermissionKey = (typeof LEADBROKER_PERMISSIONS)[number];
15
- /** Workspace-staff permission keys. */
16
- declare const WORKSPACE_PERMISSIONS: readonly ["workspace.channels.manage", "workspace.channels.secrets", "workspace.channels.view", "workspace.crm.manage", "workspace.crm.view", "workspace.customers.manage", "workspace.customers.view", "workspace.orders.manage", "workspace.orders.view", "workspace.payments.record", "workspace.site.edit", "workspace.site.view", "workspace.staff.manage"];
17
- type WorkspacePermissionKey = (typeof WORKSPACE_PERMISSIONS)[number];
18
- /** Assignable workspace-staff role bundles (grant keys at workspace scope). */
19
- declare const WORKSPACE_ROLES: readonly ["workspace.editor", "workspace.frontdesk", "workspace.manager"];
20
- type WorkspaceRole = (typeof WORKSPACE_ROLES)[number];
21
- /** Every permission key the backend can grant, across all scopes. */
22
- type PermissionKey = PlatformPermissionKey | DashPermissionKey | LeadBrokerPermissionKey | WorkspacePermissionKey;
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
-
29
- type AccessErrorCode = "unauthenticated" | "forbidden" | "unavailable" | "invalid_snapshot";
30
- /**
31
- * Typed failure for loading or validating an access snapshot. `unauthenticated`
32
- * = no/expired session (401); `forbidden` = the backend refused the snapshot
33
- * (403; e.g. wrong audience); `unavailable` = transport/5xx; `invalid_snapshot`
34
- * = the payload did not match the contract.
35
- */
36
- declare class AccessSnapshotError extends Error {
37
- readonly code: AccessErrorCode;
38
- readonly status: number | undefined;
39
- constructor(code: AccessErrorCode, message: string, status?: number);
40
- }
41
- declare function isAccessSnapshotError(error: unknown, code?: AccessErrorCode): error is AccessSnapshotError;
42
-
43
- /** Scope a permission entry applies to. Mirrors c1m-server authz.Scope*. */
44
- type AccessScopeType = "platform" | "saas_app" | "workspace";
45
- interface AccessEntry {
46
- /** Permission key, e.g. "platform.users.manage_access". */
47
- key: string;
48
- scope_type: AccessScopeType;
49
- /** "" for platform scope; saas_app slug or "*" for saas_app scope; workspace id for workspace scope. */
50
- scope_id: string;
51
- }
52
- /**
53
- * The resolved authorization snapshot for one subject, as returned by
54
- * `GET /api/v1/platform/access`. This is the *output* of the backend resolver
55
- * (base-role grant ∪ scoped grants), never the grant rows themselves.
56
- */
57
- interface AccessSnapshot {
58
- subject_id: string;
59
- /** Monotonic; bumps on any grant/role change. Use for optimistic concurrency and cache keys. */
60
- access_version: number;
61
- is_owner: boolean;
62
- active: boolean;
63
- /** Platform operator base role (derived; display only — never authorize on it). */
64
- platform_role: string;
65
- permissions: AccessEntry[];
66
- /**
67
- * Dash bundle (`dash.owner` / `dash.admin`) per saas_app id, mirrored from
68
- * the subject's dash membership. This is the admission list for the dash
69
- * area: the dashes this subject runs. What they may *do* on one is a normal
70
- * `hasPermission(snapshot, key, { saasApp })` check — platform managers hold
71
- * their authority platform-wide and so appear here not at all.
72
- */
73
- dash_roles: Record<string, string>;
74
- /** Effective workspace-staff permission keys per workspace id. */
75
- workspace_permissions: Record<string, string[]>;
76
- /** Workspace-staff role bundle per workspace id (display only). */
77
- workspace_roles: Record<string, string>;
78
- }
79
- declare function emptySnapshot(subjectId?: string): AccessSnapshot;
80
- /** Runtime validator for the wire payload. Throws AccessSnapshotError("invalid_snapshot"). */
81
- declare function parseAccessSnapshot(input: unknown): AccessSnapshot;
82
-
83
- interface PermissionCheckOptions {
84
- /**
85
- * SaaS app (dash) slug the check is about. Omit for "anywhere": platform
86
- * entries and any saas_app entry satisfy the check.
87
- */
88
- saasApp?: string;
89
- }
90
- /**
91
- * Mirrors c1m-server authz.entryCoversApp: platform scope covers every app;
92
- * saas_app scope covers "*" or a case-insensitive slug match; workspace-scoped
93
- * entries never satisfy an app-level check.
94
- */
95
- declare function entryCoversApp(entry: AccessEntry, saasApp: string | undefined): boolean;
96
- /** True when the subject is active and holds `key` for the given app (or anywhere). */
97
- declare function hasPermission(snapshot: AccessSnapshot, key: string, opts?: PermissionCheckOptions): boolean;
98
- declare function hasAnyPermission(snapshot: AccessSnapshot, keys: readonly string[], opts?: PermissionCheckOptions): boolean;
99
- declare function hasAllPermissions(snapshot: AccessSnapshot, keys: readonly string[], opts?: PermissionCheckOptions): boolean;
100
- /**
101
- * Workspace-staff check. Platform owners always pass (they own every
102
- * workspace); otherwise the workspace's effective permission list decides.
103
- * Platform/saas_app entries never confer workspace-staff permissions.
104
- */
105
- declare function hasWorkspacePermission(snapshot: AccessSnapshot, workspaceId: string, key: string): boolean;
106
- /**
107
- * The dashes this subject runs, from the mirrored dash bundle grants — the
108
- * admission list for the Admin Center's dash area. Platform managers are not
109
- * listed: their reach is platform-wide, so admit them with
110
- * `hasPermission(snapshot, "platform.tenants.manage")` instead.
111
- */
112
- declare function managedDashes(snapshot: AccessSnapshot): Array<{
113
- saasApp: string;
114
- role: string;
115
- }>;
116
- /** The dash bundle held on one dash, or "" when the subject holds none there. */
117
- declare function dashRole(snapshot: AccessSnapshot, saasApp: string): string;
118
- declare function isPlatformOwner(snapshot: AccessSnapshot): boolean;
119
- /**
120
- * The saas_app scopes under which `key` is held. Returns `{ all: true }` when a
121
- * platform-scoped or "*" entry grants it everywhere; otherwise the explicit
122
- * app slugs (empty = nowhere). Mirrors authz.AppPermissionScope.
123
- */
124
- declare function appScopes(snapshot: AccessSnapshot, key: string): {
125
- all: boolean;
126
- apps: string[];
127
- };
128
- /** Distinct permission keys held for `saasApp` (or anywhere). Handy for nav/badges. */
129
- declare function permissionsFor(snapshot: AccessSnapshot, opts?: PermissionCheckOptions): string[];
130
-
131
- declare const DEFAULT_ACCESS_ENDPOINT_PATH = "/api/v1/platform/access";
132
- interface FetchAccessSnapshotOptions {
133
- /** Backend origin, e.g. https://api.example.com (no trailing slash needed). */
134
- apiUrl: Resolvable;
135
- /** Bearer access token for the platform surface. */
136
- accessToken: string;
137
- /** Defaults to /api/v1/platform/access. */
138
- endpointPath?: string;
139
- fetchTimeoutMs?: number;
140
- fetchImpl?: typeof fetch;
141
- /** Extra headers. Authorization and Accept are always set here. */
142
- headers?: HeadersInit;
143
- /** Incoming BFF request; its client identity (IP, geo, UA) is forwarded to the backend. */
144
- request?: Request;
145
- }
146
- /**
147
- * Framework-neutral fetch of the resolved access snapshot. Throws
148
- * AccessSnapshotError: 401 → unauthenticated, 403 → forbidden, other non-2xx or
149
- * network failure → unavailable, malformed body → invalid_snapshot.
150
- */
151
- declare function fetchAccessSnapshot(opts: FetchAccessSnapshotOptions): Promise<AccessSnapshot>;
152
-
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
+ 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-CbsCWtku.js';
@@ -1,2 +1,307 @@
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
- import '../chunk-ZWSJVE5S.js';
1
+ // src/access/generated/keys.ts
2
+ var PLATFORM_PERMISSIONS = [
3
+ "affiliates.finance.manage",
4
+ "affiliates.partners.manage",
5
+ "affiliates.programmes.manage",
6
+ "affiliates.view",
7
+ "linkservice.domains.manage",
8
+ "linkservice.links.manage",
9
+ "linkservice.qr.manage",
10
+ "linkservice.view",
11
+ "platform.admin.view",
12
+ "platform.audit.view",
13
+ "platform.auth.manage",
14
+ "platform.billing.manage",
15
+ "platform.channels.manage",
16
+ "platform.channels.view",
17
+ "platform.config.manage",
18
+ "platform.docs.manage",
19
+ "platform.docs.view",
20
+ "platform.observability.manage",
21
+ "platform.observability.view",
22
+ "platform.offboarding.view",
23
+ "platform.ops.manage",
24
+ "platform.support.impersonate",
25
+ "platform.support.sessions",
26
+ "platform.tenants.archive",
27
+ "platform.tenants.manage",
28
+ "platform.tenants.restore",
29
+ "platform.users.deactivate",
30
+ "platform.users.delete",
31
+ "platform.users.invite",
32
+ "platform.users.manage_access",
33
+ "platform.users.reactivate",
34
+ "platform.users.view"
35
+ ];
36
+ var DASH_PERMISSIONS = [
37
+ "dash.apps.manage",
38
+ "dash.billing.manage",
39
+ "dash.channels.manage",
40
+ "dash.customers.manage",
41
+ "dash.domains.manage",
42
+ "dash.members.manage",
43
+ "dash.ownership.transfer",
44
+ "dash.plans.manage",
45
+ "dash.publish",
46
+ "dash.settings.manage",
47
+ "dash.workspaces.admin",
48
+ "dash.workspaces.manage"
49
+ ];
50
+ var DASH_ROLES = [
51
+ "dash.admin",
52
+ "dash.owner"
53
+ ];
54
+ var LEADBROKER_PERMISSIONS = [
55
+ "leadbroker.finance.manage",
56
+ "leadbroker.leads.dispatch",
57
+ "leadbroker.leads.review",
58
+ "leadbroker.leads.view",
59
+ "leadbroker.policy.manage"
60
+ ];
61
+ var WORKSPACE_PERMISSIONS = [
62
+ "workspace.channels.manage",
63
+ "workspace.channels.secrets",
64
+ "workspace.channels.view",
65
+ "workspace.crm.manage",
66
+ "workspace.crm.view",
67
+ "workspace.customers.manage",
68
+ "workspace.customers.view",
69
+ "workspace.orders.manage",
70
+ "workspace.orders.view",
71
+ "workspace.payments.record",
72
+ "workspace.site.edit",
73
+ "workspace.site.view",
74
+ "workspace.staff.manage"
75
+ ];
76
+ var WORKSPACE_ROLES = [
77
+ "workspace.editor",
78
+ "workspace.frontdesk",
79
+ "workspace.manager"
80
+ ];
81
+
82
+ // src/access/generated/stages.ts
83
+ var PIPELINE_STAGES = ["created", "awaiting_payment", "provisioning", "attention", "active"];
84
+ function isPipelineStage(value) {
85
+ return typeof value === "string" && PIPELINE_STAGES.includes(value);
86
+ }
87
+
88
+ // src/access/errors.ts
89
+ var AccessSnapshotError = class extends Error {
90
+ code;
91
+ status;
92
+ constructor(code, message, status) {
93
+ super(message);
94
+ this.name = "AccessSnapshotError";
95
+ this.code = code;
96
+ this.status = status;
97
+ }
98
+ };
99
+ function isAccessSnapshotError(error, code) {
100
+ return error instanceof AccessSnapshotError && (code === void 0 || error.code === code);
101
+ }
102
+
103
+ // src/access/snapshot.ts
104
+ var SCOPE_TYPES = /* @__PURE__ */ new Set(["platform", "saas_app", "workspace"]);
105
+ function emptySnapshot(subjectId = "") {
106
+ return {
107
+ subject_id: subjectId,
108
+ access_version: 0,
109
+ is_owner: false,
110
+ active: false,
111
+ platform_role: "",
112
+ permissions: [],
113
+ dash_roles: {},
114
+ workspace_permissions: {},
115
+ workspace_roles: {}
116
+ };
117
+ }
118
+ function isRecord(value) {
119
+ return typeof value === "object" && value !== null && !Array.isArray(value);
120
+ }
121
+ function fail(field, why) {
122
+ throw new AccessSnapshotError("invalid_snapshot", `access snapshot: ${field} ${why}`);
123
+ }
124
+ function parseAccessSnapshot(input) {
125
+ if (!isRecord(input)) fail("payload", "is not an object");
126
+ const { subject_id, access_version, is_owner, active, platform_role, permissions, dash_roles, workspace_permissions, workspace_roles } = input;
127
+ if (typeof subject_id !== "string" || subject_id === "") fail("subject_id", "must be a non-empty string");
128
+ if (typeof access_version !== "number" || !Number.isInteger(access_version) || access_version < 0) fail("access_version", "must be a non-negative integer");
129
+ if (typeof is_owner !== "boolean") fail("is_owner", "must be a boolean");
130
+ if (typeof active !== "boolean") fail("active", "must be a boolean");
131
+ if (platform_role !== void 0 && platform_role !== null && typeof platform_role !== "string") fail("platform_role", "must be a string");
132
+ if (!Array.isArray(permissions)) fail("permissions", "must be an array");
133
+ const entries = permissions.map((raw, i) => {
134
+ if (!isRecord(raw)) fail(`permissions[${i}]`, "is not an object");
135
+ const { key, scope_type, scope_id } = raw;
136
+ if (typeof key !== "string" || key === "") fail(`permissions[${i}].key`, "must be a non-empty string");
137
+ if (typeof scope_type !== "string" || !SCOPE_TYPES.has(scope_type)) fail(`permissions[${i}].scope_type`, "must be platform|saas_app|workspace");
138
+ if (scope_id !== void 0 && scope_id !== null && typeof scope_id !== "string") fail(`permissions[${i}].scope_id`, "must be a string");
139
+ return { key, scope_type, scope_id: typeof scope_id === "string" ? scope_id : "" };
140
+ });
141
+ const dashRoles = {};
142
+ if (dash_roles !== void 0 && dash_roles !== null) {
143
+ if (!isRecord(dash_roles)) fail("dash_roles", "must be an object");
144
+ for (const [dash, role] of Object.entries(dash_roles)) {
145
+ if (typeof role !== "string") fail(`dash_roles[${dash}]`, "must be a string");
146
+ dashRoles[dash] = role;
147
+ }
148
+ }
149
+ const wsPerms = {};
150
+ if (workspace_permissions !== void 0 && workspace_permissions !== null) {
151
+ if (!isRecord(workspace_permissions)) fail("workspace_permissions", "must be an object");
152
+ for (const [ws, keys] of Object.entries(workspace_permissions)) {
153
+ if (!Array.isArray(keys) || keys.some((k) => typeof k !== "string")) fail(`workspace_permissions[${ws}]`, "must be a string array");
154
+ wsPerms[ws] = [...keys];
155
+ }
156
+ }
157
+ const wsRoles = {};
158
+ if (workspace_roles !== void 0 && workspace_roles !== null) {
159
+ if (!isRecord(workspace_roles)) fail("workspace_roles", "must be an object");
160
+ for (const [ws, role] of Object.entries(workspace_roles)) {
161
+ if (typeof role !== "string") fail(`workspace_roles[${ws}]`, "must be a string");
162
+ wsRoles[ws] = role;
163
+ }
164
+ }
165
+ return {
166
+ subject_id,
167
+ access_version,
168
+ is_owner,
169
+ active,
170
+ platform_role: typeof platform_role === "string" ? platform_role : "",
171
+ permissions: entries,
172
+ dash_roles: dashRoles,
173
+ workspace_permissions: wsPerms,
174
+ workspace_roles: wsRoles
175
+ };
176
+ }
177
+
178
+ // src/access/predicates.ts
179
+ function entryCoversApp(entry, saasApp) {
180
+ switch (entry.scope_type) {
181
+ case "platform":
182
+ return true;
183
+ case "saas_app":
184
+ if (saasApp === void 0) return true;
185
+ return entry.scope_id === "*" || entry.scope_id.toLowerCase() === saasApp.toLowerCase();
186
+ default:
187
+ return false;
188
+ }
189
+ }
190
+ function hasPermission(snapshot, key, opts = {}) {
191
+ if (!snapshot.active) return false;
192
+ return snapshot.permissions.some((entry) => entry.key === key && entryCoversApp(entry, opts.saasApp));
193
+ }
194
+ function hasAnyPermission(snapshot, keys, opts = {}) {
195
+ return keys.some((key) => hasPermission(snapshot, key, opts));
196
+ }
197
+ function hasAllPermissions(snapshot, keys, opts = {}) {
198
+ return keys.every((key) => hasPermission(snapshot, key, opts));
199
+ }
200
+ function hasWorkspacePermission(snapshot, workspaceId, key) {
201
+ if (!snapshot.active) return false;
202
+ if (snapshot.is_owner) return true;
203
+ return (snapshot.workspace_permissions[workspaceId] ?? []).includes(key);
204
+ }
205
+ function managedDashes(snapshot) {
206
+ if (!snapshot.active) return [];
207
+ return Object.entries(snapshot.dash_roles).map(([saasApp, role]) => ({ saasApp, role })).sort((a, b) => a.saasApp.localeCompare(b.saasApp));
208
+ }
209
+ function dashRole(snapshot, saasApp) {
210
+ if (!snapshot.active) return "";
211
+ return snapshot.dash_roles[saasApp] ?? "";
212
+ }
213
+ function isPlatformOwner(snapshot) {
214
+ return snapshot.active && snapshot.is_owner;
215
+ }
216
+ function appScopes(snapshot, key) {
217
+ if (!snapshot.active) return { all: false, apps: [] };
218
+ const apps = /* @__PURE__ */ new Set();
219
+ for (const entry of snapshot.permissions) {
220
+ if (entry.key !== key) continue;
221
+ if (entry.scope_type === "platform") return { all: true, apps: [] };
222
+ if (entry.scope_type === "saas_app") {
223
+ if (entry.scope_id === "*") return { all: true, apps: [] };
224
+ apps.add(entry.scope_id.toLowerCase());
225
+ }
226
+ }
227
+ return { all: false, apps: [...apps].sort() };
228
+ }
229
+ function permissionsFor(snapshot, opts = {}) {
230
+ if (!snapshot.active) return [];
231
+ const keys = /* @__PURE__ */ new Set();
232
+ for (const entry of snapshot.permissions) if (entryCoversApp(entry, opts.saasApp)) keys.add(entry.key);
233
+ return [...keys].sort();
234
+ }
235
+
236
+ // ../transport/src/forwarding.ts
237
+ function applyForwardedClientHeaders(incoming, headers = new Headers()) {
238
+ const forwardedFor = incoming.get("x-forwarded-for");
239
+ const realIp = incoming.get("x-real-ip") ?? forwardedFor?.split(",")[0]?.trim();
240
+ if (realIp && !headers.has("X-Client-IP")) headers.set("X-Client-IP", realIp);
241
+ if (realIp && !headers.has("X-Real-IP")) headers.set("X-Real-IP", realIp);
242
+ if (forwardedFor && !headers.has("X-Forwarded-For")) headers.set("X-Forwarded-For", forwardedFor);
243
+ const country = incoming.get("cf-ipcountry") ?? incoming.get("x-vercel-ip-country") ?? incoming.get("x-geo-country") ?? incoming.get("x-country-code");
244
+ if (country && country !== "XX" && !headers.has("X-Geo-Country")) {
245
+ headers.set("X-Geo-Country", country);
246
+ }
247
+ const host = incoming.get("host");
248
+ if (host && !headers.has("X-Forwarded-Host")) headers.set("X-Forwarded-Host", host);
249
+ const proto = incoming.get("x-forwarded-proto");
250
+ if (proto && !headers.has("X-Forwarded-Proto")) headers.set("X-Forwarded-Proto", proto);
251
+ const userAgent = incoming.get("user-agent");
252
+ if (userAgent && !headers.has("X-Client-User-Agent")) headers.set("X-Client-User-Agent", userAgent);
253
+ return headers;
254
+ }
255
+ function forwardedRequestHeaders(request, init) {
256
+ return applyForwardedClientHeaders(request.headers, new Headers(init));
257
+ }
258
+
259
+ // src/internal.ts
260
+ function resolveValue(value) {
261
+ return typeof value === "function" ? value() : value;
262
+ }
263
+ async function timedFetch(url, options = {}) {
264
+ const doFetch = options.fetch ?? options.fetchImpl ?? fetch;
265
+ const controller = options.timeoutMs ? new AbortController() : void 0;
266
+ const timer = controller ? setTimeout(() => controller.abort(), options.timeoutMs) : void 0;
267
+ try {
268
+ return await doFetch(url, {
269
+ ...options.init,
270
+ cache: "no-store",
271
+ ...controller ? { signal: controller.signal } : {}
272
+ });
273
+ } finally {
274
+ if (timer) clearTimeout(timer);
275
+ }
276
+ }
277
+
278
+ // src/access/fetch.ts
279
+ var DEFAULT_ACCESS_ENDPOINT_PATH = "/api/v1/platform/access";
280
+ async function fetchAccessSnapshot(opts) {
281
+ const url = `${resolveValue(opts.apiUrl).replace(/\/$/, "")}${opts.endpointPath ?? DEFAULT_ACCESS_ENDPOINT_PATH}`;
282
+ const headers = opts.request ? forwardedRequestHeaders(opts.request, opts.headers) : new Headers(opts.headers);
283
+ headers.set("Authorization", `Bearer ${opts.accessToken}`);
284
+ headers.set("Accept", "application/json");
285
+ let response;
286
+ try {
287
+ response = await timedFetch(url, {
288
+ init: { method: "GET", headers },
289
+ timeoutMs: opts.fetchTimeoutMs,
290
+ fetchImpl: opts.fetchImpl
291
+ });
292
+ } catch (error) {
293
+ throw new AccessSnapshotError("unavailable", `access snapshot request failed: ${error.message}`);
294
+ }
295
+ if (response.status === 401) throw new AccessSnapshotError("unauthenticated", "session expired", 401);
296
+ if (response.status === 403) throw new AccessSnapshotError("forbidden", "access snapshot refused", 403);
297
+ if (!response.ok) throw new AccessSnapshotError("unavailable", `access snapshot returned ${response.status}`, response.status);
298
+ let body;
299
+ try {
300
+ body = await response.json();
301
+ } catch {
302
+ throw new AccessSnapshotError("invalid_snapshot", "access snapshot body is not JSON", response.status);
303
+ }
304
+ return parseAccessSnapshot(body);
305
+ }
306
+
307
+ 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 };
@@ -1,6 +1,5 @@
1
- import { R as Resolvable } from '../internal-D6RafCm2.js';
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, 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';
1
+ import { A as AccessSnapshot, P as PermissionCheckOptions, R as Resolvable } from '../index-CbsCWtku.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-CbsCWtku.js';
4
3
 
5
4
  /** Default cache tag for one subject's snapshot: `access:<subjectId>`. */
6
5
  declare function accessCacheTag(subjectId: string): string;