@getvitops/cli 8.0.1 → 8.2.0-alpha.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/CHANGELOG.md CHANGED
@@ -1,5 +1,233 @@
1
1
  # @getvitops/cli
2
2
 
3
+ ## 8.2.0-alpha.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 0574388: Add `site.crm` — push form submissions into HubSpot, Zoho Bigin, or Jobber.
8
+
9
+ Client sites need form submissions to land in the client's CRM. The options available before this
10
+ — a HubSpot/Bigin/Jobber iframe or JS embed — fail on three counts: the markup can't be
11
+ white-labelled against this design system, nothing can operate on the submission before it leaves
12
+ the page, and the submission never touched `createConversionRoute()`, so `_ac` ad-click attribution
13
+ was lost and no conversion notification was planned.
14
+
15
+ This adds one server-side path for all three CRMs, hung off the conversion route that already
16
+ exists. `createConversionRoute()` gets a new `crm` option (`{ config, credentials, fetch?,
17
+ timeoutMs? }`); credentials arrive as a function of `locals`, exactly like the existing `binding`
18
+ option, and are never config. A failed CRM write never fails the request and is folded into the
19
+ notification email's new "Delivery" section, so a broken CRM token is never silent.
20
+
21
+ New `@getvitops/utils/crm` subpath: `deliverToCrm()`, `mapSubmission()`, `deriveLastName()` (Bigin
22
+ requires a last name; this derives one from an explicit field, a full name, or an email address,
23
+ refusing rather than fabricating one), `submitToHubSpot()`, `submitToBigin()`, `submitToJobber()`.
24
+ `identifySubmitter()` was promoted out of `notify`'s private name-guessing cascade into
25
+ `@getvitops/utils/tracking`, since the CRM mapper needed the whole identity (first/last name,
26
+ email, phone, company), not just a display name.
27
+
28
+ Jobber is GraphQL, not REST, and answers `200 OK` for failures — a rejected `clientCreate` returns
29
+ `userErrors[]`, a malformed request returns top-level `errors[]`. `submitToJobber()` classifies on
30
+ the response body, not just the status. Its refresh tokens also rotate by default: **Refresh Token
31
+ Rotation must be turned off** in the app's Developer Center settings, since a Worker reading a
32
+ static `VITOPS_JOBBER_REFRESH_TOKEN` cannot persist a rotated one — a rotated token is detected at
33
+ exchange time and reported with the fix, rather than surfacing an hour later as an opaque 401.
34
+ Attribution and unmapped extra fields render into a best-effort note by default (works on every
35
+ Jobber plan); a resubmitting visitor creates a second Jobber client unless `crm.jobber.dedupe: true`
36
+ is set once its lookup query has been verified against a live account (defaults `false` pending
37
+ that verification — see `jobber.ts`'s docblock).
38
+
39
+ New `site.crm` config block (`provider`, `hubspot`/`bigin`/`jobber`, `fieldMap`, `trackingFields`)
40
+ and two CLI commands: `vitops crm check` (fetches the live HubSpot property list or Bigin field
41
+ list and reports every mapped name that doesn't exist there — HubSpot rejects an unknown field
42
+ outright, Bigin silently drops it; Jobber has nothing live to check yet, since its mapped values
43
+ currently render as note text) and `vitops crm setup` (creates missing HubSpot properties; Bigin
44
+ and Jobber have no such API, so both always print a manual reminder).
45
+
46
+ The generated privacy policy now names HubSpot, Zoho Bigin, or Jobber when `site.crm` configures
47
+ one. Bigin gets the same cross-border-transfer derivation Matomo Cloud already gets: a
48
+ `dataCenter: 'ca'` asserts no transfer outside Canada, any other data centre does. Jobber's
49
+ operator (Octopusapp Inc. d/b/a Jobber) is Canadian, but its own privacy policy names the United
50
+ States as a processing location too, so the policy always asserts a cross-border transfer for
51
+ Jobber regardless of config — a Canadian operator is not read as Canadian-only storage.
52
+
53
+ Credentials: `VITOPS_HUBSPOT_ACCESS_TOKEN` for HubSpot; `VITOPS_ZOHO_CLIENT_ID` /
54
+ `VITOPS_ZOHO_CLIENT_SECRET` / `VITOPS_ZOHO_REFRESH_TOKEN` for Bigin; `VITOPS_JOBBER_CLIENT_ID` /
55
+ `VITOPS_JOBBER_CLIENT_SECRET` / `VITOPS_JOBBER_REFRESH_TOKEN` for Jobber. Never config.
56
+
57
+ No consumer-facing change in `@getvitops/astro` beyond the new `crm` route option and a build
58
+ warning when `site.crm` is configured with no route answering `TRACKING_ENDPOINT` — CSS/Bricks/
59
+ tailwind outputs are unaffected.
60
+
61
+ - 0574388: Add `vitops email setup|check` — connect `site.notifications.email.from` to whether its domain is
62
+ actually onboarded onto an outbound email provider.
63
+
64
+ Before this, nothing checked that. `EMAIL.send()` throws `E_SENDER_NOT_VERIFIED` at runtime with no
65
+ build or deploy-time warning — the failure mode is silent and production-only.
66
+
67
+ `vitops email setup [domain]` onboards a sending domain (currently Cloudflare Email Sending only)
68
+ and polls DNS until its SPF/DKIM/DMARC records resolve or a timeout is reached; `vitops email
69
+ check` is the non-blocking deploy guard both `@getvitops/create` templates' `deploy`/`deploy:dev`
70
+ scripts now run first (`--strict` makes it a real gate; opt out per-site with
71
+ `site.notifications.email.verifySender: false`, or globally with `--skip` /
72
+ `VITOPS_SKIP_EMAIL_CHECK`).
73
+
74
+ Two things worth knowing before running it:
75
+ - **The onboarded entity is an exact name, and it is usually a subdomain**
76
+ (`send.yourdomain.com`), never the apex your `from` address names. When the exact domain isn't
77
+ onboarded but a sibling in the same zone already is, the command reports that as the fix — send
78
+ from the onboarded subdomain — rather than silently trying to onboard the apex, which rewrites
79
+ `_dmarc.<domain>` and can tighten DMARC policy on every other mail your domain sends.
80
+ - Candidates come from `site.notifications.email.from` (or its derived `noreply@<domains
81
+ .canonical>` default) first; a best-effort scan of `--src` only supplements it, and never guesses
82
+ at a computed `from` value.
83
+
84
+ New `@getvitops/utils/email` subpath and `site.notifications.email.verifySender` config field.
85
+ Needs `CLOUDFLARE_API_TOKEN` with an Email Sending scope in addition to the `Zone:Read` other
86
+ commands already use.
87
+
88
+ ### Patch Changes
89
+
90
+ - c3c1bcb: **New: the design-system editor, mounted inside the EmDash admin.** `vitopsEmdash({
91
+ designSystemEditor: { config } })` (`config` is your `site.json`, e.g. `import config from
92
+ './site.json' with { type: 'json' }`) adds a `/design-system` admin page mounting
93
+ `<wc-theme-editor>` — the same live token editor `@getvitops/vite`'s dev server has always
94
+ offered, now usable by the client directly, no dev server required. An edit is visible
95
+ site-wide immediately (a runtime `:root` override, served via a new plugin API route and
96
+ `page:fragments`) and — once `site.deployment.repo`/`branch` and a `VITOPS_GITHUB_TOKEN`
97
+ secret are set (see the scaffold's `SETUP.html`) — auto-commits to your `dev` branch, so it
98
+ reaches the git-tracked `site.json` through your repo's normal review path rather than
99
+ becoming a second, unreviewed source of truth. Until that's configured, the live half still
100
+ works; only the auto-commit half is skipped (and says so in the admin page). The save route
101
+ runs the exact same accessibility (APCA contrast) gate `generate()` enforces at build time,
102
+ synchronously, before persisting — nothing non-compliant ever goes live even momentarily.
103
+
104
+ Requires `@astrojs/react` + `react` + `react-dom` (already scaffold dependencies, for
105
+ EmDash's own admin) and `@getvitops/core` (added as a new scaffold dependency this release).
106
+ Declares two new plugin capabilities when enabled: `network:request` (for the GitHub
107
+ auto-commit) and `hooks.page-fragments:register` (for the live override) — reviewed once at
108
+ plugin-install time.
109
+
110
+ **Breaking for `@getvitops/emdash`**: `vitopsEmdash()`'s `hooks.page-fragments:register`
111
+ capability is now also granted whenever `designSystemEditor` is set, independent of the
112
+ existing `scripts: 'fragments'` option (which governs something unrelated — web-component
113
+ script delivery). No change if you don't use `designSystemEditor`.
114
+
115
+ Also new, supporting the above:
116
+ - `@getvitops/generator`: `validateColorContract()` and `buildReverseIndex()` (both
117
+ `/tokens` subpath, Worker-safe) — the monotonicity/contrast gate and the
118
+ `design-manifest.json` reverse-index, each extracted from `generate()`'s `build()` into
119
+ standalone, non-throwing functions. `patchToOverrideCss()` turns a design-system patch
120
+ into the `:root` override `<style>` block. `designSystemPath`/`getAt`/`setAt`/
121
+ `mergePatch`/`formatConfig` moved from `@getvitops/vite` into `@getvitops/generator/config`
122
+ (re-exported from `@getvitops/vite` unchanged) — one "patch a config file's design-system
123
+ subtree" implementation shared by the dev endpoint and the new plugin route. New
124
+ `site.deployment.repo`/`branch` config fields.
125
+ - `@getvitops/utils`: new `/git` subpath — `commitFile()`, a Worker-safe (fetch-only)
126
+ wrapper over GitHub's Contents API.
127
+ - `@getvitops/core`: `<wc-theme-editor>` gains a `save-endpoint` attribute (default
128
+ unchanged — `/__vitops/design-system`) so the same element can target the new plugin
129
+ route instead of the dev-only Vite endpoint.
130
+
131
+ - 0574388: Bump `emdash`/`@emdash-cms/cloudflare` peers to `>=1.0.0 <2` and `vite-plus` to `^1.0.0`, following
132
+ both projects' GA releases.
133
+
134
+ **Breaking for `@getvitops/emdash` consumers on EmDash 0.x**: the peer range no longer admits
135
+ `emdash@0.31.x`/`@emdash-cms/cloudflare@0.31.x`. Upgrade `emdash` and `@emdash-cms/cloudflare` to
136
+ `^1.0.1` first — nothing in `@getvitops/emdash`'s own plugin surface (`admin.portableTextBlocks`,
137
+ the `hooks.page-fragments:register` capability, `definePlugin()`) changed against EmDash 1.0, so no
138
+ code here needed to change, only the declared range.
139
+
140
+ The `emdash` scaffold template (`vp create @getvitops:emdash`) picks up several fixes alongside
141
+ the version bump:
142
+ - `tailwindcss`/`@tailwindcss/vite` are now real dependencies — the template selected
143
+ `css.format: 'tailwind'` without installing either, which threw on build.
144
+ - `site.json` now sets `site.icons.sprite: true` plus the full `semantic` list the
145
+ `vitops.actionLink` block's icon picker offers — previously its sprite icons pointed at a file
146
+ the build never generated.
147
+ - `astro.config.mjs` sets `migrations: { runtime: 'check', dev: 'auto' }`, and
148
+ `site-deploy-emdash.yml` runs EmDash 1.0's documented `build → status → apply → deploy → check`
149
+ migration sequence explicitly, rather than relying solely on first-request auto-migration. This
150
+ needs a new GitHub Environment variable, `EMDASH_TARGET_FINGERPRINT` (one per environment),
151
+ which only a human can set — run `emdash migrate --status` against the real deployed database,
152
+ review the printed identity, then `gh variable set EMDASH_TARGET_FINGERPRINT --env <env> --body
153
+ <value>`. Deploys fail clearly on the migration-apply step until it's set.
154
+ - `lint.options.typeAware`/`typeCheck` in the template's own `vite.config.ts` are commented out,
155
+ not deleted: vite-plus 1.0 only honours that option in a project's actual root config, and hard
156
+ errors on it in a nested one (which this file is, sitting inside the `design-system` monorepo).
157
+ Uncomment it once scaffolded into its own repo.
158
+
159
+ No config schema changes. `@getvitops/generator` also switches from the `zod/mini` subpath import
160
+ to the standalone `@zod/mini` package (zod 4.5+; same API) and fixes `validateConfig()` silently
161
+ losing the offending key name on an `unrecognized_keys` error (e.g. a typo'd `site.ads` platform
162
+ now names the bad key instead of reporting a bare "Invalid input").
163
+
164
+ Also fixed: `vp check`'s `tsconfig-error` for `packages/create/templates/emdash/tsconfig.json`
165
+ (`extends: "astro/tsconfigs/strict"`, unresolvable from inside this monorepo since the template
166
+ has no `node_modules` of its own — a pre-existing, structural gap, newly surfaced as a hard error
167
+ by oxlint 1.85's deeper config discovery, and blocking on every commit since this repo's pre-commit
168
+ hook runs `vp check --fix`). Fixed with a new `scripts/link-template-deps.mjs`, wired as the root
169
+ `postinstall` script: symlinks `astro`/`emdash`/`@emdash-cms/cloudflare` into the template's own
170
+ `node_modules/` (resolved fresh from sibling packages that already depend on them for real, not a
171
+ hardcoded `.pnpm` hash) and writes a minimal `astro:content` ambient shim at `.astro/types.d.ts`
172
+ (the same path `astro sync` would generate for real). Both are gitignored and only ever exist
173
+ inside this monorepo's copy of the template — a real scaffold installs its own real copies instead.
174
+ Considered and rejected first: inlining astro's strict preset (drift risk against astro's own
175
+ evolving default) and making the template a real pnpm workspace member (would change how its
176
+ `@getvitops/*: "latest"` deps resolve locally, which `templates.test.ts` exists to protect).
177
+
178
+ **Known gap, not fixed here**: `packages/astro/src/components/container.test.ts` (the
179
+ `AstroContainer`-based render tests) fails to even load under vite-plus 1.0's Vite 8 — direct
180
+ `.astro` imports in a Vitest file need the Astro Vite plugin registered, which nothing in this
181
+ repo's test config actually does (Astro's own docs call for `getViteConfig()`, which doesn't
182
+ compose with vite-plus's own `defineConfig`). A type-level shim
183
+ (`packages/astro/src/components/astro-modules.d.ts`) fixes `vp check`'s type-aware pass, but the
184
+ runtime `vp test` failure for this one file is still open.
185
+
186
+ - Updated dependencies [65a13cc]
187
+ - Updated dependencies [67e2088]
188
+ - Updated dependencies [0574388]
189
+ - Updated dependencies [c3c1bcb]
190
+ - Updated dependencies [0574388]
191
+ - Updated dependencies [0574388]
192
+ - Updated dependencies [0574388]
193
+ - Updated dependencies [1a3e811]
194
+ - Updated dependencies [0574388]
195
+ - Updated dependencies [dde3df3]
196
+ - Updated dependencies [d9f213b]
197
+ - @getvitops/generator@8.2.0-alpha.0
198
+ - @getvitops/utils@8.2.0-alpha.0
199
+
200
+ ## 8.1.0
201
+
202
+ ### Minor Changes
203
+
204
+ - **Added — `vitops init --site` and `vitops setup`, the scripted client-onboarding path.**
205
+
206
+ `vitops init --site [--name] [--url]` scaffolds a starter `site.json` (the umbrella `Config`,
207
+ embedding a starter design system at `designSystem.themes.default`) instead of a bare
208
+ `design-system.json` — exported as `defaultSiteConfig()` from `@getvitops/generator`, alongside a
209
+ new `CONFIG_SCHEMA_LOCAL_PATH` and an optional `$schema` field on `ConfigSchema` so a scaffolded
210
+ config gets editor autocomplete the same way `design-system.json` already does.
211
+
212
+ `vitops setup <repo|hosting|domain|search|ads|all>` (new `@getvitops/utils/hosting` subpath: a
213
+ pure planner + `wrangler`/`gh`-shelling executors, following the same idempotent
214
+ plan/observe/apply split as `onboarding`/`ads`) automates GitHub repo + branch policy and
215
+ Cloudflare dev D1/R2 + repo secrets, and plans/checks the workers.dev-vs-custom-domain
216
+ consistency without ever applying the cutover itself — see AGENTS.md's new "Client onboarding"
217
+ section for the full design rationale. `search`/`ads` forward to the existing `search setup`/
218
+ `ads setup` subcommands rather than reimplementing them.
219
+
220
+ No consumer-facing change in `@getvitops/vite` or `@getvitops/astro` in this release — bumped
221
+ only because they are in the `fixed` release group with `generator`/`utils`/`cli`.
222
+ `@getvitops/core` does have a real fix in this release; see the separate `banner-hidden-fix`
223
+ changeset.
224
+
225
+ ### Patch Changes
226
+
227
+ - Updated dependencies
228
+ - @getvitops/generator@8.1.0
229
+ - @getvitops/utils@8.1.0
230
+
3
231
  ## 8.0.1
4
232
 
5
233
  ### Patch Changes
@@ -23,7 +251,6 @@
23
251
 
24
252
  **Breaking (`css`/`bricks` and `tailwind` formats — `.lightbox-dialog`'s markup
25
253
  contract changed):**
26
-
27
254
  - `<Gallery />` now emits ONE `<dialog class="lightbox-dialog">` per gallery,
28
255
  wrapping a `<Carousel />`, instead of one dialog per image. A `.gallery__trigger`
29
256
  is now a plain `<a href="#slide-id">`, not a `command="show-modal"` button.
@@ -64,7 +291,6 @@
64
291
  ### Minor Changes
65
292
 
66
293
  - Add Google Business Profile reviews: fetch, cache, render.
67
-
68
294
  - **`vitops reviews`** (new CLI command) fetches a client's GBP reviews (legacy v4 API — the only
69
295
  one that has them) and writes them to `.vitops/reviews.json`, meant to be committed so a build
