@happyvertical/smrt-users 0.37.2 → 0.37.3

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/dist/sveltekit.js CHANGED
@@ -1,1006 +1,810 @@
1
- import { O as OidcLoginError, j as DEFAULT_SESSION_TTL, Z as withSessionPermissionContext, I as TerminalAuthRateLimitError, H as TerminalAuthError, Y as resolveOidcProviderConfig, v as OidcLoginService, N as encodeOidcTransaction, X as getUsersOidcConfig, L as decodeOidcTransaction, J as TerminalAuthService, A as SessionService } from "./chunks/TerminalAuthService-DcgimQYo.js";
2
- import { createLogger } from "@happyvertical/logger";
1
+ import { _ as resolveOidcProviderConfig, a as TerminalAuthRateLimitError, f as OidcLoginError, g as getUsersOidcConfig, h as encodeOidcTransaction, i as TerminalAuthError, l as withSessionPermissionContext, m as decodeOidcTransaction, o as TerminalAuthService, p as OidcLoginService, u as SessionService } from "./chunks/TerminalAuthService-BXAAuaXf.js";
3
2
  import { ObjectRegistry } from "@happyvertical/smrt-core";
3
+ import { createLogger } from "@happyvertical/logger";
4
4
  import { classnameToTablename } from "@happyvertical/smrt-core/utils";
