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