70
296
  never needs a live Google credential. `--dry` prints the plan; `--check` diffs against the cache
@@ -99,7 +325,6 @@
99
325
  `--site` for now.)
100
326
 
101
327
  **Fixed:**
102
-
103
328
  - `@getvitops/core`'s 12 runtime deps (`lit`, both `@oddbird` polyfills, both
104
329
  `@webcomponents` packages, `colorjs.io`, etc.) were listed as `dependencies` despite
105
330
  being bundled into `dist/elements.js`/`dist/polyfills.js`/`dist/deferred.js` — a
@@ -786,20 +1011,28 @@ carousel vocabulary, because they render live from the generator.
786
1011
  {
787
1012
  "designSystem": {
788
1013
  "themes": {
789
- "default": {/* … */},
1014
+ "default": {
1015
+ /* … */
1016
+ },
790
1017
  },
791
1018
  },
792
1019
  "organization": {
793
1020
  "name": "Acme",
794
1021
  "contact": "hq",
795
1022
  "locations": {
796
- "hq": {/* … */},
1023
+ "hq": {
1024
+ /* … */
1025
+ },
797
1026
  },
798
1027
  },
799
1028
  "site": {
800
1029
  "defaultLocale": "en",
801
- "domains": {/* … */},
802
- "analytics": {/* … */},
1030
+ "domains": {
1031
+ /* … */
1032
+ },
1033
+ "analytics": {
1034
+ /* … */
1035
+ },
803
1036
  },
804
1037
  }
