@niledatabase/server 4.0.1 → 4.0.2-alpha.11

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
@@ -23,39 +23,48 @@ function urlMatches(requestUrl, route15) {
23
23
 
24
24
  // src/utils/Logger.ts
25
25
  var red = "\x1B[31m";
26
- var yellow = "\x1B[33m";
26
+ var yellow = "\x1B[38;2;255;255;0m";
27
+ var purple = "\x1B[38;2;200;160;255m";
28
+ var orange = "\x1B[38;2;255;165;0m";
27
29
  var reset = "\x1B[0m";
28
30
  var baseLogger = (config, ...params) => ({
29
31
  info(message, meta) {
30
32
  if (config?.debug) {
31
33
  console.info(
32
- `[niledb][DEBUG]${params.join("")} ${message}`,
33
- meta ? `
34
- ${JSON.stringify(meta, null, 2)}` : ""
34
+ `${orange}[niledb]${reset}${purple}[DEBUG]${reset}${params.join(
35
+ ""
36
+ )}${reset} ${message}`,
37
+ meta ? `${JSON.stringify(meta)}` : ""
35
38
  );
36
39
  }
37
40
  },
38
41
  debug(message, meta) {
39
42
  if (config?.debug) {
40
43
  console.debug(
41
- `[niledb][DEBUG]${params.join("")} ${message}`,
42
- meta ? `
43
- ${JSON.stringify(meta, null, 2)}` : ""
44
+ `${orange}[niledb]${reset}${purple}[DEBUG]${reset}${params.join(
45
+ ""
46
+ )}${reset} ${message}`,
47
+ meta ? `${JSON.stringify(meta)}` : ""
44
48
  );
45
49
  }
46
50
  },
47
51
  warn(message, meta) {
48
52
  if (config?.debug) {
49
53
  console.warn(
50
- `${yellow}[niledb][WARN]${reset}${params.join("")} ${message}`,
51
- JSON.stringify(meta, null, 2)
54
+ `${orange}[niledb]${reset}${yellow}[WARN]${reset}${params.join(
55
+ ""
56
+ )}${reset} ${message}`,
57
+ meta ? JSON.stringify(meta) : ""
52
58
  );
53
59
  }
54
60
  },
55
61
  error(message, meta) {
56
62
  console.error(
57
- `${red}[niledb][ERROR]${reset}${params.join("")} ${message}`,
58
- meta
63
+ `${orange}[niledb]${reset}${red}[ERROR]${reset}${params.join(
64
+ ""
65
+ )}${red} ${message}`,
66
+ meta ? meta : "",
67
+ `${reset}`
59
68
  );
60
69
  }
61
70
  });
@@ -77,6 +86,73 @@ var X_NILE_USER_ID = "nile.user_id";
77
86
  var X_NILE_ORIGIN = "nile.origin";
78
87
  var X_NILE_SECURECOOKIES = "nile.secure_cookies";
79
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
+
80
156
  // src/api/utils/request.ts
81
157
  async function request(url, _init, config) {
82
158
  const { debug, info, error } = Logger(config, "[REQUEST]");
@@ -110,7 +186,7 @@ async function request(url, _init, config) {
110
186
  debug(`Obtained origin from request ${requestUrl.origin}`);
111
187
  }
112
188
  const params = { ...init, headers: updatedHeaders };
113
- if (params.method === "POST" || params.method === "PUT") {
189
+ if (params.method?.toLowerCase() === "post" || params.method?.toLowerCase() === "put") {
114
190
  try {
115
191
  updatedHeaders.set("content-type", "application/json");
116
192
  const initBody = await new Response(_init.request.clone().body).json();
@@ -125,22 +201,26 @@ async function request(url, _init, config) {
125
201
  }
126
202
  const fullUrl = `${url}${requestUrl.search}`;
127
203
  try {
128
- const res = await fetch(fullUrl, { ...params }).catch((e) => {
129
- error("An error has occurred in the fetch", {
130
- message: e.message,
131
- stack: e.stack
132
- });
133
- return new Response(
134
- "An unexpected (most likely configuration) problem has occurred",
135
- { status: 500 }
136
- );
137
- });
204
+ setContext(updatedHeaders);
205
+ const res = await fetch(fullUrl, { ...params }).catch(
206
+ (e) => {
207
+ error("An error has occurred in the fetch", {
208
+ message: e.message,
209
+ stack: e.stack
210
+ });
211
+ return new Response(
212
+ "An unexpected (most likely configuration) problem has occurred",
213
+ { status: 500 }
214
+ );
215
+ }
216
+ );
138
217
  const loggingRes = typeof res?.clone === "function" ? res?.clone() : null;
139
218
  info(`[${params.method ?? "GET"}] ${fullUrl}`, {
140
219
  status: res?.status,
141
220
  statusText: res?.statusText,
142
221
  text: await loggingRes?.text()
143
222
  });
223
+ setCookie(res?.headers);
144
224
  return res;
145
225
  } catch (e) {
146
226
  if (e instanceof Error) {
@@ -440,11 +520,11 @@ var ApiConfig = class {
440
520
  * If this is set, any `callbackUrl` from the client will be ignored.
441
521
  */
442
522
  callbackUrl;
443
- _token;
523
+ #token;
444
524
  constructor(config, logger) {
445
525
  const envVarConfig = { config, logger };
446
526
  this.cookieKey = getCookieKey(envVarConfig);
447
- this._token = getToken(envVarConfig);
527
+ this.#token = getToken(envVarConfig);
448
528
  this.callbackUrl = getCallbackUrl(envVarConfig);
449
529
  this.secureCookies = getSecureCookies(envVarConfig);
450
530
  this.basePath = getBasePath(envVarConfig);
@@ -453,10 +533,10 @@ var ApiConfig = class {
453
533
  this.origin = config?.api?.origin;
454
534
  }
455
535
  get token() {
456
- return this._token;
536
+ return this.#token;
457
537
  }
458
538
  set token(value) {
459
- this._token = value;
539
+ this.#token = value;
460
540
  }
461
541
  };
462
542
  var Config = class {
@@ -968,7 +1048,7 @@ var ResponseError = class {
968
1048
 
969
1049
  // src/utils/fetch.ts
970
1050
  function getTokenFromCookie(headers, cookieKey) {
971
- const cookie = headers.get("cookie")?.split("; ");
1051
+ const cookie = headers.get("cookie")?.split("; ") ?? getCookie()?.split("; ");
972
1052
  const _cookies = {};
973
1053
  if (cookie) {
974
1054
  for (const parts of cookie) {
@@ -1003,7 +1083,8 @@ function getUserFromHttp(headers, config) {
1003
1083
  }
1004
1084
  return headers?.get(X_NILE_USER_ID) ?? config.userId;
1005
1085
  }
1006
- function makeBasicHeaders(config, opts) {
1086
+ function makeBasicHeaders(config, url, opts) {
1087
+ const { warn, error } = Logger(config, "[headers]");
1007
1088
  const headers = new Headers(opts?.headers);
1008
1089
  headers.set("content-type", "application/json; charset=utf-8");
1009
1090
  const cookieKey = config.api?.cookieKey;
@@ -1016,11 +1097,31 @@ function makeBasicHeaders(config, opts) {
1016
1097
  headers.set("Authorization", `Bearer ${getToken({ config })}`);
1017
1098
  }
1018
1099
  }
1100
+ const cookie = headers.get("cookie");
1101
+ if (!cookie) {
1102
+ const contextCookie = getCookie();
1103
+ if (contextCookie) {
1104
+ headers.set("cookie", contextCookie);
1105
+ } else {
1106
+ if (!url.endsWith("/users")) {
1107
+ error(
1108
+ "Missing cookie header from request. Call nile.api.setContext(request) before making additional calls."
1109
+ );
1110
+ }
1111
+ }
1112
+ }
1019
1113
  if (config && config.api.secureCookies != null) {
1020
1114
  headers.set(X_NILE_SECURECOOKIES, String(config.api.secureCookies));
1021
1115
  }
1116
+ const savedOrigin = getOrigin();
1022
1117
  if (config && config.api.origin) {
1023
1118
  headers.set(X_NILE_ORIGIN, config.api.origin);
1119
+ } else if (savedOrigin) {
1120
+ headers.set(X_NILE_ORIGIN, savedOrigin);
1121
+ } else {
1122
+ warn(
1123
+ "nile.origin missing from header, which defaults to secure cookies only."
1124
+ );
1024
1125
  }
1025
1126
  return headers;
1026
1127
  }
@@ -1029,7 +1130,7 @@ async function _fetch(config, path, opts) {
1029
1130
  const url = `${config.api?.basePath}${path}`;
1030
1131
  const headers = new Headers(opts?.headers);
1031
1132
  const tenantId = getTenantFromHttp(headers, config);
1032
- const basicHeaders = makeBasicHeaders(config, opts);
1133
+ const basicHeaders = makeBasicHeaders(config, url, opts);
1033
1134
  updateTenantId(tenantId);
1034
1135
  const userId = getUserFromHttp(headers, config);
1035
1136
  updateUserId(userId);
@@ -1988,7 +2089,7 @@ function serverLogin(config, handlers) {
1988
2089
  if (!authCookie) {
1989
2090
  throw new Error("authentication failed");
1990
2091
  }
1991
- const [, token] = /((__Secure-)?nile\.session-token=.+?);/.exec(authCookie) ?? [];
2092
+ const token = parseToken(loginRes?.headers);
1992
2093
  if (!token) {
1993
2094
  error("Unable to obtain auth token", { authCookie });
1994
2095
  throw new Error("Server login failed");
@@ -2001,6 +2102,17 @@ function serverLogin(config, handlers) {
2001
2102
  return [headers, loginRes];
2002
2103
  };
2003
2104
  }
2105
+ function parseToken(headers) {
2106
+ let authCookie = headers?.get("set-cookie");
2107
+ if (!authCookie) {
2108
+ authCookie = headers?.get("cookie");
2109
+ }
2110
+ if (!authCookie) {
2111
+ return void 0;
2112
+ }
2113
+ const [, token] = /((__Secure-)?nile\.session-token=[^;]+)/.exec(authCookie) ?? [];
2114
+ return token;
2115
+ }
2004
2116
  var Auth = class extends Config {
2005
2117
  headers;
2006
2118
  resetHeaders;
@@ -2247,8 +2359,15 @@ var Users = class extends Config {
2247
2359
  super(config);
2248
2360
  this.headers = headers;
2249
2361
  }
2250
- get usersUrl() {
2251
- return "/users";
2362
+ usersUrl(user) {
2363
+ const params = new URLSearchParams();
2364
+ if (user.newTenantName) {
2365
+ params.set("newTenantName", user.newTenantName);
2366
+ }
2367
+ if (user.tenantId) {
2368
+ params.set("tenantId", user.tenantId);
2369
+ }
2370
+ return `/users?${params.size > 0 ? params : ""}`;
2252
2371
  }
2253
2372
  get tenantUsersUrl() {
2254
2373
  return `/tenants/${this.tenantId ?? "{tenantId}"}/users`;
@@ -2273,10 +2392,10 @@ var Users = class extends Config {
2273
2392
  }
2274
2393
  return void 0;
2275
2394
  }
2276
- createUser = async (req, init) => {
2395
+ createUser = async (user, init) => {
2277
2396
  const _requester = new Requester(this);
2278
2397
  const _init = this.handleHeaders(init);
2279
- return await _requester.post(req, this.usersUrl, _init);
2398
+ return await _requester.post(user, this.usersUrl(user), _init);
2280
2399
  };
2281
2400
  createTenantUser = async (req, init) => {
2282
2401
  const _requester = new Requester(this);
@@ -2421,6 +2540,7 @@ var Api = class {
2421
2540
  };
2422
2541
  resetHeaders = (headers) => {
2423
2542
  this.#headers = new Headers(headers ?? {});
2543
+ setContext(new Headers());
2424
2544
  this.reset();
2425
2545
  };
2426
2546
  set headers(headers) {
@@ -2450,12 +2570,21 @@ var Api = class {
2450
2570
  get headers() {
2451
2571
  return this.#headers;
2452
2572
  }
2573
+ getCookie(req) {
2574
+ if (req instanceof Headers) {
2575
+ return parseToken(req);
2576
+ } else if (req instanceof Request) {
2577
+ return parseToken(req.headers);
2578
+ }
2579
+ return null;
2580
+ }
2453
2581
  login = async (payload, config) => {
2454
2582
  const [headers, loginRes] = await serverLogin(
2455
2583
  this.config,
2456
2584
  this.handlers
2457
2585
  )(payload);
2458
2586
  this.headers = headers;
2587
+ this.setContext(headers);
2459
2588
  if (config?.returnResponse) {
2460
2589
  return loginRes;
2461
2590
  }
@@ -2469,6 +2598,17 @@ var Api = class {
2469
2598
  }
2470
2599
  return this.auth.getSession(this.#headers);
2471
2600
  };
2601
+ setContext = (req) => {
2602
+ if (req instanceof Headers) {
2603
+ setContext(req);
2604
+ } else if (req instanceof Request) {
2605
+ setContext(req.headers);
2606
+ }
2607
+ const { warn } = Logger(this.config, "[API]");
2608
+ if (warn) {
2609
+ warn("Set context expects a Request or Header object");
2610
+ }
2611
+ };
2472
2612
  };
2473
2613
 
2474
2614
  // src/Server.ts