@wix/himalaya-cli 0.1043.0 → 0.1044.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +489 -426
- package/guides/templates.md +16 -0
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -1357,7 +1357,18 @@ function idSegOf(name) {
|
|
|
1357
1357
|
function substituteIdentity(body, name, slug = name) {
|
|
1358
1358
|
const idSeg = idSegOf(slug);
|
|
1359
1359
|
const cmsPrefix = slug.replace(/[^a-z0-9]+/gi, "_").replace(/^_+|_+$/g, "").toLowerCase() || "app";
|
|
1360
|
-
|
|
1360
|
+
const values = {
|
|
1361
|
+
__HIMI_APP_NAME__: name,
|
|
1362
|
+
__HIMI_APP_SLUG__: slug,
|
|
1363
|
+
__HIMI_APP_DOTID__: `com.example.${idSeg}`,
|
|
1364
|
+
__HIMI_APP_CMS_PREFIX__: cmsPrefix
|
|
1365
|
+
};
|
|
1366
|
+
return body.replace(sentinelPattern(), (m) => values[m] ?? m);
|
|
1367
|
+
}
|
|
1368
|
+
function sentinelPattern() {
|
|
1369
|
+
SENTINEL_RE ??= new RegExp(IDENTITY_SENTINELS.map((m) => escapeRe(m)).join("|"), "g");
|
|
1370
|
+
SENTINEL_RE.lastIndex = 0;
|
|
1371
|
+
return SENTINEL_RE;
|
|
1361
1372
|
}
|
|
1362
1373
|
function sentineledFiles(files) {
|
|
1363
1374
|
return Object.entries(files).filter(([, body]) => IDENTITY_SENTINELS.some((s) => body.includes(s))).map(([rel]) => rel).sort();
|
|
@@ -1699,7 +1710,7 @@ A per-app \`npm i @wix/himalaya\` is optional and only buys your editor local ty
|
|
|
1699
1710
|
);
|
|
1700
1711
|
return finishScaffold({ dir, files, ...kept.length ? { kept: kept.sort() } : {} });
|
|
1701
1712
|
}
|
|
1702
|
-
var PLAN_FILES, PACKAGE_GITIGNORE, MODULE_SOURCE_FILE, TEMPLATES_DIR, SHOWCASE_TEMPLATES_DIR, SHOWCASE_TEMPLATE_NAMES, TEMPLATE_META_FILE, TEMPLATE_ICONS_DIR, HEX_COLOR, PALETTE_KEYS, IDENTITY_SENTINELS, escapeRe, NAME_FIELDS, IDENTITY_FILES, DOTID_RE, BINARY_EXTENSIONS, extOf;
|
|
1713
|
+
var PLAN_FILES, PACKAGE_GITIGNORE, MODULE_SOURCE_FILE, TEMPLATES_DIR, SHOWCASE_TEMPLATES_DIR, SHOWCASE_TEMPLATE_NAMES, TEMPLATE_META_FILE, TEMPLATE_ICONS_DIR, HEX_COLOR, PALETTE_KEYS, IDENTITY_SENTINELS, SENTINEL_RE, escapeRe, NAME_FIELDS, IDENTITY_FILES, DOTID_RE, BINARY_EXTENSIONS, extOf;
|
|
1703
1714
|
var init_scaffold = __esm({
|
|
1704
1715
|
"src/scaffold.ts"() {
|
|
1705
1716
|
init_source_deny();
|
|
@@ -1728,6 +1739,181 @@ var init_scaffold = __esm({
|
|
|
1728
1739
|
}
|
|
1729
1740
|
});
|
|
1730
1741
|
|
|
1742
|
+
// ../../core/serve-storage/src/sha256.ts
|
|
1743
|
+
function sha256(input) {
|
|
1744
|
+
const bytes2 = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
1745
|
+
const bitLen = bytes2.length * 8;
|
|
1746
|
+
const padded = new Uint8Array(((bytes2.length + 9 + 63) / 64 | 0) * 64);
|
|
1747
|
+
padded.set(bytes2);
|
|
1748
|
+
padded[bytes2.length] = 128;
|
|
1749
|
+
const view = new DataView(padded.buffer);
|
|
1750
|
+
view.setUint32(padded.length - 8, Math.floor(bitLen / 4294967296));
|
|
1751
|
+
view.setUint32(padded.length - 4, bitLen >>> 0);
|
|
1752
|
+
let h0 = 1779033703, h1 = 3144134277, h2 = 1013904242, h3 = 2773480762;
|
|
1753
|
+
let h4 = 1359893119, h5 = 2600822924, h6 = 528734635, h7 = 1541459225;
|
|
1754
|
+
const w = new Uint32Array(64);
|
|
1755
|
+
for (let off = 0; off < padded.length; off += 64) {
|
|
1756
|
+
for (let i = 0; i < 16; i++) w[i] = view.getUint32(off + i * 4);
|
|
1757
|
+
for (let i = 16; i < 64; i++) {
|
|
1758
|
+
const a0 = w[i - 15];
|
|
1759
|
+
const a1 = w[i - 2];
|
|
1760
|
+
const s0 = (rotr(a0, 7) ^ rotr(a0, 18) ^ a0 >>> 3) >>> 0;
|
|
1761
|
+
const s1 = (rotr(a1, 17) ^ rotr(a1, 19) ^ a1 >>> 10) >>> 0;
|
|
1762
|
+
w[i] = w[i - 16] + s0 + w[i - 7] + s1 >>> 0;
|
|
1763
|
+
}
|
|
1764
|
+
let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;
|
|
1765
|
+
for (let i = 0; i < 64; i++) {
|
|
1766
|
+
const S1 = (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) >>> 0;
|
|
1767
|
+
const ch = (e & f ^ ~e & g) >>> 0;
|
|
1768
|
+
const t1 = h + S1 + ch + K[i] + w[i] >>> 0;
|
|
1769
|
+
const S0 = (rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) >>> 0;
|
|
1770
|
+
const maj = (a & b ^ a & c ^ b & c) >>> 0;
|
|
1771
|
+
const t2 = S0 + maj >>> 0;
|
|
1772
|
+
h = g;
|
|
1773
|
+
g = f;
|
|
1774
|
+
f = e;
|
|
1775
|
+
e = d + t1 >>> 0;
|
|
1776
|
+
d = c;
|
|
1777
|
+
c = b;
|
|
1778
|
+
b = a;
|
|
1779
|
+
a = t1 + t2 >>> 0;
|
|
1780
|
+
}
|
|
1781
|
+
h0 = h0 + a >>> 0;
|
|
1782
|
+
h1 = h1 + b >>> 0;
|
|
1783
|
+
h2 = h2 + c >>> 0;
|
|
1784
|
+
h3 = h3 + d >>> 0;
|
|
1785
|
+
h4 = h4 + e >>> 0;
|
|
1786
|
+
h5 = h5 + f >>> 0;
|
|
1787
|
+
h6 = h6 + g >>> 0;
|
|
1788
|
+
h7 = h7 + h >>> 0;
|
|
1789
|
+
}
|
|
1790
|
+
const out = new Uint8Array(32);
|
|
1791
|
+
const o = new DataView(out.buffer);
|
|
1792
|
+
o.setUint32(0, h0);
|
|
1793
|
+
o.setUint32(4, h1);
|
|
1794
|
+
o.setUint32(8, h2);
|
|
1795
|
+
o.setUint32(12, h3);
|
|
1796
|
+
o.setUint32(16, h4);
|
|
1797
|
+
o.setUint32(20, h5);
|
|
1798
|
+
o.setUint32(24, h6);
|
|
1799
|
+
o.setUint32(28, h7);
|
|
1800
|
+
return out;
|
|
1801
|
+
}
|
|
1802
|
+
function sha256Hex(input) {
|
|
1803
|
+
return hex(sha256(input));
|
|
1804
|
+
}
|
|
1805
|
+
async function sha256HexAsync(input) {
|
|
1806
|
+
const bytes2 = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
1807
|
+
return hex(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes2)));
|
|
1808
|
+
}
|
|
1809
|
+
function hex(bytes2) {
|
|
1810
|
+
let s = "";
|
|
1811
|
+
for (const b of bytes2) s += b.toString(16).padStart(2, "0");
|
|
1812
|
+
return s;
|
|
1813
|
+
}
|
|
1814
|
+
var K, rotr;
|
|
1815
|
+
var init_sha256 = __esm({
|
|
1816
|
+
"../../core/serve-storage/src/sha256.ts"() {
|
|
1817
|
+
K = new Uint32Array([
|
|
1818
|
+
1116352408,
|
|
1819
|
+
1899447441,
|
|
1820
|
+
3049323471,
|
|
1821
|
+
3921009573,
|
|
1822
|
+
961987163,
|
|
1823
|
+
1508970993,
|
|
1824
|
+
2453635748,
|
|
1825
|
+
2870763221,
|
|
1826
|
+
3624381080,
|
|
1827
|
+
310598401,
|
|
1828
|
+
607225278,
|
|
1829
|
+
1426881987,
|
|
1830
|
+
1925078388,
|
|
1831
|
+
2162078206,
|
|
1832
|
+
2614888103,
|
|
1833
|
+
3248222580,
|
|
1834
|
+
3835390401,
|
|
1835
|
+
4022224774,
|
|
1836
|
+
264347078,
|
|
1837
|
+
604807628,
|
|
1838
|
+
770255983,
|
|
1839
|
+
1249150122,
|
|
1840
|
+
1555081692,
|
|
1841
|
+
1996064986,
|
|
1842
|
+
2554220882,
|
|
1843
|
+
2821834349,
|
|
1844
|
+
2952996808,
|
|
1845
|
+
3210313671,
|
|
1846
|
+
3336571891,
|
|
1847
|
+
3584528711,
|
|
1848
|
+
113926993,
|
|
1849
|
+
338241895,
|
|
1850
|
+
666307205,
|
|
1851
|
+
773529912,
|
|
1852
|
+
1294757372,
|
|
1853
|
+
1396182291,
|
|
1854
|
+
1695183700,
|
|
1855
|
+
1986661051,
|
|
1856
|
+
2177026350,
|
|
1857
|
+
2456956037,
|
|
1858
|
+
2730485921,
|
|
1859
|
+
2820302411,
|
|
1860
|
+
3259730800,
|
|
1861
|
+
3345764771,
|
|
1862
|
+
3516065817,
|
|
1863
|
+
3600352804,
|
|
1864
|
+
4094571909,
|
|
1865
|
+
275423344,
|
|
1866
|
+
430227734,
|
|
1867
|
+
506948616,
|
|
1868
|
+
659060556,
|
|
1869
|
+
883997877,
|
|
1870
|
+
958139571,
|
|
1871
|
+
1322822218,
|
|
1872
|
+
1537002063,
|
|
1873
|
+
1747873779,
|
|
1874
|
+
1955562222,
|
|
1875
|
+
2024104815,
|
|
1876
|
+
2227730452,
|
|
1877
|
+
2361852424,
|
|
1878
|
+
2428436474,
|
|
1879
|
+
2756734187,
|
|
1880
|
+
3204031479,
|
|
1881
|
+
3329325298
|
|
1882
|
+
]);
|
|
1883
|
+
rotr = (x, n) => (x >>> n | x << 32 - n) >>> 0;
|
|
1884
|
+
}
|
|
1885
|
+
});
|
|
1886
|
+
|
|
1887
|
+
// ../../core/serve-storage/src/contract.ts
|
|
1888
|
+
function strongEtag(body) {
|
|
1889
|
+
return strongEtagForSha256(sha256Hex(body));
|
|
1890
|
+
}
|
|
1891
|
+
function strongEtagForSha256(hex2) {
|
|
1892
|
+
return `"${hex2.slice(0, 32)}"`;
|
|
1893
|
+
}
|
|
1894
|
+
function isSafeSegment(name) {
|
|
1895
|
+
return !name.includes("/") && !name.includes("..") && name.length > 0;
|
|
1896
|
+
}
|
|
1897
|
+
function isValidAppId(app) {
|
|
1898
|
+
return typeof app === "string" && APP_ID_RE.test(app);
|
|
1899
|
+
}
|
|
1900
|
+
function assertAppId(app, where) {
|
|
1901
|
+
if (!isValidAppId(app)) {
|
|
1902
|
+
throw new Error(`invalid app id at ${where}: ${JSON.stringify(app)}`);
|
|
1903
|
+
}
|
|
1904
|
+
return app;
|
|
1905
|
+
}
|
|
1906
|
+
var BUNDLE_CACHE_CONTROL, DOC_CACHE_CONTROL, PINNED_CACHE_CONTROL, APP_ID_RE;
|
|
1907
|
+
var init_contract = __esm({
|
|
1908
|
+
"../../core/serve-storage/src/contract.ts"() {
|
|
1909
|
+
init_sha256();
|
|
1910
|
+
BUNDLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
1911
|
+
DOC_CACHE_CONTROL = "public, max-age=60, stale-while-revalidate=86400";
|
|
1912
|
+
PINNED_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
1913
|
+
APP_ID_RE = /^(?=.{1,63}$)[a-z0-9][a-z0-9-]*(?:\.[a-z0-9][a-z0-9-]*)?$/;
|
|
1914
|
+
}
|
|
1915
|
+
});
|
|
1916
|
+
|
|
1731
1917
|
// ../../core/ts/src/app-link.ts
|
|
1732
1918
|
function requirePreviewSegment(value, field) {
|
|
1733
1919
|
if (!PLAYER_PREVIEW_SEGMENT_PATTERN.test(value)) {
|
|
@@ -1790,10 +1976,10 @@ function findingId(source, finding) {
|
|
|
1790
1976
|
finding.path ?? finding.at,
|
|
1791
1977
|
finding.ruleCode ?? finding.code ?? finding.invariant ?? finding.pass
|
|
1792
1978
|
].map(asText).join("\0");
|
|
1793
|
-
return `${source}:${
|
|
1979
|
+
return `${source}:${sha256Hex2(identity).slice(0, 12)}`;
|
|
1794
1980
|
}
|
|
1795
1981
|
function gapToFinding(gap) {
|
|
1796
|
-
return { ...gap, id: `gap:${gap.kind}:${
|
|
1982
|
+
return { ...gap, id: `gap:${gap.kind}:${sha256Hex2(gap.key).slice(0, 12)}` };
|
|
1797
1983
|
}
|
|
1798
1984
|
function normalizedFinding(source, finding) {
|
|
1799
1985
|
return {
|
|
@@ -1866,7 +2052,7 @@ function stringField(value) {
|
|
|
1866
2052
|
function numberField(value) {
|
|
1867
2053
|
return typeof value === "number" ? value : void 0;
|
|
1868
2054
|
}
|
|
1869
|
-
function
|
|
2055
|
+
function sha256Hex2(value) {
|
|
1870
2056
|
const bytes2 = new TextEncoder().encode(value);
|
|
1871
2057
|
const K2 = [
|
|
1872
2058
|
1116352408,
|
|
@@ -12759,7 +12945,7 @@ async function fetchUpstreamBytes(url) {
|
|
|
12759
12945
|
return new Uint8Array(await res.arrayBuffer());
|
|
12760
12946
|
}
|
|
12761
12947
|
function writeCachedFace(bytes2) {
|
|
12762
|
-
const hash =
|
|
12948
|
+
const hash = sha256Hex3(bytes2);
|
|
12763
12949
|
mkdirSync9(CACHE_DIR, { recursive: true });
|
|
12764
12950
|
const tmp = join21(CACHE_DIR, `.${hash}.${process.pid}.${Date.now()}.tmp`);
|
|
12765
12951
|
try {
|
|
@@ -12775,7 +12961,7 @@ async function ensureFaceBytes(face, opts = {}) {
|
|
|
12775
12961
|
const local = faceSource(face.file, face.sha256);
|
|
12776
12962
|
if (local) {
|
|
12777
12963
|
const bytes2 = readFileSync18(local);
|
|
12778
|
-
if (local !== join21(CACHE_DIR, face.sha256) ||
|
|
12964
|
+
if (local !== join21(CACHE_DIR, face.sha256) || sha256Hex3(bytes2) === face.sha256) {
|
|
12779
12965
|
return { ok: true, bytes: bytes2, from: "local" };
|
|
12780
12966
|
}
|
|
12781
12967
|
}
|
|
@@ -12802,7 +12988,7 @@ async function fetchVerifyAndCache(url, sha2565, fetcher) {
|
|
|
12802
12988
|
} catch (err) {
|
|
12803
12989
|
return { ok: false, reason: `fetching ${url} failed: ${err.message}` };
|
|
12804
12990
|
}
|
|
12805
|
-
const got =
|
|
12991
|
+
const got = sha256Hex3(bytes2);
|
|
12806
12992
|
if (got !== sha2565) {
|
|
12807
12993
|
return {
|
|
12808
12994
|
ok: false,
|
|
@@ -12862,14 +13048,14 @@ async function catalogFaceBytes(sha2565, opts = {}) {
|
|
|
12862
13048
|
}
|
|
12863
13049
|
return void 0;
|
|
12864
13050
|
}
|
|
12865
|
-
var REPO_ROOT5, VENDORED_DIR, CACHE_DIR,
|
|
13051
|
+
var REPO_ROOT5, VENDORED_DIR, CACHE_DIR, sha256Hex3, RAW, UPSTREAM_DIR, FETCH_TIMEOUT_MS, FAILURE_MEMO_MS, recentFetches;
|
|
12866
13052
|
var init_face_source = __esm({
|
|
12867
13053
|
"../font-bake/face-source.ts"() {
|
|
12868
13054
|
init_catalog();
|
|
12869
13055
|
REPO_ROOT5 = fileURLToPath9(new URL("../..", import.meta.url));
|
|
12870
13056
|
VENDORED_DIR = process.env.HIMI_FONTS_VENDORED_DIR || join21(REPO_ROOT5, "stdlib", "fonts", "vendored", "wix-madefor");
|
|
12871
13057
|
CACHE_DIR = join21(process.env.XDG_CACHE_HOME || join21(homedir3(), ".cache"), "himi", "fonts");
|
|
12872
|
-
|
|
13058
|
+
sha256Hex3 = (bytes2) => createHash6("sha256").update(bytes2).digest("hex");
|
|
12873
13059
|
RAW = ["https://", "raw.", "githubuser", "content.com"].join("");
|
|
12874
13060
|
UPSTREAM_DIR = /^(ofl|apache|ufl)\/[a-z0-9_-]+$/;
|
|
12875
13061
|
FETCH_TIMEOUT_MS = 2e4;
|
|
@@ -18383,151 +18569,6 @@ var init_wix_gateway = __esm({
|
|
|
18383
18569
|
}
|
|
18384
18570
|
});
|
|
18385
18571
|
|
|
18386
|
-
// ../../core/serve-storage/src/sha256.ts
|
|
18387
|
-
function sha2562(input) {
|
|
18388
|
-
const bytes2 = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
18389
|
-
const bitLen = bytes2.length * 8;
|
|
18390
|
-
const padded = new Uint8Array(((bytes2.length + 9 + 63) / 64 | 0) * 64);
|
|
18391
|
-
padded.set(bytes2);
|
|
18392
|
-
padded[bytes2.length] = 128;
|
|
18393
|
-
const view = new DataView(padded.buffer);
|
|
18394
|
-
view.setUint32(padded.length - 8, Math.floor(bitLen / 4294967296));
|
|
18395
|
-
view.setUint32(padded.length - 4, bitLen >>> 0);
|
|
18396
|
-
let h0 = 1779033703, h1 = 3144134277, h2 = 1013904242, h3 = 2773480762;
|
|
18397
|
-
let h4 = 1359893119, h5 = 2600822924, h6 = 528734635, h7 = 1541459225;
|
|
18398
|
-
const w = new Uint32Array(64);
|
|
18399
|
-
for (let off = 0; off < padded.length; off += 64) {
|
|
18400
|
-
for (let i = 0; i < 16; i++) w[i] = view.getUint32(off + i * 4);
|
|
18401
|
-
for (let i = 16; i < 64; i++) {
|
|
18402
|
-
const a0 = w[i - 15];
|
|
18403
|
-
const a1 = w[i - 2];
|
|
18404
|
-
const s0 = (rotr(a0, 7) ^ rotr(a0, 18) ^ a0 >>> 3) >>> 0;
|
|
18405
|
-
const s1 = (rotr(a1, 17) ^ rotr(a1, 19) ^ a1 >>> 10) >>> 0;
|
|
18406
|
-
w[i] = w[i - 16] + s0 + w[i - 7] + s1 >>> 0;
|
|
18407
|
-
}
|
|
18408
|
-
let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;
|
|
18409
|
-
for (let i = 0; i < 64; i++) {
|
|
18410
|
-
const S1 = (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) >>> 0;
|
|
18411
|
-
const ch = (e & f ^ ~e & g) >>> 0;
|
|
18412
|
-
const t1 = h + S1 + ch + K[i] + w[i] >>> 0;
|
|
18413
|
-
const S0 = (rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) >>> 0;
|
|
18414
|
-
const maj = (a & b ^ a & c ^ b & c) >>> 0;
|
|
18415
|
-
const t2 = S0 + maj >>> 0;
|
|
18416
|
-
h = g;
|
|
18417
|
-
g = f;
|
|
18418
|
-
f = e;
|
|
18419
|
-
e = d + t1 >>> 0;
|
|
18420
|
-
d = c;
|
|
18421
|
-
c = b;
|
|
18422
|
-
b = a;
|
|
18423
|
-
a = t1 + t2 >>> 0;
|
|
18424
|
-
}
|
|
18425
|
-
h0 = h0 + a >>> 0;
|
|
18426
|
-
h1 = h1 + b >>> 0;
|
|
18427
|
-
h2 = h2 + c >>> 0;
|
|
18428
|
-
h3 = h3 + d >>> 0;
|
|
18429
|
-
h4 = h4 + e >>> 0;
|
|
18430
|
-
h5 = h5 + f >>> 0;
|
|
18431
|
-
h6 = h6 + g >>> 0;
|
|
18432
|
-
h7 = h7 + h >>> 0;
|
|
18433
|
-
}
|
|
18434
|
-
const out = new Uint8Array(32);
|
|
18435
|
-
const o = new DataView(out.buffer);
|
|
18436
|
-
o.setUint32(0, h0);
|
|
18437
|
-
o.setUint32(4, h1);
|
|
18438
|
-
o.setUint32(8, h2);
|
|
18439
|
-
o.setUint32(12, h3);
|
|
18440
|
-
o.setUint32(16, h4);
|
|
18441
|
-
o.setUint32(20, h5);
|
|
18442
|
-
o.setUint32(24, h6);
|
|
18443
|
-
o.setUint32(28, h7);
|
|
18444
|
-
return out;
|
|
18445
|
-
}
|
|
18446
|
-
function sha256Hex3(input) {
|
|
18447
|
-
return hex(sha2562(input));
|
|
18448
|
-
}
|
|
18449
|
-
async function sha256HexAsync(input) {
|
|
18450
|
-
const bytes2 = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
18451
|
-
return hex(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes2)));
|
|
18452
|
-
}
|
|
18453
|
-
function hex(bytes2) {
|
|
18454
|
-
let s = "";
|
|
18455
|
-
for (const b of bytes2) s += b.toString(16).padStart(2, "0");
|
|
18456
|
-
return s;
|
|
18457
|
-
}
|
|
18458
|
-
var K, rotr;
|
|
18459
|
-
var init_sha256 = __esm({
|
|
18460
|
-
"../../core/serve-storage/src/sha256.ts"() {
|
|
18461
|
-
K = new Uint32Array([
|
|
18462
|
-
1116352408,
|
|
18463
|
-
1899447441,
|
|
18464
|
-
3049323471,
|
|
18465
|
-
3921009573,
|
|
18466
|
-
961987163,
|
|
18467
|
-
1508970993,
|
|
18468
|
-
2453635748,
|
|
18469
|
-
2870763221,
|
|
18470
|
-
3624381080,
|
|
18471
|
-
310598401,
|
|
18472
|
-
607225278,
|
|
18473
|
-
1426881987,
|
|
18474
|
-
1925078388,
|
|
18475
|
-
2162078206,
|
|
18476
|
-
2614888103,
|
|
18477
|
-
3248222580,
|
|
18478
|
-
3835390401,
|
|
18479
|
-
4022224774,
|
|
18480
|
-
264347078,
|
|
18481
|
-
604807628,
|
|
18482
|
-
770255983,
|
|
18483
|
-
1249150122,
|
|
18484
|
-
1555081692,
|
|
18485
|
-
1996064986,
|
|
18486
|
-
2554220882,
|
|
18487
|
-
2821834349,
|
|
18488
|
-
2952996808,
|
|
18489
|
-
3210313671,
|
|
18490
|
-
3336571891,
|
|
18491
|
-
3584528711,
|
|
18492
|
-
113926993,
|
|
18493
|
-
338241895,
|
|
18494
|
-
666307205,
|
|
18495
|
-
773529912,
|
|
18496
|
-
1294757372,
|
|
18497
|
-
1396182291,
|
|
18498
|
-
1695183700,
|
|
18499
|
-
1986661051,
|
|
18500
|
-
2177026350,
|
|
18501
|
-
2456956037,
|
|
18502
|
-
2730485921,
|
|
18503
|
-
2820302411,
|
|
18504
|
-
3259730800,
|
|
18505
|
-
3345764771,
|
|
18506
|
-
3516065817,
|
|
18507
|
-
3600352804,
|
|
18508
|
-
4094571909,
|
|
18509
|
-
275423344,
|
|
18510
|
-
430227734,
|
|
18511
|
-
506948616,
|
|
18512
|
-
659060556,
|
|
18513
|
-
883997877,
|
|
18514
|
-
958139571,
|
|
18515
|
-
1322822218,
|
|
18516
|
-
1537002063,
|
|
18517
|
-
1747873779,
|
|
18518
|
-
1955562222,
|
|
18519
|
-
2024104815,
|
|
18520
|
-
2227730452,
|
|
18521
|
-
2361852424,
|
|
18522
|
-
2428436474,
|
|
18523
|
-
2756734187,
|
|
18524
|
-
3204031479,
|
|
18525
|
-
3329325298
|
|
18526
|
-
]);
|
|
18527
|
-
rotr = (x, n) => (x >>> n | x << 32 - n) >>> 0;
|
|
18528
|
-
}
|
|
18529
|
-
});
|
|
18530
|
-
|
|
18531
18572
|
// ../../core/serve-runtime/src/wix-bridge.ts
|
|
18532
18573
|
function absoluteUrlRejection(path2) {
|
|
18533
18574
|
let host = "";
|
|
@@ -18670,7 +18711,7 @@ var init_wix_bridge = __esm({
|
|
|
18670
18711
|
* header with no session cookie falls back to itself — callers refuse that case before here. */
|
|
18671
18712
|
key(msid, cookieHeader) {
|
|
18672
18713
|
const session = /(?:^|;\s*)wixSession2=([^;]*)/.exec(cookieHeader)?.[1] ?? cookieHeader;
|
|
18673
|
-
return
|
|
18714
|
+
return sha256Hex(`${msid}
|
|
18674
18715
|
${session}`);
|
|
18675
18716
|
}
|
|
18676
18717
|
async instance(msid, cookieHeader, now = Date.now()) {
|
|
@@ -18745,7 +18786,7 @@ ${session}`);
|
|
|
18745
18786
|
}
|
|
18746
18787
|
cache = /* @__PURE__ */ new Map();
|
|
18747
18788
|
key(cookieHeader, limit) {
|
|
18748
|
-
return
|
|
18789
|
+
return sha256Hex(`${limit}
|
|
18749
18790
|
${cookieHeader}`);
|
|
18750
18791
|
}
|
|
18751
18792
|
async sites(cookieHeader, limit, now = Date.now()) {
|
|
@@ -21250,7 +21291,6 @@ function shouldRevealError(args) {
|
|
|
21250
21291
|
var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
|
|
21251
21292
|
var init_validation = __esm({
|
|
21252
21293
|
"../../core/ts/src/validation.ts"() {
|
|
21253
|
-
"use strict";
|
|
21254
21294
|
EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
|
|
21255
21295
|
URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
|
|
21256
21296
|
INTEGER_RE = /^[+-]?[0-9]+$/;
|
|
@@ -24851,7 +24891,6 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
|
|
|
24851
24891
|
var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
|
|
24852
24892
|
var init_worker_subtree = __esm({
|
|
24853
24893
|
"../../core/ts/src/worker-subtree.ts"() {
|
|
24854
|
-
"use strict";
|
|
24855
24894
|
init_worker_subtree_safe_types_generated();
|
|
24856
24895
|
WORKER_SUBTREE_CEILINGS = Object.freeze({
|
|
24857
24896
|
maxEncodedBytes: 65536,
|
|
@@ -33288,36 +33327,6 @@ var init_errors = __esm({
|
|
|
33288
33327
|
}
|
|
33289
33328
|
});
|
|
33290
33329
|
|
|
33291
|
-
// ../../core/serve-storage/src/contract.ts
|
|
33292
|
-
function strongEtag(body) {
|
|
33293
|
-
return strongEtagForSha256(sha256Hex3(body));
|
|
33294
|
-
}
|
|
33295
|
-
function strongEtagForSha256(hex2) {
|
|
33296
|
-
return `"${hex2.slice(0, 32)}"`;
|
|
33297
|
-
}
|
|
33298
|
-
function isSafeSegment(name) {
|
|
33299
|
-
return !name.includes("/") && !name.includes("..") && name.length > 0;
|
|
33300
|
-
}
|
|
33301
|
-
function isValidAppId(app) {
|
|
33302
|
-
return typeof app === "string" && APP_ID_RE.test(app);
|
|
33303
|
-
}
|
|
33304
|
-
function assertAppId(app, where) {
|
|
33305
|
-
if (!isValidAppId(app)) {
|
|
33306
|
-
throw new Error(`invalid app id at ${where}: ${JSON.stringify(app)}`);
|
|
33307
|
-
}
|
|
33308
|
-
return app;
|
|
33309
|
-
}
|
|
33310
|
-
var BUNDLE_CACHE_CONTROL, DOC_CACHE_CONTROL, PINNED_CACHE_CONTROL, APP_ID_RE;
|
|
33311
|
-
var init_contract = __esm({
|
|
33312
|
-
"../../core/serve-storage/src/contract.ts"() {
|
|
33313
|
-
init_sha256();
|
|
33314
|
-
BUNDLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
33315
|
-
DOC_CACHE_CONTROL = "public, max-age=60, stale-while-revalidate=86400";
|
|
33316
|
-
PINNED_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
33317
|
-
APP_ID_RE = /^(?=.{1,63}$)[a-z0-9][a-z0-9-]*(?:\.[a-z0-9][a-z0-9-]*)?$/;
|
|
33318
|
-
}
|
|
33319
|
-
});
|
|
33320
|
-
|
|
33321
33330
|
// ../../core/serve-control/src/config.ts
|
|
33322
33331
|
var config_exports2 = {};
|
|
33323
33332
|
__export(config_exports2, {
|
|
@@ -49502,7 +49511,7 @@ function makeServeHandler(opts) {
|
|
|
49502
49511
|
}
|
|
49503
49512
|
const PINNED_MANIFEST_CACHE_CAP = 100;
|
|
49504
49513
|
const pinnedManifestCache = /* @__PURE__ */ new Map();
|
|
49505
|
-
const sha256hex = (b) =>
|
|
49514
|
+
const sha256hex = (b) => sha256Hex(b);
|
|
49506
49515
|
function resolvePin(request, url) {
|
|
49507
49516
|
return request.headers.get("x-himalaya-release") || url.searchParams.get("release") || null;
|
|
49508
49517
|
}
|
|
@@ -63214,6 +63223,7 @@ async function loadReleaseFromDir(app, dir) {
|
|
|
63214
63223
|
// src/cli.ts
|
|
63215
63224
|
init_scaffold();
|
|
63216
63225
|
init_store();
|
|
63226
|
+
init_contract();
|
|
63217
63227
|
init_app_link();
|
|
63218
63228
|
init_himi_report();
|
|
63219
63229
|
|
|
@@ -63619,7 +63629,7 @@ function screenshotArtifactPath(contentDir2, hash) {
|
|
|
63619
63629
|
return join6(resolve6(contentDir2), ".himi", "attestations", "artifacts", `${hash}.png`);
|
|
63620
63630
|
}
|
|
63621
63631
|
var GIT_HASH_MAX_BUFFER = 128 * 1024 * 1024;
|
|
63622
|
-
var
|
|
63632
|
+
var sha2562 = (bytes2) => createHash3("sha256").update(bytes2).digest("hex");
|
|
63623
63633
|
function canonical(value) {
|
|
63624
63634
|
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
63625
63635
|
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
@@ -63627,21 +63637,21 @@ function canonical(value) {
|
|
|
63627
63637
|
return `{${Object.keys(record2).filter((key2) => record2[key2] !== void 0).sort().map((key2) => `${JSON.stringify(key2)}:${canonical(record2[key2])}`).join(",")}}`;
|
|
63628
63638
|
}
|
|
63629
63639
|
function releasePayloadHash(payload) {
|
|
63630
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return
|
|
63640
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return sha2562(canonical(payload));
|
|
63631
63641
|
const record2 = payload;
|
|
63632
63642
|
const manifest = record2.manifest;
|
|
63633
|
-
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) return
|
|
63643
|
+
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) return sha2562(canonical(payload));
|
|
63634
63644
|
const manifestRecord = manifest;
|
|
63635
63645
|
const widgets = manifestRecord.widgets;
|
|
63636
|
-
if (!widgets || typeof widgets !== "object" || Array.isArray(widgets)) return
|
|
63637
|
-
return
|
|
63646
|
+
if (!widgets || typeof widgets !== "object" || Array.isArray(widgets)) return sha2562(canonical(payload));
|
|
63647
|
+
return sha2562(canonical({ ...record2, manifest: { ...manifestRecord, widgets: stableWidgets(widgets) } }));
|
|
63638
63648
|
}
|
|
63639
63649
|
function withoutSelfHash(attestation) {
|
|
63640
63650
|
const { selfHash: _selfHash, ...body } = attestation;
|
|
63641
63651
|
return body;
|
|
63642
63652
|
}
|
|
63643
63653
|
function selfHashFor(attestation) {
|
|
63644
|
-
return
|
|
63654
|
+
return sha2562(canonical(withoutSelfHash(attestation)));
|
|
63645
63655
|
}
|
|
63646
63656
|
function repoRoot(contentDir2) {
|
|
63647
63657
|
try {
|
|
@@ -63755,7 +63765,7 @@ function readRetainedAttestations(contentDir2) {
|
|
|
63755
63765
|
for (const expected of Object.values(run2.screenshots)) {
|
|
63756
63766
|
const path2 = screenshotArtifactPath(contentDir2, expected);
|
|
63757
63767
|
if (!existsSync3(path2)) errors.push(`missing screenshot for retained run ${run2.runId}: ${basename2(path2)}`);
|
|
63758
|
-
else if (
|
|
63768
|
+
else if (sha2562(readFileSync5(path2)) !== expected) errors.push(`screenshot hash does not match retained run ${run2.runId}: ${basename2(path2)}`);
|
|
63759
63769
|
}
|
|
63760
63770
|
}
|
|
63761
63771
|
const runs = [];
|
|
@@ -63814,11 +63824,11 @@ function writeAttestation(input, opts = {}) {
|
|
|
63814
63824
|
const previous = readLatestAttestation(contentDir2);
|
|
63815
63825
|
const runId = `${(opts.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()}-${(opts.randomSuffix ?? (() => randomBytes(3).toString("hex")))()}`;
|
|
63816
63826
|
const descriptorHashes = Object.fromEntries(
|
|
63817
|
-
Object.entries(input.descriptors).sort(([a], [b]) => a.localeCompare(b)).map(([screen, bytes2]) => [screen,
|
|
63827
|
+
Object.entries(input.descriptors).sort(([a], [b]) => a.localeCompare(b)).map(([screen, bytes2]) => [screen, sha2562(bytes2)])
|
|
63818
63828
|
);
|
|
63819
63829
|
const screenshotEntries = Object.entries(input.screenshots ?? {}).sort(([a], [b]) => a.localeCompare(b)).filter(([, path2]) => existsSync3(path2)).map(([screen, path2]) => {
|
|
63820
63830
|
const bytes2 = readFileSync5(path2);
|
|
63821
|
-
return { screen, bytes: bytes2, hash:
|
|
63831
|
+
return { screen, bytes: bytes2, hash: sha2562(bytes2) };
|
|
63822
63832
|
});
|
|
63823
63833
|
const screenshots = Object.fromEntries(screenshotEntries.map(({ screen, hash }) => [screen, hash]));
|
|
63824
63834
|
for (const { bytes: bytes2, hash } of screenshotEntries) {
|
|
@@ -63941,7 +63951,7 @@ function verifyAttestation(attestation, contentDir2, descriptors, expectedApp, r
|
|
|
63941
63951
|
errors.push(`missing baked descriptor for ${screen}`);
|
|
63942
63952
|
continue;
|
|
63943
63953
|
}
|
|
63944
|
-
if (
|
|
63954
|
+
if (sha2562(bytes2) !== expected) errors.push(`descriptor hash does not match for ${screen}`);
|
|
63945
63955
|
}
|
|
63946
63956
|
for (const [screen, expected] of Object.entries(attestation.screenshots)) {
|
|
63947
63957
|
const path2 = screenshotArtifactPath(contentDir2, expected);
|
|
@@ -63949,7 +63959,7 @@ function verifyAttestation(attestation, contentDir2, descriptors, expectedApp, r
|
|
|
63949
63959
|
errors.push(`missing screenshot for ${screen}: ${basename2(path2)}`);
|
|
63950
63960
|
continue;
|
|
63951
63961
|
}
|
|
63952
|
-
if (
|
|
63962
|
+
if (sha2562(readFileSync5(path2)) !== expected) errors.push(`screenshot hash does not match for ${screen}: ${basename2(path2)}`);
|
|
63953
63963
|
}
|
|
63954
63964
|
return { ok: errors.length === 0, errors };
|
|
63955
63965
|
}
|
|
@@ -67584,8 +67594,26 @@ function shellShaDivergenceWarnings(jobs) {
|
|
|
67584
67594
|
([release, built]) => `\u26A0 this build compiles the native shell at ${built.slice(0, 12)}, not release ${release.slice(0, 12)} \u2014 the release was pushed from a branch whose HEAD is not on the default branch, so the Mac pool checks out the nearest default-branch ancestor. A native-shell or tools/mobile-dist/** change on that branch is NOT in this binary even if the job reports SUCCESS; re-push from a checkout whose HEAD is on origin/master to validate it.`
|
|
67585
67595
|
);
|
|
67586
67596
|
}
|
|
67597
|
+
async function templatePublishName(sourceDir) {
|
|
67598
|
+
const id = await appId(sourceDir);
|
|
67599
|
+
return IDENTITY_SENTINELS.some((s) => id.includes(s)) ? basename14(sourceDir) : id;
|
|
67600
|
+
}
|
|
67601
|
+
function templateNameError(name, from) {
|
|
67602
|
+
if (name.startsWith(TEMPLATE_APP_PREFIX)) {
|
|
67603
|
+
const stripped = name.slice(TEMPLATE_APP_PREFIX.length);
|
|
67604
|
+
const hint = stripped && !stripped.startsWith(TEMPLATE_APP_PREFIX) && !templateNameError(stripped, from) ? `pass --name ${stripped}` : "pass --name <kebab-id>";
|
|
67605
|
+
return `template name "${name}" (${from}) already starts with "${TEMPLATE_APP_PREFIX}", which would publish to "${TEMPLATE_APP_PREFIX}${name}"; ${hint}`;
|
|
67606
|
+
}
|
|
67607
|
+
if (!TEMPLATE_NAME_PATTERN.test(name)) {
|
|
67608
|
+
return `template name "${name}" (${from}) is not a lowercase kebab id (lowercase letters and digits, hyphens only between them); pass --name <kebab-id> (it becomes ${TEMPLATE_APP_PREFIX}<name>)`;
|
|
67609
|
+
}
|
|
67610
|
+
const composed = TEMPLATE_APP_PREFIX + name;
|
|
67611
|
+
return isValidAppId(composed) ? null : `template name "${name}" (${from}) makes app id "${composed}", which is over the serve plane's app-id length limit; pass a shorter --name`;
|
|
67612
|
+
}
|
|
67587
67613
|
function materializeForPreview(appDir2, slug, displayName) {
|
|
67588
67614
|
if (!isTemplateSourceTree(appDir2)) return appDir2;
|
|
67615
|
+
const slugError = templateNameError(slug, "preview slug");
|
|
67616
|
+
if (slugError) throw Object.assign(new Error(slugError), { exitCode: 2 });
|
|
67589
67617
|
const files = readTemplateFiles(appDir2);
|
|
67590
67618
|
const forBuild = Object.fromEntries(
|
|
67591
67619
|
Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
|
|
@@ -67613,7 +67641,12 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
67613
67641
|
const dest = join60(root, `${slug}-${process.pid}`);
|
|
67614
67642
|
rmSync14(dest, { recursive: true, force: true });
|
|
67615
67643
|
mkdirSync31(dest, { recursive: true });
|
|
67616
|
-
|
|
67644
|
+
try {
|
|
67645
|
+
materializeSource(forBuild, displayName, dest, slug);
|
|
67646
|
+
} catch (e) {
|
|
67647
|
+
rmSync14(dest, { recursive: true, force: true });
|
|
67648
|
+
throw e;
|
|
67649
|
+
}
|
|
67617
67650
|
return dest;
|
|
67618
67651
|
}
|
|
67619
67652
|
async function appId(dir) {
|
|
@@ -68479,253 +68512,281 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
68479
68512
|
return outcome.code;
|
|
68480
68513
|
}
|
|
68481
68514
|
if (sub === "publish") {
|
|
68482
|
-
const
|
|
68483
|
-
const sourceDir = resolve47(str6(flags["source-dir"]) ?? appDir2);
|
|
68484
|
-
let meta;
|
|
68485
|
-
try {
|
|
68486
|
-
meta = JSON.parse(readFileSync75(join60(sourceDir, TEMPLATE_META_FILE), "utf8"));
|
|
68487
|
-
} catch {
|
|
68488
|
-
io.error(JSON.stringify({ error: `no ${TEMPLATE_META_FILE} in ${sourceDir} \u2014 a template must declare { title, description, tags } to be published`, hint: `add ${TEMPLATE_META_FILE} next to himalaya.content.json (or pass --source-dir <dir>)` }));
|
|
68489
|
-
return 2;
|
|
68490
|
-
}
|
|
68491
|
-
if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
|
|
68492
|
-
io.error(JSON.stringify({ error: `${TEMPLATE_META_FILE} must be { title: string, description: string, tags: string[], category?: string }` }));
|
|
68493
|
-
return 2;
|
|
68494
|
-
}
|
|
68515
|
+
const publishScratch = [];
|
|
68495
68516
|
try {
|
|
68496
|
-
const
|
|
68497
|
-
|
|
68498
|
-
|
|
68499
|
-
|
|
68500
|
-
|
|
68501
|
-
|
|
68502
|
-
|
|
68503
|
-
|
|
68504
|
-
|
|
68505
|
-
const force = flags.force === true;
|
|
68506
|
-
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68507
|
-
const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
|
|
68508
|
-
const out = mkdtempSync4(join60(tmpdir5(), "himi-template-"));
|
|
68509
|
-
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
68510
|
-
const outcome = await buildReleaseFromContent2(buildDir, out, {
|
|
68511
|
-
...hasWorkers ? { tier5Dir: bundleOutDir2(buildDir) } : {},
|
|
68512
|
-
collect: { lint: true, strict }
|
|
68513
|
-
});
|
|
68514
|
-
const scaffoldSourceFindings = resolve47(sourceDir) === resolve47(appDir2) ? [] : [
|
|
68515
|
-
...tokenColorIssues(sourceDir),
|
|
68516
|
-
...surfaceIssues(sourceDir, void 0, strict),
|
|
68517
|
-
...await fontIssues(sourceDir, strict),
|
|
68518
|
-
...storesV1Issues(sourceDir, strict)
|
|
68519
|
-
].map((issue2) => ({
|
|
68520
|
-
...issue2,
|
|
68521
|
-
// Say WHICH tree. The same message against two trees means two different fixes,
|
|
68522
|
-
// and the scaffold source is the one the author is least likely to be looking at.
|
|
68523
|
-
message: `scaffold source (--source-dir ${sourceDir}): ${issue2.message}`
|
|
68524
|
-
}));
|
|
68525
|
-
const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
|
|
68526
|
-
const { report: report2, hasErrors } = summarizeLint(app, bres, outcome, strict, [
|
|
68527
|
-
...await cmsIssues(buildDir, app, strict, { local: true }),
|
|
68528
|
-
...surfaceIssues(buildDir, outcome.surfaceNav, strict),
|
|
68529
|
-
...tokenColorIssues(buildDir),
|
|
68530
|
-
...await fontIssues(buildDir, strict),
|
|
68531
|
-
...storesV1Issues(buildDir, strict),
|
|
68532
|
-
...await navIssues2(buildDir, strict),
|
|
68533
|
-
...scaffoldSourceFindings
|
|
68534
|
-
]);
|
|
68535
|
-
if (hasErrors && !force) {
|
|
68536
|
-
print({ ...report2, published: false, hint: "lint found errors \u2014 fix them, or re-run with --force to publish anyway" });
|
|
68537
|
-
return 1;
|
|
68538
|
-
}
|
|
68539
|
-
const payload = await loadReleaseFromDir(app, out);
|
|
68540
|
-
const previewAuthError = templatePreviewAuthError(payload.appConfig);
|
|
68541
|
-
if (previewAuthError) {
|
|
68542
|
-
io.error(JSON.stringify({ error: previewAuthError, published: false }));
|
|
68543
|
-
return 1;
|
|
68544
|
-
}
|
|
68545
|
-
const leaked = sentineledFiles({
|
|
68546
|
-
...payload.screens,
|
|
68547
|
-
...payload.appConfig ? { "app-config.json": payload.appConfig } : {},
|
|
68548
|
-
...payload.tokens ? { "tokens.json": payload.tokens } : {}
|
|
68549
|
-
});
|
|
68550
|
-
if (leaked.length > 0) {
|
|
68551
|
-
io.error(JSON.stringify({
|
|
68552
|
-
error: `built release still contains __HIMI_APP_*__ scaffold markers in: ${leaked.join(", ")}`,
|
|
68553
|
-
hint: "point --dir at a concrete app (e.g. apps/himi-branded-lite), or fix the template so its identity fields are sentineled only in files himi init substitutes"
|
|
68554
|
-
}));
|
|
68555
|
-
return 1;
|
|
68556
|
-
}
|
|
68557
|
-
const iconPath = str6(flags.icon) ? resolve47(str6(flags.icon)) : templateIconPath(name);
|
|
68558
|
-
let iconHash;
|
|
68559
|
-
if (iconPath) {
|
|
68517
|
+
for (const f of ["dir", "source-dir", "name", "icon"]) {
|
|
68518
|
+
if (flags[f] === true) {
|
|
68519
|
+
io.error(JSON.stringify({ error: `--${f} needs a value`, published: false }));
|
|
68520
|
+
return 2;
|
|
68521
|
+
}
|
|
68522
|
+
}
|
|
68523
|
+
const appDir2 = resolve47(str6(flags.dir) ?? process.cwd());
|
|
68524
|
+
const sourceDir = resolve47(str6(flags["source-dir"]) ?? appDir2);
|
|
68525
|
+
let meta;
|
|
68560
68526
|
try {
|
|
68561
|
-
|
|
68562
|
-
payload.icon = bytes2.toString("base64");
|
|
68563
|
-
iconHash = createHash27("sha256").update(bytes2).digest("hex");
|
|
68527
|
+
meta = JSON.parse(readFileSync75(join60(sourceDir, TEMPLATE_META_FILE), "utf8"));
|
|
68564
68528
|
} catch {
|
|
68529
|
+
io.error(JSON.stringify({ error: `no ${TEMPLATE_META_FILE} in ${sourceDir} \u2014 a template must declare { title, description, tags } to be published`, hint: `add ${TEMPLATE_META_FILE} next to himalaya.content.json (or pass --source-dir <dir>)` }));
|
|
68530
|
+
return 2;
|
|
68565
68531
|
}
|
|
68566
|
-
|
|
68567
|
-
|
|
68568
|
-
|
|
68569
|
-
const files = sentinelizeArchive(readTemplateFiles(sourceDir), app);
|
|
68570
|
-
if (Object.keys(files).length === 0) {
|
|
68571
|
-
io.error(JSON.stringify({ error: `no source files collected from ${sourceDir}` }));
|
|
68572
|
-
return 1;
|
|
68573
|
-
}
|
|
68574
|
-
payload.source = { files, meta };
|
|
68575
|
-
const { collectAppSource: collectAppSource2, secretFindings: secretFindings2, zipAppSource: zipAppSource2, largestEntries: largestEntries2, MAX_APP_SOURCE_BYTES: MAX_APP_SOURCE_BYTES2 } = await Promise.resolve().then(() => (init_app_source(), app_source_exports));
|
|
68576
|
-
const templateArchive = collectAppSource2(sourceDir);
|
|
68577
|
-
const templateSecrets = secretFindings2(templateArchive.entries);
|
|
68578
|
-
if (templateSecrets.length > 0) {
|
|
68579
|
-
io.error(JSON.stringify({
|
|
68580
|
-
error: `refusing to publish: ${templateSecrets[0].path} looks like it contains ${templateSecrets[0].reason}`,
|
|
68581
|
-
file: templateSecrets[0].path,
|
|
68582
|
-
hint: "a template's source is served PUBLICLY \u2014 remove it from the tree before publishing"
|
|
68583
|
-
}));
|
|
68584
|
-
return 1;
|
|
68585
|
-
}
|
|
68586
|
-
const templateZip = zipAppSource2(templateArchive.entries);
|
|
68587
|
-
const templateSourceB64 = templateZip.toString("base64");
|
|
68588
|
-
if (templateSourceB64.length > MAX_APP_SOURCE_BYTES2) {
|
|
68589
|
-
const templateLargest = largestEntries2(templateArchive.entries);
|
|
68590
|
-
io.error(JSON.stringify({
|
|
68591
|
-
ok: false,
|
|
68592
|
-
template: name,
|
|
68593
|
-
app: templateAppId,
|
|
68594
|
-
published: false,
|
|
68595
|
-
error: "app_source_too_large",
|
|
68596
|
-
archivedBytes: templateZip.length,
|
|
68597
|
-
encodedBytes: templateSourceB64.length,
|
|
68598
|
-
limit: MAX_APP_SOURCE_BYTES2,
|
|
68599
|
-
files: templateArchive.entries.length,
|
|
68600
|
-
largest: templateLargest,
|
|
68601
|
-
// No `--no-source` here, deliberately: a template's archive is not optional the way
|
|
68602
|
-
// a push's is. `himi pull` restores templates through it, so a flag that dropped it
|
|
68603
|
-
// would publish a template nobody can restore — the failure #2423 exists to prevent.
|
|
68604
|
-
hint: `trim the template's source tree \u2014 the largest entries are ${templateLargest.map((e) => `${e.path} (${Math.round(e.compressed / 1024)} KB compressed)`).join(", ")}. Build output and dependencies are already excluded, and a template's archive is not optional, so there is no flag that publishes without it`
|
|
68605
|
-
}));
|
|
68606
|
-
return 1;
|
|
68607
|
-
}
|
|
68608
|
-
payload.appSource = templateSourceB64;
|
|
68609
|
-
const tplVis = visibilityFlag(flags, io);
|
|
68610
|
-
if (!tplVis) return 2;
|
|
68611
|
-
const publishMeta = {
|
|
68612
|
-
...str6(flags.label) ? { label: str6(flags.label) } : {},
|
|
68613
|
-
...str6(flags.notes) ? { notes: str6(flags.notes) } : {},
|
|
68614
|
-
...tplVis.value ? { visibility: tplVis.value } : {}
|
|
68615
|
-
};
|
|
68616
|
-
let sendPayload = payload;
|
|
68617
|
-
let templateBodyBytes = publishReleaseBodyBytes(payload, publishMeta);
|
|
68618
|
-
let sourceGzChars;
|
|
68619
|
-
if (templateBodyBytes > MAX_PUBLISH_BODY_BYTES) {
|
|
68620
|
-
const { gzipSync: gzipSync2 } = await import("node:zlib");
|
|
68621
|
-
const { source: plainSource, ...rest } = payload;
|
|
68622
|
-
const sourceGz = gzipSync2(Buffer.from(JSON.stringify(plainSource), "utf8"), { level: 9 }).toString("base64");
|
|
68623
|
-
sourceGzChars = sourceGz.length;
|
|
68624
|
-
const gzipped = { ...rest, sourceGz };
|
|
68625
|
-
const gzBytes = publishReleaseBodyBytes(gzipped, publishMeta);
|
|
68626
|
-
if (gzBytes <= MAX_PUBLISH_BODY_BYTES) {
|
|
68627
|
-
sendPayload = gzipped;
|
|
68628
|
-
templateBodyBytes = gzBytes;
|
|
68532
|
+
if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
|
|
68533
|
+
io.error(JSON.stringify({ error: `${TEMPLATE_META_FILE} must be { title: string, description: string, tags: string[], category?: string }` }));
|
|
68534
|
+
return 2;
|
|
68629
68535
|
}
|
|
68630
|
-
|
|
68631
|
-
|
|
68632
|
-
|
|
68633
|
-
|
|
68634
|
-
|
|
68635
|
-
|
|
68636
|
-
|
|
68637
|
-
|
|
68638
|
-
|
|
68639
|
-
|
|
68640
|
-
|
|
68641
|
-
|
|
68642
|
-
|
|
68643
|
-
|
|
68644
|
-
|
|
68645
|
-
|
|
68646
|
-
|
|
68647
|
-
|
|
68648
|
-
|
|
68649
|
-
|
|
68650
|
-
|
|
68651
|
-
|
|
68652
|
-
|
|
68653
|
-
|
|
68536
|
+
try {
|
|
68537
|
+
const appearance = extractTemplateAppearance(JSON.parse(readFileSync75(join60(sourceDir, "tokens.json"), "utf8")));
|
|
68538
|
+
meta = { ...appearance, ...meta };
|
|
68539
|
+
} catch {
|
|
68540
|
+
}
|
|
68541
|
+
const nameFlag = str6(flags.name);
|
|
68542
|
+
const name = nameFlag ?? await templatePublishName(sourceDir);
|
|
68543
|
+
const nameError = templateNameError(
|
|
68544
|
+
name,
|
|
68545
|
+
nameFlag !== void 0 ? "from --name" : `from ${sourceDir}'s himalaya.content.json, or its directory name when that is a scaffold marker`
|
|
68546
|
+
);
|
|
68547
|
+
if (nameError) {
|
|
68548
|
+
io.error(JSON.stringify({ error: nameError, published: false }));
|
|
68549
|
+
return 2;
|
|
68550
|
+
}
|
|
68551
|
+
const templateAppId = TEMPLATE_APP_PREFIX + name;
|
|
68552
|
+
const buildDir = materializeForPreview(appDir2, name, meta.title);
|
|
68553
|
+
if (buildDir !== appDir2) publishScratch.push(buildDir);
|
|
68554
|
+
const app = await appId(buildDir);
|
|
68555
|
+
const strict = flags.strict === true;
|
|
68556
|
+
const force = flags.force === true;
|
|
68557
|
+
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68558
|
+
const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
|
|
68559
|
+
const out = mkdtempSync4(join60(tmpdir5(), "himi-template-"));
|
|
68560
|
+
publishScratch.push(out);
|
|
68561
|
+
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
68562
|
+
const outcome = await buildReleaseFromContent2(buildDir, out, {
|
|
68563
|
+
...hasWorkers ? { tier5Dir: bundleOutDir2(buildDir) } : {},
|
|
68564
|
+
collect: { lint: true, strict }
|
|
68565
|
+
});
|
|
68566
|
+
const scaffoldSourceFindings = resolve47(sourceDir) === resolve47(appDir2) ? [] : [
|
|
68567
|
+
...tokenColorIssues(sourceDir),
|
|
68568
|
+
...surfaceIssues(sourceDir, void 0, strict),
|
|
68569
|
+
...await fontIssues(sourceDir, strict),
|
|
68570
|
+
...storesV1Issues(sourceDir, strict)
|
|
68571
|
+
].map((issue2) => ({
|
|
68572
|
+
...issue2,
|
|
68573
|
+
// Say WHICH tree. The same message against two trees means two different fixes,
|
|
68574
|
+
// and the scaffold source is the one the author is least likely to be looking at.
|
|
68575
|
+
message: `scaffold source (--source-dir ${sourceDir}): ${issue2.message}`
|
|
68654
68576
|
}));
|
|
68655
|
-
|
|
68656
|
-
|
|
68657
|
-
|
|
68658
|
-
|
|
68659
|
-
|
|
68660
|
-
|
|
68577
|
+
const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
|
|
68578
|
+
const { report: report2, hasErrors } = summarizeLint(app, bres, outcome, strict, [
|
|
68579
|
+
...await cmsIssues(buildDir, app, strict, { local: true }),
|
|
68580
|
+
...surfaceIssues(buildDir, outcome.surfaceNav, strict),
|
|
68581
|
+
...tokenColorIssues(buildDir),
|
|
68582
|
+
...await fontIssues(buildDir, strict),
|
|
68583
|
+
...storesV1Issues(buildDir, strict),
|
|
68584
|
+
...await navIssues2(buildDir, strict),
|
|
68585
|
+
...scaffoldSourceFindings
|
|
68586
|
+
]);
|
|
68587
|
+
if (hasErrors && !force) {
|
|
68588
|
+
print({ ...report2, published: false, hint: "lint found errors \u2014 fix them, or re-run with --force to publish anyway" });
|
|
68589
|
+
return 1;
|
|
68590
|
+
}
|
|
68591
|
+
const payload = await loadReleaseFromDir(app, out);
|
|
68592
|
+
const previewAuthError = templatePreviewAuthError(payload.appConfig);
|
|
68593
|
+
if (previewAuthError) {
|
|
68594
|
+
io.error(JSON.stringify({ error: previewAuthError, published: false }));
|
|
68595
|
+
return 1;
|
|
68596
|
+
}
|
|
68597
|
+
const leaked = sentineledFiles({
|
|
68598
|
+
...payload.screens,
|
|
68599
|
+
...payload.appConfig ? { "app-config.json": payload.appConfig } : {},
|
|
68600
|
+
...payload.tokens ? { "tokens.json": payload.tokens } : {}
|
|
68601
|
+
});
|
|
68602
|
+
if (leaked.length > 0) {
|
|
68603
|
+
io.error(JSON.stringify({
|
|
68604
|
+
error: `built release still contains __HIMI_APP_*__ scaffold markers in: ${leaked.join(", ")}`,
|
|
68605
|
+
hint: "point --dir at a concrete app (e.g. apps/himi-branded-lite), or fix the template so its identity fields are sentineled only in files himi init substitutes"
|
|
68606
|
+
}));
|
|
68607
|
+
return 1;
|
|
68608
|
+
}
|
|
68609
|
+
const iconPath = str6(flags.icon) ? resolve47(str6(flags.icon)) : templateIconPath(name);
|
|
68610
|
+
let iconHash;
|
|
68611
|
+
if (iconPath) {
|
|
68612
|
+
try {
|
|
68613
|
+
const bytes2 = readFileSync75(iconPath);
|
|
68614
|
+
payload.icon = bytes2.toString("base64");
|
|
68615
|
+
iconHash = createHash27("sha256").update(bytes2).digest("hex");
|
|
68616
|
+
} catch {
|
|
68617
|
+
}
|
|
68618
|
+
}
|
|
68619
|
+
payload.app = templateAppId;
|
|
68620
|
+
payload.manifest = { ...payload.manifest, app: templateAppId, ...iconHash ? { iconHash } : {} };
|
|
68621
|
+
const files = sentinelizeArchive(readTemplateFiles(sourceDir), app);
|
|
68622
|
+
if (Object.keys(files).length === 0) {
|
|
68623
|
+
io.error(JSON.stringify({ error: `no source files collected from ${sourceDir}` }));
|
|
68624
|
+
return 1;
|
|
68625
|
+
}
|
|
68626
|
+
payload.source = { files, meta };
|
|
68627
|
+
const { collectAppSource: collectAppSource2, secretFindings: secretFindings2, zipAppSource: zipAppSource2, largestEntries: largestEntries2, MAX_APP_SOURCE_BYTES: MAX_APP_SOURCE_BYTES2 } = await Promise.resolve().then(() => (init_app_source(), app_source_exports));
|
|
68628
|
+
const templateArchive = collectAppSource2(sourceDir);
|
|
68629
|
+
const templateSecrets = secretFindings2(templateArchive.entries);
|
|
68630
|
+
if (templateSecrets.length > 0) {
|
|
68631
|
+
io.error(JSON.stringify({
|
|
68632
|
+
error: `refusing to publish: ${templateSecrets[0].path} looks like it contains ${templateSecrets[0].reason}`,
|
|
68633
|
+
file: templateSecrets[0].path,
|
|
68634
|
+
hint: "a template's source is served PUBLICLY \u2014 remove it from the tree before publishing"
|
|
68635
|
+
}));
|
|
68636
|
+
return 1;
|
|
68637
|
+
}
|
|
68638
|
+
const templateZip = zipAppSource2(templateArchive.entries);
|
|
68639
|
+
const templateSourceB64 = templateZip.toString("base64");
|
|
68640
|
+
if (templateSourceB64.length > MAX_APP_SOURCE_BYTES2) {
|
|
68641
|
+
const templateLargest = largestEntries2(templateArchive.entries);
|
|
68642
|
+
io.error(JSON.stringify({
|
|
68643
|
+
ok: false,
|
|
68644
|
+
template: name,
|
|
68645
|
+
app: templateAppId,
|
|
68646
|
+
published: false,
|
|
68647
|
+
error: "app_source_too_large",
|
|
68648
|
+
archivedBytes: templateZip.length,
|
|
68649
|
+
encodedBytes: templateSourceB64.length,
|
|
68650
|
+
limit: MAX_APP_SOURCE_BYTES2,
|
|
68651
|
+
files: templateArchive.entries.length,
|
|
68652
|
+
largest: templateLargest,
|
|
68653
|
+
// No `--no-source` here, deliberately: a template's archive is not optional the way
|
|
68654
|
+
// a push's is. `himi pull` restores templates through it, so a flag that dropped it
|
|
68655
|
+
// would publish a template nobody can restore — the failure #2423 exists to prevent.
|
|
68656
|
+
hint: `trim the template's source tree \u2014 the largest entries are ${templateLargest.map((e) => `${e.path} (${Math.round(e.compressed / 1024)} KB compressed)`).join(", ")}. Build output and dependencies are already excluded, and a template's archive is not optional, so there is no flag that publishes without it`
|
|
68657
|
+
}));
|
|
68658
|
+
return 1;
|
|
68659
|
+
}
|
|
68660
|
+
payload.appSource = templateSourceB64;
|
|
68661
|
+
const tplVis = visibilityFlag(flags, io);
|
|
68662
|
+
if (!tplVis) return 2;
|
|
68663
|
+
const publishMeta = {
|
|
68664
|
+
...str6(flags.label) ? { label: str6(flags.label) } : {},
|
|
68665
|
+
...str6(flags.notes) ? { notes: str6(flags.notes) } : {},
|
|
68666
|
+
...tplVis.value ? { visibility: tplVis.value } : {}
|
|
68667
|
+
};
|
|
68668
|
+
let sendPayload = payload;
|
|
68669
|
+
let templateBodyBytes = publishReleaseBodyBytes(payload, publishMeta);
|
|
68670
|
+
let sourceGzChars;
|
|
68671
|
+
if (templateBodyBytes > MAX_PUBLISH_BODY_BYTES) {
|
|
68672
|
+
const { gzipSync: gzipSync2 } = await import("node:zlib");
|
|
68673
|
+
const { source: plainSource, ...rest } = payload;
|
|
68674
|
+
const sourceGz = gzipSync2(Buffer.from(JSON.stringify(plainSource), "utf8"), { level: 9 }).toString("base64");
|
|
68675
|
+
sourceGzChars = sourceGz.length;
|
|
68676
|
+
const gzipped = { ...rest, sourceGz };
|
|
68677
|
+
const gzBytes = publishReleaseBodyBytes(gzipped, publishMeta);
|
|
68678
|
+
if (gzBytes <= MAX_PUBLISH_BODY_BYTES) {
|
|
68679
|
+
sendPayload = gzipped;
|
|
68680
|
+
templateBodyBytes = gzBytes;
|
|
68681
|
+
}
|
|
68682
|
+
}
|
|
68683
|
+
if (templateBodyBytes > MAX_PUBLISH_BODY_BYTES) {
|
|
68684
|
+
io.error(JSON.stringify({
|
|
68685
|
+
ok: false,
|
|
68686
|
+
template: name,
|
|
68687
|
+
app: templateAppId,
|
|
68688
|
+
published: false,
|
|
68689
|
+
error: "publish_body_too_large",
|
|
68690
|
+
bodyBytes: templateBodyBytes,
|
|
68691
|
+
limit: MAX_PUBLISH_BODY_BYTES,
|
|
68692
|
+
// Both halves, because "the body is too big" does not say which one to cut, and the
|
|
68693
|
+
// two answer to different edits: `sourceChars` shrinks by removing FILES from the
|
|
68694
|
+
// tree, `appSourceBytes` by removing bytes (an image, a fixture) that may not be
|
|
68695
|
+
// text at all. They overlap by design — the same tree, twice — so they are reported
|
|
68696
|
+
// separately rather than summed into a figure that double-counts it.
|
|
68697
|
+
sourceChars: JSON.stringify(payload.source).length,
|
|
68698
|
+
appSourceBytes: templateSourceB64.length,
|
|
68699
|
+
// The catalog view is reported COMPRESSED as well, because "trim the tree" was the
|
|
68700
|
+
// wrong instruction and cost real time: the collector already drops binaries,
|
|
68701
|
+
// symlinks and dist/node_modules/.git/.himi, so there is rarely anything to trim.
|
|
68702
|
+
// What the two figures actually say is whether compression can still save you --
|
|
68703
|
+
// `sourceGzChars` is what this publish already tried and what remains after it.
|
|
68704
|
+
sourceGzChars,
|
|
68705
|
+
hint: "the catalog view is already sent gzipped when the plain body would not fit, and it still does not: the remainder is the release itself (screens, bundles, assets) plus the private archive, which no flag omits. Cut what the app ships, not the source tree \u2014 the collector already excludes binaries, symlinks, dist/, node_modules/, .git/ and .himi/."
|
|
68706
|
+
}));
|
|
68707
|
+
return 1;
|
|
68708
|
+
}
|
|
68709
|
+
if (sendPayload.sourceGz) {
|
|
68710
|
+
const { gzipSync: gz } = await import("node:zlib");
|
|
68711
|
+
const probeApp = templateAppId;
|
|
68712
|
+
let probeErr;
|
|
68713
|
+
try {
|
|
68714
|
+
const probe = await client2().publishRelease({
|
|
68715
|
+
app: probeApp,
|
|
68716
|
+
manifest: { releaseId: "preflight", gitSha: "0".repeat(40), app: probeApp, minBinaryVersion: null, screens: {}, bundles: {} },
|
|
68717
|
+
screens: {},
|
|
68718
|
+
sourceGz: gz(Buffer.from("null")).toString("base64")
|
|
68719
|
+
});
|
|
68720
|
+
probeErr = probe.json?.error ?? probe.status;
|
|
68721
|
+
} catch (e) {
|
|
68722
|
+
const target = targetName();
|
|
68723
|
+
io.error(JSON.stringify(serveUnreachableError(target, serveBase(), e.message)));
|
|
68724
|
+
return 1;
|
|
68725
|
+
}
|
|
68726
|
+
if (probeErr !== "source_gz_not_an_object") {
|
|
68727
|
+
io.error(JSON.stringify({
|
|
68728
|
+
ok: false,
|
|
68729
|
+
template: name,
|
|
68730
|
+
app: templateAppId,
|
|
68731
|
+
published: false,
|
|
68732
|
+
error: "serve_plane_lacks_source_gz",
|
|
68733
|
+
probe: probeErr,
|
|
68734
|
+
bodyBytes: templateBodyBytes,
|
|
68735
|
+
limit: MAX_PUBLISH_BODY_BYTES,
|
|
68736
|
+
hint: `this template only fits with a compressed catalog view, and this plane does not accept one \u2014 it answered ${JSON.stringify(probeErr)} to the capability probe instead of "source_gz_not_an_object". NOTHING was published. Upgrade the serve plane and run this again.`
|
|
68737
|
+
}));
|
|
68738
|
+
return 1;
|
|
68739
|
+
}
|
|
68740
|
+
}
|
|
68741
|
+
let r;
|
|
68661
68742
|
try {
|
|
68662
|
-
|
|
68663
|
-
app: probeApp,
|
|
68664
|
-
manifest: { releaseId: "preflight", gitSha: "0".repeat(40), app: probeApp, minBinaryVersion: null, screens: {}, bundles: {} },
|
|
68665
|
-
screens: {},
|
|
68666
|
-
sourceGz: gz(Buffer.from("null")).toString("base64")
|
|
68667
|
-
});
|
|
68668
|
-
probeErr = probe.json?.error ?? probe.status;
|
|
68743
|
+
r = await client2().publishRelease(sendPayload, publishMeta);
|
|
68669
68744
|
} catch (e) {
|
|
68670
68745
|
const target = targetName();
|
|
68671
68746
|
io.error(JSON.stringify(serveUnreachableError(target, serveBase(), e.message)));
|
|
68672
68747
|
return 1;
|
|
68673
68748
|
}
|
|
68674
|
-
if (
|
|
68749
|
+
if (!r.ok) {
|
|
68750
|
+
print({ ok: false, status: r.status, body: r.json ?? r.text });
|
|
68751
|
+
return 1;
|
|
68752
|
+
}
|
|
68753
|
+
if (sendPayload.sourceGz && r.json?.template !== true) {
|
|
68675
68754
|
io.error(JSON.stringify({
|
|
68676
68755
|
ok: false,
|
|
68677
68756
|
template: name,
|
|
68678
68757
|
app: templateAppId,
|
|
68679
68758
|
published: false,
|
|
68680
|
-
error: "
|
|
68681
|
-
|
|
68682
|
-
bodyBytes: templateBodyBytes,
|
|
68683
|
-
limit: MAX_PUBLISH_BODY_BYTES,
|
|
68684
|
-
hint: `this template only fits with a compressed catalog view, and this plane does not accept one \u2014 it answered ${JSON.stringify(probeErr)} to the capability probe instead of "source_gz_not_an_object". NOTHING was published. Upgrade the serve plane and run this again.`
|
|
68759
|
+
error: "serve_plane_ignored_source_gz",
|
|
68760
|
+
hint: `this plane accepted the publish but did not score it as a template, which means it predates compressed catalog views (\`sourceGz\`). A release WAS created for ${templateAppId} as an ordinary app \u2014 it carries no template source and will not appear in \`himi template list --remote\`. Upgrade the serve plane, then publish again; the republish repairs it.`
|
|
68685
68761
|
}));
|
|
68686
68762
|
return 1;
|
|
68687
68763
|
}
|
|
68688
|
-
|
|
68689
|
-
|
|
68690
|
-
|
|
68691
|
-
|
|
68692
|
-
} catch (e) {
|
|
68693
|
-
const target = targetName();
|
|
68694
|
-
io.error(JSON.stringify(serveUnreachableError(target, serveBase(), e.message)));
|
|
68695
|
-
return 1;
|
|
68696
|
-
}
|
|
68697
|
-
if (!r.ok) {
|
|
68698
|
-
print({ ok: false, status: r.status, body: r.json ?? r.text });
|
|
68699
|
-
return 1;
|
|
68700
|
-
}
|
|
68701
|
-
if (sendPayload.sourceGz && r.json?.template !== true) {
|
|
68702
|
-
io.error(JSON.stringify({
|
|
68703
|
-
ok: false,
|
|
68764
|
+
const releaseId = r.json?.releaseId ?? payload.manifest.releaseId;
|
|
68765
|
+
const targetFlag = str6(flags.target) ? ` --target ${str6(flags.target)}` : "";
|
|
68766
|
+
print({
|
|
68767
|
+
ok: true,
|
|
68704
68768
|
template: name,
|
|
68705
68769
|
app: templateAppId,
|
|
68706
|
-
|
|
68707
|
-
|
|
68708
|
-
|
|
68709
|
-
|
|
68710
|
-
|
|
68770
|
+
releaseId,
|
|
68771
|
+
title: meta.title,
|
|
68772
|
+
tags: meta.tags,
|
|
68773
|
+
icon: Boolean(iconHash),
|
|
68774
|
+
...meta.accent ? { accent: meta.accent } : {},
|
|
68775
|
+
...meta.palette ? { palette: meta.palette } : {},
|
|
68776
|
+
sourceFiles: Object.keys(files).length,
|
|
68777
|
+
...hasErrors && force ? { forcedPastErrors: true } : {},
|
|
68778
|
+
initWith: `himi init <new-app-name> --template ${name} --remote${targetFlag}`
|
|
68779
|
+
});
|
|
68780
|
+
return 0;
|
|
68781
|
+
} finally {
|
|
68782
|
+
for (const dir of publishScratch) {
|
|
68783
|
+
try {
|
|
68784
|
+
rmSync14(dir, { recursive: true, force: true });
|
|
68785
|
+
} catch (e) {
|
|
68786
|
+
io.error(JSON.stringify({ warning: `could not remove temp dir ${dir}: ${e.message}` }));
|
|
68787
|
+
}
|
|
68788
|
+
}
|
|
68711
68789
|
}
|
|
68712
|
-
const releaseId = r.json?.releaseId ?? payload.manifest.releaseId;
|
|
68713
|
-
const targetFlag = str6(flags.target) ? ` --target ${str6(flags.target)}` : "";
|
|
68714
|
-
print({
|
|
68715
|
-
ok: true,
|
|
68716
|
-
template: name,
|
|
68717
|
-
app: templateAppId,
|
|
68718
|
-
releaseId,
|
|
68719
|
-
title: meta.title,
|
|
68720
|
-
tags: meta.tags,
|
|
68721
|
-
icon: Boolean(iconHash),
|
|
68722
|
-
...meta.accent ? { accent: meta.accent } : {},
|
|
68723
|
-
...meta.palette ? { palette: meta.palette } : {},
|
|
68724
|
-
sourceFiles: Object.keys(files).length,
|
|
68725
|
-
...hasErrors && force ? { forcedPastErrors: true } : {},
|
|
68726
|
-
initWith: `himi init <new-app-name> --template ${name} --remote${targetFlag}`
|
|
68727
|
-
});
|
|
68728
|
-
return 0;
|
|
68729
68790
|
}
|
|
68730
68791
|
io.error(JSON.stringify({ error: "template needs a subcommand", usage: "himi template list [--remote] | himi template prompt <name> | himi template publish [--dir <app>] [--source-dir <dir>] [--name <n>] [--icon <png>] [--target <t>] | himi template trim --keep <id,id,\u2026> [--content <dir>] [--links follow|drop] [--dry-run] [--force]" }));
|
|
68731
68792
|
return 2;
|
|
@@ -73513,7 +73574,9 @@ export {
|
|
|
73513
73574
|
spawnUpdateRefresh,
|
|
73514
73575
|
staleUpdateLockFile,
|
|
73515
73576
|
switchFlagErrors,
|
|
73577
|
+
templateNameError,
|
|
73516
73578
|
templatePreviewAuthError,
|
|
73579
|
+
templatePublishName,
|
|
73517
73580
|
tokenCoversApp,
|
|
73518
73581
|
trustedConfiguredRegistry,
|
|
73519
73582
|
updateCachePath,
|
package/guides/templates.md
CHANGED
|
@@ -116,6 +116,22 @@ himi template publish --target bo # from the app dir
|
|
|
116
116
|
himi template publish --dir <app> --source-dir <dir> --name <name> --target bo
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
+
A **template tree that still carries the `__HIMI_APP_NAME__` placeholder** (a generated
|
|
120
|
+
template, as `himi init` receives it) publishes with `--dir` alone:
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
himi template publish --dir <template-dir> --target bo
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Its `himalaya.content.json` name is the placeholder, so the template name comes from the
|
|
127
|
+
**directory name**, and the preview is built from a substituted copy titled with the template's
|
|
128
|
+
own `title`. Pass `--name` only to publish under a different name. Every name, given or
|
|
129
|
+
derived, must be a lowercase kebab id short enough to fit once `himi-template-` is prefixed; a
|
|
130
|
+
name that fails is refused before anything is built.
|
|
131
|
+
|
|
132
|
+
A published template does not follow its source: after changing a template, publish it again so
|
|
133
|
+
`himi template list --remote` and `himi init … --remote` serve the new version.
|
|
134
|
+
|
|
119
135
|
`publish` builds a previewable release from the app and attaches the editable scaffold source,
|
|
120
136
|
sentinel-izing identity so it re-parameterizes on the next `himi init`. It then appears in
|
|
121
137
|
`himi template list --remote` and is scaffoldable with `himi init … --remote`. (Only the app
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1044.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
|
|
6
6
|
"keywords": [
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"artifactId": "himalaya-cli"
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
|
-
"falconPackageHash": "
|
|
68
|
+
"falconPackageHash": "7c2534e837382316a3416a0e6225572fbc86b02c8b5b35cea3d7530b"
|
|
69
69
|
}
|