5
- import { resolveApiActionSet, methodNameToKebab } from "@happyvertical/smrt-core/vite-plugin";
6
- const STANDARD_API_ACTIONS = [
7
- "list",
8
- "get",
9
- "create",
10
- "update",
11
- "delete"
5
+ import { methodNameToKebab, resolveApiActionSet } from "@happyvertical/smrt-core/vite-plugin";
6
+ //#region src/sveltekit/resource-list-handler.ts
7
+ var STANDARD_API_ACTIONS = [
8
+ "list",
9
+ "get",
10
+ "create",
11
+ "update",
12
+ "delete"
12
13
  ];
13
14
  function createResourceListHandler(options) {
14
- const {
15
- ensureRegistry,
16
- resolveSession = (event) => defaultResolveSession(event, options),
17
- commandPolicy = defaultCommandPolicy,
18
- resourceSlug = defaultResourceSlug,
19
- kebabRoutes = false
20
- } = options;
21
- return async (event) => {
22
- await ensureRegistry();
23
- let session;
24
- try {
25
- session = await resolveSession(event);
26
- } catch (error) {
27
- if (error instanceof InvalidBearerError) {
28
- return jsonResponse$1({ error: error.message }, 401);
29
- }
30
- throw error;
31
- }
32
- const resources = [];
33
- const skipWarnings = [];
34
- const slugSeen = /* @__PURE__ */ new Map();
35
- for (const [registeredName, registered] of ObjectRegistry.getAllClasses()) {
36
- const def = synthesizeDefinition(
37
- registeredName,
38
- registered
39
- );
40
- const cliConfig = def.decoratorConfig.cli;
41
- if (!cliConfig) continue;
42
- if (!isHttpCliConfig(cliConfig)) continue;
43
- if (isCollectionClass(def)) continue;
44
- const apiActionSet = resolveApiActionSet(
45
- def
46
- );
47
- const includedMethods = resolveCliIncludedMethods(
48
- cliConfig,
49
- apiActionSet
50
- );
51
- if (includedMethods.length === 0) continue;
52
- const slug = resourceSlug({
53
- className: def.className,
54
- collection: def.collection,
55
- qualifiedName: def.qualifiedName,
56
- packageName: def.packageName
57
- });
58
- const previous = slugSeen.get(slug);
59
- if (previous && previous !== def.qualifiedName) {
60
- return jsonResponse$1(
61
- {
62
- error: "resource-slug-collision",
63
- slug,
64
- classes: [previous, def.qualifiedName ?? def.className].filter(
65
- Boolean
66
- )
67
- },
68
- 500
69
- );
70
- }
71
- slugSeen.set(slug, def.qualifiedName ?? def.className);
72
- const resourceShell = {
73
- slug,
74
- className: def.className,
75
- qualifiedName: def.qualifiedName,
76
- packageName: def.packageName,
77
- label: humanLabel(def.className),
78
- apiPath: resolveApiPath(def)
79
- };
80
- const classMeta = {
81
- name: def.className,
82
- qualifiedName: def.qualifiedName,
83
- packageName: def.packageName,
84
- decoratorConfig: def.decoratorConfig
85
- };
86
- const commandNameSeen = /* @__PURE__ */ new Set();
87
- const candidates = [];
88
- for (const methodName of includedMethods) {
89
- const result = buildCommand(def, methodName, kebabRoutes);
90
- if (!result.ok) {
91
- skipWarnings.push({
92
- ref: `${def.className}.${methodName}`,
93
- reason: result.reason,
94
- candidate: result.candidate,
95
- resourceMeta: resourceShell,
96
- classMeta
97
- });
98
- continue;
99
- }
100
- if (result.command.kind === "custom" && STANDARD_API_ACTIONS.includes(
101
- result.command.commandName
102
- )) {
103
- return jsonResponse$1(
104
- {
105
- error: "command-name-shadows-crud",
106
- className: def.className,
107
- methodName,
108
- commandName: result.command.commandName
109
- },
110
- 500
111
- );
112
- }
113
- if (commandNameSeen.has(result.command.commandName)) {
114
- return jsonResponse$1(
115
- {
116
- error: "command-name-collision",
117
- className: def.className,
118
- commandName: result.command.commandName
119
- },
120
- 500
121
- );
122
- }
123
- commandNameSeen.add(result.command.commandName);
124
- candidates.push(result.command);
125
- }
126
- const policyResults = await Promise.all(
127
- candidates.map(
128
- (candidate) => commandPolicy({
129
- resource: resourceShell,
130
- command: candidate,
131
- session,
132
- classMeta
133
- })
134
- )
135
- );
136
- const allowed = candidates.filter((_, i) => policyResults[i]);
137
- if (allowed.length === 0) continue;
138
- resources.push({ ...resourceShell, commands: allowed });
139
- }
140
- const warnResults = await Promise.all(
141
- skipWarnings.map(
142
- (w) => commandPolicy({
143
- resource: w.resourceMeta,
144
- command: w.candidate,
145
- session,
146
- classMeta: w.classMeta
147
- })
148
- )
149
- );
150
- const visibleWarnings = skipWarnings.filter((_, i) => warnResults[i]).map((w) => `${w.ref}: ${w.reason}`);
151
- const body = {
152
- user: session.user ? { authenticated: true, id: String(session.user.id ?? "") } : { authenticated: false },
153
- warnings: visibleWarnings,
154
- resources
155
- };
156
- return jsonResponse$1(body, 200, {
157
- "cache-control": "private, no-store"
158
- });
159
- };
15
+ const { ensureRegistry, resolveSession = (event) => defaultResolveSession(event, options), commandPolicy = defaultCommandPolicy, resourceSlug = defaultResourceSlug, kebabRoutes = false } = options;
16
+ return async (event) => {
17
+ await ensureRegistry();
18
+ let session;
19
+ try {
20
+ session = await resolveSession(event);
21
+ } catch (error) {
22
+ if (error instanceof InvalidBearerError) return jsonResponse$1({ error: error.message }, 401);
23
+ throw error;
24
+ }
25
+ const resources = [];
26
+ const skipWarnings = [];
27
+ const slugSeen = /* @__PURE__ */ new Map();
28
+ for (const [registeredName, registered] of ObjectRegistry.getAllClasses()) {
29
+ const def = synthesizeDefinition(registeredName, registered);
30
+ const cliConfig = def.decoratorConfig.cli;
31
+ if (!cliConfig) continue;
32
+ if (!isHttpCliConfig(cliConfig)) continue;
33
+ if (isCollectionClass(def)) continue;
34
+ const includedMethods = resolveCliIncludedMethods(cliConfig, resolveApiActionSet(def));
35
+ if (includedMethods.length === 0) continue;
36
+ const slug = resourceSlug({
37
+ className: def.className,
38
+ collection: def.collection,
39
+ qualifiedName: def.qualifiedName,
40
+ packageName: def.packageName
41
+ });
42
+ const previous = slugSeen.get(slug);
43
+ if (previous && previous !== def.qualifiedName) return jsonResponse$1({
44
+ error: "resource-slug-collision",
45
+ slug,
46
+ classes: [previous, def.qualifiedName ?? def.className].filter(Boolean)
47
+ }, 500);
48
+ slugSeen.set(slug, def.qualifiedName ?? def.className);
49
+ const resourceShell = {
50
+ slug,
51
+ className: def.className,
52
+ qualifiedName: def.qualifiedName,
53
+ packageName: def.packageName,
54
+ label: humanLabel(def.className),
55
+ apiPath: resolveApiPath(def)
56
+ };
57
+ const classMeta = {
58
+ name: def.className,
59
+ qualifiedName: def.qualifiedName,
60
+ packageName: def.packageName,
61
+ decoratorConfig: def.decoratorConfig
62
+ };
63
+ const commandNameSeen = /* @__PURE__ */ new Set();
64
+ const candidates = [];
65
+ for (const methodName of includedMethods) {
66
+ const result = buildCommand(def, methodName, kebabRoutes);
67
+ if (!result.ok) {
68
+ skipWarnings.push({
69
+ ref: `${def.className}.${methodName}`,
70
+ reason: result.reason,
71
+ candidate: result.candidate,
72
+ resourceMeta: resourceShell,
73
+ classMeta
74
+ });
75
+ continue;
76
+ }
77
+ if (result.command.kind === "custom" && STANDARD_API_ACTIONS.includes(result.command.commandName)) return jsonResponse$1({
78
+ error: "command-name-shadows-crud",
79
+ className: def.className,
80
+ methodName,
81
+ commandName: result.command.commandName
82
+ }, 500);
83
+ if (commandNameSeen.has(result.command.commandName)) return jsonResponse$1({
84
+ error: "command-name-collision",
85
+ className: def.className,
86
+ commandName: result.command.commandName
87
+ }, 500);
88
+ commandNameSeen.add(result.command.commandName);
89
+ candidates.push(result.command);
90
+ }
91
+ const policyResults = await Promise.all(candidates.map((candidate) => commandPolicy({
92
+ resource: resourceShell,
93
+ command: candidate,
94
+ session,
95
+ classMeta
96
+ })));
97
+ const allowed = candidates.filter((_, i) => policyResults[i]);
98
+ if (allowed.length === 0) continue;
99
+ resources.push({
100
+ ...resourceShell,
101
+ commands: allowed
102
+ });
103
+ }
104
+ const warnResults = await Promise.all(skipWarnings.map((w) => commandPolicy({
105
+ resource: w.resourceMeta,
106
+ command: w.candidate,
107
+ session,
108
+ classMeta: w.classMeta
109
+ })));
110
+ const visibleWarnings = skipWarnings.filter((_, i) => warnResults[i]).map((w) => `${w.ref}: ${w.reason}`);
111
+ return jsonResponse$1({
112
+ user: session.user ? {
113
+ authenticated: true,
114
+ id: String(session.user.id ?? "")
115
+ } : { authenticated: false },
116
+ warnings: visibleWarnings,
117
+ resources
118
+ }, 200, { "cache-control": "private, no-store" });
119
+ };
160
120
  }
161
121
  function synthesizeDefinition(_registeredName, registered) {
162
- const methods = {};
163
- for (const [name, value] of registered.methods.entries()) {
164
- methods[name] = value;
165
- }
166
- const decoratorConfig = registered.config ?? {};
167
- const collection = registered.collection ?? deriveCollectionFromConfig(decoratorConfig) ?? classnameToTablename(registered.name);
168
- return {
169
- className: registered.name,
170
- qualifiedName: registered.qualifiedName,
171
- packageName: registered.packageName,
172
- collection,
173
- decoratorConfig,
174
- methods,
175
- tools: registered.tools,
176
- extends: registered.extends,
177
- extendsTypeArg: registered.extendsTypeArg,
178
- constructor: registered.constructor
179
- };
122
+ const methods = {};
123
+ for (const [name, value] of registered.methods.entries()) methods[name] = value;
124
+ const decoratorConfig = registered.config ?? {};
125
+ const collection = registered.collection ?? deriveCollectionFromConfig(decoratorConfig) ?? classnameToTablename(registered.name);
126
+ return {
127
+ className: registered.name,
128
+ qualifiedName: registered.qualifiedName,
129
+ packageName: registered.packageName,
130
+ collection,
131
+ decoratorConfig,
132
+ methods,
133
+ tools: registered.tools,
134
+ extends: registered.extends,
135
+ extendsTypeArg: registered.extendsTypeArg,
136
+ constructor: registered.constructor
137
+ };
180
138
  }
181
139
  function isCollectionClass(def) {
182
- if (def.extends === "SmrtCollection") return true;
183
- if (def.extendsTypeArg) return true;
184
- return ctorChainContains(def.constructor, "SmrtCollection");
140
+ if (def.extends === "SmrtCollection") return true;
141
+ if (def.extendsTypeArg) return true;
142
+ return ctorChainContains(def.constructor, "SmrtCollection");
185
143
  }
186
144
  function ctorChainContains(ctor, name, depthCap = 16) {
187
- let current = ctor;
188
- for (let i = 0; i < depthCap && current; i += 1) {
189
- if (current.name === name) return true;
190
- const next = Object.getPrototypeOf(current);
191
- if (!next || next === current) break;
192
- current = next;
193
- }
194
- return false;
145
+ let current = ctor;
146
+ for (let i = 0; i < depthCap && current; i += 1) {
147
+ if (current.name === name) return true;
148
+ const next = Object.getPrototypeOf(current);
149
+ if (!next || next === current) break;
150
+ current = next;
151
+ }
152
+ return false;
195
153
  }
196
154
  function deriveCollectionFromConfig(config) {
197
- return config?.tableName ?? void 0;
155
+ return config?.tableName ?? void 0;
198
156
  }
199
157
  function resolveCliIncludedMethods(cliConfig, apiActionSet) {
200
- if (cliConfig === true) {
201
- return STANDARD_API_ACTIONS.filter((a) => apiActionSet.has(a));
202
- }
203
- if (cliConfig === false) return [];
204
- if (typeof cliConfig !== "object" || cliConfig === null) return [];
205
- if (Array.isArray(cliConfig)) return [];
206
- const obj = cliConfig;
207
- if (obj.include !== void 0 && !Array.isArray(obj.include)) return [];
208
- if (obj.exclude !== void 0 && !Array.isArray(obj.exclude)) return [];
209
- if (obj.mirror !== void 0 && obj.mirror !== "api") return [];
210
- const include = obj.include;
211
- const exclude = obj.exclude;
212
- let candidates;
213
- if (obj.mirror === "api") {
214
- candidates = [...apiActionSet];
215
- } else if (include?.includes("*")) {
216
- candidates = [...apiActionSet];
217
- } else if (include && include.length > 0) {
218
- candidates = include.filter((m) => apiActionSet.has(m));
219
- } else {
220
- candidates = STANDARD_API_ACTIONS.filter((a) => apiActionSet.has(a));
221
- }
222
- if (exclude && exclude.length > 0) {
223
- const excludeSet = new Set(exclude);
224
- candidates = candidates.filter((m) => !excludeSet.has(m));
225
- }
226
- return candidates;
158
+ if (cliConfig === true) return STANDARD_API_ACTIONS.filter((a) => apiActionSet.has(a));
159
+ if (cliConfig === false) return [];
160
+ if (typeof cliConfig !== "object" || cliConfig === null) return [];
161
+ if (Array.isArray(cliConfig)) return [];
162
+ const obj = cliConfig;
163
+ if (obj.include !== void 0 && !Array.isArray(obj.include)) return [];
164
+ if (obj.exclude !== void 0 && !Array.isArray(obj.exclude)) return [];
165
+ if (obj.mirror !== void 0 && obj.mirror !== "api") return [];
166
+ const include = obj.include;
167
+ const exclude = obj.exclude;
168
+ let candidates;
169
+ if (obj.mirror === "api") candidates = [...apiActionSet];
170
+ else if (include?.includes("*")) candidates = [...apiActionSet];
171
+ else if (include && include.length > 0) candidates = include.filter((m) => apiActionSet.has(m));
172
+ else candidates = STANDARD_API_ACTIONS.filter((a) => apiActionSet.has(a));
173
+ if (exclude && exclude.length > 0) {
174
+ const excludeSet = new Set(exclude);
175
+ candidates = candidates.filter((m) => !excludeSet.has(m));
176
+ }
177
+ return candidates;
227
178
  }
228
179
  function isHttpCliConfig(cliConfig) {
229
- if (typeof cliConfig !== "object" || cliConfig === null) return true;
230
- if (Array.isArray(cliConfig)) return true;
231
- return cliConfig.http !== false;
180
+ if (typeof cliConfig !== "object" || cliConfig === null) return true;
181
+ if (Array.isArray(cliConfig)) return true;
182
+ return cliConfig.http !== false;
232
183
  }
233
184
  function buildCommand(def, methodName, kebabRoutes) {
234
- const isCrud = STANDARD_API_ACTIONS.includes(methodName);
235
- if (isCrud) {
236
- return {
237
- ok: true,
238
- command: buildCrudCommand(methodName)
239
- };
240
- }
241
- const methodDef = def.methods[methodName];
242
- if (!methodDef) {
243
- return {
244
- ok: true,
245
- command: buildCustomCommand(def, methodName, void 0, kebabRoutes)
246
- };
247
- }
248
- const paramCount = methodDef.parameters?.length ?? 0;
249
- if (paramCount > 1) {
250
- return {
251
- ok: false,
252
- reason: "multi-arg unsupported (use single-options-object convention)",
253
- candidate: buildCustomCommand(def, methodName, methodDef, kebabRoutes)
254
- };
255
- }
256
- const candidate = buildCustomCommand(def, methodName, methodDef, kebabRoutes);
257
- if (hasDynamicSegments(candidate.pathSegments)) {
258
- return {
259
- ok: false,
260
- reason: "dynamic-path-params unsupported",
261
- candidate
262
- };
263
- }
264
- if (candidate.httpMethod === "DELETE" && candidate.kind === "custom") {
265
- const methodHasParams = (methodDef.parameters?.length ?? 0) > 0;
266
- if (methodHasParams || hasNonIdParameters(candidate.parameters)) {
267
- return {
268
- ok: false,
269
- reason: "DELETE-with-body unsupported",
270
- candidate
271
- };
272
- }
273
- }
274
- return { ok: true, command: candidate };
185
+ if (STANDARD_API_ACTIONS.includes(methodName)) return {
186
+ ok: true,
187
+ command: buildCrudCommand(methodName)
188
+ };
189
+ const methodDef = def.methods[methodName];
190
+ if (!methodDef) return {
191
+ ok: true,
192
+ command: buildCustomCommand(def, methodName, void 0, kebabRoutes)
193
+ };
194
+ if ((methodDef.parameters?.length ?? 0) > 1) return {
195
+ ok: false,
196
+ reason: "multi-arg unsupported (use single-options-object convention)",
197
+ candidate: buildCustomCommand(def, methodName, methodDef, kebabRoutes)
198
+ };
199
+ const candidate = buildCustomCommand(def, methodName, methodDef, kebabRoutes);
200
+ if (hasDynamicSegments(candidate.pathSegments)) return {
201
+ ok: false,
202
+ reason: "dynamic-path-params unsupported",
203
+ candidate
204
+ };
205
+ if (candidate.httpMethod === "DELETE" && candidate.kind === "custom") {
206
+ if ((methodDef.parameters?.length ?? 0) > 0 || hasNonIdParameters(candidate.parameters)) return {
207
+ ok: false,
208
+ reason: "DELETE-with-body unsupported",
209
+ candidate
210
+ };
211
+ }
212
+ return {
213
+ ok: true,
214
+ command: candidate
215
+ };
275
216
  }
276
217
  function buildCrudCommand(name) {
277
- const item = name === "get" || name === "update" || name === "delete";
278
- const httpMethod = name === "list" || name === "get" ? "GET" : name === "create" ? "POST" : name === "update" ? "PUT" : "DELETE";
279
- return {
280
- methodName: name,
281
- commandName: name,
282
- kind: "crud",
283
- scope: item ? "item" : "collection",
284
- httpMethod,
285
- pathSegments: [],
286
- description: defaultCrudDescription(name)
287
- };
218
+ return {
219
+ methodName: name,
220
+ commandName: name,
221
+ kind: "crud",
222
+ scope: name === "get" || name === "update" || name === "delete" ? "item" : "collection",
223
+ httpMethod: name === "list" || name === "get" ? "GET" : name === "create" ? "POST" : name === "update" ? "PUT" : "DELETE",
224
+ pathSegments: [],
225
+ description: defaultCrudDescription(name)
226
+ };
288
227
  }
289
228
  function buildCustomCommand(def, methodName, methodDef, kebabRoutes) {
290
- const apiConfigObj = getApiConfigObject(def.decoratorConfig.api);
291
- const routeConfig = apiConfigObj?.routes?.[methodName];
292
- const defaultScope = methodDef?.isStatic ? "collection" : "item";
293
- const scope = routeConfig?.scope ?? defaultScope;
294
- const httpMethod = normalizeApiHttpMethod(routeConfig?.method);
295
- let pathSegments;
296
- if (routeConfig?.path) {
297
- pathSegments = routeConfig.path.split("/").map((s) => s.trim()).filter(Boolean);
298
- if (pathSegments.length === 0) pathSegments = [methodName];
299
- } else {
300
- pathSegments = [kebabRoutes ? methodNameToKebab(methodName) : methodName];
301
- }
302
- const parameters = resolveParametersSchema(def, methodName);
303
- return {
304
- methodName,
305
- commandName: methodNameToKebab(methodName),
306
- kind: "custom",
307
- scope,
308
- httpMethod,
309
- pathSegments,
310
- description: methodDef?.description,
311
- parameters
312
- };
229
+ const routeConfig = getApiConfigObject(def.decoratorConfig.api)?.routes?.[methodName];
230
+ const defaultScope = methodDef?.isStatic ? "collection" : "item";
231
+ const scope = routeConfig?.scope ?? defaultScope;
232
+ const httpMethod = normalizeApiHttpMethod(routeConfig?.method);
233
+ let pathSegments;
234
+ if (routeConfig?.path) {
235
+ pathSegments = routeConfig.path.split("/").map((s) => s.trim()).filter(Boolean);
236
+ if (pathSegments.length === 0) pathSegments = [methodName];
237
+ } else pathSegments = [kebabRoutes ? methodNameToKebab(methodName) : methodName];
238
+ const parameters = resolveParametersSchema(def, methodName, methodDef);
239
+ return {
240
+ methodName,
241
+ commandName: methodNameToKebab(methodName),
242
+ kind: "custom",
243
+ scope,
244
+ httpMethod,
245
+ pathSegments,
246
+ description: methodDef?.description,
247
+ parameters
248
+ };
313
249
  }
314
250
  function resolveParametersSchema(def, methodName, _methodDef) {
315
- const tool = def.tools?.find((t) => t.function.name === methodName);
316
- if (tool?.function.parameters) {
317
- const params = tool.function.parameters;
318
- if (hasUsableProperties(params)) return params;
319
- }
320
- return void 0;
251
+ const tool = def.tools?.find((t) => t.function.name === methodName);
252
+ if (tool?.function.parameters) {
253
+ const params = tool.function.parameters;
254
+ if (hasUsableProperties(params)) return params;
255
+ }
321
256
  }
322
257
  function hasUsableProperties(schema) {
323
- if (!schema || typeof schema !== "object") return false;
324
- const props = schema.properties;
325
- if (!props || typeof props !== "object") return false;
326
- return Object.keys(props).length > 0;
258
+ if (!schema || typeof schema !== "object") return false;
259
+ const props = schema.properties;
260
+ if (!props || typeof props !== "object") return false;
261
+ return Object.keys(props).length > 0;
327
262
  }
328
263
  function normalizeApiHttpMethod(method) {
329
- switch (method?.toUpperCase()) {
330
- case "GET":
331
- case "POST":
332
- case "PUT":
333
- case "PATCH":
334
- case "DELETE":
335
- return method.toUpperCase();
336
- default:
337
- return "POST";
338
- }
264
+ switch (method?.toUpperCase()) {
265
+ case "GET":
266
+ case "POST":
267
+ case "PUT":
268
+ case "PATCH":
269
+ case "DELETE": return method.toUpperCase();
270
+ default: return "POST";
271
+ }
339
272
  }
340
273
  function getApiConfigObject(api) {
341
- if (typeof api !== "object" || api === null) return void 0;
342
- return api;
274
+ if (typeof api !== "object" || api === null) return void 0;
275
+ return api;
343
276
  }
344
277
  function hasDynamicSegments(segments) {
345
- return segments.some((s) => /^\[.+\]$/.test(s) || s.startsWith(":"));
278
+ return segments.some((s) => /^\[.+\]$/.test(s) || s.startsWith(":"));
346
279
  }
347
280
  function hasNonIdParameters(parameters) {
348
- if (!parameters || typeof parameters !== "object") return false;
349
- const props = parameters.properties;
350
- if (!props) return false;
351
- const keys = Object.keys(props).filter((k) => k !== "id");
352
- return keys.length > 0;
281
+ if (!parameters || typeof parameters !== "object") return false;
282
+ const props = parameters.properties;
283
+ if (!props) return false;
284
+ return Object.keys(props).filter((k) => k !== "id").length > 0;
353
285
  }
354
286
  function defaultCrudDescription(name) {
355
- switch (name) {
356
- case "list":
357
- return "List records";
358
- case "get":
359
- return "Get a record by id";
360
- case "create":
361
- return "Create a new record";
362
- case "update":
363
- return "Update an existing record";
364
- case "delete":
365
- return "Delete a record";
366
- }
287
+ switch (name) {
288
+ case "list": return "List records";
289
+ case "get": return "Get a record by id";
290
+ case "create": return "Create a new record";
291
+ case "update": return "Update an existing record";
292
+ case "delete": return "Delete a record";
293
+ }
367
294
  }
368
295
  function resolveApiPath(def) {
369
- return def.collection;
296
+ return def.collection;
370
297
  }
371
298
  function defaultResourceSlug(meta) {
372
- return meta.collection;
299
+ return meta.collection;
373
300
  }
374
301
  function humanLabel(className) {
375
- return className.replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([a-z0-9])([A-Z])/g, "$1 $2");
376
- }
377
- class InvalidBearerError extends Error {
378
- constructor(message = "Invalid or expired bearer token.") {
379
- super(message);
380
- this.name = "InvalidBearerError";
381
- }
302
+ return className.replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([a-z0-9])([A-Z])/g, "$1 $2");
382
303
  }
