@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 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 { appListeners, discoverListeners };
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";
@@ -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
- import { pathToFileURL as pathToFileURL2 } from "url";
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
- async function loadDiscoveredListeners() {
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 = await Promise.all(entries.map(async (fileName) => {
394
- const moduleUrl = pathToFileURL2(join2(listenersDirectory, fileName)).href;
395
- const loaded = await import(moduleUrl);
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
- return appListeners;
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
- jobRegistry.register("cache.invalidate-tags", () => {
573
+ jobRegistry2.register("cache.invalidate-tags", () => {
493
574
  return new InvalidateCacheTagsJob2(resolveApplicationCache2());
494
575
  });
495
- jobRegistry.register("audit.export", () => new ExportAuditLogsJob);
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, registerDefaultJobs));
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
- import { pathToFileURL as pathToFileURL2 } from "url";
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
- async function loadDiscoveredListeners() {
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 = await Promise.all(entries.map(async (fileName) => {
394
- const moduleUrl = pathToFileURL2(join2(listenersDirectory, fileName)).href;
395
- const loaded = await import(moduleUrl);
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
- return appListeners;
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
- jobRegistry.register("cache.invalidate-tags", () => {
573
+ jobRegistry2.register("cache.invalidate-tags", () => {
493
574
  return new InvalidateCacheTagsJob2(resolveApplicationCache2());
494
575
  });
495
- jobRegistry.register("audit.export", () => new ExportAuditLogsJob);
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, registerDefaultJobs));
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
- import { pathToFileURL } from "url";
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
- async function loadDiscoveredListeners() {
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 = await Promise.all(entries.map(async (fileName) => {
300
- const moduleUrl = pathToFileURL(join(listenersDirectory, fileName)).href;
301
- const loaded = await import(moduleUrl);
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
- return appListeners;
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 as pathToFileURL2 } from "url";
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 = pathToFileURL2(join2(modulesDirectory, moduleName, "index.ts")).href;
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
- jobRegistry.register("cache.invalidate-tags", () => {
563
+ jobRegistry2.register("cache.invalidate-tags", () => {
483
564
  return new InvalidateCacheTagsJob2(resolveApplicationCache2());
484
565
  });
485
- jobRegistry.register("audit.export", () => new ExportAuditLogsJob);
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, registerDefaultJobs));
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
- import { pathToFileURL as pathToFileURL2 } from "url";
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
- async function loadDiscoveredListeners() {
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 = await Promise.all(entries.map(async (fileName) => {
797
- const moduleUrl = pathToFileURL2(join2(listenersDirectory, fileName)).href;
798
- const loaded = await import(moduleUrl);
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
- return appListeners;
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
- jobRegistry.register("cache.invalidate-tags", () => {
958
+ jobRegistry2.register("cache.invalidate-tags", () => {
882
959
  return new InvalidateCacheTagsJob2(resolveApplicationCache2());
883
960
  });
884
- jobRegistry.register("audit.export", () => new ExportAuditLogsJob);
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, registerDefaultJobs));
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 join3 } from "path";
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(join3(process.cwd(), "public"), pathname);
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.0",
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.0",
188
+ "@getstrata/core": "^1.1.2",
179
189
  "typescript": "^5.9.0"
180
190
  },
181
191
  "engines": {