@aglyn/plugins-ai 1.0.0-beta.270 → 1.0.0-beta.272
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/package.json +17 -17
- package/src/lib/activity/ai-activity-actions.d.ts +4 -3
- package/src/lib/activity/ai-activity-actions.js +4 -0
- package/src/lib/activity/ai-activity-actions.js.map +1 -1
- package/src/lib/assets/site-styles/beauty.webp +0 -0
- package/src/lib/assets/site-styles/blog.webp +0 -0
- package/src/lib/assets/site-styles/business.webp +0 -0
- package/src/lib/assets/site-styles/coming-soon.webp +0 -0
- package/src/lib/assets/site-styles/education.webp +0 -0
- package/src/lib/assets/site-styles/events.webp +0 -0
- package/src/lib/assets/site-styles/fitness.webp +0 -0
- package/src/lib/assets/site-styles/landing.webp +0 -0
- package/src/lib/assets/site-styles/music.webp +0 -0
- package/src/lib/assets/site-styles/nonprofit.webp +0 -0
- package/src/lib/assets/site-styles/personal.webp +0 -0
- package/src/lib/assets/site-styles/photography.webp +0 -0
- package/src/lib/assets/site-styles/portfolio.webp +0 -0
- package/src/lib/assets/site-styles/professional.webp +0 -0
- package/src/lib/assets/site-styles/realestate.webp +0 -0
- package/src/lib/assets/site-styles/restaurant.webp +0 -0
- package/src/lib/assets/site-styles/store.webp +0 -0
- package/src/lib/assets/site-styles/studio.webp +0 -0
- package/src/lib/assets/site-styles/trades.webp +0 -0
- package/src/lib/assets/site-styles/wellness.webp +0 -0
- package/src/lib/assets/site-styles/yoga.webp +0 -0
- package/src/lib/components/ai-credits-card.component.d.ts +4 -3
- package/src/lib/components/ai-credits-card.component.js +15 -15
- package/src/lib/components/ai-credits-card.component.js.map +1 -1
- package/src/lib/components/ai-job-input-form.component.d.ts +36 -0
- package/src/lib/components/ai-job-input-form.component.js +100 -0
- package/src/lib/components/ai-job-input-form.component.js.map +1 -0
- package/src/lib/components/ai-job-requests.d.ts +4 -0
- package/src/lib/components/ai-job-requests.js +4 -0
- package/src/lib/components/ai-job-requests.js.map +1 -1
- package/src/lib/components/ai-site-build-page.component.js +18 -0
- package/src/lib/components/ai-site-build-page.component.js.map +1 -1
- package/src/lib/components/ai-site-import-job.component.d.ts +41 -0
- package/src/lib/components/ai-site-import-job.component.js +707 -0
- package/src/lib/components/ai-site-import-job.component.js.map +1 -0
- package/src/lib/components/ai-site-import-start.component.d.ts +64 -0
- package/src/lib/components/ai-site-import-start.component.js +335 -0
- package/src/lib/components/ai-site-import-start.component.js.map +1 -0
- package/src/lib/components/ai-site-ownership-proof.component.d.ts +42 -0
- package/src/lib/components/ai-site-ownership-proof.component.js +353 -0
- package/src/lib/components/ai-site-ownership-proof.component.js.map +1 -0
- package/src/lib/components/ai-site-start-card.component.d.ts +1 -1
- package/src/lib/components/ai-site-start-card.component.js +261 -119
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-site-start-steps.component.d.ts +43 -2
- package/src/lib/components/ai-site-start-steps.component.js +651 -15
- package/src/lib/components/ai-site-start-steps.component.js.map +1 -1
- package/src/lib/components/ai-site-start-tracking.d.ts +10 -0
- package/src/lib/components/ai-site-start-tracking.js +14 -0
- package/src/lib/components/ai-site-start-tracking.js.map +1 -1
- package/src/lib/components/ai-site-style-previews.js +26 -22
- package/src/lib/components/ai-site-style-previews.js.map +1 -1
- package/src/lib/components/ai-upsell-dialog.component.d.ts +7 -5
- package/src/lib/components/ai-upsell-dialog.component.js +8 -6
- package/src/lib/components/ai-upsell-dialog.component.js.map +1 -1
- package/src/lib/components/assist-build-card.component.js +11 -1
- package/src/lib/components/assist-build-card.component.js.map +1 -1
- package/src/lib/components/assist-jobs-drawer.component.js +9 -1
- package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
- package/src/lib/components/assist-panel.component.js +8 -4
- package/src/lib/components/assist-panel.component.js.map +1 -1
- package/src/lib/components/staff-org-ai-card.component.js +4 -7
- package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
- package/src/lib/declarations.d.ts +2 -2
- package/src/lib/declarations.js +9 -5
- package/src/lib/declarations.js.map +1 -1
- package/src/lib/jobs/ai-build-capabilities.js +3 -1
- package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
- package/src/lib/jobs/ai-business-profile-prefill.d.ts +1 -1
- package/src/lib/jobs/ai-business-profile-prefill.js +14 -3
- package/src/lib/jobs/ai-business-profile-prefill.js.map +1 -1
- package/src/lib/jobs/ai-job-build-step.js +5 -3
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-drafts.d.ts +14 -0
- package/src/lib/jobs/ai-job-drafts.js +24 -0
- package/src/lib/jobs/ai-job-drafts.js.map +1 -1
- package/src/lib/jobs/ai-job-form-step.d.ts +15 -1
- package/src/lib/jobs/ai-job-form-step.js +75 -8
- package/src/lib/jobs/ai-job-form-step.js.map +1 -1
- package/src/lib/jobs/ai-job-import-step.d.ts +136 -0
- package/src/lib/jobs/ai-job-import-step.js +809 -0
- package/src/lib/jobs/ai-job-import-step.js.map +1 -0
- package/src/lib/jobs/ai-job-page-language.d.ts +52 -1
- package/src/lib/jobs/ai-job-page-language.js +99 -5
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.d.ts +19 -2
- package/src/lib/jobs/ai-job-page-step.js +42 -18
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +25 -2
- package/src/lib/jobs/ai-job-plan-step.js +103 -29
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-settings-step.js +4 -3
- package/src/lib/jobs/ai-job-settings-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +27 -0
- package/src/lib/jobs/ai-job-site-datasets.js +140 -14
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-job-site-look.js +18 -5
- package/src/lib/jobs/ai-job-site-look.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.d.ts +16 -1
- package/src/lib/jobs/ai-job-site-step.js +95 -22
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-text-step.d.ts +15 -1
- package/src/lib/jobs/ai-job-text-step.js.map +1 -1
- package/src/lib/jobs/ai-job-tracking-step.d.ts +14 -3
- package/src/lib/jobs/ai-job-tracking-step.js +28 -5
- package/src/lib/jobs/ai-job-tracking-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs.d.ts +13 -1
- package/src/lib/jobs/ai-jobs.js +77 -10
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-layout-owner-photos.d.ts +16 -1
- package/src/lib/jobs/ai-layout-owner-photos.js +47 -0
- package/src/lib/jobs/ai-layout-owner-photos.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +27 -2
- package/src/lib/jobs/ai-layout-stock-photos.js +190 -19
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-site-inspiration-signals.d.ts +98 -0
- package/src/lib/jobs/ai-site-inspiration-signals.js +585 -0
- package/src/lib/jobs/ai-site-inspiration-signals.js.map +1 -0
- package/src/lib/jobs/ai-site-inspiration.d.ts +157 -0
- package/src/lib/jobs/ai-site-inspiration.js +346 -0
- package/src/lib/jobs/ai-site-inspiration.js.map +1 -0
- package/src/lib/jobs/ai-site-publish.d.ts +26 -1
- package/src/lib/jobs/ai-site-publish.js +162 -13
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/ai-theme-brand-inputs.d.ts +77 -3
- package/src/lib/jobs/ai-theme-brand-inputs.js +135 -31
- package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.d.ts +97 -0
- package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.js +137 -0
- package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-site-inspiration-pages.d.ts +38 -0
- package/src/lib/jobs/fixtures/ai-site-inspiration-pages.js +103 -0
- package/src/lib/jobs/fixtures/ai-site-inspiration-pages.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.d.ts +25 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.js +174 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +1 -1
- package/src/lib/layout-language/ai-layout-compiler.js +438 -25
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-contact.d.ts +57 -0
- package/src/lib/layout-language/ai-layout-contact.js +137 -0
- package/src/lib/layout-language/ai-layout-contact.js.map +1 -0
- package/src/lib/layout-language/ai-layout-copy.d.ts +12 -0
- package/src/lib/layout-language/ai-layout-copy.js +34 -2
- package/src/lib/layout-language/ai-layout-copy.js.map +1 -1
- package/src/lib/layout-language/ai-layout-design.d.ts +65 -8
- package/src/lib/layout-language/ai-layout-design.js +411 -97
- package/src/lib/layout-language/ai-layout-design.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame.js +23 -0
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-labels.d.ts +2 -0
- package/src/lib/layout-language/ai-layout-labels.js +12 -6
- package/src/lib/layout-language/ai-layout-labels.js.map +1 -1
- package/src/lib/layout-language/ai-layout-language.d.ts +3 -2
- package/src/lib/layout-language/ai-layout-language.js +4 -3
- package/src/lib/layout-language/ai-layout-language.js.map +1 -1
- package/src/lib/layout-language/ai-layout-links.d.ts +13 -0
- package/src/lib/layout-language/ai-layout-links.js +30 -0
- package/src/lib/layout-language/ai-layout-links.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +49 -6
- package/src/lib/layout-language/ai-layout-pictures.js +145 -22
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/model/ai-build-job.d.ts +16 -1
- package/src/lib/model/ai-build-job.js +40 -0
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-credit-estimate.d.ts +20 -0
- package/src/lib/model/ai-credit-estimate.js +13 -0
- package/src/lib/model/ai-credit-estimate.js.map +1 -1
- package/src/lib/model/ai-job-activity.d.ts +2 -2
- package/src/lib/model/ai-job-activity.js +6 -4
- package/src/lib/model/ai-job-activity.js.map +1 -1
- package/src/lib/model/ai-job-input.d.ts +33 -0
- package/src/lib/model/ai-job-input.js +59 -0
- package/src/lib/model/ai-job-input.js.map +1 -0
- package/src/lib/model/ai-job-notice.d.ts +4 -0
- package/src/lib/model/ai-job-notice.js +28 -4
- package/src/lib/model/ai-job-notice.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +69 -3
- package/src/lib/model/ai-jobs.types.js +2 -1
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-site-details.d.ts +122 -0
- package/src/lib/model/ai-site-details.js +300 -0
- package/src/lib/model/ai-site-details.js.map +1 -0
- package/src/lib/model/ai-site-entity.d.ts +181 -0
- package/src/lib/model/ai-site-entity.js +390 -0
- package/src/lib/model/ai-site-entity.js.map +1 -0
- package/src/lib/model/ai-site-import-view.d.ts +130 -0
- package/src/lib/model/ai-site-import-view.js +182 -0
- package/src/lib/model/ai-site-import-view.js.map +1 -0
- package/src/lib/model/ai-site-import.d.ts +302 -0
- package/src/lib/model/ai-site-import.js +526 -0
- package/src/lib/model/ai-site-import.js.map +1 -0
- package/src/lib/model/ai-site-inspiration.d.ts +72 -0
- package/src/lib/model/ai-site-inspiration.js +109 -0
- package/src/lib/model/ai-site-inspiration.js.map +1 -0
- package/src/lib/model/ai-site-job.d.ts +13 -1
- package/src/lib/model/ai-site-job.js +15 -2
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-kinds.js +109 -21
- package/src/lib/model/ai-site-kinds.js.map +1 -1
- package/src/lib/model/ai-site-look.d.ts +10 -0
- package/src/lib/model/ai-site-look.js +24 -0
- package/src/lib/model/ai-site-look.js.map +1 -1
- package/src/lib/model/ai-site-start-seo.d.ts +19 -5
- package/src/lib/model/ai-site-start-seo.js +25 -7
- package/src/lib/model/ai-site-start-seo.js.map +1 -1
- package/src/lib/model/ai-site-start-steps.d.ts +9 -3
- package/src/lib/model/ai-site-start-steps.js +67 -5
- package/src/lib/model/ai-site-start-steps.js.map +1 -1
- package/src/lib/model/ai-site-start.d.ts +81 -4
- package/src/lib/model/ai-site-start.js +207 -13
- package/src/lib/model/ai-site-start.js.map +1 -1
- package/src/lib/model/ai-upsell-copy.js +4 -1
- package/src/lib/model/ai-upsell-copy.js.map +1 -1
- package/src/lib/plan-entitlements.d.ts +4 -3
- package/src/lib/plan-entitlements.js +3 -8
- package/src/lib/plan-entitlements.js.map +1 -1
- package/src/lib/runtime/ai-dataset-generation.d.ts +8 -1
- package/src/lib/runtime/ai-dataset-generation.js +12 -2
- package/src/lib/runtime/ai-dataset-generation.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +26 -33
- package/src/lib/runtime/ai-doctrine-validators.js +54 -44
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +1 -1
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-node-tree.d.ts +7 -0
- package/src/lib/runtime/ai-node-tree.js +9 -1
- package/src/lib/runtime/ai-node-tree.js.map +1 -1
- package/src/lib/server/ai-create-route.d.ts +1 -1
- package/src/lib/server/ai-create-route.js +3 -4
- package/src/lib/server/ai-create-route.js.map +1 -1
- package/src/lib/server/ai-jobs-resume.js +27 -3
- package/src/lib/server/ai-jobs-resume.js.map +1 -1
- package/src/lib/server/ai-jobs-route.js +18 -0
- package/src/lib/server/ai-jobs-route.js.map +1 -1
- package/src/lib/server/ai-site-import-route.d.ts +89 -0
- package/src/lib/server/ai-site-import-route.js +356 -0
- package/src/lib/server/ai-site-import-route.js.map +1 -0
- package/src/lib/server.js +14 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/site-import/fixtures/site-import-crawl-recordings.d.ts +45 -0
- package/src/lib/site-import/fixtures/site-import-crawl-recordings.js +313 -0
- package/src/lib/site-import/fixtures/site-import-crawl-recordings.js.map +1 -0
- package/src/lib/site-import/fixtures/site-import-wave-recordings.d.ts +50 -0
- package/src/lib/site-import/fixtures/site-import-wave-recordings.js +217 -0
- package/src/lib/site-import/fixtures/site-import-wave-recordings.js.map +1 -0
- package/src/lib/site-import/site-import-crawl.d.ts +163 -0
- package/src/lib/site-import/site-import-crawl.js +467 -0
- package/src/lib/site-import/site-import-crawl.js.map +1 -0
- package/src/lib/site-import/site-import-flag.d.ts +23 -0
- package/src/lib/site-import/site-import-flag.js +23 -0
- package/src/lib/site-import/site-import-flag.js.map +1 -0
- package/src/lib/site-import/site-import-html.d.ts +94 -0
- package/src/lib/site-import/site-import-html.js +462 -0
- package/src/lib/site-import/site-import-html.js.map +1 -0
- package/src/lib/site-import/site-import-images.d.ts +54 -0
- package/src/lib/site-import/site-import-images.js +204 -0
- package/src/lib/site-import/site-import-images.js.map +1 -0
- package/src/lib/site-import/site-import-page.d.ts +48 -0
- package/src/lib/site-import/site-import-page.js +150 -0
- package/src/lib/site-import/site-import-page.js.map +1 -0
- package/src/lib/site-import/site-import-review.d.ts +40 -0
- package/src/lib/site-import/site-import-review.js +149 -0
- package/src/lib/site-import/site-import-review.js.map +1 -0
- package/src/lib/site-import/site-import-robots.d.ts +52 -0
- package/src/lib/site-import/site-import-robots.js +126 -0
- package/src/lib/site-import/site-import-robots.js.map +1 -0
- package/src/lib/usage/assist-credits.d.ts +4 -4
- package/src/lib/usage/assist-credits.js +4 -4
- package/src/lib/usage/assist-credits.js.map +1 -1
- package/src/lib/usage/staff-org-ai-view.js +6 -3
- package/src/lib/usage/staff-org-ai-view.js.map +1 -1
- package/src/lib/usage/staff-org-ai.d.ts +4 -2
- package/src/lib/usage/staff-org-ai.js +7 -7
- package/src/lib/usage/staff-org-ai.js.map +1 -1
- package/src/lib/usage/staff-org-usage-ai.js +2 -2
- package/src/lib/usage/staff-org-usage-ai.js.map +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-site-entity.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { defaultHomeDescription, defaultSiteSeo } from '@aglyn/aglyn/app-utils/default-site'\nimport type { LocalBusinessType } from '@aglyn/aglyn/app-utils/local-business'\nimport { HostEntityType } from '@aglyn/aglyn/foundation/definitions/platform.types'\nimport { aiSiteAddressLine, aiSiteDetailsOf, aiSiteHoursSentence, aiSiteServiceAreas } from './ai-site-details'\nimport { aiSiteKindOfInputs } from './ai-site-kinds'\nimport { aiSiteSeoProposalForInputs, AI_SITE_SEO_FORM_FIELDS, type AiSiteSeoProposal } from './ai-site-start-seo'\n\n/**\n * Who publishes a site a guided start built, as its structured data and its\n * `/llms.txt` say (AGL-3979).\n *\n * Every tenant page publishes a top-level Organization (or Person) node, and\n * `/llms.txt` carries the site's agent guidance, both read off the host's\n * Setup → SEO → Entity and AI agents fields (`siteEntityJsonLd`,\n * `buildLlmsTxt`). Before this, a guided start wrote none of those fields:\n * every AI-built site published a node holding its name and nothing else — no\n * contact point, no address, no business type — and the guidance was the\n * platform's own default. The answers the person gave are the facts those\n * fields ask for, so the publish writes them.\n *\n * ── Derived, never generated ─────────────────────────────────────────────\n *\n * Each value is the person's own words or arithmetic on them: the schema\n * type from the kind of site they picked (and, for a few kinds, the words\n * they used), the description from the same composition as the site's\n * search listing, the guidance from what they said and gave. No model is\n * asked, and nothing is invented: a field the answers say nothing about is\n * left alone.\n *\n * ── Never over the owner ─────────────────────────────────────────────────\n *\n * {@link aiSiteEntityUpdates} writes only fields that are empty, so a site\n * whose owner already filled its Entity keeps every word of it, and a second\n * publish (Try again) writes nothing it wrote before.\n *\n * ── The site's own listing ───────────────────────────────────────────────\n *\n * `/llms.txt` opens with the site's title and description, and every page\n * without its own title falls back to them. A new site is created with its\n * name and a \"Welcome to …\" line there, which nobody chose, so\n * {@link aiSiteListingUpdates} puts the start's listing over that seeded\n * default, and only over it: a title or description the owner changed keeps\n * their words, and the SEO section offers the start's beside them.\n *\n * Pure: no Firestore and no React.\n */\n\n/** How a kind of site publishes: as a person, or as a business of a `schema.org` LocalBusiness type. */\ninterface KindSchema {\n person?: true\n businessType?: LocalBusinessType\n /** A narrower type the person's words name, first match wins. */\n refine?: ReadonlyArray<readonly [RegExp, LocalBusinessType]>\n}\n\n/**\n * Each `AI_SITE_KINDS` entry's `schema.org` type (`ai-site-entity.spec.ts`\n * holds every kind to an entry). A kind with no business type publishes as an\n * Organization — a blog, a band, an event, a course — unless the person gave\n * a street address or opening hours, which make it a place a visitor goes:\n * a LocalBusiness. Only types on the platform's `LOCAL_BUSINESS_TYPES` list\n * are used, since only those publish.\n */\nexport const AI_SITE_KIND_SCHEMA: Readonly<Record<string, KindSchema>> = {\n business: {\n businessType: 'LocalBusiness',\n refine: [\n [/\\b(?:marketing|consult\\w*|agency|freelanc\\w*|staffing|bookkeep\\w*|design(?:er)?s?)\\b/i, 'ProfessionalService'],\n [/\\b(?:car wash|detailing|auto repair|mechanic|tire|tyre)\\b/i, 'AutomotiveBusiness'],\n ],\n },\n trades: {\n businessType: 'HomeAndConstructionBusiness',\n refine: [\n [/\\bplumb\\w*/i, 'Plumber'],\n [/\\belectric\\w*/i, 'Electrician'],\n [/\\b(?:hvac|heating|air condition\\w*|furnace)\\b/i, 'HVACBusiness'],\n [/\\broof\\w*/i, 'RoofingContractor'],\n [/\\bpaint\\w*/i, 'HousePainter'],\n [/\\blocksmith\\w*/i, 'Locksmith'],\n [/\\bmov(?:ing|ers?)\\b/i, 'MovingCompany'],\n [/\\b(?:contractor|remodel\\w*|renovat\\w*|builders?|construction)\\b/i, 'GeneralContractor'],\n ],\n },\n professional: {\n businessType: 'ProfessionalService',\n refine: [\n [/\\b(?:law|lawyers?|attorneys?|legal|solicitors?)\\b/i, 'LegalService'],\n [/\\b(?:accounting|accountants?|bookkeep\\w*|tax|cpa)\\b/i, 'AccountingService'],\n ],\n },\n wellness: {\n businessType: 'HealthAndBeautyBusiness',\n refine: [\n [/\\b(?:dentist\\w*|dental|orthodont\\w*)\\b/i, 'Dentist'],\n [/\\b(?:clinic|doctors?|physicians?|medical|therap\\w*|chiropract\\w*|physio\\w*|counsel\\w*)\\b/i, 'MedicalBusiness'],\n ],\n },\n restaurant: {\n businessType: 'Restaurant',\n refine: [[/\\b(?:caf[eé]s?|coffee|bakery|bakeries|bars?|brewery|food truck|deli)\\b/i, 'FoodEstablishment']],\n },\n store: { businessType: 'Store' },\n portfolio: {},\n studio: { businessType: 'ProfessionalService' },\n photography: { businessType: 'ProfessionalService' },\n blog: {},\n events: {},\n fitness: { businessType: 'SportsActivityLocation' },\n yoga: { businessType: 'SportsActivityLocation' },\n beauty: { businessType: 'HealthAndBeautyBusiness' },\n realestate: { businessType: 'RealEstateAgent' },\n education: { refine: [[/\\b(?:day ?care|child ?care|preschool|nursery)\\b/i, 'ChildCare']] },\n nonprofit: { refine: [[/\\b(?:animal (?:shelter|rescue)|pet rescue)\\b/i, 'AnimalShelter']] },\n music: {},\n personal: { person: true },\n landing: {},\n 'coming-soon': {},\n}\n\n/** The schema a site's answers publish under: a Person, or an Organization with a business type or none. */\nexport interface AiSiteSchema {\n person: boolean\n businessType: LocalBusinessType | null\n}\n\n/** What a job's inputs say the site publishes as. */\nexport function aiSiteSchemaOf(inputs: Readonly<Record<string, unknown>> | null | undefined): AiSiteSchema {\n const kind = aiSiteKindOfInputs(inputs)\n const entry = (kind && AI_SITE_KIND_SCHEMA[kind.id]) || {}\n if (entry.person) return { person: true, businessType: null }\n const words = [inputs?.['businessType'], inputs?.['audience']].filter((value) => typeof value === 'string').join(' ')\n const refined = entry.refine?.find(([pattern]) => pattern.test(words))?.[1]\n const details = aiSiteDetailsOf(inputs)\n const place = Boolean(details.street || details.hours)\n return { person: false, businessType: refined ?? entry.businessType ?? (place ? 'LocalBusiness' : null) }\n}\n\n/** The Entity and AI-agent values a job's answers give; a field they say nothing about is `''` or `[]`. */\nexport interface AiSiteEntityValues {\n person: boolean\n name: string\n description: string\n email: string\n telephone: string\n address: {\n streetAddress: string\n addressLocality: string\n addressRegion: string\n postalCode: string\n addressCountry: string\n }\n /** The street address as one line, as Setup → Details → Business details holds it; `''` without a street. */\n postalAddress: string\n businessType: string\n areaServed: string[]\n openingHours: string\n priceRange: string\n sameAs: string[]\n whenToUse: string\n howToUse: string\n}\n\nconst text = (value: unknown): string => (typeof value === 'string' ? value.replace(/\\s+/g, ' ').trim() : '')\n\n/** \"a, b and c\". */\nfunction listed(parts: readonly string[]): string {\n if (parts.length < 2) return parts.join('')\n return `${parts.slice(0, -1).join(', ')} and ${parts[parts.length - 1]}`\n}\n\n/**\n * The site's agent guidance from its answers (AGL-3979): when an agent should\n * use the site — what the business is, then what the site answers — and,\n * where the person gave a way to reach it, how to reach a person. Written in\n * English, as the rest of `/llms.txt` is.\n */\nexport function aiSiteAgentGuidance(input: {\n name: string\n description: string\n areas: readonly string[]\n hours: boolean\n prices: boolean\n languages: string\n phone: string\n email: string\n address: string\n}): { whenToUse: string; howToUse: string } {\n const who = input.name || 'this business'\n const answers = [\n `what ${who} offers`,\n ...(input.areas.length ? [`the areas it serves (${input.areas.slice(0, 6).join(', ')})`] : []),\n ...(input.hours ? ['its opening hours'] : []),\n ...(input.prices ? ['its prices'] : []),\n 'how to get in touch',\n ]\n // A site the answers say nothing about gets no guidance: the platform's own\n // derived \"When to use this site\" says more than a sentence about nobody.\n const said = Boolean(input.name || input.description)\n const when = said\n ? [\n input.description,\n `Use this site for ${listed(answers)}.`,\n input.languages ? `It serves customers in ${input.languages.replace(/[.\\s]+$/, '')}.` : '',\n ]\n .filter(Boolean)\n .join(' ')\n : ''\n const reach = [input.phone ? `call ${input.phone}` : '', input.email ? `email ${input.email}` : ''].filter(Boolean)\n const how = [\n reach.length ? `To reach a person at ${who}, ${reach.join(' or ')}.` : '',\n input.address ? `${input.name || 'The business'} is at ${input.address}.` : '',\n ]\n .filter(Boolean)\n .join(' ')\n return { whenToUse: when, howToUse: how }\n}\n\n/**\n * The Entity and AI-agent values a site job's inputs imply, in the language\n * its plan writes the site in. `siteName` is the site's own name: it leads\n * the description and the guidance where the inputs name no business, and is\n * never written as the Entity's name, which falls back to it at render and so\n * follows a rename.\n */\nexport function aiSiteEntityValues(\n inputs: Readonly<Record<string, unknown>> | null | undefined,\n options: { language?: string | null; siteName?: string | null } = {},\n): AiSiteEntityValues {\n const details = aiSiteDetailsOf(inputs)\n const schema = aiSiteSchemaOf(inputs)\n const name = text(inputs?.['businessName'])\n const city = text(inputs?.['city'])\n const listing = aiSiteSeoProposalForInputs(inputs, options.language ?? null, options.siteName ?? null)\n const description = listing?.values[AI_SITE_SEO_FORM_FIELDS.description] ?? ''\n const areas = aiSiteServiceAreas(details.serviceArea)\n // A business that names no other area serves the city it is in.\n const areaServed = schema.businessType ? (areas.length ? areas : city ? [city] : []) : []\n const sameAs = details.social ? details.social.split('\\n').filter(Boolean) : []\n const address = details.street ? aiSiteAddressLine(details, city) : ''\n const guidance = aiSiteAgentGuidance({\n name: name || text(options.siteName),\n description,\n areas,\n hours: Boolean(aiSiteHoursSentence(details.hours)),\n prices: Boolean(details.priceRange),\n languages: details.languages,\n phone: details.phone,\n email: details.email,\n address,\n })\n return {\n person: schema.person,\n name,\n description,\n email: details.email,\n telephone: details.phone,\n address: {\n streetAddress: details.street,\n // The city is where the business is only where it gave a street to be on.\n addressLocality: details.street || details.postalCode ? city : '',\n addressRegion: details.region,\n postalCode: details.postalCode,\n addressCountry: details.country,\n },\n postalAddress: address,\n businessType: schema.businessType ?? '',\n areaServed,\n openingHours: details.hours,\n priceRange: details.priceRange,\n sameAs,\n ...guidance,\n }\n}\n\nconst isBlank = (value: unknown): boolean =>\n value === undefined ||\n value === null ||\n (typeof value === 'string' && !value.trim()) ||\n (Array.isArray(value) && !value.some((entry) => typeof entry === 'string' && entry.trim()))\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/** The contact a start's phone or email answers, as the Setup form's **Contact is for** says it: its default. */\nexport const AI_SITE_CONTACT_TYPE = 'customer support'\n\n/**\n * The host updates that put a start's Entity and AI-agent values on its site,\n * as field paths (`seo.entity.telephone`), for the publish's own batch: only\n * fields that are empty on the site, so nothing the owner wrote is replaced.\n * The address is written whole or not at all — a start's street beside the\n * owner's own city would be an address of neither. `{}` when there is\n * nothing to write.\n *\n * Beside the Entity, from what the site already has and the same answers:\n * - the Entity logo is the site's own logo, where it has one and the Entity\n * names none (a Person's Entity picture is their photo, never a logo);\n * - **Contact is for** says what the phone or email this start wrote answers;\n * - Setup → Details → Business details gets the email as the support email\n * (which `{{host.supportEmail}}` and a form that cannot take a message name)\n * and the street address as its one block of text.\n */\nexport function aiSiteEntityUpdates(\n seo: unknown,\n values: AiSiteEntityValues,\n site: { logoUrl?: unknown; business?: unknown } = {},\n): Record<string, unknown> {\n const current = isRecord(seo) ? seo : {}\n const entity = isRecord(current['entity']) ? current['entity'] : {}\n const agent = isRecord(current['agent']) ? current['agent'] : {}\n const business = isRecord(site.business) ? site.business : {}\n const updates: Record<string, unknown> = {}\n const fill = (path: string, now: unknown, next: string | string[]) => {\n if (!isBlank(next) && isBlank(now)) updates[path] = next\n }\n const person = values.person && isBlank(entity['type'])\n // As the Setup form's select stores it: the enum's value as text.\n if (person) updates['seo.entity.type'] = String(HostEntityType.PERSON)\n fill('seo.entity.name', entity['name'], values.name)\n fill('seo.entity.description', entity['description'], values.description)\n fill('seo.entity.email', entity['email'], values.email)\n fill('seo.entity.telephone', entity['telephone'], values.telephone)\n if (updates['seo.entity.email'] || updates['seo.entity.telephone']) {\n fill('seo.entity.contactType', entity['contactType'], AI_SITE_CONTACT_TYPE)\n }\n const address = isRecord(entity['address']) ? entity['address'] : {}\n if (Object.values(address).every(isBlank)) {\n for (const [field, value] of Object.entries(values.address)) {\n if (value) updates[`seo.entity.address.${field}`] = value\n }\n }\n // A Person carries none of a business's fields (`siteEntityJsonLd`).\n const isPerson = person || Number(entity['type']) === HostEntityType.PERSON\n if (!isPerson) {\n fill('seo.entity.logo', entity['logo'], typeof site.logoUrl === 'string' ? site.logoUrl.trim() : '')\n fill('seo.entity.businessType', entity['businessType'], values.businessType)\n fill('seo.entity.areaServed', entity['areaServed'], values.areaServed)\n fill('seo.entity.openingHours', entity['openingHours'], values.openingHours)\n fill('seo.entity.priceRange', entity['priceRange'], values.priceRange)\n }\n fill('seo.entity.sameAs', entity['sameAs'], values.sameAs)\n fill('seo.agent.whenToUse', agent['whenToUse'], values.whenToUse)\n fill('seo.agent.howToUse', agent['howToUse'], values.howToUse)\n fill('business.supportEmail', business['supportEmail'], values.email)\n fill('business.address', business['address'], values.postalAddress)\n return updates\n}\n\n/** Trimmed, or `''` for anything that is not a string: as site creation compares names. */\nconst trimmed = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\n/**\n * Which half of a site's own listing is still the one its creation seeded\n * (AGL-3979): `defaultSiteSeo(name)` — the site's name as its title and\n * \"Welcome to {name}. See what we do, browse our work and get in touch.\" as\n * its description. Blank counts as seeded too: nobody chose it.\n *\n * The title is seeded when it is the site's name, or when it still pairs with\n * a seeded description, as it does on a site renamed after it was made. The\n * description is seeded when it is the welcome line for the site's name, for\n * the title's, or for no name. Anything else is the owner's own words.\n */\nexport function aiSiteListingSeeded(seo: unknown, displayName: unknown): { title: boolean; description: boolean } {\n const current = isRecord(seo) ? seo : {}\n const title = trimmed(current['title'])\n const description = trimmed(current['description'])\n const name = trimmed(displayName)\n const welcomes = new Set([name, title, ''].map((each) => defaultHomeDescription(each)))\n const seededDescription = !description || welcomes.has(description)\n const seededTitle =\n !title ||\n title === trimmed(defaultSiteSeo(name)['title']) ||\n (Boolean(description) && description === defaultHomeDescription(title))\n return { title: seededTitle, description: seededDescription }\n}\n\n/**\n * The host updates that put a start's own listing on its site (AGL-3979), as\n * field paths for the publish's batch: each half only where it is still the\n * seeded default and differs from the listing, so the owner's own title or\n * description is never written over, and a second publish writes nothing.\n * `{}` with no listing to write.\n */\nexport function aiSiteListingUpdates(\n seo: unknown,\n displayName: unknown,\n listing: AiSiteSeoProposal | null,\n): Record<string, string> {\n if (!listing) return {}\n const current = isRecord(seo) ? seo : {}\n const seeded = aiSiteListingSeeded(current, displayName)\n const updates: Record<string, string> = {}\n const title = trimmed(listing.values[AI_SITE_SEO_FORM_FIELDS.title])\n const description = trimmed(listing.values[AI_SITE_SEO_FORM_FIELDS.description])\n if (title && seeded.title && title !== trimmed(current['title'])) updates[AI_SITE_SEO_FORM_FIELDS.title] = title\n if (description && seeded.description && description !== trimmed(current['description'])) {\n updates[AI_SITE_SEO_FORM_FIELDS.description] = description\n }\n return updates\n}\n"],"names":["defaultHomeDescription","defaultSiteSeo","HostEntityType","aiSiteAddressLine","aiSiteDetailsOf","aiSiteHoursSentence","aiSiteServiceAreas","aiSiteKindOfInputs","aiSiteSeoProposalForInputs","AI_SITE_SEO_FORM_FIELDS","AI_SITE_KIND_SCHEMA","business","businessType","refine","trades","professional","wellness","restaurant","store","portfolio","studio","photography","blog","events","fitness","yoga","beauty","realestate","education","nonprofit","music","personal","person","landing","aiSiteSchemaOf","inputs","refined","entry","kind","id","words","filter","value","join","find","pattern","test","details","place","Boolean","street","hours","text","replace","trim","listed","parts","length","slice","aiSiteAgentGuidance","input","who","name","answers","areas","prices","said","description","when","languages","reach","phone","email","how","address","whenToUse","howToUse","aiSiteEntityValues","options","schema","city","listing","language","siteName","values","serviceArea","areaServed","sameAs","social","split","guidance","priceRange","telephone","streetAddress","addressLocality","postalCode","addressRegion","region","addressCountry","country","postalAddress","openingHours","isBlank","undefined","Array","isArray","some","isRecord","AI_SITE_CONTACT_TYPE","aiSiteEntityUpdates","seo","site","current","entity","agent","updates","fill","path","now","next","String","PERSON","Object","every","field","entries","isPerson","Number","logoUrl","trimmed","aiSiteListingSeeded","displayName","title","welcomes","Set","map","each","seededDescription","has","seededTitle","aiSiteListingUpdates","seeded"],"mappings":"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"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import type { AiJobSummary } from './ai-jobs.types';
|
|
18
|
+
import { type AiSiteImportLeftOutReason, type AiSiteImportState, type AiSiteImportWave } from './ai-site-import';
|
|
19
|
+
/** A domain ownership claim, as the ownership door answers it. */
|
|
20
|
+
export interface AiSiteImportClaim {
|
|
21
|
+
domain: string;
|
|
22
|
+
status: 'pending' | 'proven';
|
|
23
|
+
current: boolean;
|
|
24
|
+
provenMethod: 'dns' | 'meta' | 'email' | null;
|
|
25
|
+
provenAt: number | null;
|
|
26
|
+
provenDetail: string | null;
|
|
27
|
+
lastChecks: Partial<Record<'dns' | 'meta' | 'email', 'proven' | 'not-yet' | 'unreachable'>>;
|
|
28
|
+
dns: {
|
|
29
|
+
host: string;
|
|
30
|
+
type: 'TXT';
|
|
31
|
+
value: string;
|
|
32
|
+
};
|
|
33
|
+
meta: {
|
|
34
|
+
name: string;
|
|
35
|
+
content: string;
|
|
36
|
+
tag: string;
|
|
37
|
+
};
|
|
38
|
+
email: {
|
|
39
|
+
domain: string;
|
|
40
|
+
pendingAddress: string | null;
|
|
41
|
+
expiresAt: number | null;
|
|
42
|
+
attemptsLeft: number | null;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Whether "Bring my site" is offered here, and if not why. */
|
|
46
|
+
export type AiSiteImportAvailability = {
|
|
47
|
+
state: 'checking';
|
|
48
|
+
}
|
|
49
|
+
/** The release flag is off, or the doors cannot be reached: the card is not drawn. */
|
|
50
|
+
| {
|
|
51
|
+
state: 'hidden';
|
|
52
|
+
}
|
|
53
|
+
/** Something the workspace can change stands in the way: the card is drawn disabled, with the reason. */
|
|
54
|
+
| {
|
|
55
|
+
state: 'blocked';
|
|
56
|
+
reason: 'plan' | 'role';
|
|
57
|
+
message: string;
|
|
58
|
+
} | {
|
|
59
|
+
state: 'ready';
|
|
60
|
+
claims: AiSiteImportClaim[];
|
|
61
|
+
};
|
|
62
|
+
/** What the card says to a plan that does not include it. */
|
|
63
|
+
export declare const AI_SITE_IMPORT_PLAN_COPY = "Bring your current website in, every page and photo, on any paid plan. Upgrade to bring yours in.";
|
|
64
|
+
/** What the card says to a member who cannot. */
|
|
65
|
+
export declare const AI_SITE_IMPORT_ROLE_COPY = "Only the workspace owner or an admin can bring a site in.";
|
|
66
|
+
/**
|
|
67
|
+
* The jobs list's `siteImport` offer (AGL-3976), as the card's state: absent
|
|
68
|
+
* is the flag off, and the card is not drawn; `plan` and `role` are drawn
|
|
69
|
+
* disabled with the reason.
|
|
70
|
+
*/
|
|
71
|
+
export declare function aiSiteImportOfferOf(offer: unknown): AiSiteImportAvailability;
|
|
72
|
+
/** Where an import job's page is. */
|
|
73
|
+
export type AiSiteImportPhase =
|
|
74
|
+
/** The site is being read. */
|
|
75
|
+
'reading'
|
|
76
|
+
/** Read and planned; the first wave waits to be started. */
|
|
77
|
+
| 'ready'
|
|
78
|
+
/** A wave was started and has not begun yet. */
|
|
79
|
+
| 'starting' | 'running'
|
|
80
|
+
/** A wave is in; the next waits to be started. */
|
|
81
|
+
| 'review'
|
|
82
|
+
/** Held for something the person does: verify again, wait for tomorrow, read again. */
|
|
83
|
+
| 'held'
|
|
84
|
+
/** Out of AI credits or at a cap: the meter's pause, carried on by Resume. */
|
|
85
|
+
| 'paused' | 'done' | 'stopped';
|
|
86
|
+
export declare function aiSiteImportPhaseOf(job: Pick<AiJobSummary, 'status' | 'review' | 'siteImport'>): AiSiteImportPhase;
|
|
87
|
+
export type AiSiteImportRowState = 'waiting' | 'active' | 'done' | 'failed' | 'skipped';
|
|
88
|
+
export interface AiSiteImportRowView {
|
|
89
|
+
slot: string;
|
|
90
|
+
title: string;
|
|
91
|
+
/** Where it is on the old site. */
|
|
92
|
+
from: string;
|
|
93
|
+
/** Where it is on the new one. */
|
|
94
|
+
to: string;
|
|
95
|
+
state: AiSiteImportRowState;
|
|
96
|
+
/** Why it failed or was left out, or what the person should know. */
|
|
97
|
+
note: string | null;
|
|
98
|
+
/** "3 photos added, 1 already in your library". */
|
|
99
|
+
photos: string | null;
|
|
100
|
+
/** The draft the row wrote, by its output id. */
|
|
101
|
+
outputId: string | null;
|
|
102
|
+
}
|
|
103
|
+
/** "3 photos added", "2 photos added, 1 already in your library". */
|
|
104
|
+
export declare function aiSiteImportPhotosText(photos: {
|
|
105
|
+
brought: number;
|
|
106
|
+
reused: number;
|
|
107
|
+
} | null | undefined): string | null;
|
|
108
|
+
/** One wave's rows, the header and footer first where the wave builds them. */
|
|
109
|
+
export declare function aiSiteImportWaveRows(job: Pick<AiJobSummary, 'items' | 'siteImport' | 'status'>, wave: AiSiteImportWave): AiSiteImportRowView[];
|
|
110
|
+
/** "About 189 credits (up to 650)" for the wave, as it stands. */
|
|
111
|
+
export declare function aiSiteImportWaveQuote(job: Pick<AiJobSummary, 'items' | 'siteImport'>, wave: AiSiteImportWave): string;
|
|
112
|
+
/** What a wave cost, its pages' credits less what was given back. */
|
|
113
|
+
export declare function aiSiteImportWaveSpent(job: Pick<AiJobSummary, 'items'>, wave: AiSiteImportWave): number;
|
|
114
|
+
/** The read site in one sentence: "Found 21 pages on harbor-dental.com: Main pages (6) and Blog (14)." */
|
|
115
|
+
export declare function aiSiteImportFoundText(state: AiSiteImportState): string;
|
|
116
|
+
/** The plan's page count against the site: "Your plan includes 25 pages and this site has 0, so 20 are brought in." */
|
|
117
|
+
export declare function aiSiteImportPlanText(state: AiSiteImportState): string;
|
|
118
|
+
/** What was left out, by reason, most first. */
|
|
119
|
+
export declare function aiSiteImportLeftOutLines(state: AiSiteImportState): Array<{
|
|
120
|
+
reason: AiSiteImportLeftOutReason;
|
|
121
|
+
count: number;
|
|
122
|
+
text: string;
|
|
123
|
+
paths: string[];
|
|
124
|
+
}>;
|
|
125
|
+
/** The wave a page offers to start next, and its button's words. */
|
|
126
|
+
export declare function aiSiteImportStartAction(job: Pick<AiJobSummary, 'siteImport' | 'items'>): {
|
|
127
|
+
wave: AiSiteImportWave;
|
|
128
|
+
label: string;
|
|
129
|
+
quote: string;
|
|
130
|
+
} | null;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ /*==========================================
|
|
17
|
+
* BRING MY SITE, AS THE CONSOLE SHOWS IT (AGL-3976).
|
|
18
|
+
*
|
|
19
|
+
* Pure: what the "Create site" choice card says before anyone clicks, and
|
|
20
|
+
* what an import job's page shows in each of its states — the site read and
|
|
21
|
+
* its waves planned, a wave running, a wave in for review, a wave held for a
|
|
22
|
+
* proof or the day's limit, the import done. The components draw these; the
|
|
23
|
+
* specs hold them.
|
|
24
|
+
*=========================================*/ import { aiCreditRangeText } from "./ai-credit-estimate.js";
|
|
25
|
+
import { AI_SITE_IMPORT_FRAME_SLOT, AI_SITE_IMPORT_LEFT_OUT_COPY, AI_SITE_IMPORT_LEFT_OUT_REASONS, aiSiteImportNextWave, aiSiteImportPagesText, aiSiteImportReviewWave, aiSiteImportRunningWave, aiSiteImportWaveCreditRange } from "./ai-site-import.js";
|
|
26
|
+
/** What the card says to a plan that does not include it. */ export const AI_SITE_IMPORT_PLAN_COPY = 'Bring your current website in, every page and photo, on any paid plan. Upgrade to bring yours in.';
|
|
27
|
+
/** What the card says to a member who cannot. */ export const AI_SITE_IMPORT_ROLE_COPY = 'Only the workspace owner or an admin can bring a site in.';
|
|
28
|
+
/**
|
|
29
|
+
* The jobs list's `siteImport` offer (AGL-3976), as the card's state: absent
|
|
30
|
+
* is the flag off, and the card is not drawn; `plan` and `role` are drawn
|
|
31
|
+
* disabled with the reason.
|
|
32
|
+
*/ export function aiSiteImportOfferOf(offer) {
|
|
33
|
+
if (offer === 'ready') return {
|
|
34
|
+
state: 'ready',
|
|
35
|
+
claims: []
|
|
36
|
+
};
|
|
37
|
+
if (offer === 'plan') return {
|
|
38
|
+
state: 'blocked',
|
|
39
|
+
reason: 'plan',
|
|
40
|
+
message: AI_SITE_IMPORT_PLAN_COPY
|
|
41
|
+
};
|
|
42
|
+
if (offer === 'role') return {
|
|
43
|
+
state: 'blocked',
|
|
44
|
+
reason: 'role',
|
|
45
|
+
message: AI_SITE_IMPORT_ROLE_COPY
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
state: 'hidden'
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function aiSiteImportPhaseOf(job) {
|
|
52
|
+
var _job_siteImport;
|
|
53
|
+
const state = (_job_siteImport = job.siteImport) != null ? _job_siteImport : null;
|
|
54
|
+
if (job.status === 'done') return 'done';
|
|
55
|
+
if (job.status === 'failed' || job.status === 'canceled') return 'stopped';
|
|
56
|
+
if (job.status === 'needs_input') return 'paused';
|
|
57
|
+
if (job.status === 'needs_review') {
|
|
58
|
+
var _job_review;
|
|
59
|
+
if (((_job_review = job.review) == null ? void 0 : _job_review.reason) !== 'wave' || !state) return 'held';
|
|
60
|
+
return aiSiteImportReviewWave(state) ? 'review' : 'ready';
|
|
61
|
+
}
|
|
62
|
+
if (!state) return 'reading';
|
|
63
|
+
return aiSiteImportRunningWave(state) ? 'running' : 'starting';
|
|
64
|
+
}
|
|
65
|
+
function rowState(row, active) {
|
|
66
|
+
if (!row) return 'waiting';
|
|
67
|
+
if (row.status === 'succeeded' || row.status === 'degraded') return 'done';
|
|
68
|
+
if (row.status === 'failed') return 'failed';
|
|
69
|
+
if (row.status === 'skipped') return 'skipped';
|
|
70
|
+
return active ? 'active' : 'waiting';
|
|
71
|
+
}
|
|
72
|
+
/** "3 photos added", "2 photos added, 1 already in your library". */ export function aiSiteImportPhotosText(photos) {
|
|
73
|
+
if (!photos || photos.brought + photos.reused === 0) return null;
|
|
74
|
+
const added = photos.brought ? `${photos.brought} ${photos.brought === 1 ? 'photo' : 'photos'} added` : '';
|
|
75
|
+
const reused = photos.reused ? `${photos.reused} already in your media library` : '';
|
|
76
|
+
return [
|
|
77
|
+
added,
|
|
78
|
+
reused
|
|
79
|
+
].filter(Boolean).join(', ');
|
|
80
|
+
}
|
|
81
|
+
/** One wave's rows, the header and footer first where the wave builds them. */ export function aiSiteImportWaveRows(job, wave) {
|
|
82
|
+
var _job_items;
|
|
83
|
+
const state = job.siteImport;
|
|
84
|
+
const items = new Map(((_job_items = job.items) != null ? _job_items : []).map((row)=>[
|
|
85
|
+
row.slot,
|
|
86
|
+
row
|
|
87
|
+
]));
|
|
88
|
+
const running = wave.status === 'running' && (job.status === 'running' || job.status === 'queued');
|
|
89
|
+
let activeTaken = false;
|
|
90
|
+
const active = (row)=>{
|
|
91
|
+
if (!running || activeTaken || !row || row.status !== 'pending' && row.status !== 'running') return false;
|
|
92
|
+
activeTaken = true;
|
|
93
|
+
return true;
|
|
94
|
+
};
|
|
95
|
+
const rows = [];
|
|
96
|
+
if (wave.frame && state.frame) {
|
|
97
|
+
var _ref, _ref1, _ref2;
|
|
98
|
+
var _row_failure;
|
|
99
|
+
const row = items.get(AI_SITE_IMPORT_FRAME_SLOT);
|
|
100
|
+
rows.push({
|
|
101
|
+
slot: AI_SITE_IMPORT_FRAME_SLOT,
|
|
102
|
+
title: 'Header and footer',
|
|
103
|
+
from: `Your menu on ${state.domain}`,
|
|
104
|
+
to: 'Every page',
|
|
105
|
+
state: rowState(row, active(row)),
|
|
106
|
+
note: (_ref = (_ref1 = row == null ? void 0 : (_row_failure = row.failure) == null ? void 0 : _row_failure.message) != null ? _ref1 : row == null ? void 0 : row.note) != null ? _ref : null,
|
|
107
|
+
photos: null,
|
|
108
|
+
outputId: (_ref2 = row == null ? void 0 : row.outputs[0]) != null ? _ref2 : null
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
for (const slot of wave.slots){
|
|
112
|
+
var _ref3, _ref4, _ref5;
|
|
113
|
+
var _row_failure1;
|
|
114
|
+
const page = state.pages.find((entry)=>entry.slot === slot);
|
|
115
|
+
if (!page) continue;
|
|
116
|
+
const row = items.get(slot);
|
|
117
|
+
rows.push({
|
|
118
|
+
slot,
|
|
119
|
+
title: page.title,
|
|
120
|
+
from: page.path,
|
|
121
|
+
to: page.slug === '/' ? '/' : `/${page.slug}`,
|
|
122
|
+
state: rowState(row, active(row)),
|
|
123
|
+
note: (_ref3 = (_ref4 = row == null ? void 0 : (_row_failure1 = row.failure) == null ? void 0 : _row_failure1.message) != null ? _ref4 : row == null ? void 0 : row.note) != null ? _ref3 : page.refused ? AI_SITE_IMPORT_LEFT_OUT_COPY[page.refused] : null,
|
|
124
|
+
photos: aiSiteImportPhotosText(page.photos),
|
|
125
|
+
outputId: (_ref5 = row == null ? void 0 : row.outputs[0]) != null ? _ref5 : null
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return rows;
|
|
129
|
+
}
|
|
130
|
+
/** "About 189 credits (up to 650)" for the wave, as it stands. */ export function aiSiteImportWaveQuote(job, wave) {
|
|
131
|
+
var _job_items;
|
|
132
|
+
return aiCreditRangeText(aiSiteImportWaveCreditRange(job.siteImport, wave, (_job_items = job.items) != null ? _job_items : null));
|
|
133
|
+
}
|
|
134
|
+
/** What a wave cost, its pages' credits less what was given back. */ export function aiSiteImportWaveSpent(job, wave) {
|
|
135
|
+
var _job_items;
|
|
136
|
+
const slots = new Set([
|
|
137
|
+
...wave.slots,
|
|
138
|
+
...wave.frame ? [
|
|
139
|
+
AI_SITE_IMPORT_FRAME_SLOT
|
|
140
|
+
] : []
|
|
141
|
+
]);
|
|
142
|
+
return ((_job_items = job.items) != null ? _job_items : []).filter((row)=>slots.has(row.slot)).reduce((total, row)=>{
|
|
143
|
+
var _row_creditsSpent, _row_creditsRefunded;
|
|
144
|
+
return total + Math.max(0, ((_row_creditsSpent = row.creditsSpent) != null ? _row_creditsSpent : 0) - ((_row_creditsRefunded = row.creditsRefunded) != null ? _row_creditsRefunded : 0));
|
|
145
|
+
}, 0);
|
|
146
|
+
}
|
|
147
|
+
/** The read site in one sentence: "Found 21 pages on harbor-dental.com: Main pages (6) and Blog (14)." */ export function aiSiteImportFoundText(state) {
|
|
148
|
+
const groups = state.groups.map((group)=>`${group.label} (${group.pages})`);
|
|
149
|
+
const listed = groups.length <= 1 ? groups.join('') : `${groups.slice(0, -1).join(', ')} and ${groups[groups.length - 1]}`;
|
|
150
|
+
const found = `Found ${aiSiteImportPagesText(state.found)} on ${state.domain}`;
|
|
151
|
+
return listed ? `${found}: ${listed}.` : `${found}.`;
|
|
152
|
+
}
|
|
153
|
+
/** The plan's page count against the site: "Your plan includes 25 pages and this site has 0, so 20 are brought in." */ export function aiSiteImportPlanText(state) {
|
|
154
|
+
const kept = state.pages.length;
|
|
155
|
+
const waves = state.waves.length;
|
|
156
|
+
const plan = state.pageLimit === null ? 'Your plan has no page limit' : `Your plan includes ${aiSiteImportPagesText(state.pageLimit)} and this site has ${state.existingPages}`;
|
|
157
|
+
return `${plan}, so ${aiSiteImportPagesText(kept)} ${kept === 1 ? 'is' : 'are'} brought in, in ${waves === 1 ? 'one wave' : `${waves} waves`}.`;
|
|
158
|
+
}
|
|
159
|
+
/** What was left out, by reason, most first. */ export function aiSiteImportLeftOutLines(state) {
|
|
160
|
+
return AI_SITE_IMPORT_LEFT_OUT_REASONS.map((reason)=>{
|
|
161
|
+
var _state_leftOutCount_reason;
|
|
162
|
+
return {
|
|
163
|
+
reason,
|
|
164
|
+
count: (_state_leftOutCount_reason = state.leftOutCount[reason]) != null ? _state_leftOutCount_reason : 0,
|
|
165
|
+
text: AI_SITE_IMPORT_LEFT_OUT_COPY[reason],
|
|
166
|
+
paths: state.leftOut.filter((entry)=>entry.reason === reason).map((entry)=>entry.path)
|
|
167
|
+
};
|
|
168
|
+
}).filter((line)=>line.count > 0).sort((a, b)=>b.count - a.count);
|
|
169
|
+
}
|
|
170
|
+
/** The wave a page offers to start next, and its button's words. */ export function aiSiteImportStartAction(job) {
|
|
171
|
+
var _job_siteImport;
|
|
172
|
+
const state = (_job_siteImport = job.siteImport) != null ? _job_siteImport : null;
|
|
173
|
+
const wave = aiSiteImportNextWave(state);
|
|
174
|
+
if (!state || !wave) return null;
|
|
175
|
+
return {
|
|
176
|
+
wave,
|
|
177
|
+
label: `Start ${wave.label}`,
|
|
178
|
+
quote: aiSiteImportWaveQuote(job, wave)
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
//# sourceMappingURL=ai-site-import-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-site-import-view.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*==========================================\n * BRING MY SITE, AS THE CONSOLE SHOWS IT (AGL-3976).\n *\n * Pure: what the \"Create site\" choice card says before anyone clicks, and\n * what an import job's page shows in each of its states — the site read and\n * its waves planned, a wave running, a wave in for review, a wave held for a\n * proof or the day's limit, the import done. The components draw these; the\n * specs hold them.\n *=========================================*/\n\nimport { aiCreditRangeText } from './ai-credit-estimate'\nimport type { AiJobItemLedger, AiJobSummary } from './ai-jobs.types'\nimport {\n AI_SITE_IMPORT_FRAME_SLOT,\n AI_SITE_IMPORT_LEFT_OUT_COPY,\n AI_SITE_IMPORT_LEFT_OUT_REASONS,\n aiSiteImportNextWave,\n aiSiteImportPagesText,\n aiSiteImportReviewWave,\n aiSiteImportRunningWave,\n aiSiteImportWaveCreditRange,\n type AiSiteImportLeftOutReason,\n type AiSiteImportState,\n type AiSiteImportWave,\n} from './ai-site-import'\n\n/** A domain ownership claim, as the ownership door answers it. */\nexport interface AiSiteImportClaim {\n domain: string\n status: 'pending' | 'proven'\n current: boolean\n provenMethod: 'dns' | 'meta' | 'email' | null\n provenAt: number | null\n provenDetail: string | null\n lastChecks: Partial<Record<'dns' | 'meta' | 'email', 'proven' | 'not-yet' | 'unreachable'>>\n dns: { host: string; type: 'TXT'; value: string }\n meta: { name: string; content: string; tag: string }\n email: { domain: string; pendingAddress: string | null; expiresAt: number | null; attemptsLeft: number | null }\n}\n\n/** Whether \"Bring my site\" is offered here, and if not why. */\nexport type AiSiteImportAvailability =\n | { state: 'checking' }\n /** The release flag is off, or the doors cannot be reached: the card is not drawn. */\n | { state: 'hidden' }\n /** Something the workspace can change stands in the way: the card is drawn disabled, with the reason. */\n | { state: 'blocked'; reason: 'plan' | 'role'; message: string }\n | { state: 'ready'; claims: AiSiteImportClaim[] }\n\n/** What the card says to a plan that does not include it. */\nexport const AI_SITE_IMPORT_PLAN_COPY =\n 'Bring your current website in, every page and photo, on any paid plan. Upgrade to bring yours in.'\n\n/** What the card says to a member who cannot. */\nexport const AI_SITE_IMPORT_ROLE_COPY = 'Only the workspace owner or an admin can bring a site in.'\n\n/**\n * The jobs list's `siteImport` offer (AGL-3976), as the card's state: absent\n * is the flag off, and the card is not drawn; `plan` and `role` are drawn\n * disabled with the reason.\n */\nexport function aiSiteImportOfferOf(offer: unknown): AiSiteImportAvailability {\n if (offer === 'ready') return { state: 'ready', claims: [] }\n if (offer === 'plan') return { state: 'blocked', reason: 'plan', message: AI_SITE_IMPORT_PLAN_COPY }\n if (offer === 'role') return { state: 'blocked', reason: 'role', message: AI_SITE_IMPORT_ROLE_COPY }\n return { state: 'hidden' }\n}\n\n/** Where an import job's page is. */\nexport type AiSiteImportPhase =\n /** The site is being read. */\n | 'reading'\n /** Read and planned; the first wave waits to be started. */\n | 'ready'\n /** A wave was started and has not begun yet. */\n | 'starting'\n | 'running'\n /** A wave is in; the next waits to be started. */\n | 'review'\n /** Held for something the person does: verify again, wait for tomorrow, read again. */\n | 'held'\n /** Out of AI credits or at a cap: the meter's pause, carried on by Resume. */\n | 'paused'\n | 'done'\n | 'stopped'\n\nexport function aiSiteImportPhaseOf(job: Pick<AiJobSummary, 'status' | 'review' | 'siteImport'>): AiSiteImportPhase {\n const state = job.siteImport ?? null\n if (job.status === 'done') return 'done'\n if (job.status === 'failed' || job.status === 'canceled') return 'stopped'\n if (job.status === 'needs_input') return 'paused'\n if (job.status === 'needs_review') {\n if (job.review?.reason !== 'wave' || !state) return 'held'\n return aiSiteImportReviewWave(state) ? 'review' : 'ready'\n }\n if (!state) return 'reading'\n return aiSiteImportRunningWave(state) ? 'running' : 'starting'\n}\n\nexport type AiSiteImportRowState = 'waiting' | 'active' | 'done' | 'failed' | 'skipped'\n\nexport interface AiSiteImportRowView {\n slot: string\n title: string\n /** Where it is on the old site. */\n from: string\n /** Where it is on the new one. */\n to: string\n state: AiSiteImportRowState\n /** Why it failed or was left out, or what the person should know. */\n note: string | null\n /** \"3 photos added, 1 already in your library\". */\n photos: string | null\n /** The draft the row wrote, by its output id. */\n outputId: string | null\n}\n\nfunction rowState(row: AiJobItemLedger | undefined, active: boolean): AiSiteImportRowState {\n if (!row) return 'waiting'\n if (row.status === 'succeeded' || row.status === 'degraded') return 'done'\n if (row.status === 'failed') return 'failed'\n if (row.status === 'skipped') return 'skipped'\n return active ? 'active' : 'waiting'\n}\n\n/** \"3 photos added\", \"2 photos added, 1 already in your library\". */\nexport function aiSiteImportPhotosText(photos: { brought: number; reused: number } | null | undefined): string | null {\n if (!photos || photos.brought + photos.reused === 0) return null\n const added = photos.brought ? `${photos.brought} ${photos.brought === 1 ? 'photo' : 'photos'} added` : ''\n const reused = photos.reused ? `${photos.reused} already in your media library` : ''\n return [added, reused].filter(Boolean).join(', ')\n}\n\n/** One wave's rows, the header and footer first where the wave builds them. */\nexport function aiSiteImportWaveRows(\n job: Pick<AiJobSummary, 'items' | 'siteImport' | 'status'>,\n wave: AiSiteImportWave,\n): AiSiteImportRowView[] {\n const state = job.siteImport as AiSiteImportState\n const items = new Map((job.items ?? []).map((row) => [row.slot, row]))\n const running = wave.status === 'running' && (job.status === 'running' || job.status === 'queued')\n let activeTaken = false\n const active = (row: AiJobItemLedger | undefined) => {\n if (!running || activeTaken || !row || (row.status !== 'pending' && row.status !== 'running')) return false\n activeTaken = true\n return true\n }\n const rows: AiSiteImportRowView[] = []\n if (wave.frame && state.frame) {\n const row = items.get(AI_SITE_IMPORT_FRAME_SLOT)\n rows.push({\n slot: AI_SITE_IMPORT_FRAME_SLOT,\n title: 'Header and footer',\n from: `Your menu on ${state.domain}`,\n to: 'Every page',\n state: rowState(row, active(row)),\n note: row?.failure?.message ?? row?.note ?? null,\n photos: null,\n outputId: row?.outputs[0] ?? null,\n })\n }\n for (const slot of wave.slots) {\n const page = state.pages.find((entry) => entry.slot === slot)\n if (!page) continue\n const row = items.get(slot)\n rows.push({\n slot,\n title: page.title,\n from: page.path,\n to: page.slug === '/' ? '/' : `/${page.slug}`,\n state: rowState(row, active(row)),\n note: row?.failure?.message ?? row?.note ?? (page.refused ? AI_SITE_IMPORT_LEFT_OUT_COPY[page.refused] : null),\n photos: aiSiteImportPhotosText(page.photos),\n outputId: row?.outputs[0] ?? null,\n })\n }\n return rows\n}\n\n/** \"About 189 credits (up to 650)\" for the wave, as it stands. */\nexport function aiSiteImportWaveQuote(job: Pick<AiJobSummary, 'items' | 'siteImport'>, wave: AiSiteImportWave): string {\n return aiCreditRangeText(aiSiteImportWaveCreditRange(job.siteImport as AiSiteImportState, wave, job.items ?? null))\n}\n\n/** What a wave cost, its pages' credits less what was given back. */\nexport function aiSiteImportWaveSpent(job: Pick<AiJobSummary, 'items'>, wave: AiSiteImportWave): number {\n const slots = new Set([...wave.slots, ...(wave.frame ? [AI_SITE_IMPORT_FRAME_SLOT] : [])])\n return (job.items ?? [])\n .filter((row) => slots.has(row.slot))\n .reduce((total, row) => total + Math.max(0, (row.creditsSpent ?? 0) - (row.creditsRefunded ?? 0)), 0)\n}\n\n/** The read site in one sentence: \"Found 21 pages on harbor-dental.com: Main pages (6) and Blog (14).\" */\nexport function aiSiteImportFoundText(state: AiSiteImportState): string {\n const groups = state.groups.map((group) => `${group.label} (${group.pages})`)\n const listed =\n groups.length <= 1 ? groups.join('') : `${groups.slice(0, -1).join(', ')} and ${groups[groups.length - 1]}`\n const found = `Found ${aiSiteImportPagesText(state.found)} on ${state.domain}`\n return listed ? `${found}: ${listed}.` : `${found}.`\n}\n\n/** The plan's page count against the site: \"Your plan includes 25 pages and this site has 0, so 20 are brought in.\" */\nexport function aiSiteImportPlanText(state: AiSiteImportState): string {\n const kept = state.pages.length\n const waves = state.waves.length\n const plan =\n state.pageLimit === null\n ? 'Your plan has no page limit'\n : `Your plan includes ${aiSiteImportPagesText(state.pageLimit)} and this site has ${state.existingPages}`\n return `${plan}, so ${aiSiteImportPagesText(kept)} ${kept === 1 ? 'is' : 'are'} brought in, in ${waves === 1 ? 'one wave' : `${waves} waves`}.`\n}\n\n/** What was left out, by reason, most first. */\nexport function aiSiteImportLeftOutLines(state: AiSiteImportState): Array<{ reason: AiSiteImportLeftOutReason; count: number; text: string; paths: string[] }> {\n return AI_SITE_IMPORT_LEFT_OUT_REASONS.map((reason) => ({\n reason,\n count: state.leftOutCount[reason] ?? 0,\n text: AI_SITE_IMPORT_LEFT_OUT_COPY[reason],\n paths: state.leftOut.filter((entry) => entry.reason === reason).map((entry) => entry.path),\n }))\n .filter((line) => line.count > 0)\n .sort((a, b) => b.count - a.count)\n}\n\n/** The wave a page offers to start next, and its button's words. */\nexport function aiSiteImportStartAction(\n job: Pick<AiJobSummary, 'siteImport' | 'items'>,\n): { wave: AiSiteImportWave; label: string; quote: string } | null {\n const state = job.siteImport ?? null\n const wave = aiSiteImportNextWave(state)\n if (!state || !wave) return null\n return { wave, label: `Start ${wave.label}`, quote: aiSiteImportWaveQuote(job, wave) }\n}\n"],"names":["aiCreditRangeText","AI_SITE_IMPORT_FRAME_SLOT","AI_SITE_IMPORT_LEFT_OUT_COPY","AI_SITE_IMPORT_LEFT_OUT_REASONS","aiSiteImportNextWave","aiSiteImportPagesText","aiSiteImportReviewWave","aiSiteImportRunningWave","aiSiteImportWaveCreditRange","AI_SITE_IMPORT_PLAN_COPY","AI_SITE_IMPORT_ROLE_COPY","aiSiteImportOfferOf","offer","state","claims","reason","message","aiSiteImportPhaseOf","job","siteImport","status","review","rowState","row","active","aiSiteImportPhotosText","photos","brought","reused","added","filter","Boolean","join","aiSiteImportWaveRows","wave","items","Map","map","slot","running","activeTaken","rows","frame","get","push","title","from","domain","to","note","failure","outputId","outputs","slots","page","pages","find","entry","path","slug","refused","aiSiteImportWaveQuote","aiSiteImportWaveSpent","Set","has","reduce","total","Math","max","creditsSpent","creditsRefunded","aiSiteImportFoundText","groups","group","label","listed","length","slice","found","aiSiteImportPlanText","kept","waves","plan","pageLimit","existingPages","aiSiteImportLeftOutLines","count","leftOutCount","text","paths","leftOut","line","sort","a","b","aiSiteImportStartAction","quote"],"mappings":"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"}
|