bunite-core 0.0.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/package.json +24 -0
- package/src/bun/core/App.ts +142 -0
- package/src/bun/core/BrowserView.ts +262 -0
- package/src/bun/core/BrowserWindow.ts +322 -0
- package/src/bun/core/Socket.ts +186 -0
- package/src/bun/core/Utils.ts +72 -0
- package/src/bun/core/windowIds.ts +7 -0
- package/src/bun/events/appEvents.ts +7 -0
- package/src/bun/events/event.ts +20 -0
- package/src/bun/events/eventEmitter.ts +28 -0
- package/src/bun/events/webviewEvents.ts +13 -0
- package/src/bun/events/windowEvents.ts +19 -0
- package/src/bun/index.ts +41 -0
- package/src/bun/preload/index.ts +73 -0
- package/src/bun/preload/inline.ts +87 -0
- package/src/bun/proc/native.ts +666 -0
- package/src/native/shared/callbacks.h +6 -0
- package/src/native/shared/cef_response_filter.h +116 -0
- package/src/native/shared/ffi_exports.h +119 -0
- package/src/native/shared/webview_storage.h +89 -0
- package/src/native/win/native_host.cpp +2453 -0
- package/src/native/win/process_helper_win.cpp +26 -0
- package/src/preload/runtime.built.js +1 -0
- package/src/preload/runtime.ts +215 -0
- package/src/preload/tsconfig.json +13 -0
- package/src/shared/paths.ts +133 -0
- package/src/shared/platform.ts +9 -0
- package/src/shared/rpc.ts +399 -0
- package/src/shared/rpcWire.ts +54 -0
- package/src/shared/rpcWireConstants.ts +3 -0
- package/src/types/config.ts +29 -0
- package/src/view/index.ts +159 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#include "include/cef_app.h"
|
|
2
|
+
|
|
3
|
+
#include <windows.h>
|
|
4
|
+
|
|
5
|
+
class BuniteHelperApp : public CefApp {
|
|
6
|
+
public:
|
|
7
|
+
void OnRegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar) override {
|
|
8
|
+
registrar->AddCustomScheme(
|
|
9
|
+
"views",
|
|
10
|
+
CEF_SCHEME_OPTION_STANDARD |
|
|
11
|
+
CEF_SCHEME_OPTION_CORS_ENABLED |
|
|
12
|
+
CEF_SCHEME_OPTION_SECURE |
|
|
13
|
+
CEF_SCHEME_OPTION_CSP_BYPASSING |
|
|
14
|
+
CEF_SCHEME_OPTION_FETCH_ENABLED
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private:
|
|
19
|
+
IMPLEMENT_REFCOUNTING(BuniteHelperApp);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int) {
|
|
23
|
+
CefMainArgs main_args(hInstance);
|
|
24
|
+
CefRefPtr<CefApp> app = new BuniteHelperApp();
|
|
25
|
+
return CefExecuteProcess(main_args, app, nullptr);
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var W=(()=>{let F;return()=>{if(!F){let q=Uint8Array.from(atob(__buniteSecretKeyBase64),(H)=>H.charCodeAt(0));F=crypto.subtle.importKey("raw",q,"AES-GCM",!1,["encrypt","decrypt"])}return F}})();async function X(F){let q=await W(),H=crypto.getRandomValues(new Uint8Array(12)),A=new Uint8Array(await crypto.subtle.encrypt({name:"AES-GCM",iv:H},q,F)),z=new Uint8Array(1+H.length+A.length);return z[0]=1,z.set(H,1),z.set(A,1+H.length),z}async function Y(F){if(F.length<29)throw Error("Invalid bunite RPC frame.");if(F[0]!==1)throw Error("Unsupported bunite RPC frame version.");let q=await W(),H=F.slice(1,13),A=F.slice(13);return new Uint8Array(await crypto.subtle.decrypt({name:"AES-GCM",iv:H},q,A))}function B(F){let q=[];function H(A){if(A===null||A===void 0)q.push(192);else if(A===!0)q.push(195);else if(A===!1)q.push(194);else if(typeof A==="number")if(Number.isInteger(A)&&A>=0&&A<128)q.push(A);else if(Number.isInteger(A)&&A>=-32&&A<0)q.push(A&255);else if(Number.isInteger(A)&&A>=0&&A<=65535)q.push(205,A>>8&255,A&255);else if(Number.isInteger(A)&&A>=0&&A<=4294967295)q.push(206,A>>24&255,A>>16&255,A>>8&255,A&255);else{let z=new ArrayBuffer(9),G=new DataView(z);G.setUint8(0,203),G.setFloat64(1,A);for(let J=0;J<9;J++)q.push(G.getUint8(J))}else if(typeof A==="string"){let z=new TextEncoder().encode(A);if(z.length<32)q.push(160|z.length);else if(z.length<256)q.push(217,z.length);else if(z.length<65536)q.push(218,z.length>>8&255,z.length&255);else q.push(219,z.length>>24&255,z.length>>16&255,z.length>>8&255,z.length&255);for(let G=0;G<z.length;G++)q.push(z[G])}else if(Array.isArray(A)){if(A.length<16)q.push(144|A.length);else if(A.length<65536)q.push(220,A.length>>8&255,A.length&255);else q.push(221,A.length>>24&255,A.length>>16&255,A.length>>8&255,A.length&255);A.forEach(H)}else if(typeof A==="object"){let z=Object.keys(A);if(z.length<16)q.push(128|z.length);else if(z.length<65536)q.push(222,z.length>>8&255,z.length&255);else q.push(223,z.length>>24&255,z.length>>16&255,z.length>>8&255,z.length&255);for(let G of z)H(G),H(A[G])}}return H(F),new Uint8Array(q)}function I(F){let q=0;function H(){let A=F[q++];if(A<=127)return A;if(A>=224)return A-256;if(A===192)return null;if(A===194)return!1;if(A===195)return!0;if(A===204)return F[q++];if(A===205){let z=F[q]<<8|F[q+1];return q+=2,z}if(A===206){let z=(F[q]<<24|F[q+1]<<16|F[q+2]<<8|F[q+3])>>>0;return q+=4,z}if(A===203){let z=new DataView(F.buffer,F.byteOffset+q,8);return q+=8,z.getFloat64(0)}if(A===208){let z=F[q++];return z>127?z-256:z}if(A===209){let z=F[q]<<8|F[q+1];return q+=2,z>32767?z-65536:z}if(A===210){let z=F[q]<<24|F[q+1]<<16|F[q+2]<<8|F[q+3];return q+=4,z}if((A&224)===160){let z=A&31,G=new TextDecoder().decode(F.subarray(q,q+z));return q+=z,G}if(A===217){let z=F[q++],G=new TextDecoder().decode(F.subarray(q,q+z));return q+=z,G}if(A===218){let z=F[q]<<8|F[q+1];q+=2;let G=new TextDecoder().decode(F.subarray(q,q+z));return q+=z,G}if(A===219){let z=(F[q]<<24|F[q+1]<<16|F[q+2]<<8|F[q+3])>>>0;q+=4;let G=new TextDecoder().decode(F.subarray(q,q+z));return q+=z,G}if((A&240)===144){let z=A&15,G=[];for(let J=0;J<z;J++)G.push(H());return G}if(A===220){let z=F[q]<<8|F[q+1];q+=2;let G=[];for(let J=0;J<z;J++)G.push(H());return G}if(A===221){let z=(F[q]<<24|F[q+1]<<16|F[q+2]<<8|F[q+3])>>>0;q+=4;let G=[];for(let J=0;J<z;J++)G.push(H());return G}if((A&240)===128){let z=A&15,G={};for(let J=0;J<z;J++)G[H()]=H();return G}if(A===222){let z=F[q]<<8|F[q+1];q+=2;let G={};for(let J=0;J<z;J++)G[H()]=H();return G}if(A===223){let z=(F[q]<<24|F[q+1]<<16|F[q+2]<<8|F[q+3])>>>0;q+=4;let G={};for(let J=0;J<z;J++)G[H()]=H();return G}if(A===196){let z=F[q++],G=F.slice(q,q+z);return q+=z,G}if(A===197){let z=F[q]<<8|F[q+1];q+=2;let G=F.slice(q,q+z);return q+=z,G}return}return H()}var N=window;N.__bunite??={};N.__buniteWebviewId=__buniteWebviewId;N.__buniteRpcSocketPort=__buniteRpcSocketPort;N.__bunite_encrypt=X;N.__bunite_decrypt=Y;N.bunite=N.__bunite;N.bunite.invoke=(()=>{let F=null,q=1,H=new Map;function A(){let G=N.__bunite?._socket;if(G&&G.readyState<=WebSocket.OPEN&&G!==F)return F=G,z(G),G;if(F&&F.readyState<=WebSocket.OPEN)return F;return F=new WebSocket(`ws://localhost:${__buniteRpcSocketPort}/socket?webviewId=${__buniteWebviewId}`),F.binaryType="arraybuffer",N.__bunite._socket=F,z(F),F}function z(G){G.addEventListener("message",async(J)=>{try{let Q=await Y(new Uint8Array(J.data)),M=I(Q);if(M?.type==="response"&&M.scope==="global"){let O=H.get(M.id);if(O)H.delete(M.id),clearTimeout(O.timeout),M.success?O.resolve(M.payload):O.reject(Error(M.error||"Unknown error"))}}catch{}})}return(G,J)=>new Promise((Q,M)=>{let O=A(),T=q++,Z=setTimeout(()=>{H.delete(T),M(Error(`bunite.invoke timed out: ${G}`))},15000);H.set(T,{resolve:Q,reject:M,timeout:Z});let _={type:"request",id:T,method:G,params:J??null,scope:"global"},U=async()=>{let $=await X(B(_));O.send($.buffer)};if(O.readyState===WebSocket.OPEN)U();else O.addEventListener("open",()=>U(),{once:!0})})})();
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
// Preload runtime — built once at package build time, injected into every views:// page.
|
|
2
|
+
// The config variables (__buniteWebviewId, __buniteRpcSocketPort, __buniteSecretKeyBase64)
|
|
3
|
+
// are injected by inline.ts as a small preamble before this script.
|
|
4
|
+
|
|
5
|
+
declare const __buniteWebviewId: number;
|
|
6
|
+
declare const __buniteRpcSocketPort: number;
|
|
7
|
+
declare const __buniteSecretKeyBase64: string;
|
|
8
|
+
|
|
9
|
+
const RPC_FRAME_VERSION = 1;
|
|
10
|
+
const RPC_IV_LENGTH = 12;
|
|
11
|
+
|
|
12
|
+
// --- Crypto key (lazy) ---
|
|
13
|
+
|
|
14
|
+
const getCryptoKey = (() => {
|
|
15
|
+
let keyPromise: Promise<CryptoKey>;
|
|
16
|
+
return () => {
|
|
17
|
+
if (!keyPromise) {
|
|
18
|
+
const raw = Uint8Array.from(atob(__buniteSecretKeyBase64), c => c.charCodeAt(0));
|
|
19
|
+
keyPromise = crypto.subtle.importKey("raw", raw, "AES-GCM", false, ["encrypt", "decrypt"]);
|
|
20
|
+
}
|
|
21
|
+
return keyPromise;
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
|
|
25
|
+
async function buniteEncrypt(data: Uint8Array): Promise<Uint8Array> {
|
|
26
|
+
const key = await getCryptoKey();
|
|
27
|
+
const iv = crypto.getRandomValues(new Uint8Array(RPC_IV_LENGTH));
|
|
28
|
+
const encrypted = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, data as unknown as ArrayBuffer));
|
|
29
|
+
const frame = new Uint8Array(1 + iv.length + encrypted.length);
|
|
30
|
+
frame[0] = RPC_FRAME_VERSION;
|
|
31
|
+
frame.set(iv, 1);
|
|
32
|
+
frame.set(encrypted, 1 + iv.length);
|
|
33
|
+
return frame;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function buniteDecrypt(frame: Uint8Array): Promise<Uint8Array> {
|
|
37
|
+
if (frame.length < 1 + RPC_IV_LENGTH + 16) {
|
|
38
|
+
throw new Error("Invalid bunite RPC frame.");
|
|
39
|
+
}
|
|
40
|
+
if (frame[0] !== RPC_FRAME_VERSION) {
|
|
41
|
+
throw new Error("Unsupported bunite RPC frame version.");
|
|
42
|
+
}
|
|
43
|
+
const key = await getCryptoKey();
|
|
44
|
+
const iv = frame.slice(1, 1 + RPC_IV_LENGTH);
|
|
45
|
+
const encrypted = frame.slice(1 + RPC_IV_LENGTH);
|
|
46
|
+
return new Uint8Array(await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, encrypted));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// --- Minimal msgpack encoder/decoder ---
|
|
50
|
+
|
|
51
|
+
function mpEncode(val: unknown): Uint8Array {
|
|
52
|
+
const parts: number[] = [];
|
|
53
|
+
|
|
54
|
+
function w(v: unknown): void {
|
|
55
|
+
if (v === null || v === undefined) {
|
|
56
|
+
parts.push(0xc0);
|
|
57
|
+
} else if (v === true) {
|
|
58
|
+
parts.push(0xc3);
|
|
59
|
+
} else if (v === false) {
|
|
60
|
+
parts.push(0xc2);
|
|
61
|
+
} else if (typeof v === "number") {
|
|
62
|
+
if (Number.isInteger(v) && v >= 0 && v < 128) {
|
|
63
|
+
parts.push(v);
|
|
64
|
+
} else if (Number.isInteger(v) && v >= -32 && v < 0) {
|
|
65
|
+
parts.push(v & 0xff);
|
|
66
|
+
} else if (Number.isInteger(v) && v >= 0 && v <= 0xffff) {
|
|
67
|
+
parts.push(0xcd, (v >> 8) & 0xff, v & 0xff);
|
|
68
|
+
} else if (Number.isInteger(v) && v >= 0 && v <= 0xffffffff) {
|
|
69
|
+
parts.push(0xce, (v >> 24) & 0xff, (v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff);
|
|
70
|
+
} else {
|
|
71
|
+
const b = new ArrayBuffer(9);
|
|
72
|
+
const dv = new DataView(b);
|
|
73
|
+
dv.setUint8(0, 0xcb);
|
|
74
|
+
dv.setFloat64(1, v);
|
|
75
|
+
for (let i = 0; i < 9; i++) parts.push(dv.getUint8(i));
|
|
76
|
+
}
|
|
77
|
+
} else if (typeof v === "string") {
|
|
78
|
+
const bytes = new TextEncoder().encode(v);
|
|
79
|
+
if (bytes.length < 32) parts.push(0xa0 | bytes.length);
|
|
80
|
+
else if (bytes.length < 256) parts.push(0xd9, bytes.length);
|
|
81
|
+
else if (bytes.length < 65536) parts.push(0xda, (bytes.length >> 8) & 0xff, bytes.length & 0xff);
|
|
82
|
+
else parts.push(0xdb, (bytes.length >> 24) & 0xff, (bytes.length >> 16) & 0xff, (bytes.length >> 8) & 0xff, bytes.length & 0xff);
|
|
83
|
+
for (let i = 0; i < bytes.length; i++) parts.push(bytes[i]);
|
|
84
|
+
} else if (Array.isArray(v)) {
|
|
85
|
+
if (v.length < 16) parts.push(0x90 | v.length);
|
|
86
|
+
else if (v.length < 65536) parts.push(0xdc, (v.length >> 8) & 0xff, v.length & 0xff);
|
|
87
|
+
else parts.push(0xdd, (v.length >> 24) & 0xff, (v.length >> 16) & 0xff, (v.length >> 8) & 0xff, v.length & 0xff);
|
|
88
|
+
v.forEach(w);
|
|
89
|
+
} else if (typeof v === "object") {
|
|
90
|
+
const keys = Object.keys(v as Record<string, unknown>);
|
|
91
|
+
if (keys.length < 16) parts.push(0x80 | keys.length);
|
|
92
|
+
else if (keys.length < 65536) parts.push(0xde, (keys.length >> 8) & 0xff, keys.length & 0xff);
|
|
93
|
+
else parts.push(0xdf, (keys.length >> 24) & 0xff, (keys.length >> 16) & 0xff, (keys.length >> 8) & 0xff, keys.length & 0xff);
|
|
94
|
+
for (const k of keys) { w(k); w((v as Record<string, unknown>)[k]); }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
w(val);
|
|
99
|
+
return new Uint8Array(parts);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function mpDecode(buf: Uint8Array): unknown {
|
|
103
|
+
let pos = 0;
|
|
104
|
+
|
|
105
|
+
function r(): unknown {
|
|
106
|
+
const b = buf[pos++];
|
|
107
|
+
if (b <= 0x7f) return b;
|
|
108
|
+
if (b >= 0xe0) return b - 256;
|
|
109
|
+
if (b === 0xc0) return null;
|
|
110
|
+
if (b === 0xc2) return false;
|
|
111
|
+
if (b === 0xc3) return true;
|
|
112
|
+
if (b === 0xcc) return buf[pos++];
|
|
113
|
+
if (b === 0xcd) { const v = (buf[pos] << 8) | buf[pos + 1]; pos += 2; return v; }
|
|
114
|
+
if (b === 0xce) { const v = ((buf[pos] << 24) | (buf[pos + 1] << 16) | (buf[pos + 2] << 8) | buf[pos + 3]) >>> 0; pos += 4; return v; }
|
|
115
|
+
if (b === 0xcb) { const dv = new DataView(buf.buffer, buf.byteOffset + pos, 8); pos += 8; return dv.getFloat64(0); }
|
|
116
|
+
if (b === 0xd0) { const v = buf[pos++]; return v > 127 ? v - 256 : v; }
|
|
117
|
+
if (b === 0xd1) { const v = (buf[pos] << 8) | buf[pos + 1]; pos += 2; return v > 32767 ? v - 65536 : v; }
|
|
118
|
+
if (b === 0xd2) { const v = (buf[pos] << 24) | (buf[pos + 1] << 16) | (buf[pos + 2] << 8) | buf[pos + 3]; pos += 4; return v; }
|
|
119
|
+
// fixstr
|
|
120
|
+
if ((b & 0xe0) === 0xa0) { const len = b & 0x1f; const s = new TextDecoder().decode(buf.subarray(pos, pos + len)); pos += len; return s; }
|
|
121
|
+
if (b === 0xd9) { const len = buf[pos++]; const s = new TextDecoder().decode(buf.subarray(pos, pos + len)); pos += len; return s; }
|
|
122
|
+
if (b === 0xda) { const len = (buf[pos] << 8) | buf[pos + 1]; pos += 2; const s = new TextDecoder().decode(buf.subarray(pos, pos + len)); pos += len; return s; }
|
|
123
|
+
if (b === 0xdb) { const len = ((buf[pos] << 24) | (buf[pos + 1] << 16) | (buf[pos + 2] << 8) | buf[pos + 3]) >>> 0; pos += 4; const s = new TextDecoder().decode(buf.subarray(pos, pos + len)); pos += len; return s; }
|
|
124
|
+
// fixarray
|
|
125
|
+
if ((b & 0xf0) === 0x90) { const len = b & 0x0f; const arr: unknown[] = []; for (let i = 0; i < len; i++) arr.push(r()); return arr; }
|
|
126
|
+
if (b === 0xdc) { const len = (buf[pos] << 8) | buf[pos + 1]; pos += 2; const arr: unknown[] = []; for (let i = 0; i < len; i++) arr.push(r()); return arr; }
|
|
127
|
+
if (b === 0xdd) { const len = ((buf[pos] << 24) | (buf[pos + 1] << 16) | (buf[pos + 2] << 8) | buf[pos + 3]) >>> 0; pos += 4; const arr: unknown[] = []; for (let i = 0; i < len; i++) arr.push(r()); return arr; }
|
|
128
|
+
// fixmap
|
|
129
|
+
if ((b & 0xf0) === 0x80) { const len = b & 0x0f; const obj: Record<string, unknown> = {}; for (let i = 0; i < len; i++) { obj[r() as string] = r(); } return obj; }
|
|
130
|
+
if (b === 0xde) { const len = (buf[pos] << 8) | buf[pos + 1]; pos += 2; const obj: Record<string, unknown> = {}; for (let i = 0; i < len; i++) { obj[r() as string] = r(); } return obj; }
|
|
131
|
+
if (b === 0xdf) { const len = ((buf[pos] << 24) | (buf[pos + 1] << 16) | (buf[pos + 2] << 8) | buf[pos + 3]) >>> 0; pos += 4; const obj: Record<string, unknown> = {}; for (let i = 0; i < len; i++) { obj[r() as string] = r(); } return obj; }
|
|
132
|
+
// bin8, bin16
|
|
133
|
+
if (b === 0xc4) { const len = buf[pos++]; const bin = buf.slice(pos, pos + len); pos += len; return bin; }
|
|
134
|
+
if (b === 0xc5) { const len = (buf[pos] << 8) | buf[pos + 1]; pos += 2; const bin = buf.slice(pos, pos + len); pos += len; return bin; }
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return r();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// --- Expose globals ---
|
|
142
|
+
|
|
143
|
+
const w = window as any;
|
|
144
|
+
w.__bunite ??= {};
|
|
145
|
+
w.__buniteWebviewId = __buniteWebviewId;
|
|
146
|
+
w.__buniteRpcSocketPort = __buniteRpcSocketPort;
|
|
147
|
+
w.__bunite_encrypt = buniteEncrypt;
|
|
148
|
+
w.__bunite_decrypt = buniteDecrypt;
|
|
149
|
+
|
|
150
|
+
// --- bunite.invoke: global IPC ---
|
|
151
|
+
|
|
152
|
+
w.bunite = w.__bunite;
|
|
153
|
+
w.bunite.invoke = (() => {
|
|
154
|
+
let socket: WebSocket | null = null;
|
|
155
|
+
let nextId = 1;
|
|
156
|
+
const pending = new Map<number, { resolve: (v: unknown) => void; reject: (e: Error) => void; timeout: ReturnType<typeof setTimeout> }>();
|
|
157
|
+
|
|
158
|
+
function ensureSocket(): WebSocket {
|
|
159
|
+
// Reuse socket opened by BuniteView if available
|
|
160
|
+
const existing = w.__bunite?._socket;
|
|
161
|
+
if (existing && existing.readyState <= WebSocket.OPEN && existing !== socket) {
|
|
162
|
+
socket = existing;
|
|
163
|
+
attachListener(existing);
|
|
164
|
+
return existing;
|
|
165
|
+
}
|
|
166
|
+
if (socket && socket.readyState <= WebSocket.OPEN) return socket;
|
|
167
|
+
socket = new WebSocket(
|
|
168
|
+
`ws://localhost:${__buniteRpcSocketPort}/socket?webviewId=${__buniteWebviewId}`
|
|
169
|
+
);
|
|
170
|
+
socket.binaryType = "arraybuffer";
|
|
171
|
+
w.__bunite._socket = socket;
|
|
172
|
+
attachListener(socket);
|
|
173
|
+
return socket;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function attachListener(ws: WebSocket) {
|
|
177
|
+
ws.addEventListener("message", async (event) => {
|
|
178
|
+
try {
|
|
179
|
+
const decrypted = await buniteDecrypt(new Uint8Array(event.data as ArrayBuffer));
|
|
180
|
+
const packet = mpDecode(decrypted) as any;
|
|
181
|
+
if (packet?.type === "response" && packet.scope === "global") {
|
|
182
|
+
const p = pending.get(packet.id);
|
|
183
|
+
if (p) {
|
|
184
|
+
pending.delete(packet.id);
|
|
185
|
+
clearTimeout(p.timeout);
|
|
186
|
+
packet.success ? p.resolve(packet.payload) : p.reject(new Error(packet.error || "Unknown error"));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
} catch { /* ignore malformed frames */ }
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return (method: string, params?: unknown) =>
|
|
194
|
+
new Promise((resolve, reject) => {
|
|
195
|
+
const ws = ensureSocket();
|
|
196
|
+
const id = nextId++;
|
|
197
|
+
const timeout = setTimeout(() => {
|
|
198
|
+
pending.delete(id);
|
|
199
|
+
reject(new Error(`bunite.invoke timed out: ${method}`));
|
|
200
|
+
}, 15000);
|
|
201
|
+
pending.set(id, { resolve, reject, timeout });
|
|
202
|
+
|
|
203
|
+
const packet = { type: "request", id, method, params: params ?? null, scope: "global" };
|
|
204
|
+
const doSend = async () => {
|
|
205
|
+
const encrypted = await buniteEncrypt(mpEncode(packet));
|
|
206
|
+
ws.send(encrypted.buffer as ArrayBuffer);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
210
|
+
doSend();
|
|
211
|
+
} else {
|
|
212
|
+
ws.addEventListener("open", () => doSend(), { once: true });
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
})();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022", "DOM"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"exactOptionalPropertyTypes": false,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"noEmit": true
|
|
11
|
+
},
|
|
12
|
+
"include": ["runtime.ts"]
|
|
13
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { ARCH, BIN_EXT, NATIVE_LIB_EXT, PLATFORM_TAG } from "./platform";
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
|
|
8
|
+
export type ResolvedNativeArtifacts = {
|
|
9
|
+
packageRoot: string;
|
|
10
|
+
source: "optional-package" | "local-build" | "missing";
|
|
11
|
+
nativePackageName: string | null;
|
|
12
|
+
cefPackageName: string | null;
|
|
13
|
+
nativeLibPath: string | null;
|
|
14
|
+
processHelperPath: string | null;
|
|
15
|
+
cefDir: string | null;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function resolvePackageRoot(packageName: string): string | null {
|
|
19
|
+
try {
|
|
20
|
+
const packageJsonPath = require.resolve(`${packageName}/package.json`);
|
|
21
|
+
return dirname(packageJsonPath);
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function resolveBunitePackageRoot(): string {
|
|
28
|
+
const packageJsonPath = require.resolve("bunite/package.json");
|
|
29
|
+
return dirname(packageJsonPath);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function resolveFallbackCefDir(): string | null {
|
|
33
|
+
const envOverride = process.env.BUNITE_CEF_DIR ?? process.env.BUNITE_CEF_ROOT;
|
|
34
|
+
if (envOverride && existsSync(envOverride)) {
|
|
35
|
+
return envOverride;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const bunitePackageRoot = resolveBunitePackageRoot();
|
|
39
|
+
const localVendorPath = join(bunitePackageRoot, "vendors", "cef");
|
|
40
|
+
if (existsSync(localVendorPath)) {
|
|
41
|
+
return localVendorPath;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const upstreamVendorPath = "C:\\project\\electrobun\\package\\vendors\\cef";
|
|
45
|
+
if (existsSync(upstreamVendorPath)) {
|
|
46
|
+
return upstreamVendorPath;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function resolveDefaultViewsRoot(): string | null {
|
|
53
|
+
const candidate = join(process.cwd(), "views");
|
|
54
|
+
return existsSync(candidate) ? candidate : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function resolveNativeArtifacts(): ResolvedNativeArtifacts {
|
|
58
|
+
const packageRoot = resolveBunitePackageRoot();
|
|
59
|
+
const nativePackageName = `@bunite/native-${PLATFORM_TAG}-${ARCH}`;
|
|
60
|
+
const cefPackageName = `@bunite/cef-${PLATFORM_TAG}-${ARCH}`;
|
|
61
|
+
const nativePackageRoot = resolvePackageRoot(nativePackageName);
|
|
62
|
+
const cefPackageRoot = resolvePackageRoot(cefPackageName);
|
|
63
|
+
|
|
64
|
+
const packagedNativeLibPath = nativePackageRoot
|
|
65
|
+
? join(nativePackageRoot, `libBuniteNative${NATIVE_LIB_EXT}`)
|
|
66
|
+
: null;
|
|
67
|
+
const packagedProcessHelperPath = nativePackageRoot
|
|
68
|
+
? join(nativePackageRoot, `process_helper${BIN_EXT}`)
|
|
69
|
+
: null;
|
|
70
|
+
const packagedCefDir = cefPackageRoot ?? null;
|
|
71
|
+
|
|
72
|
+
if (
|
|
73
|
+
packagedNativeLibPath &&
|
|
74
|
+
packagedProcessHelperPath &&
|
|
75
|
+
existsSync(packagedNativeLibPath) &&
|
|
76
|
+
existsSync(packagedProcessHelperPath)
|
|
77
|
+
) {
|
|
78
|
+
return {
|
|
79
|
+
packageRoot,
|
|
80
|
+
source: "optional-package",
|
|
81
|
+
nativePackageName,
|
|
82
|
+
cefPackageName: packagedCefDir && existsSync(packagedCefDir) ? cefPackageName : null,
|
|
83
|
+
nativeLibPath: packagedNativeLibPath,
|
|
84
|
+
processHelperPath: packagedProcessHelperPath,
|
|
85
|
+
cefDir: packagedCefDir && existsSync(packagedCefDir) ? packagedCefDir : null
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const localBuildRoot = join(packageRoot, "native-build", `${PLATFORM_TAG}-${ARCH}`);
|
|
90
|
+
const localCefDir = join(localBuildRoot, "cef");
|
|
91
|
+
const directLocalNativeLibPath = join(localBuildRoot, `libBuniteNative${NATIVE_LIB_EXT}`);
|
|
92
|
+
const directLocalProcessHelperPath = join(localBuildRoot, `process_helper${BIN_EXT}`);
|
|
93
|
+
|
|
94
|
+
if (existsSync(directLocalNativeLibPath) && existsSync(directLocalProcessHelperPath)) {
|
|
95
|
+
const resolvedLocalCefDir = existsSync(localCefDir) ? localCefDir : resolveFallbackCefDir();
|
|
96
|
+
return {
|
|
97
|
+
packageRoot,
|
|
98
|
+
source: "local-build",
|
|
99
|
+
nativePackageName: null,
|
|
100
|
+
cefPackageName: null,
|
|
101
|
+
nativeLibPath: directLocalNativeLibPath,
|
|
102
|
+
processHelperPath: directLocalProcessHelperPath,
|
|
103
|
+
cefDir: resolvedLocalCefDir
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const localBuildBinRoot = join(localBuildRoot, "Release");
|
|
108
|
+
const localNativeLibPath = join(localBuildBinRoot, `libBuniteNative${NATIVE_LIB_EXT}`);
|
|
109
|
+
const localProcessHelperPath = join(localBuildBinRoot, `process_helper${BIN_EXT}`);
|
|
110
|
+
|
|
111
|
+
if (existsSync(localNativeLibPath) && existsSync(localProcessHelperPath)) {
|
|
112
|
+
const resolvedLocalCefDir = existsSync(localCefDir) ? localCefDir : resolveFallbackCefDir();
|
|
113
|
+
return {
|
|
114
|
+
packageRoot,
|
|
115
|
+
source: "local-build",
|
|
116
|
+
nativePackageName: null,
|
|
117
|
+
cefPackageName: null,
|
|
118
|
+
nativeLibPath: localNativeLibPath,
|
|
119
|
+
processHelperPath: localProcessHelperPath,
|
|
120
|
+
cefDir: resolvedLocalCefDir
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
packageRoot,
|
|
126
|
+
source: "missing",
|
|
127
|
+
nativePackageName: nativePackageRoot ? nativePackageName : null,
|
|
128
|
+
cefPackageName: cefPackageRoot ? cefPackageName : null,
|
|
129
|
+
nativeLibPath: null,
|
|
130
|
+
processHelperPath: null,
|
|
131
|
+
cefDir: null
|
|
132
|
+
};
|
|
133
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const OS = process.platform;
|
|
2
|
+
export const ARCH = process.arch;
|
|
3
|
+
|
|
4
|
+
export const PLATFORM_TAG =
|
|
5
|
+
OS === "win32" ? "win" : OS === "darwin" ? "darwin" : OS;
|
|
6
|
+
|
|
7
|
+
export const BIN_EXT = OS === "win32" ? ".exe" : "";
|
|
8
|
+
export const NATIVE_LIB_EXT =
|
|
9
|
+
OS === "win32" ? ".dll" : OS === "darwin" ? ".dylib" : ".so";
|