@farm.js/core 0.1.60 → 0.1.62
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/{agent-mcp.d-C-2S9bnP.d.mts → agent-mcp.d-BKZ3UNbt.d.mts} +1 -1
- package/dist/{agent-mcp.d-SIoCUP1I.d.ts → agent-mcp.d-C1zr_nGS.d.ts} +1 -1
- package/dist/agent-runtime.cjs +3 -3
- package/dist/agent-runtime.d.mts +2 -2
- package/dist/agent-runtime.d.ts +2 -2
- package/dist/agent-runtime.mjs +2 -2
- package/dist/analyzer-2AHWJJR7.cjs +15 -0
- package/dist/analyzer-YESYU3GK.mjs +15 -0
- package/dist/api/route-manager.cjs +4 -4
- package/dist/api/route-manager.d.mts +4 -4
- package/dist/api/route-manager.d.ts +4 -4
- package/dist/api/route-manager.mjs +3 -3
- package/dist/api/runtime.cjs +3 -3
- package/dist/api/runtime.d.mts +3 -3
- package/dist/api/runtime.d.ts +3 -3
- package/dist/api/runtime.mjs +2 -2
- package/dist/api.cjs +5 -5
- package/dist/api.d.mts +4 -4
- package/dist/api.d.ts +4 -4
- package/dist/api.mjs +4 -4
- package/dist/{app-manifest.d-DrSAHskY.d.mts → app-manifest.d-BpvhfKRH.d.mts} +1 -1
- package/dist/{app-manifest.d-Tb3CJpL4.d.ts → app-manifest.d-ntch_bvA.d.ts} +1 -1
- package/dist/app-markdown.d.mts +3 -3
- package/dist/app-markdown.d.ts +3 -3
- package/dist/{app.d-CmWlYpZJ.d.ts → app.d-AE8_v3Db.d.ts} +4 -10
- package/dist/{app.d-D6QQM_kk.d.mts → app.d-CysWA_8v.d.mts} +4 -10
- package/dist/{chunk-FORSVMEJ.mjs → chunk-2CNKQC3G.mjs} +1 -1
- package/dist/{chunk-ZFUKPWFC.mjs → chunk-2JYBLE63.mjs} +416 -208
- package/dist/{chunk-QRX4JRBO.cjs → chunk-3CCAICF7.cjs} +5 -5
- package/dist/{chunk-ANHZ6SUL.mjs → chunk-3TXKFRSO.mjs} +1 -1
- package/dist/{chunk-BHJAYPYU.mjs → chunk-3UZVPO72.mjs} +1 -1
- package/dist/{chunk-6UUH4N4J.mjs → chunk-43V3ANPQ.mjs} +1 -1
- package/dist/chunk-4EBC7EMW.cjs +8 -0
- package/dist/{chunk-VZY7MAVS.cjs → chunk-4IHMHFQB.cjs} +27 -1
- package/dist/{chunk-FK25QSVC.cjs → chunk-4P5634G6.cjs} +2 -2
- package/dist/{chunk-4JTQPOKO.cjs → chunk-53ZCZ46B.cjs} +2 -2
- package/dist/{chunk-NQJDO7K7.cjs → chunk-545WJ5UG.cjs} +321 -37
- package/dist/{chunk-VU3MYZPO.mjs → chunk-5FE5YT2N.mjs} +26 -0
- package/dist/{chunk-A5BJKSZE.cjs → chunk-5IQ2ERQA.cjs} +2 -2
- package/dist/{chunk-SJRCWF4Z.mjs → chunk-5Y22WNTO.mjs} +2 -2
- package/dist/{chunk-U4BJKNIR.cjs → chunk-752XUZIM.cjs} +11 -6
- package/dist/{chunk-JBK7UJOI.cjs → chunk-AJB3DHN6.cjs} +2 -2
- package/dist/{chunk-YB44NKC2.cjs → chunk-AXVRUDMB.cjs} +2 -2
- package/dist/{chunk-LJVNMGE3.mjs → chunk-BM2LH2JM.mjs} +8 -3
- package/dist/{chunk-YI6FKTTN.cjs → chunk-BT4SEFLC.cjs} +261 -38
- package/dist/{chunk-LIFUPCXW.cjs → chunk-CFG4QERR.cjs} +13 -2
- package/dist/{chunk-3OWVWZ6R.cjs → chunk-CLFEQGET.cjs} +6 -6
- package/dist/{chunk-OZK2DS44.mjs → chunk-CROAFCMW.mjs} +1 -1
- package/dist/{chunk-2KTYMMWT.mjs → chunk-DPE53XWL.mjs} +1 -1
- package/dist/{chunk-3PX4AIXO.mjs → chunk-DQF3QLOH.mjs} +258 -35
- package/dist/{chunk-FSQMN2MQ.mjs → chunk-E46NXBNJ.mjs} +1 -1
- package/dist/{chunk-EGVC4LIG.mjs → chunk-E4RDMG3K.mjs} +1 -1
- package/dist/{chunk-X2CZTWQA.mjs → chunk-ECKQFEX2.mjs} +1 -1
- package/dist/{chunk-MTWXOEI4.cjs → chunk-EXXFSZOC.cjs} +246 -193
- package/dist/{chunk-UYSTTPYJ.cjs → chunk-GGNJAGGE.cjs} +643 -435
- package/dist/{chunk-XTG73QZA.cjs → chunk-GVOMPU3Y.cjs} +12 -8
- package/dist/{chunk-ZP32GNJQ.cjs → chunk-I32V5CZL.cjs} +14 -13
- package/dist/{chunk-37PYUEK5.mjs → chunk-IOF4KXMP.mjs} +7 -3
- package/dist/{chunk-ILMTRGBG.mjs → chunk-IQIKPKFP.mjs} +157 -45
- package/dist/{chunk-5JNUYGNF.cjs → chunk-IWRLV46X.cjs} +2 -2
- package/dist/{chunk-KPOMS5RO.cjs → chunk-J3GFOQOL.cjs} +3 -3
- package/dist/{chunk-NHD7BAKD.mjs → chunk-JCEFKP5M.mjs} +41 -25
- package/dist/{analyzer-LCSI3NSH.cjs → chunk-JEJQGZI7.cjs} +16 -13
- package/dist/{chunk-LB3DPQP6.cjs → chunk-JLDNXURZ.cjs} +23 -23
- package/dist/{chunk-VGG74PSU.cjs → chunk-L2JG337G.cjs} +2 -2
- package/dist/chunk-L4RTTTVE.mjs +8 -0
- package/dist/chunk-LEJDW34D.cjs +115 -0
- package/dist/{analyzer-22BEYV7S.mjs → chunk-LVWGURLD.mjs} +6 -3
- package/dist/{chunk-Z5A6CNV2.mjs → chunk-MK5E44WP.mjs} +1 -1
- package/dist/{chunk-T4EW7AAD.mjs → chunk-NKRZLQUK.mjs} +2 -2
- package/dist/{chunk-HPWB57PZ.mjs → chunk-NT3QDN2E.mjs} +1 -1
- package/dist/{chunk-T7I62A4C.mjs → chunk-OUWRNHTV.mjs} +81 -28
- package/dist/{chunk-GFT5AHAT.mjs → chunk-QDWMCFTH.mjs} +12 -1
- package/dist/{chunk-AER5I65K.mjs → chunk-QTD6EMN2.mjs} +1 -1
- package/dist/{chunk-UDJY2ZGY.cjs → chunk-RMUD75WT.cjs} +413 -301
- package/dist/chunk-RZNCMRD3.mjs +141 -0
- package/dist/{chunk-D7LTCK3U.mjs → chunk-SA7MLSP4.mjs} +11 -6
- package/dist/{chunk-2FRLSDBT.cjs → chunk-SM25ZC4S.cjs} +1 -1
- package/dist/{chunk-3YMLUNL2.cjs → chunk-SVXOCTQ2.cjs} +1 -1
- package/dist/{chunk-W2RZ73IU.cjs → chunk-SYXPWJ7N.cjs} +8 -8
- package/dist/{chunk-F6Y7ZAPQ.mjs → chunk-T46NNU4D.mjs} +6 -3
- package/dist/{chunk-IFHPDLIS.mjs → chunk-TGULJSHD.mjs} +5 -4
- package/dist/{chunk-JPIUGDK4.mjs → chunk-TZVUF5JJ.mjs} +1 -1
- package/dist/chunk-UWI3SJAK.cjs +141 -0
- package/dist/{chunk-JI5D7MXY.mjs → chunk-UYRI6U3P.mjs} +1 -1
- package/dist/{chunk-D2X5MUF5.cjs → chunk-V727H3RI.cjs} +47 -31
- package/dist/{chunk-ZMHAFH4R.mjs → chunk-VM7X5CKC.mjs} +2 -2
- package/dist/{chunk-VPTWKOCY.mjs → chunk-VWW4Q3BJ.mjs} +287 -6
- package/dist/{chunk-4P23B7DU.cjs → chunk-WKJQ2FJA.cjs} +3 -3
- package/dist/{chunk-HASX6DC7.cjs → chunk-WKPBIT5Q.cjs} +8 -8
- package/dist/{chunk-RAWWCDCT.cjs → chunk-WYAXRIYP.cjs} +3 -3
- package/dist/{chunk-3TL3AH25.cjs → chunk-X4K7TYN6.cjs} +12 -7
- package/dist/chunk-XCXHQBMM.mjs +115 -0
- package/dist/{chunk-DPJ66FSI.cjs → chunk-XX32BOMM.cjs} +7 -7
- package/dist/{chunk-2IAPKPEB.cjs → chunk-YN6BHOYY.cjs} +6 -6
- package/dist/{chunk-CBKRS3M4.cjs → chunk-Z7P2BTZ3.cjs} +7 -6
- package/dist/{chunk-SX7EECTS.mjs → chunk-ZBUAOGMY.mjs} +1 -1
- package/dist/{chunk-RPUJHJHE.mjs → chunk-ZFWYCVKS.mjs} +4 -3
- package/dist/{chunk-IFXSBJPN.cjs → chunk-ZVIEFTUA.cjs} +20 -17
- package/dist/{chunk-EXUONJYV.mjs → chunk-ZZI56IUY.mjs} +3 -3
- package/dist/{programmatic-routes-client.d-CLG2N1yH.d.ts → client-component.d-Bgt3x5Fu.d.ts} +18 -3
- package/dist/{programmatic-routes-client.d-CPbNqtIi.d.mts → client-component.d-BoqC2MLC.d.mts} +18 -3
- package/dist/{client-plugins.d-vXrbcfJ1.d.ts → client-plugins.d-BcqIy4au.d.ts} +1 -1
- package/dist/{client-plugins.d-CgQQ-EAv.d.mts → client-plugins.d-CWyYBxXf.d.mts} +1 -1
- package/dist/client-plugins.d.mts +2 -2
- package/dist/client-plugins.d.ts +2 -2
- package/dist/client.d.mts +7 -7
- package/dist/client.d.ts +7 -7
- package/dist/{config.d-DqZkLwef.d.ts → config.d-qt-mE8O5.d.mts} +6 -2
- package/dist/{config.d-DqZkLwef.d.mts → config.d-qt-mE8O5.d.ts} +6 -2
- package/dist/config.d.mts +2 -2
- package/dist/config.d.ts +2 -2
- package/dist/cron.cjs +12 -2
- package/dist/cron.d.mts +101 -3
- package/dist/cron.d.ts +101 -3
- package/dist/cron.mjs +11 -1
- package/dist/desktop.d.mts +3 -3
- package/dist/desktop.d.ts +3 -3
- package/dist/{devtools-KQZ6SRCJ.mjs → devtools-NUVXYG7I.mjs} +6 -6
- package/dist/{devtools-UF6JYHUN.cjs → devtools-SVRSGPNC.cjs} +8 -8
- package/dist/docs.cjs +9 -9
- package/dist/docs.d.mts +3 -3
- package/dist/docs.d.ts +3 -3
- package/dist/docs.mjs +8 -8
- package/dist/image/server.cjs +3 -3
- package/dist/image/server.mjs +2 -2
- package/dist/image/sharp.cjs +10 -10
- package/dist/image/sharp.mjs +2 -2
- package/dist/index.cjs +42 -27
- package/dist/{index.d-Dmfb7Kb_.d.mts → index.d-BDaiu2i5.d.mts} +1 -1
- package/dist/{index.d-DlCELfhf.d.ts → index.d-nAncqTXz.d.ts} +1 -1
- package/dist/index.d.mts +18 -18
- package/dist/index.d.ts +18 -18
- package/dist/index.mjs +42 -27
- package/dist/integrations.cjs +3 -3
- package/dist/integrations.d.mts +2 -2
- package/dist/integrations.d.ts +2 -2
- package/dist/integrations.mjs +2 -2
- package/dist/internal/app-markdown-runtime.d.mts +3 -3
- package/dist/internal/app-markdown-runtime.d.ts +3 -3
- package/dist/internal/build-runtime.cjs +27 -22
- package/dist/internal/build-runtime.d.mts +4 -4
- package/dist/internal/build-runtime.d.ts +4 -4
- package/dist/internal/build-runtime.mjs +26 -21
- package/dist/internal/cli-runtime.cjs +12 -11
- package/dist/internal/cli-runtime.mjs +11 -10
- package/dist/internal/client-error-overlay.cjs +4 -4
- package/dist/internal/client-error-overlay.mjs +1 -1
- package/dist/internal/client-runtime.d.mts +5 -5
- package/dist/internal/client-runtime.d.ts +5 -5
- package/dist/internal/compression-runtime.d.mts +2 -2
- package/dist/internal/compression-runtime.d.ts +2 -2
- package/dist/internal/config-runtime.cjs +8 -8
- package/dist/internal/config-runtime.d.mts +5 -5
- package/dist/internal/config-runtime.d.ts +5 -5
- package/dist/internal/config-runtime.mjs +7 -7
- package/dist/internal/form-actions.cjs +4 -4
- package/dist/internal/form-actions.mjs +3 -3
- package/dist/internal/infra-analytics-runtime.cjs +6 -6
- package/dist/internal/infra-analytics-runtime.mjs +4 -4
- package/dist/internal/metadata-image-runtime.cjs +3 -3
- package/dist/internal/metadata-image-runtime.mjs +2 -2
- package/dist/internal/native-server-fns.cjs +25 -0
- package/dist/internal/native-server-fns.d.mts +42 -0
- package/dist/internal/native-server-fns.d.ts +42 -0
- package/dist/internal/native-server-fns.mjs +25 -0
- package/dist/internal/product-telemetry-runtime.cjs +2 -2
- package/dist/internal/product-telemetry-runtime.mjs +1 -1
- package/dist/internal/production-node-env.cjs +2 -2
- package/dist/internal/production-node-env.mjs +1 -1
- package/dist/internal/production-runtime.cjs +16 -10
- package/dist/internal/production-runtime.d.mts +39 -12
- package/dist/internal/production-runtime.d.ts +39 -12
- package/dist/internal/production-runtime.mjs +15 -9
- package/dist/internal/react-cache.cjs +51 -0
- package/dist/internal/react-cache.d.mts +3 -0
- package/dist/internal/react-cache.d.ts +3 -0
- package/dist/internal/react-cache.mjs +51 -0
- package/dist/markdown.d.mts +2 -2
- package/dist/markdown.d.ts +2 -2
- package/dist/middleware.cjs +3 -3
- package/dist/middleware.d.mts +4 -4
- package/dist/middleware.d.ts +4 -4
- package/dist/middleware.mjs +2 -2
- package/dist/mobile.d.mts +10 -4
- package/dist/mobile.d.ts +10 -4
- package/dist/{modules-VHD7BELU.mjs → modules-KOKD4XS6.mjs} +2 -2
- package/dist/modules-QTP7WJPD.cjs +13 -0
- package/dist/native-server-fn-handler-GLRHAYWV.mjs +28 -0
- package/dist/native-server-fn-handler-J5MYRXN6.cjs +28 -0
- package/dist/native-specs-5OLED4MM.cjs +15 -0
- package/dist/{native-specs-BD7HOTMJ.mjs → native-specs-LDV6IZ4N.mjs} +1 -1
- package/dist/{native-tree-VWNW2MQ2.mjs → native-tree-AS5L3ID3.mjs} +2 -2
- package/dist/{native-tree-6G5O53O3.cjs → native-tree-Z2WYUJEV.cjs} +3 -3
- package/dist/native.cjs +1 -1
- package/dist/native.d.mts +5 -5
- package/dist/native.d.ts +5 -5
- package/dist/native.mjs +1 -1
- package/dist/{navigation-delegate.d-JXx40JzR.d.ts → navigation-delegate.d-BbUHRXxG.d.ts} +1 -1
- package/dist/{navigation-delegate.d-CnOTWOyi.d.mts → navigation-delegate.d-CSCm8ZxL.d.mts} +1 -1
- package/dist/navigation.d.mts +5 -5
- package/dist/navigation.d.ts +5 -5
- package/dist/{nitro-FLN6DRGJ.mjs → nitro-DD4QCA66.mjs} +5 -5
- package/dist/{nitro-HXAZZQKY.cjs → nitro-VRDX2H4M.cjs} +8 -8
- package/dist/plugin.cjs +19 -18
- package/dist/plugin.d.mts +5 -5
- package/dist/plugin.d.ts +5 -5
- package/dist/plugin.mjs +18 -17
- package/dist/{port-WOOQ3V56.mjs → port-UFUZL6RI.mjs} +2 -2
- package/dist/{port-C6GBH4C6.cjs → port-VTLHPZOI.cjs} +10 -10
- package/dist/{production-runtime.d-CP5s6RuY.d.mts → production-runtime.d-CcQiDko5.d.mts} +1 -1
- package/dist/{production-runtime.d-N-cE3pmy.d.ts → production-runtime.d-DgT24A0f.d.ts} +1 -1
- package/dist/{render-plan.d-DZ-qjjdG.d.mts → render-plan.d-BH9WF-JZ.d.mts} +1 -1
- package/dist/{render-plan.d-B9lAP3uX.d.ts → render-plan.d-CyrX6MDs.d.ts} +1 -1
- package/dist/renderer-client.d.mts +5 -5
- package/dist/renderer-client.d.ts +5 -5
- package/dist/{request.d-BiicaNxb.d.ts → request.d-BB8M8bcD.d.ts} +1 -1
- package/dist/{request.d-DV0oeUit.d.mts → request.d-CUrPnCW7.d.mts} +1 -1
- package/dist/request.d.mts +3 -3
- package/dist/request.d.ts +3 -3
- package/dist/{route-rendering.d-BrIKA51A.d.mts → route-rendering.d-CYxlzaFm.d.mts} +1 -1
- package/dist/{route-rendering.d-Iss0C7GR.d.ts → route-rendering.d-DYqZMIf4.d.ts} +1 -1
- package/dist/{router.d-mNTbOGV_.d.mts → router.d-7o24CD8u.d.mts} +1 -1
- package/dist/{router.d-DjGn_al7.d.ts → router.d-DaKo507j.d.ts} +1 -1
- package/dist/{routes.d-BKSjHuH9.d.ts → routes.d-BknKQcTu.d.ts} +7 -1
- package/dist/{routes.d-qd8Qf4LG.d.mts → routes.d-D1IrO9KK.d.mts} +7 -1
- package/dist/routes.d.mts +2 -2
- package/dist/routes.d.ts +2 -2
- package/dist/{rsc-pipeline-SVLBTY7H.cjs → rsc-pipeline-OF2I7PCX.cjs} +8 -8
- package/dist/{rsc-pipeline-WBLBDQXA.mjs → rsc-pipeline-RFLHDAKD.mjs} +7 -7
- package/dist/{runtime-DGUOWSMF.cjs → runtime-LBTK62AD.cjs} +70 -47
- package/dist/{runtime-HFZTVNFF.mjs → runtime-M6UJCSLA.mjs} +38 -15
- package/dist/{runtime.d-Bm_4hP5T.d.ts → runtime.d-CN73a-IL.d.ts} +1 -1
- package/dist/{runtime.d-BNVbojF1.d.mts → runtime.d-CcNuzhX6.d.mts} +1 -1
- package/dist/server-action-security.cjs +3 -3
- package/dist/server-action-security.mjs +2 -2
- package/dist/server-fn.cjs +4 -4
- package/dist/server-fn.mjs +3 -3
- package/dist/server-plugins.d.mts +3 -3
- package/dist/server-plugins.d.ts +3 -3
- package/dist/server-query.cjs +5 -5
- package/dist/server-query.mjs +4 -4
- package/dist/server.cjs +38 -37
- package/dist/server.d.mts +10 -10
- package/dist/server.d.ts +10 -10
- package/dist/server.mjs +23 -22
- package/dist/{spa-router.d-DHDoXxDE.d.mts → spa-router.d-CNi77LZm.d.mts} +2 -2
- package/dist/{spa-router.d-DAtnNoBe.d.ts → spa-router.d-Cvgf5QP4.d.ts} +2 -2
- package/dist/testing.cjs +6 -6
- package/dist/testing.d.mts +2 -2
- package/dist/testing.d.ts +2 -2
- package/dist/testing.mjs +4 -4
- package/dist/{utils.d-DwZ-KLSB.d.ts → utils.d-C3H-14_Y.d.ts} +1 -1
- package/dist/{utils.d-uKZcKJk4.d.mts → utils.d-D8VfzZYn.d.mts} +1 -1
- package/dist/version.cjs +2 -2
- package/dist/version.mjs +1 -1
- package/dist/vite.cjs +21 -18
- package/dist/vite.d.mts +5 -5
- package/dist/vite.d.ts +5 -5
- package/dist/vite.mjs +20 -17
- package/dist/workflows.cjs +3 -3
- package/dist/workflows.mjs +2 -2
- package/package.json +12 -2
- package/dist/modules-WT5D3AWY.cjs +0 -13
- package/dist/native-specs-IQQRJOOW.cjs +0 -15
|
@@ -28,8 +28,31 @@ function resolveCronConfig(cron) {
|
|
|
28
28
|
jobs: []
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
+
if (typeof cron !== "object" || Array.isArray(cron)) {
|
|
32
|
+
throw new TypeError("`cron` must be a job map, { provider, jobs }, or false.");
|
|
33
|
+
}
|
|
34
|
+
let provider;
|
|
35
|
+
let entries;
|
|
36
|
+
if ("provider" in cron && (typeof cron.provider !== "object" || cron.provider === null)) {
|
|
37
|
+
if (cron.provider !== "host" && cron.provider !== "farmjs") {
|
|
38
|
+
throw new TypeError(
|
|
39
|
+
`\`cron.provider\` must be "host" (the deploy platform's scheduler) or "farmjs" (Farm.js Infra), received ${JSON.stringify(cron.provider)}.`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
provider = cron.provider;
|
|
43
|
+
if (Object.keys(cron).some((key) => key !== "provider" && key !== "jobs")) {
|
|
44
|
+
throw new TypeError("When `cron.provider` is set, place named jobs inside `cron.jobs`.");
|
|
45
|
+
}
|
|
46
|
+
const configured = cron.jobs === void 0 ? {} : cron.jobs;
|
|
47
|
+
if (!configured || typeof configured !== "object" || Array.isArray(configured)) {
|
|
48
|
+
throw new TypeError("`cron.jobs` must be a map of job names to configurations.");
|
|
49
|
+
}
|
|
50
|
+
entries = configured;
|
|
51
|
+
} else {
|
|
52
|
+
entries = cron;
|
|
53
|
+
}
|
|
31
54
|
const jobs = [];
|
|
32
|
-
for (const [name, job] of Object.entries(
|
|
55
|
+
for (const [name, job] of Object.entries(entries)) {
|
|
33
56
|
if (!job || typeof job !== "object" || Array.isArray(job)) {
|
|
34
57
|
throw new TypeError(`Farm cron ${JSON.stringify(name)} must be a configuration object.`);
|
|
35
58
|
}
|
|
@@ -37,6 +60,7 @@ function resolveCronConfig(cron) {
|
|
|
37
60
|
jobs.push(normalizeCronJob(name, job));
|
|
38
61
|
}
|
|
39
62
|
return {
|
|
63
|
+
...provider ? { provider } : {},
|
|
40
64
|
enabled: jobs.length > 0,
|
|
41
65
|
secretEnv: DEFAULT_FARM_CRON_SECRET_ENV,
|
|
42
66
|
jobs
|
|
@@ -50,18 +74,21 @@ async function prepareFarmCronForNitro(config) {
|
|
|
50
74
|
const path = await import("path");
|
|
51
75
|
const manifestPath = path.join(root, distDir, FARM_CRON_MANIFEST);
|
|
52
76
|
const generatedDir = path.join(root, distDir, ".nitro", "farm-cron");
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
77
|
+
const provider = cron.provider ?? "host";
|
|
78
|
+
const manifest = createFarmCronManifest(cron, provider);
|
|
79
|
+
await fs.mkdir(path.dirname(manifestPath), { recursive: true });
|
|
80
|
+
await fs.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
81
|
+
`, "utf8");
|
|
82
|
+
await fs.rm(generatedDir, { recursive: true, force: true });
|
|
83
|
+
if (!cron.enabled || provider === "farmjs") {
|
|
58
84
|
return {
|
|
59
|
-
jobs: [],
|
|
85
|
+
jobs: cron.enabled ? cron.jobs : [],
|
|
60
86
|
tasks: {},
|
|
61
|
-
scheduledTasks: {}
|
|
87
|
+
scheduledTasks: {},
|
|
88
|
+
manifestPath,
|
|
89
|
+
provider
|
|
62
90
|
};
|
|
63
91
|
}
|
|
64
|
-
await fs.rm(generatedDir, { recursive: true, force: true });
|
|
65
92
|
await fs.mkdir(generatedDir, { recursive: true });
|
|
66
93
|
const tasks = {};
|
|
67
94
|
const wrapperNames = resolveCronWrapperFileNames(cron.jobs.map((job) => job.name));
|
|
@@ -74,26 +101,26 @@ async function prepareFarmCronForNitro(config) {
|
|
|
74
101
|
description: job.description || `Farm cron ${job.name}`
|
|
75
102
|
};
|
|
76
103
|
}
|
|
77
|
-
const manifest = createFarmCronManifest(cron);
|
|
78
|
-
await fs.mkdir(path.dirname(manifestPath), { recursive: true });
|
|
79
|
-
await fs.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
80
|
-
`, "utf8");
|
|
81
104
|
return {
|
|
82
105
|
jobs: cron.jobs,
|
|
83
106
|
tasks,
|
|
84
107
|
scheduledTasks: createCronScheduledTasks(cron.jobs),
|
|
85
|
-
manifestPath
|
|
108
|
+
manifestPath,
|
|
109
|
+
provider: "host"
|
|
86
110
|
};
|
|
87
111
|
}
|
|
88
|
-
function createFarmCronManifest(cron) {
|
|
112
|
+
function createFarmCronManifest(cron, provider = cron.provider ?? "host") {
|
|
89
113
|
return {
|
|
90
114
|
schemaVersion: 1,
|
|
115
|
+
provider,
|
|
91
116
|
secretEnv: cron.secretEnv,
|
|
92
|
-
jobs: cron.jobs.map((job) => ({
|
|
117
|
+
jobs: (cron.enabled ? cron.jobs : []).map((job) => ({
|
|
93
118
|
name: job.name,
|
|
94
119
|
schedule: job.schedule,
|
|
95
120
|
path: job.path,
|
|
96
|
-
description: job.description || null
|
|
121
|
+
description: job.description || null,
|
|
122
|
+
...job.timeoutMs !== void 0 ? { timeoutMs: job.timeoutMs } : {},
|
|
123
|
+
...job.input !== void 0 ? { input: job.input } : {}
|
|
97
124
|
}))
|
|
98
125
|
};
|
|
99
126
|
}
|
|
@@ -163,14 +190,161 @@ function isCronRequestAuthorized(request, options = {}) {
|
|
|
163
190
|
const headerSecret = request.headers.get("x-farm-cron-secret") || "";
|
|
164
191
|
return farmSecretsMatch(bearer, secret) || farmSecretsMatch(headerSecret, secret);
|
|
165
192
|
}
|
|
193
|
+
var inFlightCronRuns = /* @__PURE__ */ new Set();
|
|
194
|
+
function resolveCronRunControls(options) {
|
|
195
|
+
if (options.timeoutMs !== void 0 && (typeof options.timeoutMs !== "number" || !Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0)) {
|
|
196
|
+
throw new TypeError(
|
|
197
|
+
`Farm cron \`timeoutMs\` must be a positive number of milliseconds; received ${JSON.stringify(options.timeoutMs)}. Remove the option or set a positive number.`
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
if (options.overlap !== void 0 && options.overlap !== "skip") {
|
|
201
|
+
throw new TypeError(
|
|
202
|
+
`Farm cron \`overlap\` only supports "skip"; received ${JSON.stringify(options.overlap)}. Remove the option to allow overlapping runs.`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
timeoutMs: options.timeoutMs,
|
|
207
|
+
// A fresh object is this route's identity, so unnamed routes never skip each other.
|
|
208
|
+
overlapKey: options.overlap === "skip" ? options.name ?? {} : void 0
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function cronSkippedResponse() {
|
|
212
|
+
return Response.json({ skipped: true }, { status: 409 });
|
|
213
|
+
}
|
|
214
|
+
function cronTimeoutResponse(timeoutMs) {
|
|
215
|
+
return Response.json(
|
|
216
|
+
{
|
|
217
|
+
error: `The cron handler did not finish within its \`timeoutMs\` of ${timeoutMs} milliseconds. Raise \`timeoutMs\` or make the handler finish sooner.`
|
|
218
|
+
},
|
|
219
|
+
{ status: 504 }
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
function isThenable(value) {
|
|
223
|
+
return !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
|
224
|
+
}
|
|
225
|
+
function runCronRouteControlled(controls, controller, run, onSkip, onTimeout) {
|
|
226
|
+
const { overlapKey, timeoutMs } = controls;
|
|
227
|
+
if (overlapKey !== void 0) {
|
|
228
|
+
if (inFlightCronRuns.has(overlapKey)) return onSkip();
|
|
229
|
+
inFlightCronRuns.add(overlapKey);
|
|
230
|
+
}
|
|
231
|
+
const release = () => {
|
|
232
|
+
if (overlapKey !== void 0) inFlightCronRuns.delete(overlapKey);
|
|
233
|
+
};
|
|
234
|
+
let outcome;
|
|
235
|
+
try {
|
|
236
|
+
outcome = run();
|
|
237
|
+
} catch (error) {
|
|
238
|
+
release();
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
if (!isThenable(outcome)) {
|
|
242
|
+
release();
|
|
243
|
+
return outcome;
|
|
244
|
+
}
|
|
245
|
+
const pending = Promise.resolve(outcome);
|
|
246
|
+
if (timeoutMs === void 0) return pending.finally(release);
|
|
247
|
+
return new Promise((resolve, reject) => {
|
|
248
|
+
const timer = setTimeout(() => {
|
|
249
|
+
controller?.abort(
|
|
250
|
+
new Error(
|
|
251
|
+
`The cron handler did not finish within its \`timeoutMs\` of ${timeoutMs} milliseconds.`
|
|
252
|
+
)
|
|
253
|
+
);
|
|
254
|
+
resolve(onTimeout());
|
|
255
|
+
}, timeoutMs);
|
|
256
|
+
pending.then(
|
|
257
|
+
(value) => {
|
|
258
|
+
clearTimeout(timer);
|
|
259
|
+
release();
|
|
260
|
+
resolve(value);
|
|
261
|
+
},
|
|
262
|
+
(error) => {
|
|
263
|
+
clearTimeout(timer);
|
|
264
|
+
release();
|
|
265
|
+
reject(error);
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
function createFarmCronRequestContext(request, options, signal) {
|
|
271
|
+
const name = request.headers.get("x-farm-cron-name") || void 0;
|
|
272
|
+
const scheduledAtHeader = request.headers.get("x-farm-cron-scheduled-at")?.trim() || "";
|
|
273
|
+
const scheduledAtMs = /^\d+$/.test(scheduledAtHeader) ? Number(scheduledAtHeader) : Number.NaN;
|
|
274
|
+
const scheduledAt = Number.isSafeInteger(scheduledAtMs) ? new Date(scheduledAtMs) : void 0;
|
|
275
|
+
return {
|
|
276
|
+
...name !== void 0 ? { name } : {},
|
|
277
|
+
...scheduledAt !== void 0 ? { scheduledAt } : {},
|
|
278
|
+
input: options.input,
|
|
279
|
+
signal
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
var FARM_CRON_SIGNATURE_HEADER = "farmjs-signature";
|
|
283
|
+
var CRON_SIGNATURE_VERSION = "farmjs-cron-v1";
|
|
284
|
+
var CRON_SIGNATURE_WINDOW_SECONDS = 300;
|
|
285
|
+
var CRON_SIGNATURE_PATTERN = /^t=(\d{1,12}),v1=([0-9a-f]{64})$/;
|
|
286
|
+
function toHex(buffer) {
|
|
287
|
+
let hex = "";
|
|
288
|
+
for (const byte of new Uint8Array(buffer)) hex += byte.toString(16).padStart(2, "0");
|
|
289
|
+
return hex;
|
|
290
|
+
}
|
|
291
|
+
async function farmCronSignature(apiKey, t, pathname) {
|
|
292
|
+
const encoder = new TextEncoder();
|
|
293
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", encoder.encode(apiKey));
|
|
294
|
+
const key = await globalThis.crypto.subtle.importKey(
|
|
295
|
+
"raw",
|
|
296
|
+
encoder.encode(toHex(digest)),
|
|
297
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
298
|
+
false,
|
|
299
|
+
["sign"]
|
|
300
|
+
);
|
|
301
|
+
const mac = await globalThis.crypto.subtle.sign(
|
|
302
|
+
"HMAC",
|
|
303
|
+
key,
|
|
304
|
+
encoder.encode(`${CRON_SIGNATURE_VERSION}
|
|
305
|
+
${t}
|
|
306
|
+
GET ${pathname}`)
|
|
307
|
+
);
|
|
308
|
+
return toHex(mac);
|
|
309
|
+
}
|
|
310
|
+
async function authorizeCronRequest(request, options = {}, now = Date.now()) {
|
|
311
|
+
if (isCronRequestAuthorized(request, options)) return true;
|
|
312
|
+
const header = request.headers.get(FARM_CRON_SIGNATURE_HEADER);
|
|
313
|
+
if (!header) return false;
|
|
314
|
+
if (typeof request.method !== "string" || request.method.toUpperCase() !== "GET") return false;
|
|
315
|
+
if (typeof request.url !== "string") return false;
|
|
316
|
+
const parsed = CRON_SIGNATURE_PATTERN.exec(header.trim());
|
|
317
|
+
if (!parsed) return false;
|
|
318
|
+
const t = Number(parsed[1]);
|
|
319
|
+
if (Math.abs(now / 1e3 - t) > CRON_SIGNATURE_WINDOW_SECONDS) return false;
|
|
320
|
+
const apiKey = readFarmEnvironmentValue("FARMJS_API_KEY");
|
|
321
|
+
if (!apiKey) return false;
|
|
322
|
+
let pathname;
|
|
323
|
+
try {
|
|
324
|
+
const url = new URL(request.url);
|
|
325
|
+
if (url.search) return false;
|
|
326
|
+
pathname = url.pathname;
|
|
327
|
+
} catch {
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
const expected = await farmCronSignature(apiKey, t, pathname);
|
|
331
|
+
return farmSecretsMatch(parsed[2], expected);
|
|
332
|
+
}
|
|
166
333
|
function cronRoute(handler, options = {}) {
|
|
167
|
-
|
|
334
|
+
const controls = resolveCronRunControls(options);
|
|
335
|
+
if (isFarmEndpoint(handler)) return guardCronEndpoint(handler, options, controls);
|
|
168
336
|
const route = handler;
|
|
169
|
-
return (request, ...args) => {
|
|
170
|
-
if (!
|
|
171
|
-
return
|
|
337
|
+
return async (request, ...args) => {
|
|
338
|
+
if (!await authorizeCronRequest(request, options)) {
|
|
339
|
+
return unauthorizedCronResponse();
|
|
172
340
|
}
|
|
173
|
-
return
|
|
341
|
+
return runCronRouteControlled(
|
|
342
|
+
controls,
|
|
343
|
+
void 0,
|
|
344
|
+
() => route(request, ...args),
|
|
345
|
+
cronSkippedResponse,
|
|
346
|
+
() => cronTimeoutResponse(controls.timeoutMs)
|
|
347
|
+
);
|
|
174
348
|
};
|
|
175
349
|
}
|
|
176
350
|
function unauthorizedCronResponse() {
|
|
@@ -180,32 +354,76 @@ function isFarmEndpoint(value) {
|
|
|
180
354
|
return typeof value === "function" && typeof value.__handler === "function";
|
|
181
355
|
}
|
|
182
356
|
var FUNCTION_OWN_KEYS = /* @__PURE__ */ new Set(["length", "name", "prototype", "arguments", "caller"]);
|
|
183
|
-
function guardCronEndpoint(endpoint, options) {
|
|
184
|
-
const allowed = (context) => {
|
|
357
|
+
function guardCronEndpoint(endpoint, options, controls) {
|
|
358
|
+
const allowed = async (context) => {
|
|
185
359
|
const request = context?.request;
|
|
186
|
-
|
|
360
|
+
if (typeof request?.headers?.get !== "function") return false;
|
|
361
|
+
return authorizeCronRequest(request, options);
|
|
187
362
|
};
|
|
188
|
-
const
|
|
189
|
-
|
|
363
|
+
const withCron = (context) => {
|
|
364
|
+
const controller = new AbortController();
|
|
365
|
+
const cron = createFarmCronRequestContext(
|
|
366
|
+
context.request,
|
|
367
|
+
options,
|
|
368
|
+
controller.signal
|
|
369
|
+
);
|
|
370
|
+
const invocation = {
|
|
371
|
+
...context,
|
|
372
|
+
context: { ...context.context, cron }
|
|
373
|
+
};
|
|
374
|
+
return { controller, invocation };
|
|
375
|
+
};
|
|
376
|
+
const guarded = async function(context) {
|
|
377
|
+
if (!await allowed(context)) return unauthorizedCronResponse();
|
|
378
|
+
const { controller, invocation } = withCron(context);
|
|
379
|
+
return runCronRouteControlled(
|
|
380
|
+
controls,
|
|
381
|
+
controller,
|
|
382
|
+
() => endpoint.call(this, invocation),
|
|
383
|
+
cronSkippedResponse,
|
|
384
|
+
() => cronTimeoutResponse(controls.timeoutMs)
|
|
385
|
+
);
|
|
190
386
|
};
|
|
191
387
|
for (const key of Reflect.ownKeys(endpoint)) {
|
|
192
388
|
if (typeof key === "string" && FUNCTION_OWN_KEYS.has(key)) continue;
|
|
193
389
|
Object.defineProperty(guarded, key, Object.getOwnPropertyDescriptor(endpoint, key));
|
|
194
390
|
}
|
|
195
|
-
guarded.__handler = (context) =>
|
|
391
|
+
guarded.__handler = async (context) => {
|
|
392
|
+
if (!await allowed(context)) return unauthorizedCronResponse();
|
|
393
|
+
const { controller, invocation } = withCron(context);
|
|
394
|
+
return runCronRouteControlled(
|
|
395
|
+
controls,
|
|
396
|
+
controller,
|
|
397
|
+
() => endpoint.__handler(invocation),
|
|
398
|
+
cronSkippedResponse,
|
|
399
|
+
() => cronTimeoutResponse(controls.timeoutMs)
|
|
400
|
+
);
|
|
401
|
+
};
|
|
196
402
|
const invoke = endpoint.__farmInvoke;
|
|
197
403
|
if (invoke) {
|
|
198
|
-
guarded.__farmInvoke = (context) =>
|
|
199
|
-
result
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
404
|
+
guarded.__farmInvoke = async (context) => {
|
|
405
|
+
const denied = (result) => ({
|
|
406
|
+
result,
|
|
407
|
+
context: context.context,
|
|
408
|
+
handlerExecuted: false,
|
|
409
|
+
invalidations: []
|
|
410
|
+
});
|
|
411
|
+
if (!await allowed(context)) return denied(unauthorizedCronResponse());
|
|
412
|
+
const { controller, invocation } = withCron(context);
|
|
413
|
+
return runCronRouteControlled(
|
|
414
|
+
controls,
|
|
415
|
+
controller,
|
|
416
|
+
() => invoke(invocation),
|
|
417
|
+
() => denied(cronSkippedResponse()),
|
|
418
|
+
() => denied(cronTimeoutResponse(controls.timeoutMs))
|
|
419
|
+
);
|
|
203
420
|
};
|
|
204
421
|
}
|
|
205
422
|
return guarded;
|
|
206
423
|
}
|
|
424
|
+
var FARM_CRON_NAME_SEGMENT_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
207
425
|
function normalizeCronJob(name, job) {
|
|
208
|
-
if (
|
|
426
|
+
if (!FARM_CRON_NAME_SEGMENT_PATTERN.test(name)) {
|
|
209
427
|
throw new TypeError(
|
|
210
428
|
`Farm cron name ${JSON.stringify(name)} must start with a letter or number and contain only letters, numbers, dots, underscores, or hyphens.`
|
|
211
429
|
);
|
|
@@ -433,5 +651,10 @@ export {
|
|
|
433
651
|
createFarmCronCloudflareConfig,
|
|
434
652
|
mergeScheduledTasks,
|
|
435
653
|
isCronRequestAuthorized,
|
|
436
|
-
|
|
654
|
+
FARM_CRON_SIGNATURE_HEADER,
|
|
655
|
+
farmCronSignature,
|
|
656
|
+
authorizeCronRequest,
|
|
657
|
+
cronRoute,
|
|
658
|
+
FARM_CRON_NAME_SEGMENT_PATTERN,
|
|
659
|
+
normalizeCronExpression
|
|
437
660
|
};
|