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