304
+ var InvalidBearerError = class extends Error {
305
+ constructor(message = "Invalid or expired bearer token.") {
306
+ super(message);
307
+ this.name = "InvalidBearerError";
308
+ }
309
+ };
383
310
  async function defaultResolveSession(event, options) {
384
- const locals = event.locals ?? {};
385
- if (locals.user) {
386
- return {
387
- user: locals.user,
388
- membership: locals.membership ?? null,
389
- permissions: locals.permissions ?? [],
390
- tenantId: locals.tenantId ?? null,
391
- sessionId: locals.sessionId ?? null
392
- };
393
- }
394
- const bearer = parseBearerToken(event.request.headers.get("authorization"));
395
- if (bearer) {
396
- const ctx = await loadBearerSessionContext(bearer, options);
397
- if (!ctx) {
398
- throw new InvalidBearerError();
399
- }
400
- return {
401
- user: ctx.user,
402
- membership: ctx.membership ?? null,
403
- permissions: ctx.permissions,
404
- tenantId: ctx.tenantId,
405
- sessionId: ctx.sessionId
406
- };
407
- }
408
- return {
409
- user: null,
410
- membership: null,
411
- permissions: [],
412
- tenantId: null,
413
- sessionId: null
414
- };
311
+ const locals = event.locals ?? {};
312
+ if (locals.user) return {
313
+ user: locals.user,
314
+ membership: locals.membership ?? null,
315
+ permissions: locals.permissions ?? [],
316
+ tenantId: locals.tenantId ?? null,
317
+ sessionId: locals.sessionId ?? null
318
+ };
319
+ const bearer = parseBearerToken(event.request.headers.get("authorization"));
320
+ if (bearer) {
321
+ const ctx = await loadBearerSessionContext(bearer, options);
322
+ if (!ctx) throw new InvalidBearerError();
323
+ return {
324
+ user: ctx.user,
325
+ membership: ctx.membership ?? null,
326
+ permissions: ctx.permissions,
327
+ tenantId: ctx.tenantId,
328
+ sessionId: ctx.sessionId
329
+ };
330
+ }
331
+ return {
332
+ user: null,
333
+ membership: null,
334
+ permissions: [],
335
+ tenantId: null,
336
+ sessionId: null
337
+ };
415
338
  }
