@niledatabase/server 4.2.0 → 5.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,12 +2,28 @@
2
2
 
3
3
  require('dotenv/config');
4
4
  var pg = require('pg');
5
- var jose = require('jose');
6
5
 
7
6
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
7
 
9
8
  var pg__default = /*#__PURE__*/_interopDefault(pg);
10
9
 
10
+ // src/types.ts
11
+ var APIErrorErrorCodeEnum = {
12
+ InternalError: "internal_error",
13
+ BadRequest: "bad_request",
14
+ EntityNotFound: "entity_not_found",
15
+ DuplicateEntity: "duplicate_entity",
16
+ InvalidCredentials: "invalid_credentials",
17
+ UnknownOidcProvider: "unknown_oidc_provider",
18
+ ProviderAlreadyExists: "provider_already_exists",
19
+ ProviderConfigError: "provider_config_error",
20
+ ProviderMismatch: "provider_mismatch",
21
+ ProviderUpdateError: "provider_update_error",
22
+ SessionStateMissing: "session_state_missing",
23
+ SessionStateMismatch: "session_state_mismatch",
24
+ OidcCodeMissing: "oidc_code_missing"
25
+ };
26
+
11
27
  // src/users/types.ts
12
28
  var LoginUserResponseTokenTypeEnum = {
13
29
  AccessToken: "ACCESS_TOKEN",
@@ -15,10 +31,86 @@ var LoginUserResponseTokenTypeEnum = {
15
31
  IdToken: "ID_TOKEN"
16
32
  };
17
33
 
18
- // src/api/utils/routes/urlMatches.ts
19
- function urlMatches(requestUrl, route15) {
34
+ // src/api/utils/routes/index.ts
35
+ var NILEDB_API_URL = process.env.NILEDB_API_URL;
36
+ var appRoutes = (prefix = "/api") => ({
37
+ SIGNIN: `${prefix}${"/auth/signin" /* SIGNIN */}`,
38
+ PROVIDERS: `${prefix}${"/auth/providers" /* PROVIDERS */}`,
39
+ SESSION: `${prefix}${"/auth/session" /* SESSION */}`,
40
+ CSRF: `${prefix}${"/auth/csrf" /* CSRF */}`,
41
+ CALLBACK: `${prefix}${"/auth/callback" /* CALLBACK */}`,
42
+ SIGNOUT: `${prefix}${"/auth/signout" /* SIGNOUT */}`,
43
+ ERROR: `${prefix}/auth/error`,
44
+ VERIFY_REQUEST: `${prefix}/auth/verify-request`,
45
+ PASSWORD_RESET: `${prefix}/auth/reset-password`,
46
+ ME: `${prefix}${"/me" /* ME */}`,
47
+ USERS: `${prefix}${"/users" /* USERS */}`,
48
+ USER_TENANTS: `${prefix}${"/users/{userId}/tenants" /* USER_TENANTS */}`,
49
+ TENANTS: `${prefix}${"/tenants" /* TENANTS */}`,
50
+ TENANT: `${prefix}${"/tenants/{tenantId}" /* TENANT */}`,
51
+ TENANT_USER: `${prefix}${"/tenants/{tenantId}/users/{userId}" /* TENANT_USER */}`,
52
+ TENANT_USERS: `${prefix}${"/tenants/{tenantId}/users" /* TENANT_USERS */}`,
53
+ SIGNUP: `${prefix}${"/signup" /* SIGNUP */}`,
54
+ LOG: `${prefix}/_log`
55
+ });
56
+ var apiRoutes = (config) => ({
57
+ ME: makeRestUrl(config, "/me"),
58
+ USERS: (qp) => makeRestUrl(config, "/users", qp),
59
+ USER: (userId) => makeRestUrl(config, `/users/${userId}`),
60
+ TENANTS: makeRestUrl(config, "/tenants"),
61
+ TENANT: (tenantId) => makeRestUrl(config, `/tenants/${tenantId}`),
62
+ SIGNUP: makeRestUrl(config, "/signup"),
63
+ TENANT_USERS: (tenantId) => makeRestUrl(config, `/tenants/${tenantId}/users`),
64
+ TENANT_USER: makeRestUrl(
65
+ config,
66
+ `/tenants/${config.tenantId}/users/${config.userId}`
67
+ ),
68
+ USER_TENANTS: (userId) => makeRestUrl(config, `/users/${userId}/tenants`)
69
+ });
70
+ var proxyRoutes = (config) => ({
71
+ SIGNIN: makeRestUrl(config, "/auth/signin" /* SIGNIN */),
72
+ PROVIDERS: makeRestUrl(config, "/auth/providers" /* PROVIDERS */),
73
+ SESSION: makeRestUrl(config, "/auth/session" /* SESSION */),
74
+ CSRF: makeRestUrl(config, "/auth/csrf" /* CSRF */),
75
+ CALLBACK: makeRestUrl(config, "/auth/callback" /* CALLBACK */),
76
+ SIGNOUT: makeRestUrl(config, "/auth/signout" /* SIGNOUT */),
77
+ ERROR: makeRestUrl(config, "/auth/error"),
78
+ VERIFY_REQUEST: makeRestUrl(config, "/auth/verify-request"),
79
+ PASSWORD_RESET: makeRestUrl(config, "/auth/reset-password")
80
+ });
81
+ function filterNullUndefined(obj) {
82
+ if (!obj) {
83
+ return void 0;
84
+ }
85
+ return Object.fromEntries(
86
+ Object.entries(obj).filter(
87
+ ([, value]) => value !== null && value !== void 0
88
+ )
89
+ );
90
+ }
91
+ function makeRestUrl(config, path, qp) {
92
+ const url = config.apiUrl || NILEDB_API_URL;
93
+ if (!url) {
94
+ throw new Error(
95
+ "An API url is required. Set it via NILEDB_API_URL. Was auto configuration run?"
96
+ );
97
+ }
98
+ const params = new URLSearchParams(
99
+ filterNullUndefined(qp)
100
+ );
101
+ const strParams = params.toString();
102
+ return `${[url, path.substring(1, path.length)].join("/")}${strParams ? `?${strParams}` : ""}`;
103
+ }
104
+ function urlMatches(requestUrl, route16) {
20
105
  const url = new URL(requestUrl);
21
- return url.pathname.startsWith(route15);
106
+ return url.pathname.startsWith(route16);
107
+ }
108
+ function isUUID(value) {
109
+ if (!value) {
110
+ return false;
111
+ }
112
+ const regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5|7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
113
+ return regex.test(value);
22
114
  }
23
115
 
24
116
  // src/utils/Logger.ts
@@ -82,7 +174,6 @@ function matchesLog(configRoutes, request2) {
82
174
 
83
175
  // src/utils/constants.ts
84
176
  var X_NILE_TENANT = "nile.tenant_id";
85
- var X_NILE_USER_ID = "nile.user_id";
86
177
  var X_NILE_ORIGIN = "nile.origin";
87
178
  var X_NILE_SECURECOOKIES = "nile.secure_cookies";
88
179
 
@@ -101,19 +192,14 @@ async function request(url, _init, config) {
101
192
  String(request2.headers.get(X_NILE_TENANT))
102
193
  );
103
194
  }
104
- if (config.api.secureCookies != null) {
105
- updatedHeaders.set(X_NILE_SECURECOOKIES, String(config.api.secureCookies));
195
+ if (config.secureCookies != null) {
196
+ updatedHeaders.set(X_NILE_SECURECOOKIES, String(config.secureCookies));
106
197
  }
107
198
  updatedHeaders.set("host", requestUrl.host);
108
- if (config.api.callbackUrl) {
109
- const cbUrl = new URL(config.api.callbackUrl);
110
- debug(
111
- `Obtained origin from config.api.callbackUrl ${config.api.callbackUrl}`
112
- );
199
+ if (config.callbackUrl) {
200
+ const cbUrl = new URL(config.callbackUrl);
201
+ debug(`Obtained origin from config.callbackUrl ${config.callbackUrl}`);
113
202
  updatedHeaders.set(X_NILE_ORIGIN, cbUrl.origin);
114
- } else if (config.api.origin) {
115
- debug(`Obtained origin from config.api.origin ${config.api.origin}`);
116
- updatedHeaders.set(X_NILE_ORIGIN, config.api.origin);
117
203
  } else {
118
204
  updatedHeaders.set(X_NILE_ORIGIN, requestUrl.origin);
119
205
  debug(`Obtained origin from request ${requestUrl.origin}`);
@@ -134,19 +220,23 @@ async function request(url, _init, config) {
134
220
  }
135
221
  params.headers = updatedHeaders;
136
222
  const fullUrl = `${url}${requestUrl.search}`;
223
+ if (config.debug) {
224
+ params.headers.set("request-id", crypto.randomUUID());
225
+ params.cache = "no-store";
226
+ }
137
227
  try {
138
- const res = await fetch(fullUrl, { ...params }).catch(
139
- (e) => {
140
- error("An error has occurred in the fetch", {
141
- message: e.message,
142
- stack: e.stack
143
- });
144
- return new Response(
145
- "An unexpected (most likely configuration) problem has occurred",
146
- { status: 500 }
147
- );
148
- }
149
- );
228
+ const res = await fetch(fullUrl, {
229
+ ...params
230
+ }).catch((e) => {
231
+ error("An error has occurred in the fetch", {
232
+ message: e.message,
233
+ stack: e.stack
234
+ });
235
+ return new Response(
236
+ "An unexpected (most likely configuration) problem has occurred",
237
+ { status: 500 }
238
+ );
239
+ });
150
240
  const loggingRes = typeof res?.clone === "function" ? res?.clone() : null;
151
241
  info(`[${params.method ?? "GET"}] ${fullUrl}`, {
152
242
  status: res?.status,
@@ -172,8 +262,8 @@ async function request(url, _init, config) {
172
262
  async function auth(req, config) {
173
263
  const { info, error } = Logger(config, "[nileauth]");
174
264
  info("checking auth");
175
- const sessionUrl = `${config.api.basePath}/auth/session`;
176
- info(`using session${sessionUrl}`);
265
+ const sessionUrl = `${config.apiUrl}/auth/session`;
266
+ info(`using session ${sessionUrl}`);
177
267
  req.headers.delete("content-length");
178
268
  const res = await request(sessionUrl, { request: req }, config);
179
269
  if (!res) {
@@ -192,1105 +282,852 @@ async function auth(req, config) {
192
282
  return void 0;
193
283
  }
194
284
  }
195
- var getCallbackUrl = (cfg) => {
196
- const { config } = cfg;
197
- if (stringCheck(process.env.NILEDB_CALLBACK_URL)) {
198
- return process.env.NILEDB_CALLBACK_URL;
285
+
286
+ // src/api/routes/me/index.ts
287
+ var key = "ME";
288
+ async function route(request2, config) {
289
+ const url = apiRoutes(config)[key];
290
+ if (request2.method === "GET") {
291
+ return await GET(url, { request: request2 }, config);
199
292
  }
200
- return config?.api?.callbackUrl;
201
- };
202
- var getSecureCookies = (cfg) => {
203
- const { config } = cfg;
204
- if (stringCheck(process.env.NILEDB_SECURECOOKIES)) {
205
- return Boolean(process.env.NILEDB_SECURECOOKIES);
293
+ if (request2.method === "PUT") {
294
+ return await PUT(url, { request: request2 }, config);
206
295
  }
207
- return config?.api?.secureCookies;
208
- };
209
- var getDatabaseId = (cfg) => {
210
- const { config, logger } = cfg;
211
- const { info } = Logger(config, "[databaseId]");
212
- if (stringCheck(config?.databaseId)) {
213
- logger && info(`${logger}[config] ${config?.databaseId}`);
214
- return String(config?.databaseId);
215
- }
216
- const dbFromEnv = stringCheck(process.env.NILEDB_ID);
217
- if (dbFromEnv) {
218
- logger && info(`${logger}[NILEDB_ID] ${dbFromEnv}`);
219
- return dbFromEnv;
220
- }
221
- const dbId = stringCheck(process.env.NILEDB_API_URL);
222
- if (dbId) {
223
- try {
224
- const pgUrl = new URL(dbId);
225
- return pgUrl.pathname.split("/")[3];
226
- } catch (e) {
296
+ if (request2.method === "DELETE") {
297
+ const session = await auth(request2, config);
298
+ if (!session) {
299
+ return new Response(null, { status: 401 });
227
300
  }
301
+ return await DELETE(url, { request: request2 }, config);
228
302
  }
229
- return null;
230
- };
231
- var getUsername = (cfg) => {
232
- const { config, logger } = cfg;
233
- const { info } = Logger(config, "[username]");
234
- if (config?.user) {
235
- logger && info(`${logger}[config] ${config.user}`);
236
- return String(config?.user);
237
- }
238
- const user = stringCheck(process.env.NILEDB_USER);
239
- if (user) {
240
- logger && info(`${logger}[NILEDB_USER] ${user}`);
241
- return user;
242
- }
243
- const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
244
- if (pg2) {
245
- try {
246
- const url = new URL(pg2);
247
- if (url.username) {
248
- return url.username;
249
- }
250
- } catch (e) {
251
- }
303
+ return new Response("method not allowed", { status: 405 });
304
+ }
305
+ function matches(configRoutes, request2) {
306
+ return urlMatches(request2.url, configRoutes[key]);
307
+ }
308
+ async function fetchMe(config, method, body) {
309
+ const clientUrl = `${config.origin}${config.routePrefix}${"/me" /* ME */}`;
310
+ const init = {
311
+ headers: config.headers,
312
+ method: method ?? "GET"
313
+ };
314
+ if (method === "PUT") {
315
+ init.body = body;
252
316
  }
253
- return void 0;
254
- };
255
- var getPassword = (cfg) => {
256
- const { config, logger } = cfg;
257
- const log = logProtector(logger);
258
- const { info } = Logger(config, "[password]");
259
- if (stringCheck(config?.password)) {
260
- log && info(`${logger}[config] ***`);
261
- return String(config?.password);
317
+ const req = new Request(clientUrl, init);
318
+ if (method === "DELETE") {
319
+ return await config.handlers.DELETE(req);
262
320
  }
263
- const pass = stringCheck(process.env.NILEDB_PASSWORD);
264
- if (pass) {
265
- logger && info(`${logger}[NILEDB_PASSWORD] ***`);
266
- return pass;
321
+ if (method === "PUT") {
322
+ return await config.handlers.PUT(req);
267
323
  }
268
- const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
269
- if (pg2) {
270
- try {
271
- const url = new URL(pg2);
272
- if (url.password) {
273
- return url.password;
324
+ return await config.handlers.GET(req);
325
+ }
326
+ async function DELETE(url, init, config) {
327
+ init.method = "DELETE";
328
+ return await request(url, init, config);
329
+ }
330
+ async function PUT(url, init, config) {
331
+ init.method = "PUT";
332
+ return await request(url, init, config);
333
+ }
334
+ async function GET(url, init, config) {
335
+ const res = await request(url, init, config);
336
+ return res;
337
+ }
338
+
339
+ // src/utils/Event/index.ts
340
+ var Eventer = class {
341
+ events = {};
342
+ publish(eventName, value) {
343
+ const callbacks = this.events[eventName];
344
+ if (callbacks) {
345
+ for (const callback of callbacks) {
346
+ callback(value);
274
347
  }
275
- } catch (e) {
276
348
  }
277
349
  }
278
- return void 0;
279
- };
280
- var getInfoBearer = (cfg) => {
281
- return `${getUsername(cfg)}:${getPassword(cfg)}`;
282
- };
283
- var getToken = (cfg) => {
284
- const { config, logger } = cfg;
285
- const { info } = Logger(config, "[token]");
286
- if (stringCheck(config?.api?.token)) {
287
- logger && info(`${logger}[config] ${config?.api?.token}`);
288
- return String(config?.api?.token);
289
- }
290
- const token = stringCheck(process.env.NILEDB_TOKEN);
291
- if (token) {
292
- logger && info(`${logger}[NILEDB_TOKEN] ${token}`);
293
- return token;
294
- }
295
- return void 0;
296
- };
297
- var getDatabaseName = (cfg) => {
298
- const { config, logger } = cfg;
299
- const { info } = Logger(config, "[databaseName]");
300
- if (stringCheck(config?.databaseName)) {
301
- logger && info(`${logger}[config] ${config?.databaseName}`);
302
- return String(config?.databaseName);
303
- }
304
- const name = stringCheck(process.env.NILEDB_NAME);
305
- if (name) {
306
- logger && info(`${logger}[NILEDB_NAME] ${name}`);
307
- return name;
350
+ subscribe(eventName, callback) {
351
+ if (!this.events[eventName]) {
352
+ this.events[eventName] = [];
353
+ }
354
+ this.events[eventName].push(callback);
308
355
  }
309
- if (process.env.NILEDB_POSTGRES_URL) {
310
- try {
311
- const pgUrl = new URL(process.env.NILEDB_POSTGRES_URL);
312
- return pgUrl.pathname.substring(1);
313
- } catch (e) {
356
+ unsubscribe(eventName, callback) {
357
+ const callbacks = this.events[eventName];
358
+ if (!callbacks) return;
359
+ const index = callbacks.indexOf(callback);
360
+ if (index !== -1) {
361
+ callbacks.splice(index, 1);
362
+ }
363
+ if (callbacks.length === 0) {
364
+ delete this.events[eventName];
314
365
  }
315
366
  }
316
- return null;
317
367
  };
318
- var getTenantId = (cfg) => {
319
- const { config, logger } = cfg;
320
- const { info } = Logger(config, "[tenantId]");
321
- if (stringCheck(config?.tenantId)) {
322
- logger && info(`${logger}[config] ${config?.tenantId}`);
323
- return String(config?.tenantId);
324
- }
325
- if (stringCheck(process.env.NILEDB_TENANT)) {
326
- logger && info(`${logger}[NILEDB_TENANT] ${process.env.NILEDB_TENANT}`);
327
- return String(process.env.NILEDB_TENANT);
328
- }
329
- return null;
368
+ var eventer = new Eventer();
369
+ var watchTenantId = (cb) => eventer.subscribe("tenantId" /* Tenant */, cb);
370
+ var watchUserId = (cb) => eventer.subscribe("userId" /* User */, cb);
371
+ var evictPool = (val) => {
372
+ eventer.publish("EvictPool" /* EvictPool */, val);
330
373
  };
331
- var getCookieKey = (cfg) => {
332
- const { config, logger } = cfg;
333
- const { info } = Logger(config, "[cookieKey]");
334
- if (stringCheck(config?.api?.cookieKey)) {
335
- logger && info(`${logger}[config] ${config?.api?.cookieKey}`);
336
- return String(config?.api?.cookieKey);
337
- }
338
- if (stringCheck(process.env.NILEDB_COOKIE_KEY)) {
339
- logger && info(`${logger}[NILEDB_COOKIE_KEY] ${process.env.NILEDB_COOKIE_KEY}`);
340
- return String(process.env.NILEDB_COOKIE_KEY);
341
- }
342
- return "token";
374
+ var watchEvictPool = (cb) => eventer.subscribe("EvictPool" /* EvictPool */, cb);
375
+ var updateHeaders = (val) => {
376
+ eventer.publish("headers" /* Headers */, val);
343
377
  };
344
- var getBasePath = (cfg) => {
345
- const { config, logger } = cfg;
346
- const { warn, info, error } = Logger(config, "[basePath]");
347
- const basePath = config?.api?.basePath;
348
- if (stringCheck(basePath)) {
349
- logger && info(`${logger}[config] ${basePath}`);
350
- return basePath;
351
- }
352
- const envUrl = stringCheck(process.env.NILEDB_API_URL);
353
- if (envUrl) {
354
- logger && info(`${logger}[NILEDB_API_URL] ${process.env.NILEDB_API_URL}`);
355
- try {
356
- const apiUrl = new URL(envUrl);
357
- return apiUrl.href;
358
- } catch (e) {
359
- if (e instanceof Error) {
360
- error(e.stack);
361
- }
378
+ var watchHeaders = (cb) => eventer.subscribe("headers" /* Headers */, cb);
379
+
380
+ // src/utils/fetch.ts
381
+ function getTokenFromCookie(headers, cookieKey) {
382
+ const cookie = headers.get("cookie")?.split("; ");
383
+ const _cookies = {};
384
+ if (cookie) {
385
+ for (const parts of cookie) {
386
+ const cookieParts = parts.split("=");
387
+ const _cookie = cookieParts.slice(1).join("=");
388
+ const name = cookieParts[0];
389
+ _cookies[name] = _cookie;
362
390
  }
363
391
  }
364
- warn("not set. Must run auto-configuration");
365
- return void 0;
366
- };
367
- var getControlPlane = (cfg) => {
368
- const { config, logger } = cfg;
369
- const { info } = Logger(config, "[basePath]");
370
- if (stringCheck(config?.configureUrl)) {
371
- logger && info(`${logger}[config] ${config?.configureUrl}`);
372
- return String(config?.configureUrl);
373
- }
374
- const autoConfigUrl = stringCheck(process.env.NILEDB_CONFIGURE);
375
- if (autoConfigUrl) {
376
- logger && info(`${logger}[NILEDB_CONFIGURE] ${process.env.NILEDB_CONFIGURE}`);
377
- if (!autoConfigUrl.startsWith("http")) {
378
- return `https://${process.env.NILEDB_CONFIGURE}`;
392
+ if (cookie) {
393
+ for (const parts of cookie) {
394
+ const cookieParts = parts.split("=");
395
+ const _cookie = cookieParts.slice(1).join("=");
396
+ const name = cookieParts[0];
397
+ _cookies[name] = _cookie;
379
398
  }
380
- return process.env.NILEDB_CONFIGURE;
381
- }
382
- logger && info(`${logger}[default] https://global.thenile.dev`);
383
- return "https://global.thenile.dev";
384
- };
385
- function getDbHost(cfg) {
386
- const { config, logger } = cfg;
387
- const { info } = Logger(config, "[db.host]");
388
- if (stringCheck(config?.db && config.db.host)) {
389
- logger && info(`${logger}[config] ${config?.db?.host}`);
390
- return String(config?.db?.host);
391
- }
392
- if (stringCheck(process.env.NILEDB_HOST)) {
393
- logger && info(`${logger}[NILEDB_HOST] ${process.env.NILEDB_HOST}`);
394
- return process.env.NILEDB_HOST;
395
399
  }
396
- const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
397
- if (pg2) {
398
- try {
399
- const pgUrl = new URL(pg2);
400
- logger && info(`${logger}[NILEDB_POSTGRES_URL] ${pgUrl.hostname}`);
401
- return pgUrl.hostname;
402
- } catch (e) {
403
- }
400
+ {
401
+ return _cookies[cookieKey];
404
402
  }
405
- logger && info(`${logger}[default] db.thenile.dev`);
406
- return "db.thenile.dev";
407
403
  }
408
- function getDbPort(cfg) {
409
- const { config, logger } = cfg;
410
- const { info } = Logger(config, "[db.port]");
411
- if (config?.db?.port && config.db.port != null) {
412
- logger && info(`${logger}[config] ${config?.db.port}`);
413
- return Number(config.db?.port);
414
- }
415
- if (stringCheck(process.env.NILEDB_PORT)) {
416
- logger && info(`${logger}[NILEDB_PORT] ${process.env.NILEDB_PORT}`);
417
- return Number(process.env.NILEDB_PORT);
404
+ function getTenantFromHttp(headers, config) {
405
+ const cookieTenant = getTokenFromCookie(headers, X_NILE_TENANT);
406
+ return cookieTenant ?? headers?.get(X_NILE_TENANT) ?? config?.tenantId;
407
+ }
408
+
409
+ // src/api/routes/users/POST.ts
410
+ async function POST(config, init) {
411
+ init.body = init.request.body;
412
+ init.method = "POST";
413
+ const yurl = new URL(init.request.url);
414
+ const tenantId = yurl.searchParams.get("tenantId");
415
+ const newTenantName = yurl.searchParams.get("newTenantName");
416
+ const tenant = tenantId ?? getTenantFromHttp(init.request.headers);
417
+ const url = apiRoutes(config).USERS({ tenantId: tenant, newTenantName });
418
+ return await request(url, init, config);
419
+ }
420
+
421
+ // src/api/routes/users/GET.ts
422
+ async function GET2(config, init, log) {
423
+ const yurl = new URL(init.request.url);
424
+ const tenantId = yurl.searchParams.get("tenantId");
425
+ const tenant = tenantId ?? getTenantFromHttp(init.request.headers);
426
+ if (!tenant) {
427
+ log("[GET] No tenant id provided.");
428
+ return new Response(null, { status: 404 });
418
429
  }
419
- const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
420
- if (pg2) {
421
- try {
422
- const pgUrl = new URL(pg2);
423
- if (pgUrl.port) {
424
- return Number(pgUrl.port);
425
- }
426
- } catch (e) {
427
- }
430
+ const url = apiRoutes(config).TENANT_USERS(tenant);
431
+ init.method = "GET";
432
+ return await request(url, init, config);
433
+ }
434
+
435
+ // src/api/routes/users/[userId]/PUT.ts
436
+ async function PUT2(config, session, init) {
437
+ if (!session) {
438
+ return new Response(null, { status: 401 });
428
439
  }
429
- logger && info(`${logger}[default] 5432`);
430
- return 5432;
440
+ init.body = init.request.body;
441
+ init.method = "PUT";
442
+ const [userId] = new URL(init.request.url).pathname.split("/").reverse();
443
+ const url = apiRoutes(config).USER(userId);
444
+ return await request(url, init, config);
431
445
  }
432
- var logProtector = (logger) => {
433
- return process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test" ? logger : null;
434
- };
435
- var stringCheck = (str) => {
436
- if (str && str !== "") {
437
- return str;
446
+
447
+ // src/api/routes/users/index.ts
448
+ var key2 = "USERS";
449
+ async function route2(request2, config) {
450
+ const { info } = Logger(
451
+ { ...config, debug: config.debug },
452
+ `[ROUTES][${key2}]`
453
+ );
454
+ const session = await auth(request2, config);
455
+ switch (request2.method) {
456
+ case "GET":
457
+ return await GET2(config, { request: request2 }, info);
458
+ case "POST":
459
+ return await POST(config, { request: request2 });
460
+ case "PUT":
461
+ return await PUT2(config, session, { request: request2 });
462
+ default:
463
+ return new Response("method not allowed", { status: 405 });
438
464
  }
439
- return;
440
- };
465
+ }
466
+ function matches2(configRoutes, request2) {
467
+ return urlMatches(request2.url, configRoutes[key2]);
468
+ }
441
469
 
442
- // src/utils/Config/index.ts
443
- var ApiConfig = class {
444
- cookieKey;
445
- basePath;
446
- routes;
447
- routePrefix;
448
- secureCookies;
449
- origin;
450
- headers;
451
- /**
452
- * The client side callback url. Defaults to nothing (so nile.origin will be it), but in the cases of x-origin, you want to set this explicitly to be sure nile-auth does the right thing
453
- * If this is set, any `callbackUrl` from the client will be ignored.
454
- */
455
- callbackUrl;
456
- #token;
457
- constructor(config, logger) {
458
- const envVarConfig = { config, logger };
459
- this.cookieKey = getCookieKey(envVarConfig);
460
- this.#token = getToken(envVarConfig);
461
- this.callbackUrl = getCallbackUrl(envVarConfig);
462
- this.secureCookies = getSecureCookies(envVarConfig);
463
- this.basePath = getBasePath(envVarConfig);
464
- if (config?.api?.headers instanceof Headers) {
465
- this.headers = config?.api?.headers;
466
- } else if (config?.api?.headers) {
467
- this.headers = new Headers(config.api.headers);
468
- }
469
- this.routes = config?.api?.routes;
470
- this.routePrefix = config?.api?.routePrefix;
471
- this.origin = config?.api?.origin;
470
+ // src/api/routes/tenants/[tenantId]/users/GET.ts
471
+ async function GET3(config, init) {
472
+ const yurl = new URL(init.request.url);
473
+ const [, tenantId] = yurl.pathname.split("/").reverse();
474
+ const url = `${apiRoutes(config).TENANT_USERS(tenantId)}`;
475
+ return await request(url, init, config);
476
+ }
477
+
478
+ // src/api/routes/tenants/[tenantId]/users/POST.ts
479
+ async function POST2(config, session, init) {
480
+ const yurl = new URL(init.request.url);
481
+ const [, tenantId] = yurl.pathname.split("/").reverse();
482
+ init.body = JSON.stringify({ email: session.email });
483
+ init.method = "POST";
484
+ const url = apiRoutes(config).TENANT_USERS(tenantId);
485
+ return await request(url, init, config);
486
+ }
487
+
488
+ // src/api/routes/tenants/[tenantId]/users/index.ts
489
+ var key3 = "TENANT_USERS";
490
+ async function route3(request2, config) {
491
+ const { info } = Logger(
492
+ { ...config, debug: config.debug },
493
+ `[ROUTES][${key3}]`
494
+ );
495
+ const session = await auth(request2, config);
496
+ if (!session) {
497
+ info("401");
498
+ return new Response(null, { status: 401 });
472
499
  }
473
- get token() {
474
- return this.#token;
500
+ const yurl = new URL(request2.url);
501
+ const [, tenantId] = yurl.pathname.split("/").reverse();
502
+ if (!tenantId) {
503
+ info("No tenant id found in path");
504
+ return new Response(null, { status: 404 });
475
505
  }
476
- set token(value) {
477
- this.#token = value;
506
+ switch (request2.method) {
507
+ case "GET":
508
+ return await GET3(config, { request: request2 });
509
+ case "POST":
510
+ return await POST2(config, session, { request: request2 });
511
+ default:
512
+ return new Response("method not allowed", { status: 405 });
478
513
  }
479
- };
480
- var Config = class {
481
- user;
482
- password;
483
- databaseId;
484
- databaseName;
485
- logger;
486
- debug;
487
- db;
488
- api;
489
- #tenantId;
490
- #userId;
491
- get tenantId() {
492
- return this.#tenantId;
514
+ }
515
+ function matches3(configRoutes, request2) {
516
+ const url = new URL(request2.url);
517
+ const [userId, possibleTenantId, tenantId] = url.pathname.split("/").reverse();
518
+ let route16 = configRoutes[key3].replace("{tenantId}", tenantId).replace("{userId}", userId);
519
+ if (userId === "users") {
520
+ route16 = configRoutes[key3].replace("{tenantId}", possibleTenantId);
493
521
  }
494
- set tenantId(value) {
495
- this.#tenantId = value;
522
+ return urlMatches(request2.url, route16);
523
+ }
524
+ async function fetchTenantUsers(config, method, payload) {
525
+ const { body, params } = {};
526
+ if (!config.tenantId) {
527
+ throw new Error(
528
+ 'Unable to fetch tenant, the tenantId context is missing. Call nile.setContext({ tenantId }), set nile.tenantId = "tenantId", or add it to the function call'
529
+ );
496
530
  }
497
- get userId() {
498
- return this.#userId;
531
+ if (!isUUID(config.tenantId) && config.logger?.warn) {
532
+ config.logger?.warn(
533
+ "nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
534
+ );
499
535
  }
500
- set userId(value) {
501
- this.#userId = value;
536
+ const q = new URLSearchParams();
537
+ if (params?.newTenantName) {
538
+ q.set("newTenantName", params.newTenantName);
502
539
  }
503
- constructor(config, logger) {
504
- const envVarConfig = { config, logger };
505
- this.user = getUsername(envVarConfig);
506
- this.logger = config?.logger;
507
- this.password = getPassword(envVarConfig);
508
- if (process.env.NODE_ENV !== "TEST") {
509
- if (!this.user) {
510
- throw new Error(
511
- "User is required. Set NILEDB_USER as an environment variable or set `user` in the config options."
512
- );
513
- }
514
- if (!this.password) {
515
- throw new Error(
516
- "Password is required. Set NILEDB_PASSWORD as an environment variable or set `password` in the config options."
517
- );
518
- }
519
- }
520
- this.databaseId = getDatabaseId(envVarConfig);
521
- this.databaseName = getDatabaseName(envVarConfig);
522
- this.#tenantId = getTenantId(envVarConfig);
523
- this.debug = Boolean(config?.debug);
524
- this.#userId = config?.userId;
525
- const { host, port, ...dbConfig } = config?.db ?? {};
526
- const configuredHost = host ?? getDbHost(envVarConfig);
527
- const configuredPort = port ?? getDbPort(envVarConfig);
528
- this.api = new ApiConfig(config, logger);
529
- this.db = {
530
- user: this.user,
531
- password: this.password,
532
- host: configuredHost,
533
- port: configuredPort,
534
- ...dbConfig
535
- };
536
- if (this.databaseName) {
537
- this.db.database = this.databaseName;
538
- }
540
+ if (params?.tenantId) {
541
+ q.set("tenantId", params.tenantId);
539
542
  }
540
- configure = async (config) => {
541
- const { info, error, debug } = Logger(config, "[init]");
542
- const envVarConfig = {
543
- config
544
- };
545
- const { host, port, ...dbConfig } = config.db ?? {};
546
- let configuredHost = host ?? getDbHost(envVarConfig);
547
- const configuredPort = port ?? getDbPort(envVarConfig);
548
- let basePath = getBasePath(envVarConfig);
549
- if (configuredHost && this.databaseName && this.databaseId && basePath) {
550
- info("Already configured, aborting fetch");
551
- this.api = new ApiConfig(config);
552
- this.db = {
553
- user: this.user,
554
- password: this.password,
555
- host: configuredHost,
556
- port: configuredPort,
557
- database: this.databaseName,
558
- ...dbConfig
559
- };
560
- const cloned = { ...this.db };
561
- cloned.password = "***";
562
- info("[config set]", { db: cloned, api: this.api });
563
- return this;
564
- } else {
565
- const msg = [];
566
- if (!configuredHost) {
567
- msg.push("Database host");
568
- }
569
- if (!this.databaseName) {
570
- msg.push("Database name");
571
- }
572
- if (!this.databaseId) {
573
- msg.push("Database id");
574
- }
575
- if (!basePath) {
576
- msg.push("API URL");
577
- }
578
- info(
579
- `[autoconfigure] ${msg.join(", ")} ${msg.length > 1 ? "are" : "is"} missing from the config. Autoconfiguration will run.`
580
- );
581
- }
582
- const cp = getControlPlane(envVarConfig);
583
- const databaseName = getDatabaseName({ config, logger: "getInfo" });
584
- const url = new URL(`${cp}/databases/configure`);
585
- if (databaseName) {
586
- url.searchParams.set("databaseName", databaseName);
587
- }
588
- info(`configuring from ${url.href}`);
589
- const res = await fetch(url, {
590
- headers: {
591
- Authorization: `Bearer ${getInfoBearer({ config })}`
592
- }
593
- }).catch(() => {
594
- error(`Unable to auto-configure. is ${url} available?`);
595
- });
596
- if (!res) {
597
- return this;
598
- }
599
- let database;
600
- const possibleError = res.clone();
601
- try {
602
- const json = await res.json();
603
- if (res.status === 404) {
604
- info("is the configured databaseName correct?");
605
- }
606
- if (json.status && json.status !== "READY") {
607
- database = { message: "Database is not ready yet" };
608
- } else {
609
- database = json;
610
- }
611
- } catch (e) {
612
- const message = await possibleError.text();
613
- debug("Unable to auto-configure");
614
- error(message);
615
- database = { message };
616
- }
617
- info("[fetched database]", database);
618
- if (process.env.NODE_ENV !== "TEST") {
619
- if ("message" in database) {
620
- if ("statusCode" in database) {
621
- error(database);
622
- throw new Error("HTTP error has occurred");
623
- } else {
624
- throw new Error(
625
- "Unable to auto-configure. Please remove NILEDB_NAME, NILEDB_API_URL, NILEDB_POSTGRES_URL, and/or NILEDB_HOST from your environment variables."
626
- );
627
- }
628
- }
629
- if (typeof database === "object") {
630
- const { apiHost, dbHost, name, id } = database;
631
- basePath = basePath || apiHost;
632
- this.databaseId = id;
633
- this.databaseName = name;
634
- const dburl = new URL(dbHost);
635
- configuredHost = dburl.hostname;
636
- }
637
- }
638
- this.api = new ApiConfig(config);
639
- this.db = {
640
- user: this.user,
641
- password: this.password,
642
- host: configuredHost,
643
- port: configuredPort,
644
- database: this.databaseName,
645
- ...dbConfig
646
- };
647
- info("[config set]", { db: this.db, api: this.api });
648
- return this;
543
+ const clientUrl = `${config.origin}${config.routePrefix}${"/tenants/{tenantId}/users" /* TENANT_USERS */.replace(
544
+ "{tenantId}",
545
+ config.tenantId
546
+ )}`;
547
+ const m = method;
548
+ const init = {
549
+ method: m,
550
+ headers: config.headers
649
551
  };
650
- };
552
+ const req = new Request(clientUrl, init);
553
+ return await config.handlers[m](req);
554
+ }
651
555
 
652
- // src/utils/Event/index.ts
653
- var Eventer = class {
654
- events = {};
655
- // Publish event and notify all subscribers
656
- publish(eventName, value) {
657
- const callbackList = this.events[eventName];
658
- if (callbackList) {
659
- for (const callback of callbackList) {
660
- callback(value);
661
- }
662
- }
663
- }
664
- // Subscribe to events
665
- subscribe(eventName, callback) {
666
- if (!this.events[eventName]) {
667
- this.events[eventName] = [];
668
- }
669
- this.events[eventName].push(callback);
556
+ // src/api/routes/tenants/GET.ts
557
+ async function GET4(config, session, init) {
558
+ let url = `${apiRoutes(config).USER_TENANTS(session.id)}`;
559
+ if (typeof session === "object" && "user" in session && session.user) {
560
+ url = `${apiRoutes(config).USER_TENANTS(session.user.id)}`;
670
561
  }
671
- // Unsubscribe from an event
672
- unsubscribe(eventName, callback) {
673
- const callbackList = this.events[eventName];
674
- if (!callbackList) {
675
- return;
676
- }
677
- const index = callbackList.indexOf(callback);
678
- if (index !== -1) {
679
- callbackList.splice(index, 1);
680
- }
681
- if (callbackList.length === 0) {
682
- delete this.events[eventName];
683
- }
562
+ const res = await request(url, init, config);
563
+ return res;
564
+ }
565
+
566
+ // src/api/routes/tenants/[tenantId]/GET.ts
567
+ async function GET5(config, init, log) {
568
+ const yurl = new URL(init.request.url);
569
+ const [tenantId] = yurl.pathname.split("/").reverse();
570
+ if (!tenantId) {
571
+ log("[GET] No tenant id provided.");
572
+ return new Response(null, { status: 404 });
684
573
  }
685
- };
686
- var eventer = new Eventer();
687
- var updateTenantId = (tenantId) => {
688
- eventer.publish("tenantId" /* Tenant */, tenantId);
689
- };
690
- var watchTenantId = (cb) => eventer.subscribe("tenantId" /* Tenant */, cb);
691
- var updateUserId = (userId) => {
692
- eventer.publish("userId" /* User */, userId);
693
- };
694
- var watchUserId = (cb) => eventer.subscribe("userId" /* User */, cb);
695
- var watchToken = (cb) => eventer.subscribe("token" /* Token */, cb);
696
- var watchEvictPool = (cb) => eventer.subscribe("EvictPool" /* EvictPool */, cb);
697
- var evictPool = (val) => {
698
- eventer.publish("EvictPool" /* EvictPool */, val);
699
- };
574
+ init.method = "GET";
575
+ const url = `${apiRoutes(config).TENANT(tenantId)}`;
576
+ return await request(url, init, config);
577
+ }
700
578
 
701
- // src/db/PoolProxy.ts
702
- function createProxyForPool(pool, config) {
703
- const { info, error } = Logger(config, "[pool]");
704
- return new Proxy(pool, {
705
- get(target, property) {
706
- if (property === "query") {
707
- if (!config.db.connectionString) {
708
- if (!config.user || !config.password) {
709
- error(
710
- "Cannot connect to the database. User and/or password are missing. Generate them at https://console.thenile.dev"
711
- );
712
- } else if (!config.db.database) {
713
- error(
714
- "Database name is missing from the config. Call `nile.init()` or set NILEDB_ID in your .env"
715
- );
716
- }
717
- }
718
- const caller = target[property];
719
- return function query(...args) {
720
- info("query", ...args);
721
- const called = caller.apply(this, args);
722
- return called;
723
- };
724
- }
725
- return target[property];
726
- }
727
- });
579
+ // src/api/routes/tenants/[tenantId]/DELETE.ts
580
+ async function DELETE2(config, init) {
581
+ const yurl = new URL(init.request.url);
582
+ const [tenantId] = yurl.pathname.split("/").reverse();
583
+ if (!tenantId) {
584
+ return new Response(null, { status: 404 });
585
+ }
586
+ init.method = "DELETE";
587
+ const url = `${apiRoutes(config).TENANT(tenantId)}`;
588
+ return await request(url, init, config);
728
589
  }
729
590
 
730
- // src/db/NileInstance.ts
731
- var NileDatabase = class {
732
- pool;
733
- tenantId;
734
- userId;
735
- id;
736
- config;
737
- timer;
738
- constructor(config, id) {
739
- const { warn, info, debug } = Logger(config, "[NileInstance]");
740
- this.id = id;
741
- const poolConfig = {
742
- min: 0,
743
- max: 10,
744
- idleTimeoutMillis: 3e4,
745
- ...config.db
746
- };
747
- const { afterCreate, ...remaining } = poolConfig;
748
- config.db = poolConfig;
749
- this.config = config;
750
- const cloned = { ...this.config.db };
751
- cloned.password = "***";
752
- debug(`Connection pool config ${JSON.stringify(cloned)}`);
753
- this.pool = createProxyForPool(new pg__default.default.Pool(remaining), this.config);
754
- if (typeof afterCreate === "function") {
755
- warn(
756
- "Providing an pool configuration will stop automatic tenant context setting."
757
- );
758
- }
759
- this.startTimeout();
760
- this.pool.on("connect", async (client) => {
761
- debug(`pool connected ${this.id}`);
762
- this.startTimeout();
763
- const afterCreate2 = makeAfterCreate(
764
- config,
765
- `${this.id}-${this.timer}`
766
- );
767
- afterCreate2(client, (err) => {
768
- const { error } = Logger(config, "[after create callback]");
769
- if (err) {
770
- clearTimeout(this.timer);
771
- error("after create failed", {
772
- message: err.message,
773
- stack: err.stack
774
- });
775
- evictPool(this.id);
776
- }
777
- });
778
- });
779
- this.pool.on("error", (err) => {
780
- clearTimeout(this.timer);
781
- info(`pool ${this.id} failed`, {
782
- message: err.message,
783
- stack: err.stack
784
- });
785
- evictPool(this.id);
786
- });
787
- this.pool.on("release", (destroy) => {
788
- if (destroy) {
789
- clearTimeout(this.timer);
790
- evictPool(this.id);
791
- debug(`destroying pool ${this.id}`);
792
- }
793
- });
794
- }
795
- startTimeout() {
796
- const { debug } = Logger(this.config, "[NileInstance]");
797
- if (this.timer) {
798
- clearTimeout(this.timer);
799
- }
800
- this.timer = setTimeout(() => {
801
- debug(
802
- `Pool reached idleTimeoutMillis. ${this.id} evicted after ${Number(this.config.db.idleTimeoutMillis) ?? 3e4}ms`
803
- );
804
- this.pool.end(() => {
805
- clearTimeout(this.timer);
806
- evictPool(this.id);
807
- });
808
- }, Number(this.config.db.idleTimeoutMillis) ?? 3e4);
591
+ // src/api/routes/tenants/[tenantId]/PUT.ts
592
+ async function PUT3(config, init) {
593
+ const yurl = new URL(init.request.url);
594
+ const [tenantId] = yurl.pathname.split("/").reverse();
595
+ if (!tenantId) {
596
+ return new Response(null, { status: 404 });
809
597
  }
810
- shutdown() {
811
- const { debug } = Logger(this.config, "[NileInstance]");
812
- debug(`attempting to shut down ${this.id}`);
813
- clearTimeout(this.timer);
814
- this.pool.end(() => {
815
- debug(`${this.id} has been shut down`);
816
- });
598
+ init.body = init.request.body;
599
+ init.method = "PUT";
600
+ const url = `${apiRoutes(config).TENANT(tenantId)}`;
601
+ return await request(url, init, config);
602
+ }
603
+
604
+ // src/api/routes/tenants/POST.ts
605
+ async function POST3(config, init) {
606
+ init.body = init.request.body;
607
+ init.method = "POST";
608
+ const url = `${apiRoutes(config).TENANTS}`;
609
+ return await request(url, init, config);
610
+ }
611
+
612
+ // src/api/routes/tenants/index.ts
613
+ var key4 = "TENANTS";
614
+ async function route4(request2, config) {
615
+ const { info } = Logger(
616
+ { ...config, debug: config.debug },
617
+ `[ROUTES][${key4}]`
618
+ );
619
+ const session = await auth(request2, config);
620
+ if (!session) {
621
+ info("401");
622
+ return new Response(null, { status: 401 });
817
623
  }
818
- };
819
- var NileInstance_default = NileDatabase;
820
- function makeAfterCreate(config, id) {
821
- const { error, warn, debug } = Logger(config, "[afterCreate]");
822
- return (conn, done) => {
823
- conn.on("error", function errorHandler(e) {
824
- error(`Connection ${id} was terminated by server`, {
825
- message: e.message,
826
- stack: e.stack
827
- });
828
- done(e, conn);
829
- });
830
- if (config.tenantId) {
831
- const query = [`SET nile.tenant_id = '${config.tenantId}'`];
832
- if (config.userId) {
833
- if (!config.tenantId) {
834
- warn("A user id cannot be set in context without a tenant id");
835
- }
836
- query.push(`SET nile.user_id = '${config.userId}'`);
624
+ const [possibleTenantId] = request2.url.split("/").reverse();
625
+ switch (request2.method) {
626
+ case "GET":
627
+ if (isUUID(possibleTenantId)) {
628
+ return await GET5(config, { request: request2 }, info);
837
629
  }
838
- conn.query(query.join(";"), function(err) {
839
- if (err) {
840
- error("query connection failed", {
841
- cause: err.cause,
842
- stack: err.stack,
843
- message: err.message,
844
- name: err.name,
845
- id
846
- });
847
- } else {
848
- if (query.length === 1) {
849
- debug(`connection context set: tenantId=${config.tenantId}`);
850
- }
851
- if (query.length === 2) {
852
- debug(
853
- `connection context set: tenantId=${config.tenantId} userId=${config.userId}`
854
- );
855
- }
856
- }
857
- done(err, conn);
858
- });
859
- }
860
- done(null, conn);
630
+ return await GET4(config, session, { request: request2 });
631
+ case "POST":
632
+ return await POST3(config, { request: request2 });
633
+ case "DELETE":
634
+ return await DELETE2(config, { request: request2 });
635
+ case "PUT":
636
+ return await PUT3(config, { request: request2 });
637
+ default:
638
+ return new Response("method not allowed", { status: 405 });
639
+ }
640
+ }
641
+ function matches4(configRoutes, request2) {
642
+ return urlMatches(request2.url, configRoutes[key4]);
643
+ }
644
+ async function fetchTenants(config, method, body) {
645
+ const clientUrl = `${config.origin}${config.routePrefix}${"/tenants" /* TENANTS */}`;
646
+ const init = {
647
+ method,
648
+ headers: config.headers
861
649
  };
650
+ {
651
+ init.body = body;
652
+ }
653
+ const req = new Request(clientUrl, init);
654
+ return await config.handlers.POST(req);
862
655
  }
863
-
864
- // src/db/DBManager.ts
865
- var DBManager = class {
866
- connections;
867
- cleared;
868
- poolWatcherFn;
869
- makeId(tenantId, userId) {
870
- if (tenantId && userId) {
871
- return `${tenantId}:${userId}`;
872
- }
873
- if (tenantId) {
874
- return `${tenantId}`;
875
- }
876
- return "base";
656
+ async function fetchTenant(config, method, body) {
657
+ if (!config.tenantId) {
658
+ throw new Error(
659
+ 'Unable to fetch tenant, the tenantId context is missing. Call nile.setContext({ tenantId }), set nile.tenantId = "tenantId", or add it to the function call'
660
+ );
877
661
  }
878
- constructor(config) {
879
- this.cleared = false;
880
- this.connections = /* @__PURE__ */ new Map();
881
- this.poolWatcherFn = this.poolWatcher(config);
882
- watchEvictPool(this.poolWatcherFn);
662
+ if (!isUUID(config.tenantId) && config.logger?.warn) {
663
+ config.logger?.warn(
664
+ "nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
665
+ );
883
666
  }
884
- poolWatcher = (config) => (id) => {
885
- const { info, warn } = Logger(config, "[DBManager]");
886
- if (id && this.connections.has(id)) {
887
- info(`Removing ${id} from db connection pool.`);
888
- const connection = this.connections.get(id);
889
- connection?.shutdown();
890
- this.connections.delete(id);
891
- } else {
892
- warn(`missed eviction of ${id}`);
893
- }
667
+ const clientUrl = `${config.origin}${config.routePrefix}${"/tenants/{tenantId}" /* TENANT */.replace("{tenantId}", config.tenantId)}`;
668
+ const m = method ?? "GET";
669
+ const init = {
670
+ method: m,
671
+ headers: config.headers
894
672
  };
895
- getConnection = (config) => {
896
- const { info } = Logger(config, "[DBManager]");
897
- const id = this.makeId(config.tenantId, config.userId);
898
- const existing = this.connections.get(id);
899
- info(`# of instances: ${this.connections.size}`);
900
- if (existing) {
901
- info(`returning existing ${id}`);
902
- existing.startTimeout();
903
- return existing.pool;
673
+ if (m === "PUT") {
674
+ init.body = body;
675
+ }
676
+ const req = new Request(clientUrl, init);
677
+ return await config.handlers[m](req);
678
+ }
679
+ async function fetchTenantsByUser(config) {
680
+ if (config.logger?.warn) {
681
+ if (!config.userId) {
682
+ config.logger?.warn(
683
+ "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."
684
+ );
685
+ } else if (!isUUID(config.userId)) {
686
+ config.logger?.warn(
687
+ "nile.userId is not a valid UUID. This may lead to unexpected behavior in your application."
688
+ );
904
689
  }
905
- const newOne = new NileInstance_default(new Config(config), id);
906
- this.connections.set(id, newOne);
907
- info(`created new ${id}`);
908
- info(`# of instances: ${this.connections.size}`);
909
- if (this.cleared) {
910
- this.cleared = false;
911
- }
912
- return newOne.pool;
913
- };
914
- clear = (config) => {
915
- const { info } = Logger(config, "[DBManager]");
916
- info(`Clearing all connections ${this.connections.size}`);
917
- this.cleared = true;
918
- this.connections.forEach((connection) => {
919
- connection.shutdown();
920
- });
921
- this.connections.clear();
922
- };
923
- };
924
-
925
- // src/api/utils/routes/makeRestUrl.ts
926
- var NILEDB_API_URL = process.env.NILEDB_API_URL;
927
- function filterNullUndefined(obj) {
928
- if (!obj) {
929
- return void 0;
930
690
  }
931
- return Object.fromEntries(
932
- Object.entries(obj).filter(
933
- ([, value]) => value !== null && value !== void 0
934
- )
935
- );
691
+ const clientUrl = `${config.origin}${config.routePrefix}${"/users/{userId}/tenants" /* USER_TENANTS */.replace(
692
+ "{userId}",
693
+ config.userId ?? "WARN_NOT_SET"
694
+ )}`;
695
+ const req = new Request(clientUrl, { headers: config.headers });
696
+ return await config.handlers.GET(req);
936
697
  }
937
- function makeRestUrl(config, path, qp) {
938
- const url = config.api.basePath || NILEDB_API_URL;
939
- if (!url) {
940
- throw new Error(
941
- "An API url is required. Set it via NILEDB_API_URL. Was auto configuration run?"
942
- );
698
+
699
+ // src/api/routes/auth/signin.ts
700
+ var key5 = "SIGNIN";
701
+ async function route5(req, config) {
702
+ let url = proxyRoutes(config)[key5];
703
+ const init = {
704
+ method: req.method,
705
+ headers: req.headers
706
+ };
707
+ if (req.method === "POST") {
708
+ const [provider] = new URL(req.url).pathname.split("/").reverse();
709
+ url = `${proxyRoutes(config)[key5]}/${provider}`;
943
710
  }
944
- const params = new URLSearchParams(
945
- filterNullUndefined(qp)
946
- );
947
- const strParams = params.toString();
948
- return `${[url, path.substring(1, path.length)].join("/")}${strParams ? `?${strParams}` : ""}`;
711
+ const passThroughUrl = new URL(req.url);
712
+ const params = new URLSearchParams(passThroughUrl.search);
713
+ url = `${url}${params.toString() !== "" ? `?${params.toString()}` : ""}`;
714
+ const res = await request(url, { ...init, request: req }, config);
715
+ return res;
716
+ }
717
+ function matches5(configRoutes, request2) {
718
+ return urlMatches(request2.url, configRoutes[key5]);
719
+ }
720
+ async function fetchSignIn(config, provider, body) {
721
+ const clientUrl = `${config.origin}${config.routePrefix}${"/auth/signin" /* SIGNIN */}/${provider}`;
722
+ const req = new Request(clientUrl, {
723
+ method: "POST",
724
+ headers: config.headers,
725
+ body
726
+ });
727
+ return await config.handlers.POST(req);
949
728
  }
950
729
 
951
- // src/api/utils/routes/apiRoutes.ts
952
- var apiRoutes = (config) => ({
953
- ME: makeRestUrl(config, "/me"),
954
- USERS: (qp) => makeRestUrl(config, "/users", qp),
955
- USER: (userId) => makeRestUrl(config, `/users/${userId}`),
956
- TENANTS: makeRestUrl(config, "/tenants"),
957
- TENANT: (tenantId) => makeRestUrl(config, `/tenants/${tenantId}`),
958
- SIGNUP: makeRestUrl(config, "/signup"),
959
- TENANT_USERS: (tenantId) => makeRestUrl(config, `/tenants/${tenantId}/users`),
960
- TENANT_USER: (tenantId, userId) => makeRestUrl(config, `/tenants/${tenantId}/users/${userId}`),
961
- USER_TENANTS: (userId) => makeRestUrl(config, `/users/${userId}/tenants`)
962
- });
963
-
964
- // src/api/routes/me/index.ts
965
- var key = "ME";
966
- async function GET(url, init, config) {
967
- const res = await request(url, init, config);
968
- return res;
730
+ // src/api/routes/auth/session.ts
731
+ async function route6(req, config) {
732
+ return request(
733
+ proxyRoutes(config).SESSION,
734
+ {
735
+ method: req.method,
736
+ request: req
737
+ },
738
+ config
739
+ );
969
740
  }
970
- async function route(request2, config) {
971
- const url = apiRoutes(config)[key];
972
- switch (request2.method) {
973
- case "GET":
974
- return await GET(url, { request: request2 }, config);
975
- default:
976
- return new Response("method not allowed", { status: 405 });
977
- }
741
+ function matches6(configRoutes, request2) {
742
+ return urlMatches(request2.url, configRoutes.SESSION);
978
743
  }
979
- function matches(configRoutes, request2) {
980
- return urlMatches(request2.url, configRoutes[key]);
744
+ async function fetchSession(config) {
745
+ const clientUrl = `${config.origin}${config.routePrefix}${"/auth/session" /* SESSION */}`;
746
+ const req = new Request(clientUrl, {
747
+ method: "GET",
748
+ headers: config.headers
749
+ });
750
+ return await config.handlers.GET(req);
981
751
  }
982
752
 
983
- // src/utils/ResponseError.ts
984
- var ResponseError = class {
985
- response;
986
- constructor(body, init) {
987
- this.response = new Response(body, init);
988
- }
989
- };
753
+ // src/api/routes/auth/providers.ts
754
+ async function route7(req, config) {
755
+ return request(
756
+ proxyRoutes(config).PROVIDERS,
757
+ {
758
+ method: req.method,
759
+ request: req
760
+ },
761
+ config
762
+ );
763
+ }
764
+ function matches7(configRoutes, request2) {
765
+ return urlMatches(request2.url, configRoutes.PROVIDERS);
766
+ }
767
+ async function fetchProviders(config) {
768
+ const clientUrl = `${config.origin}${config.routePrefix}${"/auth/providers" /* PROVIDERS */}`;
769
+ const req = new Request(clientUrl, {
770
+ method: "GET",
771
+ headers: config.headers
772
+ });
773
+ return await config.handlers.GET(req);
774
+ }
990
775
 
991
- // src/utils/fetch.ts
992
- function getTokenFromCookie(headers, cookieKey) {
993
- const cookie = headers.get("cookie")?.split("; ");
994
- const _cookies = {};
995
- if (cookie) {
996
- for (const parts of cookie) {
997
- const cookieParts = parts.split("=");
998
- const _cookie = cookieParts.slice(1).join("=");
999
- const name = cookieParts[0];
1000
- _cookies[name] = _cookie;
1001
- }
1002
- }
1003
- if (cookie) {
1004
- for (const parts of cookie) {
1005
- const cookieParts = parts.split("=");
1006
- const _cookie = cookieParts.slice(1).join("=");
1007
- const name = cookieParts[0];
1008
- _cookies[name] = _cookie;
1009
- }
1010
- }
1011
- if (cookieKey) {
1012
- return _cookies[cookieKey];
1013
- }
1014
- return null;
776
+ // src/api/routes/auth/csrf.ts
777
+ async function route8(req, config) {
778
+ return request(
779
+ proxyRoutes(config).CSRF,
780
+ {
781
+ method: req.method,
782
+ request: req
783
+ },
784
+ config
785
+ );
1015
786
  }
1016
- function getTenantFromHttp(headers, config) {
1017
- const cookieTenant = getTokenFromCookie(headers, X_NILE_TENANT);
1018
- return cookieTenant ?? headers?.get(X_NILE_TENANT) ?? config?.tenantId;
787
+ function matches8(configRoutes, request2) {
788
+ return urlMatches(request2.url, configRoutes.CSRF);
1019
789
  }
1020
- function getUserFromHttp(headers, config) {
1021
- const token = getTokenFromCookie(headers, config.api.cookieKey);
1022
- if (token) {
1023
- const jwt = jose.decodeJwt(token);
1024
- return jwt.sub;
1025
- }
1026
- return headers?.get(X_NILE_USER_ID) ?? config.userId;
1027
- }
1028
- function makeBasicHeaders(config, url, opts) {
1029
- const { warn, error } = Logger(config, "[headers]");
1030
- const headers = new Headers(opts?.headers);
1031
- const cookieKey = config.api?.cookieKey;
1032
- headers.set("content-type", "application/json; charset=utf-8");
1033
- const origin = headers.get(X_NILE_ORIGIN);
1034
- if (!origin) {
1035
- if (config.api.headers) {
1036
- const localOrigin = config.api.headers.get(X_NILE_ORIGIN);
1037
- if (localOrigin) {
1038
- headers.set(X_NILE_ORIGIN, localOrigin);
1039
- }
1040
- }
1041
- }
1042
- const cookie = headers.get("cookie");
1043
- if (!cookie) {
1044
- if (config.api.headers) {
1045
- const configCookie = config.api.headers.get("cookie");
1046
- if (configCookie) {
1047
- headers.set("cookie", configCookie);
1048
- }
1049
- } else {
1050
- if (!url.endsWith("/users")) {
1051
- error(
1052
- "Missing cookie header from request. Call nile.api.setContext(request) before making additional calls."
1053
- );
1054
- }
1055
- }
1056
- }
1057
- const authHeader = headers.get("Authorization");
1058
- if (!authHeader) {
1059
- const token = getTokenFromCookie(headers, cookieKey);
1060
- if (token) {
1061
- headers.set("Authorization", `Bearer ${token}`);
1062
- } else if (getToken({ config })) {
1063
- headers.set("Authorization", `Bearer ${getToken({ config })}`);
1064
- }
1065
- }
1066
- if (config && config.api.secureCookies != null) {
1067
- headers.set(X_NILE_SECURECOOKIES, String(config.api.secureCookies));
1068
- }
1069
- if (config && config.api.origin) {
1070
- headers.set(X_NILE_ORIGIN, config.api.origin);
1071
- } else {
1072
- warn(
1073
- "nile.origin missing from header, which defaults to secure cookies only."
1074
- );
1075
- }
1076
- return headers;
1077
- }
1078
- async function _fetch(config, path, opts) {
1079
- const { debug, error } = Logger(config, "[server]");
1080
- const url = `${config.api?.basePath}${path}`;
1081
- const headers = new Headers(opts?.headers);
1082
- const tenantId = getTenantFromHttp(headers, config);
1083
- const basicHeaders = makeBasicHeaders(config, url, opts);
1084
- updateTenantId(tenantId);
1085
- const userId = getUserFromHttp(headers, config);
1086
- updateUserId(userId);
1087
- if (url.includes("{tenantId}") && !tenantId) {
1088
- return new ResponseError("tenantId is not set for request", {
1089
- status: 400
1090
- });
1091
- }
1092
- const useableUrl = url.replace("{tenantId}", encodeURIComponent(String(tenantId))).replace("{userId}", encodeURIComponent(String(userId)));
1093
- debug(`[fetch] ${useableUrl}`);
790
+ async function fetchCsrf(config) {
791
+ const clientUrl = `${config.origin}${config.routePrefix}${"/auth/csrf" /* CSRF */}`;
792
+ const req = new Request(clientUrl, {
793
+ method: "GET",
794
+ headers: config.headers
795
+ });
796
+ return await config.handlers.GET(req);
797
+ }
798
+
799
+ // src/api/routes/auth/callback.ts
800
+ var key6 = "CALLBACK";
801
+ async function route9(req, config) {
802
+ const { error } = Logger(
803
+ { ...config, debug: config.debug },
804
+ `[ROUTES][${key6}]`
805
+ );
806
+ const [provider] = new URL(req.url).pathname.split("/").reverse();
1094
807
  try {
1095
- const response = await fetch(useableUrl, {
1096
- ...opts,
1097
- headers: basicHeaders
1098
- }).catch((e) => {
1099
- error("[fetch][response]", {
1100
- message: e.message,
1101
- stack: e.stack,
1102
- debug: "Is nile-auth running?",
1103
- cause: e.cause
1104
- });
1105
- return new Error(e);
808
+ const passThroughUrl = new URL(req.url);
809
+ const params = new URLSearchParams(passThroughUrl.search);
810
+ const url = `${proxyRoutes(config)[key6]}/${provider}${params.toString() !== "" ? `?${params.toString()}` : ""}`;
811
+ const res = await request(
812
+ url,
813
+ {
814
+ request: req,
815
+ method: req.method
816
+ },
817
+ config
818
+ ).catch((e) => {
819
+ error("an error as occurred", e);
1106
820
  });
1107
- if (response instanceof Error) {
1108
- return new ResponseError("Failed to connect to database", {
1109
- status: 400
821
+ const location = res?.headers.get("location");
822
+ if (location) {
823
+ return new Response(res?.body, {
824
+ status: 302,
825
+ headers: res?.headers
1110
826
  });
1111
827
  }
1112
- if (response && response.status >= 200 && response.status < 300) {
1113
- if (typeof response.clone === "function") {
1114
- try {
1115
- debug(
1116
- `[fetch][response][${opts?.method ?? "GET"}] ${response.status} ${useableUrl}`,
1117
- {
1118
- body: await response.clone().json()
1119
- }
1120
- );
1121
- } catch (e) {
1122
- debug(
1123
- `[fetch][response][${opts?.method ?? "GET"}] ${response.status} ${useableUrl}`,
1124
- {
1125
- body: await response.clone().text()
1126
- }
1127
- );
1128
- }
1129
- }
1130
- return response;
1131
- }
1132
- if (response?.status === 404) {
1133
- return new ResponseError("Not found", { status: 404 });
1134
- }
1135
- if (response?.status === 401) {
1136
- return new ResponseError("Unauthorized", { status: 401 });
1137
- }
1138
- if (response?.status === 405) {
1139
- return new ResponseError("Method not allowed", { status: 405 });
1140
- }
1141
- const errorHandler = typeof response?.clone === "function" ? response.clone() : null;
1142
- let msg = "";
1143
- const res = await response?.json().catch(async (e) => {
1144
- if (errorHandler) {
1145
- msg = await errorHandler.text();
1146
- if (msg) {
1147
- error(`[fetch][response][status: ${errorHandler.status}]`, {
1148
- message: msg
1149
- });
1150
- }
1151
- return e;
1152
- }
1153
- if (!msg) {
1154
- error("[fetch][response]", { e });
1155
- }
1156
- return e;
1157
- });
1158
- if (msg) {
1159
- return new ResponseError(msg, { status: errorHandler?.status });
1160
- }
1161
- if (res && "message" in res) {
1162
- const { message } = res;
1163
- error(`[fetch][response][status: ${errorHandler?.status}] ${message}`);
1164
- return new ResponseError(message, { status: 400 });
1165
- }
1166
- if (res && "errors" in res) {
1167
- const {
1168
- errors: [message]
1169
- } = res;
1170
- error(`[fetch][response] [status: ${errorHandler?.status}] ${message}`);
1171
- return new ResponseError(message, { status: 400 });
1172
- }
1173
- error(
1174
- `[fetch][response][status: ${errorHandler?.status}] UNHANDLED ERROR`,
1175
- {
1176
- response,
1177
- message: await response.text()
1178
- }
1179
- );
1180
- return new ResponseError(null, {
1181
- status: response?.status ?? 500
828
+ return new Response(res?.body, {
829
+ status: res?.status,
830
+ headers: res?.headers
1182
831
  });
1183
832
  } catch (e) {
1184
- return new ResponseError("an unexpected error has occurred", {
1185
- status: 500
1186
- });
833
+ error(e);
1187
834
  }
835
+ return new Response("An unexpected error has occurred.", { status: 400 });
1188
836
  }
1189
-
1190
- // src/api/routes/users/POST.ts
1191
- async function POST(config, init) {
1192
- init.body = init.request.body;
1193
- init.method = "POST";
1194
- const yurl = new URL(init.request.url);
1195
- const tenantId = yurl.searchParams.get("tenantId");
1196
- const newTenantName = yurl.searchParams.get("newTenantName");
1197
- const tenant = tenantId ?? getTenantFromHttp(init.request.headers);
1198
- const url = apiRoutes(config).USERS({ tenantId: tenant, newTenantName });
1199
- return await request(url, init, config);
837
+ function matches9(configRoutes, request2) {
838
+ return urlMatches(request2.url, configRoutes.CALLBACK);
1200
839
  }
1201
-
1202
- // src/api/routes/users/GET.ts
1203
- async function GET2(config, init, log) {
1204
- const yurl = new URL(init.request.url);
1205
- const tenantId = yurl.searchParams.get("tenantId");
1206
- const tenant = tenantId ?? getTenantFromHttp(init.request.headers);
1207
- if (!tenant) {
1208
- log("[GET] No tenant id provided.");
1209
- return new Response(null, { status: 404 });
1210
- }
1211
- const url = apiRoutes(config).TENANT_USERS(tenant);
1212
- init.method = "GET";
1213
- return await request(url, init, config);
840
+ async function fetchCallback(config, provider, body) {
841
+ const clientUrl = `${config.origin}${config.routePrefix}${"/auth/callback" /* CALLBACK */}/${provider}`;
842
+ const req = new Request(clientUrl, {
843
+ method: "POST",
844
+ headers: config.headers,
845
+ body
846
+ });
847
+ return await config.handlers.POST(req);
1214
848
  }
1215
849
 
1216
- // src/api/routes/users/[userId]/PUT.ts
1217
- async function PUT(config, session, init) {
1218
- if (!session) {
1219
- return new Response(null, { status: 401 });
850
+ // src/api/routes/auth/signout.ts
851
+ var key7 = "SIGNOUT";
852
+ async function route10(request2, config) {
853
+ let url = proxyRoutes(config)[key7];
854
+ const init = {
855
+ method: request2.method
856
+ };
857
+ if (request2.method === "POST") {
858
+ init.body = request2.body;
859
+ const [provider] = new URL(request2.url).pathname.split("/").reverse();
860
+ url = `${proxyRoutes(config)[key7]}${provider !== "signout" ? `/${provider}` : ""}`;
861
+ }
862
+ const res = await request(url, { ...init, request: request2 }, config);
863
+ return res;
864
+ }
865
+ function matches10(configRoutes, request2) {
866
+ return urlMatches(request2.url, configRoutes[key7]);
867
+ }
868
+ async function fetchSignOut(config, body) {
869
+ const clientUrl = `${config.origin}${config.routePrefix}${"/auth/signout" /* SIGNOUT */}`;
870
+ const req = new Request(clientUrl, {
871
+ method: "POST",
872
+ body,
873
+ headers: config.headers
874
+ });
875
+ return await config.handlers.POST(req);
876
+ }
877
+
878
+ // src/api/routes/auth/error.ts
879
+ var key8 = "ERROR";
880
+ async function route11(req, config) {
881
+ return request(
882
+ proxyRoutes(config)[key8],
883
+ {
884
+ method: req.method,
885
+ request: req
886
+ },
887
+ config
888
+ );
889
+ }
890
+ function matches11(configRoutes, request2) {
891
+ return urlMatches(request2.url, configRoutes[key8]);
892
+ }
893
+
894
+ // src/api/routes/auth/verify-request.ts
895
+ var key9 = "VERIFY_REQUEST";
896
+ async function route12(req, config) {
897
+ return request(
898
+ proxyRoutes(config)[key9],
899
+ {
900
+ method: req.method,
901
+ request: req
902
+ },
903
+ config
904
+ );
905
+ }
906
+ function matches12(configRoutes, request2) {
907
+ return urlMatches(request2.url, configRoutes[key9]);
908
+ }
909
+
910
+ // src/api/routes/auth/password-reset.ts
911
+ var key10 = "PASSWORD_RESET";
912
+ async function route13(req, config) {
913
+ const url = proxyRoutes(config)[key10];
914
+ const res = await request(
915
+ url,
916
+ {
917
+ method: req.method,
918
+ request: req
919
+ },
920
+ config
921
+ );
922
+ const location = res?.headers.get("location");
923
+ if (location) {
924
+ return new Response(res?.body, {
925
+ status: 302,
926
+ headers: res?.headers
927
+ });
1220
928
  }
929
+ return new Response(res?.body, {
930
+ status: res?.status,
931
+ headers: res?.headers
932
+ });
933
+ }
934
+ function matches13(configRoutes, request2) {
935
+ return urlMatches(request2.url, configRoutes.PASSWORD_RESET);
936
+ }
937
+
938
+ // src/api/handlers/GET.ts
939
+ function GETTER(configRoutes, config) {
940
+ const { info, warn } = Logger(config, "[GET MATCHER]");
941
+ return async function GET6(req) {
942
+ if (matches(configRoutes, req)) {
943
+ info("matches me");
944
+ return route(req, config);
945
+ }
946
+ if (matches3(configRoutes, req)) {
947
+ info("matches tenant users");
948
+ return route3(req, config);
949
+ }
950
+ if (matches2(configRoutes, req)) {
951
+ info("matches users");
952
+ return route2(req, config);
953
+ }
954
+ if (matches4(configRoutes, req)) {
955
+ info("matches tenants");
956
+ return route4(req, config);
957
+ }
958
+ if (matches6(configRoutes, req)) {
959
+ info("matches session");
960
+ return route6(req, config);
961
+ }
962
+ if (matches5(configRoutes, req)) {
963
+ info("matches signin");
964
+ return route5(req, config);
965
+ }
966
+ if (matches7(configRoutes, req)) {
967
+ info("matches providers");
968
+ return route7(req, config);
969
+ }
970
+ if (matches8(configRoutes, req)) {
971
+ info("matches csrf");
972
+ return route8(req, config);
973
+ }
974
+ if (matches13(configRoutes, req)) {
975
+ info("matches password reset");
976
+ return route13(req, config);
977
+ }
978
+ if (matches9(configRoutes, req)) {
979
+ info("matches callback");
980
+ return route9(req, config);
981
+ }
982
+ if (matches10(configRoutes, req)) {
983
+ info("matches signout");
984
+ return route10(req, config);
985
+ }
986
+ if (matches12(configRoutes, req)) {
987
+ info("matches verify-request");
988
+ return route12(req, config);
989
+ }
990
+ if (matches11(configRoutes, req)) {
991
+ info("matches error");
992
+ return route11(req, config);
993
+ }
994
+ warn(`No GET routes matched ${req.url}`);
995
+ return new Response(null, { status: 404 });
996
+ };
997
+ }
998
+
999
+ // src/api/routes/signup/POST.ts
1000
+ async function POST4(config, init) {
1221
1001
  init.body = init.request.body;
1222
- init.method = "PUT";
1223
- const [userId] = new URL(init.request.url).pathname.split("/").reverse();
1224
- const url = apiRoutes(config).USER(userId);
1002
+ init.method = "POST";
1003
+ const url = `${apiRoutes(config).SIGNUP}`;
1225
1004
  return await request(url, init, config);
1226
1005
  }
1227
1006
 
1228
- // src/api/routes/users/index.ts
1229
- var key2 = "USERS";
1230
- async function route2(request2, config) {
1231
- const { info } = Logger(
1232
- { ...config, debug: config.debug },
1233
- `[ROUTES][${key2}]`
1234
- );
1235
- const session = await auth(request2, config);
1007
+ // src/api/routes/signup/index.tsx
1008
+ var key11 = "SIGNUP";
1009
+ async function route14(request2, config) {
1236
1010
  switch (request2.method) {
1237
- case "GET":
1238
- return await GET2(config, { request: request2 }, info);
1239
1011
  case "POST":
1240
- return await POST(config, { request: request2 });
1241
- case "PUT":
1242
- return await PUT(config, session, { request: request2 });
1012
+ return await POST4(config, { request: request2 });
1243
1013
  default:
1244
1014
  return new Response("method not allowed", { status: 405 });
1245
1015
  }
1246
1016
  }
1247
- function matches2(configRoutes, request2) {
1248
- return urlMatches(request2.url, configRoutes[key2]);
1017
+ function matches14(configRoutes, request2) {
1018
+ return urlMatches(request2.url, configRoutes[key11]);
1249
1019
  }
1250
-
1251
- // src/api/routes/tenants/[tenantId]/users/GET.ts
1252
- async function GET3(config, init) {
1253
- const yurl = new URL(init.request.url);
1254
- const [, tenantId] = yurl.pathname.split("/").reverse();
1255
- const url = `${apiRoutes(config).TENANT_USERS(tenantId)}`;
1256
- return await request(url, init, config);
1020
+ async function fetchSignUp(config, payload) {
1021
+ const { body, params } = payload ?? {};
1022
+ const q = new URLSearchParams();
1023
+ if (params?.newTenantName) {
1024
+ q.set("newTenantName", params.newTenantName);
1025
+ }
1026
+ if (params?.tenantId) {
1027
+ q.set("tenantId", params.tenantId);
1028
+ }
1029
+ const clientUrl = `${config.origin}${config.routePrefix}${"/signup" /* SIGNUP */}${q.size > 0 ? `?${q}` : ""}`;
1030
+ const req = new Request(clientUrl, {
1031
+ method: "POST",
1032
+ headers: config.headers,
1033
+ body
1034
+ });
1035
+ return await config.handlers.POST(req);
1257
1036
  }
1258
1037
 
1259
- // src/api/routes/tenants/[tenantId]/users/POST.ts
1260
- async function POST2(config, session, init) {
1261
- const yurl = new URL(init.request.url);
1262
- const [, tenantId] = yurl.pathname.split("/").reverse();
1263
- init.body = JSON.stringify({ email: session.email });
1264
- init.method = "PUT";
1265
- const url = apiRoutes(config).TENANT_USERS(tenantId);
1266
- return await request(url, init, config);
1038
+ // src/api/handlers/POST.ts
1039
+ function POSTER(configRoutes, config) {
1040
+ const { info, warn, error } = Logger(config, "[POST MATCHER]");
1041
+ return async function POST5(req) {
1042
+ if (matchesLog(configRoutes, req)) {
1043
+ if (req.body) {
1044
+ try {
1045
+ const text = await req.text();
1046
+ error(text);
1047
+ return new Response(null, {
1048
+ status: 200
1049
+ });
1050
+ } catch (e) {
1051
+ }
1052
+ }
1053
+ }
1054
+ if (matches3(configRoutes, req)) {
1055
+ info("matches tenant users");
1056
+ return route3(req, config);
1057
+ }
1058
+ if (matches14(configRoutes, req)) {
1059
+ info("matches signup");
1060
+ return route14(req, config);
1061
+ }
1062
+ if (matches2(configRoutes, req)) {
1063
+ info("matches users");
1064
+ return route2(req, config);
1065
+ }
1066
+ if (matches4(configRoutes, req)) {
1067
+ info("matches tenants");
1068
+ return route4(req, config);
1069
+ }
1070
+ if (matches6(configRoutes, req)) {
1071
+ info("matches session");
1072
+ return route6(req, config);
1073
+ }
1074
+ if (matches5(configRoutes, req)) {
1075
+ info("matches signin");
1076
+ return route5(req, config);
1077
+ }
1078
+ if (matches13(configRoutes, req)) {
1079
+ info("matches password reset");
1080
+ return route13(req, config);
1081
+ }
1082
+ if (matches7(configRoutes, req)) {
1083
+ info("matches providers");
1084
+ return route7(req, config);
1085
+ }
1086
+ if (matches8(configRoutes, req)) {
1087
+ info("matches csrf");
1088
+ return route8(req, config);
1089
+ }
1090
+ if (matches9(configRoutes, req)) {
1091
+ info("matches callback");
1092
+ return route9(req, config);
1093
+ }
1094
+ if (matches10(configRoutes, req)) {
1095
+ info("matches signout");
1096
+ return route10(req, config);
1097
+ }
1098
+ warn(`No POST routes matched ${req.url}`);
1099
+ return new Response(null, { status: 404 });
1100
+ };
1267
1101
  }
1268
1102
 
1269
1103
  // src/api/routes/tenants/[tenantId]/users/[userId]/DELETE.ts
1270
- async function DELETE(config, init) {
1104
+ async function DELETE3(config, init) {
1271
1105
  const yurl = new URL(init.request.url);
1272
- const [userId, _, tenantId] = yurl.pathname.split("/").reverse();
1106
+ const [, userId, , tenantId] = yurl.pathname.split("/").reverse();
1107
+ config.tenantId = tenantId;
1108
+ config.userId = userId;
1273
1109
  init.method = "DELETE";
1274
- init.body = JSON.stringify({ email: userId });
1275
- const url = `${apiRoutes(config).TENANT_USER(tenantId, userId)}`;
1110
+ const url = `${apiRoutes(config).TENANT_USER}/link`;
1276
1111
  return await request(url, init, config);
1277
1112
  }
1278
1113
 
1279
- // src/api/routes/tenants/[tenantId]/users/PUT.ts
1280
- async function PUT2(config, init) {
1114
+ // src/api/routes/tenants/[tenantId]/users/[userId]/PUT.ts
1115
+ async function PUT4(config, init) {
1281
1116
  const yurl = new URL(init.request.url);
1282
- const [, tenantId] = yurl.pathname.split("/").reverse();
1117
+ const [, userId, , tenantId] = yurl.pathname.split("/").reverse();
1118
+ config.tenantId = tenantId;
1119
+ config.userId = userId;
1283
1120
  init.method = "PUT";
1284
- const url = `${apiRoutes(config).TENANT_USERS(tenantId)}`;
1121
+ const url = `${apiRoutes(config).TENANT_USER}/link`;
1285
1122
  return await request(url, init, config);
1286
1123
  }
1287
1124
 
1288
- // src/api/routes/tenants/[tenantId]/users/index.ts
1289
- var key3 = "TENANT_USERS";
1290
- async function route3(request2, config) {
1125
+ // src/api/routes/tenants/[tenantId]/users/[userId]/index.ts
1126
+ var key12 = "TENANT_USER";
1127
+ async function route15(request2, config) {
1291
1128
  const { info } = Logger(
1292
1129
  { ...config, debug: config.debug },
1293
- `[ROUTES][${key3}]`
1130
+ `[ROUTES][${key12}]`
1294
1131
  );
1295
1132
  const session = await auth(request2, config);
1296
1133
  if (!session) {
@@ -1298,1140 +1135,1082 @@ async function route3(request2, config) {
1298
1135
  return new Response(null, { status: 401 });
1299
1136
  }
1300
1137
  const yurl = new URL(request2.url);
1301
- const [, tenantId] = yurl.pathname.split("/").reverse();
1302
- if (!tenantId) {
1138
+ const [, userId] = yurl.pathname.split("/").reverse();
1139
+ if (!userId) {
1303
1140
  info("No tenant id found in path");
1304
1141
  return new Response(null, { status: 404 });
1305
1142
  }
1306
1143
  switch (request2.method) {
1307
- case "GET":
1308
- return await GET3(config, { request: request2 });
1309
- case "POST":
1310
- return await POST2(config, session, { request: request2 });
1311
1144
  case "PUT":
1312
- return await PUT2(config, { request: request2 });
1145
+ return await PUT4(config, { request: request2 });
1313
1146
  case "DELETE":
1314
- return await DELETE(config, { request: request2 });
1147
+ return await DELETE3(config, { request: request2 });
1315
1148
  default:
1316
1149
  return new Response("method not allowed", { status: 405 });
1317
1150
  }
1318
1151
  }
1319
- function matches3(configRoutes, request2) {
1152
+ function matches15(configRoutes, request2) {
1320
1153
  const url = new URL(request2.url);
1321
- const [userId, possibleTenantId, tenantId] = url.pathname.split("/").reverse();
1322
- let route15 = configRoutes[key3].replace("{tenantId}", tenantId).replace("{userId}", userId);
1154
+ const [, userId, possibleTenantId, tenantId] = url.pathname.split("/").reverse();
1155
+ let route16 = configRoutes[key12].replace("{tenantId}", tenantId).replace("{userId}", userId);
1323
1156
  if (userId === "users") {
1324
- route15 = configRoutes[key3].replace("{tenantId}", possibleTenantId);
1157
+ route16 = configRoutes[key12].replace("{tenantId}", possibleTenantId);
1325
1158
  }
1326
- return urlMatches(request2.url, route15);
1159
+ return urlMatches(request2.url, route16);
1327
1160
  }
1328
-
1329
- // src/api/routes/tenants/GET.ts
1330
- async function GET4(config, session, init) {
1331
- let url = `${apiRoutes(config).USER_TENANTS(session.id)}`;
1332
- if (typeof session === "object" && "user" in session && session.user) {
1333
- url = `${apiRoutes(config).USER_TENANTS(session.user.id)}`;
1161
+ async function fetchTenantUser(config, method) {
1162
+ if (!config.tenantId) {
1163
+ throw new Error(
1164
+ "The tenantId context is missing. Call nile.setContext({ tenantId })"
1165
+ );
1334
1166
  }
1335
- const res = await request(url, init, config);
1336
- return res;
1337
- }
1338
-
1339
- // src/api/routes/tenants/[tenantId]/GET.ts
1340
- async function GET5(config, init, log) {
1341
- const yurl = new URL(init.request.url);
1342
- const [tenantId] = yurl.pathname.split("/").reverse();
1343
- if (!tenantId) {
1344
- log("[GET] No tenant id provided.");
1345
- return new Response(null, { status: 404 });
1167
+ if (!config.userId) {
1168
+ throw new Error(
1169
+ "the userId context is missing. Call nile.setContext({ userId })"
1170
+ );
1346
1171
  }
1347
- init.method = "GET";
1348
- const url = `${apiRoutes(config).TENANT(tenantId)}`;
1349
- return await request(url, init, config);
1172
+ const clientUrl = `${config.origin}${config.routePrefix}${"/tenants/{tenantId}/users/{userId}" /* TENANT_USER */.replace(
1173
+ "{tenantId}",
1174
+ config.tenantId
1175
+ ).replace("{userId}", config.userId)}/link`;
1176
+ const req = new Request(clientUrl, {
1177
+ headers: config.headers,
1178
+ method
1179
+ });
1180
+ return await config.handlers[method](req);
1350
1181
  }
1351
1182
 
1352
- // src/api/routes/tenants/[tenantId]/DELETE.ts
1353
- async function DELETE2(config, init) {
1354
- const yurl = new URL(init.request.url);
1355
- const [tenantId] = yurl.pathname.split("/").reverse();
1356
- if (!tenantId) {
1183
+ // src/api/handlers/DELETE.ts
1184
+ function DELETER(configRoutes, config) {
1185
+ const { info, warn } = Logger(config, "[DELETE MATCHER]");
1186
+ return async function DELETE4(req) {
1187
+ if (matches15(configRoutes, req)) {
1188
+ info("matches tenant user");
1189
+ return route15(req, config);
1190
+ }
1191
+ if (matches3(configRoutes, req)) {
1192
+ info("matches tenant users");
1193
+ return route3(req, config);
1194
+ }
1195
+ if (matches4(configRoutes, req)) {
1196
+ info("matches tenants");
1197
+ return route4(req, config);
1198
+ }
1199
+ if (matches(configRoutes, req)) {
1200
+ info("matches me");
1201
+ return route(req, config);
1202
+ }
1203
+ warn("No DELETE routes matched");
1357
1204
  return new Response(null, { status: 404 });
1358
- }
1359
- init.method = "DELETE";
1360
- const url = `${apiRoutes(config).TENANT(tenantId)}`;
1361
- return await request(url, init, config);
1205
+ };
1362
1206
  }
1363
1207
 
1364
- // src/api/routes/tenants/[tenantId]/PUT.ts
1365
- async function PUT3(config, init) {
1366
- const yurl = new URL(init.request.url);
1367
- const [tenantId] = yurl.pathname.split("/").reverse();
1368
- if (!tenantId) {
1208
+ // src/api/handlers/PUT.ts
1209
+ function PUTER(configRoutes, config) {
1210
+ const { info, warn } = Logger(config, "[PUT MATCHER]");
1211
+ return async function PUT5(req) {
1212
+ if (matches15(configRoutes, req)) {
1213
+ info("matches tenant user");
1214
+ return route15(req, config);
1215
+ }
1216
+ if (matches3(configRoutes, req)) {
1217
+ info("matches tenant users");
1218
+ return route3(req, config);
1219
+ }
1220
+ if (matches2(configRoutes, req)) {
1221
+ info("matches users");
1222
+ return route2(req, config);
1223
+ }
1224
+ if (matches(configRoutes, req)) {
1225
+ info("matches me");
1226
+ return route(req, config);
1227
+ }
1228
+ if (matches4(configRoutes, req)) {
1229
+ info("matches tenants");
1230
+ return route4(req, config);
1231
+ }
1232
+ if (matches13(configRoutes, req)) {
1233
+ info("matches reset password");
1234
+ return route13(req, config);
1235
+ }
1236
+ warn("No PUT routes matched");
1369
1237
  return new Response(null, { status: 404 });
1370
- }
1371
- init.body = init.request.body;
1372
- init.method = "PUT";
1373
- const url = `${apiRoutes(config).TENANT(tenantId)}`;
1374
- return await request(url, init, config);
1238
+ };
1375
1239
  }
1376
1240
 
1377
- // src/api/routes/tenants/POST.ts
1378
- async function POST3(config, init) {
1379
- init.body = init.request.body;
1380
- init.method = "POST";
1381
- const url = `${apiRoutes(config).TENANTS}`;
1382
- return await request(url, init, config);
1241
+ // src/api/handlers/index.ts
1242
+ function Handlers(configRoutes, config) {
1243
+ const GET6 = GETTER(configRoutes, config);
1244
+ const POST5 = POSTER(configRoutes, config);
1245
+ const DELETE4 = DELETER(configRoutes, config);
1246
+ const PUT5 = PUTER(configRoutes, config);
1247
+ return {
1248
+ GET: GET6,
1249
+ POST: POST5,
1250
+ DELETE: DELETE4,
1251
+ PUT: PUT5
1252
+ };
1383
1253
  }
1384
-
1385
- // src/api/routes/tenants/index.ts
1386
- function isUUID(value) {
1387
- if (!value) {
1388
- return false;
1254
+ var getApiUrl = (cfg) => {
1255
+ const { config } = cfg;
1256
+ if (config?.apiUrl != null) {
1257
+ return config?.apiUrl;
1389
1258
  }
1390
- const regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5|7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
1391
- return regex.test(value);
1392
- }
1393
- var key4 = "TENANTS";
1394
- async function route4(request2, config) {
1395
- const { info } = Logger(
1396
- { ...config, debug: config.debug },
1397
- `[ROUTES][${key4}]`
1259
+ if (stringCheck(process.env.NILEDB_API_URL)) {
1260
+ return process.env.NILEDB_API_URL;
1261
+ }
1262
+ throw new Error(
1263
+ "A connection to nile-auth is required. Set NILEDB_API_URL as an environment variable."
1398
1264
  );
1399
- const session = await auth(request2, config);
1400
- if (!session) {
1401
- info("401");
1402
- return new Response(null, { status: 401 });
1265
+ };
1266
+ var getCallbackUrl = (cfg) => {
1267
+ const { config } = cfg;
1268
+ if (stringCheck(config?.callbackUrl)) {
1269
+ return config?.callbackUrl;
1403
1270
  }
1404
- const [possibleTenantId] = request2.url.split("/").reverse();
1405
- switch (request2.method) {
1406
- case "GET":
1407
- if (isUUID(possibleTenantId)) {
1408
- return await GET5(config, { request: request2 }, info);
1409
- }
1410
- return await GET4(config, session, { request: request2 });
1411
- case "POST":
1412
- return await POST3(config, { request: request2 });
1413
- case "DELETE":
1414
- return await DELETE2(config, { request: request2 });
1415
- case "PUT":
1416
- return await PUT3(config, { request: request2 });
1417
- default:
1418
- return new Response("method not allowed", { status: 405 });
1271
+ return process.env.NILEDB_CALLBACK_URL;
1272
+ };
1273
+ var getSecureCookies = (cfg) => {
1274
+ const { config } = cfg;
1275
+ if (config?.secureCookies != null) {
1276
+ return config?.secureCookies;
1419
1277
  }
1420
- }
1421
- function matches4(configRoutes, request2) {
1422
- return urlMatches(request2.url, configRoutes[key4]);
1423
- }
1424
-
1425
- // src/api/utils/routes/proxyRoutes.ts
1426
- var proxyRoutes = (config) => ({
1427
- SIGNIN: makeRestUrl(config, "/auth/signin"),
1428
- PROVIDERS: makeRestUrl(config, "/auth/providers"),
1429
- SESSION: makeRestUrl(config, "/auth/session"),
1430
- CSRF: makeRestUrl(config, "/auth/csrf"),
1431
- CALLBACK: makeRestUrl(config, "/auth/callback"),
1432
- SIGNOUT: makeRestUrl(config, "/auth/signout"),
1433
- ERROR: makeRestUrl(config, "/auth/error"),
1434
- VERIFY_REQUEST: makeRestUrl(config, "/auth/verify-request"),
1435
- PASSWORD_RESET: makeRestUrl(config, "/auth/reset-password")
1436
- });
1437
-
1438
- // src/api/routes/auth/signin.ts
1439
- var key5 = "SIGNIN";
1440
- async function route5(req, config) {
1441
- let url = proxyRoutes(config)[key5];
1442
- const init = {
1443
- method: req.method,
1444
- headers: req.headers
1445
- };
1446
- if (req.method === "POST") {
1447
- const [provider] = new URL(req.url).pathname.split("/").reverse();
1448
- url = `${proxyRoutes(config)[key5]}/${provider}`;
1278
+ if (stringCheck(process.env.NILEDB_SECURECOOKIES)) {
1279
+ return Boolean(process.env.NILEDB_SECURECOOKIES);
1449
1280
  }
1450
- const passThroughUrl = new URL(req.url);
1451
- const params = new URLSearchParams(passThroughUrl.search);
1452
- url = `${url}${params.toString() !== "" ? `?${params.toString()}` : ""}`;
1453
- const res = await request(url, { ...init, request: req }, config);
1454
- return res;
1455
- }
1456
- function matches5(configRoutes, request2) {
1457
- return urlMatches(request2.url, configRoutes[key5]);
1458
- }
1459
-
1460
- // src/api/routes/auth/session.ts
1461
- async function route6(req, config) {
1462
- return request(
1463
- proxyRoutes(config).SESSION,
1464
- {
1465
- method: req.method,
1466
- request: req
1467
- },
1468
- config
1281
+ return void 0;
1282
+ };
1283
+ var getUsername = (cfg) => {
1284
+ const { config, logger } = cfg;
1285
+ const { info } = Logger(config, "[username]");
1286
+ if (config?.user) {
1287
+ logger && info(`${logger}[config] ${config.user}`);
1288
+ return String(config?.user);
1289
+ }
1290
+ const user = stringCheck(process.env.NILEDB_USER);
1291
+ if (user) {
1292
+ logger && info(`${logger}[NILEDB_USER] ${user}`);
1293
+ return user;
1294
+ }
1295
+ const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
1296
+ if (pg2) {
1297
+ try {
1298
+ const url = new URL(pg2);
1299
+ if (url.username) {
1300
+ return url.username;
1301
+ }
1302
+ } catch (e) {
1303
+ }
1304
+ }
1305
+ throw new Error(
1306
+ "A database user is required. Set NILEDB_USER as an environment variable."
1469
1307
  );
1470
- }
1471
- function matches6(configRoutes, request2) {
1472
- return urlMatches(request2.url, configRoutes.SESSION);
1473
- }
1474
-
1475
- // src/api/routes/auth/providers.ts
1476
- async function route7(req, config) {
1477
- return request(
1478
- proxyRoutes(config).PROVIDERS,
1479
- {
1480
- method: req.method,
1481
- request: req
1482
- },
1483
- config
1308
+ };
1309
+ var getPassword = (cfg) => {
1310
+ const { config, logger } = cfg;
1311
+ const log = logProtector(logger);
1312
+ const { info } = Logger(config, "[password]");
1313
+ if (stringCheck(config?.password)) {
1314
+ log && info(`${logger}[config] ***`);
1315
+ return String(config?.password);
1316
+ }
1317
+ const pass = stringCheck(process.env.NILEDB_PASSWORD);
1318
+ if (pass) {
1319
+ logger && info(`${logger}[NILEDB_PASSWORD] ***`);
1320
+ return pass;
1321
+ }
1322
+ const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
1323
+ if (pg2) {
1324
+ try {
1325
+ const url = new URL(pg2);
1326
+ if (url.password) {
1327
+ return url.password;
1328
+ }
1329
+ } catch (e) {
1330
+ }
1331
+ }
1332
+ throw new Error(
1333
+ "A database password is required. Set NILEDB_PASSWORD as an environment variable."
1484
1334
  );
1485
- }
1486
- function matches7(configRoutes, request2) {
1487
- return urlMatches(request2.url, configRoutes.PROVIDERS);
1488
- }
1489
-
1490
- // src/api/routes/auth/csrf.ts
1491
- async function route8(req, config) {
1492
- return request(
1493
- proxyRoutes(config).CSRF,
1494
- {
1495
- method: req.method,
1496
- request: req
1497
- },
1498
- config
1499
- );
1500
- }
1501
- function matches8(configRoutes, request2) {
1502
- return urlMatches(request2.url, configRoutes.CSRF);
1503
- }
1504
-
1505
- // src/api/routes/auth/callback.ts
1506
- var key6 = "CALLBACK";
1507
- async function route9(req, config) {
1508
- const { error } = Logger(
1509
- { ...config, debug: config.debug },
1510
- `[ROUTES][${key6}]`
1335
+ };
1336
+ var getDatabaseName = (cfg) => {
1337
+ const { config, logger } = cfg;
1338
+ const { info } = Logger(config, "[databaseName]");
1339
+ if (stringCheck(config?.databaseName)) {
1340
+ logger && info(`${logger}[config] ${config?.databaseName}`);
1341
+ return String(config?.databaseName);
1342
+ }
1343
+ const name = stringCheck(process.env.NILEDB_NAME);
1344
+ if (name) {
1345
+ logger && info(`${logger}[NILEDB_NAME] ${name}`);
1346
+ return name;
1347
+ }
1348
+ if (process.env.NILEDB_POSTGRES_URL) {
1349
+ try {
1350
+ const pgUrl = new URL(process.env.NILEDB_POSTGRES_URL);
1351
+ return pgUrl.pathname.substring(1);
1352
+ } catch (e) {
1353
+ }
1354
+ }
1355
+ throw new Error(
1356
+ "A database name is required. Set NILEDB_PASSWORD as an environment variable."
1511
1357
  );
1512
- const [provider] = new URL(req.url).pathname.split("/").reverse();
1513
- try {
1514
- const passThroughUrl = new URL(req.url);
1515
- const params = new URLSearchParams(passThroughUrl.search);
1516
- const url = `${proxyRoutes(config)[key6]}/${provider}${params.toString() !== "" ? `?${params.toString()}` : ""}`;
1517
- const res = await request(
1518
- url,
1519
- {
1520
- request: req,
1521
- method: req.method
1522
- },
1523
- config
1524
- ).catch((e) => {
1525
- error("an error as occurred", e);
1526
- });
1527
- const location = res?.headers.get("location");
1528
- if (location) {
1529
- return new Response(res?.body, {
1530
- status: 302,
1531
- headers: res?.headers
1532
- });
1358
+ };
1359
+ var getTenantId = (cfg) => {
1360
+ const { config, logger } = cfg;
1361
+ const { info } = Logger(config, "[tenantId]");
1362
+ if (stringCheck(config?.tenantId)) {
1363
+ logger && info(`${logger}[config] ${config?.tenantId}`);
1364
+ return String(config?.tenantId);
1365
+ }
1366
+ if (stringCheck(process.env.NILEDB_TENANT)) {
1367
+ logger && info(`${logger}[NILEDB_TENANT] ${process.env.NILEDB_TENANT}`);
1368
+ return String(process.env.NILEDB_TENANT);
1369
+ }
1370
+ return null;
1371
+ };
1372
+ function getDbHost(cfg) {
1373
+ const { config, logger } = cfg;
1374
+ const { info } = Logger(config, "[db.host]");
1375
+ if (stringCheck(config?.db && config.db.host)) {
1376
+ logger && info(`${logger}[config] ${config?.db?.host}`);
1377
+ return String(config?.db?.host);
1378
+ }
1379
+ if (stringCheck(process.env.NILEDB_HOST)) {
1380
+ logger && info(`${logger}[NILEDB_HOST] ${process.env.NILEDB_HOST}`);
1381
+ return process.env.NILEDB_HOST;
1382
+ }
1383
+ const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
1384
+ if (pg2) {
1385
+ try {
1386
+ const pgUrl = new URL(pg2);
1387
+ logger && info(`${logger}[NILEDB_POSTGRES_URL] ${pgUrl.hostname}`);
1388
+ return pgUrl.hostname;
1389
+ } catch (e) {
1533
1390
  }
1534
- return new Response(res?.body, {
1535
- status: res?.status,
1536
- headers: res?.headers
1537
- });
1538
- } catch (e) {
1539
- error(e);
1540
1391
  }
1541
- return new Response("An unexpected error has occurred.", { status: 400 });
1542
- }
1543
- function matches9(configRoutes, request2) {
1544
- return urlMatches(request2.url, configRoutes.CALLBACK);
1392
+ logger && info(`${logger}[default] db.thenile.dev`);
1393
+ return "db.thenile.dev";
1545
1394
  }
1546
-
1547
- // src/api/routes/auth/signout.ts
1548
- var key7 = "SIGNOUT";
1549
- async function route10(request2, config) {
1550
- let url = proxyRoutes(config)[key7];
1551
- const init = {
1552
- method: request2.method
1553
- };
1554
- if (request2.method === "POST") {
1555
- init.body = request2.body;
1556
- const [provider] = new URL(request2.url).pathname.split("/").reverse();
1557
- url = `${proxyRoutes(config)[key7]}${provider !== "signout" ? `/${provider}` : ""}`;
1395
+ function getDbPort(cfg) {
1396
+ const { config, logger } = cfg;
1397
+ const { info } = Logger(config, "[db.port]");
1398
+ if (config?.db?.port && config.db.port != null) {
1399
+ logger && info(`${logger}[config] ${config?.db.port}`);
1400
+ return Number(config.db?.port);
1558
1401
  }
1559
- const res = await request(url, { ...init, request: request2 }, config);
1560
- return res;
1561
- }
1562
- function matches10(configRoutes, request2) {
1563
- return urlMatches(request2.url, configRoutes[key7]);
1564
- }
1565
-
1566
- // src/api/routes/auth/error.ts
1567
- var key8 = "ERROR";
1568
- async function route11(req, config) {
1569
- return request(
1570
- proxyRoutes(config)[key8],
1571
- {
1572
- method: req.method,
1573
- request: req
1574
- },
1575
- config
1576
- );
1577
- }
1578
- function matches11(configRoutes, request2) {
1579
- return urlMatches(request2.url, configRoutes[key8]);
1580
- }
1581
-
1582
- // src/api/routes/auth/verify-request.ts
1583
- var key9 = "VERIFY_REQUEST";
1584
- async function route12(req, config) {
1585
- return request(
1586
- proxyRoutes(config)[key9],
1587
- {
1588
- method: req.method,
1589
- request: req
1590
- },
1591
- config
1592
- );
1593
- }
1594
- function matches12(configRoutes, request2) {
1595
- return urlMatches(request2.url, configRoutes[key9]);
1596
- }
1597
-
1598
- // src/api/routes/auth/password-reset.ts
1599
- var key10 = "PASSWORD_RESET";
1600
- async function route13(req, config) {
1601
- const url = proxyRoutes(config)[key10];
1602
- const res = await request(
1603
- url,
1604
- {
1605
- method: req.method,
1606
- request: req
1607
- },
1608
- config
1609
- );
1610
- const location = res?.headers.get("location");
1611
- if (location) {
1612
- return new Response(res?.body, {
1613
- status: 302,
1614
- headers: res?.headers
1615
- });
1402
+ if (stringCheck(process.env.NILEDB_PORT)) {
1403
+ logger && info(`${logger}[NILEDB_PORT] ${process.env.NILEDB_PORT}`);
1404
+ return Number(process.env.NILEDB_PORT);
1616
1405
  }
1617
- return new Response(res?.body, {
1618
- status: res?.status,
1619
- headers: res?.headers
1620
- });
1621
- }
1622
- function matches13(configRoutes, request2) {
1623
- return urlMatches(request2.url, configRoutes.PASSWORD_RESET);
1406
+ const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
1407
+ if (pg2) {
1408
+ try {
1409
+ const pgUrl = new URL(pg2);
1410
+ if (pgUrl.port) {
1411
+ return Number(pgUrl.port);
1412
+ }
1413
+ } catch (e) {
1414
+ }
1415
+ }
1416
+ logger && info(`${logger}[default] 5432`);
1417
+ return 5432;
1624
1418
  }
1419
+ var logProtector = (logger) => {
1420
+ return process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test" ? logger : null;
1421
+ };
1422
+ var stringCheck = (str) => {
1423
+ if (str && str !== "") {
1424
+ return str;
1425
+ }
1426
+ return;
1427
+ };
1625
1428
 
1626
- // src/api/handlers/GET.ts
1627
- function GETTER(configRoutes, config) {
1628
- const { info, warn } = Logger(config, "[GET MATCHER]");
1629
- return async function GET6(req) {
1630
- if (matches(configRoutes, req)) {
1631
- info("matches me");
1632
- return route(req, config);
1633
- }
1634
- if (matches3(configRoutes, req)) {
1635
- info("matches tenant users");
1636
- return route3(req, config);
1637
- }
1638
- if (matches2(configRoutes, req)) {
1639
- info("matches users");
1640
- return route2(req, config);
1641
- }
1642
- if (matches4(configRoutes, req)) {
1643
- info("matches tenants");
1644
- return route4(req, config);
1645
- }
1646
- if (matches6(configRoutes, req)) {
1647
- info("matches session");
1648
- return route6(req, config);
1649
- }
1650
- if (matches5(configRoutes, req)) {
1651
- info("matches signin");
1652
- return route5(req, config);
1653
- }
1654
- if (matches7(configRoutes, req)) {
1655
- info("matches providers");
1656
- return route7(req, config);
1657
- }
1658
- if (matches8(configRoutes, req)) {
1659
- info("matches csrf");
1660
- return route8(req, config);
1661
- }
1662
- if (matches13(configRoutes, req)) {
1663
- info("matches password reset");
1664
- return route13(req, config);
1665
- }
1666
- if (matches9(configRoutes, req)) {
1667
- info("matches callback");
1668
- return route9(req, config);
1669
- }
1670
- if (matches10(configRoutes, req)) {
1671
- info("matches signout");
1672
- return route10(req, config);
1673
- }
1674
- if (matches12(configRoutes, req)) {
1675
- info("matches verify-request");
1676
- return route12(req, config);
1429
+ // src/utils/Config/index.ts
1430
+ var Config = class {
1431
+ routes;
1432
+ // handlersWithContext;
1433
+ handlers;
1434
+ paths;
1435
+ logger;
1436
+ /**
1437
+ * Stores the set tenant id from Server for use in sub classes
1438
+ */
1439
+ tenantId;
1440
+ /**
1441
+ * Stores the set user id from Server for use in sub classes
1442
+ */
1443
+ userId;
1444
+ /**
1445
+ * Stores the headers to be used in `fetch` calls
1446
+ */
1447
+ headers;
1448
+ /**
1449
+ * The nile-auth url
1450
+ */
1451
+ apiUrl;
1452
+ origin;
1453
+ debug;
1454
+ /**
1455
+ * To use secure cookies or not in the fetch
1456
+ */
1457
+ secureCookies;
1458
+ callbackUrl;
1459
+ /**
1460
+ * change the starting route
1461
+ */
1462
+ routePrefix;
1463
+ db;
1464
+ // api: ApiConfig;
1465
+ constructor(config, logger) {
1466
+ const envVarConfig = { config, logger };
1467
+ this.routePrefix = config?.routePrefix ?? "/api";
1468
+ this.secureCookies = getSecureCookies(envVarConfig);
1469
+ this.callbackUrl = getCallbackUrl(envVarConfig);
1470
+ this.debug = config?.debug;
1471
+ this.origin = config?.origin ?? "http://localhost:3000";
1472
+ this.apiUrl = getApiUrl(envVarConfig);
1473
+ const user = getUsername(envVarConfig);
1474
+ const password = getPassword(envVarConfig);
1475
+ const databaseName = getDatabaseName(envVarConfig);
1476
+ const { host, port, ...dbConfig } = config?.db ?? {};
1477
+ const configuredHost = host ?? getDbHost(envVarConfig);
1478
+ const configuredPort = port ?? getDbPort(envVarConfig);
1479
+ this.db = {
1480
+ user,
1481
+ password,
1482
+ host: configuredHost,
1483
+ port: configuredPort,
1484
+ ...dbConfig
1485
+ };
1486
+ if (databaseName) {
1487
+ this.db.database = databaseName;
1677
1488
  }
1678
- if (matches11(configRoutes, req)) {
1679
- info("matches error");
1680
- return route11(req, config);
1489
+ if (config?.headers) {
1490
+ this.headers = config?.headers;
1491
+ } else {
1492
+ this.headers = new Headers();
1681
1493
  }
1682
- warn("No GET routes matched");
1683
- return new Response(null, { status: 404 });
1684
- };
1685
- }
1686
-
1687
- // src/api/routes/signup/POST.ts
1688
- async function POST4(config, init) {
1689
- init.body = init.request.body;
1690
- init.method = "POST";
1691
- const url = `${apiRoutes(config).SIGNUP}`;
1692
- return await request(url, init, config);
1693
- }
1694
-
1695
- // src/api/routes/signup/index.tsx
1696
- var key11 = "SIGNUP";
1697
- async function route14(request2, config) {
1698
- switch (request2.method) {
1699
- case "POST":
1700
- return await POST4(config, { request: request2 });
1701
- default:
1702
- return new Response("method not allowed", { status: 405 });
1494
+ this.routes = {
1495
+ ...appRoutes(config?.routePrefix),
1496
+ ...config?.routes
1497
+ };
1498
+ this.handlers = Handlers(this.routes, this);
1499
+ this.paths = {
1500
+ get: [
1501
+ this.routes.ME,
1502
+ this.routes.TENANT_USERS,
1503
+ this.routes.TENANTS,
1504
+ this.routes.TENANT,
1505
+ this.routes.SESSION,
1506
+ this.routes.SIGNIN,
1507
+ this.routes.PROVIDERS,
1508
+ this.routes.CSRF,
1509
+ this.routes.PASSWORD_RESET,
1510
+ this.routes.CALLBACK,
1511
+ this.routes.SIGNOUT,
1512
+ this.routes.VERIFY_REQUEST,
1513
+ this.routes.ERROR
1514
+ ],
1515
+ post: [
1516
+ this.routes.TENANT_USERS,
1517
+ this.routes.SIGNUP,
1518
+ this.routes.USERS,
1519
+ this.routes.TENANTS,
1520
+ this.routes.SESSION,
1521
+ `${this.routes.SIGNIN}/{provider}`,
1522
+ this.routes.PASSWORD_RESET,
1523
+ this.routes.PROVIDERS,
1524
+ this.routes.CSRF,
1525
+ `${this.routes.CALLBACK}/{provider}`,
1526
+ this.routes.SIGNOUT
1527
+ ],
1528
+ put: [
1529
+ this.routes.TENANT_USERS,
1530
+ this.routes.USERS,
1531
+ this.routes.TENANT,
1532
+ this.routes.PASSWORD_RESET
1533
+ ],
1534
+ delete: [this.routes.TENANT_USER, this.routes.TENANT]
1535
+ };
1536
+ this.tenantId = config?.tenantId;
1537
+ this.userId = config?.userId;
1538
+ this.logger = config?.logger;
1703
1539
  }
1704
- }
1705
- function matches14(configRoutes, request2) {
1706
- return urlMatches(request2.url, configRoutes[key11]);
1707
- }
1540
+ };
1708
1541
 
1709
- // src/api/handlers/POST.ts
1710
- function POSTER(configRoutes, config) {
1711
- const { info, warn, error } = Logger(config, "[POST MATCHER]");
1712
- return async function POST5(req) {
1713
- if (matchesLog(configRoutes, req)) {
1714
- if (req.body) {
1715
- try {
1716
- const text = await req.text();
1717
- error(text);
1718
- return new Response(null, {
1719
- status: 200
1720
- });
1721
- } catch (e) {
1542
+ // src/db/PoolProxy.ts
1543
+ function createProxyForPool(pool, config) {
1544
+ const { info, error } = Logger(config, "[pool]");
1545
+ return new Proxy(pool, {
1546
+ get(target, property) {
1547
+ if (property === "query") {
1548
+ if (!config.db.connectionString) {
1549
+ if (!config.db.user || !config.db.password) {
1550
+ error(
1551
+ "Cannot connect to the database. User and/or password are missing. Generate them at https://console.thenile.dev"
1552
+ );
1553
+ } else if (!config.db.database) {
1554
+ error(
1555
+ "Unable to obtain database name. Is process.env.NILEDB_POSTGRES_URL set?"
1556
+ );
1557
+ }
1722
1558
  }
1559
+ const caller = target[property];
1560
+ return function query(...args) {
1561
+ info("query", ...args);
1562
+ const called = caller.apply(this, args);
1563
+ return called;
1564
+ };
1723
1565
  }
1566
+ return target[property];
1724
1567
  }
1725
- if (matches3(configRoutes, req)) {
1726
- info("matches tenant users");
1727
- return route3(req, config);
1728
- }
1729
- if (matches14(configRoutes, req)) {
1730
- info("matches signup");
1731
- return route14(req, config);
1732
- }
1733
- if (matches2(configRoutes, req)) {
1734
- info("matches users");
1735
- return route2(req, config);
1736
- }
1737
- if (matches4(configRoutes, req)) {
1738
- info("matches tenants");
1739
- return route4(req, config);
1740
- }
1741
- if (matches6(configRoutes, req)) {
1742
- info("matches session");
1743
- return route6(req, config);
1744
- }
1745
- if (matches5(configRoutes, req)) {
1746
- info("matches signin");
1747
- return route5(req, config);
1748
- }
1749
- if (matches13(configRoutes, req)) {
1750
- info("matches password reset");
1751
- return route13(req, config);
1752
- }
1753
- if (matches7(configRoutes, req)) {
1754
- info("matches providers");
1755
- return route7(req, config);
1756
- }
1757
- if (matches8(configRoutes, req)) {
1758
- info("matches csrf");
1759
- return route8(req, config);
1760
- }
1761
- if (matches9(configRoutes, req)) {
1762
- info("matches callback");
1763
- return route9(req, config);
1764
- }
1765
- if (matches10(configRoutes, req)) {
1766
- info("matches signout");
1767
- return route10(req, config);
1768
- }
1769
- warn("No POST routes matched");
1770
- return new Response(null, { status: 404 });
1771
- };
1568
+ });
1772
1569
  }
1773
1570
 
1774
- // src/api/handlers/DELETE.ts
1775
- function DELETER(configRoutes, config) {
1776
- const { info, warn } = Logger(config, "[DELETE MATCHER]");
1777
- return async function DELETE3(req) {
1778
- if (matches3(configRoutes, req)) {
1779
- info("matches tenant users");
1780
- return route3(req, config);
1571
+ // src/db/NileInstance.ts
1572
+ var NileDatabase = class {
1573
+ pool;
1574
+ tenantId;
1575
+ userId;
1576
+ id;
1577
+ config;
1578
+ timer;
1579
+ constructor(config, id) {
1580
+ const { warn, info, debug } = Logger(config, "[NileInstance]");
1581
+ this.id = id;
1582
+ const poolConfig = {
1583
+ min: 0,
1584
+ max: 10,
1585
+ idleTimeoutMillis: 3e4,
1586
+ ...config.db
1587
+ };
1588
+ const { afterCreate, ...remaining } = poolConfig;
1589
+ config.db = poolConfig;
1590
+ this.config = config;
1591
+ const cloned = { ...this.config.db };
1592
+ cloned.password = "***";
1593
+ debug(`Connection pool config ${JSON.stringify(cloned)}`);
1594
+ this.pool = createProxyForPool(new pg__default.default.Pool(remaining), this.config);
1595
+ if (typeof afterCreate === "function") {
1596
+ warn(
1597
+ "Providing an pool configuration will stop automatic tenant context setting."
1598
+ );
1781
1599
  }
1782
- if (matches4(configRoutes, req)) {
1783
- info("matches tenants");
1784
- return route4(req, config);
1600
+ this.startTimeout();
1601
+ this.pool.on("connect", async (client) => {
1602
+ debug(`pool connected ${this.id}`);
1603
+ this.startTimeout();
1604
+ const afterCreate2 = makeAfterCreate(
1605
+ config,
1606
+ `${this.id}-${this.timer}`
1607
+ );
1608
+ afterCreate2(client, (err) => {
1609
+ const { error } = Logger(config, "[after create callback]");
1610
+ if (err) {
1611
+ clearTimeout(this.timer);
1612
+ error("after create failed", {
1613
+ message: err.message,
1614
+ stack: err.stack
1615
+ });
1616
+ evictPool(this.id);
1617
+ }
1618
+ });
1619
+ });
1620
+ this.pool.on("error", (err) => {
1621
+ clearTimeout(this.timer);
1622
+ info(`pool ${this.id} failed`, {
1623
+ message: err.message,
1624
+ stack: err.stack
1625
+ });
1626
+ evictPool(this.id);
1627
+ });
1628
+ this.pool.on("release", (destroy) => {
1629
+ if (destroy) {
1630
+ clearTimeout(this.timer);
1631
+ evictPool(this.id);
1632
+ debug(`destroying pool ${this.id}`);
1633
+ }
1634
+ });
1635
+ }
1636
+ startTimeout() {
1637
+ const { debug } = Logger(this.config, "[NileInstance]");
1638
+ if (this.timer) {
1639
+ clearTimeout(this.timer);
1640
+ }
1641
+ this.timer = setTimeout(() => {
1642
+ debug(
1643
+ `Pool reached idleTimeoutMillis. ${this.id} evicted after ${Number(this.config.db.idleTimeoutMillis) ?? 3e4}ms`
1644
+ );
1645
+ this.pool.end(() => {
1646
+ clearTimeout(this.timer);
1647
+ evictPool(this.id);
1648
+ });
1649
+ }, Number(this.config.db.idleTimeoutMillis) ?? 3e4);
1650
+ }
1651
+ shutdown() {
1652
+ const { debug } = Logger(this.config, "[NileInstance]");
1653
+ debug(`attempting to shut down ${this.id}`);
1654
+ clearTimeout(this.timer);
1655
+ this.pool.end(() => {
1656
+ debug(`${this.id} has been shut down`);
1657
+ });
1658
+ }
1659
+ };
1660
+ var NileInstance_default = NileDatabase;
1661
+ function makeAfterCreate(config, id) {
1662
+ const { error, warn, debug } = Logger(config, "[afterCreate]");
1663
+ return (conn, done) => {
1664
+ conn.on("error", function errorHandler(e) {
1665
+ error(`Connection ${id} was terminated by server`, {
1666
+ message: e.message,
1667
+ stack: e.stack
1668
+ });
1669
+ done(e, conn);
1670
+ });
1671
+ if (config.tenantId) {
1672
+ const query = [`SET nile.tenant_id = '${config.tenantId}'`];
1673
+ if (config.userId) {
1674
+ if (!config.tenantId) {
1675
+ warn("A user id cannot be set in context without a tenant id");
1676
+ }
1677
+ query.push(`SET nile.user_id = '${config.userId}'`);
1678
+ }
1679
+ conn.query(query.join(";"), function(err) {
1680
+ if (err) {
1681
+ error("query connection failed", {
1682
+ cause: err.cause,
1683
+ stack: err.stack,
1684
+ message: err.message,
1685
+ name: err.name,
1686
+ id
1687
+ });
1688
+ } else {
1689
+ if (query.length === 1) {
1690
+ debug(`connection context set: tenantId=${config.tenantId}`);
1691
+ }
1692
+ if (query.length === 2) {
1693
+ debug(
1694
+ `connection context set: tenantId=${config.tenantId} userId=${config.userId}`
1695
+ );
1696
+ }
1697
+ }
1698
+ done(err, conn);
1699
+ });
1785
1700
  }
1786
- warn("No DELETE routes matched");
1787
- return new Response(null, { status: 404 });
1701
+ done(null, conn);
1788
1702
  };
1789
1703
  }
1790
1704
 
1791
- // src/api/handlers/PUT.ts
1792
- function PUTER(configRoutes, config) {
1793
- const { info, warn } = Logger(config, "[PUT MATCHER]");
1794
- return async function PUT4(req) {
1795
- if (matches3(configRoutes, req)) {
1796
- info("matches tenant users");
1797
- return route3(req, config);
1705
+ // src/db/DBManager.ts
1706
+ var DBManager = class {
1707
+ connections;
1708
+ cleared;
1709
+ poolWatcherFn;
1710
+ makeId(tenantId, userId) {
1711
+ if (tenantId && userId) {
1712
+ return `${tenantId}:${userId}`;
1798
1713
  }
1799
- if (matches2(configRoutes, req)) {
1800
- info("matches users");
1801
- return route2(req, config);
1714
+ if (tenantId) {
1715
+ return `${tenantId}`;
1802
1716
  }
1803
- if (matches4(configRoutes, req)) {
1804
- info("matches tenants");
1805
- return route4(req, config);
1717
+ return "base";
1718
+ }
1719
+ constructor(config) {
1720
+ this.cleared = false;
1721
+ this.connections = /* @__PURE__ */ new Map();
1722
+ this.poolWatcherFn = this.poolWatcher(config);
1723
+ watchEvictPool(this.poolWatcherFn);
1724
+ }
1725
+ poolWatcher = (config) => (id) => {
1726
+ const { info, warn } = Logger(config, "[DBManager]");
1727
+ if (id && this.connections.has(id)) {
1728
+ info(`Removing ${id} from db connection pool.`);
1729
+ const connection = this.connections.get(id);
1730
+ connection?.shutdown();
1731
+ this.connections.delete(id);
1732
+ } else {
1733
+ warn(`missed eviction of ${id}`);
1806
1734
  }
1807
- if (matches13(configRoutes, req)) {
1808
- info("matches reset password");
1809
- return route13(req, config);
1735
+ };
1736
+ getConnection = (config) => {
1737
+ const { info } = Logger(config, "[DBManager]");
1738
+ const id = this.makeId(config.tenantId, config.userId);
1739
+ const existing = this.connections.get(id);
1740
+ info(`# of instances: ${this.connections.size}`);
1741
+ if (existing) {
1742
+ info(`returning existing ${id}`);
1743
+ existing.startTimeout();
1744
+ return existing.pool;
1810
1745
  }
1811
- warn("No PUT routes matched");
1812
- return new Response(null, { status: 404 });
1746
+ const newOne = new NileInstance_default(new Config(config), id);
1747
+ this.connections.set(id, newOne);
1748
+ info(`created new ${id}`);
1749
+ info(`# of instances: ${this.connections.size}`);
1750
+ if (this.cleared) {
1751
+ this.cleared = false;
1752
+ }
1753
+ return newOne.pool;
1813
1754
  };
1814
- }
1815
-
1816
- // src/api/handlers/index.ts
1817
- function Handlers(configRoutes, config) {
1818
- const GET6 = GETTER(configRoutes, config);
1819
- const POST5 = POSTER(configRoutes, config);
1820
- const DELETE3 = DELETER(configRoutes, config);
1821
- const PUT4 = PUTER(configRoutes, config);
1822
- return {
1823
- GET: GET6,
1824
- POST: POST5,
1825
- DELETE: DELETE3,
1826
- PUT: PUT4
1755
+ clear = (config) => {
1756
+ const { info } = Logger(config, "[DBManager]");
1757
+ info(`Clearing all connections ${this.connections.size}`);
1758
+ this.cleared = true;
1759
+ this.connections.forEach((connection) => {
1760
+ connection.shutdown();
1761
+ });
1762
+ this.connections.clear();
1827
1763
  };
1828
- }
1764
+ };
1829
1765
 
1830
- // src/api/utils/routes/defaultRoutes.ts
1831
- var appRoutes = (prefix = "/api") => ({
1832
- SIGNIN: `${prefix}/auth/signin`,
1833
- PROVIDERS: `${prefix}/auth/providers`,
1834
- SESSION: `${prefix}/auth/session`,
1835
- CSRF: `${prefix}/auth/csrf`,
1836
- CALLBACK: `${prefix}/auth/callback`,
1837
- SIGNOUT: `${prefix}/auth/signout`,
1838
- ERROR: `${prefix}/auth/error`,
1839
- VERIFY_REQUEST: `${prefix}/auth/verify-request`,
1840
- PASSWORD_RESET: `${prefix}/auth/reset-password`,
1841
- ME: `${prefix}/me`,
1842
- USERS: `${prefix}/users`,
1843
- TENANTS: `${prefix}/tenants`,
1844
- TENANT: `${prefix}/tenants/{tenantId}`,
1845
- TENANT_USER: `${prefix}/tenants/{tenantId}/users/{userId}`,
1846
- TENANT_USERS: `${prefix}/tenants/{tenantId}/users`,
1847
- SIGNUP: `${prefix}/signup`,
1848
- LOG: `${prefix}/_log`
1849
- });
1766
+ // src/users/index.ts
1767
+ var Users = class {
1768
+ #config;
1769
+ constructor(config) {
1770
+ this.#config = config;
1771
+ }
1772
+ async updateSelf(req, rawResponse) {
1773
+ const res = await fetchMe(this.#config, "PUT", JSON.stringify(req));
1774
+ if (rawResponse) {
1775
+ return res;
1776
+ }
1777
+ try {
1778
+ return await res?.clone().json();
1779
+ } catch {
1780
+ return res;
1781
+ }
1782
+ }
1783
+ async removeSelf() {
1784
+ const me = await this.getSelf();
1785
+ if ("id" in me) {
1786
+ this.#config.userId = me.id;
1787
+ }
1788
+ const res = await fetchMe(this.#config, "DELETE");
1789
+ updateHeaders(new Headers());
1790
+ return res;
1791
+ }
1792
+ async getSelf(rawResponse) {
1793
+ const res = await fetchMe(this.#config);
1794
+ if (rawResponse) {
1795
+ return res;
1796
+ }
1797
+ try {
1798
+ return await res?.clone().json();
1799
+ } catch {
1800
+ return res;
1801
+ }
1802
+ }
1803
+ };
1850
1804
 
1851
- // src/utils/Requester/index.ts
1852
- var Requester = class extends Config {
1805
+ // src/tenants/index.ts
1806
+ var Tenants = class {
1807
+ #logger;
1808
+ #config;
1853
1809
  constructor(config) {
1854
- super(config);
1810
+ this.#logger = Logger(config, "[tenants]");
1811
+ this.#config = config;
1855
1812
  }
1856
- async rawRequest(method, url, init, body) {
1857
- const _init = {
1858
- body,
1859
- method,
1860
- ...init
1861
- };
1862
- const res = await _fetch(this, url, _init);
1863
- if (res instanceof ResponseError) {
1864
- return res.response;
1813
+ async create(req, rawResponse) {
1814
+ let res;
1815
+ if (typeof req === "string") {
1816
+ res = await fetchTenants(
1817
+ this.#config,
1818
+ "POST",
1819
+ JSON.stringify({ name: req })
1820
+ );
1821
+ } else if (typeof req === "object" && ("name" in req || "id" in req)) {
1822
+ res = await fetchTenants(this.#config, "POST", JSON.stringify(req));
1823
+ }
1824
+ if (rawResponse) {
1825
+ return res;
1826
+ }
1827
+ try {
1828
+ return await res?.clone().json();
1829
+ } catch {
1830
+ return res;
1831
+ }
1832
+ }
1833
+ async delete(req) {
1834
+ if (typeof req === "string") {
1835
+ this.#config.tenantId = req;
1865
1836
  }
1837
+ if (typeof req === "object" && "id" in req) {
1838
+ this.#config.tenantId = req.id;
1839
+ }
1840
+ const res = await fetchTenant(this.#config, "DELETE");
1866
1841
  return res;
1867
1842
  }
1868
- /**
1869
- * three options here
1870
- * 1) pass in headers for a server side request
1871
- * 2) pass in the payload that matches the api
1872
- * 3) pass in the request object sent by a browser
1873
- * @param method
1874
- * @param url
1875
- * @param req
1876
- * @param init
1877
- * @returns
1878
- */
1879
- async request(method, url, req, init) {
1880
- const headers = new Headers(init ? init?.headers : {});
1881
- if (req instanceof Headers) {
1882
- const tenantId = req.get(X_NILE_TENANT);
1883
- const cookie = req.get("cookie");
1884
- if (tenantId) {
1885
- headers.set(X_NILE_TENANT, tenantId);
1886
- }
1887
- if (cookie) {
1888
- headers.set("cookie", cookie);
1889
- }
1890
- } else if (req instanceof Request) {
1891
- const _headers = new Headers(req?.headers);
1892
- const tenantId = _headers.get(X_NILE_TENANT);
1893
- const cookie = _headers.get("cookie");
1894
- if (tenantId) {
1895
- headers.set(X_NILE_TENANT, tenantId);
1896
- }
1897
- if (cookie) {
1898
- headers.set("cookie", cookie);
1899
- }
1843
+ async get(req, rawResponse) {
1844
+ if (typeof req === "string") {
1845
+ this.#config.tenantId = req;
1846
+ } else if (typeof req === "object" && "id" in req) {
1847
+ this.#config.tenantId = req.id;
1848
+ }
1849
+ const res = await fetchTenant(this.#config, "GET");
1850
+ if (rawResponse === true || req === true) {
1851
+ return res;
1852
+ }
1853
+ try {
1854
+ return await res?.clone().json();
1855
+ } catch {
1856
+ return res;
1900
1857
  }
1901
- let body = JSON.stringify(req);
1902
- if (method === "GET") {
1903
- body = void 0;
1904
- } else if (req instanceof Request) {
1905
- body = await new Response(req.body).text();
1906
- } else if (
1907
- // is just headers for a GET request
1908
- req instanceof Headers || JSON.stringify(req) === "{}" || req && typeof req === "object" && Object.values(req).length === 0
1909
- ) {
1910
- body = void 0;
1911
- }
1912
- const _init = {
1913
- ...init,
1914
- headers
1915
- };
1916
- return await this.rawRequest(method, url, _init, body);
1917
1858
  }
1918
- async post(req, url, init) {
1919
- const response = await this.request("POST", url, req, init);
1920
- if (response && response.status >= 200 && response.status < 300) {
1921
- const cloned = response.clone();
1922
- try {
1923
- return await cloned.json();
1924
- } catch (e) {
1859
+ async update(req, rawResponse) {
1860
+ let res;
1861
+ if (typeof req === "object" && ("name" in req || "id" in req)) {
1862
+ const { id, ...remaining } = req;
1863
+ if (id) {
1864
+ this.#config.tenantId = id;
1925
1865
  }
1866
+ res = await fetchTenant(this.#config, "PUT", JSON.stringify(remaining));
1867
+ }
1868
+ if (rawResponse) {
1869
+ return res;
1870
+ }
1871
+ try {
1872
+ return await res?.clone().json();
1873
+ } catch {
1874
+ return res;
1926
1875
  }
1927
- return response;
1928
1876
  }
1929
- async get(req, url, init, raw = false) {
1930
- const response = await this.request("GET", url, req, init);
1931
- if (raw) {
1932
- return response;
1877
+ async list(req) {
1878
+ const res = await fetchTenantsByUser(this.#config);
1879
+ if (req === true) {
1880
+ return res;
1933
1881
  }
1934
- if (response && response.status >= 200 && response.status < 300) {
1935
- const cloned = response.clone();
1936
- try {
1937
- return await cloned.json();
1938
- } catch (e) {
1939
- }
1882
+ try {
1883
+ return await res?.clone().json();
1884
+ } catch {
1885
+ return res;
1940
1886
  }
1941
- return response;
1942
1887
  }
1943
- async put(req, url, init) {
1944
- const response = await this.request("PUT", url, req, init);
1945
- if (response && response.status >= 200 && response.status < 300) {
1946
- const cloned = response.clone();
1947
- try {
1948
- return await cloned.json();
1949
- } catch (e) {
1888
+ async leaveTenant(req) {
1889
+ const me = await fetchMe(this.#config);
1890
+ try {
1891
+ const json = await me.json();
1892
+ if ("id" in json) {
1893
+ this.#config.userId = json.id;
1950
1894
  }
1895
+ } catch {
1896
+ }
1897
+ if (typeof req === "string") {
1898
+ this.#config.tenantId = req;
1899
+ } else {
1900
+ this.#handleContext(req);
1951
1901
  }
1952
- return response;
1902
+ return await fetchTenantUser(this.#config, "DELETE");
1903
+ }
1904
+ async addMember(req, rawResponse) {
1905
+ if (typeof req === "string") {
1906
+ this.#config.userId = req;
1907
+ } else {
1908
+ this.#handleContext(req);
1909
+ }
1910
+ const res = await fetchTenantUser(this.#config, "PUT");
1911
+ return responseHandler(res, rawResponse);
1912
+ }
1913
+ async removeMember(req, rawResponse) {
1914
+ this.#handleContext(req);
1915
+ const res = await fetchTenantUser(this.#config, "DELETE");
1916
+ return responseHandler(res, rawResponse);
1917
+ }
1918
+ async users(req, rawResponse) {
1919
+ this.#handleContext(req);
1920
+ const res = await fetchTenantUsers(this.#config, "GET");
1921
+ return responseHandler(
1922
+ res,
1923
+ rawResponse || typeof req === "boolean" && req
1924
+ );
1953
1925
  }
1954
- async delete(req, url, init) {
1955
- const response = await this.request("DELETE", url, req, init);
1956
- return response;
1926
+ #handleContext(req) {
1927
+ if (typeof req === "object") {
1928
+ if ("tenantId" in req) {
1929
+ this.#config.tenantId = req.tenantId;
1930
+ }
1931
+ if ("userId" in req) {
1932
+ this.#config.tenantId = req.tenantId;
1933
+ }
1934
+ }
1957
1935
  }
1958
1936
  };
1937
+ async function responseHandler(res, rawResponse) {
1938
+ if (rawResponse) {
1939
+ return res;
1940
+ }
1941
+ try {
1942
+ return await res?.clone().json();
1943
+ } catch {
1944
+ return res;
1945
+ }
1946
+ }
1959
1947
 
1960
1948
  // src/auth/index.ts
1961
- function serverLogin(config, handlers) {
1962
- const ORIGIN = config.api.origin ?? "http://localhost:3000";
1963
- const { info, error, debug } = Logger(config, "[server side login]");
1964
- const routes = appRoutes(config.api.routePrefix);
1965
- return async function login({
1966
- email,
1967
- password
1968
- }) {
1969
- if (!email || !password) {
1970
- throw new Error("Server side login requires a user email and password.");
1949
+ var Auth = class {
1950
+ #logger;
1951
+ #config;
1952
+ constructor(config) {
1953
+ this.#config = config;
1954
+ this.#logger = Logger(config, "[auth]");
1955
+ }
1956
+ async getSession(rawResponse = false) {
1957
+ const res = await fetchSession(this.#config);
1958
+ if (rawResponse) {
1959
+ return res;
1971
1960
  }
1972
- const sessionUrl = new URL(`${ORIGIN}${routes.PROVIDERS}`);
1973
- const baseHeaders = {
1974
- host: sessionUrl.host,
1975
- [X_NILE_ORIGIN]: ORIGIN
1976
- };
1977
- info(`Obtaining providers for ${email}`);
1978
- const sessionReq = new Request(sessionUrl, {
1979
- method: "GET",
1980
- ...baseHeaders
1981
- });
1982
- const sessionRes = await handlers.POST(sessionReq);
1983
- if (sessionRes?.status === 404) {
1984
- throw new Error("Unable to login, cannot find region api.");
1961
+ try {
1962
+ const session = await res.clone().json();
1963
+ if (Object.keys(session).length === 0) {
1964
+ return void 0;
1965
+ }
1966
+ return session;
1967
+ } catch {
1968
+ return res;
1969
+ }
1970
+ }
1971
+ async getCsrf(rawResponse = false) {
1972
+ const res = await fetchCsrf(this.#config);
1973
+ const csrfCook = parseCSRF(res.headers);
1974
+ if (csrfCook) {
1975
+ const [, value] = csrfCook.split("=");
1976
+ const [token] = decodeURIComponent(value).split("|");
1977
+ const setCookie = res.headers.get("set-cookie");
1978
+ if (setCookie) {
1979
+ const cookie = [
1980
+ csrfCook,
1981
+ parseCallback(res.headers),
1982
+ parseToken(res.headers)
1983
+ ].filter(Boolean).join("; ");
1984
+ this.#config.headers.set("cookie", cookie);
1985
+ updateHeaders(new Headers({ cookie }));
1986
+ }
1987
+ if (!rawResponse) {
1988
+ return { csrfToken: token };
1989
+ }
1990
+ } else {
1991
+ const existingCookie = this.#config.headers.get("cookie");
1992
+ const cookieParts = [];
1993
+ if (existingCookie) {
1994
+ cookieParts.push(
1995
+ parseToken(this.#config.headers),
1996
+ parseCallback(this.#config.headers)
1997
+ );
1998
+ }
1999
+ cookieParts.push(csrfCook);
2000
+ const cookie = cookieParts.filter(Boolean).join("; ");
2001
+ this.#config.headers.set("cookie", cookie);
2002
+ updateHeaders(new Headers({ cookie }));
2003
+ }
2004
+ if (rawResponse) {
2005
+ return res;
1985
2006
  }
1986
- let providers;
1987
2007
  try {
1988
- providers = await sessionRes?.json();
1989
- } catch (e) {
1990
- info(sessionUrl, { sessionRes });
1991
- error(e);
2008
+ return await res.clone().json();
2009
+ } catch {
2010
+ return res;
2011
+ }
2012
+ }
2013
+ async listProviders(rawResponse = false) {
2014
+ const res = await fetchProviders(this.#config);
2015
+ if (rawResponse) {
2016
+ return res;
1992
2017
  }
1993
- info("Obtaining csrf");
1994
- const csrf = new URL(`${ORIGIN}${routes.CSRF}`);
1995
- const csrfReq = new Request(csrf, {
1996
- method: "GET",
1997
- headers: new Headers({
1998
- ...baseHeaders
1999
- })
2000
- });
2001
- const csrfRes = await handlers.POST(csrfReq);
2002
- let csrfToken;
2003
2018
  try {
2004
- const json = await csrfRes?.json() ?? {};
2005
- csrfToken = json?.csrfToken;
2006
- } catch (e) {
2007
- info(sessionUrl, { csrfRes });
2008
- error(e, { csrfRes });
2019
+ return await res.clone().json();
2020
+ } catch {
2021
+ return res;
2022
+ }
2023
+ }
2024
+ async signOut() {
2025
+ const csrfRes = await this.getCsrf();
2026
+ if (!("csrfToken" in csrfRes)) {
2027
+ throw new Error("Unable to obtain CSRF token. Sign out failed.");
2028
+ }
2029
+ const body = JSON.stringify({
2030
+ csrfToken: csrfRes.csrfToken,
2031
+ json: true
2032
+ });
2033
+ const res = await fetchSignOut(this.#config, body);
2034
+ updateHeaders(new Headers({}));
2035
+ this.#config.headers = new Headers();
2036
+ return res;
2037
+ }
2038
+ async signUp(payload, rawResponse) {
2039
+ this.#config.headers = new Headers();
2040
+ const { email, password, ...params } = payload;
2041
+ if (!email || !password) {
2042
+ throw new Error(
2043
+ "Server side sign up requires a user email and password."
2044
+ );
2009
2045
  }
2046
+ const providers = await this.listProviders();
2010
2047
  const { credentials } = providers ?? {};
2011
- const csrfCookie = csrfRes?.headers.get("set-cookie");
2012
2048
  if (!credentials) {
2013
2049
  throw new Error(
2014
- "Unable to obtain credential provider. Aborting server side login."
2050
+ "Unable to obtain credential provider. Aborting server side sign up."
2015
2051
  );
2016
2052
  }
2017
- const signInUrl = new URL(credentials.callbackUrl);
2018
- if (!csrfCookie) {
2019
- debug("CSRF failed", { headers: csrfRes?.headers });
2020
- throw new Error("Unable to authenticate REST, CSRF missing.");
2053
+ const csrf = await this.getCsrf();
2054
+ let csrfToken;
2055
+ if ("csrfToken" in csrf) {
2056
+ csrfToken = csrf.csrfToken;
2057
+ } else {
2058
+ throw new Error("Unable to obtain parse CSRF. Request blocked.");
2021
2059
  }
2022
- info(`Attempting sign in with email ${email} ${signInUrl.href}`);
2023
2060
  const body = JSON.stringify({
2024
2061
  email,
2025
2062
  password,
2026
2063
  csrfToken,
2027
2064
  callbackUrl: credentials.callbackUrl
2028
2065
  });
2029
- const postReq = new Request(signInUrl, {
2030
- method: "POST",
2031
- headers: new Headers({
2032
- ...baseHeaders,
2033
- "content-type": "application/json",
2034
- cookie: csrfCookie.split(",").join("; ")
2035
- }),
2036
- body
2037
- });
2038
- const loginRes = await handlers.POST(postReq);
2039
- const authCookie = loginRes?.headers.get("set-cookie");
2040
- if (!authCookie) {
2041
- throw new Error("authentication failed");
2066
+ const res = await fetchSignUp(this.#config, { body, params });
2067
+ if (res.status > 299) {
2068
+ this.#logger.error(await res.clone().text());
2069
+ return void 0;
2042
2070
  }
2043
- const token = parseToken(loginRes?.headers);
2071
+ const token = parseToken(res.headers);
2044
2072
  if (!token) {
2045
- error("Unable to obtain auth token", { authCookie });
2046
- throw new Error("Server login failed");
2073
+ throw new Error("Server side sign up failed. Session token not found");
2047
2074
  }
2048
- info("Server login successful", { authCookie, csrfCookie });
2049
- const headers = new Headers({
2050
- ...baseHeaders,
2051
- cookie: [token, csrfCookie].join("; ")
2052
- });
2053
- return [headers, loginRes];
2054
- };
2055
- }
2056
- function parseToken(headers) {
2057
- let authCookie = headers?.get("set-cookie");
2058
- if (!authCookie) {
2059
- authCookie = headers?.get("cookie");
2060
- }
2061
- if (!authCookie) {
2062
- return void 0;
2063
- }
2064
- const [, token] = /((__Secure-)?nile\.session-token=[^;]+)/.exec(authCookie) ?? [];
2065
- return token;
2066
- }
2067
- var Auth = class extends Config {
2068
- headers;
2069
- resetHeaders;
2070
- constructor(config, headers, params) {
2071
- super(config);
2072
- this.logger = Logger(config, "[auth]");
2073
- this.headers = headers;
2074
- this.logger = Logger(config, "[auth]");
2075
- this.resetHeaders = params?.resetHeaders;
2076
- }
2077
- handleHeaders(init) {
2078
- if (this.headers) {
2079
- const cburl = getCallbackUrl2(this.headers);
2080
- if (cburl) {
2081
- try {
2082
- this.headers.set(X_NILE_ORIGIN, new URL(cburl).origin);
2083
- } catch (e) {
2084
- if (this.logger?.debug) {
2085
- this.logger.debug("Invalid URL supplied by cookie header");
2086
- }
2087
- }
2088
- }
2089
- if (init) {
2090
- init.headers = new Headers({ ...this.headers, ...init?.headers });
2091
- return init;
2092
- } else {
2093
- init = {
2094
- headers: this.headers
2095
- };
2096
- return init;
2097
- }
2075
+ this.#config.headers?.append("cookie", token);
2076
+ updateHeaders(this.#config.headers);
2077
+ if (rawResponse) {
2078
+ return res;
2098
2079
  }
2099
- return void 0;
2100
- }
2101
- get sessionUrl() {
2102
- return "/auth/session";
2103
- }
2104
- getSession = async (req, init) => {
2105
- const _requester = new Requester(this);
2106
- const _init = this.handleHeaders(init);
2107
- const session = await _requester.get(req, this.sessionUrl, _init);
2108
- if (Object.keys(session).length === 0) {
2109
- return void 0;
2080
+ try {
2081
+ return await res.clone().json();
2082
+ } catch {
2083
+ return res;
2110
2084
  }
2111
- return session;
2112
- };
2113
- get getCsrfUrl() {
2114
- return "/auth/csrf";
2115
- }
2116
- async getCsrf(req, init, raw = false) {
2117
- const _requester = new Requester(this);
2118
- const _init = this.handleHeaders(init);
2119
- return await _requester.get(req, this.getCsrfUrl, _init, raw);
2120
2085
  }
2121
- get listProvidersUrl() {
2122
- return "/auth/providers";
2123
- }
2124
- listProviders = async (req, init) => {
2125
- const _requester = new Requester(this);
2126
- const _init = this.handleHeaders(init);
2127
- return await _requester.get(req, this.listProvidersUrl, _init);
2128
- };
2129
- get signOutUrl() {
2130
- return "/auth/signout";
2131
- }
2132
- signOut = async (req, init) => {
2133
- const _requester = new Requester(this);
2134
- const _init = this.handleHeaders(init);
2135
- const csrf = await this.getCsrf(
2136
- req,
2137
- void 0,
2138
- true
2139
- );
2140
- const csrfHeader = getCsrfToken(csrf.headers, this.headers);
2141
- const callbackUrl = req && "callbackUrl" in req ? String(req.callbackUrl) : "/";
2142
- if (!csrfHeader) {
2143
- this.logger?.debug && this.logger.debug("Request blocked from invalid csrf header");
2144
- return new Response("Request blocked", { status: 400 });
2145
- }
2146
- const headers = new Headers(_init?.headers);
2147
- const { csrfToken } = await csrf.json() ?? {};
2148
- const cooks = getCookies(headers);
2149
- if (csrfHeader) {
2150
- if (cooks["__Secure-nile.csrf-token"]) {
2151
- cooks["__Secure-nile.csrf-token"] = encodeURIComponent(csrfHeader);
2152
- }
2153
- if (cooks["nile.csrf-token"]) {
2154
- cooks["nile.csrf-token"] = encodeURIComponent(csrfHeader);
2155
- }
2086
+ async signIn(provider, payload, rawResponse) {
2087
+ this.#config.headers = new Headers();
2088
+ const { info, error } = this.#logger;
2089
+ const { email, password } = payload ?? {};
2090
+ if (provider === "email" && (!email || !password)) {
2091
+ throw new Error(
2092
+ "Server side sign in requires a user email and password."
2093
+ );
2156
2094
  }
2157
- headers.set(
2158
- "cookie",
2159
- Object.keys(cooks).map((key12) => `${key12}=${cooks[key12]}`).join("; ")
2160
- );
2161
- const res = await _requester.post(req, this.signOutUrl, {
2162
- method: "post",
2163
- body: JSON.stringify({
2164
- csrfToken,
2165
- callbackUrl,
2166
- json: String(true)
2167
- }),
2168
- ..._init,
2169
- headers
2170
- });
2171
- this.resetHeaders && this.resetHeaders();
2172
- return res;
2173
- };
2174
- };
2175
- function getCallbackUrl2(headers) {
2176
- if (headers) {
2177
- const cookies = getCookies(headers);
2178
- if (cookies) {
2179
- return cookies["__Secure-nile.callback-url"] || cookies["nile.callback-url"];
2095
+ info(`Obtaining providers for ${email}`);
2096
+ const providers = await this.listProviders();
2097
+ info("Obtaining csrf");
2098
+ const csrf = await this.getCsrf();
2099
+ let csrfToken;
2100
+ if ("csrfToken" in csrf) {
2101
+ csrfToken = csrf.csrfToken;
2102
+ } else {
2103
+ throw new Error("Unable to obtain parse CSRF. Request blocked.");
2180
2104
  }
2181
- }
2182
- }
2183
- function getCsrfToken(headers, initHeaders) {
2184
- if (headers) {
2185
- const cookies = getCookies(headers);
2186
- let validCookie = "";
2187
- if (cookies) {
2188
- validCookie = cookies["__Secure-nile.csrf-token"] || cookies["nile.csrf-token"];
2105
+ const { credentials } = providers ?? {};
2106
+ if (!credentials) {
2107
+ throw new Error(
2108
+ "Unable to obtain credential provider. Aborting server side sign in."
2109
+ );
2189
2110
  }
2190
- if (validCookie) {
2191
- return validCookie;
2111
+ if (provider !== "credentials") {
2112
+ return await fetchSignIn(
2113
+ this.#config,
2114
+ provider,
2115
+ JSON.stringify({ csrfToken })
2116
+ );
2192
2117
  }
2193
- }
2194
- if (initHeaders) {
2195
- const cookies = getCookies(initHeaders);
2196
- if (cookies) {
2197
- return cookies["__Secure-nile.csrf-token"] || cookies["nile.csrf-token"];
2118
+ info(`Attempting sign in with email ${email}`);
2119
+ const body = JSON.stringify({
2120
+ email,
2121
+ password,
2122
+ csrfToken,
2123
+ callbackUrl: credentials.callbackUrl
2124
+ });
2125
+ const signInRes = await fetchCallback(this.#config, provider, body);
2126
+ const authCookie = signInRes?.headers.get("set-cookie");
2127
+ if (!authCookie) {
2128
+ throw new Error("authentication failed");
2198
2129
  }
2199
- }
2200
- }
2201
- var getCookies = (headers) => {
2202
- if (!headers) return {};
2203
- const cookieHeader = headers.get("cookie") || "";
2204
- const setCookieHeaders = headers.get("set-cookie") || "";
2205
- const allCookies = [
2206
- ...cookieHeader.split("; "),
2207
- // Regular 'cookie' header (semicolon-separated)
2208
- ...setCookieHeaders.split(/,\s*(?=[^;, ]+=)/)
2209
- // Smart split for 'set-cookie'
2210
- ].filter(Boolean);
2211
- return Object.fromEntries(
2212
- allCookies.map((cookie) => {
2213
- const [key12, ...val] = cookie.split("=");
2214
- return [
2215
- decodeURIComponent(key12.trim()),
2216
- decodeURIComponent(val.join("=").trim())
2217
- ];
2218
- })
2219
- );
2220
- };
2221
-
2222
- // src/tenants/index.ts
2223
- var Tenants = class extends Config {
2224
- headers;
2225
- constructor(config, headers) {
2226
- super(config);
2227
- this.headers = headers;
2228
- }
2229
- handleHeaders(init) {
2230
- if (this.headers) {
2231
- if (init) {
2232
- init.headers = new Headers({ ...this.headers, ...init?.headers });
2233
- return init;
2234
- } else {
2235
- init = {
2236
- headers: this.headers
2237
- };
2238
- return init;
2130
+ const token = parseToken(signInRes?.headers);
2131
+ const possibleError = signInRes?.headers.get("location");
2132
+ if (possibleError) {
2133
+ let urlError;
2134
+ try {
2135
+ urlError = new URL(possibleError).searchParams.get("error");
2136
+ } catch {
2137
+ }
2138
+ if (urlError) {
2139
+ error("Unable to log user in", { error: urlError });
2140
+ return void 0;
2239
2141
  }
2240
2142
  }
2241
- return void 0;
2242
- }
2243
- get tenantsUrl() {
2244
- return "/tenants";
2245
- }
2246
- get tenantUrl() {
2247
- return `/tenants/${this.tenantId ?? "{tenantId}"}`;
2248
- }
2249
- createTenant = async (req, init) => {
2250
- let _req;
2251
- if (typeof req === "string") {
2252
- _req = new Request(`${this.api.basePath}${this.tenantsUrl}`, {
2253
- body: JSON.stringify({ name: req }),
2254
- method: "POST",
2255
- headers: {
2256
- "content-type": "application/json"
2257
- }
2258
- });
2259
- } else if ("name" in req || "id" in req) {
2260
- _req = new Request(`${this.api.basePath}${this.tenantsUrl}`, {
2261
- body: JSON.stringify(req),
2262
- method: "POST",
2263
- headers: {
2264
- "content-type": "application/json"
2265
- }
2143
+ if (!token) {
2144
+ error("Unable to obtain auth token", {
2145
+ authCookie,
2146
+ signInRes
2266
2147
  });
2267
- } else {
2268
- _req = req;
2269
- }
2270
- const _requester = new Requester(this);
2271
- const _init = this.handleHeaders(init);
2272
- return _requester.post(_req, this.tenantsUrl, _init);
2273
- };
2274
- getTenant = async (req, init) => {
2275
- if (typeof req === "string") {
2276
- this.tenantId = req;
2277
- }
2278
- const _requester = new Requester(this);
2279
- const _init = this.handleHeaders(init);
2280
- return _requester.get(req, this.tenantUrl, _init);
2281
- };
2282
- get tenantListUrl() {
2283
- return `/users/${this.userId ?? "{userId}"}/tenants`;
2284
- }
2285
- listTenants = async (req, init) => {
2286
- const _requester = new Requester(this);
2287
- const _init = this.handleHeaders(init);
2288
- return _requester.get(req, this.tenantListUrl, _init);
2289
- };
2290
- deleteTenant = async (req, init) => {
2291
- if (typeof req === "string") {
2292
- this.tenantId = req;
2148
+ throw new Error("Server login failed");
2293
2149
  }
2294
- const _requester = new Requester(this);
2295
- const _init = this.handleHeaders(init);
2296
- return _requester.delete(req, this.tenantUrl, _init);
2297
- };
2298
- updateTenant = async (req, init) => {
2299
- let _req;
2300
- if (req && "name" in req) {
2301
- _req = new Request(`${this.api.basePath}${this.tenantUrl}`, {
2302
- body: JSON.stringify(req),
2303
- method: "PUT"
2304
- });
2150
+ info("Server sign in successful", { authCookie });
2151
+ const setCookie = signInRes.headers.get("set-cookie");
2152
+ if (setCookie) {
2153
+ const cookie = [
2154
+ parseCSRF(this.#config.headers),
2155
+ parseCallback(signInRes.headers),
2156
+ parseToken(signInRes.headers)
2157
+ ].filter(Boolean).join("; ");
2158
+ updateHeaders(new Headers({ cookie }));
2305
2159
  } else {
2306
- _req = req;
2160
+ error("Unable to set context after sign in", {
2161
+ headers: signInRes.headers
2162
+ });
2307
2163
  }
2308
- const _requester = new Requester(this);
2309
- const _init = this.handleHeaders(init);
2310
- return _requester.put(_req, this.tenantUrl, _init);
2311
- };
2312
- };
2313
-
2314
- // src/users/index.ts
2315
- var Users = class extends Config {
2316
- headers;
2317
- constructor(config, headers) {
2318
- super(config);
2319
- this.headers = headers;
2320
- }
2321
- usersUrl(user) {
2322
- const params = new URLSearchParams();
2323
- if (user.newTenantName) {
2324
- params.set("newTenantName", user.newTenantName);
2164
+ if (rawResponse) {
2165
+ return signInRes;
2325
2166
  }
2326
- if (user.tenantId) {
2327
- params.set("tenantId", user.tenantId);
2167
+ try {
2168
+ return await signInRes.clone().json();
2169
+ } catch {
2170
+ return signInRes;
2328
2171
  }
2329
- return `/users?${params.size > 0 ? params : ""}`;
2330
2172
  }
2331
- get tenantUsersUrl() {
2332
- return `/tenants/${this.tenantId ?? "{tenantId}"}/users`;
2173
+ };
2174
+ function parseCSRF(headers) {
2175
+ let cookie = headers?.get("set-cookie");
2176
+ if (!cookie) {
2177
+ cookie = headers?.get("cookie");
2333
2178
  }
2334
- get linkUsersUrl() {
2335
- return `/tenants/${this.tenantId ?? "{tenantId}"}/users/${this.userId ?? "{userId}"}/link`;
2179
+ if (!cookie) {
2180
+ return void 0;
2336
2181
  }
2337
- get tenantUserUrl() {
2338
- return `/tenants/${this.tenantId ?? "{tenantId}"}/users/${this.userId ?? "{userId}"}`;
2182
+ const [, token] = /((__Secure-)?nile\.csrf-token=[^;]+)/.exec(cookie) ?? [];
2183
+ return token;
2184
+ }
2185
+ function parseCallback(headers) {
2186
+ let cookie = headers?.get("set-cookie");
2187
+ if (!cookie) {
2188
+ cookie = headers?.get("cookie");
2339
2189
  }
2340
- handleHeaders(init) {
2341
- if (this.headers) {
2342
- if (init) {
2343
- init.headers = new Headers({ ...this.headers, ...init?.headers });
2344
- return init;
2345
- } else {
2346
- init = {
2347
- headers: this.headers
2348
- };
2349
- return init;
2350
- }
2351
- }
2190
+ if (!cookie) {
2352
2191
  return void 0;
2353
2192
  }
2354
- createUser = async (user, init) => {
2355
- const _requester = new Requester(this);
2356
- const _init = this.handleHeaders(init);
2357
- return await _requester.post(user, this.usersUrl(user), _init);
2358
- };
2359
- createTenantUser = async (req, init) => {
2360
- const _requester = new Requester(this);
2361
- const _init = this.handleHeaders(init);
2362
- return await _requester.post(req, this.tenantUsersUrl, _init);
2363
- };
2364
- updateUser = async (req, init) => {
2365
- let _req;
2366
- if (req && "id" in req) {
2367
- _req = new Request(`${this.api.basePath}${this.tenantUserUrl}`, {
2368
- body: JSON.stringify(req),
2369
- method: "PUT"
2370
- });
2371
- this.userId = String(req.id);
2372
- } else {
2373
- _req = req;
2374
- }
2375
- const _requester = new Requester(this);
2376
- const _init = this.handleHeaders(init);
2377
- return await _requester.put(_req, this.tenantUserUrl, _init);
2378
- };
2379
- listUsers = async (req, init) => {
2380
- const _requester = new Requester(this);
2381
- const _init = this.handleHeaders(init);
2382
- return await _requester.get(req, this.tenantUsersUrl, _init);
2383
- };
2384
- linkUser = async (req, init) => {
2385
- const _requester = new Requester(this);
2386
- if (typeof req === "string") {
2387
- this.userId = req;
2388
- } else {
2389
- if ("id" in req) {
2390
- this.userId = req.id;
2391
- }
2392
- if ("tenantId" in req) {
2393
- this.tenantId = req.tenantId;
2394
- }
2395
- }
2396
- const _init = this.handleHeaders(init);
2397
- return await _requester.put(req, this.linkUsersUrl, _init);
2398
- };
2399
- unlinkUser = async (req, init) => {
2400
- if (typeof req === "string") {
2401
- this.userId = req;
2402
- } else {
2403
- if ("id" in req) {
2404
- this.userId = req.id;
2405
- }
2406
- if ("tenantId" in req) {
2407
- this.tenantId = req.tenantId;
2408
- }
2409
- }
2410
- const _requester = new Requester(this);
2411
- const _init = this.handleHeaders(init);
2412
- return await _requester.delete(req, this.linkUsersUrl, _init);
2413
- };
2414
- get meUrl() {
2415
- return "/me";
2193
+ const [, token] = /((__Secure-)?nile\.callback-url=[^;]+)/.exec(cookie) ?? [];
2194
+ return token;
2195
+ }
2196
+ function parseToken(headers) {
2197
+ let authCookie = headers?.get("set-cookie");
2198
+ if (!authCookie) {
2199
+ authCookie = headers?.get("cookie");
2416
2200
  }
2417
- me = async (req, init) => {
2418
- const _requester = new Requester(this);
2419
- const _init = this.handleHeaders(init);
2420
- return await _requester.get(req, this.meUrl, _init);
2421
- };
2422
- updateMe = async (req, init) => {
2423
- const _requester = new Requester(this);
2424
- const _init = this.handleHeaders(init);
2425
- return await _requester.put(req, this.meUrl, _init);
2426
- };
2427
- };
2201
+ if (!authCookie) {
2202
+ return void 0;
2203
+ }
2204
+ const [, token] = /((__Secure-)?nile\.session-token=[^;]+)/.exec(authCookie) ?? [];
2205
+ return token;
2206
+ }
2428
2207
 
2429
2208
  // src/api/handlers/withContext/index.ts
2430
- function handlersWithContext(configRoutes, config) {
2431
- const GET6 = GETTER(configRoutes, config);
2432
- const POST5 = POSTER(configRoutes, config);
2433
- const DELETE3 = DELETER(configRoutes, config);
2434
- const PUT4 = PUTER(configRoutes, config);
2209
+ function handlersWithContext(config) {
2210
+ const GET6 = GETTER(config.routes, config);
2211
+ const POST5 = POSTER(config.routes, config);
2212
+ const DELETE4 = DELETER(config.routes, config);
2213
+ const PUT5 = PUTER(config.routes, config);
2435
2214
  return {
2436
2215
  GET: async (req) => {
2437
2216
  const response = await GET6(req);
@@ -2444,12 +2223,12 @@ function handlersWithContext(configRoutes, config) {
2444
2223
  return { response, nile: new Server(updatedConfig) };
2445
2224
  },
2446
2225
  DELETE: async (req) => {
2447
- const response = await DELETE3(req);
2226
+ const response = await DELETE4(req);
2448
2227
  const updatedConfig = updateConfig(response, config);
2449
2228
  return { response, nile: new Server(updatedConfig) };
2450
2229
  },
2451
2230
  PUT: async (req) => {
2452
- const response = await PUT4(req);
2231
+ const response = await PUT5(req);
2453
2232
  const updatedConfig = updateConfig(response, config);
2454
2233
  return { response, nile: new Server(updatedConfig) };
2455
2234
  }
@@ -2461,13 +2240,14 @@ function updateConfig(response, config) {
2461
2240
  if (response?.status === 302) {
2462
2241
  const location = response.headers.get("location");
2463
2242
  if (location) {
2464
- origin = location;
2243
+ const normalized = location.endsWith("/") ? location.slice(0, -1) : location;
2244
+ origin = normalized;
2465
2245
  }
2466
2246
  }
2467
2247
  const setCookies = [];
2468
2248
  if (response?.headers) {
2469
- for (const [key12, value] of response.headers) {
2470
- if (key12.toLowerCase() === "set-cookie") {
2249
+ for (const [key13, value] of response.headers) {
2250
+ if (key13.toLowerCase() === "set-cookie") {
2471
2251
  setCookies.push(value);
2472
2252
  }
2473
2253
  }
@@ -2478,299 +2258,200 @@ function updateConfig(response, config) {
2478
2258
  }
2479
2259
  return {
2480
2260
  ...config,
2481
- api: {
2482
- ...config.api,
2483
- origin,
2484
- headers: headers ?? void 0
2485
- }
2261
+ origin,
2262
+ headers: headers ?? void 0
2486
2263
  };
2487
2264
  }
2488
2265
 
2489
- // src/Api.ts
2490
- var Api = class {
2491
- config;
2266
+ // src/Server.ts
2267
+ var Server = class {
2492
2268
  users;
2493
- auth;
2494
2269
  tenants;
2495
- routes;
2270
+ auth;
2271
+ #config;
2272
+ #handlers;
2273
+ #paths;
2274
+ #manager;
2496
2275
  #headers;
2497
- handlers;
2498
- handlersWithContext;
2499
- paths;
2500
2276
  constructor(config) {
2501
- this.config = config;
2502
- if (config?.api.headers) {
2503
- this.headers = config?.api.headers;
2504
- }
2505
- this.auth = new Auth(config, void 0, {
2506
- resetHeaders: this.resetHeaders
2277
+ this.#config = new Config(config, "[initial config]");
2278
+ watchTenantId((tenantId) => {
2279
+ if (tenantId !== this.#config.tenantId) {
2280
+ this.#config.tenantId = tenantId;
2281
+ this.#reset();
2282
+ }
2507
2283
  });
2508
- this.users = new Users(config);
2509
- this.tenants = new Tenants(config);
2510
- this.routes = {
2511
- ...appRoutes(config?.api.routePrefix),
2512
- ...config?.api.routes
2513
- };
2514
- this.handlers = Handlers(this.routes, config);
2515
- this.handlersWithContext = handlersWithContext(this.routes, config);
2516
- this.paths = {
2517
- get: [
2518
- this.routes.ME,
2519
- this.routes.TENANT_USERS,
2520
- this.routes.TENANTS,
2521
- this.routes.TENANT,
2522
- this.routes.SESSION,
2523
- this.routes.SIGNIN,
2524
- this.routes.PROVIDERS,
2525
- this.routes.CSRF,
2526
- this.routes.PASSWORD_RESET,
2527
- this.routes.CALLBACK,
2528
- this.routes.SIGNOUT,
2529
- this.routes.VERIFY_REQUEST,
2530
- this.routes.ERROR
2531
- ],
2532
- post: [
2533
- this.routes.TENANT_USERS,
2534
- this.routes.SIGNUP,
2535
- this.routes.USERS,
2536
- this.routes.TENANTS,
2537
- this.routes.SESSION,
2538
- `${this.routes.SIGNIN}/{provider}`,
2539
- this.routes.PASSWORD_RESET,
2540
- this.routes.PROVIDERS,
2541
- this.routes.CSRF,
2542
- `${this.routes.CALLBACK}/{provider}`,
2543
- this.routes.SIGNOUT
2544
- ],
2545
- put: [
2546
- this.routes.TENANT_USERS,
2547
- this.routes.USERS,
2548
- this.routes.TENANT,
2549
- this.routes.PASSWORD_RESET
2550
- ],
2551
- delete: [this.routes.TENANT_USER, this.routes.TENANT]
2284
+ watchUserId((userId) => {
2285
+ if (userId !== this.#config.userId) {
2286
+ this.#config.userId = userId;
2287
+ this.#reset();
2288
+ }
2289
+ });
2290
+ watchHeaders((headers) => {
2291
+ this.setContext(headers);
2292
+ this.#reset();
2293
+ });
2294
+ this.#handlers = {
2295
+ ...this.#config.handlers,
2296
+ withContext: handlersWithContext(this.#config)
2552
2297
  };
2298
+ this.#paths = this.#config.paths;
2299
+ this.#config.tenantId = getTenantId({ config: this.#config });
2300
+ this.#manager = new DBManager(this.#config);
2301
+ this.#handleHeaders(config);
2302
+ this.users = new Users(this.#config);
2303
+ this.tenants = new Tenants(this.#config);
2304
+ this.auth = new Auth(this.#config);
2553
2305
  }
2554
- reset = () => {
2555
- this.users = new Users(this.config, this.#headers);
2556
- this.tenants = new Tenants(this.config, this.#headers);
2557
- this.auth = new Auth(this.config, this.#headers, {
2558
- resetHeaders: this.resetHeaders
2306
+ get db() {
2307
+ const pool = this.#manager.getConnection(this.#config);
2308
+ return Object.assign(pool, {
2309
+ clearConnections: () => {
2310
+ this.#manager.clear(this.#config);
2311
+ }
2559
2312
  });
2560
- };
2561
- updateConfig = (config) => {
2562
- this.config = config;
2563
- this.handlers = Handlers(this.routes, config);
2564
- };
2565
- resetHeaders = (headers) => {
2566
- this.#headers = new Headers(headers ?? {});
2567
- this.reset();
2568
- };
2313
+ }
2569
2314
  /**
2570
- * Merge headers together
2315
+ * A convenience function that applies a config and ensures whatever was passed is set properly
2571
2316
  */
2572
- set headers(headers) {
2573
- const updates = [];
2574
- if (headers instanceof Headers) {
2575
- headers.forEach((value, key12) => {
2576
- updates.push([key12.toLowerCase(), value]);
2577
- });
2578
- } else {
2579
- for (const [key12, value] of Object.entries(headers)) {
2580
- updates.push([key12.toLowerCase(), value]);
2581
- }
2582
- }
2583
- const merged = {};
2584
- this.#headers?.forEach((value, key12) => {
2585
- if (key12.toLowerCase() !== "cookie") {
2586
- merged[key12.toLowerCase()] = value;
2587
- }
2588
- });
2589
- for (const [key12, value] of updates) {
2590
- merged[key12] = value;
2591
- }
2592
- this.#headers = new Headers();
2593
- for (const [key12, value] of Object.entries(merged)) {
2594
- this.#headers.set(key12, value);
2317
+ getInstance(config, req) {
2318
+ const _config = { ...this.#config, ...config };
2319
+ const updatedConfig = new Config(_config);
2320
+ this.#config = new Config(updatedConfig);
2321
+ this.#config.tenantId = config.tenantId;
2322
+ this.#config.userId = config.userId;
2323
+ if (req) {
2324
+ this.setContext(req);
2595
2325
  }
2596
- this.reset();
2326
+ this.#reset();
2327
+ return this;
2597
2328
  }
2598
- get headers() {
2599
- return this.#headers;
2329
+ getPaths() {
2330
+ return this.#paths;
2600
2331
  }
2601
- getCookie(req) {
2602
- if (req instanceof Headers) {
2603
- return parseToken(req);
2604
- } else if (req instanceof Request) {
2605
- return parseToken(req.headers);
2606
- }
2607
- return null;
2332
+ get handlers() {
2333
+ return this.#handlers;
2608
2334
  }
2609
- login = async (payload, config) => {
2610
- const [headers, loginRes] = await serverLogin(
2611
- this.config,
2612
- this.handlers
2613
- )(payload);
2614
- this.setContext(headers);
2615
- try {
2616
- const res = await loginRes.json();
2617
- if (res.id) {
2618
- this.config.userId = res.id;
2619
- }
2620
- } catch (e) {
2621
- const { warn } = Logger(this.config, "[API][login]");
2622
- if (warn) {
2623
- warn("Unable to set user id from login attempt.");
2624
- }
2625
- }
2626
- if (config?.returnResponse) {
2627
- return loginRes;
2628
- }
2629
- return void 0;
2630
- };
2631
- session = async (req) => {
2632
- if (req instanceof Headers) {
2633
- return this.auth.getSession(req);
2634
- } else if (req instanceof Request) {
2635
- return auth(req, this.config);
2636
- }
2637
- return this.auth.getSession(this.#headers);
2638
- };
2639
- setContext = (req) => {
2335
+ /**
2336
+ * Allow the setting of headers from a req or header object.
2337
+ * Makes it possible to handle REST requests easily
2338
+ * Also makes it easy to set user + tenant in some way
2339
+ * @param req
2340
+ * @returns undefined
2341
+ */
2342
+ setContext(req) {
2640
2343
  try {
2641
2344
  if (req instanceof Headers) {
2642
- this.headers = req;
2345
+ this.#handleHeaders(req);
2346
+ this.#reset();
2643
2347
  return;
2644
2348
  } else if (req instanceof Request) {
2645
- this.headers = new Headers(req.headers);
2349
+ this.#handleHeaders(new Headers(req.headers));
2350
+ this.#reset();
2646
2351
  return;
2647
2352
  }
2353
+ } catch {
2354
+ }
2355
+ let ok = false;
2356
+ if (req && typeof req === "object" && "tenantId" in req) {
2357
+ ok = true;
2358
+ this.#config.tenantId = req.tenantId;
2359
+ }
2360
+ if (req && typeof req === "object" && "userId" in req) {
2361
+ ok = true;
2362
+ this.#config.userId = req.userId;
2363
+ }
2364
+ if (ok) {
2365
+ return;
2366
+ }
2367
+ if (typeof req === "object") {
2648
2368
  const headers = new Headers(req);
2649
2369
  if (headers) {
2650
- this.headers = headers;
2370
+ this.#handleHeaders(headers);
2371
+ this.#reset();
2651
2372
  return;
2652
2373
  }
2653
- } catch {
2654
2374
  }
2655
- const { warn } = Logger(this.config, "[API]");
2375
+ const { warn } = Logger(this.#config, "[API]");
2656
2376
  if (warn) {
2657
2377
  warn(
2658
2378
  "Set context expects a Request, Header instance or an object of Record<string, string>"
2659
2379
  );
2660
2380
  }
2661
- };
2662
- };
2663
-
2664
- // src/Server.ts
2665
- var Server = class {
2666
- config;
2667
- api;
2668
- manager;
2669
- constructor(config) {
2670
- this.config = new Config(config, "[initial config]");
2671
- this.api = new Api(this.config);
2672
- this.manager = new DBManager(this.config);
2673
- watchTenantId((tenantId) => {
2674
- this.tenantId = tenantId;
2675
- });
2676
- watchUserId((userId) => {
2677
- this.userId = userId;
2678
- });
2679
- watchToken((token) => {
2680
- this.token = token;
2681
- });
2682
- }
2683
- setConfig(cfg) {
2684
- this.config = new Config(cfg);
2685
- this.api.updateConfig(this.config);
2686
- }
2687
- async init(cfg) {
2688
- const updatedConfig = await this.config.configure({
2689
- ...this.config,
2690
- ...cfg
2691
- });
2692
- this.setConfig(updatedConfig);
2693
- return this;
2694
- }
2695
- set databaseId(val) {
2696
- if (val) {
2697
- this.config.databaseId = val;
2698
- this.api.users.databaseId = val;
2699
- this.api.tenants.databaseId = val;
2700
- }
2701
2381
  }
2702
- get userId() {
2703
- return this.config.userId;
2382
+ getContext() {
2383
+ return {
2384
+ headers: this.#headers,
2385
+ userId: this.#config.userId,
2386
+ tenantId: this.#config.tenantId
2387
+ };
2704
2388
  }
2705
- set userId(userId) {
2706
- this.databaseId = this.config.databaseId;
2707
- this.config.userId = userId;
2708
- if (this.api) {
2709
- this.api.users.userId = this.config.userId;
2710
- this.api.tenants.userId = this.config.userId;
2389
+ /**
2390
+ * Merge headers together
2391
+ * Internally, passed a NileConfig, externally, should be using Headers
2392
+ */
2393
+ #handleHeaders(config) {
2394
+ const updates = [];
2395
+ let headers;
2396
+ this.#headers = new Headers();
2397
+ if (config instanceof Headers) {
2398
+ headers = config;
2399
+ } else if (config?.headers) {
2400
+ headers = config?.headers;
2401
+ if (config && config.origin) {
2402
+ this.#headers.set(X_NILE_ORIGIN, config.origin);
2403
+ }
2404
+ if (config && config.secureCookies != null) {
2405
+ this.#headers.set(X_NILE_SECURECOOKIES, String(config.secureCookies));
2406
+ }
2711
2407
  }
2712
- }
2713
- get tenantId() {
2714
- return this.config.tenantId;
2715
- }
2716
- set tenantId(tenantId) {
2717
- this.databaseId = this.config.databaseId;
2718
- this.config.tenantId = tenantId;
2719
- if (this.api) {
2720
- this.api.users.tenantId = tenantId;
2721
- this.api.tenants.tenantId = tenantId;
2408
+ if (headers instanceof Headers) {
2409
+ headers.forEach((value, key13) => {
2410
+ updates.push([key13.toLowerCase(), value]);
2411
+ });
2412
+ } else {
2413
+ for (const [key13, value] of Object.entries(headers ?? {})) {
2414
+ updates.push([key13.toLowerCase(), value]);
2415
+ }
2722
2416
  }
2723
- }
2724
- get token() {
2725
- return this.config?.api?.token;
2726
- }
2727
- set token(token) {
2728
- if (token) {
2729
- this.config.api.token = token;
2730
- if (this.api) {
2731
- this.api.users.api.token = token;
2732
- this.api.tenants.api.token = token;
2417
+ const merged = {};
2418
+ this.#headers?.forEach((value, key13) => {
2419
+ if (key13.toLowerCase() !== "cookie") {
2420
+ merged[key13.toLowerCase()] = value;
2733
2421
  }
2422
+ });
2423
+ for (const [key13, value] of updates) {
2424
+ merged[key13] = value;
2734
2425
  }
2735
- }
2736
- get db() {
2737
- return this.manager.getConnection(this.config);
2738
- }
2739
- clearConnections() {
2740
- this.manager.clear(this.config);
2426
+ for (const [key13, value] of Object.entries(merged)) {
2427
+ this.#headers.set(key13, value);
2428
+ }
2429
+ this.#config.headers = this.#headers;
2741
2430
  }
2742
2431
  /**
2743
- * A convenience function that applies a config and ensures whatever was passed is set properly
2432
+ * Allow some internal mutations to reset our config + headers
2744
2433
  */
2745
- getInstance(config, req) {
2746
- const _config = { ...this.config, ...config };
2747
- const updatedConfig = new Config(_config);
2748
- this.setConfig(updatedConfig);
2749
- this.tenantId = updatedConfig.tenantId;
2750
- this.userId = updatedConfig.userId;
2751
- if (updatedConfig.api.token) {
2752
- this.token = updatedConfig.api.token;
2753
- }
2754
- this.databaseId = updatedConfig.databaseId;
2755
- if (req) {
2756
- this.api.setContext(req);
2757
- }
2758
- return this;
2759
- }
2434
+ #reset = () => {
2435
+ this.#config.headers = this.#headers ?? new Headers();
2436
+ this.users = new Users(this.#config);
2437
+ this.tenants = new Tenants(this.#config);
2438
+ this.auth = new Auth(this.#config);
2439
+ };
2760
2440
  };
2761
2441
  var server;
2762
- async function create(config) {
2442
+ function create(config) {
2763
2443
  if (!server) {
2764
2444
  server = new Server(config);
2765
2445
  }
2766
- if (config) {
2767
- return await server.init(new Config(config));
2768
- }
2769
- return await server.init();
2446
+ return server;
2770
2447
  }
2771
2448
 
2449
+ exports.APIErrorErrorCodeEnum = APIErrorErrorCodeEnum;
2772
2450
  exports.LoginUserResponseTokenTypeEnum = LoginUserResponseTokenTypeEnum;
2773
2451
  exports.Nile = create;
2774
2452
  exports.Server = Server;
2453
+ exports.parseCSRF = parseCSRF;
2454
+ exports.parseCallback = parseCallback;
2455
+ exports.parseToken = parseToken;
2775
2456
  //# sourceMappingURL=index.js.map
2776
2457
  //# sourceMappingURL=index.js.map