@getstrata/core 0.5.55 → 0.5.57
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/README.md +3 -1
- package/dist/{domain/abilities.d.ts → core/auth/abilityCatalog.d.ts} +9 -1
- package/dist/core/auth/accessControl.d.ts +1 -1
- package/dist/core/auth/membershipContext.d.ts +6 -4
- package/dist/core/auth/membershipService.d.ts +5 -6
- package/dist/core/contracts/authUserDirectory.d.ts +11 -0
- package/dist/core/contracts/membership.d.ts +20 -0
- package/dist/core/http/clientIp.d.ts +3 -0
- package/dist/core/jobs/dispatchWebhookJob.d.ts +2 -0
- package/dist/core/media/imageTransform.d.ts +13 -0
- package/dist/core/scheduler/osCron.d.ts +14 -0
- package/dist/core/tenant/tenancyConfig.d.ts +5 -0
- package/dist/core/tenant/tenantMiddleware.d.ts +1 -1
- package/dist/core/terminal/runShell.d.ts +6 -0
- package/dist/core/view/assertEtaHtmlSource.d.ts +5 -0
- package/dist/core/view/etaViewEngine.d.ts +4 -0
- package/dist/entries/audit/exportAuditLogs.js +2 -2
- package/dist/entries/audit/siemFormatter.js +2 -2
- package/dist/entries/auth/accessControl.js +4 -4
- package/dist/entries/auth/membershipMiddleware.js +21 -161
- package/dist/entries/auth/membershipScope.js +26 -166
- package/dist/entries/auth/membershipService.js +21 -161
- package/dist/entries/auth/oauth/providers.js +2 -2
- package/dist/entries/auth/password.js +2 -2
- package/dist/entries/auth/policy.js +2 -2
- package/dist/entries/auth/scimAuthMiddleware.js +22 -4
- package/dist/entries/auth/sessionCookie.js +4 -4
- package/dist/entries/auth/sessionGuard.js +12 -349
- package/dist/entries/auth/tokenHash.js +2 -2
- package/dist/entries/config/envSchema.js +2 -2
- package/dist/entries/contracts/container.js +2 -2
- package/dist/entries/contracts/di.js +2 -2
- package/dist/entries/contracts/serviceTokens.js +6 -6
- package/dist/entries/crypto/fieldEncryption.js +8 -8
- package/dist/entries/crypto/mfaSecret.js +2 -2
- package/dist/entries/database/errors.js +2 -2
- package/dist/entries/database/migrations.js +8 -8
- package/dist/entries/database/model.js +5 -5
- package/dist/entries/database/query.js +19 -19
- package/dist/entries/database/relationships.js +13 -13
- package/dist/entries/database/schema.js +13 -13
- package/dist/entries/database/seeders.js +2 -2
- package/dist/entries/facades.js +8 -8
- package/dist/entries/http/authMiddleware.js +2 -2
- package/dist/entries/http/bodySizeLimitMiddleware.js +2 -2
- package/dist/entries/http/clientIp.js +19 -0
- package/dist/entries/http/cookies.js +2 -2
- package/dist/entries/http/csrfMiddleware.js +2 -1
- package/dist/entries/http/csrfProtection.js +2 -2
- package/dist/entries/http/csrfToken.js +8 -7
- package/dist/entries/http/etag.js +8 -8
- package/dist/entries/http/flashSession.js +4 -4
- package/dist/entries/http/formRequest.js +2 -2
- package/dist/entries/http/loginThrottleMiddleware.js +20 -3
- package/dist/entries/http/memoryThrottleMiddleware.js +16 -1
- package/dist/entries/http/metricsMiddleware.js +2 -2
- package/dist/entries/http/pagination.js +4 -4
- package/dist/entries/http/parseFormBody.js +2 -2
- package/dist/entries/http/parseMultipartUpload.js +2 -2
- package/dist/entries/http/resources.js +2 -2
- package/dist/entries/http/response.js +214 -395
- package/dist/entries/http/scimThrottleMiddleware.js +40 -1
- package/dist/entries/http/securedRouteModelBinding.js +2 -2
- package/dist/entries/http/throttleMiddleware.js +20 -3
- package/dist/entries/http/validation.js +13 -13
- package/dist/entries/http/webErrorResponse.js +212 -393
- package/dist/entries/jobs/dispatchWebhookJob.js +111 -5
- package/dist/entries/lifecycle/gracefulShutdown.js +3 -3
- package/dist/entries/logging/logger.js +2 -2
- package/dist/entries/logging/requestLoggingMiddleware.js +16 -1
- package/dist/entries/mail/mailer.js +6 -6
- package/dist/entries/mail/markdownMail.js +3 -3
- package/dist/entries/mail/markdownMailable.js +2 -2
- package/dist/entries/media/imageTransform.js +40 -0
- package/dist/entries/metrics/prometheus.js +2 -2
- package/dist/entries/openapi/generator.js +2 -2
- package/dist/entries/queue/createAppQueue.js +4 -4
- package/dist/entries/queue/publicQueue.js +10 -10
- package/dist/entries/queue/queueMetrics.js +2 -2
- package/dist/entries/queue/redisQueue.js +7 -7
- package/dist/entries/queue.js +3 -3
- package/dist/entries/scheduler/osCron.js +27 -0
- package/dist/entries/scheduler/schedule.js +2 -2
- package/dist/entries/security/oauthState.js +3 -3
- package/dist/entries/security/publicReads.js +2 -2
- package/dist/entries/security/safeFetch.js +2 -2
- package/dist/entries/security/safeUrl.js +5 -5
- package/dist/entries/security/scimTenantTokens.js +3 -6
- package/dist/entries/security/totp.js +2 -2
- package/dist/entries/storage/storage.js +7 -7
- package/dist/entries/tenant/tenancyConfig.js +12 -0
- package/dist/entries/tenant/tenantDatabaseScope.js +13 -2
- package/dist/entries/terminal/runShell.js +18 -0
- package/dist/entries/validation/rules.js +12 -12
- package/dist/entries/view.js +212 -393
- package/dist/framework/public-api.d.ts +4 -1
- package/dist/index.js +2591 -2686
- package/package.json +27 -2
- package/dist/config/database.d.ts +0 -10
- package/dist/db/connection/createConnection.d.ts +0 -6
- package/dist/db/connection/index.d.ts +0 -11
- package/dist/domain/auth.d.ts +0 -4
- package/dist/domain/scim.d.ts +0 -9
- package/dist/modules/organization/memberRepository.d.ts +0 -14
- package/dist/modules/organization/memberTypes.d.ts +0 -9
- package/dist/modules/user/apiTokenRepository.d.ts +0 -8
- package/dist/modules/user/apiTokenTable.d.ts +0 -3
- package/dist/modules/user/authService.d.ts +0 -23
- package/dist/modules/user/notificationRepository.d.ts +0 -6
- package/dist/modules/user/notificationService.d.ts +0 -25
- package/dist/modules/user/notificationTable.d.ts +0 -3
- package/dist/modules/user/notificationTypes.d.ts +0 -12
- package/dist/modules/user/oauthIdentityRepository.d.ts +0 -9
- package/dist/modules/user/provider.d.ts +0 -11
- package/dist/modules/user/repository.d.ts +0 -13
- package/dist/modules/user/table.d.ts +0 -3
- package/dist/modules/user/tokenService.d.ts +0 -29
- package/dist/modules/user/types.d.ts +0 -46
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// ../../src/core/jobs/dispatchWebhookJob.ts
|
|
3
3
|
import { createHmac } from "crypto";
|
|
4
|
-
import { repositoryConnection as
|
|
4
|
+
import { repositoryConnection as db2 } from "@getstrata/core/database/repositoryConnection";
|
|
5
5
|
|
|
6
6
|
// ../../src/config/app.ts
|
|
7
7
|
var appConfig = {
|
|
@@ -169,12 +169,118 @@ async function safeFetch(input, init = {}, options = {}) {
|
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
// ../../src/core/tenant/resolveTenant.ts
|
|
173
|
+
import { repositoryConnection as db } from "@getstrata/core/database/repositoryConnection";
|
|
174
|
+
|
|
175
|
+
// ../../src/core/tenant/tenancyConfig.ts
|
|
176
|
+
function readTenancyDriver(env = process.env) {
|
|
177
|
+
return env.TENANCY_DRIVER === "none" ? "none" : "rls";
|
|
178
|
+
}
|
|
179
|
+
function isTenancyEnabled(env = process.env) {
|
|
180
|
+
return readTenancyDriver(env) !== "none";
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ../../src/core/tenant/resolveTenant.ts
|
|
184
|
+
async function resolveTenant(tenantId) {
|
|
185
|
+
if (!isTenancyEnabled()) {
|
|
186
|
+
return {
|
|
187
|
+
id: tenantId,
|
|
188
|
+
slug: "default",
|
|
189
|
+
plan: "free",
|
|
190
|
+
region: "eu"
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
const rows = await db`
|
|
194
|
+
SELECT id, slug, plan, region
|
|
195
|
+
FROM tenant
|
|
196
|
+
WHERE id = ${tenantId}
|
|
197
|
+
LIMIT 1
|
|
198
|
+
`;
|
|
199
|
+
const row = rows[0];
|
|
200
|
+
return row ? { id: row.id, slug: row.slug, plan: row.plan, region: row.region ?? "eu" } : null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ../../src/core/tenant/tenantDatabaseScope.ts
|
|
204
|
+
import { getDefaultDatabasePool } from "@getstrata/core/database/defaultConnection";
|
|
205
|
+
|
|
206
|
+
// ../../src/core/runtime/asyncContextStore.ts
|
|
207
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
208
|
+
function createAsyncContextStore(key) {
|
|
209
|
+
const symbol = Symbol.for(key);
|
|
210
|
+
const globalRecord = globalThis;
|
|
211
|
+
const existing = globalRecord[symbol];
|
|
212
|
+
if (existing) {
|
|
213
|
+
return existing;
|
|
214
|
+
}
|
|
215
|
+
const store = new AsyncLocalStorage;
|
|
216
|
+
globalRecord[symbol] = store;
|
|
217
|
+
return store;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ../../src/core/database/connectionContext.ts
|
|
221
|
+
var activeConnection = createAsyncContextStore("@getstrata/databaseConnectionContext");
|
|
222
|
+
function runWithDatabaseConnection(connection, callback) {
|
|
223
|
+
return activeConnection.run(connection, callback);
|
|
224
|
+
}
|
|
225
|
+
function getActiveDatabaseConnection(fallback) {
|
|
226
|
+
return activeConnection.getStore() ?? fallback;
|
|
227
|
+
}
|
|
228
|
+
function hasActiveDatabaseConnection() {
|
|
229
|
+
return activeConnection.getStore() !== undefined;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ../../src/core/tenant/tenantContext.ts
|
|
233
|
+
var tenantContext = createAsyncContextStore("@getstrata/tenantContext");
|
|
234
|
+
function runWithTenant(tenant, callback) {
|
|
235
|
+
return tenantContext.run(tenant, callback);
|
|
236
|
+
}
|
|
237
|
+
function currentTenant() {
|
|
238
|
+
return tenantContext.getStore() ?? null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ../../src/core/tenant/tenantDatabaseScope.ts
|
|
242
|
+
async function applyTenantContextToTransaction(transaction, tenantId) {
|
|
243
|
+
await transaction.unsafe(`SELECT set_config('app.tenant_id', $1, true)`, [String(tenantId)]);
|
|
244
|
+
await transaction.unsafe(`SELECT set_config('app.bypass_rls', $1, true)`, ["false"]);
|
|
245
|
+
}
|
|
246
|
+
async function runWithTenantDatabase(tenant, callback) {
|
|
247
|
+
if (!isTenancyEnabled()) {
|
|
248
|
+
return await runWithTenant(tenant, callback);
|
|
249
|
+
}
|
|
250
|
+
if (hasActiveDatabaseConnection()) {
|
|
251
|
+
const activeConnection2 = getActiveDatabaseConnection(getDefaultDatabasePool());
|
|
252
|
+
await applyTenantContextToTransaction(activeConnection2, tenant.id);
|
|
253
|
+
return await runWithTenant(tenant, callback);
|
|
254
|
+
}
|
|
255
|
+
return await getDefaultDatabasePool().begin(async (transaction) => {
|
|
256
|
+
await applyTenantContextToTransaction(transaction, tenant.id);
|
|
257
|
+
return await runWithDatabaseConnection(transaction, async () => {
|
|
258
|
+
return await runWithTenant(tenant, callback);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
function isInsideTenantDatabaseScope(tenantId = currentTenant()?.id) {
|
|
263
|
+
return hasActiveDatabaseConnection() && currentTenant()?.id === tenantId;
|
|
264
|
+
}
|
|
265
|
+
|
|
172
266
|
// ../../src/core/jobs/dispatchWebhookJob.ts
|
|
173
267
|
class DispatchWebhookJob extends Job {
|
|
174
268
|
maxAttempts = 3;
|
|
175
269
|
backoffMs = 2000;
|
|
176
270
|
async handle(payload) {
|
|
177
|
-
const
|
|
271
|
+
const tenant = await resolveTenant(payload.tenantId) ?? {
|
|
272
|
+
id: payload.tenantId,
|
|
273
|
+
slug: "job",
|
|
274
|
+
plan: "free",
|
|
275
|
+
region: "eu"
|
|
276
|
+
};
|
|
277
|
+
const failure = await runWithTenantDatabase(tenant, async () => await this.deliver(payload));
|
|
278
|
+
if (failure) {
|
|
279
|
+
throw failure;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
async deliver(payload) {
|
|
283
|
+
const rows = await db2`
|
|
178
284
|
SELECT id, url, secret
|
|
179
285
|
FROM webhook
|
|
180
286
|
WHERE id = ${payload.webhookId} AND active = TRUE
|
|
@@ -204,7 +310,7 @@ class DispatchWebhookJob extends Job {
|
|
|
204
310
|
}
|
|
205
311
|
} catch (error) {
|
|
206
312
|
errorMessage = error instanceof Error ? error.message : String(error);
|
|
207
|
-
await
|
|
313
|
+
await db2`
|
|
208
314
|
INSERT INTO webhook_delivery (webhook_id, event, payload, response_status, error)
|
|
209
315
|
VALUES (
|
|
210
316
|
${webhook.id},
|
|
@@ -214,9 +320,9 @@ class DispatchWebhookJob extends Job {
|
|
|
214
320
|
${errorMessage}
|
|
215
321
|
)
|
|
216
322
|
`;
|
|
217
|
-
|
|
323
|
+
return error instanceof Error ? error : new Error(errorMessage);
|
|
218
324
|
}
|
|
219
|
-
await
|
|
325
|
+
await db2`
|
|
220
326
|
INSERT INTO webhook_delivery (webhook_id, event, payload, response_status)
|
|
221
327
|
VALUES (
|
|
222
328
|
${webhook.id},
|
|
@@ -43,8 +43,8 @@ function resetGracefulShutdownForTests() {
|
|
|
43
43
|
shuttingDown = false;
|
|
44
44
|
}
|
|
45
45
|
export {
|
|
46
|
-
|
|
47
|
-
resetGracefulShutdownForTests,
|
|
46
|
+
installGracefulShutdownSignals,
|
|
48
47
|
registerShutdownHandler,
|
|
49
|
-
|
|
48
|
+
resetGracefulShutdownForTests,
|
|
49
|
+
runGracefulShutdown
|
|
50
50
|
};
|
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
// ../../src/core/logging/requestLoggingMiddleware.ts
|
|
3
3
|
import { runWithRequestMeta } from "@getstrata/core/http/requestMetaContext";
|
|
4
4
|
|
|
5
|
+
// ../../src/core/http/clientIp.ts
|
|
6
|
+
function trustForwardedFor(env = process.env) {
|
|
7
|
+
return (env.TRUST_FORWARDED_FOR ?? "false") === "true";
|
|
8
|
+
}
|
|
9
|
+
function readClientIp(request, env = process.env) {
|
|
10
|
+
if (!trustForwardedFor(env)) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const forwarded = request.headers.get("x-forwarded-for")?.split(",")[0]?.trim();
|
|
14
|
+
if (forwarded) {
|
|
15
|
+
return forwarded;
|
|
16
|
+
}
|
|
17
|
+
return request.headers.get("x-real-ip")?.trim() || undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
5
20
|
// ../../src/core/logging/logger.ts
|
|
6
21
|
class Logger {
|
|
7
22
|
channel;
|
|
@@ -42,7 +57,7 @@ var appLogger = new Logger("app");
|
|
|
42
57
|
function createRequestLoggingMiddleware() {
|
|
43
58
|
return async (request, next) => {
|
|
44
59
|
return await runWithRequestMeta({
|
|
45
|
-
ipAddress: request
|
|
60
|
+
ipAddress: readClientIp(request) ?? null,
|
|
46
61
|
userAgent: request.headers.get("user-agent"),
|
|
47
62
|
request
|
|
48
63
|
}, async () => {
|
|
@@ -198,11 +198,11 @@ function mailer() {
|
|
|
198
198
|
return appMailer;
|
|
199
199
|
}
|
|
200
200
|
export {
|
|
201
|
-
|
|
202
|
-
mailer,
|
|
203
|
-
createMailDriver,
|
|
204
|
-
buildSmtpPayload,
|
|
205
|
-
SmtpMailDriver,
|
|
201
|
+
LogMailDriver,
|
|
206
202
|
Mailer,
|
|
207
|
-
|
|
203
|
+
SmtpMailDriver,
|
|
204
|
+
buildSmtpPayload,
|
|
205
|
+
createMailDriver,
|
|
206
|
+
mailer,
|
|
207
|
+
resolveSmtpConfig
|
|
208
208
|
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// ../../src/core/media/imageTransform.ts
|
|
3
|
+
var IMAGE_MIME_TYPES = new Set(["image/jpeg", "image/png", "image/gif", "image/webp"]);
|
|
4
|
+
function normalizeMimeType(mimeType) {
|
|
5
|
+
return mimeType.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
6
|
+
}
|
|
7
|
+
function isImageMimeType(mimeType) {
|
|
8
|
+
return IMAGE_MIME_TYPES.has(normalizeMimeType(mimeType));
|
|
9
|
+
}
|
|
10
|
+
function parseThumbnailWidth(raw, options = {}) {
|
|
11
|
+
const defaultWidth = options.defaultWidth ?? 200;
|
|
12
|
+
const minWidth = options.minWidth ?? 16;
|
|
13
|
+
const maxWidth = options.maxWidth ?? 800;
|
|
14
|
+
if (!raw?.trim()) {
|
|
15
|
+
return defaultWidth;
|
|
16
|
+
}
|
|
17
|
+
const parsed = Number.parseInt(raw, 10);
|
|
18
|
+
if (!Number.isInteger(parsed)) {
|
|
19
|
+
return defaultWidth;
|
|
20
|
+
}
|
|
21
|
+
return Math.min(maxWidth, Math.max(minWidth, parsed));
|
|
22
|
+
}
|
|
23
|
+
async function resizeImageContents(contents, width, mimeType) {
|
|
24
|
+
const normalized = normalizeMimeType(mimeType);
|
|
25
|
+
const pipeline = new Bun.Image(contents).resize(width);
|
|
26
|
+
if (normalized === "image/png") {
|
|
27
|
+
return { body: await pipeline.png().bytes(), contentType: "image/png" };
|
|
28
|
+
}
|
|
29
|
+
if (normalized === "image/webp") {
|
|
30
|
+
return { body: await pipeline.webp().bytes(), contentType: "image/webp" };
|
|
31
|
+
}
|
|
32
|
+
return { body: await pipeline.jpeg().bytes(), contentType: "image/jpeg" };
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
IMAGE_MIME_TYPES,
|
|
36
|
+
isImageMimeType,
|
|
37
|
+
normalizeMimeType,
|
|
38
|
+
parseThumbnailWidth,
|
|
39
|
+
resizeImageContents
|
|
40
|
+
};
|
|
@@ -346,9 +346,9 @@ function createAppQueue(driver, redisUrl, failedJobs = createFailedJobService(),
|
|
|
346
346
|
});
|
|
347
347
|
}
|
|
348
348
|
export {
|
|
349
|
-
|
|
350
|
-
createQueueWorker,
|
|
351
|
-
createFailedJobService,
|
|
349
|
+
FAILED_JOB_SERVICE_TOKEN,
|
|
352
350
|
createAppQueue,
|
|
353
|
-
|
|
351
|
+
createFailedJobService,
|
|
352
|
+
createQueueWorker,
|
|
353
|
+
createTrackedJob
|
|
354
354
|
};
|
|
@@ -336,15 +336,15 @@ function createQueueWorker(redisUrl, failedJobs = createFailedJobService()) {
|
|
|
336
336
|
return new QueueWorker(redisUrl, failedJobs);
|
|
337
337
|
}
|
|
338
338
|
export {
|
|
339
|
-
|
|
340
|
-
jobRegistry,
|
|
341
|
-
createTrackedJob,
|
|
342
|
-
createQueueWorker,
|
|
343
|
-
createProductionQueue,
|
|
344
|
-
createFailedJobService,
|
|
345
|
-
ResilientQueue,
|
|
346
|
-
RedisQueue,
|
|
347
|
-
QueueWorker,
|
|
339
|
+
failedJobRepository_default as FailedJobRepository,
|
|
348
340
|
failedJobService_default as FailedJobService,
|
|
349
|
-
|
|
341
|
+
QueueWorker,
|
|
342
|
+
RedisQueue,
|
|
343
|
+
ResilientQueue,
|
|
344
|
+
createFailedJobService,
|
|
345
|
+
createProductionQueue,
|
|
346
|
+
createQueueWorker,
|
|
347
|
+
createTrackedJob,
|
|
348
|
+
jobRegistry,
|
|
349
|
+
runQueueJob
|
|
350
350
|
};
|
|
@@ -222,12 +222,12 @@ async function countPendingQueueJobs(redisUrl) {
|
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
224
|
export {
|
|
225
|
-
|
|
226
|
-
parseQueueJobEnvelope,
|
|
227
|
-
countPendingQueueJobs,
|
|
228
|
-
RedisQueue,
|
|
229
|
-
QueueWorker,
|
|
230
|
-
QUEUE_LOW_KEY,
|
|
225
|
+
QUEUE_HIGH_KEY,
|
|
231
226
|
QUEUE_LIST_KEY,
|
|
232
|
-
|
|
227
|
+
QUEUE_LOW_KEY,
|
|
228
|
+
QueueWorker,
|
|
229
|
+
RedisQueue,
|
|
230
|
+
countPendingQueueJobs,
|
|
231
|
+
parseQueueJobEnvelope,
|
|
232
|
+
queueKeyForPriority
|
|
233
233
|
};
|
package/dist/entries/queue.js
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// ../../src/core/scheduler/osCron.ts
|
|
3
|
+
var DEFAULT_SCHEDULE_RUN_EXPRESSION = "* * * * *";
|
|
4
|
+
var OS_CRON_JOB_TITLE = "getstrata-schedule-run";
|
|
5
|
+
function parseScheduleExpression(expression, from = new Date) {
|
|
6
|
+
return Bun.cron.parse(expression, from);
|
|
7
|
+
}
|
|
8
|
+
function registerInProcessScheduleRunner(run, expression = DEFAULT_SCHEDULE_RUN_EXPRESSION) {
|
|
9
|
+
const register = Bun.cron;
|
|
10
|
+
return register(expression, async () => {
|
|
11
|
+
await run();
|
|
12
|
+
}).unref();
|
|
13
|
+
}
|
|
14
|
+
async function installOsScheduleRunner(workerScriptPath, expression = DEFAULT_SCHEDULE_RUN_EXPRESSION, title = OS_CRON_JOB_TITLE) {
|
|
15
|
+
await Bun.cron(workerScriptPath, expression, title);
|
|
16
|
+
}
|
|
17
|
+
async function uninstallOsScheduleRunner(title = OS_CRON_JOB_TITLE) {
|
|
18
|
+
await Bun.cron.remove(title);
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
DEFAULT_SCHEDULE_RUN_EXPRESSION,
|
|
22
|
+
OS_CRON_JOB_TITLE,
|
|
23
|
+
installOsScheduleRunner,
|
|
24
|
+
parseScheduleExpression,
|
|
25
|
+
registerInProcessScheduleRunner,
|
|
26
|
+
uninstallOsScheduleRunner
|
|
27
|
+
};
|
|
@@ -68,8 +68,8 @@ function clearOAuthStateCookie() {
|
|
|
68
68
|
return `${OAUTH_STATE_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`;
|
|
69
69
|
}
|
|
70
70
|
export {
|
|
71
|
-
|
|
72
|
-
createOAuthStateCookie,
|
|
71
|
+
OAUTH_STATE_COOKIE,
|
|
73
72
|
clearOAuthStateCookie,
|
|
74
|
-
|
|
73
|
+
createOAuthStateCookie,
|
|
74
|
+
verifyOAuthState
|
|
75
75
|
};
|
|
@@ -96,10 +96,10 @@ function resetDnsLookupForTests() {
|
|
|
96
96
|
dnsLookup = dnsLookupImpl;
|
|
97
97
|
}
|
|
98
98
|
export {
|
|
99
|
-
|
|
100
|
-
resetDnsLookupForTests,
|
|
101
|
-
isBlockedIpAddress,
|
|
102
|
-
isBlockedHostname,
|
|
99
|
+
assertSafeOutboundUrl,
|
|
103
100
|
assertSafeOutboundUrlResolved,
|
|
104
|
-
|
|
101
|
+
isBlockedHostname,
|
|
102
|
+
isBlockedIpAddress,
|
|
103
|
+
resetDnsLookupForTests,
|
|
104
|
+
setDnsLookupForTests
|
|
105
105
|
};
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// ../../src/domain/scim.ts
|
|
3
|
-
var TEST_SCIM_BEARER_TOKEN = "workhub-scim-test-token";
|
|
4
|
-
|
|
5
2
|
// ../../src/core/security/timingSafeCompare.ts
|
|
6
3
|
import { timingSafeEqual } from "crypto";
|
|
7
4
|
function timingSafeCompareString(left, right) {
|
|
@@ -39,13 +36,13 @@ function resolveScimTenantFromToken(token) {
|
|
|
39
36
|
return tenantId;
|
|
40
37
|
}
|
|
41
38
|
}
|
|
42
|
-
const fallbackToken = process.env.SCIM_BEARER_TOKEN ??
|
|
39
|
+
const fallbackToken = process.env.SCIM_BEARER_TOKEN ?? "";
|
|
43
40
|
if (timingSafeCompareString(token, fallbackToken)) {
|
|
44
41
|
return 1;
|
|
45
42
|
}
|
|
46
43
|
return null;
|
|
47
44
|
}
|
|
48
45
|
export {
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
parseScimTenantTokens,
|
|
47
|
+
resolveScimTenantFromToken
|
|
51
48
|
};
|
|
@@ -122,12 +122,12 @@ function resetDefaultStorage() {
|
|
|
122
122
|
defaultStorage.current = null;
|
|
123
123
|
}
|
|
124
124
|
export {
|
|
125
|
-
|
|
126
|
-
resolveS3Config,
|
|
127
|
-
resetDefaultStorage,
|
|
128
|
-
createStorageDriver,
|
|
129
|
-
createS3Client,
|
|
130
|
-
StorageManager,
|
|
125
|
+
LocalStorageDriver,
|
|
131
126
|
S3StorageDriver,
|
|
132
|
-
|
|
127
|
+
StorageManager,
|
|
128
|
+
createS3Client,
|
|
129
|
+
createStorageDriver,
|
|
130
|
+
resetDefaultStorage,
|
|
131
|
+
resolveS3Config,
|
|
132
|
+
storage
|
|
133
133
|
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// ../../src/core/tenant/tenancyConfig.ts
|
|
3
|
+
function readTenancyDriver(env = process.env) {
|
|
4
|
+
return env.TENANCY_DRIVER === "none" ? "none" : "rls";
|
|
5
|
+
}
|
|
6
|
+
function isTenancyEnabled(env = process.env) {
|
|
7
|
+
return readTenancyDriver(env) !== "none";
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
isTenancyEnabled,
|
|
11
|
+
readTenancyDriver
|
|
12
|
+
};
|
|
@@ -28,6 +28,14 @@ function hasActiveDatabaseConnection() {
|
|
|
28
28
|
return activeConnection.getStore() !== undefined;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// ../../src/core/tenant/tenancyConfig.ts
|
|
32
|
+
function readTenancyDriver(env = process.env) {
|
|
33
|
+
return env.TENANCY_DRIVER === "none" ? "none" : "rls";
|
|
34
|
+
}
|
|
35
|
+
function isTenancyEnabled(env = process.env) {
|
|
36
|
+
return readTenancyDriver(env) !== "none";
|
|
37
|
+
}
|
|
38
|
+
|
|
31
39
|
// ../../src/core/tenant/tenantContext.ts
|
|
32
40
|
var tenantContext = createAsyncContextStore("@getstrata/tenantContext");
|
|
33
41
|
function runWithTenant(tenant, callback) {
|
|
@@ -43,6 +51,9 @@ async function applyTenantContextToTransaction(transaction, tenantId) {
|
|
|
43
51
|
await transaction.unsafe(`SELECT set_config('app.bypass_rls', $1, true)`, ["false"]);
|
|
44
52
|
}
|
|
45
53
|
async function runWithTenantDatabase(tenant, callback) {
|
|
54
|
+
if (!isTenancyEnabled()) {
|
|
55
|
+
return await runWithTenant(tenant, callback);
|
|
56
|
+
}
|
|
46
57
|
if (hasActiveDatabaseConnection()) {
|
|
47
58
|
const activeConnection2 = getActiveDatabaseConnection(getDefaultDatabasePool());
|
|
48
59
|
await applyTenantContextToTransaction(activeConnection2, tenant.id);
|
|
@@ -59,7 +70,7 @@ function isInsideTenantDatabaseScope(tenantId = currentTenant()?.id) {
|
|
|
59
70
|
return hasActiveDatabaseConnection() && currentTenant()?.id === tenantId;
|
|
60
71
|
}
|
|
61
72
|
export {
|
|
62
|
-
|
|
73
|
+
applyTenantContextToTransaction,
|
|
63
74
|
isInsideTenantDatabaseScope,
|
|
64
|
-
|
|
75
|
+
runWithTenantDatabase
|
|
65
76
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// ../../src/core/terminal/runShell.ts
|
|
3
|
+
async function runInteractiveShell(command, options = {}) {
|
|
4
|
+
await using terminal = new Bun.Terminal({
|
|
5
|
+
cols: options.cols ?? 120,
|
|
6
|
+
rows: options.rows ?? 30
|
|
7
|
+
});
|
|
8
|
+
const proc = Bun.spawn(command, {
|
|
9
|
+
terminal,
|
|
10
|
+
cwd: options.cwd,
|
|
11
|
+
stdin: "inherit"
|
|
12
|
+
});
|
|
13
|
+
await proc.exited;
|
|
14
|
+
return proc.exitCode ?? 1;
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
runInteractiveShell
|
|
18
|
+
};
|
|
@@ -151,17 +151,17 @@ function validateObject(payload, schema) {
|
|
|
151
151
|
return output;
|
|
152
152
|
}
|
|
153
153
|
export {
|
|
154
|
-
|
|
155
|
-
stringRule,
|
|
156
|
-
required,
|
|
157
|
-
positiveIntegerRule,
|
|
158
|
-
pattern,
|
|
159
|
-
optional,
|
|
160
|
-
minLength,
|
|
161
|
-
maxLength,
|
|
162
|
-
integerRule,
|
|
163
|
-
integerRange,
|
|
164
|
-
enumRule,
|
|
154
|
+
confirmed,
|
|
165
155
|
emailRule,
|
|
166
|
-
|
|
156
|
+
enumRule,
|
|
157
|
+
integerRange,
|
|
158
|
+
integerRule,
|
|
159
|
+
maxLength,
|
|
160
|
+
minLength,
|
|
161
|
+
optional,
|
|
162
|
+
pattern,
|
|
163
|
+
positiveIntegerRule,
|
|
164
|
+
required,
|
|
165
|
+
stringRule,
|
|
166
|
+
validateObject
|
|
167
167
|
};
|