416
339
  function defaultCommandPolicy(ctx) {
417
- return ctx.session.user != null;
340
+ return ctx.session.user != null;
418
341
  }
419
342
  function jsonResponse$1(body, status = 200, extraHeaders = {}) {
420
- return new Response(JSON.stringify(body), {
421
- status,
422
- headers: {
423
- "content-type": "application/json",
424
- ...extraHeaders
425
- }
426
- });
427
- }
428
- const defaultSessionLocals = {
429
- user: null,
430
- membership: null,
431
- permissions: [],
432
- tenantId: null,
433
- sessionId: null
343
+ return new Response(JSON.stringify(body), {
344
+ status,
345
+ headers: {
346
+ "content-type": "application/json",
347
+ ...extraHeaders
348
+ }
349
+ });
350
+ }
351
+ //#endregion
352
+ //#region src/sveltekit/types.ts
353
+ var defaultSessionLocals = {
354
+ user: null,
355
+ membership: null,
356
+ permissions: [],
357
+ tenantId: null,
358
+ sessionId: null
434
359
  };
435
- const logger = createLogger({ level: "info" });
360
+ //#endregion
361
+ //#region src/sveltekit/index.ts
362
+ var logger = createLogger({ level: "info" });
436
363
  function createSessionHandler(options) {
437
- const cookieName = options.cookieName ?? "sid";
438
- const ttl = options.ttl ?? DEFAULT_SESSION_TTL;
439
- const skipPaths = options.skipPaths ?? [];
440
- let sessionService = null;
441
- const getSessionService = async () => {
442
- if (!sessionService) {
443
- sessionService = await SessionService.create({
444
- ...options,
445
- defaultTTL: ttl,
446
- autoExtend: options.autoExtend ?? false
447
- });
448
- }
449
- return sessionService;
450
- };
451
- return async ({ event, resolve }) => {
452
- event.locals.user = null;
453
- event.locals.membership = null;
454
- event.locals.permissions = [];
455
- event.locals.tenantId = null;
456
- event.locals.sessionId = null;
457
- if (skipPaths.some((path) => event.url.pathname.startsWith(path))) {
458
- return resolve(event);
459
- }
460
- const sessionId = event.cookies.get(cookieName);
461
- if (!sessionId && !options.postgresRls) {
462
- return resolve(event);
463
- }
464
- try {
465
- const service = await getSessionService();
466
- return await withSessionPermissionContext(
467
- {
468
- ...options,
469
- enterTenantContext: options.enterTenantContext,
470
- postgresRls: options.postgresRls,
471
- sessionId,
472
- sessionService: service
473
- },
474
- async (context) => {
475
- if (context.session) {
476
- event.locals.user = context.user;
477
- event.locals.membership = context.membership ?? null;
478
- event.locals.permissions = context.permissions;
479
- event.locals.tenantId = context.tenantId;
480
- event.locals.sessionId = context.sessionId;
481
- }
482
- return resolve(event);
483
- }
484
- );
485
- } catch (error) {
486
- logger.error("Session or request context initialization error", {
487
- error
488
- });
489
- if (options.postgresRls) {
490
- return new Response("Internal Server Error", { status: 500 });
491
- }
492
- return resolve(event);
493
- }
494
- };
495
- }
496
- const sessionServiceCache = /* @__PURE__ */ new Map();
364
+ const cookieName = options.cookieName ?? "sid";
365
+ const ttl = options.ttl ?? 604800;
366
+ const skipPaths = options.skipPaths ?? [];
367
+ let sessionService = null;
368
+ const getSessionService = async () => {
369
+ if (!sessionService) sessionService = await SessionService.create({
370
+ ...options,
371
+ defaultTTL: ttl,
372
+ autoExtend: options.autoExtend ?? false
373
+ });
374
+ return sessionService;
375
+ };
376
+ return async ({ event, resolve }) => {
377
+ event.locals.user = null;
378
+ event.locals.membership = null;
379
+ event.locals.permissions = [];
380
+ event.locals.tenantId = null;
381
+ event.locals.sessionId = null;
382
+ if (skipPaths.some((path) => event.url.pathname.startsWith(path))) return resolve(event);
383
+ const sessionId = event.cookies.get(cookieName);
384
+ if (!sessionId && !options.postgresRls) return resolve(event);
385
+ try {
386
+ const service = await getSessionService();
387
+ return await withSessionPermissionContext({
388
+ ...options,
389
+ enterTenantContext: options.enterTenantContext,
390
+ postgresRls: options.postgresRls,
391
+ sessionId,
392
+ sessionService: service
393
+ }, async (context) => {
394
+ if (context.session) {
395
+ event.locals.user = context.user;
396
+ event.locals.membership = context.membership ?? null;
397
+ event.locals.permissions = context.permissions;
398
+ event.locals.tenantId = context.tenantId;
399
+ event.locals.sessionId = context.sessionId;
400
+ }
401
+ return resolve(event);
402
+ });
403
+ } catch (error) {
404
+ logger.error("Session or request context initialization error", { error });
405
+ if (options.postgresRls) return new Response("Internal Server Error", { status: 500 });
406
+ return resolve(event);
407
+ }
408
+ };
409
+ }
410
+ var sessionServiceCache = /* @__PURE__ */ new Map();
497
411
  async function getOrCreateSessionService(options, ttl) {
498
- const cacheKey = JSON.stringify(options.db);
499
- let service = sessionServiceCache.get(cacheKey);
500
- if (!service) {
501
- service = await SessionService.create({
502
- ...options,
503
- defaultTTL: ttl
504
- });
505
- sessionServiceCache.set(cacheKey, service);
506
- }
507
- return service;
412
+ const cacheKey = JSON.stringify(options.db);
413
+ let service = sessionServiceCache.get(cacheKey);
414
+ if (!service) {
415
+ service = await SessionService.create({
416
+ ...options,
417
+ defaultTTL: ttl
418
+ });
419
+ sessionServiceCache.set(cacheKey, service);
420
+ }
421
+ return service;
508
422
  }
