@jetezra/bridge 0.0.1 → 0.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/CHANGELOG.md +16 -0
- package/README.md +410 -97
- package/dist/chooga-bridge.cjs +311 -20
- package/dist/chooga-bridge.cjs.map +2 -2
- package/dist/chooga-bridge.d.ts +44 -11
- package/dist/chooga-bridge.min.js +1 -1
- package/dist/chooga-bridge.min.js.map +3 -3
- package/dist/chooga-bridge.mjs +311 -20
- package/dist/chooga-bridge.mjs.map +2 -2
- package/package.json +3 -2
package/dist/chooga-bridge.mjs
CHANGED
|
@@ -12,6 +12,8 @@ var BRIDGE = {
|
|
|
12
12
|
CALL_RESULT: "chooga.callResult",
|
|
13
13
|
EVENT: "chooga.event",
|
|
14
14
|
HOST_INFO: "chooga.hostInfo",
|
|
15
|
+
/** Open bag of host-defined fields for getState() / subscribe. */
|
|
16
|
+
PARAMS: "chooga.params",
|
|
15
17
|
// Mini-app → host
|
|
16
18
|
READY: "chooga.ready",
|
|
17
19
|
CLOSE: "chooga.close",
|
|
@@ -27,7 +29,22 @@ var BRIDGE = {
|
|
|
27
29
|
HOST_INFO_GET: "chooga.hostInfo.get",
|
|
28
30
|
CALL: "chooga.call"
|
|
29
31
|
};
|
|
30
|
-
var BRIDGE_VERSION = "
|
|
32
|
+
var BRIDGE_VERSION = "0.0.2";
|
|
33
|
+
var RESERVED_STATE_KEYS = /* @__PURE__ */ new Set([
|
|
34
|
+
"hostConnected",
|
|
35
|
+
"readySent",
|
|
36
|
+
"session",
|
|
37
|
+
"user",
|
|
38
|
+
"theme",
|
|
39
|
+
"safeArea",
|
|
40
|
+
"hostInfo",
|
|
41
|
+
"params",
|
|
42
|
+
"lastCapability",
|
|
43
|
+
"lastPayment",
|
|
44
|
+
"lastActivity",
|
|
45
|
+
"lastEvent",
|
|
46
|
+
"lastMessage"
|
|
47
|
+
]);
|
|
31
48
|
var state = {
|
|
32
49
|
hostConnected: false,
|
|
33
50
|
readySent: false,
|
|
@@ -36,6 +53,8 @@ var state = {
|
|
|
36
53
|
theme: null,
|
|
37
54
|
safeArea: null,
|
|
38
55
|
hostInfo: null,
|
|
56
|
+
/** Host-defined open bag — any keys the host wants the mini-app to see. */
|
|
57
|
+
params: {},
|
|
39
58
|
lastCapability: null,
|
|
40
59
|
lastPayment: null,
|
|
41
60
|
lastActivity: null,
|
|
@@ -47,12 +66,52 @@ var eventHandlers = /* @__PURE__ */ new Map();
|
|
|
47
66
|
var pending = /* @__PURE__ */ new Map();
|
|
48
67
|
var requestSeq = 0;
|
|
49
68
|
var initialized = false;
|
|
69
|
+
var debugEnabled = false;
|
|
70
|
+
var allowedOrigins = null;
|
|
71
|
+
var mockHostActive = false;
|
|
50
72
|
function nextRequestId() {
|
|
51
73
|
requestSeq += 1;
|
|
52
74
|
return `cb_${Date.now().toString(36)}_${requestSeq}`;
|
|
53
75
|
}
|
|
76
|
+
function logDebug(direction, payload) {
|
|
77
|
+
if (!debugEnabled) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const label = direction === "out" ? "[ChoogaBridge \u2192 host]" : "[ChoogaBridge \u2190 host]";
|
|
81
|
+
try {
|
|
82
|
+
console.log(label, payload);
|
|
83
|
+
} catch (_) {
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function logWarn(message, detail) {
|
|
87
|
+
if (!debugEnabled) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
console.warn("[ChoogaBridge]", message, detail);
|
|
92
|
+
} catch (_) {
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function applyHostParams(msg) {
|
|
96
|
+
const { type: _t, replace, params: nested, ...rest } = msg || {};
|
|
97
|
+
const incoming = nested && typeof nested === "object" && !Array.isArray(nested) ? { ...nested } : { ...rest };
|
|
98
|
+
if (replace) {
|
|
99
|
+
state.params = incoming;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const next = { ...state.params };
|
|
103
|
+
Object.keys(incoming).forEach((key) => {
|
|
104
|
+
if (incoming[key] === null) {
|
|
105
|
+
delete next[key];
|
|
106
|
+
} else {
|
|
107
|
+
next[key] = incoming[key];
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
state.params = next;
|
|
111
|
+
}
|
|
54
112
|
function getState() {
|
|
55
|
-
|
|
113
|
+
const params = { ...state.params };
|
|
114
|
+
const known = {
|
|
56
115
|
hostConnected: state.hostConnected,
|
|
57
116
|
readySent: state.readySent,
|
|
58
117
|
session: state.session,
|
|
@@ -60,12 +119,20 @@ function getState() {
|
|
|
60
119
|
theme: state.theme,
|
|
61
120
|
safeArea: state.safeArea,
|
|
62
121
|
hostInfo: state.hostInfo,
|
|
122
|
+
params,
|
|
63
123
|
lastCapability: state.lastCapability,
|
|
64
124
|
lastPayment: state.lastPayment,
|
|
65
125
|
lastActivity: state.lastActivity,
|
|
66
126
|
lastEvent: state.lastEvent,
|
|
67
127
|
lastMessage: state.lastMessage
|
|
68
128
|
};
|
|
129
|
+
const extras = {};
|
|
130
|
+
Object.keys(params).forEach((key) => {
|
|
131
|
+
if (!RESERVED_STATE_KEYS.has(key)) {
|
|
132
|
+
extras[key] = params[key];
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
return { ...extras, ...known };
|
|
69
136
|
}
|
|
70
137
|
function notify() {
|
|
71
138
|
const snapshot = getState();
|
|
@@ -98,6 +165,9 @@ function emitLocalEvent(name, detail) {
|
|
|
98
165
|
}
|
|
99
166
|
}
|
|
100
167
|
function detectHost() {
|
|
168
|
+
if (mockHostActive) {
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
101
171
|
return !!(typeof window !== "undefined" && window.ReactNativeWebView && typeof window.ReactNativeWebView.postMessage === "function");
|
|
102
172
|
}
|
|
103
173
|
function ensureChoogaHostShim() {
|
|
@@ -123,6 +193,7 @@ function ensureChoogaHostShim() {
|
|
|
123
193
|
window.ChoogaTheme = window.ChoogaTheme || {};
|
|
124
194
|
}
|
|
125
195
|
function postToHost(msg) {
|
|
196
|
+
logDebug("out", msg);
|
|
126
197
|
ensureChoogaHostShim();
|
|
127
198
|
if (window.ChoogaHost && typeof window.ChoogaHost.postToHost === "function") {
|
|
128
199
|
window.ChoogaHost.postToHost(msg);
|
|
@@ -176,6 +247,7 @@ function trackRequest(options = {}) {
|
|
|
176
247
|
const timer = timeoutMs > 0 ? setTimeout(() => {
|
|
177
248
|
if (pending.has(requestId)) {
|
|
178
249
|
pending.delete(requestId);
|
|
250
|
+
logWarn("request timed out", { requestId, timeoutMs });
|
|
179
251
|
reject(Object.assign(new Error("timeout"), { reason: "timeout" }));
|
|
180
252
|
}
|
|
181
253
|
}, timeoutMs) : null;
|
|
@@ -193,46 +265,76 @@ function handleHostMessage(raw) {
|
|
|
193
265
|
try {
|
|
194
266
|
msg = JSON.parse(raw);
|
|
195
267
|
} catch (_) {
|
|
268
|
+
logWarn("ignored non-JSON host message", raw);
|
|
196
269
|
return;
|
|
197
270
|
}
|
|
198
271
|
}
|
|
199
272
|
if (!msg || typeof msg !== "object" || !msg.type) {
|
|
200
273
|
return;
|
|
201
274
|
}
|
|
275
|
+
logDebug("in", msg);
|
|
202
276
|
state.hostConnected = true;
|
|
203
277
|
state.lastMessage = msg;
|
|
204
278
|
switch (msg.type) {
|
|
205
|
-
case BRIDGE.SESSION:
|
|
279
|
+
case BRIDGE.SESSION: {
|
|
280
|
+
const { type: _t, ...rest } = msg;
|
|
206
281
|
state.session = {
|
|
207
|
-
|
|
208
|
-
|
|
282
|
+
...rest,
|
|
283
|
+
token: rest.token != null ? rest.token : null,
|
|
284
|
+
expires_at: rest.expires_at != null ? rest.expires_at : null
|
|
209
285
|
};
|
|
210
286
|
break;
|
|
287
|
+
}
|
|
211
288
|
case BRIDGE.USER:
|
|
212
|
-
state.user = msg.user
|
|
289
|
+
state.user = msg.user != null ? msg.user : null;
|
|
290
|
+
if (msg.requestId) {
|
|
291
|
+
settlePending(msg.requestId, { ok: true, user: state.user });
|
|
292
|
+
}
|
|
213
293
|
break;
|
|
214
|
-
case BRIDGE.THEME:
|
|
294
|
+
case BRIDGE.THEME: {
|
|
295
|
+
const { type: _t, ...rest } = msg;
|
|
215
296
|
state.theme = {
|
|
216
|
-
|
|
217
|
-
|
|
297
|
+
...rest,
|
|
298
|
+
mode: rest.mode || "light",
|
|
299
|
+
primary_color: rest.primary_color != null ? rest.primary_color : null
|
|
218
300
|
};
|
|
219
301
|
applyTheme(state.theme);
|
|
220
302
|
break;
|
|
221
|
-
|
|
222
|
-
|
|
303
|
+
}
|
|
304
|
+
case BRIDGE.SAFE_AREA: {
|
|
305
|
+
if (msg.insets != null) {
|
|
306
|
+
state.safeArea = msg.insets;
|
|
307
|
+
} else {
|
|
308
|
+
const { type: _t, ...rest } = msg;
|
|
309
|
+
state.safeArea = Object.keys(rest).length ? rest : null;
|
|
310
|
+
}
|
|
223
311
|
break;
|
|
312
|
+
}
|
|
224
313
|
case BRIDGE.HOST_INFO: {
|
|
225
|
-
const { type: _t, ...rest } = msg;
|
|
314
|
+
const { type: _t, requestId, ...rest } = msg;
|
|
226
315
|
state.hostInfo = rest;
|
|
316
|
+
if (requestId) {
|
|
317
|
+
settlePending(requestId, { ok: true, ...rest });
|
|
318
|
+
}
|
|
227
319
|
break;
|
|
228
320
|
}
|
|
229
|
-
case BRIDGE.
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
321
|
+
case BRIDGE.PARAMS:
|
|
322
|
+
applyHostParams(msg);
|
|
323
|
+
break;
|
|
324
|
+
case BRIDGE.CAPABILITY_RESULT: {
|
|
325
|
+
const { type: _t, requestId, ...rest } = msg;
|
|
326
|
+
const result = {
|
|
327
|
+
...rest,
|
|
328
|
+
key: rest.key,
|
|
329
|
+
granted: !!rest.granted,
|
|
330
|
+
reason: rest.reason != null ? rest.reason : null
|
|
234
331
|
};
|
|
332
|
+
state.lastCapability = result;
|
|
333
|
+
if (requestId) {
|
|
334
|
+
settlePending(requestId, { ok: true, ...result });
|
|
335
|
+
}
|
|
235
336
|
break;
|
|
337
|
+
}
|
|
236
338
|
case BRIDGE.NAVIGATE_RESULT:
|
|
237
339
|
settlePending(msg.requestId, {
|
|
238
340
|
ok: !!msg.ok,
|
|
@@ -260,15 +362,36 @@ function handleHostMessage(raw) {
|
|
|
260
362
|
emitLocalEvent(msg.name, msg.detail || {});
|
|
261
363
|
break;
|
|
262
364
|
default:
|
|
365
|
+
logWarn("unknown host message type", msg.type);
|
|
263
366
|
break;
|
|
264
367
|
}
|
|
265
368
|
notify();
|
|
266
369
|
}
|
|
267
370
|
function onWindowMessage(event) {
|
|
371
|
+
if (allowedOrigins && allowedOrigins.length > 0) {
|
|
372
|
+
const origin = event && event.origin;
|
|
373
|
+
const allowAll = allowedOrigins.indexOf("*") !== -1;
|
|
374
|
+
const isOpaque = origin == null || origin === "" || origin === "null";
|
|
375
|
+
if (!allowAll && !isOpaque && allowedOrigins.indexOf(origin) === -1) {
|
|
376
|
+
logWarn("ignored message from disallowed origin", origin);
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
268
380
|
handleHostMessage(event && event.data);
|
|
269
381
|
}
|
|
382
|
+
function setDebug(enabled) {
|
|
383
|
+
debugEnabled = !!enabled;
|
|
384
|
+
return ChoogaBridge;
|
|
385
|
+
}
|
|
270
386
|
function init(options = {}) {
|
|
387
|
+
if (options.debug != null) {
|
|
388
|
+
debugEnabled = !!options.debug;
|
|
389
|
+
}
|
|
390
|
+
if (options.allowedOrigins != null) {
|
|
391
|
+
allowedOrigins = Array.isArray(options.allowedOrigins) ? options.allowedOrigins.slice() : null;
|
|
392
|
+
}
|
|
271
393
|
if (initialized) {
|
|
394
|
+
logDebug("out", { note: "init() already called \u2014 updated debug/allowedOrigins only" });
|
|
272
395
|
return ChoogaBridge;
|
|
273
396
|
}
|
|
274
397
|
initialized = true;
|
|
@@ -282,12 +405,164 @@ function init(options = {}) {
|
|
|
282
405
|
document.addEventListener("message", onWindowMessage);
|
|
283
406
|
}
|
|
284
407
|
}
|
|
408
|
+
if (debugEnabled) {
|
|
409
|
+
logDebug("out", {
|
|
410
|
+
note: "bridge initialized",
|
|
411
|
+
version: BRIDGE_VERSION,
|
|
412
|
+
hostConnected: state.hostConnected,
|
|
413
|
+
allowedOrigins
|
|
414
|
+
});
|
|
415
|
+
}
|
|
285
416
|
if (options.autoReady !== false) {
|
|
286
417
|
ready();
|
|
287
418
|
}
|
|
288
419
|
notify();
|
|
289
420
|
return ChoogaBridge;
|
|
290
421
|
}
|
|
422
|
+
function mockHost(options = {}) {
|
|
423
|
+
if (typeof window === "undefined") {
|
|
424
|
+
return ChoogaBridge;
|
|
425
|
+
}
|
|
426
|
+
ensureChoogaHostShim();
|
|
427
|
+
mockHostActive = true;
|
|
428
|
+
state.hostConnected = true;
|
|
429
|
+
const delayMs = options.delayMs != null ? options.delayMs : 0;
|
|
430
|
+
const context = options.context || {};
|
|
431
|
+
function reply(msg) {
|
|
432
|
+
const run = () => handleHostMessage(msg);
|
|
433
|
+
if (delayMs > 0) {
|
|
434
|
+
setTimeout(run, delayMs);
|
|
435
|
+
} else {
|
|
436
|
+
run();
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
window.ReactNativeWebView = {
|
|
440
|
+
postMessage(payload) {
|
|
441
|
+
let msg = payload;
|
|
442
|
+
if (typeof payload === "string") {
|
|
443
|
+
try {
|
|
444
|
+
msg = JSON.parse(payload);
|
|
445
|
+
} catch (_) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (!msg || typeof msg !== "object") {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
if (typeof options.onMessage === "function") {
|
|
453
|
+
options.onMessage(msg, reply);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
switch (msg.type) {
|
|
457
|
+
case BRIDGE.READY:
|
|
458
|
+
reply({
|
|
459
|
+
type: BRIDGE.SESSION,
|
|
460
|
+
token: "mock-token",
|
|
461
|
+
expires_at: null,
|
|
462
|
+
...context.session || {}
|
|
463
|
+
});
|
|
464
|
+
reply({
|
|
465
|
+
type: BRIDGE.USER,
|
|
466
|
+
user: context.user || { id: "mock-user", name: "Demo User" }
|
|
467
|
+
});
|
|
468
|
+
reply({
|
|
469
|
+
type: BRIDGE.THEME,
|
|
470
|
+
mode: "light",
|
|
471
|
+
primary_color: null,
|
|
472
|
+
...context.theme || {}
|
|
473
|
+
});
|
|
474
|
+
if (context.params) {
|
|
475
|
+
reply({
|
|
476
|
+
type: BRIDGE.PARAMS,
|
|
477
|
+
replace: true,
|
|
478
|
+
params: context.params
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
reply({
|
|
482
|
+
type: BRIDGE.HOST_INFO,
|
|
483
|
+
version: BRIDGE_VERSION,
|
|
484
|
+
host_version: BRIDGE_VERSION,
|
|
485
|
+
activities: context.activities || ["wallet.pick", "host.confirm"],
|
|
486
|
+
capabilities: context.capabilities || ["payments"],
|
|
487
|
+
granted: context.granted || ["payments"]
|
|
488
|
+
});
|
|
489
|
+
break;
|
|
490
|
+
case BRIDGE.ACTIVITY:
|
|
491
|
+
reply({
|
|
492
|
+
type: BRIDGE.ACTIVITY_RESULT,
|
|
493
|
+
requestId: msg.requestId,
|
|
494
|
+
ok: true,
|
|
495
|
+
name: msg.name,
|
|
496
|
+
mock: true,
|
|
497
|
+
...msg.params || {}
|
|
498
|
+
});
|
|
499
|
+
break;
|
|
500
|
+
case BRIDGE.CALL:
|
|
501
|
+
reply({
|
|
502
|
+
type: BRIDGE.CALL_RESULT,
|
|
503
|
+
requestId: msg.requestId,
|
|
504
|
+
ok: true,
|
|
505
|
+
method: msg.method,
|
|
506
|
+
mock: true,
|
|
507
|
+
...msg.params || {}
|
|
508
|
+
});
|
|
509
|
+
break;
|
|
510
|
+
case BRIDGE.NAVIGATE:
|
|
511
|
+
reply({
|
|
512
|
+
type: BRIDGE.NAVIGATE_RESULT,
|
|
513
|
+
requestId: msg.requestId,
|
|
514
|
+
ok: true,
|
|
515
|
+
reason: null
|
|
516
|
+
});
|
|
517
|
+
break;
|
|
518
|
+
case BRIDGE.USER_GET:
|
|
519
|
+
reply({
|
|
520
|
+
type: BRIDGE.USER,
|
|
521
|
+
requestId: msg.requestId,
|
|
522
|
+
user: context.user || { id: "mock-user", name: "Demo User" }
|
|
523
|
+
});
|
|
524
|
+
break;
|
|
525
|
+
case BRIDGE.HOST_INFO_GET:
|
|
526
|
+
reply({
|
|
527
|
+
type: BRIDGE.HOST_INFO,
|
|
528
|
+
requestId: msg.requestId,
|
|
529
|
+
version: BRIDGE_VERSION,
|
|
530
|
+
host_version: BRIDGE_VERSION,
|
|
531
|
+
activities: context.activities || ["wallet.pick", "host.confirm"],
|
|
532
|
+
capabilities: context.capabilities || ["payments"],
|
|
533
|
+
granted: context.granted || ["payments"]
|
|
534
|
+
});
|
|
535
|
+
break;
|
|
536
|
+
case BRIDGE.REQUEST_CAPABILITY:
|
|
537
|
+
reply({
|
|
538
|
+
type: BRIDGE.CAPABILITY_RESULT,
|
|
539
|
+
requestId: msg.requestId,
|
|
540
|
+
key: msg.key,
|
|
541
|
+
granted: true,
|
|
542
|
+
reason: null
|
|
543
|
+
});
|
|
544
|
+
break;
|
|
545
|
+
case BRIDGE.PAYMENTS_INITIATE:
|
|
546
|
+
if (msg.deliverResult === false) {
|
|
547
|
+
break;
|
|
548
|
+
}
|
|
549
|
+
reply({
|
|
550
|
+
type: BRIDGE.PAYMENTS_RESULT,
|
|
551
|
+
requestId: msg.requestId,
|
|
552
|
+
ok: true,
|
|
553
|
+
status: "succeeded",
|
|
554
|
+
reference: msg.reference || null,
|
|
555
|
+
mock: true
|
|
556
|
+
});
|
|
557
|
+
break;
|
|
558
|
+
default:
|
|
559
|
+
break;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
notify();
|
|
564
|
+
return ChoogaBridge;
|
|
565
|
+
}
|
|
291
566
|
function ready() {
|
|
292
567
|
postToHost({ type: BRIDGE.READY });
|
|
293
568
|
state.readySent = true;
|
|
@@ -299,8 +574,18 @@ function close() {
|
|
|
299
574
|
function openExternal(url) {
|
|
300
575
|
postToHost({ type: BRIDGE.OPEN_EXTERNAL, url });
|
|
301
576
|
}
|
|
302
|
-
function requestCapability(key) {
|
|
303
|
-
|
|
577
|
+
function requestCapability(key, options = {}) {
|
|
578
|
+
const requestId = nextRequestId();
|
|
579
|
+
const promise = trackRequest({
|
|
580
|
+
requestId,
|
|
581
|
+
onResult: options.onResult,
|
|
582
|
+
timeoutMs: options.timeoutMs != null ? options.timeoutMs : 3e4
|
|
583
|
+
});
|
|
584
|
+
postToHost({ type: BRIDGE.REQUEST_CAPABILITY, requestId, key });
|
|
585
|
+
if (!detectHost()) {
|
|
586
|
+
settlePending(requestId, { ok: false, key, granted: false, reason: "no_host" });
|
|
587
|
+
}
|
|
588
|
+
return promise;
|
|
304
589
|
}
|
|
305
590
|
function showProgress(options = {}) {
|
|
306
591
|
const opts = typeof options === "string" ? { message: options } : options || {};
|
|
@@ -418,7 +703,11 @@ function off(name, handler) {
|
|
|
418
703
|
}
|
|
419
704
|
function navigate(options = {}) {
|
|
420
705
|
const requestId = nextRequestId();
|
|
421
|
-
const promise = trackRequest({
|
|
706
|
+
const promise = trackRequest({
|
|
707
|
+
requestId,
|
|
708
|
+
onResult: options.onResult,
|
|
709
|
+
timeoutMs: options.timeoutMs
|
|
710
|
+
});
|
|
422
711
|
postToHost({
|
|
423
712
|
type: BRIDGE.NAVIGATE,
|
|
424
713
|
requestId,
|
|
@@ -501,6 +790,8 @@ var ChoogaBridge = {
|
|
|
501
790
|
BRIDGE,
|
|
502
791
|
BRIDGE_VERSION,
|
|
503
792
|
init,
|
|
793
|
+
setDebug,
|
|
794
|
+
mockHost,
|
|
504
795
|
ready,
|
|
505
796
|
close,
|
|
506
797
|
openExternal,
|