react-native-tapline 0.0.0-stage → 1.0.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 (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +86 -2
  3. package/TaplineNative.podspec +14 -0
  4. package/dist/actions.d.ts +160 -0
  5. package/dist/actions.js +1883 -0
  6. package/dist/actions.js.map +1 -0
  7. package/dist/agent.d.ts +79 -0
  8. package/dist/agent.js +255 -0
  9. package/dist/agent.js.map +1 -0
  10. package/dist/alerts.d.ts +35 -0
  11. package/dist/alerts.js +437 -0
  12. package/dist/alerts.js.map +1 -0
  13. package/dist/awake.d.ts +2 -0
  14. package/dist/awake.js +53 -0
  15. package/dist/awake.js.map +1 -0
  16. package/dist/checks.d.ts +19 -0
  17. package/dist/checks.js +318 -0
  18. package/dist/checks.js.map +1 -0
  19. package/dist/client.d.ts +111 -0
  20. package/dist/client.js +446 -0
  21. package/dist/client.js.map +1 -0
  22. package/dist/commands.d.ts +24 -0
  23. package/dist/commands.js +111 -0
  24. package/dist/commands.js.map +1 -0
  25. package/dist/events.d.ts +5 -0
  26. package/dist/events.js +22 -0
  27. package/dist/events.js.map +1 -0
  28. package/dist/feed.d.ts +117 -0
  29. package/dist/feed.js +440 -0
  30. package/dist/feed.js.map +1 -0
  31. package/dist/fiber.d.ts +43 -0
  32. package/dist/fiber.js +100 -0
  33. package/dist/fiber.js.map +1 -0
  34. package/dist/index.d.ts +50 -0
  35. package/dist/index.js +133 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/inspect.d.ts +245 -0
  38. package/dist/inspect.js +1343 -0
  39. package/dist/inspect.js.map +1 -0
  40. package/dist/keyboard.d.ts +10 -0
  41. package/dist/keyboard.js +63 -0
  42. package/dist/keyboard.js.map +1 -0
  43. package/dist/link.d.ts +21 -0
  44. package/dist/link.js +63 -0
  45. package/dist/link.js.map +1 -0
  46. package/dist/live.d.ts +30 -0
  47. package/dist/live.js +279 -0
  48. package/dist/live.js.map +1 -0
  49. package/dist/logs.d.ts +16 -0
  50. package/dist/logs.js +171 -0
  51. package/dist/logs.js.map +1 -0
  52. package/dist/methods.d.ts +3 -0
  53. package/dist/methods.js +47 -0
  54. package/dist/methods.js.map +1 -0
  55. package/dist/native.d.ts +34 -0
  56. package/dist/native.js +63 -0
  57. package/dist/native.js.map +1 -0
  58. package/dist/network.d.ts +27 -0
  59. package/dist/network.js +238 -0
  60. package/dist/network.js.map +1 -0
  61. package/dist/register.d.ts +24 -0
  62. package/dist/register.js +180 -0
  63. package/dist/register.js.map +1 -0
  64. package/dist/settle.d.ts +27 -0
  65. package/dist/settle.js +70 -0
  66. package/dist/settle.js.map +1 -0
  67. package/dist/storage.d.ts +10 -0
  68. package/dist/storage.js +45 -0
  69. package/dist/storage.js.map +1 -0
  70. package/dist/touches.d.ts +15 -0
  71. package/dist/touches.js +89 -0
  72. package/dist/touches.js.map +1 -0
  73. package/dist/types.d.ts +168 -0
  74. package/dist/types.js +32 -0
  75. package/dist/types.js.map +1 -0
  76. package/dist/wait.d.ts +8 -0
  77. package/dist/wait.js +99 -0
  78. package/dist/wait.js.map +1 -0
  79. package/expo-module.config.json +7 -0
  80. package/ios/TaplineNativeModule.swift +79 -0
  81. package/metro.d.ts +10 -0
  82. package/metro.js +40 -0
  83. package/package.json +100 -4
  84. package/register.d.ts +1 -0
  85. package/register.js +3 -0
package/dist/client.js ADDED
@@ -0,0 +1,446 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TaplineClient = exports.CLOSE_BAD_PAIR_CODE = exports.CLOSE_BAD_TOKEN = exports.REQUEST_TIMEOUT_MS = exports.HOST_SILENCE_MS = exports.PING_INTERVAL_MS = void 0;
4
+ exports.connectTimeoutMs = connectTimeoutMs;
5
+ exports.backoffDelay = backoffDelay;
6
+ exports.normalizeUrl = normalizeUrl;
7
+ exports.collectDeviceInfo = collectDeviceInfo;
8
+ exports.defaultCapabilities = defaultCapabilities;
9
+ const react_native_1 = require("react-native");
10
+ const actions_1 = require("./actions");
11
+ const awake_1 = require("./awake");
12
+ const events_1 = require("./events");
13
+ const touches_1 = require("./touches");
14
+ const live_1 = require("./live");
15
+ const inspect_1 = require("./inspect");
16
+ const logs_1 = require("./logs");
17
+ const methods_1 = require("./methods");
18
+ const native_1 = require("./native");
19
+ const types_1 = require("./types");
20
+ exports.PING_INTERVAL_MS = 15_000;
21
+ exports.HOST_SILENCE_MS = 45_000;
22
+ exports.REQUEST_TIMEOUT_MS = 30_000;
23
+ const BACKOFF_START_MS = 1_000;
24
+ /**
25
+ * QUALITY-BAR S4/S5: a host that starts (a new agent session, often long after the app was opened on
26
+ * a dedicated device) is found within about 2 s: a new try one second after each failed one, and a
27
+ * failed try itself takes up to a second on iOS (measured: with a 2 s wait the app was found up to 3 s
28
+ * after the host began listening). A refused connection costs next to nothing; iOS pauses the app in
29
+ * the background, so this only runs while the app is open, and only in builds with Tapline turned on.
30
+ */
31
+ const BACKOFF_MAX_MS = 1_000;
32
+ /** WebSocket close code for a token the host refused. */
33
+ exports.CLOSE_BAD_TOKEN = 4001;
34
+ /** WebSocket close code for a pairing code the host refused (invalid, expired or used). */
35
+ exports.CLOSE_BAD_PAIR_CODE = 4004;
36
+ /**
37
+ * How long a connection try may take to open before it is dropped for a fresh one: 2 s, and 4 s on
38
+ * every fourth try, so a slow link that needs longer still gets through. iOS repeats an unanswered
39
+ * try after 1 s and 3 s, so with the 1 s wait between tries a host is never left unasked for more
40
+ * than about 2 s.
41
+ */
42
+ function connectTimeoutMs(attempt) {
43
+ return attempt % 4 === 3 ? 4_000 : 2_000;
44
+ }
45
+ function backoffDelay(attempt) {
46
+ return Math.min(BACKOFF_MAX_MS, BACKOFF_START_MS * 2 ** attempt);
47
+ }
48
+ function normalizeUrl(url) {
49
+ const trimmed = url.trim();
50
+ if (/^wss?:\/\//i.test(trimmed))
51
+ return trimmed;
52
+ return `ws://${trimmed.replace(/^https?:\/\//i, '')}`;
53
+ }
54
+ function collectDeviceInfo() {
55
+ const constants = react_native_1.Platform.constants;
56
+ const info = { platform: react_native_1.Platform.OS, osVersion: String(react_native_1.Platform.Version) };
57
+ if ((0, types_1.isRecord)(constants)) {
58
+ if (typeof constants.osVersion === 'string')
59
+ info.osVersion = constants.osVersion;
60
+ else if (typeof constants.Release === 'string')
61
+ info.osVersion = constants.Release;
62
+ if (typeof constants.Model === 'string')
63
+ info.model = constants.Model;
64
+ else if (typeof constants.model === 'string')
65
+ info.model = constants.model;
66
+ if (typeof constants.deviceName === 'string')
67
+ info.name = constants.deviceName;
68
+ }
69
+ return info;
70
+ }
71
+ function defaultCapabilities() {
72
+ const capabilities = ['tree', 'press', 'longPress', 'type', 'scroll', 'toggle', 'openURL', 'back', 'check', 'commands', 'waitFor', 'logs', 'overlay'];
73
+ if ((0, actions_1.screenshotAvailable)())
74
+ capabilities.push('screenshot', 'feed');
75
+ if (typeof __DEV__ !== 'undefined' && __DEV__)
76
+ capabilities.push('reload');
77
+ return capabilities;
78
+ }
79
+ function toWireError(error) {
80
+ if (error instanceof types_1.TaplineError)
81
+ return error.toWire();
82
+ return { code: 'internal', message: error instanceof Error ? error.message : String(error) };
83
+ }
84
+ class TaplineClient {
85
+ options;
86
+ deps;
87
+ socket = null;
88
+ reconnectTimer = null;
89
+ /** Gives up on a connection try that hasn't opened. */
90
+ openTimer = null;
91
+ /** The current socket has opened. */
92
+ opened = false;
93
+ pingTimer = null;
94
+ attempt = 0;
95
+ running = false;
96
+ ready = false;
97
+ everConnected = false;
98
+ failureLogged = false;
99
+ lastHeard = 0;
100
+ queue = Promise.resolve();
101
+ token;
102
+ pairCode;
103
+ appStateSubscription = null;
104
+ stopTouchWatch = null;
105
+ constructor(options, deps = {}) {
106
+ this.options = options;
107
+ this.deps = deps;
108
+ this.token = options.token;
109
+ this.pairCode = options.pairCode;
110
+ }
111
+ get connected() {
112
+ return this.ready;
113
+ }
114
+ start() {
115
+ if (this.running)
116
+ return;
117
+ this.running = true;
118
+ this.attempt = 0;
119
+ this.watchAppState();
120
+ // A person's finger on the screen: the host tells the agent (the event goes nowhere while disconnected).
121
+ this.stopTouchWatch = (0, touches_1.onRealTouch)((at) => (0, events_1.emitEvent)('touch', { at }));
122
+ this.connect();
123
+ }
124
+ stop() {
125
+ this.running = false;
126
+ this.clearTimers();
127
+ const stopTouchWatch = this.stopTouchWatch;
128
+ this.stopTouchWatch = null;
129
+ if (stopTouchWatch)
130
+ this.safely(stopTouchWatch);
131
+ const socket = this.socket;
132
+ this.socket = null;
133
+ if (this.ready)
134
+ this.status('disconnected');
135
+ this.ready = false;
136
+ (0, logs_1.setLogSink)(null);
137
+ (0, events_1.setEventSink)(null);
138
+ (0, live_1.stopLiveFeed)();
139
+ this.setAwake(false);
140
+ const subscription = this.appStateSubscription;
141
+ this.appStateSubscription = null;
142
+ if (subscription)
143
+ this.safely(() => subscription.remove());
144
+ if (socket) {
145
+ detach(socket);
146
+ try {
147
+ socket.close(1000, 'stopped');
148
+ }
149
+ catch {
150
+ // already closed
151
+ }
152
+ }
153
+ }
154
+ status(line) {
155
+ const log = this.deps.log ?? logs_1.originalLog;
156
+ try {
157
+ log(`[tapline] ${line}`);
158
+ }
159
+ catch {
160
+ // never throw into the app
161
+ }
162
+ }
163
+ setAwake(on) {
164
+ this.safely(() => (this.deps.keepAwake ?? awake_1.keepAwake)(on));
165
+ }
166
+ watchAppState() {
167
+ if (this.appStateSubscription)
168
+ return;
169
+ this.safely(() => {
170
+ const source = this.deps.appState ?? react_native_1.AppState;
171
+ const subscription = source.addEventListener('change', (state) => this.safely(() => this.onAppState(state)));
172
+ if ((0, types_1.isRecord)(subscription) && typeof subscription.remove === 'function')
173
+ this.appStateSubscription = subscription;
174
+ });
175
+ }
176
+ /** Tells the host when the app goes to the background (iOS then pauses it), and reconnects at once when it's back. */
177
+ onAppState(state) {
178
+ if (this.ready)
179
+ this.send({ type: 'event', event: 'appState', data: { state } });
180
+ if (state === 'active' && this.running && !this.ready && this.socket === null) {
181
+ if (this.reconnectTimer !== null)
182
+ clearTimeout(this.reconnectTimer);
183
+ this.reconnectTimer = null;
184
+ this.attempt = 0;
185
+ this.connect();
186
+ }
187
+ }
188
+ clearTimers() {
189
+ if (this.reconnectTimer !== null)
190
+ clearTimeout(this.reconnectTimer);
191
+ if (this.pingTimer !== null)
192
+ clearInterval(this.pingTimer);
193
+ if (this.openTimer !== null)
194
+ clearTimeout(this.openTimer);
195
+ this.reconnectTimer = null;
196
+ this.pingTimer = null;
197
+ this.openTimer = null;
198
+ }
199
+ connect() {
200
+ if (!this.running)
201
+ return;
202
+ const Ctor = this.deps.WebSocketCtor ?? globalThis.WebSocket;
203
+ if (typeof Ctor !== 'function') {
204
+ this.status('no WebSocket available in this environment');
205
+ return;
206
+ }
207
+ let socket;
208
+ try {
209
+ socket = new Ctor(normalizeUrl(this.options.url));
210
+ }
211
+ catch {
212
+ this.scheduleReconnect();
213
+ return;
214
+ }
215
+ this.socket = socket;
216
+ this.opened = false;
217
+ socket.onopen = () => this.safely(() => this.onOpen(socket));
218
+ socket.onmessage = (event) => this.safely(() => this.onMessage(socket, event.data));
219
+ socket.onerror = () => {
220
+ // onclose follows; nothing to do
221
+ };
222
+ socket.onclose = (event) => this.safely(() => this.onClose(socket, event.code));
223
+ // A host that isn't there may not refuse the connection (a firewall drops it silently): the try
224
+ // then hangs while iOS repeats it at growing intervals, and a host that starts meanwhile is found
225
+ // late (measured: up to 6 s). Give up on a try that hasn't opened and start a fresh one.
226
+ if (this.openTimer !== null)
227
+ clearTimeout(this.openTimer);
228
+ const attempt = this.attempt;
229
+ this.openTimer = setTimeout(() => {
230
+ this.openTimer = null;
231
+ this.safely(() => {
232
+ if (socket !== this.socket || this.opened)
233
+ return;
234
+ detach(socket);
235
+ try {
236
+ socket.close();
237
+ }
238
+ catch {
239
+ // already closed
240
+ }
241
+ this.handleLoss(undefined);
242
+ });
243
+ }, connectTimeoutMs(attempt));
244
+ }
245
+ safely(fn) {
246
+ try {
247
+ fn();
248
+ }
249
+ catch {
250
+ // never throw into the app
251
+ }
252
+ }
253
+ onOpen(socket) {
254
+ if (socket !== this.socket)
255
+ return;
256
+ this.opened = true;
257
+ if (this.openTimer !== null)
258
+ clearTimeout(this.openTimer);
259
+ this.openTimer = null;
260
+ this.lastHeard = Date.now();
261
+ const device = this.deps.device ?? collectDeviceInfo();
262
+ const deviceId = this.options.deviceId;
263
+ this.send({
264
+ type: 'hello',
265
+ protocol: types_1.PROTOCOL_VERSION,
266
+ ...(this.pairCode !== undefined ? { pairCode: this.pairCode } : { token: this.token ?? '' }),
267
+ app: { name: 'App', ...this.options.app },
268
+ device: deviceId === undefined ? device : { ...device, id: deviceId },
269
+ capabilities: this.deps.capabilities ?? defaultCapabilities(),
270
+ });
271
+ }
272
+ onMessage(socket, data) {
273
+ if (socket !== this.socket || typeof data !== 'string')
274
+ return;
275
+ this.lastHeard = Date.now();
276
+ let message;
277
+ try {
278
+ message = JSON.parse(data);
279
+ }
280
+ catch {
281
+ return;
282
+ }
283
+ if (!(0, types_1.isRecord)(message))
284
+ return;
285
+ switch (message.type) {
286
+ case 'welcome':
287
+ (0, live_1.setFrameAcks)(message.frameAcks === true);
288
+ this.onWelcome(message.token);
289
+ break;
290
+ case 'frameAck':
291
+ (0, live_1.onFrameAck)();
292
+ break;
293
+ case 'ping':
294
+ this.send({ type: 'pong' });
295
+ break;
296
+ case 'request':
297
+ this.enqueue(message);
298
+ break;
299
+ default:
300
+ break; // pong and unknown types
301
+ }
302
+ }
303
+ onWelcome(token) {
304
+ // A new host session: its agent hasn't seen any list yet, so "changes" start over.
305
+ (0, inspect_1.forgetLastTree)();
306
+ if (this.pairCode !== undefined && typeof token === 'string' && token !== '') {
307
+ // Paired: the code was single-use, so later connections use the host's token.
308
+ this.pairCode = undefined;
309
+ this.token = token;
310
+ const onPaired = this.options.onPaired;
311
+ if (onPaired)
312
+ this.safely(() => onPaired(token));
313
+ }
314
+ this.ready = true;
315
+ this.everConnected = true;
316
+ this.failureLogged = false;
317
+ this.attempt = 0;
318
+ this.status('connected');
319
+ this.setAwake(true);
320
+ (0, logs_1.setLogSink)((event, payload) => this.send({ type: 'event', event, data: payload }));
321
+ (0, events_1.setEventSink)((event, data) => this.send({ type: 'event', event, data }));
322
+ if (this.pingTimer !== null)
323
+ clearInterval(this.pingTimer);
324
+ this.pingTimer = setInterval(() => this.safely(() => this.onPingTick()), exports.PING_INTERVAL_MS);
325
+ }
326
+ onPingTick() {
327
+ if (Date.now() - this.lastHeard > exports.HOST_SILENCE_MS) {
328
+ // The host stopped answering: drop the socket and reconnect.
329
+ const socket = this.socket;
330
+ if (socket) {
331
+ detach(socket);
332
+ try {
333
+ socket.close(4000, 'host silent');
334
+ }
335
+ catch {
336
+ // ignore
337
+ }
338
+ this.handleLoss(undefined);
339
+ }
340
+ return;
341
+ }
342
+ this.send({ type: 'ping' });
343
+ }
344
+ onClose(socket, code) {
345
+ if (socket !== this.socket)
346
+ return;
347
+ detach(socket);
348
+ if (code === exports.CLOSE_BAD_PAIR_CODE || (code === exports.CLOSE_BAD_TOKEN && !this.ready)) {
349
+ // Retrying a refused code or token can't work: stop and let the owner decide.
350
+ this.socket = null;
351
+ this.stop();
352
+ this.status(code === exports.CLOSE_BAD_PAIR_CODE ? 'the computer refused the pairing code' : 'the computer refused the token');
353
+ const onRejected = this.options.onRejected;
354
+ if (onRejected)
355
+ this.safely(() => onRejected(code));
356
+ return;
357
+ }
358
+ this.handleLoss(code);
359
+ }
360
+ handleLoss(code) {
361
+ this.socket = null;
362
+ if (this.pingTimer !== null)
363
+ clearInterval(this.pingTimer);
364
+ this.pingTimer = null;
365
+ (0, logs_1.setLogSink)(null);
366
+ (0, events_1.setEventSink)(null);
367
+ // Nobody can watch while disconnected; the host asks again after it reconnects.
368
+ (0, live_1.stopLiveFeed)();
369
+ this.setAwake(false);
370
+ if (this.ready) {
371
+ this.status(code ? `disconnected (code ${code})` : 'disconnected');
372
+ }
373
+ else if (!this.failureLogged) {
374
+ this.failureLogged = true;
375
+ this.status(code ? `cannot connect (code ${code}), retrying` : 'cannot reach the host, retrying');
376
+ }
377
+ this.ready = false;
378
+ this.scheduleReconnect();
379
+ }
380
+ scheduleReconnect() {
381
+ if (!this.running)
382
+ return;
383
+ if (this.reconnectTimer !== null)
384
+ clearTimeout(this.reconnectTimer);
385
+ const delay = backoffDelay(this.attempt);
386
+ this.attempt += 1;
387
+ this.reconnectTimer = setTimeout(() => {
388
+ this.reconnectTimer = null;
389
+ this.connect();
390
+ }, delay);
391
+ }
392
+ send(message) {
393
+ const socket = this.socket;
394
+ if (!socket)
395
+ return;
396
+ try {
397
+ socket.send(JSON.stringify(message));
398
+ }
399
+ catch {
400
+ // a failed send shows up as a close
401
+ }
402
+ }
403
+ /** Requests run one at a time so refs and snapshots never interleave. */
404
+ enqueue(message) {
405
+ this.queue = this.queue.then(() => this.handleRequest(message)).catch(() => undefined);
406
+ }
407
+ async handleRequest(message) {
408
+ const id = message.id;
409
+ if (typeof id !== 'number' && typeof id !== 'string')
410
+ return;
411
+ const respond = (body) => this.send({ type: 'response', id, ...body });
412
+ const name = message.method;
413
+ const table = this.deps.methods ?? methods_1.methods;
414
+ const method = typeof name === 'string' && Object.prototype.hasOwnProperty.call(table, name) ? table[name] : undefined;
415
+ if (!method) {
416
+ respond({ ok: false, error: { code: 'unsupported', message: `Unknown method ${String(name)}` } });
417
+ return;
418
+ }
419
+ let timer;
420
+ try {
421
+ const timeout = new Promise((_, reject) => {
422
+ timer = setTimeout(() => reject(new types_1.TaplineError('timeout', `${String(name)} did not finish in ${exports.REQUEST_TIMEOUT_MS / 1000} s`)), exports.REQUEST_TIMEOUT_MS);
423
+ });
424
+ // What UIKit shows over the app (when the app has Tapline's native module), so this request's
425
+ // checks see an alert or the share sheet in front.
426
+ await (0, native_1.refreshCover)();
427
+ const result = await Promise.race([method(message.params), timeout]);
428
+ respond({ ok: true, result: result === undefined ? {} : result });
429
+ }
430
+ catch (error) {
431
+ respond({ ok: false, error: toWireError(error) });
432
+ }
433
+ finally {
434
+ if (timer !== undefined)
435
+ clearTimeout(timer);
436
+ }
437
+ }
438
+ }
439
+ exports.TaplineClient = TaplineClient;
440
+ function detach(socket) {
441
+ socket.onopen = null;
442
+ socket.onmessage = null;
443
+ socket.onclose = null;
444
+ socket.onerror = null;
445
+ }
446
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { type Json } from './types';
2
+ /**
3
+ * App test commands: things an agent can ask the app to do that no screen offers quickly,
4
+ * such as switching the language, signing in as a test user or loading sample data. The app
5
+ * registers them (development and test builds); the agent lists and runs them by name.
6
+ */
7
+ export interface TaplineCommand {
8
+ /** One line for the agent: what it does and which args it takes. */
9
+ description: string;
10
+ run: (args: Record<string, unknown>) => unknown;
11
+ }
12
+ /** Registers (or replaces) a command; returns a function that removes it. */
13
+ export declare function registerTaplineCommand(name: string, command: TaplineCommand): () => void;
14
+ /** Removes the app's commands and restores the built-ins (tests). */
15
+ export declare function resetCommands(): void;
16
+ export declare function listCommands(): Array<{
17
+ name: string;
18
+ description: string;
19
+ }>;
20
+ /** `command`: runs a registered command with `args`. */
21
+ export declare function runCommand(params: unknown): Promise<{
22
+ name: string;
23
+ result: Json | null;
24
+ }>;
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerTaplineCommand = registerTaplineCommand;
4
+ exports.resetCommands = resetCommands;
5
+ exports.listCommands = listCommands;
6
+ exports.runCommand = runCommand;
7
+ const react_native_1 = require("react-native");
8
+ const types_1 = require("./types");
9
+ const NAME = /^[A-Za-z][\w.-]{0,40}$/;
10
+ const COMMAND_TIMEOUT_MS = 15_000;
11
+ const MAX_RESULT_CHARS = 4000;
12
+ const registry = new Map();
13
+ /** Built in: light or dark appearance, for checking both. */
14
+ const appearance = {
15
+ description: 'Switch the app between light and dark appearance (args: { scheme: "light" | "dark" | "system" })',
16
+ run: (args) => {
17
+ const scheme = args.scheme;
18
+ if (scheme !== 'light' && scheme !== 'dark' && scheme !== 'system') {
19
+ throw new Error('scheme must be "light", "dark" or "system"');
20
+ }
21
+ react_native_1.Appearance.setColorScheme(scheme === 'system' ? 'unspecified' : scheme);
22
+ return { scheme };
23
+ },
24
+ };
25
+ function installBuiltIns() {
26
+ registry.set('appearance', appearance);
27
+ }
28
+ installBuiltIns();
29
+ /** Registers (or replaces) a command; returns a function that removes it. */
30
+ function registerTaplineCommand(name, command) {
31
+ if (!NAME.test(name)) {
32
+ throw new Error(`Tapline command names are letters, digits, ".", "_" and "-", starting with a letter: "${name}"`);
33
+ }
34
+ if (typeof command.run !== 'function')
35
+ throw new Error(`Tapline command "${name}" needs a run function`);
36
+ registry.set(name, command);
37
+ return () => {
38
+ if (registry.get(name) === command)
39
+ registry.delete(name);
40
+ };
41
+ }
42
+ /** Removes the app's commands and restores the built-ins (tests). */
43
+ function resetCommands() {
44
+ registry.clear();
45
+ installBuiltIns();
46
+ }
47
+ function listCommands() {
48
+ return [...registry.entries()]
49
+ .map(([name, command]) => ({ name, description: String(command.description) }))
50
+ .sort((a, b) => a.name.localeCompare(b.name));
51
+ }
52
+ /** A JSON-safe copy: no functions, dates as ISO strings, cycles and deep nesting cut. */
53
+ function toJson(value, depth = 0, seen = new WeakSet()) {
54
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
55
+ return value;
56
+ if (typeof value === 'number')
57
+ return Number.isFinite(value) ? value : String(value);
58
+ if (value instanceof Date)
59
+ return Number.isNaN(value.getTime()) ? null : value.toISOString();
60
+ if (typeof value !== 'object' || depth > 6)
61
+ return undefined;
62
+ if (seen.has(value))
63
+ return '[cycle]';
64
+ seen.add(value);
65
+ if (Array.isArray(value))
66
+ return value.map((item) => toJson(item, depth + 1, seen) ?? null);
67
+ const out = {};
68
+ for (const [key, item] of Object.entries(value)) {
69
+ const json = toJson(item, depth + 1, seen);
70
+ if (json !== undefined)
71
+ out[key] = json;
72
+ }
73
+ return out;
74
+ }
75
+ /** `command`: runs a registered command with `args`. */
76
+ async function runCommand(params) {
77
+ if (!(0, types_1.isRecord)(params) || typeof params.name !== 'string' || params.name === '') {
78
+ throw new types_1.TaplineError('bad_params', 'command needs { name, args? }');
79
+ }
80
+ if (params.args !== undefined && !(0, types_1.isRecord)(params.args)) {
81
+ throw new types_1.TaplineError('bad_params', 'args must be an object');
82
+ }
83
+ const { name } = params;
84
+ const command = registry.get(name);
85
+ if (!command) {
86
+ const known = listCommands().map((c) => c.name).join(', ');
87
+ throw new types_1.TaplineError('not_found', `No command "${name}". This app has: ${known}.`);
88
+ }
89
+ let timer;
90
+ try {
91
+ const timeout = new Promise((_, reject) => {
92
+ timer = setTimeout(() => reject(new types_1.TaplineError('timeout', `Command "${name}" did not finish in ${COMMAND_TIMEOUT_MS / 1000} s`)), COMMAND_TIMEOUT_MS);
93
+ });
94
+ const value = await Promise.race([Promise.resolve().then(() => command.run((0, types_1.isRecord)(params.args) ? params.args : {})), timeout]);
95
+ let result = toJson(value) ?? null;
96
+ const text = JSON.stringify(result);
97
+ if (text.length > MAX_RESULT_CHARS)
98
+ result = { truncated: true, preview: text.slice(0, MAX_RESULT_CHARS) };
99
+ return { name, result };
100
+ }
101
+ catch (error) {
102
+ if (error instanceof types_1.TaplineError)
103
+ throw error;
104
+ throw new types_1.TaplineError('internal', `Command "${name}" failed: ${error instanceof Error ? error.message : String(error)}`);
105
+ }
106
+ finally {
107
+ if (timer !== undefined)
108
+ clearTimeout(timer);
109
+ }
110
+ }
111
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** Events the app sends the host besides logs (live frames). The client sets the sink while connected. */
2
+ export type EventSink = (event: string, data: unknown) => void;
3
+ export declare function setEventSink(next: EventSink | null): void;
4
+ /** Sends an event to the connected host; does nothing while disconnected. Never throws. */
5
+ export declare function emitEvent(event: string, data: unknown): void;
package/dist/events.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ /** Events the app sends the host besides logs (live frames). The client sets the sink while connected. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.setEventSink = setEventSink;
5
+ exports.emitEvent = emitEvent;
6
+ let sink = null;
7
+ function setEventSink(next) {
8
+ sink = next;
9
+ }
10
+ /** Sends an event to the connected host; does nothing while disconnected. Never throws. */
11
+ function emitEvent(event, data) {
12
+ const target = sink;
13
+ if (!target)
14
+ return;
15
+ try {
16
+ target(event, data);
17
+ }
18
+ catch {
19
+ // a broken socket must never reach the app
20
+ }
21
+ }
22
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":";AAAA,0GAA0G;;AAM1G,oCAEC;AAGD,8BAQC;AAfD,IAAI,IAAI,GAAqB,IAAI,CAAC;AAElC,SAAgB,YAAY,CAAC,IAAsB;IACjD,IAAI,GAAG,IAAI,CAAC;AACd,CAAC;AAED,2FAA2F;AAC3F,SAAgB,SAAS,CAAC,KAAa,EAAE,IAAa;IACpD,MAAM,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,IAAI,CAAC;QACH,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,2CAA2C;IAC7C,CAAC;AACH,CAAC"}