@getstrata/bootstrap 1.1.0 → 1.1.2
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/CHANGELOG.md +13 -0
- package/dist/bootstrap/discoverJobs.d.ts +8 -0
- package/dist/bootstrap/discoverListeners.d.ts +2 -2
- package/dist/bootstrap/public-api.d.ts +1 -0
- package/dist/entries/context.js +96 -12
- package/dist/entries/dependencies.js +96 -12
- package/dist/entries/discoverJobs.js +69 -0
- package/dist/entries/discoverListeners.js +54 -0
- package/dist/entries/providers.js +98 -14
- package/dist/index.js +96 -14
- package/package.json +13 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @getstrata/bootstrap changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.2
|
|
4
|
+
|
|
5
|
+
- Product CLI helpers, file migrations, and job discovery.
|
|
6
|
+
|
|
7
|
+
## Unreleased
|
|
8
|
+
|
|
9
|
+
- `discoverJobs()` loads `src/jobs/*.ts` default exports with `static jobName` into `jobRegistry`, same cache pattern as `discoverListeners()`.
|
|
10
|
+
- Queue providers register default jobs and discovered jobs together.
|
|
11
|
+
|
|
12
|
+
## 1.1.1
|
|
13
|
+
|
|
14
|
+
Fix generated app boot
|
|
15
|
+
|
|
3
16
|
## 1.1.0
|
|
4
17
|
|
|
5
18
|
Lockstep with `@getstrata/core` 1.1.0. Cookie sessions select `s.created_at AS session_created_at` so `users.created_at` from `u.*` cannot clobber the session issued-at. API group always includes session-mutating CSRF. `buildModuleRoutes` maps thrown API middleware errors (including CSRF `ForbiddenError`) to JSON. `HttpKernel.wrap("api")` does the same for routes used outside that builder. Path confinement on the web server and safer production defaults. The rls role denylist checks the runtime URL (`APP_DATABASE_URL` when set, otherwise `DATABASE_URL`) so fixture admin `DATABASE_URL` can stay `postgres`.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Job } from "@getstrata/core/queue";
|
|
2
|
+
type DiscoveredJobClass = (new () => Job) & {
|
|
3
|
+
jobName: string;
|
|
4
|
+
};
|
|
5
|
+
declare function discoverJobs(): string[];
|
|
6
|
+
declare function resetDiscoverJobsForTests(): void;
|
|
7
|
+
export type { DiscoveredJobClass };
|
|
8
|
+
export { discoverJobs, resetDiscoverJobsForTests };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
type ListenerRegistrar = () => void;
|
|
2
|
-
declare const appListeners: ListenerRegistrar[];
|
|
3
2
|
declare function discoverListeners(): ListenerRegistrar[];
|
|
3
|
+
declare function resetDiscoverListenersForTests(): void;
|
|
4
4
|
export type { ListenerRegistrar };
|
|
5
|
-
export {
|
|
5
|
+
export { discoverListeners, resetDiscoverListenersForTests };
|
|
@@ -16,6 +16,7 @@ export { assertAppDependenciesComplete, getRequiredDependency, resolveService, S
|
|
|
16
16
|
export type { CreateWebRoutesOptions } from "./createWebRoutes.ts";
|
|
17
17
|
export { createWebRoutes, mergeWebRoutes } from "./createWebRoutes.ts";
|
|
18
18
|
export { createAppDependencies } from "./dependencies.ts";
|
|
19
|
+
export { discoverJobs, resetDiscoverJobsForTests } from "./discoverJobs.ts";
|
|
19
20
|
export type { DiscoverModulesOptions } from "./discoverModules.ts";
|
|
20
21
|
export { configureModulesDirectory, discoverModules, ensureModulesLoaded, } from "./discoverModules.ts";
|
|
21
22
|
export type { CreateHealthRoutesOptions } from "./health.ts";
|
package/dist/entries/context.js
CHANGED
|
@@ -370,8 +370,19 @@ var events_default = eventsProvider;
|
|
|
370
370
|
|
|
371
371
|
// ../../src/bootstrap/discoverListeners.ts
|
|
372
372
|
import { existsSync, readdirSync as readdirSync2 } from "fs";
|
|
373
|
+
import { createRequire } from "module";
|
|
373
374
|
import { join as join2 } from "path";
|
|
374
|
-
|
|
375
|
+
var requireListener = createRequire(import.meta.url);
|
|
376
|
+
var DISCOVER_LISTENERS_STATE_KEY = Symbol.for("@getstrata/discoverListenersState");
|
|
377
|
+
function readDiscoverListenersState() {
|
|
378
|
+
const existing = globalThis[DISCOVER_LISTENERS_STATE_KEY];
|
|
379
|
+
if (existing) {
|
|
380
|
+
return existing;
|
|
381
|
+
}
|
|
382
|
+
const state = {};
|
|
383
|
+
globalThis[DISCOVER_LISTENERS_STATE_KEY] = state;
|
|
384
|
+
return state;
|
|
385
|
+
}
|
|
375
386
|
function resolveListenersDirectory() {
|
|
376
387
|
const fromCwd = join2(process.cwd(), "src", "listeners");
|
|
377
388
|
if (existsSync(fromCwd)) {
|
|
@@ -379,7 +390,7 @@ function resolveListenersDirectory() {
|
|
|
379
390
|
}
|
|
380
391
|
return join2(import.meta.dir, "../listeners");
|
|
381
392
|
}
|
|
382
|
-
|
|
393
|
+
function loadDiscoveredListeners() {
|
|
383
394
|
const listenersDirectory = resolveListenersDirectory();
|
|
384
395
|
let entries;
|
|
385
396
|
try {
|
|
@@ -390,16 +401,21 @@ async function loadDiscoveredListeners() {
|
|
|
390
401
|
}
|
|
391
402
|
throw error;
|
|
392
403
|
}
|
|
393
|
-
const listeners =
|
|
394
|
-
const
|
|
395
|
-
const loaded =
|
|
404
|
+
const listeners = entries.map((fileName) => {
|
|
405
|
+
const filePath = join2(listenersDirectory, fileName);
|
|
406
|
+
const loaded = requireListener(filePath);
|
|
396
407
|
return loaded.default;
|
|
397
|
-
})
|
|
408
|
+
});
|
|
398
409
|
return listeners.filter((listener) => typeof listener === "function");
|
|
399
410
|
}
|
|
400
|
-
var appListeners = await loadDiscoveredListeners();
|
|
401
411
|
function discoverListeners() {
|
|
402
|
-
|
|
412
|
+
const state = readDiscoverListenersState();
|
|
413
|
+
state.appListeners ??= loadDiscoveredListeners();
|
|
414
|
+
return state.appListeners;
|
|
415
|
+
}
|
|
416
|
+
function resetDiscoverListenersForTests() {
|
|
417
|
+
const state = readDiscoverListenersState();
|
|
418
|
+
state.appListeners = undefined;
|
|
403
419
|
}
|
|
404
420
|
|
|
405
421
|
// ../../src/bootstrap/listeners/invalidateCacheOnModelWrite.ts
|
|
@@ -483,16 +499,81 @@ import {
|
|
|
483
499
|
FAILED_JOB_SERVICE_TOKEN
|
|
484
500
|
} from "@getstrata/core/queue/createAppQueue";
|
|
485
501
|
|
|
502
|
+
// ../../src/bootstrap/discoverJobs.ts
|
|
503
|
+
import { existsSync as existsSync2, readdirSync as readdirSync3 } from "fs";
|
|
504
|
+
import { createRequire as createRequire2 } from "module";
|
|
505
|
+
import { join as join3 } from "path";
|
|
506
|
+
import { jobRegistry } from "@getstrata/core/queue/jobRegistry";
|
|
507
|
+
var requireJob = createRequire2(import.meta.url);
|
|
508
|
+
var DISCOVER_JOBS_STATE_KEY = Symbol.for("@getstrata/discoverJobsState");
|
|
509
|
+
function readDiscoverJobsState() {
|
|
510
|
+
const existing = globalThis[DISCOVER_JOBS_STATE_KEY];
|
|
511
|
+
if (existing) {
|
|
512
|
+
return existing;
|
|
513
|
+
}
|
|
514
|
+
const state = {};
|
|
515
|
+
globalThis[DISCOVER_JOBS_STATE_KEY] = state;
|
|
516
|
+
return state;
|
|
517
|
+
}
|
|
518
|
+
function resolveJobsDirectory() {
|
|
519
|
+
const fromCwd = join3(process.cwd(), "src", "jobs");
|
|
520
|
+
if (existsSync2(fromCwd)) {
|
|
521
|
+
return fromCwd;
|
|
522
|
+
}
|
|
523
|
+
return join3(import.meta.dir, "../jobs");
|
|
524
|
+
}
|
|
525
|
+
function isDiscoveredJobClass(value) {
|
|
526
|
+
if (typeof value !== "function") {
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
const jobName = value.jobName;
|
|
530
|
+
return typeof jobName === "string" && jobName.length > 0;
|
|
531
|
+
}
|
|
532
|
+
function loadDiscoveredJobClasses() {
|
|
533
|
+
const jobsDirectory = resolveJobsDirectory();
|
|
534
|
+
let entries;
|
|
535
|
+
try {
|
|
536
|
+
entries = readdirSync3(jobsDirectory, { withFileTypes: true }).filter((entry) => entry.isFile() && /\.(ts|js)$/.test(entry.name)).map((entry) => entry.name);
|
|
537
|
+
} catch (error) {
|
|
538
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
539
|
+
return [];
|
|
540
|
+
}
|
|
541
|
+
throw error;
|
|
542
|
+
}
|
|
543
|
+
return entries.flatMap((fileName) => {
|
|
544
|
+
const filePath = join3(jobsDirectory, fileName);
|
|
545
|
+
const loaded = requireJob(filePath);
|
|
546
|
+
return isDiscoveredJobClass(loaded.default) ? [loaded.default] : [];
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
function discoverJobs() {
|
|
550
|
+
const state = readDiscoverJobsState();
|
|
551
|
+
if (state.names) {
|
|
552
|
+
return state.names;
|
|
553
|
+
}
|
|
554
|
+
const names = [];
|
|
555
|
+
for (const JobClass of loadDiscoveredJobClasses()) {
|
|
556
|
+
jobRegistry.register(JobClass.jobName, () => new JobClass);
|
|
557
|
+
names.push(JobClass.jobName);
|
|
558
|
+
}
|
|
559
|
+
state.names = names;
|
|
560
|
+
return names;
|
|
561
|
+
}
|
|
562
|
+
function resetDiscoverJobsForTests() {
|
|
563
|
+
const state = readDiscoverJobsState();
|
|
564
|
+
state.names = undefined;
|
|
565
|
+
}
|
|
566
|
+
|
|
486
567
|
// ../../src/bootstrap/queue/defaultJobs.ts
|
|
487
568
|
import { ExportAuditLogsJob } from "@getstrata/core/jobs/exportAuditLogsJob";
|
|
488
569
|
import { InvalidateCacheTagsJob as InvalidateCacheTagsJob2 } from "@getstrata/core/jobs/invalidateCacheTagsJob";
|
|
489
|
-
import { jobRegistry } from "@getstrata/core/queue/jobRegistry";
|
|
570
|
+
import { jobRegistry as jobRegistry2 } from "@getstrata/core/queue/jobRegistry";
|
|
490
571
|
import { resolveApplicationCache as resolveApplicationCache2 } from "@getstrata/core/runtime/applicationRegistry";
|
|
491
572
|
function registerDefaultJobs() {
|
|
492
|
-
|
|
573
|
+
jobRegistry2.register("cache.invalidate-tags", () => {
|
|
493
574
|
return new InvalidateCacheTagsJob2(resolveApplicationCache2());
|
|
494
575
|
});
|
|
495
|
-
|
|
576
|
+
jobRegistry2.register("audit.export", () => new ExportAuditLogsJob);
|
|
496
577
|
}
|
|
497
578
|
|
|
498
579
|
// ../../src/bootstrap/providers/queue.ts
|
|
@@ -504,7 +585,10 @@ var queueProvider = {
|
|
|
504
585
|
config.set("queue.driver", driver);
|
|
505
586
|
const failedJobs = createFailedJobService();
|
|
506
587
|
container.set(FAILED_JOB_SERVICE_TOKEN, failedJobs);
|
|
507
|
-
container.set(CORE_QUEUE_TOKEN, createAppQueue(driver, config.get(REDIS_URL_CONFIG_KEY) ?? process.env.REDIS_URL, failedJobs,
|
|
588
|
+
container.set(CORE_QUEUE_TOKEN, createAppQueue(driver, config.get(REDIS_URL_CONFIG_KEY) ?? process.env.REDIS_URL, failedJobs, () => {
|
|
589
|
+
registerDefaultJobs();
|
|
590
|
+
discoverJobs();
|
|
591
|
+
}));
|
|
508
592
|
}
|
|
509
593
|
};
|
|
510
594
|
var queue_default = queueProvider;
|
|
@@ -370,8 +370,19 @@ var events_default = eventsProvider;
|
|
|
370
370
|
|
|
371
371
|
// ../../src/bootstrap/discoverListeners.ts
|
|
372
372
|
import { existsSync, readdirSync as readdirSync2 } from "fs";
|
|
373
|
+
import { createRequire } from "module";
|
|
373
374
|
import { join as join2 } from "path";
|
|
374
|
-
|
|
375
|
+
var requireListener = createRequire(import.meta.url);
|
|
376
|
+
var DISCOVER_LISTENERS_STATE_KEY = Symbol.for("@getstrata/discoverListenersState");
|
|
377
|
+
function readDiscoverListenersState() {
|
|
378
|
+
const existing = globalThis[DISCOVER_LISTENERS_STATE_KEY];
|
|
379
|
+
if (existing) {
|
|
380
|
+
return existing;
|
|
381
|
+
}
|
|
382
|
+
const state = {};
|
|
383
|
+
globalThis[DISCOVER_LISTENERS_STATE_KEY] = state;
|
|
384
|
+
return state;
|
|
385
|
+
}
|
|
375
386
|
function resolveListenersDirectory() {
|
|
376
387
|
const fromCwd = join2(process.cwd(), "src", "listeners");
|
|
377
388
|
if (existsSync(fromCwd)) {
|
|
@@ -379,7 +390,7 @@ function resolveListenersDirectory() {
|
|
|
379
390
|
}
|
|
380
391
|
return join2(import.meta.dir, "../listeners");
|
|
381
392
|
}
|
|
382
|
-
|
|
393
|
+
function loadDiscoveredListeners() {
|
|
383
394
|
const listenersDirectory = resolveListenersDirectory();
|
|
384
395
|
let entries;
|
|
385
396
|
try {
|
|
@@ -390,16 +401,21 @@ async function loadDiscoveredListeners() {
|
|
|
390
401
|
}
|
|
391
402
|
throw error;
|
|
392
403
|
}
|
|
393
|
-
const listeners =
|
|
394
|
-
const
|
|
395
|
-
const loaded =
|
|
404
|
+
const listeners = entries.map((fileName) => {
|
|
405
|
+
const filePath = join2(listenersDirectory, fileName);
|
|
406
|
+
const loaded = requireListener(filePath);
|
|
396
407
|
return loaded.default;
|
|
397
|
-
})
|
|
408
|
+
});
|
|
398
409
|
return listeners.filter((listener) => typeof listener === "function");
|
|
399
410
|
}
|
|
400
|
-
var appListeners = await loadDiscoveredListeners();
|
|
401
411
|
function discoverListeners() {
|
|
402
|
-
|
|
412
|
+
const state = readDiscoverListenersState();
|
|
413
|
+
state.appListeners ??= loadDiscoveredListeners();
|
|
414
|
+
return state.appListeners;
|
|
415
|
+
}
|
|
416
|
+
function resetDiscoverListenersForTests() {
|
|
417
|
+
const state = readDiscoverListenersState();
|
|
418
|
+
state.appListeners = undefined;
|
|
403
419
|
}
|
|
404
420
|
|
|
405
421
|
// ../../src/bootstrap/listeners/invalidateCacheOnModelWrite.ts
|
|
@@ -483,16 +499,81 @@ import {
|
|
|
483
499
|
FAILED_JOB_SERVICE_TOKEN
|
|
484
500
|
} from "@getstrata/core/queue/createAppQueue";
|
|
485
501
|
|
|
502
|
+
// ../../src/bootstrap/discoverJobs.ts
|
|
503
|
+
import { existsSync as existsSync2, readdirSync as readdirSync3 } from "fs";
|
|
504
|
+
import { createRequire as createRequire2 } from "module";
|
|
505
|
+
import { join as join3 } from "path";
|
|
506
|
+
import { jobRegistry } from "@getstrata/core/queue/jobRegistry";
|
|
507
|
+
var requireJob = createRequire2(import.meta.url);
|
|
508
|
+
var DISCOVER_JOBS_STATE_KEY = Symbol.for("@getstrata/discoverJobsState");
|
|
509
|
+
function readDiscoverJobsState() {
|
|
510
|
+
const existing = globalThis[DISCOVER_JOBS_STATE_KEY];
|
|
511
|
+
if (existing) {
|
|
512
|
+
return existing;
|
|
513
|
+
}
|
|
514
|
+
const state = {};
|
|
515
|
+
globalThis[DISCOVER_JOBS_STATE_KEY] = state;
|
|
516
|
+
return state;
|
|
517
|
+
}
|
|
518
|
+
function resolveJobsDirectory() {
|
|
519
|
+
const fromCwd = join3(process.cwd(), "src", "jobs");
|
|
520
|
+
if (existsSync2(fromCwd)) {
|
|
521
|
+
return fromCwd;
|
|
522
|
+
}
|
|
523
|
+
return join3(import.meta.dir, "../jobs");
|
|
524
|
+
}
|
|
525
|
+
function isDiscoveredJobClass(value) {
|
|
526
|
+
if (typeof value !== "function") {
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
const jobName = value.jobName;
|
|
530
|
+
return typeof jobName === "string" && jobName.length > 0;
|
|
531
|
+
}
|
|
532
|
+
function loadDiscoveredJobClasses() {
|
|
533
|
+
const jobsDirectory = resolveJobsDirectory();
|
|
534
|
+
let entries;
|
|
535
|
+
try {
|
|
536
|
+
entries = readdirSync3(jobsDirectory, { withFileTypes: true }).filter((entry) => entry.isFile() && /\.(ts|js)$/.test(entry.name)).map((entry) => entry.name);
|
|
537
|
+
} catch (error) {
|
|
538
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
539
|
+
return [];
|
|
540
|
+
}
|
|
541
|
+
throw error;
|
|
542
|
+
}
|
|
543
|
+
return entries.flatMap((fileName) => {
|
|
544
|
+
const filePath = join3(jobsDirectory, fileName);
|
|
545
|
+
const loaded = requireJob(filePath);
|
|
546
|
+
return isDiscoveredJobClass(loaded.default) ? [loaded.default] : [];
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
function discoverJobs() {
|
|
550
|
+
const state = readDiscoverJobsState();
|
|
551
|
+
if (state.names) {
|
|
552
|
+
return state.names;
|
|
553
|
+
}
|
|
554
|
+
const names = [];
|
|
555
|
+
for (const JobClass of loadDiscoveredJobClasses()) {
|
|
556
|
+
jobRegistry.register(JobClass.jobName, () => new JobClass);
|
|
557
|
+
names.push(JobClass.jobName);
|
|
558
|
+
}
|
|
559
|
+
state.names = names;
|
|
560
|
+
return names;
|
|
561
|
+
}
|
|
562
|
+
function resetDiscoverJobsForTests() {
|
|
563
|
+
const state = readDiscoverJobsState();
|
|
564
|
+
state.names = undefined;
|
|
565
|
+
}
|
|
566
|
+
|
|
486
567
|
// ../../src/bootstrap/queue/defaultJobs.ts
|
|
487
568
|
import { ExportAuditLogsJob } from "@getstrata/core/jobs/exportAuditLogsJob";
|
|
488
569
|
import { InvalidateCacheTagsJob as InvalidateCacheTagsJob2 } from "@getstrata/core/jobs/invalidateCacheTagsJob";
|
|
489
|
-
import { jobRegistry } from "@getstrata/core/queue/jobRegistry";
|
|
570
|
+
import { jobRegistry as jobRegistry2 } from "@getstrata/core/queue/jobRegistry";
|
|
490
571
|
import { resolveApplicationCache as resolveApplicationCache2 } from "@getstrata/core/runtime/applicationRegistry";
|
|
491
572
|
function registerDefaultJobs() {
|
|
492
|
-
|
|
573
|
+
jobRegistry2.register("cache.invalidate-tags", () => {
|
|
493
574
|
return new InvalidateCacheTagsJob2(resolveApplicationCache2());
|
|
494
575
|
});
|
|
495
|
-
|
|
576
|
+
jobRegistry2.register("audit.export", () => new ExportAuditLogsJob);
|
|
496
577
|
}
|
|
497
578
|
|
|
498
579
|
// ../../src/bootstrap/providers/queue.ts
|
|
@@ -504,7 +585,10 @@ var queueProvider = {
|
|
|
504
585
|
config.set("queue.driver", driver);
|
|
505
586
|
const failedJobs = createFailedJobService();
|
|
506
587
|
container.set(FAILED_JOB_SERVICE_TOKEN, failedJobs);
|
|
507
|
-
container.set(CORE_QUEUE_TOKEN, createAppQueue(driver, config.get(REDIS_URL_CONFIG_KEY) ?? process.env.REDIS_URL, failedJobs,
|
|
588
|
+
container.set(CORE_QUEUE_TOKEN, createAppQueue(driver, config.get(REDIS_URL_CONFIG_KEY) ?? process.env.REDIS_URL, failedJobs, () => {
|
|
589
|
+
registerDefaultJobs();
|
|
590
|
+
discoverJobs();
|
|
591
|
+
}));
|
|
508
592
|
}
|
|
509
593
|
};
|
|
510
594
|
var queue_default = queueProvider;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// ../../src/bootstrap/discoverJobs.ts
|
|
3
|
+
import { existsSync, readdirSync } from "fs";
|
|
4
|
+
import { createRequire } from "module";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
import { jobRegistry } from "@getstrata/core/queue/jobRegistry";
|
|
7
|
+
var requireJob = createRequire(import.meta.url);
|
|
8
|
+
var DISCOVER_JOBS_STATE_KEY = Symbol.for("@getstrata/discoverJobsState");
|
|
9
|
+
function readDiscoverJobsState() {
|
|
10
|
+
const existing = globalThis[DISCOVER_JOBS_STATE_KEY];
|
|
11
|
+
if (existing) {
|
|
12
|
+
return existing;
|
|
13
|
+
}
|
|
14
|
+
const state = {};
|
|
15
|
+
globalThis[DISCOVER_JOBS_STATE_KEY] = state;
|
|
16
|
+
return state;
|
|
17
|
+
}
|
|
18
|
+
function resolveJobsDirectory() {
|
|
19
|
+
const fromCwd = join(process.cwd(), "src", "jobs");
|
|
20
|
+
if (existsSync(fromCwd)) {
|
|
21
|
+
return fromCwd;
|
|
22
|
+
}
|
|
23
|
+
return join(import.meta.dir, "../jobs");
|
|
24
|
+
}
|
|
25
|
+
function isDiscoveredJobClass(value) {
|
|
26
|
+
if (typeof value !== "function") {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
const jobName = value.jobName;
|
|
30
|
+
return typeof jobName === "string" && jobName.length > 0;
|
|
31
|
+
}
|
|
32
|
+
function loadDiscoveredJobClasses() {
|
|
33
|
+
const jobsDirectory = resolveJobsDirectory();
|
|
34
|
+
let entries;
|
|
35
|
+
try {
|
|
36
|
+
entries = readdirSync(jobsDirectory, { withFileTypes: true }).filter((entry) => entry.isFile() && /\.(ts|js)$/.test(entry.name)).map((entry) => entry.name);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
return entries.flatMap((fileName) => {
|
|
44
|
+
const filePath = join(jobsDirectory, fileName);
|
|
45
|
+
const loaded = requireJob(filePath);
|
|
46
|
+
return isDiscoveredJobClass(loaded.default) ? [loaded.default] : [];
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function discoverJobs() {
|
|
50
|
+
const state = readDiscoverJobsState();
|
|
51
|
+
if (state.names) {
|
|
52
|
+
return state.names;
|
|
53
|
+
}
|
|
54
|
+
const names = [];
|
|
55
|
+
for (const JobClass of loadDiscoveredJobClasses()) {
|
|
56
|
+
jobRegistry.register(JobClass.jobName, () => new JobClass);
|
|
57
|
+
names.push(JobClass.jobName);
|
|
58
|
+
}
|
|
59
|
+
state.names = names;
|
|
60
|
+
return names;
|
|
61
|
+
}
|
|
62
|
+
function resetDiscoverJobsForTests() {
|
|
63
|
+
const state = readDiscoverJobsState();
|
|
64
|
+
state.names = undefined;
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
discoverJobs,
|
|
68
|
+
resetDiscoverJobsForTests
|
|
69
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// ../../src/bootstrap/discoverListeners.ts
|
|
3
|
+
import { existsSync, readdirSync } from "fs";
|
|
4
|
+
import { createRequire } from "module";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
var requireListener = createRequire(import.meta.url);
|
|
7
|
+
var DISCOVER_LISTENERS_STATE_KEY = Symbol.for("@getstrata/discoverListenersState");
|
|
8
|
+
function readDiscoverListenersState() {
|
|
9
|
+
const existing = globalThis[DISCOVER_LISTENERS_STATE_KEY];
|
|
10
|
+
if (existing) {
|
|
11
|
+
return existing;
|
|
12
|
+
}
|
|
13
|
+
const state = {};
|
|
14
|
+
globalThis[DISCOVER_LISTENERS_STATE_KEY] = state;
|
|
15
|
+
return state;
|
|
16
|
+
}
|
|
17
|
+
function resolveListenersDirectory() {
|
|
18
|
+
const fromCwd = join(process.cwd(), "src", "listeners");
|
|
19
|
+
if (existsSync(fromCwd)) {
|
|
20
|
+
return fromCwd;
|
|
21
|
+
}
|
|
22
|
+
return join(import.meta.dir, "../listeners");
|
|
23
|
+
}
|
|
24
|
+
function loadDiscoveredListeners() {
|
|
25
|
+
const listenersDirectory = resolveListenersDirectory();
|
|
26
|
+
let entries;
|
|
27
|
+
try {
|
|
28
|
+
entries = readdirSync(listenersDirectory, { withFileTypes: true }).filter((entry) => entry.isFile() && /\.(ts|js)$/.test(entry.name)).map((entry) => entry.name);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
const listeners = entries.map((fileName) => {
|
|
36
|
+
const filePath = join(listenersDirectory, fileName);
|
|
37
|
+
const loaded = requireListener(filePath);
|
|
38
|
+
return loaded.default;
|
|
39
|
+
});
|
|
40
|
+
return listeners.filter((listener) => typeof listener === "function");
|
|
41
|
+
}
|
|
42
|
+
function discoverListeners() {
|
|
43
|
+
const state = readDiscoverListenersState();
|
|
44
|
+
state.appListeners ??= loadDiscoveredListeners();
|
|
45
|
+
return state.appListeners;
|
|
46
|
+
}
|
|
47
|
+
function resetDiscoverListenersForTests() {
|
|
48
|
+
const state = readDiscoverListenersState();
|
|
49
|
+
state.appListeners = undefined;
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
discoverListeners,
|
|
53
|
+
resetDiscoverListenersForTests
|
|
54
|
+
};
|
|
@@ -276,8 +276,19 @@ var events_default = eventsProvider;
|
|
|
276
276
|
|
|
277
277
|
// ../../src/bootstrap/discoverListeners.ts
|
|
278
278
|
import { existsSync, readdirSync } from "fs";
|
|
279
|
+
import { createRequire } from "module";
|
|
279
280
|
import { join } from "path";
|
|
280
|
-
|
|
281
|
+
var requireListener = createRequire(import.meta.url);
|
|
282
|
+
var DISCOVER_LISTENERS_STATE_KEY = Symbol.for("@getstrata/discoverListenersState");
|
|
283
|
+
function readDiscoverListenersState() {
|
|
284
|
+
const existing = globalThis[DISCOVER_LISTENERS_STATE_KEY];
|
|
285
|
+
if (existing) {
|
|
286
|
+
return existing;
|
|
287
|
+
}
|
|
288
|
+
const state = {};
|
|
289
|
+
globalThis[DISCOVER_LISTENERS_STATE_KEY] = state;
|
|
290
|
+
return state;
|
|
291
|
+
}
|
|
281
292
|
function resolveListenersDirectory() {
|
|
282
293
|
const fromCwd = join(process.cwd(), "src", "listeners");
|
|
283
294
|
if (existsSync(fromCwd)) {
|
|
@@ -285,7 +296,7 @@ function resolveListenersDirectory() {
|
|
|
285
296
|
}
|
|
286
297
|
return join(import.meta.dir, "../listeners");
|
|
287
298
|
}
|
|
288
|
-
|
|
299
|
+
function loadDiscoveredListeners() {
|
|
289
300
|
const listenersDirectory = resolveListenersDirectory();
|
|
290
301
|
let entries;
|
|
291
302
|
try {
|
|
@@ -296,16 +307,21 @@ async function loadDiscoveredListeners() {
|
|
|
296
307
|
}
|
|
297
308
|
throw error;
|
|
298
309
|
}
|
|
299
|
-
const listeners =
|
|
300
|
-
const
|
|
301
|
-
const loaded =
|
|
310
|
+
const listeners = entries.map((fileName) => {
|
|
311
|
+
const filePath = join(listenersDirectory, fileName);
|
|
312
|
+
const loaded = requireListener(filePath);
|
|
302
313
|
return loaded.default;
|
|
303
|
-
})
|
|
314
|
+
});
|
|
304
315
|
return listeners.filter((listener) => typeof listener === "function");
|
|
305
316
|
}
|
|
306
|
-
var appListeners = await loadDiscoveredListeners();
|
|
307
317
|
function discoverListeners() {
|
|
308
|
-
|
|
318
|
+
const state = readDiscoverListenersState();
|
|
319
|
+
state.appListeners ??= loadDiscoveredListeners();
|
|
320
|
+
return state.appListeners;
|
|
321
|
+
}
|
|
322
|
+
function resetDiscoverListenersForTests() {
|
|
323
|
+
const state = readDiscoverListenersState();
|
|
324
|
+
state.appListeners = undefined;
|
|
309
325
|
}
|
|
310
326
|
|
|
311
327
|
// ../../src/bootstrap/listeners/invalidateCacheOnModelWrite.ts
|
|
@@ -329,7 +345,7 @@ import {
|
|
|
329
345
|
// ../../src/bootstrap/discoverModules.ts
|
|
330
346
|
import { readdirSync as readdirSync2 } from "fs";
|
|
331
347
|
import { join as join2 } from "path";
|
|
332
|
-
import { pathToFileURL
|
|
348
|
+
import { pathToFileURL } from "url";
|
|
333
349
|
var DISCOVER_MODULES_STATE_KEY = Symbol.for("@getstrata/discoverModulesState");
|
|
334
350
|
function readDiscoverModulesState() {
|
|
335
351
|
const existing = globalThis[DISCOVER_MODULES_STATE_KEY];
|
|
@@ -370,7 +386,7 @@ async function loadDiscoveredModules(options) {
|
|
|
370
386
|
throw error;
|
|
371
387
|
}
|
|
372
388
|
const modules = await Promise.all(moduleNames.map(async (moduleName) => {
|
|
373
|
-
const moduleUrl =
|
|
389
|
+
const moduleUrl = pathToFileURL(join2(modulesDirectory, moduleName, "index.ts")).href;
|
|
374
390
|
const loaded = await import(moduleUrl);
|
|
375
391
|
return loaded.default;
|
|
376
392
|
}));
|
|
@@ -473,16 +489,81 @@ import {
|
|
|
473
489
|
FAILED_JOB_SERVICE_TOKEN
|
|
474
490
|
} from "@getstrata/core/queue/createAppQueue";
|
|
475
491
|
|
|
492
|
+
// ../../src/bootstrap/discoverJobs.ts
|
|
493
|
+
import { existsSync as existsSync2, readdirSync as readdirSync3 } from "fs";
|
|
494
|
+
import { createRequire as createRequire2 } from "module";
|
|
495
|
+
import { join as join3 } from "path";
|
|
496
|
+
import { jobRegistry } from "@getstrata/core/queue/jobRegistry";
|
|
497
|
+
var requireJob = createRequire2(import.meta.url);
|
|
498
|
+
var DISCOVER_JOBS_STATE_KEY = Symbol.for("@getstrata/discoverJobsState");
|
|
499
|
+
function readDiscoverJobsState() {
|
|
500
|
+
const existing = globalThis[DISCOVER_JOBS_STATE_KEY];
|
|
501
|
+
if (existing) {
|
|
502
|
+
return existing;
|
|
503
|
+
}
|
|
504
|
+
const state = {};
|
|
505
|
+
globalThis[DISCOVER_JOBS_STATE_KEY] = state;
|
|
506
|
+
return state;
|
|
507
|
+
}
|
|
508
|
+
function resolveJobsDirectory() {
|
|
509
|
+
const fromCwd = join3(process.cwd(), "src", "jobs");
|
|
510
|
+
if (existsSync2(fromCwd)) {
|
|
511
|
+
return fromCwd;
|
|
512
|
+
}
|
|
513
|
+
return join3(import.meta.dir, "../jobs");
|
|
514
|
+
}
|
|
515
|
+
function isDiscoveredJobClass(value) {
|
|
516
|
+
if (typeof value !== "function") {
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
const jobName = value.jobName;
|
|
520
|
+
return typeof jobName === "string" && jobName.length > 0;
|
|
521
|
+
}
|
|
522
|
+
function loadDiscoveredJobClasses() {
|
|
523
|
+
const jobsDirectory = resolveJobsDirectory();
|
|
524
|
+
let entries;
|
|
525
|
+
try {
|
|
526
|
+
entries = readdirSync3(jobsDirectory, { withFileTypes: true }).filter((entry) => entry.isFile() && /\.(ts|js)$/.test(entry.name)).map((entry) => entry.name);
|
|
527
|
+
} catch (error) {
|
|
528
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
529
|
+
return [];
|
|
530
|
+
}
|
|
531
|
+
throw error;
|
|
532
|
+
}
|
|
533
|
+
return entries.flatMap((fileName) => {
|
|
534
|
+
const filePath = join3(jobsDirectory, fileName);
|
|
535
|
+
const loaded = requireJob(filePath);
|
|
536
|
+
return isDiscoveredJobClass(loaded.default) ? [loaded.default] : [];
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
function discoverJobs() {
|
|
540
|
+
const state = readDiscoverJobsState();
|
|
541
|
+
if (state.names) {
|
|
542
|
+
return state.names;
|
|
543
|
+
}
|
|
544
|
+
const names = [];
|
|
545
|
+
for (const JobClass of loadDiscoveredJobClasses()) {
|
|
546
|
+
jobRegistry.register(JobClass.jobName, () => new JobClass);
|
|
547
|
+
names.push(JobClass.jobName);
|
|
548
|
+
}
|
|
549
|
+
state.names = names;
|
|
550
|
+
return names;
|
|
551
|
+
}
|
|
552
|
+
function resetDiscoverJobsForTests() {
|
|
553
|
+
const state = readDiscoverJobsState();
|
|
554
|
+
state.names = undefined;
|
|
555
|
+
}
|
|
556
|
+
|
|
476
557
|
// ../../src/bootstrap/queue/defaultJobs.ts
|
|
477
558
|
import { ExportAuditLogsJob } from "@getstrata/core/jobs/exportAuditLogsJob";
|
|
478
559
|
import { InvalidateCacheTagsJob as InvalidateCacheTagsJob2 } from "@getstrata/core/jobs/invalidateCacheTagsJob";
|
|
479
|
-
import { jobRegistry } from "@getstrata/core/queue/jobRegistry";
|
|
560
|
+
import { jobRegistry as jobRegistry2 } from "@getstrata/core/queue/jobRegistry";
|
|
480
561
|
import { resolveApplicationCache as resolveApplicationCache2 } from "@getstrata/core/runtime/applicationRegistry";
|
|
481
562
|
function registerDefaultJobs() {
|
|
482
|
-
|
|
563
|
+
jobRegistry2.register("cache.invalidate-tags", () => {
|
|
483
564
|
return new InvalidateCacheTagsJob2(resolveApplicationCache2());
|
|
484
565
|
});
|
|
485
|
-
|
|
566
|
+
jobRegistry2.register("audit.export", () => new ExportAuditLogsJob);
|
|
486
567
|
}
|
|
487
568
|
|
|
488
569
|
// ../../src/bootstrap/providers/queue.ts
|
|
@@ -494,7 +575,10 @@ var queueProvider = {
|
|
|
494
575
|
config.set("queue.driver", driver);
|
|
495
576
|
const failedJobs = createFailedJobService();
|
|
496
577
|
container.set(FAILED_JOB_SERVICE_TOKEN, failedJobs);
|
|
497
|
-
container.set(CORE_QUEUE_TOKEN, createAppQueue(driver, config.get(REDIS_URL_CONFIG_KEY) ?? process.env.REDIS_URL, failedJobs,
|
|
578
|
+
container.set(CORE_QUEUE_TOKEN, createAppQueue(driver, config.get(REDIS_URL_CONFIG_KEY) ?? process.env.REDIS_URL, failedJobs, () => {
|
|
579
|
+
registerDefaultJobs();
|
|
580
|
+
discoverJobs();
|
|
581
|
+
}));
|
|
498
582
|
}
|
|
499
583
|
};
|
|
500
584
|
var queue_default = queueProvider;
|
package/dist/index.js
CHANGED
|
@@ -773,8 +773,19 @@ var events_default = eventsProvider;
|
|
|
773
773
|
|
|
774
774
|
// ../../src/bootstrap/discoverListeners.ts
|
|
775
775
|
import { existsSync, readdirSync as readdirSync2 } from "fs";
|
|
776
|
+
import { createRequire } from "module";
|
|
776
777
|
import { join as join2 } from "path";
|
|
777
|
-
|
|
778
|
+
var requireListener = createRequire(import.meta.url);
|
|
779
|
+
var DISCOVER_LISTENERS_STATE_KEY = Symbol.for("@getstrata/discoverListenersState");
|
|
780
|
+
function readDiscoverListenersState() {
|
|
781
|
+
const existing = globalThis[DISCOVER_LISTENERS_STATE_KEY];
|
|
782
|
+
if (existing) {
|
|
783
|
+
return existing;
|
|
784
|
+
}
|
|
785
|
+
const state = {};
|
|
786
|
+
globalThis[DISCOVER_LISTENERS_STATE_KEY] = state;
|
|
787
|
+
return state;
|
|
788
|
+
}
|
|
778
789
|
function resolveListenersDirectory() {
|
|
779
790
|
const fromCwd = join2(process.cwd(), "src", "listeners");
|
|
780
791
|
if (existsSync(fromCwd)) {
|
|
@@ -782,7 +793,7 @@ function resolveListenersDirectory() {
|
|
|
782
793
|
}
|
|
783
794
|
return join2(import.meta.dir, "../listeners");
|
|
784
795
|
}
|
|
785
|
-
|
|
796
|
+
function loadDiscoveredListeners() {
|
|
786
797
|
const listenersDirectory = resolveListenersDirectory();
|
|
787
798
|
let entries;
|
|
788
799
|
try {
|
|
@@ -793,16 +804,17 @@ async function loadDiscoveredListeners() {
|
|
|
793
804
|
}
|
|
794
805
|
throw error;
|
|
795
806
|
}
|
|
796
|
-
const listeners =
|
|
797
|
-
const
|
|
798
|
-
const loaded =
|
|
807
|
+
const listeners = entries.map((fileName) => {
|
|
808
|
+
const filePath = join2(listenersDirectory, fileName);
|
|
809
|
+
const loaded = requireListener(filePath);
|
|
799
810
|
return loaded.default;
|
|
800
|
-
})
|
|
811
|
+
});
|
|
801
812
|
return listeners.filter((listener) => typeof listener === "function");
|
|
802
813
|
}
|
|
803
|
-
var appListeners = await loadDiscoveredListeners();
|
|
804
814
|
function discoverListeners() {
|
|
805
|
-
|
|
815
|
+
const state = readDiscoverListenersState();
|
|
816
|
+
state.appListeners ??= loadDiscoveredListeners();
|
|
817
|
+
return state.appListeners;
|
|
806
818
|
}
|
|
807
819
|
|
|
808
820
|
// ../../src/bootstrap/listeners/invalidateCacheOnModelWrite.ts
|
|
@@ -872,16 +884,81 @@ import {
|
|
|
872
884
|
FAILED_JOB_SERVICE_TOKEN
|
|
873
885
|
} from "@getstrata/core/queue/createAppQueue";
|
|
874
886
|
|
|
887
|
+
// ../../src/bootstrap/discoverJobs.ts
|
|
888
|
+
import { existsSync as existsSync2, readdirSync as readdirSync3 } from "fs";
|
|
889
|
+
import { createRequire as createRequire2 } from "module";
|
|
890
|
+
import { join as join3 } from "path";
|
|
891
|
+
import { jobRegistry } from "@getstrata/core/queue/jobRegistry";
|
|
892
|
+
var requireJob = createRequire2(import.meta.url);
|
|
893
|
+
var DISCOVER_JOBS_STATE_KEY = Symbol.for("@getstrata/discoverJobsState");
|
|
894
|
+
function readDiscoverJobsState() {
|
|
895
|
+
const existing = globalThis[DISCOVER_JOBS_STATE_KEY];
|
|
896
|
+
if (existing) {
|
|
897
|
+
return existing;
|
|
898
|
+
}
|
|
899
|
+
const state = {};
|
|
900
|
+
globalThis[DISCOVER_JOBS_STATE_KEY] = state;
|
|
901
|
+
return state;
|
|
902
|
+
}
|
|
903
|
+
function resolveJobsDirectory() {
|
|
904
|
+
const fromCwd = join3(process.cwd(), "src", "jobs");
|
|
905
|
+
if (existsSync2(fromCwd)) {
|
|
906
|
+
return fromCwd;
|
|
907
|
+
}
|
|
908
|
+
return join3(import.meta.dir, "../jobs");
|
|
909
|
+
}
|
|
910
|
+
function isDiscoveredJobClass(value) {
|
|
911
|
+
if (typeof value !== "function") {
|
|
912
|
+
return false;
|
|
913
|
+
}
|
|
914
|
+
const jobName = value.jobName;
|
|
915
|
+
return typeof jobName === "string" && jobName.length > 0;
|
|
916
|
+
}
|
|
917
|
+
function loadDiscoveredJobClasses() {
|
|
918
|
+
const jobsDirectory = resolveJobsDirectory();
|
|
919
|
+
let entries;
|
|
920
|
+
try {
|
|
921
|
+
entries = readdirSync3(jobsDirectory, { withFileTypes: true }).filter((entry) => entry.isFile() && /\.(ts|js)$/.test(entry.name)).map((entry) => entry.name);
|
|
922
|
+
} catch (error) {
|
|
923
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
924
|
+
return [];
|
|
925
|
+
}
|
|
926
|
+
throw error;
|
|
927
|
+
}
|
|
928
|
+
return entries.flatMap((fileName) => {
|
|
929
|
+
const filePath = join3(jobsDirectory, fileName);
|
|
930
|
+
const loaded = requireJob(filePath);
|
|
931
|
+
return isDiscoveredJobClass(loaded.default) ? [loaded.default] : [];
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
function discoverJobs() {
|
|
935
|
+
const state = readDiscoverJobsState();
|
|
936
|
+
if (state.names) {
|
|
937
|
+
return state.names;
|
|
938
|
+
}
|
|
939
|
+
const names = [];
|
|
940
|
+
for (const JobClass of loadDiscoveredJobClasses()) {
|
|
941
|
+
jobRegistry.register(JobClass.jobName, () => new JobClass);
|
|
942
|
+
names.push(JobClass.jobName);
|
|
943
|
+
}
|
|
944
|
+
state.names = names;
|
|
945
|
+
return names;
|
|
946
|
+
}
|
|
947
|
+
function resetDiscoverJobsForTests() {
|
|
948
|
+
const state = readDiscoverJobsState();
|
|
949
|
+
state.names = undefined;
|
|
950
|
+
}
|
|
951
|
+
|
|
875
952
|
// ../../src/bootstrap/queue/defaultJobs.ts
|
|
876
953
|
import { ExportAuditLogsJob } from "@getstrata/core/jobs/exportAuditLogsJob";
|
|
877
954
|
import { InvalidateCacheTagsJob as InvalidateCacheTagsJob2 } from "@getstrata/core/jobs/invalidateCacheTagsJob";
|
|
878
|
-
import { jobRegistry } from "@getstrata/core/queue/jobRegistry";
|
|
955
|
+
import { jobRegistry as jobRegistry2 } from "@getstrata/core/queue/jobRegistry";
|
|
879
956
|
import { resolveApplicationCache as resolveApplicationCache2 } from "@getstrata/core/runtime/applicationRegistry";
|
|
880
957
|
function registerDefaultJobs() {
|
|
881
|
-
|
|
958
|
+
jobRegistry2.register("cache.invalidate-tags", () => {
|
|
882
959
|
return new InvalidateCacheTagsJob2(resolveApplicationCache2());
|
|
883
960
|
});
|
|
884
|
-
|
|
961
|
+
jobRegistry2.register("audit.export", () => new ExportAuditLogsJob);
|
|
885
962
|
}
|
|
886
963
|
|
|
887
964
|
// ../../src/bootstrap/providers/queue.ts
|
|
@@ -893,7 +970,10 @@ var queueProvider = {
|
|
|
893
970
|
config.set("queue.driver", driver);
|
|
894
971
|
const failedJobs = createFailedJobService();
|
|
895
972
|
container.set(FAILED_JOB_SERVICE_TOKEN, failedJobs);
|
|
896
|
-
container.set(CORE_QUEUE_TOKEN, createAppQueue(driver, config.get(REDIS_URL_CONFIG_KEY) ?? process.env.REDIS_URL, failedJobs,
|
|
973
|
+
container.set(CORE_QUEUE_TOKEN, createAppQueue(driver, config.get(REDIS_URL_CONFIG_KEY) ?? process.env.REDIS_URL, failedJobs, () => {
|
|
974
|
+
registerDefaultJobs();
|
|
975
|
+
discoverJobs();
|
|
976
|
+
}));
|
|
897
977
|
}
|
|
898
978
|
};
|
|
899
979
|
var queue_default = queueProvider;
|
|
@@ -995,7 +1075,7 @@ function createAppContext() {
|
|
|
995
1075
|
return appContext;
|
|
996
1076
|
}
|
|
997
1077
|
// ../../src/bootstrap/createWebRoutes.ts
|
|
998
|
-
import { join as
|
|
1078
|
+
import { join as join4 } from "path";
|
|
999
1079
|
import { isViewsEnabled as isViewsEnabled3 } from "@getstrata/core/runtime/frontendMode";
|
|
1000
1080
|
import { assertUrlPathUnderRoot } from "@getstrata/core/security/safePath";
|
|
1001
1081
|
import { notFoundHtmlResponse } from "@getstrata/core/view";
|
|
@@ -1012,7 +1092,7 @@ function createWebRoutes(dependencies, options = {}) {
|
|
|
1012
1092
|
registerRoute("GET", "/assets/*", ["global", "web"]);
|
|
1013
1093
|
const pathname = new URL(request.url).pathname;
|
|
1014
1094
|
try {
|
|
1015
|
-
const filePath = assertUrlPathUnderRoot(
|
|
1095
|
+
const filePath = assertUrlPathUnderRoot(join4(process.cwd(), "public"), pathname);
|
|
1016
1096
|
const file = Bun.file(filePath);
|
|
1017
1097
|
if (!await file.exists()) {
|
|
1018
1098
|
return notFoundHtmlResponse();
|
|
@@ -1799,6 +1879,7 @@ export {
|
|
|
1799
1879
|
createRouteKernel,
|
|
1800
1880
|
createWebRoutes,
|
|
1801
1881
|
createWebServer,
|
|
1882
|
+
discoverJobs,
|
|
1802
1883
|
discoverModelTableNames,
|
|
1803
1884
|
discoverModules,
|
|
1804
1885
|
ensureModulesLoaded,
|
|
@@ -1808,6 +1889,7 @@ export {
|
|
|
1808
1889
|
pingDatabase,
|
|
1809
1890
|
prefixRouteMap,
|
|
1810
1891
|
registerDefaultJobs,
|
|
1892
|
+
resetDiscoverJobsForTests,
|
|
1811
1893
|
resolveApplicationAuth,
|
|
1812
1894
|
resolveApplicationCache,
|
|
1813
1895
|
resolveApplicationConfig,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getstrata/bootstrap",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Strata application bootstrap: HttpKernel, DI, web session helpers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -70,6 +70,16 @@
|
|
|
70
70
|
"import": "./dist/entries/discoverModules.js",
|
|
71
71
|
"default": "./dist/entries/discoverModules.js"
|
|
72
72
|
},
|
|
73
|
+
"./discoverListeners": {
|
|
74
|
+
"types": "./dist/bootstrap/discoverListeners.d.ts",
|
|
75
|
+
"import": "./dist/entries/discoverListeners.js",
|
|
76
|
+
"default": "./dist/entries/discoverListeners.js"
|
|
77
|
+
},
|
|
78
|
+
"./discoverJobs": {
|
|
79
|
+
"types": "./dist/bootstrap/discoverJobs.d.ts",
|
|
80
|
+
"import": "./dist/entries/discoverJobs.js",
|
|
81
|
+
"default": "./dist/entries/discoverJobs.js"
|
|
82
|
+
},
|
|
73
83
|
"./health": {
|
|
74
84
|
"types": "./dist/bootstrap/health.d.ts",
|
|
75
85
|
"import": "./dist/entries/health.js",
|
|
@@ -168,14 +178,14 @@
|
|
|
168
178
|
"build:bundle": "bun build index.ts --outdir dist --target bun --external bun --external eta --external mysql2 --external @getstrata/core",
|
|
169
179
|
"build:types": "tsc -p tsconfig.types.json && bun ../../scripts/prune-bootstrap-dist-types.ts",
|
|
170
180
|
"prepublishOnly": "bun run build",
|
|
171
|
-
"build:subpaths": "bun build entries/applicationRegistry.ts entries/buildModuleRoutes.ts entries/buildWebModuleRoutes.ts entries/cache/modelCacheTags.ts entries/config.ts entries/context.ts entries/contracts.ts entries/createWebRoutes.ts entries/createSpaRoutes.ts entries/dependencies.ts entries/discoverModules.ts entries/health.ts entries/http/securedRouteModelBinding.ts entries/httpKernel.ts entries/listeners/invalidateCacheOnModelWrite.ts entries/membershipService.ts entries/metricsRoutes.ts entries/queue/defaultJobs.ts entries/providers.ts entries/providers/view.ts entries/routeRegistry.ts entries/schedule.ts entries/secretsGuard.ts entries/web/forms.ts entries/web/routing.ts entries/web/server.ts entries/web/session.ts entries/web/slug.ts --outdir dist --root . --target bun --external bun --external eta --external mysql2 --external @getstrata/core --external @getstrata/bootstrap --external @getstrata/bootstrap/applicationRegistry --external @getstrata/bootstrap/buildModuleRoutes --external @getstrata/bootstrap/buildWebModuleRoutes --external @getstrata/bootstrap/cache/modelCacheTags --external @getstrata/bootstrap/config --external @getstrata/bootstrap/context --external @getstrata/bootstrap/contracts --external @getstrata/bootstrap/createWebRoutes --external @getstrata/bootstrap/createSpaRoutes --external @getstrata/bootstrap/dependencies --external @getstrata/bootstrap/discoverModules --external @getstrata/bootstrap/health --external @getstrata/bootstrap/http/securedRouteModelBinding --external @getstrata/bootstrap/httpKernel --external @getstrata/bootstrap/listeners/invalidateCacheOnModelWrite --external @getstrata/bootstrap/membershipService --external @getstrata/bootstrap/metricsRoutes --external @getstrata/bootstrap/queue/defaultJobs --external @getstrata/bootstrap/providers --external @getstrata/bootstrap/providers/view --external @getstrata/bootstrap/routeRegistry --external @getstrata/bootstrap/schedule --external @getstrata/bootstrap/secretsGuard --external @getstrata/bootstrap/web/forms --external @getstrata/bootstrap/web/routing --external @getstrata/bootstrap/web/server --external @getstrata/bootstrap/web/session --external @getstrata/bootstrap/web/slug --external @getstrata/core/auth/accessControl --external @getstrata/core/auth/abilityChecker --external @getstrata/core/auth/authContext --external @getstrata/core/auth/emailVerification --external @getstrata/core/auth/guard --external @getstrata/core/auth/jwt --external @getstrata/core/auth/jwtGuard --external @getstrata/core/auth/basicAuthGuard --external @getstrata/core/auth/tokenAbilityChecker --external @getstrata/core/auth/membershipContext --external @getstrata/core/auth/membershipMiddleware --external @getstrata/core/auth/membershipScope --external @getstrata/core/auth/membershipService --external @getstrata/core/auth/oauth/oidcProvider --external @getstrata/core/auth/oauth/providers --external @getstrata/core/auth/oauth/samlProvider --external @getstrata/core/auth/oauth/types --external @getstrata/core/auth/saml/samlServiceProvider --external @getstrata/core/auth/password --external @getstrata/core/auth/passwordLogin --external @getstrata/core/auth/oneTimeToken --external @getstrata/core/auth/intendedUrlCookie --external @getstrata/core/auth/passwordConfirmCookie --external @getstrata/core/auth/policy --external @getstrata/core/auth/scimAuthMiddleware --external @getstrata/core/auth/sessionCookie --external @getstrata/core/auth/sessionGuard --external @getstrata/core/auth/tokenHash --external @getstrata/core/audit/exportAuditLogs --external @getstrata/core/audit/siemFormatter --external @getstrata/core/admin/formatValue --external @getstrata/core/admin/registry --external @getstrata/core/admin/types --external @getstrata/core/cache/tags --external @getstrata/core/cache/createCacheStore --external @getstrata/core/cache/repository --external @getstrata/core/cache/simpleCache --external @getstrata/core/cache/simpleCacheStore --external @getstrata/core/config/envSchema --external @getstrata/core/contracts/serviceTokens --external @getstrata/core/contracts/authUserDirectory --external @getstrata/core/contracts/container --external @getstrata/core/contracts/di --external @getstrata/core/crypto/fieldEncryption --external @getstrata/core/crypto/mfaSecret --external @getstrata/core/database --external @getstrata/core/database/baseRepository --external @getstrata/core/database/bindConnection --external @getstrata/core/database/boundConnection --external @getstrata/core/database/bunSql --external @getstrata/core/database/connection --external @getstrata/core/database/connectionContext --external @getstrata/core/database/defaultConnection --external @getstrata/core/database/dialect --external @getstrata/core/database/mysqlConnection --external @getstrata/core/database/namedConnections --external @getstrata/core/database/errors --external @getstrata/core/database/factory --external @getstrata/core/database/migrations --external @getstrata/core/database/migrations/types --external @getstrata/core/database/model --external @getstrata/core/database/query --external @getstrata/core/database/relationships --external @getstrata/core/database/repositoryConnection --external @getstrata/core/database/repositoryQuery --external @getstrata/core/database/seeders --external @getstrata/core/database/seeders/types --external @getstrata/core/database/schema --external @getstrata/core/database/sqliteConnection --external @getstrata/core/database/table --external @getstrata/core/database/transaction --external @getstrata/core/database/types --external @getstrata/core/database/whereBuilder --external @getstrata/core/errors/http --external @getstrata/core/events --external @getstrata/core/facades --external @getstrata/core/http --external @getstrata/core/http/authMiddleware --external @getstrata/core/http/authorizeMiddleware --external @getstrata/core/http/bodySizeLimitMiddleware --external @getstrata/core/http/clientIp --external @getstrata/core/http/cookies --external @getstrata/core/http/contentNegotiation --external @getstrata/core/http/contentSecurityPolicy --external @getstrata/core/http/conditionalResponse --external @getstrata/core/http/corsMiddleware --external @getstrata/core/http/csrfMiddleware --external @getstrata/core/http/csrfProtection --external @getstrata/core/http/csrfToken --external @getstrata/core/http/etag --external @getstrata/core/http/flashSession --external @getstrata/core/http/flashMiddleware --external @getstrata/core/http/formRequest --external @getstrata/core/http/middleware --external @getstrata/core/http/metricsMiddleware --external @getstrata/core/http/loginThrottleMiddleware --external @getstrata/core/http/memoryThrottleMiddleware --external @getstrata/core/http/pagination --external @getstrata/core/http/parseFormBody --external @getstrata/core/http/parseMultipartUpload --external @getstrata/core/http/requireAbilityMiddleware --external @getstrata/core/http/requireAuthMiddleware --external @getstrata/core/http/requireGlobalAdminMiddleware --external @getstrata/core/http/requireWebAuthMiddleware --external @getstrata/core/http/requireVerifiedMiddleware --external @getstrata/core/http/requirePasswordConfirmMiddleware --external @getstrata/core/http/resources --external @getstrata/core/http/response --external @getstrata/core/http/route --external @getstrata/core/http/routeMiddleware --external @getstrata/core/http/routeModelBinding --external @getstrata/core/http/safeInternalPath --external @getstrata/core/http/signedUrl --external @getstrata/core/http/statelessAuth --external @getstrata/core/http/scimThrottleMiddleware --external @getstrata/core/http/securityHeadersMiddleware --external @getstrata/core/http/securedRouteModelBinding --external @getstrata/core/http/requestMetaContext --external @getstrata/core/http/webErrorResponse --external @getstrata/core/http/webFormRequest --external @getstrata/core/http/throttleMiddleware --external @getstrata/core/http/validation --external @getstrata/core/jobs/exportAuditLogsJob --external @getstrata/core/jobs/invalidateCacheTagsJob --external @getstrata/core/lifecycle/gracefulShutdown --external @getstrata/core/logging/logger --external @getstrata/core/logging/requestLoggingMiddleware --external @getstrata/core/mail/mailer --external @getstrata/core/mail/markdownMail --external @getstrata/core/mail/markdownMailable --external @getstrata/core/mail/sanitizeMailHtml --external @getstrata/core/media/imageTransform --external @getstrata/core/metrics/prometheus --external @getstrata/core/notifications --external @getstrata/core/openapi/generator --external @getstrata/core/openapi/registeredRoute --external @getstrata/core/openapi/validate --external @getstrata/core/pagination --external @getstrata/core/queue --external @getstrata/core/queue/createAppQueue --external @getstrata/core/queue/failedJobRepository --external @getstrata/core/queue/failedJobService --external @getstrata/core/queue/jobRegistry --external @getstrata/core/queue/jobRunner --external @getstrata/core/queue/queueMetrics --external @getstrata/core/queue/publicQueue --external @getstrata/core/queue/redisQueue --external @getstrata/core/queue/types --external @getstrata/core/runtime/appEnv --external @getstrata/core/runtime/appKeyPrefix --external @getstrata/core/runtime/frontendMode --external @getstrata/core/runtime/applicationRegistry --external @getstrata/core/runtime/asyncContextStore --external @getstrata/core/scheduler/schedule --external @getstrata/core/scheduler/osCron --external @getstrata/core/security/oauthState --external @getstrata/core/security/publicReads --external @getstrata/core/security/recoveryCodes --external @getstrata/core/security/safeFetch --external @getstrata/core/security/safePath --external @getstrata/core/security/safeUrl --external @getstrata/core/security/scimTenantTokens --external @getstrata/core/security/securityEvents --external @getstrata/core/security/stripeWebhook --external @getstrata/core/security/timingSafeCompare --external @getstrata/core/security/tokenExpiry --external @getstrata/core/security/totp --external @getstrata/core/storage/storage --external @getstrata/core/tenant/tenancyConfig --external @getstrata/core/tenant/tenantContext --external @getstrata/core/tenant/tenantDatabaseScope --external @getstrata/core/tenant/databaseTenantContext --external @getstrata/core/tenant/tenantMiddleware --external @getstrata/core/tenant/enableTenantRls --external @getstrata/core/terminal/runShell --external @getstrata/core/tracing/traceContext --external @getstrata/core/tracing/tracingMiddleware --external @getstrata/core/validation/rules --external @getstrata/core/view",
|
|
181
|
+
"build:subpaths": "bun build entries/applicationRegistry.ts entries/buildModuleRoutes.ts entries/buildWebModuleRoutes.ts entries/cache/modelCacheTags.ts entries/config.ts entries/context.ts entries/contracts.ts entries/createWebRoutes.ts entries/createSpaRoutes.ts entries/dependencies.ts entries/discoverModules.ts entries/discoverListeners.ts entries/discoverJobs.ts entries/health.ts entries/http/securedRouteModelBinding.ts entries/httpKernel.ts entries/listeners/invalidateCacheOnModelWrite.ts entries/membershipService.ts entries/metricsRoutes.ts entries/queue/defaultJobs.ts entries/providers.ts entries/providers/view.ts entries/routeRegistry.ts entries/schedule.ts entries/secretsGuard.ts entries/web/forms.ts entries/web/routing.ts entries/web/server.ts entries/web/session.ts entries/web/slug.ts --outdir dist --root . --target bun --external bun --external eta --external mysql2 --external @getstrata/core --external @getstrata/bootstrap --external @getstrata/bootstrap/applicationRegistry --external @getstrata/bootstrap/buildModuleRoutes --external @getstrata/bootstrap/buildWebModuleRoutes --external @getstrata/bootstrap/cache/modelCacheTags --external @getstrata/bootstrap/config --external @getstrata/bootstrap/context --external @getstrata/bootstrap/contracts --external @getstrata/bootstrap/createWebRoutes --external @getstrata/bootstrap/createSpaRoutes --external @getstrata/bootstrap/dependencies --external @getstrata/bootstrap/discoverModules --external @getstrata/bootstrap/discoverListeners --external @getstrata/bootstrap/discoverJobs --external @getstrata/bootstrap/health --external @getstrata/bootstrap/http/securedRouteModelBinding --external @getstrata/bootstrap/httpKernel --external @getstrata/bootstrap/listeners/invalidateCacheOnModelWrite --external @getstrata/bootstrap/membershipService --external @getstrata/bootstrap/metricsRoutes --external @getstrata/bootstrap/queue/defaultJobs --external @getstrata/bootstrap/providers --external @getstrata/bootstrap/providers/view --external @getstrata/bootstrap/routeRegistry --external @getstrata/bootstrap/schedule --external @getstrata/bootstrap/secretsGuard --external @getstrata/bootstrap/web/forms --external @getstrata/bootstrap/web/routing --external @getstrata/bootstrap/web/server --external @getstrata/bootstrap/web/session --external @getstrata/bootstrap/web/slug --external @getstrata/core/auth/accessControl --external @getstrata/core/auth/abilityChecker --external @getstrata/core/auth/authContext --external @getstrata/core/auth/emailVerification --external @getstrata/core/auth/guard --external @getstrata/core/auth/jwt --external @getstrata/core/auth/jwtGuard --external @getstrata/core/auth/basicAuthGuard --external @getstrata/core/auth/tokenAbilityChecker --external @getstrata/core/auth/membershipContext --external @getstrata/core/auth/membershipMiddleware --external @getstrata/core/auth/membershipScope --external @getstrata/core/auth/membershipService --external @getstrata/core/auth/oauth/oidcProvider --external @getstrata/core/auth/oauth/providers --external @getstrata/core/auth/oauth/samlProvider --external @getstrata/core/auth/oauth/types --external @getstrata/core/auth/saml/samlServiceProvider --external @getstrata/core/auth/password --external @getstrata/core/auth/passwordLogin --external @getstrata/core/auth/oneTimeToken --external @getstrata/core/auth/intendedUrlCookie --external @getstrata/core/auth/passwordConfirmCookie --external @getstrata/core/auth/policy --external @getstrata/core/auth/scimAuthMiddleware --external @getstrata/core/auth/sessionCookie --external @getstrata/core/auth/sessionGuard --external @getstrata/core/auth/tokenHash --external @getstrata/core/audit/exportAuditLogs --external @getstrata/core/audit/siemFormatter --external @getstrata/core/admin/formatValue --external @getstrata/core/admin/registry --external @getstrata/core/admin/types --external @getstrata/core/cache/tags --external @getstrata/core/cache/createCacheStore --external @getstrata/core/cache/repository --external @getstrata/core/cache/simpleCache --external @getstrata/core/cache/simpleCacheStore --external @getstrata/core/config/envSchema --external @getstrata/core/contracts/serviceTokens --external @getstrata/core/contracts/authUserDirectory --external @getstrata/core/contracts/container --external @getstrata/core/contracts/di --external @getstrata/core/crypto/fieldEncryption --external @getstrata/core/crypto/mfaSecret --external @getstrata/core/database --external @getstrata/core/database/baseRepository --external @getstrata/core/database/bindConnection --external @getstrata/core/database/boundConnection --external @getstrata/core/database/bunSql --external @getstrata/core/database/connection --external @getstrata/core/database/connectionContext --external @getstrata/core/database/defaultConnection --external @getstrata/core/database/dialect --external @getstrata/core/database/mysqlConnection --external @getstrata/core/database/namedConnections --external @getstrata/core/database/errors --external @getstrata/core/database/factory --external @getstrata/core/database/migrations --external @getstrata/core/database/migrations/types --external @getstrata/core/database/model --external @getstrata/core/database/query --external @getstrata/core/database/relationships --external @getstrata/core/database/repositoryConnection --external @getstrata/core/database/repositoryQuery --external @getstrata/core/database/seeders --external @getstrata/core/database/seeders/types --external @getstrata/core/database/schema --external @getstrata/core/database/sqliteConnection --external @getstrata/core/database/table --external @getstrata/core/database/transaction --external @getstrata/core/database/types --external @getstrata/core/database/whereBuilder --external @getstrata/core/errors/http --external @getstrata/core/events --external @getstrata/core/facades --external @getstrata/core/http --external @getstrata/core/http/authMiddleware --external @getstrata/core/http/authorizeMiddleware --external @getstrata/core/http/bodySizeLimitMiddleware --external @getstrata/core/http/clientIp --external @getstrata/core/http/cookies --external @getstrata/core/http/contentNegotiation --external @getstrata/core/http/contentSecurityPolicy --external @getstrata/core/http/conditionalResponse --external @getstrata/core/http/corsMiddleware --external @getstrata/core/http/csrfMiddleware --external @getstrata/core/http/csrfProtection --external @getstrata/core/http/csrfToken --external @getstrata/core/http/etag --external @getstrata/core/http/flashSession --external @getstrata/core/http/flashMiddleware --external @getstrata/core/http/formRequest --external @getstrata/core/http/middleware --external @getstrata/core/http/metricsMiddleware --external @getstrata/core/http/loginThrottleMiddleware --external @getstrata/core/http/memoryThrottleMiddleware --external @getstrata/core/http/pagination --external @getstrata/core/http/parseFormBody --external @getstrata/core/http/parseMultipartUpload --external @getstrata/core/http/requireAbilityMiddleware --external @getstrata/core/http/requireAuthMiddleware --external @getstrata/core/http/requireGlobalAdminMiddleware --external @getstrata/core/http/requireWebAuthMiddleware --external @getstrata/core/http/requireVerifiedMiddleware --external @getstrata/core/http/requirePasswordConfirmMiddleware --external @getstrata/core/http/resources --external @getstrata/core/http/response --external @getstrata/core/http/route --external @getstrata/core/http/routeMiddleware --external @getstrata/core/http/routeModelBinding --external @getstrata/core/http/safeInternalPath --external @getstrata/core/http/signedUrl --external @getstrata/core/http/statelessAuth --external @getstrata/core/http/scimThrottleMiddleware --external @getstrata/core/http/securityHeadersMiddleware --external @getstrata/core/http/securedRouteModelBinding --external @getstrata/core/http/requestMetaContext --external @getstrata/core/http/webErrorResponse --external @getstrata/core/http/webFormRequest --external @getstrata/core/http/throttleMiddleware --external @getstrata/core/http/validation --external @getstrata/core/jobs/exportAuditLogsJob --external @getstrata/core/jobs/invalidateCacheTagsJob --external @getstrata/core/lifecycle/gracefulShutdown --external @getstrata/core/logging/logger --external @getstrata/core/logging/requestLoggingMiddleware --external @getstrata/core/mail/mailer --external @getstrata/core/mail/markdownMail --external @getstrata/core/mail/markdownMailable --external @getstrata/core/mail/sanitizeMailHtml --external @getstrata/core/media/imageTransform --external @getstrata/core/metrics/prometheus --external @getstrata/core/notifications --external @getstrata/core/openapi/generator --external @getstrata/core/openapi/registeredRoute --external @getstrata/core/openapi/validate --external @getstrata/core/pagination --external @getstrata/core/queue --external @getstrata/core/queue/createAppQueue --external @getstrata/core/queue/failedJobRepository --external @getstrata/core/queue/failedJobService --external @getstrata/core/queue/jobRegistry --external @getstrata/core/queue/jobRunner --external @getstrata/core/queue/queueMetrics --external @getstrata/core/queue/publicQueue --external @getstrata/core/queue/redisQueue --external @getstrata/core/queue/types --external @getstrata/core/runtime/appEnv --external @getstrata/core/runtime/appKeyPrefix --external @getstrata/core/runtime/frontendMode --external @getstrata/core/runtime/applicationRegistry --external @getstrata/core/runtime/asyncContextStore --external @getstrata/core/scheduler/schedule --external @getstrata/core/scheduler/osCron --external @getstrata/core/security/oauthState --external @getstrata/core/security/publicReads --external @getstrata/core/security/recoveryCodes --external @getstrata/core/security/safeFetch --external @getstrata/core/security/safePath --external @getstrata/core/security/safeUrl --external @getstrata/core/security/scimTenantTokens --external @getstrata/core/security/securityEvents --external @getstrata/core/security/stripeWebhook --external @getstrata/core/security/timingSafeCompare --external @getstrata/core/security/tokenExpiry --external @getstrata/core/security/totp --external @getstrata/core/storage/storage --external @getstrata/core/tenant/tenancyConfig --external @getstrata/core/tenant/tenantContext --external @getstrata/core/tenant/tenantDatabaseScope --external @getstrata/core/tenant/databaseTenantContext --external @getstrata/core/tenant/tenantMiddleware --external @getstrata/core/tenant/enableTenantRls --external @getstrata/core/terminal/runShell --external @getstrata/core/tracing/traceContext --external @getstrata/core/tracing/tracingMiddleware --external @getstrata/core/validation/rules --external @getstrata/core/view",
|
|
172
182
|
"build:shims": "true"
|
|
173
183
|
},
|
|
174
184
|
"publishConfig": {
|
|
175
185
|
"access": "public"
|
|
176
186
|
},
|
|
177
187
|
"peerDependencies": {
|
|
178
|
-
"@getstrata/core": "^1.1.
|
|
188
|
+
"@getstrata/core": "^1.1.2",
|
|
179
189
|
"typescript": "^5.9.0"
|
|
180
190
|
},
|
|
181
191
|
"engines": {
|