@niledatabase/server 5.0.0-alpha.31 → 5.0.0-alpha.33
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 +25 -11
- package/dist/index.d.ts +25 -11
- package/dist/index.js +91 -72
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +91 -72
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import pg, { PoolConfig, PoolClient } from 'pg';
|
|
1
|
+
import pg, { Pool, PoolConfig, PoolClient } from 'pg';
|
|
2
2
|
|
|
3
3
|
type LogFunction = (message: string | unknown, meta?: Record<string, unknown>) => void;
|
|
4
4
|
type Loggable = {
|
|
@@ -523,6 +523,14 @@ declare class Server {
|
|
|
523
523
|
tenants: Tenants;
|
|
524
524
|
auth: Auth;
|
|
525
525
|
constructor(config?: NileConfig);
|
|
526
|
+
/**
|
|
527
|
+
* Query the database with the current context
|
|
528
|
+
*/
|
|
529
|
+
query: Pool['query'];
|
|
530
|
+
/**
|
|
531
|
+
* Return a db object that can be used to talk to the database
|
|
532
|
+
* Does not have a context by default
|
|
533
|
+
*/
|
|
526
534
|
get db(): pg.Pool & {
|
|
527
535
|
clearConnections: () => void;
|
|
528
536
|
};
|
|
@@ -534,14 +542,16 @@ declare class Server {
|
|
|
534
542
|
get handlers(): NileHandlers;
|
|
535
543
|
get paths(): ConfigurablePaths;
|
|
536
544
|
set paths(paths: ConfigurablePaths);
|
|
537
|
-
/**
|
|
538
|
-
*
|
|
539
|
-
* If we elect to DDL, we don't want to use tenant id or user id, so remove those.
|
|
545
|
+
/**
|
|
546
|
+
* Sets the context for a particular set of requests or db calls to be sure the context is fully managed for the entire lifecycle
|
|
540
547
|
*/
|
|
541
|
-
withContext(
|
|
542
|
-
withContext<T>(context: PartialContext, fn:
|
|
548
|
+
withContext(): Promise<this>;
|
|
549
|
+
withContext<T>(context: PartialContext, fn: AsyncCallback<this, T>): Promise<T>;
|
|
550
|
+
withContext(context: PartialContext): Promise<this>;
|
|
551
|
+
withContext<T>(fn: AsyncCallback<this, T>): Promise<T>;
|
|
543
552
|
/**
|
|
544
553
|
* Creates a context without a user id and a tenant id, but keeps the headers around for auth at least.
|
|
554
|
+
* This is useful for DDL/DML, since most extensions will set the context by default
|
|
545
555
|
*/
|
|
546
556
|
noContext(): Promise<this>;
|
|
547
557
|
noContext<T>(fn: (sdk: this) => Promise<T>): Promise<T>;
|
|
@@ -552,6 +562,7 @@ declare class Server {
|
|
|
552
562
|
getContext(): Context;
|
|
553
563
|
}
|
|
554
564
|
declare function create<T = Server>(config?: NileConfig): T;
|
|
565
|
+
type AsyncCallback<TInstance, TResult> = (sdk: TInstance) => Promise<TResult>;
|
|
555
566
|
|
|
556
567
|
type Opts = {
|
|
557
568
|
basePath?: string;
|
|
@@ -561,13 +572,12 @@ type Context = {
|
|
|
561
572
|
headers: Headers;
|
|
562
573
|
tenantId: string | undefined | null;
|
|
563
574
|
userId: string | undefined | null;
|
|
564
|
-
preserveHeaders: boolean;
|
|
565
575
|
};
|
|
566
576
|
type PartialContext = {
|
|
567
577
|
headers?: null | Headers;
|
|
568
578
|
tenantId?: string | undefined | null;
|
|
569
579
|
userId?: string | undefined | null;
|
|
570
|
-
|
|
580
|
+
useLastContext?: boolean;
|
|
571
581
|
};
|
|
572
582
|
type CTX = {
|
|
573
583
|
run: <T>(ctx: Partial<Context>, fn: () => T) => T;
|
|
@@ -583,6 +593,8 @@ type ExtensionResult<TParams> = {
|
|
|
583
593
|
onResponse?: (params: TParams, ctx: CTX) => void | Promise<void>;
|
|
584
594
|
onHandleRequest?: (params?: TParams) => RouteReturn | Promise<RouteReturn>;
|
|
585
595
|
onConfigure?: (params?: TParams) => void;
|
|
596
|
+
withUserId?: () => string;
|
|
597
|
+
withTenantId?: () => string;
|
|
586
598
|
replace?: {
|
|
587
599
|
handlers: (handlers: NileHandlers) => Any;
|
|
588
600
|
};
|
|
@@ -595,7 +607,9 @@ declare enum ExtensionState {
|
|
|
595
607
|
onHandleRequest = "onHandleRequest",
|
|
596
608
|
onRequest = "onRequest",
|
|
597
609
|
onResponse = "onResponse",
|
|
598
|
-
withContext = "withContext"
|
|
610
|
+
withContext = "withContext",
|
|
611
|
+
withTenantId = "withTenantId",
|
|
612
|
+
withUserId = "withUserId"
|
|
599
613
|
}
|
|
600
614
|
type NilePoolConfig = PoolConfig & {
|
|
601
615
|
afterCreate?: AfterCreate;
|
|
@@ -692,9 +706,9 @@ type NileConfig = {
|
|
|
692
706
|
/** Hooks executed before and after each request. */
|
|
693
707
|
extensions?: Extension[];
|
|
694
708
|
/**
|
|
695
|
-
*
|
|
709
|
+
* Re-use the last set context
|
|
696
710
|
*/
|
|
697
|
-
|
|
711
|
+
useLastContext?: boolean;
|
|
698
712
|
};
|
|
699
713
|
type NileDb = NilePoolConfig & {
|
|
700
714
|
tenantId?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import pg, { PoolConfig, PoolClient } from 'pg';
|
|
1
|
+
import pg, { Pool, PoolConfig, PoolClient } from 'pg';
|
|
2
2
|
|
|
3
3
|
type LogFunction = (message: string | unknown, meta?: Record<string, unknown>) => void;
|
|
4
4
|
type Loggable = {
|
|
@@ -523,6 +523,14 @@ declare class Server {
|
|
|
523
523
|
tenants: Tenants;
|
|
524
524
|
auth: Auth;
|
|
525
525
|
constructor(config?: NileConfig);
|
|
526
|
+
/**
|
|
527
|
+
* Query the database with the current context
|
|
528
|
+
*/
|
|
529
|
+
query: Pool['query'];
|
|
530
|
+
/**
|
|
531
|
+
* Return a db object that can be used to talk to the database
|
|
532
|
+
* Does not have a context by default
|
|
533
|
+
*/
|
|
526
534
|
get db(): pg.Pool & {
|
|
527
535
|
clearConnections: () => void;
|
|
528
536
|
};
|
|
@@ -534,14 +542,16 @@ declare class Server {
|
|
|
534
542
|
get handlers(): NileHandlers;
|
|
535
543
|
get paths(): ConfigurablePaths;
|
|
536
544
|
set paths(paths: ConfigurablePaths);
|
|
537
|
-
/**
|
|
538
|
-
*
|
|
539
|
-
* If we elect to DDL, we don't want to use tenant id or user id, so remove those.
|
|
545
|
+
/**
|
|
546
|
+
* Sets the context for a particular set of requests or db calls to be sure the context is fully managed for the entire lifecycle
|
|
540
547
|
*/
|
|
541
|
-
withContext(
|
|
542
|
-
withContext<T>(context: PartialContext, fn:
|
|
548
|
+
withContext(): Promise<this>;
|
|
549
|
+
withContext<T>(context: PartialContext, fn: AsyncCallback<this, T>): Promise<T>;
|
|
550
|
+
withContext(context: PartialContext): Promise<this>;
|
|
551
|
+
withContext<T>(fn: AsyncCallback<this, T>): Promise<T>;
|
|
543
552
|
/**
|
|
544
553
|
* Creates a context without a user id and a tenant id, but keeps the headers around for auth at least.
|
|
554
|
+
* This is useful for DDL/DML, since most extensions will set the context by default
|
|
545
555
|
*/
|
|
546
556
|
noContext(): Promise<this>;
|
|
547
557
|
noContext<T>(fn: (sdk: this) => Promise<T>): Promise<T>;
|
|
@@ -552,6 +562,7 @@ declare class Server {
|
|
|
552
562
|
getContext(): Context;
|
|
553
563
|
}
|
|
554
564
|
declare function create<T = Server>(config?: NileConfig): T;
|
|
565
|
+
type AsyncCallback<TInstance, TResult> = (sdk: TInstance) => Promise<TResult>;
|
|
555
566
|
|
|
556
567
|
type Opts = {
|
|
557
568
|
basePath?: string;
|
|
@@ -561,13 +572,12 @@ type Context = {
|
|
|
561
572
|
headers: Headers;
|
|
562
573
|
tenantId: string | undefined | null;
|
|
563
574
|
userId: string | undefined | null;
|
|
564
|
-
preserveHeaders: boolean;
|
|
565
575
|
};
|
|
566
576
|
type PartialContext = {
|
|
567
577
|
headers?: null | Headers;
|
|
568
578
|
tenantId?: string | undefined | null;
|
|
569
579
|
userId?: string | undefined | null;
|
|
570
|
-
|
|
580
|
+
useLastContext?: boolean;
|
|
571
581
|
};
|
|
572
582
|
type CTX = {
|
|
573
583
|
run: <T>(ctx: Partial<Context>, fn: () => T) => T;
|
|
@@ -583,6 +593,8 @@ type ExtensionResult<TParams> = {
|
|
|
583
593
|
onResponse?: (params: TParams, ctx: CTX) => void | Promise<void>;
|
|
584
594
|
onHandleRequest?: (params?: TParams) => RouteReturn | Promise<RouteReturn>;
|
|
585
595
|
onConfigure?: (params?: TParams) => void;
|
|
596
|
+
withUserId?: () => string;
|
|
597
|
+
withTenantId?: () => string;
|
|
586
598
|
replace?: {
|
|
587
599
|
handlers: (handlers: NileHandlers) => Any;
|
|
588
600
|
};
|
|
@@ -595,7 +607,9 @@ declare enum ExtensionState {
|
|
|
595
607
|
onHandleRequest = "onHandleRequest",
|
|
596
608
|
onRequest = "onRequest",
|
|
597
609
|
onResponse = "onResponse",
|
|
598
|
-
withContext = "withContext"
|
|
610
|
+
withContext = "withContext",
|
|
611
|
+
withTenantId = "withTenantId",
|
|
612
|
+
withUserId = "withUserId"
|
|
599
613
|
}
|
|
600
614
|
type NilePoolConfig = PoolConfig & {
|
|
601
615
|
afterCreate?: AfterCreate;
|
|
@@ -692,9 +706,9 @@ type NileConfig = {
|
|
|
692
706
|
/** Hooks executed before and after each request. */
|
|
693
707
|
extensions?: Extension[];
|
|
694
708
|
/**
|
|
695
|
-
*
|
|
709
|
+
* Re-use the last set context
|
|
696
710
|
*/
|
|
697
|
-
|
|
711
|
+
useLastContext?: boolean;
|
|
698
712
|
};
|
|
699
713
|
type NileDb = NilePoolConfig & {
|
|
700
714
|
tenantId?: string;
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,8 @@ var ExtensionState = /* @__PURE__ */ ((ExtensionState2) => {
|
|
|
14
14
|
ExtensionState2["onRequest"] = "onRequest";
|
|
15
15
|
ExtensionState2["onResponse"] = "onResponse";
|
|
16
16
|
ExtensionState2["withContext"] = "withContext";
|
|
17
|
+
ExtensionState2["withTenantId"] = "withTenantId";
|
|
18
|
+
ExtensionState2["withUserId"] = "withUserId";
|
|
17
19
|
return ExtensionState2;
|
|
18
20
|
})(ExtensionState || {});
|
|
19
21
|
var APIErrorErrorCodeEnum = {
|
|
@@ -226,6 +228,14 @@ function bindRunExtensions(instance) {
|
|
|
226
228
|
if (extensionConfig.disableExtensions?.includes(ext.id)) {
|
|
227
229
|
continue;
|
|
228
230
|
}
|
|
231
|
+
if (ext.withTenantId && toRun === "withTenantId" /* withTenantId */) {
|
|
232
|
+
ctx.set({
|
|
233
|
+
tenantId: await ext.withTenantId()
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
if (ext.withUserId && toRun === "withUserId" /* withUserId */) {
|
|
237
|
+
ctx.set({ userId: await ext.withUserId() });
|
|
238
|
+
}
|
|
229
239
|
if (ext.withContext && toRun === "withContext" /* withContext */) {
|
|
230
240
|
await ext.withContext(ctx);
|
|
231
241
|
}
|
|
@@ -241,10 +251,6 @@ function bindRunExtensions(instance) {
|
|
|
241
251
|
const [param] = Array.isArray(params) ? params : [params];
|
|
242
252
|
if (ext.onRequest && toRun === "onRequest" /* onRequest */) {
|
|
243
253
|
const { ...previousContext } = ctx.get();
|
|
244
|
-
const preserveHeaders = previousContext.preserveHeaders;
|
|
245
|
-
if (preserveHeaders) {
|
|
246
|
-
ctx.set({ preserveHeaders: false });
|
|
247
|
-
}
|
|
248
254
|
if (!_init) {
|
|
249
255
|
continue;
|
|
250
256
|
}
|
|
@@ -255,7 +261,7 @@ function bindRunExtensions(instance) {
|
|
|
255
261
|
const cookie = updatedContext.headers.get("cookie");
|
|
256
262
|
if (cookie && param.headers) {
|
|
257
263
|
const updatedCookies = mergeCookies(
|
|
258
|
-
|
|
264
|
+
previousHeaders?.get("cookie"),
|
|
259
265
|
updatedContext.headers.get("cookie")
|
|
260
266
|
);
|
|
261
267
|
param.headers.set("cookie", updatedCookies);
|
|
@@ -300,6 +306,11 @@ function mergeCookies(...cookieStrings) {
|
|
|
300
306
|
}
|
|
301
307
|
async function runExtensionContext(config) {
|
|
302
308
|
await config?.extensionCtx?.runExtensions("withContext" /* withContext */, config);
|
|
309
|
+
await config?.extensionCtx?.runExtensions(
|
|
310
|
+
"withTenantId" /* withTenantId */,
|
|
311
|
+
config
|
|
312
|
+
);
|
|
313
|
+
await config?.extensionCtx?.runExtensions("withUserId" /* withUserId */, config);
|
|
303
314
|
}
|
|
304
315
|
|
|
305
316
|
// src/api/utils/request-context.ts
|
|
@@ -308,8 +319,7 @@ var storage = new async_hooks.AsyncLocalStorage();
|
|
|
308
319
|
var defaultContext = {
|
|
309
320
|
headers: new Headers(),
|
|
310
321
|
tenantId: void 0,
|
|
311
|
-
userId: void 0
|
|
312
|
-
preserveHeaders: false
|
|
322
|
+
userId: void 0
|
|
313
323
|
};
|
|
314
324
|
var lastUsedContext = defaultContext;
|
|
315
325
|
var ctx = {
|
|
@@ -359,8 +369,6 @@ var ctx = {
|
|
|
359
369
|
}
|
|
360
370
|
if ("tenantId" in partial) store.tenantId = partial.tenantId;
|
|
361
371
|
if ("userId" in partial) store.userId = partial.userId;
|
|
362
|
-
if ("preserveHeaders" in partial)
|
|
363
|
-
store.preserveHeaders = Boolean(partial.preserveHeaders);
|
|
364
372
|
silly(`[SET] ${serializeContext(store)}`);
|
|
365
373
|
lastUsedContext = { ...store };
|
|
366
374
|
},
|
|
@@ -378,8 +386,7 @@ function withNileContext(config, fn, name = "unknown") {
|
|
|
378
386
|
const context2 = {
|
|
379
387
|
headers: mergedHeaders,
|
|
380
388
|
tenantId: existing.tenantId,
|
|
381
|
-
userId: existing.userId
|
|
382
|
-
preserveHeaders: existing.preserveHeaders ?? false
|
|
389
|
+
userId: existing.userId
|
|
383
390
|
};
|
|
384
391
|
silly(`${name} [INITIAL - Request] ${serializeContext(context2)}`);
|
|
385
392
|
return ctx.run(context2, fn);
|
|
@@ -392,12 +399,10 @@ function withNileContext(config, fn, name = "unknown") {
|
|
|
392
399
|
}
|
|
393
400
|
const hasTenantId = "tenantId" in initialContext;
|
|
394
401
|
const hasUserId = "userId" in initialContext;
|
|
395
|
-
const hasPreserveHeaders = "preserveHeaders" in initialContext;
|
|
396
402
|
const context = {
|
|
397
403
|
headers: mergedHeaders,
|
|
398
404
|
tenantId: hasTenantId ? initialContext.tenantId : existing.tenantId,
|
|
399
|
-
userId: hasUserId ? initialContext.userId : existing.userId
|
|
400
|
-
preserveHeaders: hasPreserveHeaders ? Boolean(initialContext.preserveHeaders) : existing.preserveHeaders ?? false
|
|
405
|
+
userId: hasUserId ? initialContext.userId : existing.userId
|
|
401
406
|
};
|
|
402
407
|
silly(`${name} [INITIAL - Partial<Context>] ${serializeContext(context)}`);
|
|
403
408
|
return ctx.run(context, async () => {
|
|
@@ -414,8 +419,7 @@ function serializeContext(context) {
|
|
|
414
419
|
return JSON.stringify({
|
|
415
420
|
headers,
|
|
416
421
|
tenantId: context.tenantId,
|
|
417
|
-
userId: context.userId
|
|
418
|
-
preserveHeaders: context.preserveHeaders
|
|
422
|
+
userId: context.userId
|
|
419
423
|
});
|
|
420
424
|
}
|
|
421
425
|
function parseCookieHeader(header) {
|
|
@@ -2020,8 +2024,7 @@ var Config = class {
|
|
|
2020
2024
|
this.context = {
|
|
2021
2025
|
tenantId: config?.tenantId,
|
|
2022
2026
|
userId: config?.userId,
|
|
2023
|
-
headers: config?.headers ? new Headers(config.headers) : new Headers()
|
|
2024
|
-
preserveHeaders: false
|
|
2027
|
+
headers: config?.headers ? new Headers(config.headers) : new Headers()
|
|
2025
2028
|
};
|
|
2026
2029
|
this.routes = {
|
|
2027
2030
|
...appRoutes(config?.routePrefix),
|
|
@@ -2113,17 +2116,17 @@ var updateHeaders = (val) => {
|
|
|
2113
2116
|
var watchHeaders = (cb) => eventer.subscribe("headers" /* Headers */, cb);
|
|
2114
2117
|
|
|
2115
2118
|
// src/db/PoolProxy.ts
|
|
2116
|
-
function createProxyForPool(pool, config) {
|
|
2117
|
-
const { info, error } =
|
|
2119
|
+
function createProxyForPool(pool, config, logger, context) {
|
|
2120
|
+
const { info, error } = logger("[pool]");
|
|
2118
2121
|
return new Proxy(pool, {
|
|
2119
2122
|
get(target, property) {
|
|
2120
2123
|
if (property === "query") {
|
|
2121
|
-
if (!config.
|
|
2122
|
-
if (!config.
|
|
2124
|
+
if (!config.connectionString) {
|
|
2125
|
+
if (!config.user || !config.password) {
|
|
2123
2126
|
error(
|
|
2124
2127
|
"Cannot connect to the database. User and/or password are missing. Generate them at https://console.thenile.dev"
|
|
2125
2128
|
);
|
|
2126
|
-
} else if (!config.
|
|
2129
|
+
} else if (!config.database) {
|
|
2127
2130
|
error(
|
|
2128
2131
|
"Unable to obtain database name. Is process.env.NILEDB_POSTGRES_URL set?"
|
|
2129
2132
|
);
|
|
@@ -2132,7 +2135,7 @@ function createProxyForPool(pool, config) {
|
|
|
2132
2135
|
const caller = target[property];
|
|
2133
2136
|
return function query(...args) {
|
|
2134
2137
|
let log = "[QUERY]";
|
|
2135
|
-
const
|
|
2138
|
+
const [tenantId, userId] = context;
|
|
2136
2139
|
if (tenantId) {
|
|
2137
2140
|
log = `${log}[TENANT:${tenantId}]`;
|
|
2138
2141
|
}
|
|
@@ -2155,39 +2158,44 @@ var NileDatabase = class {
|
|
|
2155
2158
|
tenantId;
|
|
2156
2159
|
userId;
|
|
2157
2160
|
id;
|
|
2158
|
-
|
|
2161
|
+
logger;
|
|
2159
2162
|
timer;
|
|
2160
|
-
|
|
2161
|
-
|
|
2163
|
+
config;
|
|
2164
|
+
constructor(config, logger, id) {
|
|
2165
|
+
this.logger = logger("[NileInstance]");
|
|
2162
2166
|
this.id = id;
|
|
2163
2167
|
const poolConfig = {
|
|
2164
2168
|
min: 0,
|
|
2165
2169
|
max: 10,
|
|
2166
2170
|
idleTimeoutMillis: 3e4,
|
|
2167
|
-
...config
|
|
2171
|
+
...config
|
|
2168
2172
|
};
|
|
2169
2173
|
const { afterCreate, ...remaining } = poolConfig;
|
|
2170
|
-
config
|
|
2171
|
-
|
|
2172
|
-
const cloned = { ...this.config.db };
|
|
2174
|
+
this.config = remaining;
|
|
2175
|
+
const cloned = { ...config };
|
|
2173
2176
|
cloned.password = "***";
|
|
2174
|
-
debug(`Connection pool config ${JSON.stringify(cloned)}`);
|
|
2175
|
-
this.pool = createProxyForPool(
|
|
2177
|
+
this.logger.debug(`Connection pool config ${JSON.stringify(cloned)}`);
|
|
2178
|
+
this.pool = createProxyForPool(
|
|
2179
|
+
new pg__default.default.Pool(remaining),
|
|
2180
|
+
this.config,
|
|
2181
|
+
logger,
|
|
2182
|
+
id === "base" ? [] : id.split(":")
|
|
2183
|
+
);
|
|
2176
2184
|
if (typeof afterCreate === "function") {
|
|
2177
|
-
|
|
2185
|
+
this.logger.warn(
|
|
2178
2186
|
"Providing an pool configuration will stop automatic tenant context setting."
|
|
2179
2187
|
);
|
|
2180
2188
|
}
|
|
2181
2189
|
this.startTimeout();
|
|
2182
2190
|
this.pool.on("connect", async (client) => {
|
|
2183
|
-
debug(`pool connected ${this.id}`);
|
|
2191
|
+
this.logger.debug(`pool connected ${this.id}`);
|
|
2184
2192
|
this.startTimeout();
|
|
2185
2193
|
const afterCreate2 = makeAfterCreate(
|
|
2186
|
-
|
|
2187
|
-
`${this.id}
|
|
2194
|
+
logger,
|
|
2195
|
+
`${this.id}|${this.timer}`
|
|
2188
2196
|
);
|
|
2189
2197
|
afterCreate2(client, (err) => {
|
|
2190
|
-
const { error } =
|
|
2198
|
+
const { error } = logger("[after create callback]");
|
|
2191
2199
|
if (err) {
|
|
2192
2200
|
clearTimeout(this.timer);
|
|
2193
2201
|
error("after create failed", {
|
|
@@ -2200,7 +2208,7 @@ var NileDatabase = class {
|
|
|
2200
2208
|
});
|
|
2201
2209
|
this.pool.on("error", (err) => {
|
|
2202
2210
|
clearTimeout(this.timer);
|
|
2203
|
-
info(`pool ${this.id} failed`, {
|
|
2211
|
+
this.logger.info(`pool ${this.id} failed`, {
|
|
2204
2212
|
message: err.message,
|
|
2205
2213
|
stack: err.stack
|
|
2206
2214
|
});
|
|
@@ -2210,27 +2218,27 @@ var NileDatabase = class {
|
|
|
2210
2218
|
if (destroy) {
|
|
2211
2219
|
clearTimeout(this.timer);
|
|
2212
2220
|
evictPool(this.id);
|
|
2213
|
-
debug(`destroying pool ${this.id}`);
|
|
2221
|
+
this.logger.debug(`destroying pool ${this.id}`);
|
|
2214
2222
|
}
|
|
2215
2223
|
});
|
|
2216
2224
|
}
|
|
2217
2225
|
startTimeout() {
|
|
2218
|
-
const { debug } = this.
|
|
2226
|
+
const { debug } = this.logger;
|
|
2219
2227
|
if (this.timer) {
|
|
2220
2228
|
clearTimeout(this.timer);
|
|
2221
2229
|
}
|
|
2222
2230
|
this.timer = setTimeout(() => {
|
|
2223
2231
|
debug(
|
|
2224
|
-
`Pool reached idleTimeoutMillis. ${this.id} evicted after ${Number(this.config.
|
|
2232
|
+
`Pool reached idleTimeoutMillis. ${this.id} evicted after ${Number(this.config.idleTimeoutMillis) ?? 3e4}ms`
|
|
2225
2233
|
);
|
|
2226
2234
|
this.pool.end(() => {
|
|
2227
2235
|
clearTimeout(this.timer);
|
|
2228
2236
|
evictPool(this.id);
|
|
2229
2237
|
});
|
|
2230
|
-
}, Number(this.config.
|
|
2238
|
+
}, Number(this.config.idleTimeoutMillis) ?? 3e4);
|
|
2231
2239
|
}
|
|
2232
2240
|
shutdown() {
|
|
2233
|
-
const { debug } = this.
|
|
2241
|
+
const { debug } = this.logger;
|
|
2234
2242
|
debug(`attempting to shut down ${this.id}`);
|
|
2235
2243
|
clearTimeout(this.timer);
|
|
2236
2244
|
this.pool.end(() => {
|
|
@@ -2239,8 +2247,8 @@ var NileDatabase = class {
|
|
|
2239
2247
|
}
|
|
2240
2248
|
};
|
|
2241
2249
|
var NileInstance_default = NileDatabase;
|
|
2242
|
-
function makeAfterCreate(
|
|
2243
|
-
const { error, warn: warn2, debug } =
|
|
2250
|
+
function makeAfterCreate(logger, id) {
|
|
2251
|
+
const { error, warn: warn2, debug } = logger("[afterCreate]");
|
|
2244
2252
|
return (conn, done) => {
|
|
2245
2253
|
conn.on("error", function errorHandler(e) {
|
|
2246
2254
|
error(`Connection ${id} was terminated by server`, {
|
|
@@ -2249,8 +2257,9 @@ function makeAfterCreate(config, id) {
|
|
|
2249
2257
|
});
|
|
2250
2258
|
done(e, conn);
|
|
2251
2259
|
});
|
|
2252
|
-
const
|
|
2253
|
-
|
|
2260
|
+
const [context] = id.split("|");
|
|
2261
|
+
const [tenantId, userId] = context.split(":");
|
|
2262
|
+
if (tenantId !== "base") {
|
|
2254
2263
|
const query = [`SET nile.tenant_id = '${tenantId}'`];
|
|
2255
2264
|
if (userId) {
|
|
2256
2265
|
if (!tenantId) {
|
|
@@ -2315,9 +2324,9 @@ var DBManager = class {
|
|
|
2315
2324
|
warn2(`missed eviction of ${id}`);
|
|
2316
2325
|
}
|
|
2317
2326
|
};
|
|
2318
|
-
getConnection = (config) => {
|
|
2327
|
+
getConnection = (config, noContext = false) => {
|
|
2319
2328
|
const { info } = Logger(config)("[DBManager]");
|
|
2320
|
-
const { tenantId, userId } = ctx.getLastUsed();
|
|
2329
|
+
const { tenantId, userId } = noContext ? {} : ctx.getLastUsed();
|
|
2321
2330
|
const id = this.makeId(tenantId, userId);
|
|
2322
2331
|
const existing = this.connections.get(id);
|
|
2323
2332
|
info(`# of instances: ${this.connections.size}`);
|
|
@@ -2326,7 +2335,7 @@ var DBManager = class {
|
|
|
2326
2335
|
existing.startTimeout();
|
|
2327
2336
|
return existing.pool;
|
|
2328
2337
|
}
|
|
2329
|
-
const newOne = new NileInstance_default(config, id);
|
|
2338
|
+
const newOne = new NileInstance_default(config.db, config.logger, id);
|
|
2330
2339
|
this.connections.set(id, newOne);
|
|
2331
2340
|
info(`created new ${id}`);
|
|
2332
2341
|
info(`# of instances: ${this.connections.size}`);
|
|
@@ -2733,7 +2742,7 @@ var Auth = class {
|
|
|
2733
2742
|
].filter(Boolean).join("; ");
|
|
2734
2743
|
const uHeaders = new Headers({ cookie });
|
|
2735
2744
|
updateHeaders(uHeaders);
|
|
2736
|
-
ctx.set({ headers: uHeaders
|
|
2745
|
+
ctx.set({ headers: uHeaders });
|
|
2737
2746
|
} else {
|
|
2738
2747
|
error("Unable to set context after sign in", {
|
|
2739
2748
|
headers: signInRes.headers
|
|
@@ -2855,7 +2864,7 @@ async function obtainCsrf(config, rawResponse = false) {
|
|
|
2855
2864
|
parseToken(res.headers)
|
|
2856
2865
|
].filter(Boolean).join("; ");
|
|
2857
2866
|
headers.set("cookie", cookie);
|
|
2858
|
-
ctx.set({ headers
|
|
2867
|
+
ctx.set({ headers });
|
|
2859
2868
|
updateHeaders(headers);
|
|
2860
2869
|
}
|
|
2861
2870
|
if (!rawResponse) {
|
|
@@ -2874,7 +2883,7 @@ async function obtainCsrf(config, rawResponse = false) {
|
|
|
2874
2883
|
}
|
|
2875
2884
|
const cookie = cookieParts.filter(Boolean).join("; ");
|
|
2876
2885
|
headers.set("cookie", cookie);
|
|
2877
|
-
ctx.set({ headers
|
|
2886
|
+
ctx.set({ headers });
|
|
2878
2887
|
updateHeaders(new Headers({ cookie }));
|
|
2879
2888
|
}
|
|
2880
2889
|
if (rawResponse) {
|
|
@@ -3164,12 +3173,12 @@ var Tenants = class {
|
|
|
3164
3173
|
try {
|
|
3165
3174
|
const json = await me.json();
|
|
3166
3175
|
if ("id" in json) {
|
|
3167
|
-
ctx.set({ userId: json.id
|
|
3176
|
+
ctx.set({ userId: json.id });
|
|
3168
3177
|
}
|
|
3169
3178
|
} catch {
|
|
3170
3179
|
}
|
|
3171
3180
|
if (typeof req === "string") {
|
|
3172
|
-
ctx.set({ tenantId: req
|
|
3181
|
+
ctx.set({ tenantId: req });
|
|
3173
3182
|
} else {
|
|
3174
3183
|
this.#handleContext(req);
|
|
3175
3184
|
}
|
|
@@ -3179,7 +3188,7 @@ var Tenants = class {
|
|
|
3179
3188
|
async addMember(req, rawResponse) {
|
|
3180
3189
|
return withNileContext(this.#config, async () => {
|
|
3181
3190
|
if (typeof req === "string") {
|
|
3182
|
-
ctx.set({ userId: req
|
|
3191
|
+
ctx.set({ userId: req });
|
|
3183
3192
|
} else {
|
|
3184
3193
|
this.#handleContext(req);
|
|
3185
3194
|
}
|
|
@@ -3197,7 +3206,7 @@ var Tenants = class {
|
|
|
3197
3206
|
return withNileContext(this.#config, async () => {
|
|
3198
3207
|
this.#handleContext(req);
|
|
3199
3208
|
if (typeof req === "string") {
|
|
3200
|
-
ctx.set({ userId: req
|
|
3209
|
+
ctx.set({ userId: req });
|
|
3201
3210
|
}
|
|
3202
3211
|
const res = await fetchTenantUser(this.#config, "DELETE");
|
|
3203
3212
|
return responseHandler(res, rawResponse);
|
|
@@ -3320,10 +3329,10 @@ var Tenants = class {
|
|
|
3320
3329
|
#handleContext(req) {
|
|
3321
3330
|
if (typeof req === "object") {
|
|
3322
3331
|
if ("tenantId" in req) {
|
|
3323
|
-
ctx.set({ tenantId: req.tenantId
|
|
3332
|
+
ctx.set({ tenantId: req.tenantId });
|
|
3324
3333
|
}
|
|
3325
3334
|
if ("userId" in req) {
|
|
3326
|
-
ctx.set({ userId: req.userId
|
|
3335
|
+
ctx.set({ userId: req.userId });
|
|
3327
3336
|
}
|
|
3328
3337
|
}
|
|
3329
3338
|
}
|
|
@@ -3410,7 +3419,7 @@ function updateConfig(response, config) {
|
|
|
3410
3419
|
...config,
|
|
3411
3420
|
origin,
|
|
3412
3421
|
headers: headers ?? void 0,
|
|
3413
|
-
|
|
3422
|
+
useLastContext: true
|
|
3414
3423
|
};
|
|
3415
3424
|
}
|
|
3416
3425
|
|
|
@@ -3442,7 +3451,6 @@ var Server = class {
|
|
|
3442
3451
|
watchHeaders((headers) => {
|
|
3443
3452
|
if (headers) {
|
|
3444
3453
|
this.#config.context.headers = new Headers(headers);
|
|
3445
|
-
this.#config.context.preserveHeaders = true;
|
|
3446
3454
|
this.#reset();
|
|
3447
3455
|
}
|
|
3448
3456
|
});
|
|
@@ -3450,7 +3458,6 @@ var Server = class {
|
|
|
3450
3458
|
...this.#config.handlers,
|
|
3451
3459
|
withContext: handlersWithContext(this.#config)
|
|
3452
3460
|
};
|
|
3453
|
-
this.#config.context.preserveHeaders = config?.preserveHeaders ?? false;
|
|
3454
3461
|
this.#config.context.tenantId = getTenantId({ config: this.#config });
|
|
3455
3462
|
this.#manager = new DBManager(this.#config);
|
|
3456
3463
|
this.#handleHeaders(config);
|
|
@@ -3476,9 +3483,21 @@ var Server = class {
|
|
|
3476
3483
|
}
|
|
3477
3484
|
}
|
|
3478
3485
|
}
|
|
3479
|
-
|
|
3486
|
+
/**
|
|
3487
|
+
* Query the database with the current context
|
|
3488
|
+
*/
|
|
3489
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3490
|
+
query = (queryStream, values) => {
|
|
3480
3491
|
this.#config.context = { ...this.getContext() };
|
|
3481
3492
|
const pool = this.#manager.getConnection(this.#config);
|
|
3493
|
+
return pool.query(queryStream, values);
|
|
3494
|
+
};
|
|
3495
|
+
/**
|
|
3496
|
+
* Return a db object that can be used to talk to the database
|
|
3497
|
+
* Does not have a context by default
|
|
3498
|
+
*/
|
|
3499
|
+
get db() {
|
|
3500
|
+
const pool = this.#manager.getConnection(this.#config, true);
|
|
3482
3501
|
return Object.assign(pool, {
|
|
3483
3502
|
clearConnections: () => {
|
|
3484
3503
|
this.#manager.clear(this.#config);
|
|
@@ -3516,18 +3535,18 @@ var Server = class {
|
|
|
3516
3535
|
set paths(paths) {
|
|
3517
3536
|
this.#config.paths = paths;
|
|
3518
3537
|
}
|
|
3519
|
-
async withContext(
|
|
3520
|
-
const
|
|
3521
|
-
|
|
3522
|
-
const
|
|
3538
|
+
async withContext(contextOrFn, maybeFn) {
|
|
3539
|
+
const isFn = typeof contextOrFn === "function";
|
|
3540
|
+
const context = isFn ? {} : contextOrFn ?? {};
|
|
3541
|
+
const fn = isFn ? contextOrFn : maybeFn;
|
|
3542
|
+
const preserve = "useLastContext" in context ? context.useLastContext : true;
|
|
3523
3543
|
if (preserve) {
|
|
3524
3544
|
this.#config.context = { ...this.getContext(), ...context };
|
|
3545
|
+
} else {
|
|
3546
|
+
this.#config.context = { ...defaultContext, ...context };
|
|
3525
3547
|
}
|
|
3526
3548
|
return withNileContext(this.#config, async () => {
|
|
3527
|
-
|
|
3528
|
-
return fn(this);
|
|
3529
|
-
}
|
|
3530
|
-
return this;
|
|
3549
|
+
return fn ? fn(this) : this;
|
|
3531
3550
|
});
|
|
3532
3551
|
}
|
|
3533
3552
|
async noContext(fn) {
|