@getvitops/utils 8.1.0 → 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.
Files changed (72) hide show
  1. package/CHANGELOG.md +264 -8
  2. package/dist/{adc-BFrzpMHq.d.mts → adc-BoEoogyo.d.mts} +2 -3
  3. package/dist/adc-BoEoogyo.d.mts.map +1 -0
  4. package/dist/ads/index.d.mts +50 -17
  5. package/dist/ads/index.d.mts.map +1 -1
  6. package/dist/ads/index.mjs +75 -7
  7. package/dist/ads/index.mjs.map +1 -1
  8. package/dist/cloudflare-BiK61Oq4.d.mts.map +1 -1
  9. package/dist/color/index.d.mts +34 -35
  10. package/dist/color/index.d.mts.map +1 -1
  11. package/dist/color/index.mjs +3 -1
  12. package/dist/color/index.mjs.map +1 -1
  13. package/dist/crm/index.d.mts +288 -0
  14. package/dist/crm/index.d.mts.map +1 -0
  15. package/dist/crm/index.mjs +731 -0
  16. package/dist/crm/index.mjs.map +1 -0
  17. package/dist/email/index.d.mts +216 -0
  18. package/dist/email/index.d.mts.map +1 -0
  19. package/dist/email/index.mjs +331 -0
  20. package/dist/email/index.mjs.map +1 -0
  21. package/dist/favicon.d.mts +8 -9
  22. package/dist/favicon.d.mts.map +1 -1
  23. package/dist/git/index.d.mts +65 -0
  24. package/dist/git/index.d.mts.map +1 -0
  25. package/dist/git/index.mjs +107 -0
  26. package/dist/git/index.mjs.map +1 -0
  27. package/dist/hosting/index.d.mts +29 -29
  28. package/dist/hosting/index.d.mts.map +1 -1
  29. package/dist/hosting/index.mjs +7 -4
  30. package/dist/hosting/index.mjs.map +1 -1
  31. package/dist/identity-BoRddTx3.mjs +35 -0
  32. package/dist/identity-BoRddTx3.mjs.map +1 -0
  33. package/dist/index.d.mts +24 -25
  34. package/dist/index.d.mts.map +1 -1
  35. package/dist/index.mjs +5 -5
  36. package/dist/index.mjs.map +1 -1
  37. package/dist/indexing/index.d.mts +23 -24
  38. package/dist/indexing/index.d.mts.map +1 -1
  39. package/dist/media/index.d.mts +24 -24
  40. package/dist/media/index.d.mts.map +1 -1
  41. package/dist/media/index.mjs +3 -3
  42. package/dist/media/index.mjs.map +1 -1
  43. package/dist/notify/index.d.mts +26 -15
  44. package/dist/notify/index.d.mts.map +1 -1
  45. package/dist/notify/index.mjs +50 -20
  46. package/dist/notify/index.mjs.map +1 -1
  47. package/dist/onboarding/index.d.mts +10 -141
  48. package/dist/onboarding/index.d.mts.map +1 -1
  49. package/dist/onboarding/index.mjs +1 -144
  50. package/dist/onboarding/index.mjs.map +1 -1
  51. package/dist/plan-BLKikoOG.mjs +150 -0
  52. package/dist/plan-BLKikoOG.mjs.map +1 -0
  53. package/dist/plan-Hq8Pb0Uw.d.mts +133 -0
  54. package/dist/plan-Hq8Pb0Uw.d.mts.map +1 -0
  55. package/dist/reviews/index.d.mts +12 -13
  56. package/dist/reviews/index.d.mts.map +1 -1
  57. package/dist/schema/index.d.mts +7 -7
  58. package/dist/schema/index.d.mts.map +1 -1
  59. package/dist/security/index.d.mts +2 -2
  60. package/dist/security/index.d.mts.map +1 -1
  61. package/dist/{token-Bz_-igw-.d.mts → token-DmmoQ7um.d.mts} +6 -3
  62. package/dist/token-DmmoQ7um.d.mts.map +1 -0
  63. package/dist/tracking/index.d.mts +43 -17
  64. package/dist/tracking/index.d.mts.map +1 -1
  65. package/dist/tracking/index.mjs +2 -1
  66. package/dist/tracking/index.mjs.map +1 -1
  67. package/dist/{types-CHHjzRrv.d.mts → types-7ELci8RQ.d.mts} +4 -2
  68. package/dist/types-7ELci8RQ.d.mts.map +1 -0
  69. package/package.json +14 -4
  70. package/dist/adc-BFrzpMHq.d.mts.map +0 -1
  71. package/dist/token-Bz_-igw-.d.mts.map +0 -1
  72. package/dist/types-CHHjzRrv.d.mts.map +0 -1
@@ -68,16 +68,16 @@ interface HostingPlan {
68
68
  notes: string[];
69
69
  }
70
70
  /** Plan the whole hosting sequence from setup + observed state. */
71
- declare function plan(setup: HostingSetup, state: HostingState): HostingPlan;
71
+ export declare function plan(setup: HostingSetup, state: HostingState): HostingPlan;
72
72
  /** Any step that isn't a skip — i.e. the live state has drifted from desired. */
73
- declare function hasDrift(p: HostingPlan): boolean;
73
+ export declare function hasDrift(p: HostingPlan): boolean;
74
74
  /** Every blocked step, with a name — what `--check` reports and the CLI surfaces. */
