@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.cjs
CHANGED
|
@@ -38,6 +38,8 @@ var BRIDGE = {
|
|
|
38
38
|
CALL_RESULT: "chooga.callResult",
|
|
39
39
|
EVENT: "chooga.event",
|
|
40
40
|
HOST_INFO: "chooga.hostInfo",
|
|
41
|
+
/** Open bag of host-defined fields for getState() / subscribe. */
|
|
42
|
+
PARAMS: "chooga.params",
|
|
41
43
|
// Mini-app → host
|
|
42
44
|
READY: "chooga.ready",
|
|
43
45
|
CLOSE: "chooga.close",
|
|
@@ -53,7 +55,22 @@ var BRIDGE = {
|
|
|
53
55
|
HOST_INFO_GET: "chooga.hostInfo.get",
|
|
54
56
|
CALL: "chooga.call"
|
|
55
57
|
};
|
|
56
|
-
var BRIDGE_VERSION = "
|
|
58
|
+
var BRIDGE_VERSION = "0.0.2";
|
|
59
|
+
var RESERVED_STATE_KEYS = /* @__PURE__ */ new Set([
|
|
60
|
+
"hostConnected",
|
|
61
|
+
"readySent",
|
|
62
|
+
"session",
|
|
63
|
+
"user",
|
|
64
|
+
"theme",
|
|
65
|
+
"safeArea",
|
|
66
|
+
"hostInfo",
|
|
67
|
+
"params",
|
|
68
|
+
"lastCapability",
|
|
69
|
+
"lastPayment",
|
|
70
|
+
"lastActivity",
|
|
71
|
+
"lastEvent",
|
|
72
|
+
"lastMessage"
|
|
73
|
+
]);
|
|
57
74
|
var state = {
|
|
58
75
|
hostConnected: false,
|
|
59
76
|
readySent: false,
|
|
@@ -62,6 +79,8 @@ var state = {
|
|
|
62
79
|
theme: null,
|
|
63
80
|
safeArea: null,
|
|
64
81
|
hostInfo: null,
|
|
82
|
+
/** Host-defined open bag — any keys the host wants the mini-app to see. */
|
|
83
|
+
params: {},
|
|
65
84
|
lastCapability: null,
|
|
66
85
|
lastPayment: null,
|
|
67
86
|
lastActivity: null,
|
|
@@ -73,12 +92,52 @@ var eventHandlers = /* @__PURE__ */ new Map();
|
|
|
73
92
|
var pending = /* @__PURE__ */ new Map();
|
|
74
93
|
var requestSeq = 0;
|
|
75
94
|
var initialized = false;
|
|
95
|
+
var debugEnabled = false;
|
|
96
|
+
var allowedOrigins = null;
|
|
97
|
+
var mockHostActive = false;
|
|
76
98
|
function nextRequestId() {
|
|
77
99
|
requestSeq += 1;
|
|
78
100
|
return `cb_${Date.now().toString(36)}_${requestSeq}`;
|
|
79
101
|
}
|
|
102
|
+
function logDebug(direction, payload) {
|
|
103
|
+
if (!debugEnabled) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const label = direction === "out" ? "[ChoogaBridge \u2192 host]" : "[ChoogaBridge \u2190 host]";
|
|
107
|
+
try {
|
|
108
|
+
console.log(label, payload);
|
|
109
|
+
} catch (_) {
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function logWarn(message, detail) {
|
|
113
|
+
if (!debugEnabled) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
console.warn("[ChoogaBridge]", message, detail);
|
|
118
|
+
} catch (_) {
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function applyHostParams(msg) {
|
|
122
|
+
const { type: _t, replace, params: nested, ...rest } = msg || {};
|
|
123
|
+
const incoming = nested && typeof nested === "object" && !Array.isArray(nested) ? { ...nested } : { ...rest };
|
|
124
|
+
if (replace) {
|
|
125
|
+
state.params = incoming;
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const next = { ...state.params };
|
|
129
|
+
Object.keys(incoming).forEach((key) => {
|
|
130
|
+
if (incoming[key] === null) {
|
|
131
|
+
delete next[key];
|
|
132
|
+
} else {
|
|
133
|
+
next[key] = incoming[key];
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
state.params = next;
|
|
137
|
+
}
|
|
80
138
|
function getState() {
|
|
81
|
-
|
|
139
|
+
const params = { ...state.params };
|
|
140
|
+
const known = {
|
|
82
141
|
hostConnected: state.hostConnected,
|
|
83
142
|
readySent: state.readySent,
|
|
84
143
|
session: state.session,
|
|
@@ -86,12 +145,20 @@ function getState() {
|
|
|
86
145
|
theme: state.theme,
|
|
87
146
|
safeArea: state.safeArea,
|
|
88
147
|
hostInfo: state.hostInfo,
|
|
148
|
+
params,
|
|
89
149
|
lastCapability: state.lastCapability,
|
|
90
150
|
lastPayment: state.lastPayment,
|
|
91
151
|
lastActivity: state.lastActivity,
|
|
92
152
|
lastEvent: state.lastEvent,
|
|
93
153
|
lastMessage: state.lastMessage
|
|
94
154
|
};
|
|
155
|
+
const extras = {};
|
|
156
|
+
Object.keys(params).forEach((key) => {
|
|
157
|
+
if (!RESERVED_STATE_KEYS.has(key)) {
|
|
158
|
+
extras[key] = params[key];
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
return { ...extras, ...known };
|
|
95
162
|
}
|
|
96
163
|
function notify() {
|
|
97
164
|
const snapshot = getState();
|
|
@@ -124,6 +191,9 @@ function emitLocalEvent(name, detail) {
|
|
|
124
191
|
}
|
|
125
192
|
}
|
|
126
193
|
function detectHost() {
|
|
194
|
+
if (mockHostActive) {
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
127
197
|
return !!(typeof window !== "undefined" && window.ReactNativeWebView && typeof window.ReactNativeWebView.postMessage === "function");
|
|
128
198
|
}
|
|
129
199
|
function ensureChoogaHostShim() {
|
|
@@ -149,6 +219,7 @@ function ensureChoogaHostShim() {
|
|
|
149
219
|
window.ChoogaTheme = window.ChoogaTheme || {};
|
|
150
220
|
}
|
|
151
221
|
function postToHost(msg) {
|
|
222
|
+
logDebug("out", msg);
|
|
152
223
|
ensureChoogaHostShim();
|
|
153
224
|
if (window.ChoogaHost && typeof window.ChoogaHost.postToHost === "function") {
|
|
154
225
|
window.ChoogaHost.postToHost(msg);
|
|
@@ -202,6 +273,7 @@ function trackRequest(options = {}) {
|
|
|
202
273
|
const timer = timeoutMs > 0 ? setTimeout(() => {
|
|
203
274
|
if (pending.has(requestId)) {
|
|
204
275
|
pending.delete(requestId);
|
|
276
|
+
logWarn("request timed out", { requestId, timeoutMs });
|
|
205
277
|
reject(Object.assign(new Error("timeout"), { reason: "timeout" }));
|
|
206
278
|
}
|
|
207
279
|
}, timeoutMs) : null;
|
|
@@ -219,46 +291,76 @@ function handleHostMessage(raw) {
|
|
|
219
291
|
try {
|
|
220
292
|
msg = JSON.parse(raw);
|
|
221
293
|
} catch (_) {
|
|
294
|
+
logWarn("ignored non-JSON host message", raw);
|
|
222
295
|
return;
|
|
223
296
|
}
|
|
224
297
|
}
|
|
225
298
|
if (!msg || typeof msg !== "object" || !msg.type) {
|
|
226
299
|
return;
|
|
227
300
|
}
|
|
301
|
+
logDebug("in", msg);
|
|
228
302
|
state.hostConnected = true;
|
|
229
303
|
state.lastMessage = msg;
|
|
230
304
|
switch (msg.type) {
|
|
231
|
-
case BRIDGE.SESSION:
|
|
305
|
+
case BRIDGE.SESSION: {
|
|
306
|
+
const { type: _t, ...rest } = msg;
|
|
232
307
|
state.session = {
|
|
233
|
-
|
|
234
|
-
|
|
308
|
+
...rest,
|
|
309
|
+
token: rest.token != null ? rest.token : null,
|
|
310
|
+
expires_at: rest.expires_at != null ? rest.expires_at : null
|
|
235
311
|
};
|
|
236
312
|
break;
|
|
313
|
+
}
|
|
237
314
|
case BRIDGE.USER:
|
|
238
|
-
state.user = msg.user
|
|
315
|
+
state.user = msg.user != null ? msg.user : null;
|
|
316
|
+
if (msg.requestId) {
|
|
317
|
+
settlePending(msg.requestId, { ok: true, user: state.user });
|
|
318
|
+
}
|
|
239
319
|
break;
|
|
240
|
-
case BRIDGE.THEME:
|
|
320
|
+
case BRIDGE.THEME: {
|
|
321
|
+
const { type: _t, ...rest } = msg;
|
|
241
322
|
state.theme = {
|
|
242
|
-
|
|
243
|
-
|
|
323
|
+
...rest,
|
|
324
|
+
mode: rest.mode || "light",
|
|
325
|
+
primary_color: rest.primary_color != null ? rest.primary_color : null
|
|
244
326
|
};
|
|
245
327
|
applyTheme(state.theme);
|
|
246
328
|
break;
|
|
247
|
-
|
|
248
|
-
|
|
329
|
+
}
|
|
330
|
+
case BRIDGE.SAFE_AREA: {
|
|
331
|
+
if (msg.insets != null) {
|
|
332
|
+
state.safeArea = msg.insets;
|
|
333
|
+
} else {
|
|
334
|
+
const { type: _t, ...rest } = msg;
|
|
335
|
+
state.safeArea = Object.keys(rest).length ? rest : null;
|
|
336
|
+
}
|
|
249
337
|
break;
|
|
338
|
+
}
|
|
250
339
|
case BRIDGE.HOST_INFO: {
|
|
251
|
-
const { type: _t, ...rest } = msg;
|
|
340
|
+
const { type: _t, requestId, ...rest } = msg;
|
|
252
341
|
state.hostInfo = rest;
|
|
342
|
+
if (requestId) {
|
|
343
|
+
settlePending(requestId, { ok: true, ...rest });
|
|
344
|
+
}
|
|
253
345
|
break;
|
|
254
346
|
}
|
|
255
|
-
case BRIDGE.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
347
|
+
case BRIDGE.PARAMS:
|
|
348
|
+
applyHostParams(msg);
|
|
349
|
+
break;
|
|
350
|
+
case BRIDGE.CAPABILITY_RESULT: {
|
|
351
|
+
const { type: _t, requestId, ...rest } = msg;
|
|
352
|
+
const result = {
|
|
353
|
+
...rest,
|
|
354
|
+
key: rest.key,
|
|
355
|
+
granted: !!rest.granted,
|
|
356
|
+
reason: rest.reason != null ? rest.reason : null
|
|
260
357
|
};
|
|
358
|
+
state.lastCapability = result;
|
|
359
|
+
if (requestId) {
|
|
360
|
+
settlePending(requestId, { ok: true, ...result });
|
|
361
|
+
}
|
|
261
362
|
break;
|
|
363
|
+
}
|
|
262
364
|
case BRIDGE.NAVIGATE_RESULT:
|
|
263
365
|
settlePending(msg.requestId, {
|
|
264
366
|
ok: !!msg.ok,
|
|
@@ -286,15 +388,36 @@ function handleHostMessage(raw) {
|
|
|
286
388
|
emitLocalEvent(msg.name, msg.detail || {});
|
|
287
389
|
break;
|
|
288
390
|
default:
|
|
391
|
+
logWarn("unknown host message type", msg.type);
|
|
289
392
|
break;
|
|
290
393
|
}
|
|
291
394
|
notify();
|
|
292
395
|
}
|
|
293
396
|
function onWindowMessage(event) {
|
|
397
|
+
if (allowedOrigins && allowedOrigins.length > 0) {
|
|
398
|
+
const origin = event && event.origin;
|
|
399
|
+
const allowAll = allowedOrigins.indexOf("*") !== -1;
|
|
400
|
+
const isOpaque = origin == null || origin === "" || origin === "null";
|
|
401
|
+
if (!allowAll && !isOpaque && allowedOrigins.indexOf(origin) === -1) {
|
|
402
|
+
logWarn("ignored message from disallowed origin", origin);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
294
406
|
handleHostMessage(event && event.data);
|
|
295
407
|
}
|
|
408
|
+
function setDebug(enabled) {
|
|
409
|
+
debugEnabled = !!enabled;
|
|
410
|
+
return ChoogaBridge;
|
|
411
|
+
}
|
|
296
412
|
function init(options = {}) {
|
|
413
|
+
if (options.debug != null) {
|
|
414
|
+
debugEnabled = !!options.debug;
|
|
415
|
+
}
|
|
416
|
+
if (options.allowedOrigins != null) {
|
|
417
|
+
allowedOrigins = Array.isArray(options.allowedOrigins) ? options.allowedOrigins.slice() : null;
|
|
418
|
+
}
|
|
297
419
|
if (initialized) {
|
|
420
|
+
logDebug("out", { note: "init() already called \u2014 updated debug/allowedOrigins only" });
|
|
298
421
|
return ChoogaBridge;
|
|
299
422
|
}
|
|
300
423
|
initialized = true;
|
|
@@ -308,12 +431,164 @@ function init(options = {}) {
|
|
|
308
431
|
document.addEventListener("message", onWindowMessage);
|
|
309
432
|
}
|
|
310
433
|
}
|
|
434
|
+
if (debugEnabled) {
|
|
435
|
+
logDebug("out", {
|
|
436
|
+
note: "bridge initialized",
|
|
437
|
+
version: BRIDGE_VERSION,
|
|
438
|
+
hostConnected: state.hostConnected,
|
|
439
|
+
allowedOrigins
|
|
440
|
+
});
|
|
441
|
+
}
|
|
311
442
|
if (options.autoReady !== false) {
|
|
312
443
|
ready();
|
|
313
444
|
}
|
|
314
445
|
notify();
|
|
315
446
|
return ChoogaBridge;
|
|
316
447
|
}
|
|
448
|
+
function mockHost(options = {}) {
|
|
449
|
+
if (typeof window === "undefined") {
|
|
450
|
+
return ChoogaBridge;
|
|
451
|
+
}
|
|
452
|
+
ensureChoogaHostShim();
|
|
453
|
+
mockHostActive = true;
|
|
454
|
+
state.hostConnected = true;
|
|
455
|
+
const delayMs = options.delayMs != null ? options.delayMs : 0;
|
|
456
|
+
const context = options.context || {};
|
|
457
|
+
function reply(msg) {
|
|
458
|
+
const run = () => handleHostMessage(msg);
|
|
459
|
+
if (delayMs > 0) {
|
|
460
|
+
setTimeout(run, delayMs);
|
|
461
|
+
} else {
|
|
462
|
+
run();
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
window.ReactNativeWebView = {
|
|
466
|
+
postMessage(payload) {
|
|
467
|
+
let msg = payload;
|
|
468
|
+
if (typeof payload === "string") {
|
|
469
|
+
try {
|
|
470
|
+
msg = JSON.parse(payload);
|
|
471
|
+
} catch (_) {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
if (!msg || typeof msg !== "object") {
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
if (typeof options.onMessage === "function") {
|
|
479
|
+
options.onMessage(msg, reply);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
switch (msg.type) {
|
|
483
|
+
case BRIDGE.READY:
|
|
484
|
+
reply({
|
|
485
|
+
type: BRIDGE.SESSION,
|
|
486
|
+
token: "mock-token",
|
|
487
|
+
expires_at: null,
|
|
488
|
+
...context.session || {}
|
|
489
|
+
});
|
|
490
|
+
reply({
|
|
491
|
+
type: BRIDGE.USER,
|
|
492
|
+
user: context.user || { id: "mock-user", name: "Demo User" }
|
|
493
|
+
});
|
|
494
|
+
reply({
|
|
495
|
+
type: BRIDGE.THEME,
|
|
496
|
+
mode: "light",
|
|
497
|
+
primary_color: null,
|
|
498
|
+
...context.theme || {}
|
|
499
|
+
});
|
|
500
|
+
if (context.params) {
|
|
501
|
+
reply({
|
|
502
|
+
type: BRIDGE.PARAMS,
|
|
503
|
+
replace: true,
|
|
504
|
+
params: context.params
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
reply({
|
|
508
|
+
type: BRIDGE.HOST_INFO,
|
|
509
|
+
version: BRIDGE_VERSION,
|
|
510
|
+
host_version: BRIDGE_VERSION,
|
|
511
|
+
activities: context.activities || ["wallet.pick", "host.confirm"],
|
|
512
|
+
capabilities: context.capabilities || ["payments"],
|
|
513
|
+
granted: context.granted || ["payments"]
|
|
514
|
+
});
|
|
515
|
+
break;
|
|
516
|
+
case BRIDGE.ACTIVITY:
|
|
517
|
+
reply({
|
|
518
|
+
type: BRIDGE.ACTIVITY_RESULT,
|
|
519
|
+
requestId: msg.requestId,
|
|
520
|
+
ok: true,
|
|
521
|
+
name: msg.name,
|
|
522
|
+
mock: true,
|
|
523
|
+
...msg.params || {}
|
|
524
|
+
});
|
|
525
|
+
break;
|
|
526
|
+
case BRIDGE.CALL:
|
|
527
|
+
reply({
|
|
528
|
+
type: BRIDGE.CALL_RESULT,
|
|
529
|
+
requestId: msg.requestId,
|
|
530
|
+
ok: true,
|
|
531
|
+
method: msg.method,
|
|
532
|
+
mock: true,
|
|
533
|
+
...msg.params || {}
|
|
534
|
+
});
|
|
535
|
+
break;
|
|
536
|
+
case BRIDGE.NAVIGATE:
|
|
537
|
+
reply({
|
|
538
|
+
type: BRIDGE.NAVIGATE_RESULT,
|
|
539
|
+
requestId: msg.requestId,
|
|
540
|
+
ok: true,
|
|
541
|
+
reason: null
|
|
542
|
+
});
|
|
543
|
+
break;
|
|
544
|
+
case BRIDGE.USER_GET:
|
|
545
|
+
reply({
|
|
546
|
+
type: BRIDGE.USER,
|
|
547
|
+
requestId: msg.requestId,
|
|
548
|
+
user: context.user || { id: "mock-user", name: "Demo User" }
|
|
549
|
+
});
|
|
550
|
+
break;
|
|
551
|
+
case BRIDGE.HOST_INFO_GET:
|
|
552
|
+
reply({
|
|
553
|
+
type: BRIDGE.HOST_INFO,
|
|
554
|
+
requestId: msg.requestId,
|
|
555
|
+
version: BRIDGE_VERSION,
|
|
556
|
+
host_version: BRIDGE_VERSION,
|
|
557
|
+
activities: context.activities || ["wallet.pick", "host.confirm"],
|
|
558
|
+
capabilities: context.capabilities || ["payments"],
|
|
559
|
+
granted: context.granted || ["payments"]
|
|
560
|
+
});
|
|
561
|
+
break;
|
|
562
|
+
case BRIDGE.REQUEST_CAPABILITY:
|
|
563
|
+
reply({
|
|
564
|
+
type: BRIDGE.CAPABILITY_RESULT,
|
|
565
|
+
requestId: msg.requestId,
|
|
566
|
+
key: msg.key,
|
|
567
|
+
granted: true,
|
|
568
|
+
reason: null
|
|
569
|
+
});
|
|
570
|
+
break;
|
|
571
|
+
case BRIDGE.PAYMENTS_INITIATE:
|
|
572
|
+
if (msg.deliverResult === false) {
|
|
573
|
+
break;
|
|
574
|
+
}
|
|
575
|
+
reply({
|
|
576
|
+
type: BRIDGE.PAYMENTS_RESULT,
|
|
577
|
+
requestId: msg.requestId,
|
|
578
|
+
ok: true,
|
|
579
|
+
status: "succeeded",
|
|
580
|
+
reference: msg.reference || null,
|
|
581
|
+
mock: true
|
|
582
|
+
});
|
|
583
|
+
break;
|
|
584
|
+
default:
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
notify();
|
|
590
|
+
return ChoogaBridge;
|
|
591
|
+
}
|
|
317
592
|
function ready() {
|
|
318
593
|
postToHost({ type: BRIDGE.READY });
|
|
319
594
|
state.readySent = true;
|
|
@@ -325,8 +600,18 @@ function close() {
|
|
|
325
600
|
function openExternal(url) {
|
|
326
601
|
postToHost({ type: BRIDGE.OPEN_EXTERNAL, url });
|
|
327
602
|
}
|
|
328
|
-
function requestCapability(key) {
|
|
329
|
-
|
|
603
|
+
function requestCapability(key, options = {}) {
|
|
604
|
+
const requestId = nextRequestId();
|
|
605
|
+
const promise = trackRequest({
|
|
606
|
+
requestId,
|
|
607
|
+
onResult: options.onResult,
|
|
608
|
+
timeoutMs: options.timeoutMs != null ? options.timeoutMs : 3e4
|
|
609
|
+
});
|
|
610
|
+
postToHost({ type: BRIDGE.REQUEST_CAPABILITY, requestId, key });
|
|
611
|
+
if (!detectHost()) {
|
|
612
|
+
settlePending(requestId, { ok: false, key, granted: false, reason: "no_host" });
|
|
613
|
+
}
|
|
614
|
+
return promise;
|
|
330
615
|
}
|
|
331
616
|
function showProgress(options = {}) {
|
|
332
617
|
const opts = typeof options === "string" ? { message: options } : options || {};
|
|
@@ -444,7 +729,11 @@ function off(name, handler) {
|
|
|
444
729
|
}
|
|
445
730
|
function navigate(options = {}) {
|
|
446
731
|
const requestId = nextRequestId();
|
|
447
|
-
const promise = trackRequest({
|
|
732
|
+
const promise = trackRequest({
|
|
733
|
+
requestId,
|
|
734
|
+
onResult: options.onResult,
|
|
735
|
+
timeoutMs: options.timeoutMs
|
|
736
|
+
});
|
|
448
737
|
postToHost({
|
|
449
738
|
type: BRIDGE.NAVIGATE,
|
|
450
739
|
requestId,
|
|
@@ -527,6 +816,8 @@ var ChoogaBridge = {
|
|
|
527
816
|
BRIDGE,
|
|
528
817
|
BRIDGE_VERSION,
|
|
529
818
|
init,
|
|
819
|
+
setDebug,
|
|
820
|
+
mockHost,
|
|
530
821
|
ready,
|
|
531
822
|
close,
|
|
532
823
|
openExternal,
|