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