@cloudparse/up-miniapps-sdk 0.6.1 → 0.6.3
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/bin/up-sdk.cjs +3 -1
- package/dist/index.browser.min.js +22 -22
- package/dist/index.browser.min.js.map +1 -1
- package/dist/index.cjs +128 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -26
- package/dist/index.d.ts +54 -26
- package/dist/index.js +135 -95
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -225,35 +225,6 @@ var Bridge = class {
|
|
|
225
225
|
return this.send(type, payload, timeoutMs, retries - 1);
|
|
226
226
|
});
|
|
227
227
|
}
|
|
228
|
-
sendOnce(type, payload, timeoutMs) {
|
|
229
|
-
return new Promise((resolve, reject) => {
|
|
230
|
-
const callbackId = `${type}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
231
|
-
const timeout = setTimeout(() => {
|
|
232
|
-
if (this.callbacks.has(callbackId)) {
|
|
233
|
-
this.callbacks.delete(callbackId);
|
|
234
|
-
reject(new BridgeTimeoutError(`Bridge request timeout: ${type}`));
|
|
235
|
-
}
|
|
236
|
-
}, timeoutMs);
|
|
237
|
-
this.callbacks.set(callbackId, {
|
|
238
|
-
reject,
|
|
239
|
-
resolve,
|
|
240
|
-
timeout
|
|
241
|
-
});
|
|
242
|
-
const message = {
|
|
243
|
-
callbackId,
|
|
244
|
-
payload,
|
|
245
|
-
type
|
|
246
|
-
};
|
|
247
|
-
const win = window;
|
|
248
|
-
if (win.ReactNativeWebView?.postMessage) {
|
|
249
|
-
win.ReactNativeWebView.postMessage(JSON.stringify(message));
|
|
250
|
-
} else {
|
|
251
|
-
clearTimeout(timeout);
|
|
252
|
-
this.callbacks.delete(callbackId);
|
|
253
|
-
reject(new Error("Bridge not available"));
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
228
|
/**
|
|
258
229
|
* Internal handler for all incoming messages from the native shell.
|
|
259
230
|
* Matches incoming payloads to either pending callbacks or event listeners.
|
|
@@ -301,6 +272,35 @@ var Bridge = class {
|
|
|
301
272
|
console.warn(`[Bridge] Mock mode active: Unhandled message type ${type}`);
|
|
302
273
|
return Promise.resolve();
|
|
303
274
|
}
|
|
275
|
+
sendOnce(type, payload, timeoutMs) {
|
|
276
|
+
return new Promise((resolve, reject) => {
|
|
277
|
+
const callbackId = `${type}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
278
|
+
const timeout = setTimeout(() => {
|
|
279
|
+
if (this.callbacks.has(callbackId)) {
|
|
280
|
+
this.callbacks.delete(callbackId);
|
|
281
|
+
reject(new BridgeTimeoutError(`Bridge request timeout: ${type}`));
|
|
282
|
+
}
|
|
283
|
+
}, timeoutMs);
|
|
284
|
+
this.callbacks.set(callbackId, {
|
|
285
|
+
reject,
|
|
286
|
+
resolve,
|
|
287
|
+
timeout
|
|
288
|
+
});
|
|
289
|
+
const message = {
|
|
290
|
+
callbackId,
|
|
291
|
+
payload,
|
|
292
|
+
type
|
|
293
|
+
};
|
|
294
|
+
const win = window;
|
|
295
|
+
if (win.ReactNativeWebView?.postMessage) {
|
|
296
|
+
win.ReactNativeWebView.postMessage(JSON.stringify(message));
|
|
297
|
+
} else {
|
|
298
|
+
clearTimeout(timeout);
|
|
299
|
+
this.callbacks.delete(callbackId);
|
|
300
|
+
reject(new Error("Bridge not available"));
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
304
|
/**
|
|
305
305
|
* Determine environment. Check flag or cache result.
|
|
306
306
|
*/
|
|
@@ -2495,11 +2495,6 @@ var RouteLayer = ({
|
|
|
2495
2495
|
] });
|
|
2496
2496
|
};
|
|
2497
2497
|
|
|
2498
|
-
// src/components/Map/Map.tsx
|
|
2499
|
-
var import_react_maplibre6 = require("@vis.gl/react-maplibre");
|
|
2500
|
-
var import_react12 = __toESM(require("react"), 1);
|
|
2501
|
-
var import_maplibre_gl = require("maplibre-gl/dist/maplibre-gl.css");
|
|
2502
|
-
|
|
2503
2498
|
// src/components/Map/utils/geoCircle.ts
|
|
2504
2499
|
var EARTH_RADIUS_METERS = 6371e3;
|
|
2505
2500
|
var buildGeoCircle = (center, radiusMeters, points = 64) => {
|
|
@@ -2891,6 +2886,9 @@ var UserLocationLayer = ({
|
|
|
2891
2886
|
};
|
|
2892
2887
|
|
|
2893
2888
|
// src/components/Map/Map.tsx
|
|
2889
|
+
var import_react_maplibre6 = require("@vis.gl/react-maplibre");
|
|
2890
|
+
var import_react12 = __toESM(require("react"), 1);
|
|
2891
|
+
var import_maplibre_gl = require("maplibre-gl/dist/maplibre-gl.css");
|
|
2894
2892
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2895
2893
|
var MapInternal = ({
|
|
2896
2894
|
initialViewState = {
|
|
@@ -3426,7 +3424,12 @@ async function generateQrCode(data, options = {}) {
|
|
|
3426
3424
|
const outerPadding = options.outerPadding ?? 32;
|
|
3427
3425
|
const borderRadiusPercent = options.borderRadius ?? DEFAULT_BORDER_RADIUS_PERCENT;
|
|
3428
3426
|
const composed = label ? await composeWithLabel(qrDataUrl, label, size, backgroundColor, color) : qrDataUrl;
|
|
3429
|
-
return finalizeImage(
|
|
3427
|
+
return finalizeImage(
|
|
3428
|
+
composed,
|
|
3429
|
+
outerPadding,
|
|
3430
|
+
borderRadiusPercent,
|
|
3431
|
+
backgroundColor
|
|
3432
|
+
);
|
|
3430
3433
|
}
|
|
3431
3434
|
var blobToDataUrl = (blob) => new Promise((resolve, reject) => {
|
|
3432
3435
|
const reader = new FileReader();
|
|
@@ -3711,7 +3714,7 @@ var RoutingService = {
|
|
|
3711
3714
|
};
|
|
3712
3715
|
|
|
3713
3716
|
// package.json
|
|
3714
|
-
var version = "0.6.
|
|
3717
|
+
var version = "0.6.3";
|
|
3715
3718
|
|
|
3716
3719
|
// src/sdk.ts
|
|
3717
3720
|
function deepFreeze(obj) {
|
|
@@ -3739,6 +3742,28 @@ var MiniAppSDK = class {
|
|
|
3739
3742
|
*/
|
|
3740
3743
|
render: renderMap
|
|
3741
3744
|
});
|
|
3745
|
+
/**
|
|
3746
|
+
* QR code generation — the single source of truth for every Mini-App.
|
|
3747
|
+
* Runs entirely client-side (canvas, no Host Shell round-trip) and returns
|
|
3748
|
+
* a base64 PNG data URI, ready for an `<img src>` or `media.saveImage()`.
|
|
3749
|
+
* Mini-Apps must not reimplement this on their own.
|
|
3750
|
+
*/
|
|
3751
|
+
qrCode = Object.freeze({
|
|
3752
|
+
/**
|
|
3753
|
+
* Decodes a QR code from a static image (base64 data URI or URL) —
|
|
3754
|
+
* e.g. a photo picked via `sdk.media.pickImage()` that already
|
|
3755
|
+
* contains a QR code, as an alternative to the live `<QRScanner>`.
|
|
3756
|
+
* @param imageDataUrl A base64 data URI (e.g. from `sdk.media.pickImage()`).
|
|
3757
|
+
* @returns The decoded string, or `null` if no QR code was found.
|
|
3758
|
+
*/
|
|
3759
|
+
decode: (imageDataUrl) => decodeQrCode(imageDataUrl),
|
|
3760
|
+
/**
|
|
3761
|
+
* @param data The value to encode (e.g. a deep link).
|
|
3762
|
+
* @param options Styling/labeling options — see {@link IGenerateQrCodeOptions}.
|
|
3763
|
+
* @returns A base64 PNG data URI.
|
|
3764
|
+
*/
|
|
3765
|
+
generate: (data, options) => generateQrCode(data, options)
|
|
3766
|
+
});
|
|
3742
3767
|
bridge;
|
|
3743
3768
|
/**
|
|
3744
3769
|
* Local SQLite Storage.
|
|
@@ -3842,28 +3867,6 @@ var MiniAppSDK = class {
|
|
|
3842
3867
|
*/
|
|
3843
3868
|
saveImage: (base64, filename) => this.bridge.send("SAVE_IMAGE", { base64, filename })
|
|
3844
3869
|
});
|
|
3845
|
-
/**
|
|
3846
|
-
* QR code generation — the single source of truth for every Mini-App.
|
|
3847
|
-
* Runs entirely client-side (canvas, no Host Shell round-trip) and returns
|
|
3848
|
-
* a base64 PNG data URI, ready for an `<img src>` or `media.saveImage()`.
|
|
3849
|
-
* Mini-Apps must not reimplement this on their own.
|
|
3850
|
-
*/
|
|
3851
|
-
qrCode = Object.freeze({
|
|
3852
|
-
/**
|
|
3853
|
-
* @param data The value to encode (e.g. a deep link).
|
|
3854
|
-
* @param options Styling/labeling options — see {@link IGenerateQrCodeOptions}.
|
|
3855
|
-
* @returns A base64 PNG data URI.
|
|
3856
|
-
*/
|
|
3857
|
-
generate: (data, options) => generateQrCode(data, options),
|
|
3858
|
-
/**
|
|
3859
|
-
* Decodes a QR code from a static image (base64 data URI or URL) —
|
|
3860
|
-
* e.g. a photo picked via `sdk.media.pickImage()` that already
|
|
3861
|
-
* contains a QR code, as an alternative to the live `<QRScanner>`.
|
|
3862
|
-
* @param imageDataUrl A base64 data URI (e.g. from `sdk.media.pickImage()`).
|
|
3863
|
-
* @returns The decoded string, or `null` if no QR code was found.
|
|
3864
|
-
*/
|
|
3865
|
-
decode: (imageDataUrl) => decodeQrCode(imageDataUrl)
|
|
3866
|
-
});
|
|
3867
3870
|
/**
|
|
3868
3871
|
* Payments integration.
|
|
3869
3872
|
*/
|
|
@@ -4155,6 +4158,40 @@ function getMockAvatarUrl(seed) {
|
|
|
4155
4158
|
const shortSeed = hashToShortSeed(seed);
|
|
4156
4159
|
return `https://api.dicebear.com/10.x/notionists-neutral/png?seed=${shortSeed}&mouth=${AVATAR_MOUTH_VARIANTS}&eyes=${AVATAR_EYES_VARIANTS}&glassesProbability=50`;
|
|
4157
4160
|
}
|
|
4161
|
+
function decodeMockJWTPayload(token) {
|
|
4162
|
+
try {
|
|
4163
|
+
const raw = token.startsWith("Bearer ") ? token.slice(7) : token;
|
|
4164
|
+
const base64Url = raw.split(".")[1];
|
|
4165
|
+
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
|
4166
|
+
const jsonPayload = decodeURIComponent(
|
|
4167
|
+
atob(base64).split("").map((c) => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`).join("")
|
|
4168
|
+
);
|
|
4169
|
+
return JSON.parse(jsonPayload);
|
|
4170
|
+
} catch {
|
|
4171
|
+
return null;
|
|
4172
|
+
}
|
|
4173
|
+
}
|
|
4174
|
+
function buildMockProfile(mockJWTToken) {
|
|
4175
|
+
const claims = mockJWTToken ? decodeMockJWTPayload(mockJWTToken) : null;
|
|
4176
|
+
const uuid = claims?.sub || "mock-user-42";
|
|
4177
|
+
const fullName = claims?.name || claims?.username || "Smart Caveman";
|
|
4178
|
+
const username = claims?.username || "smart_caveman";
|
|
4179
|
+
const [firstName, ...lastNameParts] = fullName.split(" ");
|
|
4180
|
+
return {
|
|
4181
|
+
admin: true,
|
|
4182
|
+
countryCode: "FR",
|
|
4183
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4184
|
+
email: "caveman@up.app",
|
|
4185
|
+
firstName: firstName || "Smart",
|
|
4186
|
+
fullName,
|
|
4187
|
+
lastName: lastNameParts.join(" ") || "Caveman",
|
|
4188
|
+
localNumber: "0600000000",
|
|
4189
|
+
ups: 100,
|
|
4190
|
+
username,
|
|
4191
|
+
uuid,
|
|
4192
|
+
xp: 500
|
|
4193
|
+
};
|
|
4194
|
+
}
|
|
4158
4195
|
var getBearing = (p1, p2) => {
|
|
4159
4196
|
const lat1 = p1[1] * Math.PI / 180;
|
|
4160
4197
|
const lat2 = p2[1] * Math.PI / 180;
|
|
@@ -4386,20 +4423,7 @@ var BridgeMocker = ({
|
|
|
4386
4423
|
insets: { bottom: 0, left: 0, right: 0, top: 0 },
|
|
4387
4424
|
name: "Vite Dev (Mock)",
|
|
4388
4425
|
params: {},
|
|
4389
|
-
profile:
|
|
4390
|
-
admin: true,
|
|
4391
|
-
countryCode: "FR",
|
|
4392
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4393
|
-
email: "caveman@up.app",
|
|
4394
|
-
firstName: "Smart",
|
|
4395
|
-
fullName: "Smart Caveman",
|
|
4396
|
-
lastName: "Caveman",
|
|
4397
|
-
localNumber: "0600000000",
|
|
4398
|
-
ups: 100,
|
|
4399
|
-
username: "smart_caveman",
|
|
4400
|
-
uuid: "mock-user-42",
|
|
4401
|
-
xp: 500
|
|
4402
|
-
},
|
|
4426
|
+
profile: buildMockProfile(stateRef.current.mockJWTToken),
|
|
4403
4427
|
success: true,
|
|
4404
4428
|
userData: {},
|
|
4405
4429
|
uuid: appId || "mock-app-id",
|
|
@@ -4440,20 +4464,7 @@ var BridgeMocker = ({
|
|
|
4440
4464
|
return Promise.resolve();
|
|
4441
4465
|
}
|
|
4442
4466
|
if (type === "GET_USER_PROFILE") {
|
|
4443
|
-
return Promise.resolve(
|
|
4444
|
-
admin: true,
|
|
4445
|
-
countryCode: "FR",
|
|
4446
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4447
|
-
email: "caveman@up.app",
|
|
4448
|
-
firstName: "Smart",
|
|
4449
|
-
fullName: "Smart Caveman",
|
|
4450
|
-
lastName: "Caveman",
|
|
4451
|
-
localNumber: "0600000000",
|
|
4452
|
-
ups: 100,
|
|
4453
|
-
username: "smart_caveman",
|
|
4454
|
-
uuid: "mock-user-42",
|
|
4455
|
-
xp: 500
|
|
4456
|
-
});
|
|
4467
|
+
return Promise.resolve(buildMockProfile(stateRef.current.mockJWTToken));
|
|
4457
4468
|
}
|
|
4458
4469
|
if (type === "GET_PROFILE_PICTURE") {
|
|
4459
4470
|
const uuids = payload?.uuids || [];
|
|
@@ -5377,6 +5388,13 @@ function createWsService(options) {
|
|
|
5377
5388
|
let reconnectTimeout = null;
|
|
5378
5389
|
let reconnectDelay = 1e3;
|
|
5379
5390
|
let isConnecting = false;
|
|
5391
|
+
let status = "closed";
|
|
5392
|
+
const statusListeners = /* @__PURE__ */ new Set();
|
|
5393
|
+
const setStatus = (next) => {
|
|
5394
|
+
if (status === next) return;
|
|
5395
|
+
status = next;
|
|
5396
|
+
for (const cb of statusListeners) cb(status);
|
|
5397
|
+
};
|
|
5380
5398
|
const getWsUrl = () => options.baseUrl || options.api.wsUrl || "";
|
|
5381
5399
|
const sendAction = (action, channelId) => {
|
|
5382
5400
|
if (ws?.readyState === WebSocket.OPEN) {
|
|
@@ -5395,6 +5413,7 @@ function createWsService(options) {
|
|
|
5395
5413
|
return;
|
|
5396
5414
|
}
|
|
5397
5415
|
isConnecting = true;
|
|
5416
|
+
setStatus("connecting");
|
|
5398
5417
|
try {
|
|
5399
5418
|
const wsUrl = getWsUrl();
|
|
5400
5419
|
if (!wsUrl) {
|
|
@@ -5402,6 +5421,7 @@ function createWsService(options) {
|
|
|
5402
5421
|
"[WS] No WebSocket backend URL available, connection delayed."
|
|
5403
5422
|
);
|
|
5404
5423
|
isConnecting = false;
|
|
5424
|
+
setStatus("closed");
|
|
5405
5425
|
return;
|
|
5406
5426
|
}
|
|
5407
5427
|
let authParams = {};
|
|
@@ -5417,6 +5437,7 @@ function createWsService(options) {
|
|
|
5417
5437
|
} else {
|
|
5418
5438
|
console.warn("[WS] No auth available, connection delayed.");
|
|
5419
5439
|
isConnecting = false;
|
|
5440
|
+
setStatus("closed");
|
|
5420
5441
|
return;
|
|
5421
5442
|
}
|
|
5422
5443
|
const params = new URLSearchParams({ ...options.query, ...authParams });
|
|
@@ -5424,6 +5445,7 @@ function createWsService(options) {
|
|
|
5424
5445
|
ws = new WebSocket(query ? `${wsUrl}?${query}` : wsUrl);
|
|
5425
5446
|
ws.onopen = () => {
|
|
5426
5447
|
isConnecting = false;
|
|
5448
|
+
setStatus("open");
|
|
5427
5449
|
reconnectDelay = 1e3;
|
|
5428
5450
|
if (channelField) {
|
|
5429
5451
|
for (const channelId of subscriptions.keys()) {
|
|
@@ -5450,6 +5472,7 @@ function createWsService(options) {
|
|
|
5450
5472
|
};
|
|
5451
5473
|
ws.onclose = () => {
|
|
5452
5474
|
isConnecting = false;
|
|
5475
|
+
setStatus("closed");
|
|
5453
5476
|
scheduleReconnect();
|
|
5454
5477
|
};
|
|
5455
5478
|
ws.onerror = (err) => {
|
|
@@ -5460,6 +5483,7 @@ function createWsService(options) {
|
|
|
5460
5483
|
} catch (err) {
|
|
5461
5484
|
console.error("[WS] Failed to establish connection:", err);
|
|
5462
5485
|
isConnecting = false;
|
|
5486
|
+
setStatus("closed");
|
|
5463
5487
|
scheduleReconnect();
|
|
5464
5488
|
}
|
|
5465
5489
|
};
|
|
@@ -5473,6 +5497,15 @@ function createWsService(options) {
|
|
|
5473
5497
|
ws.close();
|
|
5474
5498
|
ws = null;
|
|
5475
5499
|
}
|
|
5500
|
+
setStatus("closed");
|
|
5501
|
+
};
|
|
5502
|
+
const getStatus = () => status;
|
|
5503
|
+
const onStatusChange = (callback) => {
|
|
5504
|
+
statusListeners.add(callback);
|
|
5505
|
+
callback(status);
|
|
5506
|
+
return () => {
|
|
5507
|
+
statusListeners.delete(callback);
|
|
5508
|
+
};
|
|
5476
5509
|
};
|
|
5477
5510
|
const subscribe = (channelId, callback) => {
|
|
5478
5511
|
const isNewChannel = !subscriptions.has(channelId);
|
|
@@ -5498,9 +5531,16 @@ function createWsService(options) {
|
|
|
5498
5531
|
};
|
|
5499
5532
|
};
|
|
5500
5533
|
if (channelField) {
|
|
5501
|
-
return {
|
|
5534
|
+
return {
|
|
5535
|
+
connect,
|
|
5536
|
+
disconnect,
|
|
5537
|
+
getStatus,
|
|
5538
|
+
onMessage,
|
|
5539
|
+
onStatusChange,
|
|
5540
|
+
subscribe
|
|
5541
|
+
};
|
|
5502
5542
|
}
|
|
5503
|
-
return { connect, disconnect, onMessage };
|
|
5543
|
+
return { connect, disconnect, getStatus, onMessage, onStatusChange };
|
|
5504
5544
|
}
|
|
5505
5545
|
|
|
5506
5546
|
// src/index.ts
|