@wix/himalaya-cli 0.1042.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 +526 -436
- 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, {
|
|
@@ -33630,11 +33639,13 @@ async function readBody2(req) {
|
|
|
33630
33639
|
function makeEtag(body) {
|
|
33631
33640
|
return `"${createHash16("sha256").update(body).digest("hex").slice(0, 32)}"`;
|
|
33632
33641
|
}
|
|
33642
|
+
function servedTokensPath(app) {
|
|
33643
|
+
return app.module.designTokensPath ?? resolve31(app.dir, app.module.config.designTokensPath ?? "tokens.json");
|
|
33644
|
+
}
|
|
33633
33645
|
function readAppTokens(state) {
|
|
33634
33646
|
if (!state.app) return null;
|
|
33635
33647
|
try {
|
|
33636
|
-
const
|
|
33637
|
-
const parsed = JSON.parse(readFileSync41(tokenPath, "utf8"));
|
|
33648
|
+
const parsed = JSON.parse(readFileSync41(servedTokensPath(state.app), "utf8"));
|
|
33638
33649
|
delete parsed._meta;
|
|
33639
33650
|
return parsed;
|
|
33640
33651
|
} catch {
|
|
@@ -34503,13 +34514,17 @@ async function reloadAppModuleNow(state, opts) {
|
|
|
34503
34514
|
state.moduleStore = next.createStore(current.name);
|
|
34504
34515
|
}
|
|
34505
34516
|
state.serverCache.clear();
|
|
34506
|
-
|
|
34507
|
-
|
|
34517
|
+
if (opts.invalidateScreens !== false) {
|
|
34518
|
+
const screenIds = [.../* @__PURE__ */ new Set([...oldMeta.screenIds, ...state.app.meta.screenIds])];
|
|
34519
|
+
publishSSE(state, "screen.invalidated", { screenIds, reason: opts.reason });
|
|
34520
|
+
}
|
|
34508
34521
|
const newNav = JSON.stringify(deriveNavigationConfig(state.app.meta) ?? null);
|
|
34509
34522
|
if (oldNav !== newNav) {
|
|
34510
34523
|
publishSSE(state, "config.invalidated", { reason: opts.reason, at: Date.now() });
|
|
34511
34524
|
}
|
|
34512
|
-
|
|
34525
|
+
const tokensHash = servedTokensHash(state.app);
|
|
34526
|
+
if (idiomOf(next) !== oldIdiom || tokensHash !== state.announcedTokensHash) {
|
|
34527
|
+
state.announcedTokensHash = tokensHash;
|
|
34513
34528
|
publishSSE(state, "tokens.changed", { reason: opts.reason, at: Date.now() });
|
|
34514
34529
|
}
|
|
34515
34530
|
console.log(`[himalaya-dev] reloaded app module in-process: ${current.name} (${opts.reason})`);
|
|
@@ -34525,6 +34540,17 @@ async function reloadAppModuleNow(state, opts) {
|
|
|
34525
34540
|
}
|
|
34526
34541
|
}
|
|
34527
34542
|
}
|
|
34543
|
+
function tokensAreDerived(state) {
|
|
34544
|
+
if (!state.app) return false;
|
|
34545
|
+
return resolve31(servedTokensPath(state.app)) !== resolve31(state.app.dir, "tokens.json");
|
|
34546
|
+
}
|
|
34547
|
+
function servedTokensHash(app) {
|
|
34548
|
+
try {
|
|
34549
|
+
return createHash16("sha256").update(readFileSync41(servedTokensPath(app))).digest("hex");
|
|
34550
|
+
} catch {
|
|
34551
|
+
return "";
|
|
34552
|
+
}
|
|
34553
|
+
}
|
|
34528
34554
|
function classifyAppPath(rel) {
|
|
34529
34555
|
if (!rel || rel.startsWith("..")) return null;
|
|
34530
34556
|
if (rel === "tokens.json") return "tokens";
|
|
@@ -34550,21 +34576,30 @@ function startAppSourceWatcher(state) {
|
|
|
34550
34576
|
pending.clear();
|
|
34551
34577
|
if (paths.length === 0) return;
|
|
34552
34578
|
const kinds = new Set(paths.map(classifyAppPath));
|
|
34553
|
-
|
|
34554
|
-
publishSSE(state, "tokens.changed", { reason: "file_changed", at: Date.now() });
|
|
34555
|
-
}
|
|
34579
|
+
const tokensNeedReload = kinds.has("tokens") && tokensAreDerived(state);
|
|
34556
34580
|
if (kinds.has("appconfig")) {
|
|
34557
34581
|
publishSSE(state, "config.invalidated", { reason: "file_changed", at: Date.now() });
|
|
34558
34582
|
}
|
|
34559
|
-
if (kinds.has("module")) {
|
|
34583
|
+
if (kinds.has("module") || tokensNeedReload) {
|
|
34560
34584
|
reloading = true;
|
|
34561
34585
|
const recreateStore = paths.some((p) => p.startsWith("data/") || p.startsWith("seed/"));
|
|
34562
34586
|
try {
|
|
34563
|
-
await reloadAppModule(state, {
|
|
34587
|
+
await reloadAppModule(state, {
|
|
34588
|
+
reason: kinds.has("module") ? "source_changed" : "tokens_changed",
|
|
34589
|
+
recreateStore,
|
|
34590
|
+
invalidateScreens: kinds.has("module")
|
|
34591
|
+
});
|
|
34564
34592
|
} finally {
|
|
34565
34593
|
reloading = false;
|
|
34566
34594
|
}
|
|
34567
34595
|
}
|
|
34596
|
+
if (kinds.has("tokens") && state.app) {
|
|
34597
|
+
const tokensHash = servedTokensHash(state.app);
|
|
34598
|
+
if (tokensHash !== state.announcedTokensHash) {
|
|
34599
|
+
state.announcedTokensHash = tokensHash;
|
|
34600
|
+
publishSSE(state, "tokens.changed", { reason: "file_changed", at: Date.now() });
|
|
34601
|
+
}
|
|
34602
|
+
}
|
|
34568
34603
|
};
|
|
34569
34604
|
try {
|
|
34570
34605
|
const watcher2 = watch(appDir2, { persistent: false, recursive: true }, (_event, filename) => {
|
|
@@ -36003,6 +36038,7 @@ function createDevServer(opts = {}) {
|
|
|
36003
36038
|
if (state.hotReloadEnabled) {
|
|
36004
36039
|
state.bundleWatcher = startBundleArtifactWatcher(state);
|
|
36005
36040
|
state.bundleSourceWatcher = startBundleSourceWatcher(state);
|
|
36041
|
+
if (state.app) state.announcedTokensHash = servedTokensHash(state.app);
|
|
36006
36042
|
state.appWatcher = startAppSourceWatcher(state);
|
|
36007
36043
|
}
|
|
36008
36044
|
const handleRequest = (req, res) => {
|
|
@@ -49475,7 +49511,7 @@ function makeServeHandler(opts) {
|
|
|
49475
49511
|
}
|
|
49476
49512
|
const PINNED_MANIFEST_CACHE_CAP = 100;
|
|
49477
49513
|
const pinnedManifestCache = /* @__PURE__ */ new Map();
|
|
49478
|
-
const sha256hex = (b) =>
|
|
49514
|
+
const sha256hex = (b) => sha256Hex(b);
|
|
49479
49515
|
function resolvePin(request, url) {
|
|
49480
49516
|
return request.headers.get("x-himalaya-release") || url.searchParams.get("release") || null;
|
|
49481
49517
|
}
|
|
@@ -63187,6 +63223,7 @@ async function loadReleaseFromDir(app, dir) {
|
|
|
63187
63223
|
// src/cli.ts
|
|
63188
63224
|
init_scaffold();
|
|
63189
63225
|
init_store();
|
|
63226
|
+
init_contract();
|
|
63190
63227
|
init_app_link();
|
|
63191
63228
|
init_himi_report();
|
|
63192
63229
|
|
|
@@ -63592,7 +63629,7 @@ function screenshotArtifactPath(contentDir2, hash) {
|
|
|
63592
63629
|
return join6(resolve6(contentDir2), ".himi", "attestations", "artifacts", `${hash}.png`);
|
|
63593
63630
|
}
|
|
63594
63631
|
var GIT_HASH_MAX_BUFFER = 128 * 1024 * 1024;
|
|
63595
|
-
var
|
|
63632
|
+
var sha2562 = (bytes2) => createHash3("sha256").update(bytes2).digest("hex");
|
|
63596
63633
|
function canonical(value) {
|
|
63597
63634
|
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
63598
63635
|
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
@@ -63600,21 +63637,21 @@ function canonical(value) {
|
|
|
63600
63637
|
return `{${Object.keys(record2).filter((key2) => record2[key2] !== void 0).sort().map((key2) => `${JSON.stringify(key2)}:${canonical(record2[key2])}`).join(",")}}`;
|
|
63601
63638
|
}
|
|
63602
63639
|
function releasePayloadHash(payload) {
|
|
63603
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return
|
|
63640
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return sha2562(canonical(payload));
|
|
63604
63641
|
const record2 = payload;
|
|
63605
63642
|
const manifest = record2.manifest;
|
|
63606
|
-
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) return
|
|
63643
|
+
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) return sha2562(canonical(payload));
|
|
63607
63644
|
const manifestRecord = manifest;
|
|
63608
63645
|
const widgets = manifestRecord.widgets;
|
|
63609
|
-
if (!widgets || typeof widgets !== "object" || Array.isArray(widgets)) return
|
|
63610
|
-
return
|
|
63646
|
+
if (!widgets || typeof widgets !== "object" || Array.isArray(widgets)) return sha2562(canonical(payload));
|
|
63647
|
+
return sha2562(canonical({ ...record2, manifest: { ...manifestRecord, widgets: stableWidgets(widgets) } }));
|
|
63611
63648
|
}
|
|
63612
63649
|
function withoutSelfHash(attestation) {
|
|
63613
63650
|
const { selfHash: _selfHash, ...body } = attestation;
|
|
63614
63651
|
return body;
|
|
63615
63652
|
}
|
|
63616
63653
|
function selfHashFor(attestation) {
|
|
63617
|
-
return
|
|
63654
|
+
return sha2562(canonical(withoutSelfHash(attestation)));
|
|
63618
63655
|
}
|
|
63619
63656
|
function repoRoot(contentDir2) {
|
|
63620
63657
|
try {
|
|
@@ -63728,7 +63765,7 @@ function readRetainedAttestations(contentDir2) {
|
|
|
63728
63765
|
for (const expected of Object.values(run2.screenshots)) {
|
|
63729
63766
|
const path2 = screenshotArtifactPath(contentDir2, expected);
|
|
63730
63767
|
if (!existsSync3(path2)) errors.push(`missing screenshot for retained run ${run2.runId}: ${basename2(path2)}`);
|
|
63731
|
-
else if (
|
|
63768
|
+
else if (sha2562(readFileSync5(path2)) !== expected) errors.push(`screenshot hash does not match retained run ${run2.runId}: ${basename2(path2)}`);
|
|
63732
63769
|
}
|
|
63733
63770
|
}
|
|
63734
63771
|
const runs = [];
|
|
@@ -63787,11 +63824,11 @@ function writeAttestation(input, opts = {}) {
|
|
|
63787
63824
|
const previous = readLatestAttestation(contentDir2);
|
|
63788
63825
|
const runId = `${(opts.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()}-${(opts.randomSuffix ?? (() => randomBytes(3).toString("hex")))()}`;
|
|
63789
63826
|
const descriptorHashes = Object.fromEntries(
|
|
63790
|
-
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)])
|
|
63791
63828
|
);
|
|
63792
63829
|
const screenshotEntries = Object.entries(input.screenshots ?? {}).sort(([a], [b]) => a.localeCompare(b)).filter(([, path2]) => existsSync3(path2)).map(([screen, path2]) => {
|
|
63793
63830
|
const bytes2 = readFileSync5(path2);
|
|
63794
|
-
return { screen, bytes: bytes2, hash:
|
|
63831
|
+
return { screen, bytes: bytes2, hash: sha2562(bytes2) };
|
|
63795
63832
|
});
|
|
63796
63833
|
const screenshots = Object.fromEntries(screenshotEntries.map(({ screen, hash }) => [screen, hash]));
|
|
63797
63834
|
for (const { bytes: bytes2, hash } of screenshotEntries) {
|
|
@@ -63914,7 +63951,7 @@ function verifyAttestation(attestation, contentDir2, descriptors, expectedApp, r
|
|
|
63914
63951
|
errors.push(`missing baked descriptor for ${screen}`);
|
|
63915
63952
|
continue;
|
|
63916
63953
|
}
|
|
63917
|
-
if (
|
|
63954
|
+
if (sha2562(bytes2) !== expected) errors.push(`descriptor hash does not match for ${screen}`);
|
|
63918
63955
|
}
|
|
63919
63956
|
for (const [screen, expected] of Object.entries(attestation.screenshots)) {
|
|
63920
63957
|
const path2 = screenshotArtifactPath(contentDir2, expected);
|
|
@@ -63922,7 +63959,7 @@ function verifyAttestation(attestation, contentDir2, descriptors, expectedApp, r
|
|
|
63922
63959
|
errors.push(`missing screenshot for ${screen}: ${basename2(path2)}`);
|
|
63923
63960
|
continue;
|
|
63924
63961
|
}
|
|
63925
|
-
if (
|
|
63962
|
+
if (sha2562(readFileSync5(path2)) !== expected) errors.push(`screenshot hash does not match for ${screen}: ${basename2(path2)}`);
|
|
63926
63963
|
}
|
|
63927
63964
|
return { ok: errors.length === 0, errors };
|
|
63928
63965
|
}
|
|
@@ -67557,8 +67594,26 @@ function shellShaDivergenceWarnings(jobs) {
|
|
|
67557
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.`
|
|
67558
67595
|
);
|
|
67559
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
|
+
}
|
|
67560
67613
|
function materializeForPreview(appDir2, slug, displayName) {
|
|
67561
67614
|
if (!isTemplateSourceTree(appDir2)) return appDir2;
|
|
67615
|
+
const slugError = templateNameError(slug, "preview slug");
|
|
67616
|
+
if (slugError) throw Object.assign(new Error(slugError), { exitCode: 2 });
|
|
67562
67617
|
const files = readTemplateFiles(appDir2);
|
|
67563
67618
|
const forBuild = Object.fromEntries(
|
|
67564
67619
|
Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
|
|
@@ -67586,7 +67641,12 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
67586
67641
|
const dest = join60(root, `${slug}-${process.pid}`);
|
|
67587
67642
|
rmSync14(dest, { recursive: true, force: true });
|
|
67588
67643
|
mkdirSync31(dest, { recursive: true });
|
|
67589
|
-
|
|
67644
|
+
try {
|
|
67645
|
+
materializeSource(forBuild, displayName, dest, slug);
|
|
67646
|
+
} catch (e) {
|
|
67647
|
+
rmSync14(dest, { recursive: true, force: true });
|
|
67648
|
+
throw e;
|
|
67649
|
+
}
|
|
67590
67650
|
return dest;
|
|
67591
67651
|
}
|
|
67592
67652
|
async function appId(dir) {
|
|
@@ -68452,253 +68512,281 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
68452
68512
|
return outcome.code;
|
|
68453
68513
|
}
|
|
68454
68514
|
if (sub === "publish") {
|
|
68455
|
-
const
|
|
68456
|
-
const sourceDir = resolve47(str6(flags["source-dir"]) ?? appDir2);
|
|
68457
|
-
let meta;
|
|
68458
|
-
try {
|
|
68459
|
-
meta = JSON.parse(readFileSync75(join60(sourceDir, TEMPLATE_META_FILE), "utf8"));
|
|
68460
|
-
} catch {
|
|
68461
|
-
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>)` }));
|
|
68462
|
-
return 2;
|
|
68463
|
-
}
|
|
68464
|
-
if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
|
|
68465
|
-
io.error(JSON.stringify({ error: `${TEMPLATE_META_FILE} must be { title: string, description: string, tags: string[], category?: string }` }));
|
|
68466
|
-
return 2;
|
|
68467
|
-
}
|
|
68515
|
+
const publishScratch = [];
|
|
68468
68516
|
try {
|
|
68469
|
-
const
|
|
68470
|
-
|
|
68471
|
-
|
|
68472
|
-
|
|
68473
|
-
|
|
68474
|
-
|
|
68475
|
-
|
|
68476
|
-
|
|
68477
|
-
|
|
68478
|
-
const force = flags.force === true;
|
|
68479
|
-
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68480
|
-
const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
|
|
68481
|
-
const out = mkdtempSync4(join60(tmpdir5(), "himi-template-"));
|
|
68482
|
-
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
68483
|
-
const outcome = await buildReleaseFromContent2(buildDir, out, {
|
|
68484
|
-
...hasWorkers ? { tier5Dir: bundleOutDir2(buildDir) } : {},
|
|
68485
|
-
collect: { lint: true, strict }
|
|
68486
|
-
});
|
|
68487
|
-
const scaffoldSourceFindings = resolve47(sourceDir) === resolve47(appDir2) ? [] : [
|
|
68488
|
-
...tokenColorIssues(sourceDir),
|
|
68489
|
-
...surfaceIssues(sourceDir, void 0, strict),
|
|
68490
|
-
...await fontIssues(sourceDir, strict),
|
|
68491
|
-
...storesV1Issues(sourceDir, strict)
|
|
68492
|
-
].map((issue2) => ({
|
|
68493
|
-
...issue2,
|
|
68494
|
-
// Say WHICH tree. The same message against two trees means two different fixes,
|
|
68495
|
-
// and the scaffold source is the one the author is least likely to be looking at.
|
|
68496
|
-
message: `scaffold source (--source-dir ${sourceDir}): ${issue2.message}`
|
|
68497
|
-
}));
|
|
68498
|
-
const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
|
|
68499
|
-
const { report: report2, hasErrors } = summarizeLint(app, bres, outcome, strict, [
|
|
68500
|
-
...await cmsIssues(buildDir, app, strict, { local: true }),
|
|
68501
|
-
...surfaceIssues(buildDir, outcome.surfaceNav, strict),
|
|
68502
|
-
...tokenColorIssues(buildDir),
|
|
68503
|
-
...await fontIssues(buildDir, strict),
|
|
68504
|
-
...storesV1Issues(buildDir, strict),
|
|
68505
|
-
...await navIssues2(buildDir, strict),
|
|
68506
|
-
...scaffoldSourceFindings
|
|
68507
|
-
]);
|
|
68508
|
-
if (hasErrors && !force) {
|
|
68509
|
-
print({ ...report2, published: false, hint: "lint found errors \u2014 fix them, or re-run with --force to publish anyway" });
|
|
68510
|
-
return 1;
|
|
68511
|
-
}
|
|
68512
|
-
const payload = await loadReleaseFromDir(app, out);
|
|
68513
|
-
const previewAuthError = templatePreviewAuthError(payload.appConfig);
|
|
68514
|
-
if (previewAuthError) {
|
|
68515
|
-
io.error(JSON.stringify({ error: previewAuthError, published: false }));
|
|
68516
|
-
return 1;
|
|
68517
|
-
}
|
|
68518
|
-
const leaked = sentineledFiles({
|
|
68519
|
-
...payload.screens,
|
|
68520
|
-
...payload.appConfig ? { "app-config.json": payload.appConfig } : {},
|
|
68521
|
-
...payload.tokens ? { "tokens.json": payload.tokens } : {}
|
|
68522
|
-
});
|
|
68523
|
-
if (leaked.length > 0) {
|
|
68524
|
-
io.error(JSON.stringify({
|
|
68525
|
-
error: `built release still contains __HIMI_APP_*__ scaffold markers in: ${leaked.join(", ")}`,
|
|
68526
|
-
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"
|
|
68527
|
-
}));
|
|
68528
|
-
return 1;
|
|
68529
|
-
}
|
|
68530
|
-
const iconPath = str6(flags.icon) ? resolve47(str6(flags.icon)) : templateIconPath(name);
|
|
68531
|
-
let iconHash;
|
|
68532
|
-
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;
|
|
68533
68526
|
try {
|
|
68534
|
-
|
|
68535
|
-
payload.icon = bytes2.toString("base64");
|
|
68536
|
-
iconHash = createHash27("sha256").update(bytes2).digest("hex");
|
|
68527
|
+
meta = JSON.parse(readFileSync75(join60(sourceDir, TEMPLATE_META_FILE), "utf8"));
|
|
68537
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;
|
|
68538
68531
|
}
|
|
68539
|
-
|
|
68540
|
-
|
|
68541
|
-
|
|
68542
|
-
const files = sentinelizeArchive(readTemplateFiles(sourceDir), app);
|
|
68543
|
-
if (Object.keys(files).length === 0) {
|
|
68544
|
-
io.error(JSON.stringify({ error: `no source files collected from ${sourceDir}` }));
|
|
68545
|
-
return 1;
|
|
68546
|
-
}
|
|
68547
|
-
payload.source = { files, meta };
|
|
68548
|
-
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));
|
|
68549
|
-
const templateArchive = collectAppSource2(sourceDir);
|
|
68550
|
-
const templateSecrets = secretFindings2(templateArchive.entries);
|
|
68551
|
-
if (templateSecrets.length > 0) {
|
|
68552
|
-
io.error(JSON.stringify({
|
|
68553
|
-
error: `refusing to publish: ${templateSecrets[0].path} looks like it contains ${templateSecrets[0].reason}`,
|
|
68554
|
-
file: templateSecrets[0].path,
|
|
68555
|
-
hint: "a template's source is served PUBLICLY \u2014 remove it from the tree before publishing"
|
|
68556
|
-
}));
|
|
68557
|
-
return 1;
|
|
68558
|
-
}
|
|
68559
|
-
const templateZip = zipAppSource2(templateArchive.entries);
|
|
68560
|
-
const templateSourceB64 = templateZip.toString("base64");
|
|
68561
|
-
if (templateSourceB64.length > MAX_APP_SOURCE_BYTES2) {
|
|
68562
|
-
const templateLargest = largestEntries2(templateArchive.entries);
|
|
68563
|
-
io.error(JSON.stringify({
|
|
68564
|
-
ok: false,
|
|
68565
|
-
template: name,
|
|
68566
|
-
app: templateAppId,
|
|
68567
|
-
published: false,
|
|
68568
|
-
error: "app_source_too_large",
|
|
68569
|
-
archivedBytes: templateZip.length,
|
|
68570
|
-
encodedBytes: templateSourceB64.length,
|
|
68571
|
-
limit: MAX_APP_SOURCE_BYTES2,
|
|
68572
|
-
files: templateArchive.entries.length,
|
|
68573
|
-
largest: templateLargest,
|
|
68574
|
-
// No `--no-source` here, deliberately: a template's archive is not optional the way
|
|
68575
|
-
// a push's is. `himi pull` restores templates through it, so a flag that dropped it
|
|
68576
|
-
// would publish a template nobody can restore — the failure #2423 exists to prevent.
|
|
68577
|
-
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`
|
|
68578
|
-
}));
|
|
68579
|
-
return 1;
|
|
68580
|
-
}
|
|
68581
|
-
payload.appSource = templateSourceB64;
|
|
68582
|
-
const tplVis = visibilityFlag(flags, io);
|
|
68583
|
-
if (!tplVis) return 2;
|
|
68584
|
-
const publishMeta = {
|
|
68585
|
-
...str6(flags.label) ? { label: str6(flags.label) } : {},
|
|
68586
|
-
...str6(flags.notes) ? { notes: str6(flags.notes) } : {},
|
|
68587
|
-
...tplVis.value ? { visibility: tplVis.value } : {}
|
|
68588
|
-
};
|
|
68589
|
-
let sendPayload = payload;
|
|
68590
|
-
let templateBodyBytes = publishReleaseBodyBytes(payload, publishMeta);
|
|
68591
|
-
let sourceGzChars;
|
|
68592
|
-
if (templateBodyBytes > MAX_PUBLISH_BODY_BYTES) {
|
|
68593
|
-
const { gzipSync: gzipSync2 } = await import("node:zlib");
|
|
68594
|
-
const { source: plainSource, ...rest } = payload;
|
|
68595
|
-
const sourceGz = gzipSync2(Buffer.from(JSON.stringify(plainSource), "utf8"), { level: 9 }).toString("base64");
|
|
68596
|
-
sourceGzChars = sourceGz.length;
|
|
68597
|
-
const gzipped = { ...rest, sourceGz };
|
|
68598
|
-
const gzBytes = publishReleaseBodyBytes(gzipped, publishMeta);
|
|
68599
|
-
if (gzBytes <= MAX_PUBLISH_BODY_BYTES) {
|
|
68600
|
-
sendPayload = gzipped;
|
|
68601
|
-
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;
|
|
68602
68535
|
}
|
|
68603
|
-
|
|
68604
|
-
|
|
68605
|
-
|
|
68606
|
-
|
|
68607
|
-
|
|
68608
|
-
|
|
68609
|
-
|
|
68610
|
-
|
|
68611
|
-
|
|
68612
|
-
|
|
68613
|
-
|
|
68614
|
-
|
|
68615
|
-
|
|
68616
|
-
|
|
68617
|
-
|
|
68618
|
-
|
|
68619
|
-
|
|
68620
|
-
|
|
68621
|
-
|
|
68622
|
-
|
|
68623
|
-
|
|
68624
|
-
|
|
68625
|
-
|
|
68626
|
-
|
|
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}`
|
|
68627
68576
|
}));
|
|
68628
|
-
|
|
68629
|
-
|
|
68630
|
-
|
|
68631
|
-
|
|
68632
|
-
|
|
68633
|
-
|
|
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;
|
|
68634
68742
|
try {
|
|
68635
|
-
|
|
68636
|
-
app: probeApp,
|
|
68637
|
-
manifest: { releaseId: "preflight", gitSha: "0".repeat(40), app: probeApp, minBinaryVersion: null, screens: {}, bundles: {} },
|
|
68638
|
-
screens: {},
|
|
68639
|
-
sourceGz: gz(Buffer.from("null")).toString("base64")
|
|
68640
|
-
});
|
|
68641
|
-
probeErr = probe.json?.error ?? probe.status;
|
|
68743
|
+
r = await client2().publishRelease(sendPayload, publishMeta);
|
|
68642
68744
|
} catch (e) {
|
|
68643
68745
|
const target = targetName();
|
|
68644
68746
|
io.error(JSON.stringify(serveUnreachableError(target, serveBase(), e.message)));
|
|
68645
68747
|
return 1;
|
|
68646
68748
|
}
|
|
68647
|
-
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) {
|
|
68648
68754
|
io.error(JSON.stringify({
|
|
68649
68755
|
ok: false,
|
|
68650
68756
|
template: name,
|
|
68651
68757
|
app: templateAppId,
|
|
68652
68758
|
published: false,
|
|
68653
|
-
error: "
|
|
68654
|
-
|
|
68655
|
-
bodyBytes: templateBodyBytes,
|
|
68656
|
-
limit: MAX_PUBLISH_BODY_BYTES,
|
|
68657
|
-
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.`
|
|
68658
68761
|
}));
|
|
68659
68762
|
return 1;
|
|
68660
68763
|
}
|
|
68661
|
-
|
|
68662
|
-
|
|
68663
|
-
|
|
68664
|
-
|
|
68665
|
-
} catch (e) {
|
|
68666
|
-
const target = targetName();
|
|
68667
|
-
io.error(JSON.stringify(serveUnreachableError(target, serveBase(), e.message)));
|
|
68668
|
-
return 1;
|
|
68669
|
-
}
|
|
68670
|
-
if (!r.ok) {
|
|
68671
|
-
print({ ok: false, status: r.status, body: r.json ?? r.text });
|
|
68672
|
-
return 1;
|
|
68673
|
-
}
|
|
68674
|
-
if (sendPayload.sourceGz && r.json?.template !== true) {
|
|
68675
|
-
io.error(JSON.stringify({
|
|
68676
|
-
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,
|
|
68677
68768
|
template: name,
|
|
68678
68769
|
app: templateAppId,
|
|
68679
|
-
|
|
68680
|
-
|
|
68681
|
-
|
|
68682
|
-
|
|
68683
|
-
|
|
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
|
+
}
|
|
68684
68789
|
}
|
|
68685
|
-
const releaseId = r.json?.releaseId ?? payload.manifest.releaseId;
|
|
68686
|
-
const targetFlag = str6(flags.target) ? ` --target ${str6(flags.target)}` : "";
|
|
68687
|
-
print({
|
|
68688
|
-
ok: true,
|
|
68689
|
-
template: name,
|
|
68690
|
-
app: templateAppId,
|
|
68691
|
-
releaseId,
|
|
68692
|
-
title: meta.title,
|
|
68693
|
-
tags: meta.tags,
|
|
68694
|
-
icon: Boolean(iconHash),
|
|
68695
|
-
...meta.accent ? { accent: meta.accent } : {},
|
|
68696
|
-
...meta.palette ? { palette: meta.palette } : {},
|
|
68697
|
-
sourceFiles: Object.keys(files).length,
|
|
68698
|
-
...hasErrors && force ? { forcedPastErrors: true } : {},
|
|
68699
|
-
initWith: `himi init <new-app-name> --template ${name} --remote${targetFlag}`
|
|
68700
|
-
});
|
|
68701
|
-
return 0;
|
|
68702
68790
|
}
|
|
68703
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]" }));
|
|
68704
68792
|
return 2;
|
|
@@ -73486,7 +73574,9 @@ export {
|
|
|
73486
73574
|
spawnUpdateRefresh,
|
|
73487
73575
|
staleUpdateLockFile,
|
|
73488
73576
|
switchFlagErrors,
|
|
73577
|
+
templateNameError,
|
|
73489
73578
|
templatePreviewAuthError,
|
|
73579
|
+
templatePublishName,
|
|
73490
73580
|
tokenCoversApp,
|
|
73491
73581
|
trustedConfiguredRegistry,
|
|
73492
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
|
}
|