@danxbot/ui 4.1.12 → 5.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.
- package/dist/index.js +6146 -6098
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/lib/reads/index.d.ts +1 -1
- package/dist/types/lib/reads/slots.d.ts +16 -4
- package/dist/types/lib/reads/types.d.ts +21 -10
- package/dist/types/lib/realtime/index.d.ts +1 -1
- package/dist/types/lib/realtime/registry.d.ts +21 -0
- package/dist/types/lib/realtime/types.d.ts +44 -4
- package/package.json +1 -1
package/dist/types/index.d.ts
CHANGED
|
@@ -113,5 +113,5 @@ export { ProvenanceDisclosure, ProvenanceDetail, ProvenanceBadge, ConfidenceRead
|
|
|
113
113
|
export { createSimStore, resetSimStores, useSimSettings, setSimSettings, getNetworkSpeed, getDataSource, simulateLatency, SimNetworkError, type SimStore, type SimStoreOptions, type SimSettings, type NetworkSpeed, type DataSource, type SimNamespace, } from "./lib/sim";
|
|
114
114
|
export { NodeCanvas, LAYOUT_DEFAULTS, layoutTree, pathToNode, type NodeCanvasProps, type CanvasEdge, type CanvasLayout, type CanvasNode, type CanvasOrientation, type LayoutOptions, type NodeRenderContext, type NodeRenderer, type PlacedNode, } from "./components/node-canvas";
|
|
115
115
|
export { defineRecordType, resetRecordTypes, useRecord, useRecords, useStaleness, write, writeAll, peekRecord, readState, readStaleness, subscribeToKey, subscribeToStaleness, retainKeys, sweepRecords, setRecordStoreTenant, getRecordStoreTenant, flushRecordNotifications, resetRecordStore, recordStoreStats, UNKNOWN_STATE, normalizeTypeName, normalizeTimestamp, recordKey, isRecordRef, type RecordRef, type ReadOptions, type RecordPayload, type RecordState, type RecordTypeOptions, type RecordTypeToken, type StalenessEntry, type WriteAllResult, type WriteOptions, type WriteResult, type WriteSource, type WriteVerdict, } from "./lib/records";
|
|
116
|
-
export { RealtimeProvider, useRealtime, useRealtimeEpoch, useRealtimeHealth, useRealtimeRegistry, SubscriptionRegistry, normalizeScope, scopeKey, readRealtimeEpoch, subscribeToRealtimeEpoch, subscribeToRealtimeEvents, resetRealtimeSignals, type RealtimeChannel, type RealtimeConnectionState, type RealtimeDiagnostic, type RealtimeEvent, type RealtimeHealth, type RealtimeProviderProps, type RealtimeScope, type RealtimeScopeInput, type RealtimeStatus, type RealtimeTransport, type RegistryOptions, type SubscriptionHealth, type SubscriptionLease, type SubscriptionRequest, } from "./lib/realtime";
|
|
117
|
-
export { useRecordRead, useRecordListRead, useRecordStoreSweep, applyMutationResult, acquireSlot,
|
|
116
|
+
export { RealtimeProvider, useRealtime, useRealtimeEpoch, useRealtimeHealth, useRealtimeRegistry, SubscriptionRegistry, normalizeScope, scopeKey, subscriptionKey, readRealtimeEpoch, subscribeToRealtimeEpoch, subscribeToRealtimeEvents, resetRealtimeSignals, type RealtimeChannel, type RealtimeConnectionState, type RealtimeDiagnostic, type RealtimeEvent, type RealtimeHealth, type RealtimeProviderProps, type RealtimeScope, type RealtimeScopeInput, type RealtimeStatus, type RealtimeTransport, type RegistryOptions, type SubscriptionHealth, type SubscriptionLease, type SubscriptionRequest, } from "./lib/realtime";
|
|
117
|
+
export { useRecordRead, useRecordListRead, useRecordStoreSweep, applyMutationResult, acquireSlot, appendCreated, emptySlotSnapshot, readSlot, resetSlots, slotKeys, subscribeToSlot, writeSlot, RefetchRunner, registerActiveRead, resetActiveReads, type ActiveRead, type ListFetch, type ListFetchResult, type ListReadOptions, type ListReadResult, type ReadError, type RecordFetch, type RecordReadOptions, type RecordReadResult, type RunnerOptions, type SlotSnapshot, } from "./lib/reads";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { useRecordRead, useRecordListRead, applyMutationResult, useRecordStoreSweep } from "./hooks";
|
|
2
|
-
export { acquireSlot,
|
|
2
|
+
export { acquireSlot, appendCreated, emptySlotSnapshot, readSlot, resetSlots, slotKeys, subscribeToSlot, writeSlot, type SlotSnapshot, } from "./slots";
|
|
3
3
|
export { RefetchRunner, registerActiveRead, resetActiveReads, type ActiveRead, type RunnerOptions } from "./refetch";
|
|
4
4
|
export type { ListFetch, ListFetchResult, ListReadOptions, ListReadResult, ReadError, RecordFetch, RecordReadOptions, RecordReadResult, } from "./types";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RealtimeEvent, RealtimeScope } from "../realtime";
|
|
1
2
|
export interface SlotSnapshot<T = unknown, TMeta = unknown> {
|
|
2
3
|
readonly items: readonly T[];
|
|
3
4
|
readonly pending: readonly T[];
|
|
@@ -17,7 +18,7 @@ export declare function emptySlotSnapshot(): SlotSnapshot;
|
|
|
17
18
|
export declare function acquireSlot(id: string, options: {
|
|
18
19
|
type: string;
|
|
19
20
|
tag: string;
|
|
20
|
-
|
|
21
|
+
createdScope?: RealtimeScope;
|
|
21
22
|
}): () => void;
|
|
22
23
|
/**
|
|
23
24
|
* Replace a slot's membership with a fetch's answer.
|
|
@@ -25,15 +26,26 @@ export declare function acquireSlot(id: string, options: {
|
|
|
25
26
|
* A key that arrived through a `created` event and is now in the fetched page
|
|
26
27
|
* stops being pending — the fetch has placed it, which is the only thing that
|
|
27
28
|
* ever could.
|
|
29
|
+
*
|
|
30
|
+
* @param settled the keys that were pending when this fetch was ISSUED
|
|
31
|
+
* (`slotPendingKeys`, read before the request). The answer covers them even
|
|
32
|
+
* when it does not hold them: a row that sorted onto another page is not
|
|
33
|
+
* "new" any more, it is placed — elsewhere. Without this a counted row that
|
|
34
|
+
* lands on page 2 stays "1 new" after Show, forever. A key appended after
|
|
35
|
+
* the request went out is not in this list, and stays pending.
|
|
28
36
|
*/
|
|
29
|
-
export declare function writeSlot(id: string, keys: readonly string[], meta: unknown): void;
|
|
37
|
+
export declare function writeSlot(id: string, keys: readonly string[], meta: unknown, settled?: readonly string[]): void;
|
|
38
|
+
/** The keys a slot is holding as pending right now — what a fetch issued now will settle. */
|
|
39
|
+
export declare function slotPendingKeys(id: string): readonly string[];
|
|
30
40
|
/**
|
|
31
|
-
* Append a record that entered the set elsewhere.
|
|
41
|
+
* Append a record that entered the set elsewhere, to every slot it belongs to.
|
|
32
42
|
*
|
|
33
43
|
* WITH NO POSITION. The server owns sort order and page boundary; a client that
|
|
34
44
|
* inserts at a guessed index renders a list that is subtly, confidently wrong.
|
|
45
|
+
*
|
|
46
|
+
* AND ONLY WHERE IT BELONGS — see `belongsTo`.
|
|
35
47
|
*/
|
|
36
|
-
export declare function
|
|
48
|
+
export declare function appendCreated(event: RealtimeEvent): void;
|
|
37
49
|
export declare function subscribeToSlot(id: string, listener: () => void): () => void;
|
|
38
50
|
/** The keys a slot holds right now — the roots a targeted refetch matches on. */
|
|
39
51
|
export declare function slotKeys(id: string): readonly string[];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RecordPayload, RecordState } from "../records";
|
|
2
|
+
import type { RealtimeScopeInput } from "../realtime";
|
|
2
3
|
/**
|
|
3
4
|
* A refusal.
|
|
4
5
|
*
|
|
@@ -76,18 +77,28 @@ export interface ListReadOptions<TMeta = unknown> extends CommonReadOptions {
|
|
|
76
77
|
readonly key: string;
|
|
77
78
|
readonly fetch: ListFetch<TMeta>;
|
|
78
79
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
80
|
+
* The realtime scope whose `created` events enter this list — normally the
|
|
81
|
+
* very scope the screen passes to `useRealtime` for this type. Omit it and no
|
|
82
|
+
* `created` ever appends here.
|
|
81
83
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
84
|
+
* WHY A LIST HAS TO SAY THIS. The channel carries every record of the type
|
|
85
|
+
* for the whole tenant, and the server sends an event there when ANY
|
|
86
|
+
* subscription on the tenant matched. So "a `created` arrived" never meant
|
|
87
|
+
* "it matches this list": a queue filtered to schema A counted a demand of
|
|
88
|
+
* no schema at all because a teammate had an unfiltered list open — observed,
|
|
89
|
+
* and the reason this replaced a boolean that appended every `created` of the
|
|
90
|
+
* type to every list that accepted one.
|
|
91
|
+
*
|
|
92
|
+
* How membership is decided per scope:
|
|
93
|
+
* - `"all"` — every `created` of the type belongs.
|
|
94
|
+
* - ids — a `created` whose id the list names belongs.
|
|
95
|
+
* - `{filter}` — only a `created` the server ATTRIBUTED to this scope
|
|
96
|
+
* (`RealtimeEvent.subscriptions`). The transport must implement
|
|
97
|
+
* `subscriptionsOf`, and this scope must also be subscribed with
|
|
98
|
+
* `useRealtime` — the attribution names this client's own subscriptions,
|
|
99
|
+
* so a filter nobody here subscribed to is never named.
|
|
89
100
|
*/
|
|
90
|
-
readonly
|
|
101
|
+
readonly createdScope?: RealtimeScopeInput;
|
|
91
102
|
}
|
|
92
103
|
/** The loading / refreshing / error triple, shared by both reads. */
|
|
93
104
|
interface ReadStatus {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { RealtimeProvider, useRealtimeRegistry, type RealtimeProviderProps } from "./provider";
|
|
2
2
|
export { useRealtime, useRealtimeEpoch, useRealtimeHealth } from "./hooks";
|
|
3
|
-
export { SubscriptionRegistry, normalizeScope, scopeKey, readRealtimeEpoch, subscribeToRealtimeEpoch, subscribeToRealtimeEvents, resetRealtimeSignals, type RegistryOptions, } from "./registry";
|
|
3
|
+
export { SubscriptionRegistry, normalizeScope, scopeKey, subscriptionKey, readRealtimeEpoch, subscribeToRealtimeEpoch, subscribeToRealtimeEvents, resetRealtimeSignals, type RegistryOptions, } from "./registry";
|
|
4
4
|
export type { RealtimeChannel, RealtimeConnectionState, RealtimeDiagnostic, RealtimeEvent, RealtimeHealth, RealtimeScope, RealtimeScopeInput, RealtimeStatus, RealtimeTransport, SubscriptionHealth, SubscriptionLease, SubscriptionRequest, } from "./types";
|
|
@@ -48,6 +48,16 @@ export declare function resetRealtimeSignals(): void;
|
|
|
48
48
|
*/
|
|
49
49
|
export declare function normalizeScope(input: RealtimeScopeInput): RealtimeScope;
|
|
50
50
|
export declare function scopeKey(scope: RealtimeScope): string;
|
|
51
|
+
/**
|
|
52
|
+
* The registry's key for a (type, scope) subscription — the identity
|
|
53
|
+
* `RealtimeEvent.subscriptions` names.
|
|
54
|
+
*
|
|
55
|
+
* ONE FUNCTION FOR BOTH SIDES. The registry keys its entries with it and a list
|
|
56
|
+
* slot keys its declared `createdScope` with it, so the two cannot disagree
|
|
57
|
+
* about what "the same subscription" means — a type spelled `WorkflowInput`
|
|
58
|
+
* here and `WorkflowInputResource` there would silently never match.
|
|
59
|
+
*/
|
|
60
|
+
export declare function subscriptionKey(type: string, scope: RealtimeScopeInput | RealtimeScope): string;
|
|
51
61
|
export declare class SubscriptionRegistry {
|
|
52
62
|
private readonly transport;
|
|
53
63
|
private readonly entries;
|
|
@@ -155,6 +165,17 @@ export declare class SubscriptionRegistry {
|
|
|
155
165
|
* lands in the store as the team you just joined.
|
|
156
166
|
*/
|
|
157
167
|
private deliver;
|
|
168
|
+
/**
|
|
169
|
+
* This client's subscriptions a broadcast satisfied, translated from the
|
|
170
|
+
* server's names through each entry's lease keys.
|
|
171
|
+
*
|
|
172
|
+
* THE WHOLE REASON THIS IS NEEDED: the channel is per type per tenant, so an
|
|
173
|
+
* event arrives here whenever ANY subscription on the tenant matched — a
|
|
174
|
+
* teammate's unfiltered list included. Arrival says "somebody on this team
|
|
175
|
+
* asked"; only this says "you asked". `undefined` when the transport cannot
|
|
176
|
+
* say, which is a different answer from `[]` ("it said, and none were yours").
|
|
177
|
+
*/
|
|
178
|
+
private attribute;
|
|
158
179
|
/** The event name that means "entered the set", for the read binding. */
|
|
159
180
|
get createdEventName(): string;
|
|
160
181
|
subscribeToHealth: (listener: () => void) => (() => void);
|
|
@@ -12,10 +12,13 @@ export type RealtimeConnectionState = "connecting" | "connected" | "disconnected
|
|
|
12
12
|
*
|
|
13
13
|
* - `ids` — the rows on screen. The backend keys its registry entry per model
|
|
14
14
|
* id, so this is the scope that pins specific records.
|
|
15
|
-
* - `filter` — a server-evaluated predicate. The backend re-runs it per save
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* - `filter` — a server-evaluated predicate. The backend re-runs it per save
|
|
16
|
+
* and answers "does this record match this filter" — and NOTHING about sort
|
|
17
|
+
* position or page boundary. ARRIVAL ALONE PROVES NOTHING about this filter:
|
|
18
|
+
* the channel is per type per tenant, so an event arrives whenever ANY
|
|
19
|
+
* subscription on the tenant matched, including a teammate's wider one. Only
|
|
20
|
+
* `RealtimeEvent.subscriptions` says which of this client's scopes it
|
|
21
|
+
* satisfied.
|
|
19
22
|
* - `all` — every record of the type for this tenant.
|
|
20
23
|
*/
|
|
21
24
|
export type RealtimeScope = {
|
|
@@ -57,6 +60,16 @@ export interface SubscriptionRequest {
|
|
|
57
60
|
export interface SubscriptionLease {
|
|
58
61
|
/** Milliseconds since epoch. Omit only if the server genuinely does not say. */
|
|
59
62
|
readonly expiresAt?: number;
|
|
63
|
+
/**
|
|
64
|
+
* The SERVER'S names for this registration — one per server-side entry the
|
|
65
|
+
* request fanned out to — in the same vocabulary `subscriptionsOf` returns.
|
|
66
|
+
*
|
|
67
|
+
* THIS IS HALF OF ATTRIBUTION. A broadcast names the server entries it
|
|
68
|
+
* satisfied; the registry maps those names back to its own subscriptions
|
|
69
|
+
* through these. Omitted on a keepalive, the names from the last subscribe
|
|
70
|
+
* stand — they describe the registration, which a renewal does not change.
|
|
71
|
+
*/
|
|
72
|
+
readonly keys?: readonly string[];
|
|
60
73
|
}
|
|
61
74
|
/** A joined socket channel. One per type per tenant, and no more. */
|
|
62
75
|
export interface RealtimeChannel {
|
|
@@ -111,6 +124,22 @@ export interface RealtimeTransport {
|
|
|
111
124
|
* warning, and the registry resubscribes rather than waiting.
|
|
112
125
|
*/
|
|
113
126
|
keepalive(requests: readonly SubscriptionRequest[]): Promise<readonly SubscriptionLease[]>;
|
|
127
|
+
/**
|
|
128
|
+
* Which server-side registrations a broadcast satisfied, in the vocabulary of
|
|
129
|
+
* `SubscriptionLease.keys` — or `undefined` when this payload does not say.
|
|
130
|
+
*
|
|
131
|
+
* WHY IT EXISTS: the channel carries every record of a type for a whole
|
|
132
|
+
* tenant, and the server sends an event there when ANY subscription on the
|
|
133
|
+
* tenant matched. Without this a list filtered to schema A counts a record
|
|
134
|
+
* that arrived only because a teammate has an unfiltered list open —
|
|
135
|
+
* observed, not theorised. A method rather than a field name because the
|
|
136
|
+
* field belongs to the wire format, like `isSelfEvent`.
|
|
137
|
+
*
|
|
138
|
+
* Optional: a transport whose server cannot attribute leaves it off, and a
|
|
139
|
+
* list whose membership needs attribution (a `filter` scope) then counts
|
|
140
|
+
* nothing rather than guessing.
|
|
141
|
+
*/
|
|
142
|
+
subscriptionsOf?(payload: RecordPayload): readonly string[] | undefined;
|
|
114
143
|
/** Join (or return) the channel carrying this type for this tenant. */
|
|
115
144
|
channel(type: string, tenant: string | number | undefined): RealtimeChannel;
|
|
116
145
|
connectionState(): RealtimeConnectionState;
|
|
@@ -197,6 +226,17 @@ export interface RealtimeEvent {
|
|
|
197
226
|
* consumer comparing the string would be the second place that fact lives.
|
|
198
227
|
*/
|
|
199
228
|
readonly isCreate: boolean;
|
|
229
|
+
/**
|
|
230
|
+
* This client's subscriptions the broadcast satisfied, by registry key
|
|
231
|
+
* (`subscriptionKey(type, scope)`), or `undefined` when the transport could
|
|
232
|
+
* not attribute it.
|
|
233
|
+
*
|
|
234
|
+
* AN EMPTY ARRAY IS AN ANSWER, not a missing one: the server attributed the
|
|
235
|
+
* event and none of the names were this client's — it is on the channel for
|
|
236
|
+
* somebody else's subscription. That is the case a filtered list must not
|
|
237
|
+
* count.
|
|
238
|
+
*/
|
|
239
|
+
readonly subscriptions: readonly string[] | undefined;
|
|
200
240
|
readonly payload: RecordPayload;
|
|
201
241
|
readonly tenant: string | number | undefined;
|
|
202
242
|
}
|