shipscreens 0.1.0
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/LICENSE +22 -0
- package/README.md +27 -0
- package/bin/shipscreens.js +664 -0
- package/cli/assetRefs.js +33 -0
- package/cli/auth.js +454 -0
- package/cli/buildOutputs.js +146 -0
- package/cli/commands/auth.js +65 -0
- package/cli/commands/build.js +347 -0
- package/cli/commands/copyImport.js +263 -0
- package/cli/commands/exportFramefile.js +404 -0
- package/cli/commands/init.js +339 -0
- package/cli/commands/lock.js +144 -0
- package/cli/commands/plan.js +203 -0
- package/cli/commands/stage.js +318 -0
- package/cli/commands/validate.js +89 -0
- package/cli/commands/verify.js +659 -0
- package/cli/commands/wizard.js +266 -0
- package/cli/dataUrl.js +19 -0
- package/cli/fastlaneZip.js +115 -0
- package/cli/hash.js +13 -0
- package/cli/loadConfig.js +55 -0
- package/cli/outputPaths.js +24 -0
- package/cli/packageRoot.js +8 -0
- package/cli/pathUtils.js +25 -0
- package/cli/rendererServer.js +48 -0
- package/cli/repoRoot.js +23 -0
- package/cli/rootPolicy.js +17 -0
- package/cli/schema.js +290 -0
- package/cli/snapshotFromConfig.js +116 -0
- package/cli/staticServer.js +102 -0
- package/cli/templateConfig.js +51 -0
- package/cli/viteServer.js +40 -0
- package/dist/app/apple-touch-icon.png +0 -0
- package/dist/app/assets/AgentCli-8e28laT4.js +17 -0
- package/dist/app/assets/AgentCli-8e28laT4.js.map +1 -0
- package/dist/app/assets/App-DU0xew0e.js +13 -0
- package/dist/app/assets/App-DU0xew0e.js.map +1 -0
- package/dist/app/assets/AppReviewAso-OLwc4Rw_.js +4 -0
- package/dist/app/assets/AppReviewAso-OLwc4Rw_.js.map +1 -0
- package/dist/app/assets/Cancelled-BoeZQa1S.js +2 -0
- package/dist/app/assets/Cancelled-BoeZQa1S.js.map +1 -0
- package/dist/app/assets/CliPreflightCard-CxYyogdF.js +2 -0
- package/dist/app/assets/CliPreflightCard-CxYyogdF.js.map +1 -0
- package/dist/app/assets/CopyButton-CGfuSJtU.js +2 -0
- package/dist/app/assets/CopyButton-CGfuSJtU.js.map +1 -0
- package/dist/app/assets/FastlaneScreenshots-CFT6IiRb.js +52 -0
- package/dist/app/assets/FastlaneScreenshots-CFT6IiRb.js.map +1 -0
- package/dist/app/assets/FirstExport-B_UDacZm.js +6 -0
- package/dist/app/assets/FirstExport-B_UDacZm.js.map +1 -0
- package/dist/app/assets/FivePanelFramework-C1z_xUbe.js +60 -0
- package/dist/app/assets/FivePanelFramework-C1z_xUbe.js.map +1 -0
- package/dist/app/assets/ForgotPassword-ZQ8U3ejz.js +2 -0
- package/dist/app/assets/ForgotPassword-ZQ8U3ejz.js.map +1 -0
- package/dist/app/assets/Landing-DAIP71DD.js +2 -0
- package/dist/app/assets/Landing-DAIP71DD.js.map +1 -0
- package/dist/app/assets/LanguageSwitcher-D93nCuuR.js +2 -0
- package/dist/app/assets/LanguageSwitcher-D93nCuuR.js.map +1 -0
- package/dist/app/assets/Legal-Koe7vi6H.js +2 -0
- package/dist/app/assets/Legal-Koe7vi6H.js.map +1 -0
- package/dist/app/assets/NotFound-CfY31vMZ.js +2 -0
- package/dist/app/assets/NotFound-CfY31vMZ.js.map +1 -0
- package/dist/app/assets/Pricing-BQwtFVbj.js +2 -0
- package/dist/app/assets/Pricing-BQwtFVbj.js.map +1 -0
- package/dist/app/assets/Privacy-CaHf2UM7.js +2 -0
- package/dist/app/assets/Privacy-CaHf2UM7.js.map +1 -0
- package/dist/app/assets/SignIn-Cyi2_-Mn.js +2 -0
- package/dist/app/assets/SignIn-Cyi2_-Mn.js.map +1 -0
- package/dist/app/assets/SignUp-C9QH5po_.js +2 -0
- package/dist/app/assets/SignUp-C9QH5po_.js.map +1 -0
- package/dist/app/assets/SiteHeader-Dj3gDOnR.js +2 -0
- package/dist/app/assets/SiteHeader-Dj3gDOnR.js.map +1 -0
- package/dist/app/assets/StickyMobileCta-uyWGVhdc.js +2 -0
- package/dist/app/assets/StickyMobileCta-uyWGVhdc.js.map +1 -0
- package/dist/app/assets/StoreAssetsPipeline-BJlnD3kD.js +4 -0
- package/dist/app/assets/StoreAssetsPipeline-BJlnD3kD.js.map +1 -0
- package/dist/app/assets/Success-B7k7FvJj.js +2 -0
- package/dist/app/assets/Success-B7k7FvJj.js.map +1 -0
- package/dist/app/assets/Terms-DgJWOeUD.js +2 -0
- package/dist/app/assets/Terms-DgJWOeUD.js.map +1 -0
- package/dist/app/assets/ToolsIndex-xMPoFom9.js +6 -0
- package/dist/app/assets/ToolsIndex-xMPoFom9.js.map +1 -0
- package/dist/app/assets/WorkloadCalculator-Bdt6qPR3.js +5 -0
- package/dist/app/assets/WorkloadCalculator-Bdt6qPR3.js.map +1 -0
- package/dist/app/assets/calculator-CWfp5Day.js +2 -0
- package/dist/app/assets/calculator-CWfp5Day.js.map +1 -0
- package/dist/app/assets/check-BWCiUZ-C.js +2 -0
- package/dist/app/assets/check-BWCiUZ-C.js.map +1 -0
- package/dist/app/assets/chevron-down-DbSAem1L.js +2 -0
- package/dist/app/assets/chevron-down-DbSAem1L.js.map +1 -0
- package/dist/app/assets/circle-check-CeakjiXC.js +2 -0
- package/dist/app/assets/circle-check-CeakjiXC.js.map +1 -0
- package/dist/app/assets/clipboard-copy-DgTgnK84.js +2 -0
- package/dist/app/assets/clipboard-copy-DgTgnK84.js.map +1 -0
- package/dist/app/assets/copy-C9t_FzCZ.js +2 -0
- package/dist/app/assets/copy-C9t_FzCZ.js.map +1 -0
- package/dist/app/assets/crop-B7IxIx6D.js +2 -0
- package/dist/app/assets/crop-B7IxIx6D.js.map +1 -0
- package/dist/app/assets/download-65Zuvgwm.js +2 -0
- package/dist/app/assets/download-65Zuvgwm.js.map +1 -0
- package/dist/app/assets/eye-ouNo8Nv5.js +2 -0
- package/dist/app/assets/eye-ouNo8Nv5.js.map +1 -0
- package/dist/app/assets/grid-3x3-U1Nk_ppf.js +2 -0
- package/dist/app/assets/grid-3x3-U1Nk_ppf.js.map +1 -0
- package/dist/app/assets/hero/cli-build-tree-15s.mp4 +0 -0
- package/dist/app/assets/hero/cli-build-tree-15s.webm +0 -0
- package/dist/app/assets/hero/cli-build-tree-25s.mp4 +0 -0
- package/dist/app/assets/hero/cli-build-tree-25s.webm +0 -0
- package/dist/app/assets/hero/cli-build-tree-poster.png +0 -0
- package/dist/app/assets/hero/demo.gif +0 -0
- package/dist/app/assets/hero/demo.mp4 +0 -0
- package/dist/app/assets/hero/demo.webm +0 -0
- package/dist/app/assets/icons/apple-touch-icon.png +0 -0
- package/dist/app/assets/icons/device-base.png +0 -0
- package/dist/app/assets/icons/favicon-16x16.png +0 -0
- package/dist/app/assets/icons/favicon-32x32.png +0 -0
- package/dist/app/assets/icons/favicon.ico +0 -0
- package/dist/app/assets/icons/favicon.svg +1 -0
- package/dist/app/assets/index-B8Y8Y-Mi.js +180 -0
- package/dist/app/assets/index-B8Y8Y-Mi.js.map +1 -0
- package/dist/app/assets/index-hyiQFYGv.css +1 -0
- package/dist/app/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
- package/dist/app/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
- package/dist/app/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
- package/dist/app/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
- package/dist/app/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
- package/dist/app/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
- package/dist/app/assets/inter-cyrillic-700-normal-CjBOestx.woff2 +0 -0
- package/dist/app/assets/inter-cyrillic-700-normal-DrXBdSj3.woff +0 -0
- package/dist/app/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
- package/dist/app/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
- package/dist/app/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
- package/dist/app/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
- package/dist/app/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
- package/dist/app/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
- package/dist/app/assets/inter-cyrillic-ext-700-normal-BjwYoWNd.woff2 +0 -0
- package/dist/app/assets/inter-cyrillic-ext-700-normal-LO58E6JB.woff +0 -0
- package/dist/app/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
- package/dist/app/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
- package/dist/app/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
- package/dist/app/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
- package/dist/app/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
- package/dist/app/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
- package/dist/app/assets/inter-greek-700-normal-BUv2fZ6O.woff +0 -0
- package/dist/app/assets/inter-greek-700-normal-C3JjAnD8.woff2 +0 -0
- package/dist/app/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
- package/dist/app/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
- package/dist/app/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
- package/dist/app/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
- package/dist/app/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
- package/dist/app/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
- package/dist/app/assets/inter-greek-ext-700-normal-BoQ6DsYi.woff +0 -0
- package/dist/app/assets/inter-greek-ext-700-normal-qfdV9bQt.woff2 +0 -0
- package/dist/app/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/dist/app/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- package/dist/app/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- package/dist/app/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/dist/app/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
- package/dist/app/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
- package/dist/app/assets/inter-latin-700-normal-BLAVimhd.woff +0 -0
- package/dist/app/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
- package/dist/app/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
- package/dist/app/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
- package/dist/app/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
- package/dist/app/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
- package/dist/app/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
- package/dist/app/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
- package/dist/app/assets/inter-latin-ext-700-normal-Ca8adRJv.woff2 +0 -0
- package/dist/app/assets/inter-latin-ext-700-normal-TidjK2hL.woff +0 -0
- package/dist/app/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
- package/dist/app/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
- package/dist/app/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
- package/dist/app/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
- package/dist/app/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
- package/dist/app/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
- package/dist/app/assets/inter-vietnamese-700-normal-BZaoP0fm.woff +0 -0
- package/dist/app/assets/inter-vietnamese-700-normal-DlLaEgI2.woff2 +0 -0
- package/dist/app/assets/layout-grid-X9Sgull2.js +2 -0
- package/dist/app/assets/layout-grid-X9Sgull2.js.map +1 -0
- package/dist/app/assets/merriweather-cyrillic-400-normal-AvfsDsMQ.woff2 +0 -0
- package/dist/app/assets/merriweather-cyrillic-400-normal-DAcQ8g-H.woff +0 -0
- package/dist/app/assets/merriweather-cyrillic-700-normal-CHCcU-4a.woff +0 -0
- package/dist/app/assets/merriweather-cyrillic-700-normal-wbY04GlL.woff2 +0 -0
- package/dist/app/assets/merriweather-cyrillic-ext-400-normal-D9NYhYTq.woff2 +0 -0
- package/dist/app/assets/merriweather-cyrillic-ext-400-normal-Di6yW_eE.woff +0 -0
- package/dist/app/assets/merriweather-cyrillic-ext-700-normal-Bk1p9YoV.woff2 +0 -0
- package/dist/app/assets/merriweather-cyrillic-ext-700-normal-DoooT6Vg.woff +0 -0
- package/dist/app/assets/merriweather-latin-400-normal-CvqO63Ah.woff +0 -0
- package/dist/app/assets/merriweather-latin-400-normal-G4kZaoXi.woff2 +0 -0
- package/dist/app/assets/merriweather-latin-700-normal-D4-nzrAh.woff +0 -0
- package/dist/app/assets/merriweather-latin-700-normal-DoUP8Ce-.woff2 +0 -0
- package/dist/app/assets/merriweather-latin-ext-400-normal-CLqijLtt.woff +0 -0
- package/dist/app/assets/merriweather-latin-ext-400-normal-CWVzVQq3.woff2 +0 -0
- package/dist/app/assets/merriweather-latin-ext-700-normal-CaBzXGOk.woff +0 -0
- package/dist/app/assets/merriweather-latin-ext-700-normal-jHnxg2Kc.woff2 +0 -0
- package/dist/app/assets/merriweather-vietnamese-400-normal-Dh8WVvgZ.woff +0 -0
- package/dist/app/assets/merriweather-vietnamese-400-normal-hNacsVs_.woff2 +0 -0
- package/dist/app/assets/merriweather-vietnamese-700-normal-Bp6kWjW5.woff2 +0 -0
- package/dist/app/assets/merriweather-vietnamese-700-normal-C7_HxHBa.woff +0 -0
- package/dist/app/assets/montserrat-cyrillic-400-normal-BPq32Q8K.woff2 +0 -0
- package/dist/app/assets/montserrat-cyrillic-400-normal-jEs4Tk-Z.woff +0 -0
- package/dist/app/assets/montserrat-cyrillic-700-normal-BvLYcGP1.woff +0 -0
- package/dist/app/assets/montserrat-cyrillic-700-normal-D-Pqjtdp.woff2 +0 -0
- package/dist/app/assets/montserrat-cyrillic-ext-400-normal-DRPPeomZ.woff +0 -0
- package/dist/app/assets/montserrat-cyrillic-ext-400-normal-Xqov12YL.woff2 +0 -0
- package/dist/app/assets/montserrat-cyrillic-ext-700-normal-D-Mk2xRJ.woff +0 -0
- package/dist/app/assets/montserrat-cyrillic-ext-700-normal-MyDreaeu.woff2 +0 -0
- package/dist/app/assets/montserrat-latin-400-normal-BLhwKU8k.woff2 +0 -0
- package/dist/app/assets/montserrat-latin-400-normal-xItZbAXg.woff +0 -0
- package/dist/app/assets/montserrat-latin-700-normal-BWkrl476.woff +0 -0
- package/dist/app/assets/montserrat-latin-700-normal-BdjcYUrC.woff2 +0 -0
- package/dist/app/assets/montserrat-latin-ext-400-normal-B8bwfy6Y.woff2 +0 -0
- package/dist/app/assets/montserrat-latin-ext-400-normal-BffdBkAA.woff +0 -0
- package/dist/app/assets/montserrat-latin-ext-700-normal-BOP2Nhf0.woff2 +0 -0
- package/dist/app/assets/montserrat-latin-ext-700-normal-DdDFr05Z.woff +0 -0
- package/dist/app/assets/montserrat-vietnamese-400-normal-BeEscFYY.woff +0 -0
- package/dist/app/assets/montserrat-vietnamese-400-normal-D4oHqQTd.woff2 +0 -0
- package/dist/app/assets/montserrat-vietnamese-700-normal-C0x1De3p.woff2 +0 -0
- package/dist/app/assets/montserrat-vietnamese-700-normal-DnwGT2D9.woff +0 -0
- package/dist/app/assets/playfair-display-cyrillic-400-normal-CjW2EstV.woff2 +0 -0
- package/dist/app/assets/playfair-display-cyrillic-400-normal-ZiRag6zj.woff +0 -0
- package/dist/app/assets/playfair-display-cyrillic-700-normal-Dk1mTcxf.woff +0 -0
- package/dist/app/assets/playfair-display-cyrillic-700-normal-Dw3uKy19.woff2 +0 -0
- package/dist/app/assets/playfair-display-latin-400-normal-CFtfchNt.woff2 +0 -0
- package/dist/app/assets/playfair-display-latin-400-normal-DHYHbkg3.woff +0 -0
- package/dist/app/assets/playfair-display-latin-700-normal-Bc_1Q1cG.woff +0 -0
- package/dist/app/assets/playfair-display-latin-700-normal-CuDiGg7c.woff2 +0 -0
- package/dist/app/assets/playfair-display-latin-ext-400-normal-BxlSGspa.woff2 +0 -0
- package/dist/app/assets/playfair-display-latin-ext-400-normal-qdZwdvNS.woff +0 -0
- package/dist/app/assets/playfair-display-latin-ext-700-normal-C58ejOkc.woff2 +0 -0
- package/dist/app/assets/playfair-display-latin-ext-700-normal-D5HUU8GT.woff +0 -0
- package/dist/app/assets/playfair-display-vietnamese-400-normal-BV2APVTb.woff2 +0 -0
- package/dist/app/assets/playfair-display-vietnamese-400-normal-BbvUAu4N.woff +0 -0
- package/dist/app/assets/playfair-display-vietnamese-700-normal-CaKJSIny.woff2 +0 -0
- package/dist/app/assets/playfair-display-vietnamese-700-normal-Cr1rw0mr.woff +0 -0
- package/dist/app/assets/proof/output-01.png +0 -0
- package/dist/app/assets/proof/output-02.png +0 -0
- package/dist/app/assets/proof/output-03.png +0 -0
- package/dist/app/assets/proof/output-04.png +0 -0
- package/dist/app/assets/roboto-cyrillic-400-normal-DAIM1_dR.woff2 +0 -0
- package/dist/app/assets/roboto-cyrillic-400-normal-DZJji7Rx.woff +0 -0
- package/dist/app/assets/roboto-cyrillic-500-normal-BI4HuXre.woff +0 -0
- package/dist/app/assets/roboto-cyrillic-500-normal-hCeO1jFL.woff2 +0 -0
- package/dist/app/assets/roboto-cyrillic-700-normal-BiSG5NnW.woff2 +0 -0
- package/dist/app/assets/roboto-cyrillic-700-normal-KqaQ5bNp.woff +0 -0
- package/dist/app/assets/roboto-cyrillic-ext-400-normal-DtZHuW6i.woff +0 -0
- package/dist/app/assets/roboto-cyrillic-ext-400-normal-DzMWdK87.woff2 +0 -0
- package/dist/app/assets/roboto-cyrillic-ext-500-normal-B7rQpwPu.woff2 +0 -0
- package/dist/app/assets/roboto-cyrillic-ext-500-normal-C927yMrb.woff +0 -0
- package/dist/app/assets/roboto-cyrillic-ext-700-normal-BuQgZIrO.woff +0 -0
- package/dist/app/assets/roboto-cyrillic-ext-700-normal-UFn0vR9r.woff2 +0 -0
- package/dist/app/assets/roboto-greek-400-normal-CcizSnRP.woff +0 -0
- package/dist/app/assets/roboto-greek-400-normal-jFM2czAU.woff2 +0 -0
- package/dist/app/assets/roboto-greek-500-normal-BJMS0heP.woff2 +0 -0
- package/dist/app/assets/roboto-greek-500-normal-BLLWU9W-.woff +0 -0
- package/dist/app/assets/roboto-greek-700-normal-BcGn9doz.woff2 +0 -0
- package/dist/app/assets/roboto-greek-700-normal-D3kmAf0K.woff +0 -0
- package/dist/app/assets/roboto-latin-400-normal-068yxgMN.woff +0 -0
- package/dist/app/assets/roboto-latin-400-normal-CNwBRw8h.woff2 +0 -0
- package/dist/app/assets/roboto-latin-500-normal-CC5nhZkh.woff +0 -0
- package/dist/app/assets/roboto-latin-500-normal-CkrA1NAy.woff2 +0 -0
- package/dist/app/assets/roboto-latin-700-normal-CXeAXeti.woff2 +0 -0
- package/dist/app/assets/roboto-latin-700-normal-DUekQERp.woff +0 -0
- package/dist/app/assets/roboto-latin-ext-400-normal-ZYmyxeOy.woff2 +0 -0
- package/dist/app/assets/roboto-latin-ext-400-normal-eTRLN0Nt.woff +0 -0
- package/dist/app/assets/roboto-latin-ext-500-normal-C_ARlJGk.woff2 +0 -0
- package/dist/app/assets/roboto-latin-ext-500-normal-FFcS8vBN.woff +0 -0
- package/dist/app/assets/roboto-latin-ext-700-normal-70GS1MYH.woff2 +0 -0
- package/dist/app/assets/roboto-latin-ext-700-normal-BS1OuQqR.woff +0 -0
- package/dist/app/assets/roboto-math-400-normal-B3wgz80t.woff2 +0 -0
- package/dist/app/assets/roboto-math-400-normal-rzxYvyVt.woff +0 -0
- package/dist/app/assets/roboto-math-500-normal-CFNaIMFC.woff2 +0 -0
- package/dist/app/assets/roboto-math-500-normal-DaFX-ZC8.woff +0 -0
- package/dist/app/assets/roboto-math-700-normal-VUAI6Bz2.woff2 +0 -0
- package/dist/app/assets/roboto-math-700-normal-pYD1nhov.woff +0 -0
- package/dist/app/assets/roboto-symbols-400-normal-Tzuungub.woff +0 -0
- package/dist/app/assets/roboto-symbols-400-normal-fF1SLJBj.woff2 +0 -0
- package/dist/app/assets/roboto-symbols-500-normal-BXFTxrNR.woff2 +0 -0
- package/dist/app/assets/roboto-symbols-500-normal-CAhAe-ik.woff +0 -0
- package/dist/app/assets/roboto-symbols-700-normal-CuuvBBxy.woff +0 -0
- package/dist/app/assets/roboto-symbols-700-normal-rJi6RjIy.woff2 +0 -0
- package/dist/app/assets/roboto-vietnamese-400-normal-CDDxGrUb.woff2 +0 -0
- package/dist/app/assets/roboto-vietnamese-400-normal-DmXaN3yE.woff +0 -0
- package/dist/app/assets/roboto-vietnamese-500-normal-DW96CsrR.woff +0 -0
- package/dist/app/assets/roboto-vietnamese-500-normal-HYpufUYk.woff2 +0 -0
- package/dist/app/assets/roboto-vietnamese-700-normal-Dz0HwF-w.woff +0 -0
- package/dist/app/assets/roboto-vietnamese-700-normal-iKxYNAzq.woff2 +0 -0
- package/dist/app/assets/rocket-BjOXauLe.js +2 -0
- package/dist/app/assets/rocket-BjOXauLe.js.map +1 -0
- package/dist/app/assets/shield-check-CFNhE_aD.js +2 -0
- package/dist/app/assets/shield-check-CFNhE_aD.js.map +1 -0
- package/dist/app/assets/signIn-CVoSzqCz.js +2 -0
- package/dist/app/assets/signIn-CVoSzqCz.js.map +1 -0
- package/dist/app/assets/smartphone-BcQB9gIh.js +2 -0
- package/dist/app/assets/smartphone-BcQB9gIh.js.map +1 -0
- package/dist/app/assets/terminal-CGhryJds.js +2 -0
- package/dist/app/assets/terminal-CGhryJds.js.map +1 -0
- package/dist/app/assets/useAuth-lZZC20Tl.js +4 -0
- package/dist/app/assets/useAuth-lZZC20Tl.js.map +1 -0
- package/dist/app/favicon-16x16.png +0 -0
- package/dist/app/favicon-32x32.png +0 -0
- package/dist/app/favicon.ico +0 -0
- package/dist/app/favicon.svg +10 -0
- package/dist/app/index.html +43 -0
- package/dist/apple-touch-icon.png +0 -0
- package/dist/assets/AgentCli-8e28laT4.js +17 -0
- package/dist/assets/AgentCli-8e28laT4.js.map +1 -0
- package/dist/assets/App-DU0xew0e.js +13 -0
- package/dist/assets/App-DU0xew0e.js.map +1 -0
- package/dist/assets/AppReviewAso-OLwc4Rw_.js +4 -0
- package/dist/assets/AppReviewAso-OLwc4Rw_.js.map +1 -0
- package/dist/assets/Cancelled-BoeZQa1S.js +2 -0
- package/dist/assets/Cancelled-BoeZQa1S.js.map +1 -0
- package/dist/assets/CliPreflightCard-CxYyogdF.js +2 -0
- package/dist/assets/CliPreflightCard-CxYyogdF.js.map +1 -0
- package/dist/assets/CopyButton-CGfuSJtU.js +2 -0
- package/dist/assets/CopyButton-CGfuSJtU.js.map +1 -0
- package/dist/assets/FastlaneScreenshots-CFT6IiRb.js +52 -0
- package/dist/assets/FastlaneScreenshots-CFT6IiRb.js.map +1 -0
- package/dist/assets/FirstExport-B_UDacZm.js +6 -0
- package/dist/assets/FirstExport-B_UDacZm.js.map +1 -0
- package/dist/assets/FivePanelFramework-C1z_xUbe.js +60 -0
- package/dist/assets/FivePanelFramework-C1z_xUbe.js.map +1 -0
- package/dist/assets/ForgotPassword-ZQ8U3ejz.js +2 -0
- package/dist/assets/ForgotPassword-ZQ8U3ejz.js.map +1 -0
- package/dist/assets/Landing-DAIP71DD.js +2 -0
- package/dist/assets/Landing-DAIP71DD.js.map +1 -0
- package/dist/assets/LanguageSwitcher-D93nCuuR.js +2 -0
- package/dist/assets/LanguageSwitcher-D93nCuuR.js.map +1 -0
- package/dist/assets/Legal-Koe7vi6H.js +2 -0
- package/dist/assets/Legal-Koe7vi6H.js.map +1 -0
- package/dist/assets/NotFound-CfY31vMZ.js +2 -0
- package/dist/assets/NotFound-CfY31vMZ.js.map +1 -0
- package/dist/assets/Pricing-BQwtFVbj.js +2 -0
- package/dist/assets/Pricing-BQwtFVbj.js.map +1 -0
- package/dist/assets/Privacy-CaHf2UM7.js +2 -0
- package/dist/assets/Privacy-CaHf2UM7.js.map +1 -0
- package/dist/assets/SignIn-Cyi2_-Mn.js +2 -0
- package/dist/assets/SignIn-Cyi2_-Mn.js.map +1 -0
- package/dist/assets/SignUp-C9QH5po_.js +2 -0
- package/dist/assets/SignUp-C9QH5po_.js.map +1 -0
- package/dist/assets/SiteHeader-Dj3gDOnR.js +2 -0
- package/dist/assets/SiteHeader-Dj3gDOnR.js.map +1 -0
- package/dist/assets/StickyMobileCta-uyWGVhdc.js +2 -0
- package/dist/assets/StickyMobileCta-uyWGVhdc.js.map +1 -0
- package/dist/assets/StoreAssetsPipeline-BJlnD3kD.js +4 -0
- package/dist/assets/StoreAssetsPipeline-BJlnD3kD.js.map +1 -0
- package/dist/assets/Success-B7k7FvJj.js +2 -0
- package/dist/assets/Success-B7k7FvJj.js.map +1 -0
- package/dist/assets/Terms-DgJWOeUD.js +2 -0
- package/dist/assets/Terms-DgJWOeUD.js.map +1 -0
- package/dist/assets/ToolsIndex-xMPoFom9.js +6 -0
- package/dist/assets/ToolsIndex-xMPoFom9.js.map +1 -0
- package/dist/assets/WorkloadCalculator-Bdt6qPR3.js +5 -0
- package/dist/assets/WorkloadCalculator-Bdt6qPR3.js.map +1 -0
- package/dist/assets/calculator-CWfp5Day.js +2 -0
- package/dist/assets/calculator-CWfp5Day.js.map +1 -0
- package/dist/assets/check-BWCiUZ-C.js +2 -0
- package/dist/assets/check-BWCiUZ-C.js.map +1 -0
- package/dist/assets/chevron-down-DbSAem1L.js +2 -0
- package/dist/assets/chevron-down-DbSAem1L.js.map +1 -0
- package/dist/assets/circle-check-CeakjiXC.js +2 -0
- package/dist/assets/circle-check-CeakjiXC.js.map +1 -0
- package/dist/assets/clipboard-copy-DgTgnK84.js +2 -0
- package/dist/assets/clipboard-copy-DgTgnK84.js.map +1 -0
- package/dist/assets/copy-C9t_FzCZ.js +2 -0
- package/dist/assets/copy-C9t_FzCZ.js.map +1 -0
- package/dist/assets/crop-B7IxIx6D.js +2 -0
- package/dist/assets/crop-B7IxIx6D.js.map +1 -0
- package/dist/assets/download-65Zuvgwm.js +2 -0
- package/dist/assets/download-65Zuvgwm.js.map +1 -0
- package/dist/assets/eye-ouNo8Nv5.js +2 -0
- package/dist/assets/eye-ouNo8Nv5.js.map +1 -0
- package/dist/assets/grid-3x3-U1Nk_ppf.js +2 -0
- package/dist/assets/grid-3x3-U1Nk_ppf.js.map +1 -0
- package/dist/assets/hero/cli-build-tree-15s.mp4 +0 -0
- package/dist/assets/hero/cli-build-tree-15s.webm +0 -0
- package/dist/assets/hero/cli-build-tree-25s.mp4 +0 -0
- package/dist/assets/hero/cli-build-tree-25s.webm +0 -0
- package/dist/assets/hero/cli-build-tree-poster.png +0 -0
- package/dist/assets/hero/demo.gif +0 -0
- package/dist/assets/hero/demo.mp4 +0 -0
- package/dist/assets/hero/demo.webm +0 -0
- package/dist/assets/icons/apple-touch-icon.png +0 -0
- package/dist/assets/icons/device-base.png +0 -0
- package/dist/assets/icons/favicon-16x16.png +0 -0
- package/dist/assets/icons/favicon-32x32.png +0 -0
- package/dist/assets/icons/favicon.ico +0 -0
- package/dist/assets/icons/favicon.svg +1 -0
- package/dist/assets/index-B8Y8Y-Mi.js +180 -0
- package/dist/assets/index-B8Y8Y-Mi.js.map +1 -0
- package/dist/assets/index-hyiQFYGv.css +1 -0
- package/dist/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
- package/dist/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
- package/dist/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
- package/dist/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
- package/dist/assets/inter-cyrillic-600-normal-4D_pXhcN.woff +0 -0
- package/dist/assets/inter-cyrillic-600-normal-CWCymEST.woff2 +0 -0
- package/dist/assets/inter-cyrillic-700-normal-CjBOestx.woff2 +0 -0
- package/dist/assets/inter-cyrillic-700-normal-DrXBdSj3.woff +0 -0
- package/dist/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
- package/dist/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
- package/dist/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
- package/dist/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
- package/dist/assets/inter-cyrillic-ext-600-normal-Bcila6Z-.woff +0 -0
- package/dist/assets/inter-cyrillic-ext-600-normal-Dfes3d0z.woff2 +0 -0
- package/dist/assets/inter-cyrillic-ext-700-normal-BjwYoWNd.woff2 +0 -0
- package/dist/assets/inter-cyrillic-ext-700-normal-LO58E6JB.woff +0 -0
- package/dist/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
- package/dist/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
- package/dist/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
- package/dist/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
- package/dist/assets/inter-greek-600-normal-BZpKdvQh.woff +0 -0
- package/dist/assets/inter-greek-600-normal-plRanbMR.woff2 +0 -0
- package/dist/assets/inter-greek-700-normal-BUv2fZ6O.woff +0 -0
- package/dist/assets/inter-greek-700-normal-C3JjAnD8.woff2 +0 -0
- package/dist/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
- package/dist/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
- package/dist/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
- package/dist/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
- package/dist/assets/inter-greek-ext-600-normal-B8X0CLgF.woff +0 -0
- package/dist/assets/inter-greek-ext-600-normal-DRtmH8MT.woff2 +0 -0
- package/dist/assets/inter-greek-ext-700-normal-BoQ6DsYi.woff +0 -0
- package/dist/assets/inter-greek-ext-700-normal-qfdV9bQt.woff2 +0 -0
- package/dist/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/dist/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- package/dist/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- package/dist/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/dist/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
- package/dist/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
- package/dist/assets/inter-latin-700-normal-BLAVimhd.woff +0 -0
- package/dist/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
- package/dist/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
- package/dist/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
- package/dist/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
- package/dist/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
- package/dist/assets/inter-latin-ext-600-normal-CIVaiw4L.woff +0 -0
- package/dist/assets/inter-latin-ext-600-normal-D2bJ5OIk.woff2 +0 -0
- package/dist/assets/inter-latin-ext-700-normal-Ca8adRJv.woff2 +0 -0
- package/dist/assets/inter-latin-ext-700-normal-TidjK2hL.woff +0 -0
- package/dist/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
- package/dist/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
- package/dist/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
- package/dist/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
- package/dist/assets/inter-vietnamese-600-normal-BuLX-rYi.woff +0 -0
- package/dist/assets/inter-vietnamese-600-normal-Cc8MFFhd.woff2 +0 -0
- package/dist/assets/inter-vietnamese-700-normal-BZaoP0fm.woff +0 -0
- package/dist/assets/inter-vietnamese-700-normal-DlLaEgI2.woff2 +0 -0
- package/dist/assets/layout-grid-X9Sgull2.js +2 -0
- package/dist/assets/layout-grid-X9Sgull2.js.map +1 -0
- package/dist/assets/merriweather-cyrillic-400-normal-AvfsDsMQ.woff2 +0 -0
- package/dist/assets/merriweather-cyrillic-400-normal-DAcQ8g-H.woff +0 -0
- package/dist/assets/merriweather-cyrillic-700-normal-CHCcU-4a.woff +0 -0
- package/dist/assets/merriweather-cyrillic-700-normal-wbY04GlL.woff2 +0 -0
- package/dist/assets/merriweather-cyrillic-ext-400-normal-D9NYhYTq.woff2 +0 -0
- package/dist/assets/merriweather-cyrillic-ext-400-normal-Di6yW_eE.woff +0 -0
- package/dist/assets/merriweather-cyrillic-ext-700-normal-Bk1p9YoV.woff2 +0 -0
- package/dist/assets/merriweather-cyrillic-ext-700-normal-DoooT6Vg.woff +0 -0
- package/dist/assets/merriweather-latin-400-normal-CvqO63Ah.woff +0 -0
- package/dist/assets/merriweather-latin-400-normal-G4kZaoXi.woff2 +0 -0
- package/dist/assets/merriweather-latin-700-normal-D4-nzrAh.woff +0 -0
- package/dist/assets/merriweather-latin-700-normal-DoUP8Ce-.woff2 +0 -0
- package/dist/assets/merriweather-latin-ext-400-normal-CLqijLtt.woff +0 -0
- package/dist/assets/merriweather-latin-ext-400-normal-CWVzVQq3.woff2 +0 -0
- package/dist/assets/merriweather-latin-ext-700-normal-CaBzXGOk.woff +0 -0
- package/dist/assets/merriweather-latin-ext-700-normal-jHnxg2Kc.woff2 +0 -0
- package/dist/assets/merriweather-vietnamese-400-normal-Dh8WVvgZ.woff +0 -0
- package/dist/assets/merriweather-vietnamese-400-normal-hNacsVs_.woff2 +0 -0
- package/dist/assets/merriweather-vietnamese-700-normal-Bp6kWjW5.woff2 +0 -0
- package/dist/assets/merriweather-vietnamese-700-normal-C7_HxHBa.woff +0 -0
- package/dist/assets/montserrat-cyrillic-400-normal-BPq32Q8K.woff2 +0 -0
- package/dist/assets/montserrat-cyrillic-400-normal-jEs4Tk-Z.woff +0 -0
- package/dist/assets/montserrat-cyrillic-700-normal-BvLYcGP1.woff +0 -0
- package/dist/assets/montserrat-cyrillic-700-normal-D-Pqjtdp.woff2 +0 -0
- package/dist/assets/montserrat-cyrillic-ext-400-normal-DRPPeomZ.woff +0 -0
- package/dist/assets/montserrat-cyrillic-ext-400-normal-Xqov12YL.woff2 +0 -0
- package/dist/assets/montserrat-cyrillic-ext-700-normal-D-Mk2xRJ.woff +0 -0
- package/dist/assets/montserrat-cyrillic-ext-700-normal-MyDreaeu.woff2 +0 -0
- package/dist/assets/montserrat-latin-400-normal-BLhwKU8k.woff2 +0 -0
- package/dist/assets/montserrat-latin-400-normal-xItZbAXg.woff +0 -0
- package/dist/assets/montserrat-latin-700-normal-BWkrl476.woff +0 -0
- package/dist/assets/montserrat-latin-700-normal-BdjcYUrC.woff2 +0 -0
- package/dist/assets/montserrat-latin-ext-400-normal-B8bwfy6Y.woff2 +0 -0
- package/dist/assets/montserrat-latin-ext-400-normal-BffdBkAA.woff +0 -0
- package/dist/assets/montserrat-latin-ext-700-normal-BOP2Nhf0.woff2 +0 -0
- package/dist/assets/montserrat-latin-ext-700-normal-DdDFr05Z.woff +0 -0
- package/dist/assets/montserrat-vietnamese-400-normal-BeEscFYY.woff +0 -0
- package/dist/assets/montserrat-vietnamese-400-normal-D4oHqQTd.woff2 +0 -0
- package/dist/assets/montserrat-vietnamese-700-normal-C0x1De3p.woff2 +0 -0
- package/dist/assets/montserrat-vietnamese-700-normal-DnwGT2D9.woff +0 -0
- package/dist/assets/playfair-display-cyrillic-400-normal-CjW2EstV.woff2 +0 -0
- package/dist/assets/playfair-display-cyrillic-400-normal-ZiRag6zj.woff +0 -0
- package/dist/assets/playfair-display-cyrillic-700-normal-Dk1mTcxf.woff +0 -0
- package/dist/assets/playfair-display-cyrillic-700-normal-Dw3uKy19.woff2 +0 -0
- package/dist/assets/playfair-display-latin-400-normal-CFtfchNt.woff2 +0 -0
- package/dist/assets/playfair-display-latin-400-normal-DHYHbkg3.woff +0 -0
- package/dist/assets/playfair-display-latin-700-normal-Bc_1Q1cG.woff +0 -0
- package/dist/assets/playfair-display-latin-700-normal-CuDiGg7c.woff2 +0 -0
- package/dist/assets/playfair-display-latin-ext-400-normal-BxlSGspa.woff2 +0 -0
- package/dist/assets/playfair-display-latin-ext-400-normal-qdZwdvNS.woff +0 -0
- package/dist/assets/playfair-display-latin-ext-700-normal-C58ejOkc.woff2 +0 -0
- package/dist/assets/playfair-display-latin-ext-700-normal-D5HUU8GT.woff +0 -0
- package/dist/assets/playfair-display-vietnamese-400-normal-BV2APVTb.woff2 +0 -0
- package/dist/assets/playfair-display-vietnamese-400-normal-BbvUAu4N.woff +0 -0
- package/dist/assets/playfair-display-vietnamese-700-normal-CaKJSIny.woff2 +0 -0
- package/dist/assets/playfair-display-vietnamese-700-normal-Cr1rw0mr.woff +0 -0
- package/dist/assets/proof/output-01.png +0 -0
- package/dist/assets/proof/output-02.png +0 -0
- package/dist/assets/proof/output-03.png +0 -0
- package/dist/assets/proof/output-04.png +0 -0
- package/dist/assets/roboto-cyrillic-400-normal-DAIM1_dR.woff2 +0 -0
- package/dist/assets/roboto-cyrillic-400-normal-DZJji7Rx.woff +0 -0
- package/dist/assets/roboto-cyrillic-500-normal-BI4HuXre.woff +0 -0
- package/dist/assets/roboto-cyrillic-500-normal-hCeO1jFL.woff2 +0 -0
- package/dist/assets/roboto-cyrillic-700-normal-BiSG5NnW.woff2 +0 -0
- package/dist/assets/roboto-cyrillic-700-normal-KqaQ5bNp.woff +0 -0
- package/dist/assets/roboto-cyrillic-ext-400-normal-DtZHuW6i.woff +0 -0
- package/dist/assets/roboto-cyrillic-ext-400-normal-DzMWdK87.woff2 +0 -0
- package/dist/assets/roboto-cyrillic-ext-500-normal-B7rQpwPu.woff2 +0 -0
- package/dist/assets/roboto-cyrillic-ext-500-normal-C927yMrb.woff +0 -0
- package/dist/assets/roboto-cyrillic-ext-700-normal-BuQgZIrO.woff +0 -0
- package/dist/assets/roboto-cyrillic-ext-700-normal-UFn0vR9r.woff2 +0 -0
- package/dist/assets/roboto-greek-400-normal-CcizSnRP.woff +0 -0
- package/dist/assets/roboto-greek-400-normal-jFM2czAU.woff2 +0 -0
- package/dist/assets/roboto-greek-500-normal-BJMS0heP.woff2 +0 -0
- package/dist/assets/roboto-greek-500-normal-BLLWU9W-.woff +0 -0
- package/dist/assets/roboto-greek-700-normal-BcGn9doz.woff2 +0 -0
- package/dist/assets/roboto-greek-700-normal-D3kmAf0K.woff +0 -0
- package/dist/assets/roboto-latin-400-normal-068yxgMN.woff +0 -0
- package/dist/assets/roboto-latin-400-normal-CNwBRw8h.woff2 +0 -0
- package/dist/assets/roboto-latin-500-normal-CC5nhZkh.woff +0 -0
- package/dist/assets/roboto-latin-500-normal-CkrA1NAy.woff2 +0 -0
- package/dist/assets/roboto-latin-700-normal-CXeAXeti.woff2 +0 -0
- package/dist/assets/roboto-latin-700-normal-DUekQERp.woff +0 -0
- package/dist/assets/roboto-latin-ext-400-normal-ZYmyxeOy.woff2 +0 -0
- package/dist/assets/roboto-latin-ext-400-normal-eTRLN0Nt.woff +0 -0
- package/dist/assets/roboto-latin-ext-500-normal-C_ARlJGk.woff2 +0 -0
- package/dist/assets/roboto-latin-ext-500-normal-FFcS8vBN.woff +0 -0
- package/dist/assets/roboto-latin-ext-700-normal-70GS1MYH.woff2 +0 -0
- package/dist/assets/roboto-latin-ext-700-normal-BS1OuQqR.woff +0 -0
- package/dist/assets/roboto-math-400-normal-B3wgz80t.woff2 +0 -0
- package/dist/assets/roboto-math-400-normal-rzxYvyVt.woff +0 -0
- package/dist/assets/roboto-math-500-normal-CFNaIMFC.woff2 +0 -0
- package/dist/assets/roboto-math-500-normal-DaFX-ZC8.woff +0 -0
- package/dist/assets/roboto-math-700-normal-VUAI6Bz2.woff2 +0 -0
- package/dist/assets/roboto-math-700-normal-pYD1nhov.woff +0 -0
- package/dist/assets/roboto-symbols-400-normal-Tzuungub.woff +0 -0
- package/dist/assets/roboto-symbols-400-normal-fF1SLJBj.woff2 +0 -0
- package/dist/assets/roboto-symbols-500-normal-BXFTxrNR.woff2 +0 -0
- package/dist/assets/roboto-symbols-500-normal-CAhAe-ik.woff +0 -0
- package/dist/assets/roboto-symbols-700-normal-CuuvBBxy.woff +0 -0
- package/dist/assets/roboto-symbols-700-normal-rJi6RjIy.woff2 +0 -0
- package/dist/assets/roboto-vietnamese-400-normal-CDDxGrUb.woff2 +0 -0
- package/dist/assets/roboto-vietnamese-400-normal-DmXaN3yE.woff +0 -0
- package/dist/assets/roboto-vietnamese-500-normal-DW96CsrR.woff +0 -0
- package/dist/assets/roboto-vietnamese-500-normal-HYpufUYk.woff2 +0 -0
- package/dist/assets/roboto-vietnamese-700-normal-Dz0HwF-w.woff +0 -0
- package/dist/assets/roboto-vietnamese-700-normal-iKxYNAzq.woff2 +0 -0
- package/dist/assets/rocket-BjOXauLe.js +2 -0
- package/dist/assets/rocket-BjOXauLe.js.map +1 -0
- package/dist/assets/shield-check-CFNhE_aD.js +2 -0
- package/dist/assets/shield-check-CFNhE_aD.js.map +1 -0
- package/dist/assets/signIn-CVoSzqCz.js +2 -0
- package/dist/assets/signIn-CVoSzqCz.js.map +1 -0
- package/dist/assets/smartphone-BcQB9gIh.js +2 -0
- package/dist/assets/smartphone-BcQB9gIh.js.map +1 -0
- package/dist/assets/terminal-CGhryJds.js +2 -0
- package/dist/assets/terminal-CGhryJds.js.map +1 -0
- package/dist/assets/useAuth-lZZC20Tl.js +4 -0
- package/dist/assets/useAuth-lZZC20Tl.js.map +1 -0
- package/dist/cancelled/index.html +34 -0
- package/dist/downloads/shipscreens-agent-cli-config.yml +48 -0
- package/dist/downloads/shipscreens-agent-cli-copy.csv +2 -0
- package/dist/favicon-16x16.png +0 -0
- package/dist/favicon-32x32.png +0 -0
- package/dist/favicon.ico +0 -0
- package/dist/favicon.svg +10 -0
- package/dist/forgot-password/index.html +34 -0
- package/dist/index.html +42 -0
- package/dist/legal/index.html +33 -0
- package/dist/og-image.png +0 -0
- package/dist/pricing/index.html +33 -0
- package/dist/privacy/index.html +33 -0
- package/dist/robots.txt +11 -0
- package/dist/signin/index.html +34 -0
- package/dist/signup/index.html +34 -0
- package/dist/sitemap.xml +51 -0
- package/dist/success/index.html +34 -0
- package/dist/templates/clean_blue.png +0 -0
- package/dist/templates/minimal_dark.png +0 -0
- package/dist/templates/split_modern.png +0 -0
- package/dist/templates/vibrant_gradient.png +0 -0
- package/dist/terms/index.html +33 -0
- package/dist/tools/5-panel-screenshot-framework/index.html +33 -0
- package/dist/tools/agent-cli/index.html +33 -0
- package/dist/tools/app-review-aso/index.html +33 -0
- package/dist/tools/fastlane-screenshots/index.html +33 -0
- package/dist/tools/first-export/index.html +33 -0
- package/dist/tools/index.html +33 -0
- package/dist/tools/screenshot-workload-calculator/index.html +33 -0
- package/dist/tools/store-assets-pipeline/index.html +33 -0
- package/package.json +36 -0
- package/src/constants/devices.js +122 -0
- package/templates/agent/agent-prompt.txt +21 -0
- package/templates/agent/copy.csv +2 -0
- package/templates/agent/shipscreens.config.yml +48 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { deflateSync } from 'node:zlib';
|
|
4
|
+
import { DEVICE_LIBRARY } from '../../src/constants/devices.js';
|
|
5
|
+
|
|
6
|
+
const DEFAULT_LOCALES = ['en-US'];
|
|
7
|
+
const DEFAULT_SLIDES = 5;
|
|
8
|
+
export const DEFAULT_DEVICES = [
|
|
9
|
+
{ id: 'iphone69', platform: 'ios' },
|
|
10
|
+
{ id: 'pixel8', platform: 'android', androidBucket: 'phoneScreenshots' },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
export const PLACEHOLDER_COLOR = [30, 41, 59, 255];
|
|
14
|
+
export const PLACEHOLDER_WIDTH = 1080;
|
|
15
|
+
export const PLACEHOLDER_HEIGHT = 1920;
|
|
16
|
+
|
|
17
|
+
const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
18
|
+
|
|
19
|
+
const CRC_TABLE = (() => {
|
|
20
|
+
const table = new Uint32Array(256);
|
|
21
|
+
for (let i = 0; i < table.length; i += 1) {
|
|
22
|
+
let c = i;
|
|
23
|
+
for (let k = 0; k < 8; k += 1) {
|
|
24
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
25
|
+
}
|
|
26
|
+
table[i] = c >>> 0;
|
|
27
|
+
}
|
|
28
|
+
return table;
|
|
29
|
+
})();
|
|
30
|
+
|
|
31
|
+
const crc32 = (buffer) => {
|
|
32
|
+
let crc = 0xffffffff;
|
|
33
|
+
for (const byte of buffer) {
|
|
34
|
+
crc = (crc >>> 8) ^ CRC_TABLE[(crc ^ byte) & 0xff];
|
|
35
|
+
}
|
|
36
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const pngChunk = (type, data) => {
|
|
40
|
+
const typeBuffer = Buffer.from(type, 'ascii');
|
|
41
|
+
const length = Buffer.alloc(4);
|
|
42
|
+
length.writeUInt32BE(data.length);
|
|
43
|
+
const crcBuffer = Buffer.alloc(4);
|
|
44
|
+
const crc = crc32(Buffer.concat([typeBuffer, data]));
|
|
45
|
+
crcBuffer.writeUInt32BE(crc);
|
|
46
|
+
return Buffer.concat([length, typeBuffer, data, crcBuffer]);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const createSolidPng = ({ width, height, color }) => {
|
|
50
|
+
const row = Buffer.alloc(1 + width * 4);
|
|
51
|
+
row[0] = 0;
|
|
52
|
+
for (let i = 0; i < width; i += 1) {
|
|
53
|
+
const offset = 1 + i * 4;
|
|
54
|
+
row[offset] = color[0];
|
|
55
|
+
row[offset + 1] = color[1];
|
|
56
|
+
row[offset + 2] = color[2];
|
|
57
|
+
row[offset + 3] = color[3];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const raw = Buffer.alloc(row.length * height);
|
|
61
|
+
for (let y = 0; y < height; y += 1) {
|
|
62
|
+
row.copy(raw, y * row.length);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const compressed = deflateSync(raw);
|
|
66
|
+
const ihdr = Buffer.alloc(13);
|
|
67
|
+
ihdr.writeUInt32BE(width, 0);
|
|
68
|
+
ihdr.writeUInt32BE(height, 4);
|
|
69
|
+
ihdr[8] = 8;
|
|
70
|
+
ihdr[9] = 6;
|
|
71
|
+
ihdr[10] = 0;
|
|
72
|
+
ihdr[11] = 0;
|
|
73
|
+
ihdr[12] = 0;
|
|
74
|
+
|
|
75
|
+
return Buffer.concat([
|
|
76
|
+
PNG_SIGNATURE,
|
|
77
|
+
pngChunk('IHDR', ihdr),
|
|
78
|
+
pngChunk('IDAT', compressed),
|
|
79
|
+
pngChunk('IEND', Buffer.alloc(0)),
|
|
80
|
+
]);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const parseList = (raw) => {
|
|
84
|
+
if (!raw) return [];
|
|
85
|
+
return String(raw)
|
|
86
|
+
.split(',')
|
|
87
|
+
.map((item) => item.trim())
|
|
88
|
+
.filter(Boolean);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const formatIndex = (value, width) => String(value).padStart(width, '0');
|
|
92
|
+
|
|
93
|
+
const yamlQuoteIfNeeded = (value) => {
|
|
94
|
+
if (value === null || value === undefined) return '';
|
|
95
|
+
const raw = String(value);
|
|
96
|
+
// YAML treats `# ...` as a comment. Hex colors like "#0f172a" must be quoted.
|
|
97
|
+
if (raw.startsWith('#')) return `'${raw.replace(/'/g, "''")}'`;
|
|
98
|
+
return raw;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const buildConfigYaml = ({ locales, slides, devices, assets, style } = {}) => {
|
|
102
|
+
const primaryLocale = locales[0];
|
|
103
|
+
const indexWidth = Math.max(2, String(slides).length);
|
|
104
|
+
const lines = ['schemaVersion: 1', '', 'locales:'];
|
|
105
|
+
|
|
106
|
+
locales.forEach((localeId) => {
|
|
107
|
+
lines.push(` - id: ${localeId}`);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
lines.push('', 'devices:');
|
|
111
|
+
(devices?.length ? devices : DEFAULT_DEVICES).forEach((device) => {
|
|
112
|
+
lines.push(` - id: ${device.id}`);
|
|
113
|
+
if (device.platform) lines.push(` platform: ${device.platform}`);
|
|
114
|
+
if (device.androidBucket) lines.push(` androidBucket: ${device.androidBucket}`);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (assets?.background || assets?.logo || (assets?.badges && assets.badges.length)) {
|
|
118
|
+
lines.push('', 'assets:');
|
|
119
|
+
if (assets.background) {
|
|
120
|
+
lines.push(' background:');
|
|
121
|
+
lines.push(` type: ${assets.background.type}`);
|
|
122
|
+
if (assets.background.type === 'solid') {
|
|
123
|
+
lines.push(` color: ${yamlQuoteIfNeeded(assets.background.color)}`);
|
|
124
|
+
} else if (assets.background.type === 'gradient') {
|
|
125
|
+
lines.push(` start: ${yamlQuoteIfNeeded(assets.background.start)}`);
|
|
126
|
+
lines.push(` end: ${yamlQuoteIfNeeded(assets.background.end)}`);
|
|
127
|
+
if (typeof assets.background.angle === 'number') lines.push(` angle: ${assets.background.angle}`);
|
|
128
|
+
} else if (assets.background.type === 'image') {
|
|
129
|
+
lines.push(` path: ${assets.background.path}`);
|
|
130
|
+
if (typeof assets.background.blur === 'number') lines.push(` blur: ${assets.background.blur}`);
|
|
131
|
+
if (typeof assets.background.opacity === 'number') lines.push(` opacity: ${assets.background.opacity}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (assets.logo?.path) {
|
|
135
|
+
lines.push(' logo:');
|
|
136
|
+
lines.push(` path: ${assets.logo.path}`);
|
|
137
|
+
}
|
|
138
|
+
if (assets.badges?.length) {
|
|
139
|
+
lines.push(' badges:');
|
|
140
|
+
assets.badges.forEach((badge) => {
|
|
141
|
+
lines.push(` - id: ${badge.id}`);
|
|
142
|
+
lines.push(` path: ${badge.path}`);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (style && Object.keys(style).length) {
|
|
148
|
+
lines.push('', 'style:');
|
|
149
|
+
if (style.textColor) lines.push(` textColor: ${yamlQuoteIfNeeded(style.textColor)}`);
|
|
150
|
+
if (style.layoutMode) lines.push(` layoutMode: ${style.layoutMode}`);
|
|
151
|
+
if (typeof style.topSpacing === 'number') lines.push(` topSpacing: ${style.topSpacing}`);
|
|
152
|
+
if (typeof style.deviceScale === 'number') lines.push(` deviceScale: ${style.deviceScale}`);
|
|
153
|
+
if (style.frameColor) lines.push(` frameColor: ${style.frameColor}`);
|
|
154
|
+
if (style.selectedFont) lines.push(` selectedFont: ${style.selectedFont}`);
|
|
155
|
+
if (style.badgeType) lines.push(` badgeType: ${style.badgeType}`);
|
|
156
|
+
if (typeof style.headerSize === 'number') lines.push(` headerSize: ${style.headerSize}`);
|
|
157
|
+
if (typeof style.subHeaderSize === 'number') lines.push(` subHeaderSize: ${style.subHeaderSize}`);
|
|
158
|
+
if (style.orientation) lines.push(` orientation: ${style.orientation}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
lines.push('', 'slides:');
|
|
162
|
+
for (let i = 1; i <= slides; i += 1) {
|
|
163
|
+
const index = formatIndex(i, indexWidth);
|
|
164
|
+
lines.push(` - id: ${i}`);
|
|
165
|
+
lines.push(' screenshot:');
|
|
166
|
+
lines.push(` path: assets/${primaryLocale}/${index}.png`);
|
|
167
|
+
if (locales.length > 1) {
|
|
168
|
+
lines.push(' screenshotsByLocale:');
|
|
169
|
+
locales.slice(1).forEach((localeId) => {
|
|
170
|
+
lines.push(` ${localeId}: assets/${localeId}/${index}.png`);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
lines.push(' text:');
|
|
174
|
+
locales.forEach((localeId) => {
|
|
175
|
+
lines.push(` ${localeId}:`);
|
|
176
|
+
lines.push(` header: Replace headline ${i}`);
|
|
177
|
+
lines.push(` sub: Replace subtitle ${i}`);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return `${lines.join('\n')}\n`;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export const buildCopyCsv = ({ locales, slides }) => {
|
|
185
|
+
const headers = ['Locale'];
|
|
186
|
+
for (let i = 1; i <= slides; i += 1) {
|
|
187
|
+
headers.push(`Header_${i}`, `Subtitle_${i}`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const rows = locales.map((localeId) => {
|
|
191
|
+
const cells = [localeId];
|
|
192
|
+
for (let i = 1; i <= slides; i += 1) {
|
|
193
|
+
cells.push(`Replace headline ${i}`, `Replace subtitle ${i}`);
|
|
194
|
+
}
|
|
195
|
+
return cells.join(',');
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
return `${headers.join(',')}\n${rows.join('\n')}\n`;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
export const ensureDir = async (dirPath) => {
|
|
202
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const pathExists = async (filePath) => {
|
|
206
|
+
try {
|
|
207
|
+
await fs.stat(filePath);
|
|
208
|
+
return true;
|
|
209
|
+
} catch (err) {
|
|
210
|
+
if (err?.code === 'ENOENT') return false;
|
|
211
|
+
throw err;
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
function normalizeDeviceConfig(rawDevices) {
|
|
216
|
+
if (!rawDevices?.length) return [];
|
|
217
|
+
return rawDevices.map((device) => ({
|
|
218
|
+
id: device.id,
|
|
219
|
+
platform: device.platform,
|
|
220
|
+
androidBucket: device.androidBucket,
|
|
221
|
+
}));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function resolveDevices({ devices }) {
|
|
225
|
+
if (!devices) return DEFAULT_DEVICES;
|
|
226
|
+
const list = Array.isArray(devices) ? devices : parseList(devices);
|
|
227
|
+
if (!list.length) return DEFAULT_DEVICES;
|
|
228
|
+
|
|
229
|
+
const resolved = list.map((id) => {
|
|
230
|
+
const def = DEVICE_LIBRARY[id];
|
|
231
|
+
if (!def) {
|
|
232
|
+
throw new Error(`Unknown device id: ${id}. See src/constants/devices.js for valid ids.`);
|
|
233
|
+
}
|
|
234
|
+
const group = def.group || '';
|
|
235
|
+
const isAndroid = group.toLowerCase().includes('android');
|
|
236
|
+
const platform = isAndroid ? 'android' : 'ios';
|
|
237
|
+
const androidBucket =
|
|
238
|
+
platform === 'android'
|
|
239
|
+
? group.toLowerCase().includes('tablet')
|
|
240
|
+
? 'tenInchScreenshots'
|
|
241
|
+
: 'phoneScreenshots'
|
|
242
|
+
: undefined;
|
|
243
|
+
return { id, platform, androidBucket };
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const androidBuckets = new Map();
|
|
247
|
+
resolved.forEach((device) => {
|
|
248
|
+
if (device.platform !== 'android') return;
|
|
249
|
+
const bucket = device.androidBucket || 'phoneScreenshots';
|
|
250
|
+
const existing = androidBuckets.get(bucket);
|
|
251
|
+
if (existing) {
|
|
252
|
+
throw new Error(
|
|
253
|
+
`Multiple Android devices map to the same Google Play bucket (${bucket}): ${existing.id}, ${device.id}\n` +
|
|
254
|
+
`Pick one Android device per bucket (phoneScreenshots/tenInchScreenshots).`
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
androidBuckets.set(bucket, device);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
return normalizeDeviceConfig(resolved);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export async function runInit({ dir = '.', slides = DEFAULT_SLIDES, locales, devices, assets, style, force = false } = {}) {
|
|
264
|
+
const targetDir = path.resolve(process.cwd(), dir);
|
|
265
|
+
const localeList = parseList(locales);
|
|
266
|
+
const resolvedLocales = localeList.length ? localeList : DEFAULT_LOCALES;
|
|
267
|
+
const resolvedDevices = resolveDevices({ devices });
|
|
268
|
+
|
|
269
|
+
const slideCount = Number(slides || DEFAULT_SLIDES);
|
|
270
|
+
if (!Number.isInteger(slideCount) || slideCount < 1 || slideCount > 10) {
|
|
271
|
+
throw new Error('Invalid --slides value. Expected an integer between 1 and 10.');
|
|
272
|
+
}
|
|
273
|
+
if (!resolvedLocales.length) {
|
|
274
|
+
throw new Error('Invalid --locales value. Provide at least one locale id.');
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const configPath = path.join(targetDir, 'shipscreens.config.yml');
|
|
278
|
+
const csvPath = path.join(targetDir, 'copy.csv');
|
|
279
|
+
|
|
280
|
+
const filesToCheck = [configPath, csvPath];
|
|
281
|
+
for (const localeId of resolvedLocales) {
|
|
282
|
+
for (let i = 1; i <= slideCount; i += 1) {
|
|
283
|
+
const index = formatIndex(i, Math.max(2, String(slideCount).length));
|
|
284
|
+
filesToCheck.push(path.join(targetDir, 'assets', localeId, `${index}.png`));
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (!force) {
|
|
289
|
+
const conflicts = [];
|
|
290
|
+
for (const filePath of filesToCheck) {
|
|
291
|
+
if (await pathExists(filePath)) conflicts.push(filePath);
|
|
292
|
+
}
|
|
293
|
+
if (conflicts.length) {
|
|
294
|
+
throw new Error(
|
|
295
|
+
`Init would overwrite existing files. Use --force to overwrite.\n` +
|
|
296
|
+
`Conflicts:\n${conflicts.map((item) => `- ${item}`).join('\n')}`
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
await ensureDir(targetDir);
|
|
302
|
+
|
|
303
|
+
const configYaml = buildConfigYaml({
|
|
304
|
+
locales: resolvedLocales,
|
|
305
|
+
slides: slideCount,
|
|
306
|
+
devices: resolvedDevices,
|
|
307
|
+
assets,
|
|
308
|
+
style,
|
|
309
|
+
});
|
|
310
|
+
await fs.writeFile(configPath, configYaml, 'utf8');
|
|
311
|
+
|
|
312
|
+
const csv = buildCopyCsv({ locales: resolvedLocales, slides: slideCount });
|
|
313
|
+
await fs.writeFile(csvPath, csv, 'utf8');
|
|
314
|
+
|
|
315
|
+
const placeholder = createSolidPng({
|
|
316
|
+
width: PLACEHOLDER_WIDTH,
|
|
317
|
+
height: PLACEHOLDER_HEIGHT,
|
|
318
|
+
color: PLACEHOLDER_COLOR,
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
const indexWidth = Math.max(2, String(slideCount).length);
|
|
322
|
+
for (const localeId of resolvedLocales) {
|
|
323
|
+
for (let i = 1; i <= slideCount; i += 1) {
|
|
324
|
+
const index = formatIndex(i, indexWidth);
|
|
325
|
+
const assetPath = path.join(targetDir, 'assets', localeId, `${index}.png`);
|
|
326
|
+
await ensureDir(path.dirname(assetPath));
|
|
327
|
+
await fs.writeFile(assetPath, placeholder);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return {
|
|
332
|
+
dir: targetDir,
|
|
333
|
+
configPath,
|
|
334
|
+
csvPath,
|
|
335
|
+
locales: resolvedLocales,
|
|
336
|
+
slides: slideCount,
|
|
337
|
+
devices: resolvedDevices,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { collectAssetReferences } from '../assetRefs.js';
|
|
4
|
+
import { loadShipScreensConfig } from '../loadConfig.js';
|
|
5
|
+
import { sha256File } from '../hash.js';
|
|
6
|
+
import { SHIPSCREENS_CONFIG_SCHEMA_VERSION } from '../schema.js';
|
|
7
|
+
import { isPathInsideRoot, resolveValidationRoot } from '../rootPolicy.js';
|
|
8
|
+
|
|
9
|
+
async function statFile(absolutePath) {
|
|
10
|
+
const stat = await fs.stat(absolutePath);
|
|
11
|
+
if (!stat.isFile()) {
|
|
12
|
+
throw new Error(`Not a file: ${absolutePath}`);
|
|
13
|
+
}
|
|
14
|
+
return stat;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function serializeLock(lock) {
|
|
18
|
+
return `${JSON.stringify(lock, null, 2)}\n`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function compareStrings(a, b) {
|
|
22
|
+
if (a === b) return 0;
|
|
23
|
+
return a < b ? -1 : 1;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function resolveOutPath({ configDir, outPath }) {
|
|
27
|
+
if (!outPath) return path.join(configDir, 'shipscreens.lock.json');
|
|
28
|
+
if (path.isAbsolute(outPath)) return outPath;
|
|
29
|
+
return path.resolve(configDir, outPath);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function diffLockSummary({ expected, actual }) {
|
|
33
|
+
if (!actual || typeof actual !== 'object') {
|
|
34
|
+
return 'Existing lockfile is not a JSON object.';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const expectedAssets = Array.isArray(expected.assets) ? expected.assets : [];
|
|
38
|
+
const actualAssets = Array.isArray(actual.assets) ? actual.assets : [];
|
|
39
|
+
const expectedByPath = new Map(expectedAssets.map((a) => [a.path, a]));
|
|
40
|
+
const actualByPath = new Map(actualAssets.map((a) => [a.path, a]));
|
|
41
|
+
|
|
42
|
+
const added = [];
|
|
43
|
+
const removed = [];
|
|
44
|
+
const changed = [];
|
|
45
|
+
|
|
46
|
+
for (const [assetPath, expectedAsset] of expectedByPath.entries()) {
|
|
47
|
+
const actualAsset = actualByPath.get(assetPath);
|
|
48
|
+
if (!actualAsset) {
|
|
49
|
+
added.push(assetPath);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (expectedAsset.sha256 !== actualAsset.sha256 || expectedAsset.bytes !== actualAsset.bytes) {
|
|
53
|
+
changed.push(assetPath);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
for (const assetPath of actualByPath.keys()) {
|
|
58
|
+
if (!expectedByPath.has(assetPath)) removed.push(assetPath);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
added.sort(compareStrings);
|
|
62
|
+
removed.sort(compareStrings);
|
|
63
|
+
changed.sort(compareStrings);
|
|
64
|
+
|
|
65
|
+
const lines = [`Lockfile differs: ${added.length} added, ${removed.length} removed, ${changed.length} changed`];
|
|
66
|
+
|
|
67
|
+
const maxDetails = 10;
|
|
68
|
+
added.slice(0, maxDetails).forEach((p) => lines.push(`+ ${p}`));
|
|
69
|
+
removed.slice(0, maxDetails).forEach((p) => lines.push(`- ${p}`));
|
|
70
|
+
changed.slice(0, maxDetails).forEach((p) => {
|
|
71
|
+
const e = expectedByPath.get(p);
|
|
72
|
+
const a = actualByPath.get(p);
|
|
73
|
+
lines.push(`~ ${p} (sha256 ${a.sha256} -> ${e.sha256}, bytes ${a.bytes} -> ${e.bytes})`);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (added.length > maxDetails || removed.length > maxDetails || changed.length > maxDetails) {
|
|
77
|
+
lines.push('(diff truncated)');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return lines.join('\n');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function runLock({ configPath, outPath, check = false }) {
|
|
84
|
+
const { config, configDir } = await loadShipScreensConfig(configPath);
|
|
85
|
+
const { rootPath, rootRealPath } = await resolveValidationRoot({ configDir });
|
|
86
|
+
|
|
87
|
+
const refs = collectAssetReferences(config);
|
|
88
|
+
const uniqueAssetPaths = [...new Set(refs.map((r) => r.path))].sort(compareStrings);
|
|
89
|
+
|
|
90
|
+
const assets = [];
|
|
91
|
+
for (const assetPath of uniqueAssetPaths) {
|
|
92
|
+
const absoluteAssetPath = path.resolve(configDir, assetPath);
|
|
93
|
+
if (!isPathInsideRoot({ rootPath, candidatePath: absoluteAssetPath })) {
|
|
94
|
+
throw new Error(`Path escapes repo root: ${assetPath}`);
|
|
95
|
+
}
|
|
96
|
+
const stat = await statFile(absoluteAssetPath);
|
|
97
|
+
const realAssetPath = await fs.realpath(absoluteAssetPath);
|
|
98
|
+
if (!isPathInsideRoot({ rootPath: rootRealPath, candidatePath: realAssetPath })) {
|
|
99
|
+
throw new Error(`Symlink escapes repo root: ${assetPath} (resolves to ${realAssetPath})`);
|
|
100
|
+
}
|
|
101
|
+
const sha256 = await sha256File(absoluteAssetPath);
|
|
102
|
+
assets.push({
|
|
103
|
+
path: assetPath,
|
|
104
|
+
bytes: stat.size,
|
|
105
|
+
sha256,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const lock = {
|
|
110
|
+
version: 1,
|
|
111
|
+
configSchemaVersion: SHIPSCREENS_CONFIG_SCHEMA_VERSION,
|
|
112
|
+
assets,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const resolvedOutPath = resolveOutPath({ configDir, outPath });
|
|
116
|
+
const expected = serializeLock(lock);
|
|
117
|
+
|
|
118
|
+
if (check) {
|
|
119
|
+
let existing;
|
|
120
|
+
try {
|
|
121
|
+
existing = await fs.readFile(resolvedOutPath, 'utf8');
|
|
122
|
+
} catch (err) {
|
|
123
|
+
if (err?.code === 'ENOENT') {
|
|
124
|
+
throw new Error(`Lockfile missing: ${resolvedOutPath}\nRun: shipscreens lock --config ${configPath}`);
|
|
125
|
+
}
|
|
126
|
+
throw err;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (existing !== expected) {
|
|
130
|
+
let parsedExisting = null;
|
|
131
|
+
try {
|
|
132
|
+
parsedExisting = JSON.parse(existing);
|
|
133
|
+
} catch {
|
|
134
|
+
// ignore parse error; summary will mention invalid JSON
|
|
135
|
+
}
|
|
136
|
+
throw new Error(`${diffLockSummary({ expected: lock, actual: parsedExisting })}\nRun: shipscreens lock`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return { outPath: resolvedOutPath, assetCount: assets.length, checked: true };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
await fs.writeFile(resolvedOutPath, expected, 'utf8');
|
|
143
|
+
return { outPath: resolvedOutPath, assetCount: assets.length, checked: false };
|
|
144
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { runValidate } from './validate.js';
|
|
3
|
+
import { loadShipScreensConfig } from '../loadConfig.js';
|
|
4
|
+
import { resolveOutRoot, resolveOutputPath, resolveZipOutPath } from '../outputPaths.js';
|
|
5
|
+
import { formatScreenshotIndex, getScreenshotIndexWidth } from '../buildOutputs.js';
|
|
6
|
+
|
|
7
|
+
function compareStrings(a, b) {
|
|
8
|
+
if (a === b) return 0;
|
|
9
|
+
return a < b ? -1 : 1;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function normalizeProfile(profile) {
|
|
13
|
+
const normalized = String(profile || 'any')
|
|
14
|
+
.trim()
|
|
15
|
+
.toLowerCase();
|
|
16
|
+
if (!['any', 'appstore', 'playstore'].includes(normalized)) {
|
|
17
|
+
throw new Error(`Unknown plan profile: ${normalized} (expected: appstore|playstore|any)`);
|
|
18
|
+
}
|
|
19
|
+
return normalized;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function toPosixPath(value) {
|
|
23
|
+
return String(value).split(path.sep).join('/');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function toDeviceSlug(deviceId) {
|
|
27
|
+
return String(deviceId).toLowerCase();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getAndroidBucket(device) {
|
|
31
|
+
return device.androidBucket || 'phoneScreenshots';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function groupAndroidDevicesByBucket(devices) {
|
|
35
|
+
const map = new Map();
|
|
36
|
+
devices.forEach((device) => {
|
|
37
|
+
const bucket = getAndroidBucket(device);
|
|
38
|
+
const existing = map.get(bucket);
|
|
39
|
+
if (existing) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Multiple Android devices map to the same Google Play bucket (${bucket}): ${existing.id}, ${device.id}\n` +
|
|
42
|
+
`Each bucket represents a single screenshot set on Google Play (writing both would overwrite / conflict).\n` +
|
|
43
|
+
`Set only one Android device per bucket, or set devices[].androidBucket explicitly.`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
map.set(bucket, device);
|
|
47
|
+
});
|
|
48
|
+
return map;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function resolveOutRootRel({ configDir, outRoot }) {
|
|
52
|
+
const rel = path.relative(configDir, outRoot);
|
|
53
|
+
if (!rel) return '.';
|
|
54
|
+
return toPosixPath(rel);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function resolvePathRel({ baseDir, absolutePath }) {
|
|
58
|
+
const rel = path.relative(baseDir, absolutePath);
|
|
59
|
+
if (!rel) return '.';
|
|
60
|
+
return toPosixPath(rel);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function runPlan({ configPath, outDir, iosDir, androidDir, zipOut, profile } = {}) {
|
|
64
|
+
const normalizedProfile = normalizeProfile(profile);
|
|
65
|
+
await runValidate({ configPath });
|
|
66
|
+
|
|
67
|
+
const { config, configDir } = await loadShipScreensConfig(configPath);
|
|
68
|
+
const outRoot = resolveOutRoot({ configDir, outDir });
|
|
69
|
+
|
|
70
|
+
const resolvedIosDir = resolveOutputPath({
|
|
71
|
+
outRoot,
|
|
72
|
+
value: iosDir || config.output?.directory,
|
|
73
|
+
fallback: 'fastlane/screenshots',
|
|
74
|
+
});
|
|
75
|
+
const resolvedAndroidDir = resolveOutputPath({
|
|
76
|
+
outRoot,
|
|
77
|
+
value: androidDir || config.output?.androidDirectory,
|
|
78
|
+
fallback: 'fastlane/metadata/android',
|
|
79
|
+
});
|
|
80
|
+
const resolvedZipPath = resolveZipOutPath({ outRoot, zipOut });
|
|
81
|
+
|
|
82
|
+
const devices = Array.isArray(config.devices) ? config.devices : [];
|
|
83
|
+
const iosDevices = devices
|
|
84
|
+
.filter((d) => d.platform !== 'android')
|
|
85
|
+
.map((d) => ({ id: d.id, slug: toDeviceSlug(d.id) }))
|
|
86
|
+
.sort((a, b) => compareStrings(a.slug, b.slug));
|
|
87
|
+
|
|
88
|
+
const androidBuckets = [...groupAndroidDevicesByBucket(devices.filter((d) => d.platform === 'android')).entries()]
|
|
89
|
+
.sort(([a], [b]) => compareStrings(a, b))
|
|
90
|
+
.map(([bucket, device]) => ({ bucket, deviceId: device.id }));
|
|
91
|
+
|
|
92
|
+
const locales = (config.locales || []).map((l) => l.id).sort(compareStrings);
|
|
93
|
+
const slideCount = config.slides.length;
|
|
94
|
+
const indexWidth = getScreenshotIndexWidth(slideCount);
|
|
95
|
+
const indices = Array.from({ length: slideCount }, (_, idx) => formatScreenshotIndex(idx + 1, indexWidth));
|
|
96
|
+
|
|
97
|
+
const includeIos = normalizedProfile !== 'playstore';
|
|
98
|
+
const includeAndroid = normalizedProfile !== 'appstore';
|
|
99
|
+
|
|
100
|
+
if (includeIos && !iosDevices.length) {
|
|
101
|
+
throw new Error(`No iOS devices configured. Add at least one iOS device, or use --profile playstore.`);
|
|
102
|
+
}
|
|
103
|
+
if (includeAndroid && !androidBuckets.length) {
|
|
104
|
+
throw new Error(`No Android devices configured. Add at least one Android device, or use --profile appstore.`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const outRootRel = resolveOutRootRel({ configDir, outRoot });
|
|
108
|
+
const iosDirRelToOut = resolvePathRel({ baseDir: outRoot, absolutePath: resolvedIosDir });
|
|
109
|
+
const androidDirRelToOut = resolvePathRel({ baseDir: outRoot, absolutePath: resolvedAndroidDir });
|
|
110
|
+
const zipPathRelToOut = resolvePathRel({ baseDir: outRoot, absolutePath: resolvedZipPath });
|
|
111
|
+
|
|
112
|
+
const iosSets = [];
|
|
113
|
+
if (includeIos) {
|
|
114
|
+
for (const localeId of locales) {
|
|
115
|
+
for (const device of iosDevices) {
|
|
116
|
+
const files = indices.map((padded) => `${device.slug}_${padded}.png`);
|
|
117
|
+
iosSets.push({
|
|
118
|
+
locale: localeId,
|
|
119
|
+
device: device.slug,
|
|
120
|
+
dir: path.posix.join(iosDirRelToOut, localeId),
|
|
121
|
+
files,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const androidSets = [];
|
|
128
|
+
if (includeAndroid) {
|
|
129
|
+
for (const localeId of locales) {
|
|
130
|
+
for (const { bucket } of androidBuckets) {
|
|
131
|
+
const files = indices.map((padded) => `${padded}.png`);
|
|
132
|
+
androidSets.push({
|
|
133
|
+
locale: localeId,
|
|
134
|
+
bucket,
|
|
135
|
+
dir: path.posix.join(androidDirRelToOut, localeId, 'images', bucket),
|
|
136
|
+
files,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const expectedDirFiles = [
|
|
143
|
+
...iosSets.flatMap((set) => set.files.map((file) => path.posix.join(set.dir, file))),
|
|
144
|
+
...androidSets.flatMap((set) => set.files.map((file) => path.posix.join(set.dir, file))),
|
|
145
|
+
].sort(compareStrings);
|
|
146
|
+
|
|
147
|
+
const expectedZipEntries = [
|
|
148
|
+
...iosSets.flatMap((set) => set.files.map((file) => path.posix.join('fastlane', 'screenshots', set.locale, file))),
|
|
149
|
+
...androidSets.flatMap((set) =>
|
|
150
|
+
set.files.map((file) => path.posix.join('fastlane', 'metadata', 'android', set.locale, 'images', set.bucket, file))
|
|
151
|
+
),
|
|
152
|
+
].sort(compareStrings);
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
version: 1,
|
|
156
|
+
profile: normalizedProfile,
|
|
157
|
+
out: {
|
|
158
|
+
root: outRootRel,
|
|
159
|
+
iosDir: iosDirRelToOut,
|
|
160
|
+
androidDir: androidDirRelToOut,
|
|
161
|
+
zipPath: zipPathRelToOut,
|
|
162
|
+
},
|
|
163
|
+
config: {
|
|
164
|
+
schemaVersion: config.schemaVersion,
|
|
165
|
+
locales,
|
|
166
|
+
slides: slideCount,
|
|
167
|
+
indexWidth,
|
|
168
|
+
indices,
|
|
169
|
+
iosDevices: iosDevices.map((d) => d.slug),
|
|
170
|
+
androidBuckets: androidBuckets.map((b) => b.bucket),
|
|
171
|
+
},
|
|
172
|
+
build: {
|
|
173
|
+
writes: {
|
|
174
|
+
dirFiles: expectedDirFiles,
|
|
175
|
+
zipEntries: expectedZipEntries,
|
|
176
|
+
},
|
|
177
|
+
clean: {
|
|
178
|
+
ios: {
|
|
179
|
+
locales,
|
|
180
|
+
deviceSlugs: iosDevices.map((d) => d.slug),
|
|
181
|
+
pattern: '<device>_<index>.png (unframed only)',
|
|
182
|
+
},
|
|
183
|
+
android: {
|
|
184
|
+
locales,
|
|
185
|
+
buckets: androidBuckets.map((b) => b.bucket),
|
|
186
|
+
pattern: '<index>.png',
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
stage: {
|
|
191
|
+
profiles: {
|
|
192
|
+
appstore: { includes: ['ios'], excludes: ['android'], iosVariant: 'auto' },
|
|
193
|
+
playstore: { includes: ['android'], excludes: ['ios'] },
|
|
194
|
+
any: { includes: ['ios', 'android'], excludes: [] },
|
|
195
|
+
},
|
|
196
|
+
notes: [
|
|
197
|
+
'Use shipscreens stage --profile <appstore|playstore|any> to copy only upload-ready files into a new root.',
|
|
198
|
+
'For profile=appstore, stage will refuse partial framed outputs and choose *_framed.png only when complete.',
|
|
199
|
+
],
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|