@wix/himalaya-cli 0.1251.0 → 0.1252.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/dev-server/src/wix-member-login.d.ts +6 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/state/src/index.d.ts +2 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/serve-runtime/src/wix-bridge.d.ts +144 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/serve-storage/src/sha256.d.ts +13 -0
- package/dist/cli.mjs +539 -281
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/sdk-reference.json +1 -1
- package/package.json +2 -2
|
@@ -15,6 +15,12 @@ export declare function webWixCall(method: string, path: string, body: string |
|
|
|
15
15
|
status: number;
|
|
16
16
|
body: string;
|
|
17
17
|
}>;
|
|
18
|
+
/** Open a Wix response without buffering it, for the authorized SSE bridge.
|
|
19
|
+
* Credentials stay server-side and the host lock is identical to webWixCall. */
|
|
20
|
+
export declare function webWixStream(method: string, path: string, body: string | undefined, token: string, cookie?: string, forwardedHeaders?: Record<string, string>, signal?: AbortSignal): Promise<Response>;
|
|
21
|
+
/** Keep the credential-bearing stream bridge on the same narrow endpoint policy as native
|
|
22
|
+
* Wix consumer auth. General member calls have broader Wix-host routing through webWixCall. */
|
|
23
|
+
export { isAllowedConsumerStreamTarget } from "../../serve-runtime/src/wix-bridge.js";
|
|
18
24
|
/** The signed-in member's Wix id, or null when the profile read fails (the identity route then
|
|
19
25
|
* falls back to the login email). The token belongs in `webWixCall`'s TOKEN slot: the identity
|
|
20
26
|
* route used to pass it third, where it became the GET's ignored body, so the read went out as
|
package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/state/src/index.d.ts
CHANGED
|
@@ -38,6 +38,8 @@ export interface StreamDirective {
|
|
|
38
38
|
url: string;
|
|
39
39
|
headers?: Record<string, string>;
|
|
40
40
|
body?: unknown;
|
|
41
|
+
/** Apply the host's Wix authorization to this request before opening the stream. */
|
|
42
|
+
authorize?: boolean;
|
|
41
43
|
};
|
|
42
44
|
/** Reducer action name dispatched once per parsed `data:` event. */
|
|
43
45
|
onEvent: string;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/** The narrow Wix consumer endpoints allowed to receive credentials for SSE. */
|
|
2
|
+
export declare function isAllowedConsumerStreamTarget(raw: string): boolean;
|
|
3
|
+
/** Classify an absolute-URL rejection: an off-gateway Wix account host is a
|
|
4
|
+
* native-only endpoint (`owner-only`), anything else is an open-proxy attempt. */
|
|
5
|
+
export declare function absoluteUrlRejection(path: string): "owner-only" | "open-proxy";
|
|
6
|
+
/** The bridge envelope the web host's `wixCallOverBridge` expects on a 2xx. */
|
|
7
|
+
export interface WixBridgeEnvelope {
|
|
8
|
+
status: number;
|
|
9
|
+
body: string;
|
|
10
|
+
}
|
|
11
|
+
/** One anonymous visitor token for `clientId`. #3123 Stage B: the proxy no longer serves visitor
|
|
12
|
+
* calls (each browser mints its own, core/web-host/src/wix/directWixCall.ts), so nothing caches
|
|
13
|
+
* one per pod any more — the one server-side use left is the member-login redirect, which needs a
|
|
14
|
+
* visitor token to build Wix's hosted-login URL once per login. */
|
|
15
|
+
export declare function mintAnonymousVisitor(clientId: string, fetchImpl?: typeof fetch): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Proxy one REST call to wixapis.com with the given token. `path` must be
|
|
18
|
+
* origin-relative — an absolute URL is the caller trying to use the bridge as an
|
|
19
|
+
* open proxy, which the read-only origin must never be (throws).
|
|
20
|
+
*/
|
|
21
|
+
export declare function wixVisitorCall(method: string, path: string, body: string | undefined, token: string, fetchImpl?: typeof fetch, forwardedHeaders?: Record<string, string>): Promise<WixBridgeEnvelope>;
|
|
22
|
+
/**
|
|
23
|
+
* The caller-supplied headers a proxied call may carry to Wix (#3190): the Wix ASPECT headers
|
|
24
|
+
* (locale, currency, consistency, BI, brand, consent, revisions) and the per-call site selector
|
|
25
|
+
* `wix-site-id` — native sends it on every call and the dev-server's per-business net-mock rules key
|
|
26
|
+
* on it. (`ChatToken` is the one destination-bound exception: see `normalizeWixForwardedHeaders`.)
|
|
27
|
+
* An ALLOWLIST, lower-case: anything else is dropped — above all a second credential or an
|
|
28
|
+
* identity header (`x-wix-authorization`, `x-wix-clientid`, `x-xsrf-token`, `wix-account-id`,
|
|
29
|
+
* signed instances), which would otherwise ride along with the rung's own `Authorization` and leave
|
|
30
|
+
* which identity the call runs as to the gateway. Also hop-by-hop and framing headers.
|
|
31
|
+
*
|
|
32
|
+
* The aspect headers are exactly the ones the web host's browser-direct transports forward
|
|
33
|
+
* (`DIRECT_FORWARDABLE_HEADERS`, core/web-host/src/wix/directWixCall.ts — the gateway's CORS answer
|
|
34
|
+
* minus credentials); `BRIDGE_ONLY_FORWARDABLE_HEADERS` is the one addition, and
|
|
35
|
+
* core/web-host/tests/direct-wix-call.test.ts holds the lists together, so a call cannot behave
|
|
36
|
+
* differently depending on which path served it.
|
|
37
|
+
*/
|
|
38
|
+
export declare const WIX_FORWARDABLE_HEADERS: ReadonlySet<string>;
|
|
39
|
+
/** What the bridge forwards beyond the browser-direct transports' aspect headers: the site selector
|
|
40
|
+
* (direct owner calls pick their instance by it instead). */
|
|
41
|
+
export declare const BRIDGE_ONLY_FORWARDABLE_HEADERS: ReadonlySet<string>;
|
|
42
|
+
/** The headers of an untrusted web bridge envelope that may reach Wix (`WIX_FORWARDABLE_HEADERS`, plus
|
|
43
|
+
* `ChatToken` when `path` is chat-web itself), in the caller's spelling. The bridge always owns
|
|
44
|
+
* Authorization, cookies, Host and content framing. */
|
|
45
|
+
export declare function normalizeWixForwardedHeaders(input: unknown, path?: string): Record<string, string>;
|
|
46
|
+
/** Guard the msid before it is interpolated into the mint URL (uuid-ish only). */
|
|
47
|
+
export declare function isSafeMsid(msid: string): boolean;
|
|
48
|
+
/** A `renew` never re-mints an instance younger than this, whichever mint made it (another tab's
|
|
49
|
+
* renewal, a first ask, the envelope's own 401 retry). An instance that new is the fresh one: a 401
|
|
50
|
+
* on it is Wix's answer about the endpoint, not a stale credential, and re-minting would only buy
|
|
51
|
+
* the same answer. It also means the route can't be driven to mint on every request. Once an entry
|
|
52
|
+
* is dropped (`invalidate`, a failed mint) there is nothing to hand back, and a renewal mints once,
|
|
53
|
+
* like any ask.
|
|
54
|
+
* No longer than the web host's `OWNER_RENEW_COOLDOWN_MS` (core/web-host/src/wix/directWixCall.ts,
|
|
55
|
+
* #3140): the host never sends `renew=1` sooner than that after its own re-mint, so each renewal it
|
|
56
|
+
* makes is honoured. A longer window here would hand it back the instance Wix just refused.
|
|
57
|
+
* core/serve/tests/owner-instance.test.ts pins the two together. */
|
|
58
|
+
export declare const OWNER_RENEW_MIN_AGE_MS = 5000;
|
|
59
|
+
type OwnerInstanceEntry = {
|
|
60
|
+
instance: string;
|
|
61
|
+
expiresAt: number;
|
|
62
|
+
};
|
|
63
|
+
export declare class OwnerInstanceCache {
|
|
64
|
+
private fetchImpl;
|
|
65
|
+
/** Signed instances are long-lived, but the SESSION behind them may not be —
|
|
66
|
+
* keep the window short so a logout is honored quickly. */
|
|
67
|
+
private ttlMs;
|
|
68
|
+
private mintTimeoutMs;
|
|
69
|
+
/** A monotonic clock for how long a mint TOOK (injectable for tests). */
|
|
70
|
+
private elapsedClock;
|
|
71
|
+
private cache;
|
|
72
|
+
/** The one mint on its way per (business, session). Every caller, plain or renewing, joins it:
|
|
73
|
+
* it started after whatever is cached was minted, so it is the fresh instance. */
|
|
74
|
+
private inflight;
|
|
75
|
+
constructor(fetchImpl?: typeof fetch,
|
|
76
|
+
/** Signed instances are long-lived, but the SESSION behind them may not be —
|
|
77
|
+
* keep the window short so a logout is honored quickly. */
|
|
78
|
+
ttlMs?: number, mintTimeoutMs?: number,
|
|
79
|
+
/** A monotonic clock for how long a mint TOOK (injectable for tests). */
|
|
80
|
+
elapsedClock?: () => number);
|
|
81
|
+
/** Keyed on the SESSION (`wixSession2`), not the whole cookie header: manage.wix.com's jar churns
|
|
82
|
+
* (analytics, experiments), and keying on all of it re-minted on nearly every call (#3044). A
|
|
83
|
+
* header with no session cookie falls back to itself — callers refuse that case before here. */
|
|
84
|
+
private key;
|
|
85
|
+
instance(msid: string, cookieHeader: string, now?: number): Promise<string>;
|
|
86
|
+
/** The instance and the time this cache stops trusting it (#3044: the web host caches until then).
|
|
87
|
+
* `renew`: Wix refused the instance this cache handed out (the route's `renew=1`, #3140) — mint a
|
|
88
|
+
* new one, unless the cached one is younger than OWNER_RENEW_MIN_AGE_MS or a mint is already on
|
|
89
|
+
* its way, in which case that IS the new one. */
|
|
90
|
+
entry(msid: string, cookieHeader: string, now?: number, opts?: {
|
|
91
|
+
renew?: boolean;
|
|
92
|
+
}): Promise<OwnerInstanceEntry>;
|
|
93
|
+
private mint;
|
|
94
|
+
/** Drop a cached instance so the next call re-mints. The envelope owner branch's own 401 retry;
|
|
95
|
+
* the route's `renew=1` goes through `entry(…, { renew: true })` instead. */
|
|
96
|
+
invalidate(msid: string, cookieHeader: string): void;
|
|
97
|
+
}
|
|
98
|
+
export declare const OWNER_SITES_QUERY_PATH = "/site-list/v2/sites/query";
|
|
99
|
+
export declare const OWNER_SITES_COUNT_PATH = "/site-list/v2/sites/count";
|
|
100
|
+
/** True for the ONLY two paths the account-level owner-sites rung may reach. */
|
|
101
|
+
export declare function isOwnerSitesPath(path: string): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* POST one site-list call to wixapis.com, authorized by the FORWARDED caller
|
|
104
|
+
* cookies (never an Authorization header, never stored). Host-locked AND
|
|
105
|
+
* path-locked: anything but the two owner-sites paths throws.
|
|
106
|
+
*/
|
|
107
|
+
export declare function wixOwnerSitesCall(path: string, cookieHeader: string, body: string | undefined, fetchImpl?: typeof fetch): Promise<WixBridgeEnvelope>;
|
|
108
|
+
/** One trimmed row of `GET /v1/owner/sites` — `id` IS the site's metaSiteId. */
|
|
109
|
+
export interface OwnerSiteRow {
|
|
110
|
+
id: string;
|
|
111
|
+
displayName: string;
|
|
112
|
+
namespace?: string;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* RFC 0050 extension — the trimmed "my sites" listing per session, cached
|
|
116
|
+
* briefly. The cache key is a DIGEST of the cookie header (never the cookies
|
|
117
|
+
* themselves — same posture as OwnerInstanceCache); the limit rides the digest
|
|
118
|
+
* so differently-sized listings don't cross-serve. TTL mirrors OwnerInstanceCache
|
|
119
|
+
* (and wix-cache-policy's ttl:300 for this API): sites are stable, but the
|
|
120
|
+
* SESSION behind the listing may not be — keep the window short so a logout
|
|
121
|
+
* stops listing quickly.
|
|
122
|
+
*/
|
|
123
|
+
export declare class OwnerSitesCache {
|
|
124
|
+
private fetchImpl;
|
|
125
|
+
private ttlMs;
|
|
126
|
+
private cache;
|
|
127
|
+
constructor(fetchImpl?: typeof fetch, ttlMs?: number);
|
|
128
|
+
private key;
|
|
129
|
+
sites(cookieHeader: string, limit: number, now?: number): Promise<OwnerSiteRow[]>;
|
|
130
|
+
/** Drop a cached listing (e.g. after an upstream 401) so the next call re-fetches. */
|
|
131
|
+
invalidate(cookieHeader: string, limit: number): void;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Resolve the Wix OAuth clientId for a published app-config, or a typed refusal.
|
|
135
|
+
* Only `wix-*` auth providers carry a REAL Wix clientId — a generic-oauth app's
|
|
136
|
+
* clientId is some other issuer's, and minting against it would just burn a
|
|
137
|
+
* round-trip to wixapis for a guaranteed failure.
|
|
138
|
+
*/
|
|
139
|
+
export declare function wixClientIdOf(appConfigJson: string): {
|
|
140
|
+
clientId: string;
|
|
141
|
+
} | {
|
|
142
|
+
error: "unsupported_auth" | "no_client_id";
|
|
143
|
+
};
|
|
144
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** SHA-256 of `input`, as 32 bytes. Identical to `createHash("sha256").update(input).digest()`. */
|
|
2
|
+
export declare function sha256(input: string | Uint8Array): Uint8Array;
|
|
3
|
+
/** Lowercase hex of `sha256(input)` — what `createHash("sha256").digest("hex")` produces. */
|
|
4
|
+
export declare function sha256Hex(input: string | Uint8Array): string;
|
|
5
|
+
/**
|
|
6
|
+
* The same hex digest as `sha256Hex`, via the platform's native implementation.
|
|
7
|
+
*
|
|
8
|
+
* Identical output — `sha256-parity.test.ts` proves the two agree with each other and with node —
|
|
9
|
+
* but ~40x faster, because it is not JavaScript. Use it wherever the caller is already async AND
|
|
10
|
+
* the input can be large: a package archive, an asset. It is not a drop-in for the sync one, which
|
|
11
|
+
* is what lets `strongEtag` stay a plain function.
|
|
12
|
+
*/
|
|
13
|
+
export declare function sha256HexAsync(input: string | Uint8Array): Promise<string>;
|
package/dist/cli.mjs
CHANGED
|
@@ -6911,7 +6911,6 @@ function resolveTranslation(value, catalog, sourceCatalog) {
|
|
|
6911
6911
|
var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
|
|
6912
6912
|
var init_bindings = __esm({
|
|
6913
6913
|
"../../core/ts/src/bindings.ts"() {
|
|
6914
|
-
"use strict";
|
|
6915
6914
|
BINDING_SIGILS = ["service", "flag", "item", "t"];
|
|
6916
6915
|
BINDING_SIGIL_RE = new RegExp(
|
|
6917
6916
|
`^\\$(?:${BINDING_SIGILS.filter((s2) => s2 !== "t").join("|")})\\b|^\\$t:`
|
|
@@ -13465,6 +13464,7 @@ function resolveIdiom(tokens2, ctx = {}) {
|
|
|
13465
13464
|
var IDIOM_CONTEXTS, UNSAFE_KEYS;
|
|
13466
13465
|
var init_idiom = __esm({
|
|
13467
13466
|
"../../core/ts/src/idiom.ts"() {
|
|
13467
|
+
"use strict";
|
|
13468
13468
|
IDIOM_CONTEXTS = {
|
|
13469
13469
|
ios: { native: ["ios"] },
|
|
13470
13470
|
android: { native: ["material"] },
|
|
@@ -28920,6 +28920,269 @@ var init_derive_transport_capability = __esm({
|
|
|
28920
28920
|
}
|
|
28921
28921
|
});
|
|
28922
28922
|
|
|
28923
|
+
// ../../core/serve-runtime/src/wix-bridge.ts
|
|
28924
|
+
function isAllowedConsumerStreamTarget(raw) {
|
|
28925
|
+
let url;
|
|
28926
|
+
try {
|
|
28927
|
+
url = new URL(raw);
|
|
28928
|
+
} catch {
|
|
28929
|
+
return false;
|
|
28930
|
+
}
|
|
28931
|
+
if (url.protocol !== "https:" || url.port !== "" && url.port !== "443" || url.username || url.password) return false;
|
|
28932
|
+
if (url.hostname.toLowerCase() === "www.wixapis.com") return true;
|
|
28933
|
+
return url.hostname.toLowerCase() === "apps.wix.com" && url.pathname === "/_api/nano-brain/v1/llm-sdk/generate-text";
|
|
28934
|
+
}
|
|
28935
|
+
function absoluteUrlRejection(path2) {
|
|
28936
|
+
let host = "";
|
|
28937
|
+
try {
|
|
28938
|
+
host = new URL(path2).host;
|
|
28939
|
+
} catch {
|
|
28940
|
+
}
|
|
28941
|
+
return OWNER_SCOPED_WIX_HOST.test(host) ? "owner-only" : "open-proxy";
|
|
28942
|
+
}
|
|
28943
|
+
async function mintAnonymousVisitor(clientId, fetchImpl = fetch) {
|
|
28944
|
+
const res = await fetchImpl(`${WIX_API}/oauth2/token`, {
|
|
28945
|
+
method: "POST",
|
|
28946
|
+
headers: { "Content-Type": "application/json" },
|
|
28947
|
+
body: JSON.stringify({ clientId, grantType: "anonymous" })
|
|
28948
|
+
});
|
|
28949
|
+
const text8 = await res.text();
|
|
28950
|
+
let j2 = {};
|
|
28951
|
+
try {
|
|
28952
|
+
j2 = text8 ? JSON.parse(text8) : {};
|
|
28953
|
+
} catch {
|
|
28954
|
+
}
|
|
28955
|
+
if (res.status !== 200 || !j2.access_token) throw new Error(`visitor mint failed (${res.status})`);
|
|
28956
|
+
return j2.access_token;
|
|
28957
|
+
}
|
|
28958
|
+
async function wixVisitorCall(method, path2, body, token, fetchImpl = fetch, forwardedHeaders = {}) {
|
|
28959
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(path2)) throw new Error("absolute URLs are not allowed");
|
|
28960
|
+
const url = `${WIX_API}${path2.startsWith("/") ? path2 : `/${path2}`}`;
|
|
28961
|
+
const res = await fetchImpl(url, {
|
|
28962
|
+
method,
|
|
28963
|
+
// Same header shape the dev-server bridge has always sent (wixapis accepts the
|
|
28964
|
+
// raw access token as the Authorization value).
|
|
28965
|
+
headers: { ...forwardedHeaders, Authorization: token, ...body ? { "Content-Type": "application/json" } : {} },
|
|
28966
|
+
body: method === "GET" || method === "HEAD" ? void 0 : body
|
|
28967
|
+
});
|
|
28968
|
+
return { status: res.status, body: await res.text() };
|
|
28969
|
+
}
|
|
28970
|
+
function isChatWebTarget(path2) {
|
|
28971
|
+
if (!path2 || !/^https:\/\//i.test(path2)) return false;
|
|
28972
|
+
try {
|
|
28973
|
+
const url = new URL(path2);
|
|
28974
|
+
return url.host === "manage.wix.com" && url.pathname.startsWith("/_api/chat-web/");
|
|
28975
|
+
} catch {
|
|
28976
|
+
return false;
|
|
28977
|
+
}
|
|
28978
|
+
}
|
|
28979
|
+
function normalizeWixForwardedHeaders(input, path2) {
|
|
28980
|
+
const chatWeb = isChatWebTarget(path2);
|
|
28981
|
+
let value = input;
|
|
28982
|
+
if (typeof value === "string") {
|
|
28983
|
+
try {
|
|
28984
|
+
value = JSON.parse(value);
|
|
28985
|
+
} catch {
|
|
28986
|
+
return {};
|
|
28987
|
+
}
|
|
28988
|
+
}
|
|
28989
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
28990
|
+
const out2 = {};
|
|
28991
|
+
for (const [name, headerValue] of Object.entries(value)) {
|
|
28992
|
+
const lower = name.toLowerCase();
|
|
28993
|
+
const allowed2 = WIX_FORWARDABLE_HEADERS.has(lower) || chatWeb && lower === "chattoken";
|
|
28994
|
+
if (!/^[a-z0-9-]+$/i.test(name) || !allowed2 || typeof headerValue !== "string") continue;
|
|
28995
|
+
if (/[\r\n\0]/.test(headerValue)) continue;
|
|
28996
|
+
out2[name] = headerValue;
|
|
28997
|
+
}
|
|
28998
|
+
return out2;
|
|
28999
|
+
}
|
|
29000
|
+
function isSafeMsid(msid) {
|
|
29001
|
+
return /^[0-9a-fA-F-]{10,64}$/.test(msid);
|
|
29002
|
+
}
|
|
29003
|
+
function isOwnerSitesPath(path2) {
|
|
29004
|
+
return path2 === OWNER_SITES_QUERY_PATH || path2 === OWNER_SITES_COUNT_PATH;
|
|
29005
|
+
}
|
|
29006
|
+
async function wixOwnerSitesCall(path2, cookieHeader, body, fetchImpl = fetch) {
|
|
29007
|
+
if (!isOwnerSitesPath(path2)) throw new Error("not an owner-sites path");
|
|
29008
|
+
const xsrf = /(?:^|;\s*)XSRF-TOKEN=([^;]+)/.exec(cookieHeader)?.[1];
|
|
29009
|
+
const res = await fetchImpl(`${WIX_API}${path2}`, {
|
|
29010
|
+
method: "POST",
|
|
29011
|
+
headers: {
|
|
29012
|
+
Cookie: cookieHeader,
|
|
29013
|
+
"Content-Type": "application/json",
|
|
29014
|
+
Accept: "application/json",
|
|
29015
|
+
...xsrf ? { "x-xsrf-token": xsrf } : {}
|
|
29016
|
+
},
|
|
29017
|
+
body: body ?? "{}"
|
|
29018
|
+
});
|
|
29019
|
+
return { status: res.status, body: await res.text() };
|
|
29020
|
+
}
|
|
29021
|
+
function wixClientIdOf(appConfigJson) {
|
|
29022
|
+
let cfg;
|
|
29023
|
+
try {
|
|
29024
|
+
cfg = JSON.parse(appConfigJson);
|
|
29025
|
+
} catch {
|
|
29026
|
+
return { error: "no_client_id" };
|
|
29027
|
+
}
|
|
29028
|
+
const providerId = cfg.authConfig?.providerId ?? "";
|
|
29029
|
+
if (!providerId.startsWith("wix")) return { error: "unsupported_auth" };
|
|
29030
|
+
const clientId = cfg.authConfig?.config?.clientId;
|
|
29031
|
+
if (typeof clientId !== "string" || !clientId) return { error: "no_client_id" };
|
|
29032
|
+
return { clientId };
|
|
29033
|
+
}
|
|
29034
|
+
var WIX_API, ONE_APP_SESSION, OWNER_SCOPED_WIX_HOST, WIX_FORWARDABLE_HEADERS, OWNER_REFRESH_MARGIN_MS, OWNER_RENEW_MIN_AGE_MS, OWNER_MINT_TIMEOUT_MS, OwnerInstanceCache, OWNER_SITES_QUERY_PATH, OWNER_SITES_COUNT_PATH, OwnerSitesCache;
|
|
29035
|
+
var init_wix_bridge = __esm({
|
|
29036
|
+
"../../core/serve-runtime/src/wix-bridge.ts"() {
|
|
29037
|
+
init_sha256();
|
|
29038
|
+
WIX_API = "https://www.wixapis.com";
|
|
29039
|
+
ONE_APP_SESSION = "https://apps.wix.com/_api/one-app-session-web/v3/businesses";
|
|
29040
|
+
OWNER_SCOPED_WIX_HOST = /(^|\.)wix\.com$/i;
|
|
29041
|
+
WIX_FORWARDABLE_HEADERS = /* @__PURE__ */ new Set([
|
|
29042
|
+
"x-wix-language",
|
|
29043
|
+
"x-wix-linguist",
|
|
29044
|
+
"wixlanguage",
|
|
29045
|
+
"accept-language",
|
|
29046
|
+
"x-wix-currency",
|
|
29047
|
+
"x-wix-consistent",
|
|
29048
|
+
"x-wix-client-api-revision",
|
|
29049
|
+
"x-wix-site-revision",
|
|
29050
|
+
"x-wix-bi-gateway",
|
|
29051
|
+
"x-wix-brand",
|
|
29052
|
+
"consent-policy",
|
|
29053
|
+
"commonconfig",
|
|
29054
|
+
"x-wix-client-artifact-id",
|
|
29055
|
+
"wix-site-id"
|
|
29056
|
+
]);
|
|
29057
|
+
OWNER_REFRESH_MARGIN_MS = 6e4;
|
|
29058
|
+
OWNER_RENEW_MIN_AGE_MS = 5e3;
|
|
29059
|
+
OWNER_MINT_TIMEOUT_MS = 8e3;
|
|
29060
|
+
OwnerInstanceCache = class {
|
|
29061
|
+
constructor(fetchImpl = fetch, ttlMs = 5 * 6e4, mintTimeoutMs = OWNER_MINT_TIMEOUT_MS, elapsedClock = () => performance.now()) {
|
|
29062
|
+
this.fetchImpl = fetchImpl;
|
|
29063
|
+
this.ttlMs = ttlMs;
|
|
29064
|
+
this.mintTimeoutMs = mintTimeoutMs;
|
|
29065
|
+
this.elapsedClock = elapsedClock;
|
|
29066
|
+
}
|
|
29067
|
+
cache = /* @__PURE__ */ new Map();
|
|
29068
|
+
/** The one mint on its way per (business, session). Every caller, plain or renewing, joins it:
|
|
29069
|
+
* it started after whatever is cached was minted, so it is the fresh instance. */
|
|
29070
|
+
inflight = /* @__PURE__ */ new Map();
|
|
29071
|
+
/** Keyed on the SESSION (`wixSession2`), not the whole cookie header: manage.wix.com's jar churns
|
|
29072
|
+
* (analytics, experiments), and keying on all of it re-minted on nearly every call (#3044). A
|
|
29073
|
+
* header with no session cookie falls back to itself — callers refuse that case before here. */
|
|
29074
|
+
key(msid, cookieHeader) {
|
|
29075
|
+
const session = /(?:^|;\s*)wixSession2=([^;]*)/.exec(cookieHeader)?.[1] ?? cookieHeader;
|
|
29076
|
+
return sha256Hex(`${msid}
|
|
29077
|
+
${session}`);
|
|
29078
|
+
}
|
|
29079
|
+
async instance(msid, cookieHeader, now = Date.now()) {
|
|
29080
|
+
return (await this.entry(msid, cookieHeader, now)).instance;
|
|
29081
|
+
}
|
|
29082
|
+
/** The instance and the time this cache stops trusting it (#3044: the web host caches until then).
|
|
29083
|
+
* `renew`: Wix refused the instance this cache handed out (the route's `renew=1`, #3140) — mint a
|
|
29084
|
+
* new one, unless the cached one is younger than OWNER_RENEW_MIN_AGE_MS or a mint is already on
|
|
29085
|
+
* its way, in which case that IS the new one. */
|
|
29086
|
+
async entry(msid, cookieHeader, now = Date.now(), opts = {}) {
|
|
29087
|
+
const key2 = this.key(msid, cookieHeader);
|
|
29088
|
+
const pending = this.inflight.get(key2);
|
|
29089
|
+
if (pending) return { ...await pending };
|
|
29090
|
+
let hit = this.cache.get(key2);
|
|
29091
|
+
if (opts.renew && hit && now - hit.mintedAt >= OWNER_RENEW_MIN_AGE_MS) hit = void 0;
|
|
29092
|
+
if (hit && hit.expiresAt - OWNER_REFRESH_MARGIN_MS > now) return { instance: hit.instance, expiresAt: hit.expiresAt };
|
|
29093
|
+
const mint = this.mint(key2, msid, cookieHeader, now).finally(() => this.inflight.delete(key2));
|
|
29094
|
+
this.inflight.set(key2, mint);
|
|
29095
|
+
return { ...await mint };
|
|
29096
|
+
}
|
|
29097
|
+
async mint(key2, msid, cookieHeader, now) {
|
|
29098
|
+
const startedAt = this.elapsedClock();
|
|
29099
|
+
const abort = new AbortController();
|
|
29100
|
+
let timer;
|
|
29101
|
+
const timedOut = new Promise((_2, reject) => {
|
|
29102
|
+
timer = setTimeout(() => {
|
|
29103
|
+
abort.abort();
|
|
29104
|
+
reject(new Error(`owner mint timed out after ${this.mintTimeoutMs}ms`));
|
|
29105
|
+
}, this.mintTimeoutMs);
|
|
29106
|
+
});
|
|
29107
|
+
try {
|
|
29108
|
+
const res = await Promise.race([
|
|
29109
|
+
this.fetchImpl(`${ONE_APP_SESSION}/${msid}/signed-instance?signed_instance_type=User`, {
|
|
29110
|
+
method: "GET",
|
|
29111
|
+
headers: { Cookie: cookieHeader },
|
|
29112
|
+
signal: abort.signal
|
|
29113
|
+
}),
|
|
29114
|
+
timedOut
|
|
29115
|
+
]);
|
|
29116
|
+
const text8 = await Promise.race([res.text(), timedOut]);
|
|
29117
|
+
let j2 = {};
|
|
29118
|
+
try {
|
|
29119
|
+
j2 = text8 ? JSON.parse(text8) : {};
|
|
29120
|
+
} catch {
|
|
29121
|
+
}
|
|
29122
|
+
if (res.status < 200 || res.status >= 300 || !j2.signedInstance)
|
|
29123
|
+
throw new Error(`owner mint failed (${res.status})`);
|
|
29124
|
+
const elapsed = Math.max(0, this.elapsedClock() - startedAt);
|
|
29125
|
+
const mintedAt = now + elapsed;
|
|
29126
|
+
const entry = { instance: j2.signedInstance, expiresAt: now + Math.floor(elapsed / 1e3) * 1e3 + this.ttlMs };
|
|
29127
|
+
this.cache.set(key2, { ...entry, mintedAt });
|
|
29128
|
+
return entry;
|
|
29129
|
+
} catch (e2) {
|
|
29130
|
+
this.cache.delete(key2);
|
|
29131
|
+
throw e2;
|
|
29132
|
+
} finally {
|
|
29133
|
+
clearTimeout(timer);
|
|
29134
|
+
}
|
|
29135
|
+
}
|
|
29136
|
+
/** Drop a cached instance so the next call re-mints. The envelope owner branch's own 401 retry;
|
|
29137
|
+
* the route's `renew=1` goes through `entry(…, { renew: true })` instead. */
|
|
29138
|
+
invalidate(msid, cookieHeader) {
|
|
29139
|
+
this.cache.delete(this.key(msid, cookieHeader));
|
|
29140
|
+
}
|
|
29141
|
+
};
|
|
29142
|
+
OWNER_SITES_QUERY_PATH = "/site-list/v2/sites/query";
|
|
29143
|
+
OWNER_SITES_COUNT_PATH = "/site-list/v2/sites/count";
|
|
29144
|
+
OwnerSitesCache = class {
|
|
29145
|
+
constructor(fetchImpl = fetch, ttlMs = 5 * 6e4) {
|
|
29146
|
+
this.fetchImpl = fetchImpl;
|
|
29147
|
+
this.ttlMs = ttlMs;
|
|
29148
|
+
}
|
|
29149
|
+
cache = /* @__PURE__ */ new Map();
|
|
29150
|
+
key(cookieHeader, limit) {
|
|
29151
|
+
return sha256Hex(`${limit}
|
|
29152
|
+
${cookieHeader}`);
|
|
29153
|
+
}
|
|
29154
|
+
async sites(cookieHeader, limit, now = Date.now()) {
|
|
29155
|
+
const key2 = this.key(cookieHeader, limit);
|
|
29156
|
+
const hit = this.cache.get(key2);
|
|
29157
|
+
if (hit && hit.expiresAt > now) return hit.sites;
|
|
29158
|
+
const env = await wixOwnerSitesCall(
|
|
29159
|
+
OWNER_SITES_QUERY_PATH,
|
|
29160
|
+
cookieHeader,
|
|
29161
|
+
JSON.stringify({ query: { cursorPaging: { limit } } }),
|
|
29162
|
+
this.fetchImpl
|
|
29163
|
+
);
|
|
29164
|
+
if (env.status < 200 || env.status >= 300) throw new Error(`owner sites failed (${env.status})`);
|
|
29165
|
+
let parsed = {};
|
|
29166
|
+
try {
|
|
29167
|
+
parsed = env.body ? JSON.parse(env.body) : {};
|
|
29168
|
+
} catch {
|
|
29169
|
+
}
|
|
29170
|
+
const sites = (Array.isArray(parsed.sites) ? parsed.sites : []).filter((s2) => typeof s2?.id === "string" && !!s2.id).map((s2) => ({
|
|
29171
|
+
id: s2.id,
|
|
29172
|
+
displayName: typeof s2.displayName === "string" && s2.displayName ? s2.displayName : typeof s2.name === "string" && s2.name ? s2.name : s2.id,
|
|
29173
|
+
...typeof s2.namespace === "string" && s2.namespace ? { namespace: s2.namespace } : {}
|
|
29174
|
+
}));
|
|
29175
|
+
this.cache.set(key2, { sites, expiresAt: now + this.ttlMs });
|
|
29176
|
+
return sites;
|
|
29177
|
+
}
|
|
29178
|
+
/** Drop a cached listing (e.g. after an upstream 401) so the next call re-fetches. */
|
|
29179
|
+
invalidate(cookieHeader, limit) {
|
|
29180
|
+
this.cache.delete(this.key(cookieHeader, limit));
|
|
29181
|
+
}
|
|
29182
|
+
};
|
|
29183
|
+
}
|
|
29184
|
+
});
|
|
29185
|
+
|
|
28923
29186
|
// ../../core/dev-server/src/wix-hosts.ts
|
|
28924
29187
|
function targetHost(raw) {
|
|
28925
29188
|
try {
|
|
@@ -28950,11 +29213,13 @@ var init_wix_hosts = __esm({
|
|
|
28950
29213
|
// ../../core/dev-server/src/wix-member-login.ts
|
|
28951
29214
|
var wix_member_login_exports = {};
|
|
28952
29215
|
__export(wix_member_login_exports, {
|
|
29216
|
+
isAllowedConsumerStreamTarget: () => isAllowedConsumerStreamTarget,
|
|
28953
29217
|
memberDirectLogin: () => memberDirectLogin,
|
|
28954
29218
|
memberDirectRegister: () => memberDirectRegister,
|
|
28955
29219
|
mintVisitor: () => mintVisitor,
|
|
28956
29220
|
readMemberId: () => readMemberId,
|
|
28957
|
-
webWixCall: () => webWixCall
|
|
29221
|
+
webWixCall: () => webWixCall,
|
|
29222
|
+
webWixStream: () => webWixStream
|
|
28958
29223
|
});
|
|
28959
29224
|
import { createHash as createHash12, randomBytes as randomBytes3 } from "node:crypto";
|
|
28960
29225
|
function b64url(buf) {
|
|
@@ -29087,6 +29352,25 @@ async function webWixCall(method, path2, body, token, cookie, forwardedHeaders =
|
|
|
29087
29352
|
});
|
|
29088
29353
|
return { status: res.status, body: await res.text() };
|
|
29089
29354
|
}
|
|
29355
|
+
async function webWixStream(method, path2, body, token, cookie, forwardedHeaders = {}, signal) {
|
|
29356
|
+
const url = /^https?:\/\//i.test(path2) ? path2 : `${API}${path2.startsWith("/") ? path2 : "/" + path2}`;
|
|
29357
|
+
if (!isAllowedConsumerStreamTarget(url)) {
|
|
29358
|
+
throw new Error(`refusing to send Wix credentials to an unapproved consumer endpoint (${targetHost(url) || "no host"})`);
|
|
29359
|
+
}
|
|
29360
|
+
return fetch(url, {
|
|
29361
|
+
method,
|
|
29362
|
+
headers: {
|
|
29363
|
+
...forwardedHeaders,
|
|
29364
|
+
Accept: "text/event-stream",
|
|
29365
|
+
Authorization: token,
|
|
29366
|
+
...cookie ? { Cookie: cookie } : {},
|
|
29367
|
+
...body ? { "Content-Type": "application/json" } : {}
|
|
29368
|
+
},
|
|
29369
|
+
body: method === "GET" || method === "HEAD" ? void 0 : body,
|
|
29370
|
+
redirect: "manual",
|
|
29371
|
+
signal
|
|
29372
|
+
});
|
|
29373
|
+
}
|
|
29090
29374
|
async function readMemberId(memberToken) {
|
|
29091
29375
|
try {
|
|
29092
29376
|
const identity = await webWixCall("GET", "/members/v1/members/my", void 0, memberToken);
|
|
@@ -29100,7 +29384,9 @@ async function readMemberId(memberToken) {
|
|
|
29100
29384
|
var API;
|
|
29101
29385
|
var init_wix_member_login = __esm({
|
|
29102
29386
|
"../../core/dev-server/src/wix-member-login.ts"() {
|
|
29387
|
+
init_wix_bridge();
|
|
29103
29388
|
init_wix_hosts();
|
|
29389
|
+
init_wix_bridge();
|
|
29104
29390
|
API = "https://www.wixapis.com";
|
|
29105
29391
|
}
|
|
29106
29392
|
});
|
|
@@ -29569,258 +29855,6 @@ var init_wix_gateway = __esm({
|
|
|
29569
29855
|
}
|
|
29570
29856
|
});
|
|
29571
29857
|
|
|
29572
|
-
// ../../core/serve-runtime/src/wix-bridge.ts
|
|
29573
|
-
function absoluteUrlRejection(path2) {
|
|
29574
|
-
let host = "";
|
|
29575
|
-
try {
|
|
29576
|
-
host = new URL(path2).host;
|
|
29577
|
-
} catch {
|
|
29578
|
-
}
|
|
29579
|
-
return OWNER_SCOPED_WIX_HOST.test(host) ? "owner-only" : "open-proxy";
|
|
29580
|
-
}
|
|
29581
|
-
async function mintAnonymousVisitor(clientId, fetchImpl = fetch) {
|
|
29582
|
-
const res = await fetchImpl(`${WIX_API}/oauth2/token`, {
|
|
29583
|
-
method: "POST",
|
|
29584
|
-
headers: { "Content-Type": "application/json" },
|
|
29585
|
-
body: JSON.stringify({ clientId, grantType: "anonymous" })
|
|
29586
|
-
});
|
|
29587
|
-
const text8 = await res.text();
|
|
29588
|
-
let j2 = {};
|
|
29589
|
-
try {
|
|
29590
|
-
j2 = text8 ? JSON.parse(text8) : {};
|
|
29591
|
-
} catch {
|
|
29592
|
-
}
|
|
29593
|
-
if (res.status !== 200 || !j2.access_token) throw new Error(`visitor mint failed (${res.status})`);
|
|
29594
|
-
return j2.access_token;
|
|
29595
|
-
}
|
|
29596
|
-
async function wixVisitorCall(method, path2, body, token, fetchImpl = fetch, forwardedHeaders = {}) {
|
|
29597
|
-
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(path2)) throw new Error("absolute URLs are not allowed");
|
|
29598
|
-
const url = `${WIX_API}${path2.startsWith("/") ? path2 : `/${path2}`}`;
|
|
29599
|
-
const res = await fetchImpl(url, {
|
|
29600
|
-
method,
|
|
29601
|
-
// Same header shape the dev-server bridge has always sent (wixapis accepts the
|
|
29602
|
-
// raw access token as the Authorization value).
|
|
29603
|
-
headers: { ...forwardedHeaders, Authorization: token, ...body ? { "Content-Type": "application/json" } : {} },
|
|
29604
|
-
body: method === "GET" || method === "HEAD" ? void 0 : body
|
|
29605
|
-
});
|
|
29606
|
-
return { status: res.status, body: await res.text() };
|
|
29607
|
-
}
|
|
29608
|
-
function isChatWebTarget(path2) {
|
|
29609
|
-
if (!path2 || !/^https:\/\//i.test(path2)) return false;
|
|
29610
|
-
try {
|
|
29611
|
-
const url = new URL(path2);
|
|
29612
|
-
return url.host === "manage.wix.com" && url.pathname.startsWith("/_api/chat-web/");
|
|
29613
|
-
} catch {
|
|
29614
|
-
return false;
|
|
29615
|
-
}
|
|
29616
|
-
}
|
|
29617
|
-
function normalizeWixForwardedHeaders(input, path2) {
|
|
29618
|
-
const chatWeb = isChatWebTarget(path2);
|
|
29619
|
-
let value = input;
|
|
29620
|
-
if (typeof value === "string") {
|
|
29621
|
-
try {
|
|
29622
|
-
value = JSON.parse(value);
|
|
29623
|
-
} catch {
|
|
29624
|
-
return {};
|
|
29625
|
-
}
|
|
29626
|
-
}
|
|
29627
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
29628
|
-
const out2 = {};
|
|
29629
|
-
for (const [name, headerValue] of Object.entries(value)) {
|
|
29630
|
-
const lower = name.toLowerCase();
|
|
29631
|
-
const allowed2 = WIX_FORWARDABLE_HEADERS.has(lower) || chatWeb && lower === "chattoken";
|
|
29632
|
-
if (!/^[a-z0-9-]+$/i.test(name) || !allowed2 || typeof headerValue !== "string") continue;
|
|
29633
|
-
if (/[\r\n\0]/.test(headerValue)) continue;
|
|
29634
|
-
out2[name] = headerValue;
|
|
29635
|
-
}
|
|
29636
|
-
return out2;
|
|
29637
|
-
}
|
|
29638
|
-
function isSafeMsid(msid) {
|
|
29639
|
-
return /^[0-9a-fA-F-]{10,64}$/.test(msid);
|
|
29640
|
-
}
|
|
29641
|
-
function isOwnerSitesPath(path2) {
|
|
29642
|
-
return path2 === OWNER_SITES_QUERY_PATH || path2 === OWNER_SITES_COUNT_PATH;
|
|
29643
|
-
}
|
|
29644
|
-
async function wixOwnerSitesCall(path2, cookieHeader, body, fetchImpl = fetch) {
|
|
29645
|
-
if (!isOwnerSitesPath(path2)) throw new Error("not an owner-sites path");
|
|
29646
|
-
const xsrf = /(?:^|;\s*)XSRF-TOKEN=([^;]+)/.exec(cookieHeader)?.[1];
|
|
29647
|
-
const res = await fetchImpl(`${WIX_API}${path2}`, {
|
|
29648
|
-
method: "POST",
|
|
29649
|
-
headers: {
|
|
29650
|
-
Cookie: cookieHeader,
|
|
29651
|
-
"Content-Type": "application/json",
|
|
29652
|
-
Accept: "application/json",
|
|
29653
|
-
...xsrf ? { "x-xsrf-token": xsrf } : {}
|
|
29654
|
-
},
|
|
29655
|
-
body: body ?? "{}"
|
|
29656
|
-
});
|
|
29657
|
-
return { status: res.status, body: await res.text() };
|
|
29658
|
-
}
|
|
29659
|
-
function wixClientIdOf(appConfigJson) {
|
|
29660
|
-
let cfg;
|
|
29661
|
-
try {
|
|
29662
|
-
cfg = JSON.parse(appConfigJson);
|
|
29663
|
-
} catch {
|
|
29664
|
-
return { error: "no_client_id" };
|
|
29665
|
-
}
|
|
29666
|
-
const providerId = cfg.authConfig?.providerId ?? "";
|
|
29667
|
-
if (!providerId.startsWith("wix")) return { error: "unsupported_auth" };
|
|
29668
|
-
const clientId = cfg.authConfig?.config?.clientId;
|
|
29669
|
-
if (typeof clientId !== "string" || !clientId) return { error: "no_client_id" };
|
|
29670
|
-
return { clientId };
|
|
29671
|
-
}
|
|
29672
|
-
var WIX_API, ONE_APP_SESSION, OWNER_SCOPED_WIX_HOST, WIX_FORWARDABLE_HEADERS, OWNER_REFRESH_MARGIN_MS, OWNER_RENEW_MIN_AGE_MS, OWNER_MINT_TIMEOUT_MS, OwnerInstanceCache, OWNER_SITES_QUERY_PATH, OWNER_SITES_COUNT_PATH, OwnerSitesCache;
|
|
29673
|
-
var init_wix_bridge = __esm({
|
|
29674
|
-
"../../core/serve-runtime/src/wix-bridge.ts"() {
|
|
29675
|
-
init_sha256();
|
|
29676
|
-
WIX_API = "https://www.wixapis.com";
|
|
29677
|
-
ONE_APP_SESSION = "https://apps.wix.com/_api/one-app-session-web/v3/businesses";
|
|
29678
|
-
OWNER_SCOPED_WIX_HOST = /(^|\.)wix\.com$/i;
|
|
29679
|
-
WIX_FORWARDABLE_HEADERS = /* @__PURE__ */ new Set([
|
|
29680
|
-
"x-wix-language",
|
|
29681
|
-
"x-wix-linguist",
|
|
29682
|
-
"wixlanguage",
|
|
29683
|
-
"accept-language",
|
|
29684
|
-
"x-wix-currency",
|
|
29685
|
-
"x-wix-consistent",
|
|
29686
|
-
"x-wix-client-api-revision",
|
|
29687
|
-
"x-wix-site-revision",
|
|
29688
|
-
"x-wix-bi-gateway",
|
|
29689
|
-
"x-wix-brand",
|
|
29690
|
-
"consent-policy",
|
|
29691
|
-
"commonconfig",
|
|
29692
|
-
"x-wix-client-artifact-id",
|
|
29693
|
-
"wix-site-id"
|
|
29694
|
-
]);
|
|
29695
|
-
OWNER_REFRESH_MARGIN_MS = 6e4;
|
|
29696
|
-
OWNER_RENEW_MIN_AGE_MS = 5e3;
|
|
29697
|
-
OWNER_MINT_TIMEOUT_MS = 8e3;
|
|
29698
|
-
OwnerInstanceCache = class {
|
|
29699
|
-
constructor(fetchImpl = fetch, ttlMs = 5 * 6e4, mintTimeoutMs = OWNER_MINT_TIMEOUT_MS, elapsedClock = () => performance.now()) {
|
|
29700
|
-
this.fetchImpl = fetchImpl;
|
|
29701
|
-
this.ttlMs = ttlMs;
|
|
29702
|
-
this.mintTimeoutMs = mintTimeoutMs;
|
|
29703
|
-
this.elapsedClock = elapsedClock;
|
|
29704
|
-
}
|
|
29705
|
-
cache = /* @__PURE__ */ new Map();
|
|
29706
|
-
/** The one mint on its way per (business, session). Every caller, plain or renewing, joins it:
|
|
29707
|
-
* it started after whatever is cached was minted, so it is the fresh instance. */
|
|
29708
|
-
inflight = /* @__PURE__ */ new Map();
|
|
29709
|
-
/** Keyed on the SESSION (`wixSession2`), not the whole cookie header: manage.wix.com's jar churns
|
|
29710
|
-
* (analytics, experiments), and keying on all of it re-minted on nearly every call (#3044). A
|
|
29711
|
-
* header with no session cookie falls back to itself — callers refuse that case before here. */
|
|
29712
|
-
key(msid, cookieHeader) {
|
|
29713
|
-
const session = /(?:^|;\s*)wixSession2=([^;]*)/.exec(cookieHeader)?.[1] ?? cookieHeader;
|
|
29714
|
-
return sha256Hex(`${msid}
|
|
29715
|
-
${session}`);
|
|
29716
|
-
}
|
|
29717
|
-
async instance(msid, cookieHeader, now = Date.now()) {
|
|
29718
|
-
return (await this.entry(msid, cookieHeader, now)).instance;
|
|
29719
|
-
}
|
|
29720
|
-
/** The instance and the time this cache stops trusting it (#3044: the web host caches until then).
|
|
29721
|
-
* `renew`: Wix refused the instance this cache handed out (the route's `renew=1`, #3140) — mint a
|
|
29722
|
-
* new one, unless the cached one is younger than OWNER_RENEW_MIN_AGE_MS or a mint is already on
|
|
29723
|
-
* its way, in which case that IS the new one. */
|
|
29724
|
-
async entry(msid, cookieHeader, now = Date.now(), opts = {}) {
|
|
29725
|
-
const key2 = this.key(msid, cookieHeader);
|
|
29726
|
-
const pending = this.inflight.get(key2);
|
|
29727
|
-
if (pending) return { ...await pending };
|
|
29728
|
-
let hit = this.cache.get(key2);
|
|
29729
|
-
if (opts.renew && hit && now - hit.mintedAt >= OWNER_RENEW_MIN_AGE_MS) hit = void 0;
|
|
29730
|
-
if (hit && hit.expiresAt - OWNER_REFRESH_MARGIN_MS > now) return { instance: hit.instance, expiresAt: hit.expiresAt };
|
|
29731
|
-
const mint = this.mint(key2, msid, cookieHeader, now).finally(() => this.inflight.delete(key2));
|
|
29732
|
-
this.inflight.set(key2, mint);
|
|
29733
|
-
return { ...await mint };
|
|
29734
|
-
}
|
|
29735
|
-
async mint(key2, msid, cookieHeader, now) {
|
|
29736
|
-
const startedAt = this.elapsedClock();
|
|
29737
|
-
const abort = new AbortController();
|
|
29738
|
-
let timer;
|
|
29739
|
-
const timedOut = new Promise((_2, reject) => {
|
|
29740
|
-
timer = setTimeout(() => {
|
|
29741
|
-
abort.abort();
|
|
29742
|
-
reject(new Error(`owner mint timed out after ${this.mintTimeoutMs}ms`));
|
|
29743
|
-
}, this.mintTimeoutMs);
|
|
29744
|
-
});
|
|
29745
|
-
try {
|
|
29746
|
-
const res = await Promise.race([
|
|
29747
|
-
this.fetchImpl(`${ONE_APP_SESSION}/${msid}/signed-instance?signed_instance_type=User`, {
|
|
29748
|
-
method: "GET",
|
|
29749
|
-
headers: { Cookie: cookieHeader },
|
|
29750
|
-
signal: abort.signal
|
|
29751
|
-
}),
|
|
29752
|
-
timedOut
|
|
29753
|
-
]);
|
|
29754
|
-
const text8 = await Promise.race([res.text(), timedOut]);
|
|
29755
|
-
let j2 = {};
|
|
29756
|
-
try {
|
|
29757
|
-
j2 = text8 ? JSON.parse(text8) : {};
|
|
29758
|
-
} catch {
|
|
29759
|
-
}
|
|
29760
|
-
if (res.status < 200 || res.status >= 300 || !j2.signedInstance)
|
|
29761
|
-
throw new Error(`owner mint failed (${res.status})`);
|
|
29762
|
-
const elapsed = Math.max(0, this.elapsedClock() - startedAt);
|
|
29763
|
-
const mintedAt = now + elapsed;
|
|
29764
|
-
const entry = { instance: j2.signedInstance, expiresAt: now + Math.floor(elapsed / 1e3) * 1e3 + this.ttlMs };
|
|
29765
|
-
this.cache.set(key2, { ...entry, mintedAt });
|
|
29766
|
-
return entry;
|
|
29767
|
-
} catch (e2) {
|
|
29768
|
-
this.cache.delete(key2);
|
|
29769
|
-
throw e2;
|
|
29770
|
-
} finally {
|
|
29771
|
-
clearTimeout(timer);
|
|
29772
|
-
}
|
|
29773
|
-
}
|
|
29774
|
-
/** Drop a cached instance so the next call re-mints. The envelope owner branch's own 401 retry;
|
|
29775
|
-
* the route's `renew=1` goes through `entry(…, { renew: true })` instead. */
|
|
29776
|
-
invalidate(msid, cookieHeader) {
|
|
29777
|
-
this.cache.delete(this.key(msid, cookieHeader));
|
|
29778
|
-
}
|
|
29779
|
-
};
|
|
29780
|
-
OWNER_SITES_QUERY_PATH = "/site-list/v2/sites/query";
|
|
29781
|
-
OWNER_SITES_COUNT_PATH = "/site-list/v2/sites/count";
|
|
29782
|
-
OwnerSitesCache = class {
|
|
29783
|
-
constructor(fetchImpl = fetch, ttlMs = 5 * 6e4) {
|
|
29784
|
-
this.fetchImpl = fetchImpl;
|
|
29785
|
-
this.ttlMs = ttlMs;
|
|
29786
|
-
}
|
|
29787
|
-
cache = /* @__PURE__ */ new Map();
|
|
29788
|
-
key(cookieHeader, limit) {
|
|
29789
|
-
return sha256Hex(`${limit}
|
|
29790
|
-
${cookieHeader}`);
|
|
29791
|
-
}
|
|
29792
|
-
async sites(cookieHeader, limit, now = Date.now()) {
|
|
29793
|
-
const key2 = this.key(cookieHeader, limit);
|
|
29794
|
-
const hit = this.cache.get(key2);
|
|
29795
|
-
if (hit && hit.expiresAt > now) return hit.sites;
|
|
29796
|
-
const env = await wixOwnerSitesCall(
|
|
29797
|
-
OWNER_SITES_QUERY_PATH,
|
|
29798
|
-
cookieHeader,
|
|
29799
|
-
JSON.stringify({ query: { cursorPaging: { limit } } }),
|
|
29800
|
-
this.fetchImpl
|
|
29801
|
-
);
|
|
29802
|
-
if (env.status < 200 || env.status >= 300) throw new Error(`owner sites failed (${env.status})`);
|
|
29803
|
-
let parsed = {};
|
|
29804
|
-
try {
|
|
29805
|
-
parsed = env.body ? JSON.parse(env.body) : {};
|
|
29806
|
-
} catch {
|
|
29807
|
-
}
|
|
29808
|
-
const sites = (Array.isArray(parsed.sites) ? parsed.sites : []).filter((s2) => typeof s2?.id === "string" && !!s2.id).map((s2) => ({
|
|
29809
|
-
id: s2.id,
|
|
29810
|
-
displayName: typeof s2.displayName === "string" && s2.displayName ? s2.displayName : typeof s2.name === "string" && s2.name ? s2.name : s2.id,
|
|
29811
|
-
...typeof s2.namespace === "string" && s2.namespace ? { namespace: s2.namespace } : {}
|
|
29812
|
-
}));
|
|
29813
|
-
this.cache.set(key2, { sites, expiresAt: now + this.ttlMs });
|
|
29814
|
-
return sites;
|
|
29815
|
-
}
|
|
29816
|
-
/** Drop a cached listing (e.g. after an upstream 401) so the next call re-fetches. */
|
|
29817
|
-
invalidate(cookieHeader, limit) {
|
|
29818
|
-
this.cache.delete(this.key(cookieHeader, limit));
|
|
29819
|
-
}
|
|
29820
|
-
};
|
|
29821
|
-
}
|
|
29822
|
-
});
|
|
29823
|
-
|
|
29824
29858
|
// ../../core/serve-runtime/src/flag-assignments.ts
|
|
29825
29859
|
function bad(error) {
|
|
29826
29860
|
return new Response(JSON.stringify({ error }), { status: 400, headers: { "content-type": JSON_CT, "cache-control": "no-store" } });
|
|
@@ -32482,6 +32516,8 @@ function createRicosHostSession(o2) {
|
|
|
32482
32516
|
let seq = 0;
|
|
32483
32517
|
const newId = o2.newId ?? (() => `rq${Date.now().toString(36)}${++seq}`);
|
|
32484
32518
|
const state = { ready: false, unavailable: null, dirty: false, toolbar: EMPTY_TOOLBAR, focused: false };
|
|
32519
|
+
let locale = o2.locale;
|
|
32520
|
+
let rtl = o2.rtl;
|
|
32485
32521
|
let seed2 = "";
|
|
32486
32522
|
let committed = o2.seedMode === "none";
|
|
32487
32523
|
let initSent = false, awaitingBaseline = false, disposed = false;
|
|
@@ -32513,8 +32549,8 @@ function createRicosHostSession(o2) {
|
|
|
32513
32549
|
type: "init",
|
|
32514
32550
|
contentJson: seed2,
|
|
32515
32551
|
...o2.placeholder ? { placeholder: o2.placeholder } : {},
|
|
32516
|
-
...
|
|
32517
|
-
...
|
|
32552
|
+
...locale ? { locale } : {},
|
|
32553
|
+
...rtl !== void 0 ? { rtl } : {},
|
|
32518
32554
|
...o2.palette ? { palette: o2.palette } : {}
|
|
32519
32555
|
});
|
|
32520
32556
|
};
|
|
@@ -32607,6 +32643,13 @@ function createRicosHostSession(o2) {
|
|
|
32607
32643
|
else sendInit();
|
|
32608
32644
|
}
|
|
32609
32645
|
},
|
|
32646
|
+
updateLocale(nextLocale, nextRtl) {
|
|
32647
|
+
if (locale === nextLocale && rtl === nextRtl) return;
|
|
32648
|
+
locale = nextLocale;
|
|
32649
|
+
rtl = nextRtl;
|
|
32650
|
+
if (!initSent || state.unavailable || disposed) return;
|
|
32651
|
+
o2.send({ v: 1, type: "updateLocale", locale: nextLocale ?? "en", rtl: nextRtl ?? false });
|
|
32652
|
+
},
|
|
32610
32653
|
currentContent() {
|
|
32611
32654
|
return !state.unavailable && !disposed && writes() ? lastContent : null;
|
|
32612
32655
|
},
|
|
@@ -32983,6 +33026,9 @@ function RichContentEditorView({ props, ctx, wrap, nodeId, renderChild, ...dom }
|
|
|
32983
33026
|
sessionRef.current = null;
|
|
32984
33027
|
};
|
|
32985
33028
|
}, [live3, src]);
|
|
33029
|
+
React3.useEffect(() => {
|
|
33030
|
+
sessionRef.current?.updateLocale(ctx.localeTag ?? "en", ctx.isRTL ?? document.documentElement.dir === "rtl");
|
|
33031
|
+
}, [ctx.localeTag, ctx.isRTL]);
|
|
32986
33032
|
React3.useEffect(() => {
|
|
32987
33033
|
sessionRef.current?.setSeed(seedMode === "literal" ? props.documentJson : seedMode === "binding" ? boundSeed : "");
|
|
32988
33034
|
}, [seedMode, props.documentJson, boundSeed, src]);
|
|
@@ -125503,6 +125549,155 @@ async function handleWebWix(req, res, state) {
|
|
|
125503
125549
|
res.setHeader("access-control-allow-origin", "*");
|
|
125504
125550
|
res.end(JSON.stringify(obj3));
|
|
125505
125551
|
};
|
|
125552
|
+
if (path2 === "/v1/__webwix/stream" && req.method === "POST") {
|
|
125553
|
+
const b2 = await readJson8();
|
|
125554
|
+
const method = String(b2.method ?? "GET").toUpperCase();
|
|
125555
|
+
const requestedUrl = String(b2.url ?? "");
|
|
125556
|
+
const body = b2.body === void 0 ? void 0 : typeof b2.body === "string" ? b2.body : JSON.stringify(b2.body);
|
|
125557
|
+
const forwardedHeaders = normalizeWixForwardedHeaders(b2.headers, requestedUrl);
|
|
125558
|
+
const target = (() => {
|
|
125559
|
+
try {
|
|
125560
|
+
return new URL(requestedUrl, "https://www.wixapis.com");
|
|
125561
|
+
} catch {
|
|
125562
|
+
return void 0;
|
|
125563
|
+
}
|
|
125564
|
+
})();
|
|
125565
|
+
const started = Date.now();
|
|
125566
|
+
const recordStream = (source, status, mockRuleId, headers2) => {
|
|
125567
|
+
const redactBodies = source === "proxy" || mockRuleId === UNMATCHED_FAIL_CLOSED_ID;
|
|
125568
|
+
recordWixTraffic(state.wix, state.appName, state.adminUrl, {
|
|
125569
|
+
ts: started,
|
|
125570
|
+
source,
|
|
125571
|
+
capability: "wix_api.web",
|
|
125572
|
+
host: target?.host ?? "unknown",
|
|
125573
|
+
method,
|
|
125574
|
+
// Traffic is retained and broadcast to the devtools/admin log. Keep only
|
|
125575
|
+
// the origin and path: rejected URLs may contain userinfo, and valid Wix
|
|
125576
|
+
// endpoints can carry credential-like query parameters.
|
|
125577
|
+
url: target ? `${target.origin}${target.pathname}` : "[unparseable URL]",
|
|
125578
|
+
path: target?.pathname ?? "[unparseable URL]",
|
|
125579
|
+
status,
|
|
125580
|
+
durationMs: Date.now() - started,
|
|
125581
|
+
reqBody: redactBodies ? void 0 : body,
|
|
125582
|
+
respHeaders: redactBodies ? void 0 : headers2,
|
|
125583
|
+
mockRuleId
|
|
125584
|
+
});
|
|
125585
|
+
};
|
|
125586
|
+
if (!target || !isAllowedConsumerStreamTarget(target.toString()) || !["GET", "POST"].includes(method)) {
|
|
125587
|
+
recordStream("proxy", 400);
|
|
125588
|
+
res.statusCode = 400;
|
|
125589
|
+
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
125590
|
+
res.end(JSON.stringify({ error: "webwix_stream_bad_request" }));
|
|
125591
|
+
return;
|
|
125592
|
+
}
|
|
125593
|
+
if (state.wix.mode === "mock") {
|
|
125594
|
+
const matchCtx = { host: target.host, query: Object.fromEntries(target.searchParams.entries()), headers: forwardedHeaders, body };
|
|
125595
|
+
let match = matchRuleEx(state.wix.rules, method, target.pathname, matchCtx);
|
|
125596
|
+
if (match && (match.rule.kind ?? "mock") !== "mock") {
|
|
125597
|
+
console.error(`[himalaya-dev] net-mocks: rule "${match.rule.id}" is kind:"${match.rule.kind}", which the web bridge cannot apply \u2014 ignoring it for ${method} ${target.pathname}`);
|
|
125598
|
+
match = matchRuleEx(state.wix.rules.filter((r2) => (r2.kind ?? "mock") === "mock"), method, target.pathname, matchCtx);
|
|
125599
|
+
}
|
|
125600
|
+
if (match) {
|
|
125601
|
+
const mocked = match.rule.response;
|
|
125602
|
+
if (mocked.delayMs) await new Promise((resolve57) => setTimeout(resolve57, mocked.delayMs));
|
|
125603
|
+
const payload = mocked.template ? renderTemplate(mocked.body, match.captures) : mocked.body;
|
|
125604
|
+
recordStream("mock", mocked.status, match.rule.id, mocked.headers);
|
|
125605
|
+
res.statusCode = mocked.status;
|
|
125606
|
+
res.setHeader("content-type", mocked.headers?.["content-type"] ?? "text/event-stream; charset=utf-8");
|
|
125607
|
+
res.setHeader("cache-control", "no-cache");
|
|
125608
|
+
res.end(payload ?? "");
|
|
125609
|
+
return;
|
|
125610
|
+
}
|
|
125611
|
+
if (failsClosed(state.wix)) {
|
|
125612
|
+
const refusal = hermeticRefusal(method, target.pathname);
|
|
125613
|
+
recordStream("mock", refusal.status, UNMATCHED_FAIL_CLOSED_ID, refusal.headers);
|
|
125614
|
+
res.statusCode = refusal.status;
|
|
125615
|
+
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
125616
|
+
res.end(refusal.body);
|
|
125617
|
+
return;
|
|
125618
|
+
}
|
|
125619
|
+
}
|
|
125620
|
+
const abort = new AbortController();
|
|
125621
|
+
const onResponseClose = () => {
|
|
125622
|
+
if (!res.writableFinished) abort.abort();
|
|
125623
|
+
};
|
|
125624
|
+
res.once("close", onResponseClose);
|
|
125625
|
+
try {
|
|
125626
|
+
if (!session.visitorToken && !session.memberToken) {
|
|
125627
|
+
try {
|
|
125628
|
+
session.visitorToken = await mintVisitor(resolveWixClientId(state.app) ?? WEBWIX_CLIENT_ID);
|
|
125629
|
+
} catch {
|
|
125630
|
+
}
|
|
125631
|
+
}
|
|
125632
|
+
const isMember = !!session.memberToken;
|
|
125633
|
+
let token = session.memberToken ?? session.visitorToken ?? "";
|
|
125634
|
+
let upstream = await webWixStream(method, target.toString(), body, token, void 0, forwardedHeaders, abort.signal);
|
|
125635
|
+
if ((upstream.status === 401 || upstream.status === 403) && !isMember && !abort.signal.aborted) {
|
|
125636
|
+
try {
|
|
125637
|
+
await upstream.body?.cancel();
|
|
125638
|
+
} catch {
|
|
125639
|
+
}
|
|
125640
|
+
try {
|
|
125641
|
+
token = session.visitorToken = await mintVisitor(resolveWixClientId(state.app) ?? WEBWIX_CLIENT_ID);
|
|
125642
|
+
upstream = await webWixStream(method, target.toString(), body, token, void 0, forwardedHeaders, abort.signal);
|
|
125643
|
+
} catch {
|
|
125644
|
+
}
|
|
125645
|
+
}
|
|
125646
|
+
res.statusCode = upstream.status;
|
|
125647
|
+
for (const name of ["content-type", "cache-control", "retry-after"]) {
|
|
125648
|
+
const value = upstream.headers.get(name);
|
|
125649
|
+
if (value) res.setHeader(name, value);
|
|
125650
|
+
}
|
|
125651
|
+
res.setHeader("access-control-allow-origin", "*");
|
|
125652
|
+
res.setHeader("cache-control", res.getHeader("cache-control") ?? "no-cache");
|
|
125653
|
+
recordStream("proxy", upstream.status);
|
|
125654
|
+
if (!upstream.body) {
|
|
125655
|
+
res.end();
|
|
125656
|
+
return;
|
|
125657
|
+
}
|
|
125658
|
+
const reader = upstream.body.getReader();
|
|
125659
|
+
for (; ; ) {
|
|
125660
|
+
if (abort.signal.aborted) {
|
|
125661
|
+
await reader.cancel();
|
|
125662
|
+
break;
|
|
125663
|
+
}
|
|
125664
|
+
const chunk = await reader.read();
|
|
125665
|
+
if (chunk.done) break;
|
|
125666
|
+
if (chunk.value && !res.write(chunk.value)) {
|
|
125667
|
+
await new Promise((resolve57) => {
|
|
125668
|
+
let settled = false;
|
|
125669
|
+
const finish2 = () => {
|
|
125670
|
+
if (settled) return;
|
|
125671
|
+
settled = true;
|
|
125672
|
+
res.off("drain", finish2);
|
|
125673
|
+
res.off("close", finish2);
|
|
125674
|
+
resolve57();
|
|
125675
|
+
};
|
|
125676
|
+
if (res.destroyed || !res.writable) finish2();
|
|
125677
|
+
else {
|
|
125678
|
+
res.once("drain", finish2);
|
|
125679
|
+
res.once("close", finish2);
|
|
125680
|
+
}
|
|
125681
|
+
});
|
|
125682
|
+
}
|
|
125683
|
+
}
|
|
125684
|
+
if (!res.destroyed) res.end();
|
|
125685
|
+
} catch {
|
|
125686
|
+
if (!abort.signal.aborted) {
|
|
125687
|
+
recordStream("proxy", 502);
|
|
125688
|
+
if (!res.headersSent) {
|
|
125689
|
+
res.statusCode = 502;
|
|
125690
|
+
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
125691
|
+
res.end(JSON.stringify({ error: "webwix_stream_failed" }));
|
|
125692
|
+
} else if (!res.destroyed) {
|
|
125693
|
+
res.destroy(new Error("webwix_stream_failed"));
|
|
125694
|
+
}
|
|
125695
|
+
}
|
|
125696
|
+
} finally {
|
|
125697
|
+
res.off("close", onResponseClose);
|
|
125698
|
+
}
|
|
125699
|
+
return;
|
|
125700
|
+
}
|
|
125506
125701
|
if (path2 === "/v1/__webwix/login" && req.method === "POST") {
|
|
125507
125702
|
const b2 = await readJson8();
|
|
125508
125703
|
try {
|
|
@@ -142401,7 +142596,7 @@ function json4(status, body, headers2 = {}) {
|
|
|
142401
142596
|
return new Response(JSON.stringify(body), { status, headers: { "content-type": JSON_CT2, ...headers2 } });
|
|
142402
142597
|
}
|
|
142403
142598
|
function isCookieAuthorizedPath(path2) {
|
|
142404
|
-
return path2 === "/v1/__webwix/call" || path2 === "/v1/owner" || path2.startsWith("/v1/owner/") || path2 === "/v1/__webwix/identity" || path2 === "/v1/__webwix/login" || path2 === "/v1/__webwix/register" || path2 === "/v1/__webwix/logout" || path2 === MEMBER_CALLBACK_PATH;
|
|
142599
|
+
return path2 === "/v1/__webwix/call" || path2 === "/v1/__webwix/stream" || path2 === "/v1/owner" || path2.startsWith("/v1/owner/") || path2 === "/v1/__webwix/identity" || path2 === "/v1/__webwix/login" || path2 === "/v1/__webwix/register" || path2 === "/v1/__webwix/logout" || path2 === MEMBER_CALLBACK_PATH;
|
|
142405
142600
|
}
|
|
142406
142601
|
function webwixCallLog(served, status) {
|
|
142407
142602
|
const directRung = served.rung === "visitor" || served.rung === "owner";
|
|
@@ -142767,6 +142962,48 @@ ${releaseId}`;
|
|
|
142767
142962
|
}
|
|
142768
142963
|
return json4(200, { authenticated: false, userId: null, email: null, webwixDirect }, { "cache-control": "no-store" });
|
|
142769
142964
|
}
|
|
142965
|
+
if (request.method === "POST" && path2 === "/v1/__webwix/stream") {
|
|
142966
|
+
if (opts.webwixBridge === false) return json4(503, { error: "webwix_bridge_disabled" }, { "cache-control": "no-store" });
|
|
142967
|
+
const app2 = resolveApp(request, url);
|
|
142968
|
+
const hostApp = memberApp(request);
|
|
142969
|
+
if (!app2) return json4(400, { error: "app_required" }, { "cache-control": "no-store" });
|
|
142970
|
+
if (!hostApp || app2 !== hostApp) return json4(403, { error: "webwix_stream_host_mismatch" }, { "cache-control": "no-store" });
|
|
142971
|
+
const resolvedCfg = await appConfigFor(request, url, app2);
|
|
142972
|
+
if (!resolvedCfg.ok) return resolvedCfg.response;
|
|
142973
|
+
let call;
|
|
142974
|
+
try {
|
|
142975
|
+
call = await request.json();
|
|
142976
|
+
} catch {
|
|
142977
|
+
return json4(400, { error: "invalid_json" }, { "cache-control": "no-store" });
|
|
142978
|
+
}
|
|
142979
|
+
const method = String(call.method ?? "GET").toUpperCase();
|
|
142980
|
+
if (method !== "GET" && method !== "POST") return json4(400, { error: "invalid_stream_method" }, { "cache-control": "no-store" });
|
|
142981
|
+
const rawTarget = String(call.url ?? "");
|
|
142982
|
+
const target = /^https:\/\//i.test(rawTarget) ? rawTarget : `https://www.wixapis.com${rawTarget.startsWith("/") ? rawTarget : `/${rawTarget}`}`;
|
|
142983
|
+
if (!isAllowedConsumerStreamTarget(target)) return json4(400, { error: "invalid_stream_target" }, { "cache-control": "no-store" });
|
|
142984
|
+
const cfg = wixMemberAuthOf(utf8Decode(resolvedCfg.bytes), callbackUrlFor(url));
|
|
142985
|
+
if (!cfg.ok) return json4(501, { error: "webwix_visitor_direct_only", app: app2 }, { "cache-control": "no-store" });
|
|
142986
|
+
const store2 = memberSessions();
|
|
142987
|
+
const token = memberAuthOn() && store2 ? await memberTokenFor(store2, readSessionCookie(request.headers.get("cookie")), hostApp, cfg.config.clientId) : null;
|
|
142988
|
+
if (!token) return json4(501, { error: "webwix_visitor_direct_only", app: app2 }, { "cache-control": "no-store" });
|
|
142989
|
+
const headers2 = normalizeWixForwardedHeaders(call.headers);
|
|
142990
|
+
headers2.Accept = "text/event-stream";
|
|
142991
|
+
headers2.Authorization = token;
|
|
142992
|
+
const body = call.body === void 0 ? void 0 : typeof call.body === "string" ? call.body : JSON.stringify(call.body);
|
|
142993
|
+
if (body !== void 0) headers2["Content-Type"] ??= "application/json";
|
|
142994
|
+
let upstream;
|
|
142995
|
+
try {
|
|
142996
|
+
upstream = await webwixFetch(target, { method, headers: headers2, body: method === "GET" ? void 0 : body, redirect: "manual", signal: request.signal });
|
|
142997
|
+
} catch {
|
|
142998
|
+
return json4(502, { error: "webwix_stream_upstream_failed" }, { "cache-control": "no-store" });
|
|
142999
|
+
}
|
|
143000
|
+
const responseHeaders = new Headers({ "cache-control": "no-store, no-transform" });
|
|
143001
|
+
for (const name of ["content-type", "retry-after"]) {
|
|
143002
|
+
const value = upstream.headers.get(name);
|
|
143003
|
+
if (value) responseHeaders.set(name, value);
|
|
143004
|
+
}
|
|
143005
|
+
return new Response(upstream.body, { status: upstream.status, headers: responseHeaders });
|
|
143006
|
+
}
|
|
142770
143007
|
if (request.method === "POST" && path2 === "/v1/__webwix/call") {
|
|
142771
143008
|
const served = { rung: "none" };
|
|
142772
143009
|
let status = 500;
|
|
@@ -143690,7 +143927,7 @@ var init_run_handler = __esm({
|
|
|
143690
143927
|
|
|
143691
143928
|
// ../../core/serve-runtime/src/node-adapter.ts
|
|
143692
143929
|
import { createServer as createServer6 } from "node:http";
|
|
143693
|
-
async function toRequest(req) {
|
|
143930
|
+
async function toRequest(req, signal) {
|
|
143694
143931
|
const method = (req.method ?? "GET").toUpperCase();
|
|
143695
143932
|
const host = typeof req.headers.host === "string" && req.headers.host || "serve.local";
|
|
143696
143933
|
const url = new URL(req.url ?? "/", `http://${host}`);
|
|
@@ -143706,7 +143943,7 @@ async function toRequest(req) {
|
|
|
143706
143943
|
for await (const chunk of req) chunks.push(chunk);
|
|
143707
143944
|
if (chunks.length) body = Buffer.concat(chunks);
|
|
143708
143945
|
}
|
|
143709
|
-
return new Request(url, { method, headers: headers2, body });
|
|
143946
|
+
return new Request(url, { method, headers: headers2, body, signal });
|
|
143710
143947
|
}
|
|
143711
143948
|
async function writeResponse(res, response) {
|
|
143712
143949
|
res.statusCode = response.status;
|
|
@@ -143714,10 +143951,15 @@ async function writeResponse(res, response) {
|
|
|
143714
143951
|
if (response.body && /^text\/event-stream\b/i.test(response.headers.get("content-type") ?? "")) {
|
|
143715
143952
|
res.flushHeaders();
|
|
143716
143953
|
const reader = response.body.getReader();
|
|
143717
|
-
|
|
143718
|
-
|
|
143719
|
-
|
|
143720
|
-
|
|
143954
|
+
let clientDisconnected = false;
|
|
143955
|
+
const onClose = () => {
|
|
143956
|
+
if (!res.writableEnded) {
|
|
143957
|
+
clientDisconnected = true;
|
|
143958
|
+
void reader.cancel().catch(() => {
|
|
143959
|
+
});
|
|
143960
|
+
}
|
|
143961
|
+
};
|
|
143962
|
+
res.on("close", onClose);
|
|
143721
143963
|
try {
|
|
143722
143964
|
for (; ; ) {
|
|
143723
143965
|
const { done, value } = await reader.read();
|
|
@@ -143725,7 +143967,10 @@ async function writeResponse(res, response) {
|
|
|
143725
143967
|
res.write(value);
|
|
143726
143968
|
}
|
|
143727
143969
|
} catch {
|
|
143970
|
+
if (!clientDisconnected && !res.destroyed) res.destroy();
|
|
143971
|
+
return;
|
|
143728
143972
|
}
|
|
143973
|
+
res.off("close", onClose);
|
|
143729
143974
|
res.end();
|
|
143730
143975
|
return;
|
|
143731
143976
|
}
|
|
@@ -143734,10 +143979,23 @@ async function writeResponse(res, response) {
|
|
|
143734
143979
|
}
|
|
143735
143980
|
function nodeAdapter(handler) {
|
|
143736
143981
|
return createServer6(async (req, res) => {
|
|
143982
|
+
const controller = new AbortController();
|
|
143983
|
+
const abortForDisconnect = () => {
|
|
143984
|
+
if (!res.writableEnded) controller.abort();
|
|
143985
|
+
};
|
|
143986
|
+
req.once("aborted", abortForDisconnect);
|
|
143987
|
+
res.once("close", abortForDisconnect);
|
|
143737
143988
|
try {
|
|
143738
|
-
const
|
|
143989
|
+
const request = await toRequest(req, controller.signal);
|
|
143990
|
+
const response = await handler(request);
|
|
143991
|
+
if (controller.signal.aborted || res.destroyed) {
|
|
143992
|
+
await response.body?.cancel().catch(() => {
|
|
143993
|
+
});
|
|
143994
|
+
return;
|
|
143995
|
+
}
|
|
143739
143996
|
await writeResponse(res, response);
|
|
143740
143997
|
} catch (err) {
|
|
143998
|
+
if (controller.signal.aborted || res.destroyed) return;
|
|
143741
143999
|
if (!res.headersSent) res.writeHead(500, { "content-type": "application/json; charset=utf-8" });
|
|
143742
144000
|
res.end(JSON.stringify({ error: "internal", message: err.message }));
|
|
143743
144001
|
}
|
|
@@ -143817,23 +144075,23 @@ var init_preview_assets_generated = __esm({
|
|
|
143817
144075
|
"../../packages/serve/src/preview-assets.generated.ts"() {
|
|
143818
144076
|
init_preview_assets_format();
|
|
143819
144077
|
PREVIEW_ASSET_MANIFEST = [
|
|
143820
|
-
{ key: "assets/index-
|
|
143821
|
-
{ key: "assets/pdf.worker.min-BmVo14Nb.mjs", contentType: "application/octet-stream", offset:
|
|
143822
|
-
{ key: "assets/pdfDocument-
|
|
143823
|
-
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset:
|
|
143824
|
-
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset:
|
|
143825
|
-
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset:
|
|
143826
|
-
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
143827
|
-
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset:
|
|
143828
|
-
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset:
|
|
143829
|
-
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
143830
|
-
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset:
|
|
143831
|
-
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
143832
|
-
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset:
|
|
143833
|
-
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset:
|
|
143834
|
-
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
143835
|
-
{ key: "index.html", contentType: "text/html; charset=utf-8", offset:
|
|
143836
|
-
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset:
|
|
144078
|
+
{ key: "assets/index-BASyrUOE.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1199331, sha256: "61bbacb882f499d8de973edf6cd283e953dad24fbe362d909e1d66b97aaea7af" },
|
|
144079
|
+
{ key: "assets/pdf.worker.min-BmVo14Nb.mjs", contentType: "application/octet-stream", offset: 1199339, length: 1317034, sha256: "a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e" },
|
|
144080
|
+
{ key: "assets/pdfDocument-93Ito3np.js", contentType: "application/javascript; charset=utf-8", offset: 2516373, length: 489166, sha256: "1241febb4b04acb0b3b5341d29b16488d606d7a070e96b45872392309579817e" },
|
|
144081
|
+
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 3005539, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
|
|
144082
|
+
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 3010149, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
|
|
144083
|
+
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 3498733, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
|
|
144084
|
+
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 3589657, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
|
|
144085
|
+
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 3680641, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
|
|
144086
|
+
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 3771621, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
|
|
144087
|
+
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 3862493, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
|
|
144088
|
+
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 3953473, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
|
|
144089
|
+
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 4062109, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
|
|
144090
|
+
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 4171193, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
|
|
144091
|
+
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 4280241, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
|
|
144092
|
+
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 4387941, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
|
|
144093
|
+
{ key: "index.html", contentType: "text/html; charset=utf-8", offset: 4476049, length: 4947, sha256: "14ea64c15439ccc29ea7030d38ef2212a342b8e443445a4e4e3179c0ee3e9c66" },
|
|
144094
|
+
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 4480996, length: 17344, sha256: "d057298d75e7373e5e2c4d11b7d1bcbea88e03af555ba63d97641c78509c58e4" }
|
|
143837
144095
|
];
|
|
143838
144096
|
}
|
|
143839
144097
|
});
|
|
Binary file
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"name": "StreamDirective",
|
|
21
21
|
"kind": "interface",
|
|
22
22
|
"jsdoc": "/**\n * Streaming directive (RFC 0040). An action may return its new state with a\n * transient `_stream` field; the runtime strips it from the stored state and\n * asks the native host to open the request as a Server-Sent-Events stream. For\n * every parsed `data:` event the host dispatches `onEvent(state, event)` back\n * through the normal reducer→render loop (the worker has no timers), then\n * `onDone(state)` / `onError(state, {message})` when the stream closes. Requires\n * the bundle to declare the `\"stream\"` capability; `request.url` is checked\n * against the same per-capability host allowlist as `wix_api`.\n */",
|
|
23
|
-
"decl": "export interface StreamDirective {\n /** Stable id; a new directive with the same id cancels the prior stream. */\n id: string;\n request: {\n method: \"POST\" | \"GET\";\n url: string;\n headers?: Record<string, string>;\n body?: unknown;\n };\n /** Reducer action name dispatched once per parsed `data:` event. */\n onEvent: string;\n /** Reducer action name dispatched when the stream closes cleanly. */\n onDone?: string;\n /** Reducer action name dispatched on transport/parse error. */\n onError?: string;\n}"
|
|
23
|
+
"decl": "export interface StreamDirective {\n /** Stable id; a new directive with the same id cancels the prior stream. */\n id: string;\n request: {\n method: \"POST\" | \"GET\";\n url: string;\n headers?: Record<string, string>;\n body?: unknown;\n /** Apply the host's Wix authorization to this request before opening the stream. */\n authorize?: boolean;\n };\n /** Reducer action name dispatched once per parsed `data:` event. */\n onEvent: string;\n /** Reducer action name dispatched when the stream closes cleanly. */\n onDone?: string;\n /** Reducer action name dispatched on transport/parse error. */\n onError?: string;\n}"
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"name": "StreamEvent",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1252.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": [
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"artifactId": "himalaya-cli"
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
|
-
"falconPackageHash": "
|
|
70
|
+
"falconPackageHash": "87f23d8f06f88ed92ac988ab724637b5633bcdaccfc2c23e791f1a71"
|
|
71
71
|
}
|