diff --git a/package.json b/package.json index e50c32cdfb..38a9ef4b60 100644 --- a/package.json +++ b/package.json @@ -168,7 +168,8 @@ "wrangler": "^4.68.1", "xml2js": "^0.6.2", "youch": "^4.1.0", - "youch-core": "^0.3.3" + "youch-core": "^0.3.3", + "zephyr-agent": "^0.1.13" }, "peerDependencies": { "dotenv": "*", @@ -176,7 +177,8 @@ "jiti": "^2.6.1", "rollup": "^4.59.0", "vite": "^7 || ^8 || >=8.0.0-0", - "xml2js": "^0.6.2" + "xml2js": "^0.6.2", + "zephyr-agent": "*" }, "peerDependenciesMeta": { "dotenv": { @@ -196,6 +198,9 @@ }, "jiti": { "optional": true + }, + "zephyr-agent": { + "optional": true } }, "resolutions": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 59e865b9c8..4cece77372 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -97,7 +97,7 @@ importers: version: 6.0.3(rollup@4.59.0) '@scalar/api-reference': specifier: ^1.44.26 - version: 1.44.26(axios@1.13.5)(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3) + version: 1.44.26(axios@1.13.5(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3) '@types/aws-lambda': specifier: ^8.10.160 version: 8.10.160 @@ -320,6 +320,9 @@ importers: youch-core: specifier: ^0.3.3 version: 0.3.3 + zephyr-agent: + specifier: ^0.1.13 + version: 0.1.13(https-proxy-agent@7.0.6) examples/api-routes: devDependencies: @@ -2675,6 +2678,9 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@toon-format/toon@0.9.0': + resolution: {integrity: sha512-BaMhGh1+/z8ceDrF2xL9Drd42hijbUJlivm/1goPR26RgCYsqlMkHbg48hx9a5UjZC7oZqxWPJ6ju5qvALi6Ag==} + '@trpc/client@11.10.0': resolution: {integrity: sha512-h0s2AwDtuhS8INRb4hlo4z3RKCkarWqlOy+3ffJgrlDxzzW6aLUN+9nDrcN4huPje1Em15tbCOqhIc6oaKYTRw==} peerDependencies: @@ -3178,6 +3184,11 @@ packages: avvio@9.2.0: resolution: {integrity: sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ==} + axios-retry@4.5.0: + resolution: {integrity: sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==} + peerDependencies: + axios: 0.x || 1.x + axios@1.13.5: resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} @@ -3369,6 +3380,10 @@ packages: chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} @@ -3873,6 +3888,10 @@ packages: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} engines: {node: '>=18.0.0'} + eventsource@4.1.0: + resolution: {integrity: sha512-2GuF51iuHX6A9xdTccMTsNb7VO0lHZihApxhvQzJB5A03DvHDd2FQepodbMaztPBmBcE/ox7o2gqaxGhYB9LhQ==} + engines: {node: '>=20.0.0'} + exact-mirror@0.2.7: resolution: {integrity: sha512-+MeEmDcLA4o/vjK2zujgk+1VTxPR4hdp23qLqkWfStbECtAq9gmsvQa3LW6z/0GXZyHJobrCnmy1cdeE7BjsYg==} peerDependencies: @@ -4083,6 +4102,12 @@ packages: resolution: {integrity: sha512-T2qUpKBHeUTwHcIhydgnJzhL0Hj785ms+JkxaaWQH9SDM/llXeewnOkfJcFShAHjWI+26hOChwUfCoupaXLm8g==} hasBin: true + git-up@7.0.0: + resolution: {integrity: sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==} + + git-url-parse@15.0.0: + resolution: {integrity: sha512-5reeBufLi+i4QD3ZFftcJs9jC26aULFLBU23FeKM/b1rI0K6ofIeAblmDVO7Ht22zTDE9+CkJ3ZVb0CgJmz3UQ==} + github-from-package@0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} @@ -4325,6 +4350,10 @@ packages: is-buffer@1.1.6: resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + is-ci@4.1.0: + resolution: {integrity: sha512-Ab9bQDQ11lWootZUI5qxgN2ZXwxNI5hTwnsvOc1wyxQ7zQ8OkEDw79mI0+9jI3x432NfwbVRru+3noJfXF6lSQ==} + hasBin: true + is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} @@ -4413,6 +4442,13 @@ packages: resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==} engines: {node: '>=12'} + is-retry-allowed@2.2.0: + resolution: {integrity: sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==} + engines: {node: '>=10'} + + is-ssh@1.4.1: + resolution: {integrity: sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==} + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -4473,6 +4509,9 @@ packages: joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} + jose@5.10.0: + resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} + jose@6.1.3: resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} @@ -5021,6 +5060,10 @@ packages: node-html-parser@6.1.13: resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} + node-persist@4.0.4: + resolution: {integrity: sha512-8sPAz/7tw1mCCc8xBG4f0wi+flHkSSgQeX998iQ75Pu27evA6UUWCjSE7xnrYTg2q33oU5leJ061EKPDv6BocQ==} + engines: {node: '>=10.12.0'} + node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} @@ -5137,6 +5180,10 @@ packages: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + p-timeout@3.2.0: resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} engines: {node: '>=8'} @@ -5164,6 +5211,12 @@ packages: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} + parse-path@7.1.0: + resolution: {integrity: sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==} + + parse-url@8.1.0: + resolution: {integrity: sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==} + parse5-htmlparser2-tree-adapter@7.1.0: resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} @@ -5290,12 +5343,18 @@ packages: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + protocols@2.0.2: + resolution: {integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -5473,6 +5532,10 @@ packages: resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==} engines: {node: '>=10'} + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -6535,6 +6598,10 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + yoctocolors@2.1.2: resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} engines: {node: '>=18'} @@ -6548,6 +6615,14 @@ packages: youch@4.1.0-beta.10: resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} + zephyr-agent@0.1.13: + resolution: {integrity: sha512-M6c0RlLXw4Asup8+RMoze9P9o8Oi5W9jX29bFLJbqschd0Bxzgh3RA8h+hFYB53E4hANVhJXegdyKAaAD/S8QA==} + peerDependencies: + https-proxy-agent: ^7.0.6 + + zephyr-edge-contract@0.1.13: + resolution: {integrity: sha512-S3vauLHCc45wACTP+8SxqFS5RyL9VqA0ETi0bzVdXj/XEvfpDqQqLauF0XDOxdHH/I8ZwCaL0egEv2pMqoRBug==} + zimmerframe@1.1.4: resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} @@ -7927,10 +8002,10 @@ snapshots: '@sagold/json-pointer': 5.1.2 ebnf: 1.9.1 - '@scalar/agent-chat@0.5.17(axios@1.13.5)(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3)': + '@scalar/agent-chat@0.5.17(axios@1.13.5(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3)': dependencies: '@ai-sdk/vue': 3.0.33(vue@3.5.28(typescript@5.9.3))(zod@4.3.6) - '@scalar/api-client': 2.29.3(axios@1.13.5)(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3) + '@scalar/api-client': 2.29.3(axios@1.13.5(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3) '@scalar/components': 0.19.9(typescript@5.9.3) '@scalar/helpers': 0.2.16 '@scalar/icons': 0.5.3(typescript@5.9.3) @@ -7967,7 +8042,7 @@ snapshots: dependencies: zod: 4.3.6 - '@scalar/api-client@2.29.3(axios@1.13.5)(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3)': + '@scalar/api-client@2.29.3(axios@1.13.5(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3)': dependencies: '@headlessui/tailwindcss': 0.2.2(tailwindcss@4.2.0) '@headlessui/vue': 1.7.23(vue@3.5.28(typescript@5.9.3)) @@ -7994,7 +8069,7 @@ snapshots: '@scalar/workspace-store': 0.34.3(typescript@5.9.3) '@types/har-format': 1.2.16 '@vueuse/core': 13.9.0(vue@3.5.28(typescript@5.9.3)) - '@vueuse/integrations': 13.9.0(axios@1.13.5)(focus-trap@7.8.0)(fuse.js@7.1.0)(jwt-decode@4.0.0)(vue@3.5.28(typescript@5.9.3)) + '@vueuse/integrations': 13.9.0(axios@1.13.5(debug@4.4.3))(focus-trap@7.8.0)(fuse.js@7.1.0)(jwt-decode@4.0.0)(vue@3.5.28(typescript@5.9.3)) focus-trap: 7.8.0 fuse.js: 7.1.0 js-base64: 3.7.8 @@ -8025,11 +8100,11 @@ snapshots: - typescript - universal-cookie - '@scalar/api-reference@1.44.26(axios@1.13.5)(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3)': + '@scalar/api-reference@1.44.26(axios@1.13.5(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3)': dependencies: '@headlessui/vue': 1.7.23(vue@3.5.28(typescript@5.9.3)) - '@scalar/agent-chat': 0.5.17(axios@1.13.5)(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3) - '@scalar/api-client': 2.29.3(axios@1.13.5)(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3) + '@scalar/agent-chat': 0.5.17(axios@1.13.5(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3) + '@scalar/api-client': 2.29.3(axios@1.13.5(debug@4.4.3))(jwt-decode@4.0.0)(tailwindcss@4.2.0)(typescript@5.9.3) '@scalar/code-highlight': 0.2.4 '@scalar/components': 0.19.9(typescript@5.9.3) '@scalar/helpers': 0.2.16 @@ -8628,6 +8703,8 @@ snapshots: '@tokenizer/token@0.3.0': {} + '@toon-format/toon@0.9.0': {} + '@trpc/client@11.10.0(@trpc/server@11.10.0(typescript@5.9.3))(typescript@5.9.3)': dependencies: '@trpc/server': 11.10.0(typescript@5.9.3) @@ -9023,13 +9100,13 @@ snapshots: '@vueuse/shared': 13.9.0(vue@3.5.28(typescript@5.9.3)) vue: 3.5.28(typescript@5.9.3) - '@vueuse/integrations@13.9.0(axios@1.13.5)(focus-trap@7.8.0)(fuse.js@7.1.0)(jwt-decode@4.0.0)(vue@3.5.28(typescript@5.9.3))': + '@vueuse/integrations@13.9.0(axios@1.13.5(debug@4.4.3))(focus-trap@7.8.0)(fuse.js@7.1.0)(jwt-decode@4.0.0)(vue@3.5.28(typescript@5.9.3))': dependencies: '@vueuse/core': 13.9.0(vue@3.5.28(typescript@5.9.3)) '@vueuse/shared': 13.9.0(vue@3.5.28(typescript@5.9.3)) vue: 3.5.28(typescript@5.9.3) optionalDependencies: - axios: 1.13.5 + axios: 1.13.5(debug@4.4.3) focus-trap: 7.8.0 fuse.js: 7.1.0 jwt-decode: 4.0.0 @@ -9176,9 +9253,14 @@ snapshots: '@fastify/error': 4.2.0 fastq: 1.20.1 - axios@1.13.5: + axios-retry@4.5.0(axios@1.13.5(debug@4.4.3)): dependencies: - follow-redirects: 1.15.11 + axios: 1.13.5(debug@4.4.3) + is-retry-allowed: 2.2.0 + + axios@1.13.5(debug@4.4.3): + dependencies: + follow-redirects: 1.15.11(debug@4.4.3) form-data: 4.0.5 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -9424,6 +9506,8 @@ snapshots: chownr@1.1.4: {} + ci-info@4.4.0: {} + citty@0.1.6: dependencies: consola: 3.4.2 @@ -9855,6 +9939,10 @@ snapshots: eventsource-parser@3.0.6: {} + eventsource@4.1.0: + dependencies: + eventsource-parser: 3.0.6 + exact-mirror@0.2.7(@sinclair/typebox@0.34.48): optionalDependencies: '@sinclair/typebox': 0.34.48 @@ -10028,7 +10116,9 @@ snapshots: dependencies: tabbable: 6.4.0 - follow-redirects@1.15.11: {} + follow-redirects@1.15.11(debug@4.4.3): + optionalDependencies: + debug: 4.4.3 foreground-child@3.3.1: dependencies: @@ -10122,6 +10212,15 @@ snapshots: giget@3.1.2: {} + git-up@7.0.0: + dependencies: + is-ssh: 1.4.1 + parse-url: 8.1.0 + + git-url-parse@15.0.0: + dependencies: + git-up: 7.0.0 + github-from-package@0.0.0: {} github-slugger@2.0.0: {} @@ -10364,7 +10463,7 @@ snapshots: http-proxy@1.18.1: dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.11 + follow-redirects: 1.15.11(debug@4.4.3) requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -10428,6 +10527,10 @@ snapshots: is-buffer@1.1.6: {} + is-ci@4.1.0: + dependencies: + ci-info: 4.4.0 + is-core-module@2.16.1: dependencies: hasown: 2.0.2 @@ -10490,6 +10593,12 @@ snapshots: is-regexp@3.1.0: {} + is-retry-allowed@2.2.0: {} + + is-ssh@1.4.1: + dependencies: + protocols: 2.0.2 + is-stream@2.0.1: {} is-stream@4.0.1: {} @@ -10545,6 +10654,8 @@ snapshots: '@sideway/formula': 3.0.1 '@sideway/pinpoint': 2.0.0 + jose@5.10.0: {} + jose@6.1.3: {} js-base64@3.7.8: {} @@ -11214,6 +11325,10 @@ snapshots: css-select: 5.2.2 he: 1.2.0 + node-persist@4.0.4: + dependencies: + p-limit: 3.1.0 + node-releases@2.0.27: {} normalize-path@3.0.0: {} @@ -11392,6 +11507,10 @@ snapshots: p-finally@1.0.0: {} + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + p-timeout@3.2.0: dependencies: p-finally: 1.0.0 @@ -11413,6 +11532,14 @@ snapshots: parse-ms@4.0.0: {} + parse-path@7.1.0: + dependencies: + protocols: 2.0.2 + + parse-url@8.1.0: + dependencies: + parse-path: 7.1.0 + parse5-htmlparser2-tree-adapter@7.1.0: dependencies: domhandler: 5.0.3 @@ -11553,10 +11680,18 @@ snapshots: kleur: 3.0.3 sisteransi: 1.0.5 + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + property-information@7.1.0: {} proto-list@1.2.4: {} + protocols@2.0.2: {} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -11782,6 +11917,8 @@ snapshots: ret@0.5.0: {} + retry@0.12.0: {} + reusify@1.1.0: {} rfdc@1.4.1: {} @@ -12710,7 +12847,7 @@ snapshots: wait-on@7.2.0: dependencies: - axios: 1.13.5 + axios: 1.13.5(debug@4.4.3) joi: 17.13.3 lodash: 4.17.23 minimist: 1.2.8 @@ -12841,6 +12978,8 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yocto-queue@0.1.0: {} + yoctocolors@2.1.2: {} youch-core@0.3.3: @@ -12864,6 +13003,29 @@ snapshots: cookie: 1.1.1 youch-core: 0.3.3 + zephyr-agent@0.1.13(https-proxy-agent@7.0.6): + dependencies: + '@toon-format/toon': 0.9.0 + axios: 1.13.5(debug@4.4.3) + axios-retry: 4.5.0(axios@1.13.5(debug@4.4.3)) + debug: 4.4.3 + eventsource: 4.1.0 + git-url-parse: 15.0.0 + https-proxy-agent: 7.0.6 + is-ci: 4.1.0 + jose: 5.10.0 + node-persist: 4.0.4 + open: 10.2.0 + proper-lockfile: 4.1.2 + tslib: 2.8.1 + zephyr-edge-contract: 0.1.13 + transitivePeerDependencies: + - supports-color + + zephyr-edge-contract@0.1.13: + dependencies: + tslib: 2.8.1 + zimmerframe@1.1.4: {} zod@3.25.76: {} diff --git a/src/presets/_all.gen.ts b/src/presets/_all.gen.ts index 0aabd48fde..18730bb704 100644 --- a/src/presets/_all.gen.ts +++ b/src/presets/_all.gen.ts @@ -26,6 +26,7 @@ import _stormkit from "./stormkit/preset.ts"; import _vercel from "./vercel/preset.ts"; import _winterjs from "./winterjs/preset.ts"; import _zeabur from "./zeabur/preset.ts"; +import _zephyr from "./zephyr/preset.ts"; import _zerops from "./zerops/preset.ts"; export default [ @@ -55,5 +56,6 @@ export default [ ..._vercel, ..._winterjs, ..._zeabur, + ..._zephyr, ..._zerops, ] as const; diff --git a/src/presets/_types.gen.ts b/src/presets/_types.gen.ts index 974925a21a..b88572846f 100644 --- a/src/presets/_types.gen.ts +++ b/src/presets/_types.gen.ts @@ -20,6 +20,6 @@ export interface PresetOptions { export const presetsWithConfig = ["awsAmplify","awsLambda","azure","cloudflare","firebase","netlify","vercel"] as const; -export type PresetName = "alwaysdata" | "aws-amplify" | "aws-lambda" | "azure-swa" | "base-worker" | "bun" | "cleavr" | "cloudflare-dev" | "cloudflare-durable" | "cloudflare-module" | "cloudflare-pages" | "cloudflare-pages-static" | "deno" | "deno-deploy" | "deno-server" | "digital-ocean" | "firebase-app-hosting" | "flight-control" | "genezio" | "github-pages" | "gitlab-pages" | "heroku" | "iis-handler" | "iis-node" | "koyeb" | "netlify" | "netlify-edge" | "netlify-static" | "nitro-dev" | "nitro-prerender" | "node" | "node-cluster" | "node-middleware" | "node-server" | "platform-sh" | "render-com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "winterjs" | "zeabur" | "zeabur-static" | "zerops" | "zerops-static"; +export type PresetName = "alwaysdata" | "aws-amplify" | "aws-lambda" | "azure-swa" | "base-worker" | "bun" | "cleavr" | "cloudflare-dev" | "cloudflare-durable" | "cloudflare-module" | "cloudflare-pages" | "cloudflare-pages-static" | "deno" | "deno-deploy" | "deno-server" | "digital-ocean" | "firebase-app-hosting" | "flight-control" | "genezio" | "github-pages" | "gitlab-pages" | "heroku" | "iis-handler" | "iis-node" | "koyeb" | "netlify" | "netlify-edge" | "netlify-static" | "nitro-dev" | "nitro-prerender" | "node" | "node-cluster" | "node-middleware" | "node-server" | "platform-sh" | "render-com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "winterjs" | "zeabur" | "zeabur-static" | "zephyr" | "zerops" | "zerops-static"; -export type PresetNameInput = "alwaysdata" | "aws-amplify" | "awsAmplify" | "aws_amplify" | "aws-lambda" | "awsLambda" | "aws_lambda" | "azure-swa" | "azureSwa" | "azure_swa" | "base-worker" | "baseWorker" | "base_worker" | "bun" | "cleavr" | "cloudflare-dev" | "cloudflareDev" | "cloudflare_dev" | "cloudflare-durable" | "cloudflareDurable" | "cloudflare_durable" | "cloudflare-module" | "cloudflareModule" | "cloudflare_module" | "cloudflare-pages" | "cloudflarePages" | "cloudflare_pages" | "cloudflare-pages-static" | "cloudflarePagesStatic" | "cloudflare_pages_static" | "deno" | "deno-deploy" | "denoDeploy" | "deno_deploy" | "deno-server" | "denoServer" | "deno_server" | "digital-ocean" | "digitalOcean" | "digital_ocean" | "firebase-app-hosting" | "firebaseAppHosting" | "firebase_app_hosting" | "flight-control" | "flightControl" | "flight_control" | "genezio" | "github-pages" | "githubPages" | "github_pages" | "gitlab-pages" | "gitlabPages" | "gitlab_pages" | "heroku" | "iis-handler" | "iisHandler" | "iis_handler" | "iis-node" | "iisNode" | "iis_node" | "koyeb" | "netlify" | "netlify-edge" | "netlifyEdge" | "netlify_edge" | "netlify-static" | "netlifyStatic" | "netlify_static" | "nitro-dev" | "nitroDev" | "nitro_dev" | "nitro-prerender" | "nitroPrerender" | "nitro_prerender" | "node" | "node-cluster" | "nodeCluster" | "node_cluster" | "node-middleware" | "nodeMiddleware" | "node_middleware" | "node-server" | "nodeServer" | "node_server" | "platform-sh" | "platformSh" | "platform_sh" | "render-com" | "renderCom" | "render_com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "vercelStatic" | "vercel_static" | "winterjs" | "zeabur" | "zeabur-static" | "zeaburStatic" | "zeabur_static" | "zerops" | "zerops-static" | "zeropsStatic" | "zerops_static" | (string & {}); +export type PresetNameInput = "alwaysdata" | "aws-amplify" | "awsAmplify" | "aws_amplify" | "aws-lambda" | "awsLambda" | "aws_lambda" | "azure-swa" | "azureSwa" | "azure_swa" | "base-worker" | "baseWorker" | "base_worker" | "bun" | "cleavr" | "cloudflare-dev" | "cloudflareDev" | "cloudflare_dev" | "cloudflare-durable" | "cloudflareDurable" | "cloudflare_durable" | "cloudflare-module" | "cloudflareModule" | "cloudflare_module" | "cloudflare-pages" | "cloudflarePages" | "cloudflare_pages" | "cloudflare-pages-static" | "cloudflarePagesStatic" | "cloudflare_pages_static" | "deno" | "deno-deploy" | "denoDeploy" | "deno_deploy" | "deno-server" | "denoServer" | "deno_server" | "digital-ocean" | "digitalOcean" | "digital_ocean" | "firebase-app-hosting" | "firebaseAppHosting" | "firebase_app_hosting" | "flight-control" | "flightControl" | "flight_control" | "genezio" | "github-pages" | "githubPages" | "github_pages" | "gitlab-pages" | "gitlabPages" | "gitlab_pages" | "heroku" | "iis-handler" | "iisHandler" | "iis_handler" | "iis-node" | "iisNode" | "iis_node" | "koyeb" | "netlify" | "netlify-edge" | "netlifyEdge" | "netlify_edge" | "netlify-static" | "netlifyStatic" | "netlify_static" | "nitro-dev" | "nitroDev" | "nitro_dev" | "nitro-prerender" | "nitroPrerender" | "nitro_prerender" | "node" | "node-cluster" | "nodeCluster" | "node_cluster" | "node-middleware" | "nodeMiddleware" | "node_middleware" | "node-server" | "nodeServer" | "node_server" | "platform-sh" | "platformSh" | "platform_sh" | "render-com" | "renderCom" | "render_com" | "standard" | "static" | "stormkit" | "vercel" | "vercel-static" | "vercelStatic" | "vercel_static" | "winterjs" | "zeabur" | "zeabur-static" | "zeaburStatic" | "zeabur_static" | "zephyr" | "zerops" | "zerops-static" | "zeropsStatic" | "zerops_static" | (string & {}); diff --git a/src/presets/zephyr/preset.ts b/src/presets/zephyr/preset.ts new file mode 100644 index 0000000000..81e389ccc9 --- /dev/null +++ b/src/presets/zephyr/preset.ts @@ -0,0 +1,54 @@ +import { defineNitroPreset } from "../_utils/preset.ts"; +import type { Nitro } from "nitro/types"; +import { unenvCfExternals, unenvCfNodeCompat } from "../cloudflare/unenv/preset.ts"; +import { LOGGER_TAG, uploadNitroOutputToZephyr } from "./utils.ts"; +import { resolve } from "pathe"; + +const zephyr = defineNitroPreset( + { + extends: "base-worker", + entry: "./zephyr/runtime/server", + output: { + publicDir: "{{ output.dir }}/client/{{ baseURL }}", + }, + exportConditions: ["node"], + minify: false, + rollupConfig: { + output: { + format: "esm", + exports: "named", + inlineDynamicImports: false, + }, + }, + wasm: { + lazy: false, + esmImport: true, + }, + hooks: { + "build:before": (nitro: Nitro) => { + nitro.options.unenv.push(unenvCfExternals, unenvCfNodeCompat); + }, + compiled: async (nitro: Nitro) => { + try { + await uploadNitroOutputToZephyr({ + rootDir: nitro.options.rootDir, + baseURL: nitro.options.baseURL, + outputDir: nitro.options.output.dir, + publicDir: resolve(nitro.options.output.dir, nitro.options.output.publicDir), + }); + nitro.logger.success(`[${LOGGER_TAG}] Zephyr deployment succeeded.`); + } catch (error) { + if (error instanceof Error) { + throw error; + } + throw new TypeError(`[${LOGGER_TAG}] ${String(error)}`); + } + }, + }, + }, + { + name: "zephyr" as const, + } +); + +export default [zephyr] as const; diff --git a/src/presets/zephyr/runtime/server.ts b/src/presets/zephyr/runtime/server.ts new file mode 100644 index 0000000000..91e3e309d9 --- /dev/null +++ b/src/presets/zephyr/runtime/server.ts @@ -0,0 +1,6 @@ +import "#nitro/virtual/polyfills"; +import { createHandler } from "../../cloudflare/runtime/_module-handler.ts"; + +export default createHandler({ + fetch() {}, +}); diff --git a/src/presets/zephyr/utils.ts b/src/presets/zephyr/utils.ts new file mode 100644 index 0000000000..6b819bb521 --- /dev/null +++ b/src/presets/zephyr/utils.ts @@ -0,0 +1,210 @@ +import { normalize } from "pathe"; +import { importDep } from "../../utils/dep.ts"; + +export const LOGGER_TAG = "zephyr-nitro-preset"; + +export type ZephyrProvider = "cloudflare" | (string & {}); + +const SUPPORTED_PROVIDERS = new Set(["cloudflare"]); + +const DEFAULT_DEPLOY_TARGET = "web"; +const DEFAULT_DEPLOY_SSR = true; +const SKIP_DEPLOY_PATTERNS = [/\.map$/i, /node_modules\//i, /\.git\//i, /\.DS_Store$/i]; +let pulledProvider: ZephyrProvider | undefined; + +interface DirectoryAsset { + content: Buffer; +} + +interface ZephyrEngineLike { + application_configuration: Promise<{ + PLATFORM?: string; + }>; + env: { + target: string; + ssr?: boolean; + }; + upload_assets: (props: { + assetsMap: Record; + buildStats: unknown; + snapshotType: "ssr" | "csr"; + entrypoint?: string; + hooks?: { + onDeployComplete?: (deploymentInfo: { url: string }) => void; + }; + }) => Promise; +} + +interface ZephyrAgentModule { + readDirRecursiveWithContents: ( + dirPath: string + ) => Promise>; + buildAssetsMap: ( + assets: Record, + extractBuffer: (asset: T) => Buffer | string | undefined, + getAssetType: (asset: T) => string + ) => Record; + zeBuildDashData: (engine: any) => Promise; + ZephyrEngine: { + create: (options: { builder: "unknown"; context: string }) => Promise; + }; +} + +function isZephyrProvider(provider: unknown): provider is ZephyrProvider { + return SUPPORTED_PROVIDERS.has(provider as string); +} + +function parsePulledProvider(platform: unknown): ZephyrProvider { + if (!isZephyrProvider(platform)) { + throw new TypeError( + `[${LOGGER_TAG}] Zephyr PLATFORM "${String(platform)}" is not supported yet by this Nitro preset. Supported today: cloudflare. See https://docs.zephyr-cloud.io` + ); + } + return platform; +} + +/** + * Strips leading `./` and `/`, trailing `/`, and normalizes backslashes to get a bare path segment. + */ +function normalizeBaseURL(baseURL: string): string { + let normalized = baseURL.trim().replace(/\\/g, "/"); + while (normalized.startsWith("./")) { + normalized = normalized.slice(2); + } + while (normalized.startsWith("/")) { + normalized = normalized.slice(1); + } + while (normalized.endsWith("/")) { + normalized = normalized.slice(0, -1); + } + return normalized; +} + +function resolveAssetPath( + file: { fullPath: string; relativePath: string }, + publicDir: string, + baseURL: string +): string { + const fullPath = normalize(file.fullPath); + const publicRoot = normalize(publicDir).replace(/\/+$/, ""); + if (fullPath.startsWith(`${publicRoot}/`)) { + const staticRelative = fullPath.slice(publicRoot.length + 1); + const basePath = normalizeBaseURL(baseURL); + return basePath ? `client/${basePath}/${staticRelative}` : `client/${staticRelative}`; + } + return normalize(file.relativePath); +} + +function resolveProvider(appPlatform: unknown): ZephyrProvider { + const pulled = parsePulledProvider(appPlatform); + if (!pulledProvider) { + pulledProvider = pulled; + } + if (pulledProvider !== pulled) { + throw new TypeError( + `[${LOGGER_TAG}] Zephyr PLATFORM changed from "${pulledProvider}" to "${pulled}" within the same process.` + ); + } + return pulledProvider; +} + +function shouldSkipDeployAsset(filePath: string): boolean { + return SKIP_DEPLOY_PATTERNS.some((pattern) => pattern.test(filePath)); +} + +function resolveDeployEntrypoint(assets: Record): string | undefined { + const candidates = [ + "server/index.js", + "server/index.mjs", + "server/server.js", + "server/server.mjs", + "server/_worker.js", + "server/_worker.mjs", + "index.mjs", + "index.js", + ]; + for (const candidate of candidates) { + if (Object.prototype.hasOwnProperty.call(assets, candidate)) { + return candidate; + } + } + + return undefined; +} + +export async function uploadNitroOutputToZephyr(opts: { + rootDir: string; + baseURL: string; + outputDir: string; + publicDir: string; +}): Promise<{ deploymentUrl: string | null; entrypoint?: string }> { + const zephyrAgent = await importDep({ + id: "zephyr-agent", + reason: "deploying to Zephyr", + dir: opts.rootDir, + }); + + const files = await zephyrAgent.readDirRecursiveWithContents(opts.outputDir); + + const assets = files.reduce>((memo, file) => { + const relativePath = resolveAssetPath(file, opts.publicDir, opts.baseURL); + if (shouldSkipDeployAsset(relativePath)) { + return memo; + } + + memo[relativePath] = { + content: file.content, + }; + return memo; + }, {}); + + if (Object.keys(assets).length === 0) { + throw new TypeError(`[${LOGGER_TAG}] No deployable assets found in ${opts.outputDir}.`); + } + + const entrypoint = resolveDeployEntrypoint(assets); + if (DEFAULT_DEPLOY_SSR && !entrypoint) { + throw new TypeError( + `[${LOGGER_TAG}] Could not detect SSR entrypoint in ${opts.outputDir}. Expected one of: server/index.js, server/index.mjs, server/server.js, server/server.mjs, server/_worker.js, server/_worker.mjs, index.mjs, index.js.` + ); + } + + const assetsMap = zephyrAgent.buildAssetsMap( + assets, + (asset: DirectoryAsset) => asset.content, + () => "buffer" + ); + + const zephyrEngine = await zephyrAgent.ZephyrEngine.create({ + builder: "unknown", + context: opts.rootDir || process.cwd(), + }); + + const appConfig = await zephyrEngine.application_configuration; + const provider = resolveProvider(appConfig?.PLATFORM); + if (provider !== "cloudflare") { + throw new TypeError( + `[${LOGGER_TAG}] Zephyr PLATFORM "${provider}" is not supported yet by this Nitro preset. Supported today: cloudflare. See https://docs.zephyr-cloud.io` + ); + } + + zephyrEngine.env.target = DEFAULT_DEPLOY_TARGET; + zephyrEngine.env.ssr = DEFAULT_DEPLOY_SSR; + + const buildStats = await zephyrAgent.zeBuildDashData(zephyrEngine); + let deploymentUrl: string | null = null; + + await zephyrEngine.upload_assets({ + assetsMap, + buildStats, + snapshotType: DEFAULT_DEPLOY_SSR ? "ssr" : "csr", + entrypoint, + hooks: { + onDeployComplete(deploymentInfo) { + deploymentUrl = deploymentInfo.url; + }, + }, + }); + + return { deploymentUrl, entrypoint }; +} diff --git a/test/unit/zephyr-preset.test.ts b/test/unit/zephyr-preset.test.ts new file mode 100644 index 0000000000..49915e721a --- /dev/null +++ b/test/unit/zephyr-preset.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, it, vi } from "vitest"; +import zephyrPresets from "../../src/presets/zephyr/preset.ts"; + +describe("zephyr preset", () => { + it("extends base-worker", () => { + const [preset] = zephyrPresets; + expect(preset.extends).toBe("base-worker"); + expect(preset.output?.publicDir).toBe("{{ output.dir }}/client/{{ baseURL }}"); + }); + + it("adds cloudflare unenv presets", async () => { + const [preset] = zephyrPresets; + const hooks = preset.hooks!; + + const nitro = { + options: { + preset: "zephyr", + output: { + dir: "/tmp/zephyr-output", + serverDir: "/tmp/zephyr-output/server", + }, + unenv: [], + }, + logger: { + info: vi.fn(), + success: vi.fn(), + }, + } as any; + + await hooks["build:before"]?.(nitro); + expect(nitro.options.unenv).toHaveLength(2); + expect(nitro.options.unenv[0].meta?.name).toBe("nitro:cloudflare-externals"); + expect(nitro.options.unenv[1].meta?.name).toBe("nitro:cloudflare-node-compat"); + expect(nitro.logger.info).not.toHaveBeenCalled(); + expect(nitro.logger.success).not.toHaveBeenCalled(); + }); +});