@spfn/core 0.2.0-beta.59 → 0.2.0-beta.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{boss-CjClX7G4.d.ts → boss-gXhgctn6.d.ts} +13 -0
- package/dist/codegen/index.js +5 -3
- package/dist/codegen/index.js.map +1 -1
- package/dist/event/index.js.map +1 -1
- package/dist/event/ws/index.js +13 -13
- package/dist/event/ws/index.js.map +1 -1
- package/dist/job/index.d.ts +2 -2
- package/dist/job/index.js +40 -0
- package/dist/job/index.js.map +1 -1
- package/dist/server/index.d.ts +58 -5
- package/dist/server/index.js +116 -14
- package/dist/server/index.js.map +1 -1
- package/package.json +235 -231
package/dist/server/index.js
CHANGED
|
@@ -1652,6 +1652,9 @@ async function stopBoss() {
|
|
|
1652
1652
|
function shouldClearOnStart() {
|
|
1653
1653
|
return getBossConfig()?.clearOnStart ?? false;
|
|
1654
1654
|
}
|
|
1655
|
+
function shouldSweepOrphanSchedules() {
|
|
1656
|
+
return getBossConfig()?.sweepOrphanSchedules ?? false;
|
|
1657
|
+
}
|
|
1655
1658
|
|
|
1656
1659
|
// src/job/job-router.ts
|
|
1657
1660
|
function isJobDef(value) {
|
|
@@ -1708,8 +1711,45 @@ async function registerJobs(router) {
|
|
|
1708
1711
|
jobLogger2.info("Existing jobs cleared");
|
|
1709
1712
|
}
|
|
1710
1713
|
await Promise.all(jobs.map((job2) => registerJob(job2)));
|
|
1714
|
+
for (const job2 of jobs) {
|
|
1715
|
+
if (job2.cronExpression) {
|
|
1716
|
+
registeredCronNames.add(job2.name);
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
if (shouldSweepOrphanSchedules()) {
|
|
1720
|
+
await sweepOrphanSchedules(boss);
|
|
1721
|
+
}
|
|
1711
1722
|
jobLogger2.info("All jobs registered successfully");
|
|
1712
1723
|
}
|
|
1724
|
+
var registeredCronNames = /* @__PURE__ */ new Set();
|
|
1725
|
+
async function sweepOrphanSchedules(boss) {
|
|
1726
|
+
if (registeredCronNames.size === 0) {
|
|
1727
|
+
jobLogger2.debug("No cron jobs declared; skipping orphan schedule sweep");
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1730
|
+
try {
|
|
1731
|
+
const schedules = await boss.getSchedules();
|
|
1732
|
+
const orphans = schedules.filter((schedule) => !registeredCronNames.has(schedule.name));
|
|
1733
|
+
if (orphans.length === 0) {
|
|
1734
|
+
jobLogger2.debug("No orphan schedules found");
|
|
1735
|
+
return;
|
|
1736
|
+
}
|
|
1737
|
+
await Promise.all(orphans.map(async (orphan) => {
|
|
1738
|
+
try {
|
|
1739
|
+
await boss.unschedule(orphan.name, orphan.key);
|
|
1740
|
+
jobLogger2.info(`Removed orphan schedule: ${orphan.name}`);
|
|
1741
|
+
} catch (error) {
|
|
1742
|
+
jobLogger2.error(`Failed to remove orphan schedule: ${orphan.name}`, {
|
|
1743
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1744
|
+
});
|
|
1745
|
+
}
|
|
1746
|
+
}));
|
|
1747
|
+
} catch (error) {
|
|
1748
|
+
jobLogger2.error("Orphan schedule sweep failed", {
|
|
1749
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1713
1753
|
async function ensureQueue(boss, queueName) {
|
|
1714
1754
|
await boss.createQueue(queueName);
|
|
1715
1755
|
}
|
|
@@ -2055,25 +2095,25 @@ async function onClientMessage(data, router, connection, subject) {
|
|
|
2055
2095
|
wsLogger.error(`WebSocket message handler error: ${type}`, err);
|
|
2056
2096
|
}
|
|
2057
2097
|
}
|
|
2098
|
+
function resolveWSServerCtor(mod) {
|
|
2099
|
+
return mod.WebSocketServer ?? mod.Server ?? mod.default?.WebSocketServer ?? mod.default?.Server;
|
|
2100
|
+
}
|
|
2058
2101
|
async function loadWSServer() {
|
|
2102
|
+
let mod;
|
|
2059
2103
|
try {
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
const WSS = WS.WebSocketServer ?? WS.Server;
|
|
2063
|
-
if (typeof WSS !== "function") {
|
|
2064
|
-
throw new Error(
|
|
2065
|
-
"WebSocketServer not found in ws module. Ensure ws@^8 is installed: pnpm add ws"
|
|
2066
|
-
);
|
|
2067
|
-
}
|
|
2068
|
-
return WSS;
|
|
2069
|
-
} catch (err) {
|
|
2070
|
-
if (err instanceof Error && err.message.includes("WebSocketServer not found")) {
|
|
2071
|
-
throw err;
|
|
2072
|
-
}
|
|
2104
|
+
mod = await import('ws');
|
|
2105
|
+
} catch {
|
|
2073
2106
|
throw new Error(
|
|
2074
2107
|
'@spfn/core WebSocket support requires the "ws" package.\nInstall it with: pnpm add ws'
|
|
2075
2108
|
);
|
|
2076
2109
|
}
|
|
2110
|
+
const WSS = resolveWSServerCtor(mod);
|
|
2111
|
+
if (typeof WSS !== "function") {
|
|
2112
|
+
throw new Error(
|
|
2113
|
+
"WebSocketServer not found in ws module. Ensure ws@^8 is installed: pnpm add ws"
|
|
2114
|
+
);
|
|
2115
|
+
}
|
|
2116
|
+
return WSS;
|
|
2077
2117
|
}
|
|
2078
2118
|
function getNetworkAddress() {
|
|
2079
2119
|
const nets = networkInterfaces();
|
|
@@ -2592,6 +2632,68 @@ async function cleanupOnFailure(config) {
|
|
|
2592
2632
|
serverLogger.error("Cleanup failed", cleanupError);
|
|
2593
2633
|
}
|
|
2594
2634
|
}
|
|
2635
|
+
function getInfrastructure(config) {
|
|
2636
|
+
return {
|
|
2637
|
+
database: config?.infrastructure?.database !== false,
|
|
2638
|
+
redis: config?.infrastructure?.redis !== false
|
|
2639
|
+
};
|
|
2640
|
+
}
|
|
2641
|
+
function withServerlessDefaults(config) {
|
|
2642
|
+
if (!config) {
|
|
2643
|
+
return config;
|
|
2644
|
+
}
|
|
2645
|
+
return {
|
|
2646
|
+
...config,
|
|
2647
|
+
database: {
|
|
2648
|
+
...config.database,
|
|
2649
|
+
healthCheck: { enabled: false, ...config.database?.healthCheck }
|
|
2650
|
+
}
|
|
2651
|
+
};
|
|
2652
|
+
}
|
|
2653
|
+
function warnIfJobsConfigured(config) {
|
|
2654
|
+
if (config?.jobs) {
|
|
2655
|
+
serverLogger.warn(
|
|
2656
|
+
"Jobs are configured but this is a serverless target: the in-process pg-boss worker is NOT started here, so enqueued jobs will not be processed on this deployment. Drain the queue from a scheduled endpoint (e.g. Vercel Cron \u2192 a route that processes a batch) or run jobs on an always-on target."
|
|
2657
|
+
);
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
async function initInfrastructure(config) {
|
|
2661
|
+
const infra = getInfrastructure(config);
|
|
2662
|
+
if (infra.database) {
|
|
2663
|
+
await initDatabase(config?.database);
|
|
2664
|
+
}
|
|
2665
|
+
if (infra.redis) {
|
|
2666
|
+
await initCache();
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
var appPromise;
|
|
2670
|
+
function createServerlessApp(config) {
|
|
2671
|
+
if (!appPromise) {
|
|
2672
|
+
appPromise = buildServerlessApp(config);
|
|
2673
|
+
}
|
|
2674
|
+
return appPromise;
|
|
2675
|
+
}
|
|
2676
|
+
async function buildServerlessApp(rawConfig) {
|
|
2677
|
+
loadEnv();
|
|
2678
|
+
const config = withServerlessDefaults(rawConfig);
|
|
2679
|
+
warnIfJobsConfigured(config);
|
|
2680
|
+
await initInfrastructure(config);
|
|
2681
|
+
return createServer(config);
|
|
2682
|
+
}
|
|
2683
|
+
function resetServerlessApp() {
|
|
2684
|
+
appPromise = void 0;
|
|
2685
|
+
}
|
|
2686
|
+
async function provisionInfrastructure(config) {
|
|
2687
|
+
loadEnv();
|
|
2688
|
+
if (config?.lifecycle?.beforeInfrastructure) {
|
|
2689
|
+
await config.lifecycle.beforeInfrastructure(config);
|
|
2690
|
+
}
|
|
2691
|
+
await initInfrastructure(config);
|
|
2692
|
+
if (config?.lifecycle?.afterInfrastructure) {
|
|
2693
|
+
await config.lifecycle.afterInfrastructure();
|
|
2694
|
+
}
|
|
2695
|
+
serverLogger.info("Provisioning complete");
|
|
2696
|
+
}
|
|
2595
2697
|
|
|
2596
2698
|
// src/server/config-builder.ts
|
|
2597
2699
|
function collectHooks(lifecycles, key) {
|
|
@@ -2941,6 +3043,6 @@ function defineServerConfig() {
|
|
|
2941
3043
|
return new ServerConfigBuilder();
|
|
2942
3044
|
}
|
|
2943
3045
|
|
|
2944
|
-
export { createServer, defineServerConfig, getShutdownManager, loadEnv, loadEnvFiles, startServer };
|
|
3046
|
+
export { createServer, createServerlessApp, defineServerConfig, getShutdownManager, loadEnv, loadEnvFiles, provisionInfrastructure, resetServerlessApp, startServer };
|
|
2945
3047
|
//# sourceMappingURL=index.js.map
|
|
2946
3048
|
//# sourceMappingURL=index.js.map
|