@niledatabase/server 3.0.0-alpha.9 → 3.0.0

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