509
423
  async function createSessionCookie(event, userId, tenantId, options) {
510
- const cookieName = options.cookieName ?? "sid";
511
- const ttl = options.ttl ?? DEFAULT_SESSION_TTL;
512
- const cookiePath = options.cookiePath ?? "/";
513
- const cookieSameSite = options.cookieSameSite ?? "lax";
514
- const cookieSecure = options.cookieSecure ?? event.url.protocol === "https:";
515
- const service = await getOrCreateSessionService(options, ttl);
516
- const sessionId = await service.createSession(userId, tenantId, {
517
- ttl,
518
- userAgent: options.userAgent,
519
- ipAddress: options.ipAddress,
520
- data: options.data
521
- });
522
- event.cookies.set(cookieName, sessionId, {
523
- path: cookiePath,
524
- // undefined => SvelteKit scopes the cookie to the request host.
525
- domain: options.cookieDomain,
526
- httpOnly: true,
527
- secure: cookieSecure,
528
- sameSite: cookieSameSite,
529
- maxAge: ttl
530
- });
531
- return sessionId;
424
+ const cookieName = options.cookieName ?? "sid";
425
+ const ttl = options.ttl ?? 604800;
426
+ const cookiePath = options.cookiePath ?? "/";
427
+ const cookieSameSite = options.cookieSameSite ?? "lax";
428
+ const cookieSecure = options.cookieSecure ?? event.url.protocol === "https:";
429
+ const sessionId = await (await getOrCreateSessionService(options, ttl)).createSession(userId, tenantId, {
430
+ ttl,
431
+ userAgent: options.userAgent,
432
+ ipAddress: options.ipAddress,
433
+ data: options.data
434
+ });
435
+ event.cookies.set(cookieName, sessionId, {
436
+ path: cookiePath,
437
+ domain: options.cookieDomain,
438
+ httpOnly: true,
439
+ secure: cookieSecure,
440
+ sameSite: cookieSameSite,
441
+ maxAge: ttl
442
+ });
443
+ return sessionId;
532
444
  }
533
445
  async function destroySessionCookie(event, options) {
534
- const cookieName = options.cookieName ?? "sid";
535
- const cookiePath = options.cookiePath ?? "/";
536
- const ttl = options.ttl ?? DEFAULT_SESSION_TTL;
537
- const sessionId = event.cookies.get(cookieName);
538
- if (sessionId) {
539
- try {
540
- const service = await getOrCreateSessionService(options, ttl);
541
- await service.destroySession(sessionId);
542
- } catch (error) {
543
- logger.error("Session destruction error", { error });
544
- }
545
- }
546
- event.cookies.delete(cookieName, {
547
- path: cookiePath,
548
- domain: options.cookieDomain
549
- });
446
+ const cookieName = options.cookieName ?? "sid";
447
+ const cookiePath = options.cookiePath ?? "/";
448
+ const ttl = options.ttl ?? 604800;
449
+ const sessionId = event.cookies.get(cookieName);
450
+ if (sessionId) try {
451
+ await (await getOrCreateSessionService(options, ttl)).destroySession(sessionId);
452
+ } catch (error) {
453
+ logger.error("Session destruction error", { error });
454
+ }
455
+ event.cookies.delete(cookieName, {
456
+ path: cookiePath,
457
+ domain: options.cookieDomain
458
+ });
550
459
  }
551
460
  async function switchSessionTenant(event, tenantId, options) {
552
- const cookieName = options.cookieName ?? "sid";
553
- const ttl = options.ttl ?? DEFAULT_SESSION_TTL;
554
- const sessionId = event.cookies.get(cookieName);
555
- if (!sessionId) return false;
556
- const service = await getOrCreateSessionService(options, ttl);
557
- const result = await service.switchTenant(sessionId, tenantId);
558
- if (result.rotated && result.sessionId) {
559
- const cookiePath = options.cookiePath ?? "/";
560
- const cookieSameSite = options.cookieSameSite ?? "lax";
561
- const cookieSecure = options.cookieSecure ?? event.url.protocol === "https:";
562
- const maxAge = result.session ? Math.max(
563
- 0,
564
- Math.round(
565
- (new Date(result.session.expiresAt).getTime() - Date.now()) / 1e3
566
- )
567
- ) : ttl;
568
- event.cookies.set(cookieName, result.sessionId, {
569
- path: cookiePath,
570
- // undefined => SvelteKit scopes the cookie to the request host.
571
- domain: options.cookieDomain,
572
- httpOnly: true,
573
- secure: cookieSecure,
574
- sameSite: cookieSameSite,
575
- maxAge
576
- });
577
- }
578
- return result.switched;
461
+ const cookieName = options.cookieName ?? "sid";
462
+ const ttl = options.ttl ?? 604800;
463
+ const sessionId = event.cookies.get(cookieName);
464
+ if (!sessionId) return false;
465
+ const result = await (await getOrCreateSessionService(options, ttl)).switchTenant(sessionId, tenantId);
466
+ if (result.rotated && result.sessionId) {
467
+ const cookiePath = options.cookiePath ?? "/";
468
+ const cookieSameSite = options.cookieSameSite ?? "lax";
469
+ const cookieSecure = options.cookieSecure ?? event.url.protocol === "https:";
470
+ const maxAge = result.session ? Math.max(0, Math.round((new Date(result.session.expiresAt).getTime() - Date.now()) / 1e3)) : ttl;
471
+ event.cookies.set(cookieName, result.sessionId, {
472
+ path: cookiePath,
473
+ domain: options.cookieDomain,
474
+ httpOnly: true,
475
+ secure: cookieSecure,
476
+ sameSite: cookieSameSite,
477
+ maxAge
478
+ });
479
+ }
480
+ return result.switched;
579
481
  }
580
482
  function getOidcProviderName(event, options) {
581
- if (typeof options.provider === "function") {
582
- return options.provider(event);
583
- }
584
- return options.provider ?? event.params?.provider ?? options.defaultProvider;
483
+ if (typeof options.provider === "function") return options.provider(event);
484
+ return options.provider ?? event.params?.provider ?? options.defaultProvider;
585
485
  }
586
486
  function getOidcTransactionCookieName(providerName, options) {
587
- const prefix = options.transactionCookiePrefix ?? "smrt_oidc";
588
- const safeProvider = providerName.replace(/[^a-z0-9_-]/giu, "_");
589
- return `${prefix}_${safeProvider}`;
487
+ return `${options.transactionCookiePrefix ?? "smrt_oidc"}_${providerName.replace(/[^a-z0-9_-]/giu, "_")}`;
590
488
  }
591
489
  function useSecureCookie(event, explicit) {
592
- return explicit ?? event.url.protocol === "https:";
490
+ return explicit ?? event.url.protocol === "https:";
593
491
  }
594
492
  function resolveCallbackPath(providerName, options) {
595
- if (typeof options.callbackPath === "function") {
596
- return options.callbackPath(providerName);
597
- }
598
- return options.callbackPath ?? `/auth/${providerName}/callback`;
493
+ if (typeof options.callbackPath === "function") return options.callbackPath(providerName);
494
+ return options.callbackPath ?? `/auth/${providerName}/callback`;
599
495
  }
600
496
  function resolveProviderWithRedirectUri(event, providerName, provider, options) {
601
- return {
602
- ...provider,
603
- redirectUri: provider.redirectUri ?? new URL(
604
- resolveCallbackPath(providerName, options),
605
- event.url.origin
606
- ).toString()
607
- };
497
+ return {
498
+ ...provider,
499
+ redirectUri: provider.redirectUri ?? new URL(resolveCallbackPath(providerName, options), event.url.origin).toString()
500
+ };
608
501
  }
609
502
  function createOidcService(event, options) {
610
- const providerName = getOidcProviderName(event, options);
611
- const resolved = resolveOidcProviderConfig(providerName, options);
612
- const provider = resolveProviderWithRedirectUri(
613
- event,
614
- resolved.providerName,
615
- resolved.provider,
616
- options
617
- );
618
- return new OidcLoginService({
619
- ...options,
620
- provider,
621
- providerName: resolved.providerName
622
- });
503
+ const resolved = resolveOidcProviderConfig(getOidcProviderName(event, options), options);
504
+ const provider = resolveProviderWithRedirectUri(event, resolved.providerName, resolved.provider, options);
505
+ return new OidcLoginService({
506
+ ...options,
507
+ provider,
508
+ providerName: resolved.providerName
509
+ });
623
510
  }
624
511
  function getReturnTo(event, options) {
625
- const param = options.returnToParam ?? "returnTo";
626
- return getLocalReturnTo(event.url.searchParams.get(param));
512
+ const param = options.returnToParam ?? "returnTo";
513
+ return getLocalReturnTo(event.url.searchParams.get(param));
627
514
  }
