@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.mjs CHANGED
@@ -80,6 +80,73 @@ var X_NILE_USER_ID = "nile.user_id";
80
80
  var X_NILE_ORIGIN = "nile.origin";
81
81
  var X_NILE_SECURECOOKIES = "nile.secure_cookies";
82
82
 
83
+ // src/context/asyncStorage.ts
84
+ var globalContext = null;
85
+ function setContext(headers) {
86
+ const origin = headers.get(X_NILE_ORIGIN);
87
+ const host = headers.get("host");
88
+ const cookie = headers.get("cookie");
89
+ const tenantId = headers.get(X_NILE_TENANT);
90
+ const userId = headers.get(X_NILE_USER_ID);
91
+ const context = {};
92
+ if (origin) {
93
+ context.origin = origin;
94
+ } else if (host) {
95
+ context.origin = host;
96
+ }
97
+ if (cookie) {
98
+ context.cookie = cookie;
99
+ }
100
+ if (tenantId) {
101
+ context.tenantId = tenantId;
102
+ }
103
+ if (userId) {
104
+ context.userId = userId;
105
+ }
106
+ globalContext = context;
107
+ }
108
+ function getOrigin() {
109
+ return globalContext?.origin;
110
+ }
111
+ function getCookie() {
112
+ return globalContext?.cookie;
113
+ }
114
+ function setCookie(headers) {
115
+ const getSet = headers?.getSetCookie?.();
116
+ if (getSet?.length) {
117
+ const updatedCookie = [];
118
+ for (const cook of getSet) {
119
+ const [c] = cook.split("; ");
120
+ const [, val] = c.split("=");
121
+ if (val) {
122
+ updatedCookie.push(c);
123
+ }
124
+ }
125
+ const cookie = mergeCookies(updatedCookie);
126
+ globalContext = { ...globalContext, cookie };
127
+ }
128
+ }
129
+ function mergeCookies(overrideArray) {
130
+ const cookieString = getCookie();
131
+ const cookieMap = {};
132
+ if (!cookieString) {
133
+ return overrideArray.join("; ");
134
+ }
135
+ cookieString.split(";").forEach((cookie) => {
136
+ const [rawKey, ...rawVal] = cookie.trim().split("=");
137
+ const key12 = rawKey.trim();
138
+ const value = rawVal.join("=").trim();
139
+ if (key12) cookieMap[key12] = value;
140
+ });
141
+ overrideArray.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
+ return Object.entries(cookieMap).map(([k, v]) => `${k}=${v}`).join("; ");
148
+ }
149
+
83
150
  // src/api/utils/request.ts
