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

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