805
1038
  ```
@@ -875,7 +1108,7 @@ carousel vocabulary, because they render live from the generator.
875
1108
  Also new, and worth wiring at the same time — **`gitLastmod()` for real sitemap dates**:
876
1109
 
877
1110
  ```js
878
- import vitops, { gitLastmod } from "@getvitops/astro";
1111
+ import vitops, { gitLastmod } from '@getvitops/astro';
879
1112
  vitops({ sitemap: { serialize: await gitLastmod() } });
880
1113
  ```
881
1114
 
@@ -969,7 +1202,7 @@ ffmpeg`, `apt install ffmpeg`, `winget install Gyan.FFmpeg`). The command fails
969
1202
 
970
1203
  ```js
971
1204
  // astro.config.mjs
972
- getvitops({ css: { input: "company.json", format: "css" } });
1205
+ getvitops({ css: { input: 'company.json', format: 'css' } });
973
1206
  ```
974
1207
 
975
1208
  ```
@@ -1456,15 +1689,15 @@ ffmpeg`, `apt install ffmpeg`, `winget install Gyan.FFmpeg`). The command fails
1456
1689
  which `@getvitops/astro` re-exports wholesale. So from `astro.config.mjs`:
1457
1690
 
1458
1691
  ```js
1459
- import { generateIconInclude } from "@getvitops/astro";
1460
- import icon from "astro-icon";
1692
+ import { generateIconInclude } from '@getvitops/astro';
1693
+ import icon from 'astro-icon';
1461
1694
 
1462
1695
  integrations: [
1463
1696
  icon({
1464
1697
  include: generateIconInclude({
1465
- ui: "fa7-solid",
1466
- brand: "simple-icons",
1467
- semantic: ["menu", "close", "search", "github"],
1698
+ ui: 'fa7-solid',
1699
+ brand: 'simple-icons',
1700
+ semantic: ['menu', 'close', 'search', 'github'],
1468
1701
  }),
1469
1702
  }),
1470
1703
  ];
package/dist/cli.d.mts CHANGED
@@ -1 +1 @@
1
- export { };
1
+ export {}