628
515
  function getLocalReturnTo(returnTo) {
629
- if (!returnTo) return void 0;
630
- if (returnTo.startsWith("/") && !returnTo.startsWith("//")) {
631
- return returnTo;
632
- }
633
- return void 0;
516
+ if (!returnTo) return void 0;
517
+ if (returnTo.startsWith("/") && !returnTo.startsWith("//")) return returnTo;
634
518
  }
635
519
  function getTransactionCookieSameSite(event, options) {
636
- if (options.transactionCookieSameSite) {
637
- return options.transactionCookieSameSite;
638
- }
639
- return useSecureCookie(event, options.transactionCookieSecure) ? "none" : "lax";
520
+ if (options.transactionCookieSameSite) return options.transactionCookieSameSite;
521
+ return useSecureCookie(event, options.transactionCookieSecure) ? "none" : "lax";
640
522
  }
641
523
  function getTransactionCookieSecret(provider, options) {
642
- const secret = options.transactionCookieSecret ?? provider.clientSecret;
643
- return secret && secret.length > 0 ? secret : void 0;
524
+ const secret = options.transactionCookieSecret ?? provider.clientSecret;
525
+ return secret && secret.length > 0 ? secret : void 0;
644
526
  }
645
527
  function bytesToBase64Url(bytes) {
646
- let binary = "";
647
- for (const byte of bytes) {
648
- binary += String.fromCharCode(byte);
649
- }
650
- return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
528
+ let binary = "";
529
+ for (const byte of bytes) binary += String.fromCharCode(byte);
530
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
651
531
  }
652
532
  async function signTransactionPayload(payload, secret) {
653
- const key = await crypto.subtle.importKey(
654
- "raw",
655
- new TextEncoder().encode(secret),
656
- { hash: "SHA-256", name: "HMAC" },
657
- false,
658
- ["sign"]
659
- );
660
- const signature = await crypto.subtle.sign(
661
- "HMAC",
662
- key,
663
- new TextEncoder().encode(payload)
664
- );
665
- return bytesToBase64Url(new Uint8Array(signature));
533
+ const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(secret), {
534
+ hash: "SHA-256",
535
+ name: "HMAC"
536
+ }, false, ["sign"]);
537
+ const signature = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(payload));
538
+ return bytesToBase64Url(new Uint8Array(signature));
666
539
  }
667
540
  function timingSafeEqual(left, right) {
668
- const leftBytes = new TextEncoder().encode(left);
669
- const rightBytes = new TextEncoder().encode(right);
670
- let diff = leftBytes.length ^ rightBytes.length;
671
- const length = Math.max(leftBytes.length, rightBytes.length);
672
- for (let index = 0; index < length; index += 1) {
673
- diff |= (leftBytes[index] ?? 0) ^ (rightBytes[index] ?? 0);
674
- }
675
- return diff === 0;
541
+ const leftBytes = new TextEncoder().encode(left);
542
+ const rightBytes = new TextEncoder().encode(right);
543
+ let diff = leftBytes.length ^ rightBytes.length;
544
+ const length = Math.max(leftBytes.length, rightBytes.length);
545
+ for (let index = 0; index < length; index += 1) diff |= (leftBytes[index] ?? 0) ^ (rightBytes[index] ?? 0);
546
+ return diff === 0;
676
547
  }
677
548
  async function encodeOidcTransactionCookie(transaction, secret) {
678
- const payload = encodeOidcTransaction(transaction);
679
- if (!secret) return payload;
680
- const signature = await signTransactionPayload(payload, secret);
681
- return `${payload}.${signature}`;
549
+ const payload = encodeOidcTransaction(transaction);
550
+ if (!secret) return payload;
551
+ return `${payload}.${await signTransactionPayload(payload, secret)}`;
682
552
  }
683
553
  async function decodeOidcTransactionCookie(value, secret) {
684
- if (!secret) return decodeOidcTransaction(value);
685
- const separatorIndex = value.lastIndexOf(".");
686
- if (separatorIndex < 0) {
687
- throw new OidcLoginError("Invalid OIDC login transaction signature.");
688
- }
689
- const payload = value.slice(0, separatorIndex);
690
- const signature = value.slice(separatorIndex + 1);
691
- const expectedSignature = await signTransactionPayload(payload, secret);
692
- if (!timingSafeEqual(signature, expectedSignature)) {
693
- throw new OidcLoginError("Invalid OIDC login transaction signature.");
694
- }
695
- return decodeOidcTransaction(payload);
554
+ if (!secret) return decodeOidcTransaction(value);
555
+ const separatorIndex = value.lastIndexOf(".");
556
+ if (separatorIndex < 0) throw new OidcLoginError("Invalid OIDC login transaction signature.");
557
+ const payload = value.slice(0, separatorIndex);
558
+ if (!timingSafeEqual(value.slice(separatorIndex + 1), await signTransactionPayload(payload, secret))) throw new OidcLoginError("Invalid OIDC login transaction signature.");
559
+ return decodeOidcTransaction(payload);
696
560
  }
697
561
  function getTransactionTtl(options) {
698
- return options.transactionTtl ?? getUsersOidcConfig().transactionTtl ?? 10 * 60;
562
+ return options.transactionTtl ?? getUsersOidcConfig().transactionTtl ?? 600;
699
563
  }
700
564
  async function resolveTenantId(result, event, options) {
701
- if (typeof options.tenantId === "function") {
702
- return options.tenantId(result, event);
703
- }
704
- return options.tenantId;
565
+ if (typeof options.tenantId === "function") return options.tenantId(result, event);
566
+ return options.tenantId;
705
567
  }
706
568
  function redirectResponse(location) {
707
- return new Response(null, {
708
- headers: { location: location.toString() },
709
- status: 303
710
- });
569
+ return new Response(null, {
570
+ headers: { location: location.toString() },
571
+ status: 303
572
+ });
711
573
  }
712
574
  function failureResponse(error) {
713
- const message = error instanceof Error ? error.message : "OIDC login failed.";
714
- return new Response(message, {
715
- status: 401,
716
- headers: {
717
- "content-type": "text/plain; charset=utf-8"
718
- }
719
- });
575
+ const message = error instanceof Error ? error.message : "OIDC login failed.";
576
+ return new Response(message, {
577
+ status: 401,
578
+ headers: { "content-type": "text/plain; charset=utf-8" }
579
+ });
720
580
  }
721
581
  function resolveSuccessRedirect(result, event, options) {
722
- if (typeof options.successRedirect === "function") {
723
- return options.successRedirect(result, event);
724
- }
725
- return options.successRedirect ?? result.returnTo ?? "/";
582
+ if (typeof options.successRedirect === "function") return options.successRedirect(result, event);
583
+ return options.successRedirect ?? result.returnTo ?? "/";
726
584
  }
727
585
  function resolveFailureRedirect(error, event, options) {
728
- if (!options.failureRedirect) return void 0;
729
- if (typeof options.failureRedirect === "function") {
730
- return options.failureRedirect(error, event);
731
- }
732
- return options.failureRedirect;
586
+ if (!options.failureRedirect) return void 0;
587
+ if (typeof options.failureRedirect === "function") return options.failureRedirect(error, event);
588
+ return options.failureRedirect;
733
589
  }
734
590
  async function beginOidcLogin(event, options) {
735
- const service = createOidcService(event, options);
736
- const transaction = service.createTransaction(getReturnTo(event, options));
737
- const result = await service.createAuthorizationUrl({ transaction });
738
- event.cookies.set(
739
- getOidcTransactionCookieName(service.providerName, options),
740
- await encodeOidcTransactionCookie(
741
- transaction,
742
- getTransactionCookieSecret(service.provider, options)
743
- ),
744
- {
745
- httpOnly: true,
746
- maxAge: getTransactionTtl(options),
747
- path: options.transactionCookiePath ?? "/",
748
- sameSite: getTransactionCookieSameSite(event, options),
749
- secure: useSecureCookie(event, options.transactionCookieSecure)
750
- }
751
- );
752
- return {
753
- providerName: service.providerName,
754
- transaction,
755
- url: result.url
756
- };
591
+ const service = createOidcService(event, options);
592
+ const transaction = service.createTransaction(getReturnTo(event, options));
593
+ const result = await service.createAuthorizationUrl({ transaction });
594
+ event.cookies.set(getOidcTransactionCookieName(service.providerName, options), await encodeOidcTransactionCookie(transaction, getTransactionCookieSecret(service.provider, options)), {
595
+ httpOnly: true,
596
+ maxAge: getTransactionTtl(options),
597
+ path: options.transactionCookiePath ?? "/",
598
+ sameSite: getTransactionCookieSameSite(event, options),
599
+ secure: useSecureCookie(event, options.transactionCookieSecure)
600
+ });
601
+ return {
602
+ providerName: service.providerName,
603
+ transaction,
604
+ url: result.url
605
+ };
757
606
  }
