@getvitops/generator 3.0.0 → 4.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.
@@ -611,7 +611,7 @@
611
611
  "type": "string"
612
612
  },
613
613
  "defaultColorScheme": {
614
- "description": "Initial appearance. `\"system\"` follows the OS via `prefers-color-scheme` and is what makes `<color-scheme-toggle>`'s \"System\" position resolve to anything — it removes the theme attribute, so without this the page falls through to light. It also gives a no-JS page the OS appearance. Defaults to `\"light\"`, because switching an existing site to `\"system\"` visibly flips it dark for dark-OS visitors.",
614
+ "description": "Initial appearance. `\"system\"` follows the OS via `prefers-color-scheme` and is what makes `<wc-color-scheme-toggle>`'s \"System\" position resolve to anything — it removes the theme attribute, so without this the page falls through to light. It also gives a no-JS page the OS appearance. Defaults to `\"light\"`, because switching an existing site to `\"system\"` visibly flips it dark for dark-OS visitors.",
615
615
  "type": "string",
616
616
  "enum": [
617
617
  "light",
@@ -1332,6 +1332,34 @@
1332
1332
  },
1333
1333
  "additionalProperties": {}
1334
1334
  },
1335
+ "searchConsole": {
1336
+ "description": "Domains to onboard as Google Search Console *domain properties* via `vitops search setup`, keyed by bare hostname (mirrors `dns`). Credentials come from the environment (CLOUDFLARE_API_TOKEN + the Google OAuth vars) — never in this file.",
1337
+ "type": "object",
1338
+ "propertyNames": {
1339
+ "type": "string"
1340
+ },
1341
+ "additionalProperties": {
1342
+ "type": "object",
1343
+ "properties": {
1344
+ "delegatedOwners": {
1345
+ "description": "Emails added as verification owners on the Site Verification web resource. Automated via the API — additive and idempotent, never removes an existing owner.",
1346
+ "type": "array",
1347
+ "items": {
1348
+ "type": "string",
1349
+ "format": "email",
1350
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
1351
+ }
1352
+ },
1353
+ "fullUserGroup": {
1354
+ "description": "A Google Group to grant Full-User access in Search Console. SURFACED AS A REMINDER only: Search Console exposes no user/permission API, so this step stays manual by design.",
1355
+ "type": "string",
1356
+ "format": "email",
1357
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
1358
+ }
1359
+ },
1360
+ "additionalProperties": false
1361
+ }
1362
+ },
1335
1363
  "environments": {
1336
1364
  "type": "object",
1337
1365
  "propertyNames": {
@@ -1354,6 +1382,10 @@
1354
1382
  "description": "Whether analytics fire in this environment.",
1355
1383
  "type": "boolean"
1356
1384
  },
1385
+ "ads": {
1386
+ "description": "Whether `site.ads` pixels fire in this environment. Defaults to `analytics`, then true — a preview deployment sending pageviews is survivable, one firing conversion pixels is not, so this can be turned off on its own.",
1387
+ "type": "boolean"
1388
+ },
1357
1389
  "robots": {
1358
1390
  "description": "Robots policy (e.g. \"noindex,nofollow\" for dev).",
1359
1391
  "type": "string"
@@ -2233,7 +2265,7 @@
2233
2265
  "additionalProperties": false
2234
2266
  },
2235
2267
  "indexing": {
2236
- "description": "How `vitops notify` tells search engines about a deploy: which sitemap, IndexNow key, Search Console property, and which pages to verify afterwards.",
2268
+ "description": "How `vitops search notify` tells search engines about a deploy: which sitemap, IndexNow key, Search Console property, and which pages to verify afterwards.",
2237
2269
  "type": "object",
2238
2270
  "properties": {
2239
2271
  "sitemapUrl": {
@@ -2248,7 +2280,7 @@
2248
2280
  "key": {
2249
2281
  "type": "string",
2250
2282
  "pattern": "^[a-zA-Z0-9-]{8,128}$",
2251
- "description": "IndexNow key (8–128 chars, hex is conventional). NOT a secret — it is served publicly at `keyLocation` so the engine can verify you own the host. Generate one with `vitops notify --new-key`."
2283
+ "description": "IndexNow key (8–128 chars, hex is conventional). NOT a secret — it is served publicly at `keyLocation` so the engine can verify you own the host. Generate one with `vitops search notify --new-key`."
2252
2284
  },
2253
2285
  "keyLocation": {
2254
2286
  "description": "Absolute URL of the key file. Defaults to `<canonical>/<key>.txt`; set it only when the file lives elsewhere.",
@@ -2267,7 +2299,7 @@
2267
2299
  "additionalProperties": false
2268
2300
  },
2269
2301
  "searchConsole": {
2270
- "description": "Google Search Console property. Needs a service-account credential in `VITOPS_GSC_SERVICE_ACCOUNT` or `GOOGLE_APPLICATION_CREDENTIALS` at run time — never put the key in this file.",
2302
+ "description": "Google Search Console property. Needs a credential at run time — either a service account in `VITOPS_GSC_SERVICE_ACCOUNT` / `GOOGLE_APPLICATION_CREDENTIALS`, or the user OAuth credential `vitops search setup` uses (`VITOPS_GOOGLE_CLIENT_ID` / `_CLIENT_SECRET` / `_REFRESH_TOKEN`). The service account wins when both are set. Never put a key in this file.",
2271
2303
  "type": "object",
2272
2304
  "properties": {
2273
2305
  "siteUrl": {
@@ -2285,7 +2317,7 @@
2285
2317
  "additionalProperties": false
2286
2318
  },
2287
2319
  "priorityUrls": {
2288
- "description": "The pages whose indexing actually matters. `vitops notify --check` inspects these and exits non-zero if Google has not indexed one. Kept explicit because URL Inspection is quota-bound (2000/day), so checking every page is neither affordable nor informative.",
2320
+ "description": "The pages whose indexing actually matters. `vitops search notify --check` inspects these and exits non-zero if Google has not indexed one. Kept explicit because URL Inspection is quota-bound (2000/day), so checking every page is neither affordable nor informative.",
2289
2321
  "type": "array",
2290
2322
  "items": {
2291
2323
  "type": "string",
@@ -2342,25 +2374,80 @@
2342
2374
  "additionalProperties": false
2343
2375
  },
2344
2376
  "notifications": {
2345
- "description": "Where site notifications (e.g. form submissions) are sent.",
2377
+ "description": "Where site notifications (form submissions, tracked calls) are sent. TODO: `sms` and `persist` channels — only `email` is implemented.",
2346
2378
  "type": "object",
2347
2379
  "properties": {
2348
2380
  "email": {
2349
- "type": "string",
2350
- "format": "email",
2351
- "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
2381
+ "description": "Where conversion notifications are e-mailed. A bare address is shorthand for `{ provider: \"cloudflare\", to }`.",
2382
+ "anyOf": [
2383
+ {
2384
+ "type": "string",
2385
+ "format": "email",
2386
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
2387
+ },
2388
+ {
2389
+ "type": "object",
2390
+ "properties": {
2391
+ "provider": {
2392
+ "type": "string",
2393
+ "const": "cloudflare",
2394
+ "description": "Delivery provider. Only Cloudflare Email Sending is implemented; the field is stated so adding another is additive."
2395
+ },
2396
+ "to": {
2397
+ "description": "Recipient. Defaults to the primary location’s `email`, then the first location that has one.",
2398
+ "type": "string",
2399
+ "format": "email",
2400
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
2401
+ },
2402
+ "from": {
2403
+ "description": "Sender. Defaults to `noreply@<domains.canonical>`. Its domain must be onboarded (`wrangler email sending enable <domain>`) or every send fails.",
2404
+ "type": "string",
2405
+ "format": "email",
2406
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
2407
+ },
2408
+ "fromName": {
2409
+ "description": "Display name on the From header. Defaults to `organization.name`.",
2410
+ "type": "string"
2411
+ },
2412
+ "replyTo": {
2413
+ "description": "Reply-To header.",
2414
+ "type": "string",
2415
+ "format": "email",
2416
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
2417
+ },
2418
+ "binding": {
2419
+ "description": "Workers `send_email` binding name (default `EMAIL`). Set it when using a restricted binding.",
2420
+ "type": "string"
2421
+ }
2422
+ },
2423
+ "required": [
2424
+ "provider"
2425
+ ],
2426
+ "additionalProperties": false
2427
+ }
2428
+ ]
2352
2429
  }
2353
2430
  },
2354
2431
  "additionalProperties": false
2355
2432
  },
2356
2433
  "tracking": {
2357
- "description": "Marketing/conversion tracking toggles per platform.",
2434
+ "description": "Ad-click attribution for conversion tracking.",
2358
2435
  "type": "object",
2359
2436
  "properties": {
2360
2437
  "enabled": {
2438
+ "description": "Capture ad click IDs and UTMs from the landing URL into the `_ac` cookie, for attributing conversions.",
2361
2439
  "type": "boolean"
2362
2440
  },
2441
+ "category": {
2442
+ "description": "Consent category the `_ac` cookie waits on (default `marketing`). It is a 90-day identifier tying a visitor to the ad that brought them, so it is only written once this category is granted — and asking for it is what raises the banner.",
2443
+ "type": "string",
2444
+ "enum": [
2445
+ "marketing",
2446
+ "analytics"
2447
+ ]
2448
+ },
2363
2449
  "platforms": {
2450
+ "description": "Informational list of ad platforms in use. Capture recognises every known click-ID parameter regardless.",
2364
2451
  "type": "array",
2365
2452
  "items": {
2366
2453
  "type": "string"
@@ -2369,6 +2456,61 @@
2369
2456
  },
2370
2457
  "additionalProperties": false
2371
2458
  },
2459
+ "ads": {
2460
+ "description": "Ad properties this site is linked to, keyed by platform. Read by `vitops ads setup` (ensure the DNS verification record), `vitops ads tags` (emit the consent-gated pixel), and the generated cookie notice (disclose what each pixel stores). Credentials never live here — the DNS write uses CLOUDFLARE_API_TOKEN from the environment.",
2461
+ "type": "object",
2462
+ "propertyNames": {
2463
+ "type": "string",
2464
+ "enum": [
2465
+ "google",
2466
+ "meta",
2467
+ "linkedin",
2468
+ "reddit",
2469
+ "tiktok",
2470
+ "microsoft",
2471
+ "pinterest",
2472
+ "snapchat"
2473
+ ]
2474
+ },
2475
+ "additionalProperties": {
2476
+ "type": "object",
2477
+ "properties": {
2478
+ "accountId": {
2479
+ "description": "The advertising account as the platform shows it — Google Ads customer ID, Meta ad account, LinkedIn partner ID, Reddit advertiser ID. For LinkedIn this is also the Insight Tag id; everywhere else the tag id is `pixelId`.",
2480
+ "type": "string"
2481
+ },
2482
+ "pixelId": {
2483
+ "description": "The tag/pixel ID the browser snippet initialises — Meta pixel, TikTok pixel, Reddit pixel, Microsoft UET tag ID, Pinterest tag ID, Snap pixel, or the Google Ads conversion ID (`AW-…`, which is NOT the customer ID).",
2484
+ "type": "string"
2485
+ },
2486
+ "conversionLabel": {
2487
+ "description": "Google Ads only: the conversion action label paired with the `AW-…` conversion ID.",
2488
+ "type": "string"
2489
+ },
2490
+ "domain": {
2491
+ "description": "Bare hostname to verify with this platform. Defaults to the host of `domains.canonical` — set it only when the ad account is verified against a different domain.",
2492
+ "type": "string"
2493
+ },
2494
+ "domainVerification": {
2495
+ "description": "The verification token from the platform UI, for the platforms that verify by DNS TXT (Meta, TikTok, Pinterest, Snapchat). `vitops ads setup` prompts for it and writes it here on first run. NOT a secret — it is published in DNS, and the platform fetching it back is the ownership proof, exactly like the IndexNow key. A value containing `=` is used as the whole record, which is the escape hatch if a platform changes its prefix.",
2496
+ "type": "string"
2497
+ },
2498
+ "category": {
2499
+ "description": "Consent category the tag waits on (default `marketing`). An ad pixel is advertising by default; `analytics` is for a site using one purely for its own measurement.",
2500
+ "type": "string",
2501
+ "enum": [
2502
+ "marketing",
2503
+ "analytics"
2504
+ ]
2505
+ },
2506
+ "enabled": {
2507
+ "description": "Set false to keep the property on record without emitting its tag.",
2508
+ "type": "boolean"
2509
+ }
2510
+ },
2511
+ "additionalProperties": false
2512
+ }
2513
+ },
2372
2514
  "security": {
2373
2515
  "description": "Security integrations (bot protection).",
2374
2516
  "type": "object",
@@ -2485,7 +2627,32 @@
2485
2627
  "description": "Why they receive it, as a noun phrase that reads after \"for\" (e.g. \"payment processing\")."
2486
2628
  },
2487
2629
  "country": {
2488
- "description": "Where they process it, as it should read in a sentence (e.g. \"the United States\"). Feeds the cross-border-transfer disclosure.",
2630
+ "description": "Shorthand for the common case where one country is both where they store it and whose laws reach it: asserts BOTH `storage: [{ country }]` AND `operatorCountry`. Reads inside a sentence (e.g. \"the United States\"). When the two differ — a Canadian region operated by a US company — state `storage` and `operatorCountry` instead; setting this alongside either is rejected.",
2631
+ "type": "string"
2632
+ },
2633
+ "storage": {
2634
+ "description": "Where the information actually rests. Feeds the \"stored or processed outside of <jurisdiction>\" disclosure and nothing else. Several entries are allowed, each optionally scoped to a category of information — which is what makes a Canadian-region tenant holding identity data in the US expressible.",
2635
+ "type": "array",
2636
+ "items": {
2637
+ "type": "object",
2638
+ "properties": {
2639
+ "country": {
2640
+ "type": "string",
2641
+ "description": "A country or bloc where this provider stores or processes the information, as it should read in a sentence (e.g. \"Canada\", \"the United States\", \"the European Union\"). Naming the jurisdiction the policy is written for is meaningful: it says this information does not leave it."
2642
+ },
2643
+ "scope": {
2644
+ "description": "Which information is held there, as a noun phrase that reads after \"in the case of\" (e.g. \"account and sign-in information\", \"mailbox contents\"). Omit when this location holds everything the provider receives — a scoped entry claims LESS than an unscoped one, so omitting it is the safe default.",
2645
+ "type": "string"
2646
+ }
2647
+ },
2648
+ "required": [
2649
+ "country"
2650
+ ],
2651
+ "additionalProperties": false
2652
+ }
2653
+ },
2654
+ "operatorCountry": {
2655
+ "description": "The jurisdiction that can compel this provider to hand the information over — where it is established, or from which it is controlled. Reads after \"the laws of\" (e.g. \"the United States\"); a bloc is acceptable. A SEPARATE fact from `storage`, because privacy law cares about foreign *access*, not only foreign storage: a Canadian-region service run by a US company is `storage: [{ country: \"Canada\" }]` with `operatorCountry: \"the United States\"`.",
2489
2656
  "type": "string"
2490
2657
  },
2491
2658
  "privacyUrl": {