@lo-ink/miniapp-sdk 0.19.0

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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -0
  3. package/dist/adapter.d.ts +15 -0
  4. package/dist/adapter.js +1 -0
  5. package/dist/appearance.d.ts +17 -0
  6. package/dist/appearance.js +59 -0
  7. package/dist/async.d.ts +5 -0
  8. package/dist/async.js +87 -0
  9. package/dist/client.d.ts +17 -0
  10. package/dist/client.js +230 -0
  11. package/dist/errors.d.ts +6 -0
  12. package/dist/errors.js +18 -0
  13. package/dist/features.d.ts +6 -0
  14. package/dist/features.js +41 -0
  15. package/dist/index.d.ts +9 -0
  16. package/dist/index.js +9 -0
  17. package/dist/protocol.d.ts +436 -0
  18. package/dist/protocol.js +43 -0
  19. package/dist/request-options.d.ts +6 -0
  20. package/dist/request-options.js +16 -0
  21. package/dist/session.d.ts +16 -0
  22. package/dist/session.js +56 -0
  23. package/dist/storage.d.ts +25 -0
  24. package/dist/storage.js +27 -0
  25. package/dist-cjs/adapter.d.ts +15 -0
  26. package/dist-cjs/adapter.js +2 -0
  27. package/dist-cjs/appearance.d.ts +17 -0
  28. package/dist-cjs/appearance.js +62 -0
  29. package/dist-cjs/async.d.ts +5 -0
  30. package/dist-cjs/async.js +90 -0
  31. package/dist-cjs/client.d.ts +17 -0
  32. package/dist-cjs/client.js +235 -0
  33. package/dist-cjs/errors.d.ts +6 -0
  34. package/dist-cjs/errors.js +23 -0
  35. package/dist-cjs/features.d.ts +6 -0
  36. package/dist-cjs/features.js +48 -0
  37. package/dist-cjs/index.d.ts +9 -0
  38. package/dist-cjs/index.js +25 -0
  39. package/dist-cjs/package.json +1 -0
  40. package/dist-cjs/protocol.d.ts +436 -0
  41. package/dist-cjs/protocol.js +46 -0
  42. package/dist-cjs/request-options.d.ts +6 -0
  43. package/dist-cjs/request-options.js +19 -0
  44. package/dist-cjs/session.d.ts +16 -0
  45. package/dist-cjs/session.js +59 -0
  46. package/dist-cjs/storage.d.ts +25 -0
  47. package/dist-cjs/storage.js +32 -0
  48. package/package.json +65 -0