75
- declare function blockedSteps(p: HostingPlan): {
75
+ export declare function blockedSteps(p: HostingPlan): {
76
76
  name: string;
77
77
  detail: string;
78
78
  }[];
79
79
  /** Render a plan as the block `--dry` and `--check` print. */
80
- declare function formatPlan(p: HostingPlan): string;
80
+ export declare function formatPlan(p: HostingPlan): string;
81
81
  /** The outcome of one run, for the summary table. */
82
82
  interface HostingResult {
83
83
  step: string;
@@ -85,14 +85,14 @@ interface HostingResult {
85
85
  detail: string;
86
86
  }
87
87
  /** Render the end-of-run summary: one row per step, plus blocked reminders. */
88
- declare function formatSummary(results: HostingResult[]): string;
88
+ export declare function formatSummary(results: HostingResult[]): string;
89
89
  /**
90
90
  * Plan the domain-consistency check on its own — it has no executor, only an
91
91
  * observation (`wrangler.jsonc` + the config), and it is never applied by this
92
92
  * command. See `SETUP.html`'s "Domain strategy" stage: the actual cutover is a
93
93
  * human, deliberate action.
94
94
  */
95
- declare function planDomainConsistency(state: DomainState): StepPlan;
95
+ export declare function planDomainConsistency(state: DomainState): StepPlan;
96
96
  //#endregion
97
97
  //#region src/hosting/wrangler.d.ts
98
98
  interface ExecResult {
@@ -102,9 +102,9 @@ interface ExecResult {
102
102
  }
103
103
  type ExecImpl = (cmd: string, args: string[]) => Promise<ExecResult>;
104
104
  /** The real executor — `execFile` with an argv array, never a shell string. */
105
- declare const realExec: ExecImpl;
105
+ export declare const realExec: ExecImpl;
106
106
  /** `wrangler whoami` — auth check + the 32-hex account id, from one call. */
107
- declare function wranglerWhoami(execImpl?: ExecImpl): Promise<{
107
+ export declare function wranglerWhoami(execImpl?: ExecImpl): Promise<{
108
108
  authed: boolean;
109
109
  accountId?: string;
110
110
  }>;
@@ -116,37 +116,37 @@ declare function wranglerWhoami(execImpl?: ExecImpl): Promise<{
116
116
  * the answer, so both the "does it exist" check and the post-create fallback go
117
117
  * through this.
118
118
  */
119
- declare function findD1(name: string, execImpl?: ExecImpl): Promise<string | undefined>;
119
+ export declare function findD1(name: string, execImpl?: ExecImpl): Promise<string | undefined>;
120
120
  /** Create a dev D1 database, then resolve its id via `findD1` (see its docblock). */
121
- declare function createD1(name: string, execImpl?: ExecImpl): Promise<{
121
+ export declare function createD1(name: string, execImpl?: ExecImpl): Promise<{
122
122
  ok: boolean;
123
123
  id?: string | undefined;
124
124
  message?: string | undefined;
125
125
  }>;
126
- declare function findR2Bucket(name: string, execImpl?: ExecImpl): Promise<boolean>;
127
- declare function createR2Bucket(name: string, execImpl?: ExecImpl): Promise<{
126
+ export declare function findR2Bucket(name: string, execImpl?: ExecImpl): Promise<boolean>;
127
+ export declare function createR2Bucket(name: string, execImpl?: ExecImpl): Promise<{
128
128
  ok: boolean;
129
129
  message?: string | undefined;
130
130
  }>;
131
131
  //#endregion
132
132
  //#region src/hosting/github.d.ts
133
- declare function ghAuthed(execImpl?: ExecImpl): Promise<boolean>;
134
- declare function originRemote(execImpl?: ExecImpl): Promise<string | undefined>;
135
- declare function repoNwo(execImpl?: ExecImpl): Promise<string | undefined>;
136
- declare function branches(execImpl?: ExecImpl): Promise<string[]>;
137
- declare function defaultBranch(nwo: string, execImpl?: ExecImpl): Promise<string | undefined>;
138
- declare function mainProtected(nwo: string, execImpl?: ExecImpl): Promise<boolean>;
139
- declare function environments(nwo: string, execImpl?: ExecImpl): Promise<string[]>;
140
- declare function secretsPresent(nwo: string, execImpl?: ExecImpl): Promise<string[]>;
141
- declare function createRepo(name: string, visibility: 'public' | 'private', execImpl?: ExecImpl): Promise<{
133
+ export declare function ghAuthed(execImpl?: ExecImpl): Promise<boolean>;
134
+ export declare function originRemote(execImpl?: ExecImpl): Promise<string | undefined>;
135
+ export declare function repoNwo(execImpl?: ExecImpl): Promise<string | undefined>;
136
+ export declare function branches(execImpl?: ExecImpl): Promise<string[]>;
137
+ export declare function defaultBranch(nwo: string, execImpl?: ExecImpl): Promise<string | undefined>;
138
+ export declare function mainProtected(nwo: string, execImpl?: ExecImpl): Promise<boolean>;
139
+ export declare function environments(nwo: string, execImpl?: ExecImpl): Promise<string[]>;
140
+ export declare function secretsPresent(nwo: string, execImpl?: ExecImpl): Promise<string[]>;
141
+ export declare function createRepo(name: string, visibility: 'public' | 'private', execImpl?: ExecImpl): Promise<{
142
142
  ok: boolean;
143
143
  message?: string | undefined;
144
144
  }>;
145
- declare function pushBranches(execImpl?: ExecImpl): Promise<{
145
+ export declare function pushBranches(execImpl?: ExecImpl): Promise<{
146
146
  ok: boolean;
147
147
  message?: string | undefined;
148
148
  }>;
149
- declare function setDefaultBranch(nwo: string, branch: string, execImpl?: ExecImpl): Promise<{
149
+ export declare function setDefaultBranch(nwo: string, branch: string, execImpl?: ExecImpl): Promise<{
150
150
  ok: boolean;
151
151
  message?: string | undefined;
152
152
  }>;
@@ -158,27 +158,27 @@ declare function setDefaultBranch(nwo: string, branch: string, execImpl?: ExecIm
158
158
  * (`a[]=x`) this way, so no request needs a second I/O channel `ExecImpl` would
159
159
  * have to carry just for this one call.
160
160
  */
161
- declare function protectMain(nwo: string, execImpl?: ExecImpl): Promise<{
161
+ export declare function protectMain(nwo: string, execImpl?: ExecImpl): Promise<{
162
162
  ok: boolean;
163
163
  message?: string | undefined;
164
164
  }>;
165
165
  /** The repo's admin collaborators — numeric user ids, which is what the
166
166
  * environment-reviewers API wants (not logins). */
167
- declare function adminCollaboratorIds(nwo: string, execImpl?: ExecImpl): Promise<number[]>;
167
+ export declare function adminCollaboratorIds(nwo: string, execImpl?: ExecImpl): Promise<number[]>;
168
168
  /** `PUT .../environments/production`, reviewers = current admin collaborators. */
169
- declare function createProdEnvironment(nwo: string, reviewerUserIds: number[], execImpl?: ExecImpl): Promise<{
169
+ export declare function createProdEnvironment(nwo: string, reviewerUserIds: number[], execImpl?: ExecImpl): Promise<{
170
170
  ok: boolean;
171
171
  message?: string | undefined;
172
172
  }>;
173
173
  /** `PUT .../environments/dev` with no reviewers — deliberately left open. */
174
- declare function createDevEnvironment(nwo: string, execImpl?: ExecImpl): Promise<{
174
+ export declare function createDevEnvironment(nwo: string, execImpl?: ExecImpl): Promise<{
175
175
  ok: boolean;
176
176
  message?: string | undefined;
177
177
  }>;
178
- declare function setSecret(name: string, value: string, execImpl?: ExecImpl): Promise<{
178
+ export declare function setSecret(name: string, value: string, execImpl?: ExecImpl): Promise<{
179
179
  ok: boolean;
180
180
  message?: string | undefined;
181
181
  }>;
182
182
  //#endregion
183
- export { type DomainState, type ExecImpl, type ExecResult, type HostingPlan, type HostingResult, type HostingSetup, type HostingState, type StepAction, type StepPlan, adminCollaboratorIds, blockedSteps, branches, createD1, createDevEnvironment, createProdEnvironment, createR2Bucket, createRepo, defaultBranch, environments, findD1, findR2Bucket, formatPlan, formatSummary, ghAuthed, hasDrift, mainProtected, originRemote, plan, planDomainConsistency, protectMain, pushBranches, realExec, repoNwo, secretsPresent, setDefaultBranch, setSecret, wranglerWhoami };
183
+ export type { DomainState, ExecImpl, ExecResult, HostingPlan, HostingResult, HostingSetup, HostingState, StepAction, StepPlan };
184
184
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/hosting/types.ts","../../src/hosting/plan.ts","../../src/hosting/wrangler.ts","../../src/hosting/github.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/hosting/types.ts","../../src/hosting/plan.ts","../../src/hosting/wrangler.ts","../../src/hosting/github.ts"],"mappings":";;;;;;;;;;;UAWiB;EACf;;EAEA;EACA;;EAEA;;EAEA;;;UAIe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;;EAEA;;;UAIe;EACf;EACA;;EAEA;;EAEA;EACA;;;;KC1BU;UAEK;EACf,QAAQ;EACR;;UAGe;EACf,MAAM;EACN,UAAU;EACV,eAAe;EACf,gBAAgB;EAChB,iBAAiB;EACjB,gBAAgB;EAChB,IAAI;EACJ,IAAI;;EAEJ,SAAS,eAAe;EACxB;;;wBASc,KAAK,OAAO,cAAc,OAAO,eAAe;;wBA6HhD,SAAS,GAAG;;wBAKZ,aAAa,GAAG;EAAgB;EAAc;;;wBAkB9C,WAAW,GAAG;;UAmBb;EACf;EACA;EACA;;;wBAIc,cAAc,SAAS;;;;;;;wBAevB,sBAAsB,OAAO,cAAc;;;UC/N1C;EACf;EACA;EACA;;KAGU,YAAY,aAAa,mBAAmB,QAAQ;;qBAGnD,UAAU;;wBAeD,eACpB,WAAU,WACT;EAAU;EAAiB;;;;;;;;;;wBAeR,OACpB,cACA,WAAU,WACT;;wBAYmB,SACpB,cACA,WAAU,WACT;EAAU;EAAa;EAAyB;;wBAS7B,aAAa,cAAc,WAAU,WAAsB;wBAM3D,eACpB,cACA,WAAU,WACT;EAAU;EAAa;;;;wBC/EJ,SAAS,WAAU,WAAsB;wBAIzC,aAAa,WAAU,WAAsB;wBAK7C,QAAQ,WAAU,WAAsB;wBAUxC,SAAS,WAAU,WAAsB;wBASzC,cACpB,aACA,WAAU,WACT;wBAWmB,cAAc,aAAa,WAAU,WAAsB;wBAI3D,aAAa,aAAa,WAAU,WAAsB;wBAY1D,eACpB,aACA,WAAU,WACT;wBAcmB,WACpB,cACA,kCACA,WAAU,WACT;EAAU;EAAa;;wBAYJ,aACpB,WAAU,WACT;EAAU;EAAa;;wBAKJ,iBACpB,aACA,gBACA,WAAU,WACT;EAAU;EAAa;;;;;;;;;;wBAaJ,YACpB,aACA,WAAU,WACT;EAAU;EAAa;;;;wBA0BJ,qBACpB,aACA,WAAU,WACT;;wBAWmB,sBACpB,aACA,2BACA,WAAU,WACT;EAAU;EAAa;;;wBAqBJ,qBACpB,aACA,WAAU,WACT;EAAU;EAAa;;wBAKJ,UACpB,cACA,eACA,WAAU,WACT;EAAU;EAAa"}
@@ -189,15 +189,18 @@ function formatPlan(p) {
189
189
  }
190
190
  /** Render the end-of-run summary: one row per step, plus blocked reminders. */
191
191
  function formatSummary(results) {
192
- return table([
192
+ const headers = [
193
193
  "STEP",
194
194
  "STATUS",
195
195
  "DETAIL"
196
- ], results.map((r) => [
196
+ ];
197
+ const rows = results.map((r) => [
197
198
  r.step,
198
199
  r.status,
199
200
  r.detail
200
- ]), results.filter((r) => r.status === "blocked").map((r) => ` ! ${r.step}: ${r.detail}`));
201
+ ]);
202
+ const reminders = results.filter((r) => r.status === "blocked").map((r) => ` ! ${r.step}: ${r.detail}`);
203
+ return table(headers, rows, reminders);
201
204
  }
202
205
  /**
203
206
  * Plan the domain-consistency check on its own — it has no executor, only an
@@ -247,7 +250,7 @@ const exec = promisify(execFile);
247
250
  /** The real executor — `execFile` with an argv array, never a shell string. */
248
251
  const realExec = async (cmd, args) => {
249
252
  try {
250
- const { stdout } = await exec(cmd, args, { maxBuffer: 16 * 1024 * 1024 });
253
+ const { stdout } = await exec(cmd, args, { maxBuffer: 16777216 });
251
254
  return {
252
255
  ok: true,
253
256
  stdout
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/hosting/plan.ts","../../src/hosting/wrangler.ts","../../src/hosting/github.ts"],"sourcesContent":["/**\n * Every decision `vitops setup` makes, as one pure function.\n *\n * Same split as `onboarding/plan.ts` and `ads/plan.ts`: this module decides, from\n * observed live state, what's left to do; `wrangler.ts`/`github.ts` execute a plan\n * and decide nothing. That is what makes `--dry` a complete account of a run and\n * `--check` an honest drift report with no network beyond the observation step.\n *\n * Idempotency lives here: a step whose desired state already holds resolves to\n * `skip`, so a re-run of a fully-provisioned project is all skips by construction.\n *\n * `blocked` (ads' addition to onboarding's three-state `StepAction`) covers the one\n * thing this command genuinely cannot do: mint a Cloudflare API token. That is\n * config nothing here can supply — surfaced as blocked, carrying the manual path,\n * never as a failure.\n *\n * Never destructive: no step here deletes a database, a bucket, a branch, a\n * protection rule, or a DNS record — matching `onboarding/cloudflare.ts`'s DNS\n * verbs, which have no update or delete either.\n */\nimport { table } from '../plan-format.ts';\nimport type { DomainState, HostingSetup, HostingState } from './types.ts';\n\nexport type StepAction = 'create' | 'update' | 'skip' | 'blocked';\n\nexport interface StepPlan {\n action: StepAction;\n detail: string;\n}\n\nexport interface HostingPlan {\n repo: StepPlan;\n branches: StepPlan;\n defaultBranch: StepPlan;\n mainProtection: StepPlan;\n prodEnvironment: StepPlan;\n devEnvironment: StepPlan;\n d1: StepPlan;\n r2: StepPlan;\n /** One step per repo secret this command sets. */\n secrets: Record<string, StepPlan>;\n notes: string[];\n}\n\nconst SECRETS_FOR = (setup: HostingSetup): string[] =>\n setup.platform === 'cloudflare'\n ? ['DEV_D1_ID', 'CLOUDFLARE_ACCOUNT_ID', 'CLOUDFLARE_API_TOKEN']\n : [];\n\n/** Plan the whole hosting sequence from setup + observed state. */\nexport function plan(setup: HostingSetup, state: HostingState): HostingPlan {\n const notes: string[] = [];\n\n const repo: StepPlan =\n state.originRemote && state.repoNwo\n ? { action: 'skip', detail: `repo already exists (${state.repoNwo})` }\n : {\n action: 'create',\n detail: `create GitHub repo \"${setup.projectName}\" (${setup.repoVisibility})`,\n };\n\n const branches: StepPlan =\n state.branches.includes('main') && state.branches.includes('dev')\n ? { action: 'skip', detail: 'main + dev already exist' }\n : { action: 'create', detail: 'push main + dev' };\n\n const defaultBranch: StepPlan =\n state.defaultBranch === 'dev'\n ? { action: 'skip', detail: 'dev is already the default branch' }\n : { action: 'update', detail: 'make dev the default branch' };\n\n const mainProtection: StepPlan = state.mainProtected\n ? { action: 'skip', detail: 'main is already protected' }\n : {\n action: 'blocked',\n detail:\n 'requires GitHub Pro/Team on a private repo — set it manually in Settings → Branches ' +\n '(PR + review + the \"ci\" check required) if this stays blocked',\n };\n\n const prodEnvironment: StepPlan = state.environments.includes('production')\n ? { action: 'skip', detail: 'production environment already exists' }\n : {\n action: 'blocked',\n detail:\n 'requires GitHub Pro/Team on a private repo — create a \"production\" environment ' +\n 'gated on your admin collaborators manually if this stays blocked',\n };\n\n const devEnvironment: StepPlan = state.environments.includes('dev')\n ? { action: 'skip', detail: 'dev environment already exists' }\n : {\n action: 'create',\n detail: 'create \"dev\" environment with no required reviewers (stays open)',\n };\n\n const d1: StepPlan =\n setup.platform !== 'cloudflare' || !setup.devResources\n ? { action: 'skip', detail: 'not a cloudflare project, or dev resources not requested' }\n : state.d1Present\n ? { action: 'skip', detail: `dev D1 already exists (${state.d1Id ?? 'id unknown'})` }\n : { action: 'create', detail: `create D1 database \"${setup.projectName}-dev\"` };\n\n const r2: StepPlan =\n setup.platform !== 'cloudflare' || !setup.devResources\n ? { action: 'skip', detail: 'not a cloudflare project, or dev resources not requested' }\n : state.r2Present\n ? { action: 'skip', detail: `dev R2 bucket already exists` }\n : { action: 'create', detail: `create R2 bucket \"${setup.projectName}-media-dev\"` };\n\n const secrets: Record<string, StepPlan> = {};\n for (const name of SECRETS_FOR(setup)) {\n if (!state.ghAuthed || !state.originRemote) {\n secrets[name] = {\n action: 'blocked',\n detail: 'no GitHub repo wired up yet — run the repo step first',\n };\n continue;\n }\n if (state.secretsPresent.includes(name)) {\n secrets[name] = { action: 'skip', detail: 'already set' };\n continue;\n }\n if (name === 'CLOUDFLARE_API_TOKEN') {\n secrets[name] = {\n action: 'blocked',\n detail:\n 'tokens cannot be created via any API — create one at ' +\n 'https://dash.cloudflare.com/profile/api-tokens (Workers + D1 + R2 edit), then ' +\n '`gh secret set CLOUDFLARE_API_TOKEN`',\n };\n continue;\n }\n const value =\n name === 'DEV_D1_ID'\n ? state.d1Id\n : name === 'CLOUDFLARE_ACCOUNT_ID'\n ? state.accountId\n : undefined;\n secrets[name] = value\n ? { action: 'create', detail: `set from provisioned/observed value` }\n : { action: 'blocked', detail: 'value not yet known — provision the resource first' };\n }\n\n if (!state.wranglerAuthed && setup.platform === 'cloudflare' && setup.devResources)\n notes.push('wrangler is not logged in — run `npx wrangler login` first');\n if (!state.ghAuthed) notes.push('gh is not logged in — run `gh auth login` first');\n\n return {\n repo,\n branches,\n defaultBranch,\n mainProtection,\n prodEnvironment,\n devEnvironment,\n d1,\n r2,\n secrets,\n notes,\n };\n}\n\nconst allSteps = (p: HostingPlan): StepPlan[] => [\n p.repo,\n p.branches,\n p.defaultBranch,\n p.mainProtection,\n p.prodEnvironment,\n p.devEnvironment,\n p.d1,\n p.r2,\n ...Object.values(p.secrets),\n];\n\n/** Any step that isn't a skip — i.e. the live state has drifted from desired. */\nexport function hasDrift(p: HostingPlan): boolean {\n return allSteps(p).some((s) => s.action !== 'skip');\n}\n\n/** Every blocked step, with a name — what `--check` reports and the CLI surfaces. */\nexport function blockedSteps(p: HostingPlan): { name: string; detail: string }[] {\n const named: [string, StepPlan][] = [\n ['repo', p.repo],\n ['branches', p.branches],\n ['defaultBranch', p.defaultBranch],\n ['mainProtection', p.mainProtection],\n ['prodEnvironment', p.prodEnvironment],\n ['devEnvironment', p.devEnvironment],\n ['d1', p.d1],\n ['r2', p.r2],\n ...Object.entries(p.secrets).map(([name, s]) => [`secret:${name}`, s] as [string, StepPlan]),\n ];\n return named\n .filter(([, s]) => s.action === 'blocked')\n .map(([name, s]) => ({ name, detail: s.detail }));\n}\n\n/** Render a plan as the block `--dry` and `--check` print. */\nexport function formatPlan(p: HostingPlan): string {\n const glyph = (s: StepPlan) =>\n s.action === 'skip' ? '·' : s.action === 'blocked' ? '?' : s.action === 'update' ? '~' : '+';\n const lines: string[] = [];\n lines.push(`${glyph(p.repo)} repo ${p.repo.detail}`);\n lines.push(`${glyph(p.branches)} branches ${p.branches.detail}`);\n lines.push(`${glyph(p.defaultBranch)} default branch ${p.defaultBranch.detail}`);\n lines.push(`${glyph(p.mainProtection)} main protection ${p.mainProtection.detail}`);\n lines.push(`${glyph(p.prodEnvironment)} production env ${p.prodEnvironment.detail}`);\n lines.push(`${glyph(p.devEnvironment)} dev env ${p.devEnvironment.detail}`);\n lines.push(`${glyph(p.d1)} dev D1 ${p.d1.detail}`);\n lines.push(`${glyph(p.r2)} dev R2 ${p.r2.detail}`);\n for (const [name, s] of Object.entries(p.secrets))\n lines.push(`${glyph(s)} secret ${name}${' '.repeat(Math.max(1, 11 - name.length))}${s.detail}`);\n for (const n of p.notes) lines.push(`! ${n}`);\n return lines.join('\\n');\n}\n\n/** The outcome of one run, for the summary table. */\nexport interface HostingResult {\n step: string;\n status: 'created' | 'updated' | 'present' | 'blocked' | 'failed';\n detail: string;\n}\n\n/** Render the end-of-run summary: one row per step, plus blocked reminders. */\nexport function formatSummary(results: HostingResult[]): string {\n const headers = ['STEP', 'STATUS', 'DETAIL'];\n const rows = results.map((r) => [r.step, r.status, r.detail]);\n const reminders = results\n .filter((r) => r.status === 'blocked')\n .map((r) => ` ! ${r.step}: ${r.detail}`);\n return table(headers, rows, reminders);\n}\n\n/**\n * Plan the domain-consistency check on its own — it has no executor, only an\n * observation (`wrangler.jsonc` + the config), and it is never applied by this\n * command. See `SETUP.html`'s \"Domain strategy\" stage: the actual cutover is a\n * human, deliberate action.\n */\nexport function planDomainConsistency(state: DomainState): StepPlan {\n const cutover = Boolean(state.customDomain);\n if (cutover) {\n if (!state.canonical || state.canonical !== `https://${state.customDomain}`)\n return {\n action: 'blocked',\n detail: `wrangler.jsonc names a custom domain (${state.customDomain}) but site.domains.canonical doesn't match — a visitor sees the new site while <link rel=canonical> still points at the old one`,\n };\n if (state.robots?.includes('noindex'))\n return {\n action: 'blocked',\n detail:\n 'custom domain is live but robots is still \"noindex,nofollow\" — flip it back after cutover',\n };\n return { action: 'skip', detail: 'custom domain configured and consistent' };\n }\n if (!state.robots?.includes('noindex'))\n return {\n action: 'blocked',\n detail:\n 'still on *.workers.dev but robots does not say \"noindex,nofollow\" — a workers.dev URL is indexable, and this is what stops search engines treating it as a duplicate of the real site',\n };\n return { action: 'skip', detail: 'workers.dev phase, correctly noindexed' };\n}\n","/**\n * Cloudflare resources — dev D1 + R2, plus the account id. Executes a plan and\n * decides nothing; every observation and mutation is a structured result, never a\n * throw, so the CLI decides what a failure means.\n *\n * Shells out to `wrangler` and reads `gh`'s account-id output — there is no REST\n * alternative that doesn't also need the same credential wrangler already holds\n * from `wrangler login`. Same class of executor as `@getvitops/utils/media`\n * shelling to `ffmpeg`: an external tool, not an npm dependency, with `execImpl`\n * injected so the parsing is testable without a real Cloudflare account.\n */\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst exec = promisify(execFile);\n\nexport interface ExecResult {\n ok: boolean;\n stdout: string;\n message?: string | undefined;\n}\n\nexport type ExecImpl = (cmd: string, args: string[]) => Promise<ExecResult>;\n\n/** The real executor — `execFile` with an argv array, never a shell string. */\nexport const realExec: ExecImpl = async (cmd, args) => {\n try {\n const { stdout } = await exec(cmd, args, { maxBuffer: 16 * 1024 * 1024 });\n return { ok: true, stdout };\n } catch (err) {\n const e = err as { stdout?: string; stderr?: string; message?: string };\n return {\n ok: false,\n stdout: e.stdout ?? '',\n message: e.stderr || e.message || 'command failed',\n };\n }\n};\n\n/** `wrangler whoami` — auth check + the 32-hex account id, from one call. */\nexport async function wranglerWhoami(\n execImpl: ExecImpl = realExec,\n): Promise<{ authed: boolean; accountId?: string }> {\n const res = await execImpl('npx', ['wrangler', 'whoami']);\n if (!res.ok) return { authed: false };\n const accountId = /\\b([0-9a-f]{32})\\b/.exec(res.stdout)?.[1];\n return { authed: true, ...(accountId ? { accountId } : {}) };\n}\n\n/**\n * Find an existing dev D1 database's id by name.\n *\n * `d1 create`'s own stdout carries the id, but its format has drifted across\n * wrangler versions before — a re-list is the one thing guaranteed to still hold\n * the answer, so both the \"does it exist\" check and the post-create fallback go\n * through this.\n */\nexport async function findD1(\n name: string,\n execImpl: ExecImpl = realExec,\n): Promise<string | undefined> {\n const res = await execImpl('npx', ['wrangler', 'd1', 'list', '--json']);\n if (!res.ok) return undefined;\n try {\n const list = JSON.parse(res.stdout) as { name: string; uuid: string }[];\n return list.find((d) => d.name === name)?.uuid;\n } catch {\n return undefined;\n }\n}\n\n/** Create a dev D1 database, then resolve its id via `findD1` (see its docblock). */\nexport async function createD1(\n name: string,\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; id?: string | undefined; message?: string | undefined }> {\n const res = await execImpl('npx', ['wrangler', 'd1', 'create', name]);\n if (!res.ok) return { ok: false, message: res.message };\n const inline = /\"database_id\":\\s*\"([0-9a-f-]{36})\"/.exec(res.stdout)?.[1];\n const id = inline ?? (await findD1(name, execImpl));\n if (!id) return { ok: false, message: 'created, but could not determine the database id' };\n return { ok: true, id };\n}\n\nexport async function findR2Bucket(name: string, execImpl: ExecImpl = realExec): Promise<boolean> {\n const res = await execImpl('npx', ['wrangler', 'r2', 'bucket', 'list']);\n if (!res.ok) return false;\n return new RegExp(`name:\\\\s+${name}\\\\s*$`, 'm').test(res.stdout);\n}\n\nexport async function createR2Bucket(\n name: string,\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('npx', ['wrangler', 'r2', 'bucket', 'create', name]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n","/**\n * GitHub repo, branches, environments and secrets. Executes a plan and decides\n * nothing — see `wrangler.ts`'s docblock for why this shells out (`gh` carries the\n * auth; there is no token-free REST alternative) and for the `execImpl` seam.\n *\n * Absorbs the behaviour of the templates' old `scripts/init-github.mjs`:\n * `dev` is left with **no required reviewers**, deliberately — that is what keeps\n * it the unprotected integration branch. `main` protection and the `production`\n * environment's reviewer policy both 403 on a private repo without GitHub\n * Pro/Team; that is reported as `blocked`, not `failed` — see `plan.ts`.\n */\nimport type { ExecImpl } from './wrangler.ts';\nimport { realExec } from './wrangler.ts';\n\nexport async function ghAuthed(execImpl: ExecImpl = realExec): Promise<boolean> {\n return (await execImpl('gh', ['auth', 'status'])).ok;\n}\n\nexport async function originRemote(execImpl: ExecImpl = realExec): Promise<string | undefined> {\n const res = await execImpl('git', ['remote', 'get-url', 'origin']);\n return res.ok ? res.stdout.trim() : undefined;\n}\n\nexport async function repoNwo(execImpl: ExecImpl = realExec): Promise<string | undefined> {\n const res = await execImpl('gh', ['repo', 'view', '--json', 'nameWithOwner']);\n if (!res.ok) return undefined;\n try {\n return (JSON.parse(res.stdout) as { nameWithOwner: string }).nameWithOwner;\n } catch {\n return undefined;\n }\n}\n\nexport async function branches(execImpl: ExecImpl = realExec): Promise<string[]> {\n const res = await execImpl('git', ['branch', '--list', '--format=%(refname:short)']);\n if (!res.ok) return [];\n return res.stdout\n .split('\\n')\n .map((l) => l.trim())\n .filter(Boolean);\n}\n\nexport async function defaultBranch(\n nwo: string,\n execImpl: ExecImpl = realExec,\n): Promise<string | undefined> {\n const res = await execImpl('gh', ['repo', 'view', nwo, '--json', 'defaultBranchRef']);\n if (!res.ok) return undefined;\n try {\n return (JSON.parse(res.stdout) as { defaultBranchRef?: { name: string } }).defaultBranchRef\n ?.name;\n } catch {\n return undefined;\n }\n}\n\nexport async function mainProtected(nwo: string, execImpl: ExecImpl = realExec): Promise<boolean> {\n return (await execImpl('gh', ['api', `repos/${nwo}/branches/main/protection`])).ok;\n}\n\nexport async function environments(nwo: string, execImpl: ExecImpl = realExec): Promise<string[]> {\n const res = await execImpl('gh', ['api', `repos/${nwo}/environments`]);\n if (!res.ok) return [];\n try {\n return (\n (JSON.parse(res.stdout) as { environments?: { name: string }[] }).environments ?? []\n ).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nexport async function secretsPresent(\n nwo: string,\n execImpl: ExecImpl = realExec,\n): Promise<string[]> {\n const res = await execImpl('gh', ['api', `repos/${nwo}/actions/secrets`]);\n if (!res.ok) return [];\n try {\n return ((JSON.parse(res.stdout) as { secrets?: { name: string }[] }).secrets ?? []).map(\n (s) => s.name,\n );\n } catch {\n return [];\n }\n}\n\n// ── Mutations ─────────────────────────────────────────────────────────────────\n\nexport async function createRepo(\n name: string,\n visibility: 'public' | 'private',\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('gh', [\n 'repo',\n 'create',\n name,\n `--${visibility}`,\n '--source=.',\n '--remote=origin',\n ]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n\nexport async function pushBranches(\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('git', ['push', '-u', 'origin', 'main', 'dev']);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n\nexport async function setDefaultBranch(\n nwo: string,\n branch: string,\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('gh', ['repo', 'edit', nwo, `--default-branch=${branch}`]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n\n/**\n * `PUT .../branches/main/protection`. A 403 on Pro/Team-gated repos is expected.\n *\n * Every field goes through `gh api`'s `-f`/`-F` form flags rather than a JSON body\n * on stdin — `gh api` supports nested keys (`a[b]=c`) and repeated array keys\n * (`a[]=x`) this way, so no request needs a second I/O channel `ExecImpl` would\n * have to carry just for this one call.\n */\nexport async function protectMain(\n nwo: string,\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('gh', [\n 'api',\n '--method',\n 'PUT',\n `repos/${nwo}/branches/main/protection`,\n '-F',\n 'required_status_checks[strict]=true',\n '-f',\n 'required_status_checks[contexts][]=ci',\n '-F',\n 'enforce_admins=false',\n '-F',\n 'required_pull_request_reviews[required_approving_review_count]=1',\n '-F',\n 'restrictions=null',\n '-F',\n 'allow_force_pushes=false',\n '-F',\n 'allow_deletions=false',\n ]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n\n/** The repo's admin collaborators — numeric user ids, which is what the\n * environment-reviewers API wants (not logins). */\nexport async function adminCollaboratorIds(\n nwo: string,\n execImpl: ExecImpl = realExec,\n): Promise<number[]> {\n const res = await execImpl('gh', ['api', `repos/${nwo}/collaborators?permission=admin`]);\n if (!res.ok) return [];\n try {\n return (JSON.parse(res.stdout) as { id: number }[]).map((c) => c.id);\n } catch {\n return [];\n }\n}\n\n/** `PUT .../environments/production`, reviewers = current admin collaborators. */\nexport async function createProdEnvironment(\n nwo: string,\n reviewerUserIds: number[],\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('gh', [\n 'api',\n '--method',\n 'PUT',\n `repos/${nwo}/environments/production`,\n '-f',\n `deployment_branch_policy[protected_branches]=true`,\n '-f',\n `deployment_branch_policy[custom_branch_policies]=false`,\n ...reviewerUserIds.flatMap((id) => [\n '-F',\n `reviewers[][id]=${id}`,\n '-f',\n 'reviewers[][type]=User',\n ]),\n ]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n\n/** `PUT .../environments/dev` with no reviewers — deliberately left open. */\nexport async function createDevEnvironment(\n nwo: string,\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('gh', ['api', '--method', 'PUT', `repos/${nwo}/environments/dev`]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n\nexport async function setSecret(\n name: string,\n value: string,\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('gh', ['secret', 'set', name, '--body', value]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/hosting/plan.ts","../../src/hosting/wrangler.ts","../../src/hosting/github.ts"],"sourcesContent":["/**\n * Every decision `vitops setup` makes, as one pure function.\n *\n * Same split as `onboarding/plan.ts` and `ads/plan.ts`: this module decides, from\n * observed live state, what's left to do; `wrangler.ts`/`github.ts` execute a plan\n * and decide nothing. That is what makes `--dry` a complete account of a run and\n * `--check` an honest drift report with no network beyond the observation step.\n *\n * Idempotency lives here: a step whose desired state already holds resolves to\n * `skip`, so a re-run of a fully-provisioned project is all skips by construction.\n *\n * `blocked` (ads' addition to onboarding's three-state `StepAction`) covers the one\n * thing this command genuinely cannot do: mint a Cloudflare API token. That is\n * config nothing here can supply — surfaced as blocked, carrying the manual path,\n * never as a failure.\n *\n * Never destructive: no step here deletes a database, a bucket, a branch, a\n * protection rule, or a DNS record — matching `onboarding/cloudflare.ts`'s DNS\n * verbs, which have no update or delete either.\n */\nimport { table } from '../plan-format.ts';\nimport type { DomainState, HostingSetup, HostingState } from './types.ts';\n\nexport type StepAction = 'create' | 'update' | 'skip' | 'blocked';\n\nexport interface StepPlan {\n action: StepAction;\n detail: string;\n}\n\nexport interface HostingPlan {\n repo: StepPlan;\n branches: StepPlan;\n defaultBranch: StepPlan;\n mainProtection: StepPlan;\n prodEnvironment: StepPlan;\n devEnvironment: StepPlan;\n d1: StepPlan;\n r2: StepPlan;\n /** One step per repo secret this command sets. */\n secrets: Record<string, StepPlan>;\n notes: string[];\n}\n\nconst SECRETS_FOR = (setup: HostingSetup): string[] =>\n setup.platform === 'cloudflare'\n ? ['DEV_D1_ID', 'CLOUDFLARE_ACCOUNT_ID', 'CLOUDFLARE_API_TOKEN']\n : [];\n\n/** Plan the whole hosting sequence from setup + observed state. */\nexport function plan(setup: HostingSetup, state: HostingState): HostingPlan {\n const notes: string[] = [];\n\n const repo: StepPlan =\n state.originRemote && state.repoNwo\n ? { action: 'skip', detail: `repo already exists (${state.repoNwo})` }\n : {\n action: 'create',\n detail: `create GitHub repo \"${setup.projectName}\" (${setup.repoVisibility})`,\n };\n\n const branches: StepPlan =\n state.branches.includes('main') && state.branches.includes('dev')\n ? { action: 'skip', detail: 'main + dev already exist' }\n : { action: 'create', detail: 'push main + dev' };\n\n const defaultBranch: StepPlan =\n state.defaultBranch === 'dev'\n ? { action: 'skip', detail: 'dev is already the default branch' }\n : { action: 'update', detail: 'make dev the default branch' };\n\n const mainProtection: StepPlan = state.mainProtected\n ? { action: 'skip', detail: 'main is already protected' }\n : {\n action: 'blocked',\n detail:\n 'requires GitHub Pro/Team on a private repo — set it manually in Settings → Branches ' +\n '(PR + review + the \"ci\" check required) if this stays blocked',\n };\n\n const prodEnvironment: StepPlan = state.environments.includes('production')\n ? { action: 'skip', detail: 'production environment already exists' }\n : {\n action: 'blocked',\n detail:\n 'requires GitHub Pro/Team on a private repo — create a \"production\" environment ' +\n 'gated on your admin collaborators manually if this stays blocked',\n };\n\n const devEnvironment: StepPlan = state.environments.includes('dev')\n ? { action: 'skip', detail: 'dev environment already exists' }\n : {\n action: 'create',\n detail: 'create \"dev\" environment with no required reviewers (stays open)',\n };\n\n const d1: StepPlan =\n setup.platform !== 'cloudflare' || !setup.devResources\n ? { action: 'skip', detail: 'not a cloudflare project, or dev resources not requested' }\n : state.d1Present\n ? { action: 'skip', detail: `dev D1 already exists (${state.d1Id ?? 'id unknown'})` }\n : { action: 'create', detail: `create D1 database \"${setup.projectName}-dev\"` };\n\n const r2: StepPlan =\n setup.platform !== 'cloudflare' || !setup.devResources\n ? { action: 'skip', detail: 'not a cloudflare project, or dev resources not requested' }\n : state.r2Present\n ? { action: 'skip', detail: `dev R2 bucket already exists` }\n : { action: 'create', detail: `create R2 bucket \"${setup.projectName}-media-dev\"` };\n\n const secrets: Record<string, StepPlan> = {};\n for (const name of SECRETS_FOR(setup)) {\n if (!state.ghAuthed || !state.originRemote) {\n secrets[name] = {\n action: 'blocked',\n detail: 'no GitHub repo wired up yet — run the repo step first',\n };\n continue;\n }\n if (state.secretsPresent.includes(name)) {\n secrets[name] = { action: 'skip', detail: 'already set' };\n continue;\n }\n if (name === 'CLOUDFLARE_API_TOKEN') {\n secrets[name] = {\n action: 'blocked',\n detail:\n 'tokens cannot be created via any API — create one at ' +\n 'https://dash.cloudflare.com/profile/api-tokens (Workers + D1 + R2 edit), then ' +\n '`gh secret set CLOUDFLARE_API_TOKEN`',\n };\n continue;\n }\n const value =\n name === 'DEV_D1_ID'\n ? state.d1Id\n : name === 'CLOUDFLARE_ACCOUNT_ID'\n ? state.accountId\n : undefined;\n secrets[name] = value\n ? { action: 'create', detail: `set from provisioned/observed value` }\n : { action: 'blocked', detail: 'value not yet known — provision the resource first' };\n }\n\n if (!state.wranglerAuthed && setup.platform === 'cloudflare' && setup.devResources)\n notes.push('wrangler is not logged in — run `npx wrangler login` first');\n if (!state.ghAuthed) notes.push('gh is not logged in — run `gh auth login` first');\n\n return {\n repo,\n branches,\n defaultBranch,\n mainProtection,\n prodEnvironment,\n devEnvironment,\n d1,\n r2,\n secrets,\n notes,\n };\n}\n\nconst allSteps = (p: HostingPlan): StepPlan[] => [\n p.repo,\n p.branches,\n p.defaultBranch,\n p.mainProtection,\n p.prodEnvironment,\n p.devEnvironment,\n p.d1,\n p.r2,\n ...Object.values(p.secrets),\n];\n\n/** Any step that isn't a skip — i.e. the live state has drifted from desired. */\nexport function hasDrift(p: HostingPlan): boolean {\n return allSteps(p).some((s) => s.action !== 'skip');\n}\n\n/** Every blocked step, with a name — what `--check` reports and the CLI surfaces. */\nexport function blockedSteps(p: HostingPlan): { name: string; detail: string }[] {\n const named: [string, StepPlan][] = [\n ['repo', p.repo],\n ['branches', p.branches],\n ['defaultBranch', p.defaultBranch],\n ['mainProtection', p.mainProtection],\n ['prodEnvironment', p.prodEnvironment],\n ['devEnvironment', p.devEnvironment],\n ['d1', p.d1],\n ['r2', p.r2],\n ...Object.entries(p.secrets).map(([name, s]) => [`secret:${name}`, s] as [string, StepPlan]),\n ];\n return named\n .filter(([, s]) => s.action === 'blocked')\n .map(([name, s]) => ({ name, detail: s.detail }));\n}\n\n/** Render a plan as the block `--dry` and `--check` print. */\nexport function formatPlan(p: HostingPlan): string {\n const glyph = (s: StepPlan) =>\n s.action === 'skip' ? '·' : s.action === 'blocked' ? '?' : s.action === 'update' ? '~' : '+';\n const lines: string[] = [];\n lines.push(`${glyph(p.repo)} repo ${p.repo.detail}`);\n lines.push(`${glyph(p.branches)} branches ${p.branches.detail}`);\n lines.push(`${glyph(p.defaultBranch)} default branch ${p.defaultBranch.detail}`);\n lines.push(`${glyph(p.mainProtection)} main protection ${p.mainProtection.detail}`);\n lines.push(`${glyph(p.prodEnvironment)} production env ${p.prodEnvironment.detail}`);\n lines.push(`${glyph(p.devEnvironment)} dev env ${p.devEnvironment.detail}`);\n lines.push(`${glyph(p.d1)} dev D1 ${p.d1.detail}`);\n lines.push(`${glyph(p.r2)} dev R2 ${p.r2.detail}`);\n for (const [name, s] of Object.entries(p.secrets))\n lines.push(`${glyph(s)} secret ${name}${' '.repeat(Math.max(1, 11 - name.length))}${s.detail}`);\n for (const n of p.notes) lines.push(`! ${n}`);\n return lines.join('\\n');\n}\n\n/** The outcome of one run, for the summary table. */\nexport interface HostingResult {\n step: string;\n status: 'created' | 'updated' | 'present' | 'blocked' | 'failed';\n detail: string;\n}\n\n/** Render the end-of-run summary: one row per step, plus blocked reminders. */\nexport function formatSummary(results: HostingResult[]): string {\n const headers = ['STEP', 'STATUS', 'DETAIL'];\n const rows = results.map((r) => [r.step, r.status, r.detail]);\n const reminders = results\n .filter((r) => r.status === 'blocked')\n .map((r) => ` ! ${r.step}: ${r.detail}`);\n return table(headers, rows, reminders);\n}\n\n/**\n * Plan the domain-consistency check on its own — it has no executor, only an\n * observation (`wrangler.jsonc` + the config), and it is never applied by this\n * command. See `SETUP.html`'s \"Domain strategy\" stage: the actual cutover is a\n * human, deliberate action.\n */\nexport function planDomainConsistency(state: DomainState): StepPlan {\n const cutover = Boolean(state.customDomain);\n if (cutover) {\n if (!state.canonical || state.canonical !== `https://${state.customDomain}`)\n return {\n action: 'blocked',\n detail: `wrangler.jsonc names a custom domain (${state.customDomain}) but site.domains.canonical doesn't match — a visitor sees the new site while <link rel=canonical> still points at the old one`,\n };\n if (state.robots?.includes('noindex'))\n return {\n action: 'blocked',\n detail:\n 'custom domain is live but robots is still \"noindex,nofollow\" — flip it back after cutover',\n };\n return { action: 'skip', detail: 'custom domain configured and consistent' };\n }\n if (!state.robots?.includes('noindex'))\n return {\n action: 'blocked',\n detail:\n 'still on *.workers.dev but robots does not say \"noindex,nofollow\" — a workers.dev URL is indexable, and this is what stops search engines treating it as a duplicate of the real site',\n };\n return { action: 'skip', detail: 'workers.dev phase, correctly noindexed' };\n}\n","/**\n * Cloudflare resources — dev D1 + R2, plus the account id. Executes a plan and\n * decides nothing; every observation and mutation is a structured result, never a\n * throw, so the CLI decides what a failure means.\n *\n * Shells out to `wrangler` and reads `gh`'s account-id output — there is no REST\n * alternative that doesn't also need the same credential wrangler already holds\n * from `wrangler login`. Same class of executor as `@getvitops/utils/media`\n * shelling to `ffmpeg`: an external tool, not an npm dependency, with `execImpl`\n * injected so the parsing is testable without a real Cloudflare account.\n */\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst exec = promisify(execFile);\n\nexport interface ExecResult {\n ok: boolean;\n stdout: string;\n message?: string | undefined;\n}\n\nexport type ExecImpl = (cmd: string, args: string[]) => Promise<ExecResult>;\n\n/** The real executor — `execFile` with an argv array, never a shell string. */\nexport const realExec: ExecImpl = async (cmd, args) => {\n try {\n const { stdout } = await exec(cmd, args, { maxBuffer: 16 * 1024 * 1024 });\n return { ok: true, stdout };\n } catch (err) {\n const e = err as { stdout?: string; stderr?: string; message?: string };\n return {\n ok: false,\n stdout: e.stdout ?? '',\n message: e.stderr || e.message || 'command failed',\n };\n }\n};\n\n/** `wrangler whoami` — auth check + the 32-hex account id, from one call. */\nexport async function wranglerWhoami(\n execImpl: ExecImpl = realExec,\n): Promise<{ authed: boolean; accountId?: string }> {\n const res = await execImpl('npx', ['wrangler', 'whoami']);\n if (!res.ok) return { authed: false };\n const accountId = /\\b([0-9a-f]{32})\\b/.exec(res.stdout)?.[1];\n return { authed: true, ...(accountId ? { accountId } : {}) };\n}\n\n/**\n * Find an existing dev D1 database's id by name.\n *\n * `d1 create`'s own stdout carries the id, but its format has drifted across\n * wrangler versions before — a re-list is the one thing guaranteed to still hold\n * the answer, so both the \"does it exist\" check and the post-create fallback go\n * through this.\n */\nexport async function findD1(\n name: string,\n execImpl: ExecImpl = realExec,\n): Promise<string | undefined> {\n const res = await execImpl('npx', ['wrangler', 'd1', 'list', '--json']);\n if (!res.ok) return undefined;\n try {\n const list = JSON.parse(res.stdout) as { name: string; uuid: string }[];\n return list.find((d) => d.name === name)?.uuid;\n } catch {\n return undefined;\n }\n}\n\n/** Create a dev D1 database, then resolve its id via `findD1` (see its docblock). */\nexport async function createD1(\n name: string,\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; id?: string | undefined; message?: string | undefined }> {\n const res = await execImpl('npx', ['wrangler', 'd1', 'create', name]);\n if (!res.ok) return { ok: false, message: res.message };\n const inline = /\"database_id\":\\s*\"([0-9a-f-]{36})\"/.exec(res.stdout)?.[1];\n const id = inline ?? (await findD1(name, execImpl));\n if (!id) return { ok: false, message: 'created, but could not determine the database id' };\n return { ok: true, id };\n}\n\nexport async function findR2Bucket(name: string, execImpl: ExecImpl = realExec): Promise<boolean> {\n const res = await execImpl('npx', ['wrangler', 'r2', 'bucket', 'list']);\n if (!res.ok) return false;\n return new RegExp(`name:\\\\s+${name}\\\\s*$`, 'm').test(res.stdout);\n}\n\nexport async function createR2Bucket(\n name: string,\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('npx', ['wrangler', 'r2', 'bucket', 'create', name]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n","/**\n * GitHub repo, branches, environments and secrets. Executes a plan and decides\n * nothing — see `wrangler.ts`'s docblock for why this shells out (`gh` carries the\n * auth; there is no token-free REST alternative) and for the `execImpl` seam.\n *\n * Absorbs the behaviour of the templates' old `scripts/init-github.mjs`:\n * `dev` is left with **no required reviewers**, deliberately — that is what keeps\n * it the unprotected integration branch. `main` protection and the `production`\n * environment's reviewer policy both 403 on a private repo without GitHub\n * Pro/Team; that is reported as `blocked`, not `failed` — see `plan.ts`.\n */\nimport type { ExecImpl } from './wrangler.ts';\nimport { realExec } from './wrangler.ts';\n\nexport async function ghAuthed(execImpl: ExecImpl = realExec): Promise<boolean> {\n return (await execImpl('gh', ['auth', 'status'])).ok;\n}\n\nexport async function originRemote(execImpl: ExecImpl = realExec): Promise<string | undefined> {\n const res = await execImpl('git', ['remote', 'get-url', 'origin']);\n return res.ok ? res.stdout.trim() : undefined;\n}\n\nexport async function repoNwo(execImpl: ExecImpl = realExec): Promise<string | undefined> {\n const res = await execImpl('gh', ['repo', 'view', '--json', 'nameWithOwner']);\n if (!res.ok) return undefined;\n try {\n return (JSON.parse(res.stdout) as { nameWithOwner: string }).nameWithOwner;\n } catch {\n return undefined;\n }\n}\n\nexport async function branches(execImpl: ExecImpl = realExec): Promise<string[]> {\n const res = await execImpl('git', ['branch', '--list', '--format=%(refname:short)']);\n if (!res.ok) return [];\n return res.stdout\n .split('\\n')\n .map((l) => l.trim())\n .filter(Boolean);\n}\n\nexport async function defaultBranch(\n nwo: string,\n execImpl: ExecImpl = realExec,\n): Promise<string | undefined> {\n const res = await execImpl('gh', ['repo', 'view', nwo, '--json', 'defaultBranchRef']);\n if (!res.ok) return undefined;\n try {\n return (JSON.parse(res.stdout) as { defaultBranchRef?: { name: string } }).defaultBranchRef\n ?.name;\n } catch {\n return undefined;\n }\n}\n\nexport async function mainProtected(nwo: string, execImpl: ExecImpl = realExec): Promise<boolean> {\n return (await execImpl('gh', ['api', `repos/${nwo}/branches/main/protection`])).ok;\n}\n\nexport async function environments(nwo: string, execImpl: ExecImpl = realExec): Promise<string[]> {\n const res = await execImpl('gh', ['api', `repos/${nwo}/environments`]);\n if (!res.ok) return [];\n try {\n return (\n (JSON.parse(res.stdout) as { environments?: { name: string }[] }).environments ?? []\n ).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nexport async function secretsPresent(\n nwo: string,\n execImpl: ExecImpl = realExec,\n): Promise<string[]> {\n const res = await execImpl('gh', ['api', `repos/${nwo}/actions/secrets`]);\n if (!res.ok) return [];\n try {\n return ((JSON.parse(res.stdout) as { secrets?: { name: string }[] }).secrets ?? []).map(\n (s) => s.name,\n );\n } catch {\n return [];\n }\n}\n\n// ── Mutations ─────────────────────────────────────────────────────────────────\n\nexport async function createRepo(\n name: string,\n visibility: 'public' | 'private',\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('gh', [\n 'repo',\n 'create',\n name,\n `--${visibility}`,\n '--source=.',\n '--remote=origin',\n ]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n\nexport async function pushBranches(\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('git', ['push', '-u', 'origin', 'main', 'dev']);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n\nexport async function setDefaultBranch(\n nwo: string,\n branch: string,\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('gh', ['repo', 'edit', nwo, `--default-branch=${branch}`]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n\n/**\n * `PUT .../branches/main/protection`. A 403 on Pro/Team-gated repos is expected.\n *\n * Every field goes through `gh api`'s `-f`/`-F` form flags rather than a JSON body\n * on stdin — `gh api` supports nested keys (`a[b]=c`) and repeated array keys\n * (`a[]=x`) this way, so no request needs a second I/O channel `ExecImpl` would\n * have to carry just for this one call.\n */\nexport async function protectMain(\n nwo: string,\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('gh', [\n 'api',\n '--method',\n 'PUT',\n `repos/${nwo}/branches/main/protection`,\n '-F',\n 'required_status_checks[strict]=true',\n '-f',\n 'required_status_checks[contexts][]=ci',\n '-F',\n 'enforce_admins=false',\n '-F',\n 'required_pull_request_reviews[required_approving_review_count]=1',\n '-F',\n 'restrictions=null',\n '-F',\n 'allow_force_pushes=false',\n '-F',\n 'allow_deletions=false',\n ]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n\n/** The repo's admin collaborators — numeric user ids, which is what the\n * environment-reviewers API wants (not logins). */\nexport async function adminCollaboratorIds(\n nwo: string,\n execImpl: ExecImpl = realExec,\n): Promise<number[]> {\n const res = await execImpl('gh', ['api', `repos/${nwo}/collaborators?permission=admin`]);\n if (!res.ok) return [];\n try {\n return (JSON.parse(res.stdout) as { id: number }[]).map((c) => c.id);\n } catch {\n return [];\n }\n}\n\n/** `PUT .../environments/production`, reviewers = current admin collaborators. */\nexport async function createProdEnvironment(\n nwo: string,\n reviewerUserIds: number[],\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('gh', [\n 'api',\n '--method',\n 'PUT',\n `repos/${nwo}/environments/production`,\n '-f',\n `deployment_branch_policy[protected_branches]=true`,\n '-f',\n `deployment_branch_policy[custom_branch_policies]=false`,\n ...reviewerUserIds.flatMap((id) => [\n '-F',\n `reviewers[][id]=${id}`,\n '-f',\n 'reviewers[][type]=User',\n ]),\n ]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n\n/** `PUT .../environments/dev` with no reviewers — deliberately left open. */\nexport async function createDevEnvironment(\n nwo: string,\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('gh', ['api', '--method', 'PUT', `repos/${nwo}/environments/dev`]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n\nexport async function setSecret(\n name: string,\n value: string,\n execImpl: ExecImpl = realExec,\n): Promise<{ ok: boolean; message?: string | undefined }> {\n const res = await execImpl('gh', ['secret', 'set', name, '--body', value]);\n return res.ok ? { ok: true } : { ok: false, message: res.message };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,MAAM,eAAe,UACnB,MAAM,aAAa,eACf;CAAC;CAAa;CAAyB;AAAsB,IAC7D,CAAC;;AAGP,SAAgB,KAAK,OAAqB,OAAkC;CAC1E,MAAM,QAAkB,CAAC;CAEzB,MAAM,OACJ,MAAM,gBAAgB,MAAM,UACxB;EAAE,QAAQ;EAAQ,QAAQ,wBAAwB,MAAM,QAAQ;CAAG,IACnE;EACE,QAAQ;EACR,QAAQ,uBAAuB,MAAM,YAAY,KAAK,MAAM,eAAe;CAC7E;CAEN,MAAM,WACJ,MAAM,SAAS,SAAS,MAAM,KAAK,MAAM,SAAS,SAAS,KAAK,IAC5D;EAAE,QAAQ;EAAQ,QAAQ;CAA2B,IACrD;EAAE,QAAQ;EAAU,QAAQ;CAAkB;CAEpD,MAAM,gBACJ,MAAM,kBAAkB,QACpB;EAAE,QAAQ;EAAQ,QAAQ;CAAoC,IAC9D;EAAE,QAAQ;EAAU,QAAQ;CAA8B;CAEhE,MAAM,iBAA2B,MAAM,gBACnC;EAAE,QAAQ;EAAQ,QAAQ;CAA4B,IACtD;EACE,QAAQ;EACR,QACE;CAEJ;CAEJ,MAAM,kBAA4B,MAAM,aAAa,SAAS,YAAY,IACtE;EAAE,QAAQ;EAAQ,QAAQ;CAAwC,IAClE;EACE,QAAQ;EACR,QACE;CAEJ;CAEJ,MAAM,iBAA2B,MAAM,aAAa,SAAS,KAAK,IAC9D;EAAE,QAAQ;EAAQ,QAAQ;CAAiC,IAC3D;EACE,QAAQ;EACR,QAAQ;CACV;CAEJ,MAAM,KACJ,MAAM,aAAa,gBAAgB,CAAC,MAAM,eACtC;EAAE,QAAQ;EAAQ,QAAQ;CAA2D,IACrF,MAAM,YACJ;EAAE,QAAQ;EAAQ,QAAQ,0BAA0B,MAAM,QAAQ,aAAa;CAAG,IAClF;EAAE,QAAQ;EAAU,QAAQ,uBAAuB,MAAM,YAAY;CAAO;CAEpF,MAAM,KACJ,MAAM,aAAa,gBAAgB,CAAC,MAAM,eACtC;EAAE,QAAQ;EAAQ,QAAQ;CAA2D,IACrF,MAAM,YACJ;EAAE,QAAQ;EAAQ,QAAQ;CAA+B,IACzD;EAAE,QAAQ;EAAU,QAAQ,qBAAqB,MAAM,YAAY;CAAa;CAExF,MAAM,UAAoC,CAAC;CAC3C,KAAK,MAAM,QAAQ,YAAY,KAAK,GAAG;EACrC,IAAI,CAAC,MAAM,YAAY,CAAC,MAAM,cAAc;GAC1C,QAAQ,QAAQ;IACd,QAAQ;IACR,QAAQ;GACV;GACA;EACF;EACA,IAAI,MAAM,eAAe,SAAS,IAAI,GAAG;GACvC,QAAQ,QAAQ;IAAE,QAAQ;IAAQ,QAAQ;GAAc;GACxD;EACF;EACA,IAAI,SAAS,wBAAwB;GACnC,QAAQ,QAAQ;IACd,QAAQ;IACR,QACE;GAGJ;GACA;EACF;EAOA,QAAQ,SALN,SAAS,cACL,MAAM,OACN,SAAS,0BACP,MAAM,YACN,UAEJ;GAAE,QAAQ;GAAU,QAAQ;EAAsC,IAClE;GAAE,QAAQ;GAAW,QAAQ;EAAqD;CACxF;CAEA,IAAI,CAAC,MAAM,kBAAkB,MAAM,aAAa,gBAAgB,MAAM,cACpE,MAAM,KAAK,4DAA4D;CACzE,IAAI,CAAC,MAAM,UAAU,MAAM,KAAK,iDAAiD;CAEjF,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;AAEA,MAAM,YAAY,MAA+B;CAC/C,EAAE;CACF,EAAE;CACF,EAAE;CACF,EAAE;CACF,EAAE;CACF,EAAE;CACF,EAAE;CACF,EAAE;CACF,GAAG,OAAO,OAAO,EAAE,OAAO;AAC5B;;AAGA,SAAgB,SAAS,GAAyB;CAChD,OAAO,SAAS,CAAC,CAAC,CAAC,MAAM,MAAM,EAAE,WAAW,MAAM;AACpD;;AAGA,SAAgB,aAAa,GAAoD;CAY/E,OAAO;EAVL,CAAC,QAAQ,EAAE,IAAI;EACf,CAAC,YAAY,EAAE,QAAQ;EACvB,CAAC,iBAAiB,EAAE,aAAa;EACjC,CAAC,kBAAkB,EAAE,cAAc;EACnC,CAAC,mBAAmB,EAAE,eAAe;EACrC,CAAC,kBAAkB,EAAE,cAAc;EACnC,CAAC,MAAM,EAAE,EAAE;EACX,CAAC,MAAM,EAAE,EAAE;EACX,GAAG,OAAO,QAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,OAAO,CAAC,UAAU,QAAQ,CAAC,CAAuB;CAElF,CAAC,CACT,QAAQ,GAAG,OAAO,EAAE,WAAW,SAAS,CAAC,CACzC,KAAK,CAAC,MAAM,QAAQ;EAAE;EAAM,QAAQ,EAAE;CAAO,EAAE;AACpD;;AAGA,SAAgB,WAAW,GAAwB;CACjD,MAAM,SAAS,MACb,EAAE,WAAW,SAAS,MAAM,EAAE,WAAW,YAAY,MAAM,EAAE,WAAW,WAAW,MAAM;CAC3F,MAAM,QAAkB,CAAC;CACzB,MAAM,KAAK,GAAG,MAAM,EAAE,IAAI,EAAE,oBAAoB,EAAE,KAAK,QAAQ;CAC/D,MAAM,KAAK,GAAG,MAAM,EAAE,QAAQ,EAAE,oBAAoB,EAAE,SAAS,QAAQ;CACvE,MAAM,KAAK,GAAG,MAAM,EAAE,aAAa,EAAE,oBAAoB,EAAE,cAAc,QAAQ;CACjF,MAAM,KAAK,GAAG,MAAM,EAAE,cAAc,EAAE,oBAAoB,EAAE,eAAe,QAAQ;CACnF,MAAM,KAAK,GAAG,MAAM,EAAE,eAAe,EAAE,oBAAoB,EAAE,gBAAgB,QAAQ;CACrF,MAAM,KAAK,GAAG,MAAM,EAAE,cAAc,EAAE,oBAAoB,EAAE,eAAe,QAAQ;CACnF,MAAM,KAAK,GAAG,MAAM,EAAE,EAAE,EAAE,oBAAoB,EAAE,GAAG,QAAQ;CAC3D,MAAM,KAAK,GAAG,MAAM,EAAE,EAAE,EAAE,oBAAoB,EAAE,GAAG,QAAQ;CAC3D,KAAK,MAAM,CAAC,MAAM,MAAM,OAAO,QAAQ,EAAE,OAAO,GAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,UAAU,OAAO,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ;CAChG,KAAK,MAAM,KAAK,EAAE,OAAO,MAAM,KAAK,KAAK,GAAG;CAC5C,OAAO,MAAM,KAAK,IAAI;AACxB;;AAUA,SAAgB,cAAc,SAAkC;CAC9D,MAAM,UAAU;EAAC;EAAQ;EAAU;CAAQ;CAC3C,MAAM,OAAO,QAAQ,KAAK,MAAM;EAAC,EAAE;EAAM,EAAE;EAAQ,EAAE;CAAM,CAAC;CAC5D,MAAM,YAAY,QACf,QAAQ,MAAM,EAAE,WAAW,SAAS,CAAC,CACrC,KAAK,MAAM,OAAO,EAAE,KAAK,IAAI,EAAE,QAAQ;CAC1C,OAAO,MAAM,SAAS,MAAM,SAAS;AACvC;;;;;;;AAQA,SAAgB,sBAAsB,OAA8B;CAElE,IADgB,QAAQ,MAAM,YACpB,GAAG;EACX,IAAI,CAAC,MAAM,aAAa,MAAM,cAAc,WAAW,MAAM,gBAC3D,OAAO;GACL,QAAQ;GACR,QAAQ,yCAAyC,MAAM,aAAa;EACtE;EACF,IAAI,MAAM,QAAQ,SAAS,SAAS,GAClC,OAAO;GACL,QAAQ;GACR,QACE;EACJ;EACF,OAAO;GAAE,QAAQ;GAAQ,QAAQ;EAA0C;CAC7E;CACA,IAAI,CAAC,MAAM,QAAQ,SAAS,SAAS,GACnC,OAAO;EACL,QAAQ;EACR,QACE;CACJ;CACF,OAAO;EAAE,QAAQ;EAAQ,QAAQ;CAAyC;AAC5E;;;;;;;;;;;;;;;ACxPA,MAAM,OAAO,UAAU,QAAQ;;AAW/B,MAAa,WAAqB,OAAO,KAAK,SAAS;CACrD,IAAI;EACF,MAAM,EAAE,WAAW,MAAM,KAAK,KAAK,MAAM,EAAE,WAAW,SAAiB,CAAC;EACxE,OAAO;GAAE,IAAI;GAAM;EAAO;CAC5B,SAAS,KAAK;EACZ,MAAM,IAAI;EACV,OAAO;GACL,IAAI;GACJ,QAAQ,EAAE,UAAU;GACpB,SAAS,EAAE,UAAU,EAAE,WAAW;EACpC;CACF;AACF;;AAGA,eAAsB,eACpB,WAAqB,UAC6B;CAClD,MAAM,MAAM,MAAM,SAAS,OAAO,CAAC,YAAY,QAAQ,CAAC;CACxD,IAAI,CAAC,IAAI,IAAI,OAAO,EAAE,QAAQ,MAAM;CACpC,MAAM,YAAY,qBAAqB,KAAK,IAAI,MAAM,CAAC,GAAG;CAC1D,OAAO;EAAE,QAAQ;EAAM,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;CAAG;AAC7D;;;;;;;;;AAUA,eAAsB,OACpB,MACA,WAAqB,UACQ;CAC7B,MAAM,MAAM,MAAM,SAAS,OAAO;EAAC;EAAY;EAAM;EAAQ;CAAQ,CAAC;CACtE,IAAI,CAAC,IAAI,IAAI,OAAO;CACpB,IAAI;EAEF,OADa,KAAK,MAAM,IAAI,MAClB,CAAC,CAAC,MAAM,MAAM,EAAE,SAAS,IAAI,CAAC,EAAE;CAC5C,QAAQ;EACN;CACF;AACF;;AAGA,eAAsB,SACpB,MACA,WAAqB,UAC4D;CACjF,MAAM,MAAM,MAAM,SAAS,OAAO;EAAC;EAAY;EAAM;EAAU;CAAI,CAAC;CACpE,IAAI,CAAC,IAAI,IAAI,OAAO;EAAE,IAAI;EAAO,SAAS,IAAI;CAAQ;CAEtD,MAAM,KADS,qCAAqC,KAAK,IAAI,MAAM,CAAC,GAAG,MACjD,MAAM,OAAO,MAAM,QAAQ;CACjD,IAAI,CAAC,IAAI,OAAO;EAAE,IAAI;EAAO,SAAS;CAAmD;CACzF,OAAO;EAAE,IAAI;EAAM;CAAG;AACxB;AAEA,eAAsB,aAAa,MAAc,WAAqB,UAA4B;CAChG,MAAM,MAAM,MAAM,SAAS,OAAO;EAAC;EAAY;EAAM;EAAU;CAAM,CAAC;CACtE,IAAI,CAAC,IAAI,IAAI,OAAO;CACpB,OAAO,IAAI,OAAO,YAAY,KAAK,QAAQ,GAAG,CAAC,CAAC,KAAK,IAAI,MAAM;AACjE;AAEA,eAAsB,eACpB,MACA,WAAqB,UACmC;CACxD,MAAM,MAAM,MAAM,SAAS,OAAO;EAAC;EAAY;EAAM;EAAU;EAAU;CAAI,CAAC;CAC9E,OAAO,IAAI,KAAK,EAAE,IAAI,KAAK,IAAI;EAAE,IAAI;EAAO,SAAS,IAAI;CAAQ;AACnE;;;;AClFA,eAAsB,SAAS,WAAqB,UAA4B;CAC9E,QAAQ,MAAM,SAAS,MAAM,CAAC,QAAQ,QAAQ,CAAC,EAAC,CAAE;AACpD;AAEA,eAAsB,aAAa,WAAqB,UAAuC;CAC7F,MAAM,MAAM,MAAM,SAAS,OAAO;EAAC;EAAU;EAAW;CAAQ,CAAC;CACjE,OAAO,IAAI,KAAK,IAAI,OAAO,KAAK,IAAI;AACtC;AAEA,eAAsB,QAAQ,WAAqB,UAAuC;CACxF,MAAM,MAAM,MAAM,SAAS,MAAM;EAAC;EAAQ;EAAQ;EAAU;CAAe,CAAC;CAC5E,IAAI,CAAC,IAAI,IAAI,OAAO;CACpB,IAAI;EACF,OAAQ,KAAK,MAAM,IAAI,MAAM,CAAC,CAA+B;CAC/D,QAAQ;EACN;CACF;AACF;AAEA,eAAsB,SAAS,WAAqB,UAA6B;CAC/E,MAAM,MAAM,MAAM,SAAS,OAAO;EAAC;EAAU;EAAU;CAA2B,CAAC;CACnF,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC;CACrB,OAAO,IAAI,OACR,MAAM,IAAI,CAAC,CACX,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC,CACpB,OAAO,OAAO;AACnB;AAEA,eAAsB,cACpB,KACA,WAAqB,UACQ;CAC7B,MAAM,MAAM,MAAM,SAAS,MAAM;EAAC;EAAQ;EAAQ;EAAK;EAAU;CAAkB,CAAC;CACpF,IAAI,CAAC,IAAI,IAAI,OAAO;CACpB,IAAI;EACF,OAAQ,KAAK,MAAM,IAAI,MAAM,CAAC,CAA6C,kBACvE;CACN,QAAQ;EACN;CACF;AACF;AAEA,eAAsB,cAAc,KAAa,WAAqB,UAA4B;CAChG,QAAQ,MAAM,SAAS,MAAM,CAAC,OAAO,SAAS,IAAI,0BAA0B,CAAC,EAAC,CAAE;AAClF;AAEA,eAAsB,aAAa,KAAa,WAAqB,UAA6B;CAChG,MAAM,MAAM,MAAM,SAAS,MAAM,CAAC,OAAO,SAAS,IAAI,cAAc,CAAC;CACrE,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC;CACrB,IAAI;EACF,QACG,KAAK,MAAM,IAAI,MAAM,CAAC,CAA2C,gBAAgB,CAAC,EAAC,CACpF,KAAK,MAAM,EAAE,IAAI;CACrB,QAAQ;EACN,OAAO,CAAC;CACV;AACF;AAEA,eAAsB,eACpB,KACA,WAAqB,UACF;CACnB,MAAM,MAAM,MAAM,SAAS,MAAM,CAAC,OAAO,SAAS,IAAI,iBAAiB,CAAC;CACxE,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC;CACrB,IAAI;EACF,QAAS,KAAK,MAAM,IAAI,MAAM,CAAC,CAAsC,WAAW,CAAC,EAAC,CAAE,KACjF,MAAM,EAAE,IACX;CACF,QAAQ;EACN,OAAO,CAAC;CACV;AACF;AAIA,eAAsB,WACpB,MACA,YACA,WAAqB,UACmC;CACxD,MAAM,MAAM,MAAM,SAAS,MAAM;EAC/B;EACA;EACA;EACA,KAAK;EACL;EACA;CACF,CAAC;CACD,OAAO,IAAI,KAAK,EAAE,IAAI,KAAK,IAAI;EAAE,IAAI;EAAO,SAAS,IAAI;CAAQ;AACnE;AAEA,eAAsB,aACpB,WAAqB,UACmC;CACxD,MAAM,MAAM,MAAM,SAAS,OAAO;EAAC;EAAQ;EAAM;EAAU;EAAQ;CAAK,CAAC;CACzE,OAAO,IAAI,KAAK,EAAE,IAAI,KAAK,IAAI;EAAE,IAAI;EAAO,SAAS,IAAI;CAAQ;AACnE;AAEA,eAAsB,iBACpB,KACA,QACA,WAAqB,UACmC;CACxD,MAAM,MAAM,MAAM,SAAS,MAAM;EAAC;EAAQ;EAAQ;EAAK,oBAAoB;CAAQ,CAAC;CACpF,OAAO,IAAI,KAAK,EAAE,IAAI,KAAK,IAAI;EAAE,IAAI;EAAO,SAAS,IAAI;CAAQ;AACnE;;;;;;;;;AAUA,eAAsB,YACpB,KACA,WAAqB,UACmC;CACxD,MAAM,MAAM,MAAM,SAAS,MAAM;EAC/B;EACA;EACA;EACA,SAAS,IAAI;EACb;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,OAAO,IAAI,KAAK,EAAE,IAAI,KAAK,IAAI;EAAE,IAAI;EAAO,SAAS,IAAI;CAAQ;AACnE;;;AAIA,eAAsB,qBACpB,KACA,WAAqB,UACF;CACnB,MAAM,MAAM,MAAM,SAAS,MAAM,CAAC,OAAO,SAAS,IAAI,gCAAgC,CAAC;CACvF,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC;CACrB,IAAI;EACF,OAAQ,KAAK,MAAM,IAAI,MAAM,CAAC,CAAsB,KAAK,MAAM,EAAE,EAAE;CACrE,QAAQ;EACN,OAAO,CAAC;CACV;AACF;;AAGA,eAAsB,sBACpB,KACA,iBACA,WAAqB,UACmC;CACxD,MAAM,MAAM,MAAM,SAAS,MAAM;EAC/B;EACA;EACA;EACA,SAAS,IAAI;EACb;EACA;EACA;EACA;EACA,GAAG,gBAAgB,SAAS,OAAO;GACjC;GACA,mBAAmB;GACnB;GACA;EACF,CAAC;CACH,CAAC;CACD,OAAO,IAAI,KAAK,EAAE,IAAI,KAAK,IAAI;EAAE,IAAI;EAAO,SAAS,IAAI;CAAQ;AACnE;;AAGA,eAAsB,qBACpB,KACA,WAAqB,UACmC;CACxD,MAAM,MAAM,MAAM,SAAS,MAAM;EAAC;EAAO;EAAY;EAAO,SAAS,IAAI;CAAkB,CAAC;CAC5F,OAAO,IAAI,KAAK,EAAE,IAAI,KAAK,IAAI;EAAE,IAAI;EAAO,SAAS,IAAI;CAAQ;AACnE;AAEA,eAAsB,UACpB,MACA,OACA,WAAqB,UACmC;CACxD,MAAM,MAAM,MAAM,SAAS,MAAM;EAAC;EAAU;EAAO;EAAM;EAAU;CAAK,CAAC;CACzE,OAAO,IAAI,KAAK,EAAE,IAAI,KAAK,IAAI;EAAE,IAAI;EAAO,SAAS,IAAI;CAAQ;AACnE"}
@@ -0,0 +1,35 @@
1
+ //#region src/tracking/identity.ts
2
+ function first(formData, ...keys) {
3
+ for (const k of keys) {
4
+ const v = formData[k]?.trim();
5
+ if (v) return v;
6
+ }
7
+ }
8
+ function identifySubmitter(formData) {
9
+ const fullNameField = first(formData, "name", "full_name", "fullName", "fullname", "your-name");
10
+ const firstName = first(formData, "first_name", "firstName", "firstname", "given_name");
11
+ const lastName = first(formData, "last_name", "lastName", "lastname", "family_name", "surname");
12
+ const email = first(formData, "email", "email_address", "emailAddress");
13
+ const phone = first(formData, "phone", "phone_number", "phoneNumber", "tel");
14
+ const company = first(formData, "company", "company_name", "organization", "business");
15
+ let derivedFirst = firstName;
16
+ let derivedLast = lastName;
17
+ if (!derivedFirst && !derivedLast && fullNameField) {
18
+ const parts = fullNameField.split(/\s+/);
19
+ derivedFirst = parts[0];
20
+ derivedLast = parts.slice(1).join(" ") || void 0;
21
+ }
22
+ const joined = [firstName, lastName].filter(Boolean).join(" ");
23
+ return {
24
+ firstName: derivedFirst,
25
+ lastName: derivedLast,
26
+ fullName: fullNameField || joined || email || "Unknown",
27
+ email,
28
+ phone,
29
+ company
30
+ };
31
+ }
32
+
33
+ //#endregion
34
+ export { identifySubmitter as t };
35
+ //# sourceMappingURL=identity-BoRddTx3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity-BoRddTx3.mjs","names":[],"sources":["../src/tracking/identity.ts"],"sourcesContent":["/**\n * Pulling a submitter's identity out of a form's fields.\n *\n * Extracted from `notify/render.ts`'s `submitterName()`, which needed only the\n * display name for a subject line. `crm/map.ts` needs the whole set — first\n * name, last name, email, phone, company — to fill a CRM record, and a form's\n * field names vary the same way `submitterName()` already accounted for\n * (`name` vs `first_name`/`last_name` vs neither). Two independent cascades\n * over the same handful of aliases is exactly the failure `render.ts`'s own\n * comment records: a downstream site had five of six forms carrying\n * `first_name`/`last_name`, and a cascade that only checked `name` read every\n * one of them as \"Unknown\". Keep this the one place that knows the aliases;\n * `submitterName()` and `crm/map.ts` both delegate to it.\n */\n\nexport interface SubmitterIdentity {\n firstName?: string | undefined;\n lastName?: string | undefined;\n /** The best available display name — a submitted full name, first + last\n * joined, or the email address as a last resort. Never empty. */\n fullName: string;\n email?: string | undefined;\n phone?: string | undefined;\n company?: string | undefined;\n}\n\nfunction first(formData: Record<string, string>, ...keys: string[]): string | undefined {\n for (const k of keys) {\n const v = formData[k]?.trim();\n if (v) return v;\n }\n return undefined;\n}\n\nexport function identifySubmitter(formData: Record<string, string>): SubmitterIdentity {\n const fullNameField = first(formData, 'name', 'full_name', 'fullName', 'fullname', 'your-name');\n const firstName = first(formData, 'first_name', 'firstName', 'firstname', 'given_name');\n const lastName = first(formData, 'last_name', 'lastName', 'lastname', 'family_name', 'surname');\n const email = first(formData, 'email', 'email_address', 'emailAddress');\n const phone = first(formData, 'phone', 'phone_number', 'phoneNumber', 'tel');\n const company = first(formData, 'company', 'company_name', 'organization', 'business');\n\n let derivedFirst = firstName;\n let derivedLast = lastName;\n if (!derivedFirst && !derivedLast && fullNameField) {\n const parts = fullNameField.split(/\\s+/);\n derivedFirst = parts[0];\n derivedLast = parts.slice(1).join(' ') || undefined;\n }\n\n const joined = [firstName, lastName].filter(Boolean).join(' ');\n const fullName = fullNameField || joined || email || 'Unknown';\n\n return {\n firstName: derivedFirst,\n lastName: derivedLast,\n fullName,\n email,\n phone,\n company,\n };\n}\n"],"mappings":";AA0BA,SAAS,MAAM,UAAkC,GAAG,MAAoC;CACtF,KAAK,MAAM,KAAK,MAAM;EACpB,MAAM,IAAI,SAAS,EAAE,EAAE,KAAK;EAC5B,IAAI,GAAG,OAAO;CAChB;AAEF;AAEA,SAAgB,kBAAkB,UAAqD;CACrF,MAAM,gBAAgB,MAAM,UAAU,QAAQ,aAAa,YAAY,YAAY,WAAW;CAC9F,MAAM,YAAY,MAAM,UAAU,cAAc,aAAa,aAAa,YAAY;CACtF,MAAM,WAAW,MAAM,UAAU,aAAa,YAAY,YAAY,eAAe,SAAS;CAC9F,MAAM,QAAQ,MAAM,UAAU,SAAS,iBAAiB,cAAc;CACtE,MAAM,QAAQ,MAAM,UAAU,SAAS,gBAAgB,eAAe,KAAK;CAC3E,MAAM,UAAU,MAAM,UAAU,WAAW,gBAAgB,gBAAgB,UAAU;CAErF,IAAI,eAAe;CACnB,IAAI,cAAc;CAClB,IAAI,CAAC,gBAAgB,CAAC,eAAe,eAAe;EAClD,MAAM,QAAQ,cAAc,MAAM,KAAK;EACvC,eAAe,MAAM;EACrB,cAAc,MAAM,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,KAAK;CAC5C;CAEA,MAAM,SAAS,CAAC,WAAW,QAAQ,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAG7D,OAAO;EACL,WAAW;EACX,UAAU;EACV,UALe,iBAAiB,UAAU,SAAS;EAMnD;EACA;EACA;CACF;AACF"}
package/dist/index.d.mts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { FaviconLink, FaviconOptions, FaviconTagOptions, WebManifestOptions, faviconLinks, faviconManifest, generateFavicons, writeFaviconManifest } from "./favicon.mjs";
2
2
  import { DefaultTreeAdapterTypes } from "parse5";
3
-
4
3
  //#region src/content.d.ts
5
4
  /**
6
5
  * Framework-agnostic content-model types, guards, i18n, and part-attr resolution.
@@ -62,35 +61,35 @@ type ContentNode = string | {
62
61
  text?: Localizable;
63
62
  children?: ContentNode[];
64
63
  };
65
- declare function isElmnt<T, Tag extends string = 'div'>(item: any): item is Elmnt<T, Tag>;
66
- declare function isLink(item: any): item is Link;
67
- declare function isTextLink(item: any): item is TextLink;
68
- declare function isImageLink(item: any): item is ImageLink;
64
+ export declare function isElmnt<T, Tag extends string = 'div'>(item: any): item is Elmnt<T, Tag>;
65
+ export declare function isLink(item: any): item is Link;
66
+ export declare function isTextLink(item: any): item is TextLink;
67
+ export declare function isImageLink(item: any): item is ImageLink;
69
68
  /**
70
69
  * Resolve a Localizable value to a string for the given locale. A plain string
71
70
  * is returned as-is; a locale map returns the best match (locale → default → '').
72
71
  */
73
- declare function t(value: Localizable | undefined, locale: string, defaultLocale: string): string;
72
+ export declare function t(value: Localizable | undefined, locale: string, defaultLocale: string): string;
74
73
  /**
75
74
  * Resolve per-part attrs from a presentation-type config. For the `root` part,
76
75
  * merges legacy `attrs` with `parts.root` (backward compat).
77
76
  */
78
- declare function partAttrs(present: {
77
+ export declare function partAttrs(present: {
79
78
  attrs?: Attrs;
80
79
  parts?: Record<string, Attrs>;
81
80
  } | undefined, part: string): Attrs;
82
81
  //#endregion
83
82
  //#region src/html.d.ts
84
83
  type ChildNode = DefaultTreeAdapterTypes.ChildNode;
85
- declare function parseRenderedSlots(html: string): ChildNode[];
86
- declare function getAttribute(node: ChildNode, attrName: string): string | null;
87
- declare function serialize(nodes: ChildNode | ChildNode[]): string[];
84
+ export declare function parseRenderedSlots(html: string): ChildNode[];
85
+ export declare function getAttribute(node: ChildNode, attrName: string): string | null;
86
+ export declare function serialize(nodes: ChildNode | ChildNode[]): string[];
88
87
  /** Style value types that can be combined (camelCase or --custom-prop keys). */
89
88
  type StyleObject = Record<string, string | number | null | undefined>;
90
89
  type StyleValue = string | StyleObject | null | undefined;
91
90
  type StyleList = StyleValue | StyleValue[];
92
91
  /** Combine multiple style formats into one CSS string (like `class:list` for styles). */
93
- declare function styleList(...styles: StyleList[]): string;
92
+ export declare function styleList(...styles: StyleList[]): string;
94
93
  /** Element descriptor: a tag name, text content, and optional attributes. */
95
94
  interface El<Tag extends string = string> {
96
95
  text: string;
@@ -98,9 +97,9 @@ interface El<Tag extends string = string> {
98
97
  attributes?: Record<string, unknown>;
99
98
  }
100
99
  /** Normalize a string or `El` object into an HTML string (for `set:html`). */
101
- declare function toHtml<Tag extends string>(content: string | El<Tag>): string;
100
+ export declare function toHtml<Tag extends string>(content: string | El<Tag>): string;
102
101
  /** Render an array of `ContentNode`s to an HTML string. */
103
- declare function nodesToHtml(nodes: ContentNode[], resolveText?: (value: Localizable) => string): string;
102
+ export declare function nodesToHtml(nodes: ContentNode[], resolveText?: (value: Localizable) => string): string;
104
103
  //#endregion
105
104
  //#region src/icons.d.ts
106
105
  /**
@@ -124,7 +123,7 @@ declare function nodesToHtml(nodes: ContentNode[], resolveText?: (value: Localiz
124
123
  * FA7 variants (fa7-solid, fa7-regular, etc.) all share the same icon names
125
124
  * and map to the 'fa7' key. Other sets map to themselves.
126
125
  */
127
- declare const prefixToMapKey: Record<string, string>;
126
+ export declare const prefixToMapKey: Record<string, string>;
128
127
  /**
129
128
  * Sets whose weights are a name SUFFIX inside one collection rather than
130
129
  * separate prefixed collections. Phosphor is the case that forced this:
@@ -134,8 +133,8 @@ declare const prefixToMapKey: Record<string, string>;
134
133
  *
135
134
  * The first entry is the unsuffixed default — asking for it adds nothing.
136
135
  */
137
- declare const WEIGHTED_SETS: Record<string, readonly string[]>;
138
- declare const iconMap: {
136
+ export declare const WEIGHTED_SETS: Record<string, readonly string[]>;
137
+ export declare const iconMap: {
139
138
  readonly fa7: {
140
139
  readonly menu: "bars";
141
140
  readonly close: "xmark";
@@ -590,7 +589,7 @@ type BrandIcon = keyof (typeof iconMap)['simple-icons'];
590
589
  * sets that aren't suffix-weighted; an unknown weight throws rather than silently
591
590
  * resolving to the regular glyph, which would be indistinguishable from a typo.
592
591
  */
593
- declare function resolveIcon(name: string, prefix: string, opts?: {
592
+ export declare function resolveIcon(name: string, prefix: string, opts?: {
594
593
  weight?: string;
595
594
  }): string;
596
595
  /**
@@ -600,7 +599,7 @@ declare function resolveIcon(name: string, prefix: string, opts?: {
600
599
  * @param name - Semantic brand name ('facebook') or fully-qualified ('simple-icons:facebook')
601
600
  * @param prefix - astro-icon prefix, e.g. 'simple-icons', 'fa7-brands'
602
601
  */
603
- declare function resolveBrandIcon(name: string, prefix: string): string;
602
+ export declare function resolveBrandIcon(name: string, prefix: string): string;
604
603
  /**
605
604
  * Generate the astro-icon `include` map from configured icon sets.
606
605
  *
@@ -614,7 +613,7 @@ declare function resolveBrandIcon(name: string, prefix: string): string;
614
613
  * @param iconsConfig - Icons config from site.config.yaml (icons section)
615
614
  * @returns Record<string, string[]> for astro-icon's `include` option
616
615
  */
617
- declare function generateIconInclude(iconsConfig?: {
616
+ export declare function generateIconInclude(iconsConfig?: {
618
617
  ui?: string;
619
618
  brand?: string;
620
619
  weight?: string;
@@ -638,16 +637,16 @@ interface ScanOptions {
638
637
  * Extensions worth scanning: every template language the framework's classes
639
638
  * and icon names can appear in, plus the markdown that can embed them.
640
639
  */
641
- declare const SCAN_EXT: ReadonlySet<string>;
640
+ export declare const SCAN_EXT: ReadonlySet<string>;
642
641
  /** Directories that only ever hold dependencies or build output. */
643
- declare const SCAN_SKIP: ReadonlySet<string>;
642
+ export declare const SCAN_SKIP: ReadonlySet<string>;
644
643
  /**
645
644
  * Recursively read every scannable file under `dir`.
646
645
  *
647
646
  * Dotfiles and dot-directories are skipped wholesale — they hold tooling config,
648
647
  * not templates, and `.astro`/`.git` would otherwise be walked twice over.
649
648
  */
650
- declare function scanFiles(dir: string, opts?: ScanOptions): SourceFile[];
649
+ export declare function scanFiles(dir: string, opts?: ScanOptions): SourceFile[];
651
650
  //#endregion
652
651
  //#region src/icons-scan.d.ts
653
652
  /**
@@ -693,15 +692,15 @@ interface IconScanOptions {
693
692
  props?: string[];
694
693
  }
695
694
  /** Extract every icon reference from one file's text. */
696
- declare function extractIconRefs(src: string, file?: string, opts?: IconScanOptions): {
695
+ export declare function extractIconRefs(src: string, file?: string, opts?: IconScanOptions): {
697
696
  refs: IconRef[];
698
697
  dynamic: DynamicIconRef[];
699
698
  };
700
699
  /** Run `extractIconRefs` across a file set and collect unique names. */
701
- declare function collectIconRefs(files: readonly {
700
+ export declare function collectIconRefs(files: readonly {
702
701
  path: string;
703
702
  text: string;
704
703
  }[], opts?: IconScanOptions): IconScanResult;
705
704
  //#endregion
706
- export { type Attrs, type BrandIcon, type ChildNode, type ContentNode, type DynamicIconRef, type El, type Elmnt, type FaviconLink, type FaviconOptions, type FaviconTagOptions, type IconRef, type IconRefKind, type IconScanOptions, type IconScanResult, type IconSet, type ImageLink, type ImageRef, type Link, type Localizable, SCAN_EXT, SCAN_SKIP, type ScanOptions, type SemanticIcon, type SourceFile, type StyleList, type StyleValue, type TextLink, WEIGHTED_SETS, type WebManifestOptions, collectIconRefs, extractIconRefs, faviconLinks, faviconManifest, generateFavicons, generateIconInclude, getAttribute, iconMap, isElmnt, isImageLink, isLink, isTextLink, nodesToHtml, parseRenderedSlots, partAttrs, prefixToMapKey, resolveBrandIcon, resolveIcon, scanFiles, serialize, styleList, t, toHtml, writeFaviconManifest };
705
+ export { type Attrs, type BrandIcon, type ChildNode, type ContentNode, type DynamicIconRef, type El, type Elmnt, type FaviconLink, type FaviconOptions, type FaviconTagOptions, type IconRef, type IconRefKind, type IconScanOptions, type IconScanResult, type IconSet, type ImageLink, type ImageRef, type Link, type Localizable, type ScanOptions, type SemanticIcon, type SourceFile, type StyleList, type StyleValue, type TextLink, type WebManifestOptions, faviconLinks, faviconManifest, generateFavicons, writeFaviconManifest };
707
706
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/content.ts","../src/html.ts","../src/icons.ts","../src/scan.ts","../src/icons-scan.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/content.ts","../src/html.ts","../src/icons.ts","../src/scan.ts","../src/icons-scan.ts"],"mappings":";;;;;;;;;;;KAWY,uBAAuB;;;;;UAMlB;EACf;GACC;;;UAIc;EACf;EACA,MAAM;GACL;;;UAIc;EACf,OAAO;EACP;EACA,QAAQ;GACP;;;UAIc;EACf,OAAO;EACP;EACA,QAAQ;GACP;;;KAIS,OAAO,WAAW;;;;;UAMb,MAAM,aAAa;EAClC;EACA,MAAM;EACN,QAAQ;EACR,UAAU;GACT;;;;;;KAOS;EAGN;EACA,QAAQ;EACR,OAAO;EACP,WAAW;;wBAKD,QAAQ,GAAG,4BAA4B,YAAY,QAAQ,MAAM,GAAG;wBAIpE,OAAO,YAAY,QAAQ;wBAI3B,WAAW,YAAY,QAAQ;wBAI/B,YAAY,YAAY,QAAQ;;;;;wBAUhC,EAAE,OAAO,yBAAyB,gBAAgB;;;;;wBAYlD,UACd;EAAW,QAAQ;EAAO,QAAQ,eAAe;eACjD,eACC;;;KCxGS,YAAY,wBAAwB;wBAEhC,mBAAmB,eAAe;wBAIlC,aAAa,MAAM,WAAW;wBAQ9B,UAAU,OAAO,YAAY;;KAOxC,cAAc;KACP,sBAAsB;KACtB,YAAY,aAAa;;wBAerB,aAAa,QAAQ;;UAmBpB,GAAG;EAClB;EACA,KAAK;EACL,aAAa;;;wBA4BC,OAAO,oBAAoB,kBAAkB,GAAG;;wBAkDhD,YACd,OAAO,eACP,eAAc,OAAO;;;;;;;;;;;;;;;;;;;;;;;;qBC9HV,gBAAgB;;;;;;;;;;qBAqBhB,eAAe;qBAIf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAgiBD,uBAAuB;KACvB,6BAA6B;KAC7B,0BAA0B;;;;;;;;;;;;wBAatB,YAAY,cAAc,gBAAgB;EAAS;;;;;;;;;wBAiCnD,iBAAiB,cAAc;;;;;;;;;;;;;;wBAwB/B,oBAAoB;EAClC;EACA;EACA;EACA;GACC;IACC;;;;UC5oBa;EACf;EACA;;UAGe;;EAEf,OAAO;;EAEP,WAAW;;;;;;qBAOA,UAAU;;qBAgBV,WAAW;;;;;;;wBAeR,UAAU,aAAa,OAAO,cAAc;;;;;;;;;;;;;;;;;;;KC/ChD;;UAGK;EACf;EACA,MAAM;EACN;EACA;EACA;;;UAIe;EACf;EACA;EACA;EACA;;UAGe;EACf,MAAM;EACN,SAAS;;EAET;;UAGe;;EAEf;;;wBAmEc,gBACd,aACA,eACA,OAAO;EACJ,MAAM;EAAW,SAAS;;;wBA2Cf,gBACd;EAAkB;EAAc;KAChC,OAAO,kBACN"}
package/dist/index.mjs CHANGED
@@ -115,7 +115,7 @@ function toHtml(content) {
115
115
  const t = String(tag);
116
116
  return attrStr ? `<${t} ${attrStr}>${text}</${t}>` : `<${t}>${text}</${t}>`;
117
117
  }
118
- const VOID_ELEMENTS = new Set([
118
+ const VOID_ELEMENTS = /* @__PURE__ */ new Set([
119
119
  "area",
120
120
  "base",
121
121
  "br",
@@ -706,7 +706,7 @@ function generateIconInclude(iconsConfig) {
706
706
  const brandPrefix = iconsConfig?.brand ?? "simple-icons";
707
707
  const include = {};
708
708
  const addToInclude = (prefix, names) => {
709
- include[prefix] = [...new Set([...include[prefix] ?? [], ...names])];
709
+ include[prefix] = [.../* @__PURE__ */ new Set([...include[prefix] ?? [], ...names])];
710
710
  };
711
711
  for (const [key, val] of Object.entries(iconsConfig ?? {})) if (key !== "ui" && key !== "brand" && key !== "weight" && key !== "semantic" && Array.isArray(val)) addToInclude(key, val);
712
712
  const uiMapKey = prefixToMapKey[uiPrefix];
@@ -746,7 +746,7 @@ function generateIconInclude(iconsConfig) {
746
746
  * Extensions worth scanning: every template language the framework's classes
747
747
  * and icon names can appear in, plus the markdown that can embed them.
748
748
  */
749
- const SCAN_EXT = new Set([
749
+ const SCAN_EXT = /* @__PURE__ */ new Set([
750
750
  ".astro",
751
751
  ".html",
752
752
  ".htm",
@@ -761,7 +761,7 @@ const SCAN_EXT = new Set([
761
761
  ".mdx"
762
762
  ]);
763
763
  /** Directories that only ever hold dependencies or build output. */
764
- const SCAN_SKIP = new Set([
764
+ const SCAN_SKIP = /* @__PURE__ */ new Set([
765
765
  "node_modules",
766
766
  "dist",
767
767
  ".git",
@@ -854,7 +854,7 @@ function readValue(groups) {
854
854
  }
855
855
  /** Extract every icon reference from one file's text. */
856
856
  function extractIconRefs(src, file = "<source>", opts) {
857
- const props = [...new Set([...DEFAULT_PROPS, ...opts?.props ?? []])];
857
+ const props = [.../* @__PURE__ */ new Set([...DEFAULT_PROPS, ...opts?.props ?? []])];
858
858
  const refs = [];
859
859
  const dynamic = [];
860
860
  const NAME = nameAttr();