@niledatabase/server 5.0.0-alpha.9 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +379 -138
- package/dist/index.d.ts +379 -138
- package/dist/index.js +1469 -938
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1467 -939
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var async_hooks = require('async_hooks');
|
|
3
4
|
require('dotenv/config');
|
|
4
5
|
var pg = require('pg');
|
|
5
6
|
|
|
@@ -8,6 +9,15 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
8
9
|
var pg__default = /*#__PURE__*/_interopDefault(pg);
|
|
9
10
|
|
|
10
11
|
// src/types.ts
|
|
12
|
+
var ExtensionState = /* @__PURE__ */ ((ExtensionState2) => {
|
|
13
|
+
ExtensionState2["onHandleRequest"] = "onHandleRequest";
|
|
14
|
+
ExtensionState2["onRequest"] = "onRequest";
|
|
15
|
+
ExtensionState2["onResponse"] = "onResponse";
|
|
16
|
+
ExtensionState2["withContext"] = "withContext";
|
|
17
|
+
ExtensionState2["withTenantId"] = "withTenantId";
|
|
18
|
+
ExtensionState2["withUserId"] = "withUserId";
|
|
19
|
+
return ExtensionState2;
|
|
20
|
+
})(ExtensionState || {});
|
|
11
21
|
var APIErrorErrorCodeEnum = {
|
|
12
22
|
InternalError: "internal_error",
|
|
13
23
|
BadRequest: "bad_request",
|
|
@@ -63,21 +73,18 @@ var appRoutes = (prefix = DEFAULT_PREFIX) => ({
|
|
|
63
73
|
INVITE: `${prefix}${"/tenants/{tenantId}/invite" /* INVITE */}`,
|
|
64
74
|
LOG: `${prefix}/_log`
|
|
65
75
|
});
|
|
66
|
-
var apiRoutes = (
|
|
67
|
-
ME: makeRestUrl(
|
|
68
|
-
USERS: (qp) => makeRestUrl(
|
|
69
|
-
USER: (userId) => makeRestUrl(
|
|
70
|
-
TENANTS: makeRestUrl(
|
|
71
|
-
TENANT: (tenantId) => makeRestUrl(
|
|
72
|
-
SIGNUP: makeRestUrl(
|
|
73
|
-
TENANT_USERS: (tenantId) => makeRestUrl(
|
|
74
|
-
INVITES: (tenantId) => makeRestUrl(
|
|
75
|
-
INVITE: (tenantId) => makeRestUrl(
|
|
76
|
-
TENANT_USER: makeRestUrl(
|
|
77
|
-
|
|
78
|
-
`/tenants/${config.tenantId}/users/${config.userId}`
|
|
79
|
-
),
|
|
80
|
-
USER_TENANTS: (userId) => makeRestUrl(config, `/users/${userId}/tenants`)
|
|
76
|
+
var apiRoutes = (apiUrl) => ({
|
|
77
|
+
ME: makeRestUrl(apiUrl, "/me"),
|
|
78
|
+
USERS: (qp) => makeRestUrl(apiUrl, "/users", qp),
|
|
79
|
+
USER: (userId) => makeRestUrl(apiUrl, `/users/${userId}`),
|
|
80
|
+
TENANTS: makeRestUrl(apiUrl, "/tenants"),
|
|
81
|
+
TENANT: (tenantId) => makeRestUrl(apiUrl, `/tenants/${tenantId}`),
|
|
82
|
+
SIGNUP: makeRestUrl(apiUrl, "/signup"),
|
|
83
|
+
TENANT_USERS: (tenantId) => makeRestUrl(apiUrl, `/tenants/${tenantId}/users`),
|
|
84
|
+
INVITES: (tenantId) => makeRestUrl(apiUrl, `/tenants/${tenantId}/invites`),
|
|
85
|
+
INVITE: (tenantId) => makeRestUrl(apiUrl, `/tenants/${tenantId}/invite`),
|
|
86
|
+
TENANT_USER: (tenantId, userId) => makeRestUrl(apiUrl, `/tenants/${tenantId}/users/${userId}`),
|
|
87
|
+
USER_TENANTS: (userId) => makeRestUrl(apiUrl, `/users/${userId}/tenants`)
|
|
81
88
|
});
|
|
82
89
|
var proxyRoutes = (config) => ({
|
|
83
90
|
SIGNIN: makeRestUrl(config, "/auth/signin" /* SIGNIN */),
|
|
@@ -101,8 +108,8 @@ function filterNullUndefined(obj) {
|
|
|
101
108
|
)
|
|
102
109
|
);
|
|
103
110
|
}
|
|
104
|
-
function makeRestUrl(
|
|
105
|
-
const url =
|
|
111
|
+
function makeRestUrl(apiUrl, path, qp) {
|
|
112
|
+
const url = apiUrl || NILEDB_API_URL;
|
|
106
113
|
if (!url) {
|
|
107
114
|
throw new Error(
|
|
108
115
|
"An API url is required. Set it via NILEDB_API_URL. Was auto configuration run?"
|
|
@@ -126,9 +133,309 @@ function isUUID(value) {
|
|
|
126
133
|
return regex.test(value);
|
|
127
134
|
}
|
|
128
135
|
|
|
136
|
+
// src/utils/Logger.ts
|
|
137
|
+
var red = "\x1B[31m";
|
|
138
|
+
var yellow = "\x1B[38;2;255;255;0m";
|
|
139
|
+
var purple = "\x1B[38;2;200;160;255m";
|
|
140
|
+
var orange = "\x1B[38;2;255;165;0m";
|
|
141
|
+
var reset = "\x1B[0m";
|
|
142
|
+
var baseLogger = (config, ...params) => ({
|
|
143
|
+
silly(message, meta) {
|
|
144
|
+
if (config?.debug && process.env.LOG_LEVEL === "silly") {
|
|
145
|
+
console.log(
|
|
146
|
+
`${orange}[niledb]${reset}${purple}[DEBUG]${reset}${params.join(
|
|
147
|
+
""
|
|
148
|
+
)}${reset} ${message}`,
|
|
149
|
+
meta ? `${JSON.stringify(meta)}` : ""
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
info(message, meta) {
|
|
154
|
+
if (config?.debug) {
|
|
155
|
+
console.info(
|
|
156
|
+
`${orange}[niledb]${reset}${purple}[DEBUG]${reset}${params.join(
|
|
157
|
+
""
|
|
158
|
+
)}${reset} ${message}`,
|
|
159
|
+
meta ? `${JSON.stringify(meta)}` : ""
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
debug(message, meta) {
|
|
164
|
+
if (config?.debug) {
|
|
165
|
+
console.log(
|
|
166
|
+
`${orange}[niledb]${reset}${purple}[DEBUG]${reset}${params.join(
|
|
167
|
+
""
|
|
168
|
+
)}${reset} ${message}`,
|
|
169
|
+
meta ? `${JSON.stringify(meta)}` : ""
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
warn(message, meta) {
|
|
174
|
+
if (config?.debug) {
|
|
175
|
+
console.warn(
|
|
176
|
+
`${orange}[niledb]${reset}${yellow}[WARN]${reset}${params.join(
|
|
177
|
+
""
|
|
178
|
+
)}${reset} ${message}`,
|
|
179
|
+
meta ? JSON.stringify(meta) : ""
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
error(message, meta) {
|
|
184
|
+
console.error(
|
|
185
|
+
`${orange}[niledb]${reset}${red}[ERROR]${reset}${params.join(
|
|
186
|
+
""
|
|
187
|
+
)}${red} ${message}`,
|
|
188
|
+
meta ? meta : "",
|
|
189
|
+
`${reset}`
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
function Logger(config) {
|
|
194
|
+
return (prefixes) => {
|
|
195
|
+
const { info, debug, warn: warn2, error, silly: silly2 } = config && typeof config?.logger === "function" ? config.logger(prefixes) : baseLogger(config, prefixes);
|
|
196
|
+
return {
|
|
197
|
+
info,
|
|
198
|
+
debug,
|
|
199
|
+
warn: warn2,
|
|
200
|
+
error,
|
|
201
|
+
silly: silly2
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function matchesLog(configRoutes, request2) {
|
|
206
|
+
return urlMatches(request2.url, configRoutes.LOG);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// src/api/utils/extensions.ts
|
|
210
|
+
function getRequestConfig(params) {
|
|
211
|
+
if (typeof params[1] === "object") {
|
|
212
|
+
return params[1];
|
|
213
|
+
}
|
|
214
|
+
return {};
|
|
215
|
+
}
|
|
216
|
+
function bindRunExtensions(instance) {
|
|
217
|
+
return async function runExtensions(toRun, config, params, _init) {
|
|
218
|
+
const { debug } = config.logger("[EXTENSIONS]");
|
|
219
|
+
const extensionConfig = getRequestConfig(
|
|
220
|
+
Array.isArray(params) ? params : [null, params]
|
|
221
|
+
);
|
|
222
|
+
if (config.extensions) {
|
|
223
|
+
for (const create2 of config.extensions) {
|
|
224
|
+
if (typeof create2 !== "function") {
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
const ext = create2(instance);
|
|
228
|
+
if (extensionConfig.disableExtensions?.includes(ext.id)) {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (ext.withTenantId && toRun === "withTenantId" /* withTenantId */) {
|
|
232
|
+
ctx.set({
|
|
233
|
+
tenantId: await ext.withTenantId()
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
if (ext.withUserId && toRun === "withUserId" /* withUserId */) {
|
|
237
|
+
ctx.set({ userId: await ext.withUserId() });
|
|
238
|
+
}
|
|
239
|
+
if (ext.withContext && toRun === "withContext" /* withContext */) {
|
|
240
|
+
await ext.withContext(ctx);
|
|
241
|
+
}
|
|
242
|
+
if (ext.onHandleRequest && toRun === "onHandleRequest" /* onHandleRequest */) {
|
|
243
|
+
const result = await ext.onHandleRequest(
|
|
244
|
+
Array.isArray(params) ? params : [params]
|
|
245
|
+
);
|
|
246
|
+
debug(`${ext.id ?? create2.name} ran onHandleRequest`);
|
|
247
|
+
if (result != null) {
|
|
248
|
+
return result;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const [param] = Array.isArray(params) ? params : [params];
|
|
252
|
+
if (ext.onRequest && toRun === "onRequest" /* onRequest */) {
|
|
253
|
+
const { ...previousContext } = ctx.get();
|
|
254
|
+
if (!_init) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
const previousHeaders = new Headers(previousContext.headers);
|
|
258
|
+
await ext.onRequest(_init.request, ctx);
|
|
259
|
+
const updatedContext = ctx.get();
|
|
260
|
+
if (updatedContext?.headers) {
|
|
261
|
+
const cookie = updatedContext.headers.get("cookie");
|
|
262
|
+
if (cookie && param.headers) {
|
|
263
|
+
const updatedCookies = mergeCookies(
|
|
264
|
+
previousHeaders?.get("cookie"),
|
|
265
|
+
updatedContext.headers.get("cookie")
|
|
266
|
+
);
|
|
267
|
+
param.headers.set("cookie", updatedCookies);
|
|
268
|
+
}
|
|
269
|
+
if (updatedContext.tenantId && param.headers) {
|
|
270
|
+
param.headers.set(
|
|
271
|
+
TENANT_COOKIE,
|
|
272
|
+
String(updatedContext.headers.get(TENANT_COOKIE))
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
ctx.set({ headers: param.headers });
|
|
276
|
+
}
|
|
277
|
+
debug(`${ext.id ?? create2.name} ran onRequest`);
|
|
278
|
+
}
|
|
279
|
+
if (ext.onResponse && toRun === "onResponse" /* onResponse */) {
|
|
280
|
+
const result = await ext.onResponse(param, ctx);
|
|
281
|
+
debug(`${ext.id ?? create2.name} ran onResponse`);
|
|
282
|
+
if (result != null) {
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return void 0;
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
function buildExtensionConfig(instance) {
|
|
292
|
+
return {
|
|
293
|
+
runExtensions: bindRunExtensions(instance)
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
function mergeCookies(...cookieStrings) {
|
|
297
|
+
const cookieMap = /* @__PURE__ */ new Map();
|
|
298
|
+
for (const str of cookieStrings) {
|
|
299
|
+
if (!str) continue;
|
|
300
|
+
for (const part of str.split(";")) {
|
|
301
|
+
const [key17, value] = part.split("=").map((s) => s.trim());
|
|
302
|
+
if (key17 && value) cookieMap.set(key17, value);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return [...cookieMap.entries()].map(([k, v]) => `${k}=${v}`).join("; ");
|
|
306
|
+
}
|
|
307
|
+
async function runExtensionContext(config) {
|
|
308
|
+
await config?.extensionCtx?.runExtensions("withContext" /* withContext */, config);
|
|
309
|
+
await config?.extensionCtx?.runExtensions(
|
|
310
|
+
"withTenantId" /* withTenantId */,
|
|
311
|
+
config
|
|
312
|
+
);
|
|
313
|
+
await config?.extensionCtx?.runExtensions("withUserId" /* withUserId */, config);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// src/api/utils/request-context.ts
|
|
317
|
+
var { warn, silly } = Logger({ debug: true })("[REQUEST CONTEXT]");
|
|
318
|
+
var storage = new async_hooks.AsyncLocalStorage();
|
|
319
|
+
var defaultContext = {
|
|
320
|
+
headers: new Headers(),
|
|
321
|
+
tenantId: void 0,
|
|
322
|
+
userId: void 0
|
|
323
|
+
};
|
|
324
|
+
var lastUsedContext = defaultContext;
|
|
325
|
+
var ctx = {
|
|
326
|
+
run(ctx2, fn) {
|
|
327
|
+
const merged = {
|
|
328
|
+
...defaultContext,
|
|
329
|
+
...ctx2,
|
|
330
|
+
headers: ctx2.headers instanceof Headers ? ctx2.headers : new Headers(ctx2.headers)
|
|
331
|
+
};
|
|
332
|
+
lastUsedContext = merged;
|
|
333
|
+
return storage.run(merged, fn);
|
|
334
|
+
},
|
|
335
|
+
get: () => {
|
|
336
|
+
const ctx2 = storage.getStore();
|
|
337
|
+
if (!ctx2) {
|
|
338
|
+
return { ...defaultContext };
|
|
339
|
+
}
|
|
340
|
+
silly(`[GET] ${serializeContext(ctx2)}`);
|
|
341
|
+
return ctx2;
|
|
342
|
+
},
|
|
343
|
+
/**
|
|
344
|
+
* This is a mirror of Server.getContext, but only for requests. We keep only the request
|
|
345
|
+
* information around, everything else is :above_my_pay_grade:
|
|
346
|
+
* @param partial A partial context to override
|
|
347
|
+
*/
|
|
348
|
+
set: (partial) => {
|
|
349
|
+
const store = storage.getStore();
|
|
350
|
+
if (!store) {
|
|
351
|
+
warn("ctx.set() called outside of ctx.run(). This will not persist.");
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
if (partial.headers === null) {
|
|
355
|
+
store.headers = new Headers();
|
|
356
|
+
} else if (partial.headers && store.headers instanceof Headers) {
|
|
357
|
+
for (const [key17, value] of new Headers(partial.headers).entries()) {
|
|
358
|
+
if (key17.toLowerCase() === "cookie") {
|
|
359
|
+
const existingCookies = parseCookieHeader(
|
|
360
|
+
store.headers.get("cookie") || ""
|
|
361
|
+
);
|
|
362
|
+
const newCookies = parseCookieHeader(value);
|
|
363
|
+
const mergedCookies = { ...existingCookies, ...newCookies };
|
|
364
|
+
store.headers.set("cookie", serializeCookies(mergedCookies));
|
|
365
|
+
} else {
|
|
366
|
+
store.headers.set(key17, value);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if ("tenantId" in partial) store.tenantId = partial.tenantId;
|
|
371
|
+
if ("userId" in partial) store.userId = partial.userId;
|
|
372
|
+
silly(`[SET] ${serializeContext(store)}`);
|
|
373
|
+
lastUsedContext = { ...store };
|
|
374
|
+
},
|
|
375
|
+
// for convenience only
|
|
376
|
+
getLastUsed: () => lastUsedContext
|
|
377
|
+
};
|
|
378
|
+
function withNileContext(config, fn, name = "unknown") {
|
|
379
|
+
const initialContext = config.context;
|
|
380
|
+
const existing = ctx.get();
|
|
381
|
+
const mergedHeaders = new Headers(existing.headers);
|
|
382
|
+
if (initialContext instanceof Request) {
|
|
383
|
+
initialContext.headers.forEach((value, key17) => {
|
|
384
|
+
mergedHeaders.set(key17, value);
|
|
385
|
+
});
|
|
386
|
+
const context2 = {
|
|
387
|
+
headers: mergedHeaders,
|
|
388
|
+
tenantId: existing.tenantId,
|
|
389
|
+
userId: existing.userId
|
|
390
|
+
};
|
|
391
|
+
silly(`${name} [INITIAL - Request] ${serializeContext(context2)}`);
|
|
392
|
+
return ctx.run(context2, fn);
|
|
393
|
+
}
|
|
394
|
+
if (initialContext.headers) {
|
|
395
|
+
const incoming = initialContext.headers instanceof Headers ? initialContext.headers : new Headers(initialContext.headers);
|
|
396
|
+
incoming.forEach((value, key17) => {
|
|
397
|
+
mergedHeaders.set(key17, value);
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
const hasTenantId = "tenantId" in initialContext;
|
|
401
|
+
const hasUserId = "userId" in initialContext;
|
|
402
|
+
const context = {
|
|
403
|
+
headers: mergedHeaders,
|
|
404
|
+
tenantId: hasTenantId ? initialContext.tenantId : existing.tenantId,
|
|
405
|
+
userId: hasUserId ? initialContext.userId : existing.userId
|
|
406
|
+
};
|
|
407
|
+
silly(`${name} [INITIAL - Partial<Context>] ${serializeContext(context)}`);
|
|
408
|
+
return ctx.run(context, async () => {
|
|
409
|
+
await runExtensionContext(config);
|
|
410
|
+
return fn();
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
function serializeContext(context) {
|
|
414
|
+
const headers = {};
|
|
415
|
+
const rawHeaders = new Headers(context.headers);
|
|
416
|
+
rawHeaders.forEach((value, key17) => {
|
|
417
|
+
headers[key17] = value;
|
|
418
|
+
});
|
|
419
|
+
return JSON.stringify({
|
|
420
|
+
headers,
|
|
421
|
+
tenantId: context.tenantId,
|
|
422
|
+
userId: context.userId
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
function parseCookieHeader(header) {
|
|
426
|
+
return header.split(";").map((c) => c.trim()).filter(Boolean).reduce((acc, curr) => {
|
|
427
|
+
const [key17, ...val] = curr.split("=");
|
|
428
|
+
if (key17) acc[key17] = val.join("=");
|
|
429
|
+
return acc;
|
|
430
|
+
}, {});
|
|
431
|
+
}
|
|
432
|
+
function serializeCookies(cookies) {
|
|
433
|
+
return Object.entries(cookies).map(([k, v]) => `${k}=${v}`).join("; ");
|
|
434
|
+
}
|
|
435
|
+
|
|
129
436
|
// src/api/utils/request.ts
|
|
130
437
|
async function request(url, _init, config) {
|
|
131
|
-
const { debug, info, error } = config.logger("[REQUEST]");
|
|
438
|
+
const { debug, info, error, warn: warn2 } = config.logger("[REQUEST]");
|
|
132
439
|
const { request: request2, ...init } = _init;
|
|
133
440
|
const requestUrl = new URL(request2.url);
|
|
134
441
|
const updatedHeaders = new Headers({});
|
|
@@ -162,9 +469,17 @@ async function request(url, _init, config) {
|
|
|
162
469
|
if (passedOrigin) {
|
|
163
470
|
updatedHeaders.set(HEADER_ORIGIN, passedOrigin);
|
|
164
471
|
} else {
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
472
|
+
const { headers } = ctx.get();
|
|
473
|
+
const host = headers.get("host");
|
|
474
|
+
if (host) {
|
|
475
|
+
const serverSideOrigin = `${getProtocolFromHeaders(headers)}://${host}`;
|
|
476
|
+
updatedHeaders.set(HEADER_ORIGIN, serverSideOrigin);
|
|
477
|
+
debug(`Obtained origin from server side headers ${serverSideOrigin}`);
|
|
478
|
+
} else {
|
|
479
|
+
const reqOrigin = config.routePrefix !== DEFAULT_PREFIX ? `${requestUrl.origin}${config.routePrefix}` : requestUrl.origin;
|
|
480
|
+
updatedHeaders.set(HEADER_ORIGIN, reqOrigin);
|
|
481
|
+
debug(`Obtained origin from request ${reqOrigin}`);
|
|
482
|
+
}
|
|
168
483
|
}
|
|
169
484
|
}
|
|
170
485
|
const params = { ...init };
|
|
@@ -189,7 +504,12 @@ async function request(url, _init, config) {
|
|
|
189
504
|
params.headers.set("request-id", crypto.randomUUID());
|
|
190
505
|
params.cache = "no-store";
|
|
191
506
|
}
|
|
192
|
-
await config.extensionCtx?.
|
|
507
|
+
await config.extensionCtx?.runExtensions(
|
|
508
|
+
"onRequest" /* onRequest */,
|
|
509
|
+
config,
|
|
510
|
+
params,
|
|
511
|
+
_init
|
|
512
|
+
);
|
|
193
513
|
try {
|
|
194
514
|
const res = await fetch(fullUrl, {
|
|
195
515
|
...params
|
|
@@ -209,6 +529,14 @@ async function request(url, _init, config) {
|
|
|
209
529
|
statusText: res?.statusText,
|
|
210
530
|
text: await loggingRes?.text()
|
|
211
531
|
});
|
|
532
|
+
const updatedRes = await config.extensionCtx?.runExtensions(
|
|
533
|
+
"onResponse" /* onResponse */,
|
|
534
|
+
config,
|
|
535
|
+
{ ...params, response: res }
|
|
536
|
+
);
|
|
537
|
+
if (updatedRes) {
|
|
538
|
+
return updatedRes;
|
|
539
|
+
}
|
|
212
540
|
return res;
|
|
213
541
|
} catch (e) {
|
|
214
542
|
if (e instanceof Error) {
|
|
@@ -223,6 +551,19 @@ async function request(url, _init, config) {
|
|
|
223
551
|
);
|
|
224
552
|
}
|
|
225
553
|
}
|
|
554
|
+
function getProtocolFromHeaders(headers) {
|
|
555
|
+
const get = (key17) => headers instanceof Headers ? headers.get(key17) : headers[key17.toLowerCase()];
|
|
556
|
+
const xfp = get("x-forwarded-proto");
|
|
557
|
+
if (xfp) return xfp.toLowerCase();
|
|
558
|
+
const forwarded = get("forwarded");
|
|
559
|
+
if (forwarded) {
|
|
560
|
+
const match = forwarded.match(/proto=(https?)/i);
|
|
561
|
+
if (match) return match[1].toLowerCase();
|
|
562
|
+
}
|
|
563
|
+
const ref = get("referer") || get("origin");
|
|
564
|
+
if (ref && ref.startsWith("https")) return "https";
|
|
565
|
+
return "http";
|
|
566
|
+
}
|
|
226
567
|
|
|
227
568
|
// src/api/utils/auth.ts
|
|
228
569
|
async function auth(req, config) {
|
|
@@ -232,16 +573,13 @@ async function auth(req, config) {
|
|
|
232
573
|
info(`using session ${sessionUrl}`);
|
|
233
574
|
req.headers.delete("content-length");
|
|
234
575
|
const res = await request(sessionUrl, { request: req }, config);
|
|
235
|
-
if (!res) {
|
|
236
|
-
info("no session found");
|
|
237
|
-
return void 0;
|
|
238
|
-
}
|
|
239
|
-
info("session active");
|
|
240
576
|
try {
|
|
241
577
|
const session = await new Response(res.body).json();
|
|
242
578
|
if (Object.keys(session).length === 0) {
|
|
579
|
+
info("no session found");
|
|
243
580
|
return void 0;
|
|
244
581
|
}
|
|
582
|
+
info("session active");
|
|
245
583
|
return session;
|
|
246
584
|
} catch (e) {
|
|
247
585
|
error(e);
|
|
@@ -252,7 +590,7 @@ async function auth(req, config) {
|
|
|
252
590
|
// src/api/routes/me/index.ts
|
|
253
591
|
var key = "ME";
|
|
254
592
|
async function route(request2, config) {
|
|
255
|
-
const url = apiRoutes(config)[key];
|
|
593
|
+
const url = apiRoutes(config.apiUrl)[key];
|
|
256
594
|
if (request2.method === "GET") {
|
|
257
595
|
return await GET(url, { request: request2 }, config);
|
|
258
596
|
}
|
|
@@ -273,8 +611,9 @@ function matches(configRoutes, request2) {
|
|
|
273
611
|
}
|
|
274
612
|
async function fetchMe(config, method, body) {
|
|
275
613
|
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/me" /* ME */}`;
|
|
614
|
+
const { headers } = ctx.get();
|
|
276
615
|
const init = {
|
|
277
|
-
headers
|
|
616
|
+
headers,
|
|
278
617
|
method: method ?? "GET"
|
|
279
618
|
};
|
|
280
619
|
if (method === "PUT") {
|
|
@@ -326,9 +665,9 @@ function getTokenFromCookie(headers, cookieKey) {
|
|
|
326
665
|
return _cookies[cookieKey];
|
|
327
666
|
}
|
|
328
667
|
}
|
|
329
|
-
function getTenantFromHttp(headers,
|
|
668
|
+
function getTenantFromHttp(headers, context) {
|
|
330
669
|
const cookieTenant = getTokenFromCookie(headers, TENANT_COOKIE);
|
|
331
|
-
return cookieTenant ? cookieTenant :
|
|
670
|
+
return cookieTenant ? cookieTenant : context?.tenantId;
|
|
332
671
|
}
|
|
333
672
|
|
|
334
673
|
// src/api/routes/users/POST.ts
|
|
@@ -338,8 +677,11 @@ async function POST(config, init) {
|
|
|
338
677
|
const yurl = new URL(init.request.url);
|
|
339
678
|
const tenantId = yurl.searchParams.get("tenantId");
|
|
340
679
|
const newTenantName = yurl.searchParams.get("newTenantName");
|
|
341
|
-
const tenant = tenantId ?? getTenantFromHttp(init.request.headers
|
|
342
|
-
const url = apiRoutes(config).USERS({
|
|
680
|
+
const tenant = tenantId ?? getTenantFromHttp(init.request.headers);
|
|
681
|
+
const url = apiRoutes(config.apiUrl).USERS({
|
|
682
|
+
tenantId: tenant,
|
|
683
|
+
newTenantName
|
|
684
|
+
});
|
|
343
685
|
return await request(url, init, config);
|
|
344
686
|
}
|
|
345
687
|
|
|
@@ -347,13 +689,13 @@ async function POST(config, init) {
|
|
|
347
689
|
async function GET2(config, init, log) {
|
|
348
690
|
const yurl = new URL(init.request.url);
|
|
349
691
|
const tenantId = yurl.searchParams.get("tenantId");
|
|
350
|
-
const tenant = tenantId ?? getTenantFromHttp(init.request.headers, config);
|
|
692
|
+
const tenant = tenantId ?? getTenantFromHttp(init.request.headers, config.context);
|
|
351
693
|
if (!tenant) {
|
|
352
694
|
log("[GET] No tenant id provided.");
|
|
353
695
|
return new Response(null, { status: 404 });
|
|
354
696
|
}
|
|
355
697
|
init.method = "GET";
|
|
356
|
-
const url = apiRoutes(config).TENANT_USERS(tenant);
|
|
698
|
+
const url = apiRoutes(config.apiUrl).TENANT_USERS(tenant);
|
|
357
699
|
return await request(url, init, config);
|
|
358
700
|
}
|
|
359
701
|
|
|
@@ -362,7 +704,7 @@ async function PUT2(config, init) {
|
|
|
362
704
|
init.body = init.request.body;
|
|
363
705
|
init.method = "PUT";
|
|
364
706
|
const [userId] = new URL(init.request.url).pathname.split("/").reverse();
|
|
365
|
-
const url = apiRoutes(config).USER(userId);
|
|
707
|
+
const url = apiRoutes(config.apiUrl).USER(userId);
|
|
366
708
|
return await request(url, init, config);
|
|
367
709
|
}
|
|
368
710
|
|
|
@@ -389,7 +731,7 @@ function matches2(configRoutes, request2) {
|
|
|
389
731
|
async function GET3(config, init) {
|
|
390
732
|
const yurl = new URL(init.request.url);
|
|
391
733
|
const [, tenantId] = yurl.pathname.split("/").reverse();
|
|
392
|
-
const url = `${apiRoutes(config).TENANT_USERS(tenantId)}`;
|
|
734
|
+
const url = `${apiRoutes(config.apiUrl).TENANT_USERS(tenantId)}`;
|
|
393
735
|
return await request(url, init, config);
|
|
394
736
|
}
|
|
395
737
|
|
|
@@ -403,7 +745,7 @@ async function POST2(config, init) {
|
|
|
403
745
|
const [, tenantId] = yurl.pathname.split("/").reverse();
|
|
404
746
|
init.body = JSON.stringify({ email: session.email });
|
|
405
747
|
init.method = "POST";
|
|
406
|
-
const url = apiRoutes(config).TENANT_USERS(tenantId);
|
|
748
|
+
const url = apiRoutes(config.apiUrl).TENANT_USERS(tenantId);
|
|
407
749
|
return await request(url, init, config);
|
|
408
750
|
}
|
|
409
751
|
|
|
@@ -437,12 +779,13 @@ function matches3(configRoutes, request2) {
|
|
|
437
779
|
}
|
|
438
780
|
async function fetchTenantUsers(config, method, payload) {
|
|
439
781
|
const { body, params } = {};
|
|
440
|
-
|
|
782
|
+
const { tenantId, headers } = ctx.get();
|
|
783
|
+
if (!tenantId) {
|
|
441
784
|
throw new Error(
|
|
442
785
|
"Unable to fetch the user's tenants, the tenantId context is missing. Call nile.setContext({ tenantId })"
|
|
443
786
|
);
|
|
444
787
|
}
|
|
445
|
-
if (!isUUID(
|
|
788
|
+
if (!isUUID(tenantId)) {
|
|
446
789
|
config.logger("fetchTenantUsers").warn(
|
|
447
790
|
"nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
|
|
448
791
|
);
|
|
@@ -454,14 +797,11 @@ async function fetchTenantUsers(config, method, payload) {
|
|
|
454
797
|
if (params?.tenantId) {
|
|
455
798
|
q.set("tenantId", params.tenantId);
|
|
456
799
|
}
|
|
457
|
-
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/users" /* TENANT_USERS */.replace(
|
|
458
|
-
"{tenantId}",
|
|
459
|
-
config.tenantId
|
|
460
|
-
)}`;
|
|
800
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/users" /* TENANT_USERS */.replace("{tenantId}", tenantId)}`;
|
|
461
801
|
const m = method;
|
|
462
802
|
const init = {
|
|
463
803
|
method: m,
|
|
464
|
-
headers
|
|
804
|
+
headers
|
|
465
805
|
};
|
|
466
806
|
const req = new Request(clientUrl, init);
|
|
467
807
|
return await config.handlers[m](req);
|
|
@@ -478,9 +818,9 @@ async function PUT3(config, init) {
|
|
|
478
818
|
init.body = new URLSearchParams(yurl.searchParams).toString();
|
|
479
819
|
}
|
|
480
820
|
init.method = "PUT";
|
|
481
|
-
const url = `${apiRoutes(config).INVITE(tenantId)}`;
|
|
821
|
+
const url = `${apiRoutes(config.apiUrl).INVITE(tenantId)}`;
|
|
482
822
|
const res = await request(url, init, config);
|
|
483
|
-
const location = res?.headers
|
|
823
|
+
const location = res?.headers?.get("location");
|
|
484
824
|
if (location) {
|
|
485
825
|
return new Response(res?.body, {
|
|
486
826
|
status: 302,
|
|
@@ -502,7 +842,7 @@ async function POST3(config, init) {
|
|
|
502
842
|
}
|
|
503
843
|
init.method = "POST";
|
|
504
844
|
init.body = init.request.body;
|
|
505
|
-
const url = `${apiRoutes(config).INVITE(tenantId)}`;
|
|
845
|
+
const url = `${apiRoutes(config.apiUrl).INVITE(tenantId)}`;
|
|
506
846
|
return await request(url, init, config);
|
|
507
847
|
}
|
|
508
848
|
|
|
@@ -528,21 +868,22 @@ function matches4(configRoutes, request2) {
|
|
|
528
868
|
return urlMatches(request2.url, route20);
|
|
529
869
|
}
|
|
530
870
|
async function fetchInvite(config, method, body) {
|
|
531
|
-
|
|
871
|
+
const { headers, tenantId } = ctx.get();
|
|
872
|
+
if (!tenantId) {
|
|
532
873
|
throw new Error(
|
|
533
874
|
"Unable to fetch the invite for the tenant, the tenantId context is missing. Call nile.setContext({ tenantId })"
|
|
534
875
|
);
|
|
535
876
|
}
|
|
536
|
-
if (!isUUID(
|
|
877
|
+
if (!isUUID(tenantId)) {
|
|
537
878
|
config.logger("fetchInvite").warn(
|
|
538
879
|
"nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
|
|
539
880
|
);
|
|
540
881
|
}
|
|
541
|
-
let clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/invite" /* INVITE */.replace("{tenantId}",
|
|
882
|
+
let clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/invite" /* INVITE */.replace("{tenantId}", tenantId)}`;
|
|
542
883
|
const m = method ?? "GET";
|
|
543
884
|
const init = {
|
|
544
885
|
method: m,
|
|
545
|
-
headers
|
|
886
|
+
headers
|
|
546
887
|
};
|
|
547
888
|
if (method === "POST" || method === "PUT") {
|
|
548
889
|
init.body = body;
|
|
@@ -562,7 +903,7 @@ async function GET4(config, init) {
|
|
|
562
903
|
return new Response(null, { status: 404 });
|
|
563
904
|
}
|
|
564
905
|
init.method = "GET";
|
|
565
|
-
const url = `${apiRoutes(config).INVITES(tenantId)}`;
|
|
906
|
+
const url = `${apiRoutes(config.apiUrl).INVITES(tenantId)}`;
|
|
566
907
|
return await request(url, init, config);
|
|
567
908
|
}
|
|
568
909
|
|
|
@@ -583,29 +924,29 @@ function matches5(configRoutes, request2) {
|
|
|
583
924
|
return url.pathname.endsWith(route20);
|
|
584
925
|
}
|
|
585
926
|
async function fetchInvites(config) {
|
|
586
|
-
|
|
927
|
+
const { tenantId, headers } = ctx.get();
|
|
928
|
+
if (!tenantId) {
|
|
587
929
|
throw new Error(
|
|
588
930
|
"Unable to fetch invites for the tenant, the tenantId context is missing. Call nile.setContext({ tenantId })"
|
|
589
931
|
);
|
|
590
932
|
}
|
|
591
|
-
if (!isUUID(
|
|
933
|
+
if (!isUUID(tenantId)) {
|
|
592
934
|
config.logger("fetchInvites").warn(
|
|
593
935
|
"nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
|
|
594
936
|
);
|
|
595
937
|
}
|
|
596
|
-
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/invites" /* INVITES */.replace("{tenantId}",
|
|
597
|
-
const req = new Request(clientUrl, { headers
|
|
938
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/invites" /* INVITES */.replace("{tenantId}", tenantId)}`;
|
|
939
|
+
const req = new Request(clientUrl, { headers });
|
|
598
940
|
return await config.handlers.GET(req);
|
|
599
941
|
}
|
|
600
942
|
|
|
601
943
|
// src/api/routes/tenants/GET.ts
|
|
602
944
|
async function GET5(config, session, init) {
|
|
603
|
-
let url = `${apiRoutes(config).USER_TENANTS(session.id)}`;
|
|
945
|
+
let url = `${apiRoutes(config.apiUrl).USER_TENANTS(session.id)}`;
|
|
604
946
|
if (typeof session === "object" && "user" in session && session.user) {
|
|
605
|
-
url = `${apiRoutes(config).USER_TENANTS(session.user.id)}`;
|
|
947
|
+
url = `${apiRoutes(config.apiUrl).USER_TENANTS(session.user.id)}`;
|
|
606
948
|
}
|
|
607
|
-
|
|
608
|
-
return res;
|
|
949
|
+
return await request(url, init, config);
|
|
609
950
|
}
|
|
610
951
|
|
|
611
952
|
// src/api/routes/tenants/[tenantId]/GET.ts
|
|
@@ -617,7 +958,7 @@ async function GET6(config, init, log) {
|
|
|
617
958
|
return new Response(null, { status: 404 });
|
|
618
959
|
}
|
|
619
960
|
init.method = "GET";
|
|
620
|
-
const url = `${apiRoutes(config).TENANT(tenantId)}`;
|
|
961
|
+
const url = `${apiRoutes(config.apiUrl).TENANT(tenantId)}`;
|
|
621
962
|
return await request(url, init, config);
|
|
622
963
|
}
|
|
623
964
|
|
|
@@ -629,7 +970,7 @@ async function DELETE2(config, init) {
|
|
|
629
970
|
return new Response(null, { status: 404 });
|
|
630
971
|
}
|
|
631
972
|
init.method = "DELETE";
|
|
632
|
-
const url = `${apiRoutes(config).TENANT(tenantId)}`;
|
|
973
|
+
const url = `${apiRoutes(config.apiUrl).TENANT(tenantId)}`;
|
|
633
974
|
return await request(url, init, config);
|
|
634
975
|
}
|
|
635
976
|
|
|
@@ -642,7 +983,7 @@ async function PUT4(config, init) {
|
|
|
642
983
|
}
|
|
643
984
|
init.body = init.request.body;
|
|
644
985
|
init.method = "PUT";
|
|
645
|
-
const url = `${apiRoutes(config).TENANT(tenantId)}`;
|
|
986
|
+
const url = `${apiRoutes(config.apiUrl).TENANT(tenantId)}`;
|
|
646
987
|
return await request(url, init, config);
|
|
647
988
|
}
|
|
648
989
|
|
|
@@ -650,7 +991,7 @@ async function PUT4(config, init) {
|
|
|
650
991
|
async function POST4(config, init) {
|
|
651
992
|
init.body = init.request.body;
|
|
652
993
|
init.method = "POST";
|
|
653
|
-
const url = `${apiRoutes(config).TENANTS}`;
|
|
994
|
+
const url = `${apiRoutes(config.apiUrl).TENANTS}`;
|
|
654
995
|
return await request(url, init, config);
|
|
655
996
|
}
|
|
656
997
|
|
|
@@ -684,10 +1025,11 @@ function matches6(configRoutes, request2) {
|
|
|
684
1025
|
return urlMatches(request2.url, configRoutes[key6]);
|
|
685
1026
|
}
|
|
686
1027
|
async function fetchTenants(config, method, body) {
|
|
1028
|
+
const { headers } = ctx.get();
|
|
687
1029
|
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants" /* TENANTS */}`;
|
|
688
1030
|
const init = {
|
|
689
1031
|
method,
|
|
690
|
-
headers
|
|
1032
|
+
headers
|
|
691
1033
|
};
|
|
692
1034
|
{
|
|
693
1035
|
init.body = body;
|
|
@@ -696,21 +1038,22 @@ async function fetchTenants(config, method, body) {
|
|
|
696
1038
|
return await config.handlers.POST(req);
|
|
697
1039
|
}
|
|
698
1040
|
async function fetchTenant(config, method, body) {
|
|
699
|
-
|
|
1041
|
+
const { headers, tenantId } = ctx.get();
|
|
1042
|
+
if (!tenantId) {
|
|
700
1043
|
throw new Error(
|
|
701
1044
|
"Unable to fetch tenants, the tenantId context is missing. Call nile.setContext({ tenantId })"
|
|
702
1045
|
);
|
|
703
1046
|
}
|
|
704
|
-
if (!isUUID(
|
|
1047
|
+
if (!isUUID(tenantId)) {
|
|
705
1048
|
config.logger("fetch tenant").warn(
|
|
706
1049
|
"nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
|
|
707
1050
|
);
|
|
708
1051
|
}
|
|
709
|
-
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}" /* TENANT */.replace("{tenantId}",
|
|
1052
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}" /* TENANT */.replace("{tenantId}", tenantId)}`;
|
|
710
1053
|
const m = method ?? "GET";
|
|
711
1054
|
const init = {
|
|
712
1055
|
method: m,
|
|
713
|
-
headers
|
|
1056
|
+
headers
|
|
714
1057
|
};
|
|
715
1058
|
if (m === "PUT") {
|
|
716
1059
|
init.body = body;
|
|
@@ -719,32 +1062,33 @@ async function fetchTenant(config, method, body) {
|
|
|
719
1062
|
return await config.handlers[m](req);
|
|
720
1063
|
}
|
|
721
1064
|
async function fetchTenantsByUser(config) {
|
|
722
|
-
const { warn } = config.logger("fetchTenantsByUser");
|
|
723
|
-
|
|
724
|
-
|
|
1065
|
+
const { warn: warn2 } = config.logger(" fetchTenantsByUser ");
|
|
1066
|
+
const { userId, headers } = ctx.get();
|
|
1067
|
+
if (!userId) {
|
|
1068
|
+
warn2(
|
|
725
1069
|
"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."
|
|
726
1070
|
);
|
|
727
|
-
} else if (!isUUID(
|
|
728
|
-
|
|
1071
|
+
} else if (!isUUID(userId)) {
|
|
1072
|
+
warn2(
|
|
729
1073
|
"nile.userId is not a valid UUID. This may lead to unexpected behavior in your application."
|
|
730
1074
|
);
|
|
731
1075
|
}
|
|
732
1076
|
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants" /* TENANTS */}`;
|
|
733
|
-
const req = new Request(clientUrl, { headers
|
|
1077
|
+
const req = new Request(clientUrl, { headers });
|
|
734
1078
|
return await config.handlers.GET(req);
|
|
735
1079
|
}
|
|
736
1080
|
|
|
737
1081
|
// src/api/routes/auth/signin.ts
|
|
738
1082
|
var key7 = "SIGNIN";
|
|
739
1083
|
async function route7(req, config) {
|
|
740
|
-
let url = proxyRoutes(config)[key7];
|
|
1084
|
+
let url = proxyRoutes(config.apiUrl)[key7];
|
|
741
1085
|
const init = {
|
|
742
1086
|
method: req.method,
|
|
743
1087
|
headers: req.headers
|
|
744
1088
|
};
|
|
745
1089
|
if (req.method === "POST") {
|
|
746
1090
|
const [provider] = new URL(req.url).pathname.split("/").reverse();
|
|
747
|
-
url = `${proxyRoutes(config)[key7]}/${provider}`;
|
|
1091
|
+
url = `${proxyRoutes(config.apiUrl)[key7]}/${provider}`;
|
|
748
1092
|
}
|
|
749
1093
|
const passThroughUrl = new URL(req.url);
|
|
750
1094
|
const params = new URLSearchParams(passThroughUrl.search);
|
|
@@ -757,10 +1101,11 @@ function matches7(configRoutes, request2) {
|
|
|
757
1101
|
}
|
|
758
1102
|
async function fetchSignIn(config, provider, body) {
|
|
759
1103
|
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/signin" /* SIGNIN */}/${provider}`;
|
|
1104
|
+
const { headers } = ctx.get();
|
|
760
1105
|
const req = new Request(clientUrl, {
|
|
761
1106
|
method: "POST",
|
|
762
|
-
|
|
763
|
-
|
|
1107
|
+
body,
|
|
1108
|
+
headers
|
|
764
1109
|
});
|
|
765
1110
|
return await config.handlers.POST(req);
|
|
766
1111
|
}
|
|
@@ -768,7 +1113,7 @@ async function fetchSignIn(config, provider, body) {
|
|
|
768
1113
|
// src/api/routes/auth/session.ts
|
|
769
1114
|
async function route8(req, config) {
|
|
770
1115
|
return request(
|
|
771
|
-
proxyRoutes(config).SESSION,
|
|
1116
|
+
proxyRoutes(config.apiUrl).SESSION,
|
|
772
1117
|
{
|
|
773
1118
|
method: req.method,
|
|
774
1119
|
request: req
|
|
@@ -781,9 +1126,10 @@ function matches8(configRoutes, request2) {
|
|
|
781
1126
|
}
|
|
782
1127
|
async function fetchSession(config) {
|
|
783
1128
|
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/session" /* SESSION */}`;
|
|
1129
|
+
const { headers } = ctx.get();
|
|
784
1130
|
const req = new Request(clientUrl, {
|
|
785
1131
|
method: "GET",
|
|
786
|
-
headers
|
|
1132
|
+
headers
|
|
787
1133
|
});
|
|
788
1134
|
return await config.handlers.GET(req);
|
|
789
1135
|
}
|
|
@@ -791,7 +1137,7 @@ async function fetchSession(config) {
|
|
|
791
1137
|
// src/api/routes/auth/providers.ts
|
|
792
1138
|
async function route9(req, config) {
|
|
793
1139
|
return request(
|
|
794
|
-
proxyRoutes(config).PROVIDERS,
|
|
1140
|
+
proxyRoutes(config.apiUrl).PROVIDERS,
|
|
795
1141
|
{
|
|
796
1142
|
method: req.method,
|
|
797
1143
|
request: req
|
|
@@ -804,9 +1150,10 @@ function matches9(configRoutes, request2) {
|
|
|
804
1150
|
}
|
|
805
1151
|
async function fetchProviders(config) {
|
|
806
1152
|
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/providers" /* PROVIDERS */}`;
|
|
1153
|
+
const { headers } = ctx.get();
|
|
807
1154
|
const req = new Request(clientUrl, {
|
|
808
1155
|
method: "GET",
|
|
809
|
-
headers
|
|
1156
|
+
headers
|
|
810
1157
|
});
|
|
811
1158
|
return await config.handlers.GET(req);
|
|
812
1159
|
}
|
|
@@ -814,7 +1161,7 @@ async function fetchProviders(config) {
|
|
|
814
1161
|
// src/api/routes/auth/csrf.ts
|
|
815
1162
|
async function route10(req, config) {
|
|
816
1163
|
return request(
|
|
817
|
-
proxyRoutes(config).CSRF,
|
|
1164
|
+
proxyRoutes(config.apiUrl).CSRF,
|
|
818
1165
|
{
|
|
819
1166
|
method: req.method,
|
|
820
1167
|
request: req
|
|
@@ -827,9 +1174,10 @@ function matches10(configRoutes, request2) {
|
|
|
827
1174
|
}
|
|
828
1175
|
async function fetchCsrf(config) {
|
|
829
1176
|
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/csrf" /* CSRF */}`;
|
|
1177
|
+
const { headers } = ctx.get();
|
|
830
1178
|
const req = new Request(clientUrl, {
|
|
831
1179
|
method: "GET",
|
|
832
|
-
headers
|
|
1180
|
+
headers
|
|
833
1181
|
});
|
|
834
1182
|
return await config.handlers.GET(req);
|
|
835
1183
|
}
|
|
@@ -842,7 +1190,7 @@ async function route11(req, config) {
|
|
|
842
1190
|
try {
|
|
843
1191
|
const passThroughUrl = new URL(req.url);
|
|
844
1192
|
const params = new URLSearchParams(passThroughUrl.search);
|
|
845
|
-
const url = `${proxyRoutes(config)[key8]}/${provider}${params.toString() !== "" ? `?${params.toString()}` : ""}`;
|
|
1193
|
+
const url = `${proxyRoutes(config.apiUrl)[key8]}/${provider}${params.toString() !== "" ? `?${params.toString()}` : ""}`;
|
|
846
1194
|
const res = await request(
|
|
847
1195
|
url,
|
|
848
1196
|
{
|
|
@@ -853,7 +1201,7 @@ async function route11(req, config) {
|
|
|
853
1201
|
).catch((e) => {
|
|
854
1202
|
error("an error as occurred", e);
|
|
855
1203
|
});
|
|
856
|
-
const location = res?.headers
|
|
1204
|
+
const location = res?.headers?.get("location");
|
|
857
1205
|
if (location) {
|
|
858
1206
|
return new Response(res?.body, {
|
|
859
1207
|
status: 302,
|
|
@@ -873,10 +1221,11 @@ function matches11(configRoutes, request2) {
|
|
|
873
1221
|
return urlMatches(request2.url, configRoutes.CALLBACK);
|
|
874
1222
|
}
|
|
875
1223
|
async function fetchCallback(config, provider, body, request2, method = "POST") {
|
|
1224
|
+
const { headers } = ctx.get();
|
|
876
1225
|
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/callback" /* CALLBACK */}/${provider}${request2 ? `?${new URL(request2.url).searchParams}` : ""}`;
|
|
877
1226
|
const req = new Request(clientUrl, {
|
|
878
1227
|
method,
|
|
879
|
-
headers
|
|
1228
|
+
headers,
|
|
880
1229
|
body
|
|
881
1230
|
});
|
|
882
1231
|
return await config.handlers.POST(req);
|
|
@@ -885,14 +1234,14 @@ async function fetchCallback(config, provider, body, request2, method = "POST")
|
|
|
885
1234
|
// src/api/routes/auth/signout.ts
|
|
886
1235
|
var key9 = "SIGNOUT";
|
|
887
1236
|
async function route12(request2, config) {
|
|
888
|
-
let url = proxyRoutes(config)[key9];
|
|
1237
|
+
let url = proxyRoutes(config.apiUrl)[key9];
|
|
889
1238
|
const init = {
|
|
890
1239
|
method: request2.method
|
|
891
1240
|
};
|
|
892
1241
|
if (request2.method === "POST") {
|
|
893
1242
|
init.body = request2.body;
|
|
894
1243
|
const [provider] = new URL(request2.url).pathname.split("/").reverse();
|
|
895
|
-
url = `${proxyRoutes(config)[key9]}${provider !== "signout" ? `/${provider}` : ""}`;
|
|
1244
|
+
url = `${proxyRoutes(config.apiUrl)[key9]}${provider !== "signout" ? `/${provider}` : ""}`;
|
|
896
1245
|
}
|
|
897
1246
|
const res = await request(url, { ...init, request: request2 }, config);
|
|
898
1247
|
return res;
|
|
@@ -902,10 +1251,11 @@ function matches12(configRoutes, request2) {
|
|
|
902
1251
|
}
|
|
903
1252
|
async function fetchSignOut(config, body) {
|
|
904
1253
|
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/signout" /* SIGNOUT */}`;
|
|
1254
|
+
const { headers } = ctx.get();
|
|
905
1255
|
const req = new Request(clientUrl, {
|
|
906
1256
|
method: "POST",
|
|
907
1257
|
body,
|
|
908
|
-
headers
|
|
1258
|
+
headers
|
|
909
1259
|
});
|
|
910
1260
|
return await config.handlers.POST(req);
|
|
911
1261
|
}
|
|
@@ -914,7 +1264,7 @@ async function fetchSignOut(config, body) {
|
|
|
914
1264
|
var key10 = "ERROR";
|
|
915
1265
|
async function route13(req, config) {
|
|
916
1266
|
return request(
|
|
917
|
-
proxyRoutes(config)[key10],
|
|
1267
|
+
proxyRoutes(config.apiUrl)[key10],
|
|
918
1268
|
{
|
|
919
1269
|
method: req.method,
|
|
920
1270
|
request: req
|
|
@@ -930,7 +1280,7 @@ function matches13(configRoutes, request2) {
|
|
|
930
1280
|
var key11 = "VERIFY_REQUEST";
|
|
931
1281
|
async function route14(req, config) {
|
|
932
1282
|
return request(
|
|
933
|
-
proxyRoutes(config)[key11],
|
|
1283
|
+
proxyRoutes(config.apiUrl)[key11],
|
|
934
1284
|
{
|
|
935
1285
|
method: req.method,
|
|
936
1286
|
request: req
|
|
@@ -945,7 +1295,7 @@ function matches14(configRoutes, request2) {
|
|
|
945
1295
|
// src/api/routes/auth/password-reset.ts
|
|
946
1296
|
var key12 = "PASSWORD_RESET";
|
|
947
1297
|
async function route15(req, config) {
|
|
948
|
-
const url = proxyRoutes(config)[key12];
|
|
1298
|
+
const url = proxyRoutes(config.apiUrl)[key12];
|
|
949
1299
|
const res = await request(
|
|
950
1300
|
url,
|
|
951
1301
|
{
|
|
@@ -954,7 +1304,7 @@ async function route15(req, config) {
|
|
|
954
1304
|
},
|
|
955
1305
|
config
|
|
956
1306
|
);
|
|
957
|
-
const location = res?.headers
|
|
1307
|
+
const location = res?.headers?.get("location");
|
|
958
1308
|
if (location) {
|
|
959
1309
|
return new Response(res?.body, {
|
|
960
1310
|
status: 302,
|
|
@@ -974,10 +1324,11 @@ async function fetchResetPassword(config, method, body, params, useJson = true)
|
|
|
974
1324
|
if (useJson) {
|
|
975
1325
|
authParams?.set("json", "true");
|
|
976
1326
|
}
|
|
1327
|
+
const { headers } = ctx.get();
|
|
977
1328
|
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/reset-password" /* PASSWORD_RESET */}?${authParams?.toString()}`;
|
|
978
1329
|
const init = {
|
|
979
1330
|
method,
|
|
980
|
-
headers
|
|
1331
|
+
headers
|
|
981
1332
|
};
|
|
982
1333
|
if (body && method !== "GET") {
|
|
983
1334
|
init.body = body;
|
|
@@ -989,7 +1340,7 @@ async function fetchResetPassword(config, method, body, params, useJson = true)
|
|
|
989
1340
|
// src/api/routes/auth/verify-email.ts
|
|
990
1341
|
var key13 = "VERIFY_EMAIL";
|
|
991
1342
|
async function route16(req, config) {
|
|
992
|
-
const url = proxyRoutes(config)[key13];
|
|
1343
|
+
const url = proxyRoutes(config.apiUrl)[key13];
|
|
993
1344
|
const res = await request(
|
|
994
1345
|
url,
|
|
995
1346
|
{
|
|
@@ -998,7 +1349,7 @@ async function route16(req, config) {
|
|
|
998
1349
|
},
|
|
999
1350
|
config
|
|
1000
1351
|
);
|
|
1001
|
-
const location = res?.headers
|
|
1352
|
+
const location = res?.headers?.get("location");
|
|
1002
1353
|
if (location) {
|
|
1003
1354
|
return new Response(res?.body, {
|
|
1004
1355
|
status: 302,
|
|
@@ -1015,9 +1366,10 @@ function matches16(configRoutes, request2) {
|
|
|
1015
1366
|
}
|
|
1016
1367
|
async function fetchVerifyEmail(config, method, body) {
|
|
1017
1368
|
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/verify-email" /* VERIFY_EMAIL */}`;
|
|
1369
|
+
const { headers } = ctx.get();
|
|
1018
1370
|
const init = {
|
|
1019
1371
|
method,
|
|
1020
|
-
headers
|
|
1372
|
+
headers
|
|
1021
1373
|
};
|
|
1022
1374
|
if (body) {
|
|
1023
1375
|
init.body = body;
|
|
@@ -1028,8 +1380,21 @@ async function fetchVerifyEmail(config, method, body) {
|
|
|
1028
1380
|
|
|
1029
1381
|
// src/api/handlers/GET.ts
|
|
1030
1382
|
function GETTER(configRoutes, config) {
|
|
1031
|
-
const { info, warn } = config.logger("[GET MATCHER]");
|
|
1032
|
-
return async function GET7(
|
|
1383
|
+
const { error, info, warn: warn2 } = config.logger("[GET MATCHER]");
|
|
1384
|
+
return async function GET7(...params) {
|
|
1385
|
+
const handledRequest = await config.extensionCtx?.runExtensions(
|
|
1386
|
+
"onHandleRequest" /* onHandleRequest */,
|
|
1387
|
+
config,
|
|
1388
|
+
params
|
|
1389
|
+
);
|
|
1390
|
+
if (handledRequest) {
|
|
1391
|
+
return handledRequest;
|
|
1392
|
+
}
|
|
1393
|
+
const req = params[0] instanceof Request ? params[0] : null;
|
|
1394
|
+
if (!req) {
|
|
1395
|
+
error("Proxy requests failed, a Request object was not passed.");
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1033
1398
|
if (matches(configRoutes, req)) {
|
|
1034
1399
|
info("matches me");
|
|
1035
1400
|
return route(req, config);
|
|
@@ -1094,78 +1459,16 @@ function GETTER(configRoutes, config) {
|
|
|
1094
1459
|
info("matches error");
|
|
1095
1460
|
return route13(req, config);
|
|
1096
1461
|
}
|
|
1097
|
-
|
|
1462
|
+
warn2(`No GET routes matched ${req.url}`);
|
|
1098
1463
|
return new Response(null, { status: 404 });
|
|
1099
1464
|
};
|
|
1100
1465
|
}
|
|
1101
1466
|
|
|
1102
|
-
// src/utils/Logger.ts
|
|
1103
|
-
var red = "\x1B[31m";
|
|
1104
|
-
var yellow = "\x1B[38;2;255;255;0m";
|
|
1105
|
-
var purple = "\x1B[38;2;200;160;255m";
|
|
1106
|
-
var orange = "\x1B[38;2;255;165;0m";
|
|
1107
|
-
var reset = "\x1B[0m";
|
|
1108
|
-
var baseLogger = (config, ...params) => ({
|
|
1109
|
-
info(message, meta) {
|
|
1110
|
-
if (config?.debug) {
|
|
1111
|
-
console.info(
|
|
1112
|
-
`${orange}[niledb]${reset}${purple}[DEBUG]${reset}${params.join(
|
|
1113
|
-
""
|
|
1114
|
-
)}${reset} ${message}`,
|
|
1115
|
-
meta ? `${JSON.stringify(meta)}` : ""
|
|
1116
|
-
);
|
|
1117
|
-
}
|
|
1118
|
-
},
|
|
1119
|
-
debug(message, meta) {
|
|
1120
|
-
if (config?.debug) {
|
|
1121
|
-
console.debug(
|
|
1122
|
-
`${orange}[niledb]${reset}${purple}[DEBUG]${reset}${params.join(
|
|
1123
|
-
""
|
|
1124
|
-
)}${reset} ${message}`,
|
|
1125
|
-
meta ? `${JSON.stringify(meta)}` : ""
|
|
1126
|
-
);
|
|
1127
|
-
}
|
|
1128
|
-
},
|
|
1129
|
-
warn(message, meta) {
|
|
1130
|
-
if (config?.debug) {
|
|
1131
|
-
console.warn(
|
|
1132
|
-
`${orange}[niledb]${reset}${yellow}[WARN]${reset}${params.join(
|
|
1133
|
-
""
|
|
1134
|
-
)}${reset} ${message}`,
|
|
1135
|
-
meta ? JSON.stringify(meta) : ""
|
|
1136
|
-
);
|
|
1137
|
-
}
|
|
1138
|
-
},
|
|
1139
|
-
error(message, meta) {
|
|
1140
|
-
console.error(
|
|
1141
|
-
`${orange}[niledb]${reset}${red}[ERROR]${reset}${params.join(
|
|
1142
|
-
""
|
|
1143
|
-
)}${red} ${message}`,
|
|
1144
|
-
meta ? meta : "",
|
|
1145
|
-
`${reset}`
|
|
1146
|
-
);
|
|
1147
|
-
}
|
|
1148
|
-
});
|
|
1149
|
-
function Logger(config) {
|
|
1150
|
-
return (prefixes) => {
|
|
1151
|
-
const { info, debug, warn, error } = config && typeof config?.logger === "function" ? config.logger(prefixes) : baseLogger(config, prefixes);
|
|
1152
|
-
return {
|
|
1153
|
-
info,
|
|
1154
|
-
debug,
|
|
1155
|
-
warn,
|
|
1156
|
-
error
|
|
1157
|
-
};
|
|
1158
|
-
};
|
|
1159
|
-
}
|
|
1160
|
-
function matchesLog(configRoutes, request2) {
|
|
1161
|
-
return urlMatches(request2.url, configRoutes.LOG);
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
1467
|
// src/api/routes/signup/POST.ts
|
|
1165
1468
|
async function POST5(config, init) {
|
|
1166
1469
|
init.body = init.request.body;
|
|
1167
1470
|
init.method = "POST";
|
|
1168
|
-
const url = `${apiRoutes(config).SIGNUP}`;
|
|
1471
|
+
const url = `${apiRoutes(config.apiUrl).SIGNUP}`;
|
|
1169
1472
|
return await request(url, init, config);
|
|
1170
1473
|
}
|
|
1171
1474
|
|
|
@@ -1192,9 +1495,10 @@ async function fetchSignUp(config, payload) {
|
|
|
1192
1495
|
q.set("tenantId", params.tenantId);
|
|
1193
1496
|
}
|
|
1194
1497
|
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/signup" /* SIGNUP */}${q.size > 0 ? `?${q}` : ""}`;
|
|
1498
|
+
const { headers } = ctx.get();
|
|
1195
1499
|
const req = new Request(clientUrl, {
|
|
1196
1500
|
method: "POST",
|
|
1197
|
-
headers
|
|
1501
|
+
headers,
|
|
1198
1502
|
body
|
|
1199
1503
|
});
|
|
1200
1504
|
return await config.handlers.POST(req);
|
|
@@ -1202,8 +1506,21 @@ async function fetchSignUp(config, payload) {
|
|
|
1202
1506
|
|
|
1203
1507
|
// src/api/handlers/POST.ts
|
|
1204
1508
|
function POSTER(configRoutes, config) {
|
|
1205
|
-
const { info, warn, error } = config.logger("[POST MATCHER]");
|
|
1206
|
-
return async function POST6(
|
|
1509
|
+
const { info, warn: warn2, error } = config.logger("[POST MATCHER]");
|
|
1510
|
+
return async function POST6(...params) {
|
|
1511
|
+
const handledRequest = await config.extensionCtx?.runExtensions(
|
|
1512
|
+
"onHandleRequest" /* onHandleRequest */,
|
|
1513
|
+
config,
|
|
1514
|
+
params
|
|
1515
|
+
);
|
|
1516
|
+
if (handledRequest) {
|
|
1517
|
+
return handledRequest;
|
|
1518
|
+
}
|
|
1519
|
+
const req = params[0] instanceof Request ? params[0] : null;
|
|
1520
|
+
if (!req) {
|
|
1521
|
+
error("Proxy requests failed, a Request object was not passed.");
|
|
1522
|
+
return;
|
|
1523
|
+
}
|
|
1207
1524
|
if (matchesLog(configRoutes, req)) {
|
|
1208
1525
|
try {
|
|
1209
1526
|
const json = await req.clone().json();
|
|
@@ -1225,10 +1542,6 @@ function POSTER(configRoutes, config) {
|
|
|
1225
1542
|
info("matches signup");
|
|
1226
1543
|
return route17(req, config);
|
|
1227
1544
|
}
|
|
1228
|
-
if (matches2(configRoutes, req)) {
|
|
1229
|
-
info("matches users");
|
|
1230
|
-
return route2(req, config);
|
|
1231
|
-
}
|
|
1232
1545
|
if (matches6(configRoutes, req)) {
|
|
1233
1546
|
info("matches tenants");
|
|
1234
1547
|
return route6(req, config);
|
|
@@ -1265,7 +1578,7 @@ function POSTER(configRoutes, config) {
|
|
|
1265
1578
|
info("matches verify-email");
|
|
1266
1579
|
return route16(req, config);
|
|
1267
1580
|
}
|
|
1268
|
-
|
|
1581
|
+
warn2(`No POST routes matched ${req.url}`);
|
|
1269
1582
|
return new Response(null, { status: 404 });
|
|
1270
1583
|
};
|
|
1271
1584
|
}
|
|
@@ -1274,10 +1587,8 @@ function POSTER(configRoutes, config) {
|
|
|
1274
1587
|
async function DELETE3(config, init) {
|
|
1275
1588
|
const yurl = new URL(init.request.url);
|
|
1276
1589
|
const [, userId, , tenantId] = yurl.pathname.split("/").reverse();
|
|
1277
|
-
config.tenantId = tenantId;
|
|
1278
|
-
config.userId = userId;
|
|
1279
1590
|
init.method = "DELETE";
|
|
1280
|
-
const url = `${apiRoutes(config).TENANT_USER}/link`;
|
|
1591
|
+
const url = `${apiRoutes(config.apiUrl).TENANT_USER(tenantId, userId)}/link`;
|
|
1281
1592
|
return await request(url, init, config);
|
|
1282
1593
|
}
|
|
1283
1594
|
|
|
@@ -1285,10 +1596,8 @@ async function DELETE3(config, init) {
|
|
|
1285
1596
|
async function PUT5(config, init) {
|
|
1286
1597
|
const yurl = new URL(init.request.url);
|
|
1287
1598
|
const [, userId, , tenantId] = yurl.pathname.split("/").reverse();
|
|
1288
|
-
config.tenantId = tenantId;
|
|
1289
|
-
config.userId = userId;
|
|
1290
1599
|
init.method = "PUT";
|
|
1291
|
-
const url = `${apiRoutes(config).TENANT_USER}/link`;
|
|
1600
|
+
const url = `${apiRoutes(config.apiUrl).TENANT_USER(tenantId, userId)}/link`;
|
|
1292
1601
|
return await request(url, init, config);
|
|
1293
1602
|
}
|
|
1294
1603
|
|
|
@@ -1326,22 +1635,24 @@ function matches18(configRoutes, request2) {
|
|
|
1326
1635
|
return urlMatches(request2.url, route20);
|
|
1327
1636
|
}
|
|
1328
1637
|
async function fetchTenantUser(config, method) {
|
|
1329
|
-
|
|
1638
|
+
const { headers, tenantId, userId } = ctx.get();
|
|
1639
|
+
const action = method === "PUT" ? "add" : "delete";
|
|
1640
|
+
if (!tenantId) {
|
|
1330
1641
|
throw new Error(
|
|
1331
|
-
|
|
1642
|
+
`Unable to ${action} user to the tenant, the tenantId context is missing. Use nile.withContext({ tenantId })`
|
|
1332
1643
|
);
|
|
1333
1644
|
}
|
|
1334
|
-
if (!
|
|
1645
|
+
if (!userId) {
|
|
1335
1646
|
throw new Error(
|
|
1336
|
-
|
|
1647
|
+
`Unable to ${action} user to tenant. The userId context is missing. Use nile.withContext({ userId })`
|
|
1337
1648
|
);
|
|
1338
1649
|
}
|
|
1339
|
-
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/users/{userId}" /* TENANT_USER */.replace(
|
|
1340
|
-
"{
|
|
1341
|
-
|
|
1342
|
-
)
|
|
1650
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/users/{userId}" /* TENANT_USER */.replace("{tenantId}", tenantId).replace(
|
|
1651
|
+
"{userId}",
|
|
1652
|
+
userId
|
|
1653
|
+
)}/link`;
|
|
1343
1654
|
const req = new Request(clientUrl, {
|
|
1344
|
-
headers
|
|
1655
|
+
headers,
|
|
1345
1656
|
method
|
|
1346
1657
|
});
|
|
1347
1658
|
return await config.handlers[method](req);
|
|
@@ -1355,7 +1666,7 @@ async function DELETE4(config, init) {
|
|
|
1355
1666
|
return new Response(null, { status: 404 });
|
|
1356
1667
|
}
|
|
1357
1668
|
init.method = "DELETE";
|
|
1358
|
-
const url = `${apiRoutes(config).INVITE(tenantId)}/${inviteId}`;
|
|
1669
|
+
const url = `${apiRoutes(config.apiUrl).INVITE(tenantId)}/${inviteId}`;
|
|
1359
1670
|
return await request(url, init, config);
|
|
1360
1671
|
}
|
|
1361
1672
|
|
|
@@ -1378,8 +1689,21 @@ function matches19(configRoutes, request2) {
|
|
|
1378
1689
|
|
|
1379
1690
|
// src/api/handlers/DELETE.ts
|
|
1380
1691
|
function DELETER(configRoutes, config) {
|
|
1381
|
-
const { info, warn } = config.logger("[DELETE MATCHER]");
|
|
1382
|
-
return async function DELETE5(
|
|
1692
|
+
const { error, info, warn: warn2 } = config.logger("[DELETE MATCHER]");
|
|
1693
|
+
return async function DELETE5(...params) {
|
|
1694
|
+
const handledRequest = await config.extensionCtx?.runExtensions(
|
|
1695
|
+
"onHandleRequest" /* onHandleRequest */,
|
|
1696
|
+
config,
|
|
1697
|
+
params
|
|
1698
|
+
);
|
|
1699
|
+
if (handledRequest) {
|
|
1700
|
+
return handledRequest;
|
|
1701
|
+
}
|
|
1702
|
+
const req = params[0] instanceof Request ? params[0] : null;
|
|
1703
|
+
if (!req) {
|
|
1704
|
+
error("Proxy requests failed, a Request object was not passed.");
|
|
1705
|
+
return;
|
|
1706
|
+
}
|
|
1383
1707
|
if (matches19(configRoutes, req)) {
|
|
1384
1708
|
info("matches tenant invite id");
|
|
1385
1709
|
return route19(req, config);
|
|
@@ -1388,10 +1712,6 @@ function DELETER(configRoutes, config) {
|
|
|
1388
1712
|
info("matches tenant user");
|
|
1389
1713
|
return route18(req, config);
|
|
1390
1714
|
}
|
|
1391
|
-
if (matches3(configRoutes, req)) {
|
|
1392
|
-
info("matches tenant users");
|
|
1393
|
-
return route3(req, config);
|
|
1394
|
-
}
|
|
1395
1715
|
if (matches6(configRoutes, req)) {
|
|
1396
1716
|
info("matches tenants");
|
|
1397
1717
|
return route6(req, config);
|
|
@@ -1400,18 +1720,31 @@ function DELETER(configRoutes, config) {
|
|
|
1400
1720
|
info("matches me");
|
|
1401
1721
|
return route(req, config);
|
|
1402
1722
|
}
|
|
1403
|
-
|
|
1723
|
+
warn2("No DELETE routes matched");
|
|
1404
1724
|
return new Response(null, { status: 404 });
|
|
1405
1725
|
};
|
|
1406
1726
|
}
|
|
1407
1727
|
|
|
1408
1728
|
// src/api/handlers/PUT.ts
|
|
1409
1729
|
function PUTER(configRoutes, config) {
|
|
1410
|
-
const { info, warn } = config.logger("[PUT MATCHER]");
|
|
1411
|
-
return async function PUT6(
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1730
|
+
const { error, info, warn: warn2 } = config.logger("[PUT MATCHER]");
|
|
1731
|
+
return async function PUT6(...params) {
|
|
1732
|
+
const handledRequest = await config.extensionCtx?.runExtensions(
|
|
1733
|
+
"onHandleRequest" /* onHandleRequest */,
|
|
1734
|
+
config,
|
|
1735
|
+
params
|
|
1736
|
+
);
|
|
1737
|
+
if (handledRequest) {
|
|
1738
|
+
return handledRequest;
|
|
1739
|
+
}
|
|
1740
|
+
const req = params[0] instanceof Request ? params[0] : null;
|
|
1741
|
+
if (!req) {
|
|
1742
|
+
error("Proxy requests failed, a Request object was not passed.");
|
|
1743
|
+
return;
|
|
1744
|
+
}
|
|
1745
|
+
if (matches4(configRoutes, req)) {
|
|
1746
|
+
info("matches tenant invite");
|
|
1747
|
+
return route4(req, config);
|
|
1415
1748
|
}
|
|
1416
1749
|
if (matches18(configRoutes, req)) {
|
|
1417
1750
|
info("matches tenant user");
|
|
@@ -1421,10 +1754,6 @@ function PUTER(configRoutes, config) {
|
|
|
1421
1754
|
info("matches tenant users");
|
|
1422
1755
|
return route3(req, config);
|
|
1423
1756
|
}
|
|
1424
|
-
if (matches2(configRoutes, req)) {
|
|
1425
|
-
info("matches users");
|
|
1426
|
-
return route2(req, config);
|
|
1427
|
-
}
|
|
1428
1757
|
if (matches(configRoutes, req)) {
|
|
1429
1758
|
info("matches me");
|
|
1430
1759
|
return route(req, config);
|
|
@@ -1437,7 +1766,7 @@ function PUTER(configRoutes, config) {
|
|
|
1437
1766
|
info("matches reset password");
|
|
1438
1767
|
return route15(req, config);
|
|
1439
1768
|
}
|
|
1440
|
-
|
|
1769
|
+
warn2("No PUT routes matched");
|
|
1441
1770
|
return new Response(null, { status: 404 });
|
|
1442
1771
|
};
|
|
1443
1772
|
}
|
|
@@ -1641,18 +1970,7 @@ var Config = class {
|
|
|
1641
1970
|
extensionCtx;
|
|
1642
1971
|
extensions;
|
|
1643
1972
|
logger;
|
|
1644
|
-
|
|
1645
|
-
* Stores the set tenant id from Server for use in sub classes
|
|
1646
|
-
*/
|
|
1647
|
-
tenantId;
|
|
1648
|
-
/**
|
|
1649
|
-
* Stores the set user id from Server for use in sub classes
|
|
1650
|
-
*/
|
|
1651
|
-
userId;
|
|
1652
|
-
/**
|
|
1653
|
-
* Stores the headers to be used in `fetch` calls
|
|
1654
|
-
*/
|
|
1655
|
-
headers;
|
|
1973
|
+
context;
|
|
1656
1974
|
/**
|
|
1657
1975
|
* The nile-auth url
|
|
1658
1976
|
*/
|
|
@@ -1703,11 +2021,11 @@ var Config = class {
|
|
|
1703
2021
|
if (databaseName) {
|
|
1704
2022
|
this.db.database = databaseName;
|
|
1705
2023
|
}
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
}
|
|
2024
|
+
this.context = {
|
|
2025
|
+
tenantId: config?.tenantId,
|
|
2026
|
+
userId: config?.userId,
|
|
2027
|
+
headers: config?.headers ? new Headers(config.headers) : new Headers()
|
|
2028
|
+
};
|
|
1711
2029
|
this.routes = {
|
|
1712
2030
|
...appRoutes(config?.routePrefix),
|
|
1713
2031
|
...config?.routes
|
|
@@ -1750,8 +2068,6 @@ var Config = class {
|
|
|
1750
2068
|
],
|
|
1751
2069
|
delete: [this.routes.TENANT_USER, this.routes.TENANT]
|
|
1752
2070
|
};
|
|
1753
|
-
this.tenantId = config?.tenantId;
|
|
1754
|
-
this.userId = config?.userId;
|
|
1755
2071
|
}
|
|
1756
2072
|
};
|
|
1757
2073
|
|
|
@@ -1800,17 +2116,17 @@ var updateHeaders = (val) => {
|
|
|
1800
2116
|
var watchHeaders = (cb) => eventer.subscribe("headers" /* Headers */, cb);
|
|
1801
2117
|
|
|
1802
2118
|
// src/db/PoolProxy.ts
|
|
1803
|
-
function createProxyForPool(pool, config) {
|
|
1804
|
-
const { info, error } =
|
|
2119
|
+
function createProxyForPool(pool, config, logger, context) {
|
|
2120
|
+
const { info, error } = logger("[pool]");
|
|
1805
2121
|
return new Proxy(pool, {
|
|
1806
2122
|
get(target, property) {
|
|
1807
2123
|
if (property === "query") {
|
|
1808
|
-
if (!config.
|
|
1809
|
-
if (!config.
|
|
2124
|
+
if (!config.connectionString) {
|
|
2125
|
+
if (!config.user || !config.password) {
|
|
1810
2126
|
error(
|
|
1811
2127
|
"Cannot connect to the database. User and/or password are missing. Generate them at https://console.thenile.dev"
|
|
1812
2128
|
);
|
|
1813
|
-
} else if (!config.
|
|
2129
|
+
} else if (!config.database) {
|
|
1814
2130
|
error(
|
|
1815
2131
|
"Unable to obtain database name. Is process.env.NILEDB_POSTGRES_URL set?"
|
|
1816
2132
|
);
|
|
@@ -1818,7 +2134,15 @@ function createProxyForPool(pool, config) {
|
|
|
1818
2134
|
}
|
|
1819
2135
|
const caller = target[property];
|
|
1820
2136
|
return function query(...args) {
|
|
1821
|
-
|
|
2137
|
+
let log = "[QUERY]";
|
|
2138
|
+
const [tenantId, userId] = context;
|
|
2139
|
+
if (tenantId) {
|
|
2140
|
+
log = `${log}[TENANT:${tenantId}]`;
|
|
2141
|
+
}
|
|
2142
|
+
if (userId) {
|
|
2143
|
+
log = `${log}[USER:${userId}]`;
|
|
2144
|
+
}
|
|
2145
|
+
info(log, ...args);
|
|
1822
2146
|
const called = caller.apply(this, args);
|
|
1823
2147
|
return called;
|
|
1824
2148
|
};
|
|
@@ -1834,39 +2158,44 @@ var NileDatabase = class {
|
|
|
1834
2158
|
tenantId;
|
|
1835
2159
|
userId;
|
|
1836
2160
|
id;
|
|
1837
|
-
|
|
2161
|
+
logger;
|
|
1838
2162
|
timer;
|
|
1839
|
-
|
|
1840
|
-
|
|
2163
|
+
config;
|
|
2164
|
+
constructor(config, logger, id) {
|
|
2165
|
+
this.logger = logger("[NileInstance]");
|
|
1841
2166
|
this.id = id;
|
|
1842
2167
|
const poolConfig = {
|
|
1843
2168
|
min: 0,
|
|
1844
2169
|
max: 10,
|
|
1845
2170
|
idleTimeoutMillis: 3e4,
|
|
1846
|
-
...config
|
|
2171
|
+
...config
|
|
1847
2172
|
};
|
|
1848
2173
|
const { afterCreate, ...remaining } = poolConfig;
|
|
1849
|
-
config
|
|
1850
|
-
|
|
1851
|
-
const cloned = { ...this.config.db };
|
|
2174
|
+
this.config = remaining;
|
|
2175
|
+
const cloned = { ...config };
|
|
1852
2176
|
cloned.password = "***";
|
|
1853
|
-
debug(`Connection pool config ${JSON.stringify(cloned)}`);
|
|
1854
|
-
this.pool = createProxyForPool(
|
|
2177
|
+
this.logger.debug(`Connection pool config ${JSON.stringify(cloned)}`);
|
|
2178
|
+
this.pool = createProxyForPool(
|
|
2179
|
+
new pg__default.default.Pool(remaining),
|
|
2180
|
+
this.config,
|
|
2181
|
+
logger,
|
|
2182
|
+
id === "base" ? [] : id.split(":")
|
|
2183
|
+
);
|
|
1855
2184
|
if (typeof afterCreate === "function") {
|
|
1856
|
-
warn(
|
|
2185
|
+
this.logger.warn(
|
|
1857
2186
|
"Providing an pool configuration will stop automatic tenant context setting."
|
|
1858
2187
|
);
|
|
1859
2188
|
}
|
|
1860
2189
|
this.startTimeout();
|
|
1861
2190
|
this.pool.on("connect", async (client) => {
|
|
1862
|
-
debug(`pool connected ${this.id}`);
|
|
2191
|
+
this.logger.debug(`pool connected ${this.id}`);
|
|
1863
2192
|
this.startTimeout();
|
|
1864
2193
|
const afterCreate2 = makeAfterCreate(
|
|
1865
|
-
|
|
1866
|
-
`${this.id}
|
|
2194
|
+
logger,
|
|
2195
|
+
`${this.id}|${this.timer}`
|
|
1867
2196
|
);
|
|
1868
2197
|
afterCreate2(client, (err) => {
|
|
1869
|
-
const { error } =
|
|
2198
|
+
const { error } = logger("[after create callback]");
|
|
1870
2199
|
if (err) {
|
|
1871
2200
|
clearTimeout(this.timer);
|
|
1872
2201
|
error("after create failed", {
|
|
@@ -1879,7 +2208,7 @@ var NileDatabase = class {
|
|
|
1879
2208
|
});
|
|
1880
2209
|
this.pool.on("error", (err) => {
|
|
1881
2210
|
clearTimeout(this.timer);
|
|
1882
|
-
info(`pool ${this.id} failed`, {
|
|
2211
|
+
this.logger.info(`pool ${this.id} failed`, {
|
|
1883
2212
|
message: err.message,
|
|
1884
2213
|
stack: err.stack
|
|
1885
2214
|
});
|
|
@@ -1889,27 +2218,27 @@ var NileDatabase = class {
|
|
|
1889
2218
|
if (destroy) {
|
|
1890
2219
|
clearTimeout(this.timer);
|
|
1891
2220
|
evictPool(this.id);
|
|
1892
|
-
debug(`destroying pool ${this.id}`);
|
|
2221
|
+
this.logger.debug(`destroying pool ${this.id}`);
|
|
1893
2222
|
}
|
|
1894
2223
|
});
|
|
1895
2224
|
}
|
|
1896
2225
|
startTimeout() {
|
|
1897
|
-
const { debug } = this.
|
|
2226
|
+
const { debug } = this.logger;
|
|
1898
2227
|
if (this.timer) {
|
|
1899
2228
|
clearTimeout(this.timer);
|
|
1900
2229
|
}
|
|
1901
2230
|
this.timer = setTimeout(() => {
|
|
1902
2231
|
debug(
|
|
1903
|
-
`Pool reached idleTimeoutMillis. ${this.id} evicted after ${Number(this.config.
|
|
2232
|
+
`Pool reached idleTimeoutMillis. ${this.id} evicted after ${Number(this.config.idleTimeoutMillis) ?? 3e4}ms`
|
|
1904
2233
|
);
|
|
1905
2234
|
this.pool.end(() => {
|
|
1906
2235
|
clearTimeout(this.timer);
|
|
1907
2236
|
evictPool(this.id);
|
|
1908
2237
|
});
|
|
1909
|
-
}, Number(this.config.
|
|
2238
|
+
}, Number(this.config.idleTimeoutMillis) ?? 3e4);
|
|
1910
2239
|
}
|
|
1911
2240
|
shutdown() {
|
|
1912
|
-
const { debug } = this.
|
|
2241
|
+
const { debug } = this.logger;
|
|
1913
2242
|
debug(`attempting to shut down ${this.id}`);
|
|
1914
2243
|
clearTimeout(this.timer);
|
|
1915
2244
|
this.pool.end(() => {
|
|
@@ -1918,8 +2247,8 @@ var NileDatabase = class {
|
|
|
1918
2247
|
}
|
|
1919
2248
|
};
|
|
1920
2249
|
var NileInstance_default = NileDatabase;
|
|
1921
|
-
function makeAfterCreate(
|
|
1922
|
-
const { error, warn, debug } =
|
|
2250
|
+
function makeAfterCreate(logger, id) {
|
|
2251
|
+
const { error, warn: warn2, debug } = logger("[afterCreate]");
|
|
1923
2252
|
return (conn, done) => {
|
|
1924
2253
|
conn.on("error", function errorHandler(e) {
|
|
1925
2254
|
error(`Connection ${id} was terminated by server`, {
|
|
@@ -1928,13 +2257,15 @@ function makeAfterCreate(config, id) {
|
|
|
1928
2257
|
});
|
|
1929
2258
|
done(e, conn);
|
|
1930
2259
|
});
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
2260
|
+
const [context] = id.split("|");
|
|
2261
|
+
const [tenantId, userId] = context.split(":");
|
|
2262
|
+
if (tenantId !== "base") {
|
|
2263
|
+
const query = [`SET nile.tenant_id = '${tenantId}'`];
|
|
2264
|
+
if (userId) {
|
|
2265
|
+
if (!tenantId) {
|
|
2266
|
+
warn2("A user id cannot be set in context without a tenant id");
|
|
1936
2267
|
}
|
|
1937
|
-
query.push(`SET nile.user_id = '${
|
|
2268
|
+
query.push(`SET nile.user_id = '${userId}'`);
|
|
1938
2269
|
}
|
|
1939
2270
|
conn.query(query.join(";"), function(err) {
|
|
1940
2271
|
if (err) {
|
|
@@ -1947,11 +2278,11 @@ function makeAfterCreate(config, id) {
|
|
|
1947
2278
|
});
|
|
1948
2279
|
} else {
|
|
1949
2280
|
if (query.length === 1) {
|
|
1950
|
-
debug(`connection context set: tenantId=${
|
|
2281
|
+
debug(`connection context set: tenantId=${tenantId}`);
|
|
1951
2282
|
}
|
|
1952
2283
|
if (query.length === 2) {
|
|
1953
2284
|
debug(
|
|
1954
|
-
`connection context set: tenantId=${
|
|
2285
|
+
`connection context set: tenantId=${tenantId} userId=${userId}`
|
|
1955
2286
|
);
|
|
1956
2287
|
}
|
|
1957
2288
|
}
|
|
@@ -1983,19 +2314,20 @@ var DBManager = class {
|
|
|
1983
2314
|
watchEvictPool(this.poolWatcherFn);
|
|
1984
2315
|
}
|
|
1985
2316
|
poolWatcher = (config) => (id) => {
|
|
1986
|
-
const { info, warn } = Logger(config)("[DBManager]");
|
|
2317
|
+
const { info, warn: warn2 } = Logger(config)("[DBManager]");
|
|
1987
2318
|
if (id && this.connections.has(id)) {
|
|
1988
2319
|
info(`Removing ${id} from db connection pool.`);
|
|
1989
2320
|
const connection = this.connections.get(id);
|
|
1990
2321
|
connection?.shutdown();
|
|
1991
2322
|
this.connections.delete(id);
|
|
1992
2323
|
} else {
|
|
1993
|
-
|
|
2324
|
+
warn2(`missed eviction of ${id}`);
|
|
1994
2325
|
}
|
|
1995
2326
|
};
|
|
1996
|
-
getConnection = (config) => {
|
|
2327
|
+
getConnection = (config, noContext = false) => {
|
|
1997
2328
|
const { info } = Logger(config)("[DBManager]");
|
|
1998
|
-
const
|
|
2329
|
+
const { tenantId, userId } = noContext ? {} : ctx.getLastUsed();
|
|
2330
|
+
const id = this.makeId(tenantId, userId);
|
|
1999
2331
|
const existing = this.connections.get(id);
|
|
2000
2332
|
info(`# of instances: ${this.connections.size}`);
|
|
2001
2333
|
if (existing) {
|
|
@@ -2003,7 +2335,7 @@ var DBManager = class {
|
|
|
2003
2335
|
existing.startTimeout();
|
|
2004
2336
|
return existing.pool;
|
|
2005
2337
|
}
|
|
2006
|
-
const newOne = new NileInstance_default(
|
|
2338
|
+
const newOne = new NileInstance_default(config.db, config.logger, id);
|
|
2007
2339
|
this.connections.set(id, newOne);
|
|
2008
2340
|
info(`created new ${id}`);
|
|
2009
2341
|
info(`# of instances: ${this.connections.size}`);
|
|
@@ -2027,230 +2359,284 @@ var DBManager = class {
|
|
|
2027
2359
|
var Auth = class {
|
|
2028
2360
|
#logger;
|
|
2029
2361
|
#config;
|
|
2362
|
+
/**
|
|
2363
|
+
* Create an Auth helper.
|
|
2364
|
+
*
|
|
2365
|
+
* @param config - runtime configuration used by the underlying fetch helpers
|
|
2366
|
+
* such as `serverOrigin`, `routePrefix` and default headers.
|
|
2367
|
+
*/
|
|
2030
2368
|
constructor(config) {
|
|
2031
2369
|
this.#config = config;
|
|
2032
2370
|
this.#logger = config.logger("[auth]");
|
|
2033
2371
|
}
|
|
2034
2372
|
async getSession(rawResponse = false) {
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
try {
|
|
2040
|
-
const session = await res.clone().json();
|
|
2041
|
-
if (Object.keys(session).length === 0) {
|
|
2042
|
-
return void 0;
|
|
2373
|
+
return withNileContext(this.#config, async () => {
|
|
2374
|
+
const res = await fetchSession(this.#config);
|
|
2375
|
+
if (rawResponse) {
|
|
2376
|
+
return res;
|
|
2043
2377
|
}
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2378
|
+
try {
|
|
2379
|
+
const session = await res.clone().json();
|
|
2380
|
+
if (Object.keys(session).length === 0) {
|
|
2381
|
+
return void 0;
|
|
2382
|
+
}
|
|
2383
|
+
return session;
|
|
2384
|
+
} catch {
|
|
2385
|
+
return res;
|
|
2386
|
+
}
|
|
2387
|
+
});
|
|
2048
2388
|
}
|
|
2049
2389
|
async getCsrf(rawResponse = false) {
|
|
2050
|
-
return
|
|
2390
|
+
return withNileContext(this.#config, async () => {
|
|
2391
|
+
return await obtainCsrf(this.#config, rawResponse);
|
|
2392
|
+
});
|
|
2051
2393
|
}
|
|
2052
2394
|
async listProviders(rawResponse = false) {
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2395
|
+
return withNileContext(this.#config, async () => {
|
|
2396
|
+
const res = await fetchProviders(this.#config);
|
|
2397
|
+
if (rawResponse) {
|
|
2398
|
+
return res;
|
|
2399
|
+
}
|
|
2400
|
+
try {
|
|
2401
|
+
return await res.clone().json();
|
|
2402
|
+
} catch {
|
|
2403
|
+
return res;
|
|
2404
|
+
}
|
|
2405
|
+
});
|
|
2062
2406
|
}
|
|
2407
|
+
/**
|
|
2408
|
+
* Sign the current user out by calling `/api/auth/signout`.
|
|
2409
|
+
*
|
|
2410
|
+
* The CSRF token is fetched automatically and the stored cookies are cleared
|
|
2411
|
+
* from the internal configuration once the request completes.
|
|
2412
|
+
*/
|
|
2063
2413
|
async signOut() {
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2414
|
+
return withNileContext(this.#config, async () => {
|
|
2415
|
+
const csrfRes = await this.getCsrf();
|
|
2416
|
+
if (!("csrfToken" in csrfRes)) {
|
|
2417
|
+
throw new Error("Unable to obtain CSRF token. Sign out failed.");
|
|
2418
|
+
}
|
|
2419
|
+
const body = JSON.stringify({
|
|
2420
|
+
csrfToken: csrfRes.csrfToken,
|
|
2421
|
+
json: true
|
|
2422
|
+
});
|
|
2423
|
+
const res = await fetchSignOut(this.#config, body);
|
|
2424
|
+
updateHeaders(new Headers({}));
|
|
2425
|
+
ctx.set({ headers: null });
|
|
2426
|
+
return res;
|
|
2071
2427
|
});
|
|
2072
|
-
const res = await fetchSignOut(this.#config, body);
|
|
2073
|
-
updateHeaders(new Headers({}));
|
|
2074
|
-
this.#config.headers = new Headers();
|
|
2075
|
-
return res;
|
|
2076
2428
|
}
|
|
2077
2429
|
async signUp(payload, rawResponse) {
|
|
2078
|
-
this.#config
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
csrfToken
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2430
|
+
return withNileContext(this.#config, async () => {
|
|
2431
|
+
ctx.set({ headers: null });
|
|
2432
|
+
const { email, password, ...params } = payload;
|
|
2433
|
+
if (!email || !password) {
|
|
2434
|
+
throw new Error(
|
|
2435
|
+
"Server side sign up requires a user email and password."
|
|
2436
|
+
);
|
|
2437
|
+
}
|
|
2438
|
+
const providers = await this.listProviders();
|
|
2439
|
+
const { credentials } = providers ?? {};
|
|
2440
|
+
if (!credentials) {
|
|
2441
|
+
throw new Error(
|
|
2442
|
+
"Unable to obtain credential provider. Aborting server side sign up."
|
|
2443
|
+
);
|
|
2444
|
+
}
|
|
2445
|
+
const csrf = await obtainCsrf(this.#config);
|
|
2446
|
+
let csrfToken;
|
|
2447
|
+
if ("csrfToken" in csrf) {
|
|
2448
|
+
csrfToken = csrf.csrfToken;
|
|
2449
|
+
} else {
|
|
2450
|
+
throw new Error("Unable to obtain parse CSRF. Request blocked.");
|
|
2451
|
+
}
|
|
2452
|
+
const body = JSON.stringify({
|
|
2453
|
+
email,
|
|
2454
|
+
password,
|
|
2455
|
+
csrfToken,
|
|
2456
|
+
callbackUrl: credentials.callbackUrl
|
|
2457
|
+
});
|
|
2458
|
+
const res = await fetchSignUp(this.#config, { body, params });
|
|
2459
|
+
if (res.status > 299) {
|
|
2460
|
+
this.#logger.error(await res.clone().text());
|
|
2461
|
+
return void 0;
|
|
2462
|
+
}
|
|
2463
|
+
const token = parseToken(res.headers);
|
|
2464
|
+
if (!token) {
|
|
2465
|
+
throw new Error("Server side sign up failed. Session token not found");
|
|
2466
|
+
}
|
|
2467
|
+
const { headers } = ctx.get();
|
|
2468
|
+
headers?.append("cookie", token);
|
|
2469
|
+
ctx.set({ headers });
|
|
2470
|
+
updateHeaders(headers);
|
|
2471
|
+
if (rawResponse) {
|
|
2472
|
+
return res;
|
|
2473
|
+
}
|
|
2474
|
+
try {
|
|
2475
|
+
const json = await res.clone().json();
|
|
2476
|
+
if (json && typeof json === "object" && "tenants" in json) {
|
|
2477
|
+
const tenantId = json.tenants[0];
|
|
2478
|
+
if (tenantId) {
|
|
2479
|
+
updateTenantId(tenantId);
|
|
2480
|
+
}
|
|
2125
2481
|
}
|
|
2482
|
+
return json;
|
|
2483
|
+
} catch {
|
|
2484
|
+
return res;
|
|
2126
2485
|
}
|
|
2127
|
-
return json;
|
|
2128
|
-
} catch {
|
|
2129
|
-
return res;
|
|
2130
|
-
}
|
|
2131
|
-
}
|
|
2132
|
-
async forgotPassword(req) {
|
|
2133
|
-
let email = "";
|
|
2134
|
-
const defaults = defaultCallbackUrl({
|
|
2135
|
-
config: this.#config
|
|
2136
|
-
});
|
|
2137
|
-
let callbackUrl = defaults.callbackUrl;
|
|
2138
|
-
let redirectUrl = defaults.redirectUrl;
|
|
2139
|
-
if ("email" in req) {
|
|
2140
|
-
email = req.email;
|
|
2141
|
-
}
|
|
2142
|
-
if ("callbackUrl" in req) {
|
|
2143
|
-
callbackUrl = req.callbackUrl ? req.callbackUrl : null;
|
|
2144
|
-
}
|
|
2145
|
-
if ("redirectUrl" in req) {
|
|
2146
|
-
redirectUrl = req.redirectUrl ? req.redirectUrl : null;
|
|
2147
|
-
}
|
|
2148
|
-
const body = JSON.stringify({
|
|
2149
|
-
email,
|
|
2150
|
-
redirectUrl,
|
|
2151
|
-
callbackUrl
|
|
2152
2486
|
});
|
|
2153
|
-
const data = await fetchResetPassword(
|
|
2154
|
-
this.#config,
|
|
2155
|
-
"POST",
|
|
2156
|
-
body,
|
|
2157
|
-
new URLSearchParams(),
|
|
2158
|
-
false
|
|
2159
|
-
);
|
|
2160
|
-
return data;
|
|
2161
2487
|
}
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
const
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
}
|
|
2176
|
-
if (body2.callbackUrl) {
|
|
2177
|
-
callbackUrl = body2.callbackUrl;
|
|
2178
|
-
}
|
|
2179
|
-
if (body2.redirectUrl) {
|
|
2180
|
-
redirectUrl = body2.redirectUrl;
|
|
2181
|
-
}
|
|
2182
|
-
} else {
|
|
2488
|
+
/**
|
|
2489
|
+
* Request a password reset email.
|
|
2490
|
+
*
|
|
2491
|
+
* Sends a `POST` to `/api/auth/password-reset` with the provided email and
|
|
2492
|
+
* optional callback information. The endpoint responds with a redirect URL
|
|
2493
|
+
* which is returned as a {@link Response} object.
|
|
2494
|
+
*/
|
|
2495
|
+
async forgotPassword(req) {
|
|
2496
|
+
return withNileContext(this.#config, async () => {
|
|
2497
|
+
let email = "";
|
|
2498
|
+
const defaults = defaultCallbackUrl(this.#config);
|
|
2499
|
+
let callbackUrl = defaults.callbackUrl;
|
|
2500
|
+
let redirectUrl = defaults.redirectUrl;
|
|
2183
2501
|
if ("email" in req) {
|
|
2184
2502
|
email = req.email;
|
|
2185
2503
|
}
|
|
2186
|
-
if ("password" in req) {
|
|
2187
|
-
password = req.password;
|
|
2188
|
-
}
|
|
2189
2504
|
if ("callbackUrl" in req) {
|
|
2190
|
-
callbackUrl = req.callbackUrl
|
|
2505
|
+
callbackUrl = fQUrl(req.callbackUrl ?? "", this.#config);
|
|
2191
2506
|
}
|
|
2192
2507
|
if ("redirectUrl" in req) {
|
|
2193
|
-
redirectUrl = req.redirectUrl
|
|
2508
|
+
redirectUrl = fQUrl(req.redirectUrl ?? "", this.#config);
|
|
2194
2509
|
}
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
callbackUrl
|
|
2202
|
-
});
|
|
2203
|
-
let urlWithParams;
|
|
2204
|
-
try {
|
|
2205
|
-
const data = await fetchResetPassword(this.#config, "POST", body);
|
|
2206
|
-
const cloned = data.clone();
|
|
2207
|
-
if (data.status === 400) {
|
|
2208
|
-
const text = await cloned.text();
|
|
2209
|
-
this.#logger.error(text);
|
|
2210
|
-
return data;
|
|
2211
|
-
}
|
|
2212
|
-
const { url } = await data.json();
|
|
2213
|
-
urlWithParams = url;
|
|
2214
|
-
} catch {
|
|
2215
|
-
}
|
|
2216
|
-
let token;
|
|
2217
|
-
try {
|
|
2218
|
-
const worthyParams = new URL(urlWithParams).searchParams;
|
|
2219
|
-
const answer = await fetchResetPassword(
|
|
2510
|
+
const body = JSON.stringify({
|
|
2511
|
+
email,
|
|
2512
|
+
redirectUrl,
|
|
2513
|
+
callbackUrl
|
|
2514
|
+
});
|
|
2515
|
+
const data = await fetchResetPassword(
|
|
2220
2516
|
this.#config,
|
|
2221
|
-
"
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
token = parseResetToken(answer.headers);
|
|
2226
|
-
} catch {
|
|
2227
|
-
this.#logger.warn(
|
|
2228
|
-
"Unable to parse reset password url. Password not reset."
|
|
2229
|
-
);
|
|
2230
|
-
}
|
|
2231
|
-
const cookie = this.#config.headers.get("cookie")?.split("; ");
|
|
2232
|
-
if (token) {
|
|
2233
|
-
cookie?.push(token);
|
|
2234
|
-
} else {
|
|
2235
|
-
throw new Error(
|
|
2236
|
-
"Unable to reset password, reset token is missing from response"
|
|
2517
|
+
"POST",
|
|
2518
|
+
body,
|
|
2519
|
+
new URLSearchParams(),
|
|
2520
|
+
false
|
|
2237
2521
|
);
|
|
2238
|
-
|
|
2239
|
-
this.#config.headers = new Headers({
|
|
2240
|
-
...this.#config.headers,
|
|
2241
|
-
cookie: cookie?.join("; ")
|
|
2522
|
+
return data;
|
|
2242
2523
|
});
|
|
2243
|
-
const res = await fetchResetPassword(this.#config, "PUT", body);
|
|
2244
|
-
cookie?.pop();
|
|
2245
|
-
const cleaned = cookie?.filter((c) => !c.includes("nile.session")) ?? [];
|
|
2246
|
-
cleaned.push(String(parseToken(res.headers)));
|
|
2247
|
-
const updatedHeaders = new Headers({ cookie: cleaned.join("; ") });
|
|
2248
|
-
updateHeaders(updatedHeaders);
|
|
2249
|
-
return res;
|
|
2250
2524
|
}
|
|
2525
|
+
/**
|
|
2526
|
+
* Complete a password reset.
|
|
2527
|
+
*
|
|
2528
|
+
* This workflow expects a token obtained from {@link forgotPassword}. The
|
|
2529
|
+
* function performs a POST/GET/PUT sequence against
|
|
2530
|
+
* `/api/auth/password-reset` as described in the OpenAPI specification.
|
|
2531
|
+
*
|
|
2532
|
+
* @param req - either a {@link Request} with a JSON body or an object
|
|
2533
|
+
* containing the necessary fields.
|
|
2534
|
+
*/
|
|
2535
|
+
async resetPassword(req) {
|
|
2536
|
+
return withNileContext(this.#config, async () => {
|
|
2537
|
+
let email = "";
|
|
2538
|
+
let password = "";
|
|
2539
|
+
const defaults = defaultCallbackUrl(this.#config);
|
|
2540
|
+
let callbackUrl = defaults.callbackUrl;
|
|
2541
|
+
let redirectUrl = defaults.redirectUrl;
|
|
2542
|
+
if (req instanceof Request) {
|
|
2543
|
+
const body2 = await req.json();
|
|
2544
|
+
email = body2.email;
|
|
2545
|
+
password = body2.password;
|
|
2546
|
+
const cbFromHeaders = parseCallback(req.headers);
|
|
2547
|
+
if (cbFromHeaders) {
|
|
2548
|
+
callbackUrl = cbFromHeaders;
|
|
2549
|
+
}
|
|
2550
|
+
if (body2.callbackUrl) {
|
|
2551
|
+
callbackUrl = body2.callbackUrl;
|
|
2552
|
+
}
|
|
2553
|
+
if (body2.redirectUrl) {
|
|
2554
|
+
redirectUrl = body2.redirectUrl;
|
|
2555
|
+
}
|
|
2556
|
+
} else {
|
|
2557
|
+
if ("email" in req) {
|
|
2558
|
+
email = req.email;
|
|
2559
|
+
}
|
|
2560
|
+
if ("password" in req) {
|
|
2561
|
+
password = req.password;
|
|
2562
|
+
}
|
|
2563
|
+
if ("callbackUrl" in req) {
|
|
2564
|
+
callbackUrl = req.callbackUrl ? req.callbackUrl : null;
|
|
2565
|
+
}
|
|
2566
|
+
if ("redirectUrl" in req) {
|
|
2567
|
+
redirectUrl = req.redirectUrl ? req.redirectUrl : null;
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
await this.getCsrf();
|
|
2571
|
+
const body = JSON.stringify({
|
|
2572
|
+
email,
|
|
2573
|
+
password,
|
|
2574
|
+
redirectUrl,
|
|
2575
|
+
callbackUrl
|
|
2576
|
+
});
|
|
2577
|
+
let urlWithParams;
|
|
2578
|
+
try {
|
|
2579
|
+
const data = await fetchResetPassword(this.#config, "POST", body);
|
|
2580
|
+
const cloned = data.clone();
|
|
2581
|
+
if (data.status === 400) {
|
|
2582
|
+
const text = await cloned.text();
|
|
2583
|
+
this.#logger.error(text);
|
|
2584
|
+
return data;
|
|
2585
|
+
}
|
|
2586
|
+
const { url } = await data.json();
|
|
2587
|
+
urlWithParams = url;
|
|
2588
|
+
} catch {
|
|
2589
|
+
}
|
|
2590
|
+
let token;
|
|
2591
|
+
try {
|
|
2592
|
+
const worthyParams = new URL(urlWithParams).searchParams;
|
|
2593
|
+
const answer = await fetchResetPassword(
|
|
2594
|
+
this.#config,
|
|
2595
|
+
"GET",
|
|
2596
|
+
null,
|
|
2597
|
+
worthyParams
|
|
2598
|
+
);
|
|
2599
|
+
token = parseResetToken(answer.headers);
|
|
2600
|
+
} catch {
|
|
2601
|
+
this.#logger.warn(
|
|
2602
|
+
"Unable to parse reset password url. Password not reset."
|
|
2603
|
+
);
|
|
2604
|
+
}
|
|
2605
|
+
const { headers } = ctx.get();
|
|
2606
|
+
const cookie = headers?.get("cookie")?.split("; ");
|
|
2607
|
+
if (token) {
|
|
2608
|
+
cookie?.push(token);
|
|
2609
|
+
} else {
|
|
2610
|
+
throw new Error(
|
|
2611
|
+
"Unable to reset password, reset token is missing from response"
|
|
2612
|
+
);
|
|
2613
|
+
}
|
|
2614
|
+
if (cookie) {
|
|
2615
|
+
headers?.set("cookie", cookie?.join("; "));
|
|
2616
|
+
ctx.set({
|
|
2617
|
+
headers
|
|
2618
|
+
});
|
|
2619
|
+
}
|
|
2620
|
+
const res = await fetchResetPassword(this.#config, "PUT", body);
|
|
2621
|
+
cookie?.pop();
|
|
2622
|
+
const cleaned = cookie?.filter((c) => !c.includes("nile.session")) ?? [];
|
|
2623
|
+
cleaned.push(String(parseToken(res.headers)));
|
|
2624
|
+
const updatedHeaders = new Headers({ cookie: cleaned.join("; ") });
|
|
2625
|
+
updateHeaders(updatedHeaders);
|
|
2626
|
+
return res;
|
|
2627
|
+
});
|
|
2628
|
+
}
|
|
2629
|
+
/**
|
|
2630
|
+
* Low level helper used by {@link signIn} to complete provider flows.
|
|
2631
|
+
*
|
|
2632
|
+
* Depending on the provider this issues either a GET or POST request to
|
|
2633
|
+
* `/api/auth/callback/{provider}` via {@link fetchCallback}.
|
|
2634
|
+
*/
|
|
2251
2635
|
async callback(provider, body) {
|
|
2252
2636
|
if (body instanceof Request) {
|
|
2253
|
-
|
|
2637
|
+
ctx.set({
|
|
2638
|
+
headers: body.headers
|
|
2639
|
+
});
|
|
2254
2640
|
return await fetchCallback(
|
|
2255
2641
|
this.#config,
|
|
2256
2642
|
provider,
|
|
@@ -2262,109 +2648,115 @@ var Auth = class {
|
|
|
2262
2648
|
return await fetchCallback(this.#config, provider, body);
|
|
2263
2649
|
}
|
|
2264
2650
|
async signIn(provider, payload, rawResponse) {
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2651
|
+
return withNileContext(this.#config, async () => {
|
|
2652
|
+
if (payload instanceof Request) {
|
|
2653
|
+
const body2 = new URLSearchParams(await payload.text());
|
|
2654
|
+
const origin = new URL(payload.url).origin;
|
|
2655
|
+
const payloadUrl = body2?.get("callbackUrl");
|
|
2656
|
+
const csrfToken2 = body2?.get("csrfToken");
|
|
2657
|
+
const callbackUrl = `${!payloadUrl?.startsWith("http") ? origin : ""}${payloadUrl}`;
|
|
2658
|
+
if (!csrfToken2) {
|
|
2659
|
+
throw new Error(
|
|
2660
|
+
"CSRF token in missing from request. Request it by the client before calling sign in"
|
|
2661
|
+
);
|
|
2662
|
+
}
|
|
2663
|
+
const updatedHeaders = new Headers(payload.headers);
|
|
2664
|
+
updatedHeaders.set("Content-Type", "application/x-www-form-urlencoded");
|
|
2665
|
+
ctx.set({ headers: updatedHeaders });
|
|
2666
|
+
const params = new URLSearchParams({
|
|
2667
|
+
csrfToken: csrfToken2,
|
|
2668
|
+
json: String(true)
|
|
2669
|
+
});
|
|
2670
|
+
if (payloadUrl) {
|
|
2671
|
+
params.set("callbackUrl", callbackUrl);
|
|
2672
|
+
}
|
|
2673
|
+
return await fetchSignIn(this.#config, provider, params);
|
|
2674
|
+
}
|
|
2675
|
+
ctx.set({ headers: null });
|
|
2676
|
+
const { info, error } = this.#logger;
|
|
2677
|
+
const providers = await this.listProviders();
|
|
2678
|
+
info("Obtaining csrf");
|
|
2679
|
+
const csrf = await obtainCsrf(this.#config);
|
|
2680
|
+
let csrfToken;
|
|
2681
|
+
if ("csrfToken" in csrf) {
|
|
2682
|
+
csrfToken = csrf.csrfToken;
|
|
2683
|
+
} else {
|
|
2684
|
+
throw new Error("Unable to obtain parse CSRF. Request blocked.");
|
|
2685
|
+
}
|
|
2686
|
+
const { credentials } = providers ?? {};
|
|
2687
|
+
if (!credentials) {
|
|
2272
2688
|
throw new Error(
|
|
2273
|
-
"
|
|
2689
|
+
"Unable to obtain credential provider. Aborting server side sign in."
|
|
2274
2690
|
);
|
|
2275
2691
|
}
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2692
|
+
const { email, password } = payload ?? {};
|
|
2693
|
+
if (provider === "email" && (!email || !password)) {
|
|
2694
|
+
throw new Error(
|
|
2695
|
+
"Server side sign in requires a user email and password."
|
|
2696
|
+
);
|
|
2697
|
+
}
|
|
2698
|
+
info(`Obtaining providers for ${email}`);
|
|
2699
|
+
info(`Attempting sign in with email ${email}`);
|
|
2700
|
+
if (!email) {
|
|
2701
|
+
throw new Error("Email missing from payload, unable to sign in");
|
|
2702
|
+
}
|
|
2703
|
+
const body = JSON.stringify({
|
|
2704
|
+
email,
|
|
2705
|
+
password,
|
|
2706
|
+
csrfToken,
|
|
2707
|
+
callbackUrl: credentials.callbackUrl
|
|
2284
2708
|
});
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
"Unable to obtain
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
);
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2709
|
+
const signInRes = await this.callback(provider, body);
|
|
2710
|
+
const authCookie = signInRes?.headers.get("set-cookie");
|
|
2711
|
+
if (!authCookie) {
|
|
2712
|
+
throw new Error("authentication failed");
|
|
2713
|
+
}
|
|
2714
|
+
const token = parseToken(signInRes?.headers);
|
|
2715
|
+
const possibleError = signInRes?.headers.get("location");
|
|
2716
|
+
if (possibleError) {
|
|
2717
|
+
let urlError;
|
|
2718
|
+
try {
|
|
2719
|
+
urlError = new URL(possibleError).searchParams.get("error");
|
|
2720
|
+
} catch {
|
|
2721
|
+
}
|
|
2722
|
+
if (urlError) {
|
|
2723
|
+
error("Unable to log user in", { error: urlError });
|
|
2724
|
+
return new Response(urlError, { status: signInRes.status });
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
if (!token) {
|
|
2728
|
+
error("Unable to obtain auth token", {
|
|
2729
|
+
authCookie,
|
|
2730
|
+
signInRes
|
|
2731
|
+
});
|
|
2732
|
+
throw new Error("Server login failed");
|
|
2733
|
+
}
|
|
2734
|
+
info("Server sign in successful", { authCookie });
|
|
2735
|
+
const setCookie = signInRes.headers.get("set-cookie");
|
|
2736
|
+
const { headers } = ctx.get();
|
|
2737
|
+
if (setCookie) {
|
|
2738
|
+
const cookie = [
|
|
2739
|
+
parseCSRF(headers),
|
|
2740
|
+
parseCallback(signInRes.headers),
|
|
2741
|
+
parseToken(signInRes.headers)
|
|
2742
|
+
].filter(Boolean).join("; ");
|
|
2743
|
+
const uHeaders = new Headers({ cookie });
|
|
2744
|
+
updateHeaders(uHeaders);
|
|
2745
|
+
ctx.set({ headers: uHeaders });
|
|
2746
|
+
} else {
|
|
2747
|
+
error("Unable to set context after sign in", {
|
|
2748
|
+
headers: signInRes.headers
|
|
2749
|
+
});
|
|
2750
|
+
}
|
|
2751
|
+
if (rawResponse) {
|
|
2752
|
+
return signInRes;
|
|
2753
|
+
}
|
|
2330
2754
|
try {
|
|
2331
|
-
|
|
2755
|
+
return await signInRes.clone().json();
|
|
2332
2756
|
} catch {
|
|
2757
|
+
return signInRes;
|
|
2333
2758
|
}
|
|
2334
|
-
|
|
2335
|
-
error("Unable to log user in", { error: urlError });
|
|
2336
|
-
return new Response(urlError, { status: signInRes.status });
|
|
2337
|
-
}
|
|
2338
|
-
}
|
|
2339
|
-
if (!token) {
|
|
2340
|
-
error("Unable to obtain auth token", {
|
|
2341
|
-
authCookie,
|
|
2342
|
-
signInRes
|
|
2343
|
-
});
|
|
2344
|
-
throw new Error("Server login failed");
|
|
2345
|
-
}
|
|
2346
|
-
info("Server sign in successful", { authCookie });
|
|
2347
|
-
const setCookie = signInRes.headers.get("set-cookie");
|
|
2348
|
-
if (setCookie) {
|
|
2349
|
-
const cookie = [
|
|
2350
|
-
parseCSRF(this.#config.headers),
|
|
2351
|
-
parseCallback(signInRes.headers),
|
|
2352
|
-
parseToken(signInRes.headers)
|
|
2353
|
-
].filter(Boolean).join("; ");
|
|
2354
|
-
updateHeaders(new Headers({ cookie }));
|
|
2355
|
-
} else {
|
|
2356
|
-
error("Unable to set context after sign in", {
|
|
2357
|
-
headers: signInRes.headers
|
|
2358
|
-
});
|
|
2359
|
-
}
|
|
2360
|
-
if (rawResponse) {
|
|
2361
|
-
return signInRes;
|
|
2362
|
-
}
|
|
2363
|
-
try {
|
|
2364
|
-
return await signInRes.clone().json();
|
|
2365
|
-
} catch {
|
|
2366
|
-
return signInRes;
|
|
2367
|
-
}
|
|
2759
|
+
});
|
|
2368
2760
|
}
|
|
2369
2761
|
};
|
|
2370
2762
|
function parseCSRF(headers) {
|
|
@@ -2411,22 +2803,54 @@ function parseResetToken(headers) {
|
|
|
2411
2803
|
const [, token] = /((__Secure-)?nile\.reset=[^;]+)/.exec(authCookie) ?? [];
|
|
2412
2804
|
return token;
|
|
2413
2805
|
}
|
|
2414
|
-
function
|
|
2806
|
+
function parseTenantId(headers) {
|
|
2807
|
+
let authCookie = headers?.get("set-cookie");
|
|
2808
|
+
if (!authCookie) {
|
|
2809
|
+
authCookie = headers?.get("cookie");
|
|
2810
|
+
}
|
|
2811
|
+
if (!authCookie) {
|
|
2812
|
+
return void 0;
|
|
2813
|
+
}
|
|
2814
|
+
const [, token] = /((__Secure-)?nile\.tenant-id=[^;]+)/.exec(authCookie) ?? [];
|
|
2815
|
+
if (token) {
|
|
2816
|
+
const [, tenantId] = token.split("=");
|
|
2817
|
+
return tenantId;
|
|
2818
|
+
}
|
|
2819
|
+
return null;
|
|
2820
|
+
}
|
|
2821
|
+
function defaultCallbackUrl(config) {
|
|
2415
2822
|
let cb = null;
|
|
2416
2823
|
let redirect = null;
|
|
2417
|
-
const
|
|
2824
|
+
const { headers } = ctx.get();
|
|
2825
|
+
const fallbackCb = parseCallback(headers);
|
|
2418
2826
|
if (fallbackCb) {
|
|
2419
2827
|
const [, value] = fallbackCb.split("=");
|
|
2420
2828
|
cb = decodeURIComponent(value);
|
|
2421
2829
|
if (value) {
|
|
2422
|
-
redirect = `${new URL(cb).origin}${"/auth/reset-password" /* PASSWORD_RESET */}`;
|
|
2830
|
+
redirect = `${new URL(cb).origin}${config.routePrefix}${"/auth/reset-password" /* PASSWORD_RESET */}`;
|
|
2423
2831
|
}
|
|
2424
2832
|
}
|
|
2425
2833
|
return { callbackUrl: cb, redirectUrl: redirect };
|
|
2426
2834
|
}
|
|
2835
|
+
function fQUrl(path, config) {
|
|
2836
|
+
if (path.startsWith("/")) {
|
|
2837
|
+
const { callbackUrl } = defaultCallbackUrl(config);
|
|
2838
|
+
if (callbackUrl) {
|
|
2839
|
+
const { origin } = new URL(callbackUrl);
|
|
2840
|
+
return `${origin}${path}`;
|
|
2841
|
+
}
|
|
2842
|
+
}
|
|
2843
|
+
try {
|
|
2844
|
+
new URL(path);
|
|
2845
|
+
} catch {
|
|
2846
|
+
throw new Error("An invalid URL has been passed.");
|
|
2847
|
+
}
|
|
2848
|
+
return path;
|
|
2849
|
+
}
|
|
2427
2850
|
|
|
2428
2851
|
// src/auth/obtainCsrf.ts
|
|
2429
2852
|
async function obtainCsrf(config, rawResponse = false) {
|
|
2853
|
+
const { headers } = ctx.get();
|
|
2430
2854
|
const res = await fetchCsrf(config);
|
|
2431
2855
|
const csrfCook = parseCSRF(res.headers);
|
|
2432
2856
|
if (csrfCook) {
|
|
@@ -2439,28 +2863,27 @@ async function obtainCsrf(config, rawResponse = false) {
|
|
|
2439
2863
|
parseCallback(res.headers),
|
|
2440
2864
|
parseToken(res.headers)
|
|
2441
2865
|
].filter(Boolean).join("; ");
|
|
2442
|
-
|
|
2443
|
-
|
|
2866
|
+
headers.set("cookie", cookie);
|
|
2867
|
+
ctx.set({ headers });
|
|
2868
|
+
updateHeaders(headers);
|
|
2444
2869
|
}
|
|
2445
2870
|
if (!rawResponse) {
|
|
2446
2871
|
return { csrfToken: token };
|
|
2447
2872
|
}
|
|
2448
2873
|
} else {
|
|
2449
|
-
const existingCookie =
|
|
2874
|
+
const existingCookie = headers.get("cookie");
|
|
2450
2875
|
const cookieParts = [];
|
|
2451
2876
|
if (existingCookie) {
|
|
2452
|
-
cookieParts.push(
|
|
2453
|
-
parseToken(config.headers),
|
|
2454
|
-
parseCallback(config.headers)
|
|
2455
|
-
);
|
|
2877
|
+
cookieParts.push(parseToken(headers), parseCallback(headers));
|
|
2456
2878
|
}
|
|
2457
2879
|
if (csrfCook) {
|
|
2458
2880
|
cookieParts.push(csrfCook);
|
|
2459
2881
|
} else {
|
|
2460
|
-
cookieParts.push(parseCSRF(
|
|
2882
|
+
cookieParts.push(parseCSRF(headers));
|
|
2461
2883
|
}
|
|
2462
2884
|
const cookie = cookieParts.filter(Boolean).join("; ");
|
|
2463
|
-
|
|
2885
|
+
headers.set("cookie", cookie);
|
|
2886
|
+
ctx.set({ headers });
|
|
2464
2887
|
updateHeaders(new Headers({ cookie }));
|
|
2465
2888
|
}
|
|
2466
2889
|
if (rawResponse) {
|
|
@@ -2473,74 +2896,131 @@ async function obtainCsrf(config, rawResponse = false) {
|
|
|
2473
2896
|
}
|
|
2474
2897
|
}
|
|
2475
2898
|
|
|
2899
|
+
// src/utils/qualifyDomain.ts
|
|
2900
|
+
function fQUrl2(callbackUrl, path) {
|
|
2901
|
+
if (path.startsWith("/")) {
|
|
2902
|
+
if (callbackUrl) {
|
|
2903
|
+
const { origin } = new URL(callbackUrl);
|
|
2904
|
+
return `${origin}${path}`;
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
try {
|
|
2908
|
+
new URL(path);
|
|
2909
|
+
} catch {
|
|
2910
|
+
throw new Error("An invalid URL has been passed.");
|
|
2911
|
+
}
|
|
2912
|
+
return path;
|
|
2913
|
+
}
|
|
2914
|
+
|
|
2476
2915
|
// src/users/index.ts
|
|
2477
2916
|
var Users = class {
|
|
2478
2917
|
#config;
|
|
2479
2918
|
#logger;
|
|
2919
|
+
/**
|
|
2920
|
+
* Create a new Users helper.
|
|
2921
|
+
* @param config - The configuration used for requests.
|
|
2922
|
+
*/
|
|
2480
2923
|
constructor(config) {
|
|
2481
2924
|
this.#config = config;
|
|
2482
2925
|
this.#logger = config.logger("[me]");
|
|
2483
2926
|
}
|
|
2927
|
+
/**
|
|
2928
|
+
* Update the current user via `PUT /api/me`.
|
|
2929
|
+
*
|
|
2930
|
+
* The OpenAPI description for this endpoint can be found in
|
|
2931
|
+
* `packages/server/src/api/routes/me/index.ts` under `updateSelf`.
|
|
2932
|
+
*
|
|
2933
|
+
* @param req - Partial user fields to send.
|
|
2934
|
+
* @param [rawResponse] - When `true`, return the raw {@link Response}.
|
|
2935
|
+
*/
|
|
2484
2936
|
async updateSelf(req, rawResponse) {
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2937
|
+
return withNileContext(this.#config, async () => {
|
|
2938
|
+
const res = await fetchMe(this.#config, "PUT", JSON.stringify(req));
|
|
2939
|
+
if (rawResponse) {
|
|
2940
|
+
return res;
|
|
2941
|
+
}
|
|
2942
|
+
try {
|
|
2943
|
+
return await res?.clone().json();
|
|
2944
|
+
} catch {
|
|
2945
|
+
return res;
|
|
2946
|
+
}
|
|
2947
|
+
});
|
|
2494
2948
|
}
|
|
2949
|
+
/**
|
|
2950
|
+
* Remove the current user using `DELETE /api/me`.
|
|
2951
|
+
*
|
|
2952
|
+
* After the request the authentication headers are cleared with
|
|
2953
|
+
* {@link updateHeaders}. The OpenAPI docs for this route are in
|
|
2954
|
+
* `packages/server/src/api/routes/me/index.ts` under `removeSelf`.
|
|
2955
|
+
*/
|
|
2495
2956
|
async removeSelf() {
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2957
|
+
return withNileContext(this.#config, async () => {
|
|
2958
|
+
const me = await this.getSelf();
|
|
2959
|
+
if ("id" in me) {
|
|
2960
|
+
const userId = me.id;
|
|
2961
|
+
ctx.set({ userId });
|
|
2962
|
+
}
|
|
2963
|
+
const res = await fetchMe(this.#config, "DELETE");
|
|
2964
|
+
updateHeaders(new Headers());
|
|
2965
|
+
return res;
|
|
2966
|
+
});
|
|
2503
2967
|
}
|
|
2504
2968
|
async getSelf(rawResponse) {
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2969
|
+
return withNileContext(this.#config, async () => {
|
|
2970
|
+
const res = await fetchMe(this.#config);
|
|
2971
|
+
if (rawResponse) {
|
|
2972
|
+
return res;
|
|
2973
|
+
}
|
|
2974
|
+
try {
|
|
2975
|
+
return await res?.clone().json();
|
|
2976
|
+
} catch {
|
|
2977
|
+
return res;
|
|
2978
|
+
}
|
|
2979
|
+
});
|
|
2514
2980
|
}
|
|
2515
2981
|
async verifySelf(options, rawResponse = false) {
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2982
|
+
return withNileContext(this.#config, async () => {
|
|
2983
|
+
const bypassEmail = typeof options === "object" && options?.bypassEmail === true;
|
|
2984
|
+
const callbackUrl = fQUrl2(
|
|
2985
|
+
defaultCallbackUrl2().callbackUrl,
|
|
2986
|
+
typeof options === "object" ? String(options.callbackUrl) : "/"
|
|
2987
|
+
);
|
|
2988
|
+
let res;
|
|
2989
|
+
try {
|
|
2990
|
+
const me = await this.getSelf();
|
|
2991
|
+
if (me instanceof Response) {
|
|
2992
|
+
return me;
|
|
2993
|
+
}
|
|
2994
|
+
res = await verifyEmailAddress(this.#config, me, String(callbackUrl));
|
|
2995
|
+
return res;
|
|
2996
|
+
} catch (e) {
|
|
2997
|
+
if (!bypassEmail) {
|
|
2998
|
+
let message = "Unable to verify email.";
|
|
2999
|
+
if (e instanceof Error) {
|
|
3000
|
+
message = e.message;
|
|
3001
|
+
}
|
|
3002
|
+
this.#logger?.error(
|
|
3003
|
+
`${message} you can bypass this message by setting bypassEmail: true when calling 'verifySelf'`
|
|
3004
|
+
);
|
|
3005
|
+
res = new Response(message, { status: 400 });
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
if (bypassEmail) {
|
|
3009
|
+
this.#logger?.info(
|
|
3010
|
+
"bypassing email requirements for email verification"
|
|
3011
|
+
);
|
|
3012
|
+
res = this.updateSelf({ emailVerified: true }, rawResponse);
|
|
2523
3013
|
}
|
|
2524
|
-
res = await verifyEmailAddress(this.#config, me, String(callbackUrl));
|
|
2525
3014
|
return res;
|
|
2526
|
-
}
|
|
2527
|
-
const message = "Unable to verify email.";
|
|
2528
|
-
this.#logger?.warn(message);
|
|
2529
|
-
res = new Response(message, { status: 400 });
|
|
2530
|
-
}
|
|
2531
|
-
if (bypassEmail) {
|
|
2532
|
-
res = this.updateSelf({ emailVerified: true }, rawResponse);
|
|
2533
|
-
}
|
|
2534
|
-
this.#logger.error(
|
|
2535
|
-
"Unable to verify email address. Configure your SMTP server in the console."
|
|
2536
|
-
);
|
|
2537
|
-
return res;
|
|
3015
|
+
});
|
|
2538
3016
|
}
|
|
2539
3017
|
};
|
|
2540
3018
|
async function verifyEmailAddress(config, user, callback) {
|
|
2541
|
-
|
|
3019
|
+
const { headers } = ctx.get();
|
|
3020
|
+
headers?.set("content-type", "application/x-www-form-urlencoded");
|
|
3021
|
+
ctx.set({ headers });
|
|
2542
3022
|
const { csrfToken } = await obtainCsrf(config);
|
|
2543
|
-
const defaults = defaultCallbackUrl2(
|
|
3023
|
+
const defaults = defaultCallbackUrl2();
|
|
2544
3024
|
const callbackUrl = callback ?? String(defaults.callbackUrl);
|
|
2545
3025
|
const res = await fetchVerifyEmail(
|
|
2546
3026
|
config,
|
|
@@ -2556,9 +3036,10 @@ async function verifyEmailAddress(config, user, callback) {
|
|
|
2556
3036
|
}
|
|
2557
3037
|
return res;
|
|
2558
3038
|
}
|
|
2559
|
-
function defaultCallbackUrl2(
|
|
3039
|
+
function defaultCallbackUrl2() {
|
|
2560
3040
|
let cb = null;
|
|
2561
|
-
const
|
|
3041
|
+
const { headers } = ctx.get();
|
|
3042
|
+
const fallbackCb = parseCallback(headers);
|
|
2562
3043
|
if (fallbackCb) {
|
|
2563
3044
|
const [, value] = fallbackCb.split("=");
|
|
2564
3045
|
cb = decodeURIComponent(value);
|
|
@@ -2572,194 +3053,286 @@ var Tenants = class {
|
|
|
2572
3053
|
constructor(config) {
|
|
2573
3054
|
this.#config = config;
|
|
2574
3055
|
}
|
|
3056
|
+
/**
|
|
3057
|
+
* Create a new tenant using `POST /api/tenants`.
|
|
3058
|
+
* See `packages/server/src/api/routes/tenants/POST.ts` for the
|
|
3059
|
+
* `createTenant` operation definition.
|
|
3060
|
+
*/
|
|
2575
3061
|
async create(req, rawResponse) {
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
3062
|
+
return withNileContext(this.#config, async () => {
|
|
3063
|
+
let res;
|
|
3064
|
+
if (typeof req === "string") {
|
|
3065
|
+
res = await fetchTenants(
|
|
3066
|
+
this.#config,
|
|
3067
|
+
"POST",
|
|
3068
|
+
JSON.stringify({ name: req })
|
|
3069
|
+
);
|
|
3070
|
+
} else if (typeof req === "object" && ("name" in req || "id" in req)) {
|
|
3071
|
+
res = await fetchTenants(this.#config, "POST", JSON.stringify(req));
|
|
3072
|
+
}
|
|
3073
|
+
if (rawResponse) {
|
|
3074
|
+
return res;
|
|
3075
|
+
}
|
|
3076
|
+
try {
|
|
3077
|
+
return await res?.clone().json();
|
|
3078
|
+
} catch {
|
|
3079
|
+
return res;
|
|
3080
|
+
}
|
|
3081
|
+
});
|
|
2594
3082
|
}
|
|
3083
|
+
/**
|
|
3084
|
+
* Remove a tenant via `DELETE /api/tenants/{tenantId}`.
|
|
3085
|
+
*
|
|
3086
|
+
* @param req - The tenant to remove or context containing the id.
|
|
3087
|
+
*/
|
|
2595
3088
|
async delete(req) {
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
3089
|
+
return withNileContext(this.#config, async () => {
|
|
3090
|
+
if (typeof req === "string") {
|
|
3091
|
+
ctx.set({ tenantId: req });
|
|
3092
|
+
}
|
|
3093
|
+
if (typeof req === "object" && "id" in req) {
|
|
3094
|
+
ctx.set({ tenantId: req.id });
|
|
3095
|
+
}
|
|
3096
|
+
const res = await fetchTenant(this.#config, "DELETE");
|
|
3097
|
+
return res;
|
|
3098
|
+
});
|
|
2604
3099
|
}
|
|
3100
|
+
/**
|
|
3101
|
+
* Fetch details for a tenant using `GET /api/tenants/{tenantId}`.
|
|
3102
|
+
*
|
|
3103
|
+
* @param req - Tenant identifier or context.
|
|
3104
|
+
* @param [rawResponse] - When true, return the raw {@link Response}.
|
|
3105
|
+
*/
|
|
2605
3106
|
async get(req, rawResponse) {
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
3107
|
+
return withNileContext(this.#config, async () => {
|
|
3108
|
+
if (typeof req === "string") {
|
|
3109
|
+
ctx.set({ tenantId: req });
|
|
3110
|
+
} else if (typeof req === "object" && "id" in req) {
|
|
3111
|
+
ctx.set({ tenantId: req.id });
|
|
3112
|
+
}
|
|
3113
|
+
const res = await fetchTenant(this.#config, "GET");
|
|
3114
|
+
if (rawResponse === true || req === true) {
|
|
3115
|
+
return res;
|
|
3116
|
+
}
|
|
3117
|
+
try {
|
|
3118
|
+
return await res?.clone().json();
|
|
3119
|
+
} catch {
|
|
3120
|
+
return res;
|
|
3121
|
+
}
|
|
3122
|
+
});
|
|
2620
3123
|
}
|
|
2621
3124
|
async update(req, rawResponse) {
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
3125
|
+
return withNileContext(this.#config, async () => {
|
|
3126
|
+
let res;
|
|
3127
|
+
if (typeof req === "object" && ("name" in req || "id" in req)) {
|
|
3128
|
+
const { id, ...remaining } = req;
|
|
3129
|
+
if (id) {
|
|
3130
|
+
ctx.set({ tenantId: id });
|
|
3131
|
+
}
|
|
3132
|
+
res = await fetchTenant(this.#config, "PUT", JSON.stringify(remaining));
|
|
2627
3133
|
}
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
}
|
|
3134
|
+
if (rawResponse) {
|
|
3135
|
+
return res;
|
|
3136
|
+
}
|
|
3137
|
+
try {
|
|
3138
|
+
return await res?.clone().json();
|
|
3139
|
+
} catch {
|
|
3140
|
+
return res;
|
|
3141
|
+
}
|
|
3142
|
+
});
|
|
2638
3143
|
}
|
|
3144
|
+
/**
|
|
3145
|
+
* List tenants for the current user via `GET /api/tenants`.
|
|
3146
|
+
* See `packages/server/src/api/routes/tenants/GET.ts` for details.
|
|
3147
|
+
*/
|
|
2639
3148
|
async list(req) {
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
3149
|
+
return withNileContext(
|
|
3150
|
+
this.#config,
|
|
3151
|
+
async () => {
|
|
3152
|
+
const res = await fetchTenantsByUser(this.#config);
|
|
3153
|
+
if (req === true) {
|
|
3154
|
+
return res;
|
|
3155
|
+
}
|
|
3156
|
+
try {
|
|
3157
|
+
return await res?.clone().json();
|
|
3158
|
+
} catch {
|
|
3159
|
+
return res;
|
|
3160
|
+
}
|
|
3161
|
+
},
|
|
3162
|
+
"listTenants"
|
|
3163
|
+
);
|
|
2649
3164
|
}
|
|
3165
|
+
/**
|
|
3166
|
+
* Leave the current tenant using `DELETE /api/tenants/{tenantId}/users/{userId}`.
|
|
3167
|
+
*
|
|
3168
|
+
* @param [req] - Optionally specify the tenant id to leave.
|
|
3169
|
+
*/
|
|
2650
3170
|
async leaveTenant(req) {
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
3171
|
+
return withNileContext(this.#config, async () => {
|
|
3172
|
+
const me = await fetchMe(this.#config);
|
|
3173
|
+
try {
|
|
3174
|
+
const json = await me.json();
|
|
3175
|
+
if ("id" in json) {
|
|
3176
|
+
ctx.set({ userId: json.id });
|
|
3177
|
+
}
|
|
3178
|
+
} catch {
|
|
2656
3179
|
}
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
this.#
|
|
2663
|
-
}
|
|
2664
|
-
return await fetchTenantUser(this.#config, "DELETE");
|
|
3180
|
+
if (typeof req === "string") {
|
|
3181
|
+
ctx.set({ tenantId: req });
|
|
3182
|
+
} else {
|
|
3183
|
+
this.#handleContext(req);
|
|
3184
|
+
}
|
|
3185
|
+
return await fetchTenantUser(this.#config, "DELETE");
|
|
3186
|
+
});
|
|
2665
3187
|
}
|
|
2666
3188
|
async addMember(req, rawResponse) {
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
3189
|
+
return withNileContext(this.#config, async () => {
|
|
3190
|
+
if (typeof req === "string") {
|
|
3191
|
+
ctx.set({ userId: req });
|
|
3192
|
+
} else {
|
|
3193
|
+
this.#handleContext(req);
|
|
3194
|
+
}
|
|
3195
|
+
const res = await fetchTenantUser(this.#config, "PUT");
|
|
3196
|
+
return responseHandler(res, rawResponse);
|
|
3197
|
+
});
|
|
2674
3198
|
}
|
|
3199
|
+
/**
|
|
3200
|
+
* Remove a user from a tenant with `DELETE /api/tenants/{tenantId}/users/{userId}`.
|
|
3201
|
+
*
|
|
3202
|
+
* @param req - User and tenant identifiers or context.
|
|
3203
|
+
* @param [rawResponse] - When true, return the raw {@link Response}.
|
|
3204
|
+
*/
|
|
2675
3205
|
async removeMember(req, rawResponse) {
|
|
2676
|
-
this.#
|
|
2677
|
-
|
|
2678
|
-
|
|
3206
|
+
return withNileContext(this.#config, async () => {
|
|
3207
|
+
this.#handleContext(req);
|
|
3208
|
+
if (typeof req === "string") {
|
|
3209
|
+
ctx.set({ userId: req });
|
|
3210
|
+
}
|
|
3211
|
+
const res = await fetchTenantUser(this.#config, "DELETE");
|
|
3212
|
+
return responseHandler(res, rawResponse);
|
|
3213
|
+
});
|
|
2679
3214
|
}
|
|
2680
3215
|
async users(req, rawResponse) {
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
3216
|
+
return withNileContext(
|
|
3217
|
+
this.#config,
|
|
3218
|
+
async () => {
|
|
3219
|
+
this.#handleContext(req);
|
|
3220
|
+
const res = await fetchTenantUsers(this.#config, "GET");
|
|
3221
|
+
return responseHandler(
|
|
3222
|
+
res,
|
|
3223
|
+
rawResponse || typeof req === "boolean" && req
|
|
3224
|
+
);
|
|
3225
|
+
},
|
|
3226
|
+
"users"
|
|
2686
3227
|
);
|
|
2687
3228
|
}
|
|
3229
|
+
/**
|
|
3230
|
+
* List invites for the current tenant via `GET /api/tenants/{tenantId}/invites`.
|
|
3231
|
+
*/
|
|
2688
3232
|
async invites() {
|
|
2689
|
-
|
|
2690
|
-
|
|
3233
|
+
return withNileContext(
|
|
3234
|
+
this.#config,
|
|
3235
|
+
async () => {
|
|
3236
|
+
const res = await fetchInvites(this.#config);
|
|
3237
|
+
return responseHandler(res);
|
|
3238
|
+
},
|
|
3239
|
+
"invites"
|
|
3240
|
+
);
|
|
2691
3241
|
}
|
|
2692
3242
|
async invite(req, rawResponse) {
|
|
2693
|
-
|
|
2694
|
-
const defaults = defaultCallbackUrl3(this.#config);
|
|
2695
|
-
let identifier = req;
|
|
2696
|
-
let callbackUrl = defaults.callbackUrl;
|
|
2697
|
-
let redirectUrl = defaults.redirectUrl;
|
|
2698
|
-
if (typeof req === "object") {
|
|
2699
|
-
if ("email" in req) {
|
|
2700
|
-
identifier = req.email;
|
|
2701
|
-
}
|
|
2702
|
-
if ("callbackUrl" in req) {
|
|
2703
|
-
callbackUrl = req.callbackUrl ? req.callbackUrl : "";
|
|
2704
|
-
}
|
|
2705
|
-
if ("redirectUrl" in req) {
|
|
2706
|
-
redirectUrl = req.redirectUrl ? req.redirectUrl : "";
|
|
2707
|
-
}
|
|
2708
|
-
}
|
|
2709
|
-
this.#config.headers.set(
|
|
2710
|
-
"Content-Type",
|
|
2711
|
-
"application/x-www-form-urlencoded"
|
|
2712
|
-
);
|
|
2713
|
-
const res = await fetchInvite(
|
|
3243
|
+
return withNileContext(
|
|
2714
3244
|
this.#config,
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
3245
|
+
async () => {
|
|
3246
|
+
const { csrfToken } = await obtainCsrf(
|
|
3247
|
+
this.#config
|
|
3248
|
+
);
|
|
3249
|
+
const defaults = defaultCallbackUrl3(this.#config);
|
|
3250
|
+
let identifier = req;
|
|
3251
|
+
let callbackUrl = defaults.callbackUrl;
|
|
3252
|
+
let redirectUrl = defaults.redirectUrl;
|
|
3253
|
+
if (typeof req === "object") {
|
|
3254
|
+
if ("email" in req) {
|
|
3255
|
+
identifier = req.email;
|
|
3256
|
+
}
|
|
3257
|
+
const { callbackUrl: cbUrl } = defaultCallbackUrl3(this.#config);
|
|
3258
|
+
if ("callbackUrl" in req) {
|
|
3259
|
+
callbackUrl = fQUrl2(cbUrl, req.callbackUrl ?? "/");
|
|
3260
|
+
}
|
|
3261
|
+
if ("redirectUrl" in req) {
|
|
3262
|
+
redirectUrl = fQUrl2(cbUrl, req.redirectUrl ?? "/");
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
const { headers } = ctx.get();
|
|
3266
|
+
headers?.set("Content-Type", "application/x-www-form-urlencoded");
|
|
3267
|
+
ctx.set({ headers });
|
|
3268
|
+
const res = await fetchInvite(
|
|
3269
|
+
this.#config,
|
|
3270
|
+
"POST",
|
|
3271
|
+
new URLSearchParams({
|
|
3272
|
+
identifier,
|
|
3273
|
+
csrfToken,
|
|
3274
|
+
callbackUrl,
|
|
3275
|
+
redirectUrl
|
|
3276
|
+
}).toString()
|
|
3277
|
+
);
|
|
3278
|
+
return responseHandler(res, rawResponse);
|
|
3279
|
+
},
|
|
3280
|
+
"invites"
|
|
2722
3281
|
);
|
|
2723
|
-
return responseHandler(res, rawResponse);
|
|
2724
3282
|
}
|
|
3283
|
+
/**
|
|
3284
|
+
* Accept an invite using `PUT /api/tenants/{tenantId}/invite`.
|
|
3285
|
+
*
|
|
3286
|
+
* @param req - Identifier and token from the invite email.
|
|
3287
|
+
* @param [rawResponse] - When true, return the raw {@link Response}.
|
|
3288
|
+
*/
|
|
2725
3289
|
async acceptInvite(req, rawResponse) {
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
3290
|
+
return withNileContext(this.#config, async () => {
|
|
3291
|
+
if (!req) {
|
|
3292
|
+
throw new Error("The identifier and token are required.");
|
|
3293
|
+
}
|
|
3294
|
+
const { identifier, token } = req;
|
|
3295
|
+
const { callbackUrl: cbUrl } = defaultCallbackUrl3(this.#config);
|
|
3296
|
+
const callbackUrl = fQUrl2(cbUrl, req?.callbackUrl ?? "/");
|
|
3297
|
+
const res = await fetchInvite(
|
|
3298
|
+
this.#config,
|
|
3299
|
+
"PUT",
|
|
3300
|
+
new URLSearchParams({
|
|
3301
|
+
identifier,
|
|
3302
|
+
token,
|
|
3303
|
+
callbackUrl
|
|
3304
|
+
}).toString()
|
|
3305
|
+
);
|
|
3306
|
+
return responseHandler(res, rawResponse);
|
|
3307
|
+
});
|
|
2742
3308
|
}
|
|
3309
|
+
/**
|
|
3310
|
+
* Delete a pending invite using `DELETE /api/tenants/{tenantId}/invite/{inviteId}`.
|
|
3311
|
+
*
|
|
3312
|
+
* @param req - Identifier of the invite to remove.
|
|
3313
|
+
*/
|
|
2743
3314
|
async deleteInvite(req) {
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
3315
|
+
return withNileContext(this.#config, async () => {
|
|
3316
|
+
let id = "";
|
|
3317
|
+
if (typeof req === "object") {
|
|
3318
|
+
id = req.id;
|
|
3319
|
+
} else {
|
|
3320
|
+
id = req;
|
|
3321
|
+
}
|
|
3322
|
+
if (!id) {
|
|
3323
|
+
throw new Error("An invite id is required.");
|
|
3324
|
+
}
|
|
3325
|
+
const res = await fetchInvite(this.#config, "DELETE", id);
|
|
3326
|
+
return responseHandler(res, true);
|
|
3327
|
+
});
|
|
2755
3328
|
}
|
|
2756
3329
|
#handleContext(req) {
|
|
2757
3330
|
if (typeof req === "object") {
|
|
2758
3331
|
if ("tenantId" in req) {
|
|
2759
|
-
|
|
3332
|
+
ctx.set({ tenantId: req.tenantId });
|
|
2760
3333
|
}
|
|
2761
3334
|
if ("userId" in req) {
|
|
2762
|
-
|
|
3335
|
+
ctx.set({ userId: req.userId });
|
|
2763
3336
|
}
|
|
2764
3337
|
}
|
|
2765
3338
|
}
|
|
@@ -2777,15 +3350,13 @@ async function responseHandler(res, rawResponse) {
|
|
|
2777
3350
|
function defaultCallbackUrl3(config) {
|
|
2778
3351
|
let cb = null;
|
|
2779
3352
|
let redirect = null;
|
|
2780
|
-
const
|
|
3353
|
+
const { headers, tenantId } = ctx.get();
|
|
3354
|
+
const fallbackCb = parseCallback(headers);
|
|
2781
3355
|
if (fallbackCb) {
|
|
2782
3356
|
const [, value] = fallbackCb.split("=");
|
|
2783
3357
|
cb = decodeURIComponent(value);
|
|
2784
3358
|
if (value) {
|
|
2785
|
-
redirect = `${new URL(cb).origin}${config.routePrefix}${"/tenants/{tenantId}/invite" /* INVITE */.replace(
|
|
2786
|
-
"{tenantId}",
|
|
2787
|
-
String(config.tenantId)
|
|
2788
|
-
)}`;
|
|
3359
|
+
redirect = `${new URL(cb).origin}${config.routePrefix}${"/tenants/{tenantId}/invite" /* INVITE */.replace("{tenantId}", String(tenantId))}`;
|
|
2789
3360
|
}
|
|
2790
3361
|
}
|
|
2791
3362
|
return { callbackUrl: cb, redirectUrl: redirect };
|
|
@@ -2823,90 +3394,34 @@ function handlersWithContext(config) {
|
|
|
2823
3394
|
function updateConfig(response, config) {
|
|
2824
3395
|
let origin = "http://localhost:3000";
|
|
2825
3396
|
let headers = null;
|
|
2826
|
-
if (response
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
3397
|
+
if (response instanceof Response) {
|
|
3398
|
+
if (response?.status === 302) {
|
|
3399
|
+
const location = response.headers.get("location");
|
|
3400
|
+
if (location) {
|
|
3401
|
+
const urlLocation = new URL(location);
|
|
3402
|
+
origin = urlLocation.origin;
|
|
3403
|
+
}
|
|
2831
3404
|
}
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
3405
|
+
const setCookies = [];
|
|
3406
|
+
if (response?.headers) {
|
|
3407
|
+
for (const [key17, value] of response.headers) {
|
|
3408
|
+
if (key17.toLowerCase() === "set-cookie") {
|
|
3409
|
+
setCookies.push(value);
|
|
3410
|
+
}
|
|
2838
3411
|
}
|
|
2839
3412
|
}
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
3413
|
+
if (setCookies.length > 0) {
|
|
3414
|
+
const cookieHeader = setCookies.map((cookieStr) => cookieStr.split(";")[0]).join("; ");
|
|
3415
|
+
headers = new Headers({ cookie: cookieHeader });
|
|
3416
|
+
}
|
|
2844
3417
|
}
|
|
2845
3418
|
return {
|
|
2846
3419
|
...config,
|
|
2847
3420
|
origin,
|
|
2848
3421
|
headers: headers ?? void 0,
|
|
2849
|
-
|
|
2850
|
-
};
|
|
2851
|
-
}
|
|
2852
|
-
|
|
2853
|
-
// src/api/utils/extensions.ts
|
|
2854
|
-
function bindHandleOnRequest(instance) {
|
|
2855
|
-
return async function handleOnRequest(config, _init, params) {
|
|
2856
|
-
const { debug } = config.logger("[EXTENSIONS]");
|
|
2857
|
-
if (config.extensions) {
|
|
2858
|
-
for (const create2 of config.extensions) {
|
|
2859
|
-
if (typeof create2 !== "function") {
|
|
2860
|
-
return void 0;
|
|
2861
|
-
}
|
|
2862
|
-
const ext = await create2(instance);
|
|
2863
|
-
if (ext.onRequest) {
|
|
2864
|
-
const previousContext = instance.getContext();
|
|
2865
|
-
if (previousContext.preserveHeaders) {
|
|
2866
|
-
instance.setContext({ preserveHeaders: false });
|
|
2867
|
-
}
|
|
2868
|
-
await ext.onRequest(_init.request);
|
|
2869
|
-
const updatedContext = instance.getContext();
|
|
2870
|
-
if (updatedContext?.headers) {
|
|
2871
|
-
const cookie = updatedContext.headers.get("cookie");
|
|
2872
|
-
if (cookie) {
|
|
2873
|
-
params.headers.set(
|
|
2874
|
-
"cookie",
|
|
2875
|
-
mergeCookies(
|
|
2876
|
-
previousContext.preserveHeaders ? previousContext.headers?.get("cookie") : null,
|
|
2877
|
-
updatedContext.headers.get("cookie")
|
|
2878
|
-
)
|
|
2879
|
-
);
|
|
2880
|
-
}
|
|
2881
|
-
if (updatedContext.tenantId) {
|
|
2882
|
-
params.headers.set(
|
|
2883
|
-
TENANT_COOKIE,
|
|
2884
|
-
String(updatedContext.headers.get(TENANT_COOKIE))
|
|
2885
|
-
);
|
|
2886
|
-
}
|
|
2887
|
-
}
|
|
2888
|
-
debug(`${ext.id ?? create2.name} ran onRequest`);
|
|
2889
|
-
}
|
|
2890
|
-
}
|
|
2891
|
-
}
|
|
3422
|
+
useLastContext: true
|
|
2892
3423
|
};
|
|
2893
3424
|
}
|
|
2894
|
-
function buildExtensionConfig(instance) {
|
|
2895
|
-
return {
|
|
2896
|
-
handleOnRequest: bindHandleOnRequest(instance)
|
|
2897
|
-
};
|
|
2898
|
-
}
|
|
2899
|
-
function mergeCookies(...cookieStrings) {
|
|
2900
|
-
const cookieMap = /* @__PURE__ */ new Map();
|
|
2901
|
-
for (const str of cookieStrings) {
|
|
2902
|
-
if (!str) continue;
|
|
2903
|
-
for (const part of str.split(";")) {
|
|
2904
|
-
const [key17, value] = part.split("=").map((s) => s.trim());
|
|
2905
|
-
if (key17 && value) cookieMap.set(key17, value);
|
|
2906
|
-
}
|
|
2907
|
-
}
|
|
2908
|
-
return [...cookieMap.entries()].map(([k, v]) => `${k}=${v}`).join("; ");
|
|
2909
|
-
}
|
|
2910
3425
|
|
|
2911
3426
|
// src/Server.ts
|
|
2912
3427
|
var Server = class {
|
|
@@ -2915,149 +3430,164 @@ var Server = class {
|
|
|
2915
3430
|
auth;
|
|
2916
3431
|
#config;
|
|
2917
3432
|
#handlers;
|
|
2918
|
-
#paths;
|
|
2919
3433
|
#manager;
|
|
2920
|
-
#headers;
|
|
2921
|
-
#preserveHeaders;
|
|
2922
3434
|
constructor(config) {
|
|
2923
3435
|
this.#config = new Config({
|
|
2924
3436
|
...config,
|
|
2925
3437
|
extensionCtx: buildExtensionConfig(this)
|
|
2926
3438
|
});
|
|
2927
3439
|
watchTenantId((tenantId) => {
|
|
2928
|
-
if (tenantId !== this.#config.tenantId) {
|
|
2929
|
-
this.#config.tenantId = tenantId;
|
|
3440
|
+
if (tenantId !== this.#config.context.tenantId) {
|
|
3441
|
+
this.#config.context.tenantId = String(tenantId);
|
|
2930
3442
|
this.#reset();
|
|
2931
3443
|
}
|
|
2932
3444
|
});
|
|
2933
3445
|
watchUserId((userId) => {
|
|
2934
|
-
if (userId !== this.#config.userId) {
|
|
2935
|
-
this.#config.userId = userId;
|
|
3446
|
+
if (userId !== this.#config.context.userId) {
|
|
3447
|
+
this.#config.context.userId = String(userId);
|
|
2936
3448
|
this.#reset();
|
|
2937
3449
|
}
|
|
2938
3450
|
});
|
|
2939
3451
|
watchHeaders((headers) => {
|
|
2940
|
-
|
|
2941
|
-
|
|
3452
|
+
if (headers) {
|
|
3453
|
+
this.#config.context.headers = new Headers(headers);
|
|
3454
|
+
this.#reset();
|
|
3455
|
+
}
|
|
2942
3456
|
});
|
|
2943
3457
|
this.#handlers = {
|
|
2944
3458
|
...this.#config.handlers,
|
|
2945
3459
|
withContext: handlersWithContext(this.#config)
|
|
2946
3460
|
};
|
|
2947
|
-
this.#
|
|
2948
|
-
this.#paths = this.#config.paths;
|
|
2949
|
-
this.#config.tenantId = getTenantId({ config: this.#config });
|
|
3461
|
+
this.#config.context.tenantId = getTenantId({ config: this.#config });
|
|
2950
3462
|
this.#manager = new DBManager(this.#config);
|
|
2951
3463
|
this.#handleHeaders(config);
|
|
2952
3464
|
this.users = new Users(this.#config);
|
|
2953
3465
|
this.tenants = new Tenants(this.#config);
|
|
2954
3466
|
this.auth = new Auth(this.#config);
|
|
3467
|
+
if (config?.extensions) {
|
|
3468
|
+
for (const create2 of config.extensions) {
|
|
3469
|
+
if (typeof create2 !== "function") {
|
|
3470
|
+
continue;
|
|
3471
|
+
}
|
|
3472
|
+
const ext = create2(this);
|
|
3473
|
+
if (ext.onConfigure) {
|
|
3474
|
+
ext.onConfigure();
|
|
3475
|
+
}
|
|
3476
|
+
if (ext?.replace?.handlers) {
|
|
3477
|
+
this.#config.logger("[EXTENSION]").debug(`${ext.id} replacing handlers`);
|
|
3478
|
+
this.#handlers = ext.replace.handlers({
|
|
3479
|
+
...this.#config.handlers,
|
|
3480
|
+
withContext: handlersWithContext(this.#config)
|
|
3481
|
+
});
|
|
3482
|
+
}
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
2955
3485
|
}
|
|
2956
|
-
|
|
3486
|
+
/**
|
|
3487
|
+
* Query the database with the current context
|
|
3488
|
+
*/
|
|
3489
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3490
|
+
query = (queryStream, values) => {
|
|
3491
|
+
this.#config.context = { ...this.getContext() };
|
|
2957
3492
|
const pool = this.#manager.getConnection(this.#config);
|
|
3493
|
+
return pool.query(queryStream, values);
|
|
3494
|
+
};
|
|
3495
|
+
/**
|
|
3496
|
+
* Return a db object that can be used to talk to the database
|
|
3497
|
+
* Does not have a context by default
|
|
3498
|
+
*/
|
|
3499
|
+
get db() {
|
|
3500
|
+
const pool = this.#manager.getConnection(this.#config, true);
|
|
2958
3501
|
return Object.assign(pool, {
|
|
2959
3502
|
clearConnections: () => {
|
|
2960
3503
|
this.#manager.clear(this.#config);
|
|
2961
3504
|
}
|
|
2962
3505
|
});
|
|
2963
3506
|
}
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
*/
|
|
2967
|
-
getInstance(config, req) {
|
|
2968
|
-
const _config = { ...this.#config, ...config };
|
|
2969
|
-
const updatedConfig = new Config(_config);
|
|
2970
|
-
this.#config = new Config(updatedConfig);
|
|
2971
|
-
this.#config.tenantId = config.tenantId;
|
|
2972
|
-
this.#config.userId = config.userId;
|
|
2973
|
-
if (req) {
|
|
2974
|
-
this.setContext(req);
|
|
2975
|
-
}
|
|
2976
|
-
this.#reset();
|
|
2977
|
-
return this;
|
|
3507
|
+
get logger() {
|
|
3508
|
+
return this.#config.logger;
|
|
2978
3509
|
}
|
|
2979
|
-
|
|
2980
|
-
return
|
|
3510
|
+
get extensions() {
|
|
3511
|
+
return {
|
|
3512
|
+
remove: async (id) => {
|
|
3513
|
+
if (!this.#config.extensions) return;
|
|
3514
|
+
const resolved = this.#config.extensions.map((ext) => ext(this));
|
|
3515
|
+
const index = resolved.findIndex((ext) => ext.id === id);
|
|
3516
|
+
if (index !== -1) {
|
|
3517
|
+
this.#config.extensions.splice(index, 1);
|
|
3518
|
+
}
|
|
3519
|
+
return resolved;
|
|
3520
|
+
},
|
|
3521
|
+
add: (extension) => {
|
|
3522
|
+
if (!this.#config.extensions) {
|
|
3523
|
+
this.#config.extensions = [];
|
|
3524
|
+
}
|
|
3525
|
+
this.#config.extensions.push(extension);
|
|
3526
|
+
}
|
|
3527
|
+
};
|
|
2981
3528
|
}
|
|
2982
3529
|
get handlers() {
|
|
2983
3530
|
return this.#handlers;
|
|
2984
3531
|
}
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
this.#reset();
|
|
3001
|
-
return;
|
|
3002
|
-
}
|
|
3003
|
-
} catch {
|
|
3004
|
-
}
|
|
3005
|
-
let ok = false;
|
|
3006
|
-
if (req && typeof req === "object" && "tenantId" in req) {
|
|
3007
|
-
ok = true;
|
|
3008
|
-
this.#config.tenantId = req.tenantId;
|
|
3009
|
-
}
|
|
3010
|
-
if (req && typeof req === "object" && "userId" in req) {
|
|
3011
|
-
ok = true;
|
|
3012
|
-
this.#config.userId = req.userId;
|
|
3013
|
-
}
|
|
3014
|
-
if (req && typeof req === "object" && "preserveHeaders" in req) {
|
|
3015
|
-
ok = true;
|
|
3016
|
-
this.#preserveHeaders = Boolean(req.preserveHeaders);
|
|
3017
|
-
}
|
|
3018
|
-
if (ok) {
|
|
3019
|
-
return;
|
|
3532
|
+
get paths() {
|
|
3533
|
+
return this.#config.paths;
|
|
3534
|
+
}
|
|
3535
|
+
set paths(paths) {
|
|
3536
|
+
this.#config.paths = paths;
|
|
3537
|
+
}
|
|
3538
|
+
async withContext(contextOrFn, maybeFn) {
|
|
3539
|
+
const isFn = typeof contextOrFn === "function";
|
|
3540
|
+
const context = isFn ? {} : contextOrFn ?? {};
|
|
3541
|
+
const fn = isFn ? contextOrFn : maybeFn;
|
|
3542
|
+
const preserve = "useLastContext" in context ? context.useLastContext : true;
|
|
3543
|
+
if (preserve) {
|
|
3544
|
+
this.#config.context = { ...this.getContext(), ...context };
|
|
3545
|
+
} else {
|
|
3546
|
+
this.#config.context = { ...defaultContext, ...context };
|
|
3020
3547
|
}
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3548
|
+
return withNileContext(this.#config, async () => {
|
|
3549
|
+
return fn ? fn(this) : this;
|
|
3550
|
+
});
|
|
3551
|
+
}
|
|
3552
|
+
async noContext(fn) {
|
|
3553
|
+
this.#config.context.tenantId = void 0;
|
|
3554
|
+
this.#config.context.userId = void 0;
|
|
3555
|
+
return withNileContext(this.#config, async () => {
|
|
3556
|
+
ctx.set({ userId: void 0, tenantId: void 0 });
|
|
3557
|
+
if (fn) {
|
|
3558
|
+
return fn(this);
|
|
3027
3559
|
}
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
if (warn) {
|
|
3031
|
-
warn(
|
|
3032
|
-
"Set context expects a Request, Header instance or an object of Record<string, string>"
|
|
3033
|
-
);
|
|
3034
|
-
}
|
|
3560
|
+
return this;
|
|
3561
|
+
});
|
|
3035
3562
|
}
|
|
3563
|
+
/**
|
|
3564
|
+
*
|
|
3565
|
+
* @returns the last used (basically global) context object, useful for debugging or making your own context
|
|
3566
|
+
*/
|
|
3036
3567
|
getContext() {
|
|
3037
|
-
return
|
|
3038
|
-
headers: this.#headers,
|
|
3039
|
-
userId: this.#config.userId,
|
|
3040
|
-
tenantId: this.#config.tenantId,
|
|
3041
|
-
preserveHeaders: this.#preserveHeaders
|
|
3042
|
-
};
|
|
3568
|
+
return ctx.getLastUsed();
|
|
3043
3569
|
}
|
|
3044
3570
|
/**
|
|
3045
3571
|
* Merge headers together
|
|
3572
|
+
* Saves them in a singleton for use in a request later. It's basically the "default" value
|
|
3046
3573
|
* Internally, passed a NileConfig, externally, should be using Headers
|
|
3047
3574
|
*/
|
|
3048
3575
|
#handleHeaders(config) {
|
|
3049
3576
|
const updates = [];
|
|
3050
3577
|
let headers;
|
|
3051
|
-
this.#headers = new Headers();
|
|
3578
|
+
this.#config.context.headers = new Headers();
|
|
3052
3579
|
if (config instanceof Headers) {
|
|
3053
3580
|
headers = config;
|
|
3054
3581
|
} else if (config?.headers) {
|
|
3055
3582
|
headers = config?.headers;
|
|
3056
3583
|
if (config && config.origin) {
|
|
3057
|
-
this.#headers.set(HEADER_ORIGIN, config.origin);
|
|
3584
|
+
this.#config.context.headers.set(HEADER_ORIGIN, config.origin);
|
|
3058
3585
|
}
|
|
3059
3586
|
if (config && config.secureCookies != null) {
|
|
3060
|
-
this.#headers.set(
|
|
3587
|
+
this.#config.context.headers.set(
|
|
3588
|
+
HEADER_SECURE_COOKIES,
|
|
3589
|
+
String(config.secureCookies)
|
|
3590
|
+
);
|
|
3061
3591
|
}
|
|
3062
3592
|
}
|
|
3063
3593
|
if (headers instanceof Headers) {
|
|
@@ -3070,8 +3600,7 @@ var Server = class {
|
|
|
3070
3600
|
}
|
|
3071
3601
|
}
|
|
3072
3602
|
const merged = {};
|
|
3073
|
-
this.#config.
|
|
3074
|
-
this.#headers?.forEach((value, key17) => {
|
|
3603
|
+
this.#config.context.headers?.forEach((value, key17) => {
|
|
3075
3604
|
if (key17.toLowerCase() !== "cookie") {
|
|
3076
3605
|
merged[key17.toLowerCase()] = value;
|
|
3077
3606
|
}
|
|
@@ -3080,16 +3609,15 @@ var Server = class {
|
|
|
3080
3609
|
merged[key17] = value;
|
|
3081
3610
|
}
|
|
3082
3611
|
for (const [key17, value] of Object.entries(merged)) {
|
|
3083
|
-
this.#headers.set(key17, value);
|
|
3612
|
+
this.#config.context.headers.set(key17, value);
|
|
3084
3613
|
}
|
|
3085
3614
|
this.#config.logger("[handleHeaders]").debug(JSON.stringify(merged));
|
|
3086
|
-
this.#config.headers = this.#headers;
|
|
3087
3615
|
}
|
|
3088
3616
|
/**
|
|
3089
3617
|
* Allow some internal mutations to reset our config + headers
|
|
3090
3618
|
*/
|
|
3091
3619
|
#reset = () => {
|
|
3092
|
-
this.#config.
|
|
3620
|
+
this.#config.extensionCtx = buildExtensionConfig(this);
|
|
3093
3621
|
this.users = new Users(this.#config);
|
|
3094
3622
|
this.tenants = new Tenants(this.#config);
|
|
3095
3623
|
this.auth = new Auth(this.#config);
|
|
@@ -3104,6 +3632,7 @@ function create(config) {
|
|
|
3104
3632
|
}
|
|
3105
3633
|
|
|
3106
3634
|
exports.APIErrorErrorCodeEnum = APIErrorErrorCodeEnum;
|
|
3635
|
+
exports.ExtensionState = ExtensionState;
|
|
3107
3636
|
exports.HEADER_ORIGIN = HEADER_ORIGIN;
|
|
3108
3637
|
exports.HEADER_SECURE_COOKIES = HEADER_SECURE_COOKIES;
|
|
3109
3638
|
exports.LoginUserResponseTokenTypeEnum = LoginUserResponseTokenTypeEnum;
|
|
@@ -3113,6 +3642,8 @@ exports.TENANT_COOKIE = TENANT_COOKIE;
|
|
|
3113
3642
|
exports.USER_COOKIE = USER_COOKIE;
|
|
3114
3643
|
exports.parseCSRF = parseCSRF;
|
|
3115
3644
|
exports.parseCallback = parseCallback;
|
|
3645
|
+
exports.parseResetToken = parseResetToken;
|
|
3646
|
+
exports.parseTenantId = parseTenantId;
|
|
3116
3647
|
exports.parseToken = parseToken;
|
|
3117
3648
|
//# sourceMappingURL=index.js.map
|
|
3118
3649
|
//# sourceMappingURL=index.js.map
|