758
607
  async function completeOidcLogin(event, options) {
759
- const service = createOidcService(event, options);
760
- const cookieName = getOidcTransactionCookieName(
761
- service.providerName,
762
- options
763
- );
764
- const cookiePath = options.transactionCookiePath ?? "/";
765
- try {
766
- const rawTransaction = event.cookies.get(cookieName);
767
- if (!rawTransaction) {
768
- throw new OidcLoginError("Missing OIDC login transaction cookie.");
769
- }
770
- const decodedTransaction = await decodeOidcTransactionCookie(
771
- rawTransaction,
772
- getTransactionCookieSecret(service.provider, options)
773
- );
774
- const transaction = {
775
- ...decodedTransaction,
776
- returnTo: getLocalReturnTo(decodedTransaction.returnTo)
777
- };
778
- const ttl = getTransactionTtl(options);
779
- if (Date.now() - transaction.createdAt > ttl * 1e3) {
780
- throw new OidcLoginError("OIDC login transaction has expired.");
781
- }
782
- const result = await service.completeLogin(event.url, transaction);
783
- const tenantId = await resolveTenantId(result, event, options);
784
- const sessionId = await createSessionCookie(
785
- event,
786
- result.user.id,
787
- tenantId ?? void 0,
788
- {
789
- ...options,
790
- cookieName: options.sessionCookieName,
791
- cookiePath: options.sessionCookiePath,
792
- cookieSameSite: options.sessionCookieSameSite,
793
- cookieSecure: useSecureCookie(event, options.sessionCookieSecure),
794
- data: {
795
- oidcIssuer: result.claims.iss,
796
- oidcProvider: service.providerName
797
- },
798
- ipAddress: event.getClientAddress?.(),
799
- ttl: options.sessionTtl,
800
- userAgent: event.request.headers.get("user-agent") ?? void 0
801
- }
802
- );
803
- return {
804
- ...result,
805
- providerName: service.providerName,
806
- returnTo: transaction.returnTo,
807
- sessionId
808
- };
809
- } finally {
810
- event.cookies.delete(cookieName, { path: cookiePath });
811
- }
608
+ const service = createOidcService(event, options);
609
+ const cookieName = getOidcTransactionCookieName(service.providerName, options);
610
+ const cookiePath = options.transactionCookiePath ?? "/";
611
+ try {
612
+ const rawTransaction = event.cookies.get(cookieName);
613
+ if (!rawTransaction) throw new OidcLoginError("Missing OIDC login transaction cookie.");
614
+ const decodedTransaction = await decodeOidcTransactionCookie(rawTransaction, getTransactionCookieSecret(service.provider, options));
615
+ const transaction = {
616
+ ...decodedTransaction,
617
+ returnTo: getLocalReturnTo(decodedTransaction.returnTo)
618
+ };
619
+ const ttl = getTransactionTtl(options);
620
+ if (Date.now() - transaction.createdAt > ttl * 1e3) throw new OidcLoginError("OIDC login transaction has expired.");
621
+ const result = await service.completeLogin(event.url, transaction);
622
+ const tenantId = await resolveTenantId(result, event, options);
623
+ const sessionId = await createSessionCookie(event, result.user.id, tenantId ?? void 0, {
624
+ ...options,
625
+ cookieName: options.sessionCookieName,
626
+ cookiePath: options.sessionCookiePath,
627
+ cookieSameSite: options.sessionCookieSameSite,
628
+ cookieSecure: useSecureCookie(event, options.sessionCookieSecure),
629
+ data: {
630
+ oidcIssuer: result.claims.iss,
631
+ oidcProvider: service.providerName
632
+ },
633
+ ipAddress: event.getClientAddress?.(),
634
+ ttl: options.sessionTtl,
635
+ userAgent: event.request.headers.get("user-agent") ?? void 0
636
+ });
637
+ return {
638
+ ...result,
639
+ providerName: service.providerName,
640
+ returnTo: transaction.returnTo,
641
+ sessionId
642
+ };
643
+ } finally {
644
+ event.cookies.delete(cookieName, { path: cookiePath });
645
+ }
812
646
  }
813
647
  function createOidcLoginHandler(options) {
814
- return async (event) => {
815
- const { url } = await beginOidcLogin(event, options);
816
- return redirectResponse(url);
817
- };
648
+ return async (event) => {
649
+ const { url } = await beginOidcLogin(event, options);
650
+ return redirectResponse(url);
651
+ };
818
652
  }
819
653
  function createOidcCallbackHandler(options) {
820
- return async (event) => {
821
- try {
822
- const result = await completeOidcLogin(event, options);
823
- const redirectTo = await resolveSuccessRedirect(result, event, options);
824
- return redirectResponse(redirectTo);
825
- } catch (error) {
826
- const failureRedirect = resolveFailureRedirect(error, event, options);
827
- if (failureRedirect) return redirectResponse(failureRedirect);
828
- return failureResponse(error);
829
- }
830
- };
831
- }
832
- const terminalAuthServiceCache = /* @__PURE__ */ new Map();
654
+ return async (event) => {
655
+ try {
656
+ return redirectResponse(await resolveSuccessRedirect(await completeOidcLogin(event, options), event, options));
657
+ } catch (error) {
658
+ const failureRedirect = resolveFailureRedirect(error, event, options);
659
+ if (failureRedirect) return redirectResponse(failureRedirect);
660
+ return failureResponse(error);
661
+ }
662
+ };
663
+ }
664
+ var terminalAuthServiceCache = /* @__PURE__ */ new Map();
833
665
  function terminalAuthCacheKey(options) {
834
- return JSON.stringify({
835
- db: options.db,
836
- cookie: options.sessionCookieName,
837
- prefix: options.userCodePrefix,
838
- reqTtl: options.requestTtlSeconds,
839
- sessTtl: options.sessionTtlSeconds,
840
- poll: options.pollIntervalSeconds,
841
- path: options.verificationPath,
842
- autoExtend: options.sessionAutoExtend,
843
- maxAttempts: options.maxApproveAttempts,
844
- attemptWindow: options.approveAttemptWindowSeconds
845
- });
666
+ return JSON.stringify({
667
+ db: options.db,
668
+ cookie: options.sessionCookieName,
669
+ prefix: options.userCodePrefix,
670
+ reqTtl: options.requestTtlSeconds,
671
+ sessTtl: options.sessionTtlSeconds,
672
+ poll: options.pollIntervalSeconds,
673
+ path: options.verificationPath,
674
+ autoExtend: options.sessionAutoExtend,
675
+ maxAttempts: options.maxApproveAttempts,
676
+ attemptWindow: options.approveAttemptWindowSeconds
677
+ });
846
678
  }
847
679
  async function getOrCreateTerminalAuthService(options) {
848
- const key = terminalAuthCacheKey(options);
849
- let service = terminalAuthServiceCache.get(key);
850
- if (!service) {
851
- service = await TerminalAuthService.create(options);
852
- terminalAuthServiceCache.set(key, service);
853
- }
854
- return service;
680
+ const key = terminalAuthCacheKey(options);
681
+ let service = terminalAuthServiceCache.get(key);
682
+ if (!service) {
683
+ service = await TerminalAuthService.create(options);
684
+ terminalAuthServiceCache.set(key, service);
685
+ }
686
+ return service;
855
687
  }
856
688
  function parseBearerToken(authorization) {
857
- const match = authorization?.match(/^Bearer\s+(.+)$/iu);
858
- return match?.[1]?.trim() || null;
689
+ return (authorization?.match(/^Bearer\s+(.+)$/iu))?.[1]?.trim() || null;
859
690
  }
860
691
  function createTerminalAuthStartHandler(options) {
861
- return async (event) => {
862
- const service = await getOrCreateTerminalAuthService(options);
863
- const origin = typeof options.verificationOrigin === "function" ? options.verificationOrigin(event) : options.verificationOrigin ?? event.url.origin;
864
- const result = await service.createRequest(origin);
865
- return jsonResponse(result, 201, NO_STORE_HEADERS);
866
- };
692
+ return async (event) => {
693
+ const service = await getOrCreateTerminalAuthService(options);
694
+ const origin = typeof options.verificationOrigin === "function" ? options.verificationOrigin(event) : options.verificationOrigin ?? event.url.origin;
695
+ return jsonResponse(await service.createRequest(origin), 201, NO_STORE_HEADERS);
696
+ };
867
697
  }
