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

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