@getstrata/core 0.5.55 → 0.5.56
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 +2 -0
- package/dist/core/media/imageTransform.d.ts +13 -0
- package/dist/core/scheduler/osCron.d.ts +14 -0
- 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/membershipScope.js +6 -6
- 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/sessionCookie.js +4 -4
- package/dist/entries/auth/sessionGuard.js +0 -91
- 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/cookies.js +2 -2
- package/dist/entries/http/csrfProtection.js +2 -2
- package/dist/entries/http/csrfToken.js +6 -6
- 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 +2 -2
- 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 +186 -98
- package/dist/entries/http/securedRouteModelBinding.js +2 -2
- package/dist/entries/http/throttleMiddleware.js +2 -2
- package/dist/entries/http/validation.js +13 -13
- package/dist/entries/http/webErrorResponse.js +184 -96
- package/dist/entries/lifecycle/gracefulShutdown.js +3 -3
- package/dist/entries/logging/logger.js +2 -2
- 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 +2 -2
- package/dist/entries/security/totp.js +2 -2
- package/dist/entries/storage/storage.js +7 -7
- package/dist/entries/tenant/tenantDatabaseScope.js +2 -2
- package/dist/entries/terminal/runShell.js +18 -0
- package/dist/entries/validation/rules.js +12 -12
- package/dist/entries/view.js +186 -98
- package/dist/index.js +431 -469
- package/package.json +17 -2
|
@@ -81,8 +81,183 @@ async function withDatabaseErrorHandling(operation) {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// ../../src/core/view/etaViewEngine.ts
|
|
84
|
-
import { join } from "path";
|
|
84
|
+
import { join, relative } from "path";
|
|
85
85
|
import { Eta } from "eta";
|
|
86
|
+
|
|
87
|
+
// ../../src/core/view/assertEtaHtmlSource.ts
|
|
88
|
+
var HTML_TAGS = new Set([
|
|
89
|
+
"a",
|
|
90
|
+
"abbr",
|
|
91
|
+
"address",
|
|
92
|
+
"article",
|
|
93
|
+
"aside",
|
|
94
|
+
"audio",
|
|
95
|
+
"b",
|
|
96
|
+
"blockquote",
|
|
97
|
+
"body",
|
|
98
|
+
"button",
|
|
99
|
+
"canvas",
|
|
100
|
+
"caption",
|
|
101
|
+
"cite",
|
|
102
|
+
"code",
|
|
103
|
+
"col",
|
|
104
|
+
"colgroup",
|
|
105
|
+
"data",
|
|
106
|
+
"datalist",
|
|
107
|
+
"dd",
|
|
108
|
+
"del",
|
|
109
|
+
"details",
|
|
110
|
+
"dfn",
|
|
111
|
+
"dialog",
|
|
112
|
+
"div",
|
|
113
|
+
"dl",
|
|
114
|
+
"dt",
|
|
115
|
+
"em",
|
|
116
|
+
"fieldset",
|
|
117
|
+
"figcaption",
|
|
118
|
+
"figure",
|
|
119
|
+
"footer",
|
|
120
|
+
"form",
|
|
121
|
+
"h1",
|
|
122
|
+
"h2",
|
|
123
|
+
"h3",
|
|
124
|
+
"h4",
|
|
125
|
+
"h5",
|
|
126
|
+
"h6",
|
|
127
|
+
"header",
|
|
128
|
+
"hgroup",
|
|
129
|
+
"hr",
|
|
130
|
+
"html",
|
|
131
|
+
"i",
|
|
132
|
+
"iframe",
|
|
133
|
+
"img",
|
|
134
|
+
"input",
|
|
135
|
+
"ins",
|
|
136
|
+
"kbd",
|
|
137
|
+
"label",
|
|
138
|
+
"legend",
|
|
139
|
+
"li",
|
|
140
|
+
"main",
|
|
141
|
+
"map",
|
|
142
|
+
"mark",
|
|
143
|
+
"menu",
|
|
144
|
+
"meter",
|
|
145
|
+
"nav",
|
|
146
|
+
"object",
|
|
147
|
+
"ol",
|
|
148
|
+
"optgroup",
|
|
149
|
+
"option",
|
|
150
|
+
"output",
|
|
151
|
+
"p",
|
|
152
|
+
"picture",
|
|
153
|
+
"pre",
|
|
154
|
+
"progress",
|
|
155
|
+
"q",
|
|
156
|
+
"rp",
|
|
157
|
+
"rt",
|
|
158
|
+
"ruby",
|
|
159
|
+
"s",
|
|
160
|
+
"samp",
|
|
161
|
+
"script",
|
|
162
|
+
"search",
|
|
163
|
+
"section",
|
|
164
|
+
"select",
|
|
165
|
+
"slot",
|
|
166
|
+
"small",
|
|
167
|
+
"source",
|
|
168
|
+
"span",
|
|
169
|
+
"strong",
|
|
170
|
+
"style",
|
|
171
|
+
"sub",
|
|
172
|
+
"summary",
|
|
173
|
+
"sup",
|
|
174
|
+
"table",
|
|
175
|
+
"tbody",
|
|
176
|
+
"td",
|
|
177
|
+
"template",
|
|
178
|
+
"textarea",
|
|
179
|
+
"tfoot",
|
|
180
|
+
"th",
|
|
181
|
+
"thead",
|
|
182
|
+
"time",
|
|
183
|
+
"title",
|
|
184
|
+
"tr",
|
|
185
|
+
"track",
|
|
186
|
+
"u",
|
|
187
|
+
"ul",
|
|
188
|
+
"var",
|
|
189
|
+
"video",
|
|
190
|
+
"wbr"
|
|
191
|
+
]);
|
|
192
|
+
var TAG_PATTERN = "([a-z][a-z0-9]*)";
|
|
193
|
+
var CLASS_OR_ID_PATTERN = "[.#][\\w-]+";
|
|
194
|
+
var CLASS_ID_SHORTHAND = new RegExp(`^${TAG_PATTERN}(?:${CLASS_OR_ID_PATTERN})+`);
|
|
195
|
+
var ATTRIBUTE_SHORTHAND = new RegExp(`^${TAG_PATTERN}(?:${CLASS_OR_ID_PATTERN})*\\s+[\\w:-]+=`);
|
|
196
|
+
var TAG_SHORTHAND = new RegExp(`^${TAG_PATTERN}(?:>|\\s+\\S|$)`);
|
|
197
|
+
function htmlTagName(match) {
|
|
198
|
+
const tag = match?.[1];
|
|
199
|
+
return tag && HTML_TAGS.has(tag) ? tag : undefined;
|
|
200
|
+
}
|
|
201
|
+
function describePugLikeLine(line) {
|
|
202
|
+
if (/^\|(?:\s|$)/.test(line)) {
|
|
203
|
+
return "piped text";
|
|
204
|
+
}
|
|
205
|
+
if (htmlTagName(line.match(CLASS_ID_SHORTHAND))) {
|
|
206
|
+
return "class/id shorthand";
|
|
207
|
+
}
|
|
208
|
+
if (htmlTagName(line.match(ATTRIBUTE_SHORTHAND))) {
|
|
209
|
+
return "attribute shorthand";
|
|
210
|
+
}
|
|
211
|
+
if (htmlTagName(line.match(TAG_SHORTHAND))) {
|
|
212
|
+
return "tag shorthand";
|
|
213
|
+
}
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
function updateSkipBlock(lower, skipBlock) {
|
|
217
|
+
if (skipBlock) {
|
|
218
|
+
if (skipBlock === "comment" && lower.includes("-->")) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
if (skipBlock !== "comment" && lower.includes(`</${skipBlock}`)) {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
return skipBlock;
|
|
225
|
+
}
|
|
226
|
+
if (lower.startsWith("<!--") && !lower.includes("-->")) {
|
|
227
|
+
return "comment";
|
|
228
|
+
}
|
|
229
|
+
if (lower.startsWith("<script") && !lower.includes("</script")) {
|
|
230
|
+
return "script";
|
|
231
|
+
}
|
|
232
|
+
if (lower.startsWith("<style") && !lower.includes("</style")) {
|
|
233
|
+
return "style";
|
|
234
|
+
}
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
function assertEtaHtmlSource(templateName, source) {
|
|
238
|
+
let skipBlock = null;
|
|
239
|
+
for (const rawLine of source.split(/\r?\n/)) {
|
|
240
|
+
const trimmed = rawLine.trim();
|
|
241
|
+
if (!trimmed) {
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const lower = trimmed.toLowerCase();
|
|
245
|
+
const nextSkipBlock = updateSkipBlock(lower, skipBlock);
|
|
246
|
+
if (skipBlock || nextSkipBlock) {
|
|
247
|
+
skipBlock = nextSkipBlock;
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (trimmed.startsWith("<") || trimmed.startsWith("<%")) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
const kind = describePugLikeLine(trimmed);
|
|
254
|
+
if (kind) {
|
|
255
|
+
throw new Error(`Eta view "${templateName}" contains Pug-like markup (${kind}: ${trimmed}). Eta views must be HTML + <% %> tags, not Pug.`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// ../../src/core/view/etaViewEngine.ts
|
|
86
261
|
var DEFAULT_VIEWS_DIRECTORY = join(process.cwd(), "resources/views");
|
|
87
262
|
var DEFAULT_LAYOUT = "layouts/app.eta";
|
|
88
263
|
|
|
@@ -95,6 +270,12 @@ class EtaViewEngine {
|
|
|
95
270
|
autoTrim: false
|
|
96
271
|
});
|
|
97
272
|
this.resolveLayoutData = resolveLayoutData;
|
|
273
|
+
const readFile = this.eta.readFile?.bind(this.eta);
|
|
274
|
+
this.eta.readFile = (path) => {
|
|
275
|
+
const source = readFile ? readFile(path) : "";
|
|
276
|
+
assertEtaHtmlSource(relative(viewsDirectory, path) || path, source);
|
|
277
|
+
return source;
|
|
278
|
+
};
|
|
98
279
|
}
|
|
99
280
|
async render(name, data = {}, options = {}) {
|
|
100
281
|
const template = name.endsWith(".eta") ? name : `${name}.eta`;
|
|
@@ -358,99 +539,6 @@ function resolveAbilitiesForRole(role) {
|
|
|
358
539
|
return [...MEMBER_ABILITIES];
|
|
359
540
|
}
|
|
360
541
|
|
|
361
|
-
// ../../src/modules/user/authService.ts
|
|
362
|
-
class AuthService {
|
|
363
|
-
users;
|
|
364
|
-
tokens;
|
|
365
|
-
oauthIdentities;
|
|
366
|
-
oauthProviders = new Map;
|
|
367
|
-
constructor(users, tokens, oauthIdentities) {
|
|
368
|
-
this.users = users;
|
|
369
|
-
this.tokens = tokens;
|
|
370
|
-
this.oauthIdentities = oauthIdentities;
|
|
371
|
-
}
|
|
372
|
-
registerOAuthProvider(provider) {
|
|
373
|
-
this.oauthProviders.set(provider.name, provider);
|
|
374
|
-
}
|
|
375
|
-
getOAuthProvider(name) {
|
|
376
|
-
return this.oauthProviders.get(name);
|
|
377
|
-
}
|
|
378
|
-
async loginWithPassword(email, password, options = {}) {
|
|
379
|
-
const user = await this.users.findByEmail(email);
|
|
380
|
-
if (!user?.password_hash) {
|
|
381
|
-
logSecurityEvent("auth_login_failed", { reason: "unknown_user", email });
|
|
382
|
-
throw new UnauthorizedError("Invalid credentials.");
|
|
383
|
-
}
|
|
384
|
-
const valid = await verifyPassword(password, user.password_hash);
|
|
385
|
-
if (!valid) {
|
|
386
|
-
logSecurityEvent("auth_login_failed", { reason: "invalid_password", user_id: user.id });
|
|
387
|
-
throw new UnauthorizedError("Invalid credentials.");
|
|
388
|
-
}
|
|
389
|
-
if (isFeatureEnabled("emailVerification") && !user.email_verified_at) {
|
|
390
|
-
logSecurityEvent("auth_login_blocked", { reason: "email_unverified", user_id: user.id });
|
|
391
|
-
throw new UnauthorizedError("Email address is not verified.");
|
|
392
|
-
}
|
|
393
|
-
if (isFeatureEnabled("mfa") && user.mfa_enabled) {
|
|
394
|
-
const mfaSecret = revealMfaSecret(user.mfa_secret);
|
|
395
|
-
if (!mfaSecret || !options.mfaCode || !verifyTotp(mfaSecret, options.mfaCode)) {
|
|
396
|
-
logSecurityEvent("auth_login_failed", { reason: "invalid_mfa", user_id: user.id });
|
|
397
|
-
throw new UnauthorizedError("Invalid MFA code.");
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
logSecurityEvent("auth_login_success", { user_id: user.id, method: "password" });
|
|
401
|
-
return await this.tokens.createToken(user.id, {
|
|
402
|
-
name: "password-login",
|
|
403
|
-
abilities: resolveAbilitiesForRole(user.role),
|
|
404
|
-
expiresInDays: resolveDefaultTokenExpiryDays() ?? undefined
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
async loginWithOAuth(providerName, code) {
|
|
408
|
-
const provider = this.oauthProviders.get(providerName);
|
|
409
|
-
if (!provider) {
|
|
410
|
-
throw new UnauthorizedError("Unsupported OAuth provider.");
|
|
411
|
-
}
|
|
412
|
-
const profile = await provider.exchangeCode(code);
|
|
413
|
-
const user = await this.findOrCreateOAuthUser(providerName, profile);
|
|
414
|
-
logSecurityEvent("auth_login_success", { user_id: user.id, method: `oauth:${providerName}` });
|
|
415
|
-
return await this.tokens.createToken(user.id, {
|
|
416
|
-
name: `${providerName}-oauth`,
|
|
417
|
-
abilities: resolveAbilitiesForRole(user.role),
|
|
418
|
-
expiresInDays: resolveDefaultTokenExpiryDays() ?? undefined
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
buildOAuthAuthorizationUrl(providerName, state) {
|
|
422
|
-
const provider = this.oauthProviders.get(providerName);
|
|
423
|
-
if (!provider) {
|
|
424
|
-
throw new UnauthorizedError("Unsupported OAuth provider.");
|
|
425
|
-
}
|
|
426
|
-
return provider.getAuthorizationUrl(state);
|
|
427
|
-
}
|
|
428
|
-
async findOrCreateOAuthUser(providerName, profile) {
|
|
429
|
-
const existingIdentity = await this.oauthIdentities.findByProviderUser(providerName, profile.providerUserId);
|
|
430
|
-
if (existingIdentity) {
|
|
431
|
-
return await this.users.findByIdOrThrow(existingIdentity.user_id);
|
|
432
|
-
}
|
|
433
|
-
const existingUser = await this.users.findByEmail(profile.email);
|
|
434
|
-
const user = existingUser ?? await this.users.create({
|
|
435
|
-
name: profile.name,
|
|
436
|
-
email: profile.email,
|
|
437
|
-
role: "member",
|
|
438
|
-
tenant_id: currentTenantId(),
|
|
439
|
-
email_verified_at: new Date,
|
|
440
|
-
created_at: new Date,
|
|
441
|
-
updated_at: new Date
|
|
442
|
-
});
|
|
443
|
-
await this.oauthIdentities.create({
|
|
444
|
-
user_id: user.id,
|
|
445
|
-
provider: providerName,
|
|
446
|
-
provider_user_id: profile.providerUserId,
|
|
447
|
-
email: profile.email,
|
|
448
|
-
created_at: new Date
|
|
449
|
-
});
|
|
450
|
-
return user;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
542
|
// ../../src/modules/user/notificationRepository.ts
|
|
455
543
|
import { BaseRepository as BaseRepository2 } from "@getstrata/core/database/baseRepository";
|
|
456
544
|
|
|
@@ -834,6 +922,6 @@ function webErrorResponse(error, request) {
|
|
|
834
922
|
});
|
|
835
923
|
}
|
|
836
924
|
export {
|
|
837
|
-
|
|
838
|
-
|
|
925
|
+
normalizeFieldErrors,
|
|
926
|
+
webErrorResponse
|
|
839
927
|
};
|
|
@@ -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
|
};
|
|
@@ -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
|
};
|
|
@@ -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
|
};
|
|
@@ -59,7 +59,7 @@ function isInsideTenantDatabaseScope(tenantId = currentTenant()?.id) {
|
|
|
59
59
|
return hasActiveDatabaseConnection() && currentTenant()?.id === tenantId;
|
|
60
60
|
}
|
|
61
61
|
export {
|
|
62
|
-
|
|
62
|
+
applyTenantContextToTransaction,
|
|
63
63
|
isInsideTenantDatabaseScope,
|
|
64
|
-
|
|
64
|
+
runWithTenantDatabase
|
|
65
65
|
};
|
|
@@ -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
|
+
};
|