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