868
698
  function createTerminalAuthTokenHandler(options) {
869
- return async (event) => {
870
- const body = await event.request.json().catch(() => null);
871
- const deviceCode = typeof body?.deviceCode === "string" ? body.deviceCode.trim() : "";
872
- if (!deviceCode) {
873
- return jsonResponse({ error: "deviceCode is required." }, 400);
874
- }
875
- const service = await getOrCreateTerminalAuthService(options);
876
- const result = await service.exchangeDeviceCode(deviceCode);
877
- return jsonResponse(result, 200, NO_STORE_HEADERS);
878
- };
699
+ return async (event) => {
700
+ const body = await event.request.json().catch(() => null);
701
+ const deviceCode = typeof body?.deviceCode === "string" ? body.deviceCode.trim() : "";
702
+ if (!deviceCode) return jsonResponse({ error: "deviceCode is required." }, 400);
703
+ return jsonResponse(await (await getOrCreateTerminalAuthService(options)).exchangeDeviceCode(deviceCode), 200, NO_STORE_HEADERS);
704
+ };
879
705
  }
880
706
  function createBearerSessionDeleteHandler(options) {
881
- return async (event) => {
882
- const token = parseBearerToken(event.request.headers.get("authorization"));
883
- if (token) {
884
- try {
885
- const service = await getOrCreateTerminalAuthService(options);
886
- await service.destroyBearerSession(token);
887
- } catch (error) {
888
- logger.error("Terminal bearer session revocation error", { error });
889
- }
890
- }
891
- return jsonResponse({ authenticated: false });
892
- };
707
+ return async (event) => {
708
+ const token = parseBearerToken(event.request.headers.get("authorization"));
709
+ if (token) try {
710
+ await (await getOrCreateTerminalAuthService(options)).destroyBearerSession(token);
711
+ } catch (error) {
712
+ logger.error("Terminal bearer session revocation error", { error });
713
+ }
714
+ return jsonResponse({ authenticated: false });
715
+ };
893
716
  }
894
717
  async function loadBearerSessionContext(token, options) {
895
- const service = await getOrCreateTerminalAuthService(options);
896
- return service.loadBearerSession(token);
718
+ return (await getOrCreateTerminalAuthService(options)).loadBearerSession(token);
897
719
  }
898
720
  function mountTerminalLoginPage(options) {
899
- const codeParam = options.codeQueryParam ?? "code";
900
- return {
901
- load: async (event) => {
902
- const userCode = event.url.searchParams.get(codeParam)?.trim().toUpperCase() ?? "";
903
- let requestStatus = null;
904
- if (userCode) {
905
- const service = await getOrCreateTerminalAuthService(options);
906
- const request = await service.getRequestForUserCode(userCode);
907
- requestStatus = request?.status ?? null;
908
- }
909
- return { requestStatus, userCode };
910
- },
911
- approve: async (event) => {
912
- const formData = await event.request.formData();
913
- const userCode = formData.get("userCode")?.toString().trim().toUpperCase() ?? "";
914
- if (!userCode) {
915
- return {
916
- type: "failure",
917
- status: 400,
918
- data: {
919
- status: 400,
920
- error: "Enter a terminal login code.",
921
- userCode
922
- }
923
- };
924
- }
925
- const user = options.resolveUser(event);
926
- const tenantId = options.resolveTenantId(event);
927
- if (!user?.id) {
928
- return {
929
- type: "failure",
930
- status: 401,
931
- data: {
932
- status: 401,
933
- error: "Sign in before approving terminal access.",
934
- userCode
935
- }
936
- };
937
- }
938
- try {
939
- const service = await getOrCreateTerminalAuthService(options);
940
- const approveInput = {
941
- ipAddress: event.getClientAddress?.(),
942
- tenantId: tenantId ?? null,
943
- user: {
944
- email: user.email ?? "",
945
- id: user.id
946
- },
947
- userAgent: event.request.headers.get("user-agent") ?? void 0,
948
- userCode
949
- };
950
- const request = await service.approveRequest(approveInput);
951
- return {
952
- approved: true,
953
- requestStatus: request.status,
954
- userCode
955
- };
956
- } catch (error) {
957
- if (error instanceof TerminalAuthRateLimitError) {
958
- return {
959
- type: "failure",
960
- status: 429,
961
- data: { status: 429, error: error.message, userCode }
962
- };
963
- }
964
- const message = error instanceof TerminalAuthError ? error.message : error instanceof Error ? error.message : "Unable to approve terminal login.";
965
- return {
966
- type: "failure",
967
- status: 400,
968
- data: { status: 400, error: message, userCode }
969
- };
970
- }
971
- }
972
- };
721
+ const codeParam = options.codeQueryParam ?? "code";
722
+ return {
723
+ load: async (event) => {
724
+ const userCode = event.url.searchParams.get(codeParam)?.trim().toUpperCase() ?? "";
725
+ let requestStatus = null;
726
+ if (userCode) requestStatus = (await (await getOrCreateTerminalAuthService(options)).getRequestForUserCode(userCode))?.status ?? null;
727
+ return {
728
+ requestStatus,
729
+ userCode
730
+ };
731
+ },
732
+ approve: async (event) => {
733
+ const userCode = (await event.request.formData()).get("userCode")?.toString().trim().toUpperCase() ?? "";
734
+ if (!userCode) return {
735
+ type: "failure",
736
+ status: 400,
737
+ data: {
738
+ status: 400,
739
+ error: "Enter a terminal login code.",
740
+ userCode
741
+ }
742
+ };
743
+ const user = options.resolveUser(event);
744
+ const tenantId = options.resolveTenantId(event);
745
+ if (!user?.id) return {
746
+ type: "failure",
747
+ status: 401,
748
+ data: {
749
+ status: 401,
750
+ error: "Sign in before approving terminal access.",
751
+ userCode
752
+ }
753
+ };
754
+ try {
755
+ const service = await getOrCreateTerminalAuthService(options);
756
+ const approveInput = {
757
+ ipAddress: event.getClientAddress?.(),
758
+ tenantId: tenantId ?? null,
759
+ user: {
760
+ email: user.email ?? "",
761
+ id: user.id
762
+ },
763
+ userAgent: event.request.headers.get("user-agent") ?? void 0,
764
+ userCode
765
+ };
766
+ return {
767
+ approved: true,
768
+ requestStatus: (await service.approveRequest(approveInput)).status,
769
+ userCode
770
+ };
771
+ } catch (error) {
772
+ if (error instanceof TerminalAuthRateLimitError) return {
773
+ type: "failure",
774
+ status: 429,
775
+ data: {
776
+ status: 429,
777
+ error: error.message,
778
+ userCode
779
+ }
780
+ };
781
+ return {
782
+ type: "failure",
783
+ status: 400,
784
+ data: {
785
+ status: 400,
786
+ error: error instanceof TerminalAuthError ? error.message : error instanceof Error ? error.message : "Unable to approve terminal login.",
787
+ userCode
788
+ }
789
+ };
790
+ }
791
+ }
792
+ };
973
793
  }
974
794
  function jsonResponse(body, status = 200, extraHeaders) {
975
- return new Response(JSON.stringify(body), {
976
- status,
977
- headers: { "content-type": "application/json", ...extraHeaders }
978
- });
979
- }
980
- const NO_STORE_HEADERS = {
981
- "cache-control": "private, no-store",
982
- pragma: "no-cache"
983
- };
984
- export {
985
- InvalidBearerError,
986
- TerminalAuthError,
987
- TerminalAuthRateLimitError,
988
- TerminalAuthService,
989
- beginOidcLogin,
990
- completeOidcLogin,
991
- createBearerSessionDeleteHandler,
992
- createOidcCallbackHandler,
993
- createOidcLoginHandler,
994
- createResourceListHandler,
995
- createSessionCookie,
996
- createSessionHandler,
997
- createTerminalAuthStartHandler,
998
- createTerminalAuthTokenHandler,
999
- defaultSessionLocals,
1000
- destroySessionCookie,
1001
- loadBearerSessionContext,
1002
- mountTerminalLoginPage,
1003
- parseBearerToken,
1004
- switchSessionTenant
795
+ return new Response(JSON.stringify(body), {
796
+ status,
797
+ headers: {
798
+ "content-type": "application/json",
799
+ ...extraHeaders
800
+ }
801
+ });
802
+ }
803
+ var NO_STORE_HEADERS = {
804
+ "cache-control": "private, no-store",
805
+ pragma: "no-cache"
1005
806
  };
1006
- //# sourceMappingURL=sveltekit.js.map
807
+ //#endregion
808
+ export { InvalidBearerError, TerminalAuthError, TerminalAuthRateLimitError, TerminalAuthService, beginOidcLogin, completeOidcLogin, createBearerSessionDeleteHandler, createOidcCallbackHandler, createOidcLoginHandler, createResourceListHandler, createSessionCookie, createSessionHandler, createTerminalAuthStartHandler, createTerminalAuthTokenHandler, defaultSessionLocals, destroySessionCookie, loadBearerSessionContext, mountTerminalLoginPage, parseBearerToken, switchSessionTenant };
809
+
810
+ //# sourceMappingURL=sveltekit.js.map