@@ -0,0 +1,436 @@
1
+ /** Stable, platform-neutral features a host can advertise. */
2
+ export declare const MINI_APP_CAPABILITIES: readonly ["ready", "expand", "fullscreen", "hideKeyboard", "orientation", "backButton", "mainButton", "secondaryButton", "settingsButton", "closingConfirmation", "headerColor", "backgroundColor", "bottomBarColor", "haptics", "popup", "openLink", "sendData", "switchInlineQuery", "clipboard", "location", "biometry", "sensors", "downloadFile", "qrScanner", "requestWriteAccess", "requestContact", "shareMessage", "shareToStory", "invoice", "cloudStorage", "deviceStorage", "secureStorage"];
3
+ export type Capability = (typeof MINI_APP_CAPABILITIES)[number];
4
+ export declare const MINI_APP_PROTOCOL_VERSION: 1;
5
+ export declare const MINI_APP_LIMITS: Readonly<{
6
+ envelopeBytes: 65536;
7
+ sendDataBytes: 4096;
8
+ inlineQueryLength: 256;
9
+ qrPromptLength: 64;
10
+ preparedMessageIdLength: 128;
11
+ }>;
12
+ export type Insets = {
13
+ top: number;
14
+ right: number;
15
+ bottom: number;
16
+ left: number;
17
+ };
18
+ export type ColorScheme = "light" | "dark";
19
+ export type ThemeColors = {
20
+ background?: string;
21
+ text?: string;
22
+ mutedText?: string;
23
+ link?: string;
24
+ action?: string;
25
+ actionText?: string;
26
+ secondaryBackground?: string;
27
+ headerBackground?: string;
28
+ accentText?: string;
29
+ sectionBackground?: string;
30
+ sectionHeaderText?: string;
31
+ subtitleText?: string;
32
+ destructiveText?: string;
33
+ bottomBarBackground?: string;
34
+ };
35
+ export type HostSnapshot = {
36
+ colorScheme?: ColorScheme;
37
+ theme?: Readonly<ThemeColors>;
38
+ viewportHeight?: number;
39
+ stableViewportHeight?: number;
40
+ safeArea?: Insets;
41
+ contentSafeArea?: Insets;
42
+ isFullscreen?: boolean;
43
+ isOrientationLocked?: boolean;
44
+ };
45
+ export type MiniAppEventMap = {
46
+ activated: undefined;
47
+ deactivated: undefined;
48
+ themeChanged: HostSnapshot;
49
+ viewportChanged: HostSnapshot;
50
+ safeAreaChanged: Insets;
51
+ contentSafeAreaChanged: Insets;
52
+ fullscreenChanged: boolean;
53
+ fullscreenFailed: {
54
+ reason?: string;
55
+ };
56
+ backButtonClicked: undefined;
57
+ mainButtonClicked: undefined;
58
+ secondaryButtonClicked: undefined;
59
+ settingsButtonClicked: undefined;
60
+ qrTextReceived: {
61
+ data: string;
62
+ };
63
+ qrScannerClosed: undefined;
64
+ accelerometerChanged: {
65
+ x: number;
66
+ y: number;
67
+ z: number;
68
+ };
69
+ accelerometerFailed: {
70
+ reason?: string;
71
+ };
72
+ gyroscopeChanged: {
73
+ x: number;
74
+ y: number;
75
+ z: number;
76
+ };
77
+ gyroscopeFailed: {
78
+ reason?: string;
79
+ };
80
+ orientationFailed: {
81
+ reason?: string;
82
+ };
83
+ orientationChanged: {
84
+ absolute: boolean;
85
+ alpha: number;
86
+ beta: number;
87
+ gamma: number;
88
+ };
89
+ };
90
+ export type MiniAppEvent = keyof MiniAppEventMap;
91
+ export type ButtonId = "back" | "main" | "secondary" | "settings";
92
+ export type ButtonParams = {
93
+ text?: string;
94
+ active?: boolean;
95
+ visible?: boolean;
96
+ progressVisible?: boolean;
97
+ color?: string;
98
+ textColor?: string;
99
+ shine?: boolean;
100
+ position?: "left" | "right" | "top" | "bottom";
101
+ };
102
+ export type StoryShareParams = {
103
+ text?: string;
104
+ link?: {
105
+ url: string;
106
+ name?: string;
107
+ };
108
+ };
109
+ export type LocationData = {
110
+ latitude: number;
111
+ longitude: number;
112
+ altitude: number | null;
113
+ course: number | null;
114
+ speed: number | null;
115
+ horizontalAccuracy: number | null;
116
+ verticalAccuracy: number | null;
117
+ courseAccuracy: number | null;
118
+ speedAccuracy: number | null;
119
+ };
120
+ export type BiometryInfo = {
121
+ available: boolean;
122
+ type: "finger" | "face" | "unknown";
123
+ accessRequested: boolean;
124
+ accessGranted: boolean;
125
+ tokenSaved: boolean;
126
+ deviceId: string;
127
+ };
128
+ export type SensorOptions = {
129
+ refreshRate?: number;
130
+ };
131
+ export type InvoiceStatus = "paid" | "cancelled" | "failed" | "pending";
132
+ export type RequestContext = {
133
+ signal?: AbortSignal;
134
+ };
135
+ export type MiniAppOperationMap = {
136
+ ready: {
137
+ input: undefined;
138
+ output: void;
139
+ };
140
+ expand: {
141
+ input: undefined;
142
+ output: void;
143
+ };
144
+ requestFullscreen: {
145
+ input: undefined;
146
+ output: void;
147
+ };
148
+ exitFullscreen: {
149
+ input: undefined;
150
+ output: void;
151
+ };
152
+ hideKeyboard: {
153
+ input: undefined;
154
+ output: void;
155
+ };
156
+ setOrientationLock: {
157
+ input: {
158
+ locked: boolean;
159
+ };
160
+ output: void;
161
+ };
162
+ setButton: {
163
+ input: {
164
+ button: ButtonId;
165
+ params: ButtonParams;
166
+ };
167
+ output: void;
168
+ };
169
+ setClosingConfirmation: {
170
+ input: {
171
+ enabled: boolean;
172
+ };
173
+ output: void;
174
+ };
175
+ setHeaderColor: {
176
+ input: {
177
+ color: string;
178
+ };
179
+ output: void;
180
+ };
181
+ setBackgroundColor: {
182
+ input: {
183
+ color: string;
184
+ };
185
+ output: void;
186
+ };
187
+ setBottomBarColor: {
188
+ input: {
189
+ color: string;
190
+ };
191
+ output: void;
192
+ };
193
+ haptic: {
194
+ input: {
195
+ kind: "success" | "warning" | "error" | "light" | "medium" | "heavy" | "rigid" | "soft";
196
+ };
197
+ output: void;
198
+ };
199
+ showPopup: {
200
+ input: {
201
+ title?: string;
202
+ message: string;
203
+ buttons?: readonly {
204
+ id?: string;
205
+ text?: string;
206
+ kind?: "default" | "ok" | "close" | "cancel" | "destructive";
207
+ }[];
208
+ };
209
+ output: string | undefined;
210
+ };
211
+ openLink: {
212
+ input: {
213
+ url: string;
214
+ instantView?: boolean;
215
+ externalBrowser?: boolean;
216
+ };
217
+ output: void;
218
+ };
219
+ sendData: {
220
+ input: {
221
+ data: string;
222
+ };
223
+ output: void;
224
+ };
225
+ switchInlineQuery: {
226
+ input: {
227
+ query: string;
228
+ chatTypes?: readonly ("users" | "bots" | "groups" | "channels")[];
229
+ };
230
+ output: void;
231
+ };
232
+ readClipboard: {
233
+ input: undefined;
234
+ output: string | null;
235
+ };
236
+ getLocation: {
237
+ input: undefined;
238
+ output: LocationData | null;
239
+ };
240
+ openLocationSettings: {
241
+ input: undefined;
242
+ output: void;
243
+ };
244
+ getBiometryInfo: {
245
+ input: undefined;
246
+ output: BiometryInfo;
247
+ };
248
+ requestBiometryAccess: {
249
+ input: {
250
+ reason?: string;
251
+ };
252
+ output: boolean;
253
+ };
254
+ authenticateBiometry: {
255
+ input: {
256
+ reason?: string;
257
+ };
258
+ output: {
259
+ authenticated: boolean;
260
+ token?: string;
261
+ };
262
+ };
263
+ updateBiometryToken: {
264
+ input: {
265
+ token: string;
266
+ };
267
+ output: boolean;
268
+ };
269
+ openBiometrySettings: {
270
+ input: undefined;
271
+ output: void;
272
+ };
273
+ startAccelerometer: {
274
+ input: SensorOptions;
275
+ output: boolean;
276
+ };
277
+ stopAccelerometer: {
278
+ input: undefined;
279
+ output: boolean;
280
+ };
281
+ startGyroscope: {
282
+ input: SensorOptions;
283
+ output: boolean;
284
+ };
285
+ stopGyroscope: {
286
+ input: undefined;
287
+ output: boolean;
288
+ };
289
+ startDeviceOrientation: {
290
+ input: SensorOptions & {
291
+ absolute?: boolean;
292
+ };
293
+ output: boolean;
294
+ };
295
+ stopDeviceOrientation: {
296
+ input: undefined;
297
+ output: boolean;
298
+ };
299
+ downloadFile: {
300
+ input: {
301
+ url: string;
302
+ fileName: string;
303
+ };
304
+ output: boolean;
305
+ };
306
+ openQrScanner: {
307
+ input: {
308
+ text?: string;
309
+ };
310
+ output: void;
311
+ };
312
+ closeQrScanner: {
313
+ input: undefined;
314
+ output: void;
315
+ };
316
+ requestWriteAccess: {
317
+ input: undefined;
318
+ output: boolean;
319
+ };
320
+ requestContact: {
321
+ input: undefined;
322
+ output: boolean;
323
+ };
324
+ shareMessage: {
325
+ input: {
326
+ id: string;
327
+ };
328
+ output: boolean;
329
+ };
330
+ shareToStory: {
331
+ input: {
332
+ mediaUrl: string;
333
+ params?: StoryShareParams;
334
+ };
335
+ output: void;
336
+ };
337
+ openInvoice: {
338
+ input: {
339
+ url: string;
340
+ };
341
+ output: InvoiceStatus;
342
+ };
343
+ cloudStorageSet: {
344
+ input: {
345
+ key: string;
346
+ value: string;
347
+ };
348
+ output: boolean;
349
+ };
350
+ cloudStorageGet: {
351
+ input: {
352
+ key: string;
353
+ };
354
+ output: string;
355
+ };
356
+ cloudStorageGetMany: {
357
+ input: {
358
+ keys: readonly string[];
359
+ };
360
+ output: Record<string, string>;
361
+ };
362
+ cloudStorageRemove: {
363
+ input: {
364
+ key: string;
365
+ };
366
+ output: boolean;
367
+ };
368
+ cloudStorageRemoveMany: {
369
+ input: {
370
+ keys: readonly string[];
371
+ };
372
+ output: boolean;
373
+ };
374
+ cloudStorageKeys: {
375
+ input: undefined;
376
+ output: string[];
377
+ };
378
+ deviceStorageSet: {
379
+ input: {
380
+ key: string;
381
+ value: string;
382
+ };
383
+ output: boolean;
384
+ };
385
+ deviceStorageGet: {
386
+ input: {
387
+ key: string;
388
+ };
389
+ output: string | null;
390
+ };
391
+ deviceStorageRemove: {
392
+ input: {
393
+ key: string;
394
+ };
395
+ output: boolean;
396
+ };
397
+ deviceStorageClear: {
398
+ input: undefined;
399
+ output: boolean;
400
+ };
401
+ secureStorageSet: {
402
+ input: {
403
+ key: string;
404
+ value: string;
405
+ };
406
+ output: boolean;
407
+ };
408
+ secureStorageGet: {
409
+ input: {
410
+ key: string;
411
+ };
412
+ output: {
413
+ value: string | null;
414
+ canRestore: boolean;
415
+ };
416
+ };
417
+ secureStorageRestore: {
418
+ input: {
419
+ key: string;
420
+ };
421
+ output: string;
422
+ };
423
+ secureStorageRemove: {
424
+ input: {
425
+ key: string;
426
+ };
427
+ output: boolean;
428
+ };
429
+ secureStorageClear: {
430
+ input: undefined;
431
+ output: boolean;
432
+ };
433
+ };
434
+ export type MiniAppOperation = keyof MiniAppOperationMap;
435
+ export type OperationInput<K extends MiniAppOperation> = MiniAppOperationMap[K]["input"];
436
+ export type OperationOutput<K extends MiniAppOperation> = MiniAppOperationMap[K]["output"];
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MINI_APP_LIMITS = exports.MINI_APP_PROTOCOL_VERSION = exports.MINI_APP_CAPABILITIES = void 0;
4
+ /** Stable, platform-neutral features a host can advertise. */
5
+ exports.MINI_APP_CAPABILITIES = [
6
+ "ready",
7
+ "expand",
8
+ "fullscreen",
9
+ "hideKeyboard",
10
+ "orientation",
11
+ "backButton",
12
+ "mainButton",
13
+ "secondaryButton",
14
+ "settingsButton",
15
+ "closingConfirmation",
16
+ "headerColor",
17
+ "backgroundColor",
18
+ "bottomBarColor",
19
+ "haptics",
20
+ "popup",
21
+ "openLink",
22
+ "sendData",
23
+ "switchInlineQuery",
24
+ "clipboard",
25
+ "location",
26
+ "biometry",
27
+ "sensors",
28
+ "downloadFile",
29
+ "qrScanner",
30
+ "requestWriteAccess",
31
+ "requestContact",
32
+ "shareMessage",
33
+ "shareToStory",
34
+ "invoice",
35
+ "cloudStorage",
36
+ "deviceStorage",
37
+ "secureStorage",
38
+ ];
39
+ exports.MINI_APP_PROTOCOL_VERSION = 1;
40
+ exports.MINI_APP_LIMITS = Object.freeze({
41
+ envelopeBytes: 65_536,
42
+ sendDataBytes: 4_096,
43
+ inlineQueryLength: 256,
44
+ qrPromptLength: 64,
45
+ preparedMessageIdLength: 128,
46
+ });
@@ -0,0 +1,6 @@
1
+ export type RequestOptions = {
2
+ signal?: AbortSignal;
3
+ timeoutMs?: number;
4
+ };
5
+ /** Snapshot caller-owned options before a request acquires timers or listeners. */
6
+ export declare function readRequestOptions(options: RequestOptions): RequestOptions;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readRequestOptions = readRequestOptions;
4
+ /** Snapshot caller-owned options before a request acquires timers or listeners. */
5
+ function readRequestOptions(options) {
6
+ if (!options || typeof options !== "object" || Array.isArray(options)) {
7
+ throw new TypeError("Request options must be an object");
8
+ }
9
+ const { signal, timeoutMs } = options;
10
+ if (signal !== undefined &&
11
+ (signal === null ||
12
+ typeof signal !== "object" ||
13
+ typeof signal.aborted !== "boolean" ||
14
+ typeof signal.addEventListener !== "function" ||
15
+ typeof signal.removeEventListener !== "function")) {
16
+ throw new TypeError("signal must be an AbortSignal");
17
+ }
18
+ return { signal, timeoutMs };
19
+ }
@@ -0,0 +1,16 @@
1
+ import type { MiniAppAdapter } from "./adapter.js";
2
+ export interface AppSession {
3
+ token: string;
4
+ startParam: string;
5
+ }
6
+ /** Cache entries are hints. The server must validate launch data and cached sessions. */
7
+ export declare function authenticate<T extends AppSession>(adapter: MiniAppAdapter, options: {
8
+ storageKey: string;
9
+ authenticate: (launch: {
10
+ adapterId: string;
11
+ launchData: string;
12
+ }) => Promise<T>;
13
+ validate: (token: string) => Promise<unknown>;
14
+ isUnauthorized: (error: unknown) => boolean;
15
+ storage?: Storage | null;
16
+ }): Promise<AppSession>;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.authenticate = authenticate;
4
+ /** Cache entries are hints. The server must validate launch data and cached sessions. */
5
+ async function authenticate(adapter, options) {
6
+ let fingerprint = "";
7
+ if (globalThis.crypto?.subtle) {
8
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(adapter.launchData));
9
+ fingerprint = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
10
+ }
11
+ const storage = options.storage ?? null;
12
+ let cached;
13
+ try {
14
+ cached = JSON.parse(storage?.getItem(options.storageKey) ?? "null");
15
+ }
16
+ catch {
17
+ /* untrusted */
18
+ }
19
+ if (fingerprint && cached && typeof cached === "object") {
20
+ const value = cached;
21
+ if (value.fingerprint === fingerprint &&
22
+ value.adapterId === adapter.id &&
23
+ typeof value.token === "string" &&
24
+ value.token &&
25
+ typeof value.startParam === "string") {
26
+ try {
27
+ await options.validate(value.token);
28
+ return { token: value.token, startParam: value.startParam };
29
+ }
30
+ catch (error) {
31
+ if (!options.isUnauthorized(error))
32
+ throw error;
33
+ }
34
+ }
35
+ }
36
+ const session = await options.authenticate({
37
+ adapterId: adapter.id,
38
+ launchData: adapter.launchData,
39
+ });
40
+ if (typeof session.token !== "string" ||
41
+ !session.token ||
42
+ typeof session.startParam !== "string") {
43
+ throw new TypeError("Invalid application session");
44
+ }
45
+ if (fingerprint) {
46
+ try {
47
+ storage?.setItem(options.storageKey, JSON.stringify({
48
+ adapterId: adapter.id,
49
+ fingerprint,
50
+ token: session.token,
51
+ startParam: session.startParam,
52
+ }));
53
+ }
54
+ catch {
55
+ /* optional */
56
+ }
57
+ }
58
+ return { token: session.token, startParam: session.startParam };
59
+ }
@@ -0,0 +1,25 @@
1
+ import type { MiniAppClient, CallOptions } from "./client.js";
2
+ export declare function cloudStorage(client: MiniAppClient): {
3
+ setItem: (key: string, value: string, options?: CallOptions) => Promise<boolean>;
4
+ getItem: (key: string, options?: CallOptions) => Promise<string>;
5
+ getItems: (keys: readonly string[], options?: CallOptions) => Promise<Record<string, string>>;
6
+ removeItem: (key: string, options?: CallOptions) => Promise<boolean>;
7
+ removeItems: (keys: readonly string[], options?: CallOptions) => Promise<boolean>;
8
+ getKeys: (options?: CallOptions) => Promise<string[]>;
9
+ };
10
+ export declare function deviceStorage(client: MiniAppClient): {
11
+ setItem: (key: string, value: string, options?: CallOptions) => Promise<boolean>;
12
+ getItem: (key: string, options?: CallOptions) => Promise<string | null>;
13
+ removeItem: (key: string, options?: CallOptions) => Promise<boolean>;
14
+ clear: (options?: CallOptions) => Promise<boolean>;
15
+ };
16
+ export declare function secureStorage(client: MiniAppClient): {
17
+ setItem: (key: string, value: string, options?: CallOptions) => Promise<boolean>;
18
+ getItem: (key: string, options?: CallOptions) => Promise<{
19
+ value: string | null;
20
+ canRestore: boolean;
21
+ }>;
22
+ restoreItem: (key: string, options?: CallOptions) => Promise<string>;
23
+ removeItem: (key: string, options?: CallOptions) => Promise<boolean>;
24
+ clear: (options?: CallOptions) => Promise<boolean>;
25
+ };
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cloudStorage = cloudStorage;
4
+ exports.deviceStorage = deviceStorage;
5
+ exports.secureStorage = secureStorage;
6
+ function cloudStorage(client) {
7
+ return {
8
+ setItem: (key, value, options) => client.call("cloudStorageSet", { key, value }, options),
9
+ getItem: (key, options) => client.call("cloudStorageGet", { key }, options),
10
+ getItems: (keys, options) => client.call("cloudStorageGetMany", { keys }, options),
11
+ removeItem: (key, options) => client.call("cloudStorageRemove", { key }, options),
12
+ removeItems: (keys, options) => client.call("cloudStorageRemoveMany", { keys }, options),
13
+ getKeys: (options) => client.call("cloudStorageKeys", undefined, options),
14
+ };
15
+ }
16
+ function deviceStorage(client) {
17
+ return {
18
+ setItem: (key, value, options) => client.call("deviceStorageSet", { key, value }, options),
19
+ getItem: (key, options) => client.call("deviceStorageGet", { key }, options),
20
+ removeItem: (key, options) => client.call("deviceStorageRemove", { key }, options),
21
+ clear: (options) => client.call("deviceStorageClear", undefined, options),
22
+ };
23
+ }
24
+ function secureStorage(client) {
25
+ return {
26
+ setItem: (key, value, options) => client.call("secureStorageSet", { key, value }, options),
27
+ getItem: (key, options) => client.call("secureStorageGet", { key }, options),
28
+ restoreItem: (key, options) => client.call("secureStorageRestore", { key }, options),
29
+ removeItem: (key, options) => client.call("secureStorageRemove", { key }, options),
30
+ clear: (options) => client.call("secureStorageClear", undefined, options),
31
+ };
32
+ }