@wix/himalaya-cli 0.945.0 → 0.947.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 +13 -0
- package/package.json +2 -2
- package/templates/beauty-salon/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/beauty-salon-owner/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-home/index.ts +7 -3
- package/templates/branded-lite/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/community-club/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/community-club-owner/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/community-club-owner/tier5-src/himi-owner-lite-home/index.ts +7 -3
- package/templates/events-meetups/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/events-meetups-owner/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-home/index.ts +7 -3
- package/templates/gym-fitness/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/gym-fitness-owner/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-home/index.ts +7 -3
- package/templates/himi-chat/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/nonprofit-cause/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-home/index.ts +7 -3
- package/templates/owner-lite/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/owner-lite/tier5-src/himi-owner-lite-home/index.ts +7 -3
- package/templates/podcast-creator/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/podcast-creator-owner/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-home/index.ts +7 -3
- package/templates/portfolio-creative/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/portfolio-creative-owner/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-home/index.ts +7 -3
- package/templates/restaurant/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/restaurant-owner/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-home/index.ts +7 -3
- package/templates/retail-store/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/retail-store-owner/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-home/index.ts +7 -3
- package/templates/yoga-studio/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/yoga-studio-owner/tier5-src/_shared/owner-load-error.ts +68 -24
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-home/index.ts +7 -3
package/dist/cli.mjs
CHANGED
|
@@ -55607,6 +55607,17 @@ var TERMINAL_DIST_STATUSES = /* @__PURE__ */ new Set([
|
|
|
55607
55607
|
"BLOCKED",
|
|
55608
55608
|
"STATUS_UNKNOWN"
|
|
55609
55609
|
]);
|
|
55610
|
+
function shellShaDivergenceWarnings(jobs) {
|
|
55611
|
+
const seen = /* @__PURE__ */ new Map();
|
|
55612
|
+
for (const j of jobs) {
|
|
55613
|
+
const release = typeof j.release === "string" ? j.release : void 0;
|
|
55614
|
+
const built = typeof j.gitCommitSha === "string" ? j.gitCommitSha : void 0;
|
|
55615
|
+
if (j.shellShaSource === "release" && release && built && release !== built) seen.set(release, built);
|
|
55616
|
+
}
|
|
55617
|
+
return [...seen].map(
|
|
55618
|
+
([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.`
|
|
55619
|
+
);
|
|
55620
|
+
}
|
|
55610
55621
|
function materializeForPreview(appDir2, slug, displayName) {
|
|
55611
55622
|
if (!isTemplateSourceTree(appDir2)) return appDir2;
|
|
55612
55623
|
const files = readTemplateFiles(appDir2);
|
|
@@ -59821,6 +59832,7 @@ ${label2}`);
|
|
|
59821
59832
|
return 1;
|
|
59822
59833
|
}
|
|
59823
59834
|
const jobs = r.json?.jobs ?? [];
|
|
59835
|
+
for (const line of shellShaDivergenceWarnings(jobs)) (flags.json === true ? io.error : io.log)(line);
|
|
59824
59836
|
const noWait = flags["no-wait"] === true || flags.wait === false;
|
|
59825
59837
|
if (noWait) {
|
|
59826
59838
|
print({ status: r.status, ...r.json ?? {} });
|
|
@@ -60760,6 +60772,7 @@ export {
|
|
|
60760
60772
|
serveUnreachableError,
|
|
60761
60773
|
serveUnreachableHint,
|
|
60762
60774
|
servesAll,
|
|
60775
|
+
shellShaDivergenceWarnings,
|
|
60763
60776
|
switchFlagErrors,
|
|
60764
60777
|
templatePreviewAuthError,
|
|
60765
60778
|
tokenCoversApp,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.947.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": [
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"artifactId": "himalaya-cli"
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
|
-
"falconPackageHash": "
|
|
67
|
+
"falconPackageHash": "e6f6c45f77b9ba2728e1098c0c46b7d7eb3e6fb922394d52a0797dd7"
|
|
68
68
|
}
|
|
@@ -53,6 +53,17 @@ const HTML_BODY = /<!DOCTYPE html|<html[\s>]|<head[\s>]/i;
|
|
|
53
53
|
* "app":"…"}` — and it is short enough to slip under MAX_RAW, so truncation
|
|
54
54
|
* never caught it and the owner read the machine's word for it. */
|
|
55
55
|
const JSON_BODY = /HTTP \d{3}:\s*[[{]/;
|
|
56
|
+
/** `HTTP <status> [SERVICE_CODE]: message` — the shape a Wix service uses when
|
|
57
|
+
* it refuses with a named reason. */
|
|
58
|
+
const CODED = /HTTP (\d{3}) \[([A-Z0-9_]+)\]/;
|
|
59
|
+
/**
|
|
60
|
+
* The codes that all mean one thing to an owner: the session cannot address this
|
|
61
|
+
* business. Found on a real session whose account did not own the business the app
|
|
62
|
+
* had persisted — Home rendered
|
|
63
|
+
* `HTTP 428 [MISSING_METASITE_ID]: Couldn't extract metasiteId from the request
|
|
64
|
+
* context` where "6 orders" belongs.
|
|
65
|
+
*/
|
|
66
|
+
const SITE_CONTEXT_CODES = ["MISSING_METASITE_ID", "MISSING_REQUEST_SITE_CONTEXT", "MISSING_SITE_CONTEXT"];
|
|
56
67
|
/** Longest raw upstream text worth showing. Beyond this it stops being a
|
|
57
68
|
* message and starts being a payload dump. */
|
|
58
69
|
const MAX_RAW = 200;
|
|
@@ -69,6 +80,29 @@ const MAX_RAW = 200;
|
|
|
69
80
|
*/
|
|
70
81
|
function humanWireError(msg: string): string {
|
|
71
82
|
const status = STATUS.exec(msg)?.[1];
|
|
83
|
+
// A JSON ENVELOPE or a NAMED REASON CODE is the machine's word for it, and the
|
|
84
|
+
// owner gets neither. Both reductions used to live in `ownerDisplayError` only,
|
|
85
|
+
// on the belief that this function's output was parsed downstream — see the note
|
|
86
|
+
// on `ownerLoadError`, which records why that was wrong and how it was checked.
|
|
87
|
+
if (JSON_BODY.test(msg) && status) {
|
|
88
|
+
return copyParam(
|
|
89
|
+
"ownerCommon.upstreamStatus",
|
|
90
|
+
`Wix returned an error (HTTP ${status}). Try again in a moment.`,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
const coded = CODED.exec(msg);
|
|
94
|
+
if (coded) {
|
|
95
|
+
if (SITE_CONTEXT_CODES.includes(coded[2])) {
|
|
96
|
+
return copyParam(
|
|
97
|
+
"ownerCommon.noSiteContext",
|
|
98
|
+
"This business isn’t available to your Wix account right now. Switch business, or sign in again as its owner.",
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return copyParam(
|
|
102
|
+
"ownerCommon.upstreamStatus",
|
|
103
|
+
`Wix returned an error (HTTP ${coded[1]}). Try again in a moment.`,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
72
106
|
if (HTML_BODY.test(msg)) {
|
|
73
107
|
if (status === "403") {
|
|
74
108
|
return copyParam(
|
|
@@ -101,36 +135,46 @@ export function ownerPreviewUnavailable(): string {
|
|
|
101
135
|
/**
|
|
102
136
|
* `ownerLoadError` for a screen that does nothing but RENDER the string.
|
|
103
137
|
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* native write-behind (`shouldQueueOwnerWrite`) depends on exactly it.
|
|
138
|
+
* One difference left, and it is about WHERE the app is rather than what the
|
|
139
|
+
* error says: this names the web preview when there IS one. `isBridgeUnavailable`
|
|
140
|
+
* reads "not live" as "preview", and native injects no mode at all, so the
|
|
141
|
+
* default would answer a device-side `HTTP 503` with "open this app on a device"
|
|
142
|
+
* — on the device. That predicate is deliberately left alone: native
|
|
143
|
+
* write-behind (`shouldQueueOwnerWrite`) depends on exactly it.
|
|
111
144
|
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* `CATALOG_V3_CALLING_CATALOG_V1_API` in it to choose its v1 fallback, and
|
|
115
|
-
* `owner-load-error.test.ts` pins that verbatim. A display-only caller has
|
|
116
|
-
* no such reader, and the bridge's typed refusals are JSON and short enough
|
|
117
|
-
* (68 chars) to slip under MAX_RAW, so nothing else was catching them.
|
|
118
|
-
*
|
|
119
|
-
* So: use this ONLY where the value is rendered and never matched on.
|
|
145
|
+
* The reductions this used to add are now in `humanWireError`, so every owner
|
|
146
|
+
* screen gets them rather than the two that happened to call this.
|
|
120
147
|
*/
|
|
121
148
|
export function ownerDisplayError(e: unknown): string {
|
|
122
149
|
if (isOwnerPreviewHost() && isBridgeUnavailable(e)) return ownerPreviewUnavailable();
|
|
123
|
-
|
|
124
|
-
const status = STATUS.exec(msg)?.[1];
|
|
125
|
-
if (JSON_BODY.test(msg) && status) {
|
|
126
|
-
return copyParam(
|
|
127
|
-
"ownerCommon.upstreamStatus",
|
|
128
|
-
`Wix returned an error (HTTP ${status}). Try again in a moment.`,
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
return humanWireError(msg);
|
|
150
|
+
return humanWireError(String((e as Error)?.message ?? e));
|
|
132
151
|
}
|
|
133
152
|
|
|
153
|
+
/**
|
|
154
|
+
* The default. Reduces the same shapes as `ownerDisplayError`.
|
|
155
|
+
*
|
|
156
|
+
* It used to reduce LESS, on the stated grounds that its output is parsed
|
|
157
|
+
* downstream — "the products worker matches `CATALOG_V3_CALLING_CATALOG_V1_API`
|
|
158
|
+
* in it to choose its v1 fallback". **That was not true**, and it cost 17 owner
|
|
159
|
+
* screens their error copy: they printed `HTTP 428 [MISSING_METASITE_ID]: …`
|
|
160
|
+
* verbatim for a contract that does not exist.
|
|
161
|
+
*
|
|
162
|
+
* Checked before changing it, and worth recording so nobody restores the belief:
|
|
163
|
+
*
|
|
164
|
+
* • the catalog v1/v3 decision is made INSIDE the Wix stores SDK, on the RAW
|
|
165
|
+
* thrown error — its `catalogVersionFromMismatch` reads the error's own
|
|
166
|
+
* `message`, and only that module calls it. It never sees this function's
|
|
167
|
+
* output.
|
|
168
|
+
* • `CATALOG_V3_CALLING_CATALOG_V1_API` appears nowhere else in the codebase
|
|
169
|
+
* outside comments, tests and that one SDK module.
|
|
170
|
+
* • the collection framework's `clearOnError` is handed the RAW error
|
|
171
|
+
* (`error => /401|403|forbidden/i.test(String(error))`), separately from
|
|
172
|
+
* `errorMessage: ownerLoadError` — so the one place that does match on a
|
|
173
|
+
* failure is unaffected by what this returns.
|
|
174
|
+
*
|
|
175
|
+
* So: the raw error remains available to logic everywhere it was; this function's
|
|
176
|
+
* result is display copy, and now reads like it.
|
|
177
|
+
*/
|
|
134
178
|
export function ownerLoadError(e: unknown): string {
|
|
135
179
|
const msg = String((e as Error)?.message ?? e);
|
|
136
180
|
if (isBridgeUnavailable(e)) return ownerPreviewUnavailable();
|
|
@@ -53,6 +53,17 @@ const HTML_BODY = /<!DOCTYPE html|<html[\s>]|<head[\s>]/i;
|
|
|
53
53
|
* "app":"…"}` — and it is short enough to slip under MAX_RAW, so truncation
|
|
54
54
|
* never caught it and the owner read the machine's word for it. */
|
|
55
55
|
const JSON_BODY = /HTTP \d{3}:\s*[[{]/;
|
|
56
|
+
/** `HTTP <status> [SERVICE_CODE]: message` — the shape a Wix service uses when
|
|
57
|
+
* it refuses with a named reason. */
|
|
58
|
+
const CODED = /HTTP (\d{3}) \[([A-Z0-9_]+)\]/;
|
|
59
|
+
/**
|
|
60
|
+
* The codes that all mean one thing to an owner: the session cannot address this
|
|
61
|
+
* business. Found on a real session whose account did not own the business the app
|
|
62
|
+
* had persisted — Home rendered
|
|
63
|
+
* `HTTP 428 [MISSING_METASITE_ID]: Couldn't extract metasiteId from the request
|
|
64
|
+
* context` where "6 orders" belongs.
|
|
65
|
+
*/
|
|
66
|
+
const SITE_CONTEXT_CODES = ["MISSING_METASITE_ID", "MISSING_REQUEST_SITE_CONTEXT", "MISSING_SITE_CONTEXT"];
|
|
56
67
|
/** Longest raw upstream text worth showing. Beyond this it stops being a
|
|
57
68
|
* message and starts being a payload dump. */
|
|
58
69
|
const MAX_RAW = 200;
|
|
@@ -69,6 +80,29 @@ const MAX_RAW = 200;
|
|
|
69
80
|
*/
|
|
70
81
|
function humanWireError(msg: string): string {
|
|
71
82
|
const status = STATUS.exec(msg)?.[1];
|
|
83
|
+
// A JSON ENVELOPE or a NAMED REASON CODE is the machine's word for it, and the
|
|
84
|
+
// owner gets neither. Both reductions used to live in `ownerDisplayError` only,
|
|
85
|
+
// on the belief that this function's output was parsed downstream — see the note
|
|
86
|
+
// on `ownerLoadError`, which records why that was wrong and how it was checked.
|
|
87
|
+
if (JSON_BODY.test(msg) && status) {
|
|
88
|
+
return copyParam(
|
|
89
|
+
"ownerCommon.upstreamStatus",
|
|
90
|
+
`Wix returned an error (HTTP ${status}). Try again in a moment.`,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
const coded = CODED.exec(msg);
|
|
94
|
+
if (coded) {
|
|
95
|
+
if (SITE_CONTEXT_CODES.includes(coded[2])) {
|
|
96
|
+
return copyParam(
|
|
97
|
+
"ownerCommon.noSiteContext",
|
|
98
|
+
"This business isn’t available to your Wix account right now. Switch business, or sign in again as its owner.",
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return copyParam(
|
|
102
|
+
"ownerCommon.upstreamStatus",
|
|
103
|
+
`Wix returned an error (HTTP ${coded[1]}). Try again in a moment.`,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
72
106
|
if (HTML_BODY.test(msg)) {
|
|
73
107
|
if (status === "403") {
|
|
74
108
|
return copyParam(
|
|
@@ -101,36 +135,46 @@ export function ownerPreviewUnavailable(): string {
|
|
|
101
135
|
/**
|
|
102
136
|
* `ownerLoadError` for a screen that does nothing but RENDER the string.
|
|
103
137
|
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* native write-behind (`shouldQueueOwnerWrite`) depends on exactly it.
|
|
138
|
+
* One difference left, and it is about WHERE the app is rather than what the
|
|
139
|
+
* error says: this names the web preview when there IS one. `isBridgeUnavailable`
|
|
140
|
+
* reads "not live" as "preview", and native injects no mode at all, so the
|
|
141
|
+
* default would answer a device-side `HTTP 503` with "open this app on a device"
|
|
142
|
+
* — on the device. That predicate is deliberately left alone: native
|
|
143
|
+
* write-behind (`shouldQueueOwnerWrite`) depends on exactly it.
|
|
111
144
|
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* `CATALOG_V3_CALLING_CATALOG_V1_API` in it to choose its v1 fallback, and
|
|
115
|
-
* `owner-load-error.test.ts` pins that verbatim. A display-only caller has
|
|
116
|
-
* no such reader, and the bridge's typed refusals are JSON and short enough
|
|
117
|
-
* (68 chars) to slip under MAX_RAW, so nothing else was catching them.
|
|
118
|
-
*
|
|
119
|
-
* So: use this ONLY where the value is rendered and never matched on.
|
|
145
|
+
* The reductions this used to add are now in `humanWireError`, so every owner
|
|
146
|
+
* screen gets them rather than the two that happened to call this.
|
|
120
147
|
*/
|
|
121
148
|
export function ownerDisplayError(e: unknown): string {
|
|
122
149
|
if (isOwnerPreviewHost() && isBridgeUnavailable(e)) return ownerPreviewUnavailable();
|
|
123
|
-
|
|
124
|
-
const status = STATUS.exec(msg)?.[1];
|
|
125
|
-
if (JSON_BODY.test(msg) && status) {
|
|
126
|
-
return copyParam(
|
|
127
|
-
"ownerCommon.upstreamStatus",
|
|
128
|
-
`Wix returned an error (HTTP ${status}). Try again in a moment.`,
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
return humanWireError(msg);
|
|
150
|
+
return humanWireError(String((e as Error)?.message ?? e));
|
|
132
151
|
}
|
|
133
152
|
|
|
153
|
+
/**
|
|
154
|
+
* The default. Reduces the same shapes as `ownerDisplayError`.
|
|
155
|
+
*
|
|
156
|
+
* It used to reduce LESS, on the stated grounds that its output is parsed
|
|
157
|
+
* downstream — "the products worker matches `CATALOG_V3_CALLING_CATALOG_V1_API`
|
|
158
|
+
* in it to choose its v1 fallback". **That was not true**, and it cost 17 owner
|
|
159
|
+
* screens their error copy: they printed `HTTP 428 [MISSING_METASITE_ID]: …`
|
|
160
|
+
* verbatim for a contract that does not exist.
|
|
161
|
+
*
|
|
162
|
+
* Checked before changing it, and worth recording so nobody restores the belief:
|
|
163
|
+
*
|
|
164
|
+
* • the catalog v1/v3 decision is made INSIDE the Wix stores SDK, on the RAW
|
|
165
|
+
* thrown error — its `catalogVersionFromMismatch` reads the error's own
|
|
166
|
+
* `message`, and only that module calls it. It never sees this function's
|
|
167
|
+
* output.
|
|
168
|
+
* • `CATALOG_V3_CALLING_CATALOG_V1_API` appears nowhere else in the codebase
|
|
169
|
+
* outside comments, tests and that one SDK module.
|
|
170
|
+
* • the collection framework's `clearOnError` is handed the RAW error
|
|
171
|
+
* (`error => /401|403|forbidden/i.test(String(error))`), separately from
|
|
172
|
+
* `errorMessage: ownerLoadError` — so the one place that does match on a
|
|
173
|
+
* failure is unaffected by what this returns.
|
|
174
|
+
*
|
|
175
|
+
* So: the raw error remains available to logic everywhere it was; this function's
|
|
176
|
+
* result is display copy, and now reads like it.
|
|
177
|
+
*/
|
|
134
178
|
export function ownerLoadError(e: unknown): string {
|
|
135
179
|
const msg = String((e as Error)?.message ?? e);
|
|
136
180
|
if (isBridgeUnavailable(e)) return ownerPreviewUnavailable();
|
|
@@ -13,7 +13,11 @@ import { queryMembers } from "@himalaya/wix-members";
|
|
|
13
13
|
import { queryReviews } from "@himalaya/wix-reviews";
|
|
14
14
|
import { queryReservations } from "@himalaya/wix-table-reservations";
|
|
15
15
|
import { getSiteAnalytics, getSiteTimeZone, localDateRange, localDateOf, localMidnightUtc } from "@himalaya/wix-analytics";
|
|
16
|
-
|
|
16
|
+
// `ownerDisplayError`, not `ownerLoadError`: every string below is bound into a
|
|
17
|
+
// `text(...)` and never matched on — the RAW reason is kept beside it in
|
|
18
|
+
// `<part>Reason` for anything that needs it — so the display-only reduction is
|
|
19
|
+
// both safe here and the reason a 428 reason code stopped reaching the owner.
|
|
20
|
+
import { ownerDisplayError, isBridgeUnavailable, isOwnerPreviewDemo } from "../_shared/owner-load-error.js";
|
|
17
21
|
import { DEMO_DASHBOARD, DEMO_NOTE, DEMO_TODAY } from "../_shared/owner-preview-demo.js";
|
|
18
22
|
import { stashCopy, copyParam, copyTemplate } from "../_shared/himi-copy.js";
|
|
19
23
|
import { formatCurrency } from "../_shared/engine-intl.js";
|
|
@@ -566,7 +570,7 @@ async function loadSource(source: HomeSourceId, parts = sourceParts(source)): Pr
|
|
|
566
570
|
const item = settled[index];
|
|
567
571
|
if (item.status === "fulfilled") result[part] = item.value.payload;
|
|
568
572
|
else {
|
|
569
|
-
result[`${part}Error`] =
|
|
573
|
+
result[`${part}Error`] = ownerDisplayError(item.reason);
|
|
570
574
|
result[`${part}Reason`] = item.reason;
|
|
571
575
|
}
|
|
572
576
|
}
|
|
@@ -798,7 +802,7 @@ async function loadDashboard(s: HomeState, sources: HomeSourceId[]): Promise<Hom
|
|
|
798
802
|
if (failedReasons.length > 0 && failedReasons.every((reason) => isBridgeUnavailable(reason))) {
|
|
799
803
|
return demoDashboard(shape({ ...s, sourceStates: [], sourceFailures: [] }));
|
|
800
804
|
}
|
|
801
|
-
return shape({ ...composeState(), status: "error", error:
|
|
805
|
+
return shape({ ...composeState(), status: "error", error: ownerDisplayError(failedReasons[0]) });
|
|
802
806
|
}
|
|
803
807
|
return filteredSchedule(composeState(), activeScheduleFilter);
|
|
804
808
|
}
|
|
@@ -53,6 +53,17 @@ const HTML_BODY = /<!DOCTYPE html|<html[\s>]|<head[\s>]/i;
|
|
|
53
53
|
* "app":"…"}` — and it is short enough to slip under MAX_RAW, so truncation
|
|
54
54
|
* never caught it and the owner read the machine's word for it. */
|
|
55
55
|
const JSON_BODY = /HTTP \d{3}:\s*[[{]/;
|
|
56
|
+
/** `HTTP <status> [SERVICE_CODE]: message` — the shape a Wix service uses when
|
|
57
|
+
* it refuses with a named reason. */
|
|
58
|
+
const CODED = /HTTP (\d{3}) \[([A-Z0-9_]+)\]/;
|
|
59
|
+
/**
|
|
60
|
+
* The codes that all mean one thing to an owner: the session cannot address this
|
|
61
|
+
* business. Found on a real session whose account did not own the business the app
|
|
62
|
+
* had persisted — Home rendered
|
|
63
|
+
* `HTTP 428 [MISSING_METASITE_ID]: Couldn't extract metasiteId from the request
|
|
64
|
+
* context` where "6 orders" belongs.
|
|
65
|
+
*/
|
|
66
|
+
const SITE_CONTEXT_CODES = ["MISSING_METASITE_ID", "MISSING_REQUEST_SITE_CONTEXT", "MISSING_SITE_CONTEXT"];
|
|
56
67
|
/** Longest raw upstream text worth showing. Beyond this it stops being a
|
|
57
68
|
* message and starts being a payload dump. */
|
|
58
69
|
const MAX_RAW = 200;
|
|
@@ -69,6 +80,29 @@ const MAX_RAW = 200;
|
|
|
69
80
|
*/
|
|
70
81
|
function humanWireError(msg: string): string {
|
|
71
82
|
const status = STATUS.exec(msg)?.[1];
|
|
83
|
+
// A JSON ENVELOPE or a NAMED REASON CODE is the machine's word for it, and the
|
|
84
|
+
// owner gets neither. Both reductions used to live in `ownerDisplayError` only,
|
|
85
|
+
// on the belief that this function's output was parsed downstream — see the note
|
|
86
|
+
// on `ownerLoadError`, which records why that was wrong and how it was checked.
|
|
87
|
+
if (JSON_BODY.test(msg) && status) {
|
|
88
|
+
return copyParam(
|
|
89
|
+
"ownerCommon.upstreamStatus",
|
|
90
|
+
`Wix returned an error (HTTP ${status}). Try again in a moment.`,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
const coded = CODED.exec(msg);
|
|
94
|
+
if (coded) {
|
|
95
|
+
if (SITE_CONTEXT_CODES.includes(coded[2])) {
|
|
96
|
+
return copyParam(
|
|
97
|
+
"ownerCommon.noSiteContext",
|
|
98
|
+
"This business isn’t available to your Wix account right now. Switch business, or sign in again as its owner.",
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return copyParam(
|
|
102
|
+
"ownerCommon.upstreamStatus",
|
|
103
|
+
`Wix returned an error (HTTP ${coded[1]}). Try again in a moment.`,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
72
106
|
if (HTML_BODY.test(msg)) {
|
|
73
107
|
if (status === "403") {
|
|
74
108
|
return copyParam(
|
|
@@ -101,36 +135,46 @@ export function ownerPreviewUnavailable(): string {
|
|
|
101
135
|
/**
|
|
102
136
|
* `ownerLoadError` for a screen that does nothing but RENDER the string.
|
|
103
137
|
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* native write-behind (`shouldQueueOwnerWrite`) depends on exactly it.
|
|
138
|
+
* One difference left, and it is about WHERE the app is rather than what the
|
|
139
|
+
* error says: this names the web preview when there IS one. `isBridgeUnavailable`
|
|
140
|
+
* reads "not live" as "preview", and native injects no mode at all, so the
|
|
141
|
+
* default would answer a device-side `HTTP 503` with "open this app on a device"
|
|
142
|
+
* — on the device. That predicate is deliberately left alone: native
|
|
143
|
+
* write-behind (`shouldQueueOwnerWrite`) depends on exactly it.
|
|
111
144
|
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* `CATALOG_V3_CALLING_CATALOG_V1_API` in it to choose its v1 fallback, and
|
|
115
|
-
* `owner-load-error.test.ts` pins that verbatim. A display-only caller has
|
|
116
|
-
* no such reader, and the bridge's typed refusals are JSON and short enough
|
|
117
|
-
* (68 chars) to slip under MAX_RAW, so nothing else was catching them.
|
|
118
|
-
*
|
|
119
|
-
* So: use this ONLY where the value is rendered and never matched on.
|
|
145
|
+
* The reductions this used to add are now in `humanWireError`, so every owner
|
|
146
|
+
* screen gets them rather than the two that happened to call this.
|
|
120
147
|
*/
|
|
121
148
|
export function ownerDisplayError(e: unknown): string {
|
|
122
149
|
if (isOwnerPreviewHost() && isBridgeUnavailable(e)) return ownerPreviewUnavailable();
|
|
123
|
-
|
|
124
|
-
const status = STATUS.exec(msg)?.[1];
|
|
125
|
-
if (JSON_BODY.test(msg) && status) {
|
|
126
|
-
return copyParam(
|
|
127
|
-
"ownerCommon.upstreamStatus",
|
|
128
|
-
`Wix returned an error (HTTP ${status}). Try again in a moment.`,
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
return humanWireError(msg);
|
|
150
|
+
return humanWireError(String((e as Error)?.message ?? e));
|
|
132
151
|
}
|
|
133
152
|
|
|
153
|
+
/**
|
|
154
|
+
* The default. Reduces the same shapes as `ownerDisplayError`.
|
|
155
|
+
*
|
|
156
|
+
* It used to reduce LESS, on the stated grounds that its output is parsed
|
|
157
|
+
* downstream — "the products worker matches `CATALOG_V3_CALLING_CATALOG_V1_API`
|
|
158
|
+
* in it to choose its v1 fallback". **That was not true**, and it cost 17 owner
|
|
159
|
+
* screens their error copy: they printed `HTTP 428 [MISSING_METASITE_ID]: …`
|
|
160
|
+
* verbatim for a contract that does not exist.
|
|
161
|
+
*
|
|
162
|
+
* Checked before changing it, and worth recording so nobody restores the belief:
|
|
163
|
+
*
|
|
164
|
+
* • the catalog v1/v3 decision is made INSIDE the Wix stores SDK, on the RAW
|
|
165
|
+
* thrown error — its `catalogVersionFromMismatch` reads the error's own
|
|
166
|
+
* `message`, and only that module calls it. It never sees this function's
|
|
167
|
+
* output.
|
|
168
|
+
* • `CATALOG_V3_CALLING_CATALOG_V1_API` appears nowhere else in the codebase
|
|
169
|
+
* outside comments, tests and that one SDK module.
|
|
170
|
+
* • the collection framework's `clearOnError` is handed the RAW error
|
|
171
|
+
* (`error => /401|403|forbidden/i.test(String(error))`), separately from
|
|
172
|
+
* `errorMessage: ownerLoadError` — so the one place that does match on a
|
|
173
|
+
* failure is unaffected by what this returns.
|
|
174
|
+
*
|
|
175
|
+
* So: the raw error remains available to logic everywhere it was; this function's
|
|
176
|
+
* result is display copy, and now reads like it.
|
|
177
|
+
*/
|
|
134
178
|
export function ownerLoadError(e: unknown): string {
|
|
135
179
|
const msg = String((e as Error)?.message ?? e);
|
|
136
180
|
if (isBridgeUnavailable(e)) return ownerPreviewUnavailable();
|
|
@@ -53,6 +53,17 @@ const HTML_BODY = /<!DOCTYPE html|<html[\s>]|<head[\s>]/i;
|
|
|
53
53
|
* "app":"…"}` — and it is short enough to slip under MAX_RAW, so truncation
|
|
54
54
|
* never caught it and the owner read the machine's word for it. */
|
|
55
55
|
const JSON_BODY = /HTTP \d{3}:\s*[[{]/;
|
|
56
|
+
/** `HTTP <status> [SERVICE_CODE]: message` — the shape a Wix service uses when
|
|
57
|
+
* it refuses with a named reason. */
|
|
58
|
+
const CODED = /HTTP (\d{3}) \[([A-Z0-9_]+)\]/;
|
|
59
|
+
/**
|
|
60
|
+
* The codes that all mean one thing to an owner: the session cannot address this
|
|
61
|
+
* business. Found on a real session whose account did not own the business the app
|
|
62
|
+
* had persisted — Home rendered
|
|
63
|
+
* `HTTP 428 [MISSING_METASITE_ID]: Couldn't extract metasiteId from the request
|
|
64
|
+
* context` where "6 orders" belongs.
|
|
65
|
+
*/
|
|
66
|
+
const SITE_CONTEXT_CODES = ["MISSING_METASITE_ID", "MISSING_REQUEST_SITE_CONTEXT", "MISSING_SITE_CONTEXT"];
|
|
56
67
|
/** Longest raw upstream text worth showing. Beyond this it stops being a
|
|
57
68
|
* message and starts being a payload dump. */
|
|
58
69
|
const MAX_RAW = 200;
|
|
@@ -69,6 +80,29 @@ const MAX_RAW = 200;
|
|
|
69
80
|
*/
|
|
70
81
|
function humanWireError(msg: string): string {
|
|
71
82
|
const status = STATUS.exec(msg)?.[1];
|
|
83
|
+
// A JSON ENVELOPE or a NAMED REASON CODE is the machine's word for it, and the
|
|
84
|
+
// owner gets neither. Both reductions used to live in `ownerDisplayError` only,
|
|
85
|
+
// on the belief that this function's output was parsed downstream — see the note
|
|
86
|
+
// on `ownerLoadError`, which records why that was wrong and how it was checked.
|
|
87
|
+
if (JSON_BODY.test(msg) && status) {
|
|
88
|
+
return copyParam(
|
|
89
|
+
"ownerCommon.upstreamStatus",
|
|
90
|
+
`Wix returned an error (HTTP ${status}). Try again in a moment.`,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
const coded = CODED.exec(msg);
|
|
94
|
+
if (coded) {
|
|
95
|
+
if (SITE_CONTEXT_CODES.includes(coded[2])) {
|
|
96
|
+
return copyParam(
|
|
97
|
+
"ownerCommon.noSiteContext",
|
|
98
|
+
"This business isn’t available to your Wix account right now. Switch business, or sign in again as its owner.",
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return copyParam(
|
|
102
|
+
"ownerCommon.upstreamStatus",
|
|
103
|
+
`Wix returned an error (HTTP ${coded[1]}). Try again in a moment.`,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
72
106
|
if (HTML_BODY.test(msg)) {
|
|
73
107
|
if (status === "403") {
|
|
74
108
|
return copyParam(
|
|
@@ -101,36 +135,46 @@ export function ownerPreviewUnavailable(): string {
|
|
|
101
135
|
/**
|
|
102
136
|
* `ownerLoadError` for a screen that does nothing but RENDER the string.
|
|
103
137
|
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* native write-behind (`shouldQueueOwnerWrite`) depends on exactly it.
|
|
138
|
+
* One difference left, and it is about WHERE the app is rather than what the
|
|
139
|
+
* error says: this names the web preview when there IS one. `isBridgeUnavailable`
|
|
140
|
+
* reads "not live" as "preview", and native injects no mode at all, so the
|
|
141
|
+
* default would answer a device-side `HTTP 503` with "open this app on a device"
|
|
142
|
+
* — on the device. That predicate is deliberately left alone: native
|
|
143
|
+
* write-behind (`shouldQueueOwnerWrite`) depends on exactly it.
|
|
111
144
|
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* `CATALOG_V3_CALLING_CATALOG_V1_API` in it to choose its v1 fallback, and
|
|
115
|
-
* `owner-load-error.test.ts` pins that verbatim. A display-only caller has
|
|
116
|
-
* no such reader, and the bridge's typed refusals are JSON and short enough
|
|
117
|
-
* (68 chars) to slip under MAX_RAW, so nothing else was catching them.
|
|
118
|
-
*
|
|
119
|
-
* So: use this ONLY where the value is rendered and never matched on.
|
|
145
|
+
* The reductions this used to add are now in `humanWireError`, so every owner
|
|
146
|
+
* screen gets them rather than the two that happened to call this.
|
|
120
147
|
*/
|
|
121
148
|
export function ownerDisplayError(e: unknown): string {
|
|
122
149
|
if (isOwnerPreviewHost() && isBridgeUnavailable(e)) return ownerPreviewUnavailable();
|
|
123
|
-
|
|
124
|
-
const status = STATUS.exec(msg)?.[1];
|
|
125
|
-
if (JSON_BODY.test(msg) && status) {
|
|
126
|
-
return copyParam(
|
|
127
|
-
"ownerCommon.upstreamStatus",
|
|
128
|
-
`Wix returned an error (HTTP ${status}). Try again in a moment.`,
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
return humanWireError(msg);
|
|
150
|
+
return humanWireError(String((e as Error)?.message ?? e));
|
|
132
151
|
}
|
|
133
152
|
|
|
153
|
+
/**
|
|
154
|
+
* The default. Reduces the same shapes as `ownerDisplayError`.
|
|
155
|
+
*
|
|
156
|
+
* It used to reduce LESS, on the stated grounds that its output is parsed
|
|
157
|
+
* downstream — "the products worker matches `CATALOG_V3_CALLING_CATALOG_V1_API`
|
|
158
|
+
* in it to choose its v1 fallback". **That was not true**, and it cost 17 owner
|
|
159
|
+
* screens their error copy: they printed `HTTP 428 [MISSING_METASITE_ID]: …`
|
|
160
|
+
* verbatim for a contract that does not exist.
|
|
161
|
+
*
|
|
162
|
+
* Checked before changing it, and worth recording so nobody restores the belief:
|
|
163
|
+
*
|
|
164
|
+
* • the catalog v1/v3 decision is made INSIDE the Wix stores SDK, on the RAW
|
|
165
|
+
* thrown error — its `catalogVersionFromMismatch` reads the error's own
|
|
166
|
+
* `message`, and only that module calls it. It never sees this function's
|
|
167
|
+
* output.
|
|
168
|
+
* • `CATALOG_V3_CALLING_CATALOG_V1_API` appears nowhere else in the codebase
|
|
169
|
+
* outside comments, tests and that one SDK module.
|
|
170
|
+
* • the collection framework's `clearOnError` is handed the RAW error
|
|
171
|
+
* (`error => /401|403|forbidden/i.test(String(error))`), separately from
|
|
172
|
+
* `errorMessage: ownerLoadError` — so the one place that does match on a
|
|
173
|
+
* failure is unaffected by what this returns.
|
|
174
|
+
*
|
|
175
|
+
* So: the raw error remains available to logic everywhere it was; this function's
|
|
176
|
+
* result is display copy, and now reads like it.
|
|
177
|
+
*/
|
|
134
178
|
export function ownerLoadError(e: unknown): string {
|
|
135
179
|
const msg = String((e as Error)?.message ?? e);
|
|
136
180
|
if (isBridgeUnavailable(e)) return ownerPreviewUnavailable();
|