84
151
  async function request(url, _init, config) {
85
152
  const { debug, info, error } = Logger(config, "[REQUEST]");
@@ -112,7 +179,7 @@ async function request(url, _init, config) {
112
179
  updatedHeaders.set(X_NILE_ORIGIN, requestUrl.origin);
113
180
  debug(`Obtained origin from request ${requestUrl.origin}`);
114
181
  }
115
- const params = { ...init };
182
+ const params = { ...init, headers: updatedHeaders };
116
183
  if (params.method?.toLowerCase() === "post" || params.method?.toLowerCase() === "put") {
117
184
  try {
118
185
  updatedHeaders.set("content-type", "application/json");
@@ -126,9 +193,9 @@ async function request(url, _init, config) {
126
193
  params.body = initBody ?? requestBody;
127
194
  }
128
195
  }
129
- params.headers = updatedHeaders;
130
196
  const fullUrl = `${url}${requestUrl.search}`;
131
197
  try {
198
+ setContext(updatedHeaders);
132
199
  const res = await fetch(fullUrl, { ...params }).catch(
133
200
  (e) => {
134
201
  error("An error has occurred in the fetch", {
@@ -147,6 +214,7 @@ async function request(url, _init, config) {
147
214
  statusText: res?.statusText,
148
215
  text: await loggingRes?.text()
149
216
  });
217
+ setCookie(res?.headers);
150
218
  return res;
151
219
  } catch (e) {
152
220
  if (e instanceof Error) {
@@ -188,17 +256,20 @@ async function auth(req, config) {
188
256
  }
189
257
  var getCallbackUrl = (cfg) => {
190
258
  const { config } = cfg;
191
- if (stringCheck(process.env.NILEDB_CALLBACK_URL)) {
192
- return process.env.NILEDB_CALLBACK_URL;
259
+ if (stringCheck(config?.api?.callbackUrl)) {
260
+ return config?.api?.callbackUrl;
193
261
  }
194
- return config?.api?.callbackUrl;
262
+ return process.env.NILEDB_CALLBACK_URL;
195
263
  };
196
264
  var getSecureCookies = (cfg) => {
197
265
  const { config } = cfg;
266
+ if (config?.api?.secureCookies != null) {
267
+ return config?.api?.secureCookies;
268
+ }
198
269
  if (stringCheck(process.env.NILEDB_SECURECOOKIES)) {
199
270
  return Boolean(process.env.NILEDB_SECURECOOKIES);
200
271
  }
201
- return config?.api?.secureCookies;
272
+ return void 0;
202
273
  };
203
274
  var getDatabaseId = (cfg) => {
204
275
  const { config, logger } = cfg;
@@ -271,9 +342,6 @@ var getPassword = (cfg) => {
271
342
  }
272
343
  return void 0;
273
344
  };
274
- var getInfoBearer = (cfg) => {
275
- return `${getUsername(cfg)}:${getPassword(cfg)}`;
276
- };
277
345
  var getToken = (cfg) => {
278
346
  const { config, logger } = cfg;
279
347
  const { info } = Logger(config, "[token]");
@@ -358,24 +426,6 @@ var getBasePath = (cfg) => {
358
426
  warn("not set. Must run auto-configuration");
359
427
  return void 0;
360
428
  };
361
- var getControlPlane = (cfg) => {
362
- const { config, logger } = cfg;
363
- const { info } = Logger(config, "[basePath]");
364
- if (stringCheck(config?.configureUrl)) {
365
- logger && info(`${logger}[config] ${config?.configureUrl}`);
366
- return String(config?.configureUrl);
367
- }
368
- const autoConfigUrl = stringCheck(process.env.NILEDB_CONFIGURE);
369
- if (autoConfigUrl) {
370
- logger && info(`${logger}[NILEDB_CONFIGURE] ${process.env.NILEDB_CONFIGURE}`);
371
- if (!autoConfigUrl.startsWith("http")) {
372
- return `https://${process.env.NILEDB_CONFIGURE}`;
373
- }
374
- return process.env.NILEDB_CONFIGURE;
375
- }
376
- logger && info(`${logger}[default] https://global.thenile.dev`);
377
- return "https://global.thenile.dev";
378
- };
379
429
  function getDbHost(cfg) {
380
430
  const { config, logger } = cfg;
381
431
  const { info } = Logger(config, "[db.host]");
@@ -441,7 +491,6 @@ var ApiConfig = class {
441
491
  routePrefix;
442
492
  secureCookies;
443
493
  origin;
444
- headers;
445
494
  /**
446
495
  * 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
447
496
  * If this is set, any `callbackUrl` from the client will be ignored.
@@ -455,11 +504,6 @@ var ApiConfig = class {
455
504
  this.callbackUrl = getCallbackUrl(envVarConfig);
456
505
  this.secureCookies = getSecureCookies(envVarConfig);
457
506
  this.basePath = getBasePath(envVarConfig);
458
- if (config?.api?.headers instanceof Headers) {
459
- this.headers = config?.api?.headers;
460
- } else if (config?.api?.headers) {
461
- this.headers = new Headers(config.api.headers);
462
- }
463
507
  this.routes = config?.api?.routes;
464
508
  this.routePrefix = config?.api?.routePrefix;
465
509
  this.origin = config?.api?.origin;
@@ -531,116 +575,6 @@ var Config = class {
531
575
  this.db.database = this.databaseName;
532
576
  }
533
577
  }
534
- configure = async (config) => {
535
- const { info, error, debug } = Logger(config, "[init]");
536
- const envVarConfig = {
537
- config
538
- };
539
- const { host, port, ...dbConfig } = config.db ?? {};
540
- let configuredHost = host ?? getDbHost(envVarConfig);
541
- const configuredPort = port ?? getDbPort(envVarConfig);
542
- let basePath = getBasePath(envVarConfig);
543
- if (configuredHost && this.databaseName && this.databaseId && basePath) {
544
- info("Already configured, aborting fetch");
545
- this.api = new ApiConfig(config);
546
- this.db = {
547
- user: this.user,
548
- password: this.password,
549
- host: configuredHost,
550
- port: configuredPort,
551
- database: this.databaseName,
552
- ...dbConfig
553
- };
554
- const cloned = { ...this.db };
555
- cloned.password = "***";
556
- info("[config set]", { db: cloned, api: this.api });
557
- return this;
558
- } else {
559
- const msg = [];
560
- if (!configuredHost) {
561
- msg.push("Database host");
562
- }
563
- if (!this.databaseName) {
564
- msg.push("Database name");
565
- }
566
- if (!this.databaseId) {
567
- msg.push("Database id");
568
- }
569
- if (!basePath) {
570
- msg.push("API URL");
571
- }
572
- info(
573
- `[autoconfigure] ${msg.join(", ")} ${msg.length > 1 ? "are" : "is"} missing from the config. Autoconfiguration will run.`
574
- );
575
- }
576
- const cp = getControlPlane(envVarConfig);
577
- const databaseName = getDatabaseName({ config, logger: "getInfo" });
578
- const url = new URL(`${cp}/databases/configure`);
579
- if (databaseName) {
580
- url.searchParams.set("databaseName", databaseName);
581
- }
582
- info(`configuring from ${url.href}`);
583
- const res = await fetch(url, {
584
- headers: {
585
- Authorization: `Bearer ${getInfoBearer({ config })}`
586
- }
587
- }).catch(() => {
588
- error(`Unable to auto-configure. is ${url} available?`);
589
- });
590
- if (!res) {
591
- return this;
592
- }
593
- let database;
594
- const possibleError = res.clone();
595
- try {
596
- const json = await res.json();
597
- if (res.status === 404) {
598
- info("is the configured databaseName correct?");
599
- }
600
- if (json.status && json.status !== "READY") {
601
- database = { message: "Database is not ready yet" };
602
- } else {
603
- database = json;
604
- }
605
- } catch (e) {
606
- const message = await possibleError.text();
607
- debug("Unable to auto-configure");
608
- error(message);
609
- database = { message };
610
- }
611
- info("[fetched database]", database);
612
- if (process.env.NODE_ENV !== "TEST") {
613
- if ("message" in database) {
614
- if ("statusCode" in database) {
615
- error(database);
616
- throw new Error("HTTP error has occurred");
617
- } else {
618
- throw new Error(
619
- "Unable to auto-configure. Please remove NILEDB_NAME, NILEDB_API_URL, NILEDB_POSTGRES_URL, and/or NILEDB_HOST from your environment variables."
620
- );
621
- }
622
- }
623
- if (typeof database === "object") {
624
- const { apiHost, dbHost, name, id } = database;
625
- basePath = basePath || apiHost;
626
- this.databaseId = id;
627
- this.databaseName = name;
628
- const dburl = new URL(dbHost);
629
- configuredHost = dburl.hostname;
630
- }
631
- }
632
- this.api = new ApiConfig(config);
633
- this.db = {
634
- user: this.user,
635
- password: this.password,
636
- host: configuredHost,
637
- port: configuredPort,
638
- database: this.databaseName,
639
- ...dbConfig
640
- };
641
- info("[config set]", { db: this.db, api: this.api });
642
- return this;
643
- };
644
578
  };
645
579
 
646
580
  // src/utils/Event/index.ts
@@ -984,7 +918,7 @@ var ResponseError = class {
984
918
 
985
919
  // src/utils/fetch.ts
986
920
  function getTokenFromCookie(headers, cookieKey) {
987
- const cookie = headers.get("cookie")?.split("; ");
921
+ const cookie = headers.get("cookie")?.split("; ") ?? getCookie()?.split("; ");
988
922
  const _cookies = {};
989
923
  if (cookie) {
990
924
  for (const parts of cookie) {
@@ -1022,24 +956,22 @@ function getUserFromHttp(headers, config) {
1022
956
  function makeBasicHeaders(config, url, opts) {
1023
957
  const { warn, error } = Logger(config, "[headers]");
1024
958
  const headers = new Headers(opts?.headers);
1025
- const cookieKey = config.api?.cookieKey;
1026
959
  headers.set("content-type", "application/json; charset=utf-8");
1027
- const origin = headers.get(X_NILE_ORIGIN);
1028
- if (!origin) {
1029
- if (config.api.headers) {
1030
- const localOrigin = config.api.headers.get(X_NILE_ORIGIN);
1031
- if (localOrigin) {
1032
- headers.set(X_NILE_ORIGIN, localOrigin);
1033
- }
960
+ const cookieKey = config.api?.cookieKey;
961
+ const authHeader = headers.get("Authorization");
962
+ if (!authHeader) {
963
+ const token = getTokenFromCookie(headers, cookieKey);
964
+ if (token) {
965
+ headers.set("Authorization", `Bearer ${token}`);
966
+ } else if (getToken({ config })) {
967
+ headers.set("Authorization", `Bearer ${getToken({ config })}`);
1034
968
  }
1035
969
  }
1036
970
  const cookie = headers.get("cookie");
1037
971
  if (!cookie) {
1038
- if (config.api.headers) {
1039
- const configCookie = config.api.headers.get("cookie");
1040
- if (configCookie) {
1041
- headers.set("cookie", configCookie);
1042
- }
972
+ const contextCookie = getCookie();
973
+ if (contextCookie) {
974
+ headers.set("cookie", contextCookie);
1043
975
  } else {
1044
976
  if (!url.endsWith("/users")) {
1045
977
  error(
@@ -1048,20 +980,14 @@ function makeBasicHeaders(config, url, opts) {
1048
980
  }
1049
981
  }
1050
982
  }
1051
- const authHeader = headers.get("Authorization");
1052
- if (!authHeader) {
1053
- const token = getTokenFromCookie(headers, cookieKey);
1054
- if (token) {
1055
- headers.set("Authorization", `Bearer ${token}`);
1056
- } else if (getToken({ config })) {
1057
- headers.set("Authorization", `Bearer ${getToken({ config })}`);
1058
- }
1059
- }
1060
983
  if (config && config.api.secureCookies != null) {
1061
984
  headers.set(X_NILE_SECURECOOKIES, String(config.api.secureCookies));
1062
985
  }
986
+ const savedOrigin = getOrigin();
1063
987
  if (config && config.api.origin) {
1064
988
  headers.set(X_NILE_ORIGIN, config.api.origin);
989
+ } else if (savedOrigin) {
990
+ headers.set(X_NILE_ORIGIN, savedOrigin);
1065
991
  } else {
1066
992
  warn(
1067
993
  "nile.origin missing from header, which defaults to secure cookies only."
@@ -1093,8 +1019,7 @@ async function _fetch(config, path, opts) {
1093
1019
  error("[fetch][response]", {
1094
1020
  message: e.message,
1095
1021
  stack: e.stack,
1096
- debug: "Is nile-auth running?",
1097
- cause: e.cause
1022
+ debug: "Is nile-auth running?"
1098
1023
  });
1099
1024
  return new Error(e);
1100
1025
  });
@@ -2420,66 +2345,6 @@ var Users = class extends Config {
2420
2345
  };
2421
2346
  };
2422
2347
 
2423
- // src/api/handlers/withContext/index.ts
2424
- function handlersWithContext(configRoutes, config) {
2425
- const GET6 = GETTER(configRoutes, config);
2426
- const POST5 = POSTER(configRoutes, config);
2427
- const DELETE3 = DELETER(configRoutes, config);
2428
- const PUT4 = PUTER(configRoutes, config);
2429
- return {
2430
- GET: async (req) => {
2431
- const response = await GET6(req);
2432
- const updatedConfig = updateConfig(response, config);
2433
- return { response, nile: new Server(updatedConfig) };
2434
- },
2435
- POST: async (req) => {
2436
- const response = await POST5(req);
2437
- const updatedConfig = updateConfig(response, config);
2438
- return { response, nile: new Server(updatedConfig) };
2439
- },
2440
- DELETE: async (req) => {
2441
- const response = await DELETE3(req);
2442
- const updatedConfig = updateConfig(response, config);
2443
- return { response, nile: new Server(updatedConfig) };
2444
- },
2445
- PUT: async (req) => {
2446
- const response = await PUT4(req);
2447
- const updatedConfig = updateConfig(response, config);
2448
- return { response, nile: new Server(updatedConfig) };
2449
- }
2450
- };
2451
- }
2452
- function updateConfig(response, config) {
2453
- let origin = "http://localhost:3000";
2454
- let headers = null;
2455
- if (response?.status === 302) {
2456
- const location = response.headers.get("location");
2457
- if (location) {
2458
- origin = location;
2459
- }
2460
- }
2461
- const setCookies = [];
2462
- if (response?.headers) {
2463
- for (const [key12, value] of response.headers) {
2464
- if (key12.toLowerCase() === "set-cookie") {
2465
- setCookies.push(value);
2466
- }
2467
- }
2468
- }
2469
- if (setCookies.length > 0) {
2470
- const cookieHeader = setCookies.map((cookieStr) => cookieStr.split(";")[0]).join("; ");
2471
- headers = new Headers({ cookie: cookieHeader });
2472
- }
2473
- return {
2474
- ...config,
2475
- api: {
2476
- ...config.api,
2477
- origin,
2478
- headers: headers ?? void 0
2479
- }
2480
- };
2481
- }
2482
-
2483
2348
  // src/Api.ts
2484
2349
  var Api = class {
2485
2350
  config;
@@ -2489,13 +2354,9 @@ var Api = class {
2489
2354
  routes;
2490
2355
  #headers;
2491
2356
  handlers;
2492
- handlersWithContext;
2493
2357
  paths;
2494
2358
  constructor(config) {
2495
2359
  this.config = config;
2496
- if (config?.api.headers) {
2497
- this.headers = config?.api.headers;
2498
- }
2499
2360
  this.auth = new Auth(config, void 0, {
2500
2361
  resetHeaders: this.resetHeaders
2501
2362
  });
@@ -2506,7 +2367,6 @@ var Api = class {
2506
2367
  ...config?.api.routes
2507
2368
  };
2508
2369
  this.handlers = Handlers(this.routes, config);
2509
- this.handlersWithContext = handlersWithContext(this.routes, config);
2510
2370
  this.paths = {
2511
2371
  get: [
2512
2372
  this.routes.ME,
@@ -2558,11 +2418,9 @@ var Api = class {
2558
2418
  };
2559
2419
  resetHeaders = (headers) => {
2560
2420
  this.#headers = new Headers(headers ?? {});
2421
+ setContext(new Headers());
2561
2422
  this.reset();
2562
2423
  };
2563
- /**
2564
- * Merge headers together
2565
- */
2566
2424
  set headers(headers) {
2567
2425
  const updates = [];
2568
2426
  if (headers instanceof Headers) {
@@ -2576,9 +2434,7 @@ var Api = class {
2576
2434
  }
2577
2435
  const merged = {};
2578
2436
  this.#headers?.forEach((value, key12) => {
2579
- if (key12.toLowerCase() !== "cookie") {
2580
- merged[key12.toLowerCase()] = value;
2581
- }
2437
+ merged[key12.toLowerCase()] = value;
2582
2438
  });
2583
2439
  for (const [key12, value] of updates) {
2584
2440
  merged[key12] = value;
@@ -2605,18 +2461,8 @@ var Api = class {
2605
2461
  this.config,
2606
2462
  this.handlers
2607
2463
  )(payload);
2464
+ this.headers = headers;
2608
2465
  this.setContext(headers);
2609
- try {
2610
- const res = await loginRes.json();
2611
- if (res.id) {
2612
- this.config.userId = res.id;
2613
- }
2614
- } catch (e) {
2615
- const { warn } = Logger(this.config, "[API][login]");
2616
- if (warn) {
2617
- warn("Unable to set user id from login attempt.");
2618
- }
2619
- }
2620
2466
  if (config?.returnResponse) {
2621
2467
  return loginRes;
2622
2468
  }
@@ -2631,26 +2477,21 @@ var Api = class {
2631
2477
  return this.auth.getSession(this.#headers);
2632
2478
  };
2633
2479
  setContext = (req) => {
2634
- try {
2635
- if (req instanceof Headers) {
2636
- this.headers = req;
2637
- return;
2638
- } else if (req instanceof Request) {
2639
- this.headers = new Headers(req.headers);
2640
- return;
2641
- }
2642
- const headers = new Headers(req);
2643
- if (headers) {
2644
- this.headers = headers;
2645
- return;
2646
- }
2647
- } catch {
2480
+ if (req instanceof Headers) {
2481
+ setContext(req);
2482
+ return;
2483
+ } else if (req instanceof Request) {
2484
+ setContext(req.headers);
2485
+ return;
2648
2486
  }
2649
- const { warn } = Logger(this.config, "[API]");
2650
- if (warn) {
2651
- warn(
2652
- "Set context expects a Request, Header instance or an object of Record<string, string>"
2653
- );
2487
+ const headers = new Headers(req);
2488
+ if (headers) {
2489
+ setContext(headers);
2490
+ } else {
2491
+ const { warn } = Logger(this.config, "[API]");
2492
+ if (warn) {
2493
+ warn("Set context expects a Request or Header object");
2494
+ }
2654
2495
  }
2655
2496
  };
2656
2497
  };
@@ -2678,14 +2519,6 @@ var Server = class {
2678
2519
  this.config = new Config(cfg);
2679
2520
  this.api.updateConfig(this.config);
2680
2521
  }
2681
- async init(cfg) {
2682
- const updatedConfig = await this.config.configure({
2683
- ...this.config,
2684
- ...cfg
2685
- });
2686
- this.setConfig(updatedConfig);
2687
- return this;
2688
- }
2689
2522
  set databaseId(val) {
2690
2523
  if (val) {
2691
2524
  this.config.databaseId = val;
@@ -2736,7 +2569,7 @@ var Server = class {
2736
2569
  /**
2737
2570
  * A convenience function that applies a config and ensures whatever was passed is set properly
2738
2571
  */
2739
- getInstance(config, req) {
2572
+ getInstance(config) {
2740
2573
  const _config = { ...this.config, ...config };
2741
2574
  const updatedConfig = new Config(_config);
2742
2575
  this.setConfig(updatedConfig);
@@ -2746,21 +2579,15 @@ var Server = class {
2746
2579
  this.token = updatedConfig.api.token;
2747
2580
  }
2748
2581
  this.databaseId = updatedConfig.databaseId;
2749
- if (req) {
2750
- this.api.setContext(req);
2751
- }
2752
2582
  return this;
2753
2583
  }
2754
2584
  };
2755
2585
  var server;
2756
- async function create(config) {
2586
+ function create(config) {
2757
2587
  if (!server) {
2758
2588
  server = new Server(config);
2759
2589
  }
2760
- if (config) {
2761
- return await server.init(new Config(config));
2762
- }
2763
- return await server.init();
2590
+ return server;
2764
2591
  }
2765
2592
 
2766
2593
  export { LoginUserResponseTokenTypeEnum, create as Nile, Server };