@omega.js/web 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 +98 -0
- package/README.md +640 -0
- package/bin/omega +2 -0
- package/bin/omega-web +2 -0
- package/bin/omg +2 -0
- package/core/_includes/admin/sections/sidebar.json +100 -0
- package/core/_includes/admin/sections/topbar.json +11 -0
- package/core/_includes/backend/sections/sidebar.json +39 -0
- package/core/_includes/backend/sections/topbar.json +16 -0
- package/core/_includes/core/body.html +102 -0
- package/core/_includes/core/foot.html +536 -0
- package/core/_includes/core/head.html +423 -0
- package/core/_includes/core/pricing/price-per-unit.html +33 -0
- package/core/_includes/core/showcase/entry-body.html +94 -0
- package/core/_includes/core/showcase/index-body.html +43 -0
- package/core/_includes/core/showcase/nav.html +60 -0
- package/core/_includes/frontend/sections/footer.json +74 -0
- package/core/_includes/frontend/sections/nav.json +70 -0
- package/core/_includes/global/sections/account.json +31 -0
- package/core/_includes/modules/engagement/giscus.html +26 -0
- package/core/_layouts/blueprint/404.html +10 -0
- package/core/_layouts/blueprint/about.html +10 -0
- package/core/_layouts/blueprint/account/index.html +11 -0
- package/core/_layouts/blueprint/admin/calendar/index.html +590 -0
- package/core/_layouts/blueprint/admin/dashboard/index.html +301 -0
- package/core/_layouts/blueprint/admin/firebase/index.html +214 -0
- package/core/_layouts/blueprint/admin/posts/editor.html +157 -0
- package/core/_layouts/blueprint/admin/posts/index.html +126 -0
- package/core/_layouts/blueprint/admin/stackblitz/index.html +30 -0
- package/core/_layouts/blueprint/admin/studio/index.html +85 -0
- package/core/_layouts/blueprint/admin/users/index.html +272 -0
- package/core/_layouts/blueprint/admin/users/new.html +82 -0
- package/core/_layouts/blueprint/admin/verts/index.html +204 -0
- package/core/_layouts/blueprint/alternatives/alternative.html +15 -0
- package/core/_layouts/blueprint/alternatives/index.html +10 -0
- package/core/_layouts/blueprint/app.html +10 -0
- package/core/_layouts/blueprint/auth/reset.html +19 -0
- package/core/_layouts/blueprint/auth/signin.html +19 -0
- package/core/_layouts/blueprint/auth/signup.html +19 -0
- package/core/_layouts/blueprint/auth/token.html +19 -0
- package/core/_layouts/blueprint/blog/categories/category.html +8 -0
- package/core/_layouts/blueprint/blog/categories/index.html +11 -0
- package/core/_layouts/blueprint/blog/index.html +10 -0
- package/core/_layouts/blueprint/blog/post.html +5 -0
- package/core/_layouts/blueprint/blog/tags/index.html +11 -0
- package/core/_layouts/blueprint/blog/tags/tag.html +8 -0
- package/core/_layouts/blueprint/careers.md +13 -0
- package/core/_layouts/blueprint/collection/category.html +9 -0
- package/core/_layouts/blueprint/collection/document.html +9 -0
- package/core/_layouts/blueprint/collection/index.html +9 -0
- package/core/_layouts/blueprint/connections/callback.html +11 -0
- package/core/_layouts/blueprint/contact.html +14 -0
- package/core/_layouts/blueprint/dashboard/index.html +10 -0
- package/core/_layouts/blueprint/download.html +20 -0
- package/core/_layouts/blueprint/extension/index.html +14 -0
- package/core/_layouts/blueprint/extension/installed.html +11 -0
- package/core/_layouts/blueprint/feedback.html +10 -0
- package/core/_layouts/blueprint/index.html +16 -0
- package/core/_layouts/blueprint/legal/cookies.md +57 -0
- package/core/_layouts/blueprint/legal/privacy.md +109 -0
- package/core/_layouts/blueprint/legal/terms.md +155 -0
- package/core/_layouts/blueprint/payment/checkout.html +15 -0
- package/core/_layouts/blueprint/payment/confirmation.html +14 -0
- package/core/_layouts/blueprint/portal/email-preferences.html +15 -0
- package/core/_layouts/blueprint/pricing.html +20 -0
- package/core/_layouts/blueprint/status.html +10 -0
- package/core/_layouts/blueprint/team/index.html +10 -0
- package/core/_layouts/blueprint/team/member.html +5 -0
- package/core/_layouts/blueprint/updates/index.html +10 -0
- package/core/_layouts/blueprint/updates/update.html +10 -0
- package/core/_layouts/core/root.html +45 -0
- package/core/_layouts/modules/utilities/redirect.html +129 -0
- package/core/css/_studio.scss +237 -0
- package/core/css/components/_index.scss +146 -0
- package/core/css/core/_.scss +0 -0
- package/core/css/core/_alert.scss +87 -0
- package/core/css/core/_animations.scss +343 -0
- package/core/css/core/_bindings.scss +116 -0
- package/core/css/core/_blog-search.scss +57 -0
- package/core/css/core/_chatsy.scss +61 -0
- package/core/css/core/_consent.scss +424 -0
- package/core/css/core/_custom-font-awesome.scss +146 -0
- package/core/css/core/_exit-popup.scss +42 -0
- package/core/css/core/_generated-badge.scss +33 -0
- package/core/css/core/_initialize.scss +29 -0
- package/core/css/core/_lazy-loading.scss +104 -0
- package/core/css/core/_social-sharing.scss +41 -0
- package/core/css/core/_tones.scss +32 -0
- package/core/css/core/_utilities.scss +157 -0
- package/core/css/main.scss +54 -0
- package/core/css/motion/_index.scss +368 -0
- package/core/css/pages/404/index.scss +0 -0
- package/core/css/pages/admin/calendar/index.scss +692 -0
- package/core/css/pages/admin/firebase/index.scss +33 -0
- package/core/css/pages/admin/index.scss +9 -0
- package/core/css/pages/admin/users/index.scss +9 -0
- package/core/css/pages/admin/verts/index.scss +9 -0
- package/core/css/pages/alternatives/[alternative]/index.scss +0 -0
- package/core/css/pages/blog/[slug].scss +55 -0
- package/core/css/pages/dashboard/account/index.scss +242 -0
- package/core/css/pages/download/index.scss +480 -0
- package/core/css/pages/extension/installed/index.scss +317 -0
- package/core/css/pages/feedback/index.scss +31 -0
- package/core/css/pages/payment/confirmation/index.scss +14 -0
- package/core/css/pages/pricing/index.scss +0 -0
- package/core/css/pages/status/index.scss +162 -0
- package/core/css/pages/test/libraries/layers/index.scss +28 -0
- package/core/css/pages/updates/[update].scss +46 -0
- package/core/css/pages/updates/index.scss +13 -0
- package/core/css/shell/_index.scss +207 -0
- package/core/css/tokens/_index.scss +166 -0
- package/core/icons/flags/ar.svg +1 -0
- package/core/icons/flags/bd.svg +1 -0
- package/core/icons/flags/ca.svg +1 -0
- package/core/icons/flags/ch.svg +1 -0
- package/core/icons/flags/cn.svg +1 -0
- package/core/icons/flags/co.svg +1 -0
- package/core/icons/flags/cw.svg +1 -0
- package/core/icons/flags/cz.svg +1 -0
- package/core/icons/flags/de.svg +1 -0
- package/core/icons/flags/dk.svg +1 -0
- package/core/icons/flags/eg.svg +1 -0
- package/core/icons/flags/es.svg +1 -0
- package/core/icons/flags/fi.svg +1 -0
- package/core/icons/flags/fr.svg +1 -0
- package/core/icons/flags/gb.svg +1 -0
- package/core/icons/flags/gq.svg +1 -0
- package/core/icons/flags/gr.svg +1 -0
- package/core/icons/flags/gt.svg +1 -0
- package/core/icons/flags/hn.svg +1 -0
- package/core/icons/flags/id.svg +1 -0
- package/core/icons/flags/ie.svg +1 -0
- package/core/icons/flags/in.svg +1 -0
- package/core/icons/flags/ir.svg +1 -0
- package/core/icons/flags/it.svg +1 -0
- package/core/icons/flags/jp.svg +1 -0
- package/core/icons/flags/kp.svg +1 -0
- package/core/icons/flags/kr.svg +1 -0
- package/core/icons/flags/ly.svg +1 -0
- package/core/icons/flags/ma.svg +1 -0
- package/core/icons/flags/mu.svg +1 -0
- package/core/icons/flags/mx.svg +1 -0
- package/core/icons/flags/ng.svg +1 -0
- package/core/icons/flags/pa.svg +1 -0
- package/core/icons/flags/ph.svg +1 -0
- package/core/icons/flags/pk.svg +1 -0
- package/core/icons/flags/pt.svg +1 -0
- package/core/icons/flags/ru.svg +1 -0
- package/core/icons/flags/sa.svg +1 -0
- package/core/icons/flags/sd.svg +1 -0
- package/core/icons/flags/se.svg +1 -0
- package/core/icons/flags/th.svg +1 -0
- package/core/icons/flags/tm.svg +1 -0
- package/core/icons/flags/tr.svg +1 -0
- package/core/icons/flags/us.svg +1 -0
- package/core/icons/flags/uy.svg +1 -0
- package/core/icons/flags/vn.svg +1 -0
- package/core/icons/flags/za.svg +1 -0
- package/core/images/exit-popup/subscriber-1.jpg +0 -0
- package/core/images/exit-popup/subscriber-2.jpg +0 -0
- package/core/images/exit-popup/subscriber-3.jpg +0 -0
- package/core/images/exit-popup/subscriber-4.jpg +0 -0
- package/core/images/placeholder/photo-1.jpg +0 -0
- package/core/images/placeholder/photo-2.jpg +0 -0
- package/core/images/placeholder/photo-3.jpg +0 -0
- package/core/js/core/analytics-loader.js +253 -0
- package/core/js/core/app-shell.js +136 -0
- package/core/js/core/appearance.js +195 -0
- package/core/js/core/auth.js +457 -0
- package/core/js/core/complete.js +72 -0
- package/core/js/core/consent.js +384 -0
- package/core/js/core/dev-icon-audit.js +63 -0
- package/core/js/core/dev-palette.js +670 -0
- package/core/js/core/dev-sections.js +53 -0
- package/core/js/core/exit-popup.js +276 -0
- package/core/js/core/initialize.js +8 -0
- package/core/js/core/language-switcher.js +167 -0
- package/core/js/core/lazy-loading.js +479 -0
- package/core/js/core/motion.js +28 -0
- package/core/js/core/query-strings.js +146 -0
- package/core/js/core/service-worker.js +28 -0
- package/core/js/core/social-sharing.js +293 -0
- package/core/js/first-paint.js +35 -0
- package/core/js/layouts/modules/utilities/redirect.js +122 -0
- package/core/js/libs/admin-helpers.js +62 -0
- package/core/js/libs/alert-dismiss.js +35 -0
- package/core/js/libs/analytics.js +368 -0
- package/core/js/libs/auth/email.js +144 -0
- package/core/js/libs/auth/errors.js +119 -0
- package/core/js/libs/auth/forms.js +206 -0
- package/core/js/libs/auth/index.js +181 -0
- package/core/js/libs/auth/oauth.js +394 -0
- package/core/js/libs/auth/orphan.js +110 -0
- package/core/js/libs/auth/password-toggle.js +44 -0
- package/core/js/libs/auth/session-params.js +266 -0
- package/core/js/libs/auth/tracking.js +41 -0
- package/core/js/libs/charts.js +516 -0
- package/core/js/libs/consent-region.js +127 -0
- package/core/js/libs/dev.js +150 -0
- package/core/js/libs/graph.js +201 -0
- package/core/js/libs/initialize-tooltips.js +31 -0
- package/core/js/libs/logger.js +38 -0
- package/core/js/libs/omega-copy.js +89 -0
- package/core/js/libs/path-prefix.js +44 -0
- package/core/js/libs/payment-config.js +76 -0
- package/core/js/libs/recaptcha.js +94 -0
- package/core/js/libs/sale-name.js +295 -0
- package/core/js/libs/showcase-frames.js +37 -0
- package/core/js/libs/srcset.js +69 -0
- package/core/js/libs/tracking-consent.js +161 -0
- package/core/js/main.js +144 -0
- package/core/js/pages/404/index.js +57 -0
- package/core/js/pages/admin/calendar/calendar-core.js +701 -0
- package/core/js/pages/admin/calendar/calendar-events.js +853 -0
- package/core/js/pages/admin/calendar/calendar-renderer.js +807 -0
- package/core/js/pages/admin/calendar/campaign-preview.js +105 -0
- package/core/js/pages/admin/calendar/index.js +40 -0
- package/core/js/pages/admin/firebase/index.js +727 -0
- package/core/js/pages/admin/index.js +531 -0
- package/core/js/pages/admin/posts/editor/index.js +230 -0
- package/core/js/pages/admin/posts/index.js +237 -0
- package/core/js/pages/admin/studio/index.js +538 -0
- package/core/js/pages/admin/users/index.js +669 -0
- package/core/js/pages/admin/users/new/index.js +65 -0
- package/core/js/pages/admin/verts/index.js +407 -0
- package/core/js/pages/alternatives/[alternative]/index.js +17 -0
- package/core/js/pages/app/index.js +135 -0
- package/core/js/pages/blog/[slug].js +132 -0
- package/core/js/pages/blog/_search.mjs +108 -0
- package/core/js/pages/blog/index.js +193 -0
- package/core/js/pages/blog/page/[num]/index.js +7 -0
- package/core/js/pages/connections/callback/index.js +148 -0
- package/core/js/pages/contact/index.js +170 -0
- package/core/js/pages/cookies.js +2 -0
- package/core/js/pages/dashboard/account/index.js +366 -0
- package/core/js/pages/dashboard/account/modules/orders.js +82 -0
- package/core/js/pages/dashboard/account/sections/api-keys.js +149 -0
- package/core/js/pages/dashboard/account/sections/billing.js +1667 -0
- package/core/js/pages/dashboard/account/sections/connections.js +333 -0
- package/core/js/pages/dashboard/account/sections/data-request.js +225 -0
- package/core/js/pages/dashboard/account/sections/delete.js +80 -0
- package/core/js/pages/dashboard/account/sections/notifications.js +167 -0
- package/core/js/pages/dashboard/account/sections/orders.js +151 -0
- package/core/js/pages/dashboard/account/sections/profile.js +200 -0
- package/core/js/pages/dashboard/account/sections/referrals.js +217 -0
- package/core/js/pages/dashboard/account/sections/refund.js +253 -0
- package/core/js/pages/dashboard/account/sections/security.js +726 -0
- package/core/js/pages/dashboard/account/sections/team.js +247 -0
- package/core/js/pages/download/index.js +418 -0
- package/core/js/pages/extension/index.js +164 -0
- package/core/js/pages/extension/installed/index.js +135 -0
- package/core/js/pages/feedback/index.js +193 -0
- package/core/js/pages/legal/_document.js +91 -0
- package/core/js/pages/payment/checkout/index.js +420 -0
- package/core/js/pages/payment/checkout/modules/api.js +139 -0
- package/core/js/pages/payment/checkout/modules/dev-section.js +175 -0
- package/core/js/pages/payment/checkout/modules/discount.js +69 -0
- package/core/js/pages/payment/checkout/modules/pricing.js +73 -0
- package/core/js/pages/payment/checkout/modules/state.js +339 -0
- package/core/js/pages/payment/checkout/modules/tracking.js +54 -0
- package/core/js/pages/payment/confirmation/index.js +91 -0
- package/core/js/pages/payment/confirmation/modules/celebration.js +45 -0
- package/core/js/pages/payment/confirmation/modules/state.js +112 -0
- package/core/js/pages/payment/confirmation/modules/tracking.js +133 -0
- package/core/js/pages/payment/confirmation/modules/verify.js +142 -0
- package/core/js/pages/portal/email-preferences/index.js +183 -0
- package/core/js/pages/pricing/index.js +425 -0
- package/core/js/pages/privacy.js +2 -0
- package/core/js/pages/reset/index.js +12 -0
- package/core/js/pages/signin/index.js +22 -0
- package/core/js/pages/signup/index.js +23 -0
- package/core/js/pages/status/index.js +687 -0
- package/core/js/pages/terms.js +2 -0
- package/core/js/pages/test/components/[category]/[name]/index.js +26 -0
- package/core/js/pages/test/libraries/appearance/index.js +220 -0
- package/core/js/pages/test/libraries/form-manager/index.js +328 -0
- package/core/js/pages/test/libraries/layers/index.js +16 -0
- package/core/js/pages/test/libraries/verts/index.js +68 -0
- package/core/js/pages/test/sections/[category]/[name]/index.js +28 -0
- package/core/js/pages/test/styleguide/index.js +35 -0
- package/core/js/pages/token/index.js +203 -0
- package/core/logos/brandmarks/original/apple-app-store.svg +1 -0
- package/core/logos/brandmarks/original/apple.svg +6 -0
- package/core/logos/brandmarks/original/bitbucket.svg +14 -0
- package/core/logos/brandmarks/original/bitcoin.svg +1 -0
- package/core/logos/brandmarks/original/bluesky.svg +7 -0
- package/core/logos/brandmarks/original/bootstrap.svg +43 -0
- package/core/logos/brandmarks/original/brave.svg +1 -0
- package/core/logos/brandmarks/original/chrome.svg +1 -0
- package/core/logos/brandmarks/original/discord.svg +1 -0
- package/core/logos/brandmarks/original/dropbox.svg +10 -0
- package/core/logos/brandmarks/original/edge.svg +1 -0
- package/core/logos/brandmarks/original/facebook-f.svg +1 -0
- package/core/logos/brandmarks/original/facebook.svg +8 -0
- package/core/logos/brandmarks/original/figma.svg +10 -0
- package/core/logos/brandmarks/original/firefox.svg +1 -0
- package/core/logos/brandmarks/original/github.svg +6 -0
- package/core/logos/brandmarks/original/gitlab.svg +17 -0
- package/core/logos/brandmarks/original/google-a-s.svg +1 -0
- package/core/logos/brandmarks/original/google-chrome-webstore.svg +49 -0
- package/core/logos/brandmarks/original/google-play-store.svg +1 -0
- package/core/logos/brandmarks/original/google-web-search.svg +1 -0
- package/core/logos/brandmarks/original/google.svg +1 -0
- package/core/logos/brandmarks/original/gulp.svg +4 -0
- package/core/logos/brandmarks/original/html-5.svg +1 -0
- package/core/logos/brandmarks/original/instagram.svg +1 -0
- package/core/logos/brandmarks/original/javascript.svg +1 -0
- package/core/logos/brandmarks/original/jira.svg +18 -0
- package/core/logos/brandmarks/original/kick.svg +7 -0
- package/core/logos/brandmarks/original/linkedin.svg +1 -0
- package/core/logos/brandmarks/original/linux.svg +28 -0
- package/core/logos/brandmarks/original/messenger.svg +16 -0
- package/core/logos/brandmarks/original/microsoft.svg +1 -0
- package/core/logos/brandmarks/original/npm.svg +8 -0
- package/core/logos/brandmarks/original/opera.svg +1 -0
- package/core/logos/brandmarks/original/patreon.svg +6 -0
- package/core/logos/brandmarks/original/pinterest.svg +6 -0
- package/core/logos/brandmarks/original/reddit.svg +1 -0
- package/core/logos/brandmarks/original/safari.svg +31 -0
- package/core/logos/brandmarks/original/sass.svg +3 -0
- package/core/logos/brandmarks/original/signal.svg +6 -0
- package/core/logos/brandmarks/original/skype.svg +47 -0
- package/core/logos/brandmarks/original/slack.svg +33 -0
- package/core/logos/brandmarks/original/soundcloud.svg +1 -0
- package/core/logos/brandmarks/original/spotify.svg +5 -0
- package/core/logos/brandmarks/original/steam.svg +6 -0
- package/core/logos/brandmarks/original/telegram.svg +14 -0
- package/core/logos/brandmarks/original/tiktok.svg +1 -0
- package/core/logos/brandmarks/original/trello.svg +16 -0
- package/core/logos/brandmarks/original/tumblr.svg +1 -0
- package/core/logos/brandmarks/original/twitch.svg +6 -0
- package/core/logos/brandmarks/original/twitter.svg +6 -0
- package/core/logos/brandmarks/original/unity.svg +6 -0
- package/core/logos/brandmarks/original/x.svg +7 -0
- package/core/logos/brandmarks/original/yahoo-y.svg +1 -0
- package/core/logos/brandmarks/original/youtube-square.svg +1 -0
- package/core/logos/brandmarks/original/youtube.svg +1 -0
- package/core/logos/combomarks/dark/airbnb.svg +30 -0
- package/core/logos/combomarks/dark/slack.svg +38 -0
- package/core/logos/combomarks/dark/spotify.svg +35 -0
- package/core/logos/combomarks/dark/twilio.svg +26 -0
- package/core/logos/combomarks/dark/weebly.svg +35 -0
- package/core/logos/combomarks/gray/airbnb.svg +33 -0
- package/core/logos/combomarks/gray/alphabet.svg +23 -0
- package/core/logos/combomarks/gray/amazon.svg +38 -0
- package/core/logos/combomarks/gray/boring-company.svg +91 -0
- package/core/logos/combomarks/gray/burberry.svg +239 -0
- package/core/logos/combomarks/gray/embark.svg +21 -0
- package/core/logos/combomarks/gray/fitbit.svg +61 -0
- package/core/logos/combomarks/gray/fred-perry.svg +94 -0
- package/core/logos/combomarks/gray/google.svg +27 -0
- package/core/logos/combomarks/gray/hollister.svg +34 -0
- package/core/logos/combomarks/gray/hubspot.svg +27 -0
- package/core/logos/combomarks/gray/kaplan.svg +33 -0
- package/core/logos/combomarks/gray/lenovo.svg +27 -0
- package/core/logos/combomarks/gray/levis.svg +25 -0
- package/core/logos/combomarks/gray/mapbox.svg +37 -0
- package/core/logos/combomarks/gray/netflix.svg +15 -0
- package/core/logos/combomarks/gray/new-balance.svg +32 -0
- package/core/logos/combomarks/gray/nike.svg +17 -0
- package/core/logos/combomarks/gray/paypal.svg +41 -0
- package/core/logos/combomarks/gray/puma.svg +82 -0
- package/core/logos/combomarks/gray/samsung.svg +26 -0
- package/core/logos/combomarks/gray/shopify.svg +36 -0
- package/core/logos/combomarks/gray/slack.svg +42 -0
- package/core/logos/combomarks/gray/spotify.svg +38 -0
- package/core/logos/combomarks/gray/stripe.svg +24 -0
- package/core/logos/combomarks/gray/tnf.svg +30 -0
- package/core/logos/combomarks/gray/twilio.svg +29 -0
- package/core/logos/combomarks/gray/uber.svg +24 -0
- package/core/logos/combomarks/gray/weebly.svg +38 -0
- package/core/logos/combomarks/original/airbnb.svg +33 -0
- package/core/logos/combomarks/original/alphabet.svg +23 -0
- package/core/logos/combomarks/original/amazon.svg +38 -0
- package/core/logos/combomarks/original/asana.svg +8 -0
- package/core/logos/combomarks/original/boring-company.svg +91 -0
- package/core/logos/combomarks/original/discord.svg +6 -0
- package/core/logos/combomarks/original/embark.svg +24 -0
- package/core/logos/combomarks/original/fitbit.svg +60 -0
- package/core/logos/combomarks/original/github.svg +6 -0
- package/core/logos/combomarks/original/gitlab.svg +20 -0
- package/core/logos/combomarks/original/google.svg +28 -0
- package/core/logos/combomarks/original/hubspot.svg +29 -0
- package/core/logos/combomarks/original/instagram.svg +7 -0
- package/core/logos/combomarks/original/kickstarter.svg +6 -0
- package/core/logos/combomarks/original/lenovo.svg +24 -0
- package/core/logos/combomarks/original/linkedin.svg +6 -0
- package/core/logos/combomarks/original/mapbox.svg +39 -0
- package/core/logos/combomarks/original/mastodon.svg +7 -0
- package/core/logos/combomarks/original/medium.svg +6 -0
- package/core/logos/combomarks/original/meta.svg +22 -0
- package/core/logos/combomarks/original/microsoft.svg +13 -0
- package/core/logos/combomarks/original/monday.svg +12 -0
- package/core/logos/combomarks/original/netflix.svg +15 -0
- package/core/logos/combomarks/original/notion.svg +9 -0
- package/core/logos/combomarks/original/paypal.svg +41 -0
- package/core/logos/combomarks/original/reddit.svg +13 -0
- package/core/logos/combomarks/original/samsung.svg +25 -0
- package/core/logos/combomarks/original/shopify.svg +35 -0
- package/core/logos/combomarks/original/slack.svg +47 -0
- package/core/logos/combomarks/original/spotify.svg +37 -0
- package/core/logos/combomarks/original/stackoverflow.svg +28 -0
- package/core/logos/combomarks/original/stripe.svg +24 -0
- package/core/logos/combomarks/original/tiktok.svg +12 -0
- package/core/logos/combomarks/original/tumblr.svg +6 -0
- package/core/logos/combomarks/original/uber.svg +24 -0
- package/core/logos/combomarks/original/weebly.svg +34 -0
- package/core/logos/combomarks/original/whatsapp.svg +20 -0
- package/core/logos/combomarks/original/youtube.svg +10 -0
- package/core/logos/combomarks/original/zoom.svg +7 -0
- package/core/logos/combomarks/white/airbnb.svg +33 -0
- package/core/logos/combomarks/white/alphabet.svg +23 -0
- package/core/logos/combomarks/white/amazon.svg +38 -0
- package/core/logos/combomarks/white/boring-company.svg +91 -0
- package/core/logos/combomarks/white/embark.svg +21 -0
- package/core/logos/combomarks/white/fitbit.svg +61 -0
- package/core/logos/combomarks/white/google.svg +27 -0
- package/core/logos/combomarks/white/hubspot.svg +27 -0
- package/core/logos/combomarks/white/kaplan.svg +33 -0
- package/core/logos/combomarks/white/lenovo.svg +27 -0
- package/core/logos/combomarks/white/mapbox.svg +37 -0
- package/core/logos/combomarks/white/netflix.svg +15 -0
- package/core/logos/combomarks/white/paypal.svg +40 -0
- package/core/logos/combomarks/white/samsung.svg +26 -0
- package/core/logos/combomarks/white/shopify.svg +36 -0
- package/core/logos/combomarks/white/slack.svg +42 -0
- package/core/logos/combomarks/white/spotify.svg +38 -0
- package/core/logos/combomarks/white/stripe.svg +24 -0
- package/core/logos/combomarks/white/twilio.svg +29 -0
- package/core/logos/combomarks/white/uber.svg +24 -0
- package/core/logos/combomarks/white/weebly.svg +38 -0
- package/defaults/pages/404.md +4 -0
- package/defaults/pages/about.md +4 -0
- package/defaults/pages/admin/calendar/index.html +4 -0
- package/defaults/pages/admin/firebase/index.html +4 -0
- package/defaults/pages/admin/index.md +4 -0
- package/defaults/pages/admin/posts/editor.html +4 -0
- package/defaults/pages/admin/posts/index.html +4 -0
- package/defaults/pages/admin/stackblitz/index.html +4 -0
- package/defaults/pages/admin/studio/index.html +4 -0
- package/defaults/pages/admin/users/index.html +4 -0
- package/defaults/pages/admin/users/new.html +4 -0
- package/defaults/pages/admin/verts/index.html +4 -0
- package/defaults/pages/ads-txt.html +11 -0
- package/defaults/pages/alternatives/index.md +4 -0
- package/defaults/pages/app.md +4 -0
- package/defaults/pages/auth/reset.md +4 -0
- package/defaults/pages/auth/signin.md +4 -0
- package/defaults/pages/auth/signup.md +4 -0
- package/defaults/pages/auth/token.md +4 -0
- package/defaults/pages/blog/categories/category.html +21 -0
- package/defaults/pages/blog/categories.md +4 -0
- package/defaults/pages/blog/index-json.html +27 -0
- package/defaults/pages/blog/tags/tag.html +21 -0
- package/defaults/pages/blog/tags.md +4 -0
- package/defaults/pages/blog.md +22 -0
- package/defaults/pages/careers.md +4 -0
- package/defaults/pages/connections/callback.md +4 -0
- package/defaults/pages/contact.md +4 -0
- package/defaults/pages/dashboard/account.md +4 -0
- package/defaults/pages/dashboard/index.md +12 -0
- package/defaults/pages/download.md +4 -0
- package/defaults/pages/extension/index.html +4 -0
- package/defaults/pages/extension/installed.html +4 -0
- package/defaults/pages/feedback.md +4 -0
- package/defaults/pages/feeds/posts-json.html +40 -0
- package/defaults/pages/feeds/posts-xml.html +38 -0
- package/defaults/pages/humans.html +25 -0
- package/defaults/pages/index.md +4 -0
- package/defaults/pages/legal/cookies.md +4 -0
- package/defaults/pages/legal/privacy.md +4 -0
- package/defaults/pages/legal/terms.md +4 -0
- package/defaults/pages/llms-txt.html +46 -0
- package/defaults/pages/opensearch.html +16 -0
- package/defaults/pages/pages-json.html +42 -0
- package/defaults/pages/payment/checkout.md +4 -0
- package/defaults/pages/payment/confirmation.md +4 -0
- package/defaults/pages/portal/email-preferences.md +4 -0
- package/defaults/pages/pricing.md +4 -0
- package/defaults/pages/redirects/account.md +12 -0
- package/defaults/pages/redirects/admin/dashboard.md +11 -0
- package/defaults/pages/redirects/auth/change-password.md +9 -0
- package/defaults/pages/redirects/auth/forgot.md +9 -0
- package/defaults/pages/redirects/auth/join.md +9 -0
- package/defaults/pages/redirects/auth/login.md +9 -0
- package/defaults/pages/redirects/auth/recover.md +9 -0
- package/defaults/pages/redirects/auth/register.md +9 -0
- package/defaults/pages/redirects/auth/reset-password.md +9 -0
- package/defaults/pages/redirects/billing/cancel.md +9 -0
- package/defaults/pages/redirects/billing/refund.md +9 -0
- package/defaults/pages/robots.html +36 -0
- package/defaults/pages/security-txt.html +11 -0
- package/defaults/pages/sitemap.html +37 -0
- package/defaults/pages/status.md +4 -0
- package/defaults/pages/team/index.md +4 -0
- package/defaults/pages/test/account/dashboard.html +16 -0
- package/defaults/pages/test/index.md +12 -0
- package/defaults/pages/test/libraries/appearance.html +268 -0
- package/defaults/pages/test/libraries/cover.html +50 -0
- package/defaults/pages/test/libraries/error.html +30 -0
- package/defaults/pages/test/libraries/firestore.html +202 -0
- package/defaults/pages/test/libraries/form-manager.html +374 -0
- package/defaults/pages/test/libraries/layers.html +52 -0
- package/defaults/pages/test/libraries/lazy-loading.html +450 -0
- package/defaults/pages/test/libraries/verts.html +149 -0
- package/defaults/pages/test/redirect/external.md +13 -0
- package/defaults/pages/test/redirect/internal.md +13 -0
- package/defaults/pages/test/styleguide/index.html +588 -0
- package/defaults/pages/test/translation/index.md +50 -0
- package/defaults/pages/updates/index.md +4 -0
- package/defaults/sample-posts/2026-01-12-welcome-to-the-blog.md +26 -0
- package/defaults/sample-posts/2026-02-03-a-field-guide-to-good-defaults.md +50 -0
- package/defaults/sample-posts/2026-02-24-shipping-week-notes.md +37 -0
- package/defaults/sample-posts/2026-03-17-the-case-for-one-config.md +36 -0
- package/defaults/sample-posts/2026-04-09-write-release-notes-people-read.md +34 -0
- package/defaults/sample-posts/2026-05-21-dark-mode-done-properly.md +38 -0
- package/defaults/sample-posts/2026-06-02-the-boring-deploy-is-the-good-deploy.md +30 -0
- package/defaults/sample-posts/2026-06-11-naming-things-a-survival-guide.md +30 -0
- package/defaults/sample-posts/2026-06-19-your-pricing-page-is-a-product.md +28 -0
- package/defaults/sample-posts/2026-06-30-email-is-an-api-with-feelings.md +28 -0
- package/defaults/sample-posts/2026-07-08-ship-the-docs-with-the-diff.md +30 -0
- package/defaults/sample-team/avery-quinn.md +22 -0
- package/defaults/sample-team/jordan-reyes.md +25 -0
- package/defaults/sample-team/riley-nakamura.md +22 -0
- package/defaults/sample-team/sam-okafor.md +22 -0
- package/defaults/sample-updates/v1.0.0.md +28 -0
- package/defaults/sample-updates/v1.1.0.md +27 -0
- package/defaults/sample-updates/v1.2.0.md +27 -0
- package/defaults/sample-updates/v1.3.0.md +28 -0
- package/defaults/showcase/components.html +62 -0
- package/defaults/showcase/entry.html +76 -0
- package/defaults/showcase/frame.html +62 -0
- package/defaults/showcase/index.html +59 -0
- package/dist/assets.js +1349 -0
- package/dist/brand-tokens.js +195 -0
- package/dist/build.js +192 -0
- package/dist/cachebreak-html.js +71 -0
- package/dist/cli-run.js +25 -0
- package/dist/cli.js +47 -0
- package/dist/collections.js +183 -0
- package/dist/commands/audit.js +470 -0
- package/dist/commands/build.js +197 -0
- package/dist/commands/clean.js +18 -0
- package/dist/commands/customize.js +125 -0
- package/dist/commands/deploy.js +441 -0
- package/dist/commands/dev.js +1067 -0
- package/dist/commands/install.js +31 -0
- package/dist/commands/lib/deploy-precheck.js +43 -0
- package/dist/commands/lib/ensure-target.js +115 -0
- package/dist/commands/migrate.js +86 -0
- package/dist/commands/purge.js +31 -0
- package/dist/commands/test.js +237 -0
- package/dist/commands/translate.js +57 -0
- package/dist/commands/update.js +22 -0
- package/dist/commands/version.js +11 -0
- package/dist/config-sections.js +245 -0
- package/dist/consumer-scan.js +118 -0
- package/dist/consumer.js +49 -0
- package/dist/customize.js +328 -0
- package/dist/decisions.js +153 -0
- package/dist/dist-audit.js +417 -0
- package/dist/dynamic-pages.js +357 -0
- package/dist/engine.js +1402 -0
- package/dist/firebase-auth-helpers.js +198 -0
- package/dist/font-metrics.js +420 -0
- package/dist/frontmatter-liquid.js +253 -0
- package/dist/github-secrets.js +80 -0
- package/dist/hero-animations.js +170 -0
- package/dist/imagemin.js +261 -0
- package/dist/index.js +41 -0
- package/dist/inline-icons.js +65 -0
- package/dist/language-flags.js +55 -0
- package/dist/layers.js +80 -0
- package/dist/layouts.js +44 -0
- package/dist/limit-collections.js +199 -0
- package/dist/link-resolver.js +303 -0
- package/dist/markdown-images.js +85 -0
- package/dist/merge.js +20 -0
- package/dist/migrate/codemod.js +172 -0
- package/dist/migrate/config-convert.js +448 -0
- package/dist/migrate/consumer-assets.js +130 -0
- package/dist/migrate/index.js +223 -0
- package/dist/migrate/lint.js +108 -0
- package/dist/migrate/rules.js +1929 -0
- package/dist/minify-html.js +148 -0
- package/dist/mode-helpers.js +96 -0
- package/dist/omega-bin.js +7 -0
- package/dist/overrides.js +190 -0
- package/dist/path-prefix.js +167 -0
- package/dist/paths.js +37 -0
- package/dist/pricing.js +301 -0
- package/dist/purge.js +95 -0
- package/dist/redirect-page.js +45 -0
- package/dist/sample-content.js +210 -0
- package/dist/scaffold.js +123 -0
- package/dist/sections.js +810 -0
- package/dist/service-worker.js +200 -0
- package/dist/social-pages.js +142 -0
- package/dist/srcset.js +67 -0
- package/dist/static-assets.js +154 -0
- package/dist/target-shortlinks.js +123 -0
- package/dist/theme-vocabulary.js +76 -0
- package/dist/translate/collect-text-nodes.js +93 -0
- package/dist/translate/default-routes.js +152 -0
- package/dist/translate/generate-defaults.js +297 -0
- package/dist/translate/index.js +568 -0
- package/dist/translate/packaged-defaults.js +127 -0
- package/dist/translate/sitemap.js +108 -0
- package/dist/vendor/account/engine.js +182 -0
- package/dist/vendor/account/features.js +220 -0
- package/dist/vendor/account/index.js +53 -0
- package/dist/vendor/account/schema.js +272 -0
- package/dist/vendor/account/subscription.js +38 -0
- package/dist/vendor/config/company.js +31 -0
- package/dist/vendor/config/defaults.js +173 -0
- package/dist/vendor/config/demo.js +18 -0
- package/dist/vendor/config/desktop-artifacts.js +110 -0
- package/dist/vendor/config/edit.js +769 -0
- package/dist/vendor/config/env-delivery.js +145 -0
- package/dist/vendor/config/env-rules.js +93 -0
- package/dist/vendor/config/env-schema.js +1078 -0
- package/dist/vendor/config/env.js +445 -0
- package/dist/vendor/config/hooks.js +97 -0
- package/dist/vendor/config/index.js +237 -0
- package/dist/vendor/config/instances.js +208 -0
- package/dist/vendor/config/load.js +490 -0
- package/dist/vendor/config/merge.js +68 -0
- package/dist/vendor/config/order.js +139 -0
- package/dist/vendor/config/ports.js +374 -0
- package/dist/vendor/config/providers.js +32 -0
- package/dist/vendor/config/repo.js +142 -0
- package/dist/vendor/config/retired-keys.js +430 -0
- package/dist/vendor/config/schema.js +1610 -0
- package/dist/vendor/config/secrets.js +50 -0
- package/dist/vendor/config/seed.js +34 -0
- package/dist/vendor/config/site-global.js +205 -0
- package/dist/vendor/config/validate.js +554 -0
- package/dist/vendor/config/winback.js +61 -0
- package/dist/vendor/devkit/actions-secrets.js +145 -0
- package/dist/vendor/devkit/attach-log-file.js +262 -0
- package/dist/vendor/devkit/bare-requires.js +153 -0
- package/dist/vendor/devkit/bundle.js +292 -0
- package/dist/vendor/devkit/ci-workflows.js +520 -0
- package/dist/vendor/devkit/cli-router.js +156 -0
- package/dist/vendor/devkit/command-path.js +46 -0
- package/dist/vendor/devkit/defaults-engine.js +372 -0
- package/dist/vendor/devkit/deploy-precheck.js +54 -0
- package/dist/vendor/devkit/deploy-record.js +180 -0
- package/dist/vendor/devkit/deploy.js +286 -0
- package/dist/vendor/devkit/env-watch.js +132 -0
- package/dist/vendor/devkit/framework-deps.js +46 -0
- package/dist/vendor/devkit/icons.js +178 -0
- package/dist/vendor/devkit/license.js +155 -0
- package/dist/vendor/devkit/local-https.js +360 -0
- package/dist/vendor/devkit/local.js +1905 -0
- package/dist/vendor/devkit/logger.js +128 -0
- package/dist/vendor/devkit/merge-line-files.js +296 -0
- package/dist/vendor/devkit/omega-bin.js +345 -0
- package/dist/vendor/devkit/reads.js +274 -0
- package/dist/vendor/devkit/safe-install.js +18 -0
- package/dist/vendor/devkit/scaffold-guard.js +96 -0
- package/dist/vendor/devkit/stop-signals.js +28 -0
- package/dist/vendor/devkit/strip-dev-blocks-plugin.js +29 -0
- package/dist/vendor/devkit/strip-dev-blocks.js +32 -0
- package/dist/vendor/devkit/target-secrets.js +165 -0
- package/dist/vendor/devkit/test/scope.js +162 -0
- package/dist/vendor/devkit/translate/cache.js +84 -0
- package/dist/vendor/devkit/translate/engine.js +243 -0
- package/dist/vendor/devkit/translate/index.js +49 -0
- package/dist/vendor/devkit/translate/languages.js +134 -0
- package/dist/vendor/devkit/translate/providers.js +188 -0
- package/dist/vendor/devkit/update.js +569 -0
- package/dist/vendor/template-kit/data/language-flags.js +54 -0
- package/dist/vendor/template-kit/data/languages.js +195 -0
- package/dist/vendor/template-kit/data/social-urls.js +26 -0
- package/dist/vendor/template-kit/filters.js +227 -0
- package/dist/vendor/template-kit/index.js +28 -0
- package/dist/vendor/template-kit/jekyll-compat.js +268 -0
- package/dist/vendor/template-kit/register-liquid.js +0 -0
- package/dist/vendor/template-kit/tags/collections.js +191 -0
- package/dist/vendor/template-kit/tags/conditionals.js +101 -0
- package/dist/vendor/template-kit/tags/content.js +175 -0
- package/dist/vendor/template-kit/tags/index.js +33 -0
- package/dist/vendor/template-kit/tags/media.js +376 -0
- package/dist/vendor/template-kit/variable-resolver.js +163 -0
- package/docs/ads-system.md +109 -0
- package/docs/classy-v2/DIRECTION.md +92 -0
- package/docs/classy-v2/draft-1.html +1932 -0
- package/docs/classy-v2/draft-2.html +1956 -0
- package/docs/frontmatter.md +153 -0
- package/docs/index.md +254 -0
- package/docs/libs.md +298 -0
- package/docs/omega-sections-spec.md +159 -0
- package/docs/page-contract.md +112 -0
- package/docs/sections.md +845 -0
- package/docs/shared/agent-docs.md +89 -0
- package/docs/shared/analytics.md +612 -0
- package/docs/shared/brands.md +51 -0
- package/docs/shared/breaking-changes.md +497 -0
- package/docs/shared/config.md +1387 -0
- package/docs/shared/deploys.md +215 -0
- package/docs/shared/icons.md +201 -0
- package/docs/shared/local-dev.md +147 -0
- package/docs/shared/logging.md +202 -0
- package/docs/shared/monitoring.md +153 -0
- package/docs/shared/publishing.md +183 -0
- package/docs/shared/rulings.md +34 -0
- package/docs/shared/testing.md +147 -0
- package/docs/shared/theming.md +604 -0
- package/docs/shared/translation.md +291 -0
- package/docs/shared/updates.md +61 -0
- package/docs/template-kit.md +128 -0
- package/docs/test-framework.md +163 -0
- package/package.json +122 -0
- package/runtime/boot.js +149 -0
- package/runtime/icons.js +77 -0
- package/runtime/manager.js +36 -0
- package/scaffold/.github/workflows/build.yml +139 -0
- package/scaffold/.nvmrc +1 -0
- package/scaffold/AGENTS.md +55 -0
- package/scaffold/CLAUDE.md +1 -0
- package/scaffold/_.gitattributes +4 -0
- package/scaffold/_.gitignore +27 -0
- package/scaffold/config/omega.json5 +20 -0
- package/scaffold/src/assets/css/pages/.gitkeep +0 -0
- package/scaffold/src/assets/images/.gitkeep +0 -0
- package/scaffold/src/assets/js/pages/.gitkeep +0 -0
- package/scaffold/src/pages/.gitkeep +0 -0
- package/scaffold/src/pages/example.md.txt +94 -0
- package/scaffold/src/service-worker.js +16 -0
- package/sw/entry.js +19 -0
- package/sw/manager.js +281 -0
- package/themes/_template/README.md +115 -0
- package/themes/_template/_config.scss +60 -0
- package/themes/_template/_theme.js +14 -0
- package/themes/_template/_theme.scss +28 -0
- package/themes/_template/css/base/_root.scss +19 -0
- package/themes/_template/css/components/_components.scss +23 -0
- package/themes/base/README.md +5 -0
- package/themes/base/_components/data/org-chart/component.html +33 -0
- package/themes/base/_components/data/org-chart/component.json5 +33 -0
- package/themes/base/_components/data/org-chart/component.scss +183 -0
- package/themes/base/_components/heading/masthead/component.html +22 -0
- package/themes/base/_components/heading/masthead/component.json5 +30 -0
- package/themes/base/_components/heading/section-head/component.html +18 -0
- package/themes/base/_components/heading/section-head/component.json5 +27 -0
- package/themes/base/_components/pricing/features/component.html +29 -0
- package/themes/base/_components/pricing/features/component.json5 +30 -0
- package/themes/base/_hero/orbit/index.html +30 -0
- package/themes/base/_hero/orbit/script.js +33 -0
- package/themes/base/_hero/orbit/style.scss +133 -0
- package/themes/base/_includes/admin/sections/sidebar.html +3 -0
- package/themes/base/_includes/admin/sections/topbar.html +3 -0
- package/themes/base/_includes/backend/sections/sidebar.html +3 -0
- package/themes/base/_includes/backend/sections/topbar.html +3 -0
- package/themes/base/_includes/frontend/components/connection-card.html +49 -0
- package/themes/base/_includes/frontend/components/post-card.html +54 -0
- package/themes/base/_includes/frontend/sections/account-connections.html +42 -0
- package/themes/base/_includes/frontend/sections/account-section-header.html +11 -0
- package/themes/base/_includes/frontend/sections/footer.html +154 -0
- package/themes/base/_includes/frontend/sections/nav.html +276 -0
- package/themes/base/_includes/global/sections/account.html +72 -0
- package/themes/base/_includes/global/sections/app-sidebar.html +248 -0
- package/themes/base/_includes/global/sections/app-topbar.html +228 -0
- package/themes/base/_includes/global/sections/page-header.html +99 -0
- package/themes/base/_layouts/admin/core/minimal-viewport-locked.html +22 -0
- package/themes/base/_layouts/admin/core/minimal.html +23 -0
- package/themes/base/_layouts/backend/core/base.html +57 -0
- package/themes/base/_layouts/backend/core/minimal-viewport-locked.html +32 -0
- package/themes/base/_layouts/backend/core/minimal.html +32 -0
- package/themes/base/_layouts/backend/pages/dashboard/index.html +230 -0
- package/themes/base/_layouts/frontend/core/base.html +31 -0
- package/themes/base/_layouts/frontend/core/cover.html +40 -0
- package/themes/base/_layouts/frontend/core/minimal.html +47 -0
- package/themes/base/_layouts/frontend/pages/404.html +54 -0
- package/themes/base/_layouts/frontend/pages/about.html +144 -0
- package/themes/base/_layouts/frontend/pages/account/index.html +2104 -0
- package/themes/base/_layouts/frontend/pages/alternatives/alternative.html +319 -0
- package/themes/base/_layouts/frontend/pages/alternatives/index.html +186 -0
- package/themes/base/_layouts/frontend/pages/app.html +142 -0
- package/themes/base/_layouts/frontend/pages/auth/reset.html +53 -0
- package/themes/base/_layouts/frontend/pages/auth/signin.html +90 -0
- package/themes/base/_layouts/frontend/pages/auth/signup.html +141 -0
- package/themes/base/_layouts/frontend/pages/auth/token.html +44 -0
- package/themes/base/_layouts/frontend/pages/blog/categories/category.html +88 -0
- package/themes/base/_layouts/frontend/pages/blog/categories/index.html +88 -0
- package/themes/base/_layouts/frontend/pages/blog/index.html +255 -0
- package/themes/base/_layouts/frontend/pages/blog/post.html +261 -0
- package/themes/base/_layouts/frontend/pages/blog/tags/index.html +84 -0
- package/themes/base/_layouts/frontend/pages/blog/tags/tag.html +88 -0
- package/themes/base/_layouts/frontend/pages/collection/category.html +72 -0
- package/themes/base/_layouts/frontend/pages/collection/document.html +54 -0
- package/themes/base/_layouts/frontend/pages/collection/index.html +84 -0
- package/themes/base/_layouts/frontend/pages/connections/callback.html +55 -0
- package/themes/base/_layouts/frontend/pages/contact.html +214 -0
- package/themes/base/_layouts/frontend/pages/download.html +793 -0
- package/themes/base/_layouts/frontend/pages/extension/index.html +253 -0
- package/themes/base/_layouts/frontend/pages/extension/installed.html +198 -0
- package/themes/base/_layouts/frontend/pages/feedback.html +171 -0
- package/themes/base/_layouts/frontend/pages/index.html +66 -0
- package/themes/base/_layouts/frontend/pages/legal/document.html +78 -0
- package/themes/base/_layouts/frontend/pages/payment/checkout.html +459 -0
- package/themes/base/_layouts/frontend/pages/payment/confirmation.html +131 -0
- package/themes/base/_layouts/frontend/pages/portal/email-preferences.html +104 -0
- package/themes/base/_layouts/frontend/pages/pricing.html +596 -0
- package/themes/base/_layouts/frontend/pages/status.html +361 -0
- package/themes/base/_layouts/frontend/pages/team/index.html +210 -0
- package/themes/base/_layouts/frontend/pages/team/member.html +125 -0
- package/themes/base/_layouts/frontend/pages/updates/index.html +119 -0
- package/themes/base/_layouts/frontend/pages/updates/update.html +118 -0
- package/themes/base/_sections/about/hero/section.html +68 -0
- package/themes/base/_sections/about/hero/section.json5 +58 -0
- package/themes/base/_sections/about/letter/section.html +60 -0
- package/themes/base/_sections/about/letter/section.json5 +56 -0
- package/themes/base/_sections/about/photo-band/section.html +24 -0
- package/themes/base/_sections/about/photo-band/section.json5 +23 -0
- package/themes/base/_sections/about/principles/section.html +17 -0
- package/themes/base/_sections/about/principles/section.json5 +34 -0
- package/themes/base/_sections/about/timeline/section.html +20 -0
- package/themes/base/_sections/about/timeline/section.json5 +34 -0
- package/themes/base/_sections/marketing/bento/section.html +91 -0
- package/themes/base/_sections/marketing/bento/section.json5 +152 -0
- package/themes/base/_sections/marketing/cta/section.html +44 -0
- package/themes/base/_sections/marketing/cta/section.json5 +47 -0
- package/themes/base/_sections/marketing/faq/section.html +52 -0
- package/themes/base/_sections/marketing/faq/section.json5 +68 -0
- package/themes/base/_sections/marketing/hero/section.html +349 -0
- package/themes/base/_sections/marketing/hero/section.json5 +335 -0
- package/themes/base/_sections/marketing/newsletter-cta/section.html +38 -0
- package/themes/base/_sections/marketing/newsletter-cta/section.js +86 -0
- package/themes/base/_sections/marketing/newsletter-cta/section.json5 +29 -0
- package/themes/base/_sections/marketing/pricing-cards/section.html +115 -0
- package/themes/base/_sections/marketing/pricing-cards/section.json5 +72 -0
- package/themes/base/_sections/marketing/product-demo/section.html +62 -0
- package/themes/base/_sections/marketing/product-demo/section.js +44 -0
- package/themes/base/_sections/marketing/product-demo/section.json5 +52 -0
- package/themes/base/_sections/marketing/prose/section.html +22 -0
- package/themes/base/_sections/marketing/prose/section.json5 +41 -0
- package/themes/base/_sections/marketing/showcase/section.html +35 -0
- package/themes/base/_sections/marketing/showcase/section.json5 +52 -0
- package/themes/base/_sections/marketing/stats/section.html +32 -0
- package/themes/base/_sections/marketing/stats/section.json5 +44 -0
- package/themes/base/_sections/marketing/testimonials/section.html +54 -0
- package/themes/base/_sections/marketing/testimonials/section.json5 +70 -0
- package/themes/base/_sections/marketing/trusted-by/section.html +30 -0
- package/themes/base/_sections/marketing/trusted-by/section.json5 +38 -0
- package/themes/base/_sections/verts/unit/section.html +7 -0
- package/themes/base/_sections/verts/unit/section.js +22 -0
- package/themes/base/_sections/verts/unit/section.json5 +24 -0
- package/themes/base/_sections/verts/unit/section.scss +24 -0
- package/themes/base/_theme.js +13 -0
- package/themes/base/_theme.scss +4 -0
- package/themes/bootstrap/_theme.js +16 -0
- package/themes/bootstrap/_theme.scss +11 -0
- package/themes/bootstrap/js/index.esm.js +19 -0
- package/themes/bootstrap/js/index.umd.js +34 -0
- package/themes/bootstrap/js/src/alert.js +87 -0
- package/themes/bootstrap/js/src/base-component.js +86 -0
- package/themes/bootstrap/js/src/button.js +72 -0
- package/themes/bootstrap/js/src/carousel.js +474 -0
- package/themes/bootstrap/js/src/collapse.js +297 -0
- package/themes/bootstrap/js/src/dom/data.js +55 -0
- package/themes/bootstrap/js/src/dom/event-handler.js +317 -0
- package/themes/bootstrap/js/src/dom/manipulator.js +71 -0
- package/themes/bootstrap/js/src/dom/selector-engine.js +126 -0
- package/themes/bootstrap/js/src/dropdown.js +458 -0
- package/themes/bootstrap/js/src/modal.js +378 -0
- package/themes/bootstrap/js/src/offcanvas.js +282 -0
- package/themes/bootstrap/js/src/popover.js +97 -0
- package/themes/bootstrap/js/src/scrollspy.js +296 -0
- package/themes/bootstrap/js/src/tab.js +315 -0
- package/themes/bootstrap/js/src/toast.js +224 -0
- package/themes/bootstrap/js/src/tooltip.js +632 -0
- package/themes/bootstrap/js/src/util/backdrop.js +151 -0
- package/themes/bootstrap/js/src/util/component-functions.js +35 -0
- package/themes/bootstrap/js/src/util/config.js +65 -0
- package/themes/bootstrap/js/src/util/focustrap.js +115 -0
- package/themes/bootstrap/js/src/util/index.js +306 -0
- package/themes/bootstrap/js/src/util/sanitizer.js +117 -0
- package/themes/bootstrap/js/src/util/scrollbar.js +114 -0
- package/themes/bootstrap/js/src/util/swipe.js +146 -0
- package/themes/bootstrap/js/src/util/template-factory.js +160 -0
- package/themes/bootstrap/overrides/_accordion.scss +21 -0
- package/themes/bootstrap/overrides/_avatars.scss +51 -0
- package/themes/bootstrap/overrides/_blog-images.scss +45 -0
- package/themes/bootstrap/overrides/_buttons-adaptive.scss +141 -0
- package/themes/bootstrap/overrides/_color-shades.scss +25 -0
- package/themes/bootstrap/overrides/_cursor-utilities.scss +13 -0
- package/themes/bootstrap/overrides/_index.scss +30 -0
- package/themes/bootstrap/overrides/_links.scss +26 -0
- package/themes/bootstrap/overrides/_soft-colors.scss +99 -0
- package/themes/bootstrap/overrides/_spacing-extended.scss +74 -0
- package/themes/bootstrap/overrides/_spinners.scss +22 -0
- package/themes/bootstrap/overrides/_typography-utilities.scss +40 -0
- package/themes/bootstrap/scss/_accordion.scss +153 -0
- package/themes/bootstrap/scss/_alert.scss +68 -0
- package/themes/bootstrap/scss/_badge.scss +38 -0
- package/themes/bootstrap/scss/_breadcrumb.scss +40 -0
- package/themes/bootstrap/scss/_button-group.scss +147 -0
- package/themes/bootstrap/scss/_buttons.scss +216 -0
- package/themes/bootstrap/scss/_card.scss +238 -0
- package/themes/bootstrap/scss/_carousel.scss +226 -0
- package/themes/bootstrap/scss/_close.scss +66 -0
- package/themes/bootstrap/scss/_containers.scss +41 -0
- package/themes/bootstrap/scss/_dropdown.scss +250 -0
- package/themes/bootstrap/scss/_forms.scss +9 -0
- package/themes/bootstrap/scss/_functions.scss +302 -0
- package/themes/bootstrap/scss/_grid.scss +39 -0
- package/themes/bootstrap/scss/_helpers.scss +12 -0
- package/themes/bootstrap/scss/_images.scss +42 -0
- package/themes/bootstrap/scss/_list-group.scss +199 -0
- package/themes/bootstrap/scss/_maps.scss +174 -0
- package/themes/bootstrap/scss/_mixins.scss +42 -0
- package/themes/bootstrap/scss/_modal.scss +240 -0
- package/themes/bootstrap/scss/_nav.scss +197 -0
- package/themes/bootstrap/scss/_navbar.scss +289 -0
- package/themes/bootstrap/scss/_offcanvas.scss +147 -0
- package/themes/bootstrap/scss/_pagination.scss +109 -0
- package/themes/bootstrap/scss/_placeholders.scss +51 -0
- package/themes/bootstrap/scss/_popover.scss +196 -0
- package/themes/bootstrap/scss/_progress.scss +68 -0
- package/themes/bootstrap/scss/_reboot.scss +611 -0
- package/themes/bootstrap/scss/_root.scss +187 -0
- package/themes/bootstrap/scss/_spinners.scss +85 -0
- package/themes/bootstrap/scss/_tables.scss +171 -0
- package/themes/bootstrap/scss/_toasts.scss +73 -0
- package/themes/bootstrap/scss/_tooltip.scss +119 -0
- package/themes/bootstrap/scss/_transitions.scss +27 -0
- package/themes/bootstrap/scss/_type.scss +106 -0
- package/themes/bootstrap/scss/_utilities.scss +806 -0
- package/themes/bootstrap/scss/_variables-dark.scss +102 -0
- package/themes/bootstrap/scss/_variables.scss +1753 -0
- package/themes/bootstrap/scss/bootstrap-grid.scss +62 -0
- package/themes/bootstrap/scss/bootstrap-reboot.scss +10 -0
- package/themes/bootstrap/scss/bootstrap-utilities.scss +19 -0
- package/themes/bootstrap/scss/bootstrap.scss +52 -0
- package/themes/bootstrap/scss/forms/_floating-labels.scss +97 -0
- package/themes/bootstrap/scss/forms/_form-check.scss +189 -0
- package/themes/bootstrap/scss/forms/_form-control.scss +214 -0
- package/themes/bootstrap/scss/forms/_form-range.scss +91 -0
- package/themes/bootstrap/scss/forms/_form-select.scss +80 -0
- package/themes/bootstrap/scss/forms/_form-text.scss +11 -0
- package/themes/bootstrap/scss/forms/_input-group.scss +132 -0
- package/themes/bootstrap/scss/forms/_labels.scss +36 -0
- package/themes/bootstrap/scss/forms/_validation.scss +12 -0
- package/themes/bootstrap/scss/helpers/_clearfix.scss +3 -0
- package/themes/bootstrap/scss/helpers/_color-bg.scss +7 -0
- package/themes/bootstrap/scss/helpers/_colored-links.scss +30 -0
- package/themes/bootstrap/scss/helpers/_focus-ring.scss +5 -0
- package/themes/bootstrap/scss/helpers/_icon-link.scss +25 -0
- package/themes/bootstrap/scss/helpers/_position.scss +36 -0
- package/themes/bootstrap/scss/helpers/_ratio.scss +26 -0
- package/themes/bootstrap/scss/helpers/_stacks.scss +15 -0
- package/themes/bootstrap/scss/helpers/_stretched-link.scss +15 -0
- package/themes/bootstrap/scss/helpers/_text-truncation.scss +7 -0
- package/themes/bootstrap/scss/helpers/_visually-hidden.scss +8 -0
- package/themes/bootstrap/scss/helpers/_vr.scss +8 -0
- package/themes/bootstrap/scss/mixins/_alert.scss +18 -0
- package/themes/bootstrap/scss/mixins/_backdrop.scss +14 -0
- package/themes/bootstrap/scss/mixins/_banner.scss +7 -0
- package/themes/bootstrap/scss/mixins/_border-radius.scss +78 -0
- package/themes/bootstrap/scss/mixins/_box-shadow.scss +18 -0
- package/themes/bootstrap/scss/mixins/_breakpoints.scss +127 -0
- package/themes/bootstrap/scss/mixins/_buttons.scss +70 -0
- package/themes/bootstrap/scss/mixins/_caret.scss +69 -0
- package/themes/bootstrap/scss/mixins/_clearfix.scss +9 -0
- package/themes/bootstrap/scss/mixins/_color-mode.scss +21 -0
- package/themes/bootstrap/scss/mixins/_color-scheme.scss +7 -0
- package/themes/bootstrap/scss/mixins/_container.scss +11 -0
- package/themes/bootstrap/scss/mixins/_deprecate.scss +10 -0
- package/themes/bootstrap/scss/mixins/_forms.scss +163 -0
- package/themes/bootstrap/scss/mixins/_gradients.scss +47 -0
- package/themes/bootstrap/scss/mixins/_grid.scss +151 -0
- package/themes/bootstrap/scss/mixins/_image.scss +16 -0
- package/themes/bootstrap/scss/mixins/_list-group.scss +26 -0
- package/themes/bootstrap/scss/mixins/_lists.scss +7 -0
- package/themes/bootstrap/scss/mixins/_pagination.scss +10 -0
- package/themes/bootstrap/scss/mixins/_reset-text.scss +17 -0
- package/themes/bootstrap/scss/mixins/_resize.scss +6 -0
- package/themes/bootstrap/scss/mixins/_table-variants.scss +24 -0
- package/themes/bootstrap/scss/mixins/_text-truncate.scss +8 -0
- package/themes/bootstrap/scss/mixins/_transition.scss +26 -0
- package/themes/bootstrap/scss/mixins/_utilities.scss +97 -0
- package/themes/bootstrap/scss/mixins/_visually-hidden.scss +38 -0
- package/themes/bootstrap/scss/tests/jasmine.js +16 -0
- package/themes/bootstrap/scss/tests/mixins/_auto-import-of-variables-dark.test.scss +7 -0
- package/themes/bootstrap/scss/tests/mixins/_color-modes.test.scss +69 -0
- package/themes/bootstrap/scss/tests/mixins/_media-query-color-mode-full.test.scss +8 -0
- package/themes/bootstrap/scss/tests/mixins/_utilities.test.scss +393 -0
- package/themes/bootstrap/scss/tests/sass-true/register.js +14 -0
- package/themes/bootstrap/scss/tests/sass-true/runner.js +17 -0
- package/themes/bootstrap/scss/tests/utilities/_api.test.scss +75 -0
- package/themes/bootstrap/scss/utilities/_api.scss +47 -0
- package/themes/bootstrap/scss/vendor/_rfs.scss +348 -0
- package/themes/classy/README.md +89 -0
- package/themes/classy/_config.scss +245 -0
- package/themes/classy/_theme.js +31 -0
- package/themes/classy/_theme.scss +57 -0
- package/themes/classy/css/app/_panels.scss +183 -0
- package/themes/classy/css/base/_fonts.scss +79 -0
- package/themes/classy/css/base/_no-raise.scss +49 -0
- package/themes/classy/css/base/_root.scss +113 -0
- package/themes/classy/css/base/_typography.scss +154 -0
- package/themes/classy/css/base/_utilities.scss +284 -0
- package/themes/classy/css/components/_alerts.scss +51 -0
- package/themes/classy/css/components/_badges.scss +46 -0
- package/themes/classy/css/components/_buttons.scss +175 -0
- package/themes/classy/css/components/_cards.scss +41 -0
- package/themes/classy/css/components/_dropdowns.scss +48 -0
- package/themes/classy/css/components/_forms.scss +171 -0
- package/themes/classy/css/components/_receipt.scss +45 -0
- package/themes/classy/css/layout/_footer.scss +298 -0
- package/themes/classy/css/layout/_general.scss +209 -0
- package/themes/classy/css/layout/_nav.scss +154 -0
- package/themes/classy/css/layout/_shell.scss +458 -0
- package/themes/classy/css/marketing/_bento.scss +238 -0
- package/themes/classy/css/marketing/_content.scss +1328 -0
- package/themes/classy/css/marketing/_downloads.scss +246 -0
- package/themes/classy/css/marketing/_hero.scss +311 -0
- package/themes/classy/css/marketing/_sections.scss +649 -0
- package/themes/classy/css/pages/404/index.scss +67 -0
- package/themes/classy/css/pages/_auth.scss +235 -0
- package/themes/classy/css/pages/admin/firebase/index.scss +22 -0
- package/themes/classy/css/pages/blog/[slug].scss +56 -0
- package/themes/classy/css/pages/cookies.scss +2 -0
- package/themes/classy/css/pages/dashboard/account/index.scss +31 -0
- package/themes/classy/css/pages/feedback/index.scss +39 -0
- package/themes/classy/css/pages/legal/_document.scss +192 -0
- package/themes/classy/css/pages/payment/checkout/index.scss +585 -0
- package/themes/classy/css/pages/payment/confirmation/index.scss +9 -0
- package/themes/classy/css/pages/privacy.scss +2 -0
- package/themes/classy/css/pages/status/index.scss +164 -0
- package/themes/classy/css/pages/terms.scss +2 -0
- package/themes/classy/css/pages/updates/index.scss +128 -0
- package/themes/classy/fonts/inter-italic-latin-ext.woff2 +0 -0
- package/themes/classy/fonts/inter-italic-latin.woff2 +0 -0
- package/themes/classy/fonts/inter-normal-latin-ext.woff2 +0 -0
- package/themes/classy/fonts/inter-normal-latin.woff2 +0 -0
- package/themes/classy/fonts/newsreader-italic-latin-ext.woff2 +0 -0
- package/themes/classy/fonts/newsreader-italic-latin.woff2 +0 -0
- package/themes/classy/fonts/newsreader-normal-latin-ext.woff2 +0 -0
- package/themes/classy/fonts/newsreader-normal-latin.woff2 +0 -0
- package/themes/classy/js/hero-demo-form.js +56 -0
- package/themes/neobrutalism/README.md +118 -0
- package/themes/neobrutalism/_config.scss +139 -0
- package/themes/neobrutalism/_layouts/frontend/core/base.html +30 -0
- package/themes/neobrutalism/_layouts/frontend/pages/index.html +275 -0
- package/themes/neobrutalism/_theme.js +24 -0
- package/themes/neobrutalism/_theme.scss +61 -0
- package/themes/neobrutalism/css/base/_mixins.scss +46 -0
- package/themes/neobrutalism/css/base/_root.scss +169 -0
- package/themes/neobrutalism/css/base/_typography.scss +61 -0
- package/themes/neobrutalism/css/base/_utilities.scss +89 -0
- package/themes/neobrutalism/css/components/_billing-toggle.scss +74 -0
- package/themes/neobrutalism/css/components/_buttons.scss +148 -0
- package/themes/neobrutalism/css/components/_cards.scss +47 -0
- package/themes/neobrutalism/css/components/_forms.scss +88 -0
- package/themes/neobrutalism/css/components/_marketing.scss +244 -0
- package/themes/neobrutalism/css/layout/_general.scss +213 -0
- package/themes/neobrutalism/css/layout/_navigation.scss +171 -0
- package/themes/neobrutalism/css/pages/index.scss +203 -0
- package/themes/neobrutalism/css/pages/pricing/index.scss +58 -0
- package/themes/neobrutalism/css/pages/test/libraries/layers/index.scss +7 -0
- package/themes/neobrutalism/js/pages/test/libraries/layers/index.js +9 -0
- package/themes/newsflash/README.md +117 -0
- package/themes/newsflash/_components/heading/lede/component.html +14 -0
- package/themes/newsflash/_components/heading/lede/component.json5 +23 -0
- package/themes/newsflash/_components/heading/rule-head/component.html +17 -0
- package/themes/newsflash/_components/heading/rule-head/component.json5 +23 -0
- package/themes/newsflash/_components/news/byline/component.html +12 -0
- package/themes/newsflash/_components/news/byline/component.json5 +18 -0
- package/themes/newsflash/_components/news/story-card/component.html +25 -0
- package/themes/newsflash/_components/news/story-card/component.json5 +21 -0
- package/themes/newsflash/_config.scss +147 -0
- package/themes/newsflash/_layouts/frontend/core/base.html +51 -0
- package/themes/newsflash/_layouts/frontend/pages/blog/index.html +299 -0
- package/themes/newsflash/_layouts/frontend/pages/blog/post.html +235 -0
- package/themes/newsflash/_layouts/frontend/pages/index.html +328 -0
- package/themes/newsflash/_sections/marketing/desks/section.html +39 -0
- package/themes/newsflash/_sections/marketing/desks/section.json5 +49 -0
- package/themes/newsflash/_sections/marketing/newsletter-cta/section.html +103 -0
- package/themes/newsflash/_sections/marketing/newsletter-cta/section.json5 +50 -0
- package/themes/newsflash/_sections/marketing/rundown/section.html +28 -0
- package/themes/newsflash/_sections/marketing/rundown/section.json5 +40 -0
- package/themes/newsflash/_theme.js +24 -0
- package/themes/newsflash/_theme.scss +70 -0
- package/themes/newsflash/css/base/_fonts.scss +80 -0
- package/themes/newsflash/css/base/_mixins.scss +51 -0
- package/themes/newsflash/css/base/_root.scss +257 -0
- package/themes/newsflash/css/base/_typography.scss +49 -0
- package/themes/newsflash/css/base/_utilities.scss +122 -0
- package/themes/newsflash/css/components/_badges.scss +65 -0
- package/themes/newsflash/css/components/_billing-toggle.scss +61 -0
- package/themes/newsflash/css/components/_buttons.scss +139 -0
- package/themes/newsflash/css/components/_cards.scss +47 -0
- package/themes/newsflash/css/components/_editorial.scss +173 -0
- package/themes/newsflash/css/components/_forms.scss +75 -0
- package/themes/newsflash/css/components/_infinite-scroll.scss +102 -0
- package/themes/newsflash/css/components/_panels.scss +156 -0
- package/themes/newsflash/css/components/_ticker.scss +67 -0
- package/themes/newsflash/css/layout/_general.scss +330 -0
- package/themes/newsflash/css/layout/_navigation.scss +168 -0
- package/themes/newsflash/css/pages/404/index.scss +79 -0
- package/themes/newsflash/css/pages/blog/[slug].scss +186 -0
- package/themes/newsflash/css/pages/blog/index.scss +17 -0
- package/themes/newsflash/css/pages/index.scss +157 -0
- package/themes/newsflash/css/pages/pricing/index.scss +55 -0
- package/themes/newsflash/css/pages/test/libraries/layers/index.scss +7 -0
- package/themes/newsflash/fonts/fraunces-italic-latin-ext.woff2 +0 -0
- package/themes/newsflash/fonts/fraunces-italic-latin.woff2 +0 -0
- package/themes/newsflash/fonts/fraunces-normal-latin-ext.woff2 +0 -0
- package/themes/newsflash/fonts/fraunces-normal-latin.woff2 +0 -0
- package/themes/newsflash/fonts/schibsted-grotesk-italic-latin-ext.woff2 +0 -0
- package/themes/newsflash/fonts/schibsted-grotesk-italic-latin.woff2 +0 -0
- package/themes/newsflash/fonts/schibsted-grotesk-normal-latin-ext.woff2 +0 -0
- package/themes/newsflash/fonts/schibsted-grotesk-normal-latin.woff2 +0 -0
- package/themes/newsflash/js/pages/blog/[slug].js +29 -0
- package/themes/newsflash/js/pages/test/libraries/layers/index.js +9 -0
- package/translations/es/pages/404.json +86 -0
- package/translations/es/pages/account.json +36 -0
- package/translations/es/pages/app.json +44 -0
- package/translations/es/pages/cancel.json +36 -0
- package/translations/es/pages/change-password.json +36 -0
- package/translations/es/pages/connections/callback.json +41 -0
- package/translations/es/pages/dashboard/account.json +475 -0
- package/translations/es/pages/dashboard.json +36 -0
- package/translations/es/pages/forgot.json +36 -0
- package/translations/es/pages/join.json +36 -0
- package/translations/es/pages/login.json +36 -0
- package/translations/es/pages/payment/checkout.json +83 -0
- package/translations/es/pages/payment/confirmation.json +62 -0
- package/translations/es/pages/portal/email-preferences.json +46 -0
- package/translations/es/pages/recover.json +36 -0
- package/translations/es/pages/refund.json +36 -0
- package/translations/es/pages/register.json +36 -0
- package/translations/es/pages/reset-password.json +36 -0
- package/translations/es/pages/reset.json +42 -0
- package/translations/es/pages/signin.json +45 -0
- package/translations/es/pages/signup.json +60 -0
- package/translations/es/pages/token.json +39 -0
- package/translations/fa/pages/404.json +86 -0
- package/translations/fa/pages/account.json +36 -0
- package/translations/fa/pages/app.json +44 -0
- package/translations/fa/pages/cancel.json +36 -0
- package/translations/fa/pages/change-password.json +36 -0
- package/translations/fa/pages/connections/callback.json +41 -0
- package/translations/fa/pages/dashboard/account.json +475 -0
- package/translations/fa/pages/dashboard.json +36 -0
- package/translations/fa/pages/forgot.json +36 -0
- package/translations/fa/pages/join.json +36 -0
- package/translations/fa/pages/login.json +36 -0
- package/translations/fa/pages/payment/checkout.json +83 -0
- package/translations/fa/pages/payment/confirmation.json +62 -0
- package/translations/fa/pages/portal/email-preferences.json +46 -0
- package/translations/fa/pages/recover.json +36 -0
- package/translations/fa/pages/refund.json +36 -0
- package/translations/fa/pages/register.json +36 -0
- package/translations/fa/pages/reset-password.json +36 -0
- package/translations/fa/pages/reset.json +42 -0
- package/translations/fa/pages/signin.json +45 -0
- package/translations/fa/pages/signup.json +60 -0
- package/translations/fa/pages/token.json +39 -0
|
@@ -0,0 +1,1067 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `omega dev` — the development loop:
|
|
3
|
+
* 1. dev-mode assets (stable un-hashed names, no minify) → .omega/manifest
|
|
4
|
+
* 2. programmatic Eleventy watch + serve over src/
|
|
5
|
+
* 3. asset-source watchers (consumer src/assets + packaged theme/core
|
|
6
|
+
* layers) rebuild bundles IN PLACE — URLs are stable in dev, so the
|
|
7
|
+
* rendered HTML stays valid without a re-render; the dev server
|
|
8
|
+
* watches the built asset trees and live-reloads the browser (css
|
|
9
|
+
* hot-swaps, js reloads — no hand refresh).
|
|
10
|
+
*
|
|
11
|
+
* Port (N7): the website convention is 4000, resolved through the allocator —
|
|
12
|
+
* taken ports bump +1. Multi-instance web brands offset deterministically:
|
|
13
|
+
* each instance wants 4000 + its position in the instances array, so
|
|
14
|
+
* targets/website and targets/website-admin dev side-by-side. `omega dev
|
|
15
|
+
* --port=4001` (or a config `ports.website` entry) PINS the port instead:
|
|
16
|
+
* busy = hard error, never a silent bump. The
|
|
17
|
+
* resolved map of a live sibling backend (its `.temp/ports.json`) plus this
|
|
18
|
+
* website port and its resolved ORIGIN (protocol included,
|
|
19
|
+
* [#262](https://github.com/Omega-JS-Stack/omega/issues/262)) are injected into
|
|
20
|
+
* the page chrome as `dev` so
|
|
21
|
+
* @omega.js/client connects to the stack that is ACTUALLY running — read PER
|
|
22
|
+
* RESPONSE (the render-time bake is advisory, rewritten as the page is served,
|
|
23
|
+
* [#346](https://github.com/Omega-JS-Stack/omega/issues/346)) and per request
|
|
24
|
+
* for the auth-emulator proxy, because a backend that boots after this server
|
|
25
|
+
* (or restarts onto bumped ports) is the normal case
|
|
26
|
+
* ([#300](https://github.com/Omega-JS-Stack/omega/issues/300)).
|
|
27
|
+
*
|
|
28
|
+
* `omega dev --local` first links every @omega.js framework the brand uses to
|
|
29
|
+
* the local Omega monorepo (file: installs, idempotent) and starts the
|
|
30
|
+
* monorepo's src→dist watch, then runs the normal dev loop (master plan §8).
|
|
31
|
+
*/
|
|
32
|
+
const fs = require('node:fs');
|
|
33
|
+
const http = require('node:http');
|
|
34
|
+
const path = require('node:path');
|
|
35
|
+
const jetpack = require('fs-jetpack');
|
|
36
|
+
const Logger = require('../vendor/devkit/logger.js');
|
|
37
|
+
const {
|
|
38
|
+
CLASSIC_PORTS, isPortFree, resolvePorts, envPort,
|
|
39
|
+
readSiblingPorts, writePortsFile, clearPortsFile,
|
|
40
|
+
findBrandRoot, hasOmegaConfig, loadConfig, instancePortOffset,
|
|
41
|
+
} = require('../vendor/config/index.js');
|
|
42
|
+
const { emitIcons } = require('../vendor/devkit/icons.js');
|
|
43
|
+
const { watchEnvChain } = require('../vendor/devkit/env-watch.js');
|
|
44
|
+
const { STOP_SIGNALS } = require('../vendor/devkit/stop-signals.js');
|
|
45
|
+
const attachLogFile = require('../vendor/devkit/attach-log-file.js');
|
|
46
|
+
const { ensureTarget } = require('./lib/ensure-target.js');
|
|
47
|
+
const { emitLanguageFlags } = require('../language-flags.js');
|
|
48
|
+
const { buildAssets } = require('../assets.js');
|
|
49
|
+
const { buildServiceWorker, writeBuildMeta } = require('../service-worker.js');
|
|
50
|
+
const { resolveStaticDirs, copyStaticAssets, hasFaviconSet, brandmarkSvgUrl } = require('../static-assets.js');
|
|
51
|
+
const { devImageFallback } = require('../imagemin.js');
|
|
52
|
+
const { configureOmega } = require('../engine.js');
|
|
53
|
+
const reads = require('../vendor/devkit/reads.js');
|
|
54
|
+
const { reconcileSampleContent } = require('../sample-content.js');
|
|
55
|
+
const { resolveThemeLayers } = require('../layers.js');
|
|
56
|
+
const { consumerPaths, loadSiteData } = require('../consumer.js');
|
|
57
|
+
const { PATHS, resolveClientEntry } = require('../paths.js');
|
|
58
|
+
|
|
59
|
+
const logger = new Logger('dev');
|
|
60
|
+
|
|
61
|
+
const WATCH_DEBOUNCE_MS = 250;
|
|
62
|
+
// The rescan lane settles faster than the asset lane: a scan is a readdir, and
|
|
63
|
+
// the sooner it lands the sooner a permalink collision is on screen.
|
|
64
|
+
const RESCAN_DEBOUNCE_MS = 50;
|
|
65
|
+
// How often a re-arming watcher probes for its directory to come back. A
|
|
66
|
+
// prepare's wipe-to-rewrite gap is a build's worth of time, so a coarse probe
|
|
67
|
+
// costs nothing and never busy-loops.
|
|
68
|
+
const REARM_POLL_MS = 200;
|
|
69
|
+
|
|
70
|
+
module.exports = async function (options) {
|
|
71
|
+
options = options || {};
|
|
72
|
+
|
|
73
|
+
// Tee the whole run to <targetRoot>/logs/dev.log — first statement of the verb
|
|
74
|
+
// so a crash on the way up is already in the file (#197).
|
|
75
|
+
attachLogFile(path.join(consumerPaths().root, 'logs', 'dev.log'));
|
|
76
|
+
|
|
77
|
+
// The local half of the retired `omega setup` (#675) — idempotent, offline,
|
|
78
|
+
// and quiet on a converged target.
|
|
79
|
+
ensureTarget({ projectDir: consumerPaths().root, log: (line) => logger.log(line), warn: (line) => logger.warn(line) });
|
|
80
|
+
|
|
81
|
+
if (options.local) {
|
|
82
|
+
await linkBrandToMonorepo();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const paths = consumerPaths();
|
|
86
|
+
const siteData = loadSiteData(paths.root);
|
|
87
|
+
// The target's own package version — read ONCE and handed to both consumers: the
|
|
88
|
+
// build manifest and the page chrome's Configuration block (the client's
|
|
89
|
+
// release tag, #380).
|
|
90
|
+
const version = jetpack.read(path.join(paths.root, 'package.json'), 'json')?.version;
|
|
91
|
+
const clientEntry = resolveClientEntry();
|
|
92
|
+
const { port, bumped } = await resolveWebsitePort(paths.root, Number(options.port) || null);
|
|
93
|
+
|
|
94
|
+
// HTTPS (same contract as the backend's serve/emulator): the PUBLIC website
|
|
95
|
+
// port speaks TLS through the shared mkcert proxy; eleventy sits on an
|
|
96
|
+
// internal plain-http port behind it (WebSocket live-reload tunnels through).
|
|
97
|
+
// `--no-https` or no mkcert → plain http on the public port, as before.
|
|
98
|
+
const { ensureLocalHttpsCerts, startLocalHttpsProxy, mkcertInstallHint } = require('../vendor/devkit/local-https.js');
|
|
99
|
+
let httpsCerts = null;
|
|
100
|
+
let internalPort = null;
|
|
101
|
+
if (options.https !== false) {
|
|
102
|
+
httpsCerts = await ensureLocalHttpsCerts({
|
|
103
|
+
certsDir: path.join(paths.root, '.temp', 'certs'),
|
|
104
|
+
log: (line) => logger.log(line),
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
if (httpsCerts) {
|
|
108
|
+
({ ports: { internal: internalPort } } = await resolvePorts({ wanted: { internal: 4443 } }));
|
|
109
|
+
} else {
|
|
110
|
+
logger.log(`HTTPS disabled — could not obtain certificates (install mkcert: ${mkcertInstallHint()})`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// The resolved website ORIGIN — protocol and port together, since only this
|
|
115
|
+
// point in the boot knows whether the public port speaks TLS. Everything that
|
|
116
|
+
// needs "where the dev website answers" reads THIS: site.url, the page chrome,
|
|
117
|
+
// and the ports file siblings read (#262).
|
|
118
|
+
const origin = devWebsiteOrigin(port, httpsCerts !== null);
|
|
119
|
+
applyDevSiteUrl(siteData, origin);
|
|
120
|
+
|
|
121
|
+
// LIVE, never a snapshot: both the baked page chrome and the auth-emulator
|
|
122
|
+
// proxy resolve the sibling backend's map at use time (#300).
|
|
123
|
+
const devPorts = devPortsOption(paths.root, port, origin);
|
|
124
|
+
const authPort = () => devPorts().ports.auth;
|
|
125
|
+
|
|
126
|
+
// ---- Sample content on disk (spec §8): mirror the injected filler under
|
|
127
|
+
// the gitignored .omega/sample-content/ so it can be read and copied —
|
|
128
|
+
// machine-owned, regenerated every boot, gone per-collection once the
|
|
129
|
+
// consumer owns that collection.
|
|
130
|
+
const samples = reconcileSampleContent({
|
|
131
|
+
targetRoot: paths.root,
|
|
132
|
+
consumerDir: paths.src,
|
|
133
|
+
defaultsDir: PATHS.defaults,
|
|
134
|
+
});
|
|
135
|
+
if (samples.written.length) {
|
|
136
|
+
logger.log(`Sample content: ${samples.written.length} files → ${path.relative(paths.root, samples.root)}/ (gitignored, regenerated each boot)`);
|
|
137
|
+
}
|
|
138
|
+
samples.removed.forEach((collectionDir) => logger.log(`Sample content: ${collectionDir} is yours now — materialized samples removed`));
|
|
139
|
+
|
|
140
|
+
const activeTheme = (siteData.theme && siteData.theme.id) || 'classy';
|
|
141
|
+
const themeLayerDirs = resolveAssetThemeLayers(paths, activeTheme);
|
|
142
|
+
const layers = [
|
|
143
|
+
...(fs.existsSync(paths.assets) ? [paths.assets] : []),
|
|
144
|
+
...themeLayerDirs,
|
|
145
|
+
PATHS.core,
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
// ---- Fresh output + dev assets
|
|
149
|
+
fs.rmSync(paths.out, { recursive: true, force: true });
|
|
150
|
+
|
|
151
|
+
const build = (only) => buildAssets({
|
|
152
|
+
layers,
|
|
153
|
+
themeRoots: themeLayerDirs,
|
|
154
|
+
sectionRoots: [paths.src, ...themeLayerDirs],
|
|
155
|
+
themesDir: PATHS.themes,
|
|
156
|
+
coreDir: PATHS.core,
|
|
157
|
+
outDir: paths.out,
|
|
158
|
+
clientEntry,
|
|
159
|
+
dev: true,
|
|
160
|
+
only,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Static assets (minted brand identity + src/assets) resolve up front —
|
|
164
|
+
// the manifest's favicon flag depends on what will ship
|
|
165
|
+
const staticDirs = resolveStaticDirs({
|
|
166
|
+
brandRoot: findBrandRoot(paths.root),
|
|
167
|
+
assetsDir: paths.assets,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const manifest = await build();
|
|
171
|
+
manifest.favicons = hasFaviconSet(staticDirs);
|
|
172
|
+
manifest.brandmarkSvg = brandmarkSvgUrl(staticDirs);
|
|
173
|
+
jetpack.write(paths.manifest, JSON.stringify(manifest, null, 2));
|
|
174
|
+
logger.log('Assets built (dev mode: stable names, no minify, sourcemaps)');
|
|
175
|
+
|
|
176
|
+
// ---- Service worker + build meta (/service-worker.js, /build.js,
|
|
177
|
+
// /build.json) — dev serves the REAL service worker so push/caching are
|
|
178
|
+
// testable; registration takeover + cache eviction keep one localhost
|
|
179
|
+
// port safe across different projects.
|
|
180
|
+
const buildSw = async () => {
|
|
181
|
+
writeBuildMeta({
|
|
182
|
+
siteData,
|
|
183
|
+
outDir: paths.out,
|
|
184
|
+
environment: 'development',
|
|
185
|
+
version,
|
|
186
|
+
consumerDir: paths.src,
|
|
187
|
+
clientEntry,
|
|
188
|
+
manifest,
|
|
189
|
+
});
|
|
190
|
+
await buildServiceWorker({
|
|
191
|
+
consumerDir: paths.src,
|
|
192
|
+
outDir: paths.out,
|
|
193
|
+
clientEntry,
|
|
194
|
+
dev: true,
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
await buildSw();
|
|
198
|
+
|
|
199
|
+
// Copied once at boot; they change rarely, so no watcher (restart to pick
|
|
200
|
+
// up new ones)
|
|
201
|
+
copyStaticAssets({
|
|
202
|
+
staticDirs,
|
|
203
|
+
outDir: paths.out,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Runtime icon set (/assets/icons/) — the browser-side auto-renderer fetches
|
|
207
|
+
// these on demand (JS-set fa-* markup, e.g. the share buttons); emitted once
|
|
208
|
+
// at boot like the statics (the set never changes mid-dev).
|
|
209
|
+
emitIcons({
|
|
210
|
+
outDir: paths.out,
|
|
211
|
+
coreIconsDir: path.join(PATHS.core, 'icons'),
|
|
212
|
+
});
|
|
213
|
+
emitLanguageFlags({ outDir: paths.out });
|
|
214
|
+
|
|
215
|
+
// ---- Rebuild assets in place on source changes
|
|
216
|
+
const watchDirs = [
|
|
217
|
+
paths.assets,
|
|
218
|
+
...themeLayerDirs,
|
|
219
|
+
path.join(PATHS.core, 'js'),
|
|
220
|
+
path.join(PATHS.core, 'css'),
|
|
221
|
+
// Consumer-local section/component assets (§7) live OUTSIDE the asset
|
|
222
|
+
// trees (src/_sections) — theme-layer sections are covered by the theme
|
|
223
|
+
// roots above.
|
|
224
|
+
path.join(paths.src, '_sections'),
|
|
225
|
+
path.join(paths.src, '_components'),
|
|
226
|
+
].filter((dir) => fs.existsSync(dir));
|
|
227
|
+
|
|
228
|
+
// The rebuild folds back into the LIVE manifest (#765): the theme layers are
|
|
229
|
+
// watched here, so a theme's @font-face edit rebuilds the sheet — and the
|
|
230
|
+
// preload list it carries has to reach the served head, not wait for an
|
|
231
|
+
// unrelated template edit. The manifest file is the courier (see the
|
|
232
|
+
// watch target registered with Eleventy below).
|
|
233
|
+
watchAssetSources({
|
|
234
|
+
dirs: watchDirs,
|
|
235
|
+
clientDist: path.dirname(clientEntry),
|
|
236
|
+
build,
|
|
237
|
+
manifest,
|
|
238
|
+
manifestPath: paths.manifest,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// The .env chain is a dev INPUT too (#681): an edit to any layer reloads the
|
|
242
|
+
// cascade into process.env, so the next rebuild reads the new values instead
|
|
243
|
+
// of the ones this process booted with.
|
|
244
|
+
//
|
|
245
|
+
// Reach, exactly: a NEW key AND an EDITED value both land on that next
|
|
246
|
+
// rebuild, and a key dropped from the file is dropped from the process — the
|
|
247
|
+
// reload re-reads what a file layer owns (#724). A SHELL-set value still wins
|
|
248
|
+
// over every file, whatever the file now says.
|
|
249
|
+
watchEnvSources(paths.root);
|
|
250
|
+
|
|
251
|
+
// The consumer's service-worker entry lives OUTSIDE the asset trees
|
|
252
|
+
// (src/service-worker.js) — its own watcher; the browser picks the new
|
|
253
|
+
// worker up on the next reload's registration update check.
|
|
254
|
+
const consumerSwEntry = path.join(paths.src, 'service-worker.js');
|
|
255
|
+
if (fs.existsSync(consumerSwEntry)) {
|
|
256
|
+
let swTimer = null;
|
|
257
|
+
fs.watch(consumerSwEntry, () => {
|
|
258
|
+
clearTimeout(swTimer);
|
|
259
|
+
swTimer = setTimeout(() => {
|
|
260
|
+
buildSw()
|
|
261
|
+
.then(() => logger.log('Service worker rebuilt — reload to activate the new worker'))
|
|
262
|
+
.catch((error) => logger.error('Service worker rebuild failed:', error));
|
|
263
|
+
}, WATCH_DEBOUNCE_MS);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// ---- Eleventy watch + serve
|
|
268
|
+
const Eleventy = require('@11ty/eleventy').default;
|
|
269
|
+
let rescanWatchers = [];
|
|
270
|
+
const elev = new Eleventy(paths.src, paths.out, {
|
|
271
|
+
quietMode: true,
|
|
272
|
+
configPath: false,
|
|
273
|
+
config: (eleventyConfig) => {
|
|
274
|
+
eleventyConfig.setServerOptions(devServerOptions(paths.out, authPort, devPorts));
|
|
275
|
+
// The asset manifest is a template INPUT (the head reads its css/js URLs
|
|
276
|
+
// and its font preloads), and the asset watcher rewrites it when the
|
|
277
|
+
// preload list moves (#765). Watching the file is what re-renders the
|
|
278
|
+
// head then — no config reset, because the engine holds the manifest
|
|
279
|
+
// object by reference and the rebuild already updated it.
|
|
280
|
+
eleventyConfig.addWatchTarget(paths.manifest);
|
|
281
|
+
// Arms the watch registration for the config build below — the engine's
|
|
282
|
+
// captured reads are what fill it in (#200). The reset union goes to
|
|
283
|
+
// Eleventy, the rescan union to the light content watcher; a config
|
|
284
|
+
// reset re-runs this callback, so the previous rescan watchers close
|
|
285
|
+
// before the new union arms.
|
|
286
|
+
registerTemplateWatchTargets(eleventyConfig, {
|
|
287
|
+
onRescans: (rescans) => {
|
|
288
|
+
rescanWatchers.forEach((watcher) => watcher.close());
|
|
289
|
+
rescanWatchers = watchRescanTargets(rescans);
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
return configureOmega(eleventyConfig, {
|
|
293
|
+
consumerDir: paths.src,
|
|
294
|
+
siteData,
|
|
295
|
+
activeTheme,
|
|
296
|
+
assetManifest: manifest,
|
|
297
|
+
environment: 'development',
|
|
298
|
+
version,
|
|
299
|
+
dev: devPorts,
|
|
300
|
+
});
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
await elev.init();
|
|
305
|
+
await elev.watch();
|
|
306
|
+
elev.serve(httpsCerts ? internalPort : port);
|
|
307
|
+
|
|
308
|
+
// TLS terminator on the public port → eleventy on the internal one
|
|
309
|
+
if (httpsCerts) {
|
|
310
|
+
startLocalHttpsProxy({
|
|
311
|
+
port,
|
|
312
|
+
targetPort: internalPort,
|
|
313
|
+
certs: httpsCerts,
|
|
314
|
+
log: (line) => logger.log(line),
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Publish the resolved website port for sibling tools (same contract as the
|
|
319
|
+
// backend emulator's ports file) and retract it on shutdown. The PUBLIC
|
|
320
|
+
// port is the published one — the internal eleventy port is plumbing. The
|
|
321
|
+
// ORIGIN rides along, because a sibling reading `website: 4000` cannot know
|
|
322
|
+
// whether this run speaks TLS (#262).
|
|
323
|
+
writePortsFile(paths.root, { website: port }, { origin });
|
|
324
|
+
process.on('exit', () => clearPortsFile(paths.root));
|
|
325
|
+
// Every way this dev server is asked to stop exits deliberately, off the ONE
|
|
326
|
+
// devkit list ([#629](https://github.com/Omega-JS-Stack/omega/issues/629)):
|
|
327
|
+
// the `exit` hook above is what retracts the ports file, and a signal with no
|
|
328
|
+
// listener never runs it.
|
|
329
|
+
STOP_SIGNALS.forEach((signal) => process.on(signal, () => process.exit(0)));
|
|
330
|
+
|
|
331
|
+
if (bumped) {
|
|
332
|
+
logger.log(`Port ${CLASSIC_PORTS.website} was taken — bumped to ${port}`);
|
|
333
|
+
}
|
|
334
|
+
logger.log(`Dev server: ${httpsCerts ? 'https' : 'http'}://localhost:${port}`);
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* The asset lane's theme layer chain (#137). `resolveThemeLayers` probes
|
|
339
|
+
* `<consumerDir>/themes/<id>` for a consumer-local theme, and EVERY other
|
|
340
|
+
* caller — the engine, the production build, customize, the override map —
|
|
341
|
+
* passes the Eleventy input dir, so a consumer-local theme lives at
|
|
342
|
+
* `src/themes/<id>`. Resolving the asset lane from the target ROOT instead made
|
|
343
|
+
* that theme invisible to the scss/js build AND to the asset watcher (both
|
|
344
|
+
* derive from this list), so a brand's own theme silently rendered with the
|
|
345
|
+
* packaged theme's styles.
|
|
346
|
+
* @param {object} paths - consumerPaths() output
|
|
347
|
+
* @param {string} activeTheme - theme id
|
|
348
|
+
* @returns {string[]} ordered theme layer dirs
|
|
349
|
+
*/
|
|
350
|
+
function resolveAssetThemeLayers(paths, activeTheme) {
|
|
351
|
+
return resolveThemeLayers({ activeTheme, consumerDir: paths.src, themesDir: PATHS.themes });
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// The session's server-options objects, keyed by (outDir, authPort) — why they
|
|
355
|
+
// must be the IDENTICAL object on every config reset is in devServerOptions.
|
|
356
|
+
const SERVER_OPTIONS = new Map();
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Dev-server options: the image-variant fallback middleware (dev never runs
|
|
360
|
+
* the responsive matrix — missing -NNNpx/.webp URLs rewrite to the verbatim
|
|
361
|
+
* original) + live-reload on ASSET rebuilds. Eleventy's dev server only
|
|
362
|
+
* reloads on its own template re-renders; our asset watcher writes bundles
|
|
363
|
+
* straight into the out dir, so the server chokidars those trees too — css
|
|
364
|
+
* changes hot-swap without a full reload, js changes reload the page. Kills
|
|
365
|
+
* the "refresh the browser" hand step.
|
|
366
|
+
*
|
|
367
|
+
* The auth-emulator proxy goes FIRST: it owns whole URL prefixes and answers
|
|
368
|
+
* them itself, so it must run before the clean-URL rewriter gets a chance to
|
|
369
|
+
* treat one as a page path.
|
|
370
|
+
*
|
|
371
|
+
* ONE object per (outDir, authPort), for the life of the process (#206). The
|
|
372
|
+
* config callback runs again on every config RESET, and Eleventy decides
|
|
373
|
+
* whether to restart the dev server by `assert.deepStrictEqual`-ing the
|
|
374
|
+
* config's serverOptions against the copy it saved at boot
|
|
375
|
+
* (EleventyServe.hasOptionsChanged) — where differing FUNCTION references can
|
|
376
|
+
* only ever read as "changed". Handing back a rebuilt object therefore
|
|
377
|
+
* restarted the server (close + relisten) on every single reset, and an edit
|
|
378
|
+
* burst raced a queued build's restart against a socket the previous one had
|
|
379
|
+
* not released yet: ERR_SERVER_ALREADY_LISTEN, process dead. Nothing here
|
|
380
|
+
* varies during a session — the middleware closes over outDir and the auth
|
|
381
|
+
* port RESOLVER, both fixed at boot — so the cache is the whole fix: Eleventy's
|
|
382
|
+
* DeepCopy of the object shares the middleware array and its function
|
|
383
|
+
* references, and the identical object compares equal across every reset.
|
|
384
|
+
* @param {string} outDir
|
|
385
|
+
* @param {number|function} [authPort] - the auth emulator port to proxy, or a
|
|
386
|
+
* GETTER resolving it per request (the live map, #300); a getter keys as
|
|
387
|
+
* `live`, since a session runs exactly one dev server and the getter's
|
|
388
|
+
* identity would otherwise change on every config reset
|
|
389
|
+
* @param {function} [devChrome] - the live dev-chrome getter (devPortsOption);
|
|
390
|
+
* given, every HTML response is rewritten to carry it (#346)
|
|
391
|
+
* @returns {object} setServerOptions() payload
|
|
392
|
+
*/
|
|
393
|
+
function devServerOptions(outDir, authPort, devChrome) {
|
|
394
|
+
const key = `${outDir} ${typeof authPort === 'function' ? 'live' : authPort} ${devChrome ? 'inject' : 'plain'}`;
|
|
395
|
+
|
|
396
|
+
if (!SERVER_OPTIONS.has(key)) {
|
|
397
|
+
SERVER_OPTIONS.set(key, {
|
|
398
|
+
middleware: [
|
|
399
|
+
devAuthEmulator(authPort),
|
|
400
|
+
// After the proxy, which answers its own prefixes and returns: the
|
|
401
|
+
// emulator's pages are not this site's pages, and nothing rewrites them
|
|
402
|
+
...(devChrome ? [devInjectDevPorts(devChrome)] : []),
|
|
403
|
+
devCleanUrls(outDir),
|
|
404
|
+
devImageFallback(outDir),
|
|
405
|
+
],
|
|
406
|
+
watch: [
|
|
407
|
+
path.join(outDir, 'assets', 'css'),
|
|
408
|
+
path.join(outDir, 'assets', 'js'),
|
|
409
|
+
],
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return SERVER_OPTIONS.get(key);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Force a config RESET on edits under the template-source dirs (#49). Both
|
|
418
|
+
* layered layouts (registered as virtual templates, content read at config
|
|
419
|
+
* time) and the json-in-_includes data system (read into site.data._includes
|
|
420
|
+
* at config time) are CAPTURES — and Eleventy reuses one config across watch
|
|
421
|
+
* rebuilds unless the changed file triggers a reset, so without this the
|
|
422
|
+
* rebuild logs "Wrote N files" and re-renders the stale capture until the
|
|
423
|
+
* server is restarted.
|
|
424
|
+
*
|
|
425
|
+
* The targets are DERIVED, never listed (#200): `configureOmega` reads every
|
|
426
|
+
* config-time input through the captured-read helper (@omega.js/devkit/reads), which
|
|
427
|
+
* records the directory of each read — the union IS the set of dirs the
|
|
428
|
+
* capture depends on, so a capture added to the engine later registers itself.
|
|
429
|
+
* A hand list could only ever be the set someone remembered (#139).
|
|
430
|
+
*
|
|
431
|
+
* Ordering: Eleventy runs this before `configureOmega` in the same config
|
|
432
|
+
* callback, so it ARMS the registration instead of doing it — the recorded
|
|
433
|
+
* union only exists once the engine's capture scope closes, which happens on
|
|
434
|
+
* the way out of `configureOmega`, still inside this callback and long before
|
|
435
|
+
* Eleventy reads its watch targets.
|
|
436
|
+
*
|
|
437
|
+
* What lands in the union: each layer's machinery dirs (`_layouts`,
|
|
438
|
+
* `_includes`, `_sections`, `_components`, a theme's `fonts/`), the packaged
|
|
439
|
+
* `defaults` tree (#136), and the layer roots the theme chain PROBES — a
|
|
440
|
+
* consumer-local `src/themes/<id>` included, so an scss edit inside a brand's
|
|
441
|
+
* own theme rides BOTH lanes: the asset watcher's rebuild AND a config reset
|
|
442
|
+
* (the same accepted cost the `_sections` dirs already pay, #138).
|
|
443
|
+
*
|
|
444
|
+
* Packaged targets register REAL paths (the helper realpaths anything outside
|
|
445
|
+
* the consumer dir). A linked brand reaches the framework through a
|
|
446
|
+
* `node_modules/@omega.js/web` symlink, and Eleventy's watcher ignores
|
|
447
|
+
* everything under `node_modules` — the resolved path sidesteps it.
|
|
448
|
+
*
|
|
449
|
+
* BOTH path forms are registered for cwd-contained targets. The absolute form
|
|
450
|
+
* alone carries the reset today (the dev loop hands Eleventy absolute dirs, so
|
|
451
|
+
* the watcher's event arrives absolute and matches it). Registering the
|
|
452
|
+
* relative form ADDS a second, relative event for the same edit — each event
|
|
453
|
+
* decides the reset for itself and the last one wins the throttle, which is
|
|
454
|
+
* why the relative form must never be registered ALONE — and is kept as
|
|
455
|
+
* insurance so a reset still fires if Eleventy ever reports these edits in
|
|
456
|
+
* relative form. Its observable cost is a duplicate "File changed" line per
|
|
457
|
+
* save. A target OUTSIDE cwd (a linked brand's framework layers, a hoisted
|
|
458
|
+
* node_modules) registers ONLY absolute: an escaping `../` watch target makes
|
|
459
|
+
* Eleventy re-root its watcher to the common ancestor, after which NO event
|
|
460
|
+
* path matches ANY registered target and every reset dies — including the
|
|
461
|
+
* consumer ones (#134 verification).
|
|
462
|
+
*
|
|
463
|
+
* Dropping the relative form was TRIED and reverted (#344). It is not dead
|
|
464
|
+
* insurance: with only the absolute form registered, the packaged-layer reset
|
|
465
|
+
* starves — an interleaved A/B of dev-watch.test.js, one run per arm per
|
|
466
|
+
* round, went 0/8 red on both forms and 5/8 red on absolute-only. The extra
|
|
467
|
+
* registrations change how chokidar arranges its FSEvents streams (its
|
|
468
|
+
* consolidation threshold is a count of watched paths under one parent), and
|
|
469
|
+
* the arrangement the duplicates produce is the one that reliably delivers a
|
|
470
|
+
* freshly created packaged tmp dir's events. Measure before touching this.
|
|
471
|
+
*
|
|
472
|
+
* ONLY the reset union lands here. The same scope also records the RESCAN
|
|
473
|
+
* union (#200 Lane B) — the content scans, whose dirs must never carry a reset
|
|
474
|
+
* — and `options.onRescans` hands it to the lane that owns it
|
|
475
|
+
* (watchRescanTargets below).
|
|
476
|
+
* @param {object} eleventyConfig
|
|
477
|
+
* @param {object} [options]
|
|
478
|
+
* @param {function} [options.onRescans] - (rescanTargets) => void, the rescan lane
|
|
479
|
+
*/
|
|
480
|
+
function registerTemplateWatchTargets(eleventyConfig, options) {
|
|
481
|
+
reads.onNextScope((targets, rescans) => {
|
|
482
|
+
for (const { dir } of targets) {
|
|
483
|
+
const relative = path.relative(process.cwd(), dir);
|
|
484
|
+
const forms = relative.startsWith('..') ? [dir] : new Set([dir, relative]);
|
|
485
|
+
for (const form of forms) {
|
|
486
|
+
eleventyConfig.addWatchTarget(form, { resetConfig: true });
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
if (options && options.onRescans) options.onRescans(rescans);
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* The ASSET lane's source watchers: one recursive fs.watch per asset source
|
|
495
|
+
* dir, all feeding ONE debounced rebuild.
|
|
496
|
+
*
|
|
497
|
+
* Narrowed rebuilds: a css-only change set rebuilds just the stylesheets — no
|
|
498
|
+
* js files are rewritten, so the dev server HOT-SWAPS the css without a page
|
|
499
|
+
* reload. js changes rebuild js (full reload — scripts need one), and an
|
|
500
|
+
* unknown/mixed set rebuilds everything.
|
|
501
|
+
*
|
|
502
|
+
* @omega.js/client's dist rides the same lane (#378). It reaches the bundle
|
|
503
|
+
* through the `@omega.js/client` alias, resolved once at boot — so without it
|
|
504
|
+
* here a client edit rebuilt the client's dist and stopped, and the site served
|
|
505
|
+
* its boot-time bytes until an unrelated asset edit or a stack restart.
|
|
506
|
+
* @param {object} options
|
|
507
|
+
* @param {string[]} options.dirs - the asset source dirs (existing ones only)
|
|
508
|
+
* @param {string} [options.clientDist] - the resolved @omega.js/client dist dir
|
|
509
|
+
* @param {function} options.build - (only) => Promise, the dev asset rebuild
|
|
510
|
+
* @param {object} [options.manifest] - the LIVE manifest the engine renders
|
|
511
|
+
* from; given with manifestPath, a rebuild that moved the font preload list
|
|
512
|
+
* folds into it and rewrites the file (#765)
|
|
513
|
+
* @param {string} [options.manifestPath] - where that manifest is written
|
|
514
|
+
* @returns {{ close: function }} the live watchers (the dev loop keeps them for
|
|
515
|
+
* the life of the process; tests close them)
|
|
516
|
+
*/
|
|
517
|
+
function watchAssetSources(options) {
|
|
518
|
+
let timer = null;
|
|
519
|
+
let pendingKinds = new Set();
|
|
520
|
+
const kindOf = (file) => {
|
|
521
|
+
if (/\.(scss|css)$/.test(file || '')) return 'css';
|
|
522
|
+
if (/\.(js|mjs)$/.test(file || '')) return 'js';
|
|
523
|
+
return 'other';
|
|
524
|
+
};
|
|
525
|
+
const schedule = (file) => {
|
|
526
|
+
pendingKinds.add(kindOf(file));
|
|
527
|
+
clearTimeout(timer);
|
|
528
|
+
timer = setTimeout(() => {
|
|
529
|
+
const kinds = pendingKinds;
|
|
530
|
+
pendingKinds = new Set();
|
|
531
|
+
const only = kinds.size === 1 && !kinds.has('other') ? kinds.values().next().value : undefined;
|
|
532
|
+
options.build(only)
|
|
533
|
+
.then((next) => {
|
|
534
|
+
// #765: the head's font preloads are manifest CONTENT, not a stable
|
|
535
|
+
// dev URL, so a rebuild that moved them has to reach the browser.
|
|
536
|
+
// The list folds into the live manifest (the engine holds it by
|
|
537
|
+
// reference) and the manifest FILE is rewritten — Eleventy watches
|
|
538
|
+
// that file, so its re-render happens AFTER this build rather than
|
|
539
|
+
// racing it, and only when the head's list actually moved.
|
|
540
|
+
if (options.manifest && options.manifestPath && refreshLiveManifest(options.manifest, next)) {
|
|
541
|
+
jetpack.write(options.manifestPath, JSON.stringify(options.manifest, null, 2));
|
|
542
|
+
}
|
|
543
|
+
logger.log(`Assets rebuilt (${only || 'all'}) — browser live-reloads${only === 'css' ? ' via css hot-swap' : ''}`);
|
|
544
|
+
})
|
|
545
|
+
.catch((error) => logger.error('Asset rebuild failed:', error));
|
|
546
|
+
}, WATCH_DEBOUNCE_MS);
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
const watchers = options.dirs.map((dir) => fs.watch(dir, { recursive: true }, (event, file) => schedule(file)));
|
|
550
|
+
|
|
551
|
+
// The client dist is the one watched root that gets REPLACED rather than
|
|
552
|
+
// written into (its own `npm run prepare` deletes dist/ and writes it again),
|
|
553
|
+
// so it registers replace-safe. Absent at boot (no client installed) → not
|
|
554
|
+
// watched, the same existence rule the dirs above are filtered by.
|
|
555
|
+
if (options.clientDist && fs.existsSync(options.clientDist)) {
|
|
556
|
+
watchers.push(watchReplaceable(options.clientDist, schedule));
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return {
|
|
560
|
+
close: () => {
|
|
561
|
+
clearTimeout(timer);
|
|
562
|
+
watchers.forEach((watcher) => watcher.close());
|
|
563
|
+
},
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Fold a rebuild's manifest back into the LIVE one the engine renders from
|
|
569
|
+
* (#765). Dev hands Eleventy the boot manifest by reference, which is right
|
|
570
|
+
* for every asset URL — dev names are stable, so a rebuilt bundle keeps its
|
|
571
|
+
* URL. The font preload list is different: it is CONTENT (the first-paint
|
|
572
|
+
* faces the compiled sheet declares), so a theme's @font-face edit has to
|
|
573
|
+
* reach the next render instead of the boot capture.
|
|
574
|
+
*
|
|
575
|
+
* A js-only rebuild returns before the css lane and carries no list, so it
|
|
576
|
+
* leaves the live one alone; a css rebuild replaces it, an emptied list
|
|
577
|
+
* included. The answer is whether the list MOVED — the caller rewrites the
|
|
578
|
+
* manifest file on a change, and that file is what makes Eleventy re-render
|
|
579
|
+
* (see watchAssetSources), so an unchanged list must not trigger one.
|
|
580
|
+
* @param {object} manifest - the live manifest the engine holds
|
|
581
|
+
* @param {object} next - what the rebuild returned
|
|
582
|
+
* @returns {boolean} whether the preload list changed
|
|
583
|
+
*/
|
|
584
|
+
function refreshLiveManifest(manifest, next) {
|
|
585
|
+
const preloads = next && next.fontPreloads;
|
|
586
|
+
if (!preloads || JSON.stringify(preloads) === JSON.stringify(manifest.fontPreloads)) return false;
|
|
587
|
+
|
|
588
|
+
manifest.fontPreloads = preloads;
|
|
589
|
+
|
|
590
|
+
return true;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* The ENV lane's watcher (#681): every layer of the `.env` chain — company,
|
|
595
|
+
* brand, this target — and each layer's `.env.<environment>` overlay. A change
|
|
596
|
+
* reloads the cascade into process.env, and the log line names the FILE, never
|
|
597
|
+
* a value. Resolution and watching live in @omega.js/devkit/env-watch, shared
|
|
598
|
+
* with the desktop and extension dev lanes; this binds web's own target name.
|
|
599
|
+
* @param {string} root - the target root
|
|
600
|
+
* @param {object} [options]
|
|
601
|
+
* @param {string} [options.environment] - the environment whose overlay counts
|
|
602
|
+
* @returns {{ inputs: Array<{ layer: string, path: string }>, close: function }}
|
|
603
|
+
*/
|
|
604
|
+
function watchEnvSources(root, options) {
|
|
605
|
+
return watchEnvChain({
|
|
606
|
+
projectDir: root,
|
|
607
|
+
target: 'web',
|
|
608
|
+
environment: options && options.environment,
|
|
609
|
+
log: (line) => logger.log(line),
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* A recursive fs.watch over a directory that may be REPLACED under it. A
|
|
615
|
+
* handle is bound to the directory it was opened on: once that directory is
|
|
616
|
+
* deleted, the handle is watching something the filesystem no longer resolves
|
|
617
|
+
* — on some platforms it errors or closes, on others it stays quietly useless.
|
|
618
|
+
* So: whenever the root is gone (an event that finds it missing, an `error`, a
|
|
619
|
+
* `close` nobody asked for), drop the handle, probe until the directory is back,
|
|
620
|
+
* watch the NEW one, and report the replacement as one change.
|
|
621
|
+
* @param {string} dir - the directory to watch
|
|
622
|
+
* @param {function} onChange - (file) => void, the same sink the plain watchers use
|
|
623
|
+
* @returns {{ close: function }}
|
|
624
|
+
*/
|
|
625
|
+
function watchReplaceable(dir, onChange) {
|
|
626
|
+
let watcher = null;
|
|
627
|
+
let poll = null;
|
|
628
|
+
let closed = false;
|
|
629
|
+
|
|
630
|
+
const arm = () => {
|
|
631
|
+
watcher = fs.watch(dir, { recursive: true }, (event, file) => {
|
|
632
|
+
if (!fs.existsSync(dir)) return rearm();
|
|
633
|
+
return onChange(file);
|
|
634
|
+
});
|
|
635
|
+
watcher.on('error', rearm);
|
|
636
|
+
watcher.on('close', rearm);
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
// Arming the probe FIRST makes every re-entrant call (closing the handle
|
|
640
|
+
// emits its own 'close') a no-op instead of a second interval.
|
|
641
|
+
const rearm = () => {
|
|
642
|
+
if (closed || poll) return;
|
|
643
|
+
|
|
644
|
+
poll = setInterval(() => {
|
|
645
|
+
if (!fs.existsSync(dir)) return;
|
|
646
|
+
try {
|
|
647
|
+
arm();
|
|
648
|
+
} catch (error) {
|
|
649
|
+
return; // replaced again between the probe and the watch — keep probing
|
|
650
|
+
}
|
|
651
|
+
clearInterval(poll);
|
|
652
|
+
poll = null;
|
|
653
|
+
onChange(dir);
|
|
654
|
+
}, REARM_POLL_MS);
|
|
655
|
+
|
|
656
|
+
const dead = watcher;
|
|
657
|
+
watcher = null;
|
|
658
|
+
if (dead) dead.close();
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
arm();
|
|
662
|
+
|
|
663
|
+
return {
|
|
664
|
+
close: () => {
|
|
665
|
+
closed = true;
|
|
666
|
+
clearInterval(poll);
|
|
667
|
+
if (watcher) watcher.close();
|
|
668
|
+
},
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* The RESCAN lane (#200 Lane B): a light watcher per recorded rescan dir that
|
|
674
|
+
* re-runs just the capture whose input changed. No config reset ever — that is
|
|
675
|
+
* the entire reason these dirs are a separate union: they hold the brand's
|
|
676
|
+
* CONTENT (pages/, the collection dirs), and a reset there would drag every
|
|
677
|
+
* page edit off Eleventy's incremental lane.
|
|
678
|
+
*
|
|
679
|
+
* What a re-run buys: the live decision object is current the moment a file
|
|
680
|
+
* lands (the permalink-collision diagnostic re-emits right there, before any
|
|
681
|
+
* rebuild finishes). It is NOT what makes a render fresh — the engine
|
|
682
|
+
* re-scans on `eleventy.before`, so whichever watcher sees the file first, the
|
|
683
|
+
* render that follows reads current answers.
|
|
684
|
+
*
|
|
685
|
+
* Debounced like the asset lane: an editor's save is several events, and a
|
|
686
|
+
* scan per event is pure waste. A dir that does not exist yet is skipped —
|
|
687
|
+
* fs.watch cannot arm a missing path, and a collection dir appearing under
|
|
688
|
+
* Eleventy's input dir triggers a rebuild (and its re-scan) by itself.
|
|
689
|
+
*
|
|
690
|
+
* Closing DROPS the queued re-run: every config reset closes this union and
|
|
691
|
+
* opens the new one, and a debounce still in flight belongs to captures the
|
|
692
|
+
* previous build owned.
|
|
693
|
+
* @param {Array<{ dir: string, rerun: function }>} targets - the recorded rescan union
|
|
694
|
+
* @returns {Array<{ close: function }>} the live watchers (the caller closes them)
|
|
695
|
+
*/
|
|
696
|
+
function watchRescanTargets(targets) {
|
|
697
|
+
return targets.filter((target) => fs.existsSync(target.dir)).map((target) => {
|
|
698
|
+
let timer = null;
|
|
699
|
+
const watcher = fs.watch(target.dir, { recursive: true }, () => {
|
|
700
|
+
clearTimeout(timer);
|
|
701
|
+
timer = setTimeout(() => {
|
|
702
|
+
try {
|
|
703
|
+
target.rerun();
|
|
704
|
+
} catch (error) {
|
|
705
|
+
logger.error('Rescan failed:', error);
|
|
706
|
+
}
|
|
707
|
+
}, RESCAN_DEBOUNCE_MS);
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
return {
|
|
711
|
+
close: () => {
|
|
712
|
+
clearTimeout(timer);
|
|
713
|
+
watcher.close();
|
|
714
|
+
},
|
|
715
|
+
};
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Serve the Firebase auth emulator THROUGH the site origin (#156) — the dev
|
|
721
|
+
* counterpart of the self-hosted /__/auth/* helpers a production build ships
|
|
722
|
+
* (src/firebase-auth-helpers.js).
|
|
723
|
+
*
|
|
724
|
+
* The emulator's OAuth handler hands a redirect credential back by writing
|
|
725
|
+
* `firebase:redirectEvent:*` into sessionStorage on ITS OWN origin, and the
|
|
726
|
+
* SDK's helper iframe reads it back from there. Served on the emulator's port,
|
|
727
|
+
* that origin is a third party to the site, and browser storage partitioning
|
|
728
|
+
* gives the iframe a different, empty partition — the return leg dead-ends.
|
|
729
|
+
* Proxied here, handler and iframe are both first-party to the site, so they
|
|
730
|
+
* share one partition and signInWithRedirect completes in dev exactly as it
|
|
731
|
+
* does in production.
|
|
732
|
+
*
|
|
733
|
+
* The prefixes are the emulator's whole surface, mounted at the site ROOT
|
|
734
|
+
* because connectAuthEmulator() discards any path on the URL it is given
|
|
735
|
+
* (@firebase/auth: "Always replace path with /") — a sub-path mount is not
|
|
736
|
+
* available to us. `/emulator/*` covers the handler, the helper iframe and the
|
|
737
|
+
* out-of-band action links; the two googleapis.com prefixes are the REST
|
|
738
|
+
* surface, which the SDK addresses as `<emulator origin>/<apiHost><path>`.
|
|
739
|
+
* None of them can collide with a page URL.
|
|
740
|
+
*
|
|
741
|
+
* The target port is resolved PER REQUEST (#300). With the proxy on, this —
|
|
742
|
+
* not the baked `dev.ports` — is where every auth call actually goes, so a
|
|
743
|
+
* boot-time number kept sending sign-ins to whatever emulator held the
|
|
744
|
+
* classic 9099 (a neighbouring project's, in the report) long after this
|
|
745
|
+
* brand's suite came up bumped.
|
|
746
|
+
* @param {number|function} [authPort] - the port, or a getter for the live one
|
|
747
|
+
* @returns {function} connect-style middleware
|
|
748
|
+
*/
|
|
749
|
+
function devAuthEmulator(authPort) {
|
|
750
|
+
const prefixes = ['/emulator', '/identitytoolkit.googleapis.com', '/securetoken.googleapis.com'];
|
|
751
|
+
const resolvePort = () => (typeof authPort === 'function' ? authPort() : authPort) || CLASSIC_PORTS.auth;
|
|
752
|
+
|
|
753
|
+
// Hop-by-hop framing headers belong to THIS connection, not the upstream's —
|
|
754
|
+
// copying them makes Node chunk a body it is already re-chunking.
|
|
755
|
+
const skipHeaders = new Set(['connection', 'keep-alive', 'transfer-encoding']);
|
|
756
|
+
|
|
757
|
+
// setHeader + statusCode, never writeHead. Eleventy's dev server wraps `res`
|
|
758
|
+
// to inject its live-reload script (eleventy-dev-server/server/wrapResponse):
|
|
759
|
+
// a writeHead carrying a text/html content-type is DEFERRED into a replay
|
|
760
|
+
// queue, but a piped Buffer write flushes the real headers first, and the
|
|
761
|
+
// replay then throws ERR_HTTP_HEADERS_SENT and takes the whole dev server
|
|
762
|
+
// down. Going through setHeader keeps that queue empty. It also keeps the
|
|
763
|
+
// wrapper's html transform off the emulator's pages — the live-reload script
|
|
764
|
+
// has no business inside the OAuth handler.
|
|
765
|
+
const answer = (res, status, headers) => {
|
|
766
|
+
res.statusCode = status;
|
|
767
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
768
|
+
if (!skipHeaders.has(name.toLowerCase())) {
|
|
769
|
+
res.setHeader(name, value);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
// The emulator deliberately binds 127.0.0.1 only, while the site listens on
|
|
775
|
+
// every interface — proxying for a LAN client would silently remove that
|
|
776
|
+
// safety property and hand the emulator's whole REST surface to the network.
|
|
777
|
+
const isLoopback = (address) => address === '::1'
|
|
778
|
+
|| (address || '').startsWith('127.')
|
|
779
|
+
|| (address || '').startsWith('::ffff:127.');
|
|
780
|
+
|
|
781
|
+
return (req, res, next) => {
|
|
782
|
+
const pathname = (req.url || '').split('?')[0];
|
|
783
|
+
|
|
784
|
+
if (!prefixes.some((prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`))) {
|
|
785
|
+
return next();
|
|
786
|
+
}
|
|
787
|
+
if (!isLoopback(req.socket?.remoteAddress)) {
|
|
788
|
+
return next();
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
const port = resolvePort();
|
|
792
|
+
const upstream = http.request({
|
|
793
|
+
host: '127.0.0.1',
|
|
794
|
+
port,
|
|
795
|
+
method: req.method,
|
|
796
|
+
path: req.url,
|
|
797
|
+
headers: { ...req.headers, host: `127.0.0.1:${port}` },
|
|
798
|
+
}, (upstreamRes) => {
|
|
799
|
+
answer(res, upstreamRes.statusCode, upstreamRes.headers);
|
|
800
|
+
upstreamRes.pipe(res);
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
// A website-only dev session (no emulator suite running) is an expected
|
|
804
|
+
// external condition, not our bug: answer the auth call with a 502 that
|
|
805
|
+
// names the port instead of hanging the request.
|
|
806
|
+
upstream.on('error', (error) => {
|
|
807
|
+
logger.error(`Auth emulator proxy: ${pathname} → :${port} failed (${error.message})`);
|
|
808
|
+
answer(res, 502, { 'content-type': 'text/plain; charset=utf-8' });
|
|
809
|
+
res.end(Buffer.from(`Auth emulator on port ${port} is not reachable`));
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
return req.pipe(upstream);
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* The `dev:` value of the Configuration chrome, as `core/_includes/core/foot.html`
|
|
818
|
+
* renders it (`dev: {{ jekyll.dev | jsonify }},`) — one compact JSON line, or
|
|
819
|
+
* `null` on a build that bakes no dev chrome. The lookahead is what makes the
|
|
820
|
+
* non-greedy body stop at the object's OWN close brace rather than the nested
|
|
821
|
+
* ports one. The coupling to that template is pinned by the served-page test,
|
|
822
|
+
* which rewrites a REAL rendered page.
|
|
823
|
+
*/
|
|
824
|
+
const DEV_CHROME = /(\n\s*dev: )(?:\{.*?\}|null)(?=,\n)/s;
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Serve-time dev-ports injection (#346): every HTML response leaves this server
|
|
828
|
+
* carrying the map of the stack running RIGHT NOW, whatever its page baked.
|
|
829
|
+
*
|
|
830
|
+
* The render-time bake is a snapshot of the moment a page was built, and the
|
|
831
|
+
* normal boot order builds every page before the backend publishes anything:
|
|
832
|
+
* the website build finishes in under a second while the emulator suite seeds
|
|
833
|
+
* for minutes, so the whole initial fleet bakes `{ website }` alone and nothing
|
|
834
|
+
* re-renders it — no source file changed. Same hole for a mid-session emulator
|
|
835
|
+
* restart onto bumped numbers. Rewriting the chrome as the page goes out covers
|
|
836
|
+
* both by construction; the bake stays as it is on disk, advisory, and the
|
|
837
|
+
* built output is byte-for-byte what the build wrote.
|
|
838
|
+
*
|
|
839
|
+
* The rewrite wraps `res.end` rather than the response object: eleventy wrapped
|
|
840
|
+
* `res` before the middleware chain ran (its live-reload injection), so ours is
|
|
841
|
+
* the OUTER end — it rewrites the string the static handler hands over, and
|
|
842
|
+
* eleventy's transform then runs on the rewritten html and sizes the body from
|
|
843
|
+
* it. HTML only, and only a response whose body arrives as a string, which is
|
|
844
|
+
* how eleventy serves a page. A response with no chrome (a redirect stub, an
|
|
845
|
+
* error page) matches nothing and passes through untouched.
|
|
846
|
+
* @param {function} devChrome - the live dev-chrome getter (devPortsOption)
|
|
847
|
+
* @returns {function} connect-style middleware
|
|
848
|
+
*/
|
|
849
|
+
function devInjectDevPorts(devChrome) {
|
|
850
|
+
return (req, res, next) => {
|
|
851
|
+
const end = res.end;
|
|
852
|
+
|
|
853
|
+
res.end = (data, ...rest) => {
|
|
854
|
+
const contentType = String(res.getHeader('content-type') || '');
|
|
855
|
+
|
|
856
|
+
if (typeof data === 'string' && contentType.startsWith('text/html')) {
|
|
857
|
+
return end.call(res, data.replace(DEV_CHROME, (match, open) => `${open}${JSON.stringify(devChrome())}`), ...rest);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
return end.call(res, data, ...rest);
|
|
861
|
+
};
|
|
862
|
+
|
|
863
|
+
return next();
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* Clean-URL resolution, the legacy serve.js contract: pages are flat `.html`
|
|
869
|
+
* files with slash-free URLs, so `/signin` (and a stray `/signin/`) serves
|
|
870
|
+
* `signin.html`. Mirrors production GitHub Pages, which resolves extensionless
|
|
871
|
+
* paths against `.html` files natively.
|
|
872
|
+
* @param {string} outDir
|
|
873
|
+
* @returns {function} connect-style middleware
|
|
874
|
+
*/
|
|
875
|
+
function devCleanUrls(outDir) {
|
|
876
|
+
const root = path.resolve(outDir);
|
|
877
|
+
|
|
878
|
+
return (req, res, next) => {
|
|
879
|
+
const [pathname, query] = (req.url || '').split('?');
|
|
880
|
+
|
|
881
|
+
// A malformed percent-escape throws URIError — not a clean-URL
|
|
882
|
+
// candidate, fall through to the static handler.
|
|
883
|
+
let decoded;
|
|
884
|
+
try {
|
|
885
|
+
decoded = decodeURIComponent(pathname);
|
|
886
|
+
} catch (e) {
|
|
887
|
+
return next();
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
const clean = decoded.replace(/\/+$/, '');
|
|
891
|
+
|
|
892
|
+
if (!clean) {
|
|
893
|
+
return next();
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
// Legacy serve.js contract: rewrite only when the request doesn't hit a
|
|
897
|
+
// real file but `<path>.html` exists. No extension sniffing — dotted
|
|
898
|
+
// slugs (/updates/v1.0.0) are page URLs too.
|
|
899
|
+
const original = path.resolve(root, `.${decoded}`);
|
|
900
|
+
const resolved = path.resolve(root, `.${clean}.html`);
|
|
901
|
+
if (
|
|
902
|
+
resolved.startsWith(root + path.sep)
|
|
903
|
+
&& jetpack.exists(original) !== 'file'
|
|
904
|
+
&& jetpack.exists(resolved) === 'file'
|
|
905
|
+
) {
|
|
906
|
+
req.url = `${clean}.html${query ? `?${query}` : ''}`;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
return next();
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* The dev website ORIGIN this run answers on — the ONE place protocol and port
|
|
915
|
+
* are put together (#262). Every consumer of "where the dev website is" derives
|
|
916
|
+
* from this: site.url, the published ports file, and the page chrome.
|
|
917
|
+
* @param {number} port - the resolved dev-server (public) port
|
|
918
|
+
* @param {boolean} [https] - whether the public port speaks TLS (mkcert proxy)
|
|
919
|
+
* @returns {string} the origin, protocol included
|
|
920
|
+
*/
|
|
921
|
+
function devWebsiteOrigin(port, https) {
|
|
922
|
+
return `${https ? 'https' : 'http'}://localhost:${port}`;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
/**
|
|
926
|
+
* Dev builds link to THIS server, never the live site (legacy _config_dev.yml
|
|
927
|
+
* url-override parity): site.url is the one root every absolute-URL surface
|
|
928
|
+
* derives from — canonicals/og tags, omega_external, absolute_url, redirect
|
|
929
|
+
* pages, nav — so pointing it at the local origin keeps every click in dev.
|
|
930
|
+
* @param {object} siteData - the loaded site global (mutated)
|
|
931
|
+
* @param {string} origin - the resolved dev website origin (devWebsiteOrigin)
|
|
932
|
+
*/
|
|
933
|
+
function applyDevSiteUrl(siteData, origin) {
|
|
934
|
+
siteData.url = origin;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/**
|
|
938
|
+
* Resolve the website port through the allocator (N7). An explicit `--port`
|
|
939
|
+
* flag or a config `ports.website` entry PINS the port (busy = hard error);
|
|
940
|
+
* otherwise start from OMEGA_WEBSITE_PORT (a parent that already allocated)
|
|
941
|
+
* or the classic 4000 and bump +1 while taken.
|
|
942
|
+
*/
|
|
943
|
+
async function resolveWebsitePort(root, flagPort) {
|
|
944
|
+
const pins = {};
|
|
945
|
+
|
|
946
|
+
if (flagPort) {
|
|
947
|
+
if (!(await isPortFree(flagPort))) {
|
|
948
|
+
throw new Error(`Port ${flagPort} (pinned via --port) is already in use — free it or pick another`);
|
|
949
|
+
}
|
|
950
|
+
pins.website = flagPort;
|
|
951
|
+
} else {
|
|
952
|
+
const configPin = loadPortPins(root).website;
|
|
953
|
+
if (typeof configPin === 'number') {
|
|
954
|
+
pins.website = configPin;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
const wanted = { website: websiteWantedPort(root) };
|
|
959
|
+
const { ports, bumped } = await resolvePorts({ wanted, pins });
|
|
960
|
+
return { port: ports.website, bumped: bumped.length > 0 };
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* The wanted (pre-allocator) website port: OMEGA_WEBSITE_PORT (a parent that
|
|
965
|
+
* already allocated) or the classic 4000, plus this target's deterministic
|
|
966
|
+
* instance offset (multi-instance targets: an instance wants base + its
|
|
967
|
+
* position in the instances array, so N instances dev side-by-side off the
|
|
968
|
+
* same base). Lenient like loadPortPins — no config means no offset.
|
|
969
|
+
*/
|
|
970
|
+
function websiteWantedPort(root) {
|
|
971
|
+
const base = envPort('website') || CLASSIC_PORTS.website;
|
|
972
|
+
|
|
973
|
+
try {
|
|
974
|
+
if (!hasOmegaConfig(root)) {
|
|
975
|
+
return base;
|
|
976
|
+
}
|
|
977
|
+
const { config, instance } = loadConfig(root, 'web');
|
|
978
|
+
return base + instancePortOffset(config.targets?.web, instance);
|
|
979
|
+
} catch (error) {
|
|
980
|
+
return base;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/**
|
|
985
|
+
* Read explicit port pins from the consumer's config `ports` section.
|
|
986
|
+
* Lenient — a missing/broken config means no pins, never a dev-loop failure.
|
|
987
|
+
*/
|
|
988
|
+
function loadPortPins(root) {
|
|
989
|
+
try {
|
|
990
|
+
if (!hasOmegaConfig(root)) {
|
|
991
|
+
return {};
|
|
992
|
+
}
|
|
993
|
+
const config = loadConfig(root, 'web').config;
|
|
994
|
+
return config.ports && typeof config.ports === 'object' ? config.ports : {};
|
|
995
|
+
} catch (error) {
|
|
996
|
+
return {};
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/**
|
|
1001
|
+
* The `dev` chrome the engine bakes into every page — as a GETTER, called per
|
|
1002
|
+
* render (#300). The sibling backend's published map (its live emulator
|
|
1003
|
+
* ports) merges OVER this server's own website port, so the browser always
|
|
1004
|
+
* connects to the stack that is actually running: a backend that booted after
|
|
1005
|
+
* this server, or an emulator that restarted onto bumped numbers, lands in
|
|
1006
|
+
* the very next render instead of never.
|
|
1007
|
+
*
|
|
1008
|
+
* The website ORIGIN rides the same map (#262): a page knows its own origin,
|
|
1009
|
+
* but a desktop/extension surface reading this chrome does not, and protocol is
|
|
1010
|
+
* not derivable from a port number.
|
|
1011
|
+
* @param {string} root - this target's root (its own ports file is skipped)
|
|
1012
|
+
* @param {number} port - the resolved website port
|
|
1013
|
+
* @param {string} origin - the resolved website origin (devWebsiteOrigin)
|
|
1014
|
+
* @returns {function} () => the dev chrome object
|
|
1015
|
+
*/
|
|
1016
|
+
function devPortsOption(root, port, origin) {
|
|
1017
|
+
return () => ({
|
|
1018
|
+
ports: { ...readSiblingPorts(root), website: port },
|
|
1019
|
+
origin,
|
|
1020
|
+
authEmulatorProxy: true,
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* `--local` prelude: file:-install every @omega.js framework used anywhere in
|
|
1026
|
+
* this brand (all targets, walked up from cwd) from the local Omega monorepo,
|
|
1027
|
+
* then start the monorepo's src→dist watch as a session-scoped child.
|
|
1028
|
+
*/
|
|
1029
|
+
// Exposed for tests (the command function stays the main export)
|
|
1030
|
+
module.exports.resolveWebsitePort = resolveWebsitePort;
|
|
1031
|
+
module.exports.websiteWantedPort = websiteWantedPort;
|
|
1032
|
+
module.exports.devPortsOption = devPortsOption;
|
|
1033
|
+
module.exports.devServerOptions = devServerOptions;
|
|
1034
|
+
module.exports.resolveAssetThemeLayers = resolveAssetThemeLayers;
|
|
1035
|
+
module.exports.registerTemplateWatchTargets = registerTemplateWatchTargets;
|
|
1036
|
+
module.exports.watchAssetSources = watchAssetSources;
|
|
1037
|
+
module.exports.watchEnvSources = watchEnvSources;
|
|
1038
|
+
module.exports.refreshLiveManifest = refreshLiveManifest;
|
|
1039
|
+
module.exports.watchRescanTargets = watchRescanTargets;
|
|
1040
|
+
module.exports.applyDevSiteUrl = applyDevSiteUrl;
|
|
1041
|
+
module.exports.devWebsiteOrigin = devWebsiteOrigin;
|
|
1042
|
+
|
|
1043
|
+
async function linkBrandToMonorepo() {
|
|
1044
|
+
const local = require('../vendor/devkit/local.js');
|
|
1045
|
+
const monorepoRoot = local.resolveMonorepoRoot();
|
|
1046
|
+
const brandRoot = local.findBrandRoot(process.cwd());
|
|
1047
|
+
logger.log(`Local mode: linking @omega.js packages from ${monorepoRoot}`);
|
|
1048
|
+
|
|
1049
|
+
for (const targetDir of local.discoverTargets(brandRoot)) {
|
|
1050
|
+
await local.linkLocalPackages({ dir: targetDir, monorepoRoot, logger });
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// Session-scoped by the helper itself — the watch dies with this dev server
|
|
1054
|
+
// (no orphans), the same way the brand-root `omega dev` gets it (#587). All
|
|
1055
|
+
// that is left here is the dev server's own Ctrl-C policy: a SIGINT listener
|
|
1056
|
+
// suppresses node's default kill, so it has to exit deliberately.
|
|
1057
|
+
const watch = local.startMonorepoWatch({ monorepoRoot, logger });
|
|
1058
|
+
if (watch.child) {
|
|
1059
|
+
STOP_SIGNALS.forEach((signal) => process.on(signal, () => process.exit(0)));
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// The same gate the brand-root boot uses (#670): nothing reads a dist while a
|
|
1063
|
+
// prepare is still rewriting it — a fresh watch's initial pass, and an
|
|
1064
|
+
// already-running watch's, read from its log (#622). Awaited on BOTH
|
|
1065
|
+
// branches, which is why this prelude never had the skip #622 fixed.
|
|
1066
|
+
await watch.ready;
|
|
1067
|
+
}
|