@niledatabase/server 5.0.0-alpha.31 → 5.0.0-alpha.32

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 CHANGED
@@ -534,14 +534,16 @@ declare class Server {
534
534
  get handlers(): NileHandlers;
535
535
  get paths(): ConfigurablePaths;
536
536
  set paths(paths: ConfigurablePaths);
537
- /** Allows setting of context outside of the request lifecycle
538
- * Basically means you want to disregard cookies and do everything manually
539
- * If we elect to DDL, we don't want to use tenant id or user id, so remove those.
537
+ /**
538
+ * 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
539
  */
541
- withContext(context?: PartialContext): Promise<this>;
542
- withContext<T>(context: PartialContext, fn: (sdk: this) => Promise<T>): Promise<T>;
540
+ withContext(): Promise<this>;
541
+ withContext<T>(context: PartialContext, fn: AsyncCallback<this, T>): Promise<T>;
542
+ withContext(context: PartialContext): Promise<this>;
543
+ withContext<T>(fn: AsyncCallback<this, T>): Promise<T>;
543
544
  /**
544
545
  * Creates a context without a user id and a tenant id, but keeps the headers around for auth at least.
546
+ * This is useful for DDL/DML, since most extensions will set the context by default
545
547
  */
546
548
  noContext(): Promise<this>;
547
549
  noContext<T>(fn: (sdk: this) => Promise<T>): Promise<T>;
@@ -552,6 +554,7 @@ declare class Server {
552
554
  getContext(): Context;
553
555
  }
554
556
  declare function create<T = Server>(config?: NileConfig): T;
557
+ type AsyncCallback<TInstance, TResult> = (sdk: TInstance) => Promise<TResult>;
555
558
 
556
559
  type Opts = {
557
560
  basePath?: string;
@@ -561,13 +564,12 @@ type Context = {
561
564
  headers: Headers;
562
565
  tenantId: string | undefined | null;
563
566
  userId: string | undefined | null;
564
- preserveHeaders: boolean;
565
567
  };
566
568
  type PartialContext = {
567
569
  headers?: null | Headers;
568
570
  tenantId?: string | undefined | null;
569
571
  userId?: string | undefined | null;
570
- preserveHeaders?: boolean;
572
+ useLastContext?: boolean;
571
573
  };
572
574
  type CTX = {
573
575
  run: <T>(ctx: Partial<Context>, fn: () => T) => T;
@@ -583,6 +585,8 @@ type ExtensionResult<TParams> = {
583
585
  onResponse?: (params: TParams, ctx: CTX) => void | Promise<void>;
584
586
  onHandleRequest?: (params?: TParams) => RouteReturn | Promise<RouteReturn>;
585
587
  onConfigure?: (params?: TParams) => void;
588
+ withUserId?: () => string;
589
+ withTenantId?: () => string;
586
590
  replace?: {
587
591
  handlers: (handlers: NileHandlers) => Any;
588
592
  };
@@ -595,7 +599,9 @@ declare enum ExtensionState {
595
599
  onHandleRequest = "onHandleRequest",
596
600
  onRequest = "onRequest",
597
601
  onResponse = "onResponse",
598
- withContext = "withContext"
602
+ withContext = "withContext",
603
+ withTenantId = "withTenantId",
604
+ withUserId = "withUserId"
599
605
  }
600
606
  type NilePoolConfig = PoolConfig & {
601
607
  afterCreate?: AfterCreate;
@@ -692,9 +698,9 @@ type NileConfig = {
692
698
  /** Hooks executed before and after each request. */
693
699
  extensions?: Extension[];
694
700
  /**
695
- * Preserve incoming request headers when running extensions.
701
+ * Re-use the last set context
696
702
  */
697
- preserveHeaders?: boolean;
703
+ useLastContext?: boolean;
698
704
  };
699
705
  type NileDb = NilePoolConfig & {
700
706
  tenantId?: string;
package/dist/index.d.ts CHANGED
@@ -534,14 +534,16 @@ declare class Server {
534
534
  get handlers(): NileHandlers;
535
535
  get paths(): ConfigurablePaths;
536
536
  set paths(paths: ConfigurablePaths);
537
- /** Allows setting of context outside of the request lifecycle
538
- * Basically means you want to disregard cookies and do everything manually
539
- * If we elect to DDL, we don't want to use tenant id or user id, so remove those.
537
+ /**
538
+ * 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
539
  */
541
- withContext(context?: PartialContext): Promise<this>;
542
- withContext<T>(context: PartialContext, fn: (sdk: this) => Promise<T>): Promise<T>;
540
+ withContext(): Promise<this>;
541
+ withContext<T>(context: PartialContext, fn: AsyncCallback<this, T>): Promise<T>;
542
+ withContext(context: PartialContext): Promise<this>;
543
+ withContext<T>(fn: AsyncCallback<this, T>): Promise<T>;
543
544
  /**
544
545
  * Creates a context without a user id and a tenant id, but keeps the headers around for auth at least.
546
+ * This is useful for DDL/DML, since most extensions will set the context by default
545
547
  */
546
548
  noContext(): Promise<this>;
547
549
  noContext<T>(fn: (sdk: this) => Promise<T>): Promise<T>;
@@ -552,6 +554,7 @@ declare class Server {
552
554
  getContext(): Context;
553
555
  }
554
556
  declare function create<T = Server>(config?: NileConfig): T;
557
+ type AsyncCallback<TInstance, TResult> = (sdk: TInstance) => Promise<TResult>;
555
558
 
556
559
  type Opts = {
557
560
  basePath?: string;
@@ -561,13 +564,12 @@ type Context = {
561
564
  headers: Headers;
562
565
  tenantId: string | undefined | null;
563
566
  userId: string | undefined | null;
564
- preserveHeaders: boolean;
565
567
  };
566
568
  type PartialContext = {
567
569
  headers?: null | Headers;
568
570
  tenantId?: string | undefined | null;
569
571
  userId?: string | undefined | null;
570
- preserveHeaders?: boolean;
572
+ useLastContext?: boolean;
571
573
  };
572
574
  type CTX = {
573
575
  run: <T>(ctx: Partial<Context>, fn: () => T) => T;
@@ -583,6 +585,8 @@ type ExtensionResult<TParams> = {
583
585
  onResponse?: (params: TParams, ctx: CTX) => void | Promise<void>;
584
586
  onHandleRequest?: (params?: TParams) => RouteReturn | Promise<RouteReturn>;
585
587
  onConfigure?: (params?: TParams) => void;
588
+ withUserId?: () => string;
589
+ withTenantId?: () => string;
586
590
  replace?: {
587
591
  handlers: (handlers: NileHandlers) => Any;
588
592
  };
@@ -595,7 +599,9 @@ declare enum ExtensionState {
595
599
  onHandleRequest = "onHandleRequest",
596
600
  onRequest = "onRequest",
597
601
  onResponse = "onResponse",
598
- withContext = "withContext"
602
+ withContext = "withContext",
603
+ withTenantId = "withTenantId",
604
+ withUserId = "withUserId"
599
605
  }
600
606
  type NilePoolConfig = PoolConfig & {
601
607
  afterCreate?: AfterCreate;
@@ -692,9 +698,9 @@ type NileConfig = {
692
698
  /** Hooks executed before and after each request. */
693
699
  extensions?: Extension[];
694
700
  /**
695
- * Preserve incoming request headers when running extensions.
701
+ * Re-use the last set context
696
702
  */
697
- preserveHeaders?: boolean;
703
+ useLastContext?: boolean;
698
704
  };
699
705
  type NileDb = NilePoolConfig & {
700
706
  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
- preserveHeaders ? previousHeaders?.get("cookie") : null,
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),
@@ -2733,7 +2736,7 @@ var Auth = class {
2733
2736
  ].filter(Boolean).join("; ");
2734
2737
  const uHeaders = new Headers({ cookie });
2735
2738
  updateHeaders(uHeaders);
2736
- ctx.set({ headers: uHeaders, preserveHeaders: true });
2739
+ ctx.set({ headers: uHeaders });
2737
2740
  } else {
2738
2741
  error("Unable to set context after sign in", {
2739
2742
  headers: signInRes.headers
@@ -2855,7 +2858,7 @@ async function obtainCsrf(config, rawResponse = false) {
2855
2858
  parseToken(res.headers)
2856
2859
  ].filter(Boolean).join("; ");
2857
2860
  headers.set("cookie", cookie);
2858
- ctx.set({ headers, preserveHeaders: true });
2861
+ ctx.set({ headers });
2859
2862
  updateHeaders(headers);
2860
2863
  }
2861
2864
  if (!rawResponse) {
@@ -2874,7 +2877,7 @@ async function obtainCsrf(config, rawResponse = false) {
2874
2877
  }
2875
2878
  const cookie = cookieParts.filter(Boolean).join("; ");
2876
2879
  headers.set("cookie", cookie);
2877
- ctx.set({ headers, preserveHeaders: true });
2880
+ ctx.set({ headers });
2878
2881
  updateHeaders(new Headers({ cookie }));
2879
2882
  }
2880
2883
  if (rawResponse) {
@@ -3164,12 +3167,12 @@ var Tenants = class {
3164
3167
  try {
3165
3168
  const json = await me.json();
3166
3169
  if ("id" in json) {
3167
- ctx.set({ userId: json.id, preserveHeaders: true });
3170
+ ctx.set({ userId: json.id });
3168
3171
  }
3169
3172
  } catch {
3170
3173
  }
3171
3174
  if (typeof req === "string") {
3172
- ctx.set({ tenantId: req, preserveHeaders: true });
3175
+ ctx.set({ tenantId: req });
3173
3176
  } else {
3174
3177
  this.#handleContext(req);
3175
3178
  }
@@ -3179,7 +3182,7 @@ var Tenants = class {
3179
3182
  async addMember(req, rawResponse) {
3180
3183
  return withNileContext(this.#config, async () => {
3181
3184
  if (typeof req === "string") {
3182
- ctx.set({ userId: req, preserveHeaders: true });
3185
+ ctx.set({ userId: req });
3183
3186
  } else {
3184
3187
  this.#handleContext(req);
3185
3188
  }
@@ -3197,7 +3200,7 @@ var Tenants = class {
3197
3200
  return withNileContext(this.#config, async () => {
3198
3201
  this.#handleContext(req);
3199
3202
  if (typeof req === "string") {
3200
- ctx.set({ userId: req, preserveHeaders: true });
3203
+ ctx.set({ userId: req });
3201
3204
  }
3202
3205
  const res = await fetchTenantUser(this.#config, "DELETE");
3203
3206
  return responseHandler(res, rawResponse);
@@ -3320,10 +3323,10 @@ var Tenants = class {
3320
3323
  #handleContext(req) {
3321
3324
  if (typeof req === "object") {
3322
3325
  if ("tenantId" in req) {
3323
- ctx.set({ tenantId: req.tenantId, preserveHeaders: true });
3326
+ ctx.set({ tenantId: req.tenantId });
3324
3327
  }
3325
3328
  if ("userId" in req) {
3326
- ctx.set({ userId: req.userId, preserveHeaders: true });
3329
+ ctx.set({ userId: req.userId });
3327
3330
  }
3328
3331
  }
3329
3332
  }
@@ -3410,7 +3413,7 @@ function updateConfig(response, config) {
3410
3413
  ...config,
3411
3414
  origin,
3412
3415
  headers: headers ?? void 0,
3413
- preserveHeaders: true
3416
+ useLastContext: true
3414
3417
  };
3415
3418
  }
3416
3419
 
@@ -3442,7 +3445,6 @@ var Server = class {
3442
3445
  watchHeaders((headers) => {
3443
3446
  if (headers) {
3444
3447
  this.#config.context.headers = new Headers(headers);
3445
- this.#config.context.preserveHeaders = true;
3446
3448
  this.#reset();
3447
3449
  }
3448
3450
  });
@@ -3450,7 +3452,6 @@ var Server = class {
3450
3452
  ...this.#config.handlers,
3451
3453
  withContext: handlersWithContext(this.#config)
3452
3454
  };
3453
- this.#config.context.preserveHeaders = config?.preserveHeaders ?? false;
3454
3455
  this.#config.context.tenantId = getTenantId({ config: this.#config });
3455
3456
  this.#manager = new DBManager(this.#config);
3456
3457
  this.#handleHeaders(config);
@@ -3516,18 +3517,18 @@ var Server = class {
3516
3517
  set paths(paths) {
3517
3518
  this.#config.paths = paths;
3518
3519
  }
3519
- async withContext(context, fn) {
3520
- const { ...initialContext } = context ?? defaultContext;
3521
- this.#config.context = { ...initialContext };
3522
- const preserve = (context && "preserveHeaders" in context && context.preserveHeaders) ?? true;
3520
+ async withContext(contextOrFn, maybeFn) {
3521
+ const isFn = typeof contextOrFn === "function";
3522
+ const context = isFn ? {} : contextOrFn ?? {};
3523
+ const fn = isFn ? contextOrFn : maybeFn;
3524
+ const preserve = "useLastContext" in context ? context.useLastContext : true;
3523
3525
  if (preserve) {
3524
3526
  this.#config.context = { ...this.getContext(), ...context };
3527
+ } else {
3528
+ this.#config.context = { ...defaultContext, ...context };
3525
3529
  }
3526
3530
  return withNileContext(this.#config, async () => {
3527
- if (fn) {
3528
- return fn(this);
3529
- }
3530
- return this;
3531
+ return fn ? fn(this) : this;
3531
3532
  });
3532
3533
  }
3533
3534
  async noContext(fn) {