@wix/himalaya-cli 0.1579.0 → 0.1580.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/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/motion/src/index.d.ts +51 -5
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/media/src/index.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/media/src/rendition.d.ts +42 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/motion.mjs +22 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-media.mjs +78 -0
- package/dist/cli.mjs +9019 -7448
- package/dist/preview-assets.generated.bin +0 -0
- package/dist/quickjs-intl.js +462 -0
- package/dist/quickjs-web-globals.js +540 -0
- package/dist/quickjs-worker-entry.js +313 -0
- package/guides/himi-json-output.md +30 -1
- package/guides/one-app-section-mappings.md +4 -5
- package/guides/one-app-to-himi-app.md +214 -6
- package/guides/one-app-viewer.md +2 -2
- package/guides/sdk-reference.json +36 -6
- package/package.json +3 -2
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
// ../../core/dev-server/src/quickjs-worker-entry.ts
|
|
2
|
+
import { parentPort, workerData } from "node:worker_threads";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
var CTL_READY = 0;
|
|
5
|
+
var CTL_LEN = 1;
|
|
6
|
+
var CTL_SEQ = 2;
|
|
7
|
+
var CTL_WORDS = 4;
|
|
8
|
+
var DATA_OFFSET = CTL_WORDS * 4;
|
|
9
|
+
var sessions = /* @__PURE__ */ new Map();
|
|
10
|
+
var { sab, intlPath, webGlobalsPath } = workerData;
|
|
11
|
+
var webGlobalsInstaller = null;
|
|
12
|
+
async function installWebGlobalsInto(ctx) {
|
|
13
|
+
webGlobalsInstaller ??= (await import(pathToFileURL(webGlobalsPath).href)).installWebGlobals;
|
|
14
|
+
webGlobalsInstaller(ctx);
|
|
15
|
+
}
|
|
16
|
+
var intlInstaller = null;
|
|
17
|
+
async function installIntlInto(ctx) {
|
|
18
|
+
intlInstaller ??= (await import(pathToFileURL(intlPath).href)).installIntl;
|
|
19
|
+
intlInstaller(ctx);
|
|
20
|
+
}
|
|
21
|
+
var ctl = new Int32Array(sab, 0, CTL_WORDS);
|
|
22
|
+
var data = new Uint8Array(sab, DATA_OFFSET);
|
|
23
|
+
var decoder = new TextDecoder();
|
|
24
|
+
var crossingSeq = 0;
|
|
25
|
+
function crossToHost(kind, method, path, body, waitMs, headers = "") {
|
|
26
|
+
const mine = ++crossingSeq;
|
|
27
|
+
const deadline = Date.now() + waitMs;
|
|
28
|
+
Atomics.store(ctl, CTL_SEQ, 0);
|
|
29
|
+
Atomics.store(ctl, CTL_READY, 0);
|
|
30
|
+
parentPort.postMessage({ want: { kind, method, path, body, headers, seq: mine } });
|
|
31
|
+
for (; ; ) {
|
|
32
|
+
const left = deadline - Date.now();
|
|
33
|
+
if (left <= 0) {
|
|
34
|
+
return JSON.stringify({ ok: false, e: `the host transport did not answer within ${waitMs}ms` });
|
|
35
|
+
}
|
|
36
|
+
const res = Atomics.wait(ctl, CTL_READY, 0, left);
|
|
37
|
+
if (res === "timed-out") {
|
|
38
|
+
return JSON.stringify({ ok: false, e: `the host transport did not answer within ${waitMs}ms` });
|
|
39
|
+
}
|
|
40
|
+
if (Atomics.load(ctl, CTL_SEQ) !== mine) {
|
|
41
|
+
Atomics.store(ctl, CTL_READY, 0);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const len = Atomics.load(ctl, CTL_LEN);
|
|
45
|
+
if (len < 0 || len > data.length) {
|
|
46
|
+
return JSON.stringify({ ok: false, e: `the host transport returned an out-of-range length (${len})` });
|
|
47
|
+
}
|
|
48
|
+
return decoder.decode(data.subarray(0, len));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
var modulePromise = null;
|
|
52
|
+
async function realmModule() {
|
|
53
|
+
modulePromise ??= (async () => {
|
|
54
|
+
const { newQuickJSWASMModuleFromVariant } = await import("quickjs-emscripten");
|
|
55
|
+
const variant = await import("@jitl/quickjs-wasmfile-release-sync");
|
|
56
|
+
return newQuickJSWASMModuleFromVariant(variant.default ?? variant);
|
|
57
|
+
})();
|
|
58
|
+
return modulePromise;
|
|
59
|
+
}
|
|
60
|
+
async function boot(msg) {
|
|
61
|
+
const mod = await realmModule();
|
|
62
|
+
const runtime = mod.newRuntime();
|
|
63
|
+
runtime.setMemoryLimit(msg.memoryLimitBytes);
|
|
64
|
+
let deadline = Date.now() + (msg.timeoutMs > 0 ? msg.timeoutMs : 2e3);
|
|
65
|
+
let waiting = false;
|
|
66
|
+
runtime.setInterruptHandler(() => !waiting && Date.now() > deadline);
|
|
67
|
+
const ctx = runtime.newContext();
|
|
68
|
+
let keepAlive = false;
|
|
69
|
+
try {
|
|
70
|
+
const host = ctx.newFunction("__himiWixCall", (mH, pH, bH, hH) => {
|
|
71
|
+
waiting = true;
|
|
72
|
+
try {
|
|
73
|
+
const answer = crossToHost(
|
|
74
|
+
"wix",
|
|
75
|
+
ctx.getString(mH),
|
|
76
|
+
ctx.getString(pH),
|
|
77
|
+
ctx.getString(bH),
|
|
78
|
+
// An explicit per-crossing budget when the caller set one; otherwise the remaining boot
|
|
79
|
+
// time, floored, so a stalled transport still surfaces as a rejected call rather than as
|
|
80
|
+
// the whole boot timing out with no attribution.
|
|
81
|
+
msg.answerTimeoutMs !== void 0 ? msg.answerTimeoutMs : Math.max(1e3, deadline - Date.now()),
|
|
82
|
+
// `undefined` when the guest called with three arguments, which every caller did
|
|
83
|
+
// before per-call site scope existed.
|
|
84
|
+
hH === void 0 ? "" : ctx.getString(hH)
|
|
85
|
+
);
|
|
86
|
+
return ctx.newString(answer);
|
|
87
|
+
} finally {
|
|
88
|
+
waiting = false;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
ctx.setProp(ctx.global, "__himiWixCall", host);
|
|
92
|
+
host.dispose();
|
|
93
|
+
const dispatchHost = ctx.newFunction("__himiDispatch", (aH, pH) => {
|
|
94
|
+
waiting = true;
|
|
95
|
+
try {
|
|
96
|
+
const answer = crossToHost(
|
|
97
|
+
"dispatch",
|
|
98
|
+
"",
|
|
99
|
+
ctx.getString(aH),
|
|
100
|
+
ctx.getString(pH),
|
|
101
|
+
msg.answerTimeoutMs !== void 0 ? msg.answerTimeoutMs : Math.max(1e3, deadline - Date.now())
|
|
102
|
+
);
|
|
103
|
+
return ctx.newString(answer);
|
|
104
|
+
} finally {
|
|
105
|
+
waiting = false;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
ctx.setProp(ctx.global, "__himiDispatch", dispatchHost);
|
|
109
|
+
dispatchHost.dispose();
|
|
110
|
+
const pre = ctx.evalCode(msg.prelude, "himi-sandbox.js");
|
|
111
|
+
if (pre.error) {
|
|
112
|
+
const detail = ctx.dump(pre.error);
|
|
113
|
+
pre.error.dispose();
|
|
114
|
+
throw new Error(`sandbox prelude failed: ${String(detail?.message ?? detail)}`);
|
|
115
|
+
}
|
|
116
|
+
const bridge = pre.value;
|
|
117
|
+
const readback = ctx.getProp(bridge, "readback");
|
|
118
|
+
const dispatch2 = ctx.getProp(bridge, "dispatch");
|
|
119
|
+
const actionsReadback = ctx.getProp(bridge, "actions");
|
|
120
|
+
bridge.dispose();
|
|
121
|
+
if (msg.webGlobals && !msg.hide?.length) await installWebGlobalsInto(ctx);
|
|
122
|
+
if (msg.intl) await installIntlInto(ctx);
|
|
123
|
+
let bundleThrow = null;
|
|
124
|
+
try {
|
|
125
|
+
const res = ctx.evalCode(msg.bundleJs, msg.filename);
|
|
126
|
+
if (res.error) {
|
|
127
|
+
const detail = ctx.dump(res.error);
|
|
128
|
+
res.error.dispose();
|
|
129
|
+
bundleThrow = String(detail?.message ?? detail);
|
|
130
|
+
} else {
|
|
131
|
+
res.value.dispose();
|
|
132
|
+
}
|
|
133
|
+
let actions = "[]";
|
|
134
|
+
let sweepError = null;
|
|
135
|
+
try {
|
|
136
|
+
actions = drain(ctx, runtime, msg.skipLoad ? "himi.quickjs.actions" : "himi.quickjs.loads");
|
|
137
|
+
} catch (e) {
|
|
138
|
+
sweepError = String(e?.message ?? e);
|
|
139
|
+
}
|
|
140
|
+
const services = readbackJson(ctx, readback);
|
|
141
|
+
sessions.set(msg.id, {
|
|
142
|
+
runtime,
|
|
143
|
+
ctx,
|
|
144
|
+
dispatch: dispatch2,
|
|
145
|
+
actions: actionsReadback,
|
|
146
|
+
setDeadline(timeoutMs) {
|
|
147
|
+
deadline = Date.now() + (timeoutMs > 0 ? timeoutMs : 2e3);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
keepAlive = true;
|
|
151
|
+
return { actions, error: bundleThrow ?? sweepError ?? void 0, console: services, sessionId: msg.id };
|
|
152
|
+
} finally {
|
|
153
|
+
readback.dispose();
|
|
154
|
+
if (!keepAlive) {
|
|
155
|
+
dispatch2.dispose();
|
|
156
|
+
actionsReadback.dispose();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
} finally {
|
|
160
|
+
if (!keepAlive) {
|
|
161
|
+
try {
|
|
162
|
+
ctx.dispose();
|
|
163
|
+
} catch {
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
runtime.dispose();
|
|
167
|
+
} catch {
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function dispatch(msg) {
|
|
173
|
+
const session = sessions.get(msg.sessionId);
|
|
174
|
+
if (!session) throw new Error("the contained guest session is no longer available");
|
|
175
|
+
session.setDeadline(msg.timeoutMs);
|
|
176
|
+
const service = session.ctx.newString(msg.service);
|
|
177
|
+
const action = session.ctx.newString(msg.action);
|
|
178
|
+
const args = session.ctx.newString(msg.argsJson);
|
|
179
|
+
try {
|
|
180
|
+
const called = session.ctx.callFunction(
|
|
181
|
+
session.dispatch,
|
|
182
|
+
session.ctx.undefined,
|
|
183
|
+
service,
|
|
184
|
+
action,
|
|
185
|
+
args,
|
|
186
|
+
typeof msg.online === "boolean" ? msg.online ? session.ctx.true : session.ctx.false : session.ctx.undefined
|
|
187
|
+
);
|
|
188
|
+
if (called.error) {
|
|
189
|
+
const detail = session.ctx.dump(called.error);
|
|
190
|
+
called.error.dispose();
|
|
191
|
+
throw new Error(`the guest dispatch could not be started: ${String(detail?.message ?? detail)}`);
|
|
192
|
+
}
|
|
193
|
+
settlePromise(session.ctx, session.runtime, called.value, "guest dispatch");
|
|
194
|
+
drainDetachedJobs(session.ctx, session.runtime);
|
|
195
|
+
return { actions: readbackJson(session.ctx, session.actions) };
|
|
196
|
+
} finally {
|
|
197
|
+
service.dispose();
|
|
198
|
+
action.dispose();
|
|
199
|
+
args.dispose();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function release(sessionId) {
|
|
203
|
+
const session = sessions.get(sessionId);
|
|
204
|
+
if (!session) return;
|
|
205
|
+
sessions.delete(sessionId);
|
|
206
|
+
try {
|
|
207
|
+
session.dispatch.dispose();
|
|
208
|
+
} catch {
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
session.actions.dispose();
|
|
212
|
+
} catch {
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
session.ctx.dispose();
|
|
216
|
+
} catch {
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
session.runtime.dispose();
|
|
220
|
+
} catch {
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function drain(ctx, runtime, trigger) {
|
|
224
|
+
const trig = ctx.evalCode(`globalThis[${JSON.stringify(trigger)}]`, "himi-actions.js");
|
|
225
|
+
if (trig.error) {
|
|
226
|
+
const detail = ctx.dump(trig.error);
|
|
227
|
+
trig.error.dispose();
|
|
228
|
+
throw new Error(`the guest load sweep could not be started: ${String(detail?.message ?? detail)}`);
|
|
229
|
+
}
|
|
230
|
+
return settlePromise(ctx, runtime, trig.value, "guest load sweep");
|
|
231
|
+
}
|
|
232
|
+
function settlePromise(ctx, runtime, promise, label) {
|
|
233
|
+
try {
|
|
234
|
+
for (let i = 0; i < MAX_PUMP_ROUNDS; i++) {
|
|
235
|
+
const state = ctx.getPromiseState(promise);
|
|
236
|
+
if (state.type === "fulfilled") {
|
|
237
|
+
const out = String(ctx.dump(state.value));
|
|
238
|
+
state.value.dispose();
|
|
239
|
+
return out;
|
|
240
|
+
}
|
|
241
|
+
if (state.type === "rejected") {
|
|
242
|
+
const detail = ctx.dump(state.error);
|
|
243
|
+
state.error.dispose();
|
|
244
|
+
throw new Error(`the ${label} failed: ${String(detail?.message ?? detail)}`);
|
|
245
|
+
}
|
|
246
|
+
state.value?.dispose?.();
|
|
247
|
+
const pending = runtime.executePendingJobs();
|
|
248
|
+
if (pending.error) {
|
|
249
|
+
const detail = ctx.dump(pending.error);
|
|
250
|
+
pending.error.dispose();
|
|
251
|
+
throw new Error(`a guest job threw during the load sweep: ${String(detail?.message ?? detail)}`);
|
|
252
|
+
}
|
|
253
|
+
if (pending.value === 0) {
|
|
254
|
+
const ticked = ctx.evalCode(`globalThis["himi.quickjs.tick"]`, "himi-tick.js");
|
|
255
|
+
if (ticked.error) {
|
|
256
|
+
const detail = ctx.dump(ticked.error);
|
|
257
|
+
ticked.error.dispose();
|
|
258
|
+
throw new Error(`the guest timer pump failed: ${String(detail?.message ?? detail)}`);
|
|
259
|
+
}
|
|
260
|
+
const fired = ctx.dump(ticked.value) === true;
|
|
261
|
+
ticked.value.dispose();
|
|
262
|
+
if (fired) continue;
|
|
263
|
+
throw new Error(
|
|
264
|
+
`the ${label} is pending with no runnable jobs \u2014 a worker awaited something the sandbox never resolves (a capability this realm does not provide)`
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
throw new Error(`the ${label} did not settle within ${MAX_PUMP_ROUNDS} job rounds`);
|
|
269
|
+
} finally {
|
|
270
|
+
promise.dispose();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function drainDetachedJobs(ctx, runtime) {
|
|
274
|
+
for (let i = 0; i < MAX_PUMP_ROUNDS; i++) {
|
|
275
|
+
const pending = runtime.executePendingJobs();
|
|
276
|
+
if (pending.error) {
|
|
277
|
+
const detail = ctx.dump(pending.error);
|
|
278
|
+
pending.error.dispose();
|
|
279
|
+
throw new Error(`a nested guest job threw after dispatch: ${String(detail?.message ?? detail)}`);
|
|
280
|
+
}
|
|
281
|
+
if (pending.value === 0) {
|
|
282
|
+
const ticked = ctx.evalCode(`globalThis["himi.quickjs.tick"]`, "himi-tick.js");
|
|
283
|
+
if (ticked.error) {
|
|
284
|
+
const detail = ctx.dump(ticked.error);
|
|
285
|
+
ticked.error.dispose();
|
|
286
|
+
throw new Error(`the nested guest timer pump failed: ${String(detail?.message ?? detail)}`);
|
|
287
|
+
}
|
|
288
|
+
const fired = ctx.dump(ticked.value) === true;
|
|
289
|
+
ticked.value.dispose();
|
|
290
|
+
if (!fired) return;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
throw new Error(`nested guest actions did not quiesce within ${MAX_PUMP_ROUNDS} job rounds`);
|
|
294
|
+
}
|
|
295
|
+
var MAX_PUMP_ROUNDS = 1e4;
|
|
296
|
+
parentPort.on("message", (msg) => {
|
|
297
|
+
if ("end" in msg) {
|
|
298
|
+
process.exit(0);
|
|
299
|
+
}
|
|
300
|
+
const operation = msg.kind === "warm" ? realmModule().then(() => ({})) : msg.kind === "boot" ? boot(msg) : msg.kind === "dispatch" ? Promise.resolve(dispatch(msg)) : Promise.resolve((release(msg.sessionId), {}));
|
|
301
|
+
operation.then((r) => parentPort.postMessage({ id: msg.id, ...r })).catch((e) => parentPort.postMessage({ id: msg.id, error: String(e?.message ?? e) }));
|
|
302
|
+
});
|
|
303
|
+
function readbackJson(ctx, readback) {
|
|
304
|
+
const called = ctx.callFunction(readback, ctx.undefined);
|
|
305
|
+
if (called.error) {
|
|
306
|
+
const detail = ctx.dump(called.error);
|
|
307
|
+
called.error.dispose();
|
|
308
|
+
throw new Error(String(detail?.message ?? detail));
|
|
309
|
+
}
|
|
310
|
+
const dumped = ctx.dump(called.value);
|
|
311
|
+
called.value.dispose();
|
|
312
|
+
return String(dumped);
|
|
313
|
+
}
|
|
@@ -6,7 +6,7 @@ repurposed when human wording changes. New codes may be added; consumers must
|
|
|
6
6
|
handle an unknown code as a failure, without parsing prose.
|
|
7
7
|
|
|
8
8
|
**Rollout:** this contract is enforced for **`himi push`**, including `--only`,
|
|
9
|
-
first, for **`himi store iap connect`**, for **`himi site member-app`**, for **`himi fidelity`**, for the **`himi base44`** entity and function verbs, and for **`himi l10n import`**. Other subcommands still have legacy failures without codes and are a
|
|
9
|
+
first, for **`himi publish-size`**, for **`himi store iap connect`**, for **`himi site member-app`**, for **`himi fidelity`**, for the **`himi base44`** entity and function verbs, and for **`himi l10n import`**. Other subcommands still have legacy failures without codes and are a
|
|
10
10
|
follow-up migration. This is an additive change: existing `error`, `errors`,
|
|
11
11
|
`message`, `hint`, status, body, and gate-specific fields stay as they were.
|
|
12
12
|
Some legacy envelopes have no singular `error` or `hint`; consumers must not
|
|
@@ -47,6 +47,22 @@ keeps its existing fields and adds the code:
|
|
|
47
47
|
| `source_icon_unavailable` | Verified source evidence or its logo is missing, unreadable, unavailable, over the download/decoding budget, or cannot be normalized. |
|
|
48
48
|
| `source_icon_unusable` | The prepared source mark fails mechanical launcher/store checks. Existing icon files and metadata are left unchanged. |
|
|
49
49
|
|
|
50
|
+
## `himi publish-size` codes
|
|
51
|
+
|
|
52
|
+
This local planning command never claims or publishes. Every failure includes
|
|
53
|
+
`pushed: false` and `claimed: false`.
|
|
54
|
+
|
|
55
|
+
| Code | Meaning |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| `invalid_usage` | Unsupported, repeated, missing or invalid measurement options (exit 2). Publishing flags are refused. |
|
|
58
|
+
| `build_failed` | The contained local release could not be built completely, required host/network access, or the isolated build failed; measuring missing screens or bundles would undercount (exit 1). |
|
|
59
|
+
| `app_source_contains_secrets` | The shared source scanner found possible credentials (exit 1). |
|
|
60
|
+
| `app_source_too_large` | The base64 source archive exceeds its independent limit (exit 1). |
|
|
61
|
+
| `publish_body_too_large` | Measured draft JSON plus the explicit metadata planning reserve exceeds the publish budget (exit 1). `bodyBytes` and `overageBytes` describe the measured envelope; `planningBytes` and `planningOverageBytes` also include the reserve. |
|
|
62
|
+
|
|
63
|
+
`ok: true` means the measured draft plus its reserve fits. It does not certify
|
|
64
|
+
publication readiness or bound metadata not yet supplied to the final push.
|
|
65
|
+
|
|
50
66
|
## `himi one-app validate-payments` codes
|
|
51
67
|
|
|
52
68
|
| Code | Meaning |
|
|
@@ -58,6 +74,19 @@ keeps its existing fields and adds the code:
|
|
|
58
74
|
The checker validates recorded evidence and decisions; it does not independently
|
|
59
75
|
verify merchant readiness or create transactions. General publication remains unchanged.
|
|
60
76
|
|
|
77
|
+
## `himi one-app validate-identity` codes
|
|
78
|
+
|
|
79
|
+
| Code | Meaning |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `invalid_usage` | Missing, repeated or unsupported identity-check arguments. |
|
|
82
|
+
| `identity_source_unverified` | Collected source hashes or the business display name cannot be verified. Recollect older evidence that did not save business identity. |
|
|
83
|
+
| `identity_target_unverified` | The technical app slug, target compilation or complete built descriptors are unavailable. |
|
|
84
|
+
| `literal_slug_visible` | Built display text or the known business-chat identity seed contains the technical slug instead of the collected business identity, without matching exact authored source copy. |
|
|
85
|
+
|
|
86
|
+
The check reads built descriptors, not every possible runtime string. A passing
|
|
87
|
+
result does not verify dynamic live data, translations, branding images or device
|
|
88
|
+
appearance. It does not change publication or coverage policy.
|
|
89
|
+
|
|
61
90
|
## Push codes
|
|
62
91
|
|
|
63
92
|
| Code | Meaning |
|
|
@@ -16,7 +16,7 @@ Use this companion to the [Structure inference guide](https://apps.wix.com/_api/
|
|
|
16
16
|
- Existing screen builders often return a complete screen. Preserve the source inline placement using supported composition; do not replace a mixed source screen with an unrelated full vertical screen.
|
|
17
17
|
- Map data selectors, labels/media, design, permissions, CTA parameters and target destinations. The source definition's `settingsData.componentId` identifies a source editor component, not a Himalaya implementation or a complete settings schema.
|
|
18
18
|
|
|
19
|
-
Source snapshots: Catalyst `617c06d43d2a5608b6876d724553269b1e5346f0`; Himalaya `97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67`. GitHub references are pinned to these inspected versions. Recheck implementation contracts if using another version. No customer data was fetched, no app was generated, and no parity tests were run for
|
|
19
|
+
Source snapshots: Catalyst `617c06d43d2a5608b6876d724553269b1e5346f0`; Himalaya `97f1542f2f7d6e8cb7a902b912c87dcaa37e5a67`. GitHub references are pinned to these inspected versions. Recheck implementation contracts if using another version. No customer data was fetched, no app was generated, and no parity tests were run for the original documentation inventory. The Pages row now links the current source-selected editorial reconstruction recipe; its capture/decoder tests do not certify an individual app’s parity.
|
|
20
20
|
|
|
21
21
|
## Coverage summary
|
|
22
22
|
|
|
@@ -24,9 +24,9 @@ Source snapshots: Catalyst `617c06d43d2a5608b6876d724553269b1e5346f0`; Himalaya
|
|
|
24
24
|
| --- | ---: |
|
|
25
25
|
| Module | 13 |
|
|
26
26
|
| Primitive | 7 |
|
|
27
|
-
| Composition |
|
|
27
|
+
| Composition | 9 |
|
|
28
28
|
| Partial | 24 |
|
|
29
|
-
| Empty |
|
|
29
|
+
| Empty | 24 |
|
|
30
30
|
| Total | 77 |
|
|
31
31
|
|
|
32
32
|
## Mappings by server group
|
|
@@ -169,7 +169,7 @@ carousel placement remain separate gaps; the mappings above stay Partial.
|
|
|
169
169
|
|
|
170
170
|
| Source sectionDefinitionId | Source viewer component | Himalaya implementation | Placement / reuse | Class | Settings, actions and gaps |
|
|
171
171
|
| --- | --- | --- | --- | --- | --- |
|
|
172
|
-
| `pages_section` | `Pages.SectionPageClientScreen` |
|
|
172
|
+
| `pages_section` | `Pages.SectionPageClientScreen` | [Pages capture recipe](https://apps.wix.com/_api/himi-serve/docs/one-app-to-himi-app.md#referenced-pages-content) / `oneAppPageSection` | Editable inline native RichContent | Composition | Select `settings.value.pageId`; use the collector’s Visitor-only referenced read and `pages-content.json`. Preserve source placement order, text, formatting and links. Ready/empty captures can be reconstructed; missing, forbidden, malformed and unsupported captures remain explicit gaps. This is editorial reconstruction, not a live runtime Pages adapter. |
|
|
173
173
|
|
|
174
174
|
### 12. photoalbum-section-definitions.json
|
|
175
175
|
|
|
@@ -358,7 +358,6 @@ These are the exact definitions whose target cells above remain empty. “Not fo
|
|
|
358
358
|
| `loyalty-section-definitions.json` | `loyalty_status_section` | The existing Loyalty worker lists the program and rewards but does not load this member's points balance/tier/status. A rewards catalog is not a loyalty-status widget. |
|
|
359
359
|
| `referrals-section-definitions.json` | `referrals_refer_section` | No consumer referral-code/link sharing and referral-status feature was found. Do not map to Loyalty or generic sharing without a user decision. A visitor-readable program read exists; see the row above. |
|
|
360
360
|
| `referrals-section-definitions.json` | `referrals_description_section` | No referral-program description/data implementation was found. Text primitives alone do not resolve the business-bound referral content. A visitor-readable program read exists; see the row above. |
|
|
361
|
-
| `pages-section-definitions.json` | `pages_section` | No matching Wix Pages content fetch/render adapter was found. Generic CMS or RichContent renderers do not identify the original page entity or its data contract. |
|
|
362
361
|
| `photoalbum-section-definitions.json` | `photoAlbums_list_section` | Existing Photo Albums code is an empty-state placeholder with no album API wired. Pro Gallery uses a different data source and is not a substitute; choose an implementation explicitly. |
|
|
363
362
|
| `photoalbum-section-definitions.json` | `photoAlbums_photos_list` | Existing Photo Albums code is an empty-state placeholder with no album API wired. Pro Gallery uses a different data source and is not a substitute; choose an implementation explicitly. |
|
|
364
363
|
| `photoalbum-section-definitions.json` | `photoAlbums_carousel_section` | Existing Photo Albums code is an empty-state placeholder with no album API wired. Pro Gallery uses a different data source and is not a substitute; choose an implementation explicitly. |
|
|
@@ -116,6 +116,15 @@ user request. Preserve the collected files as evidence. Read the [versioned
|
|
|
116
116
|
reference index](https://apps.wix.com/_api/himi-serve/docs/one-app-reference.md) and its five guides before interpreting
|
|
117
117
|
settings or claiming coverage.
|
|
118
118
|
|
|
119
|
+
When raw source placements reference `pages_section`, collection also saves
|
|
120
|
+
`pages-content.json`. It selects `settings.value.pageId`, reads only those unique
|
|
121
|
+
documents as the site's Visitor, and retains every original placement separately.
|
|
122
|
+
The evidence records capture time, source identity, a serialized response JSON SHA-256,
|
|
123
|
+
decoded content and an editable native RichContent component per placement.
|
|
124
|
+
The hash identifies that captured response, not an invented server revision.
|
|
125
|
+
Recollect to refresh editorial content; a changed response produces a changed hash.
|
|
126
|
+
Never import the evidence directory into runtime code.
|
|
127
|
+
|
|
119
128
|
An unavailable supporting runtime view is recorded as `runtime_context_unavailable`
|
|
120
129
|
with its platform and typed failure code; that enriched file is absent. Continue
|
|
121
130
|
from authored intent and mark the platform behavior as unverified in the report.
|
|
@@ -500,16 +509,69 @@ Apply these interpretation rules:
|
|
|
500
509
|
alone does not prove native navigation or control availability. Record any
|
|
501
510
|
unavailable device check as unverified.
|
|
502
511
|
- Business context contains `phoneNumber`, `website`, `services`, optional public
|
|
503
|
-
`contact`,
|
|
504
|
-
|
|
512
|
+
`contact`, an optional validated public `memberCount`, and optional `displayName`
|
|
513
|
+
from the same-site Business title, with their permitted nested values.
|
|
514
|
+
Use `displayName` for business identity; structure wins on authored screen titles,
|
|
515
|
+
phone/URL/design.
|
|
505
516
|
Installed services do not add features. Installation IDs are not record IDs.
|
|
506
|
-
Do not restore excluded Business
|
|
517
|
+
Do not restore other excluded Business colors, identity or member fields.
|
|
507
518
|
- Referenced editor-authored documents, such as Pages rich text, are presentation
|
|
508
519
|
evidence too. Fetch only the referenced documents through verified read-only
|
|
509
520
|
routes, record their IDs and versions, and reconstruct their authored content
|
|
510
521
|
as editable native components. Keep changing business records live; do not
|
|
511
522
|
substitute captured catalogs, memberships or transaction data for runtime reads.
|
|
512
523
|
|
|
524
|
+
### Referenced Pages content
|
|
525
|
+
|
|
526
|
+
`pages_section` is an editor-authored document selected by
|
|
527
|
+
`settings.value.pageId`. It is not a CMS collection, Blog post or placeholder.
|
|
528
|
+
Use `pages-content.json` to reconstruct each ready placement as editable app
|
|
529
|
+
source, in its original layout array order, interleaved with the other sections.
|
|
530
|
+
Repeated page IDs may share one captured document but retain separate placement
|
|
531
|
+
IDs. Preserve source visibility/access rules and every screen alias that uses
|
|
532
|
+
that layout; do not multiply canonical placements by navigation aliases.
|
|
533
|
+
|
|
534
|
+
The collector's fixed read is
|
|
535
|
+
`GET https://apps.wix.com/social-content/api/v1/pages/{pageId}` using the source
|
|
536
|
+
site's Visitor signed instance. The response contains
|
|
537
|
+
`{pageId, content: {title, body: {contentType, content}}}`. It verifies the returned
|
|
538
|
+
page ID. `RICH_CONTENT` and `DRAFTJS` contain serialized JSON; `PLAIN_TEXT` stays
|
|
539
|
+
literal. The pinned [original reader](https://github.com/wix-private/wix-one-app-pages/blob/5055bf29109c51c48f0009a403bb70976c54e8dc/packages/wix-one-app-pages/src/services/pages-api.ts "audience-lint-ok: optional pinned upstream evidence, not a local authoring dependency") documents this contract.
|
|
540
|
+
No page listing, source mutation or manager credential fallback is needed.
|
|
541
|
+
|
|
542
|
+
Use the emitted `placement.component`, or rebuild it with the screens SDK's
|
|
543
|
+
`decodeOneAppPage(response, pageId)` and `oneAppPageSection(page, {id})`.
|
|
544
|
+
Copy the resulting component into an editable app source file, then insert it
|
|
545
|
+
into the actual generated screen's payload. Keep it outside collection-bound
|
|
546
|
+
rows that a worker replaces on load. Rendering a separate unused sample or merely
|
|
547
|
+
changing the catalog classification does not restore a migrated placement.
|
|
548
|
+
The component uses literal `RichContent.documentJson`; no source prose is a
|
|
549
|
+
service binding. The existing viewer preserves text, supported formatting, media
|
|
550
|
+
and safe http(s)/mailto/tel links. Legacy bare website domains gain HTTPS before
|
|
551
|
+
encoding; `normalizedWebsiteLinks` records the count. Relative paths, credentials
|
|
552
|
+
and unsafe schemes do not gain an implicit origin. Root editor metadata is omitted from rendered
|
|
553
|
+
content. Keep normal RichContent links or use the existing rich-link handler;
|
|
554
|
+
do not replace them with generic navigation or a WebView.
|
|
555
|
+
|
|
556
|
+
`ready` and genuine `empty` are successful captures. The section helper renders an
|
|
557
|
+
empty page's message from optional `emptyTitle` / `emptyDescription`; localize
|
|
558
|
+
that copy to the app and preserve the source empty-state intent. `invalid` (including missing
|
|
559
|
+
or malformed selectors/content), `unsupported`, `forbidden`, `unauthorized`,
|
|
560
|
+
`not_found` and `unavailable` remain distinct gaps. A failed document has no
|
|
561
|
+
emitted component. Preserve the gap and resolve it before claiming its coverage;
|
|
562
|
+
never substitute an empty paragraph, demo copy or owner read. Supported DraftJS
|
|
563
|
+
text, styled links, flat lists, headings and images are converted; nested lists
|
|
564
|
+
and unknown plugins remain explicit `unsupported` gaps.
|
|
565
|
+
|
|
566
|
+
This reconstruction captures editorial presentation only. Changing catalogs,
|
|
567
|
+
transactions and member records remain live. It uses the existing cross-platform
|
|
568
|
+
RichContent component and does not require a new Pages endpoint in native/web
|
|
569
|
+
runtime transports. A CLI/SDK source merge still needs its normal publication,
|
|
570
|
+
and an existing customer app must be regenerated, checked and published before
|
|
571
|
+
its text changes. Validate the actual generated screens and record every source
|
|
572
|
+
placement's text/link and native checks in the coverage ledger; collection alone
|
|
573
|
+
is not customer acceptance or permission to mark all rows supported.
|
|
574
|
+
|
|
513
575
|
### Navigation from top tabs
|
|
514
576
|
|
|
515
577
|
`navigation-plan.json` records the source navigation kind and the planned target.
|
|
@@ -984,6 +1046,43 @@ cannot be inspected: call the builder in your generator and serialize the value
|
|
|
984
1046
|
returns. Run the generator inside the app (after `npm install`), so
|
|
985
1047
|
`@wix/himalaya/screens` resolves to the app's own dependency.
|
|
986
1048
|
|
|
1049
|
+
### Preserve the template features the source exposes
|
|
1050
|
+
|
|
1051
|
+
Treat trimming as a source-feature decision, not a list of screens reached during
|
|
1052
|
+
one visitor walkthrough. Before removing a template destination, compare the source
|
|
1053
|
+
Account and native widget journeys under the appropriate visitor/member state.
|
|
1054
|
+
Keep the supported destination and its data/permission contract when the source
|
|
1055
|
+
exposes it. Do not add unrelated verticals merely because the template has them.
|
|
1056
|
+
|
|
1057
|
+
| Source feature | Preserve in the generated app |
|
|
1058
|
+
| --- | --- |
|
|
1059
|
+
| Business identity | Use the collected `business-context.json.displayName` for business identity and bind live chat header/sender/app-info values to the actual business or host state. Preserve the source logo as an image or image binding. Keep the authored app/screen title separate. The technical app slug is an identifier, not a replacement display name. Avoid a global string replacement across source, routes and URLs. |
|
|
1060
|
+
| Account Orders and Subscriptions | Retain source-exposed My activity links and their supported `himi_orders` / `himi_my_subscriptions` destinations, including their workers and sign-in/return routing. A visitor gate is not evidence that a member destination should be deleted. Installed services alone do not prove source exposure; compare the source Account. |
|
|
1061
|
+
| Programs | Reuse the supported Program card/detail and worker behavior. Preserve access type and the actual login/request/join/pay/Continue action for the visitor or participant state. Do not replace these with an image/title-only card or a generic authenticated Continue. Preserve paid/private policy; do not invoke a live purchase or membership mutation as part of a read-only comparison. |
|
|
1062
|
+
| Feed attachments | Reuse the template's rich post card and its `RichContent`/attachment presentation. Preserve inline images, files and their destinations together with text and actions. A text-only replacement is a functional loss even when it can read the post body. |
|
|
1063
|
+
|
|
1064
|
+
After applying identity and before claiming completion, run:
|
|
1065
|
+
|
|
1066
|
+
```sh
|
|
1067
|
+
himi one-app validate-identity --evidence-dir .himi/one-app --content . --json
|
|
1068
|
+
```
|
|
1069
|
+
|
|
1070
|
+
The command verifies the collected business-name hash, builds the current content,
|
|
1071
|
+
and checks emitted screen titles, supported component display fields and the known
|
|
1072
|
+
business-chat identity seed for accidental literal slugs. It ignores route IDs,
|
|
1073
|
+
URLs and arbitrary API/action values. Exact authored source copy containing the
|
|
1074
|
+
slug and a real business whose display name is its slug are preserved. An unrelated
|
|
1075
|
+
source page title cannot waive the business-chat identity or its name seed. An older
|
|
1076
|
+
collection without a business display name remains unverified; recollect rather
|
|
1077
|
+
than editing its evidence or guessing a name.
|
|
1078
|
+
|
|
1079
|
+
This is a narrow identity check. It cannot prove every dynamic or translated
|
|
1080
|
+
string, branding image, account journey, access policy or attachment is correct.
|
|
1081
|
+
Inspect the actual generated descriptors and workers, exercise recorded examples,
|
|
1082
|
+
then compare those four source journeys in the real host. Keep their missing
|
|
1083
|
+
behavior explicit in coverage and the report. A stock template screenshot or a
|
|
1084
|
+
passing identity check cannot substitute for the fresh reconstruction/device pass.
|
|
1085
|
+
|
|
987
1086
|
### Screen-content contract
|
|
988
1087
|
|
|
989
1088
|
Use the current [screen design guide](https://apps.wix.com/_api/himi-serve/docs/designing-himi-screens.md) and the app's
|
|
@@ -1108,6 +1207,116 @@ configuration, workers, evidence, screenshots or logs.
|
|
|
1108
1207
|
|
|
1109
1208
|
## 4. Verify the reconstructed app and publish its draft
|
|
1110
1209
|
|
|
1210
|
+
### Check the publish budget before final evidence
|
|
1211
|
+
|
|
1212
|
+
Plan for the **8,388,608-byte** publish JSON budget before spending time on final
|
|
1213
|
+
screenshots, behavioral runs or native UX records. `.himi` file size and source
|
|
1214
|
+
directory totals are different measurements: publication carries JSON-escaped
|
|
1215
|
+
descriptors, base64 bundles/assets/icon and the compressed source archive together.
|
|
1216
|
+
|
|
1217
|
+
First repoint navigation and retained detail/back-link destinations at the implemented
|
|
1218
|
+
generated screens, including destination IDs configured in shared workers. Keep every required
|
|
1219
|
+
source journey and its shared destinations in `SPEC.md`'s Screen catalogue, including
|
|
1220
|
+
cart, checkout, authentication and detail routes. Inspect a trim plan before applying it:
|
|
1221
|
+
|
|
1222
|
+
```sh
|
|
1223
|
+
himi template trim --from-spec SPEC.md --links follow --dry-run
|
|
1224
|
+
```
|
|
1225
|
+
|
|
1226
|
+
Review the retained/removed screens, workers and navigation. Trim only unused template
|
|
1227
|
+
definitions that the generated screens replace; `--links follow` can retain linked
|
|
1228
|
+
destinations that still matter. Review `workerRefs` and `reparented` results, and preserve
|
|
1229
|
+
overflow entries and back navigation instead of accepting their deletion. Do not remove a required vertical or drop its actions
|
|
1230
|
+
merely to fit. Apply the same reviewed command without `--dry-run`, then measure:
|
|
1231
|
+
|
|
1232
|
+
```sh
|
|
1233
|
+
himi publish-size --app <intended-publish-slug> --json
|
|
1234
|
+
```
|
|
1235
|
+
|
|
1236
|
+
This builds locally using the same release payload, source collector and JSON serializer
|
|
1237
|
+
as push. It never looks up an owner, claims a slug or publishes; no credentials or final
|
|
1238
|
+
UX/attestation records are required. It can write local build output. It reports
|
|
1239
|
+
`bodyBytes`, `limit`, `remainingBytes`, `overageBytes`, source archive bytes and screen/
|
|
1240
|
+
bundle counts. Failed static record-ID enumeration, missing declared icons/screens/bundles, unavailable font assets, failed declared widgets
|
|
1241
|
+
and failed token snapshots are refused instead of undercounted. The builder's optional
|
|
1242
|
+
token absence (404) is reported without inventing token bytes; it does not certify styling.
|
|
1243
|
+
The default `reserveBytes` is a **65,536-byte planning allowance** for final metadata;
|
|
1244
|
+
`planningBytes` includes it. `--reserve-bytes <n>` changes that allowance.
|
|
1245
|
+
|
|
1246
|
+
Measurement uses an isolated contained build: put the intended configuration and
|
|
1247
|
+
collected static seed IDs in the package explicitly. Host environment substitutions
|
|
1248
|
+
are not its input. A source module that needs host code or live catalog enumeration
|
|
1249
|
+
is refused as `build_failed`; materialize the verified source IDs from the collection
|
|
1250
|
+
before measuring, or report that prerequisite as blocked. Never swallow that refusal
|
|
1251
|
+
and treat missing detail screens as saved bytes.
|
|
1252
|
+
|
|
1253
|
+
`bodyBytes` is exact for the stated slug, source-included draft and **no publish metadata**.
|
|
1254
|
+
The allowance is not a verified upper bound: final label/notes, evidence and migration
|
|
1255
|
+
metadata must fit within the remaining bytes. A changed slug changes both app fields;
|
|
1256
|
+
`minimumBodyBytes` uses empty slugs and no metadata as a lower bound. If even that exceeds
|
|
1257
|
+
the limit, unknown owner metadata cannot rescue the build. A passing size check is
|
|
1258
|
+
conditional on those remaining bytes; the final push still measures its exact envelope
|
|
1259
|
+
and runs every evidence gate. The push command has no size-only dry run; use the
|
|
1260
|
+
measurement command for probes. Transport compression is not evidence that the current push guard accepts
|
|
1261
|
+
an oversized JSON body.
|
|
1262
|
+
|
|
1263
|
+
Init-generated `.agents/`, `.claude/` and `HIMALAYA.md` are already excluded by the
|
|
1264
|
+
source archive policy shown in `himi push --help`.
|
|
1265
|
+
Keep source included; do not work around the budget with `--no-source` or `--force`.
|
|
1266
|
+
|
|
1267
|
+
For a large static 8-bit PNG icon, lossless recompression is optional. Keep the original and candidate
|
|
1268
|
+
under `.himi/` while checking, use no resize, palette reduction, quantization or lossy
|
|
1269
|
+
format, and prove decoded RGBA pixels, dimensions and color profile are unchanged before
|
|
1270
|
+
replacing the declared icon. For example, with the optional `sharp` image tool installed
|
|
1271
|
+
locally (`npm install --prefix .himi/pixel-tools --no-save --package-lock=false sharp@0.33.5`):
|
|
1272
|
+
|
|
1273
|
+
```sh
|
|
1274
|
+
node --input-type=module - <declared-icon.png> .himi/icon-lossless.png <<'JS'
|
|
1275
|
+
import assert from 'node:assert/strict';
|
|
1276
|
+
import { createRequire } from 'node:module';
|
|
1277
|
+
import { createHash } from 'node:crypto';
|
|
1278
|
+
import { resolve } from 'node:path';
|
|
1279
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
1280
|
+
const sharp = createRequire(resolve('.himi/pixel-tools/tool.cjs'))('sharp');
|
|
1281
|
+
const [input, output] = process.argv.slice(2);
|
|
1282
|
+
assert.notEqual(resolve(input), resolve(output), 'preserve the original');
|
|
1283
|
+
const beforeMeta = await sharp(input).metadata();
|
|
1284
|
+
assert.equal(beforeMeta.format, 'png');
|
|
1285
|
+
assert.equal(beforeMeta.depth, 'uchar', 'retain higher-precision originals');
|
|
1286
|
+
assert.equal(beforeMeta.pages ?? 1, 1, 'retain animated originals');
|
|
1287
|
+
const before = await sharp(input).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
1288
|
+
await sharp(input).keepMetadata().png({ compressionLevel: 9, adaptiveFiltering: true, palette: false }).toFile(output);
|
|
1289
|
+
const afterMeta = await sharp(output).metadata();
|
|
1290
|
+
const after = await sharp(output).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
1291
|
+
assert.deepEqual(after.info, before.info);
|
|
1292
|
+
assert.deepEqual(afterMeta.icc, beforeMeta.icc);
|
|
1293
|
+
assert.equal(afterMeta.orientation ?? 1, beforeMeta.orientation ?? 1);
|
|
1294
|
+
assert.ok(after.data.equals(before.data), 'decoded RGBA pixels must match exactly');
|
|
1295
|
+
const hash = bytes => createHash('sha256').update(bytes).digest('hex');
|
|
1296
|
+
console.log(JSON.stringify({ pixelsEqual: true, width: after.info.width, height: after.info.height,
|
|
1297
|
+
channels: after.info.channels, beforeBytes: statSync(input).size, afterBytes: statSync(output).size,
|
|
1298
|
+
beforeSHA256: hash(readFileSync(input)), afterSHA256: hash(readFileSync(output)), rgbaSHA256: hash(after.data) }));
|
|
1299
|
+
JS
|
|
1300
|
+
```
|
|
1301
|
+
|
|
1302
|
+
Only copy the candidate over the declared icon if that proof passes and the file is
|
|
1303
|
+
smaller. If the tool is unavailable, retain the original and report that optimization
|
|
1304
|
+
as unverified. Re-run `himi icon check`, size measurement and affected visual checks
|
|
1305
|
+
after replacing it. Save the equality result and original/candidate hashes.
|
|
1306
|
+
|
|
1307
|
+
If required journeys still exceed the budget, stop before final evidence and report the
|
|
1308
|
+
measured bytes, limit and overage, source archive size, major contributing journeys/
|
|
1309
|
+
assets, reviewed trim results, compression/pixel proof, what was tried and what was
|
|
1310
|
+
preserved. Attach the numerical output and sanitized manifest/inventory; file sizes can
|
|
1311
|
+
explain contributors but never substitute for the assembled measurement. Hand this to
|
|
1312
|
+
the migration project owner for the maintained
|
|
1313
|
+
[Himalaya issue tracker](https://github.com/wix-private/himalaya/issues) (repository access
|
|
1314
|
+
required). If you lack access, return the prepared report to that owner for escalation;
|
|
1315
|
+
do not guess a person's contact or claim a hosted preview exists. This step does not
|
|
1316
|
+
authorize posting an issue, changing the server limit or publishing.
|
|
1317
|
+
|
|
1318
|
+
### Run the final checks
|
|
1319
|
+
|
|
1111
1320
|
After the source composition and same-site binding are implemented, use the
|
|
1112
1321
|
existing authoring loop:
|
|
1113
1322
|
|
|
@@ -1210,9 +1419,8 @@ himi push --draft --target bo
|
|
|
1210
1419
|
Keep the editable source archive included. The publish body is limited to 8,388,608
|
|
1211
1420
|
bytes. It is about base64(source archive + worker bundles + assets + icons) plus the
|
|
1212
1421
|
descriptor JSON, so a large app can exceed it: one 33-page migration measured
|
|
1213
|
-
11,259,935 bytes. Measure early, not at the end
|
|
1214
|
-
|
|
1215
|
-
paths below. `himi push` refuses an oversized body locally, before it sends anything,
|
|
1422
|
+
11,259,935 bytes. Measure early, not at the end, with `himi publish-size` (see
|
|
1423
|
+
"Check the publish budget before final evidence"). `himi push` refuses an oversized body locally, before it sends anything,
|
|
1216
1424
|
with `publish_body_too_large`; its `breakdown`
|
|
1217
1425
|
gives each part's bytes (`appSource`, `screens`, `bundles`, `assets`, `icon`, `other`)
|
|
1218
1426
|
and the largest entries by name. Reduce it in this order, and repeat affected
|