@niledatabase/server 5.0.0-alpha.0 → 5.0.0-alpha.10
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 +447 -204
- package/dist/index.d.ts +447 -204
- package/dist/index.js +2538 -2023
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2534 -2027
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -16
- package/dist/express.d.mts +0 -32
- package/dist/express.d.ts +0 -32
- package/dist/express.js +0 -167
- package/dist/express.js.map +0 -1
- package/dist/express.mjs +0 -163
- package/dist/express.mjs.map +0 -1
- package/dist/nitro.d.mts +0 -7
- package/dist/nitro.d.ts +0 -7
- package/dist/nitro.js +0 -36
- package/dist/nitro.js.map +0 -1
- package/dist/nitro.mjs +0 -34
- package/dist/nitro.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -2,12 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
require('dotenv/config');
|
|
4
4
|
var pg = require('pg');
|
|
5
|
-
var jose = require('jose');
|
|
6
5
|
|
|
7
6
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
7
|
|
|
9
8
|
var pg__default = /*#__PURE__*/_interopDefault(pg);
|
|
10
9
|
|
|
10
|
+
// src/types.ts
|
|
11
|
+
var APIErrorErrorCodeEnum = {
|
|
12
|
+
InternalError: "internal_error",
|
|
13
|
+
BadRequest: "bad_request",
|
|
14
|
+
EntityNotFound: "entity_not_found",
|
|
15
|
+
DuplicateEntity: "duplicate_entity",
|
|
16
|
+
InvalidCredentials: "invalid_credentials",
|
|
17
|
+
UnknownOidcProvider: "unknown_oidc_provider",
|
|
18
|
+
ProviderAlreadyExists: "provider_already_exists",
|
|
19
|
+
ProviderConfigError: "provider_config_error",
|
|
20
|
+
ProviderMismatch: "provider_mismatch",
|
|
21
|
+
ProviderUpdateError: "provider_update_error",
|
|
22
|
+
SessionStateMissing: "session_state_missing",
|
|
23
|
+
SessionStateMismatch: "session_state_mismatch",
|
|
24
|
+
OidcCodeMissing: "oidc_code_missing"
|
|
25
|
+
};
|
|
26
|
+
|
|
11
27
|
// src/users/types.ts
|
|
12
28
|
var LoginUserResponseTokenTypeEnum = {
|
|
13
29
|
AccessToken: "ACCESS_TOKEN",
|
|
@@ -15,212 +31,184 @@ var LoginUserResponseTokenTypeEnum = {
|
|
|
15
31
|
IdToken: "ID_TOKEN"
|
|
16
32
|
};
|
|
17
33
|
|
|
18
|
-
// src/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
34
|
+
// src/utils/constants.ts
|
|
35
|
+
var TENANT_COOKIE = "nile.tenant-id";
|
|
36
|
+
var USER_COOKIE = "nile.user-id";
|
|
37
|
+
var HEADER_ORIGIN = "nile-origin";
|
|
38
|
+
var HEADER_SECURE_COOKIES = "nile-secure-cookies";
|
|
23
39
|
|
|
24
|
-
// src/utils/
|
|
25
|
-
var
|
|
26
|
-
var
|
|
27
|
-
var
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
warn(message, meta) {
|
|
52
|
-
if (config?.debug) {
|
|
53
|
-
console.warn(
|
|
54
|
-
`${orange}[niledb]${reset}${yellow}[WARN]${reset}${params.join(
|
|
55
|
-
""
|
|
56
|
-
)}${reset} ${message}`,
|
|
57
|
-
meta ? JSON.stringify(meta) : ""
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
error(message, meta) {
|
|
62
|
-
console.error(
|
|
63
|
-
`${orange}[niledb]${reset}${red}[ERROR]${reset}${params.join(
|
|
64
|
-
""
|
|
65
|
-
)}${red} ${message}`,
|
|
66
|
-
meta ? meta : "",
|
|
67
|
-
`${reset}`
|
|
68
|
-
);
|
|
69
|
-
}
|
|
40
|
+
// src/api/utils/routes/index.ts
|
|
41
|
+
var NILEDB_API_URL = process.env.NILEDB_API_URL;
|
|
42
|
+
var DEFAULT_PREFIX = "/api";
|
|
43
|
+
var appRoutes = (prefix = DEFAULT_PREFIX) => ({
|
|
44
|
+
SIGNIN: `${prefix}${"/auth/signin" /* SIGNIN */}`,
|
|
45
|
+
PROVIDERS: `${prefix}${"/auth/providers" /* PROVIDERS */}`,
|
|
46
|
+
SESSION: `${prefix}${"/auth/session" /* SESSION */}`,
|
|
47
|
+
CSRF: `${prefix}${"/auth/csrf" /* CSRF */}`,
|
|
48
|
+
CALLBACK: `${prefix}${"/auth/callback" /* CALLBACK */}`,
|
|
49
|
+
SIGNOUT: `${prefix}${"/auth/signout" /* SIGNOUT */}`,
|
|
50
|
+
ERROR: `${prefix}/auth/error`,
|
|
51
|
+
VERIFY_REQUEST: `${prefix}/auth/verify-request`,
|
|
52
|
+
VERIFY_EMAIL: `${prefix}${"/auth/verify-email" /* VERIFY_EMAIL */}`,
|
|
53
|
+
PASSWORD_RESET: `${prefix}${"/auth/reset-password" /* PASSWORD_RESET */}`,
|
|
54
|
+
ME: `${prefix}${"/me" /* ME */}`,
|
|
55
|
+
USERS: `${prefix}${"/users" /* USERS */}`,
|
|
56
|
+
USER_TENANTS: `${prefix}${"/users/{userId}/tenants" /* USER_TENANTS */}`,
|
|
57
|
+
TENANTS: `${prefix}${"/tenants" /* TENANTS */}`,
|
|
58
|
+
TENANT: `${prefix}${"/tenants/{tenantId}" /* TENANT */}`,
|
|
59
|
+
TENANT_USER: `${prefix}${"/tenants/{tenantId}/users/{userId}" /* TENANT_USER */}`,
|
|
60
|
+
TENANT_USERS: `${prefix}${"/tenants/{tenantId}/users" /* TENANT_USERS */}`,
|
|
61
|
+
SIGNUP: `${prefix}${"/signup" /* SIGNUP */}`,
|
|
62
|
+
INVITES: `${prefix}${"/tenants/{tenantId}/invites" /* INVITES */}`,
|
|
63
|
+
INVITE: `${prefix}${"/tenants/{tenantId}/invite" /* INVITE */}`,
|
|
64
|
+
LOG: `${prefix}/_log`
|
|
70
65
|
});
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
var
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
if (cookie) {
|
|
104
|
-
context.cookie = cookie;
|
|
105
|
-
}
|
|
106
|
-
if (tenantId) {
|
|
107
|
-
context.tenantId = tenantId;
|
|
108
|
-
}
|
|
109
|
-
if (userId) {
|
|
110
|
-
context.userId = userId;
|
|
66
|
+
var apiRoutes = (config) => ({
|
|
67
|
+
ME: makeRestUrl(config, "/me"),
|
|
68
|
+
USERS: (qp) => makeRestUrl(config, "/users", qp),
|
|
69
|
+
USER: (userId) => makeRestUrl(config, `/users/${userId}`),
|
|
70
|
+
TENANTS: makeRestUrl(config, "/tenants"),
|
|
71
|
+
TENANT: (tenantId) => makeRestUrl(config, `/tenants/${tenantId}`),
|
|
72
|
+
SIGNUP: makeRestUrl(config, "/signup"),
|
|
73
|
+
TENANT_USERS: (tenantId) => makeRestUrl(config, `/tenants/${tenantId}/users`),
|
|
74
|
+
INVITES: (tenantId) => makeRestUrl(config, `/tenants/${tenantId}/invites`),
|
|
75
|
+
INVITE: (tenantId) => makeRestUrl(config, `/tenants/${tenantId}/invite`),
|
|
76
|
+
TENANT_USER: makeRestUrl(
|
|
77
|
+
config,
|
|
78
|
+
`/tenants/${config.tenantId}/users/${config.userId}`
|
|
79
|
+
),
|
|
80
|
+
USER_TENANTS: (userId) => makeRestUrl(config, `/users/${userId}/tenants`)
|
|
81
|
+
});
|
|
82
|
+
var proxyRoutes = (config) => ({
|
|
83
|
+
SIGNIN: makeRestUrl(config, "/auth/signin" /* SIGNIN */),
|
|
84
|
+
PROVIDERS: makeRestUrl(config, "/auth/providers" /* PROVIDERS */),
|
|
85
|
+
SESSION: makeRestUrl(config, "/auth/session" /* SESSION */),
|
|
86
|
+
CSRF: makeRestUrl(config, "/auth/csrf" /* CSRF */),
|
|
87
|
+
CALLBACK: makeRestUrl(config, "/auth/callback" /* CALLBACK */),
|
|
88
|
+
SIGNOUT: makeRestUrl(config, "/auth/signout" /* SIGNOUT */),
|
|
89
|
+
ERROR: makeRestUrl(config, "/auth/error"),
|
|
90
|
+
VERIFY_REQUEST: makeRestUrl(config, "/auth/verify-request"),
|
|
91
|
+
PASSWORD_RESET: makeRestUrl(config, "/auth/reset-password" /* PASSWORD_RESET */),
|
|
92
|
+
VERIFY_EMAIL: makeRestUrl(config, "/auth/verify-email" /* VERIFY_EMAIL */)
|
|
93
|
+
});
|
|
94
|
+
function filterNullUndefined(obj) {
|
|
95
|
+
if (!obj) {
|
|
96
|
+
return void 0;
|
|
111
97
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
function getCookie() {
|
|
118
|
-
return globalContext?.cookie;
|
|
98
|
+
return Object.fromEntries(
|
|
99
|
+
Object.entries(obj).filter(
|
|
100
|
+
([, value]) => value !== null && value !== void 0
|
|
101
|
+
)
|
|
102
|
+
);
|
|
119
103
|
}
|
|
120
|
-
function
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const [, val] = c.split("=");
|
|
127
|
-
if (val) {
|
|
128
|
-
updatedCookie.push(c);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
const cookie = mergeCookies(updatedCookie);
|
|
132
|
-
globalContext = { ...globalContext, cookie };
|
|
104
|
+
function makeRestUrl(config, path, qp) {
|
|
105
|
+
const url = config.apiUrl || NILEDB_API_URL;
|
|
106
|
+
if (!url) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
"An API url is required. Set it via NILEDB_API_URL. Was auto configuration run?"
|
|
109
|
+
);
|
|
133
110
|
}
|
|
111
|
+
const params = new URLSearchParams(
|
|
112
|
+
filterNullUndefined(qp)
|
|
113
|
+
);
|
|
114
|
+
const strParams = params.toString();
|
|
115
|
+
return `${[url, path.substring(1, path.length)].join("/")}${strParams ? `?${strParams}` : ""}`;
|
|
116
|
+
}
|
|
117
|
+
function urlMatches(requestUrl, route20) {
|
|
118
|
+
const url = new URL(requestUrl);
|
|
119
|
+
return url.pathname.startsWith(route20);
|
|
134
120
|
}
|
|
135
|
-
function
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (!cookieString) {
|
|
139
|
-
return overrideArray.join("; ");
|
|
121
|
+
function isUUID(value) {
|
|
122
|
+
if (!value) {
|
|
123
|
+
return false;
|
|
140
124
|
}
|
|
141
|
-
|
|
142
|
-
|
|
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("; ");
|
|
125
|
+
const regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5|7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
126
|
+
return regex.test(value);
|
|
154
127
|
}
|
|
155
128
|
|
|
156
129
|
// src/api/utils/request.ts
|
|
157
130
|
async function request(url, _init, config) {
|
|
158
|
-
const { debug, info, error } =
|
|
131
|
+
const { debug, info, error } = config.logger("[REQUEST]");
|
|
159
132
|
const { request: request2, ...init } = _init;
|
|
160
133
|
const requestUrl = new URL(request2.url);
|
|
161
134
|
const updatedHeaders = new Headers({});
|
|
162
135
|
if (request2.headers.get("cookie")) {
|
|
163
136
|
updatedHeaders.set("cookie", String(request2.headers.get("cookie")));
|
|
164
137
|
}
|
|
165
|
-
if (request2.headers.get(
|
|
138
|
+
if (request2.headers.get(TENANT_COOKIE)) {
|
|
166
139
|
updatedHeaders.set(
|
|
167
|
-
|
|
168
|
-
String(request2.headers.get(
|
|
140
|
+
TENANT_COOKIE,
|
|
141
|
+
String(request2.headers.get(TENANT_COOKIE))
|
|
169
142
|
);
|
|
170
143
|
}
|
|
171
|
-
if (config.
|
|
172
|
-
updatedHeaders.set(
|
|
144
|
+
if (config.secureCookies != null) {
|
|
145
|
+
updatedHeaders.set(HEADER_SECURE_COOKIES, String(config.secureCookies));
|
|
146
|
+
} else {
|
|
147
|
+
updatedHeaders.set(
|
|
148
|
+
HEADER_SECURE_COOKIES,
|
|
149
|
+
process.env.NODE_ENV === "production" ? "true" : "false"
|
|
150
|
+
);
|
|
173
151
|
}
|
|
174
152
|
updatedHeaders.set("host", requestUrl.host);
|
|
175
|
-
if (config.
|
|
176
|
-
const cbUrl = new URL(config.
|
|
177
|
-
debug(
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
debug(`Obtained origin from config.api.origin ${config.api.origin}`);
|
|
183
|
-
updatedHeaders.set(X_NILE_ORIGIN, config.api.origin);
|
|
153
|
+
if (config.callbackUrl) {
|
|
154
|
+
const cbUrl = new URL(config.callbackUrl);
|
|
155
|
+
debug(`Obtained origin from config.callbackUrl ${config.callbackUrl}`);
|
|
156
|
+
updatedHeaders.set(HEADER_ORIGIN, cbUrl.origin);
|
|
157
|
+
} else if (config.origin) {
|
|
158
|
+
debug(`Obtained origin from config.origin ${config.origin}`);
|
|
159
|
+
updatedHeaders.set(HEADER_ORIGIN, config.origin);
|
|
184
160
|
} else {
|
|
185
|
-
|
|
186
|
-
|
|
161
|
+
const passedOrigin = request2.headers.get(HEADER_ORIGIN);
|
|
162
|
+
if (passedOrigin) {
|
|
163
|
+
updatedHeaders.set(HEADER_ORIGIN, passedOrigin);
|
|
164
|
+
} else {
|
|
165
|
+
const reqOrigin = config.routePrefix !== DEFAULT_PREFIX ? `${requestUrl.origin}${config.routePrefix}` : requestUrl.origin;
|
|
166
|
+
updatedHeaders.set(HEADER_ORIGIN, reqOrigin);
|
|
167
|
+
debug(`Obtained origin from request ${reqOrigin}`);
|
|
168
|
+
}
|
|
187
169
|
}
|
|
188
|
-
const params = { ...init
|
|
170
|
+
const params = { ...init };
|
|
189
171
|
if (params.method?.toLowerCase() === "post" || params.method?.toLowerCase() === "put") {
|
|
190
172
|
try {
|
|
191
173
|
updatedHeaders.set("content-type", "application/json");
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
|
|
174
|
+
const bodyStream = _init.body ?? _init.request?.body ?? request2.body;
|
|
175
|
+
const bodyText = await new Response(bodyStream).text();
|
|
176
|
+
try {
|
|
177
|
+
params.body = JSON.stringify(JSON.parse(bodyText));
|
|
178
|
+
} catch {
|
|
179
|
+
updatedHeaders.set("content-type", "application/x-www-form-urlencoded");
|
|
180
|
+
params.body = bodyText;
|
|
181
|
+
}
|
|
195
182
|
} catch (e) {
|
|
196
|
-
|
|
197
|
-
const initBody = await new Response(_init.request.clone().body).text();
|
|
198
|
-
const requestBody = await new Response(request2.clone().body).text();
|
|
199
|
-
params.body = initBody ?? requestBody;
|
|
183
|
+
error("Failed to parse request body");
|
|
200
184
|
}
|
|
201
185
|
}
|
|
186
|
+
params.headers = updatedHeaders;
|
|
202
187
|
const fullUrl = `${url}${requestUrl.search}`;
|
|
188
|
+
if (config.debug) {
|
|
189
|
+
params.headers.set("request-id", crypto.randomUUID());
|
|
190
|
+
params.cache = "no-store";
|
|
191
|
+
}
|
|
192
|
+
await config.extensionCtx?.handleOnRequest(config, _init, params);
|
|
203
193
|
try {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
);
|
|
194
|
+
const res = await fetch(fullUrl, {
|
|
195
|
+
...params
|
|
196
|
+
}).catch((e) => {
|
|
197
|
+
error("An error has occurred in the fetch", {
|
|
198
|
+
message: e.message,
|
|
199
|
+
stack: e.stack
|
|
200
|
+
});
|
|
201
|
+
return new Response(
|
|
202
|
+
"An unexpected (most likely configuration) problem has occurred",
|
|
203
|
+
{ status: 500 }
|
|
204
|
+
);
|
|
205
|
+
});
|
|
217
206
|
const loggingRes = typeof res?.clone === "function" ? res?.clone() : null;
|
|
218
207
|
info(`[${params.method ?? "GET"}] ${fullUrl}`, {
|
|
219
208
|
status: res?.status,
|
|
220
209
|
statusText: res?.statusText,
|
|
221
210
|
text: await loggingRes?.text()
|
|
222
211
|
});
|
|
223
|
-
setCookie(res?.headers);
|
|
224
212
|
return res;
|
|
225
213
|
} catch (e) {
|
|
226
214
|
if (e instanceof Error) {
|
|
@@ -238,10 +226,10 @@ async function request(url, _init, config) {
|
|
|
238
226
|
|
|
239
227
|
// src/api/utils/auth.ts
|
|
240
228
|
async function auth(req, config) {
|
|
241
|
-
const { info, error } =
|
|
229
|
+
const { info, error } = config.logger("[nileauth]");
|
|
242
230
|
info("checking auth");
|
|
243
|
-
const sessionUrl = `${config.
|
|
244
|
-
info(`using session${sessionUrl}`);
|
|
231
|
+
const sessionUrl = `${config.apiUrl}/auth/session`;
|
|
232
|
+
info(`using session ${sessionUrl}`);
|
|
245
233
|
req.headers.delete("content-length");
|
|
246
234
|
const res = await request(sessionUrl, { request: req }, config);
|
|
247
235
|
if (!res) {
|
|
@@ -260,1009 +248,368 @@ async function auth(req, config) {
|
|
|
260
248
|
return void 0;
|
|
261
249
|
}
|
|
262
250
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
};
|
|
270
|
-
var getSecureCookies = (cfg) => {
|
|
271
|
-
const { config } = cfg;
|
|
272
|
-
if (config?.api?.secureCookies != null) {
|
|
273
|
-
return config?.api?.secureCookies;
|
|
251
|
+
|
|
252
|
+
// src/api/routes/me/index.ts
|
|
253
|
+
var key = "ME";
|
|
254
|
+
async function route(request2, config) {
|
|
255
|
+
const url = apiRoutes(config)[key];
|
|
256
|
+
if (request2.method === "GET") {
|
|
257
|
+
return await GET(url, { request: request2 }, config);
|
|
274
258
|
}
|
|
275
|
-
if (
|
|
276
|
-
return
|
|
259
|
+
if (request2.method === "PUT") {
|
|
260
|
+
return await PUT(url, { request: request2 }, config);
|
|
277
261
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
const { info } = Logger(config, "[databaseId]");
|
|
283
|
-
if (stringCheck(config?.databaseId)) {
|
|
284
|
-
logger && info(`${logger}[config] ${config?.databaseId}`);
|
|
285
|
-
return String(config?.databaseId);
|
|
286
|
-
}
|
|
287
|
-
const dbFromEnv = stringCheck(process.env.NILEDB_ID);
|
|
288
|
-
if (dbFromEnv) {
|
|
289
|
-
logger && info(`${logger}[NILEDB_ID] ${dbFromEnv}`);
|
|
290
|
-
return dbFromEnv;
|
|
291
|
-
}
|
|
292
|
-
const dbId = stringCheck(process.env.NILEDB_API_URL);
|
|
293
|
-
if (dbId) {
|
|
294
|
-
try {
|
|
295
|
-
const pgUrl = new URL(dbId);
|
|
296
|
-
return pgUrl.pathname.split("/")[3];
|
|
297
|
-
} catch (e) {
|
|
262
|
+
if (request2.method === "DELETE") {
|
|
263
|
+
const session = await auth(request2, config);
|
|
264
|
+
if (!session) {
|
|
265
|
+
return new Response(null, { status: 401 });
|
|
298
266
|
}
|
|
267
|
+
return await DELETE(url, { request: request2 }, config);
|
|
299
268
|
}
|
|
300
|
-
return
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
|
|
315
|
-
if (pg2) {
|
|
316
|
-
try {
|
|
317
|
-
const url = new URL(pg2);
|
|
318
|
-
if (url.username) {
|
|
319
|
-
return url.username;
|
|
320
|
-
}
|
|
321
|
-
} catch (e) {
|
|
322
|
-
}
|
|
269
|
+
return new Response("method not allowed", { status: 405 });
|
|
270
|
+
}
|
|
271
|
+
function matches(configRoutes, request2) {
|
|
272
|
+
return urlMatches(request2.url, configRoutes[key]);
|
|
273
|
+
}
|
|
274
|
+
async function fetchMe(config, method, body) {
|
|
275
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/me" /* ME */}`;
|
|
276
|
+
const init = {
|
|
277
|
+
headers: config.headers,
|
|
278
|
+
method: method ?? "GET"
|
|
279
|
+
};
|
|
280
|
+
if (method === "PUT") {
|
|
281
|
+
init.body = body;
|
|
323
282
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
const { config, logger } = cfg;
|
|
328
|
-
const log = logProtector(logger);
|
|
329
|
-
const { info } = Logger(config, "[password]");
|
|
330
|
-
if (stringCheck(config?.password)) {
|
|
331
|
-
log && info(`${logger}[config] ***`);
|
|
332
|
-
return String(config?.password);
|
|
283
|
+
const req = new Request(clientUrl, init);
|
|
284
|
+
if (method === "DELETE") {
|
|
285
|
+
return await config.handlers.DELETE(req);
|
|
333
286
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
logger && info(`${logger}[NILEDB_PASSWORD] ***`);
|
|
337
|
-
return pass;
|
|
287
|
+
if (method === "PUT") {
|
|
288
|
+
return await config.handlers.PUT(req);
|
|
338
289
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
290
|
+
return await config.handlers.GET(req);
|
|
291
|
+
}
|
|
292
|
+
async function DELETE(url, init, config) {
|
|
293
|
+
init.method = "DELETE";
|
|
294
|
+
return await request(url, init, config);
|
|
295
|
+
}
|
|
296
|
+
async function PUT(url, init, config) {
|
|
297
|
+
init.method = "PUT";
|
|
298
|
+
return await request(url, init, config);
|
|
299
|
+
}
|
|
300
|
+
async function GET(url, init, config) {
|
|
301
|
+
const res = await request(url, init, config);
|
|
302
|
+
return res;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// src/utils/fetch.ts
|
|
306
|
+
function getTokenFromCookie(headers, cookieKey) {
|
|
307
|
+
const cookie = headers.get("cookie")?.split("; ");
|
|
308
|
+
const _cookies = {};
|
|
309
|
+
if (cookie) {
|
|
310
|
+
for (const parts of cookie) {
|
|
311
|
+
const cookieParts = parts.split("=");
|
|
312
|
+
const _cookie = cookieParts.slice(1).join("=");
|
|
313
|
+
const name = cookieParts[0];
|
|
314
|
+
_cookies[name] = _cookie;
|
|
347
315
|
}
|
|
348
316
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
logger && info(`${logger}[config] ${config?.api?.token}`);
|
|
356
|
-
return String(config?.api?.token);
|
|
357
|
-
}
|
|
358
|
-
const token = stringCheck(process.env.NILEDB_TOKEN);
|
|
359
|
-
if (token) {
|
|
360
|
-
logger && info(`${logger}[NILEDB_TOKEN] ${token}`);
|
|
361
|
-
return token;
|
|
362
|
-
}
|
|
363
|
-
return void 0;
|
|
364
|
-
};
|
|
365
|
-
var getDatabaseName = (cfg) => {
|
|
366
|
-
const { config, logger } = cfg;
|
|
367
|
-
const { info } = Logger(config, "[databaseName]");
|
|
368
|
-
if (stringCheck(config?.databaseName)) {
|
|
369
|
-
logger && info(`${logger}[config] ${config?.databaseName}`);
|
|
370
|
-
return String(config?.databaseName);
|
|
371
|
-
}
|
|
372
|
-
const name = stringCheck(process.env.NILEDB_NAME);
|
|
373
|
-
if (name) {
|
|
374
|
-
logger && info(`${logger}[NILEDB_NAME] ${name}`);
|
|
375
|
-
return name;
|
|
376
|
-
}
|
|
377
|
-
if (process.env.NILEDB_POSTGRES_URL) {
|
|
378
|
-
try {
|
|
379
|
-
const pgUrl = new URL(process.env.NILEDB_POSTGRES_URL);
|
|
380
|
-
return pgUrl.pathname.substring(1);
|
|
381
|
-
} catch (e) {
|
|
317
|
+
if (cookie) {
|
|
318
|
+
for (const parts of cookie) {
|
|
319
|
+
const cookieParts = parts.split("=");
|
|
320
|
+
const _cookie = cookieParts.slice(1).join("=");
|
|
321
|
+
const name = cookieParts[0];
|
|
322
|
+
_cookies[name] = _cookie;
|
|
382
323
|
}
|
|
383
324
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
var getTenantId = (cfg) => {
|
|
387
|
-
const { config, logger } = cfg;
|
|
388
|
-
const { info } = Logger(config, "[tenantId]");
|
|
389
|
-
if (stringCheck(config?.tenantId)) {
|
|
390
|
-
logger && info(`${logger}[config] ${config?.tenantId}`);
|
|
391
|
-
return String(config?.tenantId);
|
|
392
|
-
}
|
|
393
|
-
if (stringCheck(process.env.NILEDB_TENANT)) {
|
|
394
|
-
logger && info(`${logger}[NILEDB_TENANT] ${process.env.NILEDB_TENANT}`);
|
|
395
|
-
return String(process.env.NILEDB_TENANT);
|
|
396
|
-
}
|
|
397
|
-
return null;
|
|
398
|
-
};
|
|
399
|
-
var getCookieKey = (cfg) => {
|
|
400
|
-
const { config, logger } = cfg;
|
|
401
|
-
const { info } = Logger(config, "[cookieKey]");
|
|
402
|
-
if (stringCheck(config?.api?.cookieKey)) {
|
|
403
|
-
logger && info(`${logger}[config] ${config?.api?.cookieKey}`);
|
|
404
|
-
return String(config?.api?.cookieKey);
|
|
405
|
-
}
|
|
406
|
-
if (stringCheck(process.env.NILEDB_COOKIE_KEY)) {
|
|
407
|
-
logger && info(`${logger}[NILEDB_COOKIE_KEY] ${process.env.NILEDB_COOKIE_KEY}`);
|
|
408
|
-
return String(process.env.NILEDB_COOKIE_KEY);
|
|
409
|
-
}
|
|
410
|
-
return "token";
|
|
411
|
-
};
|
|
412
|
-
var getBasePath = (cfg) => {
|
|
413
|
-
const { config, logger } = cfg;
|
|
414
|
-
const { warn, info, error } = Logger(config, "[basePath]");
|
|
415
|
-
const basePath = config?.api?.basePath;
|
|
416
|
-
if (stringCheck(basePath)) {
|
|
417
|
-
logger && info(`${logger}[config] ${basePath}`);
|
|
418
|
-
return basePath;
|
|
419
|
-
}
|
|
420
|
-
const envUrl = stringCheck(process.env.NILEDB_API_URL);
|
|
421
|
-
if (envUrl) {
|
|
422
|
-
logger && info(`${logger}[NILEDB_API_URL] ${process.env.NILEDB_API_URL}`);
|
|
423
|
-
try {
|
|
424
|
-
const apiUrl = new URL(envUrl);
|
|
425
|
-
return apiUrl.href;
|
|
426
|
-
} catch (e) {
|
|
427
|
-
if (e instanceof Error) {
|
|
428
|
-
error(e.stack);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
325
|
+
{
|
|
326
|
+
return _cookies[cookieKey];
|
|
431
327
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
328
|
+
}
|
|
329
|
+
function getTenantFromHttp(headers, config) {
|
|
330
|
+
const cookieTenant = getTokenFromCookie(headers, TENANT_COOKIE);
|
|
331
|
+
return cookieTenant ? cookieTenant : config?.tenantId;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// src/api/routes/users/POST.ts
|
|
335
|
+
async function POST(config, init) {
|
|
336
|
+
init.body = init.request.body;
|
|
337
|
+
init.method = "POST";
|
|
338
|
+
const yurl = new URL(init.request.url);
|
|
339
|
+
const tenantId = yurl.searchParams.get("tenantId");
|
|
340
|
+
const newTenantName = yurl.searchParams.get("newTenantName");
|
|
341
|
+
const tenant = tenantId ?? getTenantFromHttp(init.request.headers, config);
|
|
342
|
+
const url = apiRoutes(config).USERS({ tenantId: tenant, newTenantName });
|
|
343
|
+
return await request(url, init, config);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// src/api/routes/users/GET.ts
|
|
347
|
+
async function GET2(config, init, log) {
|
|
348
|
+
const yurl = new URL(init.request.url);
|
|
349
|
+
const tenantId = yurl.searchParams.get("tenantId");
|
|
350
|
+
const tenant = tenantId ?? getTenantFromHttp(init.request.headers, config);
|
|
351
|
+
if (!tenant) {
|
|
352
|
+
log("[GET] No tenant id provided.");
|
|
353
|
+
return new Response(null, { status: 404 });
|
|
445
354
|
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
355
|
+
init.method = "GET";
|
|
356
|
+
const url = apiRoutes(config).TENANT_USERS(tenant);
|
|
357
|
+
return await request(url, init, config);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// src/api/routes/users/[userId]/PUT.ts
|
|
361
|
+
async function PUT2(config, init) {
|
|
362
|
+
init.body = init.request.body;
|
|
363
|
+
init.method = "PUT";
|
|
364
|
+
const [userId] = new URL(init.request.url).pathname.split("/").reverse();
|
|
365
|
+
const url = apiRoutes(config).USER(userId);
|
|
366
|
+
return await request(url, init, config);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/api/routes/users/index.ts
|
|
370
|
+
var key2 = "USERS";
|
|
371
|
+
async function route2(request2, config) {
|
|
372
|
+
const { info } = config.logger(`[ROUTES][${key2}]`);
|
|
373
|
+
switch (request2.method) {
|
|
374
|
+
case "GET":
|
|
375
|
+
return await GET2(config, { request: request2 }, info);
|
|
376
|
+
case "POST":
|
|
377
|
+
return await POST(config, { request: request2 });
|
|
378
|
+
case "PUT":
|
|
379
|
+
return await PUT2(config, { request: request2 });
|
|
380
|
+
default:
|
|
381
|
+
return new Response("method not allowed", { status: 405 });
|
|
454
382
|
}
|
|
455
|
-
logger && info(`${logger}[default] db.thenile.dev`);
|
|
456
|
-
return "db.thenile.dev";
|
|
457
383
|
}
|
|
458
|
-
function
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
384
|
+
function matches2(configRoutes, request2) {
|
|
385
|
+
return urlMatches(request2.url, configRoutes[key2]);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// src/api/routes/tenants/[tenantId]/users/GET.ts
|
|
389
|
+
async function GET3(config, init) {
|
|
390
|
+
const yurl = new URL(init.request.url);
|
|
391
|
+
const [, tenantId] = yurl.pathname.split("/").reverse();
|
|
392
|
+
const url = `${apiRoutes(config).TENANT_USERS(tenantId)}`;
|
|
393
|
+
return await request(url, init, config);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// src/api/routes/tenants/[tenantId]/users/POST.ts
|
|
397
|
+
async function POST2(config, init) {
|
|
398
|
+
const session = await auth(init.request, config);
|
|
399
|
+
if (!session) {
|
|
400
|
+
return new Response(null, { status: 401 });
|
|
464
401
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
402
|
+
const yurl = new URL(init.request.url);
|
|
403
|
+
const [, tenantId] = yurl.pathname.split("/").reverse();
|
|
404
|
+
init.body = JSON.stringify({ email: session.email });
|
|
405
|
+
init.method = "POST";
|
|
406
|
+
const url = apiRoutes(config).TENANT_USERS(tenantId);
|
|
407
|
+
return await request(url, init, config);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// src/api/routes/tenants/[tenantId]/users/index.ts
|
|
411
|
+
var key3 = "TENANT_USERS";
|
|
412
|
+
async function route3(request2, config) {
|
|
413
|
+
const { info } = config.logger(`[ROUTES][${key3}]`);
|
|
414
|
+
const yurl = new URL(request2.url);
|
|
415
|
+
const [, tenantId] = yurl.pathname.split("/").reverse();
|
|
416
|
+
if (!tenantId) {
|
|
417
|
+
info("No tenant id found in path");
|
|
418
|
+
return new Response(null, { status: 404 });
|
|
468
419
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
} catch (e) {
|
|
477
|
-
}
|
|
420
|
+
switch (request2.method) {
|
|
421
|
+
case "GET":
|
|
422
|
+
return await GET3(config, { request: request2 });
|
|
423
|
+
case "POST":
|
|
424
|
+
return await POST2(config, { request: request2 });
|
|
425
|
+
default:
|
|
426
|
+
return new Response("method not allowed", { status: 405 });
|
|
478
427
|
}
|
|
479
|
-
logger && info(`${logger}[default] 5432`);
|
|
480
|
-
return 5432;
|
|
481
428
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
if (
|
|
487
|
-
|
|
429
|
+
function matches3(configRoutes, request2) {
|
|
430
|
+
const url = new URL(request2.url);
|
|
431
|
+
const [userId, possibleTenantId, tenantId] = url.pathname.split("/").reverse();
|
|
432
|
+
let route20 = configRoutes[key3].replace("{tenantId}", tenantId).replace("{userId}", userId);
|
|
433
|
+
if (userId === "users") {
|
|
434
|
+
route20 = configRoutes[key3].replace("{tenantId}", possibleTenantId);
|
|
488
435
|
}
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
routePrefix;
|
|
498
|
-
secureCookies;
|
|
499
|
-
origin;
|
|
500
|
-
/**
|
|
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
|
|
502
|
-
* If this is set, any `callbackUrl` from the client will be ignored.
|
|
503
|
-
*/
|
|
504
|
-
callbackUrl;
|
|
505
|
-
#token;
|
|
506
|
-
constructor(config, logger) {
|
|
507
|
-
const envVarConfig = { config, logger };
|
|
508
|
-
this.cookieKey = getCookieKey(envVarConfig);
|
|
509
|
-
this.#token = getToken(envVarConfig);
|
|
510
|
-
this.callbackUrl = getCallbackUrl(envVarConfig);
|
|
511
|
-
this.secureCookies = getSecureCookies(envVarConfig);
|
|
512
|
-
this.basePath = getBasePath(envVarConfig);
|
|
513
|
-
this.routes = config?.api?.routes;
|
|
514
|
-
this.routePrefix = config?.api?.routePrefix;
|
|
515
|
-
this.origin = config?.api?.origin;
|
|
436
|
+
return urlMatches(request2.url, route20);
|
|
437
|
+
}
|
|
438
|
+
async function fetchTenantUsers(config, method, payload) {
|
|
439
|
+
const { body, params } = {};
|
|
440
|
+
if (!config.tenantId) {
|
|
441
|
+
throw new Error(
|
|
442
|
+
"Unable to fetch the user's tenants, the tenantId context is missing. Call nile.setContext({ tenantId })"
|
|
443
|
+
);
|
|
516
444
|
}
|
|
517
|
-
|
|
518
|
-
|
|
445
|
+
if (!isUUID(config.tenantId)) {
|
|
446
|
+
config.logger("fetchTenantUsers").warn(
|
|
447
|
+
"nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
|
|
448
|
+
);
|
|
519
449
|
}
|
|
520
|
-
|
|
521
|
-
|
|
450
|
+
const q = new URLSearchParams();
|
|
451
|
+
if (params?.newTenantName) {
|
|
452
|
+
q.set("newTenantName", params.newTenantName);
|
|
522
453
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
user;
|
|
526
|
-
password;
|
|
527
|
-
databaseId;
|
|
528
|
-
databaseName;
|
|
529
|
-
logger;
|
|
530
|
-
debug;
|
|
531
|
-
db;
|
|
532
|
-
api;
|
|
533
|
-
#tenantId;
|
|
534
|
-
#userId;
|
|
535
|
-
get tenantId() {
|
|
536
|
-
return this.#tenantId;
|
|
537
|
-
}
|
|
538
|
-
set tenantId(value) {
|
|
539
|
-
this.#tenantId = value;
|
|
540
|
-
}
|
|
541
|
-
get userId() {
|
|
542
|
-
return this.#userId;
|
|
543
|
-
}
|
|
544
|
-
set userId(value) {
|
|
545
|
-
this.#userId = value;
|
|
546
|
-
}
|
|
547
|
-
constructor(config, logger) {
|
|
548
|
-
const envVarConfig = { config, logger };
|
|
549
|
-
this.user = getUsername(envVarConfig);
|
|
550
|
-
this.logger = config?.logger;
|
|
551
|
-
this.password = getPassword(envVarConfig);
|
|
552
|
-
if (process.env.NODE_ENV !== "TEST") {
|
|
553
|
-
if (!this.user) {
|
|
554
|
-
throw new Error(
|
|
555
|
-
"User is required. Set NILEDB_USER as an environment variable or set `user` in the config options."
|
|
556
|
-
);
|
|
557
|
-
}
|
|
558
|
-
if (!this.password) {
|
|
559
|
-
throw new Error(
|
|
560
|
-
"Password is required. Set NILEDB_PASSWORD as an environment variable or set `password` in the config options."
|
|
561
|
-
);
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
this.databaseId = getDatabaseId(envVarConfig);
|
|
565
|
-
this.databaseName = getDatabaseName(envVarConfig);
|
|
566
|
-
this.#tenantId = getTenantId(envVarConfig);
|
|
567
|
-
this.debug = Boolean(config?.debug);
|
|
568
|
-
this.#userId = config?.userId;
|
|
569
|
-
const { host, port, ...dbConfig } = config?.db ?? {};
|
|
570
|
-
const configuredHost = host ?? getDbHost(envVarConfig);
|
|
571
|
-
const configuredPort = port ?? getDbPort(envVarConfig);
|
|
572
|
-
this.api = new ApiConfig(config, logger);
|
|
573
|
-
this.db = {
|
|
574
|
-
user: this.user,
|
|
575
|
-
password: this.password,
|
|
576
|
-
host: configuredHost,
|
|
577
|
-
port: configuredPort,
|
|
578
|
-
...dbConfig
|
|
579
|
-
};
|
|
580
|
-
if (this.databaseName) {
|
|
581
|
-
this.db.database = this.databaseName;
|
|
582
|
-
}
|
|
454
|
+
if (params?.tenantId) {
|
|
455
|
+
q.set("tenantId", params.tenantId);
|
|
583
456
|
}
|
|
584
|
-
}
|
|
457
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/users" /* TENANT_USERS */.replace(
|
|
458
|
+
"{tenantId}",
|
|
459
|
+
config.tenantId
|
|
460
|
+
)}`;
|
|
461
|
+
const m = method;
|
|
462
|
+
const init = {
|
|
463
|
+
method: m,
|
|
464
|
+
headers: config.headers
|
|
465
|
+
};
|
|
466
|
+
const req = new Request(clientUrl, init);
|
|
467
|
+
return await config.handlers[m](req);
|
|
468
|
+
}
|
|
585
469
|
|
|
586
|
-
// src/
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
if (callbackList) {
|
|
593
|
-
for (const callback of callbackList) {
|
|
594
|
-
callback(value);
|
|
595
|
-
}
|
|
596
|
-
}
|
|
470
|
+
// src/api/routes/tenants/[tenantId]/invite/PUT.ts
|
|
471
|
+
async function PUT3(config, init) {
|
|
472
|
+
const yurl = new URL(init.request.url);
|
|
473
|
+
const [, tenantId] = yurl.pathname.split("/").reverse();
|
|
474
|
+
if (!tenantId) {
|
|
475
|
+
return new Response(null, { status: 404 });
|
|
597
476
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
if (!this.events[eventName]) {
|
|
601
|
-
this.events[eventName] = [];
|
|
602
|
-
}
|
|
603
|
-
this.events[eventName].push(callback);
|
|
477
|
+
if (yurl.searchParams.size > 0) {
|
|
478
|
+
init.body = new URLSearchParams(yurl.searchParams).toString();
|
|
604
479
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
}
|
|
615
|
-
if (callbackList.length === 0) {
|
|
616
|
-
delete this.events[eventName];
|
|
617
|
-
}
|
|
480
|
+
init.method = "PUT";
|
|
481
|
+
const url = `${apiRoutes(config).INVITE(tenantId)}`;
|
|
482
|
+
const res = await request(url, init, config);
|
|
483
|
+
const location = res?.headers.get("location");
|
|
484
|
+
if (location) {
|
|
485
|
+
return new Response(res?.body, {
|
|
486
|
+
status: 302,
|
|
487
|
+
headers: res?.headers
|
|
488
|
+
});
|
|
618
489
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
eventer.publish("tenantId" /* Tenant */, tenantId);
|
|
623
|
-
};
|
|
624
|
-
var watchTenantId = (cb) => eventer.subscribe("tenantId" /* Tenant */, cb);
|
|
625
|
-
var updateUserId = (userId) => {
|
|
626
|
-
eventer.publish("userId" /* User */, userId);
|
|
627
|
-
};
|
|
628
|
-
var watchUserId = (cb) => eventer.subscribe("userId" /* User */, cb);
|
|
629
|
-
var watchToken = (cb) => eventer.subscribe("token" /* Token */, cb);
|
|
630
|
-
var watchEvictPool = (cb) => eventer.subscribe("EvictPool" /* EvictPool */, cb);
|
|
631
|
-
var evictPool = (val) => {
|
|
632
|
-
eventer.publish("EvictPool" /* EvictPool */, val);
|
|
633
|
-
};
|
|
634
|
-
|
|
635
|
-
// src/db/PoolProxy.ts
|
|
636
|
-
function createProxyForPool(pool, config) {
|
|
637
|
-
const { info, error } = Logger(config, "[pool]");
|
|
638
|
-
return new Proxy(pool, {
|
|
639
|
-
get(target, property) {
|
|
640
|
-
if (property === "query") {
|
|
641
|
-
if (!config.db.connectionString) {
|
|
642
|
-
if (!config.user || !config.password) {
|
|
643
|
-
error(
|
|
644
|
-
"Cannot connect to the database. User and/or password are missing. Generate them at https://console.thenile.dev"
|
|
645
|
-
);
|
|
646
|
-
} else if (!config.db.database) {
|
|
647
|
-
error(
|
|
648
|
-
"Database name is missing from the config. Call `nile.init()` or set NILEDB_ID in your .env"
|
|
649
|
-
);
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
const caller = target[property];
|
|
653
|
-
return function query(...args) {
|
|
654
|
-
info("query", ...args);
|
|
655
|
-
const called = caller.apply(this, args);
|
|
656
|
-
return called;
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
return target[property];
|
|
660
|
-
}
|
|
490
|
+
return new Response(res?.body, {
|
|
491
|
+
status: res?.status,
|
|
492
|
+
headers: res?.headers
|
|
661
493
|
});
|
|
662
494
|
}
|
|
663
495
|
|
|
664
|
-
// src/
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
tenantId;
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
config;
|
|
671
|
-
timer;
|
|
672
|
-
constructor(config, id) {
|
|
673
|
-
const { warn, info, debug } = Logger(config, "[NileInstance]");
|
|
674
|
-
this.id = id;
|
|
675
|
-
const poolConfig = {
|
|
676
|
-
min: 0,
|
|
677
|
-
max: 10,
|
|
678
|
-
idleTimeoutMillis: 3e4,
|
|
679
|
-
...config.db
|
|
680
|
-
};
|
|
681
|
-
const { afterCreate, ...remaining } = poolConfig;
|
|
682
|
-
config.db = poolConfig;
|
|
683
|
-
this.config = config;
|
|
684
|
-
const cloned = { ...this.config.db };
|
|
685
|
-
cloned.password = "***";
|
|
686
|
-
debug(`Connection pool config ${JSON.stringify(cloned)}`);
|
|
687
|
-
this.pool = createProxyForPool(new pg__default.default.Pool(remaining), this.config);
|
|
688
|
-
if (typeof afterCreate === "function") {
|
|
689
|
-
warn(
|
|
690
|
-
"Providing an pool configuration will stop automatic tenant context setting."
|
|
691
|
-
);
|
|
692
|
-
}
|
|
693
|
-
this.startTimeout();
|
|
694
|
-
this.pool.on("connect", async (client) => {
|
|
695
|
-
debug(`pool connected ${this.id}`);
|
|
696
|
-
this.startTimeout();
|
|
697
|
-
const afterCreate2 = makeAfterCreate(
|
|
698
|
-
config,
|
|
699
|
-
`${this.id}-${this.timer}`
|
|
700
|
-
);
|
|
701
|
-
afterCreate2(client, (err) => {
|
|
702
|
-
const { error } = Logger(config, "[after create callback]");
|
|
703
|
-
if (err) {
|
|
704
|
-
clearTimeout(this.timer);
|
|
705
|
-
error("after create failed", {
|
|
706
|
-
message: err.message,
|
|
707
|
-
stack: err.stack
|
|
708
|
-
});
|
|
709
|
-
evictPool(this.id);
|
|
710
|
-
}
|
|
711
|
-
});
|
|
712
|
-
});
|
|
713
|
-
this.pool.on("error", (err) => {
|
|
714
|
-
clearTimeout(this.timer);
|
|
715
|
-
info(`pool ${this.id} failed`, {
|
|
716
|
-
message: err.message,
|
|
717
|
-
stack: err.stack
|
|
718
|
-
});
|
|
719
|
-
evictPool(this.id);
|
|
720
|
-
});
|
|
721
|
-
this.pool.on("release", (destroy) => {
|
|
722
|
-
if (destroy) {
|
|
723
|
-
clearTimeout(this.timer);
|
|
724
|
-
evictPool(this.id);
|
|
725
|
-
debug(`destroying pool ${this.id}`);
|
|
726
|
-
}
|
|
727
|
-
});
|
|
728
|
-
}
|
|
729
|
-
startTimeout() {
|
|
730
|
-
const { debug } = Logger(this.config, "[NileInstance]");
|
|
731
|
-
if (this.timer) {
|
|
732
|
-
clearTimeout(this.timer);
|
|
733
|
-
}
|
|
734
|
-
this.timer = setTimeout(() => {
|
|
735
|
-
debug(
|
|
736
|
-
`Pool reached idleTimeoutMillis. ${this.id} evicted after ${Number(this.config.db.idleTimeoutMillis) ?? 3e4}ms`
|
|
737
|
-
);
|
|
738
|
-
this.pool.end(() => {
|
|
739
|
-
clearTimeout(this.timer);
|
|
740
|
-
evictPool(this.id);
|
|
741
|
-
});
|
|
742
|
-
}, Number(this.config.db.idleTimeoutMillis) ?? 3e4);
|
|
743
|
-
}
|
|
744
|
-
shutdown() {
|
|
745
|
-
const { debug } = Logger(this.config, "[NileInstance]");
|
|
746
|
-
debug(`attempting to shut down ${this.id}`);
|
|
747
|
-
clearTimeout(this.timer);
|
|
748
|
-
this.pool.end(() => {
|
|
749
|
-
debug(`${this.id} has been shut down`);
|
|
750
|
-
});
|
|
496
|
+
// src/api/routes/tenants/[tenantId]/invite/POST.ts
|
|
497
|
+
async function POST3(config, init) {
|
|
498
|
+
const yurl = new URL(init.request.url);
|
|
499
|
+
const [, tenantId] = yurl.pathname.split("/").reverse();
|
|
500
|
+
if (!tenantId) {
|
|
501
|
+
return new Response(null, { status: 404 });
|
|
751
502
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
return (conn, done) => {
|
|
757
|
-
conn.on("error", function errorHandler(e) {
|
|
758
|
-
error(`Connection ${id} was terminated by server`, {
|
|
759
|
-
message: e.message,
|
|
760
|
-
stack: e.stack
|
|
761
|
-
});
|
|
762
|
-
done(e, conn);
|
|
763
|
-
});
|
|
764
|
-
if (config.tenantId) {
|
|
765
|
-
const query = [`SET nile.tenant_id = '${config.tenantId}'`];
|
|
766
|
-
if (config.userId) {
|
|
767
|
-
if (!config.tenantId) {
|
|
768
|
-
warn("A user id cannot be set in context without a tenant id");
|
|
769
|
-
}
|
|
770
|
-
query.push(`SET nile.user_id = '${config.userId}'`);
|
|
771
|
-
}
|
|
772
|
-
conn.query(query.join(";"), function(err) {
|
|
773
|
-
if (err) {
|
|
774
|
-
error("query connection failed", {
|
|
775
|
-
cause: err.cause,
|
|
776
|
-
stack: err.stack,
|
|
777
|
-
message: err.message,
|
|
778
|
-
name: err.name,
|
|
779
|
-
id
|
|
780
|
-
});
|
|
781
|
-
} else {
|
|
782
|
-
if (query.length === 1) {
|
|
783
|
-
debug(`connection context set: tenantId=${config.tenantId}`);
|
|
784
|
-
}
|
|
785
|
-
if (query.length === 2) {
|
|
786
|
-
debug(
|
|
787
|
-
`connection context set: tenantId=${config.tenantId} userId=${config.userId}`
|
|
788
|
-
);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
done(err, conn);
|
|
792
|
-
});
|
|
793
|
-
}
|
|
794
|
-
done(null, conn);
|
|
795
|
-
};
|
|
503
|
+
init.method = "POST";
|
|
504
|
+
init.body = init.request.body;
|
|
505
|
+
const url = `${apiRoutes(config).INVITE(tenantId)}`;
|
|
506
|
+
return await request(url, init, config);
|
|
796
507
|
}
|
|
797
508
|
|
|
798
|
-
// src/
|
|
799
|
-
var
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
return
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
}
|
|
812
|
-
constructor(config) {
|
|
813
|
-
this.cleared = false;
|
|
814
|
-
this.connections = /* @__PURE__ */ new Map();
|
|
815
|
-
this.poolWatcherFn = this.poolWatcher(config);
|
|
816
|
-
watchEvictPool(this.poolWatcherFn);
|
|
817
|
-
}
|
|
818
|
-
poolWatcher = (config) => (id) => {
|
|
819
|
-
const { info, warn } = Logger(config, "[DBManager]");
|
|
820
|
-
if (id && this.connections.has(id)) {
|
|
821
|
-
info(`Removing ${id} from db connection pool.`);
|
|
822
|
-
const connection = this.connections.get(id);
|
|
823
|
-
connection?.shutdown();
|
|
824
|
-
this.connections.delete(id);
|
|
825
|
-
} else {
|
|
826
|
-
warn(`missed eviction of ${id}`);
|
|
827
|
-
}
|
|
828
|
-
};
|
|
829
|
-
getConnection = (config) => {
|
|
830
|
-
const { info } = Logger(config, "[DBManager]");
|
|
831
|
-
const id = this.makeId(config.tenantId, config.userId);
|
|
832
|
-
const existing = this.connections.get(id);
|
|
833
|
-
info(`# of instances: ${this.connections.size}`);
|
|
834
|
-
if (existing) {
|
|
835
|
-
info(`returning existing ${id}`);
|
|
836
|
-
existing.startTimeout();
|
|
837
|
-
return existing.pool;
|
|
838
|
-
}
|
|
839
|
-
const newOne = new NileInstance_default(new Config(config), id);
|
|
840
|
-
this.connections.set(id, newOne);
|
|
841
|
-
info(`created new ${id}`);
|
|
842
|
-
info(`# of instances: ${this.connections.size}`);
|
|
843
|
-
if (this.cleared) {
|
|
844
|
-
this.cleared = false;
|
|
845
|
-
}
|
|
846
|
-
return newOne.pool;
|
|
847
|
-
};
|
|
848
|
-
clear = (config) => {
|
|
849
|
-
const { info } = Logger(config, "[DBManager]");
|
|
850
|
-
info(`Clearing all connections ${this.connections.size}`);
|
|
851
|
-
this.cleared = true;
|
|
852
|
-
this.connections.forEach((connection) => {
|
|
853
|
-
connection.shutdown();
|
|
854
|
-
});
|
|
855
|
-
this.connections.clear();
|
|
856
|
-
};
|
|
857
|
-
};
|
|
858
|
-
|
|
859
|
-
// src/api/utils/routes/makeRestUrl.ts
|
|
860
|
-
var NILEDB_API_URL = process.env.NILEDB_API_URL;
|
|
861
|
-
function filterNullUndefined(obj) {
|
|
862
|
-
if (!obj) {
|
|
863
|
-
return void 0;
|
|
509
|
+
// src/api/routes/tenants/[tenantId]/invite/index.ts
|
|
510
|
+
var key4 = "INVITE";
|
|
511
|
+
async function route4(request2, config) {
|
|
512
|
+
switch (request2.method) {
|
|
513
|
+
// the browser is a GET, but we need to PUT it into nile-auth
|
|
514
|
+
// server side, this is a put
|
|
515
|
+
case "GET":
|
|
516
|
+
case "PUT":
|
|
517
|
+
return await PUT3(config, { request: request2 });
|
|
518
|
+
case "POST":
|
|
519
|
+
return await POST3(config, { request: request2 });
|
|
520
|
+
default:
|
|
521
|
+
return new Response("method not allowed", { status: 405 });
|
|
864
522
|
}
|
|
865
|
-
return Object.fromEntries(
|
|
866
|
-
Object.entries(obj).filter(
|
|
867
|
-
([, value]) => value !== null && value !== void 0
|
|
868
|
-
)
|
|
869
|
-
);
|
|
870
523
|
}
|
|
871
|
-
function
|
|
872
|
-
const url =
|
|
873
|
-
|
|
524
|
+
function matches4(configRoutes, request2) {
|
|
525
|
+
const url = new URL(request2.url);
|
|
526
|
+
const [, tenantId] = url.pathname.split("/").reverse();
|
|
527
|
+
const route20 = configRoutes[key4].replace("{tenantId}", tenantId);
|
|
528
|
+
return urlMatches(request2.url, route20);
|
|
529
|
+
}
|
|
530
|
+
async function fetchInvite(config, method, body) {
|
|
531
|
+
if (!config.tenantId) {
|
|
874
532
|
throw new Error(
|
|
875
|
-
"
|
|
533
|
+
"Unable to fetch the invite for the tenant, the tenantId context is missing. Call nile.setContext({ tenantId })"
|
|
876
534
|
);
|
|
877
535
|
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
536
|
+
if (!isUUID(config.tenantId)) {
|
|
537
|
+
config.logger("fetchInvite").warn(
|
|
538
|
+
"nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
let clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/invite" /* INVITE */.replace("{tenantId}", config.tenantId)}`;
|
|
542
|
+
const m = method ?? "GET";
|
|
543
|
+
const init = {
|
|
544
|
+
method: m,
|
|
545
|
+
headers: config.headers
|
|
546
|
+
};
|
|
547
|
+
if (method === "POST" || method === "PUT") {
|
|
548
|
+
init.body = body;
|
|
549
|
+
}
|
|
550
|
+
if (method === "DELETE") {
|
|
551
|
+
clientUrl = `${clientUrl}/${body}`;
|
|
552
|
+
}
|
|
553
|
+
const req = new Request(clientUrl, init);
|
|
554
|
+
return await config.handlers[m](req);
|
|
883
555
|
}
|
|
884
556
|
|
|
885
|
-
// src/api/
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
USER_TENANTS: (userId) => makeRestUrl(config, `/users/${userId}/tenants`)
|
|
896
|
-
});
|
|
897
|
-
|
|
898
|
-
// src/api/routes/me/index.ts
|
|
899
|
-
var key = "ME";
|
|
900
|
-
async function GET(url, init, config) {
|
|
901
|
-
const res = await request(url, init, config);
|
|
902
|
-
return res;
|
|
557
|
+
// src/api/routes/tenants/[tenantId]/invites/GET.ts
|
|
558
|
+
async function GET4(config, init) {
|
|
559
|
+
const yurl = new URL(init.request.url);
|
|
560
|
+
const [, tenantId] = yurl.pathname.split("/").reverse();
|
|
561
|
+
if (!tenantId) {
|
|
562
|
+
return new Response(null, { status: 404 });
|
|
563
|
+
}
|
|
564
|
+
init.method = "GET";
|
|
565
|
+
const url = `${apiRoutes(config).INVITES(tenantId)}`;
|
|
566
|
+
return await request(url, init, config);
|
|
903
567
|
}
|
|
904
|
-
|
|
905
|
-
|
|
568
|
+
|
|
569
|
+
// src/api/routes/tenants/[tenantId]/invites/index.ts
|
|
570
|
+
var key5 = "INVITES";
|
|
571
|
+
async function route5(request2, config) {
|
|
906
572
|
switch (request2.method) {
|
|
907
573
|
case "GET":
|
|
908
|
-
return await
|
|
574
|
+
return await GET4(config, { request: request2 });
|
|
909
575
|
default:
|
|
910
576
|
return new Response("method not allowed", { status: 405 });
|
|
911
577
|
}
|
|
912
578
|
}
|
|
913
|
-
function
|
|
914
|
-
|
|
579
|
+
function matches5(configRoutes, request2) {
|
|
580
|
+
const url = new URL(request2.url);
|
|
581
|
+
const [, tenantId] = url.pathname.split("/").reverse();
|
|
582
|
+
const route20 = configRoutes[key5].replace("{tenantId}", tenantId);
|
|
583
|
+
return url.pathname.endsWith(route20);
|
|
915
584
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
this.response = new Response(body, init);
|
|
585
|
+
async function fetchInvites(config) {
|
|
586
|
+
if (!config.tenantId) {
|
|
587
|
+
throw new Error(
|
|
588
|
+
"Unable to fetch invites for the tenant, the tenantId context is missing. Call nile.setContext({ tenantId })"
|
|
589
|
+
);
|
|
922
590
|
}
|
|
923
|
-
|
|
591
|
+
if (!isUUID(config.tenantId)) {
|
|
592
|
+
config.logger("fetchInvites").warn(
|
|
593
|
+
"nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/invites" /* INVITES */.replace("{tenantId}", config.tenantId)}`;
|
|
597
|
+
const req = new Request(clientUrl, { headers: config.headers });
|
|
598
|
+
return await config.handlers.GET(req);
|
|
599
|
+
}
|
|
924
600
|
|
|
925
|
-
// src/
|
|
926
|
-
function
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
for (const parts of cookie) {
|
|
931
|
-
const cookieParts = parts.split("=");
|
|
932
|
-
const _cookie = cookieParts.slice(1).join("=");
|
|
933
|
-
const name = cookieParts[0];
|
|
934
|
-
_cookies[name] = _cookie;
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
if (cookie) {
|
|
938
|
-
for (const parts of cookie) {
|
|
939
|
-
const cookieParts = parts.split("=");
|
|
940
|
-
const _cookie = cookieParts.slice(1).join("=");
|
|
941
|
-
const name = cookieParts[0];
|
|
942
|
-
_cookies[name] = _cookie;
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
if (cookieKey) {
|
|
946
|
-
return _cookies[cookieKey];
|
|
947
|
-
}
|
|
948
|
-
return null;
|
|
949
|
-
}
|
|
950
|
-
function getTenantFromHttp(headers, config) {
|
|
951
|
-
const cookieTenant = getTokenFromCookie(headers, X_NILE_TENANT);
|
|
952
|
-
return cookieTenant ?? headers?.get(X_NILE_TENANT) ?? config?.tenantId;
|
|
953
|
-
}
|
|
954
|
-
function getUserFromHttp(headers, config) {
|
|
955
|
-
const token = getTokenFromCookie(headers, config.api.cookieKey);
|
|
956
|
-
if (token) {
|
|
957
|
-
const jwt = jose.decodeJwt(token);
|
|
958
|
-
return jwt.sub;
|
|
959
|
-
}
|
|
960
|
-
return headers?.get(X_NILE_USER_ID) ?? config.userId;
|
|
961
|
-
}
|
|
962
|
-
function makeBasicHeaders(config, url, opts) {
|
|
963
|
-
const { warn, error } = Logger(config, "[headers]");
|
|
964
|
-
const headers = new Headers(opts?.headers);
|
|
965
|
-
headers.set("content-type", "application/json; charset=utf-8");
|
|
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 })}`);
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
const cookie = headers.get("cookie");
|
|
977
|
-
if (!cookie) {
|
|
978
|
-
const contextCookie = getCookie();
|
|
979
|
-
if (contextCookie) {
|
|
980
|
-
headers.set("cookie", contextCookie);
|
|
981
|
-
} else {
|
|
982
|
-
if (!url.endsWith("/users")) {
|
|
983
|
-
error(
|
|
984
|
-
"Missing cookie header from request. Call nile.api.setContext(request) before making additional calls."
|
|
985
|
-
);
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
if (config && config.api.secureCookies != null) {
|
|
990
|
-
headers.set(X_NILE_SECURECOOKIES, String(config.api.secureCookies));
|
|
991
|
-
}
|
|
992
|
-
const savedOrigin = getOrigin();
|
|
993
|
-
if (config && config.api.origin) {
|
|
994
|
-
headers.set(X_NILE_ORIGIN, config.api.origin);
|
|
995
|
-
} else if (savedOrigin) {
|
|
996
|
-
headers.set(X_NILE_ORIGIN, savedOrigin);
|
|
997
|
-
} else {
|
|
998
|
-
warn(
|
|
999
|
-
"nile.origin missing from header, which defaults to secure cookies only."
|
|
1000
|
-
);
|
|
1001
|
-
}
|
|
1002
|
-
return headers;
|
|
1003
|
-
}
|
|
1004
|
-
async function _fetch(config, path, opts) {
|
|
1005
|
-
const { debug, error } = Logger(config, "[server]");
|
|
1006
|
-
const url = `${config.api?.basePath}${path}`;
|
|
1007
|
-
const headers = new Headers(opts?.headers);
|
|
1008
|
-
const tenantId = getTenantFromHttp(headers, config);
|
|
1009
|
-
const basicHeaders = makeBasicHeaders(config, url, opts);
|
|
1010
|
-
updateTenantId(tenantId);
|
|
1011
|
-
const userId = getUserFromHttp(headers, config);
|
|
1012
|
-
updateUserId(userId);
|
|
1013
|
-
if (url.includes("{tenantId}") && !tenantId) {
|
|
1014
|
-
return new ResponseError("tenantId is not set for request", {
|
|
1015
|
-
status: 400
|
|
1016
|
-
});
|
|
1017
|
-
}
|
|
1018
|
-
const useableUrl = url.replace("{tenantId}", encodeURIComponent(String(tenantId))).replace("{userId}", encodeURIComponent(String(userId)));
|
|
1019
|
-
debug(`[fetch] ${useableUrl}`);
|
|
1020
|
-
try {
|
|
1021
|
-
const response = await fetch(useableUrl, {
|
|
1022
|
-
...opts,
|
|
1023
|
-
headers: basicHeaders
|
|
1024
|
-
}).catch((e) => {
|
|
1025
|
-
error("[fetch][response]", {
|
|
1026
|
-
message: e.message,
|
|
1027
|
-
stack: e.stack,
|
|
1028
|
-
debug: "Is nile-auth running?"
|
|
1029
|
-
});
|
|
1030
|
-
return new Error(e);
|
|
1031
|
-
});
|
|
1032
|
-
if (response instanceof Error) {
|
|
1033
|
-
return new ResponseError("Failed to connect to database", {
|
|
1034
|
-
status: 400
|
|
1035
|
-
});
|
|
1036
|
-
}
|
|
1037
|
-
if (response && response.status >= 200 && response.status < 300) {
|
|
1038
|
-
if (typeof response.clone === "function") {
|
|
1039
|
-
try {
|
|
1040
|
-
debug(
|
|
1041
|
-
`[fetch][response][${opts?.method ?? "GET"}] ${response.status} ${useableUrl}`,
|
|
1042
|
-
{
|
|
1043
|
-
body: await response.clone().json()
|
|
1044
|
-
}
|
|
1045
|
-
);
|
|
1046
|
-
} catch (e) {
|
|
1047
|
-
debug(
|
|
1048
|
-
`[fetch][response][${opts?.method ?? "GET"}] ${response.status} ${useableUrl}`,
|
|
1049
|
-
{
|
|
1050
|
-
body: await response.clone().text()
|
|
1051
|
-
}
|
|
1052
|
-
);
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
return response;
|
|
1056
|
-
}
|
|
1057
|
-
if (response?.status === 404) {
|
|
1058
|
-
return new ResponseError("Not found", { status: 404 });
|
|
1059
|
-
}
|
|
1060
|
-
if (response?.status === 401) {
|
|
1061
|
-
return new ResponseError("Unauthorized", { status: 401 });
|
|
1062
|
-
}
|
|
1063
|
-
if (response?.status === 405) {
|
|
1064
|
-
return new ResponseError("Method not allowed", { status: 405 });
|
|
1065
|
-
}
|
|
1066
|
-
const errorHandler = typeof response?.clone === "function" ? response.clone() : null;
|
|
1067
|
-
let msg = "";
|
|
1068
|
-
const res = await response?.json().catch(async (e) => {
|
|
1069
|
-
if (errorHandler) {
|
|
1070
|
-
msg = await errorHandler.text();
|
|
1071
|
-
if (msg) {
|
|
1072
|
-
error(`[fetch][response][status: ${errorHandler.status}]`, {
|
|
1073
|
-
message: msg
|
|
1074
|
-
});
|
|
1075
|
-
}
|
|
1076
|
-
return e;
|
|
1077
|
-
}
|
|
1078
|
-
if (!msg) {
|
|
1079
|
-
error("[fetch][response]", { e });
|
|
1080
|
-
}
|
|
1081
|
-
return e;
|
|
1082
|
-
});
|
|
1083
|
-
if (msg) {
|
|
1084
|
-
return new ResponseError(msg, { status: errorHandler?.status });
|
|
1085
|
-
}
|
|
1086
|
-
if (res && "message" in res) {
|
|
1087
|
-
const { message } = res;
|
|
1088
|
-
error(`[fetch][response][status: ${errorHandler?.status}] ${message}`);
|
|
1089
|
-
return new ResponseError(message, { status: 400 });
|
|
1090
|
-
}
|
|
1091
|
-
if (res && "errors" in res) {
|
|
1092
|
-
const {
|
|
1093
|
-
errors: [message]
|
|
1094
|
-
} = res;
|
|
1095
|
-
error(`[fetch][response] [status: ${errorHandler?.status}] ${message}`);
|
|
1096
|
-
return new ResponseError(message, { status: 400 });
|
|
1097
|
-
}
|
|
1098
|
-
error(
|
|
1099
|
-
`[fetch][response][status: ${errorHandler?.status}] UNHANDLED ERROR`,
|
|
1100
|
-
{
|
|
1101
|
-
response,
|
|
1102
|
-
message: await response.text()
|
|
1103
|
-
}
|
|
1104
|
-
);
|
|
1105
|
-
return new ResponseError(null, {
|
|
1106
|
-
status: response?.status ?? 500
|
|
1107
|
-
});
|
|
1108
|
-
} catch (e) {
|
|
1109
|
-
return new ResponseError("an unexpected error has occurred", {
|
|
1110
|
-
status: 500
|
|
1111
|
-
});
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
// src/api/routes/users/POST.ts
|
|
1116
|
-
async function POST(config, init) {
|
|
1117
|
-
init.body = init.request.body;
|
|
1118
|
-
init.method = "POST";
|
|
1119
|
-
const yurl = new URL(init.request.url);
|
|
1120
|
-
const tenantId = yurl.searchParams.get("tenantId");
|
|
1121
|
-
const newTenantName = yurl.searchParams.get("newTenantName");
|
|
1122
|
-
const tenant = tenantId ?? getTenantFromHttp(init.request.headers);
|
|
1123
|
-
const url = apiRoutes(config).USERS({ tenantId: tenant, newTenantName });
|
|
1124
|
-
return await request(url, init, config);
|
|
1125
|
-
}
|
|
1126
|
-
|
|
1127
|
-
// src/api/routes/users/GET.ts
|
|
1128
|
-
async function GET2(config, init, log) {
|
|
1129
|
-
const yurl = new URL(init.request.url);
|
|
1130
|
-
const tenantId = yurl.searchParams.get("tenantId");
|
|
1131
|
-
const tenant = tenantId ?? getTenantFromHttp(init.request.headers);
|
|
1132
|
-
if (!tenant) {
|
|
1133
|
-
log("[GET] No tenant id provided.");
|
|
1134
|
-
return new Response(null, { status: 404 });
|
|
1135
|
-
}
|
|
1136
|
-
const url = apiRoutes(config).TENANT_USERS(tenant);
|
|
1137
|
-
init.method = "GET";
|
|
1138
|
-
return await request(url, init, config);
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
// src/api/routes/users/[userId]/PUT.ts
|
|
1142
|
-
async function PUT(config, session, init) {
|
|
1143
|
-
if (!session) {
|
|
1144
|
-
return new Response(null, { status: 401 });
|
|
1145
|
-
}
|
|
1146
|
-
init.body = init.request.body;
|
|
1147
|
-
init.method = "PUT";
|
|
1148
|
-
const [userId] = new URL(init.request.url).pathname.split("/").reverse();
|
|
1149
|
-
const url = apiRoutes(config).USER(userId);
|
|
1150
|
-
return await request(url, init, config);
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
// src/api/routes/users/index.ts
|
|
1154
|
-
var key2 = "USERS";
|
|
1155
|
-
async function route2(request2, config) {
|
|
1156
|
-
const { info } = Logger(
|
|
1157
|
-
{ ...config, debug: config.debug },
|
|
1158
|
-
`[ROUTES][${key2}]`
|
|
1159
|
-
);
|
|
1160
|
-
const session = await auth(request2, config);
|
|
1161
|
-
switch (request2.method) {
|
|
1162
|
-
case "GET":
|
|
1163
|
-
return await GET2(config, { request: request2 }, info);
|
|
1164
|
-
case "POST":
|
|
1165
|
-
return await POST(config, { request: request2 });
|
|
1166
|
-
case "PUT":
|
|
1167
|
-
return await PUT(config, session, { request: request2 });
|
|
1168
|
-
default:
|
|
1169
|
-
return new Response("method not allowed", { status: 405 });
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
function matches2(configRoutes, request2) {
|
|
1173
|
-
return urlMatches(request2.url, configRoutes[key2]);
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
// src/api/routes/tenants/[tenantId]/users/GET.ts
|
|
1177
|
-
async function GET3(config, init) {
|
|
1178
|
-
const yurl = new URL(init.request.url);
|
|
1179
|
-
const [, tenantId] = yurl.pathname.split("/").reverse();
|
|
1180
|
-
const url = `${apiRoutes(config).TENANT_USERS(tenantId)}`;
|
|
1181
|
-
return await request(url, init, config);
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
// src/api/routes/tenants/[tenantId]/users/POST.ts
|
|
1185
|
-
async function POST2(config, session, init) {
|
|
1186
|
-
const yurl = new URL(init.request.url);
|
|
1187
|
-
const [, tenantId] = yurl.pathname.split("/").reverse();
|
|
1188
|
-
init.body = JSON.stringify({ email: session.email });
|
|
1189
|
-
init.method = "PUT";
|
|
1190
|
-
const url = apiRoutes(config).TENANT_USERS(tenantId);
|
|
1191
|
-
return await request(url, init, config);
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
// src/api/routes/tenants/[tenantId]/users/[userId]/DELETE.ts
|
|
1195
|
-
async function DELETE(config, init) {
|
|
1196
|
-
const yurl = new URL(init.request.url);
|
|
1197
|
-
const [userId, _, tenantId] = yurl.pathname.split("/").reverse();
|
|
1198
|
-
init.method = "DELETE";
|
|
1199
|
-
init.body = JSON.stringify({ email: userId });
|
|
1200
|
-
const url = `${apiRoutes(config).TENANT_USER(tenantId, userId)}`;
|
|
1201
|
-
return await request(url, init, config);
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
// src/api/routes/tenants/[tenantId]/users/PUT.ts
|
|
1205
|
-
async function PUT2(config, init) {
|
|
1206
|
-
const yurl = new URL(init.request.url);
|
|
1207
|
-
const [, tenantId] = yurl.pathname.split("/").reverse();
|
|
1208
|
-
init.method = "PUT";
|
|
1209
|
-
const url = `${apiRoutes(config).TENANT_USERS(tenantId)}`;
|
|
1210
|
-
return await request(url, init, config);
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
// src/api/routes/tenants/[tenantId]/users/index.ts
|
|
1214
|
-
var key3 = "TENANT_USERS";
|
|
1215
|
-
async function route3(request2, config) {
|
|
1216
|
-
const { info } = Logger(
|
|
1217
|
-
{ ...config, debug: config.debug },
|
|
1218
|
-
`[ROUTES][${key3}]`
|
|
1219
|
-
);
|
|
1220
|
-
const session = await auth(request2, config);
|
|
1221
|
-
if (!session) {
|
|
1222
|
-
info("401");
|
|
1223
|
-
return new Response(null, { status: 401 });
|
|
1224
|
-
}
|
|
1225
|
-
const yurl = new URL(request2.url);
|
|
1226
|
-
const [, tenantId] = yurl.pathname.split("/").reverse();
|
|
1227
|
-
if (!tenantId) {
|
|
1228
|
-
info("No tenant id found in path");
|
|
1229
|
-
return new Response(null, { status: 404 });
|
|
1230
|
-
}
|
|
1231
|
-
switch (request2.method) {
|
|
1232
|
-
case "GET":
|
|
1233
|
-
return await GET3(config, { request: request2 });
|
|
1234
|
-
case "POST":
|
|
1235
|
-
return await POST2(config, session, { request: request2 });
|
|
1236
|
-
case "PUT":
|
|
1237
|
-
return await PUT2(config, { request: request2 });
|
|
1238
|
-
case "DELETE":
|
|
1239
|
-
return await DELETE(config, { request: request2 });
|
|
1240
|
-
default:
|
|
1241
|
-
return new Response("method not allowed", { status: 405 });
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
function matches3(configRoutes, request2) {
|
|
1245
|
-
const url = new URL(request2.url);
|
|
1246
|
-
const [userId, possibleTenantId, tenantId] = url.pathname.split("/").reverse();
|
|
1247
|
-
let route15 = configRoutes[key3].replace("{tenantId}", tenantId).replace("{userId}", userId);
|
|
1248
|
-
if (userId === "users") {
|
|
1249
|
-
route15 = configRoutes[key3].replace("{tenantId}", possibleTenantId);
|
|
1250
|
-
}
|
|
1251
|
-
return urlMatches(request2.url, route15);
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
// src/api/routes/tenants/GET.ts
|
|
1255
|
-
async function GET4(config, session, init) {
|
|
1256
|
-
let url = `${apiRoutes(config).USER_TENANTS(session.id)}`;
|
|
1257
|
-
if (typeof session === "object" && "user" in session && session.user) {
|
|
1258
|
-
url = `${apiRoutes(config).USER_TENANTS(session.user.id)}`;
|
|
601
|
+
// src/api/routes/tenants/GET.ts
|
|
602
|
+
async function GET5(config, session, init) {
|
|
603
|
+
let url = `${apiRoutes(config).USER_TENANTS(session.id)}`;
|
|
604
|
+
if (typeof session === "object" && "user" in session && session.user) {
|
|
605
|
+
url = `${apiRoutes(config).USER_TENANTS(session.user.id)}`;
|
|
1259
606
|
}
|
|
1260
607
|
const res = await request(url, init, config);
|
|
1261
608
|
return res;
|
|
1262
609
|
}
|
|
1263
610
|
|
|
1264
611
|
// src/api/routes/tenants/[tenantId]/GET.ts
|
|
1265
|
-
async function
|
|
612
|
+
async function GET6(config, init, log) {
|
|
1266
613
|
const yurl = new URL(init.request.url);
|
|
1267
614
|
const [tenantId] = yurl.pathname.split("/").reverse();
|
|
1268
615
|
if (!tenantId) {
|
|
@@ -1287,7 +634,7 @@ async function DELETE2(config, init) {
|
|
|
1287
634
|
}
|
|
1288
635
|
|
|
1289
636
|
// src/api/routes/tenants/[tenantId]/PUT.ts
|
|
1290
|
-
async function
|
|
637
|
+
async function PUT4(config, init) {
|
|
1291
638
|
const yurl = new URL(init.request.url);
|
|
1292
639
|
const [tenantId] = yurl.pathname.split("/").reverse();
|
|
1293
640
|
if (!tenantId) {
|
|
@@ -1300,7 +647,7 @@ async function PUT3(config, init) {
|
|
|
1300
647
|
}
|
|
1301
648
|
|
|
1302
649
|
// src/api/routes/tenants/POST.ts
|
|
1303
|
-
async function
|
|
650
|
+
async function POST4(config, init) {
|
|
1304
651
|
init.body = init.request.body;
|
|
1305
652
|
init.method = "POST";
|
|
1306
653
|
const url = `${apiRoutes(config).TENANTS}`;
|
|
@@ -1308,19 +655,9 @@ async function POST3(config, init) {
|
|
|
1308
655
|
}
|
|
1309
656
|
|
|
1310
657
|
// src/api/routes/tenants/index.ts
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
}
|
|
1315
|
-
const regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5|7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
1316
|
-
return regex.test(value);
|
|
1317
|
-
}
|
|
1318
|
-
var key4 = "TENANTS";
|
|
1319
|
-
async function route4(request2, config) {
|
|
1320
|
-
const { info } = Logger(
|
|
1321
|
-
{ ...config, debug: config.debug },
|
|
1322
|
-
`[ROUTES][${key4}]`
|
|
1323
|
-
);
|
|
658
|
+
var key6 = "TENANTS";
|
|
659
|
+
async function route6(request2, config) {
|
|
660
|
+
const { info } = config.logger(`[ROUTES][${key6}]`);
|
|
1324
661
|
const session = await auth(request2, config);
|
|
1325
662
|
if (!session) {
|
|
1326
663
|
info("401");
|
|
@@ -1330,47 +667,84 @@ async function route4(request2, config) {
|
|
|
1330
667
|
switch (request2.method) {
|
|
1331
668
|
case "GET":
|
|
1332
669
|
if (isUUID(possibleTenantId)) {
|
|
1333
|
-
return await
|
|
670
|
+
return await GET6(config, { request: request2 }, info);
|
|
1334
671
|
}
|
|
1335
|
-
return await
|
|
672
|
+
return await GET5(config, session, { request: request2 });
|
|
1336
673
|
case "POST":
|
|
1337
|
-
return await
|
|
674
|
+
return await POST4(config, { request: request2 });
|
|
1338
675
|
case "DELETE":
|
|
1339
676
|
return await DELETE2(config, { request: request2 });
|
|
1340
677
|
case "PUT":
|
|
1341
|
-
return await
|
|
678
|
+
return await PUT4(config, { request: request2 });
|
|
1342
679
|
default:
|
|
1343
680
|
return new Response("method not allowed", { status: 405 });
|
|
1344
681
|
}
|
|
1345
682
|
}
|
|
1346
|
-
function
|
|
1347
|
-
return urlMatches(request2.url, configRoutes[
|
|
683
|
+
function matches6(configRoutes, request2) {
|
|
684
|
+
return urlMatches(request2.url, configRoutes[key6]);
|
|
685
|
+
}
|
|
686
|
+
async function fetchTenants(config, method, body) {
|
|
687
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants" /* TENANTS */}`;
|
|
688
|
+
const init = {
|
|
689
|
+
method,
|
|
690
|
+
headers: config.headers
|
|
691
|
+
};
|
|
692
|
+
{
|
|
693
|
+
init.body = body;
|
|
694
|
+
}
|
|
695
|
+
const req = new Request(clientUrl, init);
|
|
696
|
+
return await config.handlers.POST(req);
|
|
697
|
+
}
|
|
698
|
+
async function fetchTenant(config, method, body) {
|
|
699
|
+
if (!config.tenantId) {
|
|
700
|
+
throw new Error(
|
|
701
|
+
"Unable to fetch tenants, the tenantId context is missing. Call nile.setContext({ tenantId })"
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
if (!isUUID(config.tenantId)) {
|
|
705
|
+
config.logger("fetch tenant").warn(
|
|
706
|
+
"nile.tenantId is not a valid UUID. This may lead to unexpected behavior in your application."
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}" /* TENANT */.replace("{tenantId}", config.tenantId)}`;
|
|
710
|
+
const m = method ?? "GET";
|
|
711
|
+
const init = {
|
|
712
|
+
method: m,
|
|
713
|
+
headers: config.headers
|
|
714
|
+
};
|
|
715
|
+
if (m === "PUT") {
|
|
716
|
+
init.body = body;
|
|
717
|
+
}
|
|
718
|
+
const req = new Request(clientUrl, init);
|
|
719
|
+
return await config.handlers[m](req);
|
|
720
|
+
}
|
|
721
|
+
async function fetchTenantsByUser(config) {
|
|
722
|
+
const { warn } = config.logger("fetchTenantsByUser");
|
|
723
|
+
if (!config.userId) {
|
|
724
|
+
warn(
|
|
725
|
+
"nile.userId is not set. The call will still work for the API, but the database context is not set properly and may lead to unexpected behavior in your application."
|
|
726
|
+
);
|
|
727
|
+
} else if (!isUUID(config.userId)) {
|
|
728
|
+
warn(
|
|
729
|
+
"nile.userId is not a valid UUID. This may lead to unexpected behavior in your application."
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants" /* TENANTS */}`;
|
|
733
|
+
const req = new Request(clientUrl, { headers: config.headers });
|
|
734
|
+
return await config.handlers.GET(req);
|
|
1348
735
|
}
|
|
1349
|
-
|
|
1350
|
-
// src/api/utils/routes/proxyRoutes.ts
|
|
1351
|
-
var proxyRoutes = (config) => ({
|
|
1352
|
-
SIGNIN: makeRestUrl(config, "/auth/signin"),
|
|
1353
|
-
PROVIDERS: makeRestUrl(config, "/auth/providers"),
|
|
1354
|
-
SESSION: makeRestUrl(config, "/auth/session"),
|
|
1355
|
-
CSRF: makeRestUrl(config, "/auth/csrf"),
|
|
1356
|
-
CALLBACK: makeRestUrl(config, "/auth/callback"),
|
|
1357
|
-
SIGNOUT: makeRestUrl(config, "/auth/signout"),
|
|
1358
|
-
ERROR: makeRestUrl(config, "/auth/error"),
|
|
1359
|
-
VERIFY_REQUEST: makeRestUrl(config, "/auth/verify-request"),
|
|
1360
|
-
PASSWORD_RESET: makeRestUrl(config, "/auth/reset-password")
|
|
1361
|
-
});
|
|
1362
736
|
|
|
1363
737
|
// src/api/routes/auth/signin.ts
|
|
1364
|
-
var
|
|
1365
|
-
async function
|
|
1366
|
-
let url = proxyRoutes(config)[
|
|
738
|
+
var key7 = "SIGNIN";
|
|
739
|
+
async function route7(req, config) {
|
|
740
|
+
let url = proxyRoutes(config)[key7];
|
|
1367
741
|
const init = {
|
|
1368
742
|
method: req.method,
|
|
1369
743
|
headers: req.headers
|
|
1370
744
|
};
|
|
1371
745
|
if (req.method === "POST") {
|
|
1372
746
|
const [provider] = new URL(req.url).pathname.split("/").reverse();
|
|
1373
|
-
url = `${proxyRoutes(config)[
|
|
747
|
+
url = `${proxyRoutes(config)[key7]}/${provider}`;
|
|
1374
748
|
}
|
|
1375
749
|
const passThroughUrl = new URL(req.url);
|
|
1376
750
|
const params = new URLSearchParams(passThroughUrl.search);
|
|
@@ -1378,12 +752,21 @@ async function route5(req, config) {
|
|
|
1378
752
|
const res = await request(url, { ...init, request: req }, config);
|
|
1379
753
|
return res;
|
|
1380
754
|
}
|
|
1381
|
-
function
|
|
1382
|
-
return urlMatches(request2.url, configRoutes[
|
|
755
|
+
function matches7(configRoutes, request2) {
|
|
756
|
+
return urlMatches(request2.url, configRoutes[key7]);
|
|
757
|
+
}
|
|
758
|
+
async function fetchSignIn(config, provider, body) {
|
|
759
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/signin" /* SIGNIN */}/${provider}`;
|
|
760
|
+
const req = new Request(clientUrl, {
|
|
761
|
+
method: "POST",
|
|
762
|
+
headers: config.headers,
|
|
763
|
+
body
|
|
764
|
+
});
|
|
765
|
+
return await config.handlers.POST(req);
|
|
1383
766
|
}
|
|
1384
767
|
|
|
1385
768
|
// src/api/routes/auth/session.ts
|
|
1386
|
-
async function
|
|
769
|
+
async function route8(req, config) {
|
|
1387
770
|
return request(
|
|
1388
771
|
proxyRoutes(config).SESSION,
|
|
1389
772
|
{
|
|
@@ -1393,12 +776,20 @@ async function route6(req, config) {
|
|
|
1393
776
|
config
|
|
1394
777
|
);
|
|
1395
778
|
}
|
|
1396
|
-
function
|
|
779
|
+
function matches8(configRoutes, request2) {
|
|
1397
780
|
return urlMatches(request2.url, configRoutes.SESSION);
|
|
1398
781
|
}
|
|
782
|
+
async function fetchSession(config) {
|
|
783
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/session" /* SESSION */}`;
|
|
784
|
+
const req = new Request(clientUrl, {
|
|
785
|
+
method: "GET",
|
|
786
|
+
headers: config.headers
|
|
787
|
+
});
|
|
788
|
+
return await config.handlers.GET(req);
|
|
789
|
+
}
|
|
1399
790
|
|
|
1400
791
|
// src/api/routes/auth/providers.ts
|
|
1401
|
-
async function
|
|
792
|
+
async function route9(req, config) {
|
|
1402
793
|
return request(
|
|
1403
794
|
proxyRoutes(config).PROVIDERS,
|
|
1404
795
|
{
|
|
@@ -1408,12 +799,20 @@ async function route7(req, config) {
|
|
|
1408
799
|
config
|
|
1409
800
|
);
|
|
1410
801
|
}
|
|
1411
|
-
function
|
|
802
|
+
function matches9(configRoutes, request2) {
|
|
1412
803
|
return urlMatches(request2.url, configRoutes.PROVIDERS);
|
|
1413
804
|
}
|
|
805
|
+
async function fetchProviders(config) {
|
|
806
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/providers" /* PROVIDERS */}`;
|
|
807
|
+
const req = new Request(clientUrl, {
|
|
808
|
+
method: "GET",
|
|
809
|
+
headers: config.headers
|
|
810
|
+
});
|
|
811
|
+
return await config.handlers.GET(req);
|
|
812
|
+
}
|
|
1414
813
|
|
|
1415
814
|
// src/api/routes/auth/csrf.ts
|
|
1416
|
-
async function
|
|
815
|
+
async function route10(req, config) {
|
|
1417
816
|
return request(
|
|
1418
817
|
proxyRoutes(config).CSRF,
|
|
1419
818
|
{
|
|
@@ -1423,22 +822,27 @@ async function route8(req, config) {
|
|
|
1423
822
|
config
|
|
1424
823
|
);
|
|
1425
824
|
}
|
|
1426
|
-
function
|
|
825
|
+
function matches10(configRoutes, request2) {
|
|
1427
826
|
return urlMatches(request2.url, configRoutes.CSRF);
|
|
1428
827
|
}
|
|
828
|
+
async function fetchCsrf(config) {
|
|
829
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/csrf" /* CSRF */}`;
|
|
830
|
+
const req = new Request(clientUrl, {
|
|
831
|
+
method: "GET",
|
|
832
|
+
headers: config.headers
|
|
833
|
+
});
|
|
834
|
+
return await config.handlers.GET(req);
|
|
835
|
+
}
|
|
1429
836
|
|
|
1430
837
|
// src/api/routes/auth/callback.ts
|
|
1431
|
-
var
|
|
1432
|
-
async function
|
|
1433
|
-
const { error } =
|
|
1434
|
-
{ ...config, debug: config.debug },
|
|
1435
|
-
`[ROUTES][${key6}]`
|
|
1436
|
-
);
|
|
838
|
+
var key8 = "CALLBACK";
|
|
839
|
+
async function route11(req, config) {
|
|
840
|
+
const { error } = config.logger(`[ROUTES][${key8}]`);
|
|
1437
841
|
const [provider] = new URL(req.url).pathname.split("/").reverse();
|
|
1438
842
|
try {
|
|
1439
843
|
const passThroughUrl = new URL(req.url);
|
|
1440
844
|
const params = new URLSearchParams(passThroughUrl.search);
|
|
1441
|
-
const url = `${proxyRoutes(config)[
|
|
845
|
+
const url = `${proxyRoutes(config)[key8]}/${provider}${params.toString() !== "" ? `?${params.toString()}` : ""}`;
|
|
1442
846
|
const res = await request(
|
|
1443
847
|
url,
|
|
1444
848
|
{
|
|
@@ -1465,34 +869,52 @@ async function route9(req, config) {
|
|
|
1465
869
|
}
|
|
1466
870
|
return new Response("An unexpected error has occurred.", { status: 400 });
|
|
1467
871
|
}
|
|
1468
|
-
function
|
|
872
|
+
function matches11(configRoutes, request2) {
|
|
1469
873
|
return urlMatches(request2.url, configRoutes.CALLBACK);
|
|
1470
874
|
}
|
|
875
|
+
async function fetchCallback(config, provider, body, request2, method = "POST") {
|
|
876
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/callback" /* CALLBACK */}/${provider}${request2 ? `?${new URL(request2.url).searchParams}` : ""}`;
|
|
877
|
+
const req = new Request(clientUrl, {
|
|
878
|
+
method,
|
|
879
|
+
headers: config.headers,
|
|
880
|
+
body
|
|
881
|
+
});
|
|
882
|
+
return await config.handlers.POST(req);
|
|
883
|
+
}
|
|
1471
884
|
|
|
1472
885
|
// src/api/routes/auth/signout.ts
|
|
1473
|
-
var
|
|
1474
|
-
async function
|
|
1475
|
-
let url = proxyRoutes(config)[
|
|
886
|
+
var key9 = "SIGNOUT";
|
|
887
|
+
async function route12(request2, config) {
|
|
888
|
+
let url = proxyRoutes(config)[key9];
|
|
1476
889
|
const init = {
|
|
1477
890
|
method: request2.method
|
|
1478
891
|
};
|
|
1479
892
|
if (request2.method === "POST") {
|
|
1480
893
|
init.body = request2.body;
|
|
1481
894
|
const [provider] = new URL(request2.url).pathname.split("/").reverse();
|
|
1482
|
-
url = `${proxyRoutes(config)[
|
|
895
|
+
url = `${proxyRoutes(config)[key9]}${provider !== "signout" ? `/${provider}` : ""}`;
|
|
1483
896
|
}
|
|
1484
897
|
const res = await request(url, { ...init, request: request2 }, config);
|
|
1485
898
|
return res;
|
|
1486
899
|
}
|
|
1487
|
-
function
|
|
1488
|
-
return urlMatches(request2.url, configRoutes[
|
|
1489
|
-
}
|
|
900
|
+
function matches12(configRoutes, request2) {
|
|
901
|
+
return urlMatches(request2.url, configRoutes[key9]);
|
|
902
|
+
}
|
|
903
|
+
async function fetchSignOut(config, body) {
|
|
904
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/signout" /* SIGNOUT */}`;
|
|
905
|
+
const req = new Request(clientUrl, {
|
|
906
|
+
method: "POST",
|
|
907
|
+
body,
|
|
908
|
+
headers: config.headers
|
|
909
|
+
});
|
|
910
|
+
return await config.handlers.POST(req);
|
|
911
|
+
}
|
|
1490
912
|
|
|
1491
913
|
// src/api/routes/auth/error.ts
|
|
1492
|
-
var
|
|
1493
|
-
async function
|
|
914
|
+
var key10 = "ERROR";
|
|
915
|
+
async function route13(req, config) {
|
|
1494
916
|
return request(
|
|
1495
|
-
proxyRoutes(config)[
|
|
917
|
+
proxyRoutes(config)[key10],
|
|
1496
918
|
{
|
|
1497
919
|
method: req.method,
|
|
1498
920
|
request: req
|
|
@@ -1500,15 +922,15 @@ async function route11(req, config) {
|
|
|
1500
922
|
config
|
|
1501
923
|
);
|
|
1502
924
|
}
|
|
1503
|
-
function
|
|
1504
|
-
return urlMatches(request2.url, configRoutes[
|
|
925
|
+
function matches13(configRoutes, request2) {
|
|
926
|
+
return urlMatches(request2.url, configRoutes[key10]);
|
|
1505
927
|
}
|
|
1506
928
|
|
|
1507
929
|
// src/api/routes/auth/verify-request.ts
|
|
1508
|
-
var
|
|
1509
|
-
async function
|
|
930
|
+
var key11 = "VERIFY_REQUEST";
|
|
931
|
+
async function route14(req, config) {
|
|
1510
932
|
return request(
|
|
1511
|
-
proxyRoutes(config)[
|
|
933
|
+
proxyRoutes(config)[key11],
|
|
1512
934
|
{
|
|
1513
935
|
method: req.method,
|
|
1514
936
|
request: req
|
|
@@ -1516,14 +938,14 @@ async function route12(req, config) {
|
|
|
1516
938
|
config
|
|
1517
939
|
);
|
|
1518
940
|
}
|
|
1519
|
-
function
|
|
1520
|
-
return urlMatches(request2.url, configRoutes[
|
|
941
|
+
function matches14(configRoutes, request2) {
|
|
942
|
+
return urlMatches(request2.url, configRoutes[key11]);
|
|
1521
943
|
}
|
|
1522
944
|
|
|
1523
945
|
// src/api/routes/auth/password-reset.ts
|
|
1524
|
-
var
|
|
1525
|
-
async function
|
|
1526
|
-
const url = proxyRoutes(config)[
|
|
946
|
+
var key12 = "PASSWORD_RESET";
|
|
947
|
+
async function route15(req, config) {
|
|
948
|
+
const url = proxyRoutes(config)[key12];
|
|
1527
949
|
const res = await request(
|
|
1528
950
|
url,
|
|
1529
951
|
{
|
|
@@ -1544,73 +966,203 @@ async function route13(req, config) {
|
|
|
1544
966
|
headers: res?.headers
|
|
1545
967
|
});
|
|
1546
968
|
}
|
|
1547
|
-
function
|
|
969
|
+
function matches15(configRoutes, request2) {
|
|
1548
970
|
return urlMatches(request2.url, configRoutes.PASSWORD_RESET);
|
|
1549
971
|
}
|
|
972
|
+
async function fetchResetPassword(config, method, body, params, useJson = true) {
|
|
973
|
+
const authParams = new URLSearchParams(params ?? {});
|
|
974
|
+
if (useJson) {
|
|
975
|
+
authParams?.set("json", "true");
|
|
976
|
+
}
|
|
977
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/reset-password" /* PASSWORD_RESET */}?${authParams?.toString()}`;
|
|
978
|
+
const init = {
|
|
979
|
+
method,
|
|
980
|
+
headers: config.headers
|
|
981
|
+
};
|
|
982
|
+
if (body && method !== "GET") {
|
|
983
|
+
init.body = body;
|
|
984
|
+
}
|
|
985
|
+
const req = new Request(clientUrl, init);
|
|
986
|
+
return await config.handlers[method](req);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// src/api/routes/auth/verify-email.ts
|
|
990
|
+
var key13 = "VERIFY_EMAIL";
|
|
991
|
+
async function route16(req, config) {
|
|
992
|
+
const url = proxyRoutes(config)[key13];
|
|
993
|
+
const res = await request(
|
|
994
|
+
url,
|
|
995
|
+
{
|
|
996
|
+
method: req.method,
|
|
997
|
+
request: req
|
|
998
|
+
},
|
|
999
|
+
config
|
|
1000
|
+
);
|
|
1001
|
+
const location = res?.headers.get("location");
|
|
1002
|
+
if (location) {
|
|
1003
|
+
return new Response(res?.body, {
|
|
1004
|
+
status: 302,
|
|
1005
|
+
headers: res?.headers
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
return new Response(res?.body, {
|
|
1009
|
+
status: res?.status,
|
|
1010
|
+
headers: res?.headers
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
function matches16(configRoutes, request2) {
|
|
1014
|
+
return urlMatches(request2.url, configRoutes[key13]);
|
|
1015
|
+
}
|
|
1016
|
+
async function fetchVerifyEmail(config, method, body) {
|
|
1017
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/auth/verify-email" /* VERIFY_EMAIL */}`;
|
|
1018
|
+
const init = {
|
|
1019
|
+
method,
|
|
1020
|
+
headers: config.headers
|
|
1021
|
+
};
|
|
1022
|
+
if (body) {
|
|
1023
|
+
init.body = body;
|
|
1024
|
+
}
|
|
1025
|
+
const req = new Request(clientUrl, init);
|
|
1026
|
+
return await config.handlers[method](req);
|
|
1027
|
+
}
|
|
1550
1028
|
|
|
1551
1029
|
// src/api/handlers/GET.ts
|
|
1552
1030
|
function GETTER(configRoutes, config) {
|
|
1553
|
-
const { info, warn } =
|
|
1554
|
-
return async function
|
|
1031
|
+
const { info, warn } = config.logger("[GET MATCHER]");
|
|
1032
|
+
return async function GET7(req) {
|
|
1555
1033
|
if (matches(configRoutes, req)) {
|
|
1556
1034
|
info("matches me");
|
|
1557
1035
|
return route(req, config);
|
|
1558
1036
|
}
|
|
1037
|
+
if (matches5(configRoutes, req)) {
|
|
1038
|
+
info("matches tenant invites");
|
|
1039
|
+
return route5(req, config);
|
|
1040
|
+
}
|
|
1041
|
+
if (matches4(configRoutes, req)) {
|
|
1042
|
+
info("matches invite");
|
|
1043
|
+
return route4(req, config);
|
|
1044
|
+
}
|
|
1559
1045
|
if (matches3(configRoutes, req)) {
|
|
1560
1046
|
info("matches tenant users");
|
|
1561
1047
|
return route3(req, config);
|
|
1562
1048
|
}
|
|
1049
|
+
if (matches6(configRoutes, req)) {
|
|
1050
|
+
info("matches tenants");
|
|
1051
|
+
return route6(req, config);
|
|
1052
|
+
}
|
|
1563
1053
|
if (matches2(configRoutes, req)) {
|
|
1564
1054
|
info("matches users");
|
|
1565
1055
|
return route2(req, config);
|
|
1566
1056
|
}
|
|
1567
|
-
if (
|
|
1568
|
-
info("matches tenants");
|
|
1569
|
-
return route4(req, config);
|
|
1570
|
-
}
|
|
1571
|
-
if (matches6(configRoutes, req)) {
|
|
1057
|
+
if (matches8(configRoutes, req)) {
|
|
1572
1058
|
info("matches session");
|
|
1573
|
-
return
|
|
1059
|
+
return route8(req, config);
|
|
1574
1060
|
}
|
|
1575
|
-
if (
|
|
1061
|
+
if (matches7(configRoutes, req)) {
|
|
1576
1062
|
info("matches signin");
|
|
1577
|
-
return
|
|
1063
|
+
return route7(req, config);
|
|
1578
1064
|
}
|
|
1579
|
-
if (
|
|
1065
|
+
if (matches9(configRoutes, req)) {
|
|
1580
1066
|
info("matches providers");
|
|
1581
|
-
return
|
|
1067
|
+
return route9(req, config);
|
|
1582
1068
|
}
|
|
1583
|
-
if (
|
|
1069
|
+
if (matches10(configRoutes, req)) {
|
|
1584
1070
|
info("matches csrf");
|
|
1585
|
-
return
|
|
1071
|
+
return route10(req, config);
|
|
1586
1072
|
}
|
|
1587
|
-
if (
|
|
1073
|
+
if (matches15(configRoutes, req)) {
|
|
1588
1074
|
info("matches password reset");
|
|
1589
|
-
return
|
|
1075
|
+
return route15(req, config);
|
|
1590
1076
|
}
|
|
1591
|
-
if (
|
|
1077
|
+
if (matches11(configRoutes, req)) {
|
|
1592
1078
|
info("matches callback");
|
|
1593
|
-
return
|
|
1079
|
+
return route11(req, config);
|
|
1594
1080
|
}
|
|
1595
|
-
if (
|
|
1081
|
+
if (matches12(configRoutes, req)) {
|
|
1596
1082
|
info("matches signout");
|
|
1597
|
-
return
|
|
1083
|
+
return route12(req, config);
|
|
1598
1084
|
}
|
|
1599
|
-
if (
|
|
1085
|
+
if (matches14(configRoutes, req)) {
|
|
1600
1086
|
info("matches verify-request");
|
|
1601
|
-
return
|
|
1087
|
+
return route14(req, config);
|
|
1602
1088
|
}
|
|
1603
|
-
if (
|
|
1089
|
+
if (matches16(configRoutes, req)) {
|
|
1090
|
+
info("matches verify-email");
|
|
1091
|
+
return route16(req, config);
|
|
1092
|
+
}
|
|
1093
|
+
if (matches13(configRoutes, req)) {
|
|
1604
1094
|
info("matches error");
|
|
1605
|
-
return
|
|
1095
|
+
return route13(req, config);
|
|
1606
1096
|
}
|
|
1607
|
-
warn(
|
|
1097
|
+
warn(`No GET routes matched ${req.url}`);
|
|
1608
1098
|
return new Response(null, { status: 404 });
|
|
1609
1099
|
};
|
|
1610
1100
|
}
|
|
1611
1101
|
|
|
1102
|
+
// src/utils/Logger.ts
|
|
1103
|
+
var red = "\x1B[31m";
|
|
1104
|
+
var yellow = "\x1B[38;2;255;255;0m";
|
|
1105
|
+
var purple = "\x1B[38;2;200;160;255m";
|
|
1106
|
+
var orange = "\x1B[38;2;255;165;0m";
|
|
1107
|
+
var reset = "\x1B[0m";
|
|
1108
|
+
var baseLogger = (config, ...params) => ({
|
|
1109
|
+
info(message, meta) {
|
|
1110
|
+
if (config?.debug) {
|
|
1111
|
+
console.info(
|
|
1112
|
+
`${orange}[niledb]${reset}${purple}[DEBUG]${reset}${params.join(
|
|
1113
|
+
""
|
|
1114
|
+
)}${reset} ${message}`,
|
|
1115
|
+
meta ? `${JSON.stringify(meta)}` : ""
|
|
1116
|
+
);
|
|
1117
|
+
}
|
|
1118
|
+
},
|
|
1119
|
+
debug(message, meta) {
|
|
1120
|
+
if (config?.debug) {
|
|
1121
|
+
console.debug(
|
|
1122
|
+
`${orange}[niledb]${reset}${purple}[DEBUG]${reset}${params.join(
|
|
1123
|
+
""
|
|
1124
|
+
)}${reset} ${message}`,
|
|
1125
|
+
meta ? `${JSON.stringify(meta)}` : ""
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
},
|
|
1129
|
+
warn(message, meta) {
|
|
1130
|
+
if (config?.debug) {
|
|
1131
|
+
console.warn(
|
|
1132
|
+
`${orange}[niledb]${reset}${yellow}[WARN]${reset}${params.join(
|
|
1133
|
+
""
|
|
1134
|
+
)}${reset} ${message}`,
|
|
1135
|
+
meta ? JSON.stringify(meta) : ""
|
|
1136
|
+
);
|
|
1137
|
+
}
|
|
1138
|
+
},
|
|
1139
|
+
error(message, meta) {
|
|
1140
|
+
console.error(
|
|
1141
|
+
`${orange}[niledb]${reset}${red}[ERROR]${reset}${params.join(
|
|
1142
|
+
""
|
|
1143
|
+
)}${red} ${message}`,
|
|
1144
|
+
meta ? meta : "",
|
|
1145
|
+
`${reset}`
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
});
|
|
1149
|
+
function Logger(config) {
|
|
1150
|
+
return (prefixes) => {
|
|
1151
|
+
const { info, debug, warn, error } = config && typeof config?.logger === "function" ? config.logger(prefixes) : baseLogger(config, prefixes);
|
|
1152
|
+
return {
|
|
1153
|
+
info,
|
|
1154
|
+
debug,
|
|
1155
|
+
warn,
|
|
1156
|
+
error
|
|
1157
|
+
};
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
function matchesLog(configRoutes, request2) {
|
|
1161
|
+
return urlMatches(request2.url, configRoutes.LOG);
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1612
1164
|
// src/api/routes/signup/POST.ts
|
|
1613
|
-
async function
|
|
1165
|
+
async function POST5(config, init) {
|
|
1614
1166
|
init.body = init.request.body;
|
|
1615
1167
|
init.method = "POST";
|
|
1616
1168
|
const url = `${apiRoutes(config).SIGNUP}`;
|
|
@@ -1618,365 +1170,1224 @@ async function POST4(config, init) {
|
|
|
1618
1170
|
}
|
|
1619
1171
|
|
|
1620
1172
|
// src/api/routes/signup/index.tsx
|
|
1621
|
-
var
|
|
1622
|
-
async function
|
|
1173
|
+
var key14 = "SIGNUP";
|
|
1174
|
+
async function route17(request2, config) {
|
|
1623
1175
|
switch (request2.method) {
|
|
1624
1176
|
case "POST":
|
|
1625
|
-
return await
|
|
1177
|
+
return await POST5(config, { request: request2 });
|
|
1626
1178
|
default:
|
|
1627
1179
|
return new Response("method not allowed", { status: 405 });
|
|
1628
1180
|
}
|
|
1629
1181
|
}
|
|
1630
|
-
function
|
|
1631
|
-
return urlMatches(request2.url, configRoutes[
|
|
1182
|
+
function matches17(configRoutes, request2) {
|
|
1183
|
+
return urlMatches(request2.url, configRoutes[key14]);
|
|
1184
|
+
}
|
|
1185
|
+
async function fetchSignUp(config, payload) {
|
|
1186
|
+
const { body, params } = payload ?? {};
|
|
1187
|
+
const q = new URLSearchParams();
|
|
1188
|
+
if (params?.newTenantName) {
|
|
1189
|
+
q.set("newTenantName", params.newTenantName);
|
|
1190
|
+
}
|
|
1191
|
+
if (params?.tenantId) {
|
|
1192
|
+
q.set("tenantId", params.tenantId);
|
|
1193
|
+
}
|
|
1194
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/signup" /* SIGNUP */}${q.size > 0 ? `?${q}` : ""}`;
|
|
1195
|
+
const req = new Request(clientUrl, {
|
|
1196
|
+
method: "POST",
|
|
1197
|
+
headers: config.headers,
|
|
1198
|
+
body
|
|
1199
|
+
});
|
|
1200
|
+
return await config.handlers.POST(req);
|
|
1632
1201
|
}
|
|
1633
1202
|
|
|
1634
1203
|
// src/api/handlers/POST.ts
|
|
1635
1204
|
function POSTER(configRoutes, config) {
|
|
1636
|
-
const { info, warn, error } =
|
|
1637
|
-
return async function
|
|
1205
|
+
const { info, warn, error } = config.logger("[POST MATCHER]");
|
|
1206
|
+
return async function POST6(req) {
|
|
1638
1207
|
if (matchesLog(configRoutes, req)) {
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
status: 200
|
|
1645
|
-
});
|
|
1646
|
-
} catch (e) {
|
|
1647
|
-
}
|
|
1208
|
+
try {
|
|
1209
|
+
const json = await req.clone().json();
|
|
1210
|
+
error(req.body && json);
|
|
1211
|
+
} catch {
|
|
1212
|
+
error(await req.text());
|
|
1648
1213
|
}
|
|
1214
|
+
return new Response(null, { status: 200 });
|
|
1649
1215
|
}
|
|
1650
1216
|
if (matches3(configRoutes, req)) {
|
|
1651
1217
|
info("matches tenant users");
|
|
1652
1218
|
return route3(req, config);
|
|
1653
1219
|
}
|
|
1654
|
-
if (
|
|
1220
|
+
if (matches4(configRoutes, req)) {
|
|
1221
|
+
info("matches tenant invite");
|
|
1222
|
+
return route4(req, config);
|
|
1223
|
+
}
|
|
1224
|
+
if (matches17(configRoutes, req)) {
|
|
1655
1225
|
info("matches signup");
|
|
1656
|
-
return
|
|
1226
|
+
return route17(req, config);
|
|
1657
1227
|
}
|
|
1658
1228
|
if (matches2(configRoutes, req)) {
|
|
1659
1229
|
info("matches users");
|
|
1660
1230
|
return route2(req, config);
|
|
1661
1231
|
}
|
|
1662
|
-
if (
|
|
1663
|
-
info("matches tenants");
|
|
1664
|
-
return
|
|
1232
|
+
if (matches6(configRoutes, req)) {
|
|
1233
|
+
info("matches tenants");
|
|
1234
|
+
return route6(req, config);
|
|
1235
|
+
}
|
|
1236
|
+
if (matches8(configRoutes, req)) {
|
|
1237
|
+
info("matches session");
|
|
1238
|
+
return route8(req, config);
|
|
1239
|
+
}
|
|
1240
|
+
if (matches7(configRoutes, req)) {
|
|
1241
|
+
info("matches signin");
|
|
1242
|
+
return route7(req, config);
|
|
1243
|
+
}
|
|
1244
|
+
if (matches15(configRoutes, req)) {
|
|
1245
|
+
info("matches password reset");
|
|
1246
|
+
return route15(req, config);
|
|
1247
|
+
}
|
|
1248
|
+
if (matches9(configRoutes, req)) {
|
|
1249
|
+
info("matches providers");
|
|
1250
|
+
return route9(req, config);
|
|
1251
|
+
}
|
|
1252
|
+
if (matches10(configRoutes, req)) {
|
|
1253
|
+
info("matches csrf");
|
|
1254
|
+
return route10(req, config);
|
|
1255
|
+
}
|
|
1256
|
+
if (matches11(configRoutes, req)) {
|
|
1257
|
+
info("matches callback");
|
|
1258
|
+
return route11(req, config);
|
|
1259
|
+
}
|
|
1260
|
+
if (matches12(configRoutes, req)) {
|
|
1261
|
+
info("matches signout");
|
|
1262
|
+
return route12(req, config);
|
|
1263
|
+
}
|
|
1264
|
+
if (matches16(configRoutes, req)) {
|
|
1265
|
+
info("matches verify-email");
|
|
1266
|
+
return route16(req, config);
|
|
1267
|
+
}
|
|
1268
|
+
warn(`No POST routes matched ${req.url}`);
|
|
1269
|
+
return new Response(null, { status: 404 });
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// src/api/routes/tenants/[tenantId]/users/[userId]/DELETE.ts
|
|
1274
|
+
async function DELETE3(config, init) {
|
|
1275
|
+
const yurl = new URL(init.request.url);
|
|
1276
|
+
const [, userId, , tenantId] = yurl.pathname.split("/").reverse();
|
|
1277
|
+
config.tenantId = tenantId;
|
|
1278
|
+
config.userId = userId;
|
|
1279
|
+
init.method = "DELETE";
|
|
1280
|
+
const url = `${apiRoutes(config).TENANT_USER}/link`;
|
|
1281
|
+
return await request(url, init, config);
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
// src/api/routes/tenants/[tenantId]/users/[userId]/PUT.ts
|
|
1285
|
+
async function PUT5(config, init) {
|
|
1286
|
+
const yurl = new URL(init.request.url);
|
|
1287
|
+
const [, userId, , tenantId] = yurl.pathname.split("/").reverse();
|
|
1288
|
+
config.tenantId = tenantId;
|
|
1289
|
+
config.userId = userId;
|
|
1290
|
+
init.method = "PUT";
|
|
1291
|
+
const url = `${apiRoutes(config).TENANT_USER}/link`;
|
|
1292
|
+
return await request(url, init, config);
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
// src/api/routes/tenants/[tenantId]/users/[userId]/index.ts
|
|
1296
|
+
var key15 = "TENANT_USER";
|
|
1297
|
+
async function route18(request2, config) {
|
|
1298
|
+
const { info } = config.logger(`[ROUTES][${key15}]`);
|
|
1299
|
+
const session = await auth(request2, config);
|
|
1300
|
+
if (!session) {
|
|
1301
|
+
info("401");
|
|
1302
|
+
return new Response(null, { status: 401 });
|
|
1303
|
+
}
|
|
1304
|
+
const yurl = new URL(request2.url);
|
|
1305
|
+
const [, userId] = yurl.pathname.split("/").reverse();
|
|
1306
|
+
if (!userId) {
|
|
1307
|
+
info("No tenant id found in path");
|
|
1308
|
+
return new Response(null, { status: 404 });
|
|
1309
|
+
}
|
|
1310
|
+
switch (request2.method) {
|
|
1311
|
+
case "PUT":
|
|
1312
|
+
return await PUT5(config, { request: request2 });
|
|
1313
|
+
case "DELETE":
|
|
1314
|
+
return await DELETE3(config, { request: request2 });
|
|
1315
|
+
default:
|
|
1316
|
+
return new Response("method not allowed", { status: 405 });
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
function matches18(configRoutes, request2) {
|
|
1320
|
+
const url = new URL(request2.url);
|
|
1321
|
+
const [, userId, possibleTenantId, tenantId] = url.pathname.split("/").reverse();
|
|
1322
|
+
let route20 = configRoutes[key15].replace("{tenantId}", tenantId).replace("{userId}", userId);
|
|
1323
|
+
if (userId === "users") {
|
|
1324
|
+
route20 = configRoutes[key15].replace("{tenantId}", possibleTenantId);
|
|
1325
|
+
}
|
|
1326
|
+
return urlMatches(request2.url, route20);
|
|
1327
|
+
}
|
|
1328
|
+
async function fetchTenantUser(config, method) {
|
|
1329
|
+
if (!config.tenantId) {
|
|
1330
|
+
throw new Error(
|
|
1331
|
+
"The tenantId context is missing. Call nile.setContext({ tenantId })"
|
|
1332
|
+
);
|
|
1333
|
+
}
|
|
1334
|
+
if (!config.userId) {
|
|
1335
|
+
throw new Error(
|
|
1336
|
+
"the userId context is missing. Call nile.setContext({ userId })"
|
|
1337
|
+
);
|
|
1338
|
+
}
|
|
1339
|
+
const clientUrl = `${config.serverOrigin}${config.routePrefix}${"/tenants/{tenantId}/users/{userId}" /* TENANT_USER */.replace(
|
|
1340
|
+
"{tenantId}",
|
|
1341
|
+
config.tenantId
|
|
1342
|
+
).replace("{userId}", config.userId)}/link`;
|
|
1343
|
+
const req = new Request(clientUrl, {
|
|
1344
|
+
headers: config.headers,
|
|
1345
|
+
method
|
|
1346
|
+
});
|
|
1347
|
+
return await config.handlers[method](req);
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
// src/api/routes/tenants/[tenantId]/invite/[inviteId]/DELETE.ts
|
|
1351
|
+
async function DELETE4(config, init) {
|
|
1352
|
+
const yurl = new URL(init.request.url);
|
|
1353
|
+
const [inviteId, , tenantId] = yurl.pathname.split("/").reverse();
|
|
1354
|
+
if (!tenantId) {
|
|
1355
|
+
return new Response(null, { status: 404 });
|
|
1356
|
+
}
|
|
1357
|
+
init.method = "DELETE";
|
|
1358
|
+
const url = `${apiRoutes(config).INVITE(tenantId)}/${inviteId}`;
|
|
1359
|
+
return await request(url, init, config);
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
// src/api/routes/tenants/[tenantId]/invite/[inviteId]/index.ts
|
|
1363
|
+
var key16 = "INVITE";
|
|
1364
|
+
async function route19(request2, config) {
|
|
1365
|
+
switch (request2.method) {
|
|
1366
|
+
case "DELETE":
|
|
1367
|
+
return await DELETE4(config, { request: request2 });
|
|
1368
|
+
default:
|
|
1369
|
+
return new Response("method not allowed", { status: 405 });
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
function matches19(configRoutes, request2) {
|
|
1373
|
+
const url = new URL(request2.url);
|
|
1374
|
+
const [inviteId, , tenantId] = url.pathname.split("/").reverse();
|
|
1375
|
+
const route20 = configRoutes[key16].replace("{tenantId}", tenantId).replace("{inviteId}", inviteId);
|
|
1376
|
+
return urlMatches(request2.url, route20);
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
// src/api/handlers/DELETE.ts
|
|
1380
|
+
function DELETER(configRoutes, config) {
|
|
1381
|
+
const { info, warn } = config.logger("[DELETE MATCHER]");
|
|
1382
|
+
return async function DELETE5(req) {
|
|
1383
|
+
if (matches19(configRoutes, req)) {
|
|
1384
|
+
info("matches tenant invite id");
|
|
1385
|
+
return route19(req, config);
|
|
1386
|
+
}
|
|
1387
|
+
if (matches18(configRoutes, req)) {
|
|
1388
|
+
info("matches tenant user");
|
|
1389
|
+
return route18(req, config);
|
|
1390
|
+
}
|
|
1391
|
+
if (matches3(configRoutes, req)) {
|
|
1392
|
+
info("matches tenant users");
|
|
1393
|
+
return route3(req, config);
|
|
1394
|
+
}
|
|
1395
|
+
if (matches6(configRoutes, req)) {
|
|
1396
|
+
info("matches tenants");
|
|
1397
|
+
return route6(req, config);
|
|
1398
|
+
}
|
|
1399
|
+
if (matches(configRoutes, req)) {
|
|
1400
|
+
info("matches me");
|
|
1401
|
+
return route(req, config);
|
|
1402
|
+
}
|
|
1403
|
+
warn("No DELETE routes matched");
|
|
1404
|
+
return new Response(null, { status: 404 });
|
|
1405
|
+
};
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
// src/api/handlers/PUT.ts
|
|
1409
|
+
function PUTER(configRoutes, config) {
|
|
1410
|
+
const { info, warn } = config.logger("[PUT MATCHER]");
|
|
1411
|
+
return async function PUT6(req) {
|
|
1412
|
+
if (matches4(configRoutes, req)) {
|
|
1413
|
+
info("matches tenant invite");
|
|
1414
|
+
return route4(req, config);
|
|
1415
|
+
}
|
|
1416
|
+
if (matches18(configRoutes, req)) {
|
|
1417
|
+
info("matches tenant user");
|
|
1418
|
+
return route18(req, config);
|
|
1419
|
+
}
|
|
1420
|
+
if (matches3(configRoutes, req)) {
|
|
1421
|
+
info("matches tenant users");
|
|
1422
|
+
return route3(req, config);
|
|
1423
|
+
}
|
|
1424
|
+
if (matches2(configRoutes, req)) {
|
|
1425
|
+
info("matches users");
|
|
1426
|
+
return route2(req, config);
|
|
1427
|
+
}
|
|
1428
|
+
if (matches(configRoutes, req)) {
|
|
1429
|
+
info("matches me");
|
|
1430
|
+
return route(req, config);
|
|
1431
|
+
}
|
|
1432
|
+
if (matches6(configRoutes, req)) {
|
|
1433
|
+
info("matches tenants");
|
|
1434
|
+
return route6(req, config);
|
|
1435
|
+
}
|
|
1436
|
+
if (matches15(configRoutes, req)) {
|
|
1437
|
+
info("matches reset password");
|
|
1438
|
+
return route15(req, config);
|
|
1439
|
+
}
|
|
1440
|
+
warn("No PUT routes matched");
|
|
1441
|
+
return new Response(null, { status: 404 });
|
|
1442
|
+
};
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
// src/api/handlers/index.ts
|
|
1446
|
+
function Handlers(configRoutes, config) {
|
|
1447
|
+
const GET7 = GETTER(configRoutes, config);
|
|
1448
|
+
const POST6 = POSTER(configRoutes, config);
|
|
1449
|
+
const DELETE5 = DELETER(configRoutes, config);
|
|
1450
|
+
const PUT6 = PUTER(configRoutes, config);
|
|
1451
|
+
return {
|
|
1452
|
+
GET: GET7,
|
|
1453
|
+
POST: POST6,
|
|
1454
|
+
DELETE: DELETE5,
|
|
1455
|
+
PUT: PUT6
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
var getApiUrl = (cfg) => {
|
|
1459
|
+
const { config } = cfg;
|
|
1460
|
+
if (config?.apiUrl != null) {
|
|
1461
|
+
return config?.apiUrl;
|
|
1462
|
+
}
|
|
1463
|
+
if (stringCheck(process.env.NILEDB_API_URL)) {
|
|
1464
|
+
return process.env.NILEDB_API_URL;
|
|
1465
|
+
}
|
|
1466
|
+
throw new Error(
|
|
1467
|
+
"A connection to nile-auth is required. Set NILEDB_API_URL as an environment variable."
|
|
1468
|
+
);
|
|
1469
|
+
};
|
|
1470
|
+
var getCallbackUrl = (cfg) => {
|
|
1471
|
+
const { config } = cfg;
|
|
1472
|
+
if (stringCheck(config?.callbackUrl)) {
|
|
1473
|
+
return config?.callbackUrl;
|
|
1474
|
+
}
|
|
1475
|
+
return process.env.NILEDB_CALLBACK_URL;
|
|
1476
|
+
};
|
|
1477
|
+
var getSecureCookies = (cfg) => {
|
|
1478
|
+
const { config } = cfg;
|
|
1479
|
+
if (config?.secureCookies != null) {
|
|
1480
|
+
return config?.secureCookies;
|
|
1481
|
+
}
|
|
1482
|
+
if (stringCheck(process.env.NILEDB_SECURECOOKIES)) {
|
|
1483
|
+
return Boolean(process.env.NILEDB_SECURECOOKIES);
|
|
1484
|
+
}
|
|
1485
|
+
return void 0;
|
|
1486
|
+
};
|
|
1487
|
+
var getUsername = (cfg) => {
|
|
1488
|
+
const { config } = cfg;
|
|
1489
|
+
const logger = config.logger;
|
|
1490
|
+
const { info } = logger();
|
|
1491
|
+
if (config?.user) {
|
|
1492
|
+
info(`[config] ${config.user}`);
|
|
1493
|
+
return String(config?.user);
|
|
1494
|
+
}
|
|
1495
|
+
const user = stringCheck(process.env.NILEDB_USER);
|
|
1496
|
+
if (user) {
|
|
1497
|
+
info(`[NILEDB_USER] ${user}`);
|
|
1498
|
+
return user;
|
|
1499
|
+
}
|
|
1500
|
+
const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
|
|
1501
|
+
if (pg2) {
|
|
1502
|
+
try {
|
|
1503
|
+
const url = new URL(pg2);
|
|
1504
|
+
if (url.username) {
|
|
1505
|
+
return url.username;
|
|
1506
|
+
}
|
|
1507
|
+
} catch (e) {
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
throw new Error(
|
|
1511
|
+
"A database user is required. Set NILEDB_USER as an environment variable."
|
|
1512
|
+
);
|
|
1513
|
+
};
|
|
1514
|
+
var getPassword = (cfg) => {
|
|
1515
|
+
const { config } = cfg;
|
|
1516
|
+
const logger = config.logger;
|
|
1517
|
+
const log = logProtector(logger);
|
|
1518
|
+
if (stringCheck(config?.password)) {
|
|
1519
|
+
log && log("[config]").info("***");
|
|
1520
|
+
return String(config?.password);
|
|
1521
|
+
}
|
|
1522
|
+
const pass = stringCheck(process.env.NILEDB_PASSWORD);
|
|
1523
|
+
if (pass) {
|
|
1524
|
+
logger("[NILEDB_PASSWORD]").info("***");
|
|
1525
|
+
return pass;
|
|
1526
|
+
}
|
|
1527
|
+
const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
|
|
1528
|
+
if (pg2) {
|
|
1529
|
+
try {
|
|
1530
|
+
const url = new URL(pg2);
|
|
1531
|
+
if (url.password) {
|
|
1532
|
+
return url.password;
|
|
1533
|
+
}
|
|
1534
|
+
} catch (e) {
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
throw new Error(
|
|
1538
|
+
"A database password is required. Set NILEDB_PASSWORD as an environment variable."
|
|
1539
|
+
);
|
|
1540
|
+
};
|
|
1541
|
+
var getDatabaseName = (cfg) => {
|
|
1542
|
+
const { config } = cfg;
|
|
1543
|
+
const { info } = config.logger("[databaseName]");
|
|
1544
|
+
if (stringCheck(config?.databaseName)) {
|
|
1545
|
+
info(`[config] ${config?.databaseName}`);
|
|
1546
|
+
return String(config?.databaseName);
|
|
1547
|
+
}
|
|
1548
|
+
const name = stringCheck(process.env.NILEDB_NAME);
|
|
1549
|
+
if (name) {
|
|
1550
|
+
info(`[NILEDB_NAME] ${name}`);
|
|
1551
|
+
return name;
|
|
1552
|
+
}
|
|
1553
|
+
if (process.env.NILEDB_POSTGRES_URL) {
|
|
1554
|
+
try {
|
|
1555
|
+
const pgUrl = new URL(process.env.NILEDB_POSTGRES_URL);
|
|
1556
|
+
return pgUrl.pathname.substring(1);
|
|
1557
|
+
} catch (e) {
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
throw new Error(
|
|
1561
|
+
"A database name is required. Set NILEDB_PASSWORD as an environment variable."
|
|
1562
|
+
);
|
|
1563
|
+
};
|
|
1564
|
+
var getTenantId = (cfg) => {
|
|
1565
|
+
const { config } = cfg;
|
|
1566
|
+
const { info } = config.logger("[tenantId]");
|
|
1567
|
+
if (stringCheck(config?.tenantId)) {
|
|
1568
|
+
info(`[config] ${config?.tenantId}`);
|
|
1569
|
+
return String(config?.tenantId);
|
|
1570
|
+
}
|
|
1571
|
+
if (stringCheck(process.env.NILEDB_TENANT)) {
|
|
1572
|
+
info(`[NILEDB_TENANT] ${process.env.NILEDB_TENANT}`);
|
|
1573
|
+
return String(process.env.NILEDB_TENANT);
|
|
1574
|
+
}
|
|
1575
|
+
return null;
|
|
1576
|
+
};
|
|
1577
|
+
function getDbHost(cfg) {
|
|
1578
|
+
const { config } = cfg;
|
|
1579
|
+
const logger = config.logger;
|
|
1580
|
+
const { info } = logger("[db.host]");
|
|
1581
|
+
if (stringCheck(config?.db && config.db.host)) {
|
|
1582
|
+
info(`[config] ${config?.db?.host}`);
|
|
1583
|
+
return String(config?.db?.host);
|
|
1584
|
+
}
|
|
1585
|
+
if (stringCheck(process.env.NILEDB_HOST)) {
|
|
1586
|
+
info(`[NILEDB_HOST] ${process.env.NILEDB_HOST}`);
|
|
1587
|
+
return process.env.NILEDB_HOST;
|
|
1588
|
+
}
|
|
1589
|
+
const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
|
|
1590
|
+
if (pg2) {
|
|
1591
|
+
try {
|
|
1592
|
+
const pgUrl = new URL(pg2);
|
|
1593
|
+
info(`[NILEDB_POSTGRES_URL] ${pgUrl.hostname}`);
|
|
1594
|
+
return pgUrl.hostname;
|
|
1595
|
+
} catch (e) {
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
info("[default] db.thenile.dev");
|
|
1599
|
+
return "db.thenile.dev";
|
|
1600
|
+
}
|
|
1601
|
+
function getDbPort(cfg) {
|
|
1602
|
+
const { config } = cfg;
|
|
1603
|
+
const logger = config.logger;
|
|
1604
|
+
const { info } = logger("[db.port]");
|
|
1605
|
+
if (config?.db?.port && config.db.port != null) {
|
|
1606
|
+
info(`[config] ${config?.db.port}`);
|
|
1607
|
+
return Number(config.db?.port);
|
|
1608
|
+
}
|
|
1609
|
+
if (stringCheck(process.env.NILEDB_PORT)) {
|
|
1610
|
+
info(`[NILEDB_PORT] ${process.env.NILEDB_PORT}`);
|
|
1611
|
+
return Number(process.env.NILEDB_PORT);
|
|
1612
|
+
}
|
|
1613
|
+
const pg2 = stringCheck(process.env.NILEDB_POSTGRES_URL);
|
|
1614
|
+
if (pg2) {
|
|
1615
|
+
try {
|
|
1616
|
+
const pgUrl = new URL(pg2);
|
|
1617
|
+
if (pgUrl.port) {
|
|
1618
|
+
return Number(pgUrl.port);
|
|
1619
|
+
}
|
|
1620
|
+
} catch (e) {
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
info("[default] 5432");
|
|
1624
|
+
return 5432;
|
|
1625
|
+
}
|
|
1626
|
+
var logProtector = (logger) => {
|
|
1627
|
+
return process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test" ? logger : null;
|
|
1628
|
+
};
|
|
1629
|
+
var stringCheck = (str) => {
|
|
1630
|
+
if (str && str !== "") {
|
|
1631
|
+
return str;
|
|
1632
|
+
}
|
|
1633
|
+
return;
|
|
1634
|
+
};
|
|
1635
|
+
|
|
1636
|
+
// src/utils/Config/index.ts
|
|
1637
|
+
var Config = class {
|
|
1638
|
+
routes;
|
|
1639
|
+
handlers;
|
|
1640
|
+
paths;
|
|
1641
|
+
extensionCtx;
|
|
1642
|
+
extensions;
|
|
1643
|
+
logger;
|
|
1644
|
+
/**
|
|
1645
|
+
* Stores the set tenant id from Server for use in sub classes
|
|
1646
|
+
*/
|
|
1647
|
+
tenantId;
|
|
1648
|
+
/**
|
|
1649
|
+
* Stores the set user id from Server for use in sub classes
|
|
1650
|
+
*/
|
|
1651
|
+
userId;
|
|
1652
|
+
/**
|
|
1653
|
+
* Stores the headers to be used in `fetch` calls
|
|
1654
|
+
*/
|
|
1655
|
+
headers;
|
|
1656
|
+
/**
|
|
1657
|
+
* The nile-auth url
|
|
1658
|
+
*/
|
|
1659
|
+
apiUrl;
|
|
1660
|
+
origin;
|
|
1661
|
+
/**
|
|
1662
|
+
* important for separating the `origin` config value from a default in order to make requests
|
|
1663
|
+
*/
|
|
1664
|
+
serverOrigin;
|
|
1665
|
+
debug;
|
|
1666
|
+
/**
|
|
1667
|
+
* To use secure cookies or not in the fetch
|
|
1668
|
+
*/
|
|
1669
|
+
secureCookies;
|
|
1670
|
+
callbackUrl;
|
|
1671
|
+
/**
|
|
1672
|
+
* change the starting route
|
|
1673
|
+
*/
|
|
1674
|
+
routePrefix;
|
|
1675
|
+
db;
|
|
1676
|
+
constructor(config) {
|
|
1677
|
+
this.routePrefix = config?.routePrefix ?? "/api";
|
|
1678
|
+
this.debug = config?.debug;
|
|
1679
|
+
this.origin = config?.origin;
|
|
1680
|
+
this.extensions = config?.extensions;
|
|
1681
|
+
this.extensionCtx = config?.extensionCtx;
|
|
1682
|
+
this.serverOrigin = config?.origin ?? "http://localhost:3000";
|
|
1683
|
+
this.logger = Logger(config);
|
|
1684
|
+
const envVarConfig = {
|
|
1685
|
+
config: { ...config, logger: this.logger }
|
|
1686
|
+
};
|
|
1687
|
+
this.secureCookies = getSecureCookies(envVarConfig);
|
|
1688
|
+
this.callbackUrl = getCallbackUrl(envVarConfig);
|
|
1689
|
+
this.apiUrl = getApiUrl(envVarConfig);
|
|
1690
|
+
const user = getUsername(envVarConfig);
|
|
1691
|
+
const password = getPassword(envVarConfig);
|
|
1692
|
+
const databaseName = getDatabaseName(envVarConfig);
|
|
1693
|
+
const { host, port, ...dbConfig } = config?.db ?? {};
|
|
1694
|
+
const configuredHost = host ?? getDbHost(envVarConfig);
|
|
1695
|
+
const configuredPort = port ?? getDbPort(envVarConfig);
|
|
1696
|
+
this.db = {
|
|
1697
|
+
user,
|
|
1698
|
+
password,
|
|
1699
|
+
host: configuredHost,
|
|
1700
|
+
port: configuredPort,
|
|
1701
|
+
...dbConfig
|
|
1702
|
+
};
|
|
1703
|
+
if (databaseName) {
|
|
1704
|
+
this.db.database = databaseName;
|
|
1705
|
+
}
|
|
1706
|
+
if (config?.headers) {
|
|
1707
|
+
this.headers = config?.headers;
|
|
1708
|
+
} else {
|
|
1709
|
+
this.headers = new Headers();
|
|
1710
|
+
}
|
|
1711
|
+
this.routes = {
|
|
1712
|
+
...appRoutes(config?.routePrefix),
|
|
1713
|
+
...config?.routes
|
|
1714
|
+
};
|
|
1715
|
+
this.handlers = Handlers(this.routes, this);
|
|
1716
|
+
this.paths = {
|
|
1717
|
+
get: [
|
|
1718
|
+
this.routes.ME,
|
|
1719
|
+
this.routes.TENANT_USERS,
|
|
1720
|
+
this.routes.TENANTS,
|
|
1721
|
+
this.routes.TENANT,
|
|
1722
|
+
this.routes.SESSION,
|
|
1723
|
+
this.routes.SIGNIN,
|
|
1724
|
+
this.routes.PROVIDERS,
|
|
1725
|
+
this.routes.CSRF,
|
|
1726
|
+
this.routes.PASSWORD_RESET,
|
|
1727
|
+
this.routes.CALLBACK,
|
|
1728
|
+
this.routes.SIGNOUT,
|
|
1729
|
+
this.routes.VERIFY_REQUEST,
|
|
1730
|
+
this.routes.ERROR
|
|
1731
|
+
],
|
|
1732
|
+
post: [
|
|
1733
|
+
this.routes.TENANT_USERS,
|
|
1734
|
+
this.routes.SIGNUP,
|
|
1735
|
+
this.routes.USERS,
|
|
1736
|
+
this.routes.TENANTS,
|
|
1737
|
+
this.routes.SESSION,
|
|
1738
|
+
`${this.routes.SIGNIN}/{provider}`,
|
|
1739
|
+
this.routes.PASSWORD_RESET,
|
|
1740
|
+
this.routes.PROVIDERS,
|
|
1741
|
+
this.routes.CSRF,
|
|
1742
|
+
`${this.routes.CALLBACK}/{provider}`,
|
|
1743
|
+
this.routes.SIGNOUT
|
|
1744
|
+
],
|
|
1745
|
+
put: [
|
|
1746
|
+
this.routes.TENANT_USERS,
|
|
1747
|
+
this.routes.USERS,
|
|
1748
|
+
this.routes.TENANT,
|
|
1749
|
+
this.routes.PASSWORD_RESET
|
|
1750
|
+
],
|
|
1751
|
+
delete: [this.routes.TENANT_USER, this.routes.TENANT]
|
|
1752
|
+
};
|
|
1753
|
+
this.tenantId = config?.tenantId;
|
|
1754
|
+
this.userId = config?.userId;
|
|
1755
|
+
}
|
|
1756
|
+
};
|
|
1757
|
+
|
|
1758
|
+
// src/utils/Event/index.ts
|
|
1759
|
+
var Eventer = class {
|
|
1760
|
+
events = {};
|
|
1761
|
+
publish(eventName, value) {
|
|
1762
|
+
const callbacks = this.events[eventName];
|
|
1763
|
+
if (callbacks) {
|
|
1764
|
+
for (const callback of callbacks) {
|
|
1765
|
+
callback(value);
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
subscribe(eventName, callback) {
|
|
1770
|
+
if (!this.events[eventName]) {
|
|
1771
|
+
this.events[eventName] = [];
|
|
1772
|
+
}
|
|
1773
|
+
this.events[eventName].push(callback);
|
|
1774
|
+
}
|
|
1775
|
+
unsubscribe(eventName, callback) {
|
|
1776
|
+
const callbacks = this.events[eventName];
|
|
1777
|
+
if (!callbacks) return;
|
|
1778
|
+
const index = callbacks.indexOf(callback);
|
|
1779
|
+
if (index !== -1) {
|
|
1780
|
+
callbacks.splice(index, 1);
|
|
1781
|
+
}
|
|
1782
|
+
if (callbacks.length === 0) {
|
|
1783
|
+
delete this.events[eventName];
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
};
|
|
1787
|
+
var eventer = new Eventer();
|
|
1788
|
+
var updateTenantId = (tenantId) => {
|
|
1789
|
+
eventer.publish("tenantId" /* Tenant */, tenantId);
|
|
1790
|
+
};
|
|
1791
|
+
var watchTenantId = (cb) => eventer.subscribe("tenantId" /* Tenant */, cb);
|
|
1792
|
+
var watchUserId = (cb) => eventer.subscribe("userId" /* User */, cb);
|
|
1793
|
+
var evictPool = (val) => {
|
|
1794
|
+
eventer.publish("EvictPool" /* EvictPool */, val);
|
|
1795
|
+
};
|
|
1796
|
+
var watchEvictPool = (cb) => eventer.subscribe("EvictPool" /* EvictPool */, cb);
|
|
1797
|
+
var updateHeaders = (val) => {
|
|
1798
|
+
eventer.publish("headers" /* Headers */, val);
|
|
1799
|
+
};
|
|
1800
|
+
var watchHeaders = (cb) => eventer.subscribe("headers" /* Headers */, cb);
|
|
1801
|
+
|
|
1802
|
+
// src/db/PoolProxy.ts
|
|
1803
|
+
function createProxyForPool(pool, config) {
|
|
1804
|
+
const { info, error } = config.logger("[pool]");
|
|
1805
|
+
return new Proxy(pool, {
|
|
1806
|
+
get(target, property) {
|
|
1807
|
+
if (property === "query") {
|
|
1808
|
+
if (!config.db.connectionString) {
|
|
1809
|
+
if (!config.db.user || !config.db.password) {
|
|
1810
|
+
error(
|
|
1811
|
+
"Cannot connect to the database. User and/or password are missing. Generate them at https://console.thenile.dev"
|
|
1812
|
+
);
|
|
1813
|
+
} else if (!config.db.database) {
|
|
1814
|
+
error(
|
|
1815
|
+
"Unable to obtain database name. Is process.env.NILEDB_POSTGRES_URL set?"
|
|
1816
|
+
);
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
const caller = target[property];
|
|
1820
|
+
return function query(...args) {
|
|
1821
|
+
info("query", ...args);
|
|
1822
|
+
const called = caller.apply(this, args);
|
|
1823
|
+
return called;
|
|
1824
|
+
};
|
|
1825
|
+
}
|
|
1826
|
+
return target[property];
|
|
1827
|
+
}
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
// src/db/NileInstance.ts
|
|
1832
|
+
var NileDatabase = class {
|
|
1833
|
+
pool;
|
|
1834
|
+
tenantId;
|
|
1835
|
+
userId;
|
|
1836
|
+
id;
|
|
1837
|
+
config;
|
|
1838
|
+
timer;
|
|
1839
|
+
constructor(config, id) {
|
|
1840
|
+
const { warn, info, debug } = config.logger("[NileInstance]");
|
|
1841
|
+
this.id = id;
|
|
1842
|
+
const poolConfig = {
|
|
1843
|
+
min: 0,
|
|
1844
|
+
max: 10,
|
|
1845
|
+
idleTimeoutMillis: 3e4,
|
|
1846
|
+
...config.db
|
|
1847
|
+
};
|
|
1848
|
+
const { afterCreate, ...remaining } = poolConfig;
|
|
1849
|
+
config.db = poolConfig;
|
|
1850
|
+
this.config = config;
|
|
1851
|
+
const cloned = { ...this.config.db };
|
|
1852
|
+
cloned.password = "***";
|
|
1853
|
+
debug(`Connection pool config ${JSON.stringify(cloned)}`);
|
|
1854
|
+
this.pool = createProxyForPool(new pg__default.default.Pool(remaining), this.config);
|
|
1855
|
+
if (typeof afterCreate === "function") {
|
|
1856
|
+
warn(
|
|
1857
|
+
"Providing an pool configuration will stop automatic tenant context setting."
|
|
1858
|
+
);
|
|
1859
|
+
}
|
|
1860
|
+
this.startTimeout();
|
|
1861
|
+
this.pool.on("connect", async (client) => {
|
|
1862
|
+
debug(`pool connected ${this.id}`);
|
|
1863
|
+
this.startTimeout();
|
|
1864
|
+
const afterCreate2 = makeAfterCreate(
|
|
1865
|
+
config,
|
|
1866
|
+
`${this.id}-${this.timer}`
|
|
1867
|
+
);
|
|
1868
|
+
afterCreate2(client, (err) => {
|
|
1869
|
+
const { error } = config.logger("[after create callback]");
|
|
1870
|
+
if (err) {
|
|
1871
|
+
clearTimeout(this.timer);
|
|
1872
|
+
error("after create failed", {
|
|
1873
|
+
message: err.message,
|
|
1874
|
+
stack: err.stack
|
|
1875
|
+
});
|
|
1876
|
+
evictPool(this.id);
|
|
1877
|
+
}
|
|
1878
|
+
});
|
|
1879
|
+
});
|
|
1880
|
+
this.pool.on("error", (err) => {
|
|
1881
|
+
clearTimeout(this.timer);
|
|
1882
|
+
info(`pool ${this.id} failed`, {
|
|
1883
|
+
message: err.message,
|
|
1884
|
+
stack: err.stack
|
|
1885
|
+
});
|
|
1886
|
+
evictPool(this.id);
|
|
1887
|
+
});
|
|
1888
|
+
this.pool.on("release", (destroy) => {
|
|
1889
|
+
if (destroy) {
|
|
1890
|
+
clearTimeout(this.timer);
|
|
1891
|
+
evictPool(this.id);
|
|
1892
|
+
debug(`destroying pool ${this.id}`);
|
|
1893
|
+
}
|
|
1894
|
+
});
|
|
1895
|
+
}
|
|
1896
|
+
startTimeout() {
|
|
1897
|
+
const { debug } = this.config.logger("[NileInstance]");
|
|
1898
|
+
if (this.timer) {
|
|
1899
|
+
clearTimeout(this.timer);
|
|
1900
|
+
}
|
|
1901
|
+
this.timer = setTimeout(() => {
|
|
1902
|
+
debug(
|
|
1903
|
+
`Pool reached idleTimeoutMillis. ${this.id} evicted after ${Number(this.config.db.idleTimeoutMillis) ?? 3e4}ms`
|
|
1904
|
+
);
|
|
1905
|
+
this.pool.end(() => {
|
|
1906
|
+
clearTimeout(this.timer);
|
|
1907
|
+
evictPool(this.id);
|
|
1908
|
+
});
|
|
1909
|
+
}, Number(this.config.db.idleTimeoutMillis) ?? 3e4);
|
|
1910
|
+
}
|
|
1911
|
+
shutdown() {
|
|
1912
|
+
const { debug } = this.config.logger("[NileInstance]");
|
|
1913
|
+
debug(`attempting to shut down ${this.id}`);
|
|
1914
|
+
clearTimeout(this.timer);
|
|
1915
|
+
this.pool.end(() => {
|
|
1916
|
+
debug(`${this.id} has been shut down`);
|
|
1917
|
+
});
|
|
1918
|
+
}
|
|
1919
|
+
};
|
|
1920
|
+
var NileInstance_default = NileDatabase;
|
|
1921
|
+
function makeAfterCreate(config, id) {
|
|
1922
|
+
const { error, warn, debug } = config.logger("[afterCreate]");
|
|
1923
|
+
return (conn, done) => {
|
|
1924
|
+
conn.on("error", function errorHandler(e) {
|
|
1925
|
+
error(`Connection ${id} was terminated by server`, {
|
|
1926
|
+
message: e.message,
|
|
1927
|
+
stack: e.stack
|
|
1928
|
+
});
|
|
1929
|
+
done(e, conn);
|
|
1930
|
+
});
|
|
1931
|
+
if (config.tenantId) {
|
|
1932
|
+
const query = [`SET nile.tenant_id = '${config.tenantId}'`];
|
|
1933
|
+
if (config.userId) {
|
|
1934
|
+
if (!config.tenantId) {
|
|
1935
|
+
warn("A user id cannot be set in context without a tenant id");
|
|
1936
|
+
}
|
|
1937
|
+
query.push(`SET nile.user_id = '${config.userId}'`);
|
|
1938
|
+
}
|
|
1939
|
+
conn.query(query.join(";"), function(err) {
|
|
1940
|
+
if (err) {
|
|
1941
|
+
error("query connection failed", {
|
|
1942
|
+
cause: err.cause,
|
|
1943
|
+
stack: err.stack,
|
|
1944
|
+
message: err.message,
|
|
1945
|
+
name: err.name,
|
|
1946
|
+
id
|
|
1947
|
+
});
|
|
1948
|
+
} else {
|
|
1949
|
+
if (query.length === 1) {
|
|
1950
|
+
debug(`connection context set: tenantId=${config.tenantId}`);
|
|
1951
|
+
}
|
|
1952
|
+
if (query.length === 2) {
|
|
1953
|
+
debug(
|
|
1954
|
+
`connection context set: tenantId=${config.tenantId} userId=${config.userId}`
|
|
1955
|
+
);
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
done(err, conn);
|
|
1959
|
+
});
|
|
1960
|
+
}
|
|
1961
|
+
done(null, conn);
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
// src/db/DBManager.ts
|
|
1966
|
+
var DBManager = class {
|
|
1967
|
+
connections;
|
|
1968
|
+
cleared;
|
|
1969
|
+
poolWatcherFn;
|
|
1970
|
+
makeId(tenantId, userId) {
|
|
1971
|
+
if (tenantId && userId) {
|
|
1972
|
+
return `${tenantId}:${userId}`;
|
|
1973
|
+
}
|
|
1974
|
+
if (tenantId) {
|
|
1975
|
+
return `${tenantId}`;
|
|
1976
|
+
}
|
|
1977
|
+
return "base";
|
|
1978
|
+
}
|
|
1979
|
+
constructor(config) {
|
|
1980
|
+
this.cleared = false;
|
|
1981
|
+
this.connections = /* @__PURE__ */ new Map();
|
|
1982
|
+
this.poolWatcherFn = this.poolWatcher(config);
|
|
1983
|
+
watchEvictPool(this.poolWatcherFn);
|
|
1984
|
+
}
|
|
1985
|
+
poolWatcher = (config) => (id) => {
|
|
1986
|
+
const { info, warn } = Logger(config)("[DBManager]");
|
|
1987
|
+
if (id && this.connections.has(id)) {
|
|
1988
|
+
info(`Removing ${id} from db connection pool.`);
|
|
1989
|
+
const connection = this.connections.get(id);
|
|
1990
|
+
connection?.shutdown();
|
|
1991
|
+
this.connections.delete(id);
|
|
1992
|
+
} else {
|
|
1993
|
+
warn(`missed eviction of ${id}`);
|
|
1994
|
+
}
|
|
1995
|
+
};
|
|
1996
|
+
getConnection = (config) => {
|
|
1997
|
+
const { info } = Logger(config)("[DBManager]");
|
|
1998
|
+
const id = this.makeId(config.tenantId, config.userId);
|
|
1999
|
+
const existing = this.connections.get(id);
|
|
2000
|
+
info(`# of instances: ${this.connections.size}`);
|
|
2001
|
+
if (existing) {
|
|
2002
|
+
info(`returning existing ${id}`);
|
|
2003
|
+
existing.startTimeout();
|
|
2004
|
+
return existing.pool;
|
|
2005
|
+
}
|
|
2006
|
+
const newOne = new NileInstance_default(new Config(config), id);
|
|
2007
|
+
this.connections.set(id, newOne);
|
|
2008
|
+
info(`created new ${id}`);
|
|
2009
|
+
info(`# of instances: ${this.connections.size}`);
|
|
2010
|
+
if (this.cleared) {
|
|
2011
|
+
this.cleared = false;
|
|
2012
|
+
}
|
|
2013
|
+
return newOne.pool;
|
|
2014
|
+
};
|
|
2015
|
+
clear = (config) => {
|
|
2016
|
+
const { info } = Logger(config)("[DBManager]");
|
|
2017
|
+
info(`Clearing all connections ${this.connections.size}`);
|
|
2018
|
+
this.cleared = true;
|
|
2019
|
+
this.connections.forEach((connection) => {
|
|
2020
|
+
connection.shutdown();
|
|
2021
|
+
});
|
|
2022
|
+
this.connections.clear();
|
|
2023
|
+
};
|
|
2024
|
+
};
|
|
2025
|
+
|
|
2026
|
+
// src/auth/index.ts
|
|
2027
|
+
var Auth = class {
|
|
2028
|
+
#logger;
|
|
2029
|
+
#config;
|
|
2030
|
+
constructor(config) {
|
|
2031
|
+
this.#config = config;
|
|
2032
|
+
this.#logger = config.logger("[auth]");
|
|
2033
|
+
}
|
|
2034
|
+
async getSession(rawResponse = false) {
|
|
2035
|
+
const res = await fetchSession(this.#config);
|
|
2036
|
+
if (rawResponse) {
|
|
2037
|
+
return res;
|
|
2038
|
+
}
|
|
2039
|
+
try {
|
|
2040
|
+
const session = await res.clone().json();
|
|
2041
|
+
if (Object.keys(session).length === 0) {
|
|
2042
|
+
return void 0;
|
|
2043
|
+
}
|
|
2044
|
+
return session;
|
|
2045
|
+
} catch {
|
|
2046
|
+
return res;
|
|
1665
2047
|
}
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
2048
|
+
}
|
|
2049
|
+
async getCsrf(rawResponse = false) {
|
|
2050
|
+
return await obtainCsrf(this.#config, rawResponse);
|
|
2051
|
+
}
|
|
2052
|
+
async listProviders(rawResponse = false) {
|
|
2053
|
+
const res = await fetchProviders(this.#config);
|
|
2054
|
+
if (rawResponse) {
|
|
2055
|
+
return res;
|
|
1669
2056
|
}
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
2057
|
+
try {
|
|
2058
|
+
return await res.clone().json();
|
|
2059
|
+
} catch {
|
|
2060
|
+
return res;
|
|
1673
2061
|
}
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
2062
|
+
}
|
|
2063
|
+
async signOut() {
|
|
2064
|
+
const csrfRes = await this.getCsrf();
|
|
2065
|
+
if (!("csrfToken" in csrfRes)) {
|
|
2066
|
+
throw new Error("Unable to obtain CSRF token. Sign out failed.");
|
|
1677
2067
|
}
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
2068
|
+
const body = JSON.stringify({
|
|
2069
|
+
csrfToken: csrfRes.csrfToken,
|
|
2070
|
+
json: true
|
|
2071
|
+
});
|
|
2072
|
+
const res = await fetchSignOut(this.#config, body);
|
|
2073
|
+
updateHeaders(new Headers({}));
|
|
2074
|
+
this.#config.headers = new Headers();
|
|
2075
|
+
return res;
|
|
2076
|
+
}
|
|
2077
|
+
async signUp(payload, rawResponse) {
|
|
2078
|
+
this.#config.headers = new Headers();
|
|
2079
|
+
const { email, password, ...params } = payload;
|
|
2080
|
+
if (!email || !password) {
|
|
2081
|
+
throw new Error(
|
|
2082
|
+
"Server side sign up requires a user email and password."
|
|
2083
|
+
);
|
|
1681
2084
|
}
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
2085
|
+
const providers = await this.listProviders();
|
|
2086
|
+
const { credentials } = providers ?? {};
|
|
2087
|
+
if (!credentials) {
|
|
2088
|
+
throw new Error(
|
|
2089
|
+
"Unable to obtain credential provider. Aborting server side sign up."
|
|
2090
|
+
);
|
|
1685
2091
|
}
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
2092
|
+
const csrf = await this.getCsrf();
|
|
2093
|
+
let csrfToken;
|
|
2094
|
+
if ("csrfToken" in csrf) {
|
|
2095
|
+
csrfToken = csrf.csrfToken;
|
|
2096
|
+
} else {
|
|
2097
|
+
throw new Error("Unable to obtain parse CSRF. Request blocked.");
|
|
1689
2098
|
}
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
2099
|
+
const body = JSON.stringify({
|
|
2100
|
+
email,
|
|
2101
|
+
password,
|
|
2102
|
+
csrfToken,
|
|
2103
|
+
callbackUrl: credentials.callbackUrl
|
|
2104
|
+
});
|
|
2105
|
+
const res = await fetchSignUp(this.#config, { body, params });
|
|
2106
|
+
if (res.status > 299) {
|
|
2107
|
+
this.#logger.error(await res.clone().text());
|
|
2108
|
+
return void 0;
|
|
1693
2109
|
}
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
}
|
|
1698
|
-
|
|
1699
|
-
// src/api/handlers/DELETE.ts
|
|
1700
|
-
function DELETER(configRoutes, config) {
|
|
1701
|
-
const { info, warn } = Logger(config, "[DELETE MATCHER]");
|
|
1702
|
-
return async function DELETE3(req) {
|
|
1703
|
-
if (matches3(configRoutes, req)) {
|
|
1704
|
-
info("matches tenant users");
|
|
1705
|
-
return route3(req, config);
|
|
2110
|
+
const token = parseToken(res.headers);
|
|
2111
|
+
if (!token) {
|
|
2112
|
+
throw new Error("Server side sign up failed. Session token not found");
|
|
1706
2113
|
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
2114
|
+
this.#config.headers?.append("cookie", token);
|
|
2115
|
+
updateHeaders(this.#config.headers);
|
|
2116
|
+
if (rawResponse) {
|
|
2117
|
+
return res;
|
|
1710
2118
|
}
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
return route3(req, config);
|
|
2119
|
+
try {
|
|
2120
|
+
const json = await res.clone().json();
|
|
2121
|
+
if (json && typeof json === "object" && "tenants" in json) {
|
|
2122
|
+
const tenantId = json.tenants[0];
|
|
2123
|
+
if (tenantId) {
|
|
2124
|
+
updateTenantId(tenantId);
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
return json;
|
|
2128
|
+
} catch {
|
|
2129
|
+
return res;
|
|
1723
2130
|
}
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
2131
|
+
}
|
|
2132
|
+
async forgotPassword(req) {
|
|
2133
|
+
let email = "";
|
|
2134
|
+
const defaults = defaultCallbackUrl({
|
|
2135
|
+
config: this.#config
|
|
2136
|
+
});
|
|
2137
|
+
let callbackUrl = defaults.callbackUrl;
|
|
2138
|
+
let redirectUrl = defaults.redirectUrl;
|
|
2139
|
+
if ("email" in req) {
|
|
2140
|
+
email = req.email;
|
|
1727
2141
|
}
|
|
1728
|
-
if (
|
|
1729
|
-
|
|
1730
|
-
return route4(req, config);
|
|
2142
|
+
if ("callbackUrl" in req) {
|
|
2143
|
+
callbackUrl = req.callbackUrl ? req.callbackUrl : null;
|
|
1731
2144
|
}
|
|
1732
|
-
if (
|
|
1733
|
-
|
|
1734
|
-
return route13(req, config);
|
|
2145
|
+
if ("redirectUrl" in req) {
|
|
2146
|
+
redirectUrl = req.redirectUrl ? req.redirectUrl : null;
|
|
1735
2147
|
}
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
const POST5 = POSTER(configRoutes, config);
|
|
1745
|
-
const DELETE3 = DELETER(configRoutes, config);
|
|
1746
|
-
const PUT4 = PUTER(configRoutes, config);
|
|
1747
|
-
return {
|
|
1748
|
-
GET: GET6,
|
|
1749
|
-
POST: POST5,
|
|
1750
|
-
DELETE: DELETE3,
|
|
1751
|
-
PUT: PUT4
|
|
1752
|
-
};
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
// src/api/utils/routes/defaultRoutes.ts
|
|
1756
|
-
var appRoutes = (prefix = "/api") => ({
|
|
1757
|
-
SIGNIN: `${prefix}/auth/signin`,
|
|
1758
|
-
PROVIDERS: `${prefix}/auth/providers`,
|
|
1759
|
-
SESSION: `${prefix}/auth/session`,
|
|
1760
|
-
CSRF: `${prefix}/auth/csrf`,
|
|
1761
|
-
CALLBACK: `${prefix}/auth/callback`,
|
|
1762
|
-
SIGNOUT: `${prefix}/auth/signout`,
|
|
1763
|
-
ERROR: `${prefix}/auth/error`,
|
|
1764
|
-
VERIFY_REQUEST: `${prefix}/auth/verify-request`,
|
|
1765
|
-
PASSWORD_RESET: `${prefix}/auth/reset-password`,
|
|
1766
|
-
ME: `${prefix}/me`,
|
|
1767
|
-
USERS: `${prefix}/users`,
|
|
1768
|
-
TENANTS: `${prefix}/tenants`,
|
|
1769
|
-
TENANT: `${prefix}/tenants/{tenantId}`,
|
|
1770
|
-
TENANT_USER: `${prefix}/tenants/{tenantId}/users/{userId}`,
|
|
1771
|
-
TENANT_USERS: `${prefix}/tenants/{tenantId}/users`,
|
|
1772
|
-
SIGNUP: `${prefix}/signup`,
|
|
1773
|
-
LOG: `${prefix}/_log`
|
|
1774
|
-
});
|
|
1775
|
-
|
|
1776
|
-
// src/utils/Requester/index.ts
|
|
1777
|
-
var Requester = class extends Config {
|
|
1778
|
-
constructor(config) {
|
|
1779
|
-
super(config);
|
|
1780
|
-
}
|
|
1781
|
-
async rawRequest(method, url, init, body) {
|
|
1782
|
-
const _init = {
|
|
2148
|
+
const body = JSON.stringify({
|
|
2149
|
+
email,
|
|
2150
|
+
redirectUrl,
|
|
2151
|
+
callbackUrl
|
|
2152
|
+
});
|
|
2153
|
+
const data = await fetchResetPassword(
|
|
2154
|
+
this.#config,
|
|
2155
|
+
"POST",
|
|
1783
2156
|
body,
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
* @returns
|
|
1803
|
-
*/
|
|
1804
|
-
async request(method, url, req, init) {
|
|
1805
|
-
const headers = new Headers(init ? init?.headers : {});
|
|
1806
|
-
if (req instanceof Headers) {
|
|
1807
|
-
const tenantId = req.get(X_NILE_TENANT);
|
|
1808
|
-
const cookie = req.get("cookie");
|
|
1809
|
-
if (tenantId) {
|
|
1810
|
-
headers.set(X_NILE_TENANT, tenantId);
|
|
2157
|
+
new URLSearchParams(),
|
|
2158
|
+
false
|
|
2159
|
+
);
|
|
2160
|
+
return data;
|
|
2161
|
+
}
|
|
2162
|
+
async resetPassword(req) {
|
|
2163
|
+
let email = "";
|
|
2164
|
+
let password = "";
|
|
2165
|
+
const defaults = defaultCallbackUrl({ config: this.#config });
|
|
2166
|
+
let callbackUrl = defaults.callbackUrl;
|
|
2167
|
+
let redirectUrl = defaults.redirectUrl;
|
|
2168
|
+
if (req instanceof Request) {
|
|
2169
|
+
const body2 = await req.json();
|
|
2170
|
+
email = body2.email;
|
|
2171
|
+
password = body2.password;
|
|
2172
|
+
const cbFromHeaders = parseCallback(req.headers);
|
|
2173
|
+
if (cbFromHeaders) {
|
|
2174
|
+
callbackUrl = cbFromHeaders;
|
|
1811
2175
|
}
|
|
1812
|
-
if (
|
|
1813
|
-
|
|
2176
|
+
if (body2.callbackUrl) {
|
|
2177
|
+
callbackUrl = body2.callbackUrl;
|
|
1814
2178
|
}
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
const tenantId = _headers.get(X_NILE_TENANT);
|
|
1818
|
-
const cookie = _headers.get("cookie");
|
|
1819
|
-
if (tenantId) {
|
|
1820
|
-
headers.set(X_NILE_TENANT, tenantId);
|
|
2179
|
+
if (body2.redirectUrl) {
|
|
2180
|
+
redirectUrl = body2.redirectUrl;
|
|
1821
2181
|
}
|
|
1822
|
-
|
|
1823
|
-
|
|
2182
|
+
} else {
|
|
2183
|
+
if ("email" in req) {
|
|
2184
|
+
email = req.email;
|
|
1824
2185
|
}
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
if (method === "GET") {
|
|
1828
|
-
body = void 0;
|
|
1829
|
-
} else if (req instanceof Request) {
|
|
1830
|
-
body = await new Response(req.body).text();
|
|
1831
|
-
} else if (
|
|
1832
|
-
// is just headers for a GET request
|
|
1833
|
-
req instanceof Headers || JSON.stringify(req) === "{}" || req && typeof req === "object" && Object.values(req).length === 0
|
|
1834
|
-
) {
|
|
1835
|
-
body = void 0;
|
|
1836
|
-
}
|
|
1837
|
-
const _init = {
|
|
1838
|
-
...init,
|
|
1839
|
-
headers
|
|
1840
|
-
};
|
|
1841
|
-
return await this.rawRequest(method, url, _init, body);
|
|
1842
|
-
}
|
|
1843
|
-
async post(req, url, init) {
|
|
1844
|
-
const response = await this.request("POST", url, req, init);
|
|
1845
|
-
if (response && response.status >= 200 && response.status < 300) {
|
|
1846
|
-
const cloned = response.clone();
|
|
1847
|
-
try {
|
|
1848
|
-
return await cloned.json();
|
|
1849
|
-
} catch (e) {
|
|
2186
|
+
if ("password" in req) {
|
|
2187
|
+
password = req.password;
|
|
1850
2188
|
}
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
if (raw) {
|
|
1857
|
-
return response;
|
|
1858
|
-
}
|
|
1859
|
-
if (response && response.status >= 200 && response.status < 300) {
|
|
1860
|
-
const cloned = response.clone();
|
|
1861
|
-
try {
|
|
1862
|
-
return await cloned.json();
|
|
1863
|
-
} catch (e) {
|
|
2189
|
+
if ("callbackUrl" in req) {
|
|
2190
|
+
callbackUrl = req.callbackUrl ? req.callbackUrl : null;
|
|
2191
|
+
}
|
|
2192
|
+
if ("redirectUrl" in req) {
|
|
2193
|
+
redirectUrl = req.redirectUrl ? req.redirectUrl : null;
|
|
1864
2194
|
}
|
|
1865
2195
|
}
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
2196
|
+
await this.getCsrf();
|
|
2197
|
+
const body = JSON.stringify({
|
|
2198
|
+
email,
|
|
2199
|
+
password,
|
|
2200
|
+
redirectUrl,
|
|
2201
|
+
callbackUrl
|
|
2202
|
+
});
|
|
2203
|
+
let urlWithParams;
|
|
2204
|
+
try {
|
|
2205
|
+
const data = await fetchResetPassword(this.#config, "POST", body);
|
|
2206
|
+
const cloned = data.clone();
|
|
2207
|
+
if (data.status === 400) {
|
|
2208
|
+
const text = await cloned.text();
|
|
2209
|
+
this.#logger.error(text);
|
|
2210
|
+
return data;
|
|
1875
2211
|
}
|
|
2212
|
+
const { url } = await data.json();
|
|
2213
|
+
urlWithParams = url;
|
|
2214
|
+
} catch {
|
|
1876
2215
|
}
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
email,
|
|
1892
|
-
password
|
|
1893
|
-
}) {
|
|
1894
|
-
if (!email || !password) {
|
|
1895
|
-
throw new Error("Server side login requires a user email and password.");
|
|
2216
|
+
let token;
|
|
2217
|
+
try {
|
|
2218
|
+
const worthyParams = new URL(urlWithParams).searchParams;
|
|
2219
|
+
const answer = await fetchResetPassword(
|
|
2220
|
+
this.#config,
|
|
2221
|
+
"GET",
|
|
2222
|
+
null,
|
|
2223
|
+
worthyParams
|
|
2224
|
+
);
|
|
2225
|
+
token = parseResetToken(answer.headers);
|
|
2226
|
+
} catch {
|
|
2227
|
+
this.#logger.warn(
|
|
2228
|
+
"Unable to parse reset password url. Password not reset."
|
|
2229
|
+
);
|
|
1896
2230
|
}
|
|
1897
|
-
const
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
2231
|
+
const cookie = this.#config.headers.get("cookie")?.split("; ");
|
|
2232
|
+
if (token) {
|
|
2233
|
+
cookie?.push(token);
|
|
2234
|
+
} else {
|
|
2235
|
+
throw new Error(
|
|
2236
|
+
"Unable to reset password, reset token is missing from response"
|
|
2237
|
+
);
|
|
2238
|
+
}
|
|
2239
|
+
this.#config.headers = new Headers({
|
|
2240
|
+
...this.#config.headers,
|
|
2241
|
+
cookie: cookie?.join("; ")
|
|
1906
2242
|
});
|
|
1907
|
-
const
|
|
1908
|
-
|
|
1909
|
-
|
|
2243
|
+
const res = await fetchResetPassword(this.#config, "PUT", body);
|
|
2244
|
+
cookie?.pop();
|
|
2245
|
+
const cleaned = cookie?.filter((c) => !c.includes("nile.session")) ?? [];
|
|
2246
|
+
cleaned.push(String(parseToken(res.headers)));
|
|
2247
|
+
const updatedHeaders = new Headers({ cookie: cleaned.join("; ") });
|
|
2248
|
+
updateHeaders(updatedHeaders);
|
|
2249
|
+
return res;
|
|
2250
|
+
}
|
|
2251
|
+
async callback(provider, body) {
|
|
2252
|
+
if (body instanceof Request) {
|
|
2253
|
+
this.#config.headers = body.headers;
|
|
2254
|
+
return await fetchCallback(
|
|
2255
|
+
this.#config,
|
|
2256
|
+
provider,
|
|
2257
|
+
void 0,
|
|
2258
|
+
body,
|
|
2259
|
+
"GET"
|
|
2260
|
+
);
|
|
1910
2261
|
}
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
2262
|
+
return await fetchCallback(this.#config, provider, body);
|
|
2263
|
+
}
|
|
2264
|
+
async signIn(provider, payload, rawResponse) {
|
|
2265
|
+
if (payload instanceof Request) {
|
|
2266
|
+
const body2 = new URLSearchParams(await payload.text());
|
|
2267
|
+
const origin = new URL(payload.url).origin;
|
|
2268
|
+
const payloadUrl = body2?.get("callbackUrl");
|
|
2269
|
+
const csrfToken2 = body2?.get("csrfToken");
|
|
2270
|
+
const callbackUrl = `${!payloadUrl?.startsWith("http") ? origin : ""}${payloadUrl}`;
|
|
2271
|
+
if (!csrfToken2) {
|
|
2272
|
+
throw new Error(
|
|
2273
|
+
"CSRF token in missing from request. Request it by the client before calling sign in"
|
|
2274
|
+
);
|
|
2275
|
+
}
|
|
2276
|
+
this.#config.headers = new Headers(payload.headers);
|
|
2277
|
+
this.#config.headers.set(
|
|
2278
|
+
"Content-Type",
|
|
2279
|
+
"application/x-www-form-urlencoded"
|
|
2280
|
+
);
|
|
2281
|
+
const params = new URLSearchParams({
|
|
2282
|
+
csrfToken: csrfToken2,
|
|
2283
|
+
json: String(true)
|
|
2284
|
+
});
|
|
2285
|
+
if (payloadUrl) {
|
|
2286
|
+
params.set("callbackUrl", callbackUrl);
|
|
2287
|
+
}
|
|
2288
|
+
return await fetchSignIn(this.#config, provider, params);
|
|
1917
2289
|
}
|
|
2290
|
+
this.#config.headers = new Headers();
|
|
2291
|
+
const { info, error } = this.#logger;
|
|
2292
|
+
const providers = await this.listProviders();
|
|
1918
2293
|
info("Obtaining csrf");
|
|
1919
|
-
const csrf =
|
|
1920
|
-
const csrfReq = new Request(csrf, {
|
|
1921
|
-
method: "GET",
|
|
1922
|
-
headers: new Headers({
|
|
1923
|
-
...baseHeaders
|
|
1924
|
-
})
|
|
1925
|
-
});
|
|
1926
|
-
const csrfRes = await handlers.POST(csrfReq);
|
|
2294
|
+
const csrf = await this.getCsrf();
|
|
1927
2295
|
let csrfToken;
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
info(sessionUrl, { csrfRes });
|
|
1933
|
-
error(e, { csrfRes });
|
|
2296
|
+
if ("csrfToken" in csrf) {
|
|
2297
|
+
csrfToken = csrf.csrfToken;
|
|
2298
|
+
} else {
|
|
2299
|
+
throw new Error("Unable to obtain parse CSRF. Request blocked.");
|
|
1934
2300
|
}
|
|
1935
2301
|
const { credentials } = providers ?? {};
|
|
1936
|
-
const csrfCookie = csrfRes?.headers.get("set-cookie");
|
|
1937
2302
|
if (!credentials) {
|
|
1938
2303
|
throw new Error(
|
|
1939
|
-
"Unable to obtain credential provider. Aborting server side
|
|
2304
|
+
"Unable to obtain credential provider. Aborting server side sign in."
|
|
1940
2305
|
);
|
|
1941
2306
|
}
|
|
1942
|
-
const
|
|
1943
|
-
if (!
|
|
1944
|
-
|
|
1945
|
-
|
|
2307
|
+
const { email, password } = payload ?? {};
|
|
2308
|
+
if (provider === "email" && (!email || !password)) {
|
|
2309
|
+
throw new Error(
|
|
2310
|
+
"Server side sign in requires a user email and password."
|
|
2311
|
+
);
|
|
1946
2312
|
}
|
|
1947
|
-
info(`
|
|
2313
|
+
info(`Obtaining providers for ${email}`);
|
|
2314
|
+
info(`Attempting sign in with email ${email}`);
|
|
1948
2315
|
const body = JSON.stringify({
|
|
1949
2316
|
email,
|
|
1950
2317
|
password,
|
|
1951
2318
|
csrfToken,
|
|
1952
2319
|
callbackUrl: credentials.callbackUrl
|
|
1953
2320
|
});
|
|
1954
|
-
const
|
|
1955
|
-
|
|
1956
|
-
headers: new Headers({
|
|
1957
|
-
...baseHeaders,
|
|
1958
|
-
"content-type": "application/json",
|
|
1959
|
-
cookie: csrfCookie.split(",").join("; ")
|
|
1960
|
-
}),
|
|
1961
|
-
body
|
|
1962
|
-
});
|
|
1963
|
-
const loginRes = await handlers.POST(postReq);
|
|
1964
|
-
const authCookie = loginRes?.headers.get("set-cookie");
|
|
2321
|
+
const signInRes = await this.callback(provider, body);
|
|
2322
|
+
const authCookie = signInRes?.headers.get("set-cookie");
|
|
1965
2323
|
if (!authCookie) {
|
|
1966
2324
|
throw new Error("authentication failed");
|
|
1967
2325
|
}
|
|
1968
|
-
const token = parseToken(
|
|
2326
|
+
const token = parseToken(signInRes?.headers);
|
|
2327
|
+
const possibleError = signInRes?.headers.get("location");
|
|
2328
|
+
if (possibleError) {
|
|
2329
|
+
let urlError;
|
|
2330
|
+
try {
|
|
2331
|
+
urlError = new URL(possibleError).searchParams.get("error");
|
|
2332
|
+
} catch {
|
|
2333
|
+
}
|
|
2334
|
+
if (urlError) {
|
|
2335
|
+
error("Unable to log user in", { error: urlError });
|
|
2336
|
+
return new Response(urlError, { status: signInRes.status });
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
1969
2339
|
if (!token) {
|
|
1970
|
-
error("Unable to obtain auth token", {
|
|
2340
|
+
error("Unable to obtain auth token", {
|
|
2341
|
+
authCookie,
|
|
2342
|
+
signInRes
|
|
2343
|
+
});
|
|
1971
2344
|
throw new Error("Server login failed");
|
|
1972
2345
|
}
|
|
1973
|
-
info("Server
|
|
1974
|
-
const
|
|
1975
|
-
|
|
1976
|
-
cookie
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
2346
|
+
info("Server sign in successful", { authCookie });
|
|
2347
|
+
const setCookie = signInRes.headers.get("set-cookie");
|
|
2348
|
+
if (setCookie) {
|
|
2349
|
+
const cookie = [
|
|
2350
|
+
parseCSRF(this.#config.headers),
|
|
2351
|
+
parseCallback(signInRes.headers),
|
|
2352
|
+
parseToken(signInRes.headers)
|
|
2353
|
+
].filter(Boolean).join("; ");
|
|
2354
|
+
updateHeaders(new Headers({ cookie }));
|
|
2355
|
+
} else {
|
|
2356
|
+
error("Unable to set context after sign in", {
|
|
2357
|
+
headers: signInRes.headers
|
|
2358
|
+
});
|
|
2359
|
+
}
|
|
2360
|
+
if (rawResponse) {
|
|
2361
|
+
return signInRes;
|
|
2362
|
+
}
|
|
2363
|
+
try {
|
|
2364
|
+
return await signInRes.clone().json();
|
|
2365
|
+
} catch {
|
|
2366
|
+
return signInRes;
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
};
|
|
2370
|
+
function parseCSRF(headers) {
|
|
2371
|
+
let cookie = headers?.get("set-cookie");
|
|
2372
|
+
if (!cookie) {
|
|
2373
|
+
cookie = headers?.get("cookie");
|
|
2374
|
+
}
|
|
2375
|
+
if (!cookie) {
|
|
2376
|
+
return void 0;
|
|
2377
|
+
}
|
|
2378
|
+
const [, token] = /((__Secure-)?nile\.csrf-token=[^;]+)/.exec(cookie) ?? [];
|
|
2379
|
+
return token;
|
|
2380
|
+
}
|
|
2381
|
+
function parseCallback(headers) {
|
|
2382
|
+
let cookie = headers?.get("set-cookie");
|
|
2383
|
+
if (!cookie) {
|
|
2384
|
+
cookie = headers?.get("cookie");
|
|
2385
|
+
}
|
|
2386
|
+
if (!cookie) {
|
|
2387
|
+
return void 0;
|
|
2388
|
+
}
|
|
2389
|
+
const [, token] = /((__Secure-)?nile\.callback-url=[^;]+)/.exec(cookie) ?? [];
|
|
2390
|
+
return token;
|
|
1980
2391
|
}
|
|
1981
2392
|
function parseToken(headers) {
|
|
1982
2393
|
let authCookie = headers?.get("set-cookie");
|
|
@@ -1989,604 +2400,700 @@ function parseToken(headers) {
|
|
|
1989
2400
|
const [, token] = /((__Secure-)?nile\.session-token=[^;]+)/.exec(authCookie) ?? [];
|
|
1990
2401
|
return token;
|
|
1991
2402
|
}
|
|
1992
|
-
|
|
1993
|
-
headers;
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
this.headers = headers;
|
|
1999
|
-
this.logger = Logger(config, "[auth]");
|
|
2000
|
-
this.resetHeaders = params?.resetHeaders;
|
|
2001
|
-
}
|
|
2002
|
-
handleHeaders(init) {
|
|
2003
|
-
if (this.headers) {
|
|
2004
|
-
const cburl = getCallbackUrl2(this.headers);
|
|
2005
|
-
if (cburl) {
|
|
2006
|
-
try {
|
|
2007
|
-
this.headers.set(X_NILE_ORIGIN, new URL(cburl).origin);
|
|
2008
|
-
} catch (e) {
|
|
2009
|
-
if (this.logger?.debug) {
|
|
2010
|
-
this.logger.debug("Invalid URL supplied by cookie header");
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2013
|
-
}
|
|
2014
|
-
if (init) {
|
|
2015
|
-
init.headers = new Headers({ ...this.headers, ...init?.headers });
|
|
2016
|
-
return init;
|
|
2017
|
-
} else {
|
|
2018
|
-
init = {
|
|
2019
|
-
headers: this.headers
|
|
2020
|
-
};
|
|
2021
|
-
return init;
|
|
2022
|
-
}
|
|
2023
|
-
}
|
|
2403
|
+
function parseResetToken(headers) {
|
|
2404
|
+
let authCookie = headers?.get("set-cookie");
|
|
2405
|
+
if (!authCookie) {
|
|
2406
|
+
authCookie = headers?.get("cookie");
|
|
2407
|
+
}
|
|
2408
|
+
if (!authCookie) {
|
|
2024
2409
|
return void 0;
|
|
2025
2410
|
}
|
|
2026
|
-
|
|
2027
|
-
|
|
2411
|
+
const [, token] = /((__Secure-)?nile\.reset=[^;]+)/.exec(authCookie) ?? [];
|
|
2412
|
+
return token;
|
|
2413
|
+
}
|
|
2414
|
+
function defaultCallbackUrl({ config }) {
|
|
2415
|
+
let cb = null;
|
|
2416
|
+
let redirect = null;
|
|
2417
|
+
const fallbackCb = parseCallback(config.headers);
|
|
2418
|
+
if (fallbackCb) {
|
|
2419
|
+
const [, value] = fallbackCb.split("=");
|
|
2420
|
+
cb = decodeURIComponent(value);
|
|
2421
|
+
if (value) {
|
|
2422
|
+
redirect = `${new URL(cb).origin}${"/auth/reset-password" /* PASSWORD_RESET */}`;
|
|
2423
|
+
}
|
|
2028
2424
|
}
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2425
|
+
return { callbackUrl: cb, redirectUrl: redirect };
|
|
2426
|
+
}
|
|
2427
|
+
|
|
2428
|
+
// src/auth/obtainCsrf.ts
|
|
2429
|
+
async function obtainCsrf(config, rawResponse = false) {
|
|
2430
|
+
const res = await fetchCsrf(config);
|
|
2431
|
+
const csrfCook = parseCSRF(res.headers);
|
|
2432
|
+
if (csrfCook) {
|
|
2433
|
+
const [, value] = csrfCook.split("=");
|
|
2434
|
+
const [token] = decodeURIComponent(value).split("|");
|
|
2435
|
+
const setCookie = res.headers.get("set-cookie");
|
|
2436
|
+
if (setCookie) {
|
|
2437
|
+
const cookie = [
|
|
2438
|
+
csrfCook,
|
|
2439
|
+
parseCallback(res.headers),
|
|
2440
|
+
parseToken(res.headers)
|
|
2441
|
+
].filter(Boolean).join("; ");
|
|
2442
|
+
config.headers.set("cookie", cookie);
|
|
2443
|
+
updateHeaders(new Headers({ cookie }));
|
|
2444
|
+
}
|
|
2445
|
+
if (!rawResponse) {
|
|
2446
|
+
return { csrfToken: token };
|
|
2035
2447
|
}
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2448
|
+
} else {
|
|
2449
|
+
const existingCookie = config.headers.get("cookie");
|
|
2450
|
+
const cookieParts = [];
|
|
2451
|
+
if (existingCookie) {
|
|
2452
|
+
cookieParts.push(
|
|
2453
|
+
parseToken(config.headers),
|
|
2454
|
+
parseCallback(config.headers)
|
|
2455
|
+
);
|
|
2456
|
+
}
|
|
2457
|
+
if (csrfCook) {
|
|
2458
|
+
cookieParts.push(csrfCook);
|
|
2459
|
+
} else {
|
|
2460
|
+
cookieParts.push(parseCSRF(config.headers));
|
|
2461
|
+
}
|
|
2462
|
+
const cookie = cookieParts.filter(Boolean).join("; ");
|
|
2463
|
+
config.headers.set("cookie", cookie);
|
|
2464
|
+
updateHeaders(new Headers({ cookie }));
|
|
2040
2465
|
}
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
const _init = this.handleHeaders(init);
|
|
2044
|
-
return await _requester.get(req, this.getCsrfUrl, _init, raw);
|
|
2466
|
+
if (rawResponse) {
|
|
2467
|
+
return res;
|
|
2045
2468
|
}
|
|
2046
|
-
|
|
2047
|
-
return
|
|
2469
|
+
try {
|
|
2470
|
+
return await res.clone().json();
|
|
2471
|
+
} catch {
|
|
2472
|
+
return res;
|
|
2048
2473
|
}
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
const
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
const
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
// src/users/index.ts
|
|
2477
|
+
var Users = class {
|
|
2478
|
+
#config;
|
|
2479
|
+
#logger;
|
|
2480
|
+
constructor(config) {
|
|
2481
|
+
this.#config = config;
|
|
2482
|
+
this.#logger = config.logger("[me]");
|
|
2483
|
+
}
|
|
2484
|
+
async updateSelf(req, rawResponse) {
|
|
2485
|
+
const res = await fetchMe(this.#config, "PUT", JSON.stringify(req));
|
|
2486
|
+
if (rawResponse) {
|
|
2487
|
+
return res;
|
|
2488
|
+
}
|
|
2489
|
+
try {
|
|
2490
|
+
return await res?.clone().json();
|
|
2491
|
+
} catch {
|
|
2492
|
+
return res;
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
async removeSelf() {
|
|
2496
|
+
const me = await this.getSelf();
|
|
2497
|
+
if ("id" in me) {
|
|
2498
|
+
this.#config.userId = me.id;
|
|
2499
|
+
}
|
|
2500
|
+
const res = await fetchMe(this.#config, "DELETE");
|
|
2501
|
+
updateHeaders(new Headers());
|
|
2502
|
+
return res;
|
|
2503
|
+
}
|
|
2504
|
+
async getSelf(rawResponse) {
|
|
2505
|
+
const res = await fetchMe(this.#config);
|
|
2506
|
+
if (rawResponse) {
|
|
2507
|
+
return res;
|
|
2508
|
+
}
|
|
2509
|
+
try {
|
|
2510
|
+
return await res?.clone().json();
|
|
2511
|
+
} catch {
|
|
2512
|
+
return res;
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
async verifySelf(options, rawResponse = false) {
|
|
2516
|
+
const bypassEmail = typeof options === "object" ? options.bypassEmail ?? process.env.NODE_ENV !== "production" : process.env.NODE_ENV !== "production";
|
|
2517
|
+
const callbackUrl = typeof options === "object" ? options.callbackUrl : defaultCallbackUrl2(this.#config).callbackUrl;
|
|
2518
|
+
let res;
|
|
2519
|
+
try {
|
|
2520
|
+
const me = await this.getSelf();
|
|
2521
|
+
if (me instanceof Response) {
|
|
2522
|
+
return me;
|
|
2080
2523
|
}
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2524
|
+
res = await verifyEmailAddress(this.#config, me, String(callbackUrl));
|
|
2525
|
+
return res;
|
|
2526
|
+
} catch {
|
|
2527
|
+
const message = "Unable to verify email.";
|
|
2528
|
+
this.#logger?.warn(message);
|
|
2529
|
+
res = new Response(message, { status: 400 });
|
|
2530
|
+
}
|
|
2531
|
+
if (bypassEmail) {
|
|
2532
|
+
res = this.updateSelf({ emailVerified: true }, rawResponse);
|
|
2533
|
+
}
|
|
2534
|
+
this.#logger.error(
|
|
2535
|
+
"Unable to verify email address. Configure your SMTP server in the console."
|
|
2085
2536
|
);
|
|
2086
|
-
const res = await _requester.post(req, this.signOutUrl, {
|
|
2087
|
-
method: "post",
|
|
2088
|
-
body: JSON.stringify({
|
|
2089
|
-
csrfToken,
|
|
2090
|
-
callbackUrl,
|
|
2091
|
-
json: String(true)
|
|
2092
|
-
}),
|
|
2093
|
-
..._init,
|
|
2094
|
-
headers
|
|
2095
|
-
});
|
|
2096
|
-
this.resetHeaders && this.resetHeaders();
|
|
2097
2537
|
return res;
|
|
2098
|
-
}
|
|
2538
|
+
}
|
|
2099
2539
|
};
|
|
2100
|
-
function
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2540
|
+
async function verifyEmailAddress(config, user, callback) {
|
|
2541
|
+
config.headers.set("content-type", "application/x-www-form-urlencoded");
|
|
2542
|
+
const { csrfToken } = await obtainCsrf(config);
|
|
2543
|
+
const defaults = defaultCallbackUrl2(config);
|
|
2544
|
+
const callbackUrl = callback ?? String(defaults.callbackUrl);
|
|
2545
|
+
const res = await fetchVerifyEmail(
|
|
2546
|
+
config,
|
|
2547
|
+
"POST",
|
|
2548
|
+
new URLSearchParams({
|
|
2549
|
+
csrfToken,
|
|
2550
|
+
email: user.email,
|
|
2551
|
+
callbackUrl
|
|
2552
|
+
}).toString()
|
|
2553
|
+
);
|
|
2554
|
+
if (res.status > 299) {
|
|
2555
|
+
throw new Error(await res.text());
|
|
2106
2556
|
}
|
|
2557
|
+
return res;
|
|
2107
2558
|
}
|
|
2108
|
-
function
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
}
|
|
2115
|
-
if (validCookie) {
|
|
2116
|
-
return validCookie;
|
|
2117
|
-
}
|
|
2118
|
-
}
|
|
2119
|
-
if (initHeaders) {
|
|
2120
|
-
const cookies = getCookies(initHeaders);
|
|
2121
|
-
if (cookies) {
|
|
2122
|
-
return cookies["__Secure-nile.csrf-token"] || cookies["nile.csrf-token"];
|
|
2123
|
-
}
|
|
2559
|
+
function defaultCallbackUrl2(config) {
|
|
2560
|
+
let cb = null;
|
|
2561
|
+
const fallbackCb = parseCallback(config.headers);
|
|
2562
|
+
if (fallbackCb) {
|
|
2563
|
+
const [, value] = fallbackCb.split("=");
|
|
2564
|
+
cb = decodeURIComponent(value);
|
|
2124
2565
|
}
|
|
2566
|
+
return { callbackUrl: cb };
|
|
2125
2567
|
}
|
|
2126
|
-
var getCookies = (headers) => {
|
|
2127
|
-
if (!headers) return {};
|
|
2128
|
-
const cookieHeader = headers.get("cookie") || "";
|
|
2129
|
-
const setCookieHeaders = headers.get("set-cookie") || "";
|
|
2130
|
-
const allCookies = [
|
|
2131
|
-
...cookieHeader.split("; "),
|
|
2132
|
-
// Regular 'cookie' header (semicolon-separated)
|
|
2133
|
-
...setCookieHeaders.split(/,\s*(?=[^;, ]+=)/)
|
|
2134
|
-
// Smart split for 'set-cookie'
|
|
2135
|
-
].filter(Boolean);
|
|
2136
|
-
return Object.fromEntries(
|
|
2137
|
-
allCookies.map((cookie) => {
|
|
2138
|
-
const [key12, ...val] = cookie.split("=");
|
|
2139
|
-
return [
|
|
2140
|
-
decodeURIComponent(key12.trim()),
|
|
2141
|
-
decodeURIComponent(val.join("=").trim())
|
|
2142
|
-
];
|
|
2143
|
-
})
|
|
2144
|
-
);
|
|
2145
|
-
};
|
|
2146
2568
|
|
|
2147
2569
|
// src/tenants/index.ts
|
|
2148
|
-
var Tenants = class
|
|
2149
|
-
|
|
2150
|
-
constructor(config
|
|
2151
|
-
|
|
2152
|
-
this.headers = headers;
|
|
2153
|
-
}
|
|
2154
|
-
handleHeaders(init) {
|
|
2155
|
-
if (this.headers) {
|
|
2156
|
-
if (init) {
|
|
2157
|
-
init.headers = new Headers({ ...this.headers, ...init?.headers });
|
|
2158
|
-
return init;
|
|
2159
|
-
} else {
|
|
2160
|
-
init = {
|
|
2161
|
-
headers: this.headers
|
|
2162
|
-
};
|
|
2163
|
-
return init;
|
|
2164
|
-
}
|
|
2165
|
-
}
|
|
2166
|
-
return void 0;
|
|
2167
|
-
}
|
|
2168
|
-
get tenantsUrl() {
|
|
2169
|
-
return "/tenants";
|
|
2170
|
-
}
|
|
2171
|
-
get tenantUrl() {
|
|
2172
|
-
return `/tenants/${this.tenantId ?? "{tenantId}"}`;
|
|
2570
|
+
var Tenants = class {
|
|
2571
|
+
#config;
|
|
2572
|
+
constructor(config) {
|
|
2573
|
+
this.#config = config;
|
|
2173
2574
|
}
|
|
2174
|
-
|
|
2175
|
-
let
|
|
2575
|
+
async create(req, rawResponse) {
|
|
2576
|
+
let res;
|
|
2176
2577
|
if (typeof req === "string") {
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
} else if ("name" in req || "id" in req) {
|
|
2185
|
-
_req = new Request(`${this.api.basePath}${this.tenantsUrl}`, {
|
|
2186
|
-
body: JSON.stringify(req),
|
|
2187
|
-
method: "POST",
|
|
2188
|
-
headers: {
|
|
2189
|
-
"content-type": "application/json"
|
|
2190
|
-
}
|
|
2191
|
-
});
|
|
2192
|
-
} else {
|
|
2193
|
-
_req = req;
|
|
2578
|
+
res = await fetchTenants(
|
|
2579
|
+
this.#config,
|
|
2580
|
+
"POST",
|
|
2581
|
+
JSON.stringify({ name: req })
|
|
2582
|
+
);
|
|
2583
|
+
} else if (typeof req === "object" && ("name" in req || "id" in req)) {
|
|
2584
|
+
res = await fetchTenants(this.#config, "POST", JSON.stringify(req));
|
|
2194
2585
|
}
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2586
|
+
if (rawResponse) {
|
|
2587
|
+
return res;
|
|
2588
|
+
}
|
|
2589
|
+
try {
|
|
2590
|
+
return await res?.clone().json();
|
|
2591
|
+
} catch {
|
|
2592
|
+
return res;
|
|
2202
2593
|
}
|
|
2203
|
-
const _requester = new Requester(this);
|
|
2204
|
-
const _init = this.handleHeaders(init);
|
|
2205
|
-
return _requester.get(req, this.tenantUrl, _init);
|
|
2206
|
-
};
|
|
2207
|
-
get tenantListUrl() {
|
|
2208
|
-
return `/users/${this.userId ?? "{userId}"}/tenants`;
|
|
2209
2594
|
}
|
|
2210
|
-
|
|
2211
|
-
const _requester = new Requester(this);
|
|
2212
|
-
const _init = this.handleHeaders(init);
|
|
2213
|
-
return _requester.get(req, this.tenantListUrl, _init);
|
|
2214
|
-
};
|
|
2215
|
-
deleteTenant = async (req, init) => {
|
|
2595
|
+
async delete(req) {
|
|
2216
2596
|
if (typeof req === "string") {
|
|
2217
|
-
this.tenantId = req;
|
|
2597
|
+
this.#config.tenantId = req;
|
|
2218
2598
|
}
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
return _requester.delete(req, this.tenantUrl, _init);
|
|
2222
|
-
};
|
|
2223
|
-
updateTenant = async (req, init) => {
|
|
2224
|
-
let _req;
|
|
2225
|
-
if (req && "name" in req) {
|
|
2226
|
-
_req = new Request(`${this.api.basePath}${this.tenantUrl}`, {
|
|
2227
|
-
body: JSON.stringify(req),
|
|
2228
|
-
method: "PUT"
|
|
2229
|
-
});
|
|
2230
|
-
} else {
|
|
2231
|
-
_req = req;
|
|
2599
|
+
if (typeof req === "object" && "id" in req) {
|
|
2600
|
+
this.#config.tenantId = req.id;
|
|
2232
2601
|
}
|
|
2233
|
-
const
|
|
2234
|
-
|
|
2235
|
-
return _requester.put(_req, this.tenantUrl, _init);
|
|
2236
|
-
};
|
|
2237
|
-
};
|
|
2238
|
-
|
|
2239
|
-
// src/users/index.ts
|
|
2240
|
-
var Users = class extends Config {
|
|
2241
|
-
headers;
|
|
2242
|
-
constructor(config, headers) {
|
|
2243
|
-
super(config);
|
|
2244
|
-
this.headers = headers;
|
|
2602
|
+
const res = await fetchTenant(this.#config, "DELETE");
|
|
2603
|
+
return res;
|
|
2245
2604
|
}
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2605
|
+
async get(req, rawResponse) {
|
|
2606
|
+
if (typeof req === "string") {
|
|
2607
|
+
this.#config.tenantId = req;
|
|
2608
|
+
} else if (typeof req === "object" && "id" in req) {
|
|
2609
|
+
this.#config.tenantId = req.id;
|
|
2250
2610
|
}
|
|
2251
|
-
|
|
2252
|
-
|
|
2611
|
+
const res = await fetchTenant(this.#config, "GET");
|
|
2612
|
+
if (rawResponse === true || req === true) {
|
|
2613
|
+
return res;
|
|
2614
|
+
}
|
|
2615
|
+
try {
|
|
2616
|
+
return await res?.clone().json();
|
|
2617
|
+
} catch {
|
|
2618
|
+
return res;
|
|
2253
2619
|
}
|
|
2254
|
-
return `/users?${params.size > 0 ? params : ""}`;
|
|
2255
|
-
}
|
|
2256
|
-
get tenantUsersUrl() {
|
|
2257
|
-
return `/tenants/${this.tenantId ?? "{tenantId}"}/users`;
|
|
2258
|
-
}
|
|
2259
|
-
get linkUsersUrl() {
|
|
2260
|
-
return `/tenants/${this.tenantId ?? "{tenantId}"}/users/${this.userId ?? "{userId}"}/link`;
|
|
2261
|
-
}
|
|
2262
|
-
get tenantUserUrl() {
|
|
2263
|
-
return `/tenants/${this.tenantId ?? "{tenantId}"}/users/${this.userId ?? "{userId}"}`;
|
|
2264
2620
|
}
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
init = {
|
|
2272
|
-
headers: this.headers
|
|
2273
|
-
};
|
|
2274
|
-
return init;
|
|
2621
|
+
async update(req, rawResponse) {
|
|
2622
|
+
let res;
|
|
2623
|
+
if (typeof req === "object" && ("name" in req || "id" in req)) {
|
|
2624
|
+
const { id, ...remaining } = req;
|
|
2625
|
+
if (id) {
|
|
2626
|
+
this.#config.tenantId = id;
|
|
2275
2627
|
}
|
|
2628
|
+
res = await fetchTenant(this.#config, "PUT", JSON.stringify(remaining));
|
|
2629
|
+
}
|
|
2630
|
+
if (rawResponse) {
|
|
2631
|
+
return res;
|
|
2632
|
+
}
|
|
2633
|
+
try {
|
|
2634
|
+
return await res?.clone().json();
|
|
2635
|
+
} catch {
|
|
2636
|
+
return res;
|
|
2276
2637
|
}
|
|
2277
|
-
return void 0;
|
|
2278
2638
|
}
|
|
2279
|
-
|
|
2280
|
-
const
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
}
|
|
2298
|
-
_req = req;
|
|
2639
|
+
async list(req) {
|
|
2640
|
+
const res = await fetchTenantsByUser(this.#config);
|
|
2641
|
+
if (req === true) {
|
|
2642
|
+
return res;
|
|
2643
|
+
}
|
|
2644
|
+
try {
|
|
2645
|
+
return await res?.clone().json();
|
|
2646
|
+
} catch {
|
|
2647
|
+
return res;
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
async leaveTenant(req) {
|
|
2651
|
+
const me = await fetchMe(this.#config);
|
|
2652
|
+
try {
|
|
2653
|
+
const json = await me.json();
|
|
2654
|
+
if ("id" in json) {
|
|
2655
|
+
this.#config.userId = json.id;
|
|
2656
|
+
}
|
|
2657
|
+
} catch {
|
|
2299
2658
|
}
|
|
2300
|
-
const _requester = new Requester(this);
|
|
2301
|
-
const _init = this.handleHeaders(init);
|
|
2302
|
-
return await _requester.put(_req, this.tenantUserUrl, _init);
|
|
2303
|
-
};
|
|
2304
|
-
listUsers = async (req, init) => {
|
|
2305
|
-
const _requester = new Requester(this);
|
|
2306
|
-
const _init = this.handleHeaders(init);
|
|
2307
|
-
return await _requester.get(req, this.tenantUsersUrl, _init);
|
|
2308
|
-
};
|
|
2309
|
-
linkUser = async (req, init) => {
|
|
2310
|
-
const _requester = new Requester(this);
|
|
2311
2659
|
if (typeof req === "string") {
|
|
2312
|
-
this.
|
|
2660
|
+
this.#config.tenantId = req;
|
|
2313
2661
|
} else {
|
|
2314
|
-
|
|
2315
|
-
this.userId = req.id;
|
|
2316
|
-
}
|
|
2317
|
-
if ("tenantId" in req) {
|
|
2318
|
-
this.tenantId = req.tenantId;
|
|
2319
|
-
}
|
|
2662
|
+
this.#handleContext(req);
|
|
2320
2663
|
}
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
unlinkUser = async (req, init) => {
|
|
2664
|
+
return await fetchTenantUser(this.#config, "DELETE");
|
|
2665
|
+
}
|
|
2666
|
+
async addMember(req, rawResponse) {
|
|
2325
2667
|
if (typeof req === "string") {
|
|
2326
|
-
this.userId = req;
|
|
2668
|
+
this.#config.userId = req;
|
|
2327
2669
|
} else {
|
|
2328
|
-
|
|
2329
|
-
|
|
2670
|
+
this.#handleContext(req);
|
|
2671
|
+
}
|
|
2672
|
+
const res = await fetchTenantUser(this.#config, "PUT");
|
|
2673
|
+
return responseHandler(res, rawResponse);
|
|
2674
|
+
}
|
|
2675
|
+
async removeMember(req, rawResponse) {
|
|
2676
|
+
this.#handleContext(req);
|
|
2677
|
+
const res = await fetchTenantUser(this.#config, "DELETE");
|
|
2678
|
+
return responseHandler(res, rawResponse);
|
|
2679
|
+
}
|
|
2680
|
+
async users(req, rawResponse) {
|
|
2681
|
+
this.#handleContext(req);
|
|
2682
|
+
const res = await fetchTenantUsers(this.#config, "GET");
|
|
2683
|
+
return responseHandler(
|
|
2684
|
+
res,
|
|
2685
|
+
rawResponse || typeof req === "boolean" && req
|
|
2686
|
+
);
|
|
2687
|
+
}
|
|
2688
|
+
async invites() {
|
|
2689
|
+
const res = await fetchInvites(this.#config);
|
|
2690
|
+
return responseHandler(res);
|
|
2691
|
+
}
|
|
2692
|
+
async invite(req, rawResponse) {
|
|
2693
|
+
const { csrfToken } = await obtainCsrf(this.#config);
|
|
2694
|
+
const defaults = defaultCallbackUrl3(this.#config);
|
|
2695
|
+
let identifier = req;
|
|
2696
|
+
let callbackUrl = defaults.callbackUrl;
|
|
2697
|
+
let redirectUrl = defaults.redirectUrl;
|
|
2698
|
+
if (typeof req === "object") {
|
|
2699
|
+
if ("email" in req) {
|
|
2700
|
+
identifier = req.email;
|
|
2330
2701
|
}
|
|
2331
|
-
if ("
|
|
2332
|
-
|
|
2702
|
+
if ("callbackUrl" in req) {
|
|
2703
|
+
callbackUrl = req.callbackUrl ? req.callbackUrl : "";
|
|
2704
|
+
}
|
|
2705
|
+
if ("redirectUrl" in req) {
|
|
2706
|
+
redirectUrl = req.redirectUrl ? req.redirectUrl : "";
|
|
2333
2707
|
}
|
|
2334
2708
|
}
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
});
|
|
2369
|
-
this.users = new Users(config);
|
|
2370
|
-
this.tenants = new Tenants(config);
|
|
2371
|
-
this.routes = {
|
|
2372
|
-
...appRoutes(config?.api.routePrefix),
|
|
2373
|
-
...config?.api.routes
|
|
2374
|
-
};
|
|
2375
|
-
this.handlers = Handlers(this.routes, config);
|
|
2376
|
-
this.paths = {
|
|
2377
|
-
get: [
|
|
2378
|
-
this.routes.ME,
|
|
2379
|
-
this.routes.TENANT_USERS,
|
|
2380
|
-
this.routes.TENANTS,
|
|
2381
|
-
this.routes.TENANT,
|
|
2382
|
-
this.routes.SESSION,
|
|
2383
|
-
this.routes.SIGNIN,
|
|
2384
|
-
this.routes.PROVIDERS,
|
|
2385
|
-
this.routes.CSRF,
|
|
2386
|
-
this.routes.PASSWORD_RESET,
|
|
2387
|
-
this.routes.CALLBACK,
|
|
2388
|
-
this.routes.SIGNOUT,
|
|
2389
|
-
this.routes.VERIFY_REQUEST,
|
|
2390
|
-
this.routes.ERROR
|
|
2391
|
-
],
|
|
2392
|
-
post: [
|
|
2393
|
-
this.routes.TENANT_USERS,
|
|
2394
|
-
this.routes.SIGNUP,
|
|
2395
|
-
this.routes.USERS,
|
|
2396
|
-
this.routes.TENANTS,
|
|
2397
|
-
this.routes.SESSION,
|
|
2398
|
-
`${this.routes.SIGNIN}/{provider}`,
|
|
2399
|
-
this.routes.PASSWORD_RESET,
|
|
2400
|
-
this.routes.PROVIDERS,
|
|
2401
|
-
this.routes.CSRF,
|
|
2402
|
-
`${this.routes.CALLBACK}/{provider}`,
|
|
2403
|
-
this.routes.SIGNOUT
|
|
2404
|
-
],
|
|
2405
|
-
put: [
|
|
2406
|
-
this.routes.TENANT_USERS,
|
|
2407
|
-
this.routes.USERS,
|
|
2408
|
-
this.routes.TENANT,
|
|
2409
|
-
this.routes.PASSWORD_RESET
|
|
2410
|
-
],
|
|
2411
|
-
delete: [this.routes.TENANT_USER, this.routes.TENANT]
|
|
2412
|
-
};
|
|
2709
|
+
this.#config.headers.set(
|
|
2710
|
+
"Content-Type",
|
|
2711
|
+
"application/x-www-form-urlencoded"
|
|
2712
|
+
);
|
|
2713
|
+
const res = await fetchInvite(
|
|
2714
|
+
this.#config,
|
|
2715
|
+
"POST",
|
|
2716
|
+
new URLSearchParams({
|
|
2717
|
+
identifier,
|
|
2718
|
+
csrfToken,
|
|
2719
|
+
callbackUrl,
|
|
2720
|
+
redirectUrl
|
|
2721
|
+
}).toString()
|
|
2722
|
+
);
|
|
2723
|
+
return responseHandler(res, rawResponse);
|
|
2724
|
+
}
|
|
2725
|
+
async acceptInvite(req, rawResponse) {
|
|
2726
|
+
if (!req) {
|
|
2727
|
+
throw new Error("The identifier and token are required.");
|
|
2728
|
+
}
|
|
2729
|
+
const { identifier, token } = req;
|
|
2730
|
+
const defaults = defaultCallbackUrl3(this.#config);
|
|
2731
|
+
const callbackUrl = String(defaults.callbackUrl);
|
|
2732
|
+
const res = await fetchInvite(
|
|
2733
|
+
this.#config,
|
|
2734
|
+
"PUT",
|
|
2735
|
+
new URLSearchParams({
|
|
2736
|
+
identifier,
|
|
2737
|
+
token,
|
|
2738
|
+
callbackUrl
|
|
2739
|
+
}).toString()
|
|
2740
|
+
);
|
|
2741
|
+
return responseHandler(res, rawResponse);
|
|
2413
2742
|
}
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
resetHeaders: this.resetHeaders
|
|
2419
|
-
});
|
|
2420
|
-
};
|
|
2421
|
-
updateConfig = (config) => {
|
|
2422
|
-
this.config = config;
|
|
2423
|
-
this.handlers = Handlers(this.routes, config);
|
|
2424
|
-
};
|
|
2425
|
-
resetHeaders = (headers) => {
|
|
2426
|
-
this.#headers = new Headers(headers ?? {});
|
|
2427
|
-
setContext(new Headers());
|
|
2428
|
-
this.reset();
|
|
2429
|
-
};
|
|
2430
|
-
set headers(headers) {
|
|
2431
|
-
const updates = [];
|
|
2432
|
-
if (headers instanceof Headers) {
|
|
2433
|
-
headers.forEach((value, key12) => {
|
|
2434
|
-
updates.push([key12.toLowerCase(), value]);
|
|
2435
|
-
});
|
|
2743
|
+
async deleteInvite(req) {
|
|
2744
|
+
let id = "";
|
|
2745
|
+
if (typeof req === "object") {
|
|
2746
|
+
id = req.id;
|
|
2436
2747
|
} else {
|
|
2437
|
-
|
|
2438
|
-
updates.push([key12.toLowerCase(), value]);
|
|
2439
|
-
}
|
|
2748
|
+
id = req;
|
|
2440
2749
|
}
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
merged[key12.toLowerCase()] = value;
|
|
2444
|
-
});
|
|
2445
|
-
for (const [key12, value] of updates) {
|
|
2446
|
-
merged[key12] = value;
|
|
2750
|
+
if (!id) {
|
|
2751
|
+
throw new Error("An invite id is required.");
|
|
2447
2752
|
}
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2753
|
+
const res = await fetchInvite(this.#config, "DELETE", id);
|
|
2754
|
+
return responseHandler(res, true);
|
|
2755
|
+
}
|
|
2756
|
+
#handleContext(req) {
|
|
2757
|
+
if (typeof req === "object") {
|
|
2758
|
+
if ("tenantId" in req) {
|
|
2759
|
+
this.#config.tenantId = req.tenantId;
|
|
2760
|
+
}
|
|
2761
|
+
if ("userId" in req) {
|
|
2762
|
+
this.#config.tenantId = req.tenantId;
|
|
2763
|
+
}
|
|
2451
2764
|
}
|
|
2452
|
-
this.reset();
|
|
2453
2765
|
}
|
|
2454
|
-
|
|
2455
|
-
|
|
2766
|
+
};
|
|
2767
|
+
async function responseHandler(res, rawResponse) {
|
|
2768
|
+
if (rawResponse) {
|
|
2769
|
+
return res;
|
|
2770
|
+
}
|
|
2771
|
+
try {
|
|
2772
|
+
return await res?.clone().json();
|
|
2773
|
+
} catch {
|
|
2774
|
+
return res;
|
|
2456
2775
|
}
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2776
|
+
}
|
|
2777
|
+
function defaultCallbackUrl3(config) {
|
|
2778
|
+
let cb = null;
|
|
2779
|
+
let redirect = null;
|
|
2780
|
+
const fallbackCb = parseCallback(config.headers);
|
|
2781
|
+
if (fallbackCb) {
|
|
2782
|
+
const [, value] = fallbackCb.split("=");
|
|
2783
|
+
cb = decodeURIComponent(value);
|
|
2784
|
+
if (value) {
|
|
2785
|
+
redirect = `${new URL(cb).origin}${config.routePrefix}${"/tenants/{tenantId}/invite" /* INVITE */.replace(
|
|
2786
|
+
"{tenantId}",
|
|
2787
|
+
String(config.tenantId)
|
|
2788
|
+
)}`;
|
|
2462
2789
|
}
|
|
2463
|
-
return null;
|
|
2464
2790
|
}
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2791
|
+
return { callbackUrl: cb, redirectUrl: redirect };
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2794
|
+
// src/api/handlers/withContext/index.ts
|
|
2795
|
+
function handlersWithContext(config) {
|
|
2796
|
+
const GET7 = GETTER(config.routes, config);
|
|
2797
|
+
const POST6 = POSTER(config.routes, config);
|
|
2798
|
+
const DELETE5 = DELETER(config.routes, config);
|
|
2799
|
+
const PUT6 = PUTER(config.routes, config);
|
|
2800
|
+
return {
|
|
2801
|
+
GET: async (req) => {
|
|
2802
|
+
const response = await GET7(req);
|
|
2803
|
+
const updatedConfig = updateConfig(response, config);
|
|
2804
|
+
return { response, nile: new Server(updatedConfig) };
|
|
2805
|
+
},
|
|
2806
|
+
POST: async (req) => {
|
|
2807
|
+
const response = await POST6(req);
|
|
2808
|
+
const updatedConfig = updateConfig(response, config);
|
|
2809
|
+
return { response, nile: new Server(updatedConfig) };
|
|
2810
|
+
},
|
|
2811
|
+
DELETE: async (req) => {
|
|
2812
|
+
const response = await DELETE5(req);
|
|
2813
|
+
const updatedConfig = updateConfig(response, config);
|
|
2814
|
+
return { response, nile: new Server(updatedConfig) };
|
|
2815
|
+
},
|
|
2816
|
+
PUT: async (req) => {
|
|
2817
|
+
const response = await PUT6(req);
|
|
2818
|
+
const updatedConfig = updateConfig(response, config);
|
|
2819
|
+
return { response, nile: new Server(updatedConfig) };
|
|
2474
2820
|
}
|
|
2475
|
-
return void 0;
|
|
2476
2821
|
};
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2822
|
+
}
|
|
2823
|
+
function updateConfig(response, config) {
|
|
2824
|
+
let origin = "http://localhost:3000";
|
|
2825
|
+
let headers = null;
|
|
2826
|
+
if (response?.status === 302) {
|
|
2827
|
+
const location = response.headers.get("location");
|
|
2828
|
+
if (location) {
|
|
2829
|
+
const urlLocation = new URL(location);
|
|
2830
|
+
origin = urlLocation.origin;
|
|
2482
2831
|
}
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
setContext(req.headers);
|
|
2491
|
-
return;
|
|
2832
|
+
}
|
|
2833
|
+
const setCookies = [];
|
|
2834
|
+
if (response?.headers) {
|
|
2835
|
+
for (const [key17, value] of response.headers) {
|
|
2836
|
+
if (key17.toLowerCase() === "set-cookie") {
|
|
2837
|
+
setCookies.push(value);
|
|
2838
|
+
}
|
|
2492
2839
|
}
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2840
|
+
}
|
|
2841
|
+
if (setCookies.length > 0) {
|
|
2842
|
+
const cookieHeader = setCookies.map((cookieStr) => cookieStr.split(";")[0]).join("; ");
|
|
2843
|
+
headers = new Headers({ cookie: cookieHeader });
|
|
2844
|
+
}
|
|
2845
|
+
return {
|
|
2846
|
+
...config,
|
|
2847
|
+
origin,
|
|
2848
|
+
headers: headers ?? void 0,
|
|
2849
|
+
preserveHeaders: true
|
|
2850
|
+
};
|
|
2851
|
+
}
|
|
2852
|
+
|
|
2853
|
+
// src/api/utils/extensions.ts
|
|
2854
|
+
function bindHandleOnRequest(instance) {
|
|
2855
|
+
return async function handleOnRequest(config, _init, params) {
|
|
2856
|
+
const { debug } = config.logger("[EXTENSIONS]");
|
|
2857
|
+
if (config.extensions) {
|
|
2858
|
+
for (const create2 of config.extensions) {
|
|
2859
|
+
if (typeof create2 !== "function") {
|
|
2860
|
+
return void 0;
|
|
2861
|
+
}
|
|
2862
|
+
const ext = await create2(instance);
|
|
2863
|
+
if (ext.onRequest) {
|
|
2864
|
+
const previousContext = instance.getContext();
|
|
2865
|
+
if (previousContext.preserveHeaders) {
|
|
2866
|
+
instance.setContext({ preserveHeaders: false });
|
|
2867
|
+
}
|
|
2868
|
+
await ext.onRequest(_init.request);
|
|
2869
|
+
const updatedContext = instance.getContext();
|
|
2870
|
+
if (updatedContext?.headers) {
|
|
2871
|
+
const cookie = updatedContext.headers.get("cookie");
|
|
2872
|
+
if (cookie) {
|
|
2873
|
+
params.headers.set(
|
|
2874
|
+
"cookie",
|
|
2875
|
+
mergeCookies(
|
|
2876
|
+
previousContext.preserveHeaders ? previousContext.headers?.get("cookie") : null,
|
|
2877
|
+
updatedContext.headers.get("cookie")
|
|
2878
|
+
)
|
|
2879
|
+
);
|
|
2880
|
+
}
|
|
2881
|
+
if (updatedContext.tenantId) {
|
|
2882
|
+
params.headers.set(
|
|
2883
|
+
TENANT_COOKIE,
|
|
2884
|
+
String(updatedContext.headers.get(TENANT_COOKIE))
|
|
2885
|
+
);
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2888
|
+
debug(`${ext.id ?? create2.name} ran onRequest`);
|
|
2889
|
+
}
|
|
2500
2890
|
}
|
|
2501
2891
|
}
|
|
2502
2892
|
};
|
|
2503
|
-
}
|
|
2893
|
+
}
|
|
2894
|
+
function buildExtensionConfig(instance) {
|
|
2895
|
+
return {
|
|
2896
|
+
handleOnRequest: bindHandleOnRequest(instance)
|
|
2897
|
+
};
|
|
2898
|
+
}
|
|
2899
|
+
function mergeCookies(...cookieStrings) {
|
|
2900
|
+
const cookieMap = /* @__PURE__ */ new Map();
|
|
2901
|
+
for (const str of cookieStrings) {
|
|
2902
|
+
if (!str) continue;
|
|
2903
|
+
for (const part of str.split(";")) {
|
|
2904
|
+
const [key17, value] = part.split("=").map((s) => s.trim());
|
|
2905
|
+
if (key17 && value) cookieMap.set(key17, value);
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
return [...cookieMap.entries()].map(([k, v]) => `${k}=${v}`).join("; ");
|
|
2909
|
+
}
|
|
2504
2910
|
|
|
2505
2911
|
// src/Server.ts
|
|
2506
2912
|
var Server = class {
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2913
|
+
users;
|
|
2914
|
+
tenants;
|
|
2915
|
+
auth;
|
|
2916
|
+
#config;
|
|
2917
|
+
#handlers;
|
|
2918
|
+
#paths;
|
|
2919
|
+
#manager;
|
|
2920
|
+
#headers;
|
|
2921
|
+
#preserveHeaders;
|
|
2510
2922
|
constructor(config) {
|
|
2511
|
-
this
|
|
2512
|
-
|
|
2513
|
-
|
|
2923
|
+
this.#config = new Config({
|
|
2924
|
+
...config,
|
|
2925
|
+
extensionCtx: buildExtensionConfig(this)
|
|
2926
|
+
});
|
|
2514
2927
|
watchTenantId((tenantId) => {
|
|
2515
|
-
this.tenantId
|
|
2928
|
+
if (tenantId !== this.#config.tenantId) {
|
|
2929
|
+
this.#config.tenantId = tenantId;
|
|
2930
|
+
this.#reset();
|
|
2931
|
+
}
|
|
2516
2932
|
});
|
|
2517
2933
|
watchUserId((userId) => {
|
|
2518
|
-
this.userId
|
|
2934
|
+
if (userId !== this.#config.userId) {
|
|
2935
|
+
this.#config.userId = userId;
|
|
2936
|
+
this.#reset();
|
|
2937
|
+
}
|
|
2519
2938
|
});
|
|
2520
|
-
|
|
2521
|
-
this.
|
|
2939
|
+
watchHeaders((headers) => {
|
|
2940
|
+
this.setContext(headers);
|
|
2941
|
+
this.#reset();
|
|
2522
2942
|
});
|
|
2943
|
+
this.#handlers = {
|
|
2944
|
+
...this.#config.handlers,
|
|
2945
|
+
withContext: handlersWithContext(this.#config)
|
|
2946
|
+
};
|
|
2947
|
+
this.#preserveHeaders = config?.preserveHeaders ?? false;
|
|
2948
|
+
this.#paths = this.#config.paths;
|
|
2949
|
+
this.#config.tenantId = getTenantId({ config: this.#config });
|
|
2950
|
+
this.#manager = new DBManager(this.#config);
|
|
2951
|
+
this.#handleHeaders(config);
|
|
2952
|
+
this.users = new Users(this.#config);
|
|
2953
|
+
this.tenants = new Tenants(this.#config);
|
|
2954
|
+
this.auth = new Auth(this.#config);
|
|
2523
2955
|
}
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2956
|
+
get db() {
|
|
2957
|
+
const pool = this.#manager.getConnection(this.#config);
|
|
2958
|
+
return Object.assign(pool, {
|
|
2959
|
+
clearConnections: () => {
|
|
2960
|
+
this.#manager.clear(this.#config);
|
|
2961
|
+
}
|
|
2962
|
+
});
|
|
2527
2963
|
}
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2964
|
+
/**
|
|
2965
|
+
* A convenience function that applies a config and ensures whatever was passed is set properly
|
|
2966
|
+
*/
|
|
2967
|
+
getInstance(config, req) {
|
|
2968
|
+
const _config = { ...this.#config, ...config };
|
|
2969
|
+
const updatedConfig = new Config(_config);
|
|
2970
|
+
this.#config = new Config(updatedConfig);
|
|
2971
|
+
this.#config.tenantId = config.tenantId;
|
|
2972
|
+
this.#config.userId = config.userId;
|
|
2973
|
+
if (req) {
|
|
2974
|
+
this.setContext(req);
|
|
2533
2975
|
}
|
|
2976
|
+
this.#reset();
|
|
2977
|
+
return this;
|
|
2534
2978
|
}
|
|
2535
|
-
|
|
2536
|
-
return this
|
|
2537
|
-
}
|
|
2538
|
-
set userId(userId) {
|
|
2539
|
-
this.databaseId = this.config.databaseId;
|
|
2540
|
-
this.config.userId = userId;
|
|
2541
|
-
if (this.api) {
|
|
2542
|
-
this.api.users.userId = this.config.userId;
|
|
2543
|
-
this.api.tenants.userId = this.config.userId;
|
|
2544
|
-
}
|
|
2979
|
+
getPaths() {
|
|
2980
|
+
return this.#paths;
|
|
2545
2981
|
}
|
|
2546
|
-
get
|
|
2547
|
-
return this
|
|
2982
|
+
get handlers() {
|
|
2983
|
+
return this.#handlers;
|
|
2548
2984
|
}
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2985
|
+
/**
|
|
2986
|
+
* Allow the setting of headers from a req or header object.
|
|
2987
|
+
* Makes it possible to handle REST requests easily
|
|
2988
|
+
* Also makes it easy to set user + tenant in some way
|
|
2989
|
+
* @param req
|
|
2990
|
+
* @returns undefined
|
|
2991
|
+
*/
|
|
2992
|
+
setContext(req) {
|
|
2993
|
+
try {
|
|
2994
|
+
if (req instanceof Headers) {
|
|
2995
|
+
this.#handleHeaders(req);
|
|
2996
|
+
this.#reset();
|
|
2997
|
+
return;
|
|
2998
|
+
} else if (req instanceof Request) {
|
|
2999
|
+
this.#handleHeaders(new Headers(req.headers));
|
|
3000
|
+
this.#reset();
|
|
3001
|
+
return;
|
|
3002
|
+
}
|
|
3003
|
+
} catch {
|
|
2555
3004
|
}
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
if (
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
3005
|
+
let ok = false;
|
|
3006
|
+
if (req && typeof req === "object" && "tenantId" in req) {
|
|
3007
|
+
ok = true;
|
|
3008
|
+
this.#config.tenantId = req.tenantId;
|
|
3009
|
+
}
|
|
3010
|
+
if (req && typeof req === "object" && "userId" in req) {
|
|
3011
|
+
ok = true;
|
|
3012
|
+
this.#config.userId = req.userId;
|
|
3013
|
+
}
|
|
3014
|
+
if (req && typeof req === "object" && "preserveHeaders" in req) {
|
|
3015
|
+
ok = true;
|
|
3016
|
+
this.#preserveHeaders = Boolean(req.preserveHeaders);
|
|
3017
|
+
}
|
|
3018
|
+
if (ok) {
|
|
3019
|
+
return;
|
|
3020
|
+
}
|
|
3021
|
+
if (typeof req === "object") {
|
|
3022
|
+
const headers = new Headers(req);
|
|
3023
|
+
if (headers) {
|
|
3024
|
+
this.#handleHeaders(headers);
|
|
3025
|
+
this.#reset();
|
|
3026
|
+
return;
|
|
2566
3027
|
}
|
|
2567
3028
|
}
|
|
3029
|
+
const { warn } = Logger(this.#config)("[API]");
|
|
3030
|
+
if (warn) {
|
|
3031
|
+
warn(
|
|
3032
|
+
"Set context expects a Request, Header instance or an object of Record<string, string>"
|
|
3033
|
+
);
|
|
3034
|
+
}
|
|
2568
3035
|
}
|
|
2569
|
-
|
|
2570
|
-
return
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
3036
|
+
getContext() {
|
|
3037
|
+
return {
|
|
3038
|
+
headers: this.#headers,
|
|
3039
|
+
userId: this.#config.userId,
|
|
3040
|
+
tenantId: this.#config.tenantId,
|
|
3041
|
+
preserveHeaders: this.#preserveHeaders
|
|
3042
|
+
};
|
|
2574
3043
|
}
|
|
2575
3044
|
/**
|
|
2576
|
-
*
|
|
3045
|
+
* Merge headers together
|
|
3046
|
+
* Internally, passed a NileConfig, externally, should be using Headers
|
|
2577
3047
|
*/
|
|
2578
|
-
|
|
2579
|
-
const
|
|
2580
|
-
|
|
2581
|
-
this
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
if (
|
|
2585
|
-
|
|
3048
|
+
#handleHeaders(config) {
|
|
3049
|
+
const updates = [];
|
|
3050
|
+
let headers;
|
|
3051
|
+
this.#headers = new Headers();
|
|
3052
|
+
if (config instanceof Headers) {
|
|
3053
|
+
headers = config;
|
|
3054
|
+
} else if (config?.headers) {
|
|
3055
|
+
headers = config?.headers;
|
|
3056
|
+
if (config && config.origin) {
|
|
3057
|
+
this.#headers.set(HEADER_ORIGIN, config.origin);
|
|
3058
|
+
}
|
|
3059
|
+
if (config && config.secureCookies != null) {
|
|
3060
|
+
this.#headers.set(HEADER_SECURE_COOKIES, String(config.secureCookies));
|
|
3061
|
+
}
|
|
2586
3062
|
}
|
|
2587
|
-
|
|
2588
|
-
|
|
3063
|
+
if (headers instanceof Headers) {
|
|
3064
|
+
headers.forEach((value, key17) => {
|
|
3065
|
+
updates.push([key17.toLowerCase(), value]);
|
|
3066
|
+
});
|
|
3067
|
+
} else {
|
|
3068
|
+
for (const [key17, value] of Object.entries(headers ?? {})) {
|
|
3069
|
+
updates.push([key17.toLowerCase(), value]);
|
|
3070
|
+
}
|
|
3071
|
+
}
|
|
3072
|
+
const merged = {};
|
|
3073
|
+
this.#config.tenantId = getTenantFromHttp(this.#headers, this.#config);
|
|
3074
|
+
this.#headers?.forEach((value, key17) => {
|
|
3075
|
+
if (key17.toLowerCase() !== "cookie") {
|
|
3076
|
+
merged[key17.toLowerCase()] = value;
|
|
3077
|
+
}
|
|
3078
|
+
});
|
|
3079
|
+
for (const [key17, value] of updates) {
|
|
3080
|
+
merged[key17] = value;
|
|
3081
|
+
}
|
|
3082
|
+
for (const [key17, value] of Object.entries(merged)) {
|
|
3083
|
+
this.#headers.set(key17, value);
|
|
3084
|
+
}
|
|
3085
|
+
this.#config.logger("[handleHeaders]").debug(JSON.stringify(merged));
|
|
3086
|
+
this.#config.headers = this.#headers;
|
|
2589
3087
|
}
|
|
3088
|
+
/**
|
|
3089
|
+
* Allow some internal mutations to reset our config + headers
|
|
3090
|
+
*/
|
|
3091
|
+
#reset = () => {
|
|
3092
|
+
this.#config.headers = this.#headers ?? new Headers();
|
|
3093
|
+
this.users = new Users(this.#config);
|
|
3094
|
+
this.tenants = new Tenants(this.#config);
|
|
3095
|
+
this.auth = new Auth(this.#config);
|
|
3096
|
+
};
|
|
2590
3097
|
};
|
|
2591
3098
|
var server;
|
|
2592
3099
|
function create(config) {
|
|
@@ -2596,8 +3103,16 @@ function create(config) {
|
|
|
2596
3103
|
return server;
|
|
2597
3104
|
}
|
|
2598
3105
|
|
|
3106
|
+
exports.APIErrorErrorCodeEnum = APIErrorErrorCodeEnum;
|
|
3107
|
+
exports.HEADER_ORIGIN = HEADER_ORIGIN;
|
|
3108
|
+
exports.HEADER_SECURE_COOKIES = HEADER_SECURE_COOKIES;
|
|
2599
3109
|
exports.LoginUserResponseTokenTypeEnum = LoginUserResponseTokenTypeEnum;
|
|
2600
3110
|
exports.Nile = create;
|
|
2601
3111
|
exports.Server = Server;
|
|
3112
|
+
exports.TENANT_COOKIE = TENANT_COOKIE;
|
|
3113
|
+
exports.USER_COOKIE = USER_COOKIE;
|
|
3114
|
+
exports.parseCSRF = parseCSRF;
|
|
3115
|
+
exports.parseCallback = parseCallback;
|
|
3116
|
+
exports.parseToken = parseToken;
|
|
2602
3117
|
//# sourceMappingURL=index.js.map
|
|
2603
3118
|
//# sourceMappingURL=index.js.map
|