@niledatabase/server 4.2.0 → 5.0.0-alpha.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.js CHANGED
@@ -86,6 +86,73 @@ var X_NILE_USER_ID = "nile.user_id";
86
86
  var X_NILE_ORIGIN = "nile.origin";
87
87
  var X_NILE_SECURECOOKIES = "nile.secure_cookies";
88
88
 
89
+ // src/context/asyncStorage.ts
90
+ var globalContext = null;
91
+ function setContext(headers) {
92
+ const origin = headers.get(X_NILE_ORIGIN);
93
+ const host = headers.get("host");
94
+ const cookie = headers.get("cookie");
95
+ const tenantId = headers.get(X_NILE_TENANT);
96
+ const userId = headers.get(X_NILE_USER_ID);
97
+ const context = {};
98
+ if (origin) {
99
+ context.origin = origin;
100
+ } else if (host) {
101
+ context.origin = host;
102
+ }
103
+ if (cookie) {
104
+ context.cookie = cookie;
105
+ }
106
+ if (tenantId) {
107
+ context.tenantId = tenantId;
108
+ }
109
+ if (userId) {
110
+ context.userId = userId;
111
+ }
112
+ globalContext = context;
113
+ }
114
+ function getOrigin() {
115
+ return globalContext?.origin;
116
+ }
117
+ function getCookie() {
118
+ return globalContext?.cookie;
119
+ }
120
+ function setCookie(headers) {
121
+ const getSet = headers?.getSetCookie?.();
122
+ if (getSet?.length) {
123
+ const updatedCookie = [];
124
+ for (const cook of getSet) {
125
+ const [c] = cook.split("; ");
126
+ const [, val] = c.split("=");
127
+ if (val) {
128
+ updatedCookie.push(c);
129
+ }
130
+ }
131
+ const cookie = mergeCookies(updatedCookie);
132
+ globalContext = { ...globalContext, cookie };
133
+ }
134
+ }
135
+ function mergeCookies(overrideArray) {
136
+ const cookieString = getCookie();
137
+ const cookieMap = {};
138
+ if (!cookieString) {
139
+ return overrideArray.join("; ");
140
+ }
141
+ cookieString.split(";").forEach((cookie) => {
142
+ const [rawKey, ...rawVal] = cookie.trim().split("=");
143
+ const key12 = rawKey.trim();
144
+ const value = rawVal.join("=").trim();
145
+ if (key12) cookieMap[key12] = value;
146
+ });
147
+ overrideArray.forEach((cookie) => {
148
+ const [rawKey, ...rawVal] = cookie.trim().split("=");
149
+ const key12 = rawKey.trim();
150
+ const value = rawVal.join("=").trim();
151
+ if (key12) cookieMap[key12] = value;
152
+ });
153
+ return Object.entries(cookieMap).map(([k, v]) => `${k}=${v}`).join("; ");
154
+ }
155
+
89
156
  // src/api/utils/request.ts
