api-ape 0.0.0 → 1.0.2
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/README.md +458 -0
- package/client/README.md +69 -0
- package/client/browser.js +17 -0
- package/client/connectSocket.js +260 -0
- package/dist/ape.js +454 -0
- package/example/ExpressJs/README.md +97 -0
- package/example/ExpressJs/api/message.js +11 -0
- package/example/ExpressJs/backend.js +37 -0
- package/example/ExpressJs/index.html +88 -0
- package/example/ExpressJs/package-lock.json +834 -0
- package/example/ExpressJs/package.json +10 -0
- package/example/ExpressJs/styles.css +128 -0
- package/example/NextJs/.dockerignore +29 -0
- package/example/NextJs/Dockerfile +52 -0
- package/example/NextJs/Dockerfile.dev +27 -0
- package/example/NextJs/README.md +113 -0
- package/example/NextJs/ape/client.js +66 -0
- package/example/NextJs/ape/embed.js +12 -0
- package/example/NextJs/ape/index.js +23 -0
- package/example/NextJs/ape/logic/chat.js +62 -0
- package/example/NextJs/ape/onConnect.js +69 -0
- package/example/NextJs/ape/onDisconnect.js +13 -0
- package/example/NextJs/ape/onError.js +9 -0
- package/example/NextJs/ape/onReceive.js +15 -0
- package/example/NextJs/ape/onSend.js +15 -0
- package/example/NextJs/api/message.js +44 -0
- package/example/NextJs/docker-compose.yml +22 -0
- package/example/NextJs/next-env.d.ts +5 -0
- package/example/NextJs/next.config.js +8 -0
- package/example/NextJs/package-lock.json +5107 -0
- package/example/NextJs/package.json +25 -0
- package/example/NextJs/pages/Info.tsx +153 -0
- package/example/NextJs/pages/_app.tsx +6 -0
- package/example/NextJs/pages/index.tsx +264 -0
- package/example/NextJs/public/favicon.ico +0 -0
- package/example/NextJs/public/vercel.svg +4 -0
- package/example/NextJs/server.js +40 -0
- package/example/NextJs/styles/Chat.module.css +448 -0
- package/example/NextJs/styles/Home.module.css +129 -0
- package/example/NextJs/styles/globals.css +26 -0
- package/example/NextJs/tsconfig.json +20 -0
- package/example/README.md +66 -0
- package/index.d.ts +179 -0
- package/index.js +11 -0
- package/package.json +11 -4
- package/server/README.md +93 -0
- package/server/index.js +6 -0
- package/server/lib/broadcast.js +63 -0
- package/server/lib/loader.js +10 -0
- package/server/lib/main.js +23 -0
- package/server/lib/wiring.js +94 -0
- package/server/security/extractRootDomain.js +21 -0
- package/server/security/origin.js +13 -0
- package/server/security/reply.js +21 -0
- package/server/socket/open.js +10 -0
- package/server/socket/receive.js +66 -0
- package/server/socket/send.js +55 -0
- package/server/utils/deepRequire.js +45 -0
- package/server/utils/genId.js +24 -0
- package/todo.md +85 -0
- package/utils/jss.js +273 -0
- package/utils/jss.test.js +261 -0
- package/utils/messageHash.js +43 -0
- package/utils/messageHash.test.js +56 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import messageHash from '../utils/messageHash'
|
|
2
|
+
import jss from '../utils/jss'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
let connect;
|
|
6
|
+
|
|
7
|
+
// Configuration
|
|
8
|
+
let configuredPort = null
|
|
9
|
+
let configuredHost = null
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Configure api-ape client connection
|
|
13
|
+
* @param {object} opts
|
|
14
|
+
* @param {number} [opts.port] - WebSocket port (default: 9010 for local, 443/80 for remote)
|
|
15
|
+
* @param {string} [opts.host] - WebSocket host (default: auto-detect from window.location)
|
|
16
|
+
*/
|
|
17
|
+
function configure(opts = {}) {
|
|
18
|
+
if (opts.port) configuredPort = opts.port
|
|
19
|
+
if (opts.host) configuredHost = opts.host
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get WebSocket URL - auto-detects from window.location, keeps /api/ape path
|
|
24
|
+
*/
|
|
25
|
+
function getSocketUrl() {
|
|
26
|
+
const hostname = configuredHost || window.location.hostname
|
|
27
|
+
const localServers = ["localhost", "127.0.0.1", "[::1]"]
|
|
28
|
+
const isLocal = localServers.includes(hostname)
|
|
29
|
+
const isHttps = window.location.protocol === "https:"
|
|
30
|
+
|
|
31
|
+
// Default port: 9010 for local dev, otherwise use window.location.port or implicit 443/80
|
|
32
|
+
const defaultPort = isLocal ? 9010 : (window.location.port || (isHttps ? 443 : 80))
|
|
33
|
+
const port = configuredPort || defaultPort
|
|
34
|
+
|
|
35
|
+
// Build URL - keep /api/ape path
|
|
36
|
+
const protocol = isHttps ? "wss" : "ws"
|
|
37
|
+
const portSuffix = (isLocal || port !== 80 && port !== 443) ? `:${port}` : ""
|
|
38
|
+
|
|
39
|
+
return `${protocol}://${hostname}${portSuffix}/api/ape`
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let reconnect = false
|
|
43
|
+
const connentTimeout = 5000
|
|
44
|
+
const totalRequestTimeout = 10000
|
|
45
|
+
//const location = window.location
|
|
46
|
+
|
|
47
|
+
const joinKey = "/"
|
|
48
|
+
// Properties accessed directly on `ape` that should NOT be intercepted
|
|
49
|
+
const reservedKeys = new Set(['on'])
|
|
50
|
+
const handler = {
|
|
51
|
+
get(fn, key) {
|
|
52
|
+
// Skip proxy interception for reserved keys - return actual property
|
|
53
|
+
if (reservedKeys.has(key)) {
|
|
54
|
+
return fn[key]
|
|
55
|
+
}
|
|
56
|
+
const wrapperFn = function (a, b) {
|
|
57
|
+
let path = joinKey + key, body;
|
|
58
|
+
if (2 === arguments.length) {
|
|
59
|
+
path += a
|
|
60
|
+
body = b
|
|
61
|
+
} else {
|
|
62
|
+
body = a
|
|
63
|
+
}
|
|
64
|
+
return fn(path, body)
|
|
65
|
+
}
|
|
66
|
+
return new Proxy(wrapperFn, handler)
|
|
67
|
+
} // END get
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function wrap(api) {
|
|
71
|
+
return new Proxy(api, handler)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let __socket = false, ready = false, wsSend = false;
|
|
75
|
+
const waitingOn = {};
|
|
76
|
+
const reciverOn = [];
|
|
77
|
+
|
|
78
|
+
let aWaitingSend = []
|
|
79
|
+
const reciverOnAr = [];
|
|
80
|
+
const ofTypesOb = {};
|
|
81
|
+
|
|
82
|
+
function connectSocket() {
|
|
83
|
+
|
|
84
|
+
if (!__socket) {
|
|
85
|
+
__socket = new WebSocket(getSocketUrl())
|
|
86
|
+
|
|
87
|
+
__socket.onopen = event => {
|
|
88
|
+
//console.log('socket connected()');
|
|
89
|
+
ready = true;
|
|
90
|
+
aWaitingSend.forEach(({ type, data, next, err, waiting, createdAt, timer }) => {
|
|
91
|
+
clearTimeout(timer)
|
|
92
|
+
//TODO: clear throw of wait for server
|
|
93
|
+
const resultPromise = wsSend(type, data, createdAt)
|
|
94
|
+
if (waiting) {
|
|
95
|
+
resultPromise.then(next)
|
|
96
|
+
.catch(err)
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
// cloudfler drops the connetion and the client has to remake,
|
|
100
|
+
// we clear the array as we dont need this info every RE-connent
|
|
101
|
+
aWaitingSend = []
|
|
102
|
+
} // END onopen
|
|
103
|
+
|
|
104
|
+
__socket.onmessage = function (event) {
|
|
105
|
+
//console.log('WebSocket message:', event);
|
|
106
|
+
const { err, type, queryId, data } = jss.parse(event.data)
|
|
107
|
+
|
|
108
|
+
// Messages with queryId must fulfill matching promise
|
|
109
|
+
if (queryId) {
|
|
110
|
+
if (waitingOn[queryId]) {
|
|
111
|
+
waitingOn[queryId](err, data)
|
|
112
|
+
delete waitingOn[queryId]
|
|
113
|
+
} else {
|
|
114
|
+
// No matching promise - error and ignore
|
|
115
|
+
console.error(`🦍 No matching queryId: ${queryId}`)
|
|
116
|
+
}
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Only messages WITHOUT queryId go to setOnReciver
|
|
121
|
+
if (ofTypesOb[type]) {
|
|
122
|
+
ofTypesOb[type].forEach(worker => worker({ err, type, data }))
|
|
123
|
+
} // if ofTypesOb[type]
|
|
124
|
+
reciverOnAr.forEach(worker => worker({ err, type, data }))
|
|
125
|
+
|
|
126
|
+
} // END onmessage
|
|
127
|
+
|
|
128
|
+
__socket.onerror = function (err) {
|
|
129
|
+
console.error('socket ERROR:', err);
|
|
130
|
+
} // END onerror
|
|
131
|
+
|
|
132
|
+
__socket.onclose = function (event) {
|
|
133
|
+
console.warn('socket disconnect:', event);
|
|
134
|
+
__socket = false
|
|
135
|
+
ready = false;
|
|
136
|
+
setTimeout(() => reconnect && connectSocket(), 500);
|
|
137
|
+
} // END onclose
|
|
138
|
+
|
|
139
|
+
} // END if ! __socket
|
|
140
|
+
wsSend = function (type, data, createdAt, dirctCall) {
|
|
141
|
+
let rej, promiseIsLive = false;
|
|
142
|
+
const timeLetForReqToBeMade = (createdAt + totalRequestTimeout) - Date.now()
|
|
143
|
+
|
|
144
|
+
const timer = setTimeout(() => {
|
|
145
|
+
if (promiseIsLive) {
|
|
146
|
+
rej(new Error("Request Timedout for :" + type))
|
|
147
|
+
}
|
|
148
|
+
}, timeLetForReqToBeMade);
|
|
149
|
+
const payload = {
|
|
150
|
+
type,
|
|
151
|
+
data,
|
|
152
|
+
//referer:window.location.href,
|
|
153
|
+
createdAt: new Date(createdAt),
|
|
154
|
+
requestedAt: dirctCall ? undefined
|
|
155
|
+
: new Date()
|
|
156
|
+
}
|
|
157
|
+
const message = jss.stringify(payload)
|
|
158
|
+
const queryId = messageHash(message);
|
|
159
|
+
|
|
160
|
+
const replyPromise = new Promise((resolve, reject) => {
|
|
161
|
+
rej = reject
|
|
162
|
+
waitingOn[queryId] = (err, result) => {
|
|
163
|
+
clearTimeout(timer)
|
|
164
|
+
replyPromise.then = next.bind(replyPromise)
|
|
165
|
+
if (err) {
|
|
166
|
+
reject(err)
|
|
167
|
+
} else {
|
|
168
|
+
resolve(result)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
__socket.send(message);
|
|
172
|
+
});
|
|
173
|
+
const next = replyPromise.then;
|
|
174
|
+
replyPromise.then = worker => {
|
|
175
|
+
promiseIsLive = true;
|
|
176
|
+
replyPromise.then = next.bind(replyPromise)
|
|
177
|
+
replyPromise.catch = err.bind(replyPromise)
|
|
178
|
+
return next.call(replyPromise, worker)
|
|
179
|
+
}
|
|
180
|
+
const err = replyPromise.catch;
|
|
181
|
+
replyPromise.catch = worker => {
|
|
182
|
+
promiseIsLive = true;
|
|
183
|
+
replyPromise.catch = err.bind(replyPromise)
|
|
184
|
+
replyPromise.then = next.bind(replyPromise)
|
|
185
|
+
return err.call(replyPromise, worker)
|
|
186
|
+
}
|
|
187
|
+
return replyPromise
|
|
188
|
+
} // END wsSend
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
const sender = (type, data) => {
|
|
192
|
+
if ("string" !== typeof type) {
|
|
193
|
+
throw new Error("Missing Path vaule")
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const createdAt = Date.now()
|
|
197
|
+
|
|
198
|
+
if (ready) {
|
|
199
|
+
return wsSend(type, data, createdAt, true)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const timeLetForReqToBeMade = (createdAt + connentTimeout) - Date.now() // 5sec for reconnent
|
|
203
|
+
|
|
204
|
+
const timer = setTimeout(() => {
|
|
205
|
+
const errMessage = "Request not sent for :" + type
|
|
206
|
+
if (payload.waiting) {
|
|
207
|
+
payload.err(new Error(errMessage))
|
|
208
|
+
} else {
|
|
209
|
+
throw new Error(errMessage)
|
|
210
|
+
}
|
|
211
|
+
}, timeLetForReqToBeMade);
|
|
212
|
+
|
|
213
|
+
const payload = { type, data, next: undefined, err: undefined, waiting: false, createdAt, timer };
|
|
214
|
+
const waitingOnOpen = new Promise((res, er) => { payload.next = res; payload.err = er; })
|
|
215
|
+
|
|
216
|
+
const waitingOnOpenThen = waitingOnOpen.then;
|
|
217
|
+
const waitingOnOpenCatch = waitingOnOpen.catch;
|
|
218
|
+
waitingOnOpen.then = worker => {
|
|
219
|
+
payload.waiting = true;
|
|
220
|
+
waitingOnOpen.then = waitingOnOpenThen.bind(waitingOnOpen)
|
|
221
|
+
waitingOnOpen.catch = waitingOnOpenCatch.bind(waitingOnOpen)
|
|
222
|
+
return waitingOnOpenThen.call(waitingOnOpen, worker)
|
|
223
|
+
}
|
|
224
|
+
waitingOnOpen.catch = worker => {
|
|
225
|
+
payload.waiting = true;
|
|
226
|
+
waitingOnOpen.catch = waitingOnOpenCatch.bind(waitingOnOpen)
|
|
227
|
+
waitingOnOpen.then = waitingOnOpenThen.bind(waitingOnOpen)
|
|
228
|
+
return waitingOnOpenCatch.call(waitingOnOpen, worker)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
aWaitingSend.push(payload)
|
|
232
|
+
if (!__socket) {
|
|
233
|
+
connectSocket()
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return waitingOnOpen
|
|
237
|
+
} // END sender
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
sender: wrap(sender),
|
|
241
|
+
setOnReciver: (onTypeStFn, handlerFn) => {
|
|
242
|
+
if ("string" === typeof onTypeStFn) {
|
|
243
|
+
// Replace handler for this type (prevents duplicates in React StrictMode)
|
|
244
|
+
ofTypesOb[onTypeStFn] = [handlerFn]
|
|
245
|
+
} else {
|
|
246
|
+
// For general receivers, prevent duplicates by checking
|
|
247
|
+
if (!reciverOnAr.includes(onTypeStFn)) {
|
|
248
|
+
reciverOnAr.push(onTypeStFn)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
} // END setOnReciver
|
|
252
|
+
} // END return
|
|
253
|
+
} // END connectSocket
|
|
254
|
+
|
|
255
|
+
connectSocket.autoReconnect = () => reconnect = true
|
|
256
|
+
connectSocket.configure = configure
|
|
257
|
+
connect = connectSocket
|
|
258
|
+
|
|
259
|
+
export default connect;
|
|
260
|
+
export { configure };
|
package/dist/ape.js
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
|
|
28
|
+
// utils/messageHash.js
|
|
29
|
+
var require_messageHash = __commonJS({
|
|
30
|
+
"utils/messageHash.js"(exports, module) {
|
|
31
|
+
var alphabet = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
32
|
+
function toBase32(n) {
|
|
33
|
+
const remainder = Math.floor(n / 32);
|
|
34
|
+
const current = n % 32;
|
|
35
|
+
if (0 === remainder) {
|
|
36
|
+
return alphabet[current];
|
|
37
|
+
}
|
|
38
|
+
return toBase32(remainder) + alphabet[current];
|
|
39
|
+
}
|
|
40
|
+
function jenkinsOneAtATimeHash(keyString) {
|
|
41
|
+
var hash = 0;
|
|
42
|
+
for (var charIndex = 0; charIndex < keyString.length; ++charIndex) {
|
|
43
|
+
hash += keyString.charCodeAt(charIndex);
|
|
44
|
+
hash += hash << 10;
|
|
45
|
+
hash ^= hash >> 6;
|
|
46
|
+
}
|
|
47
|
+
hash += hash << 3;
|
|
48
|
+
hash ^= hash >> 11;
|
|
49
|
+
return (hash + (hash << 15) & 4294967295) >>> 0;
|
|
50
|
+
}
|
|
51
|
+
function messageHash2(messageSt) {
|
|
52
|
+
return toBase32(jenkinsOneAtATimeHash(messageSt));
|
|
53
|
+
}
|
|
54
|
+
module.exports = messageHash2;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// utils/jjs.js
|
|
59
|
+
var require_jjs = __commonJS({
|
|
60
|
+
"utils/jjs.js"(exports, module) {
|
|
61
|
+
function encode(obj) {
|
|
62
|
+
const tagLookup = {
|
|
63
|
+
"[object RegExp]": "R",
|
|
64
|
+
"[object Date]": "D",
|
|
65
|
+
"[object Error]": "E",
|
|
66
|
+
"[object Undefined]": "U",
|
|
67
|
+
"[object Map]": "M",
|
|
68
|
+
"[object Set]": "S"
|
|
69
|
+
};
|
|
70
|
+
const visited = /* @__PURE__ */ new WeakMap();
|
|
71
|
+
function encodeValue(value, path = "") {
|
|
72
|
+
const type = typeof value;
|
|
73
|
+
const tag = tagLookup[Object.prototype.toString.call(value)];
|
|
74
|
+
if (tag !== void 0) {
|
|
75
|
+
if ("D" === tag) return [tag, value.valueOf()];
|
|
76
|
+
if ("E" === tag) return [tag, [value.name, value.message, value.stack]];
|
|
77
|
+
if ("R" === tag) return [tag, value.toString()];
|
|
78
|
+
if ("U" === tag) return [tag, null];
|
|
79
|
+
if ("S" === tag) return [tag, Array.from(value)];
|
|
80
|
+
if ("M" === tag) return [tag, Object.fromEntries(value)];
|
|
81
|
+
return [tag, JSON.stringify(value)];
|
|
82
|
+
} else if (type === "object" && value !== null) {
|
|
83
|
+
if (visited.has(value)) {
|
|
84
|
+
return ["P", visited.get(value)];
|
|
85
|
+
}
|
|
86
|
+
visited.set(value, path);
|
|
87
|
+
const isArray = Array.isArray(value);
|
|
88
|
+
const keys2 = isArray ? Array.from(Array(value.length).keys()) : Object.keys(value);
|
|
89
|
+
const result2 = isArray ? [] : {};
|
|
90
|
+
const typesFound = [];
|
|
91
|
+
for (let i = 0; i < keys2.length; i++) {
|
|
92
|
+
const key = keys2[i];
|
|
93
|
+
const [t, v] = encodeValue(value[key], key);
|
|
94
|
+
if (isArray) {
|
|
95
|
+
typesFound.push(t);
|
|
96
|
+
result2.push(v);
|
|
97
|
+
} else if (value[key] !== void 0) {
|
|
98
|
+
result2[key + (t ? `<!${t}>` : "")] = v;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
visited.delete(value);
|
|
102
|
+
if (isArray && typesFound.find((t) => !!t)) {
|
|
103
|
+
return [`[${typesFound.join()}]`, result2];
|
|
104
|
+
}
|
|
105
|
+
return ["", result2];
|
|
106
|
+
} else {
|
|
107
|
+
return ["", value];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
let keys = [];
|
|
111
|
+
if (Array.isArray(obj)) {
|
|
112
|
+
keys = Array.from(Array(obj.length).keys());
|
|
113
|
+
} else {
|
|
114
|
+
keys = Object.keys(obj);
|
|
115
|
+
}
|
|
116
|
+
const result = {};
|
|
117
|
+
for (let i = 0; i < keys.length; i++) {
|
|
118
|
+
const key = keys[i];
|
|
119
|
+
if (obj[key] !== void 0) {
|
|
120
|
+
const [t, v] = encodeValue(obj[key], key);
|
|
121
|
+
result[key + (t ? `<!${t}>` : "")] = v;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
function stringify(obj) {
|
|
127
|
+
return JSON.stringify(encode(obj));
|
|
128
|
+
}
|
|
129
|
+
function parse(encoded) {
|
|
130
|
+
return decode(JSON.parse(encoded));
|
|
131
|
+
}
|
|
132
|
+
function decode(data) {
|
|
133
|
+
const result = {};
|
|
134
|
+
const pointers2Res = [];
|
|
135
|
+
const tagLookup = {
|
|
136
|
+
R: (s) => new RegExp(s),
|
|
137
|
+
D: (n) => new Date(n),
|
|
138
|
+
P: function(sourceToPointAt, replaceAtThisPlace) {
|
|
139
|
+
pointers2Res.push([sourceToPointAt, replaceAtThisPlace + ""]);
|
|
140
|
+
return sourceToPointAt;
|
|
141
|
+
},
|
|
142
|
+
E: ([name, message, stack]) => {
|
|
143
|
+
let err;
|
|
144
|
+
try {
|
|
145
|
+
err = new global[name](message);
|
|
146
|
+
if (err instanceof Error) err.stack = stack;
|
|
147
|
+
else throw {};
|
|
148
|
+
} catch (e) {
|
|
149
|
+
err = new Error(message);
|
|
150
|
+
err.name = name;
|
|
151
|
+
err.stack = stack;
|
|
152
|
+
}
|
|
153
|
+
return err;
|
|
154
|
+
},
|
|
155
|
+
U: () => void 0,
|
|
156
|
+
S: (a) => new Set(a),
|
|
157
|
+
M: (o) => new Map(Object.entries(o))
|
|
158
|
+
};
|
|
159
|
+
const visited = /* @__PURE__ */ new Map();
|
|
160
|
+
function decodeValue(name, tag, val) {
|
|
161
|
+
if (tag in tagLookup) {
|
|
162
|
+
return tagLookup[tag](val, this);
|
|
163
|
+
} else if (Array.isArray(val)) {
|
|
164
|
+
if (tag && tag.startsWith("[")) {
|
|
165
|
+
const typeTags = tag.slice(1, -1).split(",");
|
|
166
|
+
const result2 = [];
|
|
167
|
+
for (let i = 0; i < val.length; i++) {
|
|
168
|
+
const decodedValue = decodeValue.call(
|
|
169
|
+
`${this}${this ? "/" : ""}${name}`,
|
|
170
|
+
"",
|
|
171
|
+
typeTags[i],
|
|
172
|
+
val[i]
|
|
173
|
+
);
|
|
174
|
+
result2.push(decodedValue);
|
|
175
|
+
}
|
|
176
|
+
return result2;
|
|
177
|
+
} else {
|
|
178
|
+
const result2 = [];
|
|
179
|
+
for (let i = 0; i < val.length; i++) {
|
|
180
|
+
const decodedValue = decodeValue.call(`${this}${this ? "/" : ""}${name}`, "", "", val[i]);
|
|
181
|
+
result2.push(decodedValue);
|
|
182
|
+
}
|
|
183
|
+
return result2;
|
|
184
|
+
}
|
|
185
|
+
} else if ("object" === typeof val && val !== null) {
|
|
186
|
+
if (visited.has(val)) {
|
|
187
|
+
return visited.get(val);
|
|
188
|
+
}
|
|
189
|
+
visited.set(val, {});
|
|
190
|
+
const result2 = {};
|
|
191
|
+
for (const key in val) {
|
|
192
|
+
const [nam, tag2] = parseKeyWithTags(key);
|
|
193
|
+
const decodedValue = decodeValue.call(
|
|
194
|
+
`${name}${name ? "/" : ""}${nam}`,
|
|
195
|
+
nam,
|
|
196
|
+
tag2,
|
|
197
|
+
val[key]
|
|
198
|
+
);
|
|
199
|
+
result2[nam] = decodedValue;
|
|
200
|
+
}
|
|
201
|
+
visited.set(val, result2);
|
|
202
|
+
return result2;
|
|
203
|
+
} else {
|
|
204
|
+
return val;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function parseKeyWithTags(key) {
|
|
208
|
+
const match = key.match(/(.+)(<!(.+)>)/);
|
|
209
|
+
if (match) {
|
|
210
|
+
return [match[1], match[3]];
|
|
211
|
+
} else {
|
|
212
|
+
return [key, void 0];
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
for (const key in data) {
|
|
216
|
+
const [name, tag] = parseKeyWithTags(key);
|
|
217
|
+
result[name] = decodeValue.call("", name, tag, data[key]);
|
|
218
|
+
}
|
|
219
|
+
pointers2Res.forEach(changeAttributeReference.bind(null, result));
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
function changeAttributeReference(obj, [refPath, attrPath]) {
|
|
223
|
+
const refKeys = refPath.split("/");
|
|
224
|
+
const attrKeys = attrPath.split("/");
|
|
225
|
+
let ref = obj;
|
|
226
|
+
let attr = obj;
|
|
227
|
+
for (let i = 0; i < refKeys.length - 1; i++) {
|
|
228
|
+
ref = ref[refKeys[i]];
|
|
229
|
+
}
|
|
230
|
+
for (let i = 0; i < attrKeys.length - 1; i++) {
|
|
231
|
+
attr = attr[attrKeys[i]];
|
|
232
|
+
}
|
|
233
|
+
attr[attrKeys[attrKeys.length - 1]] = ref[refKeys[refKeys.length - 1]];
|
|
234
|
+
return obj;
|
|
235
|
+
}
|
|
236
|
+
module.exports = { parse, stringify, encode, decode };
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// client/connectSocket.js
|
|
241
|
+
var import_messageHash = __toESM(require_messageHash());
|
|
242
|
+
var import_jjs = __toESM(require_jjs());
|
|
243
|
+
var connect;
|
|
244
|
+
var configuredPort = null;
|
|
245
|
+
var configuredHost = null;
|
|
246
|
+
function configure(opts = {}) {
|
|
247
|
+
if (opts.port) configuredPort = opts.port;
|
|
248
|
+
if (opts.host) configuredHost = opts.host;
|
|
249
|
+
}
|
|
250
|
+
function getSocketUrl() {
|
|
251
|
+
const hostname = configuredHost || window.location.hostname;
|
|
252
|
+
const localServers = ["localhost", "127.0.0.1", "[::1]"];
|
|
253
|
+
const isLocal = localServers.includes(hostname);
|
|
254
|
+
const isHttps = window.location.protocol === "https:";
|
|
255
|
+
const defaultPort = isLocal ? 9010 : window.location.port || (isHttps ? 443 : 80);
|
|
256
|
+
const port2 = configuredPort || defaultPort;
|
|
257
|
+
const protocol = isHttps ? "wss" : "ws";
|
|
258
|
+
const portSuffix = isLocal || port2 !== 80 && port2 !== 443 ? `:${port2}` : "";
|
|
259
|
+
return `${protocol}://${hostname}${portSuffix}/api/ape`;
|
|
260
|
+
}
|
|
261
|
+
var reconnect = false;
|
|
262
|
+
var connentTimeout = 5e3;
|
|
263
|
+
var totalRequestTimeout = 1e4;
|
|
264
|
+
var joinKey = "/";
|
|
265
|
+
var reservedKeys = /* @__PURE__ */ new Set(["on"]);
|
|
266
|
+
var handler = {
|
|
267
|
+
get(fn, key) {
|
|
268
|
+
if (reservedKeys.has(key)) {
|
|
269
|
+
return fn[key];
|
|
270
|
+
}
|
|
271
|
+
const wrapperFn = function(a, b) {
|
|
272
|
+
let path = joinKey + key, body;
|
|
273
|
+
if (2 === arguments.length) {
|
|
274
|
+
path += a;
|
|
275
|
+
body = b;
|
|
276
|
+
} else {
|
|
277
|
+
body = a;
|
|
278
|
+
}
|
|
279
|
+
return fn(path, body);
|
|
280
|
+
};
|
|
281
|
+
return new Proxy(wrapperFn, handler);
|
|
282
|
+
}
|
|
283
|
+
// END get
|
|
284
|
+
};
|
|
285
|
+
function wrap(api) {
|
|
286
|
+
return new Proxy(api, handler);
|
|
287
|
+
}
|
|
288
|
+
var __socket = false;
|
|
289
|
+
var ready = false;
|
|
290
|
+
var wsSend = false;
|
|
291
|
+
var waitingOn = {};
|
|
292
|
+
var aWaitingSend = [];
|
|
293
|
+
var reciverOnAr = [];
|
|
294
|
+
var ofTypesOb = {};
|
|
295
|
+
function connectSocket() {
|
|
296
|
+
if (!__socket) {
|
|
297
|
+
__socket = new WebSocket(getSocketUrl());
|
|
298
|
+
__socket.onopen = (event) => {
|
|
299
|
+
ready = true;
|
|
300
|
+
aWaitingSend.forEach(({ type, data, next, err, waiting, createdAt, timer }) => {
|
|
301
|
+
clearTimeout(timer);
|
|
302
|
+
const resultPromise = wsSend(type, data, createdAt);
|
|
303
|
+
if (waiting) {
|
|
304
|
+
resultPromise.then(next).catch(err);
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
aWaitingSend = [];
|
|
308
|
+
};
|
|
309
|
+
__socket.onmessage = function(event) {
|
|
310
|
+
const { err, type, queryId, data } = import_jjs.default.parse(event.data);
|
|
311
|
+
if (queryId) {
|
|
312
|
+
if (waitingOn[queryId]) {
|
|
313
|
+
waitingOn[queryId](err, data);
|
|
314
|
+
delete waitingOn[queryId];
|
|
315
|
+
} else {
|
|
316
|
+
console.error(`\u{1F98D} No matching queryId: ${queryId}`);
|
|
317
|
+
}
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (ofTypesOb[type]) {
|
|
321
|
+
ofTypesOb[type].forEach((worker) => worker({ err, type, data }));
|
|
322
|
+
}
|
|
323
|
+
reciverOnAr.forEach((worker) => worker({ err, type, data }));
|
|
324
|
+
};
|
|
325
|
+
__socket.onerror = function(err) {
|
|
326
|
+
console.error("socket ERROR:", err);
|
|
327
|
+
};
|
|
328
|
+
__socket.onclose = function(event) {
|
|
329
|
+
console.warn("socket disconnect:", event);
|
|
330
|
+
__socket = false;
|
|
331
|
+
ready = false;
|
|
332
|
+
setTimeout(() => reconnect && connectSocket(), 500);
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
wsSend = function(type, data, createdAt, dirctCall) {
|
|
336
|
+
let rej, promiseIsLive = false;
|
|
337
|
+
const timeLetForReqToBeMade = createdAt + totalRequestTimeout - Date.now();
|
|
338
|
+
const timer = setTimeout(() => {
|
|
339
|
+
if (promiseIsLive) {
|
|
340
|
+
rej(new Error("Request Timedout for :" + type));
|
|
341
|
+
}
|
|
342
|
+
}, timeLetForReqToBeMade);
|
|
343
|
+
const payload = {
|
|
344
|
+
type,
|
|
345
|
+
data,
|
|
346
|
+
//referer:window.location.href,
|
|
347
|
+
createdAt: new Date(createdAt),
|
|
348
|
+
requestedAt: dirctCall ? void 0 : /* @__PURE__ */ new Date()
|
|
349
|
+
};
|
|
350
|
+
const message = import_jjs.default.stringify(payload);
|
|
351
|
+
const queryId = (0, import_messageHash.default)(message);
|
|
352
|
+
const replyPromise = new Promise((resolve, reject) => {
|
|
353
|
+
rej = reject;
|
|
354
|
+
waitingOn[queryId] = (err2, result) => {
|
|
355
|
+
clearTimeout(timer);
|
|
356
|
+
replyPromise.then = next.bind(replyPromise);
|
|
357
|
+
if (err2) {
|
|
358
|
+
reject(err2);
|
|
359
|
+
} else {
|
|
360
|
+
resolve(result);
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
__socket.send(message);
|
|
364
|
+
});
|
|
365
|
+
const next = replyPromise.then;
|
|
366
|
+
replyPromise.then = (worker) => {
|
|
367
|
+
promiseIsLive = true;
|
|
368
|
+
replyPromise.then = next.bind(replyPromise);
|
|
369
|
+
replyPromise.catch = err.bind(replyPromise);
|
|
370
|
+
return next.call(replyPromise, worker);
|
|
371
|
+
};
|
|
372
|
+
const err = replyPromise.catch;
|
|
373
|
+
replyPromise.catch = (worker) => {
|
|
374
|
+
promiseIsLive = true;
|
|
375
|
+
replyPromise.catch = err.bind(replyPromise);
|
|
376
|
+
replyPromise.then = next.bind(replyPromise);
|
|
377
|
+
return err.call(replyPromise, worker);
|
|
378
|
+
};
|
|
379
|
+
return replyPromise;
|
|
380
|
+
};
|
|
381
|
+
const sender2 = (type, data) => {
|
|
382
|
+
if ("string" !== typeof type) {
|
|
383
|
+
throw new Error("Missing Path vaule");
|
|
384
|
+
}
|
|
385
|
+
const createdAt = Date.now();
|
|
386
|
+
if (ready) {
|
|
387
|
+
return wsSend(type, data, createdAt, true);
|
|
388
|
+
}
|
|
389
|
+
const timeLetForReqToBeMade = createdAt + connentTimeout - Date.now();
|
|
390
|
+
const timer = setTimeout(() => {
|
|
391
|
+
const errMessage = "Request not sent for :" + type;
|
|
392
|
+
if (payload.waiting) {
|
|
393
|
+
payload.err(new Error(errMessage));
|
|
394
|
+
} else {
|
|
395
|
+
throw new Error(errMessage);
|
|
396
|
+
}
|
|
397
|
+
}, timeLetForReqToBeMade);
|
|
398
|
+
const payload = { type, data, next: void 0, err: void 0, waiting: false, createdAt, timer };
|
|
399
|
+
const waitingOnOpen = new Promise((res, er) => {
|
|
400
|
+
payload.next = res;
|
|
401
|
+
payload.err = er;
|
|
402
|
+
});
|
|
403
|
+
const waitingOnOpenThen = waitingOnOpen.then;
|
|
404
|
+
const waitingOnOpenCatch = waitingOnOpen.catch;
|
|
405
|
+
waitingOnOpen.then = (worker) => {
|
|
406
|
+
payload.waiting = true;
|
|
407
|
+
waitingOnOpen.then = waitingOnOpenThen.bind(waitingOnOpen);
|
|
408
|
+
waitingOnOpen.catch = waitingOnOpenCatch.bind(waitingOnOpen);
|
|
409
|
+
return waitingOnOpenThen.call(waitingOnOpen, worker);
|
|
410
|
+
};
|
|
411
|
+
waitingOnOpen.catch = (worker) => {
|
|
412
|
+
payload.waiting = true;
|
|
413
|
+
waitingOnOpen.catch = waitingOnOpenCatch.bind(waitingOnOpen);
|
|
414
|
+
waitingOnOpen.then = waitingOnOpenThen.bind(waitingOnOpen);
|
|
415
|
+
return waitingOnOpenCatch.call(waitingOnOpen, worker);
|
|
416
|
+
};
|
|
417
|
+
aWaitingSend.push(payload);
|
|
418
|
+
if (!__socket) {
|
|
419
|
+
connectSocket();
|
|
420
|
+
}
|
|
421
|
+
return waitingOnOpen;
|
|
422
|
+
};
|
|
423
|
+
return {
|
|
424
|
+
sender: wrap(sender2),
|
|
425
|
+
setOnReciver: (onTypeStFn, handlerFn) => {
|
|
426
|
+
if ("string" === typeof onTypeStFn) {
|
|
427
|
+
ofTypesOb[onTypeStFn] = [handlerFn];
|
|
428
|
+
} else {
|
|
429
|
+
if (!reciverOnAr.includes(onTypeStFn)) {
|
|
430
|
+
reciverOnAr.push(onTypeStFn);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
// END setOnReciver
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
connectSocket.autoReconnect = () => reconnect = true;
|
|
438
|
+
connectSocket.configure = configure;
|
|
439
|
+
connect = connectSocket;
|
|
440
|
+
var connectSocket_default = connect;
|
|
441
|
+
|
|
442
|
+
// client/browser.js
|
|
443
|
+
var port = window.location.port || (window.location.protocol === "https:" ? 443 : 80);
|
|
444
|
+
connectSocket_default.configure({ port: parseInt(port, 10) });
|
|
445
|
+
var { sender, setOnReciver } = connectSocket_default();
|
|
446
|
+
connectSocket_default.autoReconnect();
|
|
447
|
+
window.ape = sender;
|
|
448
|
+
Object.defineProperty(window.ape, "on", {
|
|
449
|
+
value: setOnReciver,
|
|
450
|
+
writable: false,
|
|
451
|
+
enumerable: false,
|
|
452
|
+
configurable: false
|
|
453
|
+
});
|
|
454
|
+
})();
|