@lark-base-open/base-site-channel 0.1.1
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/LICENSE +6 -0
- package/README.md +797 -0
- package/dist/binary_fetch-0a477817.d.ts +88 -0
- package/dist/client.d.ts +52 -0
- package/dist/client.mjs +1 -0
- package/dist/index.d.ts +79 -0
- package/dist/index.mjs +288 -0
- package/dist/runtime-contract.d.ts +313 -0
- package/dist/runtime-contract.mjs +1 -0
- package/dist/runtime.d.ts +115 -0
- package/dist/runtime.mjs +4 -0
- package/package.json +1 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
declare enum ChannelErrorType {
|
|
2
|
+
IFRAME_LOAD_ERROR = "iframeLoadError",
|
|
3
|
+
NOT_ALLOWED_URL = "notAllowedUrl",
|
|
4
|
+
HANDSHAKE_TIME_OUT = "handshakeTimeout",
|
|
5
|
+
CHANNEL_UNAVAILABLE = "channelUnavailable"
|
|
6
|
+
}
|
|
7
|
+
interface LoadStatusErrorInfo {
|
|
8
|
+
type: ChannelErrorType;
|
|
9
|
+
message?: string;
|
|
10
|
+
}
|
|
11
|
+
declare enum ChannelErrorCode {
|
|
12
|
+
UNKNOWN = -1,
|
|
13
|
+
IFRAME_LOAD_ERROR = 10001,
|
|
14
|
+
NOT_ALLOWED_URL = 10002,
|
|
15
|
+
HANDSHAKE_TIME_OUT = 10003,
|
|
16
|
+
API_NOT_FOUND = 10004,
|
|
17
|
+
REQUEST_TIMEOUT = 10005,
|
|
18
|
+
CHANNEL_DESTROYED = 10006,
|
|
19
|
+
BINARY_FETCH_DISABLED = 10007,
|
|
20
|
+
DUPLICATED_REQUEST = 10008,
|
|
21
|
+
CHANNEL_UNAVAILABLE = 10009
|
|
22
|
+
}
|
|
23
|
+
type ApiHandler<T = unknown, P = unknown> = (params: T) => Promise<P>;
|
|
24
|
+
type EventHandler<T = unknown> = (params: T) => void | Promise<void>;
|
|
25
|
+
interface IApi {
|
|
26
|
+
invokeApi: <T, P>(key: string, params: T, options?: InvokeApiOptions) => Promise<P>;
|
|
27
|
+
registerApi: <T, P>(key: string, handler: ApiHandler<T, P>) => void;
|
|
28
|
+
emitEvent: <T>(key: string, params: T) => Promise<void>;
|
|
29
|
+
subscribeEvent: <T>(key: string, handler: EventHandler<T>) => () => void;
|
|
30
|
+
unsubscribeEvent: <T>(key: string, handler?: EventHandler<T>) => void;
|
|
31
|
+
}
|
|
32
|
+
interface InvokeApiOptions {
|
|
33
|
+
timeoutMs?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface BinaryFetchItem {
|
|
37
|
+
itemId: string;
|
|
38
|
+
url: string;
|
|
39
|
+
}
|
|
40
|
+
type BinaryFetchCredentials = 'omit' | 'same-origin' | 'include';
|
|
41
|
+
interface BinaryFetchParams {
|
|
42
|
+
items: BinaryFetchItem[];
|
|
43
|
+
concurrency?: number;
|
|
44
|
+
credentials?: BinaryFetchCredentials;
|
|
45
|
+
}
|
|
46
|
+
interface BinaryFetchJobResult {
|
|
47
|
+
jobId: string;
|
|
48
|
+
}
|
|
49
|
+
interface BinaryFetchCancelParams {
|
|
50
|
+
jobId: string;
|
|
51
|
+
}
|
|
52
|
+
interface BinaryFetchJobStartProgress {
|
|
53
|
+
type: 'job-start';
|
|
54
|
+
jobId: string;
|
|
55
|
+
total: number;
|
|
56
|
+
}
|
|
57
|
+
interface BinaryFetchItemCompleteProgress {
|
|
58
|
+
type: 'item-complete';
|
|
59
|
+
jobId: string;
|
|
60
|
+
itemId: string;
|
|
61
|
+
totalBytes?: number;
|
|
62
|
+
buffer: ArrayBuffer;
|
|
63
|
+
}
|
|
64
|
+
interface BinaryFetchItemErrorProgress {
|
|
65
|
+
type: 'item-error';
|
|
66
|
+
jobId: string;
|
|
67
|
+
itemId: string;
|
|
68
|
+
error: string;
|
|
69
|
+
}
|
|
70
|
+
interface BinaryFetchJobCompleteProgress {
|
|
71
|
+
type: 'job-complete';
|
|
72
|
+
jobId: string;
|
|
73
|
+
successCount: number;
|
|
74
|
+
failCount: number;
|
|
75
|
+
}
|
|
76
|
+
interface BinaryFetchJobCancelledProgress {
|
|
77
|
+
type: 'job-cancelled';
|
|
78
|
+
jobId: string;
|
|
79
|
+
}
|
|
80
|
+
type BinaryFetchProgress = BinaryFetchJobStartProgress | BinaryFetchItemCompleteProgress | BinaryFetchItemErrorProgress | BinaryFetchJobCompleteProgress | BinaryFetchJobCancelledProgress;
|
|
81
|
+
type BinaryFetchProgressHandler = (progress: BinaryFetchProgress) => void | Promise<void>;
|
|
82
|
+
interface BinaryFetchApi {
|
|
83
|
+
fetchBinaryList: (params: BinaryFetchParams) => Promise<BinaryFetchJobResult>;
|
|
84
|
+
subscribeBinaryFetchProgress: (handler: BinaryFetchProgressHandler) => () => void;
|
|
85
|
+
cancelBinaryFetch: (jobId: string) => Promise<void>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export { ApiHandler as A, BinaryFetchApi as B, ChannelErrorCode as C, EventHandler as E, InvokeApiOptions as I, LoadStatusErrorInfo as L, IApi as a, BinaryFetchCancelParams as b, BinaryFetchItem as c, BinaryFetchJobCancelledProgress as d, BinaryFetchJobCompleteProgress as e, BinaryFetchJobResult as f, BinaryFetchJobStartProgress as g, BinaryFetchItemCompleteProgress as h, BinaryFetchItemErrorProgress as i, BinaryFetchParams as j, BinaryFetchProgress as k, BinaryFetchProgressHandler as l, ChannelErrorType as m };
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { I as InvokeApiOptions, A as ApiHandler, j as BinaryFetchParams, f as BinaryFetchJobResult, k as BinaryFetchProgress, E as EventHandler, a as IApi, B as BinaryFetchApi } from './binary_fetch-0a477817.js';
|
|
2
|
+
|
|
3
|
+
type IClient = IApi & BinaryFetchApi;
|
|
4
|
+
interface ClientOptions {
|
|
5
|
+
hostOrigin?: string;
|
|
6
|
+
}
|
|
7
|
+
declare class Client implements IClient {
|
|
8
|
+
private pendingRequests;
|
|
9
|
+
private eventMap;
|
|
10
|
+
private eventHandlerMap;
|
|
11
|
+
private _msgChannel;
|
|
12
|
+
private _invokeId;
|
|
13
|
+
private _handshakePromise;
|
|
14
|
+
private _handshakeResolve;
|
|
15
|
+
private _handshakeReject;
|
|
16
|
+
private _handshakeRetryTimes;
|
|
17
|
+
private _handshakeStatus;
|
|
18
|
+
private _handshakeTimeout;
|
|
19
|
+
private _prefixId;
|
|
20
|
+
private readonly hostOrigin;
|
|
21
|
+
private _destroyed;
|
|
22
|
+
private logInfo;
|
|
23
|
+
private logWarn;
|
|
24
|
+
private logError;
|
|
25
|
+
constructor(options?: ClientOptions);
|
|
26
|
+
private failHandshake;
|
|
27
|
+
private sendProactiveHandshakeMsg;
|
|
28
|
+
private _initHandshake;
|
|
29
|
+
private startHandshake;
|
|
30
|
+
private retryHandshake;
|
|
31
|
+
private updateInvokeId;
|
|
32
|
+
private handleChannelMessage;
|
|
33
|
+
private handleHostCallback;
|
|
34
|
+
private handleHostInvoke;
|
|
35
|
+
private handleHostEvent;
|
|
36
|
+
private handleHandshakeCallback;
|
|
37
|
+
private listeningHostMsg;
|
|
38
|
+
private sendMsg2Host;
|
|
39
|
+
invokeApi<T, P>(key: string, params: T, options?: InvokeApiOptions): Promise<P>;
|
|
40
|
+
registerApi<T, P>(key: string, handler: ApiHandler<T, P>): void;
|
|
41
|
+
emitEvent<T>(key: string, params: T): Promise<void>;
|
|
42
|
+
fetchBinaryList(params: BinaryFetchParams): Promise<BinaryFetchJobResult>;
|
|
43
|
+
subscribeBinaryFetchProgress(handler: (progress: BinaryFetchProgress) => void | Promise<void>): () => void;
|
|
44
|
+
cancelBinaryFetch(jobId: string): Promise<void>;
|
|
45
|
+
destroy(): void;
|
|
46
|
+
subscribeEvent<T>(key: string, handler: EventHandler<T>): () => void;
|
|
47
|
+
unsubscribeEvent<T>(key: string, handler?: EventHandler<T>): void;
|
|
48
|
+
}
|
|
49
|
+
declare const createClient: (options?: ClientOptions) => Client;
|
|
50
|
+
declare const client: Client;
|
|
51
|
+
|
|
52
|
+
export { Client, ClientOptions, client, createClient };
|
package/dist/client.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var V=Object.defineProperty,q=Object.defineProperties;var J=Object.getOwnPropertyDescriptors;var N=Object.getOwnPropertySymbols;var $=Object.prototype.hasOwnProperty,G=Object.prototype.propertyIsEnumerable;var B=(n,e,t)=>e in n?V(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t,o=(n,e)=>{for(var t in e||(e={}))$.call(e,t)&&B(n,t,e[t]);if(N)for(var t of N(e))G.call(e,t)&&B(n,t,e[t]);return n},I=(n,e)=>q(n,J(e));var p=(n,e,t)=>new Promise((r,s)=>{var i=l=>{try{h(t.next(l))}catch(v){s(v)}},a=l=>{try{h(t.throw(l))}catch(v){s(v)}},h=l=>l.done?r(l.value):Promise.resolve(l.value).then(i,a);h((t=t.apply(n,e)).next())});import{uniqueId as H}from"lodash-es";var k="same-origin",w="__internal_fetchBinaryList__",F="__internal_cancelBinaryFetch__",O="__internal_binaryFetchProgress__";function A(n){return Number.isFinite(n)?Math.max(1,Math.floor(n)):4}function T(n){return n==="omit"||n==="include"?n:k}var m=(s=>(s.IFRAME_LOAD_ERROR="iframeLoadError",s.NOT_ALLOWED_URL="notAllowedUrl",s.HANDSHAKE_TIME_OUT="handshakeTimeout",s.CHANNEL_UNAVAILABLE="channelUnavailable",s))(m||{});var c=class extends Error{constructor(t,r){super(r);this.code=t,this.name="ChannelCallbackError"}};function D(n){return new c(10004,`api "${n}" is not registered`)}function K(n){return new c(10005,`api "${n}" timed out`)}function b(){return new c(10006,"channel has been destroyed")}function U(n){return new c(10008,`request "${n}" was superseded by a new one`)}var X="unknown error";function j(n){return typeof n=="object"&&n!==null}function Z(n){if(typeof n=="string"&&n)return n;if(n instanceof c&&n.message||n instanceof Error&&n.message)return n.message;if(j(n)){let{msg:e,message:t}=n;if(typeof e=="string"&&e)return e;if(typeof t=="string"&&t)return t}return X}function ee(n){if(n instanceof c)return n.code;if(!j(n))return-1;let{code:e}=n;return typeof e=="string"&&e||typeof e=="number"&&Number.isFinite(e)?e:-1}function d(n){return{code:ee(n),msg:Z(n)}}function S(n){return n instanceof ArrayBuffer||ArrayBuffer.isView(n)||typeof Blob!="undefined"&&n instanceof Blob}function te(n){return S(n)||Object.values(n).some(e=>S(e))}function W(n){return n&&typeof n=="object"?te(n)?n:JSON.parse(JSON.stringify(n)):n}var ne={["iframeLoadError"]:10001,["notAllowedUrl"]:10002,["handshakeTimeout"]:10003,["channelUnavailable"]:10009};function re(n){return typeof n=="object"&&n!==null}function se(n){if(!re(n))return!1;let{type:e}=n;return typeof e=="string"&&Object.values(m).includes(e)}function x(n){return se(n)?{code:ne[n.type],msg:n.message||n.type}:d(n)}function M(n){let e=Promise.reject(n);return e.catch(()=>{}),e}var E=class{constructor(e,t){this._target=e,this._options=t}sendMsg(e,t){if(!this._target)throw new Error("target window is not found");this._target.postMessage(e,this._options.targetOrigin,t!=null?t:[])}listenMsg(e){this._eventHandler=t=>{t.source===this._options.sourceWindow&&this._options.allowedOrigins.includes(t.origin)&&e(t)},typeof window!="undefined"&&window.addEventListener("message",this._eventHandler)}destroy(){typeof window!="undefined"&&this._eventHandler&&window.removeEventListener("message",this._eventHandler),this._eventHandler=void 0}};var f=class{constructor(e,t,r){e==="host"?this.channelManager=new E(t,r):e==="client"&&(this.channelManager=new E(window.parent,r))}static createInstance(e,t,r){return new f(e,t,r)}sendMsg(e,t){var r;(r=this.channelManager)==null||r.sendMsg(e,t)}listenMsg(e){var t;(t=this.channelManager)==null||t.listenMsg(e)}destroy(){var e;(e=this.channelManager)==null||e.destroy()}};var _=class{constructor(){this.requests=new Map}create(e,t,r=3e4){return this.reject(e,d(U(e))),new Promise((s,i)=>{let a=setTimeout(()=>{var h;((h=this.requests.get(e))==null?void 0:h.timeout)===a&&(this.requests.delete(e),i(d(K(t))))},r);this.requests.set(e,{reject:i,resolve:s,timeout:a})})}resolve(e,t){let r=this.take(e);return r?(r.resolve(t),!0):!1}reject(e,t){let r=this.take(e);return r?(r.reject(t),!0):!1}rejectAll(e){for(let t of this.requests.keys())this.reject(t,e)}take(e){let t=this.requests.get(e);if(t)return this.requests.delete(e),clearTimeout(t.timeout),t}};var L=n=>typeof n=="object"&&n!==null,oe=new Set(["blockId","expectedPrefixId","id","jobId","prefixId","url"]),u=n=>{let e={};for(let[t,r]of Object.entries(n))if(!(t==="inputParams"||t==="outputParams")){if(oe.has(t)){e[`${t}Present`]=!!r;continue}if(t==="error"){Object.assign(e,g(r));continue}if(t==="errorInfo"&&L(r)){e.errorType=typeof r.type=="string"?r.type:"object";continue}(typeof r=="string"||typeof r=="number"||typeof r=="boolean")&&(e[t]=r)}return e},y=n=>{let e={idPresent:!!n.id,type:n.type},t=L(n.payload)?n.payload:{};return typeof t.key=="string"&&(e.key=t.key),n.type==="callback"&&typeof t.code=="number"&&(e.callbackCode=t.code),n.type==="handshake"&&typeof t.proactive=="boolean"&&(e.proactive=t.proactive),e},R=n=>n.type!=="invoke"&&n.type!=="callback",g=n=>{if(!L(n))return{errorType:typeof n};let e={errorType:n instanceof Error?n.name:"object"};return(typeof n.code=="number"||typeof n.code=="string")&&(e.errorCode=n.code),e};var le=()=>{let n=Reflect.get(globalThis,"BearWebSlardarWeb");return typeof n=="function"?n:void 0},he=n=>{let e={};for(let[t,r]of Object.entries(u(n)))typeof r=="string"||typeof r=="number"?e[t]=r:typeof r=="boolean"&&(e[t]=String(r));return e},Y=(n,e,t,r)=>{console[e](`[base-site-channel][${n}]`,t,r)},C=(n,e,t,r={})=>{let s=u(r),i=le();if(!i){Y(n,e,t,s);return}try{i("sendLog",{content:`[base-site-channel][${n}] ${t}`,extra:o({event_name:"Runtime_SiteChannel_Message",bizType:"Runtime",subType:"SiteChannel",action:"Message",channel_side:n,channel_message:t},he(s)),level:e})}catch(a){Y(n,e,t,I(o({},s),{slardarFallback:!0,slardarErrorType:a instanceof Error?a.name:typeof a}))}};var pe=()=>{var t;if(typeof window=="undefined")return null;let e=((t=window.location.ancestorOrigins)==null?void 0:t[0])||document.referrer;if(!e)return null;try{return new URL(e).origin}catch(r){return null}},ue=n=>{try{return new URL(n).origin}catch(e){return null}},P=class{constructor(e={}){this.pendingRequests=new _;this.eventMap=new Map;this.eventHandlerMap=new Map;this._msgChannel=null;this._invokeId="";this._handshakePromise=M({type:"channelUnavailable",message:"channel handshake is not initialized"});this._handshakeResolve=null;this._handshakeReject=null;this._handshakeRetryTimes=0;this._handshakeStatus=0;this._handshakeTimeout=null;this._prefixId="";this._destroyed=!1;let t=e.hostOrigin?ue(e.hostOrigin):null;if(this.hostOrigin=t!=null?t:pe(),e.hostOrigin&&!t&&this.logWarn("invalid hostOrigin, fallback to parent origin"),typeof window=="undefined"||window.parent===window){this.failHandshake("invalid window context",{hasWindow:typeof window!="undefined",isTopWindow:typeof window!="undefined"?window.parent===window:!0});return}if(!this.hostOrigin){this.failHandshake("host origin unavailable");return}this._msgChannel=f.createInstance("client",window.parent,{allowedOrigins:[this.hostOrigin],sourceWindow:window.parent,targetOrigin:this.hostOrigin}),this.listeningHostMsg(),this.startHandshake()}logInfo(e,t={}){C("client","info",e,o({hasPrefixId:!!this._prefixId,handshakeStatus:this._handshakeStatus},u(t)))}logWarn(e,t={}){C("client","warn",e,o({hasPrefixId:!!this._prefixId,handshakeStatus:this._handshakeStatus},u(t)))}logError(e,t={}){C("client","error",e,o({hasPrefixId:!!this._prefixId,handshakeStatus:this._handshakeStatus},u(t)))}failHandshake(e,t={}){this._handshakeStatus=2,this._handshakePromise=M({type:"channelUnavailable",message:e}),this.logError(`init failed: ${e}`,t)}sendProactiveHandshakeMsg(){var t;let e={id:H("handshake-"),type:"handshake",payload:{proactive:!0}};this.logInfo("send proactive handshake",y(e)),(t=this._msgChannel)==null||t.sendMsg(e)}_initHandshake(){this._handshakeRetryTimes=0,clearTimeout(this._handshakeTimeout),this._handshakeStatus=0,this.logInfo("init handshake"),this._handshakePromise=new Promise((e,t)=>{this._handshakeResolve=e,this._handshakeReject=t,this._handshakeTimeout=setTimeout(()=>this.retryHandshake(t),2e3)})}startHandshake(){this._initHandshake(),this._handshakePromise.then(()=>{this._handshakeStatus=1,this.logInfo("handshake success")}).catch(e=>{this._handshakeStatus=2,this.logError("handshake failed",{error:e})}),this.sendProactiveHandshakeMsg()}retryHandshake(e){this._handshakeStatus===0&&(this._handshakeRetryTimes<5?(this.logWarn("retry handshake",{retryTimes:this._handshakeRetryTimes+1}),this.sendProactiveHandshakeMsg(),this._handshakeRetryTimes++,this._handshakeTimeout=setTimeout(()=>this.retryHandshake(e),2e3+2**this._handshakeRetryTimes)):(this.logError("handshake retry timeout",{retryTimes:this._handshakeRetryTimes}),e({type:"handshakeTimeout",message:"iframe handshake time out"})))}updateInvokeId(){this._invokeId=H(`${this._prefixId}-invoke-`)}handleChannelMessage(e){let{data:t}=e;R(t)&&this.logInfo("receive host message",y(t));let{type:r}=t;r==="callback"?this.handleHostCallback(t):r==="handshake"?this.handleHandshakeCallback(t):r==="invoke"?this.handleHostInvoke(t).catch(s=>{this.logError("handle host invoke error",o(o({},y(t)),g(s)))}):r==="event"&&this.handleHostEvent(t).catch(s=>{this.logError("handle host event error",o(o({},y(t)),g(s)))})}handleHostCallback(e){let{id:t,payload:r}=e,s={logId:t,key:r.key,callbackCode:r.code};if(r.code===1){if(this.pendingRequests.reject(t,r.res)){this.logWarn("api response received",s);return}}else if(this.pendingRequests.resolve(t,r.res)){this.logInfo("api response received",s);return}this.logWarn("host callback request not found",{id:t,key:r.key})}handleHostInvoke(e){return p(this,null,function*(){yield this._handshakePromise;let{id:t,payload:r}=e,{key:s,params:i,prefixId:a}=r;if(a!==this._prefixId){this.logWarn("ignore host invoke because prefixId mismatch",{id:t,key:s,prefixId:a,expectedPrefixId:this._prefixId});return}let h=this.eventMap.get(s);if(typeof h!="function"){this.logWarn("host invoke handler not found",{id:t,key:s}),this.sendMsg2Host({id:t,type:"callback",payload:{key:s,res:d(D(s)),code:1}});return}this.logInfo("handle host invoke",{id:t,key:s});try{let l=W(yield h(i));this.sendMsg2Host({id:t,type:"callback",payload:{key:s,res:l,code:0}}),this.logInfo("host invoke success",{id:t,key:s})}catch(l){this.logError("host invoke failed",o({id:t,key:s},g(l))),this.sendMsg2Host({id:t,type:"callback",payload:{key:s,res:d(l),code:1}})}})}handleHostEvent(e){return p(this,null,function*(){yield this._handshakePromise;let{payload:t}=e,{key:r,params:s,prefixId:i}=t;if(i!==this._prefixId){this.logWarn("ignore host event because prefixId mismatch",{key:r,prefixId:i,expectedPrefixId:this._prefixId});return}let a=this.eventHandlerMap.get(r);if(!(a!=null&&a.size)){this.logWarn("host event handler not found",{key:r});return}this.logInfo("handle host event",{key:r,handlerCount:a.size}),yield Promise.allSettled(Array.from(a,h=>h(s)))})}handleHandshakeCallback(e){var i,a;let{id:t,payload:r}=e;this._prefixId=(i=r==null?void 0:r.prefixId)!=null?i:"",this.logInfo("receive handshake callback",{id:t,prefixId:this._prefixId}),(a=this._handshakeResolve)==null||a.call(this);let s={id:t,type:"handshake",payload:{proactive:!1,info:{isHandshakeSuccess:!0}}};this.sendMsg2Host(s)}listeningHostMsg(){var e;this.logInfo("start listening host messages"),(e=this._msgChannel)==null||e.listenMsg(this.handleChannelMessage.bind(this))}sendMsg2Host(e,t){var r;R(e)&&this.logInfo("send message to host",y(e)),(r=this._msgChannel)==null||r.sendMsg(e,t)}invokeApi(e,t,r){return p(this,null,function*(){if(this._destroyed)return Promise.reject(d(b()));try{yield this._handshakePromise}catch(a){return this.logError("invoke api blocked by handshake error",o({key:e},g(a))),Promise.reject(x(a))}this._invokeId||this.updateInvokeId();let s=this._invokeId,i=this.pendingRequests.create(s,e,r==null?void 0:r.timeoutMs);return this.logInfo("api request sent",{key:e,logId:s}),this.sendMsg2Host({type:"invoke",id:s,payload:{key:e,params:t,prefixId:this._prefixId}}),this.updateInvokeId(),i})}registerApi(e,t){if(this.eventMap.has(e)){this.logWarn("register api ignored because key already exists",{key:e});return}this.eventMap.set(e,t),this.logInfo("register api",{key:e})}emitEvent(e,t){return p(this,null,function*(){try{yield this._handshakePromise}catch(r){return this.logError("emit event blocked by handshake error",o({key:e},g(r))),Promise.reject(x(r))}this.logInfo("emit event",{key:e}),this.sendMsg2Host({type:"event",id:H(`${this._prefixId}-event-`),payload:{key:e,params:t,prefixId:this._prefixId}})})}fetchBinaryList(e){return p(this,null,function*(){var t;return this.logInfo("invoke built-in binary fetch",{status:"start",itemCount:e.items.length,concurrency:A(e.concurrency),credentials:T(e.credentials)}),this.invokeApi(w,{items:e.items,concurrency:A(e.concurrency),credentials:T((t=e.credentials)!=null?t:k)})})}subscribeBinaryFetchProgress(e){return this.subscribeEvent(O,e)}cancelBinaryFetch(e){return p(this,null,function*(){this.logInfo("invoke built-in binary fetch cancel",{jobId:e,status:"cancel-requested"}),yield this.invokeApi(F,{jobId:e})})}destroy(){var t,r;if(this._destroyed)return;this._destroyed=!0,this.logInfo("destroy client"),(t=this._msgChannel)==null||t.destroy(),clearTimeout(this._handshakeTimeout);let e=d(b());(r=this._handshakeReject)==null||r.call(this,{type:"handshakeTimeout",message:e.msg}),this.pendingRequests.rejectAll(e),this.eventMap.clear(),this.eventHandlerMap.clear()}subscribeEvent(e,t){var s;let r=(s=this.eventHandlerMap.get(e))!=null?s:new Set;return r.add(t),this.eventHandlerMap.set(e,r),this.logInfo("subscribe event",{key:e,handlerCount:r.size}),()=>this.unsubscribeEvent(e,t)}unsubscribeEvent(e,t){let r=this.eventHandlerMap.get(e);if(!r){this.logWarn("unsubscribe event ignored because key is not subscribed",{key:e});return}if(!t){this.eventHandlerMap.delete(e),this.logInfo("unsubscribe all event handlers",{key:e,handlerCount:0});return}r.delete(t),r.size===0&&this.eventHandlerMap.delete(e),this.logInfo("unsubscribe event",{key:e,handlerCount:r.size})}},ge=n=>new P(n),_t=ge();export{P as Client,_t as client,ge as createClient};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { L as LoadStatusErrorInfo, A as ApiHandler, I as InvokeApiOptions, E as EventHandler, a as IApi } from './binary_fetch-0a477817.js';
|
|
2
|
+
export { B as BinaryFetchApi, b as BinaryFetchCancelParams, c as BinaryFetchItem, h as BinaryFetchItemCompleteProgress, i as BinaryFetchItemErrorProgress, d as BinaryFetchJobCancelledProgress, e as BinaryFetchJobCompleteProgress, f as BinaryFetchJobResult, g as BinaryFetchJobStartProgress, j as BinaryFetchParams, k as BinaryFetchProgress, l as BinaryFetchProgressHandler, C as ChannelErrorCode, m as ChannelErrorType } from './binary_fetch-0a477817.js';
|
|
3
|
+
|
|
4
|
+
interface IHost extends IApi {
|
|
5
|
+
blockId: string;
|
|
6
|
+
destroy: () => void;
|
|
7
|
+
}
|
|
8
|
+
declare enum LoadStatus {
|
|
9
|
+
PENDING = "pending",
|
|
10
|
+
LOADING = "loading",
|
|
11
|
+
LOADED = "loaded",
|
|
12
|
+
ERROR = "error"
|
|
13
|
+
}
|
|
14
|
+
type OnLoadStatusChange = (status: LoadStatus, errorInfo?: LoadStatusErrorInfo) => void;
|
|
15
|
+
interface HostOptions {
|
|
16
|
+
enableBinaryFetch?: boolean;
|
|
17
|
+
}
|
|
18
|
+
declare class Host implements IHost {
|
|
19
|
+
private client;
|
|
20
|
+
private _allowedOrigins;
|
|
21
|
+
private _msgChannel;
|
|
22
|
+
private eventMap;
|
|
23
|
+
private eventHandlerMap;
|
|
24
|
+
private pendingRequests;
|
|
25
|
+
private clientMessageHandler;
|
|
26
|
+
private _invokeId;
|
|
27
|
+
private _handshakePromise;
|
|
28
|
+
private _handshakeResolve;
|
|
29
|
+
private _handshakeReject;
|
|
30
|
+
private _handshakeRetryTimes;
|
|
31
|
+
private _handshakeStatus;
|
|
32
|
+
private _handshakeTimeout;
|
|
33
|
+
private _extraAttributes;
|
|
34
|
+
private _binaryFetchWorker;
|
|
35
|
+
private _binaryFetchWorkerUrl;
|
|
36
|
+
private _binaryFetchJobMap;
|
|
37
|
+
private _destroyed;
|
|
38
|
+
private readonly _enableBinaryFetch;
|
|
39
|
+
private readonly _allowAllOrigins;
|
|
40
|
+
private _onLoadStatusChange;
|
|
41
|
+
blockId: string;
|
|
42
|
+
private logInfo;
|
|
43
|
+
private logWarn;
|
|
44
|
+
private logError;
|
|
45
|
+
constructor(containerEl: HTMLElement, onLoadStatusChange: OnLoadStatusChange, instanceId: string | undefined, allowedOrigin: string[], extraAttributes: Record<string, string> | undefined, options?: HostOptions);
|
|
46
|
+
private createBlockContainer;
|
|
47
|
+
private isOriginAllowed;
|
|
48
|
+
private initHandshake;
|
|
49
|
+
private rejectHandshake;
|
|
50
|
+
private updateInvokeId;
|
|
51
|
+
setClientUrl(url: string): void;
|
|
52
|
+
get clientWin(): Window;
|
|
53
|
+
private listeningClientMessage;
|
|
54
|
+
private handleClientInvoke;
|
|
55
|
+
private handleClientCallback;
|
|
56
|
+
private handleClientEvent;
|
|
57
|
+
private sendCallbackHandshake;
|
|
58
|
+
private handleHandshakeMsg;
|
|
59
|
+
private retrySendHandshakeCallback;
|
|
60
|
+
private sendMsg2Client;
|
|
61
|
+
private sendClientInvokeResponse;
|
|
62
|
+
private getBinaryFetchWorker;
|
|
63
|
+
private startBinaryFetchJob;
|
|
64
|
+
private cancelBinaryFetchJob;
|
|
65
|
+
private handleBinaryFetchWorkerMessage;
|
|
66
|
+
registerApi<T, P>(key: string, handler: ApiHandler<T, P>): void;
|
|
67
|
+
invokeApi<T, P>(key: string, params: T, options?: InvokeApiOptions): Promise<P>;
|
|
68
|
+
emitEvent<T>(key: string, params: T): Promise<void>;
|
|
69
|
+
subscribeEvent<T>(key: string, handler: EventHandler<T>): () => void;
|
|
70
|
+
unsubscribeEvent<T>(key: string, handler?: EventHandler<T>): void;
|
|
71
|
+
destroy(): void;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
declare class ChannelCallbackError extends Error {
|
|
75
|
+
readonly code: number | string;
|
|
76
|
+
constructor(code: number | string, message: string);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export { ChannelCallbackError, Host, HostOptions, LoadStatus, LoadStatusErrorInfo, OnLoadStatusChange };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
var X=Object.defineProperty,Q=Object.defineProperties;var Z=Object.getOwnPropertyDescriptors;var P=Object.getOwnPropertySymbols;var ee=Object.prototype.hasOwnProperty,te=Object.prototype.propertyIsEnumerable;var H=(n,e,t)=>e in n?X(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t,c=(n,e)=>{for(var t in e||(e={}))ee.call(e,t)&&H(n,t,e[t]);if(P)for(var t of P(e))te.call(e,t)&&H(n,t,e[t]);return n},T=(n,e)=>Q(n,Z(e));var b=(n,e,t)=>new Promise((r,o)=>{var i=a=>{try{d(t.next(a))}catch(R){o(R)}},s=a=>{try{d(t.throw(a))}catch(R){o(R)}},d=a=>a.done?r(a.value):Promise.resolve(a.value).then(i,s);d((t=t.apply(n,e)).next())});import{uniqueId as A}from"lodash-es";var y="same-origin",L="__internal_fetchBinaryList__",M="__internal_cancelBinaryFetch__",w="__internal_binaryFetchProgress__";function O(n){if(n.type==="item-complete")return[n.buffer]}function S(n){return Number.isFinite(n)?Math.max(1,Math.floor(n)):4}function W(n){return n==="omit"||n==="include"?n:y}var m=(o=>(o.IFRAME_LOAD_ERROR="iframeLoadError",o.NOT_ALLOWED_URL="notAllowedUrl",o.HANDSHAKE_TIME_OUT="handshakeTimeout",o.CHANNEL_UNAVAILABLE="channelUnavailable",o))(m||{});var k=(l=>(l[l.UNKNOWN=-1]="UNKNOWN",l[l.IFRAME_LOAD_ERROR=10001]="IFRAME_LOAD_ERROR",l[l.NOT_ALLOWED_URL=10002]="NOT_ALLOWED_URL",l[l.HANDSHAKE_TIME_OUT=10003]="HANDSHAKE_TIME_OUT",l[l.API_NOT_FOUND=10004]="API_NOT_FOUND",l[l.REQUEST_TIMEOUT=10005]="REQUEST_TIMEOUT",l[l.CHANNEL_DESTROYED=10006]="CHANNEL_DESTROYED",l[l.BINARY_FETCH_DISABLED=10007]="BINARY_FETCH_DISABLED",l[l.DUPLICATED_REQUEST=10008]="DUPLICATED_REQUEST",l[l.CHANNEL_UNAVAILABLE=10009]="CHANNEL_UNAVAILABLE",l))(k||{});var u=class extends Error{constructor(t,r){super(r);this.code=t,this.name="ChannelCallbackError"}};function U(n){return new u(10004,`api "${n}" is not registered`)}function J(n){return new u(10005,`api "${n}" timed out`)}function E(){return new u(10006,"channel has been destroyed")}function K(n){return new u(10008,`request "${n}" was superseded by a new one`)}function Y(){return new u(10007,"built-in binary fetch is disabled")}var ne="unknown error";function z(n){return typeof n=="object"&&n!==null}function re(n){if(typeof n=="string"&&n)return n;if(n instanceof u&&n.message||n instanceof Error&&n.message)return n.message;if(z(n)){let{msg:e,message:t}=n;if(typeof e=="string"&&e)return e;if(typeof t=="string"&&t)return t}return ne}function oe(n){if(n instanceof u)return n.code;if(!z(n))return-1;let{code:e}=n;return typeof e=="string"&&e||typeof e=="number"&&Number.isFinite(e)?e:-1}function h(n){return{code:oe(n),msg:re(n)}}function D(n){return n instanceof ArrayBuffer||ArrayBuffer.isView(n)||typeof Blob!="undefined"&&n instanceof Blob}function se(n){return D(n)||Object.values(n).some(e=>D(e))}function v(n){return n&&typeof n=="object"?se(n)?n:JSON.parse(JSON.stringify(n)):n}var ie={["iframeLoadError"]:10001,["notAllowedUrl"]:10002,["handshakeTimeout"]:10003,["channelUnavailable"]:10009};function ae(n){return typeof n=="object"&&n!==null}function le(n){if(!ae(n))return!1;let{type:e}=n;return typeof e=="string"&&Object.values(m).includes(e)}function x(n){return le(n)?{code:ie[n.type],msg:n.message||n.type}:h(n)}function q(n){let e=Promise.reject(n);return e.catch(()=>{}),e}var C=class{constructor(e,t){this._target=e,this._options=t}sendMsg(e,t){if(!this._target)throw new Error("target window is not found");this._target.postMessage(e,this._options.targetOrigin,t!=null?t:[])}listenMsg(e){this._eventHandler=t=>{t.source===this._options.sourceWindow&&this._options.allowedOrigins.includes(t.origin)&&e(t)},typeof window!="undefined"&&window.addEventListener("message",this._eventHandler)}destroy(){typeof window!="undefined"&&this._eventHandler&&window.removeEventListener("message",this._eventHandler),this._eventHandler=void 0}};var f=class{constructor(e,t,r){e==="host"?this.channelManager=new C(t,r):e==="client"&&(this.channelManager=new C(window.parent,r))}static createInstance(e,t,r){return new f(e,t,r)}sendMsg(e,t){var r;(r=this.channelManager)==null||r.sendMsg(e,t)}listenMsg(e){var t;(t=this.channelManager)==null||t.listenMsg(e)}destroy(){var e;(e=this.channelManager)==null||e.destroy()}};var _=class{constructor(){this.requests=new Map}create(e,t,r=3e4){return this.reject(e,h(K(e))),new Promise((o,i)=>{let s=setTimeout(()=>{var d;((d=this.requests.get(e))==null?void 0:d.timeout)===s&&(this.requests.delete(e),i(h(J(t))))},r);this.requests.set(e,{reject:i,resolve:o,timeout:s})})}resolve(e,t){let r=this.take(e);return r?(r.resolve(t),!0):!1}reject(e,t){let r=this.take(e);return r?(r.reject(t),!0):!1}rejectAll(e){for(let t of this.requests.keys())this.reject(t,e)}take(e){let t=this.requests.get(e);if(t)return this.requests.delete(e),clearTimeout(t.timeout),t}};var F=n=>typeof n=="object"&&n!==null,de=new Set(["blockId","expectedPrefixId","id","jobId","prefixId","url"]),p=n=>{let e={};for(let[t,r]of Object.entries(n))if(!(t==="inputParams"||t==="outputParams")){if(de.has(t)){e[`${t}Present`]=!!r;continue}if(t==="error"){Object.assign(e,g(r));continue}if(t==="errorInfo"&&F(r)){e.errorType=typeof r.type=="string"?r.type:"object";continue}(typeof r=="string"||typeof r=="number"||typeof r=="boolean")&&(e[t]=r)}return e},I=n=>{let e={idPresent:!!n.id,type:n.type},t=F(n.payload)?n.payload:{};return typeof t.key=="string"&&(e.key=t.key),n.type==="callback"&&typeof t.code=="number"&&(e.callbackCode=t.code),n.type==="handshake"&&typeof t.proactive=="boolean"&&(e.proactive=t.proactive),e},B=n=>n.type!=="invoke"&&n.type!=="callback",g=n=>{if(!F(n))return{errorType:typeof n};let e={errorType:n instanceof Error?n.name:"object"};return(typeof n.code=="number"||typeof n.code=="string")&&(e.errorCode=n.code),e};var ue=()=>{let n=Reflect.get(globalThis,"BearWebSlardarWeb");return typeof n=="function"?n:void 0},ge=n=>{let e={};for(let[t,r]of Object.entries(p(n)))typeof r=="string"||typeof r=="number"?e[t]=r:typeof r=="boolean"&&(e[t]=String(r));return e},V=(n,e,t,r)=>{console[e](`[base-site-channel][${n}]`,t,r)},j=(n,e,t,r={})=>{let o=p(r),i=ue();if(!i){V(n,e,t,o);return}try{i("sendLog",{content:`[base-site-channel][${n}] ${t}`,extra:c({event_name:"Runtime_SiteChannel_Message",bizType:"Runtime",subType:"SiteChannel",action:"Message",channel_side:n,channel_message:t},ge(o)),level:e})}catch(s){V(n,e,t,T(c({},o),{slardarFallback:!0,slardarErrorType:s instanceof Error?s.name:typeof s}))}};var G=`
|
|
2
|
+
(function () {
|
|
3
|
+
var DEFAULT_JOB_CONCURRENCY = ${4};
|
|
4
|
+
var DEFAULT_CREDENTIALS = '${y}';
|
|
5
|
+
var GLOBAL_MAX_CONCURRENCY = ${6};
|
|
6
|
+
var globalActiveCount = 0;
|
|
7
|
+
var scheduleCursor = 0;
|
|
8
|
+
var isScheduling = false;
|
|
9
|
+
|
|
10
|
+
function logInfo(message, extra) {
|
|
11
|
+
console.info('[base-site-channel][worker]', message, extra || {});
|
|
12
|
+
}
|
|
13
|
+
function logWarn(message, extra) {
|
|
14
|
+
console.warn('[base-site-channel][worker]', message, extra || {});
|
|
15
|
+
}
|
|
16
|
+
function logError(message, extra) {
|
|
17
|
+
console.error('[base-site-channel][worker]', message, extra || {});
|
|
18
|
+
}
|
|
19
|
+
function normalizeConcurrency(concurrency) {
|
|
20
|
+
if (!Number.isFinite(concurrency)) return DEFAULT_JOB_CONCURRENCY;
|
|
21
|
+
return Math.max(1, Math.floor(concurrency));
|
|
22
|
+
}
|
|
23
|
+
function normalizeCredentials(credentials) {
|
|
24
|
+
if (credentials === 'omit' || credentials === 'include') return credentials;
|
|
25
|
+
return DEFAULT_CREDENTIALS;
|
|
26
|
+
}
|
|
27
|
+
function normalizeWorkerError(error) {
|
|
28
|
+
if (error instanceof Error) return error.message;
|
|
29
|
+
if (typeof error === 'string') return error;
|
|
30
|
+
try {
|
|
31
|
+
return JSON.stringify(error);
|
|
32
|
+
} catch (e) {
|
|
33
|
+
return 'unknown binary fetch error';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function isAbortError(error) {
|
|
37
|
+
return error && typeof error === 'object' && error.name === 'AbortError';
|
|
38
|
+
}
|
|
39
|
+
function postProgress(progress, transfer) {
|
|
40
|
+
self.postMessage(progress, transfer || []);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
var jobMap = new Map();
|
|
44
|
+
|
|
45
|
+
function canScheduleJob(job) {
|
|
46
|
+
return (
|
|
47
|
+
!job.aborted &&
|
|
48
|
+
!job.finished &&
|
|
49
|
+
job.cursor < job.items.length &&
|
|
50
|
+
job.activeCount < job.concurrency
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getNextRunnableJob() {
|
|
55
|
+
var jobs = Array.from(jobMap.values());
|
|
56
|
+
if (jobs.length === 0) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
for (var offset = 0; offset < jobs.length; offset += 1) {
|
|
60
|
+
var index = (scheduleCursor + offset) % jobs.length;
|
|
61
|
+
var job = jobs[index];
|
|
62
|
+
if (canScheduleJob(job)) {
|
|
63
|
+
scheduleCursor = (index + 1) % jobs.length;
|
|
64
|
+
return job;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function finishCancelledJob(job) {
|
|
71
|
+
if (job.finished || !job.aborted || job.activeCount > 0) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
job.finished = true;
|
|
75
|
+
jobMap.delete(job.jobId);
|
|
76
|
+
logWarn('job cancelled', {
|
|
77
|
+
jobId: job.jobId,
|
|
78
|
+
status: 'job-cancelled',
|
|
79
|
+
globalActiveCount: globalActiveCount,
|
|
80
|
+
});
|
|
81
|
+
postProgress({
|
|
82
|
+
type: 'job-cancelled',
|
|
83
|
+
jobId: job.jobId,
|
|
84
|
+
});
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function finishCompletedJob(job) {
|
|
89
|
+
if (job.finished || job.aborted || job.activeCount > 0 || job.cursor < job.items.length) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
job.finished = true;
|
|
93
|
+
jobMap.delete(job.jobId);
|
|
94
|
+
logInfo('job complete', {
|
|
95
|
+
jobId: job.jobId,
|
|
96
|
+
status: 'job-complete',
|
|
97
|
+
successCount: job.successCount,
|
|
98
|
+
failCount: job.failCount,
|
|
99
|
+
globalActiveCount: globalActiveCount,
|
|
100
|
+
});
|
|
101
|
+
postProgress({
|
|
102
|
+
type: 'job-complete',
|
|
103
|
+
jobId: job.jobId,
|
|
104
|
+
successCount: job.successCount,
|
|
105
|
+
failCount: job.failCount,
|
|
106
|
+
});
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function finishJobIfSettled(job) {
|
|
111
|
+
if (finishCancelledJob(job)) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
return finishCompletedJob(job);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function fetchItem(job, item) {
|
|
118
|
+
var controller = new AbortController();
|
|
119
|
+
job.controllers.add(controller);
|
|
120
|
+
try {
|
|
121
|
+
var response = await fetch(item.url, {
|
|
122
|
+
signal: controller.signal,
|
|
123
|
+
credentials: job.credentials,
|
|
124
|
+
});
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
throw new Error('request failed with status ' + response.status);
|
|
127
|
+
}
|
|
128
|
+
var buffer = await response.arrayBuffer();
|
|
129
|
+
if (job.aborted || job.finished) {
|
|
130
|
+
return { success: false, aborted: true };
|
|
131
|
+
}
|
|
132
|
+
logInfo('item complete', {
|
|
133
|
+
jobId: job.jobId,
|
|
134
|
+
itemId: item.itemId,
|
|
135
|
+
status: 'item-complete',
|
|
136
|
+
credentials: job.credentials,
|
|
137
|
+
totalBytes: buffer.byteLength,
|
|
138
|
+
});
|
|
139
|
+
postProgress(
|
|
140
|
+
{
|
|
141
|
+
type: 'item-complete',
|
|
142
|
+
jobId: job.jobId,
|
|
143
|
+
itemId: item.itemId,
|
|
144
|
+
totalBytes: buffer.byteLength,
|
|
145
|
+
buffer: buffer,
|
|
146
|
+
},
|
|
147
|
+
[buffer]
|
|
148
|
+
);
|
|
149
|
+
return { status: 'success' };
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (job.aborted || isAbortError(error)) {
|
|
152
|
+
logWarn('item aborted', {
|
|
153
|
+
jobId: job.jobId,
|
|
154
|
+
itemId: item.itemId,
|
|
155
|
+
status: 'item-aborted',
|
|
156
|
+
});
|
|
157
|
+
return { status: 'aborted' };
|
|
158
|
+
}
|
|
159
|
+
var message = normalizeWorkerError(error);
|
|
160
|
+
logError('item error', {
|
|
161
|
+
jobId: job.jobId,
|
|
162
|
+
itemId: item.itemId,
|
|
163
|
+
status: 'item-error',
|
|
164
|
+
credentials: job.credentials,
|
|
165
|
+
error: message,
|
|
166
|
+
});
|
|
167
|
+
postProgress({
|
|
168
|
+
type: 'item-error',
|
|
169
|
+
jobId: job.jobId,
|
|
170
|
+
itemId: item.itemId,
|
|
171
|
+
error: message,
|
|
172
|
+
});
|
|
173
|
+
return { status: 'error' };
|
|
174
|
+
} finally {
|
|
175
|
+
job.controllers.delete(controller);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function dispatchNextItem(job) {
|
|
180
|
+
var item = job.items[job.cursor];
|
|
181
|
+
if (!item) {
|
|
182
|
+
finishJobIfSettled(job);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
job.cursor += 1;
|
|
186
|
+
job.activeCount += 1;
|
|
187
|
+
globalActiveCount += 1;
|
|
188
|
+
logInfo('dispatch item', {
|
|
189
|
+
jobId: job.jobId,
|
|
190
|
+
itemId: item.itemId,
|
|
191
|
+
status: 'item-dispatched',
|
|
192
|
+
jobActiveCount: job.activeCount,
|
|
193
|
+
globalActiveCount: globalActiveCount,
|
|
194
|
+
jobConcurrency: job.concurrency,
|
|
195
|
+
credentials: job.credentials,
|
|
196
|
+
globalMaxConcurrency: GLOBAL_MAX_CONCURRENCY,
|
|
197
|
+
});
|
|
198
|
+
Promise.resolve(fetchItem(job, item))
|
|
199
|
+
.then(function (result) {
|
|
200
|
+
if (result.status === 'success') {
|
|
201
|
+
job.successCount += 1;
|
|
202
|
+
} else if (result.status === 'error') {
|
|
203
|
+
job.failCount += 1;
|
|
204
|
+
}
|
|
205
|
+
})
|
|
206
|
+
.finally(function () {
|
|
207
|
+
job.activeCount = Math.max(0, job.activeCount - 1);
|
|
208
|
+
globalActiveCount = Math.max(0, globalActiveCount - 1);
|
|
209
|
+
finishJobIfSettled(job);
|
|
210
|
+
schedule();
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function schedule() {
|
|
215
|
+
if (isScheduling) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
isScheduling = true;
|
|
219
|
+
try {
|
|
220
|
+
while (globalActiveCount < GLOBAL_MAX_CONCURRENCY) {
|
|
221
|
+
var job = getNextRunnableJob();
|
|
222
|
+
if (!job) {
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
dispatchNextItem(job);
|
|
226
|
+
}
|
|
227
|
+
} finally {
|
|
228
|
+
isScheduling = false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function startJob(message) {
|
|
233
|
+
var job = {
|
|
234
|
+
jobId: message.jobId,
|
|
235
|
+
items: message.items || [],
|
|
236
|
+
concurrency: normalizeConcurrency(message.concurrency),
|
|
237
|
+
credentials: normalizeCredentials(message.credentials),
|
|
238
|
+
aborted: false,
|
|
239
|
+
finished: false,
|
|
240
|
+
cursor: 0,
|
|
241
|
+
activeCount: 0,
|
|
242
|
+
successCount: 0,
|
|
243
|
+
failCount: 0,
|
|
244
|
+
controllers: new Set(),
|
|
245
|
+
};
|
|
246
|
+
jobMap.set(job.jobId, job);
|
|
247
|
+
logInfo('job start', {
|
|
248
|
+
jobId: job.jobId,
|
|
249
|
+
status: 'job-start',
|
|
250
|
+
total: job.items.length,
|
|
251
|
+
concurrency: job.concurrency,
|
|
252
|
+
credentials: job.credentials,
|
|
253
|
+
globalMaxConcurrency: GLOBAL_MAX_CONCURRENCY,
|
|
254
|
+
});
|
|
255
|
+
postProgress({
|
|
256
|
+
type: 'job-start',
|
|
257
|
+
jobId: job.jobId,
|
|
258
|
+
total: job.items.length,
|
|
259
|
+
});
|
|
260
|
+
finishJobIfSettled(job);
|
|
261
|
+
schedule();
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function cancelJob(message) {
|
|
265
|
+
var job = jobMap.get(message.jobId);
|
|
266
|
+
if (!job || job.finished || job.aborted) return;
|
|
267
|
+
job.aborted = true;
|
|
268
|
+
logWarn('cancel job', {
|
|
269
|
+
jobId: job.jobId,
|
|
270
|
+
status: 'cancel-requested',
|
|
271
|
+
activeCount: job.activeCount,
|
|
272
|
+
globalActiveCount: globalActiveCount,
|
|
273
|
+
});
|
|
274
|
+
job.controllers.forEach(function (controller) {
|
|
275
|
+
controller.abort();
|
|
276
|
+
});
|
|
277
|
+
finishJobIfSettled(job);
|
|
278
|
+
schedule();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
self.addEventListener('message', function (event) {
|
|
282
|
+
var data = event.data;
|
|
283
|
+
if (!data || !data.type) return;
|
|
284
|
+
if (data.type === 'start-job') return startJob(data);
|
|
285
|
+
if (data.type === 'cancel-job') return cancelJob(data);
|
|
286
|
+
});
|
|
287
|
+
})();
|
|
288
|
+
`;var $=(o=>(o.PENDING="pending",o.LOADING="loading",o.LOADED="loaded",o.ERROR="error",o))($||{}),Ee=n=>{let e=new Set;return n.forEach(t=>{try{e.add(new URL(t).origin)}catch(r){}}),e},N=class{constructor(e,t=()=>{},r,o=[],i,s={}){this._allowedOrigins=new Set;this.eventMap=new Map;this.eventHandlerMap=new Map;this.pendingRequests=new _;this._invokeId="";this._handshakePromise=q({type:"channelUnavailable",message:"client url is not set yet"});this._handshakeResolve=null;this._handshakeReject=null;this._handshakeRetryTimes=0;this._handshakeStatus=0;this._handshakeTimeout=null;this._binaryFetchWorker=null;this._binaryFetchWorkerUrl=null;this._binaryFetchJobMap=new Map;this._destroyed=!1;this._onLoadStatusChange=t,this._extraAttributes=i,this.createBlockContainer(e),this.blockId=r!=null?r:"",this._allowAllOrigins=o.length===0,this._allowedOrigins=Ee(o),!this._allowAllOrigins&&this._allowedOrigins.size!==o.length&&this.logWarn("invalid allowedOrigin entry ignored"),this._enableBinaryFetch=s.enableBinaryFetch===!0}logInfo(e,t={}){j("host","info",e,c({hasBlockId:!!this.blockId,handshakeStatus:this._handshakeStatus},p(t)))}logWarn(e,t={}){j("host","warn",e,c({hasBlockId:!!this.blockId,handshakeStatus:this._handshakeStatus},p(t)))}logError(e,t={}){j("host","error",e,c({hasBlockId:!!this.blockId,handshakeStatus:this._handshakeStatus},p(t)))}createBlockContainer(e){this.client=document==null?void 0:document.createElement("iframe"),this.client&&(this.client.className="base-site-iframe",this.client.style.setProperty("width","100%"),this._extraAttributes&&Object.entries(this._extraAttributes).forEach(([t,r])=>{this.client.setAttribute(t,r)}),this.client.style.setProperty("height","100%"),this.client.addEventListener("error",t=>{var r;this.rejectHandshake({type:"iframeLoadError",message:(r=t.message)!=null?r:JSON.stringify(t)})}),e.appendChild(this.client))}isOriginAllowed(e){return this._allowAllOrigins?!0:this._allowedOrigins.has(e)}initHandshake(){this._handshakeRetryTimes=0,this._handshakeStatus=0,this.logInfo("init handshake");let e=new Promise((t,r)=>{this._handshakeResolve=t,this._handshakeReject=r});e.then(()=>{this._handshakeStatus=1,this.logInfo("handshake success"),this._onLoadStatusChange("loaded")}).catch(t=>{this._handshakeStatus=2,this._onLoadStatusChange("error",t),this.logError("handshake failed",{errorInfo:t})}),this._handshakePromise=e}rejectHandshake(e){var t;this._handshakeStatus===0&&(this.logWarn("reject handshake",{errorInfo:e}),(t=this._handshakeReject)==null||t.call(this,e))}updateInvokeId(){this._invokeId=A(`${this.blockId}-invoke-`)}setClientUrl(e){if(!this.client||!e)return;clearTimeout(this._handshakeTimeout),this.initHandshake(),this._onLoadStatusChange("loading"),this._msgChannel&&(this.logInfo("destroy previous message channel"),this._msgChannel.destroy(),this.pendingRequests.rejectAll(h(E())));let t=new URL(e).origin;this.logInfo("set client url",{origin:t}),this.isOriginAllowed(t)?(this._msgChannel=f.createInstance("host",this.clientWin,{allowedOrigins:[t],sourceWindow:this.clientWin,targetOrigin:t}),this.client.src=e,this.listeningClientMessage()):(this.client.src=e,this.logWarn("client url origin not allowed",{origin:t}),this.rejectHandshake({type:"notAllowedUrl"}))}get clientWin(){var e;return(e=this.client)==null?void 0:e.contentWindow}listeningClientMessage(){this.clientMessageHandler=e=>{let{data:t}=e;B(t)&&this.logInfo("receive client message",I(t)),t.type==="invoke"?this.handleClientInvoke(t).catch(r=>{this.logError("handle client invoke error",c(c({},I(t)),g(r)))}):t.type==="callback"?this.handleClientCallback(t):t.type==="handshake"?this.handleHandshakeMsg(t):t.type==="event"&&this.handleClientEvent(t).catch(r=>{this.logError("handle client event error",c(c({},I(t)),g(r)))})},this._msgChannel.listenMsg(this.clientMessageHandler)}handleClientInvoke(e){return b(this,null,function*(){yield this._handshakePromise;let{id:t,payload:r}=e,{key:o,params:i,prefixId:s}=r;if(s!==this.blockId){this.logWarn("ignore client invoke because prefixId mismatch",{id:t,key:o,prefixId:s,expectedPrefixId:this.blockId});return}if(this.logInfo("api request received",{logId:t,key:o}),!this._enableBinaryFetch&&(o===L||o===M)){this.logWarn("built-in binary fetch invoke rejected because capability is disabled",{id:t,key:o}),this.sendClientInvokeResponse(t,o,h(Y()),1);return}if(o===L){this.logInfo("handle built-in binary fetch invoke",{id:t,key:o,status:"start"});try{let a=v(yield this.startBinaryFetchJob(i,s));this.sendClientInvokeResponse(t,o,a,0)}catch(a){this.logError("built-in binary fetch invoke failed",c({id:t,key:o},g(a))),this.sendClientInvokeResponse(t,o,h(a),1)}return}if(o===M){this.logInfo("handle built-in binary fetch cancel invoke",{id:t,key:o,status:"cancel-requested"});try{let a=v(yield this.cancelBinaryFetchJob(i,s));this.sendClientInvokeResponse(t,o,a,0)}catch(a){this.logError("built-in binary fetch cancel invoke failed",c({id:t,key:o},g(a))),this.sendClientInvokeResponse(t,o,h(a),1)}return}let d=this.eventMap.get(o);if(typeof d=="function")try{let a=v(yield d(i));this.sendClientInvokeResponse(t,o,a,0)}catch(a){this.logError("client invoke failed",c({id:t,key:o},g(a))),this.sendClientInvokeResponse(t,o,h(a),1)}else this.logWarn("client invoke handler not found",{id:t,key:o}),this.sendClientInvokeResponse(t,o,h(U(o)),1)})}handleClientCallback(e){let{id:t,payload:r}=e;if(r.code===1){if(this.pendingRequests.reject(t,r.res)){this.logWarn("client callback returned error",{id:t,key:r.key});return}}else if(this.pendingRequests.resolve(t,r.res)){this.logInfo("client callback success",{id:t,key:r.key});return}this.logWarn("client callback request not found",{id:t,key:r.key})}handleClientEvent(e){return b(this,null,function*(){yield this._handshakePromise;let{payload:t}=e,{key:r,params:o,prefixId:i}=t;if(i!==this.blockId){this.logWarn("ignore client event because prefixId mismatch",{key:r,prefixId:i,expectedPrefixId:this.blockId});return}let s=this.eventHandlerMap.get(r);if(!(s!=null&&s.size)){this.logWarn("client event handler not found",{key:r});return}this.logInfo("handle client event",{key:r,handlerCount:s.size}),yield Promise.allSettled(Array.from(s,d=>d(o)))})}sendCallbackHandshake(e){this.sendMsg2Client({id:e,type:"handshake",payload:{proactive:!1,prefixId:this.blockId}})}handleHandshakeMsg(e){return b(this,null,function*(){var t;e.payload.proactive?(clearTimeout(this._handshakeTimeout),this._handshakeRetryTimes=0,this.logInfo("receive proactive handshake",{id:e.id}),this.sendCallbackHandshake(e.id),this.retrySendHandshakeCallback(e.id)):(this.logInfo("receive handshake callback",{id:e.id}),(t=this._handshakeResolve)==null||t.call(this))})}retrySendHandshakeCallback(e){this._handshakeTimeout=setTimeout(()=>{if(this._handshakeStatus===0){if(this._handshakeRetryTimes>5){this.logError("handshake callback retry timeout",{handshakeId:e,retryTimes:this._handshakeRetryTimes}),this.rejectHandshake({type:"handshakeTimeout"});return}this.logWarn("retry handshake callback",{handshakeId:e,retryTimes:this._handshakeRetryTimes+1}),this.sendCallbackHandshake(e),this._handshakeRetryTimes++,this.retrySendHandshakeCallback(e)}},2e3*2**this._handshakeRetryTimes)}sendMsg2Client(e,t){B(e)&&this.logInfo("send message to client",I(e)),this._msgChannel.sendMsg(e,t)}sendClientInvokeResponse(e,t,r,o){let i={logId:e,key:t,callbackCode:o};o===1?this.logWarn("api response sent",i):this.logInfo("api response sent",i),this.sendMsg2Client({id:e,type:"callback",payload:{res:r,key:t,code:o}})}getBinaryFetchWorker(){if(this._binaryFetchWorker)return this._binaryFetchWorker;if(typeof Worker=="undefined")throw new Error("Worker is not supported in current environment");let e=new Blob([G],{type:"text/javascript"}),t=URL.createObjectURL(e),r=new Worker(t);return this._binaryFetchWorkerUrl=t,r.addEventListener("message",o=>{this.handleBinaryFetchWorkerMessage(o.data)}),r.addEventListener("error",o=>{this.logError("binary fetch worker runtime error",{status:"worker-error",error:o.message})}),this._binaryFetchWorker=r,this.logInfo("binary fetch worker created",{status:"worker-created"}),r}startBinaryFetchJob(e,t){return b(this,null,function*(){var s;let r=Array.isArray(e==null?void 0:e.items)?e.items:[],o=A(`${this.blockId}-binary-fetch-`);this._binaryFetchJobMap.set(o,{jobId:o,prefixId:t});let i={type:"start-job",jobId:o,items:r,concurrency:S(e==null?void 0:e.concurrency),credentials:W((s=e==null?void 0:e.credentials)!=null?s:y)};return this.getBinaryFetchWorker().postMessage(i),this.logInfo("binary fetch job dispatched to worker",{jobId:o,status:"job-dispatched",itemCount:r.length,concurrency:i.concurrency,credentials:i.credentials}),{jobId:o}})}cancelBinaryFetchJob(e,t){return b(this,null,function*(){let r=this._binaryFetchJobMap.get(e.jobId);if(!r){this.logWarn("binary fetch job not found when cancel",{jobId:e.jobId,status:"job-missing"});return}if(r.prefixId!==t){this.logWarn("ignore binary fetch cancel because prefixId mismatch",{jobId:e.jobId,prefixId:t,expectedPrefixId:r.prefixId});return}this.getBinaryFetchWorker().postMessage({type:"cancel-job",jobId:e.jobId}),this.logInfo("binary fetch cancel sent to worker",{jobId:e.jobId,status:"cancel-sent"})})}handleBinaryFetchWorkerMessage(e){let t=this._binaryFetchJobMap.get(e.jobId);if(!t){this.logWarn("ignore worker progress because job not found",{jobId:e.jobId,status:e.type});return}this.logInfo("receive binary fetch worker progress",{jobId:e.jobId,itemId:"itemId"in e?e.itemId:void 0,status:e.type});let r=O(e);this.sendMsg2Client({type:"event",id:A(`${this.blockId}-binary-fetch-event-`),payload:{key:w,params:e,prefixId:t.prefixId}},r),(e.type==="job-complete"||e.type==="job-cancelled")&&this._binaryFetchJobMap.delete(e.jobId)}registerApi(e,t){if(this.eventMap.has(e)){this.logWarn("register api ignored because key already exists",{key:e});return}this.eventMap.set(e,t),this.logInfo("register api",{key:e})}invokeApi(e,t,r){return b(this,null,function*(){if(this._destroyed)return Promise.reject(h(E()));try{yield this._handshakePromise}catch(s){return this.logError("invoke api blocked by handshake error",c({key:e},g(s))),Promise.reject(x(s))}this._invokeId||this.updateInvokeId();let o=this._invokeId,i=this.pendingRequests.create(o,e,r==null?void 0:r.timeoutMs);return this.logInfo("invoke api",{key:e,id:o}),this.sendMsg2Client({type:"invoke",id:o,payload:{key:e,params:t,prefixId:this.blockId}}),this.updateInvokeId(),i})}emitEvent(e,t){return b(this,null,function*(){try{yield this._handshakePromise}catch(r){return this.logError("emit event blocked by handshake error",c({key:e},g(r))),Promise.reject(x(r))}this.logInfo("emit event",{key:e}),this.sendMsg2Client({type:"event",id:A(`${this.blockId}-event-`),payload:{key:e,params:t,prefixId:this.blockId}})})}subscribeEvent(e,t){var o;let r=(o=this.eventHandlerMap.get(e))!=null?o:new Set;return r.add(t),this.eventHandlerMap.set(e,r),this.logInfo("subscribe event",{key:e,handlerCount:r.size}),()=>this.unsubscribeEvent(e,t)}unsubscribeEvent(e,t){let r=this.eventHandlerMap.get(e);if(!r){this.logWarn("unsubscribe event ignored because key is not subscribed",{key:e});return}if(!t){this.eventHandlerMap.delete(e),this.logInfo("unsubscribe all event handlers",{key:e,handlerCount:0});return}r.delete(t),r.size===0&&this.eventHandlerMap.delete(e),this.logInfo("unsubscribe event",{key:e,handlerCount:r.size})}destroy(){var e,t,r,o;this._destroyed||(this._destroyed=!0,this.logInfo("destroy host"),(e=this._msgChannel)==null||e.destroy(),clearTimeout(this._handshakeTimeout),(t=this._handshakeReject)==null||t.call(this,{type:"handshakeTimeout",message:E().message}),(r=this._binaryFetchWorker)==null||r.terminate(),this._binaryFetchWorker=null,this._binaryFetchWorkerUrl&&(URL.revokeObjectURL(this._binaryFetchWorkerUrl),this._binaryFetchWorkerUrl=null),this._binaryFetchJobMap.clear(),this.pendingRequests.rejectAll(h(E())),this.eventMap.clear(),this.eventHandlerMap.clear(),(o=this.client)==null||o.remove())}};export{u as ChannelCallbackError,k as ChannelErrorCode,m as ChannelErrorType,N as Host,$ as LoadStatus};
|