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
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.commitRevision = commitRevision;
4
+ exports.onCommit = onCommit;
5
+ exports.installHook = installHook;
6
+ exports.getRoots = getRoots;
7
+ exports.resetRegistry = resetRegistry;
8
+ /**
9
+ * Import this FIRST in the app's entry file, before React / React Native:
10
+ *
11
+ * import 'react-native-tapline/register';
12
+ *
13
+ * It installs a minimal React DevTools global hook (or wraps the existing one,
14
+ * chaining every call) so Tapline can see the app's fiber roots. This file must
15
+ * not import react or react-native.
16
+ */
17
+ const fiber_1 = require("./fiber");
18
+ const types_1 = require("./types");
19
+ const WRAPPED = Symbol.for('tapline.hookWrapped');
20
+ /** renderer id -> roots seen via onCommitFiberRoot */
21
+ const rootsByRenderer = new Map();
22
+ let installedHook = null;
23
+ /** How many React commits have happened: the screen's revision, for the live viewer. */
24
+ let revision = 0;
25
+ const commitListeners = new Set();
26
+ function committed() {
27
+ revision += 1;
28
+ for (const listener of commitListeners)
29
+ safely(() => listener(revision));
30
+ }
31
+ /** The number of React commits so far; it changes whenever the UI may have changed. */
32
+ function commitRevision() {
33
+ return revision;
34
+ }
35
+ /** Called after every React commit with the new revision; returns a function that stops it. */
36
+ function onCommit(listener) {
37
+ commitListeners.add(listener);
38
+ return () => {
39
+ commitListeners.delete(listener);
40
+ };
41
+ }
42
+ function record(rendererId, root) {
43
+ if (!(0, fiber_1.isFiberRoot)(root))
44
+ return;
45
+ let set = rootsByRenderer.get(rendererId);
46
+ if (!set) {
47
+ set = new Set();
48
+ rootsByRenderer.set(rendererId, set);
49
+ }
50
+ // A root with no children has been unmounted.
51
+ if (root.current.child === null)
52
+ set.delete(root);
53
+ else
54
+ set.add(root);
55
+ }
56
+ function forgetByFiber(fiber) {
57
+ if (!(0, fiber_1.isFiber)(fiber) || fiber.tag !== fiber_1.HostRoot)
58
+ return;
59
+ for (const set of rootsByRenderer.values()) {
60
+ for (const root of set) {
61
+ if (root.current === fiber || root.current.alternate === fiber || root === fiber.stateNode) {
62
+ set.delete(root);
63
+ }
64
+ }
65
+ }
66
+ }
67
+ function numberArg(value) {
68
+ return typeof value === 'number' ? value : 0;
69
+ }
70
+ function safely(fn) {
71
+ try {
72
+ fn();
73
+ }
74
+ catch {
75
+ // never break React because of Tapline
76
+ }
77
+ }
78
+ function wrap(hook, name, before) {
79
+ const previous = hook[name];
80
+ const wrapped = function (...args) {
81
+ safely(() => before(args));
82
+ return typeof previous === 'function' ? previous.apply(hook, args) : undefined;
83
+ };
84
+ hook[name] = wrapped;
85
+ }
86
+ function createHook() {
87
+ let nextId = 1;
88
+ const hook = {
89
+ supportsFiber: true,
90
+ renderers: new Map(),
91
+ inject(renderer) {
92
+ const id = nextId++;
93
+ hook.renderers?.set(id, renderer);
94
+ return id;
95
+ },
96
+ onCommitFiberRoot() { },
97
+ onCommitFiberUnmount() { },
98
+ onPostCommitFiberRoot() { },
99
+ checkDCE() { },
100
+ onScheduleFiberRoot() { },
101
+ setStrictMode() { },
102
+ sub() {
103
+ return () => { };
104
+ },
105
+ on() { },
106
+ off() { },
107
+ emit() { },
108
+ getFiberRoots(rendererId) {
109
+ return rootsByRenderer.get(rendererId) ?? new Set();
110
+ },
111
+ };
112
+ return hook;
113
+ }
114
+ /**
115
+ * Install (or wrap) the hook on `target` (default: globalThis). Idempotent per
116
+ * hook object. Returns the hook in effect.
117
+ */
118
+ function installHook(target = globalThis) {
119
+ const holder = target;
120
+ const existing = holder.__REACT_DEVTOOLS_GLOBAL_HOOK__;
121
+ let hook;
122
+ if ((0, types_1.isRecord)(existing)) {
123
+ hook = existing;
124
+ if (Object.prototype.hasOwnProperty.call(hook, WRAPPED)) {
125
+ installedHook = hook;
126
+ return hook;
127
+ }
128
+ }
129
+ else {
130
+ hook = createHook();
131
+ try {
132
+ Object.defineProperty(target, '__REACT_DEVTOOLS_GLOBAL_HOOK__', {
133
+ configurable: true,
134
+ enumerable: false,
135
+ writable: true,
136
+ value: hook,
137
+ });
138
+ }
139
+ catch {
140
+ holder.__REACT_DEVTOOLS_GLOBAL_HOOK__ = hook;
141
+ }
142
+ }
143
+ wrap(hook, 'onCommitFiberRoot', (args) => {
144
+ record(numberArg(args[0]), args[1]);
145
+ committed();
146
+ });
147
+ wrap(hook, 'onCommitFiberUnmount', (args) => forgetByFiber(args[1]));
148
+ Object.defineProperty(hook, WRAPPED, { value: true, enumerable: false });
149
+ installedHook = hook;
150
+ return hook;
151
+ }
152
+ /** All live fiber roots known to Tapline. */
153
+ function getRoots() {
154
+ const found = new Set();
155
+ for (const set of rootsByRenderer.values())
156
+ for (const root of set)
157
+ found.add(root);
158
+ // An already-present DevTools hook may know roots committed before we wrapped it.
159
+ const hook = installedHook;
160
+ if (hook && hook.renderers instanceof Map && typeof hook.getFiberRoots === 'function') {
161
+ for (const id of hook.renderers.keys()) {
162
+ safely(() => {
163
+ const roots = hook.getFiberRoots?.(id);
164
+ if (roots instanceof Set) {
165
+ for (const root of roots)
166
+ if ((0, fiber_1.isFiberRoot)(root))
167
+ found.add(root);
168
+ }
169
+ });
170
+ }
171
+ }
172
+ return [...found].filter((root) => root.current.child !== null);
173
+ }
174
+ /** Test helper: forget recorded roots and the installed-hook memory. */
175
+ function resetRegistry() {
176
+ rootsByRenderer.clear();
177
+ installedHook = null;
178
+ }
179
+ installHook();
180
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * AGENT-TOOLS §6: the screen counts as still after `quietMs` without a React commit, with a cap.
3
+ * Resolves with the milliseconds waited. Native-driver animations don't commit, so the tree can be
4
+ * still while pixels move; that's fine for an element list.
5
+ */
6
+ export declare function waitUntilStill(options: {
7
+ quietMs: number;
8
+ capMs: number;
9
+ onCommit: (listener: () => void) => () => void;
10
+ now: () => number;
11
+ /** Called when the wait ended at the cap, with the screen still changing. */
12
+ onCap?: () => void;
13
+ }): Promise<number>;
14
+ /**
15
+ * After the commits stop, a native-driver animation (a sheet sliding up) can still be moving.
16
+ * Polls `measure` every `pollMs` and resolves with the milliseconds waited once two readings in a
17
+ * row agree within 1 pt in x and y, or at `capMs`. A null reading (can't be measured) ends the wait.
18
+ */
19
+ export declare function waitUntilSteady(measure: () => Promise<{
20
+ x: number;
21
+ y: number;
22
+ } | null>, options: {
23
+ pollMs: number;
24
+ capMs: number;
25
+ now: () => number;
26
+ onCap?: () => void;
27
+ }): Promise<number>;
package/dist/settle.js ADDED
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.waitUntilStill = waitUntilStill;
4
+ exports.waitUntilSteady = waitUntilSteady;
5
+ /**
6
+ * AGENT-TOOLS §6: the screen counts as still after `quietMs` without a React commit, with a cap.
7
+ * Resolves with the milliseconds waited. Native-driver animations don't commit, so the tree can be
8
+ * still while pixels move; that's fine for an element list.
9
+ */
10
+ function waitUntilStill(options) {
11
+ const started = options.now();
12
+ return new Promise((resolve) => {
13
+ let done = false;
14
+ let quiet;
15
+ let unsubscribe = () => undefined;
16
+ const finish = () => {
17
+ if (done)
18
+ return;
19
+ done = true;
20
+ if (quiet !== undefined)
21
+ clearTimeout(quiet);
22
+ clearTimeout(cap);
23
+ unsubscribe();
24
+ resolve(Math.max(0, Math.min(options.capMs, options.now() - started)));
25
+ };
26
+ const cap = setTimeout(() => {
27
+ if (!done)
28
+ options.onCap?.();
29
+ finish();
30
+ }, options.capMs);
31
+ const restart = () => {
32
+ if (done)
33
+ return;
34
+ if (quiet !== undefined)
35
+ clearTimeout(quiet);
36
+ quiet = setTimeout(finish, options.quietMs);
37
+ };
38
+ unsubscribe = options.onCommit(restart);
39
+ restart();
40
+ });
41
+ }
42
+ /**
43
+ * After the commits stop, a native-driver animation (a sheet sliding up) can still be moving.
44
+ * Polls `measure` every `pollMs` and resolves with the milliseconds waited once two readings in a
45
+ * row agree within 1 pt in x and y, or at `capMs`. A null reading (can't be measured) ends the wait.
46
+ */
47
+ async function waitUntilSteady(measure, options) {
48
+ const started = options.now();
49
+ const elapsed = () => Math.max(0, Math.min(options.capMs, options.now() - started));
50
+ if (options.capMs <= 0)
51
+ return 0;
52
+ let previous = await measure();
53
+ if (previous === null)
54
+ return 0;
55
+ for (;;) {
56
+ const left = options.capMs - (options.now() - started);
57
+ if (left <= 0) {
58
+ options.onCap?.();
59
+ return elapsed();
60
+ }
61
+ await new Promise((resolve) => setTimeout(resolve, Math.min(options.pollMs, left)));
62
+ const next = await measure();
63
+ if (next === null)
64
+ return elapsed();
65
+ if (Math.abs(next.x - previous.x) <= 1 && Math.abs(next.y - previous.y) <= 1)
66
+ return elapsed();
67
+ previous = next;
68
+ }
69
+ }
70
+ //# sourceMappingURL=settle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settle.js","sourceRoot":"","sources":["../src/settle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /** Where Tapline remembers the paired computer and this install's id. */
2
+ export interface TaplineStorage {
3
+ getItem(key: string): Promise<string | null>;
4
+ setItem(key: string, value: string): Promise<void>;
5
+ removeItem(key: string): Promise<void>;
6
+ }
7
+ /** expo-secure-store when the app has it (keychain on iOS), else null. */
8
+ export declare function secureStoreStorage(): TaplineStorage | null;
9
+ /** Kept only while the app runs. */
10
+ export declare function memoryStorage(): TaplineStorage;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.secureStoreStorage = secureStoreStorage;
4
+ exports.memoryStorage = memoryStorage;
5
+ const types_1 = require("./types");
6
+ function isSecureStore(value) {
7
+ return ((0, types_1.isRecord)(value) &&
8
+ typeof value.getItemAsync === 'function' &&
9
+ typeof value.setItemAsync === 'function' &&
10
+ typeof value.deleteItemAsync === 'function');
11
+ }
12
+ /** expo-secure-store when the app has it (keychain on iOS), else null. */
13
+ function secureStoreStorage() {
14
+ let loaded;
15
+ try {
16
+ loaded = require('expo-secure-store');
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ const store = (0, types_1.isRecord)(loaded) && isSecureStore(loaded.default) ? loaded.default : loaded;
22
+ if (!isSecureStore(store))
23
+ return null;
24
+ return {
25
+ getItem: (key) => store.getItemAsync(key),
26
+ setItem: (key, value) => store.setItemAsync(key, value),
27
+ removeItem: (key) => store.deleteItemAsync(key),
28
+ };
29
+ }
30
+ /** Kept only while the app runs. */
31
+ function memoryStorage() {
32
+ const items = new Map();
33
+ return {
34
+ getItem: (key) => Promise.resolve(items.get(key) ?? null),
35
+ setItem: (key, value) => {
36
+ items.set(key, value);
37
+ return Promise.resolve();
38
+ },
39
+ removeItem: (key) => {
40
+ items.delete(key);
41
+ return Promise.resolve();
42
+ },
43
+ };
44
+ }
45
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":";;AAyBA,gDAcC;AAGD,sCAaC;AAvDD,mCAAmC;AAenC,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,CACL,IAAA,gBAAQ,EAAC,KAAK,CAAC;QACf,OAAO,KAAK,CAAC,YAAY,KAAK,UAAU;QACxC,OAAO,KAAK,CAAC,YAAY,KAAK,UAAU;QACxC,OAAO,KAAK,CAAC,eAAe,KAAK,UAAU,CAC5C,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,SAAgB,kBAAkB;IAChC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,KAAK,GAAG,IAAA,gBAAQ,EAAC,MAAM,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAC1F,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO;QACL,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC;QACzC,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC;QACvD,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC;KAChD,CAAC;AACJ,CAAC;AAED,oCAAoC;AACpC,SAAgB,aAAa;IAC3B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,OAAO;QACL,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;QACzD,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YACtB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACtB,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;QACD,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE;YAClB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAClB,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ /** At most one touch is passed on per this many milliseconds. */
2
+ export declare const TOUCH_THROTTLE_MS = 500;
3
+ export type TouchListener = (at: number) => void;
4
+ /** Calls `listener` (with the touch time) for each real touch that passes the throttle; returns the unsubscribe. */
5
+ export declare function onRealTouch(listener: TouchListener): () => void;
6
+ /**
7
+ * A touch started on the app. Returns true when it was passed on to the listeners; false when
8
+ * nobody listens (Tapline stopped) or it came within `TOUCH_THROTTLE_MS` of the last passed one.
9
+ * A touch that is dropped is not lost: when its window ends, one `touch` report with the time of the
10
+ * latest dropped touch goes out (so a second touch a person made inside the window shows up too).
11
+ * Never throws.
12
+ */
13
+ export declare function noteRealTouch(now: number): boolean;
14
+ /** Forgets the throttle and every listener (tests). */
15
+ export declare function resetTouches(): void;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ // Real touches. Tapline never touches the screen itself (an agent's `tap` calls the element's handler),
3
+ // so any touch that reaches the app's root is a person's finger, or another tool that makes real
4
+ // touches. The wrapper around the app's root (alerts.tsx) calls `noteRealTouch`; the client listens
5
+ // and tells the host, which then warns the agent that a person used the app.
6
+ //
7
+ // Limit: a React Native `Modal` is its own native window, so touches inside one never reach the
8
+ // wrapper and are not seen.
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.TOUCH_THROTTLE_MS = void 0;
11
+ exports.onRealTouch = onRealTouch;
12
+ exports.noteRealTouch = noteRealTouch;
13
+ exports.resetTouches = resetTouches;
14
+ /** At most one touch is passed on per this many milliseconds. */
15
+ exports.TOUCH_THROTTLE_MS = 500;
16
+ const listeners = new Set();
17
+ let lastPassedAt = null;
18
+ /** The time of the latest touch dropped in the current window; it is reported when the window ends. */
19
+ let droppedAt = null;
20
+ let trailing = null;
21
+ function cancelTrailing() {
22
+ if (trailing !== null)
23
+ clearTimeout(trailing);
24
+ trailing = null;
25
+ droppedAt = null;
26
+ }
27
+ function emit(at) {
28
+ for (const listener of [...listeners]) {
29
+ try {
30
+ listener(at);
31
+ }
32
+ catch {
33
+ // a listener must never reach the app
34
+ }
35
+ }
36
+ }
37
+ /** The window ended with touches dropped in it: report the latest of them once. */
38
+ function flushTrailing() {
39
+ trailing = null;
40
+ const at = droppedAt;
41
+ droppedAt = null;
42
+ if (at === null || lastPassedAt === null || listeners.size === 0)
43
+ return;
44
+ // The trailing report starts the next window, counted from where this one ended, so the rate
45
+ // stays at one per window however late the timer fires.
46
+ lastPassedAt += exports.TOUCH_THROTTLE_MS;
47
+ emit(at);
48
+ }
49
+ /** Calls `listener` (with the touch time) for each real touch that passes the throttle; returns the unsubscribe. */
50
+ function onRealTouch(listener) {
51
+ listeners.add(listener);
52
+ return () => {
53
+ listeners.delete(listener);
54
+ if (listeners.size === 0) {
55
+ lastPassedAt = null;
56
+ cancelTrailing();
57
+ }
58
+ };
59
+ }
60
+ /**
61
+ * A touch started on the app. Returns true when it was passed on to the listeners; false when
62
+ * nobody listens (Tapline stopped) or it came within `TOUCH_THROTTLE_MS` of the last passed one.
63
+ * A touch that is dropped is not lost: when its window ends, one `touch` report with the time of the
64
+ * latest dropped touch goes out (so a second touch a person made inside the window shows up too).
65
+ * Never throws.
66
+ */
67
+ function noteRealTouch(now) {
68
+ if (listeners.size === 0)
69
+ return false;
70
+ // A clock that went backwards must not silence touches until it catches up.
71
+ if (lastPassedAt !== null && now >= lastPassedAt && now - lastPassedAt < exports.TOUCH_THROTTLE_MS) {
72
+ droppedAt = now;
73
+ if (trailing === null)
74
+ trailing = setTimeout(flushTrailing, lastPassedAt + exports.TOUCH_THROTTLE_MS - now);
75
+ return false;
76
+ }
77
+ // A touch that passes covers every earlier one: nothing is left to report at the end of a window.
78
+ cancelTrailing();
79
+ lastPassedAt = now;
80
+ emit(now);
81
+ return true;
82
+ }
83
+ /** Forgets the throttle and every listener (tests). */
84
+ function resetTouches() {
85
+ listeners.clear();
86
+ lastPassedAt = null;
87
+ cancelTrailing();
88
+ }
89
+ //# sourceMappingURL=touches.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"touches.js","sourceRoot":"","sources":["../src/touches.ts"],"names":[],"mappings":";AAAA,wGAAwG;AACxG,iGAAiG;AACjG,oGAAoG;AACpG,6EAA6E;AAC7E,EAAE;AACF,gGAAgG;AAChG,4BAA4B;;;AA0C5B,kCASC;AASD,sCAaC;AAGD,oCAIC;AA9ED,iEAAiE;AACpD,QAAA,iBAAiB,GAAG,GAAG,CAAC;AAIrC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAiB,CAAC;AAC3C,IAAI,YAAY,GAAkB,IAAI,CAAC;AACvC,uGAAuG;AACvG,IAAI,SAAS,GAAkB,IAAI,CAAC;AACpC,IAAI,QAAQ,GAAyC,IAAI,CAAC;AAE1D,SAAS,cAAc;IACrB,IAAI,QAAQ,KAAK,IAAI;QAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC9C,QAAQ,GAAG,IAAI,CAAC;IAChB,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC;AAED,SAAS,IAAI,CAAC,EAAU;IACtB,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,SAAS,CAAC,EAAE,CAAC;QACtC,IAAI,CAAC;YACH,QAAQ,CAAC,EAAE,CAAC,CAAC;QACf,CAAC;QAAC,MAAM,CAAC;YACP,sCAAsC;QACxC,CAAC;IACH,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,SAAS,aAAa;IACpB,QAAQ,GAAG,IAAI,CAAC;IAChB,MAAM,EAAE,GAAG,SAAS,CAAC;IACrB,SAAS,GAAG,IAAI,CAAC;IACjB,IAAI,EAAE,KAAK,IAAI,IAAI,YAAY,KAAK,IAAI,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO;IACzE,6FAA6F;IAC7F,wDAAwD;IACxD,YAAY,IAAI,yBAAiB,CAAC;IAClC,IAAI,CAAC,EAAE,CAAC,CAAC;AACX,CAAC;AAED,oHAAoH;AACpH,SAAgB,WAAW,CAAC,QAAuB;IACjD,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxB,OAAO,GAAG,EAAE;QACV,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC3B,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACzB,YAAY,GAAG,IAAI,CAAC;YACpB,cAAc,EAAE,CAAC;QACnB,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,aAAa,CAAC,GAAW;IACvC,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,4EAA4E;IAC5E,IAAI,YAAY,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,IAAI,GAAG,GAAG,YAAY,GAAG,yBAAiB,EAAE,CAAC;QAC3F,SAAS,GAAG,GAAG,CAAC;QAChB,IAAI,QAAQ,KAAK,IAAI;YAAE,QAAQ,GAAG,UAAU,CAAC,aAAa,EAAE,YAAY,GAAG,yBAAiB,GAAG,GAAG,CAAC,CAAC;QACpG,OAAO,KAAK,CAAC;IACf,CAAC;IACD,kGAAkG;IAClG,cAAc,EAAE,CAAC;IACjB,YAAY,GAAG,GAAG,CAAC;IACnB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,IAAI,CAAC;AACd,CAAC;AAED,uDAAuD;AACvD,SAAgB,YAAY;IAC1B,SAAS,CAAC,KAAK,EAAE,CAAC;IAClB,YAAY,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,CAAC;AACnB,CAAC"}
@@ -0,0 +1,168 @@
1
+ /** Wire-protocol and shared types (see docs/PROTOCOL.md, version 1). */
2
+ export declare const PROTOCOL_VERSION = 1;
3
+ export type ErrorCode = 'not_found' | 'ambiguous' | 'not_actionable' | 'unsupported' | 'bad_params' | 'timeout' | 'internal';
4
+ export interface WireError {
5
+ code: ErrorCode;
6
+ message: string;
7
+ /** Candidate refs, only for `ambiguous`. */
8
+ refs?: string[];
9
+ /** The candidates as elements (role, id, actions, frame), only for `ambiguous`. */
10
+ candidates?: TaplineElement[];
11
+ }
12
+ /** An error that maps 1:1 onto a protocol error response. */
13
+ export declare class TaplineError extends Error {
14
+ readonly code: ErrorCode;
15
+ readonly refs: string[] | undefined;
16
+ readonly candidates: TaplineElement[] | undefined;
17
+ constructor(code: ErrorCode, message: string, refs?: string[], candidates?: TaplineElement[]);
18
+ toWire(): WireError;
19
+ }
20
+ export interface Frame {
21
+ x: number;
22
+ y: number;
23
+ width: number;
24
+ height: number;
25
+ }
26
+ export type Action = 'press' | 'longPress' | 'type' | 'submit' | 'toggle' | 'scroll';
27
+ export interface TaplineElement {
28
+ ref: string;
29
+ type: string;
30
+ role: string | null;
31
+ testID: string | null;
32
+ label: string | null;
33
+ /** The element's text, whitespace-collapsed; at most 2000 characters of it. */
34
+ text: string;
35
+ /** How many characters of the text were left out; absent when it is whole. */
36
+ textMore?: number;
37
+ /** TextInput content; null for everything else. */
38
+ value: string | null;
39
+ /** An empty TextInput's placeholder (AGENT-TOOLS v1.7); absent when the input has text or none. */
40
+ placeholder?: string;
41
+ /** Null only when the element could not be measured. */
42
+ frame: Frame | null;
43
+ actions: Action[];
44
+ disabled: boolean;
45
+ selected: boolean;
46
+ /** true / false / 'mixed' for checkable controls (Switch, checkbox role), else null. */
47
+ checked: boolean | 'mixed' | null;
48
+ }
49
+ export interface ScreenInfo {
50
+ width: number;
51
+ height: number;
52
+ scale: number;
53
+ }
54
+ export interface RouteInfo {
55
+ /** Route names from the outermost navigator to the focused screen, e.g. ["(tabs)", "nutrition"]. */
56
+ names: string[];
57
+ /** The focused screen's simple params (strings, numbers, booleans, null). */
58
+ params?: Record<string, string | number | boolean | null>;
59
+ }
60
+ /** What an element was before, for the fields that changed. */
61
+ export type ChangedFields = Partial<Pick<TaplineElement, 'text' | 'label' | 'value' | 'placeholder' | 'checked' | 'selected' | 'disabled' | 'actions'>>;
62
+ /** The difference from the previous `tree` call (only with `changes: true`). Refs of unchanged elements are kept. */
63
+ export interface TreeChanges {
64
+ /** Whether the focused route is the same as before. */
65
+ sameRoute: boolean;
66
+ /** Refs of elements that are new. */
67
+ added: string[];
68
+ /** Elements that are gone, as they were (their refs no longer work). */
69
+ removed: TaplineElement[];
70
+ /** Elements whose text, value, state or actions changed, with the old values. */
71
+ changed: Array<{
72
+ ref: string;
73
+ was: ChangedFields;
74
+ }>;
75
+ /** Refs of elements that only moved. */
76
+ moved: string[];
77
+ /**
78
+ * Elements off screen (above or below it, before and now) whose text, label, value or state
79
+ * changed, as they are now and without a ref, with the old values. At most 5; absent when none.
80
+ */
81
+ offScreen?: Array<{
82
+ element: TaplineElement;
83
+ was: ChangedFields;
84
+ }>;
85
+ /** How many more changed off screen than `offScreen` holds; absent when none. */
86
+ offScreenMore?: number;
87
+ /** The software keyboard came up or went down since then; absent when it didn't, or isn't known. */
88
+ keyboard?: 'shown' | 'hidden';
89
+ }
90
+ /** An alert the app showed and nobody has answered yet. */
91
+ export interface TreeAlert {
92
+ kind: 'alert' | 'prompt';
93
+ title: string;
94
+ message: string | null;
95
+ buttons: Array<{
96
+ text: string;
97
+ style: 'default' | 'cancel' | 'destructive';
98
+ }>;
99
+ /** Tapline's in-app stand-in (its buttons are elements to press) rather than the OS alert. */
100
+ standIn: boolean;
101
+ }
102
+ export interface TreeResult {
103
+ screen: ScreenInfo;
104
+ elements: TaplineElement[];
105
+ /** How many elements lie wholly above and below the screen (scroll to reach them); absent when none. */
106
+ offScreen?: {
107
+ above: number;
108
+ below: number;
109
+ };
110
+ /** Open alerts (Alert.alert / Alert.prompt) the app showed, oldest first. */
111
+ alerts?: TreeAlert[];
112
+ /** Network requests still running (fetch / XMLHttpRequest); absent when none. */
113
+ network?: {
114
+ inFlight: number;
115
+ };
116
+ /** True while the software keyboard is up; absent when it is down or isn't known. */
117
+ keyboard?: true;
118
+ /** The focused screen, when the app uses React Navigation (Expo Router included). */
119
+ route?: RouteInfo;
120
+ /** With `changes: true` and a previous tree: what changed since then. */
121
+ changes?: TreeChanges;
122
+ }
123
+ export type Target = {
124
+ ref: string;
125
+ index?: number;
126
+ } | {
127
+ testID: string;
128
+ index?: number;
129
+ } | {
130
+ label: string;
131
+ index?: number;
132
+ } | {
133
+ text: string;
134
+ index?: number;
135
+ } | {
136
+ x: number;
137
+ y: number;
138
+ index?: number;
139
+ };
140
+ export type LogLevel = 'log' | 'info' | 'warn' | 'error';
141
+ export interface LogEntry {
142
+ level: LogLevel;
143
+ message: string;
144
+ ts: number;
145
+ }
146
+ export interface ErrorEventData {
147
+ message: string;
148
+ stack: string;
149
+ fatal: boolean;
150
+ ts: number;
151
+ }
152
+ export interface AppInfo {
153
+ name?: string;
154
+ id?: string;
155
+ version?: string;
156
+ build?: string;
157
+ }
158
+ export interface DeviceInfo {
159
+ platform: string;
160
+ osVersion: string;
161
+ model?: string;
162
+ name?: string;
163
+ }
164
+ export type Json = string | number | boolean | null | Json[] | {
165
+ [key: string]: Json;
166
+ };
167
+ export type UnknownRecord = Record<string, unknown>;
168
+ export declare function isRecord(value: unknown): value is UnknownRecord;
package/dist/types.js ADDED
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ /** Wire-protocol and shared types (see docs/PROTOCOL.md, version 1). */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.TaplineError = exports.PROTOCOL_VERSION = void 0;
5
+ exports.isRecord = isRecord;
6
+ exports.PROTOCOL_VERSION = 1;
7
+ /** An error that maps 1:1 onto a protocol error response. */
8
+ class TaplineError extends Error {
9
+ code;
10
+ refs;
11
+ candidates;
12
+ constructor(code, message, refs, candidates) {
13
+ super(message);
14
+ this.name = 'TaplineError';
15
+ this.code = code;
16
+ this.refs = refs;
17
+ this.candidates = candidates;
18
+ }
19
+ toWire() {
20
+ const wire = { code: this.code, message: this.message };
21
+ if (this.refs)
22
+ wire.refs = this.refs;
23
+ if (this.candidates)
24
+ wire.candidates = this.candidates;
25
+ return wire;
26
+ }
27
+ }
28
+ exports.TaplineError = TaplineError;
29
+ function isRecord(value) {
30
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
31
+ }
32
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,wEAAwE;;;AAwLxE,4BAEC;AAxLY,QAAA,gBAAgB,GAAG,CAAC,CAAC;AAoBlC,6DAA6D;AAC7D,MAAa,YAAa,SAAQ,KAAK;IAC5B,IAAI,CAAY;IAChB,IAAI,CAAuB;IAC3B,UAAU,CAA+B;IAElD,YAAY,IAAe,EAAE,OAAe,EAAE,IAAe,EAAE,UAA6B;QAC1F,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,MAAM;QACJ,MAAM,IAAI,GAAc,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QACnE,IAAI,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACrC,IAAI,IAAI,CAAC,UAAU;YAAE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QACvD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAnBD,oCAmBC;AA8ID,SAAgB,QAAQ,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC"}