@woodsportal/hubspot-kit 1.0.30 → 1.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/chunk-4GOJPOW3.js +258 -0
- package/dist/chunk-4GOJPOW3.js.map +1 -0
- package/dist/cli.js +546 -240
- package/dist/cli.js.map +1 -1
- package/dist/{exec-U2OJATR3.js → exec-VY6BGWF3.js} +6 -2
- package/examples/greenfield/module-hybrid-cdn/public/fields.json +7 -2
- package/examples/greenfield/module-hybrid-cdn/public/module.html +22 -0
- package/examples/greenfield/module-hybrid-cdn/src/cdn/app-entry.ts +5 -0
- package/examples/greenfield/module-hybrid-cdn/src/portal/api-endpoint.ts +11 -0
- package/examples/greenfield/module-hybrid-cdn/vite.config.cdn-app.mjs +1 -0
- package/examples/greenfield/module-hybrid-cdn/vite.config.cdn-esm.mjs +1 -0
- package/examples/greenfield/module-hybrid-cdn/vite.config.cdn-vendor.mjs +1 -0
- package/package.json +1 -1
- package/scripts/build-cdn.mjs +11 -7
- package/scripts/hubspot-module-postbuild.mjs +10 -6
- package/scripts/portal-subprocess-stdio.mjs +38 -0
- package/scripts/publish-cdn-github.mjs +20 -2
- package/scripts/resolve-vite-config.mjs +26 -0
- package/scripts/run-hubspot-module-postbuild.mjs +4 -1
- package/scripts/run-vite-build.mjs +13 -5
- package/templates/module-hybrid-cdn/public/fields.json +7 -2
- package/templates/module-hybrid-cdn/public/module.html +22 -0
- package/templates/module-hybrid-cdn/src/cdn/app-entry.ts +5 -0
- package/templates/module-hybrid-cdn/src/portal/api-endpoint.ts +11 -0
- package/templates/module-hybrid-cdn/vite.config.cdn-app.mjs +1 -0
- package/templates/module-hybrid-cdn/vite.config.cdn-esm.mjs +1 -0
- package/templates/module-hybrid-cdn/vite.config.cdn-vendor.mjs +1 -0
- package/vite/vite.config.hubspot.mjs +8 -2
- package/dist/chunk-GTTIJVAR.js +0 -127
- package/dist/chunk-GTTIJVAR.js.map +0 -1
- /package/dist/{exec-U2OJATR3.js.map → exec-VY6BGWF3.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -4,9 +4,11 @@ import {
|
|
|
4
4
|
WpHsError,
|
|
5
5
|
isWpHsError,
|
|
6
6
|
runCommand,
|
|
7
|
+
runCommandAsync,
|
|
7
8
|
runNodeScript,
|
|
9
|
+
runNodeScriptAsync,
|
|
8
10
|
runNodeScriptLongRunning
|
|
9
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-4GOJPOW3.js";
|
|
10
12
|
|
|
11
13
|
// src/cli/program.ts
|
|
12
14
|
import { readFileSync as readFileSync15 } from "fs";
|
|
@@ -248,34 +250,41 @@ import pc from "picocolors";
|
|
|
248
250
|
function shouldUseColor() {
|
|
249
251
|
if (process.env.NO_COLOR !== void 0) return false;
|
|
250
252
|
if (process.env.CI === "true") return false;
|
|
251
|
-
return process.
|
|
253
|
+
return process.stderr.isTTY === true;
|
|
252
254
|
}
|
|
253
255
|
function createLogger(options = {}) {
|
|
254
256
|
const useColor = shouldUseColor();
|
|
255
257
|
const { verbose = false, quiet = false, json = false } = options;
|
|
256
|
-
const
|
|
258
|
+
const write = (line) => {
|
|
259
|
+
process.stderr.write(`${line}
|
|
260
|
+
`);
|
|
261
|
+
};
|
|
262
|
+
const emit = (level, message) => {
|
|
257
263
|
if (json) return;
|
|
258
264
|
if (quiet && level !== "error" && level !== "warn") return;
|
|
259
265
|
if (level === "debug" && !verbose) return;
|
|
260
266
|
const prefix = level === "error" ? useColor ? pc.red("error") : "error" : level === "warn" ? useColor ? pc.yellow("warn") : "warn" : level === "debug" ? useColor ? pc.dim("debug") : "debug" : useColor ? pc.cyan("info") : "info";
|
|
261
|
-
|
|
262
|
-
const stream = level === "error" || level === "warn" ? process.stderr : process.stdout;
|
|
263
|
-
stream.write(`[${prefix}] ${line}
|
|
264
|
-
`);
|
|
267
|
+
write(`[${prefix}] ${message}`);
|
|
265
268
|
};
|
|
266
269
|
return {
|
|
267
|
-
debug: (message
|
|
268
|
-
info: (message
|
|
269
|
-
warn: (message
|
|
270
|
-
error: (message
|
|
271
|
-
success: (message
|
|
272
|
-
if (json) return;
|
|
273
|
-
if (quiet) return;
|
|
270
|
+
debug: (message) => emit("debug", message),
|
|
271
|
+
info: (message) => emit("info", message),
|
|
272
|
+
warn: (message) => emit("warn", message),
|
|
273
|
+
error: (message) => emit("error", message),
|
|
274
|
+
success: (message) => {
|
|
275
|
+
if (json || quiet) return;
|
|
274
276
|
const prefix = useColor ? pc.green("ok") : "ok";
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
277
|
+
write(`[${prefix}] ${message}`);
|
|
278
|
+
},
|
|
279
|
+
step: (message) => {
|
|
280
|
+
if (json || quiet) return;
|
|
281
|
+
const bullet = useColor ? pc.cyan("\u2192") : "\u2192";
|
|
282
|
+
write(`${bullet} ${message}`);
|
|
283
|
+
},
|
|
284
|
+
stepDone: (message) => {
|
|
285
|
+
if (json || quiet) return;
|
|
286
|
+
const mark = useColor ? pc.green("\u2713") : "\u2713";
|
|
287
|
+
write(` ${mark} ${message}`);
|
|
279
288
|
},
|
|
280
289
|
json: (payload) => {
|
|
281
290
|
if (!json) return;
|
|
@@ -305,16 +314,73 @@ function isInteractiveCli(ctx) {
|
|
|
305
314
|
}
|
|
306
315
|
function shouldShowProgress(ctx, override) {
|
|
307
316
|
if (override === false) return false;
|
|
317
|
+
if (ctx.global.verbose) return false;
|
|
308
318
|
return isInteractiveCli(ctx);
|
|
309
319
|
}
|
|
310
|
-
|
|
320
|
+
function isVerboseStepLog(ctx) {
|
|
321
|
+
return ctx.global.verbose === true && !ctx.global.quiet && !ctx.global.json;
|
|
322
|
+
}
|
|
323
|
+
async function yieldForSpinnerPaint() {
|
|
324
|
+
await new Promise((resolve24) => {
|
|
325
|
+
setImmediate(resolve24);
|
|
326
|
+
});
|
|
327
|
+
await new Promise((resolve24) => {
|
|
328
|
+
setTimeout(resolve24, 48);
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
async function runCliTasks(ctx, tasks, options = {}) {
|
|
311
332
|
if (!shouldShowProgress(ctx, options.progress)) {
|
|
312
|
-
|
|
313
|
-
|
|
333
|
+
const verbose = isVerboseStepLog(ctx);
|
|
334
|
+
if (verbose && options.intro) {
|
|
335
|
+
ctx.logger.info(options.intro);
|
|
314
336
|
}
|
|
337
|
+
for (const step of tasks) {
|
|
338
|
+
if (verbose) {
|
|
339
|
+
ctx.logger.step(step.title);
|
|
340
|
+
}
|
|
341
|
+
try {
|
|
342
|
+
await step.task();
|
|
343
|
+
if (verbose) {
|
|
344
|
+
ctx.logger.stepDone(step.title);
|
|
345
|
+
}
|
|
346
|
+
} catch (error) {
|
|
347
|
+
if (verbose) {
|
|
348
|
+
ctx.logger.error(step.title);
|
|
349
|
+
}
|
|
350
|
+
throw error;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
if (tasks.length === 0) {
|
|
315
356
|
return;
|
|
316
357
|
}
|
|
317
|
-
|
|
358
|
+
const spinner2 = p.spinner();
|
|
359
|
+
const firstTitle = tasks[0].title;
|
|
360
|
+
spinner2.start(options.intro ?? firstTitle);
|
|
361
|
+
await yieldForSpinnerPaint();
|
|
362
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
363
|
+
const step = tasks[i];
|
|
364
|
+
if (i > 0) {
|
|
365
|
+
spinner2.start(step.title);
|
|
366
|
+
await yieldForSpinnerPaint();
|
|
367
|
+
} else if (options.intro) {
|
|
368
|
+
spinner2.message(firstTitle);
|
|
369
|
+
await yieldForSpinnerPaint();
|
|
370
|
+
}
|
|
371
|
+
try {
|
|
372
|
+
await step.task();
|
|
373
|
+
spinner2.stop(step.title);
|
|
374
|
+
} catch (error) {
|
|
375
|
+
spinner2.stop(pc2.red(step.title));
|
|
376
|
+
throw error;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function shouldQuietSubprocess(ctx, options = {}) {
|
|
381
|
+
if (ctx.global.verbose) return false;
|
|
382
|
+
if (options.quietSubprocess === true || options.quietVite === true) return true;
|
|
383
|
+
return shouldShowProgress(ctx, options.progress);
|
|
318
384
|
}
|
|
319
385
|
function printCommandDone(ctx, message) {
|
|
320
386
|
if (isInteractiveCli(ctx)) {
|
|
@@ -533,6 +599,91 @@ function templateDevDependencies() {
|
|
|
533
599
|
};
|
|
534
600
|
}
|
|
535
601
|
|
|
602
|
+
// src/lib/hubspot-fields-json.ts
|
|
603
|
+
var HUBSPOT_MODULE_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
604
|
+
"boolean",
|
|
605
|
+
"choice",
|
|
606
|
+
"color",
|
|
607
|
+
"cta",
|
|
608
|
+
"date",
|
|
609
|
+
"datetime",
|
|
610
|
+
"email",
|
|
611
|
+
"embed",
|
|
612
|
+
"file",
|
|
613
|
+
"followup_email",
|
|
614
|
+
"font",
|
|
615
|
+
"form",
|
|
616
|
+
"group",
|
|
617
|
+
"html",
|
|
618
|
+
"hubdb_row",
|
|
619
|
+
"hubdb_table",
|
|
620
|
+
"icon",
|
|
621
|
+
"image",
|
|
622
|
+
"link",
|
|
623
|
+
"logo",
|
|
624
|
+
"meeting",
|
|
625
|
+
"menu",
|
|
626
|
+
"number",
|
|
627
|
+
"page",
|
|
628
|
+
"payment",
|
|
629
|
+
"richtext",
|
|
630
|
+
"salesforce_campaign",
|
|
631
|
+
"simple_menu",
|
|
632
|
+
"spacing",
|
|
633
|
+
"tag",
|
|
634
|
+
"text",
|
|
635
|
+
"url",
|
|
636
|
+
"video",
|
|
637
|
+
"workflow"
|
|
638
|
+
]);
|
|
639
|
+
function isFieldRecord(value) {
|
|
640
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
641
|
+
}
|
|
642
|
+
function validateFieldNode(node, path, issues) {
|
|
643
|
+
if (!isFieldRecord(node)) {
|
|
644
|
+
issues.push({ path, message: "expected a field object" });
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
const type = node.type;
|
|
648
|
+
if (typeof type !== "string" || type.length === 0) {
|
|
649
|
+
issues.push({ path: `${path}.type`, message: "missing field type" });
|
|
650
|
+
} else if (!HUBSPOT_MODULE_FIELD_TYPES.has(type)) {
|
|
651
|
+
issues.push({
|
|
652
|
+
path: `${path}.type`,
|
|
653
|
+
message: type === "textarea" ? `'textarea' is not a HubSpot field type \u2014 use "type": "text" with "display": "textarea"` : `'${type}' is not a valid HubSpot field type`
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
if (type !== "group") {
|
|
657
|
+
const name = node.name;
|
|
658
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
659
|
+
issues.push({ path: `${path}.name`, message: "missing field name" });
|
|
660
|
+
}
|
|
661
|
+
const label = node.label;
|
|
662
|
+
if (typeof label !== "string" || label.trim().length === 0) {
|
|
663
|
+
issues.push({ path: `${path}.label`, message: "missing field label" });
|
|
664
|
+
}
|
|
665
|
+
} else {
|
|
666
|
+
const children = node.children;
|
|
667
|
+
if (!Array.isArray(children)) {
|
|
668
|
+
issues.push({ path: `${path}.children`, message: "group fields require a children array" });
|
|
669
|
+
} else {
|
|
670
|
+
children.forEach((child, index) => {
|
|
671
|
+
validateFieldNode(child, `${path}.children[${index}]`, issues);
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
function validateHubSpotFieldsJson(fields) {
|
|
677
|
+
if (!Array.isArray(fields)) {
|
|
678
|
+
return [{ path: "$", message: "fields.json must be a top-level array" }];
|
|
679
|
+
}
|
|
680
|
+
const issues = [];
|
|
681
|
+
fields.forEach((field, index) => {
|
|
682
|
+
validateFieldNode(field, `[${index}]`, issues);
|
|
683
|
+
});
|
|
684
|
+
return issues;
|
|
685
|
+
}
|
|
686
|
+
|
|
536
687
|
// src/lib/upload-only-module.ts
|
|
537
688
|
import { existsSync as existsSync4 } from "fs";
|
|
538
689
|
import { resolve as resolve5 } from "path";
|
|
@@ -656,6 +807,89 @@ function checkDevViteConfig(ctx) {
|
|
|
656
807
|
severity: "error"
|
|
657
808
|
};
|
|
658
809
|
}
|
|
810
|
+
function checkFieldsJson(ctx) {
|
|
811
|
+
if (isThemeProject(ctx.config)) return null;
|
|
812
|
+
const path = resolve6(ctx.projectRoot, "public/fields.json");
|
|
813
|
+
if (!existsSync5(path)) {
|
|
814
|
+
return {
|
|
815
|
+
name: "fields-json",
|
|
816
|
+
ok: false,
|
|
817
|
+
message: "public/fields.json missing",
|
|
818
|
+
remediation: "Copy fields.json from @woodsportal/hubspot-kit templates for your project type",
|
|
819
|
+
severity: "error"
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
try {
|
|
823
|
+
const fields = JSON.parse(readFileSync4(path, "utf8"));
|
|
824
|
+
const issues = validateHubSpotFieldsJson(fields);
|
|
825
|
+
if (issues.length === 0) {
|
|
826
|
+
return {
|
|
827
|
+
name: "fields-json",
|
|
828
|
+
ok: true,
|
|
829
|
+
message: "public/fields.json uses valid HubSpot field types",
|
|
830
|
+
severity: "error"
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
const preview = issues.slice(0, 3).map((issue) => `${issue.path}: ${issue.message}`).join("; ");
|
|
834
|
+
return {
|
|
835
|
+
name: "fields-json",
|
|
836
|
+
ok: false,
|
|
837
|
+
message: `public/fields.json has ${issues.length} issue(s) \u2014 ${preview}`,
|
|
838
|
+
remediation: 'Use HubSpot field types (e.g. "text" + "display": "textarea", not type "textarea"). See templates/module-hybrid-cdn/public/fields.json',
|
|
839
|
+
severity: "error"
|
|
840
|
+
};
|
|
841
|
+
} catch (error) {
|
|
842
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
843
|
+
return {
|
|
844
|
+
name: "fields-json",
|
|
845
|
+
ok: false,
|
|
846
|
+
message: `public/fields.json is invalid JSON \u2014 ${message}`,
|
|
847
|
+
remediation: "Fix JSON syntax in public/fields.json",
|
|
848
|
+
severity: "error"
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
function checkHybridModuleHtml(ctx) {
|
|
853
|
+
if (isThemeProject(ctx.config) || !usesCdnPipeline(ctx.config)) return null;
|
|
854
|
+
const path = resolve6(ctx.projectRoot, "public/module.html");
|
|
855
|
+
if (!existsSync5(path)) {
|
|
856
|
+
return {
|
|
857
|
+
name: "module-html",
|
|
858
|
+
ok: false,
|
|
859
|
+
message: "public/module.html missing",
|
|
860
|
+
remediation: "Copy module.html from @woodsportal/hubspot-kit templates/module-hybrid-cdn",
|
|
861
|
+
severity: "error"
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
const html = readFileSync4(path, "utf8");
|
|
865
|
+
const needs = ["__PORTAL_CDN_BASE__", "require_js", "require_css", "hubSpotData", 'id="app"'];
|
|
866
|
+
const missing = needs.filter((token) => !html.includes(token));
|
|
867
|
+
const usesUndeclaredCdnFields = /module\.portal_(cdn_base_url|vendor_script|app_script|app_css)/.test(
|
|
868
|
+
html
|
|
869
|
+
);
|
|
870
|
+
const ok = missing.length === 0 && !usesUndeclaredCdnFields;
|
|
871
|
+
return {
|
|
872
|
+
name: "module-html-hybrid",
|
|
873
|
+
ok,
|
|
874
|
+
message: ok ? "public/module.html includes CDN require_js + hubSpotData" : usesUndeclaredCdnFields ? "public/module.html references undeclared module.portal_cdn_* fields" : `public/module.html missing hybrid CDN markers: ${missing.join(", ")}`,
|
|
875
|
+
remediation: ok ? void 0 : usesUndeclaredCdnFields ? "Use __PORTAL_CDN_BASE__ placeholders in module.html (see templates/module-hybrid-cdn) \u2014 CDN URLs are injected at build time" : "Update public/module.html from templates/module-hybrid-cdn (hybrid loads app from jsDelivr)",
|
|
876
|
+
severity: "error"
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
function checkCdnViteConfigs(ctx) {
|
|
880
|
+
if (isThemeProject(ctx.config) || !usesCdnPipeline(ctx.config)) return [];
|
|
881
|
+
return ["vite.config.cdn-vendor.mjs", "vite.config.cdn-app.mjs"].map((file) => {
|
|
882
|
+
const path = resolve6(ctx.projectRoot, file);
|
|
883
|
+
const ok = existsSync5(path);
|
|
884
|
+
return {
|
|
885
|
+
name: file.replace(/\./g, "-"),
|
|
886
|
+
ok,
|
|
887
|
+
message: ok ? `${file} present` : `${file} missing`,
|
|
888
|
+
remediation: ok ? void 0 : `Add ${file} that re-exports @woodsportal/hubspot-kit/vite/${file}`,
|
|
889
|
+
severity: "error"
|
|
890
|
+
};
|
|
891
|
+
});
|
|
892
|
+
}
|
|
659
893
|
function checkDevEntry(ctx) {
|
|
660
894
|
const checks = [];
|
|
661
895
|
const indexHtml = resolve6(ctx.projectRoot, "index.html");
|
|
@@ -825,7 +1059,9 @@ async function gatherDoctorChecks(ctx) {
|
|
|
825
1059
|
if (uploadOnlyNote) {
|
|
826
1060
|
checks.push(uploadOnlyNote);
|
|
827
1061
|
} else {
|
|
828
|
-
checks.push(checkDevViteConfig(ctx), ...checkDevEntry(ctx));
|
|
1062
|
+
checks.push(checkDevViteConfig(ctx), ...checkCdnViteConfigs(ctx), ...checkDevEntry(ctx));
|
|
1063
|
+
const hybridHtml = checkHybridModuleHtml(ctx);
|
|
1064
|
+
if (hybridHtml) checks.push(hybridHtml);
|
|
829
1065
|
const viteCheck = checkViteInstalled(ctx);
|
|
830
1066
|
if (viteCheck) checks.push(viteCheck);
|
|
831
1067
|
checks.push(...checkModuleConfigUiDeps(ctx));
|
|
@@ -836,6 +1072,8 @@ async function gatherDoctorChecks(ctx) {
|
|
|
836
1072
|
title: "Checking woodscli.json and project layout",
|
|
837
1073
|
task: async () => {
|
|
838
1074
|
checks.push(...checkConfig(ctx), ...checkWphsWorkspace(ctx));
|
|
1075
|
+
const fieldsCheck = checkFieldsJson(ctx);
|
|
1076
|
+
if (fieldsCheck) checks.push(fieldsCheck);
|
|
839
1077
|
const adapterCheck = checkAdapter(ctx);
|
|
840
1078
|
if (adapterCheck) checks.push(adapterCheck);
|
|
841
1079
|
}
|
|
@@ -930,148 +1168,21 @@ async function runConfigValidate(ctx) {
|
|
|
930
1168
|
}
|
|
931
1169
|
|
|
932
1170
|
// src/cli/commands/build.ts
|
|
933
|
-
import { resolve as
|
|
934
|
-
|
|
935
|
-
// src/lib/build-tier.ts
|
|
936
|
-
var DEFAULT_BUILD_TIER = "dev";
|
|
937
|
-
function parseBuildTier(value) {
|
|
938
|
-
if (value === "dev" || value === "stg" || value === "prod") return value;
|
|
939
|
-
return DEFAULT_BUILD_TIER;
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
// src/cli/commands/build.ts
|
|
943
|
-
function tierToStgFlag(tier) {
|
|
944
|
-
return tier === "dev" || tier === "stg" ? ["--stg"] : [];
|
|
945
|
-
}
|
|
946
|
-
function buildTasks(ctx, options, run) {
|
|
947
|
-
const tier = options.tier ?? DEFAULT_BUILD_TIER;
|
|
948
|
-
const isTheme = isThemeProject(ctx.config);
|
|
949
|
-
const useCdn = usesCdnPipeline(ctx.config) && !isTheme;
|
|
950
|
-
const tasks2 = [];
|
|
951
|
-
if (isTheme && !options.cdnOnly) {
|
|
952
|
-
return tasks2;
|
|
953
|
-
}
|
|
954
|
-
if (ctx.config.projectType === "module-monolith" && !options.cdnOnly) {
|
|
955
|
-
tasks2.push({
|
|
956
|
-
title: `Building monolith module (${tier})`,
|
|
957
|
-
task: async () => {
|
|
958
|
-
run("run-vite-build.mjs", [
|
|
959
|
-
resolve7(ctx.projectRoot, "vite.config.monolith.mjs"),
|
|
960
|
-
...tierToStgFlag(tier)
|
|
961
|
-
]);
|
|
962
|
-
run("run-hubspot-module-postbuild.mjs");
|
|
963
|
-
}
|
|
964
|
-
});
|
|
965
|
-
return tasks2;
|
|
966
|
-
}
|
|
967
|
-
if (!options.hubspotOnly && useCdn) {
|
|
968
|
-
tasks2.push({
|
|
969
|
-
title: `Building CDN (${tier})`,
|
|
970
|
-
task: async () => {
|
|
971
|
-
if (options.cdnEsm) {
|
|
972
|
-
run("run-vite-build.mjs", [
|
|
973
|
-
resolve7(ctx.projectRoot, "vite.config.cdn-esm.mjs"),
|
|
974
|
-
...tierToStgFlag(tier)
|
|
975
|
-
]);
|
|
976
|
-
} else {
|
|
977
|
-
run("build-cdn.mjs", tierToStgFlag(tier));
|
|
978
|
-
}
|
|
979
|
-
run("generate-cdn-manifest.mjs");
|
|
980
|
-
}
|
|
981
|
-
});
|
|
982
|
-
}
|
|
983
|
-
if (!options.cdnOnly) {
|
|
984
|
-
tasks2.push({
|
|
985
|
-
title: `Building HubSpot module (${tier})`,
|
|
986
|
-
task: async () => {
|
|
987
|
-
run("run-vite-build.mjs", [
|
|
988
|
-
resolve7(ctx.projectRoot, "vite.config.hubspot.mjs"),
|
|
989
|
-
...tierToStgFlag(tier)
|
|
990
|
-
]);
|
|
991
|
-
run("run-hubspot-module-postbuild.mjs");
|
|
992
|
-
}
|
|
993
|
-
});
|
|
994
|
-
}
|
|
995
|
-
if (!options.cdnOnly && !options.hubspotOnly) {
|
|
996
|
-
tasks2.push({
|
|
997
|
-
title: "Running bundle checks",
|
|
998
|
-
task: async () => {
|
|
999
|
-
run("check-hubspot-bundle-size.mjs");
|
|
1000
|
-
run("write-audit-artifacts.mjs");
|
|
1001
|
-
}
|
|
1002
|
-
});
|
|
1003
|
-
}
|
|
1004
|
-
return tasks2;
|
|
1005
|
-
}
|
|
1006
|
-
async function runBuild(ctx, options) {
|
|
1007
|
-
const tier = options.tier ?? DEFAULT_BUILD_TIER;
|
|
1008
|
-
const env = { ...process.env, WP_HS_PROJECT_ROOT: ctx.projectRoot };
|
|
1009
|
-
const isTheme = isThemeProject(ctx.config);
|
|
1010
|
-
const execOpts = {
|
|
1011
|
-
cwd: ctx.projectRoot,
|
|
1012
|
-
env,
|
|
1013
|
-
logger: ctx.logger,
|
|
1014
|
-
dryRun: ctx.global.dryRun
|
|
1015
|
-
};
|
|
1016
|
-
const run = (script, args = []) => {
|
|
1017
|
-
runNodeScript(kitPath("scripts", script), args, execOpts);
|
|
1018
|
-
};
|
|
1019
|
-
try {
|
|
1020
|
-
if (isTheme && !options.cdnOnly) {
|
|
1021
|
-
if (ctx.global.json) {
|
|
1022
|
-
ctx.logger.json({ command: "build", tier, ok: true, projectType: ctx.config.projectType });
|
|
1023
|
-
} else if (!options.progress) {
|
|
1024
|
-
ctx.logger.info("Theme project \u2014 skipping CDN/module.js build (use wp upload for theme assets)");
|
|
1025
|
-
printCommandDone(ctx, "Theme build complete (no-op)");
|
|
1026
|
-
} else {
|
|
1027
|
-
await runCliTasks(
|
|
1028
|
-
ctx,
|
|
1029
|
-
[{ title: "Theme project (no module build)", task: async () => {
|
|
1030
|
-
} }],
|
|
1031
|
-
options
|
|
1032
|
-
);
|
|
1033
|
-
printCommandDone(ctx, "Theme build complete (no-op)");
|
|
1034
|
-
}
|
|
1035
|
-
return ExitCode.SUCCESS;
|
|
1036
|
-
}
|
|
1037
|
-
const tasks2 = buildTasks(ctx, options, run);
|
|
1038
|
-
await runCliTasks(ctx, tasks2, options);
|
|
1039
|
-
if (ctx.global.json) {
|
|
1040
|
-
ctx.logger.json({
|
|
1041
|
-
command: "build",
|
|
1042
|
-
tier,
|
|
1043
|
-
ok: true,
|
|
1044
|
-
outDir: resolve7(ctx.projectRoot, ctx.config.module.outDir)
|
|
1045
|
-
});
|
|
1046
|
-
} else {
|
|
1047
|
-
printCommandDone(ctx, "Build complete");
|
|
1048
|
-
}
|
|
1049
|
-
return ExitCode.SUCCESS;
|
|
1050
|
-
} catch (error) {
|
|
1051
|
-
throw new WpHsError(error instanceof Error ? error.message : String(error), {
|
|
1052
|
-
exitCode: ExitCode.BUILD_FAILED
|
|
1053
|
-
});
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
// src/cli/commands/dev.ts
|
|
1058
|
-
import { existsSync as existsSync7 } from "fs";
|
|
1059
|
-
import { resolve as resolve10 } from "path";
|
|
1060
|
-
import { spawn } from "child_process";
|
|
1171
|
+
import { resolve as resolve8 } from "path";
|
|
1061
1172
|
|
|
1062
1173
|
// src/lib/cli-banner.ts
|
|
1063
1174
|
import pc3 from "picocolors";
|
|
1064
1175
|
|
|
1065
1176
|
// src/lib/kit-version.ts
|
|
1066
1177
|
import { readFileSync as readFileSync5 } from "fs";
|
|
1067
|
-
import { resolve as
|
|
1178
|
+
import { resolve as resolve7 } from "path";
|
|
1068
1179
|
var cachedVersion = null;
|
|
1069
1180
|
function readKitVersion() {
|
|
1070
1181
|
if (cachedVersion) {
|
|
1071
1182
|
return cachedVersion;
|
|
1072
1183
|
}
|
|
1073
1184
|
try {
|
|
1074
|
-
const pkg = JSON.parse(readFileSync5(
|
|
1185
|
+
const pkg = JSON.parse(readFileSync5(resolve7(getKitRoot(), "package.json"), "utf8"));
|
|
1075
1186
|
cachedVersion = pkg.version ?? "0.0.0";
|
|
1076
1187
|
} catch {
|
|
1077
1188
|
cachedVersion = "0.0.0";
|
|
@@ -1179,6 +1290,153 @@ ${tips}
|
|
|
1179
1290
|
`);
|
|
1180
1291
|
}
|
|
1181
1292
|
|
|
1293
|
+
// src/lib/build-tier.ts
|
|
1294
|
+
var DEFAULT_BUILD_TIER = "dev";
|
|
1295
|
+
function parseBuildTier(value) {
|
|
1296
|
+
if (value === "dev" || value === "stg" || value === "prod") return value;
|
|
1297
|
+
return DEFAULT_BUILD_TIER;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// src/cli/commands/build.ts
|
|
1301
|
+
function tierToStgFlag(tier) {
|
|
1302
|
+
return tier === "dev" || tier === "stg" ? ["--stg"] : [];
|
|
1303
|
+
}
|
|
1304
|
+
function buildTasks(ctx, options, run) {
|
|
1305
|
+
const tier = options.tier ?? DEFAULT_BUILD_TIER;
|
|
1306
|
+
const isTheme = isThemeProject(ctx.config);
|
|
1307
|
+
const useCdn = usesCdnPipeline(ctx.config) && !isTheme;
|
|
1308
|
+
const tasks = [];
|
|
1309
|
+
if (isTheme && !options.cdnOnly) {
|
|
1310
|
+
return tasks;
|
|
1311
|
+
}
|
|
1312
|
+
if (ctx.config.projectType === "module-monolith" && !options.cdnOnly) {
|
|
1313
|
+
tasks.push({
|
|
1314
|
+
title: `Building monolith module (${tier})`,
|
|
1315
|
+
task: async () => {
|
|
1316
|
+
await run("run-vite-build.mjs", [
|
|
1317
|
+
resolve8(ctx.projectRoot, "vite.config.monolith.mjs"),
|
|
1318
|
+
...tierToStgFlag(tier)
|
|
1319
|
+
]);
|
|
1320
|
+
await run("run-hubspot-module-postbuild.mjs");
|
|
1321
|
+
}
|
|
1322
|
+
});
|
|
1323
|
+
return tasks;
|
|
1324
|
+
}
|
|
1325
|
+
if (!options.hubspotOnly && useCdn) {
|
|
1326
|
+
tasks.push({
|
|
1327
|
+
title: `Building CDN (${tier})`,
|
|
1328
|
+
task: async () => {
|
|
1329
|
+
if (options.cdnEsm) {
|
|
1330
|
+
await run("run-vite-build.mjs", [
|
|
1331
|
+
resolve8(ctx.projectRoot, "vite.config.cdn-esm.mjs"),
|
|
1332
|
+
...tierToStgFlag(tier)
|
|
1333
|
+
]);
|
|
1334
|
+
} else {
|
|
1335
|
+
await run("build-cdn.mjs", tierToStgFlag(tier));
|
|
1336
|
+
}
|
|
1337
|
+
await run("generate-cdn-manifest.mjs");
|
|
1338
|
+
}
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
if (!options.cdnOnly) {
|
|
1342
|
+
tasks.push({
|
|
1343
|
+
title: `Building HubSpot module (${tier})`,
|
|
1344
|
+
task: async () => {
|
|
1345
|
+
await run("run-vite-build.mjs", [
|
|
1346
|
+
resolve8(ctx.projectRoot, "vite.config.hubspot.mjs"),
|
|
1347
|
+
...tierToStgFlag(tier)
|
|
1348
|
+
]);
|
|
1349
|
+
await run("run-hubspot-module-postbuild.mjs");
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
if (!options.cdnOnly && !options.hubspotOnly) {
|
|
1354
|
+
tasks.push({
|
|
1355
|
+
title: "Running bundle checks",
|
|
1356
|
+
task: async () => {
|
|
1357
|
+
await run("check-hubspot-bundle-size.mjs");
|
|
1358
|
+
await run("write-audit-artifacts.mjs");
|
|
1359
|
+
}
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
return tasks;
|
|
1363
|
+
}
|
|
1364
|
+
function buildIntroLine(ctx, tier, options) {
|
|
1365
|
+
const isTheme = isThemeProject(ctx.config);
|
|
1366
|
+
const useCdn = usesCdnPipeline(ctx.config) && !isTheme;
|
|
1367
|
+
const parts = [];
|
|
1368
|
+
if (!options.hubspotOnly && useCdn) parts.push("CDN");
|
|
1369
|
+
if (!options.cdnOnly) parts.push("HubSpot module");
|
|
1370
|
+
if (!options.cdnOnly && !options.hubspotOnly && !isTheme) parts.push("bundle checks");
|
|
1371
|
+
if (parts.length === 0) return void 0;
|
|
1372
|
+
return `${formatProjectLabel(ctx.config)} \xB7 ${parts.join(" + ")} (${tier})`;
|
|
1373
|
+
}
|
|
1374
|
+
async function runBuild(ctx, options) {
|
|
1375
|
+
const tier = options.tier ?? DEFAULT_BUILD_TIER;
|
|
1376
|
+
const quietSubprocess = shouldQuietSubprocess(ctx, options);
|
|
1377
|
+
const env = {
|
|
1378
|
+
...process.env,
|
|
1379
|
+
WP_HS_PROJECT_ROOT: ctx.projectRoot,
|
|
1380
|
+
...quietSubprocess ? { WP_HS_QUIET_BUILD: "1" } : {}
|
|
1381
|
+
};
|
|
1382
|
+
const isTheme = isThemeProject(ctx.config);
|
|
1383
|
+
const execOpts = {
|
|
1384
|
+
cwd: ctx.projectRoot,
|
|
1385
|
+
projectRoot: ctx.projectRoot,
|
|
1386
|
+
env,
|
|
1387
|
+
logger: ctx.logger,
|
|
1388
|
+
dryRun: ctx.global.dryRun,
|
|
1389
|
+
streamOutput: ctx.global.verbose
|
|
1390
|
+
};
|
|
1391
|
+
const run = (script, args = []) => {
|
|
1392
|
+
return runNodeScriptAsync(kitPath("scripts", script), args, execOpts);
|
|
1393
|
+
};
|
|
1394
|
+
try {
|
|
1395
|
+
if (isTheme && !options.cdnOnly) {
|
|
1396
|
+
if (ctx.global.json) {
|
|
1397
|
+
ctx.logger.json({ command: "build", tier, ok: true, projectType: ctx.config.projectType });
|
|
1398
|
+
} else if (!options.progress) {
|
|
1399
|
+
ctx.logger.info("Theme project \u2014 skipping CDN/module.js build (use wp upload for theme assets)");
|
|
1400
|
+
printCommandDone(ctx, "Theme build complete (no-op)");
|
|
1401
|
+
} else {
|
|
1402
|
+
await runCliTasks(
|
|
1403
|
+
ctx,
|
|
1404
|
+
[{ title: "Theme project (no module build)", task: async () => {
|
|
1405
|
+
} }],
|
|
1406
|
+
options
|
|
1407
|
+
);
|
|
1408
|
+
printCommandDone(ctx, "Theme build complete (no-op)");
|
|
1409
|
+
}
|
|
1410
|
+
return ExitCode.SUCCESS;
|
|
1411
|
+
}
|
|
1412
|
+
const tasks = buildTasks(ctx, options, run);
|
|
1413
|
+
await runCliTasks(ctx, tasks, {
|
|
1414
|
+
...options,
|
|
1415
|
+
intro: buildIntroLine(ctx, tier, options)
|
|
1416
|
+
});
|
|
1417
|
+
if (ctx.global.json) {
|
|
1418
|
+
ctx.logger.json({
|
|
1419
|
+
command: "build",
|
|
1420
|
+
tier,
|
|
1421
|
+
ok: true,
|
|
1422
|
+
outDir: resolve8(ctx.projectRoot, ctx.config.module.outDir)
|
|
1423
|
+
});
|
|
1424
|
+
} else if (!options.quiet) {
|
|
1425
|
+
printCommandDone(ctx, "Build complete");
|
|
1426
|
+
}
|
|
1427
|
+
return ExitCode.SUCCESS;
|
|
1428
|
+
} catch (error) {
|
|
1429
|
+
throw new WpHsError(error instanceof Error ? error.message : String(error), {
|
|
1430
|
+
exitCode: ExitCode.BUILD_FAILED
|
|
1431
|
+
});
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
// src/cli/commands/dev.ts
|
|
1436
|
+
import { existsSync as existsSync7 } from "fs";
|
|
1437
|
+
import { resolve as resolve10 } from "path";
|
|
1438
|
+
import { spawn } from "child_process";
|
|
1439
|
+
|
|
1182
1440
|
// src/vite/resolve-dev-config.ts
|
|
1183
1441
|
import { existsSync as existsSync6 } from "fs";
|
|
1184
1442
|
import { resolve as resolve9 } from "path";
|
|
@@ -1318,64 +1576,6 @@ ${toAppend}
|
|
|
1318
1576
|
`);
|
|
1319
1577
|
}
|
|
1320
1578
|
|
|
1321
|
-
// src/cli/commands/publish.ts
|
|
1322
|
-
async function runPublish(ctx, options) {
|
|
1323
|
-
if (!usesCdnPipeline(ctx.config)) {
|
|
1324
|
-
throw new WpHsError("This project does not use the CDN pipeline.", {
|
|
1325
|
-
exitCode: ExitCode.USER_ERROR,
|
|
1326
|
-
remediation: "module-monolith / cdn.mode none: use wp build && wp upload (or wp deploy without CDN publish)."
|
|
1327
|
-
});
|
|
1328
|
-
}
|
|
1329
|
-
const tier = options.tier ?? DEFAULT_BUILD_TIER;
|
|
1330
|
-
const env = mergeProjectEnv(ctx.projectRoot, {
|
|
1331
|
-
...process.env,
|
|
1332
|
-
WP_HS_PROJECT_ROOT: ctx.projectRoot
|
|
1333
|
-
});
|
|
1334
|
-
const execOpts = {
|
|
1335
|
-
cwd: ctx.projectRoot,
|
|
1336
|
-
env,
|
|
1337
|
-
logger: ctx.logger,
|
|
1338
|
-
dryRun: ctx.global.dryRun || options.dryRun
|
|
1339
|
-
};
|
|
1340
|
-
const verifyFlag = tier === "prod" ? ["--prod"] : ["--stg"];
|
|
1341
|
-
const publishArgs = options.dryRun ? ["--dry-run"] : [];
|
|
1342
|
-
try {
|
|
1343
|
-
await runCliTasks(
|
|
1344
|
-
ctx,
|
|
1345
|
-
[
|
|
1346
|
-
{
|
|
1347
|
-
title: `Verifying CDN API endpoint (${tier})`,
|
|
1348
|
-
task: async () => {
|
|
1349
|
-
if (options.dryRun) return;
|
|
1350
|
-
runNodeScript(kitPath("scripts", "verify-cdn-api-endpoint.mjs"), verifyFlag, execOpts);
|
|
1351
|
-
}
|
|
1352
|
-
},
|
|
1353
|
-
{
|
|
1354
|
-
title: options.dryRun ? `CDN publish dry-run (${tier})` : `Publishing CDN (${tier})`,
|
|
1355
|
-
task: async () => {
|
|
1356
|
-
runNodeScript(kitPath("scripts", "publish-cdn-github.mjs"), publishArgs, execOpts);
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
],
|
|
1360
|
-
options
|
|
1361
|
-
);
|
|
1362
|
-
if (ctx.global.json) {
|
|
1363
|
-
ctx.logger.json({ command: "publish", tier, dryRun: Boolean(options.dryRun), ok: true });
|
|
1364
|
-
} else {
|
|
1365
|
-
printCommandDone(
|
|
1366
|
-
ctx,
|
|
1367
|
-
options.dryRun ? "CDN publish dry-run complete" : "CDN publish complete"
|
|
1368
|
-
);
|
|
1369
|
-
}
|
|
1370
|
-
return ExitCode.SUCCESS;
|
|
1371
|
-
} catch (error) {
|
|
1372
|
-
throw new WpHsError(error instanceof Error ? error.message : String(error), {
|
|
1373
|
-
exitCode: ExitCode.PUBLISH_FAILED,
|
|
1374
|
-
remediation: "Check CDN PAT, portal.cdn.json, and verify-cdn-api-endpoint."
|
|
1375
|
-
});
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
1579
|
// src/cli/commands/upload.ts
|
|
1380
1580
|
import { resolve as resolve12 } from "path";
|
|
1381
1581
|
async function uploadModuleOrTheme(ctx) {
|
|
@@ -1385,19 +1585,23 @@ async function uploadModuleOrTheme(ctx) {
|
|
|
1385
1585
|
throw new WpHsError("theme block missing in woodscli.json", { exitCode: ExitCode.USER_ERROR });
|
|
1386
1586
|
}
|
|
1387
1587
|
const srcDir = resolve12(ctx.projectRoot, theme.srcDir);
|
|
1388
|
-
|
|
1588
|
+
await runCommandAsync("hs", ["cms", "upload", srcDir, theme.uploadPath], {
|
|
1389
1589
|
cwd: ctx.projectRoot,
|
|
1590
|
+
projectRoot: ctx.projectRoot,
|
|
1390
1591
|
logger: ctx.logger,
|
|
1391
|
-
dryRun: ctx.global.dryRun
|
|
1592
|
+
dryRun: ctx.global.dryRun,
|
|
1593
|
+
streamOutput: ctx.global.verbose
|
|
1392
1594
|
});
|
|
1393
1595
|
return `Uploaded theme ${srcDir} \u2192 ${theme.uploadPath}`;
|
|
1394
1596
|
}
|
|
1395
1597
|
const outDir = resolve12(ctx.projectRoot, ctx.config.module.outDir);
|
|
1396
1598
|
const uploadPath = ctx.config.module.uploadPath;
|
|
1397
|
-
|
|
1599
|
+
await runCommandAsync("hs", ["cms", "upload", outDir, uploadPath], {
|
|
1398
1600
|
cwd: ctx.projectRoot,
|
|
1601
|
+
projectRoot: ctx.projectRoot,
|
|
1399
1602
|
logger: ctx.logger,
|
|
1400
|
-
dryRun: ctx.global.dryRun
|
|
1603
|
+
dryRun: ctx.global.dryRun,
|
|
1604
|
+
streamOutput: ctx.global.verbose
|
|
1401
1605
|
});
|
|
1402
1606
|
return `Uploaded ${outDir} \u2192 ${uploadPath}`;
|
|
1403
1607
|
}
|
|
@@ -1434,73 +1638,110 @@ async function runUpload(ctx, options = {}) {
|
|
|
1434
1638
|
}
|
|
1435
1639
|
return ExitCode.SUCCESS;
|
|
1436
1640
|
} catch (error) {
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1641
|
+
const detail = error instanceof WpHsError ? error.message : error instanceof Error ? error.message : String(error);
|
|
1642
|
+
throw new WpHsError(
|
|
1643
|
+
detail.includes("HubSpot upload failed") ? detail : `HubSpot upload failed
|
|
1644
|
+
${detail}`,
|
|
1645
|
+
{
|
|
1646
|
+
exitCode: ExitCode.PUBLISH_FAILED,
|
|
1647
|
+
cause: error,
|
|
1648
|
+
remediation: "Run wp auth, then build the module before upload."
|
|
1649
|
+
}
|
|
1650
|
+
);
|
|
1442
1651
|
}
|
|
1443
1652
|
}
|
|
1444
1653
|
|
|
1445
1654
|
// src/cli/commands/deploy.ts
|
|
1446
1655
|
async function runDeploy(ctx, options) {
|
|
1447
|
-
ensureHubSpotCliSetup(ctx, "cms");
|
|
1448
1656
|
const tier = options.tier ?? DEFAULT_BUILD_TIER;
|
|
1449
|
-
const
|
|
1657
|
+
const intro = `${formatProjectLabel(ctx.config)} \xB7 deploy (${tier})`;
|
|
1658
|
+
const quietSubprocess = shouldQuietSubprocess(ctx, options);
|
|
1659
|
+
const nested = {
|
|
1660
|
+
progress: false,
|
|
1661
|
+
quiet: true,
|
|
1662
|
+
quietSubprocess: true
|
|
1663
|
+
};
|
|
1664
|
+
const baseEnv = mergeProjectEnv(ctx.projectRoot, {
|
|
1665
|
+
...process.env,
|
|
1666
|
+
WP_HS_PROJECT_ROOT: ctx.projectRoot,
|
|
1667
|
+
...quietSubprocess ? { WP_HS_QUIET_BUILD: "1" } : {}
|
|
1668
|
+
});
|
|
1450
1669
|
const execOpts = {
|
|
1451
1670
|
cwd: ctx.projectRoot,
|
|
1452
|
-
|
|
1671
|
+
projectRoot: ctx.projectRoot,
|
|
1672
|
+
env: baseEnv,
|
|
1453
1673
|
logger: ctx.logger,
|
|
1454
|
-
dryRun: ctx.global.dryRun
|
|
1674
|
+
dryRun: ctx.global.dryRun,
|
|
1675
|
+
streamOutput: ctx.global.verbose
|
|
1455
1676
|
};
|
|
1456
1677
|
const useCdn = usesCdnPipeline(ctx.config) && !isThemeProject(ctx.config);
|
|
1457
|
-
const
|
|
1458
|
-
const
|
|
1678
|
+
const verifyFlag = tier === "prod" ? ["--prod"] : ["--stg"];
|
|
1679
|
+
const tasks = [
|
|
1680
|
+
{
|
|
1681
|
+
title: "Checking HubSpot CLI",
|
|
1682
|
+
task: async () => {
|
|
1683
|
+
ensureHubSpotCliSetup(ctx, "cms");
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
];
|
|
1459
1687
|
if (useCdn) {
|
|
1460
|
-
|
|
1688
|
+
tasks.push({
|
|
1461
1689
|
title: `Building CDN (${tier})`,
|
|
1462
1690
|
task: async () => {
|
|
1463
1691
|
await runBuild(ctx, { tier, cdnOnly: true, ...nested });
|
|
1464
1692
|
}
|
|
1465
1693
|
});
|
|
1466
1694
|
if (!options.skipPublish) {
|
|
1467
|
-
|
|
1468
|
-
title: `
|
|
1695
|
+
tasks.push({
|
|
1696
|
+
title: `Verifying CDN API (${tier})`,
|
|
1697
|
+
task: async () => {
|
|
1698
|
+
await runNodeScriptAsync(kitPath("scripts", "verify-cdn-api-endpoint.mjs"), verifyFlag, execOpts);
|
|
1699
|
+
}
|
|
1700
|
+
});
|
|
1701
|
+
tasks.push({
|
|
1702
|
+
title: `Publishing CDN to GitHub (${tier})`,
|
|
1469
1703
|
task: async () => {
|
|
1470
|
-
await
|
|
1704
|
+
await runNodeScriptAsync(kitPath("scripts", "publish-cdn-github.mjs"), [], execOpts);
|
|
1471
1705
|
}
|
|
1472
1706
|
});
|
|
1473
1707
|
}
|
|
1474
|
-
|
|
1708
|
+
tasks.push({
|
|
1475
1709
|
title: `Building HubSpot module (${tier})`,
|
|
1476
1710
|
task: async () => {
|
|
1477
1711
|
await runBuild(ctx, { tier, hubspotOnly: true, ...nested });
|
|
1478
1712
|
}
|
|
1479
1713
|
});
|
|
1480
1714
|
} else {
|
|
1481
|
-
|
|
1715
|
+
tasks.push({
|
|
1482
1716
|
title: `Building module (${tier})`,
|
|
1483
1717
|
task: async () => {
|
|
1484
1718
|
await runBuild(ctx, { tier, ...nested });
|
|
1485
1719
|
}
|
|
1486
1720
|
});
|
|
1487
1721
|
}
|
|
1488
|
-
|
|
1722
|
+
tasks.push(
|
|
1489
1723
|
{
|
|
1490
1724
|
title: "Running bundle checks",
|
|
1491
1725
|
task: async () => {
|
|
1492
|
-
|
|
1493
|
-
|
|
1726
|
+
await runNodeScriptAsync(kitPath("scripts", "check-hubspot-bundle-size.mjs"), [], execOpts);
|
|
1727
|
+
await runNodeScriptAsync(kitPath("scripts", "write-audit-artifacts.mjs"), [], execOpts);
|
|
1494
1728
|
}
|
|
1495
1729
|
},
|
|
1496
1730
|
{
|
|
1497
1731
|
title: "Uploading to HubSpot",
|
|
1498
1732
|
task: async () => {
|
|
1499
|
-
await runUpload(ctx, {
|
|
1733
|
+
await runUpload(ctx, {
|
|
1734
|
+
tier,
|
|
1735
|
+
...nested,
|
|
1736
|
+
skipPrereqCheck: true
|
|
1737
|
+
});
|
|
1500
1738
|
}
|
|
1501
1739
|
}
|
|
1502
1740
|
);
|
|
1503
|
-
await runCliTasks(ctx,
|
|
1741
|
+
await runCliTasks(ctx, tasks, {
|
|
1742
|
+
...options,
|
|
1743
|
+
intro
|
|
1744
|
+
});
|
|
1504
1745
|
if (!ctx.global.json) {
|
|
1505
1746
|
printCommandDone(
|
|
1506
1747
|
ctx,
|
|
@@ -1510,6 +1751,71 @@ async function runDeploy(ctx, options) {
|
|
|
1510
1751
|
return ExitCode.SUCCESS;
|
|
1511
1752
|
}
|
|
1512
1753
|
|
|
1754
|
+
// src/cli/commands/publish.ts
|
|
1755
|
+
async function runPublish(ctx, options) {
|
|
1756
|
+
if (!usesCdnPipeline(ctx.config)) {
|
|
1757
|
+
throw new WpHsError("This project does not use the CDN pipeline.", {
|
|
1758
|
+
exitCode: ExitCode.USER_ERROR,
|
|
1759
|
+
remediation: "module-monolith / cdn.mode none: use wp build && wp upload (or wp deploy without CDN publish)."
|
|
1760
|
+
});
|
|
1761
|
+
}
|
|
1762
|
+
const tier = options.tier ?? DEFAULT_BUILD_TIER;
|
|
1763
|
+
const quietSubprocess = shouldQuietSubprocess(ctx, options);
|
|
1764
|
+
const env = mergeProjectEnv(ctx.projectRoot, {
|
|
1765
|
+
...process.env,
|
|
1766
|
+
WP_HS_PROJECT_ROOT: ctx.projectRoot,
|
|
1767
|
+
...quietSubprocess ? { WP_HS_QUIET_BUILD: "1" } : {}
|
|
1768
|
+
});
|
|
1769
|
+
const execOpts = {
|
|
1770
|
+
cwd: ctx.projectRoot,
|
|
1771
|
+
projectRoot: ctx.projectRoot,
|
|
1772
|
+
env,
|
|
1773
|
+
logger: ctx.logger,
|
|
1774
|
+
dryRun: ctx.global.dryRun || options.dryRun,
|
|
1775
|
+
streamOutput: ctx.global.verbose
|
|
1776
|
+
};
|
|
1777
|
+
const verifyFlag = tier === "prod" ? ["--prod"] : ["--stg"];
|
|
1778
|
+
const publishArgs = options.dryRun ? ["--dry-run"] : [];
|
|
1779
|
+
try {
|
|
1780
|
+
await runCliTasks(
|
|
1781
|
+
ctx,
|
|
1782
|
+
[
|
|
1783
|
+
{
|
|
1784
|
+
title: `Verifying CDN API endpoint (${tier})`,
|
|
1785
|
+
task: async () => {
|
|
1786
|
+
if (options.dryRun) return;
|
|
1787
|
+
await runNodeScriptAsync(kitPath("scripts", "verify-cdn-api-endpoint.mjs"), verifyFlag, execOpts);
|
|
1788
|
+
}
|
|
1789
|
+
},
|
|
1790
|
+
{
|
|
1791
|
+
title: options.dryRun ? `CDN publish dry-run (${tier})` : `Publishing CDN to GitHub (${tier})`,
|
|
1792
|
+
task: async () => {
|
|
1793
|
+
await runNodeScriptAsync(kitPath("scripts", "publish-cdn-github.mjs"), publishArgs, execOpts);
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
],
|
|
1797
|
+
{
|
|
1798
|
+
...options,
|
|
1799
|
+
intro: options.quiet ? void 0 : `${formatProjectLabel(ctx.config)} \xB7 CDN publish (${tier})`
|
|
1800
|
+
}
|
|
1801
|
+
);
|
|
1802
|
+
if (ctx.global.json) {
|
|
1803
|
+
ctx.logger.json({ command: "publish", tier, dryRun: Boolean(options.dryRun), ok: true });
|
|
1804
|
+
} else if (!options.quiet) {
|
|
1805
|
+
printCommandDone(
|
|
1806
|
+
ctx,
|
|
1807
|
+
options.dryRun ? "CDN publish dry-run complete" : "CDN publish complete"
|
|
1808
|
+
);
|
|
1809
|
+
}
|
|
1810
|
+
return ExitCode.SUCCESS;
|
|
1811
|
+
} catch (error) {
|
|
1812
|
+
throw new WpHsError(error instanceof Error ? error.message : String(error), {
|
|
1813
|
+
exitCode: ExitCode.PUBLISH_FAILED,
|
|
1814
|
+
remediation: "Check CDN PAT, portal.cdn.json, and verify-cdn-api-endpoint."
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1513
1819
|
// src/cli/commands/audit.ts
|
|
1514
1820
|
import { createHash } from "crypto";
|
|
1515
1821
|
import { cpSync, existsSync as existsSync9, mkdirSync, readFileSync as readFileSync7, readdirSync, rmSync, statSync } from "fs";
|
|
@@ -2519,7 +2825,7 @@ async function runExamplesSmoke(ctx, options = {}) {
|
|
|
2519
2825
|
const tier = options.tier ?? "static";
|
|
2520
2826
|
const args = ["--tier", tier];
|
|
2521
2827
|
if (options.scenario) args.push("--scenario", options.scenario);
|
|
2522
|
-
const { runNodeScript: runNodeScript2 } = await import("./exec-
|
|
2828
|
+
const { runNodeScript: runNodeScript2 } = await import("./exec-VY6BGWF3.js");
|
|
2523
2829
|
runNodeScript2(kitPath("examples", "smoke", "run-matrix.mjs"), args, {
|
|
2524
2830
|
cwd: ctx.projectRoot,
|
|
2525
2831
|
logger: ctx.logger,
|
|
@@ -2910,7 +3216,7 @@ function buildContext(global) {
|
|
|
2910
3216
|
return { projectRoot, config, logger, global };
|
|
2911
3217
|
}
|
|
2912
3218
|
function attachGlobals(command) {
|
|
2913
|
-
command.option("--project <path>", "Project root (woodscli.json)").option("--ci", "Non-interactive CI mode", false).option("--json", "Machine-readable JSON output", false).option("--verbose", "
|
|
3219
|
+
command.option("--project <path>", "Project root (woodscli.json)").option("--ci", "Non-interactive CI mode", false).option("--json", "Machine-readable JSON output", false).option("--verbose", "Step-by-step logs and child-process output (disables spinners)", false).option("--quiet", "Errors only", false).option("--dry-run", "Print planned actions without executing", false).option("-y, --yes", "Assume yes (non-interactive)", false);
|
|
2914
3220
|
}
|
|
2915
3221
|
async function handle(fn) {
|
|
2916
3222
|
try {
|
|
@@ -3090,7 +3396,7 @@ function createProgram() {
|
|
|
3090
3396
|
program2.command("auth").description("Authenticate HubSpot CLI (hs auth)").action(async () => {
|
|
3091
3397
|
const global = program2.opts();
|
|
3092
3398
|
const ctx = buildContext(global);
|
|
3093
|
-
const { runCommand: runCommand2 } = await import("./exec-
|
|
3399
|
+
const { runCommand: runCommand2 } = await import("./exec-VY6BGWF3.js");
|
|
3094
3400
|
runCommand2("hs", ["auth"], {
|
|
3095
3401
|
cwd: ctx.projectRoot,
|
|
3096
3402
|
logger: ctx.logger,
|