@niledatabase/server 5.0.0-alpha.2 → 5.0.0-alpha.20

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/index.mjs CHANGED
@@ -2,6 +2,12 @@ import 'dotenv/config';
2
2
  import pg from 'pg';
3
3
 
4
4
  // src/types.ts
5
+ var ExtensionState = /* @__PURE__ */ ((ExtensionState2) => {
6
+ ExtensionState2["onHandleRequest"] = "onHandleRequest";
7
+ ExtensionState2["onRequest"] = "onRequest";
8
+ ExtensionState2["onResponse"] = "onResponse";
9
+ return ExtensionState2;
10
+ })(ExtensionState || {});
5
11
  var APIErrorErrorCodeEnum = {
6
12
  InternalError: "internal_error",
7
13
  BadRequest: "bad_request",
@@ -25,6 +31,12 @@ var LoginUserResponseTokenTypeEnum = {
25
31
  IdToken: "ID_TOKEN"
26
32
  };
27
33
 
34
+ // src/utils/constants.ts
35
+ var TENANT_COOKIE = "nile.tenant-id";
36
+ var USER_COOKIE = "nile.user-id";
37
+ var HEADER_ORIGIN = "nile-origin";
38
+ var HEADER_SECURE_COOKIES = "nile-secure-cookies";
39
+
28
40
  // src/api/utils/routes/index.ts
29
41
  var NILEDB_API_URL = process.env.NILEDB_API_URL;
30
42
  var DEFAULT_PREFIX = "/api";
@@ -47,6 +59,8 @@ var appRoutes = (prefix = DEFAULT_PREFIX) => ({
47
59
  TENANT_USER: `${prefix}${"/tenants/{tenantId}/users/{userId}" /* TENANT_USER */}`,
48
60
  TENANT_USERS: `${prefix}${"/tenants/{tenantId}/users" /* TENANT_USERS */}`,
49
61
  SIGNUP: `${prefix}${"/signup" /* SIGNUP */}`,
62
+ INVITES: `${prefix}${"/tenants/{tenantId}/invites" /* INVITES */}`,
63
+ INVITE: `${prefix}${"/tenants/{tenantId}/invite" /* INVITE */}`,
50
64
  LOG: `${prefix}/_log`
51
65
  });
52
66
  var apiRoutes = (config) => ({
@@ -57,6 +71,8 @@ var apiRoutes = (config) => ({
57
71
  TENANT: (tenantId) => makeRestUrl(config, `/tenants/${tenantId}`),
58
72
  SIGNUP: makeRestUrl(config, "/signup"),
59
73
  TENANT_USERS: (tenantId) => makeRestUrl(config, `/tenants/${tenantId}/users`),
74
+ INVITES: (tenantId) => makeRestUrl(config, `/tenants/${tenantId}/invites`),
75
+ INVITE: (tenantId) => makeRestUrl(config, `/tenants/${tenantId}/invite`),
60
76
  TENANT_USER: makeRestUrl(
61
77
  config,
62
78
  `/tenants/${config.tenantId}/users/${config.userId}`
@@ -98,9 +114,9 @@ function makeRestUrl(config, path, qp) {
98
114
  const strParams = params.toString();
99
115
  return `${[url, path.substring(1, path.length)].join("/")}${strParams ? `?${strParams}` : ""}`;
100
116
  }
101
- function urlMatches(requestUrl, route17) {
117
+ function urlMatches(requestUrl, route20) {
102
118
  const url = new URL(requestUrl);
103
- return url.pathname.startsWith(route17);
119
+ return url.pathname.startsWith(route20);
104
120
  }
105
121
  function isUUID(value) {
106
122
  if (!value) {
@@ -110,90 +126,26 @@ function isUUID(value) {
110
126
  return regex.test(value);
111
127
  }
112
128
 
113
- // src/utils/Logger.ts
114
- var red = "\x1B[31m";
115
- var yellow = "\x1B[38;2;255;255;0m";
116
- var purple = "\x1B[38;2;200;160;255m";
117
- var orange = "\x1B[38;2;255;165;0m";
118
- var reset = "\x1B[0m";
119
- var baseLogger = (config, ...params) => ({
120
- info(message, meta) {
121
- if (config?.debug) {
122
- console.info(
123
- `${orange}[niledb]${reset}${purple}[DEBUG]${reset}${params.join(
124
- ""
125
- )}${reset} ${message}`,
126
- meta ? `${JSON.stringify(meta)}` : ""
127
- );
128
- }
129
- },
130
- debug(message, meta) {
131
- if (config?.debug) {
132
- console.debug(
133
- `${orange}[niledb]${reset}${purple}[DEBUG]${reset}${params.join(
134
- ""
135
- )}${reset} ${message}`,
136
- meta ? `${JSON.stringify(meta)}` : ""
137
- );
138
- }
139
- },
140
- warn(message, meta) {
141
- if (config?.debug) {
142
- console.warn(
143
- `${orange}[niledb]${reset}${yellow}[WARN]${reset}${params.join(
144
- ""
145
- )}${reset} ${message}`,
146
- meta ? JSON.stringify(meta) : ""
147
- );
148
- }
149
- },
150
- error(message, meta) {
151
- console.error(
152
- `${orange}[niledb]${reset}${red}[ERROR]${reset}${params.join(
153
- ""
154
- )}${red} ${message}`,
155
- meta ? meta : "",
156
- `${reset}`
157
- );
158
- }
159
- });
160
- function Logger(config, ...params) {
161
- const base = baseLogger(config, params);
162
- const info = config?.logger?.info ?? base.info;
163
- const debug = config?.logger?.debug ?? base.debug;
164
- const warn = config?.logger?.warn ?? base.warn;
165
- const error = config?.logger?.error ?? base.error;
166
- return { info, warn, error, debug };
167
- }
168
- function matchesLog(configRoutes, request2) {
169
- return urlMatches(request2.url, configRoutes.LOG);
170
- }
171
-
172
- // src/utils/constants.ts
173
- var X_NILE_TENANT = "nile-tenant-id";
174
- var X_NILE_ORIGIN = "nile-origin";
175
- var X_NILE_SECURECOOKIES = "nile-secure-cookies";
176
-
177
129
  // src/api/utils/request.ts
178
130
  async function request(url, _init, config) {
179
- const { debug, info, error } = Logger(config, "[REQUEST]");
131
+ const { debug, info, error } = config.logger("[REQUEST]");
180
132
  const { request: request2, ...init } = _init;
181
133
  const requestUrl = new URL(request2.url);
182
134
  const updatedHeaders = new Headers({});
183
135
  if (request2.headers.get("cookie")) {
184
136
  updatedHeaders.set("cookie", String(request2.headers.get("cookie")));
185
137
  }
186
- if (request2.headers.get(X_NILE_TENANT)) {
138
+ if (request2.headers.get(TENANT_COOKIE)) {
187
139
  updatedHeaders.set(
188
- X_NILE_TENANT,
189
- String(request2.headers.get(X_NILE_TENANT))
140
+ TENANT_COOKIE,
141
+ String(request2.headers.get(TENANT_COOKIE))
190
142
  );
191
143
  }
192
144
  if (config.secureCookies != null) {
193
- updatedHeaders.set(X_NILE_SECURECOOKIES, String(config.secureCookies));
145
+ updatedHeaders.set(HEADER_SECURE_COOKIES, String(config.secureCookies));
194
146
  } else {
195
147
  updatedHeaders.set(
196
- X_NILE_SECURECOOKIES,
148
+ HEADER_SECURE_COOKIES,
197
149
  process.env.NODE_ENV === "production" ? "true" : "false"
198
150
  );
199
151
  }
@@ -201,17 +153,17 @@ async function request(url, _init, config) {
201
153
  if (config.callbackUrl) {
202
154
  const cbUrl = new URL(config.callbackUrl);
203
155
  debug(`Obtained origin from config.callbackUrl ${config.callbackUrl}`);
204
- updatedHeaders.set(X_NILE_ORIGIN, cbUrl.origin);
156
+ updatedHeaders.set(HEADER_ORIGIN, cbUrl.origin);
205
157
  } else if (config.origin) {
206
158
  debug(`Obtained origin from config.origin ${config.origin}`);
207
- updatedHeaders.set(X_NILE_ORIGIN, config.origin);
159
+ updatedHeaders.set(HEADER_ORIGIN, config.origin);
208
160
  } else {
209
- const passedOrigin = request2.headers.get(X_NILE_ORIGIN);
161
+ const passedOrigin = request2.headers.get(HEADER_ORIGIN);
210
162
  if (passedOrigin) {
211
- updatedHeaders.set(X_NILE_ORIGIN, passedOrigin);
163
+ updatedHeaders.set(HEADER_ORIGIN, passedOrigin);
212
164
  } else {
213
165
  const reqOrigin = config.routePrefix !== DEFAULT_PREFIX ? `${requestUrl.origin}${config.routePrefix}` : requestUrl.origin;
214
- updatedHeaders.set(X_NILE_ORIGIN, reqOrigin);
166
+ updatedHeaders.set(HEADER_ORIGIN, reqOrigin);
215
167
  debug(`Obtained origin from request ${reqOrigin}`);
216
168
  }
217
169
  }
@@ -219,14 +171,16 @@ async function request(url, _init, config) {
219
171
  if (params.method?.toLowerCase() === "post" || params.method?.toLowerCase() === "put") {
220
172
  try {
221
173
  updatedHeaders.set("content-type", "application/json");
222
- const initBody = await new Response(_init.request.clone().body).json();
223
- const requestBody = await new Response(request2.clone().body).json();
224
- params.body = JSON.stringify(initBody ?? requestBody);
174
+ const bodyStream = _init.body ?? _init.request?.body ?? request2.body;
175
+ const bodyText = await new Response(bodyStream).text();
176
+ try {
177
+ params.body = JSON.stringify(JSON.parse(bodyText));
178
+ } catch {
179
+ updatedHeaders.set("content-type", "application/x-www-form-urlencoded");
180
+ params.body = bodyText;
181
+ }
225
182
  } catch (e) {
226
- updatedHeaders.set("content-type", "application/x-www-form-urlencoded");
227
- const initBody = await new Response(_init.request.clone().body).text();
228
- const requestBody = await new Response(request2.clone().body).text();
229
- params.body = initBody ?? requestBody;
183
+ error("Failed to parse request body");
230
184
  }
231
185
  }
232
186
  params.headers = updatedHeaders;
@@ -235,6 +189,12 @@ async function request(url, _init, config) {
235
189
  params.headers.set("request-id", crypto.randomUUID());
236
190
  params.cache = "no-store";
237
191
  }
192
+ await config.extensionCtx?.runExtensions(
193
+ "onRequest" /* onRequest */,
194
+ config,
195
+ params,
196
+ _init
197
+ );
238
198
  try {
239
199
  const res = await fetch(fullUrl, {
240
200
  ...params
@@ -254,6 +214,14 @@ async function request(url, _init, config) {
254
214
  statusText: res?.statusText,
255
215
  text: await loggingRes?.text()
256
216
  });
217
+ const updatedRes = await config.extensionCtx?.runExtensions(
218
+ "onResponse" /* onResponse */,
219
+ config,
220
+ params
221
+ );
222
+ if (updatedRes) {
223
+ return updatedRes;
224
+ }
257
225
  return res;
258
226
  } catch (e) {
259
227
  if (e instanceof Error) {
@@ -271,22 +239,19 @@ async function request(url, _init, config) {
271
239
 
272
240
  // src/api/utils/auth.ts
273
241
  async function auth(req, config) {
274
- const { info, error } = Logger(config, "[nileauth]");
242
+ const { info, error } = config.logger("[nileauth]");
275
243
  info("checking auth");
276
244
  const sessionUrl = `${config.apiUrl}/auth/session`;
277
245
  info(`using session ${sessionUrl}`);
278
246
  req.headers.delete("content-length");
279
247
  const res = await request(sessionUrl, { request: req }, config);
280
- if (!res) {
281
- info("no session found");
282
- return void 0;
283
- }
284
- info("session active");
285
248
  try {
286
249
  const session = await new Response(res.body).json();
287
250
  if (Object.keys(session).length === 0) {
251
+ info("no session found");
288
252
  return void 0;
289
253
  }
254
+ info("session active");
290
255
  return session;
291
256
  } catch (e) {
292
257
  error(e);
@@ -372,8 +337,8 @@ function getTokenFromCookie(headers, cookieKey) {
372
337
  }
373
338
  }
374
339
  function getTenantFromHttp(headers, config) {
375
- const cookieTenant = getTokenFromCookie(headers, X_NILE_TENANT);
376
- return cookieTenant ?? headers?.get(X_NILE_TENANT) ?? config?.tenantId;
340
+ const cookieTenant = getTokenFromCookie(headers, TENANT_COOKIE);
341
+ return cookieTenant ? cookieTenant : config?.tenantId;
377
342
  }
378
343
 
379
344
  // src/api/routes/users/POST.ts
@@ -383,7 +348,7 @@ async function POST(config, init) {
383
348
  const yurl = new URL(init.request.url);
384
349
  const tenantId = yurl.searchParams.get("tenantId");
385
350
  const newTenantName = yurl.searchParams.get("newTenantName");
386
- const tenant = tenantId ?? getTenantFromHttp(init.request.headers);
351
+ const tenant = tenantId ?? getTenantFromHttp(init.request.headers, config);
387
352
  const url = apiRoutes(config).USERS({ tenantId: tenant, newTenantName });
388
353
  return await request(url, init, config);
389
354
  }
@@ -392,21 +357,18 @@ async function POST(config, init) {
392
357
  async function GET2(config, init, log) {
393
358
  const yurl = new URL(init.request.url);
394
359
  const tenantId = yurl.searchParams.get("tenantId");
395
- const tenant = tenantId ?? getTenantFromHttp(init.request.headers);
360
+ const tenant = tenantId ?? getTenantFromHttp(init.request.headers, config);
396
361
  if (!tenant) {
397
362
  log("[GET] No tenant id provided.");
398
363
  return new Response(null, { status: 404 });
399
364
  }
400
- const url = apiRoutes(config).TENANT_USERS(tenant);
401
365
  init.method = "GET";
366
+ const url = apiRoutes(config).TENANT_USERS(tenant);
402
367
  return await request(url, init, config);
403
368
  }
404
369
 
405
370
  // src/api/routes/users/[userId]/PUT.ts
406
- async function PUT2(config, session, init) {
407
- if (!session) {
408
- return new Response(null, { status: 401 });
409
- }
371
+ async function PUT2(config, init) {
410
372
  init.body = init.request.body;
411
373
  init.method = "PUT";
412
374
  const [userId] = new URL(init.request.url).pathname.split("/").reverse();
@@ -417,18 +379,14 @@ async function PUT2(config, session, init) {
417
379
  // src/api/routes/users/index.ts
418
380
  var key2 = "USERS";
419
381
  async function route2(request2, config) {
420
- const { info } = Logger(
421
- { ...config, debug: config.debug },
422
- `[ROUTES][${key2}]`
423
- );
424
- const session = await auth(request2, config);
382
+ const { info } = config.logger(`[ROUTES][${key2}]`);
425
383
  switch (request2.method) {
426
384
  case "GET":
427
385
  return await GET2(config, { request: request2 }, info);
428
386
  case "POST":
429
387
  return await POST(config, { request: request2 });
430
388
  case "PUT":
431
- return await PUT2(config, session, { request: request2 });
389
+ return await PUT2(config, { request: request2 });
432
390
  default:
433
391
  return new Response("method not allowed", { status: 405 });
434
392
  }
@@ -446,7 +404,11 @@ async function GET3(config, init) {
446
404
  }
447
405
 
448
406
  // src/api/routes/tenants/[tenantId]/users/POST.ts
449
- async function POST2(config, session, init) {
407
+ async function POST2(config, init) {
408
+ const session = await auth(init.request, config);
409
+ if (!session) {
410
+ return new Response(null, { status: 401 });
411
+ }
450
412
  const yurl = new URL(init.request.url);
451
413
  const [, tenantId] = yurl.pathname.split("/").reverse();
452
414
  init.body = JSON.stringify({ email: session.email });
@@ -458,15 +420,7 @@ async function POST2(config, session, init) {
458
420
  // src/api/routes/tenants/[tenantId]/users/index.ts
459
421
  var key3 = "TENANT_USERS";
460
422
  async function route3(request2, config) {
461
- const { info } = Logger(
462
- { ...config, debug: config.debug },
463
- `[ROUTES][${key3}]`
464
- );
465
- const session = await auth(request2, config);
466
- if (!session) {
467
- info("401");
468
- return new Response(null, { status: 401 });
469
- }
423
+ const { info } = config.logger(`[ROUTES][${key3}]`);
470
424
  const yurl = new URL(request2.url);
471
425
  const [, tenantId] = yurl.pathname.split("/").reverse();
472
426
  if (!tenantId) {
@@ -477,7 +431,7 @@ async function route3(request2, config) {
477
431
  case "GET":
478
432
  return await GET3(config, { request: request2 });
479
433
  case "POST":
480
- return await POST2(config, session, { request: request2 });
434
+ return await POST2(config, { request: request2 });
481
435
  default:
482
436
  return new Response("method not allowed", { status: 405 });
483
437
  }
@@ -485,21 +439,21 @@ async function route3(request2, config) {
485
439
  function matches3(configRoutes, request2) {
486
440
  const url = new URL(request2.url);
487
441
  const [userId, possibleTenantId, tenantId] = url.pathname.split("/").reverse();
488
- let route17 = configRoutes[key3].replace("{tenantId}", tenantId).replace("{userId}", userId);
442
+ let route20 = configRoutes[key3].replace("{tenantId}", tenantId).replace("{userId}", userId);
489
443
  if (userId === "users") {
490
- route17 = configRoutes[key3].replace("{tenantId}", possibleTenantId);
444
+ route20 = configRoutes[key3].replace("{tenantId}", possibleTenantId);
491
445
  }
492
- return urlMatches(request2.url, route17);
446
+ return urlMatches(request2.url, route20);
493
447
  }
494
448
  async function fetchTenantUsers(config, method, payload) {
495
449
  const { body, params } = {};
496
450
  if (!config.tenantId) {
497
451
  throw new Error(
498
- 'Unable to fetch tenant, the tenantId context is missing. Call nile.setContext({ tenantId }), set nile.tenantId = "tenantId", or add it to the function call'
452
+ "Unable to fetch the user's tenants, the tenantId context is missing. Call nile.setContext({ tenantId })"
499
453
  );
500
454
  }
501
- if (!isUUID(config.tenantId) && config.logger?.warn) {
502
- config.logger?.warn(
455
+ if (!isUUID(config.tenantId)) {
456
+ config.logger("fetchTenantUsers").warn(
503
457
  "nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
504
458
  );
505
459
  }
@@ -523,8 +477,139 @@ async function fetchTenantUsers(config, method, payload) {
523
477
  return await config.handlers[m](req);
524
478
  }
525
479
 
480
+ // src/api/routes/tenants/[tenantId]/invite/PUT.ts
481
+ async function PUT3(config, init) {
482
+ const yurl = new URL(init.request.url);
483
+ const [, tenantId] = yurl.pathname.split("/").reverse();
484
+ if (!tenantId) {
485
+ return new Response(null, { status: 404 });
486
+ }
487
+ if (yurl.searchParams.size > 0) {
488
+ init.body = new URLSearchParams(yurl.searchParams).toString();
489
+ }
490
+ init.method = "PUT";
491
+ const url = `${apiRoutes(config).INVITE(tenantId)}`;
492
+ const res = await request(url, init, config);
493
+ const location = res?.headers?.get("location");
494
+ if (location) {
495
+ return new Response(res?.body, {
496
+ status: 302,
497
+ headers: res?.headers
498
+ });
499
+ }
500
+ return new Response(res?.body, {
501
+ status: res?.status,
502
+ headers: res?.headers
503
+ });
504
+ }
505
+
506
+ // src/api/routes/tenants/[tenantId]/invite/POST.ts
507
+ async function POST3(config, init) {
508
+ const yurl = new URL(init.request.url);
509
+ const [, tenantId] = yurl.pathname.split("/").reverse();
510
+ if (!tenantId) {
511
+ return new Response(null, { status: 404 });
512
+ }
513
+ init.method = "POST";
514
+ init.body = init.request.body;
515
+ const url = `${apiRoutes(config).INVITE(tenantId)}`;
516
+ return await request(url, init, config);
517
+ }
518
+
519
+ // src/api/routes/tenants/[tenantId]/invite/index.ts
520
+ var key4 = "INVITE";
521
+ async function route4(request2, config) {
522
+ switch (request2.method) {
523
+ // the browser is a GET, but we need to PUT it into nile-auth
524
+ // server side, this is a put
525
+ case "GET":
526
+ case "PUT":
527
+ return await PUT3(config, { request: request2 });
528
+ case "POST":
529
+ return await POST3(config, { request: request2 });
530
+ default:
531
+ return new Response("method not allowed", { status: 405 });
532
+ }
533
+ }
534
+ function matches4(configRoutes, request2) {
535
+ const url = new URL(request2.url);
536
+ const [, tenantId] = url.pathname.split("/").reverse();
537
+ const route20 = configRoutes[key4].replace("{tenantId}", tenantId);
538
+ return urlMatches(request2.url, route20);
539
+ }
540
+ async function fetchInvite(config, method, body) {
541
+ if (!config.tenantId) {
542
+ throw new Error(
543
+ "Unable to fetch the invite for the tenant, the tenantId context is missing. Call nile.setContext({ tenantId })"
544
+ );
545
+ }
546
+ if (!isUUID(config.tenantId)) {
547
+ config.logger("fetchInvite").warn(
548
+ "nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
549
+ );
550
+ }
551
+ let clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/invite" /* INVITE */.replace("{tenantId}", config.tenantId)}`;
552
+ const m = method ?? "GET";
553
+ const init = {
554
+ method: m,
555
+ headers: config.headers
556
+ };
557
+ if (method === "POST" || method === "PUT") {
558
+ init.body = body;
559
+ }
560
+ if (method === "DELETE") {
561
+ clientUrl = `${clientUrl}/${body}`;
562
+ }
563
+ const req = new Request(clientUrl, init);
564
+ return await config.handlers[m](req);
565
+ }
566
+
567
+ // src/api/routes/tenants/[tenantId]/invites/GET.ts
568
+ async function GET4(config, init) {
569
+ const yurl = new URL(init.request.url);
570
+ const [, tenantId] = yurl.pathname.split("/").reverse();
571
+ if (!tenantId) {
572
+ return new Response(null, { status: 404 });
573
+ }
574
+ init.method = "GET";
575
+ const url = `${apiRoutes(config).INVITES(tenantId)}`;
576
+ return await request(url, init, config);
577
+ }
578
+
579
+ // src/api/routes/tenants/[tenantId]/invites/index.ts
580
+ var key5 = "INVITES";
581
+ async function route5(request2, config) {
582
+ switch (request2.method) {
583
+ case "GET":
584
+ return await GET4(config, { request: request2 });
585
+ default:
586
+ return new Response("method not allowed", { status: 405 });
587
+ }
588
+ }
589
+ function matches5(configRoutes, request2) {
590
+ const url = new URL(request2.url);
591
+ const [, tenantId] = url.pathname.split("/").reverse();
592
+ const route20 = configRoutes[key5].replace("{tenantId}", tenantId);
593
+ return url.pathname.endsWith(route20);
594
+ }
595
+ async function fetchInvites(config) {
596
+ if (!config.tenantId) {
597
+ throw new Error(
598
+ "Unable to fetch invites for the tenant, the tenantId context is missing. Call nile.setContext({ tenantId })"
599
+ );
600
+ }
601
+ if (!isUUID(config.tenantId)) {
602
+ config.logger("fetchInvites").warn(
603
+ "nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
604
+ );
605
+ }
606
+ const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/invites" /* INVITES */.replace("{tenantId}", config.tenantId)}`;
607
+ const req = new Request(clientUrl, { headers: config.headers });
608
+ return await config.handlers.GET(req);
609
+ }
610
+
526
611
  // src/api/routes/tenants/GET.ts
527
- async function GET4(config, session, init) {
612
+ async function GET5(config, session, init) {
528
613
  let url = `${apiRoutes(config).USER_TENANTS(session.id)}`;
529
614
  if (typeof session === "object" && "user" in session && session.user) {
530
615
  url = `${apiRoutes(config).USER_TENANTS(session.user.id)}`;
@@ -534,7 +619,7 @@ async function GET4(config, session, init) {
534
619
  }
535
620
 
536
621
  // src/api/routes/tenants/[tenantId]/GET.ts
537
- async function GET5(config, init, log) {
622
+ async function GET6(config, init, log) {
538
623
  const yurl = new URL(init.request.url);
539
624
  const [tenantId] = yurl.pathname.split("/").reverse();
540
625
  if (!tenantId) {
@@ -559,7 +644,7 @@ async function DELETE2(config, init) {
559
644
  }
560
645
 
561
646
  // src/api/routes/tenants/[tenantId]/PUT.ts
562
- async function PUT3(config, init) {
647
+ async function PUT4(config, init) {
563
648
  const yurl = new URL(init.request.url);
564
649
  const [tenantId] = yurl.pathname.split("/").reverse();
565
650
  if (!tenantId) {
@@ -572,7 +657,7 @@ async function PUT3(config, init) {
572
657
  }
573
658
 
574
659
  // src/api/routes/tenants/POST.ts
575
- async function POST3(config, init) {
660
+ async function POST4(config, init) {
576
661
  init.body = init.request.body;
577
662
  init.method = "POST";
578
663
  const url = `${apiRoutes(config).TENANTS}`;
@@ -580,12 +665,9 @@ async function POST3(config, init) {
580
665
  }
581
666
 
582
667
  // src/api/routes/tenants/index.ts
583
- var key4 = "TENANTS";
584
- async function route4(request2, config) {
585
- const { info } = Logger(
586
- { ...config, debug: config.debug },
587
- `[ROUTES][${key4}]`
588
- );
668
+ var key6 = "TENANTS";
669
+ async function route6(request2, config) {
670
+ const { info } = config.logger(`[ROUTES][${key6}]`);
589
671
  const session = await auth(request2, config);
590
672
  if (!session) {
591
673
  info("401");
@@ -595,21 +677,21 @@ async function route4(request2, config) {
595
677
  switch (request2.method) {
596
678
  case "GET":
597
679
  if (isUUID(possibleTenantId)) {
598
- return await GET5(config, { request: request2 }, info);
680
+ return await GET6(config, { request: request2 }, info);
599
681
  }
600
- return await GET4(config, session, { request: request2 });
682
+ return await GET5(config, session, { request: request2 });
601
683
  case "POST":
602
- return await POST3(config, { request: request2 });
684
+ return await POST4(config, { request: request2 });
603
685
  case "DELETE":
604
686
  return await DELETE2(config, { request: request2 });
605
687
  case "PUT":
606
- return await PUT3(config, { request: request2 });
688
+ return await PUT4(config, { request: request2 });
607
689
  default:
608
690
  return new Response("method not allowed", { status: 405 });
609
691
  }
610
692
  }
611
- function matches4(configRoutes, request2) {
612
- return urlMatches(request2.url, configRoutes[key4]);
693
+ function matches6(configRoutes, request2) {
694
+ return urlMatches(request2.url, configRoutes[key6]);
613
695
  }
614
696
  async function fetchTenants(config, method, body) {
615
697
  const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants" /* TENANTS */}`;
@@ -626,11 +708,11 @@ async function fetchTenants(config, method, body) {
626
708
  async function fetchTenant(config, method, body) {
627
709
  if (!config.tenantId) {
628
710
  throw new Error(
629
- 'Unable to fetch tenant, the tenantId context is missing. Call nile.setContext({ tenantId }), set nile.tenantId = "tenantId", or add it to the function call'
711
+ "Unable to fetch tenants, the tenantId context is missing. Call nile.setContext({ tenantId })"
630
712
  );
631
713
  }
632
- if (!isUUID(config.tenantId) && config.logger?.warn) {
633
- config.logger?.warn(
714
+ if (!isUUID(config.tenantId)) {
715
+ config.logger("fetch tenant").warn(
634
716
  "nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
635
717
  );
636
718
  }
@@ -647,36 +729,32 @@ async function fetchTenant(config, method, body) {
647
729
  return await config.handlers[m](req);
648
730
  }
649
731
  async function fetchTenantsByUser(config) {
650
- if (config.logger?.warn) {
651
- if (!config.userId) {
652
- config.logger?.warn(
653
- "nile.userId is not set. The call will still work for the API, but the database context is not set properly and may lead to unexpected behavior in your application."
654
- );
655
- } else if (!isUUID(config.userId)) {
656
- config.logger?.warn(
657
- "nile.userId is not a valid UUID. This may lead to unexpected behavior in your application."
658
- );
659
- }
732
+ const { warn } = config.logger("fetchTenantsByUser");
733
+ if (!config.userId) {
734
+ warn(
735
+ "nile.userId is not set. The call will still work for the API, but the database context is not set properly and may lead to unexpected behavior in your application."
736
+ );
737
+ } else if (!isUUID(config.userId)) {
738
+ warn(
739
+ "nile.userId is not a valid UUID. This may lead to unexpected behavior in your application."
740
+ );
660
741
  }
661
- const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/users/{userId}/tenants" /* USER_TENANTS */.replace(
662
- "{userId}",
663
- config.userId ?? "WARN_NOT_SET"
664
- )}`;
742
+ const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants" /* TENANTS */}`;
665
743
  const req = new Request(clientUrl, { headers: config.headers });
666
744
  return await config.handlers.GET(req);
667
745
  }
668
746
 
669
747
  // src/api/routes/auth/signin.ts
670
- var key5 = "SIGNIN";
671
- async function route5(req, config) {
672
- let url = proxyRoutes(config)[key5];
748
+ var key7 = "SIGNIN";
749
+ async function route7(req, config) {
750
+ let url = proxyRoutes(config)[key7];
673
751
  const init = {
674
752
  method: req.method,
675
753
  headers: req.headers
676
754
  };
677
755
  if (req.method === "POST") {
678
756
  const [provider] = new URL(req.url).pathname.split("/").reverse();
679
- url = `${proxyRoutes(config)[key5]}/${provider}`;
757
+ url = `${proxyRoutes(config)[key7]}/${provider}`;
680
758
  }
681
759
  const passThroughUrl = new URL(req.url);
682
760
  const params = new URLSearchParams(passThroughUrl.search);
@@ -684,8 +762,8 @@ async function route5(req, config) {
684
762
  const res = await request(url, { ...init, request: req }, config);
685
763
  return res;
686
764
  }
687
- function matches5(configRoutes, request2) {
688
- return urlMatches(request2.url, configRoutes[key5]);
765
+ function matches7(configRoutes, request2) {
766
+ return urlMatches(request2.url, configRoutes[key7]);
689
767
  }
690
768
  async function fetchSignIn(config, provider, body) {
691
769
  const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/signin" /* SIGNIN */}/${provider}`;
@@ -698,7 +776,7 @@ async function fetchSignIn(config, provider, body) {
698
776
  }
699
777
 
700
778
  // src/api/routes/auth/session.ts
701
- async function route6(req, config) {
779
+ async function route8(req, config) {
702
780
  return request(
703
781
  proxyRoutes(config).SESSION,
704
782
  {
@@ -708,7 +786,7 @@ async function route6(req, config) {
708
786
  config
709
787
  );
710
788
  }
711
- function matches6(configRoutes, request2) {
789
+ function matches8(configRoutes, request2) {
712
790
  return urlMatches(request2.url, configRoutes.SESSION);
713
791
  }
714
792
  async function fetchSession(config) {
@@ -721,7 +799,7 @@ async function fetchSession(config) {
721
799
  }
722
800
 
723
801
  // src/api/routes/auth/providers.ts
724
- async function route7(req, config) {
802
+ async function route9(req, config) {
725
803
  return request(
726
804
  proxyRoutes(config).PROVIDERS,
727
805
  {
@@ -731,7 +809,7 @@ async function route7(req, config) {
731
809
  config
732
810
  );
733
811
  }
734
- function matches7(configRoutes, request2) {
812
+ function matches9(configRoutes, request2) {
735
813
  return urlMatches(request2.url, configRoutes.PROVIDERS);
736
814
  }
737
815
  async function fetchProviders(config) {
@@ -744,7 +822,7 @@ async function fetchProviders(config) {
744
822
  }
745
823
 
746
824
  // src/api/routes/auth/csrf.ts
747
- async function route8(req, config) {
825
+ async function route10(req, config) {
748
826
  return request(
749
827
  proxyRoutes(config).CSRF,
750
828
  {
@@ -754,7 +832,7 @@ async function route8(req, config) {
754
832
  config
755
833
  );
756
834
  }
757
- function matches8(configRoutes, request2) {
835
+ function matches10(configRoutes, request2) {
758
836
  return urlMatches(request2.url, configRoutes.CSRF);
759
837
  }
760
838
  async function fetchCsrf(config) {
@@ -767,17 +845,14 @@ async function fetchCsrf(config) {
767
845
  }
768
846
 
769
847
  // src/api/routes/auth/callback.ts
770
- var key6 = "CALLBACK";
771
- async function route9(req, config) {
772
- const { error } = Logger(
773
- { ...config, debug: config.debug },
774
- `[ROUTES][${key6}]`
775
- );
848
+ var key8 = "CALLBACK";
849
+ async function route11(req, config) {
850
+ const { error } = config.logger(`[ROUTES][${key8}]`);
776
851
  const [provider] = new URL(req.url).pathname.split("/").reverse();
777
852
  try {
778
853
  const passThroughUrl = new URL(req.url);
779
854
  const params = new URLSearchParams(passThroughUrl.search);
780
- const url = `${proxyRoutes(config)[key6]}/${provider}${params.toString() !== "" ? `?${params.toString()}` : ""}`;
855
+ const url = `${proxyRoutes(config)[key8]}/${provider}${params.toString() !== "" ? `?${params.toString()}` : ""}`;
781
856
  const res = await request(
782
857
  url,
783
858
  {
@@ -788,7 +863,7 @@ async function route9(req, config) {
788
863
  ).catch((e) => {
789
864
  error("an error as occurred", e);
790
865
  });
791
- const location = res?.headers.get("location");
866
+ const location = res?.headers?.get("location");
792
867
  if (location) {
793
868
  return new Response(res?.body, {
794
869
  status: 302,
@@ -804,7 +879,7 @@ async function route9(req, config) {
804
879
  }
805
880
  return new Response("An unexpected error has occurred.", { status: 400 });
806
881
  }
807
- function matches9(configRoutes, request2) {
882
+ function matches11(configRoutes, request2) {
808
883
  return urlMatches(request2.url, configRoutes.CALLBACK);
809
884
  }
810
885
  async function fetchCallback(config, provider, body, request2, method = "POST") {
@@ -818,22 +893,22 @@ async function fetchCallback(config, provider, body, request2, method = "POST")
818
893
  }
819
894
 
820
895
  // src/api/routes/auth/signout.ts
821
- var key7 = "SIGNOUT";
822
- async function route10(request2, config) {
823
- let url = proxyRoutes(config)[key7];
896
+ var key9 = "SIGNOUT";
897
+ async function route12(request2, config) {
898
+ let url = proxyRoutes(config)[key9];
824
899
  const init = {
825
900
  method: request2.method
826
901
  };
827
902
  if (request2.method === "POST") {
828
903
  init.body = request2.body;
829
904
  const [provider] = new URL(request2.url).pathname.split("/").reverse();
830
- url = `${proxyRoutes(config)[key7]}${provider !== "signout" ? `/${provider}` : ""}`;
905
+ url = `${proxyRoutes(config)[key9]}${provider !== "signout" ? `/${provider}` : ""}`;
831
906
  }
832
907
  const res = await request(url, { ...init, request: request2 }, config);
833
908
  return res;
834
909
  }
835
- function matches10(configRoutes, request2) {
836
- return urlMatches(request2.url, configRoutes[key7]);
910
+ function matches12(configRoutes, request2) {
911
+ return urlMatches(request2.url, configRoutes[key9]);
837
912
  }
838
913
  async function fetchSignOut(config, body) {
839
914
  const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/signout" /* SIGNOUT */}`;
@@ -846,10 +921,10 @@ async function fetchSignOut(config, body) {
846
921
  }
847
922
 
848
923
  // src/api/routes/auth/error.ts
849
- var key8 = "ERROR";
850
- async function route11(req, config) {
924
+ var key10 = "ERROR";
925
+ async function route13(req, config) {
851
926
  return request(
852
- proxyRoutes(config)[key8],
927
+ proxyRoutes(config)[key10],
853
928
  {
854
929
  method: req.method,
855
930
  request: req
@@ -857,15 +932,15 @@ async function route11(req, config) {
857
932
  config
858
933
  );
859
934
  }
860
- function matches11(configRoutes, request2) {
861
- return urlMatches(request2.url, configRoutes[key8]);
935
+ function matches13(configRoutes, request2) {
936
+ return urlMatches(request2.url, configRoutes[key10]);
862
937
  }
863
938
 
864
939
  // src/api/routes/auth/verify-request.ts
865
- var key9 = "VERIFY_REQUEST";
866
- async function route12(req, config) {
940
+ var key11 = "VERIFY_REQUEST";
941
+ async function route14(req, config) {
867
942
  return request(
868
- proxyRoutes(config)[key9],
943
+ proxyRoutes(config)[key11],
869
944
  {
870
945
  method: req.method,
871
946
  request: req
@@ -873,14 +948,14 @@ async function route12(req, config) {
873
948
  config
874
949
  );
875
950
  }
876
- function matches12(configRoutes, request2) {
877
- return urlMatches(request2.url, configRoutes[key9]);
951
+ function matches14(configRoutes, request2) {
952
+ return urlMatches(request2.url, configRoutes[key11]);
878
953
  }
879
954
 
880
955
  // src/api/routes/auth/password-reset.ts
881
- var key10 = "PASSWORD_RESET";
882
- async function route13(req, config) {
883
- const url = proxyRoutes(config)[key10];
956
+ var key12 = "PASSWORD_RESET";
957
+ async function route15(req, config) {
958
+ const url = proxyRoutes(config)[key12];
884
959
  const res = await request(
885
960
  url,
886
961
  {
@@ -889,7 +964,7 @@ async function route13(req, config) {
889
964
  },
890
965
  config
891
966
  );
892
- const location = res?.headers.get("location");
967
+ const location = res?.headers?.get("location");
893
968
  if (location) {
894
969
  return new Response(res?.body, {
895
970
  status: 302,
@@ -901,12 +976,14 @@ async function route13(req, config) {
901
976
  headers: res?.headers
902
977
  });
903
978
  }
904
- function matches13(configRoutes, request2) {
979
+ function matches15(configRoutes, request2) {
905
980
  return urlMatches(request2.url, configRoutes.PASSWORD_RESET);
906
981
  }
907
- async function fetchResetPassword(config, method, body, params) {
982
+ async function fetchResetPassword(config, method, body, params, useJson = true) {
908
983
  const authParams = new URLSearchParams(params ?? {});
909
- authParams?.set("json", "true");
984
+ if (useJson) {
985
+ authParams?.set("json", "true");
986
+ }
910
987
  const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/reset-password" /* PASSWORD_RESET */}?${authParams?.toString()}`;
911
988
  const init = {
912
989
  method,
@@ -920,9 +997,9 @@ async function fetchResetPassword(config, method, body, params) {
920
997
  }
921
998
 
922
999
  // src/api/routes/auth/verify-email.ts
923
- var key11 = "VERIFY_EMAIL";
924
- async function route14(req, config) {
925
- const url = proxyRoutes(config)[key11];
1000
+ var key13 = "VERIFY_EMAIL";
1001
+ async function route16(req, config) {
1002
+ const url = proxyRoutes(config)[key13];
926
1003
  const res = await request(
927
1004
  url,
928
1005
  {
@@ -931,7 +1008,7 @@ async function route14(req, config) {
931
1008
  },
932
1009
  config
933
1010
  );
934
- const location = res?.headers.get("location");
1011
+ const location = res?.headers?.get("location");
935
1012
  if (location) {
936
1013
  return new Response(res?.body, {
937
1014
  status: 302,
@@ -943,8 +1020,8 @@ async function route14(req, config) {
943
1020
  headers: res?.headers
944
1021
  });
945
1022
  }
946
- function matches14(configRoutes, request2) {
947
- return urlMatches(request2.url, configRoutes[key11]);
1023
+ function matches16(configRoutes, request2) {
1024
+ return urlMatches(request2.url, configRoutes[key13]);
948
1025
  }
949
1026
  async function fetchVerifyEmail(config, method, body) {
950
1027
  const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/verify-email" /* VERIFY_EMAIL */}`;
@@ -961,71 +1038,154 @@ async function fetchVerifyEmail(config, method, body) {
961
1038
 
962
1039
  // src/api/handlers/GET.ts
963
1040
  function GETTER(configRoutes, config) {
964
- const { info, warn } = Logger(config, "[GET MATCHER]");
965
- return async function GET6(req) {
1041
+ const { error, info, warn } = config.logger("[GET MATCHER]");
1042
+ return async function GET7(...params) {
1043
+ const handledRequest = await config.extensionCtx?.runExtensions(
1044
+ "onHandleRequest" /* onHandleRequest */,
1045
+ config,
1046
+ params
1047
+ );
1048
+ if (handledRequest) {
1049
+ return handledRequest;
1050
+ }
1051
+ const req = params[0] instanceof Request ? params[0] : null;
1052
+ if (!req) {
1053
+ error("Proxy requests failed, a Request object was not passed.");
1054
+ return;
1055
+ }
966
1056
  if (matches(configRoutes, req)) {
967
1057
  info("matches me");
968
1058
  return route(req, config);
969
1059
  }
1060
+ if (matches5(configRoutes, req)) {
1061
+ info("matches tenant invites");
1062
+ return route5(req, config);
1063
+ }
1064
+ if (matches4(configRoutes, req)) {
1065
+ info("matches invite");
1066
+ return route4(req, config);
1067
+ }
970
1068
  if (matches3(configRoutes, req)) {
971
1069
  info("matches tenant users");
972
1070
  return route3(req, config);
973
1071
  }
1072
+ if (matches6(configRoutes, req)) {
1073
+ info("matches tenants");
1074
+ return route6(req, config);
1075
+ }
974
1076
  if (matches2(configRoutes, req)) {
975
1077
  info("matches users");
976
1078
  return route2(req, config);
977
1079
  }
978
- if (matches4(configRoutes, req)) {
979
- info("matches tenants");
980
- return route4(req, config);
981
- }
982
- if (matches6(configRoutes, req)) {
1080
+ if (matches8(configRoutes, req)) {
983
1081
  info("matches session");
984
- return route6(req, config);
1082
+ return route8(req, config);
985
1083
  }
986
- if (matches5(configRoutes, req)) {
1084
+ if (matches7(configRoutes, req)) {
987
1085
  info("matches signin");
988
- return route5(req, config);
1086
+ return route7(req, config);
989
1087
  }
990
- if (matches7(configRoutes, req)) {
1088
+ if (matches9(configRoutes, req)) {
991
1089
  info("matches providers");
992
- return route7(req, config);
1090
+ return route9(req, config);
993
1091
  }
994
- if (matches8(configRoutes, req)) {
1092
+ if (matches10(configRoutes, req)) {
995
1093
  info("matches csrf");
996
- return route8(req, config);
1094
+ return route10(req, config);
997
1095
  }
998
- if (matches13(configRoutes, req)) {
1096
+ if (matches15(configRoutes, req)) {
999
1097
  info("matches password reset");
1000
- return route13(req, config);
1098
+ return route15(req, config);
1001
1099
  }
1002
- if (matches9(configRoutes, req)) {
1100
+ if (matches11(configRoutes, req)) {
1003
1101
  info("matches callback");
1004
- return route9(req, config);
1005
- }
1006
- if (matches10(configRoutes, req)) {
1007
- info("matches signout");
1008
- return route10(req, config);
1102
+ return route11(req, config);
1009
1103
  }
1010
1104
  if (matches12(configRoutes, req)) {
1011
- info("matches verify-request");
1105
+ info("matches signout");
1012
1106
  return route12(req, config);
1013
1107
  }
1014
1108
  if (matches14(configRoutes, req)) {
1015
- info("matches verify-email");
1109
+ info("matches verify-request");
1016
1110
  return route14(req, config);
1017
1111
  }
1018
- if (matches11(configRoutes, req)) {
1112
+ if (matches16(configRoutes, req)) {
1113
+ info("matches verify-email");
1114
+ return route16(req, config);
1115
+ }
1116
+ if (matches13(configRoutes, req)) {
1019
1117
  info("matches error");
1020
- return route11(req, config);
1118
+ return route13(req, config);
1021
1119
  }
1022
1120
  warn(`No GET routes matched ${req.url}`);
1023
1121
  return new Response(null, { status: 404 });
1024
1122
  };
1025
1123
  }
1026
1124
 
1125
+ // src/utils/Logger.ts
1126
+ var red = "\x1B[31m";
1127
+ var yellow = "\x1B[38;2;255;255;0m";
1128
+ var purple = "\x1B[38;2;200;160;255m";
1129
+ var orange = "\x1B[38;2;255;165;0m";
1130
+ var reset = "\x1B[0m";
1131
+ var baseLogger = (config, ...params) => ({
1132
+ info(message, meta) {
1133
+ if (config?.debug) {
1134
+ console.info(
1135
+ `${orange}[niledb]${reset}${purple}[DEBUG]${reset}${params.join(
1136
+ ""
1137
+ )}${reset} ${message}`,
1138
+ meta ? `${JSON.stringify(meta)}` : ""
1139
+ );
1140
+ }
1141
+ },
1142
+ debug(message, meta) {
1143
+ if (config?.debug) {
1144
+ console.debug(
1145
+ `${orange}[niledb]${reset}${purple}[DEBUG]${reset}${params.join(
1146
+ ""
1147
+ )}${reset} ${message}`,
1148
+ meta ? `${JSON.stringify(meta)}` : ""
1149
+ );
1150
+ }
1151
+ },
1152
+ warn(message, meta) {
1153
+ if (config?.debug) {
1154
+ console.warn(
1155
+ `${orange}[niledb]${reset}${yellow}[WARN]${reset}${params.join(
1156
+ ""
1157
+ )}${reset} ${message}`,
1158
+ meta ? JSON.stringify(meta) : ""
1159
+ );
1160
+ }
1161
+ },
1162
+ error(message, meta) {
1163
+ console.error(
1164
+ `${orange}[niledb]${reset}${red}[ERROR]${reset}${params.join(
1165
+ ""
1166
+ )}${red} ${message}`,
1167
+ meta ? meta : "",
1168
+ `${reset}`
1169
+ );
1170
+ }
1171
+ });
1172
+ function Logger(config) {
1173
+ return (prefixes) => {
1174
+ const { info, debug, warn, error } = config && typeof config?.logger === "function" ? config.logger(prefixes) : baseLogger(config, prefixes);
1175
+ return {
1176
+ info,
1177
+ debug,
1178
+ warn,
1179
+ error
1180
+ };
1181
+ };
1182
+ }
1183
+ function matchesLog(configRoutes, request2) {
1184
+ return urlMatches(request2.url, configRoutes.LOG);
1185
+ }
1186
+
1027
1187
  // src/api/routes/signup/POST.ts
1028
- async function POST4(config, init) {
1188
+ async function POST5(config, init) {
1029
1189
  init.body = init.request.body;
1030
1190
  init.method = "POST";
1031
1191
  const url = `${apiRoutes(config).SIGNUP}`;
@@ -1033,17 +1193,17 @@ async function POST4(config, init) {
1033
1193
  }
1034
1194
 
1035
1195
  // src/api/routes/signup/index.tsx
1036
- var key12 = "SIGNUP";
1037
- async function route15(request2, config) {
1196
+ var key14 = "SIGNUP";
1197
+ async function route17(request2, config) {
1038
1198
  switch (request2.method) {
1039
1199
  case "POST":
1040
- return await POST4(config, { request: request2 });
1200
+ return await POST5(config, { request: request2 });
1041
1201
  default:
1042
1202
  return new Response("method not allowed", { status: 405 });
1043
1203
  }
1044
1204
  }
1045
- function matches15(configRoutes, request2) {
1046
- return urlMatches(request2.url, configRoutes[key12]);
1205
+ function matches17(configRoutes, request2) {
1206
+ return urlMatches(request2.url, configRoutes[key14]);
1047
1207
  }
1048
1208
  async function fetchSignUp(config, payload) {
1049
1209
  const { body, params } = payload ?? {};
@@ -1065,8 +1225,21 @@ async function fetchSignUp(config, payload) {
1065
1225
 
1066
1226
  // src/api/handlers/POST.ts
1067
1227
  function POSTER(configRoutes, config) {
1068
- const { info, warn, error } = Logger(config, "[POST MATCHER]");
1069
- return async function POST5(req) {
1228
+ const { info, warn, error } = config.logger("[POST MATCHER]");
1229
+ return async function POST6(...params) {
1230
+ const handledRequest = await config.extensionCtx?.runExtensions(
1231
+ "onHandleRequest" /* onHandleRequest */,
1232
+ config,
1233
+ params
1234
+ );
1235
+ if (handledRequest) {
1236
+ return handledRequest;
1237
+ }
1238
+ const req = params[0] instanceof Request ? params[0] : null;
1239
+ if (!req) {
1240
+ error("Proxy requests failed, a Request object was not passed.");
1241
+ return;
1242
+ }
1070
1243
  if (matchesLog(configRoutes, req)) {
1071
1244
  try {
1072
1245
  const json = await req.clone().json();
@@ -1080,49 +1253,53 @@ function POSTER(configRoutes, config) {
1080
1253
  info("matches tenant users");
1081
1254
  return route3(req, config);
1082
1255
  }
1083
- if (matches15(configRoutes, req)) {
1256
+ if (matches4(configRoutes, req)) {
1257
+ info("matches tenant invite");
1258
+ return route4(req, config);
1259
+ }
1260
+ if (matches17(configRoutes, req)) {
1084
1261
  info("matches signup");
1085
- return route15(req, config);
1262
+ return route17(req, config);
1086
1263
  }
1087
1264
  if (matches2(configRoutes, req)) {
1088
1265
  info("matches users");
1089
1266
  return route2(req, config);
1090
1267
  }
1091
- if (matches4(configRoutes, req)) {
1092
- info("matches tenants");
1093
- return route4(req, config);
1094
- }
1095
1268
  if (matches6(configRoutes, req)) {
1096
- info("matches session");
1269
+ info("matches tenants");
1097
1270
  return route6(req, config);
1098
1271
  }
1099
- if (matches5(configRoutes, req)) {
1100
- info("matches signin");
1101
- return route5(req, config);
1102
- }
1103
- if (matches13(configRoutes, req)) {
1104
- info("matches password reset");
1105
- return route13(req, config);
1272
+ if (matches8(configRoutes, req)) {
1273
+ info("matches session");
1274
+ return route8(req, config);
1106
1275
  }
1107
1276
  if (matches7(configRoutes, req)) {
1108
- info("matches providers");
1277
+ info("matches signin");
1109
1278
  return route7(req, config);
1110
1279
  }
1111
- if (matches8(configRoutes, req)) {
1112
- info("matches csrf");
1113
- return route8(req, config);
1280
+ if (matches15(configRoutes, req)) {
1281
+ info("matches password reset");
1282
+ return route15(req, config);
1114
1283
  }
1115
1284
  if (matches9(configRoutes, req)) {
1116
- info("matches callback");
1285
+ info("matches providers");
1117
1286
  return route9(req, config);
1118
1287
  }
1119
1288
  if (matches10(configRoutes, req)) {
1120
- info("matches signout");
1289
+ info("matches csrf");
1121
1290
  return route10(req, config);
1122
1291
  }
1123
- if (matches14(configRoutes, req)) {
1292
+ if (matches11(configRoutes, req)) {
1293
+ info("matches callback");
1294
+ return route11(req, config);
1295
+ }
1296
+ if (matches12(configRoutes, req)) {
1297
+ info("matches signout");
1298
+ return route12(req, config);
1299
+ }
1300
+ if (matches16(configRoutes, req)) {
1124
1301
  info("matches verify-email");
1125
- return route14(req, config);
1302
+ return route16(req, config);
1126
1303
  }
1127
1304
  warn(`No POST routes matched ${req.url}`);
1128
1305
  return new Response(null, { status: 404 });
@@ -1141,7 +1318,7 @@ async function DELETE3(config, init) {
1141
1318
  }
1142
1319
 
1143
1320
  // src/api/routes/tenants/[tenantId]/users/[userId]/PUT.ts
1144
- async function PUT4(config, init) {
1321
+ async function PUT5(config, init) {
1145
1322
  const yurl = new URL(init.request.url);
1146
1323
  const [, userId, , tenantId] = yurl.pathname.split("/").reverse();
1147
1324
  config.tenantId = tenantId;
@@ -1152,12 +1329,9 @@ async function PUT4(config, init) {
1152
1329
  }
1153
1330
 
1154
1331
  // src/api/routes/tenants/[tenantId]/users/[userId]/index.ts
1155
- var key13 = "TENANT_USER";
1156
- async function route16(request2, config) {
1157
- const { info } = Logger(
1158
- { ...config, debug: config.debug },
1159
- `[ROUTES][${key13}]`
1160
- );
1332
+ var key15 = "TENANT_USER";
1333
+ async function route18(request2, config) {
1334
+ const { info } = config.logger(`[ROUTES][${key15}]`);
1161
1335
  const session = await auth(request2, config);
1162
1336
  if (!session) {
1163
1337
  info("401");
@@ -1171,21 +1345,21 @@ async function route16(request2, config) {
1171
1345
  }
1172
1346
  switch (request2.method) {
1173
1347
  case "PUT":
1174
- return await PUT4(config, { request: request2 });
1348
+ return await PUT5(config, { request: request2 });
1175
1349
  case "DELETE":
1176
1350
  return await DELETE3(config, { request: request2 });
1177
1351
  default:
1178
1352
  return new Response("method not allowed", { status: 405 });
1179
1353
  }
1180
1354
  }
1181
- function matches16(configRoutes, request2) {
1355
+ function matches18(configRoutes, request2) {
1182
1356
  const url = new URL(request2.url);
1183
1357
  const [, userId, possibleTenantId, tenantId] = url.pathname.split("/").reverse();
1184
- let route17 = configRoutes[key13].replace("{tenantId}", tenantId).replace("{userId}", userId);
1358
+ let route20 = configRoutes[key15].replace("{tenantId}", tenantId).replace("{userId}", userId);
1185
1359
  if (userId === "users") {
1186
- route17 = configRoutes[key13].replace("{tenantId}", possibleTenantId);
1360
+ route20 = configRoutes[key15].replace("{tenantId}", possibleTenantId);
1187
1361
  }
1188
- return urlMatches(request2.url, route17);
1362
+ return urlMatches(request2.url, route20);
1189
1363
  }
1190
1364
  async function fetchTenantUser(config, method) {
1191
1365
  if (!config.tenantId) {
@@ -1209,21 +1383,63 @@ async function fetchTenantUser(config, method) {
1209
1383
  return await config.handlers[method](req);
1210
1384
  }
1211
1385
 
1386
+ // src/api/routes/tenants/[tenantId]/invite/[inviteId]/DELETE.ts
1387
+ async function DELETE4(config, init) {
1388
+ const yurl = new URL(init.request.url);
1389
+ const [inviteId, , tenantId] = yurl.pathname.split("/").reverse();
1390
+ if (!tenantId) {
1391
+ return new Response(null, { status: 404 });
1392
+ }
1393
+ init.method = "DELETE";
1394
+ const url = `${apiRoutes(config).INVITE(tenantId)}/${inviteId}`;
1395
+ return await request(url, init, config);
1396
+ }
1397
+
1398
+ // src/api/routes/tenants/[tenantId]/invite/[inviteId]/index.ts
1399
+ var key16 = "INVITE";
1400
+ async function route19(request2, config) {
1401
+ switch (request2.method) {
1402
+ case "DELETE":
1403
+ return await DELETE4(config, { request: request2 });
1404
+ default:
1405
+ return new Response("method not allowed", { status: 405 });
1406
+ }
1407
+ }
1408
+ function matches19(configRoutes, request2) {
1409
+ const url = new URL(request2.url);
1410
+ const [inviteId, , tenantId] = url.pathname.split("/").reverse();
1411
+ const route20 = configRoutes[key16].replace("{tenantId}", tenantId).replace("{inviteId}", inviteId);
1412
+ return urlMatches(request2.url, route20);
1413
+ }
1414
+
1212
1415
  // src/api/handlers/DELETE.ts
1213
1416
  function DELETER(configRoutes, config) {
1214
- const { info, warn } = Logger(config, "[DELETE MATCHER]");
1215
- return async function DELETE4(req) {
1216
- if (matches16(configRoutes, req)) {
1217
- info("matches tenant user");
1218
- return route16(req, config);
1417
+ const { error, info, warn } = config.logger("[DELETE MATCHER]");
1418
+ return async function DELETE5(...params) {
1419
+ const handledRequest = await config.extensionCtx?.runExtensions(
1420
+ "onHandleRequest" /* onHandleRequest */,
1421
+ config,
1422
+ params
1423
+ );
1424
+ if (handledRequest) {
1425
+ return handledRequest;
1219
1426
  }
1220
- if (matches3(configRoutes, req)) {
1221
- info("matches tenant users");
1222
- return route3(req, config);
1427
+ const req = params[0] instanceof Request ? params[0] : null;
1428
+ if (!req) {
1429
+ error("Proxy requests failed, a Request object was not passed.");
1430
+ return;
1223
1431
  }
1224
- if (matches4(configRoutes, req)) {
1432
+ if (matches19(configRoutes, req)) {
1433
+ info("matches tenant invite id");
1434
+ return route19(req, config);
1435
+ }
1436
+ if (matches18(configRoutes, req)) {
1437
+ info("matches tenant user");
1438
+ return route18(req, config);
1439
+ }
1440
+ if (matches6(configRoutes, req)) {
1225
1441
  info("matches tenants");
1226
- return route4(req, config);
1442
+ return route6(req, config);
1227
1443
  }
1228
1444
  if (matches(configRoutes, req)) {
1229
1445
  info("matches me");
@@ -1236,11 +1452,28 @@ function DELETER(configRoutes, config) {
1236
1452
 
1237
1453
  // src/api/handlers/PUT.ts
1238
1454
  function PUTER(configRoutes, config) {
1239
- const { info, warn } = Logger(config, "[PUT MATCHER]");
1240
- return async function PUT5(req) {
1241
- if (matches16(configRoutes, req)) {
1455
+ const { error, info, warn } = config.logger("[PUT MATCHER]");
1456
+ return async function PUT6(...params) {
1457
+ const handledRequest = await config.extensionCtx?.runExtensions(
1458
+ "onHandleRequest" /* onHandleRequest */,
1459
+ config,
1460
+ params
1461
+ );
1462
+ if (handledRequest) {
1463
+ return handledRequest;
1464
+ }
1465
+ const req = params[0] instanceof Request ? params[0] : null;
1466
+ if (!req) {
1467
+ error("Proxy requests failed, a Request object was not passed.");
1468
+ return;
1469
+ }
1470
+ if (matches4(configRoutes, req)) {
1471
+ info("matches tenant invite");
1472
+ return route4(req, config);
1473
+ }
1474
+ if (matches18(configRoutes, req)) {
1242
1475
  info("matches tenant user");
1243
- return route16(req, config);
1476
+ return route18(req, config);
1244
1477
  }
1245
1478
  if (matches3(configRoutes, req)) {
1246
1479
  info("matches tenant users");
@@ -1254,13 +1487,13 @@ function PUTER(configRoutes, config) {
1254
1487
  info("matches me");
1255
1488
  return route(req, config);
1256
1489
  }
1257
- if (matches4(configRoutes, req)) {
1490
+ if (matches6(configRoutes, req)) {
1258
1491
  info("matches tenants");
1259
- return route4(req, config);
1492
+ return route6(req, config);
1260
1493
  }
1261
- if (matches13(configRoutes, req)) {
1494
+ if (matches15(configRoutes, req)) {
1262
1495
  info("matches reset password");
1263
- return route13(req, config);
1496
+ return route15(req, config);
1264
1497
  }
1265
1498
  warn("No PUT routes matched");
1266
1499
  return new Response(null, { status: 404 });
@@ -1269,15 +1502,15 @@ function PUTER(configRoutes, config) {
1269
1502
 
1270
1503
  // src/api/handlers/index.ts
1271
1504
  function Handlers(configRoutes, config) {
1272
- const GET6 = GETTER(configRoutes, config);
1273
- const POST5 = POSTER(configRoutes, config);
1274
- const DELETE4 = DELETER(configRoutes, config);
1275
- const PUT5 = PUTER(configRoutes, config);
1505
+ const GET7 = GETTER(configRoutes, config);
1506
+ const POST6 = POSTER(configRoutes, config);
1507
+ const DELETE5 = DELETER(configRoutes, config);
1508
+ const PUT6 = PUTER(configRoutes, config);
1276
1509
  return {
1277
- GET: GET6,
1278
- POST: POST5,
1279
- DELETE: DELETE4,
1280
- PUT: PUT5
1510
+ GET: GET7,
1511
+ POST: POST6,
1512
+ DELETE: DELETE5,
1513
+ PUT: PUT6
1281
1514
  };
1282
1515
  }
1283
1516
  var getApiUrl = (cfg) => {
@@ -1310,15 +1543,16 @@ var getSecureCookies = (cfg) => {
1310
1543
  return void 0;
1311
1544
  };
1312
1545
  var getUsername = (cfg) => {
1313
- const { config, logger } = cfg;
1314
- const { info } = Logger(config, "[username]");
1546
+ const { config } = cfg;
1547
+ const logger = config.logger;
1548
+ const { info } = logger();
1315
1549
  if (config?.user) {
1316
- logger && info(`${logger}[config] ${config.user}`);
1550
+ info(`[config] ${config.user}`);
1317
1551
  return String(config?.user);
1318
1552
  }
1319
1553
  const user = stringCheck(process.env.NILEDB_USER);
1320
1554
  if (user) {
1321
- logger && info(`${logger}[NILEDB_USER] ${user}`);
1555
+ info(`[NILEDB_USER] ${user}`);
1322
1556
  return user;
1323
1557
  }
1324
1558
  const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
@@ -1336,16 +1570,16 @@ var getUsername = (cfg) => {
1336
1570
  );
1337
1571
  };
1338
1572
  var getPassword = (cfg) => {
1339
- const { config, logger } = cfg;
1573
+ const { config } = cfg;
1574
+ const logger = config.logger;
1340
1575
  const log = logProtector(logger);
1341
- const { info } = Logger(config, "[password]");
1342
1576
  if (stringCheck(config?.password)) {
1343
- log && info(`${logger}[config] ***`);
1577
+ log && log("[config]").info("***");
1344
1578
  return String(config?.password);
1345
1579
  }
1346
1580
  const pass = stringCheck(process.env.NILEDB_PASSWORD);
1347
1581
  if (pass) {
1348
- logger && info(`${logger}[NILEDB_PASSWORD] ***`);
1582
+ logger("[NILEDB_PASSWORD]").info("***");
1349
1583
  return pass;
1350
1584
  }
1351
1585
  const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
@@ -1363,15 +1597,15 @@ var getPassword = (cfg) => {
1363
1597
  );
1364
1598
  };
1365
1599
  var getDatabaseName = (cfg) => {
1366
- const { config, logger } = cfg;
1367
- const { info } = Logger(config, "[databaseName]");
1600
+ const { config } = cfg;
1601
+ const { info } = config.logger("[databaseName]");
1368
1602
  if (stringCheck(config?.databaseName)) {
1369
- logger && info(`${logger}[config] ${config?.databaseName}`);
1603
+ info(`[config] ${config?.databaseName}`);
1370
1604
  return String(config?.databaseName);
1371
1605
  }
1372
1606
  const name = stringCheck(process.env.NILEDB_NAME);
1373
1607
  if (name) {
1374
- logger && info(`${logger}[NILEDB_NAME] ${name}`);
1608
+ info(`[NILEDB_NAME] ${name}`);
1375
1609
  return name;
1376
1610
  }
1377
1611
  if (process.env.NILEDB_POSTGRES_URL) {
@@ -1386,50 +1620,52 @@ var getDatabaseName = (cfg) => {
1386
1620
  );
1387
1621
  };
1388
1622
  var getTenantId = (cfg) => {
1389
- const { config, logger } = cfg;
1390
- const { info } = Logger(config, "[tenantId]");
1623
+ const { config } = cfg;
1624
+ const { info } = config.logger("[tenantId]");
1391
1625
  if (stringCheck(config?.tenantId)) {
1392
- logger && info(`${logger}[config] ${config?.tenantId}`);
1626
+ info(`[config] ${config?.tenantId}`);
1393
1627
  return String(config?.tenantId);
1394
1628
  }
1395
1629
  if (stringCheck(process.env.NILEDB_TENANT)) {
1396
- logger && info(`${logger}[NILEDB_TENANT] ${process.env.NILEDB_TENANT}`);
1630
+ info(`[NILEDB_TENANT] ${process.env.NILEDB_TENANT}`);
1397
1631
  return String(process.env.NILEDB_TENANT);
1398
1632
  }
1399
1633
  return null;
1400
1634
  };
1401
1635
  function getDbHost(cfg) {
1402
- const { config, logger } = cfg;
1403
- const { info } = Logger(config, "[db.host]");
1636
+ const { config } = cfg;
1637
+ const logger = config.logger;
1638
+ const { info } = logger("[db.host]");
1404
1639
  if (stringCheck(config?.db && config.db.host)) {
1405
- logger && info(`${logger}[config] ${config?.db?.host}`);
1640
+ info(`[config] ${config?.db?.host}`);
1406
1641
  return String(config?.db?.host);
1407
1642
  }
1408
1643
  if (stringCheck(process.env.NILEDB_HOST)) {
1409
- logger && info(`${logger}[NILEDB_HOST] ${process.env.NILEDB_HOST}`);
1644
+ info(`[NILEDB_HOST] ${process.env.NILEDB_HOST}`);
1410
1645
  return process.env.NILEDB_HOST;
1411
1646
  }
1412
1647
  const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
1413
1648
  if (pg2) {
1414
1649
  try {
1415
1650
  const pgUrl = new URL(pg2);
1416
- logger && info(`${logger}[NILEDB_POSTGRES_URL] ${pgUrl.hostname}`);
1651
+ info(`[NILEDB_POSTGRES_URL] ${pgUrl.hostname}`);
1417
1652
  return pgUrl.hostname;
1418
1653
  } catch (e) {
1419
1654
  }
1420
1655
  }
1421
- logger && info(`${logger}[default] db.thenile.dev`);
1656
+ info("[default] db.thenile.dev");
1422
1657
  return "db.thenile.dev";
1423
1658
  }
1424
1659
  function getDbPort(cfg) {
1425
- const { config, logger } = cfg;
1426
- const { info } = Logger(config, "[db.port]");
1660
+ const { config } = cfg;
1661
+ const logger = config.logger;
1662
+ const { info } = logger("[db.port]");
1427
1663
  if (config?.db?.port && config.db.port != null) {
1428
- logger && info(`${logger}[config] ${config?.db.port}`);
1664
+ info(`[config] ${config?.db.port}`);
1429
1665
  return Number(config.db?.port);
1430
1666
  }
1431
1667
  if (stringCheck(process.env.NILEDB_PORT)) {
1432
- logger && info(`${logger}[NILEDB_PORT] ${process.env.NILEDB_PORT}`);
1668
+ info(`[NILEDB_PORT] ${process.env.NILEDB_PORT}`);
1433
1669
  return Number(process.env.NILEDB_PORT);
1434
1670
  }
1435
1671
  const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
@@ -1442,7 +1678,7 @@ function getDbPort(cfg) {
1442
1678
  } catch (e) {
1443
1679
  }
1444
1680
  }
1445
- logger && info(`${logger}[default] 5432`);
1681
+ info("[default] 5432");
1446
1682
  return 5432;
1447
1683
  }
1448
1684
  var logProtector = (logger) => {
@@ -1460,6 +1696,8 @@ var Config = class {
1460
1696
  routes;
1461
1697
  handlers;
1462
1698
  paths;
1699
+ extensionCtx;
1700
+ extensions;
1463
1701
  logger;
1464
1702
  /**
1465
1703
  * Stores the set tenant id from Server for use in sub classes
@@ -1493,15 +1731,19 @@ var Config = class {
1493
1731
  */
1494
1732
  routePrefix;
1495
1733
  db;
1496
- // api: ApiConfig;
1497
- constructor(config, logger) {
1498
- const envVarConfig = { config, logger };
1734
+ constructor(config) {
1499
1735
  this.routePrefix = config?.routePrefix ?? "/api";
1500
- this.secureCookies = getSecureCookies(envVarConfig);
1501
- this.callbackUrl = getCallbackUrl(envVarConfig);
1502
1736
  this.debug = config?.debug;
1503
1737
  this.origin = config?.origin;
1738
+ this.extensions = config?.extensions;
1739
+ this.extensionCtx = config?.extensionCtx;
1504
1740
  this.serverOrigin = config?.origin ?? "http://localhost:3000";
1741
+ this.logger = Logger(config);
1742
+ const envVarConfig = {
1743
+ config: { ...config, logger: this.logger }
1744
+ };
1745
+ this.secureCookies = getSecureCookies(envVarConfig);
1746
+ this.callbackUrl = getCallbackUrl(envVarConfig);
1505
1747
  this.apiUrl = getApiUrl(envVarConfig);
1506
1748
  const user = getUsername(envVarConfig);
1507
1749
  const password = getPassword(envVarConfig);
@@ -1568,7 +1810,6 @@ var Config = class {
1568
1810
  };
1569
1811
  this.tenantId = config?.tenantId;
1570
1812
  this.userId = config?.userId;
1571
- this.logger = config?.logger;
1572
1813
  }
1573
1814
  };
1574
1815
 
@@ -1602,6 +1843,9 @@ var Eventer = class {
1602
1843
  }
1603
1844
  };
1604
1845
  var eventer = new Eventer();
1846
+ var updateTenantId = (tenantId) => {
1847
+ eventer.publish("tenantId" /* Tenant */, tenantId);
1848
+ };
1605
1849
  var watchTenantId = (cb) => eventer.subscribe("tenantId" /* Tenant */, cb);
1606
1850
  var watchUserId = (cb) => eventer.subscribe("userId" /* User */, cb);
1607
1851
  var evictPool = (val) => {
@@ -1615,7 +1859,7 @@ var watchHeaders = (cb) => eventer.subscribe("headers" /* Headers */, cb);
1615
1859
 
1616
1860
  // src/db/PoolProxy.ts
1617
1861
  function createProxyForPool(pool, config) {
1618
- const { info, error } = Logger(config, "[pool]");
1862
+ const { info, error } = config.logger("[pool]");
1619
1863
  return new Proxy(pool, {
1620
1864
  get(target, property) {
1621
1865
  if (property === "query") {
@@ -1651,7 +1895,7 @@ var NileDatabase = class {
1651
1895
  config;
1652
1896
  timer;
1653
1897
  constructor(config, id) {
1654
- const { warn, info, debug } = Logger(config, "[NileInstance]");
1898
+ const { warn, info, debug } = config.logger("[NileInstance]");
1655
1899
  this.id = id;
1656
1900
  const poolConfig = {
1657
1901
  min: 0,
@@ -1680,7 +1924,7 @@ var NileDatabase = class {
1680
1924
  `${this.id}-${this.timer}`
1681
1925
  );
1682
1926
  afterCreate2(client, (err) => {
1683
- const { error } = Logger(config, "[after create callback]");
1927
+ const { error } = config.logger("[after create callback]");
1684
1928
  if (err) {
1685
1929
  clearTimeout(this.timer);
1686
1930
  error("after create failed", {
@@ -1708,7 +1952,7 @@ var NileDatabase = class {
1708
1952
  });
1709
1953
  }
1710
1954
  startTimeout() {
1711
- const { debug } = Logger(this.config, "[NileInstance]");
1955
+ const { debug } = this.config.logger("[NileInstance]");
1712
1956
  if (this.timer) {
1713
1957
  clearTimeout(this.timer);
1714
1958
  }
@@ -1723,7 +1967,7 @@ var NileDatabase = class {
1723
1967
  }, Number(this.config.db.idleTimeoutMillis) ?? 3e4);
1724
1968
  }
1725
1969
  shutdown() {
1726
- const { debug } = Logger(this.config, "[NileInstance]");
1970
+ const { debug } = this.config.logger("[NileInstance]");
1727
1971
  debug(`attempting to shut down ${this.id}`);
1728
1972
  clearTimeout(this.timer);
1729
1973
  this.pool.end(() => {
@@ -1733,7 +1977,7 @@ var NileDatabase = class {
1733
1977
  };
1734
1978
  var NileInstance_default = NileDatabase;
1735
1979
  function makeAfterCreate(config, id) {
1736
- const { error, warn, debug } = Logger(config, "[afterCreate]");
1980
+ const { error, warn, debug } = config.logger("[afterCreate]");
1737
1981
  return (conn, done) => {
1738
1982
  conn.on("error", function errorHandler(e) {
1739
1983
  error(`Connection ${id} was terminated by server`, {
@@ -1797,7 +2041,7 @@ var DBManager = class {
1797
2041
  watchEvictPool(this.poolWatcherFn);
1798
2042
  }
1799
2043
  poolWatcher = (config) => (id) => {
1800
- const { info, warn } = Logger(config, "[DBManager]");
2044
+ const { info, warn } = Logger(config)("[DBManager]");
1801
2045
  if (id && this.connections.has(id)) {
1802
2046
  info(`Removing ${id} from db connection pool.`);
1803
2047
  const connection = this.connections.get(id);
@@ -1808,7 +2052,7 @@ var DBManager = class {
1808
2052
  }
1809
2053
  };
1810
2054
  getConnection = (config) => {
1811
- const { info } = Logger(config, "[DBManager]");
2055
+ const { info } = Logger(config)("[DBManager]");
1812
2056
  const id = this.makeId(config.tenantId, config.userId);
1813
2057
  const existing = this.connections.get(id);
1814
2058
  info(`# of instances: ${this.connections.size}`);
@@ -1827,7 +2071,7 @@ var DBManager = class {
1827
2071
  return newOne.pool;
1828
2072
  };
1829
2073
  clear = (config) => {
1830
- const { info } = Logger(config, "[DBManager]");
2074
+ const { info } = Logger(config)("[DBManager]");
1831
2075
  info(`Clearing all connections ${this.connections.size}`);
1832
2076
  this.cleared = true;
1833
2077
  this.connections.forEach((connection) => {
@@ -1841,9 +2085,15 @@ var DBManager = class {
1841
2085
  var Auth = class {
1842
2086
  #logger;
1843
2087
  #config;
2088
+ /**
2089
+ * Create an Auth helper.
2090
+ *
2091
+ * @param config - runtime configuration used by the underlying fetch helpers
2092
+ * such as `serverOrigin`, `routePrefix` and default headers.
2093
+ */
1844
2094
  constructor(config) {
1845
2095
  this.#config = config;
1846
- this.#logger = Logger(config, "[auth]");
2096
+ this.#logger = config.logger("[auth]");
1847
2097
  }
1848
2098
  async getSession(rawResponse = false) {
1849
2099
  const res = await fetchSession(this.#config);
@@ -1861,7 +2111,7 @@ var Auth = class {
1861
2111
  }
1862
2112
  }
1863
2113
  async getCsrf(rawResponse = false) {
1864
- return await getCsrf(this.#config, rawResponse);
2114
+ return await obtainCsrf(this.#config, rawResponse);
1865
2115
  }
1866
2116
  async listProviders(rawResponse = false) {
1867
2117
  const res = await fetchProviders(this.#config);
@@ -1874,6 +2124,12 @@ var Auth = class {
1874
2124
  return res;
1875
2125
  }
1876
2126
  }
2127
+ /**
2128
+ * Sign the current user out by calling `/api/auth/signout`.
2129
+ *
2130
+ * The CSRF token is fetched automatically and the stored cookies are cleared
2131
+ * from the internal configuration once the request completes.
2132
+ */
1877
2133
  async signOut() {
1878
2134
  const csrfRes = await this.getCsrf();
1879
2135
  if (!("csrfToken" in csrfRes)) {
@@ -1931,16 +2187,71 @@ var Auth = class {
1931
2187
  return res;
1932
2188
  }
1933
2189
  try {
1934
- return await res.clone().json();
2190
+ const json = await res.clone().json();
2191
+ if (json && typeof json === "object" && "tenants" in json) {
2192
+ const tenantId = json.tenants[0];
2193
+ if (tenantId) {
2194
+ updateTenantId(tenantId);
2195
+ }
2196
+ }
2197
+ return json;
1935
2198
  } catch {
1936
2199
  return res;
1937
2200
  }
1938
2201
  }
2202
+ /**
2203
+ * Request a password reset email.
2204
+ *
2205
+ * Sends a `POST` to `/api/auth/password-reset` with the provided email and
2206
+ * optional callback information. The endpoint responds with a redirect URL
2207
+ * which is returned as a {@link Response} object.
2208
+ */
2209
+ async forgotPassword(req) {
2210
+ let email = "";
2211
+ const defaults = defaultCallbackUrl({
2212
+ config: this.#config
2213
+ });
2214
+ let callbackUrl = defaults.callbackUrl;
2215
+ let redirectUrl = defaults.redirectUrl;
2216
+ if ("email" in req) {
2217
+ email = req.email;
2218
+ }
2219
+ if ("callbackUrl" in req) {
2220
+ callbackUrl = req.callbackUrl ? req.callbackUrl : null;
2221
+ }
2222
+ if ("redirectUrl" in req) {
2223
+ redirectUrl = req.redirectUrl ? req.redirectUrl : null;
2224
+ }
2225
+ const body = JSON.stringify({
2226
+ email,
2227
+ redirectUrl,
2228
+ callbackUrl
2229
+ });
2230
+ const data = await fetchResetPassword(
2231
+ this.#config,
2232
+ "POST",
2233
+ body,
2234
+ new URLSearchParams(),
2235
+ false
2236
+ );
2237
+ return data;
2238
+ }
2239
+ /**
2240
+ * Complete a password reset.
2241
+ *
2242
+ * This workflow expects a token obtained from {@link forgotPassword}. The
2243
+ * function performs a POST/GET/PUT sequence against
2244
+ * `/api/auth/password-reset` as described in the OpenAPI specification.
2245
+ *
2246
+ * @param req - either a {@link Request} with a JSON body or an object
2247
+ * containing the necessary fields.
2248
+ */
1939
2249
  async resetPassword(req) {
1940
2250
  let email = "";
1941
2251
  let password = "";
1942
- let callbackUrl = null;
1943
- let redirectUrl = null;
2252
+ const defaults = defaultCallbackUrl({ config: this.#config });
2253
+ let callbackUrl = defaults.callbackUrl;
2254
+ let redirectUrl = defaults.redirectUrl;
1944
2255
  if (req instanceof Request) {
1945
2256
  const body2 = await req.json();
1946
2257
  email = body2.email;
@@ -1969,19 +2280,6 @@ var Auth = class {
1969
2280
  redirectUrl = req.redirectUrl ? req.redirectUrl : null;
1970
2281
  }
1971
2282
  }
1972
- const fallbackCb = parseCallback(this.#config.headers);
1973
- if (fallbackCb) {
1974
- const [, value] = fallbackCb.split("=");
1975
- if (value) {
1976
- const parsedUrl = decodeURIComponent(value);
1977
- if (!redirectUrl) {
1978
- redirectUrl = `${new URL(parsedUrl).origin}${"/auth/reset-password" /* PASSWORD_RESET */}`;
1979
- }
1980
- }
1981
- if (!callbackUrl) {
1982
- callbackUrl = value;
1983
- }
1984
- }
1985
2283
  await this.getCsrf();
1986
2284
  const body = JSON.stringify({
1987
2285
  email,
@@ -2037,6 +2335,12 @@ var Auth = class {
2037
2335
  updateHeaders(updatedHeaders);
2038
2336
  return res;
2039
2337
  }
2338
+ /**
2339
+ * Low level helper used by {@link signIn} to complete provider flows.
2340
+ *
2341
+ * Depending on the provider this issues either a GET or POST request to
2342
+ * `/api/auth/callback/{provider}` via {@link fetchCallback}.
2343
+ */
2040
2344
  async callback(provider, body) {
2041
2345
  if (body instanceof Request) {
2042
2346
  this.#config.headers = body.headers;
@@ -2101,6 +2405,9 @@ var Auth = class {
2101
2405
  }
2102
2406
  info(`Obtaining providers for ${email}`);
2103
2407
  info(`Attempting sign in with email ${email}`);
2408
+ if (!email) {
2409
+ throw new Error("Email missing from payload, unable to sign in");
2410
+ }
2104
2411
  const body = JSON.stringify({
2105
2412
  email,
2106
2413
  password,
@@ -2122,7 +2429,7 @@ var Auth = class {
2122
2429
  }
2123
2430
  if (urlError) {
2124
2431
  error("Unable to log user in", { error: urlError });
2125
- return void 0;
2432
+ return new Response(urlError, { status: signInRes.status });
2126
2433
  }
2127
2434
  }
2128
2435
  if (!token) {
@@ -2200,11 +2507,25 @@ function parseResetToken(headers) {
2200
2507
  const [, token] = /((__Secure-)?nile\.reset=[^;]+)/.exec(authCookie) ?? [];
2201
2508
  return token;
2202
2509
  }
2510
+ function defaultCallbackUrl({ config }) {
2511
+ let cb = null;
2512
+ let redirect = null;
2513
+ const fallbackCb = parseCallback(config.headers);
2514
+ if (fallbackCb) {
2515
+ const [, value] = fallbackCb.split("=");
2516
+ cb = decodeURIComponent(value);
2517
+ if (value) {
2518
+ redirect = `${new URL(cb).origin}${"/auth/reset-password" /* PASSWORD_RESET */}`;
2519
+ }
2520
+ }
2521
+ return { callbackUrl: cb, redirectUrl: redirect };
2522
+ }
2203
2523
 
2204
- // src/auth/getCsrf.ts
2205
- async function getCsrf(config, rawResponse = false) {
2524
+ // src/auth/obtainCsrf.ts
2525
+ async function obtainCsrf(config, rawResponse = false) {
2206
2526
  const res = await fetchCsrf(config);
2207
2527
  const csrfCook = parseCSRF(res.headers);
2528
+ const h = new Headers();
2208
2529
  if (csrfCook) {
2209
2530
  const [, value] = csrfCook.split("=");
2210
2531
  const [token] = decodeURIComponent(value).split("|");
@@ -2216,7 +2537,8 @@ async function getCsrf(config, rawResponse = false) {
2216
2537
  parseToken(res.headers)
2217
2538
  ].filter(Boolean).join("; ");
2218
2539
  config.headers.set("cookie", cookie);
2219
- updateHeaders(new Headers({ cookie }));
2540
+ h.set("cookie", cookie);
2541
+ updateHeaders(h);
2220
2542
  }
2221
2543
  if (!rawResponse) {
2222
2544
  return { csrfToken: token };
@@ -2253,10 +2575,23 @@ async function getCsrf(config, rawResponse = false) {
2253
2575
  var Users = class {
2254
2576
  #config;
2255
2577
  #logger;
2578
+ /**
2579
+ * Create a new Users helper.
2580
+ * @param config - The configuration used for requests.
2581
+ */
2256
2582
  constructor(config) {
2257
2583
  this.#config = config;
2258
- this.#logger = Logger(config, "[me]");
2584
+ this.#logger = config.logger("[me]");
2259
2585
  }
2586
+ /**
2587
+ * Update the current user via `PUT /api/me`.
2588
+ *
2589
+ * The OpenAPI description for this endpoint can be found in
2590
+ * `packages/server/src/api/routes/me/index.ts` under `updateSelf`.
2591
+ *
2592
+ * @param req - Partial user fields to send.
2593
+ * @param [rawResponse] - When `true`, return the raw {@link Response}.
2594
+ */
2260
2595
  async updateSelf(req, rawResponse) {
2261
2596
  const res = await fetchMe(this.#config, "PUT", JSON.stringify(req));
2262
2597
  if (rawResponse) {
@@ -2268,6 +2603,13 @@ var Users = class {
2268
2603
  return res;
2269
2604
  }
2270
2605
  }
2606
+ /**
2607
+ * Remove the current user using `DELETE /api/me`.
2608
+ *
2609
+ * After the request the authentication headers are cleared with
2610
+ * {@link updateHeaders}. The OpenAPI docs for this route are in
2611
+ * `packages/server/src/api/routes/me/index.ts` under `removeSelf`.
2612
+ */
2271
2613
  async removeSelf() {
2272
2614
  const me = await this.getSelf();
2273
2615
  if ("id" in me) {
@@ -2288,50 +2630,71 @@ var Users = class {
2288
2630
  return res;
2289
2631
  }
2290
2632
  }
2291
- async verifySelf(bypassEmail = process.env.NODE_ENV !== "production", rawResponse = false) {
2633
+ async verifySelf(options, rawResponse = false) {
2634
+ const bypassEmail = typeof options === "object" ? options.bypassEmail ?? process.env.NODE_ENV !== "production" : process.env.NODE_ENV !== "production";
2635
+ const callbackUrl = typeof options === "object" ? options.callbackUrl : defaultCallbackUrl2(this.#config).callbackUrl;
2636
+ let res;
2292
2637
  try {
2293
2638
  const me = await this.getSelf();
2294
2639
  if (me instanceof Response) {
2295
2640
  return me;
2296
2641
  }
2297
- const res = await verifyEmailAddress(this.#config, me);
2642
+ res = await verifyEmailAddress(this.#config, me, String(callbackUrl));
2298
2643
  return res;
2299
2644
  } catch {
2300
- this.#logger?.warn(
2301
- "Unable to verify email. The current user's email will be set to verified any way. Be sure to configure emails for production."
2302
- );
2645
+ const message = "Unable to verify email.";
2646
+ this.#logger?.warn(message);
2647
+ res = new Response(message, { status: 400 });
2303
2648
  }
2304
2649
  if (bypassEmail) {
2305
- return await this.updateSelf({ emailVerified: true }, rawResponse);
2650
+ res = this.updateSelf({ emailVerified: true }, rawResponse);
2306
2651
  }
2307
2652
  this.#logger.error(
2308
2653
  "Unable to verify email address. Configure your SMTP server in the console."
2309
2654
  );
2310
- return void 0;
2655
+ return res;
2311
2656
  }
2312
2657
  };
2313
- async function verifyEmailAddress(config, user) {
2658
+ async function verifyEmailAddress(config, user, callback) {
2314
2659
  config.headers.set("content-type", "application/x-www-form-urlencoded");
2315
- const { csrfToken } = await getCsrf(config);
2660
+ const { csrfToken } = await obtainCsrf(config);
2661
+ const defaults = defaultCallbackUrl2(config);
2662
+ const callbackUrl = callback ?? String(defaults.callbackUrl);
2316
2663
  const res = await fetchVerifyEmail(
2317
2664
  config,
2318
2665
  "POST",
2319
- new URLSearchParams({ csrfToken, email: user.email }).toString()
2666
+ new URLSearchParams({
2667
+ csrfToken,
2668
+ email: user.email,
2669
+ callbackUrl
2670
+ }).toString()
2320
2671
  );
2321
2672
  if (res.status > 299) {
2322
2673
  throw new Error(await res.text());
2323
2674
  }
2324
2675
  return res;
2325
2676
  }
2677
+ function defaultCallbackUrl2(config) {
2678
+ let cb = null;
2679
+ const fallbackCb = parseCallback(config.headers);
2680
+ if (fallbackCb) {
2681
+ const [, value] = fallbackCb.split("=");
2682
+ cb = decodeURIComponent(value);
2683
+ }
2684
+ return { callbackUrl: cb };
2685
+ }
2326
2686
 
2327
2687
  // src/tenants/index.ts
2328
2688
  var Tenants = class {
2329
- #logger;
2330
2689
  #config;
2331
2690
  constructor(config) {
2332
- this.#logger = Logger(config, "[tenants]");
2333
2691
  this.#config = config;
2334
2692
  }
2693
+ /**
2694
+ * Create a new tenant using `POST /api/tenants`.
2695
+ * See `packages/server/src/api/routes/tenants/POST.ts` for the
2696
+ * `createTenant` operation definition.
2697
+ */
2335
2698
  async create(req, rawResponse) {
2336
2699
  let res;
2337
2700
  if (typeof req === "string") {
@@ -2352,6 +2715,11 @@ var Tenants = class {
2352
2715
  return res;
2353
2716
  }
2354
2717
  }
2718
+ /**
2719
+ * Remove a tenant via `DELETE /api/tenants/{tenantId}`.
2720
+ *
2721
+ * @param req - The tenant to remove or context containing the id.
2722
+ */
2355
2723
  async delete(req) {
2356
2724
  if (typeof req === "string") {
2357
2725
  this.#config.tenantId = req;
@@ -2362,6 +2730,12 @@ var Tenants = class {
2362
2730
  const res = await fetchTenant(this.#config, "DELETE");
2363
2731
  return res;
2364
2732
  }
2733
+ /**
2734
+ * Fetch details for a tenant using `GET /api/tenants/{tenantId}`.
2735
+ *
2736
+ * @param req - Tenant identifier or context.
2737
+ * @param [rawResponse] - When true, return the raw {@link Response}.
2738
+ */
2365
2739
  async get(req, rawResponse) {
2366
2740
  if (typeof req === "string") {
2367
2741
  this.#config.tenantId = req;
@@ -2396,6 +2770,10 @@ var Tenants = class {
2396
2770
  return res;
2397
2771
  }
2398
2772
  }
2773
+ /**
2774
+ * List tenants for the current user via `GET /api/tenants`.
2775
+ * See `packages/server/src/api/routes/tenants/GET.ts` for details.
2776
+ */
2399
2777
  async list(req) {
2400
2778
  const res = await fetchTenantsByUser(this.#config);
2401
2779
  if (req === true) {
@@ -2407,6 +2785,11 @@ var Tenants = class {
2407
2785
  return res;
2408
2786
  }
2409
2787
  }
2788
+ /**
2789
+ * Leave the current tenant using `DELETE /api/tenants/{tenantId}/users/{userId}`.
2790
+ *
2791
+ * @param [req] - Optionally specify the tenant id to leave.
2792
+ */
2410
2793
  async leaveTenant(req) {
2411
2794
  const me = await fetchMe(this.#config);
2412
2795
  try {
@@ -2432,6 +2815,12 @@ var Tenants = class {
2432
2815
  const res = await fetchTenantUser(this.#config, "PUT");
2433
2816
  return responseHandler(res, rawResponse);
2434
2817
  }
2818
+ /**
2819
+ * Remove a user from a tenant with `DELETE /api/tenants/{tenantId}/users/{userId}`.
2820
+ *
2821
+ * @param req - User and tenant identifiers or context.
2822
+ * @param [rawResponse] - When true, return the raw {@link Response}.
2823
+ */
2435
2824
  async removeMember(req, rawResponse) {
2436
2825
  this.#handleContext(req);
2437
2826
  const res = await fetchTenantUser(this.#config, "DELETE");
@@ -2445,6 +2834,88 @@ var Tenants = class {
2445
2834
  rawResponse || typeof req === "boolean" && req
2446
2835
  );
2447
2836
  }
2837
+ /**
2838
+ * List invites for the current tenant via `GET /api/tenants/{tenantId}/invites`.
2839
+ */
2840
+ async invites() {
2841
+ const res = await fetchInvites(this.#config);
2842
+ return responseHandler(res);
2843
+ }
2844
+ async invite(req, rawResponse) {
2845
+ const { csrfToken } = await obtainCsrf(this.#config);
2846
+ const defaults = defaultCallbackUrl3(this.#config);
2847
+ let identifier = req;
2848
+ let callbackUrl = defaults.callbackUrl;
2849
+ let redirectUrl = defaults.redirectUrl;
2850
+ if (typeof req === "object") {
2851
+ if ("email" in req) {
2852
+ identifier = req.email;
2853
+ }
2854
+ if ("callbackUrl" in req) {
2855
+ callbackUrl = req.callbackUrl ? req.callbackUrl : "";
2856
+ }
2857
+ if ("redirectUrl" in req) {
2858
+ redirectUrl = req.redirectUrl ? req.redirectUrl : "";
2859
+ }
2860
+ }
2861
+ this.#config.headers.set(
2862
+ "Content-Type",
2863
+ "application/x-www-form-urlencoded"
2864
+ );
2865
+ const res = await fetchInvite(
2866
+ this.#config,
2867
+ "POST",
2868
+ new URLSearchParams({
2869
+ identifier,
2870
+ csrfToken,
2871
+ callbackUrl,
2872
+ redirectUrl
2873
+ }).toString()
2874
+ );
2875
+ return responseHandler(res, rawResponse);
2876
+ }
2877
+ /**
2878
+ * Accept an invite using `PUT /api/tenants/{tenantId}/invite`.
2879
+ *
2880
+ * @param req - Identifier and token from the invite email.
2881
+ * @param [rawResponse] - When true, return the raw {@link Response}.
2882
+ */
2883
+ async acceptInvite(req, rawResponse) {
2884
+ if (!req) {
2885
+ throw new Error("The identifier and token are required.");
2886
+ }
2887
+ const { identifier, token } = req;
2888
+ const defaults = defaultCallbackUrl3(this.#config);
2889
+ const callbackUrl = String(defaults.callbackUrl);
2890
+ const res = await fetchInvite(
2891
+ this.#config,
2892
+ "PUT",
2893
+ new URLSearchParams({
2894
+ identifier,
2895
+ token,
2896
+ callbackUrl
2897
+ }).toString()
2898
+ );
2899
+ return responseHandler(res, rawResponse);
2900
+ }
2901
+ /**
2902
+ * Delete a pending invite using `DELETE /api/tenants/{tenantId}/invite/{inviteId}`.
2903
+ *
2904
+ * @param req - Identifier of the invite to remove.
2905
+ */
2906
+ async deleteInvite(req) {
2907
+ let id = "";
2908
+ if (typeof req === "object") {
2909
+ id = req.id;
2910
+ } else {
2911
+ id = req;
2912
+ }
2913
+ if (!id) {
2914
+ throw new Error("An invite id is required.");
2915
+ }
2916
+ const res = await fetchInvite(this.#config, "DELETE", id);
2917
+ return responseHandler(res, true);
2918
+ }
2448
2919
  #handleContext(req) {
2449
2920
  if (typeof req === "object") {
2450
2921
  if ("tenantId" in req) {
@@ -2466,31 +2937,47 @@ async function responseHandler(res, rawResponse) {
2466
2937
  return res;
2467
2938
  }
2468
2939
  }
2940
+ function defaultCallbackUrl3(config) {
2941
+ let cb = null;
2942
+ let redirect = null;
2943
+ const fallbackCb = parseCallback(config.headers);
2944
+ if (fallbackCb) {
2945
+ const [, value] = fallbackCb.split("=");
2946
+ cb = decodeURIComponent(value);
2947
+ if (value) {
2948
+ redirect = `${new URL(cb).origin}${config.routePrefix}${"/tenants/{tenantId}/invite" /* INVITE */.replace(
2949
+ "{tenantId}",
2950
+ String(config.tenantId)
2951
+ )}`;
2952
+ }
2953
+ }
2954
+ return { callbackUrl: cb, redirectUrl: redirect };
2955
+ }
2469
2956
 
2470
2957
  // src/api/handlers/withContext/index.ts
2471
2958
  function handlersWithContext(config) {
2472
- const GET6 = GETTER(config.routes, config);
2473
- const POST5 = POSTER(config.routes, config);
2474
- const DELETE4 = DELETER(config.routes, config);
2475
- const PUT5 = PUTER(config.routes, config);
2959
+ const GET7 = GETTER(config.routes, config);
2960
+ const POST6 = POSTER(config.routes, config);
2961
+ const DELETE5 = DELETER(config.routes, config);
2962
+ const PUT6 = PUTER(config.routes, config);
2476
2963
  return {
2477
2964
  GET: async (req) => {
2478
- const response = await GET6(req);
2965
+ const response = await GET7(req);
2479
2966
  const updatedConfig = updateConfig(response, config);
2480
2967
  return { response, nile: new Server(updatedConfig) };
2481
2968
  },
2482
2969
  POST: async (req) => {
2483
- const response = await POST5(req);
2970
+ const response = await POST6(req);
2484
2971
  const updatedConfig = updateConfig(response, config);
2485
2972
  return { response, nile: new Server(updatedConfig) };
2486
2973
  },
2487
2974
  DELETE: async (req) => {
2488
- const response = await DELETE4(req);
2975
+ const response = await DELETE5(req);
2489
2976
  const updatedConfig = updateConfig(response, config);
2490
2977
  return { response, nile: new Server(updatedConfig) };
2491
2978
  },
2492
2979
  PUT: async (req) => {
2493
- const response = await PUT5(req);
2980
+ const response = await PUT6(req);
2494
2981
  const updatedConfig = updateConfig(response, config);
2495
2982
  return { response, nile: new Server(updatedConfig) };
2496
2983
  }
@@ -2499,31 +2986,126 @@ function handlersWithContext(config) {
2499
2986
  function updateConfig(response, config) {
2500
2987
  let origin = "http://localhost:3000";
2501
2988
  let headers = null;
2502
- if (response?.status === 302) {
2503
- const location = response.headers.get("location");
2504
- if (location) {
2505
- const urlLocation = new URL(location);
2506
- origin = urlLocation.origin;
2989
+ if (response instanceof Response) {
2990
+ if (response?.status === 302) {
2991
+ const location = response.headers.get("location");
2992
+ if (location) {
2993
+ const urlLocation = new URL(location);
2994
+ origin = urlLocation.origin;
2995
+ }
2507
2996
  }
2508
- }
2509
- const setCookies = [];
2510
- if (response?.headers) {
2511
- for (const [key14, value] of response.headers) {
2512
- if (key14.toLowerCase() === "set-cookie") {
2513
- setCookies.push(value);
2997
+ const setCookies = [];
2998
+ if (response?.headers) {
2999
+ for (const [key17, value] of response.headers) {
3000
+ if (key17.toLowerCase() === "set-cookie") {
3001
+ setCookies.push(value);
3002
+ }
2514
3003
  }
2515
3004
  }
2516
- }
2517
- if (setCookies.length > 0) {
2518
- const cookieHeader = setCookies.map((cookieStr) => cookieStr.split(";")[0]).join("; ");
2519
- headers = new Headers({ cookie: cookieHeader });
3005
+ if (setCookies.length > 0) {
3006
+ const cookieHeader = setCookies.map((cookieStr) => cookieStr.split(";")[0]).join("; ");
3007
+ headers = new Headers({ cookie: cookieHeader });
3008
+ }
2520
3009
  }
2521
3010
  return {
2522
3011
  ...config,
2523
3012
  origin,
2524
- headers: headers ?? void 0
3013
+ headers: headers ?? void 0,
3014
+ preserveHeaders: true
3015
+ };
3016
+ }
3017
+
3018
+ // src/api/utils/extensions.ts
3019
+ function getRequestConfig(params) {
3020
+ if (typeof params[1] === "object") {
3021
+ return params[1];
3022
+ }
3023
+ return {};
3024
+ }
3025
+ function bindRunExtensions(instance) {
3026
+ return async function runExtensions(toRun, config, params, _init) {
3027
+ const { debug } = config.logger("[EXTENSIONS]");
3028
+ const extensionConfig = getRequestConfig(
3029
+ Array.isArray(params) ? params : [null, params]
3030
+ );
3031
+ if (config.extensions) {
3032
+ for (const create2 of config.extensions) {
3033
+ if (typeof create2 !== "function") {
3034
+ continue;
3035
+ }
3036
+ const ext = create2(instance);
3037
+ if (extensionConfig.disableExtensions?.includes(ext.id)) {
3038
+ continue;
3039
+ }
3040
+ if (ext.onHandleRequest && toRun === "onHandleRequest" /* onHandleRequest */) {
3041
+ const result = await ext.onHandleRequest(
3042
+ ...Array.isArray(params) ? params : [params]
3043
+ );
3044
+ if (result != null) {
3045
+ return result;
3046
+ }
3047
+ continue;
3048
+ }
3049
+ const [param] = Array.isArray(params) ? params : [params];
3050
+ if (ext.onRequest && toRun === "onRequest" /* onRequest */) {
3051
+ const previousContext = instance.getContext();
3052
+ if (previousContext.preserveHeaders) {
3053
+ instance.setContext({ preserveHeaders: false });
3054
+ }
3055
+ if (!_init) {
3056
+ continue;
3057
+ }
3058
+ await ext.onRequest(_init.request);
3059
+ const updatedContext = instance.getContext();
3060
+ if (updatedContext?.headers) {
3061
+ const cookie = updatedContext.headers.get("cookie");
3062
+ if (cookie && param.headers) {
3063
+ param.headers.set(
3064
+ "cookie",
3065
+ mergeCookies(
3066
+ previousContext.preserveHeaders ? previousContext.headers?.get("cookie") : null,
3067
+ updatedContext.headers.get("cookie")
3068
+ )
3069
+ );
3070
+ }
3071
+ if (updatedContext.tenantId && param.headers) {
3072
+ param.headers.set(
3073
+ TENANT_COOKIE,
3074
+ String(updatedContext.headers.get(TENANT_COOKIE))
3075
+ );
3076
+ }
3077
+ }
3078
+ debug(`${ext.id ?? create2.name} ran onRequest`);
3079
+ continue;
3080
+ }
3081
+ if (ext.onResponse && toRun === "onResponse" /* onResponse */) {
3082
+ const result = await ext.onResponse(param);
3083
+ if (result != null) {
3084
+ return result;
3085
+ }
3086
+ continue;
3087
+ }
3088
+ }
3089
+ }
3090
+ return void 0;
2525
3091
  };
2526
3092
  }
3093
+ function buildExtensionConfig(instance) {
3094
+ return {
3095
+ runExtensions: bindRunExtensions(instance)
3096
+ };
3097
+ }
3098
+ function mergeCookies(...cookieStrings) {
3099
+ const cookieMap = /* @__PURE__ */ new Map();
3100
+ for (const str of cookieStrings) {
3101
+ if (!str) continue;
3102
+ for (const part of str.split(";")) {
3103
+ const [key17, value] = part.split("=").map((s) => s.trim());
3104
+ if (key17 && value) cookieMap.set(key17, value);
3105
+ }
3106
+ }
3107
+ return [...cookieMap.entries()].map(([k, v]) => `${k}=${v}`).join("; ");
3108
+ }
2527
3109
 
2528
3110
  // src/Server.ts
2529
3111
  var Server = class {
@@ -2532,11 +3114,14 @@ var Server = class {
2532
3114
  auth;
2533
3115
  #config;
2534
3116
  #handlers;
2535
- #paths;
2536
3117
  #manager;
2537
3118
  #headers;
3119
+ #preserveHeaders;
2538
3120
  constructor(config) {
2539
- this.#config = new Config(config, "[initial config]");
3121
+ this.#config = new Config({
3122
+ ...config,
3123
+ extensionCtx: buildExtensionConfig(this)
3124
+ });
2540
3125
  watchTenantId((tenantId) => {
2541
3126
  if (tenantId !== this.#config.tenantId) {
2542
3127
  this.#config.tenantId = tenantId;
@@ -2557,13 +3142,24 @@ var Server = class {
2557
3142
  ...this.#config.handlers,
2558
3143
  withContext: handlersWithContext(this.#config)
2559
3144
  };
2560
- this.#paths = this.#config.paths;
3145
+ this.#preserveHeaders = config?.preserveHeaders ?? false;
2561
3146
  this.#config.tenantId = getTenantId({ config: this.#config });
2562
3147
  this.#manager = new DBManager(this.#config);
2563
3148
  this.#handleHeaders(config);
2564
3149
  this.users = new Users(this.#config);
2565
3150
  this.tenants = new Tenants(this.#config);
2566
3151
  this.auth = new Auth(this.#config);
3152
+ if (config?.extensions) {
3153
+ for (const create2 of config.extensions) {
3154
+ if (typeof create2 !== "function") {
3155
+ continue;
3156
+ }
3157
+ const ext = create2(this);
3158
+ if (ext.onConfigure) {
3159
+ ext.onConfigure();
3160
+ }
3161
+ }
3162
+ }
2567
3163
  }
2568
3164
  get db() {
2569
3165
  const pool = this.#manager.getConnection(this.#config);
@@ -2573,6 +3169,28 @@ var Server = class {
2573
3169
  }
2574
3170
  });
2575
3171
  }
3172
+ get logger() {
3173
+ return this.#config.logger;
3174
+ }
3175
+ get extensions() {
3176
+ return {
3177
+ remove: async (id) => {
3178
+ if (!this.#config.extensions) return;
3179
+ const resolved = this.#config.extensions.map((ext) => ext(this));
3180
+ const index = resolved.findIndex((ext) => ext.id === id);
3181
+ if (index !== -1) {
3182
+ this.#config.extensions.splice(index, 1);
3183
+ }
3184
+ return resolved;
3185
+ },
3186
+ add: (extension) => {
3187
+ if (!this.#config.extensions) {
3188
+ this.#config.extensions = [];
3189
+ }
3190
+ this.#config.extensions.push(extension);
3191
+ }
3192
+ };
3193
+ }
2576
3194
  /**
2577
3195
  * A convenience function that applies a config and ensures whatever was passed is set properly
2578
3196
  */
@@ -2588,12 +3206,15 @@ var Server = class {
2588
3206
  this.#reset();
2589
3207
  return this;
2590
3208
  }
2591
- getPaths() {
2592
- return this.#paths;
2593
- }
2594
3209
  get handlers() {
2595
3210
  return this.#handlers;
2596
3211
  }
3212
+ get paths() {
3213
+ return this.#config.paths;
3214
+ }
3215
+ set paths(paths) {
3216
+ this.#config.paths = paths;
3217
+ }
2597
3218
  /**
2598
3219
  * Allow the setting of headers from a req or header object.
2599
3220
  * Makes it possible to handle REST requests easily
@@ -2601,7 +3222,40 @@ var Server = class {
2601
3222
  * @param req
2602
3223
  * @returns undefined
2603
3224
  */
2604
- setContext(req) {
3225
+ setContext = (req, ...remaining) => {
3226
+ let ok = false;
3227
+ if (req && typeof req === "object" && "tenantId" in req) {
3228
+ ok = true;
3229
+ this.#config.tenantId = req.tenantId;
3230
+ }
3231
+ if (req && typeof req === "object" && "userId" in req) {
3232
+ ok = true;
3233
+ this.#config.userId = req.userId;
3234
+ }
3235
+ if (req && typeof req === "object" && "preserveHeaders" in req) {
3236
+ ok = true;
3237
+ this.#preserveHeaders = Boolean(req.preserveHeaders);
3238
+ }
3239
+ let atLeastOne = false;
3240
+ if (this.#config?.extensions) {
3241
+ for (const create2 of this.#config.extensions) {
3242
+ if (typeof create2 !== "function") {
3243
+ continue;
3244
+ }
3245
+ const ext = create2(this);
3246
+ if (typeof ext.onSetContext === "function") {
3247
+ if (req) {
3248
+ ext.onSetContext(req, ...remaining);
3249
+ atLeastOne = true;
3250
+ } else {
3251
+ this.#config.logger("extension").warn("attempted to call onSetContext without a value");
3252
+ }
3253
+ }
3254
+ }
3255
+ }
3256
+ if (atLeastOne) {
3257
+ return;
3258
+ }
2605
3259
  try {
2606
3260
  if (req instanceof Headers) {
2607
3261
  this.#handleHeaders(req);
@@ -2614,38 +3268,44 @@ var Server = class {
2614
3268
  }
2615
3269
  } catch {
2616
3270
  }
2617
- let ok = false;
2618
- if (req && typeof req === "object" && "tenantId" in req) {
2619
- ok = true;
2620
- this.#config.tenantId = req.tenantId;
2621
- }
2622
- if (req && typeof req === "object" && "userId" in req) {
2623
- ok = true;
2624
- this.#config.userId = req.userId;
2625
- }
2626
3271
  if (ok) {
2627
3272
  return;
2628
3273
  }
2629
3274
  if (typeof req === "object") {
2630
- const headers = new Headers(req);
2631
- if (headers) {
2632
- this.#handleHeaders(headers);
2633
- this.#reset();
2634
- return;
3275
+ try {
3276
+ const headers = new Headers(req);
3277
+ if (headers) {
3278
+ this.#handleHeaders(headers);
3279
+ this.#reset();
3280
+ return;
3281
+ }
3282
+ } catch {
2635
3283
  }
2636
3284
  }
2637
- const { warn } = Logger(this.#config, "[API]");
3285
+ const { warn } = Logger(this.#config)("[API]");
2638
3286
  if (warn) {
2639
3287
  warn(
2640
3288
  "Set context expects a Request, Header instance or an object of Record<string, string>"
2641
3289
  );
2642
3290
  }
2643
- }
3291
+ };
2644
3292
  getContext() {
3293
+ if (this.#config?.extensions) {
3294
+ for (const create2 of this.#config.extensions) {
3295
+ if (typeof create2 !== "function") {
3296
+ continue;
3297
+ }
3298
+ const ext = create2(this);
3299
+ if (typeof ext.onGetContext === "function") {
3300
+ return ext.onGetContext();
3301
+ }
3302
+ }
3303
+ }
2645
3304
  return {
2646
3305
  headers: this.#headers,
2647
- userId: this.#config.userId,
2648
- tenantId: this.#config.tenantId
3306
+ userId: this.#config?.userId,
3307
+ tenantId: this.#config?.tenantId,
3308
+ preserveHeaders: this.#preserveHeaders
2649
3309
  };
2650
3310
  }
2651
3311
  /**
@@ -2661,33 +3321,35 @@ var Server = class {
2661
3321
  } else if (config?.headers) {
2662
3322
  headers = config?.headers;
2663
3323
  if (config && config.origin) {
2664
- this.#headers.set(X_NILE_ORIGIN, config.origin);
3324
+ this.#headers.set(HEADER_ORIGIN, config.origin);
2665
3325
  }
2666
3326
  if (config && config.secureCookies != null) {
2667
- this.#headers.set(X_NILE_SECURECOOKIES, String(config.secureCookies));
3327
+ this.#headers.set(HEADER_SECURE_COOKIES, String(config.secureCookies));
2668
3328
  }
2669
3329
  }
2670
3330
  if (headers instanceof Headers) {
2671
- headers.forEach((value, key14) => {
2672
- updates.push([key14.toLowerCase(), value]);
3331
+ headers.forEach((value, key17) => {
3332
+ updates.push([key17.toLowerCase(), value]);
2673
3333
  });
2674
3334
  } else {
2675
- for (const [key14, value] of Object.entries(headers ?? {})) {
2676
- updates.push([key14.toLowerCase(), value]);
3335
+ for (const [key17, value] of Object.entries(headers ?? {})) {
3336
+ updates.push([key17.toLowerCase(), value]);
2677
3337
  }
2678
3338
  }
2679
3339
  const merged = {};
2680
- this.#headers?.forEach((value, key14) => {
2681
- if (key14.toLowerCase() !== "cookie") {
2682
- merged[key14.toLowerCase()] = value;
3340
+ this.#config.tenantId = getTenantFromHttp(this.#headers, this.#config);
3341
+ this.#headers?.forEach((value, key17) => {
3342
+ if (key17.toLowerCase() !== "cookie") {
3343
+ merged[key17.toLowerCase()] = value;
2683
3344
  }
2684
3345
  });
2685
- for (const [key14, value] of updates) {
2686
- merged[key14] = value;
3346
+ for (const [key17, value] of updates) {
3347
+ merged[key17] = value;
2687
3348
  }
2688
- for (const [key14, value] of Object.entries(merged)) {
2689
- this.#headers.set(key14, value);
3349
+ for (const [key17, value] of Object.entries(merged)) {
3350
+ this.#headers.set(key17, value);
2690
3351
  }
3352
+ this.#config.logger("[handleHeaders]").debug(JSON.stringify(merged));
2691
3353
  this.#config.headers = this.#headers;
2692
3354
  }
2693
3355
  /**
@@ -2695,6 +3357,7 @@ var Server = class {
2695
3357
  */
2696
3358
  #reset = () => {
2697
3359
  this.#config.headers = this.#headers ?? new Headers();
3360
+ this.#config.extensionCtx = buildExtensionConfig(this);
2698
3361
  this.users = new Users(this.#config);
2699
3362
  this.tenants = new Tenants(this.#config);
2700
3363
  this.auth = new Auth(this.#config);
@@ -2708,6 +3371,6 @@ function create(config) {
2708
3371
  return server;
2709
3372
  }
2710
3373
 
2711
- export { APIErrorErrorCodeEnum, LoginUserResponseTokenTypeEnum, create as Nile, Server, parseCSRF, parseCallback, parseToken };
3374
+ export { APIErrorErrorCodeEnum, ExtensionState, HEADER_ORIGIN, HEADER_SECURE_COOKIES, LoginUserResponseTokenTypeEnum, create as Nile, Server, TENANT_COOKIE, USER_COOKIE, parseCSRF, parseCallback, parseResetToken, parseToken };
2712
3375
  //# sourceMappingURL=index.mjs.map
2713
3376
  //# sourceMappingURL=index.mjs.map