@qontinui/ui-bridge-native 0.6.12 → 0.6.14
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/README.md +36 -16
- package/dist/control/action-executor.d.ts +42 -2
- package/dist/control/action-executor.d.ts.map +1 -1
- package/dist/control/index.js +723 -4
- package/dist/control/index.js.map +1 -1
- package/dist/control/index.mjs +723 -5
- package/dist/control/index.mjs.map +1 -1
- package/dist/control/types.d.ts +82 -1
- package/dist/control/types.d.ts.map +1 -1
- package/dist/core/abortable.d.ts +151 -0
- package/dist/core/abortable.d.ts.map +1 -0
- package/dist/core/action-effect.d.ts +74 -0
- package/dist/core/action-effect.d.ts.map +1 -0
- package/dist/core/element-actions.d.ts +38 -0
- package/dist/core/element-actions.d.ts.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +756 -15
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +738 -16
- package/dist/core/index.mjs.map +1 -1
- package/dist/core/param-schema.d.ts +282 -0
- package/dist/core/param-schema.d.ts.map +1 -0
- package/dist/core/registry.d.ts +272 -2
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/core/types.d.ts +231 -32
- package/dist/core/types.d.ts.map +1 -1
- package/dist/debug/index.js.map +1 -1
- package/dist/debug/index.mjs.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1568 -135
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1550 -136
- package/dist/index.mjs.map +1 -1
- package/dist/react/UIBridgeNativeProvider.d.ts +18 -24
- package/dist/react/UIBridgeNativeProvider.d.ts.map +1 -1
- package/dist/react/index.js +1385 -130
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1385 -130
- package/dist/react/index.mjs.map +1 -1
- package/dist/react/useUIBridge.d.ts +19 -22
- package/dist/react/useUIBridge.d.ts.map +1 -1
- package/dist/react/useUIComponent.d.ts +113 -8
- package/dist/react/useUIComponent.d.ts.map +1 -1
- package/dist/react/useUIElement.d.ts +34 -8
- package/dist/react/useUIElement.d.ts.map +1 -1
- package/dist/server/handlers.d.ts.map +1 -1
- package/dist/server/http-server.d.ts +15 -2
- package/dist/server/http-server.d.ts.map +1 -1
- package/dist/server/index.js +345 -43
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +345 -44
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/observability.d.ts +40 -0
- package/dist/server/observability.d.ts.map +1 -1
- package/dist/server/types.d.ts +57 -1
- package/dist/server/types.d.ts.map +1 -1
- package/dist/transport/CloudRelayClient.d.ts.map +1 -1
- package/dist/transport/DeviceAnnouncer.d.ts +35 -7
- package/dist/transport/DeviceAnnouncer.d.ts.map +1 -1
- package/dist/transport/index.d.ts +1 -1
- package/dist/transport/index.d.ts.map +1 -1
- package/dist/transport/relay-logging.d.ts +50 -0
- package/dist/transport/relay-logging.d.ts.map +1 -0
- package/package.json +2 -2
package/dist/control/types.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Types for action execution and control operations.
|
|
5
5
|
*/
|
|
6
6
|
import type { NativeActionRequest, NativeActionResponse, NativeFindRequest, NativeFindResponse, NativeElementState, WaitOptions } from '../core/types';
|
|
7
|
+
import type { ParamValidationMode } from '../core/param-schema';
|
|
7
8
|
/**
|
|
8
9
|
* Extended action request with control-specific options
|
|
9
10
|
*/
|
|
@@ -24,6 +25,13 @@ export interface ControlActionRequest extends NativeActionRequest {
|
|
|
24
25
|
export interface ControlActionResponse extends NativeActionResponse {
|
|
25
26
|
/** Request ID for correlation */
|
|
26
27
|
requestId?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Machine-readable failure code, set only when an action failed for a
|
|
30
|
+
* reason with an honest code of its own — today only `NOT_SUPPORTED`
|
|
31
|
+
* (`scrollIntoView` with no usable declared scroll container). Absent on
|
|
32
|
+
* every other failure, which the HTTP handler reports as `ACTION_FAILED`.
|
|
33
|
+
*/
|
|
34
|
+
code?: string;
|
|
27
35
|
/** Retry count */
|
|
28
36
|
retryCount?: number;
|
|
29
37
|
}
|
|
@@ -37,6 +45,57 @@ export interface ComponentActionRequest {
|
|
|
37
45
|
params?: Record<string, unknown>;
|
|
38
46
|
/** Request ID for correlation */
|
|
39
47
|
requestId?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Abandon the action if it has not produced a result within this many
|
|
50
|
+
* milliseconds (plan `2026-08-20-ui-bridge-action-declaration-shape`,
|
|
51
|
+
* Phase 3). Omitted = no timeout.
|
|
52
|
+
*
|
|
53
|
+
* The wire-reachable half of cancellation: an `AbortSignal` cannot be
|
|
54
|
+
* JSON-serialized, so an HTTP caller has no other way to call off a hung
|
|
55
|
+
* handler. In-process callers should prefer the `{ signal }` option bag on
|
|
56
|
+
* `executeComponentAction`; whichever fires first wins.
|
|
57
|
+
*
|
|
58
|
+
* Abandonment does not depend on the handler observing its signal — the
|
|
59
|
+
* executor races the handler promise.
|
|
60
|
+
*
|
|
61
|
+
* **Validated and clamped at the executor**, so no wire caller reaches a
|
|
62
|
+
* timer unchecked: `0` abandons on the next tick; a negative, `NaN`,
|
|
63
|
+
* infinite or non-numeric value is REFUSED (the response is `success: false`
|
|
64
|
+
* naming `timeoutMs`); anything above 24h is clamped, because past 2^31-1
|
|
65
|
+
* `setTimeout` wraps negative and fires immediately. See
|
|
66
|
+
* `core/abortable.ts` `normalizeActionTimeoutMs`.
|
|
67
|
+
*/
|
|
68
|
+
timeoutMs?: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Per-invocation options for `NativeActionExecutor.executeComponentAction`.
|
|
72
|
+
*
|
|
73
|
+
* In-process only — nothing here survives JSON serialization, which is why the
|
|
74
|
+
* wire-reachable timeout lives on {@link ComponentActionRequest} instead.
|
|
75
|
+
*
|
|
76
|
+
* Mirrors `@qontinui/ui-bridge` `ComponentActionInvokeOptions`; kept local
|
|
77
|
+
* because that package is an OPTIONAL peer dependency here (see
|
|
78
|
+
* `core/types.ts`).
|
|
79
|
+
*/
|
|
80
|
+
export interface ComponentActionInvokeOptions {
|
|
81
|
+
/**
|
|
82
|
+
* Cancellation signal owned by the caller. Aborting it abandons the
|
|
83
|
+
* invocation whether or not the handler observes the signal it is given.
|
|
84
|
+
*/
|
|
85
|
+
signal?: AbortSignal;
|
|
86
|
+
/**
|
|
87
|
+
* What to do when `params` violate the action's declared `paramSchema`
|
|
88
|
+
* (Phase 2). Omitted = `getDefaultParamValidationMode()`, which starts at
|
|
89
|
+
* `'warn'`. Deliberately NOT on {@link ComponentActionRequest}: enforcement
|
|
90
|
+
* is a deployment's policy, not the validated caller's to switch off.
|
|
91
|
+
*
|
|
92
|
+
* NOTE: this tree's {@link ComponentActionResponse} carries no
|
|
93
|
+
* `failureDetails`, so an enforced rejection surfaces as a prose `error`
|
|
94
|
+
* naming each offending param — the same limitation Phase 3's cancellation
|
|
95
|
+
* path hit here. Giving the native channel structured failure details is a
|
|
96
|
+
* separate change.
|
|
97
|
+
*/
|
|
98
|
+
paramValidation?: ParamValidationMode;
|
|
40
99
|
}
|
|
41
100
|
/**
|
|
42
101
|
* Component action response
|
|
@@ -97,7 +156,7 @@ export interface NativeActionExecutor {
|
|
|
97
156
|
/**
|
|
98
157
|
* Execute a component action
|
|
99
158
|
*/
|
|
100
|
-
executeComponentAction(componentId: string, request: ComponentActionRequest): Promise<ComponentActionResponse>;
|
|
159
|
+
executeComponentAction(componentId: string, request: ComponentActionRequest, options?: ComponentActionInvokeOptions): Promise<ComponentActionResponse>;
|
|
101
160
|
/**
|
|
102
161
|
* Find elements
|
|
103
162
|
*/
|
|
@@ -168,6 +227,28 @@ export interface ScrollActionParams {
|
|
|
168
227
|
/** Animate the scroll */
|
|
169
228
|
animated?: boolean;
|
|
170
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* `scrollIntoView` action params.
|
|
232
|
+
*
|
|
233
|
+
* Vertical containers only. A container declared `horizontal` is answered
|
|
234
|
+
* `NOT_SUPPORTED` where the bridge can see the declaration (captured props, or
|
|
235
|
+
* a FlatList / SectionList instance), or where the element is measured laid
|
|
236
|
+
* out beyond the container's width — which also refuses an element wider than
|
|
237
|
+
* its vertical container, or one inside a nested horizontal carousel whose
|
|
238
|
+
* declared ancestor is the outer vertical feed; see `performScrollIntoView`.
|
|
239
|
+
*/
|
|
240
|
+
export interface ScrollIntoViewActionParams {
|
|
241
|
+
/**
|
|
242
|
+
* Gap (logical dp) left between the top of the scroll container's viewport
|
|
243
|
+
* and the element after scrolling. Finite and non-negative; default 16.
|
|
244
|
+
*
|
|
245
|
+
* Measured from the container's CONTENT origin, so a `paddingTop` on the
|
|
246
|
+
* ScrollView's own style, or an iOS `contentInset.top` / automatic
|
|
247
|
+
* safe-area inset, shifts where the element lands — add it here if the row
|
|
248
|
+
* must clear a header.
|
|
249
|
+
*/
|
|
250
|
+
padding?: number;
|
|
251
|
+
}
|
|
171
252
|
/**
|
|
172
253
|
* Swipe action params
|
|
173
254
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/control/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACZ,MAAM,eAAe,CAAC;AAEvB;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,mBAAmB;IAC/D,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oBAAoB;IACpB,YAAY,CAAC,EAAE;QACb,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IACjE,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,2BAA2B;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,kCAAkC;IAClC,GAAG,EAAE,OAAO,CAAC;IACb,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAEhG;;OAEG;IACH,sBAAsB,CACpB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,sBAAsB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/control/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abandonment primitive for action invocation.
|
|
3
|
+
*
|
|
4
|
+
* Plan `2026-08-20-ui-bridge-action-declaration-shape`, Phase 3.
|
|
5
|
+
*
|
|
6
|
+
* `ActionHandler`'s `options.signal` is **cooperative**: a well-behaved handler
|
|
7
|
+
* observes it and returns early. Cooperation cannot be enforced, and a handler
|
|
8
|
+
* that hangs is exactly the case cancellation exists for — so the executor
|
|
9
|
+
* never trusts the handler to observe the signal. It races the handler promise
|
|
10
|
+
* against the abort and reports the outcome either way.
|
|
11
|
+
*
|
|
12
|
+
* DUPLICATE OF `@qontinui/ui-bridge` `src/core/abortable.ts` — DELIBERATELY NOT
|
|
13
|
+
* AN IMPORT. `@qontinui/ui-bridge` is an OPTIONAL peerDependency of this
|
|
14
|
+
* package and is absent from `dependencies`, so a consumer may install
|
|
15
|
+
* `@qontinui/ui-bridge-native` alone; importing from it would resolve inside
|
|
16
|
+
* this monorepo and then fail for that consumer. See the same note on
|
|
17
|
+
* `core/types.ts` `ActionHandler`.
|
|
18
|
+
*
|
|
19
|
+
* KEEP IN SYNC with `@qontinui/ui-bridge` `src/core/abortable.ts` — including
|
|
20
|
+
* `MAX_ACTION_TIMEOUT_MS` and `normalizeActionTimeoutMs` below. The module has
|
|
21
|
+
* no imports and touches no DOM API — only `AbortController` and `setTimeout`,
|
|
22
|
+
* both present in React Native.
|
|
23
|
+
*/
|
|
24
|
+
/** Which of the two cancellation sources fired. */
|
|
25
|
+
export type AbortReason = 'signal' | 'timeout';
|
|
26
|
+
/**
|
|
27
|
+
* Ceiling applied to a caller-supplied `timeoutMs` — **24 hours**.
|
|
28
|
+
*
|
|
29
|
+
* `ComponentActionRequest.timeoutMs` crosses the wire, so it is attacker- (or
|
|
30
|
+
* typo-) controlled: an HTTP or WebSocket caller can put any JSON number in
|
|
31
|
+
* it and it would otherwise land in `setTimeout` unchecked. Two concrete
|
|
32
|
+
* hazards that ceiling closes:
|
|
33
|
+
*
|
|
34
|
+
* - **`setTimeout`'s 32-bit delay overflow.** Any delay above 2147483647ms
|
|
35
|
+
* wraps to a *negative* 32-bit int in every major runtime and the timer
|
|
36
|
+
* fires **immediately** — so `timeoutMs: 2147483648` ("about 25 days,
|
|
37
|
+
* effectively no timeout") would abandon the action on the next tick, the
|
|
38
|
+
* exact opposite of what the caller asked for. Clamping below that boundary
|
|
39
|
+
* makes the semantics monotonic: a bigger number never means a shorter wait.
|
|
40
|
+
* - **A pinned timer per in-flight request.** Nothing here is unbounded work,
|
|
41
|
+
* but a 100-year timeout is indistinguishable from "no timeout" while still
|
|
42
|
+
* holding the handler's abandonment machinery alive, so there is nothing to
|
|
43
|
+
* buy above a day.
|
|
44
|
+
*
|
|
45
|
+
* Clamping (rather than rejecting) is right at the top end because the intent
|
|
46
|
+
* is unambiguous — "effectively forever" — and the clamped value honours it as
|
|
47
|
+
* closely as the platform can. The malformed cases below are rejected instead,
|
|
48
|
+
* because there the intent is NOT recoverable.
|
|
49
|
+
*/
|
|
50
|
+
export declare const MAX_ACTION_TIMEOUT_MS = 86400000;
|
|
51
|
+
/**
|
|
52
|
+
* Outcome of {@link normalizeActionTimeoutMs}. Discriminated on `ok` so a
|
|
53
|
+
* rejected value cannot be read as a timeout by accident.
|
|
54
|
+
*/
|
|
55
|
+
export type TimeoutNormalization = {
|
|
56
|
+
ok: true;
|
|
57
|
+
/** `undefined` ≡ no timeout. Always a finite integer in `[0, MAX]`. */
|
|
58
|
+
timeoutMs: number | undefined;
|
|
59
|
+
/** True iff the caller's value was above {@link MAX_ACTION_TIMEOUT_MS}. */
|
|
60
|
+
clamped: boolean;
|
|
61
|
+
} | {
|
|
62
|
+
ok: false;
|
|
63
|
+
reason: string;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Validate and clamp a wire-supplied `timeoutMs` before it can reach a timer.
|
|
67
|
+
*
|
|
68
|
+
* The policy, stated once so all three executors share it:
|
|
69
|
+
*
|
|
70
|
+
* | Supplied | Result | Why |
|
|
71
|
+
* |---|---|---|
|
|
72
|
+
* | absent / `null` | no timeout | the documented "omitted ⇒ no timeout" default |
|
|
73
|
+
* | `0` | abandon on the next tick | a coherent request ("don't let it run"), and what `setTimeout(…, 0)` already means |
|
|
74
|
+
* | `1 … MAX` | honoured, floored to an integer | fractional ms is not a thing a timer can express |
|
|
75
|
+
* | `> MAX` | clamped to {@link MAX_ACTION_TIMEOUT_MS} | see that constant — above 2^31-1 the platform timer silently inverts |
|
|
76
|
+
* | negative | **rejected** | `setTimeout` would treat it as `0`, i.e. a sign typo would abandon every call instantly and silently |
|
|
77
|
+
* | `NaN` / `±Infinity` | **rejected** | `setTimeout(NaN)` is `setTimeout(0)` — same silent-instant-abandon trap |
|
|
78
|
+
* | not a number (`"5000"`, `{}`, `true`) | **rejected** | JSON has numbers; a string here means the caller built the body wrong, and coercing would hide it |
|
|
79
|
+
*
|
|
80
|
+
* Rejection is loud on purpose: every rejected case is one where *ignoring*
|
|
81
|
+
* the field fails open (the action runs uncancellable) and *coercing* it fails
|
|
82
|
+
* closed at zero. Neither is what the caller asked for, and both are silent —
|
|
83
|
+
* which is the defect class this whole plan exists to remove.
|
|
84
|
+
*/
|
|
85
|
+
export declare function normalizeActionTimeoutMs(raw: unknown): TimeoutNormalization;
|
|
86
|
+
/**
|
|
87
|
+
* Result of {@link runAbortable}. Discriminated on `aborted` so the caller
|
|
88
|
+
* cannot read `result` off an abandoned invocation.
|
|
89
|
+
*/
|
|
90
|
+
export type AbortableOutcome<T> = {
|
|
91
|
+
aborted: false;
|
|
92
|
+
result: T;
|
|
93
|
+
} | {
|
|
94
|
+
aborted: true;
|
|
95
|
+
reason: AbortReason;
|
|
96
|
+
};
|
|
97
|
+
/** Cancellation sources composed by {@link runAbortable}. */
|
|
98
|
+
export interface RunAbortableOptions {
|
|
99
|
+
/**
|
|
100
|
+
* An in-process caller's signal. Cannot cross the wire — that is what
|
|
101
|
+
* `timeoutMs` is for.
|
|
102
|
+
*/
|
|
103
|
+
signal?: AbortSignal;
|
|
104
|
+
/**
|
|
105
|
+
* Milliseconds after which the invocation is abandoned. Serializable, so
|
|
106
|
+
* this is the arm an HTTP/WebSocket caller can actually use.
|
|
107
|
+
*
|
|
108
|
+
* Expected to have been through {@link normalizeActionTimeoutMs} already —
|
|
109
|
+
* every executor seam runs it, because this value arrives from the wire.
|
|
110
|
+
* The `Number.isFinite` / `>= 0` guard below is defence in depth for a
|
|
111
|
+
* direct in-process caller, and ignores anything malformed rather than
|
|
112
|
+
* letting it reach `setTimeout`.
|
|
113
|
+
*/
|
|
114
|
+
timeoutMs?: number;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* A fresh `AbortSignal` that is never aborted.
|
|
118
|
+
*
|
|
119
|
+
* `ActionHandlerOptions` promises the bag is *always* supplied, so a handler
|
|
120
|
+
* written the way the docs describe — `(params, { signal }) => …` — must never
|
|
121
|
+
* be called with `undefined` as its second argument. Not every invocation seam
|
|
122
|
+
* has a cancellation source to give it though: an ELEMENT custom action
|
|
123
|
+
* (`ControlActionRequest`) carries no `timeoutMs` and the executor holds no
|
|
124
|
+
* controller for it, so there is nothing that could ever abort. Those seams
|
|
125
|
+
* pass this instead of `undefined`, which keeps the destructure safe and keeps
|
|
126
|
+
* `signal.aborted` honestly `false`.
|
|
127
|
+
*
|
|
128
|
+
* **Fresh per call, deliberately.** A shared singleton would accumulate one
|
|
129
|
+
* listener per handler that calls `signal.addEventListener('abort', …)` and
|
|
130
|
+
* never releases them — a leak on a hot path. A `AbortController` allocation
|
|
131
|
+
* is a few bytes and custom element actions are not a hot path.
|
|
132
|
+
*
|
|
133
|
+
* When element actions grow a cancellation source, replace the call sites with
|
|
134
|
+
* a real `runAbortable` race — the handler contract does not change.
|
|
135
|
+
*/
|
|
136
|
+
export declare function inertAbortSignal(): AbortSignal;
|
|
137
|
+
/**
|
|
138
|
+
* Invoke `invoke` with a derived `AbortSignal`, abandoning it if either the
|
|
139
|
+
* caller's signal aborts or `timeoutMs` elapses.
|
|
140
|
+
*
|
|
141
|
+
* - Returns `{ aborted: true, reason }` **without invoking at all** when the
|
|
142
|
+
* caller's signal is already aborted.
|
|
143
|
+
* - Returns `{ aborted: false, result }` on normal completion.
|
|
144
|
+
* - **Rejects** if `invoke` throws/rejects while the race is still live, so a
|
|
145
|
+
* genuine handler error stays distinguishable from a cancellation.
|
|
146
|
+
* - A rejection that arrives *after* an abort already won is swallowed:
|
|
147
|
+
* `Promise.race` has a rejection handler attached, so the abandoned handler
|
|
148
|
+
* cannot surface as an unhandled rejection.
|
|
149
|
+
*/
|
|
150
|
+
export declare function runAbortable<T>(invoke: (signal: AbortSignal) => T | Promise<T>, options?: RunAbortableOptions): Promise<AbortableOutcome<T>>;
|
|
151
|
+
//# sourceMappingURL=abortable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abortable.d.ts","sourceRoot":"","sources":["../../src/core/abortable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,mDAAmD;AACnD,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,qBAAqB,WAAa,CAAC;AAEhD;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IACE,EAAE,EAAE,IAAI,CAAC;IACT,uEAAuE;IACvE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,2EAA2E;IAC3E,OAAO,EAAE,OAAO,CAAC;CAClB,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,oBAAoB,CA0B3E;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAC1B;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,CAAC,CAAA;CAAE,GAC7B;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC;AAE3C,6DAA6D;AAC7D,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,IAAI,WAAW,CAE9C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAClC,MAAM,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC/C,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAsD9B"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action effect defaults for `@qontinui/ui-bridge-native`.
|
|
3
|
+
*
|
|
4
|
+
* Plan `2026-08-20-ui-bridge-action-declaration-shape`, Phase 4.
|
|
5
|
+
*
|
|
6
|
+
* `IREffect` ("read" | "write" | "destructive") has exactly one job: **exclude
|
|
7
|
+
* destructive actions from automatic walks.** Two sources feed it, in order:
|
|
8
|
+
*
|
|
9
|
+
* 1. `action.effect` — the author's explicit per-registration declaration.
|
|
10
|
+
* 2. `NATIVE_STANDARD_ACTION_EFFECTS[action.id]` — the static default below.
|
|
11
|
+
*
|
|
12
|
+
* **1 wins.** A static `press → write` map is wrong precisely on a delete
|
|
13
|
+
* control — guaranteed wrong in the one case the annotation exists for — and it
|
|
14
|
+
* fails *open*, so an unmarked destructive action gets walked.
|
|
15
|
+
*
|
|
16
|
+
* DUPLICATE of `@qontinui/ui-bridge` `src/core/action-effect.ts` +
|
|
17
|
+
* `src/native/core/action-effect.ts`, and deliberately not a re-export:
|
|
18
|
+
* `@qontinui/ui-bridge` is an OPTIONAL peer of this package, so a consumer may
|
|
19
|
+
* install `@qontinui/ui-bridge-native` alone. Same constraint that keeps
|
|
20
|
+
* `ActionHandler` / `ComponentAction` / `IREffect` duplicated in
|
|
21
|
+
* `./types` — see the long note there. KEEP IN SYNC.
|
|
22
|
+
*/
|
|
23
|
+
import type { IREffect, NativeStandardAction } from './types';
|
|
24
|
+
/**
|
|
25
|
+
* Static default effect for each {@link NativeStandardAction} verb.
|
|
26
|
+
*
|
|
27
|
+
* Typed `Record<NativeStandardAction, IREffect>` so adding a verb without
|
|
28
|
+
* classifying it is a compile error — a *map* silently falling behind the
|
|
29
|
+
* *union* it describes is exactly the drift class this plan exists to fix.
|
|
30
|
+
*
|
|
31
|
+
* **No verb maps to `'destructive'`, and none ever should.** Destructiveness
|
|
32
|
+
* is a property of what a control does, not of the verb used to reach it;
|
|
33
|
+
* `'destructive'` is reachable only through an explicit `effect`.
|
|
34
|
+
*
|
|
35
|
+
* The non-obvious calls, justified:
|
|
36
|
+
*
|
|
37
|
+
* - **`longPress` → `read`.** The touch analogue of a right-click: it reveals
|
|
38
|
+
* a context menu / selection affordance. Long-press is *associated* with
|
|
39
|
+
* delete on mobile, but it only surfaces the option — the delete is a
|
|
40
|
+
* separate press with its own effect.
|
|
41
|
+
* - **`swipe` → `write`.** Genuinely ambiguous, and it resolves the other way
|
|
42
|
+
* from `longPress`: a swipe is sometimes just a scroll gesture (read), but
|
|
43
|
+
* swipe-to-delete / swipe-to-archive **commits on the gesture itself**, with
|
|
44
|
+
* nothing in the verb to tell the two apart. It takes the more cautious
|
|
45
|
+
* classification, and a swipe-to-delete row must still declare
|
|
46
|
+
* `effect: 'destructive'`.
|
|
47
|
+
* - **`focus` / `blur` → `read`.** They move focus, which is UI state, not
|
|
48
|
+
* persistent state.
|
|
49
|
+
* - **`scrollIntoView` → `read`.** It moves the declared scroll container's
|
|
50
|
+
* content offset (UI state) and fires no element handler.
|
|
51
|
+
*
|
|
52
|
+
* Note this union carries `click`, `setValue` and `scrollIntoView` that the
|
|
53
|
+
* `@qontinui/ui-bridge` `native/core` copy does not — a real divergence
|
|
54
|
+
* between the two native unions, not a sync error.
|
|
55
|
+
*/
|
|
56
|
+
export declare const NATIVE_STANDARD_ACTION_EFFECTS: Record<NativeStandardAction, IREffect>;
|
|
57
|
+
/**
|
|
58
|
+
* The static default for a native action id, or `undefined` when the id is not
|
|
59
|
+
* one of the native standard verbs (the normal case for a `ComponentAction`,
|
|
60
|
+
* whose ids are free-form).
|
|
61
|
+
*
|
|
62
|
+
* `undefined` means **unknown**, not "safe" — a caller that walks unknown
|
|
63
|
+
* actions is choosing to fail open and should say so.
|
|
64
|
+
*/
|
|
65
|
+
export declare function nativeStandardActionEffect(actionId: string): IREffect | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Resolve the effective annotation for a declared action: **explicit
|
|
68
|
+
* declaration first, static verb map second.**
|
|
69
|
+
*/
|
|
70
|
+
export declare function resolveActionEffect(action: {
|
|
71
|
+
id: string;
|
|
72
|
+
effect?: IREffect;
|
|
73
|
+
}): IREffect | undefined;
|
|
74
|
+
//# sourceMappingURL=action-effect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-effect.d.ts","sourceRoot":"","sources":["../../src/core/action-effect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,8BAA8B,EAAE,MAAM,CAAC,oBAAoB,EAAE,QAAQ,CAiBjF,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAIjF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB,GAAG,QAAQ,GAAG,SAAS,CAEvB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE wire projection for an element's custom actions.
|
|
3
|
+
*
|
|
4
|
+
* Plan `2026-09-04-effect-calculus-joins-the-component-action-registry`,
|
|
5
|
+
* Design decision 4 step 3.
|
|
6
|
+
*
|
|
7
|
+
* DUPLICATE of `@qontinui/ui-bridge` `src/core/element-actions.ts`, for the same
|
|
8
|
+
* reason the types beside it are duplicated: this package must not import from
|
|
9
|
+
* `@qontinui/ui-bridge` (an optional peer). KEEP IN SYNC — a divergence here is
|
|
10
|
+
* a divergence in what the two channels advertise about the same annotation.
|
|
11
|
+
*
|
|
12
|
+
* ---------------------------------------------------------------------------
|
|
13
|
+
* WHAT THIS DOES NOT DO: default the effect
|
|
14
|
+
* ---------------------------------------------------------------------------
|
|
15
|
+
*
|
|
16
|
+
* `effect` is carried through **verbatim and undefaulted**. An action whose
|
|
17
|
+
* author declared nothing is emitted with `effect` absent, never with a
|
|
18
|
+
* manufactured `'read'` — a default rendered as a declaration is a fail-open lie
|
|
19
|
+
* on exactly the surface the annotation exists to protect. **Absent means
|
|
20
|
+
* UNCLASSIFIED, not safe**, which is what served policy `operating-rules`
|
|
21
|
+
* `what-makes-an-action-destructive` requires of an unestablished effect.
|
|
22
|
+
*/
|
|
23
|
+
import type { CustomAction, SerializedElementAction } from './types';
|
|
24
|
+
type ProjectableCustomActions = Record<string, Pick<CustomAction, 'label' | 'description' | 'effect'> | undefined>;
|
|
25
|
+
/**
|
|
26
|
+
* Project `RegisteredNativeElement.customActions` to its wire shape.
|
|
27
|
+
*
|
|
28
|
+
* - `undefined` in → `undefined` out (an element with no custom actions must not
|
|
29
|
+
* start emitting `[]`; `JSON.stringify` keeps `[]` and drops `undefined`).
|
|
30
|
+
* - An empty record in → `[]` out, matching what `Object.keys({})` gave before.
|
|
31
|
+
*
|
|
32
|
+
* The emitted `id` is the RECORD KEY — the executor dispatches by key, so the
|
|
33
|
+
* key is the name a caller must send. Nullish entries are skipped: they carry no
|
|
34
|
+
* handler, so advertising them would advertise a capability that does not exist.
|
|
35
|
+
*/
|
|
36
|
+
export declare function serializeElementCustomActions(customActions: ProjectableCustomActions | undefined): SerializedElementAction[] | undefined;
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=element-actions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"element-actions.d.ts","sourceRoot":"","sources":["../../src/core/element-actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAErE,KAAK,wBAAwB,GAAG,MAAM,CACpC,MAAM,EACN,IAAI,CAAC,YAAY,EAAE,OAAO,GAAG,aAAa,GAAG,QAAQ,CAAC,GAAG,SAAS,CACnE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,wBAAwB,GAAG,SAAS,GAClD,uBAAuB,EAAE,GAAG,SAAS,CAcvC"}
|
package/dist/core/index.d.ts
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* Core types and registry for React Native.
|
|
5
5
|
*/
|
|
6
6
|
export * from './types';
|
|
7
|
+
export * from './abortable';
|
|
8
|
+
export * from './param-schema';
|
|
9
|
+
export * from './action-effect';
|
|
7
10
|
export * from './registry';
|
|
8
11
|
export * from './element-identifier';
|
|
12
|
+
export { serializeElementCustomActions } from './element-actions';
|
|
9
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/core/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,SAAS,CAAC;AAGxB,cAAc,aAAa,CAAC;AAG5B,cAAc,gBAAgB,CAAC;AAG/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AAGrC,OAAO,EAAE,6BAA6B,EAAE,MAAM,mBAAmB,CAAC"}
|