90
157
  async function request(url, _init, config) {
91
158
  const { debug, info, error } = Logger(config, "[REQUEST]");
@@ -118,7 +185,7 @@ async function request(url, _init, config) {
118
185
  updatedHeaders.set(X_NILE_ORIGIN, requestUrl.origin);
119
186
  debug(`Obtained origin from request ${requestUrl.origin}`);
120
187
  }
121
- const params = { ...init };
188
+ const params = { ...init, headers: updatedHeaders };
122
189
  if (params.method?.toLowerCase() === "post" || params.method?.toLowerCase() === "put") {
123
190
  try {
124
191
  updatedHeaders.set("content-type", "application/json");
@@ -132,9 +199,9 @@ async function request(url, _init, config) {
132
199
  params.body = initBody ?? requestBody;
133
200
  }
134
201
  }
135
- params.headers = updatedHeaders;
136
202
  const fullUrl = `${url}${requestUrl.search}`;
137
203
  try {
204
+ setContext(updatedHeaders);
138
205
  const res = await fetch(fullUrl, { ...params }).catch(
139
206
  (e) => {
140
207
  error("An error has occurred in the fetch", {
@@ -153,6 +220,7 @@ async function request(url, _init, config) {
153
220
  statusText: res?.statusText,
154
221
  text: await loggingRes?.text()
155
222
  });
223
+ setCookie(res?.headers);
156
224
  return res;
157
225
  } catch (e) {
158
226
  if (e instanceof Error) {
@@ -194,17 +262,20 @@ async function auth(req, config) {
194
262
  }
195
263
  var getCallbackUrl = (cfg) => {
196
264
  const { config } = cfg;
197
- if (stringCheck(process.env.NILEDB_CALLBACK_URL)) {
198
- return process.env.NILEDB_CALLBACK_URL;
265
+ if (stringCheck(config?.api?.callbackUrl)) {
266
+ return config?.api?.callbackUrl;
199
267
  }
200
- return config?.api?.callbackUrl;
268
+ return process.env.NILEDB_CALLBACK_URL;
201
269
  };
202
270
  var getSecureCookies = (cfg) => {
203
271
  const { config } = cfg;
272
+ if (config?.api?.secureCookies != null) {
273
+ return config?.api?.secureCookies;
274
+ }
204
275
  if (stringCheck(process.env.NILEDB_SECURECOOKIES)) {
205
276
  return Boolean(process.env.NILEDB_SECURECOOKIES);
206
277
  }
207
- return config?.api?.secureCookies;
278
+ return void 0;
208
279
  };
209
280
  var getDatabaseId = (cfg) => {
210
281
  const { config, logger } = cfg;
@@ -277,9 +348,6 @@ var getPassword = (cfg) => {
277
348
  }
278
349
  return void 0;
279
350
  };
280
- var getInfoBearer = (cfg) => {
281
- return `${getUsername(cfg)}:${getPassword(cfg)}`;
282
- };
283
351
  var getToken = (cfg) => {
284
352
  const { config, logger } = cfg;
285
353
  const { info } = Logger(config, "[token]");
@@ -364,24 +432,6 @@ var getBasePath = (cfg) => {
364
432
  warn("not set. Must run auto-configuration");
365
433
  return void 0;
366
434
  };
367
- var getControlPlane = (cfg) => {
368
- const { config, logger } = cfg;
369
- const { info } = Logger(config, "[basePath]");
370
- if (stringCheck(config?.configureUrl)) {
371
- logger && info(`${logger}[config] ${config?.configureUrl}`);
372
- return String(config?.configureUrl);
373
- }
374
- const autoConfigUrl = stringCheck(process.env.NILEDB_CONFIGURE);
375
- if (autoConfigUrl) {
376
- logger && info(`${logger}[NILEDB_CONFIGURE] ${process.env.NILEDB_CONFIGURE}`);
377
- if (!autoConfigUrl.startsWith("http")) {
378
- return `https://${process.env.NILEDB_CONFIGURE}`;
379
- }
380
- return process.env.NILEDB_CONFIGURE;
381
- }
382
- logger && info(`${logger}[default] https://global.thenile.dev`);
383
- return "https://global.thenile.dev";
384
- };
385
435
  function getDbHost(cfg) {
386
436
  const { config, logger } = cfg;
387
437
  const { info } = Logger(config, "[db.host]");
@@ -447,7 +497,6 @@ var ApiConfig = class {
447
497
  routePrefix;
448
498
  secureCookies;
449
499
  origin;
450
- headers;
451
500
  /**
452
501
  * The client side callback url. Defaults to nothing (so nile.origin will be it), but in the cases of x-origin, you want to set this explicitly to be sure nile-auth does the right thing
453
502
  * If this is set, any `callbackUrl` from the client will be ignored.
@@ -461,11 +510,6 @@ var ApiConfig = class {
461
510
  this.callbackUrl = getCallbackUrl(envVarConfig);
462
511
  this.secureCookies = getSecureCookies(envVarConfig);
463
512
  this.basePath = getBasePath(envVarConfig);
464
- if (config?.api?.headers instanceof Headers) {
465
- this.headers = config?.api?.headers;
466
- } else if (config?.api?.headers) {
467
- this.headers = new Headers(config.api.headers);
468
- }
469
513
  this.routes = config?.api?.routes;
470
514
  this.routePrefix = config?.api?.routePrefix;
471
515
  this.origin = config?.api?.origin;
@@ -537,116 +581,6 @@ var Config = class {
537
581
  this.db.database = this.databaseName;
538
582
  }
539
583
  }
540
- configure = async (config) => {
541
- const { info, error, debug } = Logger(config, "[init]");
542
- const envVarConfig = {
543
- config
544
- };
545
- const { host, port, ...dbConfig } = config.db ?? {};
546
- let configuredHost = host ?? getDbHost(envVarConfig);
547
- const configuredPort = port ?? getDbPort(envVarConfig);
548
- let basePath = getBasePath(envVarConfig);
549
- if (configuredHost && this.databaseName && this.databaseId && basePath) {
550
- info("Already configured, aborting fetch");
551
- this.api = new ApiConfig(config);
552
- this.db = {
553
- user: this.user,
554
- password: this.password,
555
- host: configuredHost,
556
- port: configuredPort,
557
- database: this.databaseName,
558
- ...dbConfig
559
- };
560
- const cloned = { ...this.db };
561
- cloned.password = "***";
562
- info("[config set]", { db: cloned, api: this.api });
563
- return this;
564
- } else {
565
- const msg = [];
566
- if (!configuredHost) {
567
- msg.push("Database host");
568
- }
569
- if (!this.databaseName) {
570
- msg.push("Database name");
571
- }
572
- if (!this.databaseId) {
573
- msg.push("Database id");
574
- }
575
- if (!basePath) {
576
- msg.push("API URL");
577
- }
578
- info(
579
- `[autoconfigure] ${msg.join(", ")} ${msg.length > 1 ? "are" : "is"} missing from the config. Autoconfiguration will run.`
580
- );
581
- }
582
- const cp = getControlPlane(envVarConfig);
583
- const databaseName = getDatabaseName({ config, logger: "getInfo" });
584
- const url = new URL(`${cp}/databases/configure`);
585
- if (databaseName) {
586
- url.searchParams.set("databaseName", databaseName);
587
- }
588
- info(`configuring from ${url.href}`);
589
- const res = await fetch(url, {
590
- headers: {
591
- Authorization: `Bearer ${getInfoBearer({ config })}`
592
- }
593
- }).catch(() => {
594
- error(`Unable to auto-configure. is ${url} available?`);
595
- });
596
- if (!res) {
597
- return this;
598
- }
599
- let database;
600
- const possibleError = res.clone();
601
- try {
602
- const json = await res.json();
603
- if (res.status === 404) {
604
- info("is the configured databaseName correct?");
605
- }
606
- if (json.status && json.status !== "READY") {
607
- database = { message: "Database is not ready yet" };
608
- } else {
609
- database = json;
610
- }
611
- } catch (e) {
612
- const message = await possibleError.text();
613
- debug("Unable to auto-configure");
614
- error(message);
615
- database = { message };
616
- }
617
- info("[fetched database]", database);
618
- if (process.env.NODE_ENV !== "TEST") {
619
- if ("message" in database) {
620
- if ("statusCode" in database) {
621
- error(database);
622
- throw new Error("HTTP error has occurred");
623
- } else {
624
- throw new Error(
625
- "Unable to auto-configure. Please remove NILEDB_NAME, NILEDB_API_URL, NILEDB_POSTGRES_URL, and/or NILEDB_HOST from your environment variables."
626
- );
627
- }
628
- }
629
- if (typeof database === "object") {
630
- const { apiHost, dbHost, name, id } = database;
631
- basePath = basePath || apiHost;
632
- this.databaseId = id;
633
- this.databaseName = name;
634
- const dburl = new URL(dbHost);
635
- configuredHost = dburl.hostname;
636
- }
637
- }
638
- this.api = new ApiConfig(config);
639
- this.db = {
640
- user: this.user,
641
- password: this.password,
642
- host: configuredHost,
643
- port: configuredPort,
644
- database: this.databaseName,
645
- ...dbConfig
646
- };
647
- info("[config set]", { db: this.db, api: this.api });
648
- return this;
649
- };
650
584
  };
651
585
 
652
586
  // src/utils/Event/index.ts
@@ -990,7 +924,7 @@ var ResponseError = class {
990
924
 
991
925
  // src/utils/fetch.ts
992
926
  function getTokenFromCookie(headers, cookieKey) {
993
- const cookie = headers.get("cookie")?.split("; ");
927
+ const cookie = headers.get("cookie")?.split("; ") ?? getCookie()?.split("; ");
994
928
  const _cookies = {};
995
929
  if (cookie) {
996
930
  for (const parts of cookie) {
@@ -1028,24 +962,22 @@ function getUserFromHttp(headers, config) {
1028
962
  function makeBasicHeaders(config, url, opts) {
1029
963
  const { warn, error } = Logger(config, "[headers]");
1030
964
  const headers = new Headers(opts?.headers);
1031
- const cookieKey = config.api?.cookieKey;
1032
965
  headers.set("content-type", "application/json; charset=utf-8");
1033
- const origin = headers.get(X_NILE_ORIGIN);
1034
- if (!origin) {
1035
- if (config.api.headers) {
1036
- const localOrigin = config.api.headers.get(X_NILE_ORIGIN);
1037
- if (localOrigin) {
1038
- headers.set(X_NILE_ORIGIN, localOrigin);
1039
- }
966
+ const cookieKey = config.api?.cookieKey;
967
+ const authHeader = headers.get("Authorization");
968
+ if (!authHeader) {
969
+ const token = getTokenFromCookie(headers, cookieKey);
970
+ if (token) {
971
+ headers.set("Authorization", `Bearer ${token}`);
972
+ } else if (getToken({ config })) {
973
+ headers.set("Authorization", `Bearer ${getToken({ config })}`);
1040
974
  }
1041
975
  }
1042
976
  const cookie = headers.get("cookie");
1043
977
  if (!cookie) {
1044
- if (config.api.headers) {
1045
- const configCookie = config.api.headers.get("cookie");
1046
- if (configCookie) {
1047
- headers.set("cookie", configCookie);
1048
- }
978
+ const contextCookie = getCookie();
979
+ if (contextCookie) {
980
+ headers.set("cookie", contextCookie);
1049
981
  } else {
1050
982
  if (!url.endsWith("/users")) {
1051
983
  error(
@@ -1054,20 +986,14 @@ function makeBasicHeaders(config, url, opts) {
1054
986
  }
1055
987
  }
1056
988
  }
1057
- const authHeader = headers.get("Authorization");
1058
- if (!authHeader) {
1059
- const token = getTokenFromCookie(headers, cookieKey);
1060
- if (token) {
1061
- headers.set("Authorization", `Bearer ${token}`);
1062
- } else if (getToken({ config })) {
1063
- headers.set("Authorization", `Bearer ${getToken({ config })}`);
1064
- }
1065
- }
1066
989
  if (config && config.api.secureCookies != null) {
1067
990
  headers.set(X_NILE_SECURECOOKIES, String(config.api.secureCookies));
1068
991
  }
992
+ const savedOrigin = getOrigin();
1069
993
  if (config && config.api.origin) {
1070
994
  headers.set(X_NILE_ORIGIN, config.api.origin);
995
+ } else if (savedOrigin) {
996
+ headers.set(X_NILE_ORIGIN, savedOrigin);
1071
997
  } else {
1072
998
  warn(
1073
999
  "nile.origin missing from header, which defaults to secure cookies only."
@@ -1099,8 +1025,7 @@ async function _fetch(config, path, opts) {
1099
1025
  error("[fetch][response]", {
1100
1026
  message: e.message,
1101
1027
  stack: e.stack,
1102
- debug: "Is nile-auth running?",
1103
- cause: e.cause
1028
+ debug: "Is nile-auth running?"
1104
1029
  });
1105
1030
  return new Error(e);
1106
1031
  });
@@ -2426,66 +2351,6 @@ var Users = class extends Config {
2426
2351
  };
2427
2352
  };
2428
2353
 
2429
- // src/api/handlers/withContext/index.ts
2430
- function handlersWithContext(configRoutes, config) {
2431
- const GET6 = GETTER(configRoutes, config);
2432
- const POST5 = POSTER(configRoutes, config);
2433
- const DELETE3 = DELETER(configRoutes, config);
2434
- const PUT4 = PUTER(configRoutes, config);
2435
- return {
2436
- GET: async (req) => {
2437
- const response = await GET6(req);
2438
- const updatedConfig = updateConfig(response, config);
2439
- return { response, nile: new Server(updatedConfig) };
2440
- },
2441
- POST: async (req) => {
2442
- const response = await POST5(req);
2443
- const updatedConfig = updateConfig(response, config);
2444
- return { response, nile: new Server(updatedConfig) };
2445
- },
2446
- DELETE: async (req) => {
2447
- const response = await DELETE3(req);
2448
- const updatedConfig = updateConfig(response, config);
2449
- return { response, nile: new Server(updatedConfig) };
2450
- },
2451
- PUT: async (req) => {
2452
- const response = await PUT4(req);
2453
- const updatedConfig = updateConfig(response, config);
2454
- return { response, nile: new Server(updatedConfig) };
2455
- }
2456
- };
2457
- }
2458
- function updateConfig(response, config) {
2459
- let origin = "http://localhost:3000";
2460
- let headers = null;
2461
- if (response?.status === 302) {
2462
- const location = response.headers.get("location");
2463
- if (location) {
2464
- origin = location;
2465
- }
2466
- }
2467
- const setCookies = [];
2468
- if (response?.headers) {
2469
- for (const [key12, value] of response.headers) {
2470
- if (key12.toLowerCase() === "set-cookie") {
2471
- setCookies.push(value);
2472
- }
2473
- }
2474
- }
2475
- if (setCookies.length > 0) {
2476
- const cookieHeader = setCookies.map((cookieStr) => cookieStr.split(";")[0]).join("; ");
2477
- headers = new Headers({ cookie: cookieHeader });
2478
- }
2479
- return {
2480
- ...config,
2481
- api: {
2482
- ...config.api,
2483
- origin,
2484
- headers: headers ?? void 0
2485
- }
2486
- };
2487
- }
2488
-
2489
2354
  // src/Api.ts
2490
2355
  var Api = class {
2491
2356
  config;
@@ -2495,13 +2360,9 @@ var Api = class {
2495
2360
  routes;
2496
2361
  #headers;
2497
2362
  handlers;
2498
- handlersWithContext;
2499
2363
  paths;
2500
2364
  constructor(config) {
2501
2365
  this.config = config;
2502
- if (config?.api.headers) {
2503
- this.headers = config?.api.headers;
2504
- }
2505
2366
  this.auth = new Auth(config, void 0, {
2506
2367
  resetHeaders: this.resetHeaders
2507
2368
  });
@@ -2512,7 +2373,6 @@ var Api = class {
2512
2373
  ...config?.api.routes
2513
2374
  };
2514
2375
  this.handlers = Handlers(this.routes, config);
2515
- this.handlersWithContext = handlersWithContext(this.routes, config);
2516
2376
  this.paths = {
2517
2377
  get: [
2518
2378
  this.routes.ME,
@@ -2564,11 +2424,9 @@ var Api = class {
2564
2424
  };
2565
2425
  resetHeaders = (headers) => {
2566
2426
  this.#headers = new Headers(headers ?? {});
2427
+ setContext(new Headers());
2567
2428
  this.reset();
2568
2429
  };
2569
- /**
2570
- * Merge headers together
2571
- */
2572
2430
  set headers(headers) {
2573
2431
  const updates = [];
2574
2432
  if (headers instanceof Headers) {
@@ -2582,9 +2440,7 @@ var Api = class {
2582
2440
  }
2583
2441
  const merged = {};
2584
2442
  this.#headers?.forEach((value, key12) => {
2585
- if (key12.toLowerCase() !== "cookie") {
2586
- merged[key12.toLowerCase()] = value;
2587
- }
2443
+ merged[key12.toLowerCase()] = value;
2588
2444
  });
2589
2445
  for (const [key12, value] of updates) {
2590
2446
  merged[key12] = value;
@@ -2611,18 +2467,8 @@ var Api = class {
2611
2467
  this.config,
2612
2468
  this.handlers
2613
2469
  )(payload);
2470
+ this.headers = headers;
2614
2471
  this.setContext(headers);
2615
- try {
2616
- const res = await loginRes.json();
2617
- if (res.id) {
2618
- this.config.userId = res.id;
2619
- }
2620
- } catch (e) {
2621
- const { warn } = Logger(this.config, "[API][login]");
2622
- if (warn) {
2623
- warn("Unable to set user id from login attempt.");
2624
- }
2625
- }
2626
2472
  if (config?.returnResponse) {
2627
2473
  return loginRes;
2628
2474
  }
@@ -2637,26 +2483,21 @@ var Api = class {
2637
2483
  return this.auth.getSession(this.#headers);
2638
2484
  };
2639
2485
  setContext = (req) => {
2640
- try {
2641
- if (req instanceof Headers) {
2642
- this.headers = req;
2643
- return;
2644
- } else if (req instanceof Request) {
2645
- this.headers = new Headers(req.headers);
2646
- return;
2647
- }
2648
- const headers = new Headers(req);
2649
- if (headers) {
2650
- this.headers = headers;
2651
- return;
2652
- }
2653
- } catch {
2486
+ if (req instanceof Headers) {
2487
+ setContext(req);
2488
+ return;
2489
+ } else if (req instanceof Request) {
2490
+ setContext(req.headers);
2491
+ return;
2654
2492
  }
2655
- const { warn } = Logger(this.config, "[API]");
2656
- if (warn) {
2657
- warn(
2658
- "Set context expects a Request, Header instance or an object of Record<string, string>"
2659
- );
2493
+ const headers = new Headers(req);
2494
+ if (headers) {
2495
+ setContext(headers);
2496
+ } else {
2497
+ const { warn } = Logger(this.config, "[API]");
2498
+ if (warn) {
2499
+ warn("Set context expects a Request or Header object");
2500
+ }
2660
2501
  }
2661
2502
  };
2662
2503
  };
@@ -2684,14 +2525,6 @@ var Server = class {
2684
2525
  this.config = new Config(cfg);
2685
2526
  this.api.updateConfig(this.config);
2686
2527
  }
2687
- async init(cfg) {
2688
- const updatedConfig = await this.config.configure({
2689
- ...this.config,
2690
- ...cfg
2691
- });
2692
- this.setConfig(updatedConfig);
2693
- return this;
2694
- }
2695
2528
  set databaseId(val) {
2696
2529
  if (val) {
2697
2530
  this.config.databaseId = val;
@@ -2742,7 +2575,7 @@ var Server = class {
2742
2575
  /**
2743
2576
  * A convenience function that applies a config and ensures whatever was passed is set properly
2744
2577
  */
2745
- getInstance(config, req) {
2578
+ getInstance(config) {
2746
2579
  const _config = { ...this.config, ...config };
2747
2580
  const updatedConfig = new Config(_config);
2748
2581
  this.setConfig(updatedConfig);
@@ -2752,21 +2585,15 @@ var Server = class {
2752
2585
  this.token = updatedConfig.api.token;
2753
2586
  }
2754
2587
  this.databaseId = updatedConfig.databaseId;
2755
- if (req) {
2756
- this.api.setContext(req);
2757
- }
2758
2588
  return this;
2759
2589
  }
2760
2590
  };
2761
2591
  var server;
2762
- async function create(config) {
2592
+ function create(config) {
2763
2593
  if (!server) {
2764
2594
  server = new Server(config);
2765
2595
  }
2766
- if (config) {
2767
- return await server.init(new Config(config));
2768
- }
2769
- return await server.init();
2596
+ return server;
2770
2597
  }
2771
2598
 
2772
2599
  exports.LoginUserResponseTokenTypeEnum = LoginUserResponseTokenTypeEnum;