@elaraai/e3-ui-components 1.0.79 → 1.0.80
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 +1 -1
- package/dist/components/DatasetPreview.d.ts.map +1 -1
- package/dist/components/PagedDatasetPreview.d.ts.map +1 -1
- package/dist/components/TaskPreview.d.ts.map +1 -1
- package/dist/components/UITaskPreview.d.ts +7 -3
- package/dist/components/UITaskPreview.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useDatasetValue.d.ts +13 -2
- package/dist/hooks/useDatasetValue.d.ts.map +1 -1
- package/dist/hooks/useTaskDetails.d.ts +1 -5
- package/dist/hooks/useTaskDetails.d.ts.map +1 -1
- package/dist/hooks/workspaces.d.ts +16 -3
- package/dist/hooks/workspaces.d.ts.map +1 -1
- package/dist/index.cjs +740 -319
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +745 -324
- package/dist/index.js.map +1 -1
- package/dist/platform/bind-runtime.d.ts +14 -5
- package/dist/platform/bind-runtime.d.ts.map +1 -1
- package/dist/platform/dataset-hooks.d.ts +12 -4
- package/dist/platform/dataset-hooks.d.ts.map +1 -1
- package/dist/platform/dataset-store.d.ts +47 -11
- package/dist/platform/dataset-store.d.ts.map +1 -1
- package/dist/platform/func-runtime.d.ts +14 -4
- package/dist/platform/func-runtime.d.ts.map +1 -1
- package/dist/platform/index.d.ts +1 -1
- package/dist/platform/index.d.ts.map +1 -1
- package/dist/platform/paged-runtime.d.ts +183 -49
- package/dist/platform/paged-runtime.d.ts.map +1 -1
- package/dist/platform/record-runtime.d.ts +14 -4
- package/dist/platform/record-runtime.d.ts.map +1 -1
- package/dist/platform/staged-store.d.ts +19 -2
- package/dist/platform/staged-store.d.ts.map +1 -1
- package/package.json +13 -13
package/dist/index.js
CHANGED
|
@@ -18,22 +18,22 @@ var __privateWrapper = (obj, member, setter, getter) => ({
|
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
20
|
var _focused, _cleanup, _setup, _a, _provider, _providerCalled, _b, _online, _cleanup2, _setup2, _c, _gcTimeout, _d, _initialState, _revertState, _cache, _client, _retryer, _defaultOptions, _abortSignalConsumed, _Query_instances, isInitialPausedFetch_fn, dispatch_fn, _e, _client2, _observers, _mutationCache, _retryer2, _Mutation_instances, dispatch_fn2, _f, _mutations, _scopes, _mutationId, _g, _queries, _h, _queryCache, _mutationCache2, _defaultOptions2, _queryDefaults, _mutationDefaults, _mountCount, _unsubscribeFocus, _unsubscribeOnline, _i, _j;
|
|
21
|
-
import { variant, SortedMap, compareFor, EastError, fromEastTypeValue, East, none as none$1, some, OptionType, BooleanType, NullType, ConflictError, equalFor, toEastTypeValue, PatchType, diffFor, applyFor, encodeBeast2For, decodeBeast2For, BlobType, IntegerType, StructType,
|
|
21
|
+
import { variant, SortedMap, compareFor, EastError, fromEastTypeValue, East, none as none$1, some, OptionType, BooleanType, NullType, ConflictError, equalFor, toEastTypeValue, PatchType, diffFor, applyFor, encodeBeast2For, decodeBeast2For, BlobType, StringType, IntegerType, StructType, walkPatch, pathToString, pathDisplay, printFor, isVariant, prunePatchFor, detectConflictsFor, mergeWithResolutionsFor, validatePatchFor, isEastSet, isEastDict, ArrayType, parseFor } from "@elaraai/east";
|
|
22
22
|
import { EastTypeType } from "@elaraai/east/internal";
|
|
23
|
-
import { DataBindModeType, DataBindPrimitives, bindPlatformFn, DataPagedPrimitives, bindPagedPlatformFn, FuncBindPrimitives, FuncErrorType, FuncStatusType, funcBindPlatformFn, RecordBindPrimitives, recordBindPlatformFn, Diff, Ontology, FuncBindHandleType, Experiment, decisionBindPlatformFn, DecisionBindPrimitives, DecisionConstraintType, DiffBindingType, CommitStateType, VerdictType, AnswerType, judgementInputType, DecisionType, DecisionQueue, DecisionJournal
|
|
23
|
+
import { DataBindModeType, DataBindPrimitives, bindPlatformFn, DataPagedPrimitives, bindPagedPlatformFn, bindPagedPinnedPlatformFn, FuncBindPrimitives, FuncErrorType, FuncStatusType, funcBindPlatformFn, RecordBindPrimitives, recordBindPlatformFn, Diff, Ontology, FuncBindHandleType, Experiment, decisionBindPlatformFn, DecisionBindPrimitives, DecisionConstraintType, DiffBindingType, CommitStateType, VerdictType, AnswerType, judgementInputType, DecisionType, DecisionQueue, DecisionJournal } from "@elaraai/e3-ui/internal";
|
|
24
24
|
import { registerReactiveTracker, registerPlatformImplementation, StateRuntime, getRegisteredPlatformImplementations, boundSliceConfig } from "@elaraai/east-ui-components/platform";
|
|
25
25
|
import { TreePathType, DatasetStatusType } from "@elaraai/e3-types";
|
|
26
|
-
import { workspaceStatus, datasetListAt, datasetList, dataflowExecuteLaunch, datasetSet, datasetGet, ApiError, datasetFindKey, datasetGetPage, workspaceFunctionCall, workspaceFunctionList, workspaceRecordHistory, workspaceRecordMutate, workspaceRecordDescribe, repoCreate, repoGc, repoGcStart, repoGcStatus, repoList, repoRemove, repoStatus, packageExport, packageGet, packageImport, packageList, packageRemove, workspaceCreate, workspaceDeploy, workspaceExport, workspaceGet, workspaceList, workspaceRemove,
|
|
26
|
+
import { workspaceStatus, datasetListAt, datasetList, dataflowExecuteLaunch, datasetSet, datasetGet, ApiError, DatasetHashMismatchError, datasetGetStatus, datasetFindKey, datasetGetPage, workspaceFunctionCall, workspaceFunctionList, workspaceRecordHistory, workspaceRecordMutate, workspaceRecordDescribe, repoCreate, repoGc, repoGcStart, repoGcStatus, repoList, repoRemove, repoStatus, packageExport, packageGet, packageImport, packageList, packageRemove, workspaceCreate, workspaceDeploy, workspaceExport, workspaceGet, workspaceList, workspaceRemove, datasetListRecursive, datasetListRecursivePaths, datasetListWithStatus, taskExecutionList, taskGet, taskList, dataflowCancel, dataflowExecute, dataflowExecutePoll, dataflowGraph, taskLogs } from "@elaraai/e3-api-client";
|
|
27
27
|
import { SeekQueryType, SeekRangeType, ValueTree } from "@elaraai/east-ui";
|
|
28
28
|
import { jsx as jsx$1, Fragment, jsxs } from "react/jsx-runtime";
|
|
29
29
|
import * as React from "react";
|
|
30
|
-
import React__default, { useId, useMemo, useContext, createContext, useRef,
|
|
30
|
+
import React__default, { useId, useMemo, useContext, createContext, useRef, useState, useEffect, useCallback, useSyncExternalStore, memo, forwardRef, useLayoutEffect, Fragment as Fragment$1, Component } from "react";
|
|
31
31
|
import { Box, Flex, Text, HStack, Input, useSlotRecipe, useRecipe, VStack, useToken, Drawer, Portal, Field, NativeSelect, Textarea, chakra, Tooltip, SegmentGroup, Menu, HoverCard, useChakraContext, Spinner, Code, Clipboard, IconButton, Button, Tabs, Badge, useTabs } from "@chakra-ui/react";
|
|
32
32
|
import { implementUIComponent, getSomeorUndefined, formatPredicate, SliceEditPopover, SlicePredicateBuilder, EastChakraSelect, EastChakraStringInput, EastChakraDateTimeInput, EastChakraFloatInput, EastChakraIntegerInput, formatTick, useSliceReactivity, useContainerBelow, usePersistedState, SliceRailCluster, EastChakraComponent, ClauseChip, StateImpl, NavImpl, SliceImpl, SliceApplyImpl, OverlayImpl, ClipboardImpl, DownloadImpl, ShareImpl, LoadingIcon, DatasetKeySearch, EastChakraValueTree, keyRangePredicates, createUIStore, UIStoreProvider } from "@elaraai/east-ui-components";
|
|
33
33
|
import { DatasetKeySearch as DatasetKeySearch2 } from "@elaraai/east-ui-components";
|
|
34
34
|
import { createPortal } from "react-dom";
|
|
35
35
|
import { sliceMatches, pruneRetainedPages } from "@elaraai/east-ui/internal";
|
|
36
|
-
import { QueryClient as QueryClient$1, QueryClientProvider, useMutation, useQuery,
|
|
36
|
+
import { QueryClient as QueryClient$1, QueryClientProvider, useMutation, useQuery, useQueryClient, keepPreviousData } from "@tanstack/react-query";
|
|
37
37
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
38
38
|
var Subscribable = class {
|
|
39
39
|
constructor() {
|
|
@@ -2060,6 +2060,7 @@ const realClock = {
|
|
|
2060
2060
|
return { clear: () => clearInterval(id3) };
|
|
2061
2061
|
}
|
|
2062
2062
|
};
|
|
2063
|
+
const HASH_POLL_MS = 1e3;
|
|
2063
2064
|
function createDefaultDatasetApi(apiUrl, repo, getToken) {
|
|
2064
2065
|
const opts = () => ({ token: getToken() });
|
|
2065
2066
|
return {
|
|
@@ -2125,12 +2126,17 @@ class ReactiveDatasetCache {
|
|
|
2125
2126
|
__publicField(this, "keyVersions", /* @__PURE__ */ new Map());
|
|
2126
2127
|
// Workspace status polling — groups subscriptions by workspace for
|
|
2127
2128
|
// efficiency. Each entry holds the active interval handle from the
|
|
2128
|
-
// injected {@link Clock} so tests can drive ticking deterministically
|
|
2129
|
+
// injected {@link Clock} so tests can drive ticking deterministically,
|
|
2130
|
+
// and each polled path with how many watchers poll it.
|
|
2129
2131
|
__publicField(this, "workspacePollers", /* @__PURE__ */ new Map());
|
|
2130
2132
|
__publicField(this, "clock");
|
|
2131
2133
|
// In-flight poll dedup — concurrent callers (interval tick + a
|
|
2132
2134
|
// post-write trigger) share a single round-trip rather than racing.
|
|
2133
2135
|
__publicField(this, "inFlightPolls", /* @__PURE__ */ new Map());
|
|
2136
|
+
// Hash-only watches, by workspace and path: each callback with the hash it
|
|
2137
|
+
// was last told. A watched path rides its workspace's poll, but its
|
|
2138
|
+
// content is never fetched — a paged source reads windows, never the value.
|
|
2139
|
+
__publicField(this, "hashWatches", /* @__PURE__ */ new Map());
|
|
2134
2140
|
// Batching
|
|
2135
2141
|
__publicField(this, "batchDepth", 0);
|
|
2136
2142
|
__publicField(this, "changedKeys", /* @__PURE__ */ new Set());
|
|
@@ -2219,9 +2225,7 @@ class ReactiveDatasetCache {
|
|
|
2219
2225
|
hash: void 0,
|
|
2220
2226
|
status: variant("stale", null)
|
|
2221
2227
|
});
|
|
2222
|
-
|
|
2223
|
-
void this.pollWorkspaceStatus(workspace);
|
|
2224
|
-
}
|
|
2228
|
+
void this.refresh(workspace);
|
|
2225
2229
|
} catch (error3) {
|
|
2226
2230
|
if (!this.destroyed && this.writeEpochs.get(key) === myEpoch) {
|
|
2227
2231
|
const baseline = this.writeBaselines.get(key);
|
|
@@ -2327,15 +2331,15 @@ class ReactiveDatasetCache {
|
|
|
2327
2331
|
* 3. Only fetches full content when hash changes
|
|
2328
2332
|
*
|
|
2329
2333
|
* Multiple subscriptions to the same workspace share a single poller.
|
|
2330
|
-
* Pair with {@link clearRefetchInterval} on unmount so the
|
|
2331
|
-
* stop when nothing is watching.
|
|
2334
|
+
* Pair each call with one {@link clearRefetchInterval} on unmount so the
|
|
2335
|
+
* poller can stop when nothing is watching.
|
|
2332
2336
|
*/
|
|
2333
2337
|
setRefetchInterval(workspace, path2, intervalMs) {
|
|
2334
2338
|
var _a2;
|
|
2335
2339
|
const pathStr = datasetPathToString(path2);
|
|
2336
2340
|
let poller = this.workspacePollers.get(workspace);
|
|
2337
2341
|
if (poller) {
|
|
2338
|
-
poller.paths.
|
|
2342
|
+
poller.paths.set(pathStr, (poller.paths.get(pathStr) ?? 0) + 1);
|
|
2339
2343
|
if (intervalMs < poller.intervalMs) {
|
|
2340
2344
|
(_a2 = poller.handle) == null ? void 0 : _a2.clear();
|
|
2341
2345
|
poller.intervalMs = intervalMs;
|
|
@@ -2347,7 +2351,7 @@ class ReactiveDatasetCache {
|
|
|
2347
2351
|
} else {
|
|
2348
2352
|
poller = {
|
|
2349
2353
|
intervalMs,
|
|
2350
|
-
paths: /* @__PURE__ */ new
|
|
2354
|
+
paths: /* @__PURE__ */ new Map([[pathStr, 1]]),
|
|
2351
2355
|
handle: this.clock.setInterval(
|
|
2352
2356
|
() => this.pollWorkspaceStatus(workspace),
|
|
2353
2357
|
intervalMs
|
|
@@ -2358,23 +2362,79 @@ class ReactiveDatasetCache {
|
|
|
2358
2362
|
}
|
|
2359
2363
|
}
|
|
2360
2364
|
/**
|
|
2361
|
-
* Stop polling a dataset
|
|
2362
|
-
*
|
|
2365
|
+
* Stop polling a dataset for one watcher; the path goes when its last
|
|
2366
|
+
* watcher clears it, and the workspace poller is torn down when its last
|
|
2367
|
+
* path goes.
|
|
2363
2368
|
*/
|
|
2364
2369
|
clearRefetchInterval(workspace, path2) {
|
|
2365
|
-
var _a2;
|
|
2366
2370
|
const poller = this.workspacePollers.get(workspace);
|
|
2367
2371
|
if (!poller) return;
|
|
2368
|
-
|
|
2369
|
-
|
|
2372
|
+
const pathStr = datasetPathToString(path2);
|
|
2373
|
+
const watchers = (poller.paths.get(pathStr) ?? 0) - 1;
|
|
2374
|
+
if (watchers > 0) {
|
|
2375
|
+
poller.paths.set(pathStr, watchers);
|
|
2376
|
+
return;
|
|
2377
|
+
}
|
|
2378
|
+
poller.paths.delete(pathStr);
|
|
2379
|
+
this.stopIdlePoller(workspace);
|
|
2380
|
+
}
|
|
2381
|
+
/**
|
|
2382
|
+
* Follow a dataset's content hash without fetching its content; see the
|
|
2383
|
+
* interface doc.
|
|
2384
|
+
*/
|
|
2385
|
+
watchHash(workspace, path2, onHash, intervalMs = HASH_POLL_MS) {
|
|
2386
|
+
var _a2;
|
|
2387
|
+
const pathStr = datasetPathToString(path2);
|
|
2388
|
+
let byPath = this.hashWatches.get(workspace);
|
|
2389
|
+
if (!byPath) {
|
|
2390
|
+
byPath = /* @__PURE__ */ new Map();
|
|
2391
|
+
this.hashWatches.set(workspace, byPath);
|
|
2392
|
+
}
|
|
2393
|
+
let callbacks = byPath.get(pathStr);
|
|
2394
|
+
if (!callbacks) {
|
|
2395
|
+
callbacks = /* @__PURE__ */ new Map();
|
|
2396
|
+
byPath.set(pathStr, callbacks);
|
|
2397
|
+
}
|
|
2398
|
+
callbacks.set(onHash, void 0);
|
|
2399
|
+
const poller = this.workspacePollers.get(workspace);
|
|
2400
|
+
if (!poller) {
|
|
2401
|
+
this.workspacePollers.set(workspace, {
|
|
2402
|
+
intervalMs,
|
|
2403
|
+
paths: /* @__PURE__ */ new Map(),
|
|
2404
|
+
handle: this.clock.setInterval(() => this.pollWorkspaceStatus(workspace), intervalMs)
|
|
2405
|
+
});
|
|
2406
|
+
void this.pollWorkspaceStatus(workspace);
|
|
2407
|
+
} else if (intervalMs < poller.intervalMs) {
|
|
2370
2408
|
(_a2 = poller.handle) == null ? void 0 : _a2.clear();
|
|
2371
|
-
|
|
2409
|
+
poller.intervalMs = intervalMs;
|
|
2410
|
+
poller.handle = this.clock.setInterval(() => this.pollWorkspaceStatus(workspace), intervalMs);
|
|
2372
2411
|
}
|
|
2412
|
+
return () => {
|
|
2413
|
+
const watched = this.hashWatches.get(workspace);
|
|
2414
|
+
const set3 = watched == null ? void 0 : watched.get(pathStr);
|
|
2415
|
+
if (!watched || !set3) return;
|
|
2416
|
+
set3.delete(onHash);
|
|
2417
|
+
if (set3.size === 0) watched.delete(pathStr);
|
|
2418
|
+
if (watched.size === 0) this.hashWatches.delete(workspace);
|
|
2419
|
+
this.stopIdlePoller(workspace);
|
|
2420
|
+
};
|
|
2421
|
+
}
|
|
2422
|
+
/** Stops a workspace's poller once it has no path to reconcile and no hash
|
|
2423
|
+
* to follow — without this, a long-lived session polls forever. */
|
|
2424
|
+
stopIdlePoller(workspace) {
|
|
2425
|
+
var _a2;
|
|
2426
|
+
const poller = this.workspacePollers.get(workspace);
|
|
2427
|
+
if (!poller || poller.paths.size > 0 || this.hashWatches.has(workspace)) return;
|
|
2428
|
+
(_a2 = poller.handle) == null ? void 0 : _a2.clear();
|
|
2429
|
+
this.workspacePollers.delete(workspace);
|
|
2373
2430
|
}
|
|
2374
2431
|
refresh(workspace) {
|
|
2375
2432
|
if (this.destroyed) return Promise.resolve();
|
|
2376
2433
|
if (!this.workspacePollers.has(workspace)) return Promise.resolve();
|
|
2377
|
-
|
|
2434
|
+
const inFlight = this.inFlightPolls.get(workspace);
|
|
2435
|
+
if (inFlight === void 0) return this.pollWorkspaceStatus(workspace);
|
|
2436
|
+
const again = () => this.destroyed || !this.workspacePollers.has(workspace) ? void 0 : this.pollWorkspaceStatus(workspace);
|
|
2437
|
+
return inFlight.then(again, again);
|
|
2378
2438
|
}
|
|
2379
2439
|
/**
|
|
2380
2440
|
* Poll workspace status and reconcile the cache with the server.
|
|
@@ -2390,11 +2450,12 @@ class ReactiveDatasetCache {
|
|
|
2390
2450
|
return promise4;
|
|
2391
2451
|
}
|
|
2392
2452
|
async doPollWorkspaceStatus(workspace) {
|
|
2453
|
+
var _a2;
|
|
2393
2454
|
if (this.destroyed) return;
|
|
2394
2455
|
const poller = this.workspacePollers.get(workspace);
|
|
2395
|
-
if (!poller || poller.paths.size === 0) return;
|
|
2456
|
+
if (!poller || poller.paths.size === 0 && !this.hashWatches.has(workspace)) return;
|
|
2396
2457
|
const epochsAtStart = /* @__PURE__ */ new Map();
|
|
2397
|
-
for (const pathStr of poller.paths) {
|
|
2458
|
+
for (const pathStr of poller.paths.keys()) {
|
|
2398
2459
|
const key = pathStr ? `${workspace}.${pathStr}` : workspace;
|
|
2399
2460
|
epochsAtStart.set(key, this.writeEpochs.get(key) ?? 0);
|
|
2400
2461
|
}
|
|
@@ -2408,15 +2469,28 @@ class ReactiveDatasetCache {
|
|
|
2408
2469
|
if (this.destroyed) return;
|
|
2409
2470
|
const infoByPath = /* @__PURE__ */ new Map();
|
|
2410
2471
|
for (const info of status.datasets) infoByPath.set(info.path, info);
|
|
2472
|
+
for (const [pathStr, callbacks] of this.hashWatches.get(workspace) ?? []) {
|
|
2473
|
+
const info = infoByPath.get(pathStr ? `.${pathStr}` : "");
|
|
2474
|
+
const hash2 = ((_a2 = info == null ? void 0 : info.hash) == null ? void 0 : _a2.type) === "some" ? info.hash.value : null;
|
|
2475
|
+
for (const [onHash, told] of [...callbacks]) {
|
|
2476
|
+
if (told === hash2 || !callbacks.has(onHash)) continue;
|
|
2477
|
+
callbacks.set(onHash, hash2);
|
|
2478
|
+
try {
|
|
2479
|
+
onHash(hash2);
|
|
2480
|
+
} catch (error3) {
|
|
2481
|
+
console.error(`A hash watch on ${workspace}.${pathStr} failed:`, error3);
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2411
2485
|
const pending = [];
|
|
2412
2486
|
this.batch(() => {
|
|
2413
|
-
var
|
|
2414
|
-
for (const pathStr of poller.paths) {
|
|
2487
|
+
var _a3;
|
|
2488
|
+
for (const pathStr of poller.paths.keys()) {
|
|
2415
2489
|
const e3Path = pathStr ? `.${pathStr}` : "";
|
|
2416
2490
|
const info = infoByPath.get(e3Path);
|
|
2417
2491
|
const key = pathStr ? `${workspace}.${pathStr}` : workspace;
|
|
2418
2492
|
const path2 = this.stringToPath(pathStr);
|
|
2419
|
-
const currentHash = ((
|
|
2493
|
+
const currentHash = ((_a3 = info == null ? void 0 : info.hash) == null ? void 0 : _a3.type) === "some" ? info.hash.value : null;
|
|
2420
2494
|
const knownHash = this.knownHashes.get(key);
|
|
2421
2495
|
if (info == null ? void 0 : info.status) {
|
|
2422
2496
|
const previous = this.statuses.get(key);
|
|
@@ -2582,6 +2656,7 @@ class ReactiveDatasetCache {
|
|
|
2582
2656
|
}
|
|
2583
2657
|
this.workspacePollers.clear();
|
|
2584
2658
|
this.inFlightPolls.clear();
|
|
2659
|
+
this.hashWatches.clear();
|
|
2585
2660
|
this.keySubscribers.clear();
|
|
2586
2661
|
this.globalSubscribers.clear();
|
|
2587
2662
|
this.knownHashes.clear();
|
|
@@ -2696,9 +2771,16 @@ class MemoryStagedAdapter {
|
|
|
2696
2771
|
this.map.clear();
|
|
2697
2772
|
}
|
|
2698
2773
|
}
|
|
2774
|
+
const SCOPE_SEPARATOR = "\0";
|
|
2775
|
+
function cacheKeyOf(key) {
|
|
2776
|
+
return key.slice(key.indexOf(SCOPE_SEPARATOR) + 1);
|
|
2777
|
+
}
|
|
2699
2778
|
class StagedStore {
|
|
2700
2779
|
constructor(adapter) {
|
|
2780
|
+
// By scope and `datasetCacheKey`; subscribers and versions go by the
|
|
2781
|
+
// `datasetCacheKey` alone, which is what a reactive view tracks.
|
|
2701
2782
|
__publicField(this, "entries", /* @__PURE__ */ new Map());
|
|
2783
|
+
__publicField(this, "scope", null);
|
|
2702
2784
|
__publicField(this, "subscribers", /* @__PURE__ */ new Map());
|
|
2703
2785
|
__publicField(this, "versions", /* @__PURE__ */ new Map());
|
|
2704
2786
|
__publicField(this, "adapter");
|
|
@@ -2722,25 +2804,25 @@ class StagedStore {
|
|
|
2722
2804
|
}
|
|
2723
2805
|
}
|
|
2724
2806
|
hasPending(workspace, path2) {
|
|
2725
|
-
return this.entries.has(
|
|
2807
|
+
return this.entries.has(this.keyOf(workspace, path2));
|
|
2726
2808
|
}
|
|
2727
2809
|
getBuffered(workspace, path2) {
|
|
2728
2810
|
var _a2;
|
|
2729
|
-
return (_a2 = this.entries.get(
|
|
2811
|
+
return (_a2 = this.entries.get(this.keyOf(workspace, path2))) == null ? void 0 : _a2.buffered;
|
|
2730
2812
|
}
|
|
2731
2813
|
getSnapshot(workspace, path2) {
|
|
2732
2814
|
var _a2;
|
|
2733
|
-
return (_a2 = this.entries.get(
|
|
2815
|
+
return (_a2 = this.entries.get(this.keyOf(workspace, path2))) == null ? void 0 : _a2.snapshot;
|
|
2734
2816
|
}
|
|
2735
2817
|
getEntry(workspace, path2) {
|
|
2736
|
-
return this.entries.get(
|
|
2818
|
+
return this.entries.get(this.keyOf(workspace, path2));
|
|
2737
2819
|
}
|
|
2738
2820
|
write(workspace, path2, snapshotIfNew, buffered) {
|
|
2739
|
-
const key =
|
|
2821
|
+
const key = this.keyOf(workspace, path2);
|
|
2740
2822
|
const existing = this.entries.get(key);
|
|
2741
2823
|
const next2 = existing ? { snapshot: existing.snapshot, buffered } : { snapshot: snapshotIfNew, buffered };
|
|
2742
2824
|
this.entries.set(key, next2);
|
|
2743
|
-
this.notify(
|
|
2825
|
+
this.notify(datasetCacheKey(workspace, path2));
|
|
2744
2826
|
const persisted = {
|
|
2745
2827
|
snapshot: next2.snapshot,
|
|
2746
2828
|
buffered: next2.buffered
|
|
@@ -2748,15 +2830,26 @@ class StagedStore {
|
|
|
2748
2830
|
this.persist(key, () => this.adapter.save(key, persisted));
|
|
2749
2831
|
}
|
|
2750
2832
|
discard(workspace, path2) {
|
|
2751
|
-
const key =
|
|
2833
|
+
const key = this.keyOf(workspace, path2);
|
|
2752
2834
|
if (!this.entries.has(key)) return false;
|
|
2753
2835
|
this.entries.delete(key);
|
|
2754
|
-
this.notify(
|
|
2836
|
+
this.notify(datasetCacheKey(workspace, path2));
|
|
2755
2837
|
this.persist(key, () => this.adapter.remove(key));
|
|
2756
2838
|
return true;
|
|
2757
2839
|
}
|
|
2758
2840
|
listKeys() {
|
|
2759
|
-
|
|
2841
|
+
const prefix2 = `${this.scope ?? ""}${SCOPE_SEPARATOR}`;
|
|
2842
|
+
return [...this.entries.keys()].filter((key) => key.startsWith(prefix2)).map(cacheKeyOf);
|
|
2843
|
+
}
|
|
2844
|
+
setScope(scope) {
|
|
2845
|
+
const before = this.scope;
|
|
2846
|
+
this.scope = scope;
|
|
2847
|
+
this.notifyScopes(before, scope);
|
|
2848
|
+
return () => {
|
|
2849
|
+
if (this.scope !== scope) return;
|
|
2850
|
+
this.scope = null;
|
|
2851
|
+
this.notifyScopes(scope, null);
|
|
2852
|
+
};
|
|
2760
2853
|
}
|
|
2761
2854
|
subscribe(key, callback) {
|
|
2762
2855
|
let set3 = this.subscribers.get(key);
|
|
@@ -2779,15 +2872,29 @@ class StagedStore {
|
|
|
2779
2872
|
this.errorListeners.delete(cb);
|
|
2780
2873
|
};
|
|
2781
2874
|
}
|
|
2782
|
-
/** Test-only: clear in-memory + persisted state. */
|
|
2875
|
+
/** Test-only: clear in-memory + persisted state, in every scope. */
|
|
2783
2876
|
async clear() {
|
|
2784
2877
|
const keys = [...this.entries.keys()];
|
|
2785
2878
|
this.entries.clear();
|
|
2786
|
-
for (const key of keys) this.notify(key);
|
|
2879
|
+
for (const key of new Set(keys.map(cacheKeyOf))) this.notify(key);
|
|
2787
2880
|
await this.flushPending();
|
|
2788
2881
|
await this.adapter.clear();
|
|
2789
2882
|
}
|
|
2790
2883
|
// ----- internals -------------------------------------------------------
|
|
2884
|
+
/** The key a path's entry is held under in the current scope. */
|
|
2885
|
+
keyOf(workspace, path2) {
|
|
2886
|
+
return `${this.scope ?? ""}${SCOPE_SEPARATOR}${datasetCacheKey(workspace, path2)}`;
|
|
2887
|
+
}
|
|
2888
|
+
/** Tells every path with an entry in either scope that what it reads has
|
|
2889
|
+
* changed: the scope's move shows one's entries and hides the other's. */
|
|
2890
|
+
notifyScopes(from2, to) {
|
|
2891
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2892
|
+
for (const key of this.entries.keys()) {
|
|
2893
|
+
const scope = key.slice(0, key.indexOf(SCOPE_SEPARATOR));
|
|
2894
|
+
if (scope === (from2 ?? "") || scope === (to ?? "")) keys.add(cacheKeyOf(key));
|
|
2895
|
+
}
|
|
2896
|
+
for (const key of keys) this.notify(key);
|
|
2897
|
+
}
|
|
2791
2898
|
notify(key) {
|
|
2792
2899
|
this.versions.set(key, (this.versions.get(key) ?? 0) + 1);
|
|
2793
2900
|
const subs = this.subscribers.get(key);
|
|
@@ -2804,7 +2911,7 @@ class StagedStore {
|
|
|
2804
2911
|
const settled = prev2.then(op, op).then(
|
|
2805
2912
|
() => void 0,
|
|
2806
2913
|
(err) => {
|
|
2807
|
-
this.emitPersistError(key, err);
|
|
2914
|
+
this.emitPersistError(cacheKeyOf(key), err);
|
|
2808
2915
|
}
|
|
2809
2916
|
).then(() => {
|
|
2810
2917
|
if (this.saveChains.get(key) === settled) this.saveChains.delete(key);
|
|
@@ -2835,11 +2942,18 @@ class StagedStore {
|
|
|
2835
2942
|
return;
|
|
2836
2943
|
}
|
|
2837
2944
|
for (const [key, p2] of persisted) {
|
|
2945
|
+
if (!key.includes(SCOPE_SEPARATOR)) {
|
|
2946
|
+
this.persist(key, () => this.adapter.remove(key));
|
|
2947
|
+
this.emitPersistError(key, new Error(
|
|
2948
|
+
`a staged edit of ${key} that an older build left names no server or repository, and was dropped`
|
|
2949
|
+
));
|
|
2950
|
+
continue;
|
|
2951
|
+
}
|
|
2838
2952
|
this.entries.set(key, {
|
|
2839
2953
|
snapshot: p2.snapshot,
|
|
2840
2954
|
buffered: p2.buffered
|
|
2841
2955
|
});
|
|
2842
|
-
this.notify(key);
|
|
2956
|
+
this.notify(cacheKeyOf(key));
|
|
2843
2957
|
}
|
|
2844
2958
|
}
|
|
2845
2959
|
}
|
|
@@ -2956,8 +3070,14 @@ class BindRuntime {
|
|
|
2956
3070
|
}
|
|
2957
3071
|
this.cache = cache3;
|
|
2958
3072
|
}
|
|
2959
|
-
/**
|
|
2960
|
-
|
|
3073
|
+
/**
|
|
3074
|
+
* Clear the active cache and drop any queued writes.
|
|
3075
|
+
*
|
|
3076
|
+
* @param cache - Clear only while this is the active cache, so a provider
|
|
3077
|
+
* tearing down after another installed its own leaves that one in place
|
|
3078
|
+
*/
|
|
3079
|
+
clearCache(cache3) {
|
|
3080
|
+
if (cache3 !== void 0 && this.cache !== cache3) return;
|
|
2961
3081
|
this.cache = null;
|
|
2962
3082
|
this.clearPendingWrites();
|
|
2963
3083
|
this.handleCache.clear();
|
|
@@ -3282,6 +3402,10 @@ class BindRuntime {
|
|
|
3282
3402
|
this.queueWrite(() => cache3.launchDataflow(ws));
|
|
3283
3403
|
return null;
|
|
3284
3404
|
};
|
|
3405
|
+
const hasSource = () => {
|
|
3406
|
+
this.trackPath(ws, sourcePath);
|
|
3407
|
+
return cache3.has(ws, sourcePath);
|
|
3408
|
+
};
|
|
3285
3409
|
if (mode === "direct" && !patchPath) {
|
|
3286
3410
|
return {
|
|
3287
3411
|
read: () => {
|
|
@@ -3304,7 +3428,7 @@ class BindRuntime {
|
|
|
3304
3428
|
pending: () => false,
|
|
3305
3429
|
commit: () => null,
|
|
3306
3430
|
discard: () => null,
|
|
3307
|
-
has:
|
|
3431
|
+
has: hasSource,
|
|
3308
3432
|
status: () => {
|
|
3309
3433
|
this.trackPath(ws, sourcePath);
|
|
3310
3434
|
return cache3.getStatus(ws, sourcePath);
|
|
@@ -3353,7 +3477,7 @@ class BindRuntime {
|
|
|
3353
3477
|
this.queueWrite(() => cache3.write(ws, pPath2, encodePatch(UNCHANGED_VARIANT)));
|
|
3354
3478
|
return null;
|
|
3355
3479
|
},
|
|
3356
|
-
has:
|
|
3480
|
+
has: hasSource,
|
|
3357
3481
|
status: () => {
|
|
3358
3482
|
this.trackPath(ws, sourcePath);
|
|
3359
3483
|
return cache3.getStatus(ws, sourcePath);
|
|
@@ -3397,7 +3521,7 @@ class BindRuntime {
|
|
|
3397
3521
|
staged.discard(ws, sourcePath);
|
|
3398
3522
|
return null;
|
|
3399
3523
|
},
|
|
3400
|
-
has:
|
|
3524
|
+
has: hasSource,
|
|
3401
3525
|
status: () => {
|
|
3402
3526
|
this.trackPath(ws, sourcePath);
|
|
3403
3527
|
return cache3.getStatus(ws, sourcePath);
|
|
@@ -3444,7 +3568,7 @@ class BindRuntime {
|
|
|
3444
3568
|
staged.discard(ws, sourcePath);
|
|
3445
3569
|
return null;
|
|
3446
3570
|
},
|
|
3447
|
-
has:
|
|
3571
|
+
has: hasSource,
|
|
3448
3572
|
status: () => {
|
|
3449
3573
|
this.trackPath(ws, sourcePath);
|
|
3450
3574
|
return cache3.getStatus(ws, sourcePath);
|
|
@@ -3502,8 +3626,8 @@ function getReactiveDatasetCache() {
|
|
|
3502
3626
|
function initializeReactiveDatasetCache(cache3) {
|
|
3503
3627
|
defaultBindRuntime.initializeCache(cache3);
|
|
3504
3628
|
}
|
|
3505
|
-
function clearReactiveDatasetCache() {
|
|
3506
|
-
defaultBindRuntime.clearCache();
|
|
3629
|
+
function clearReactiveDatasetCache(cache3) {
|
|
3630
|
+
defaultBindRuntime.clearCache(cache3);
|
|
3507
3631
|
}
|
|
3508
3632
|
function enableBindingTracking() {
|
|
3509
3633
|
return defaultBindRuntime.enableTracking();
|
|
@@ -3683,7 +3807,11 @@ class TrackedChannelStore {
|
|
|
3683
3807
|
this.keyVersions.clear();
|
|
3684
3808
|
}
|
|
3685
3809
|
}
|
|
3686
|
-
|
|
3810
|
+
const NO_INDEX = { index: null, join: false };
|
|
3811
|
+
function selectorKey(selector2) {
|
|
3812
|
+
return selector2.index === null ? "" : `@${selector2.index}${selector2.join ? "+join" : ""}`;
|
|
3813
|
+
}
|
|
3814
|
+
function createDefaultPagedApi(apiUrl, repo, getToken, datasets) {
|
|
3687
3815
|
const opts = () => ({ token: getToken() });
|
|
3688
3816
|
return {
|
|
3689
3817
|
async getPage(workspace, path2, window3) {
|
|
@@ -3691,58 +3819,115 @@ function createDefaultPagedApi(apiUrl, repo, getToken) {
|
|
|
3691
3819
|
},
|
|
3692
3820
|
async findKey(workspace, path2, query) {
|
|
3693
3821
|
return datasetFindKey(apiUrl, repo, workspace, path2, query, opts());
|
|
3822
|
+
},
|
|
3823
|
+
async getRevision(workspace, path2) {
|
|
3824
|
+
const status = await datasetGetStatus(apiUrl, repo, workspace, path2, opts());
|
|
3825
|
+
return status.hash.type === "some" ? status.hash.value : null;
|
|
3826
|
+
},
|
|
3827
|
+
watchRevision(workspace, path2, onChange2) {
|
|
3828
|
+
return datasets.watchHash(workspace, path2, onChange2);
|
|
3694
3829
|
}
|
|
3695
3830
|
};
|
|
3696
3831
|
}
|
|
3697
3832
|
const RETRY_AFTER_MS = 2e3;
|
|
3698
3833
|
const MAX_RETAINED_WINDOWS = 24;
|
|
3699
|
-
const PERMANENT_PAGE_ERRORS = /* @__PURE__ */ new Set([
|
|
3700
|
-
|
|
3834
|
+
const PERMANENT_PAGE_ERRORS = /* @__PURE__ */ new Set([
|
|
3835
|
+
"bad_request",
|
|
3836
|
+
"dataset_not_canonical",
|
|
3837
|
+
"dataset_not_indexed",
|
|
3838
|
+
"dataset_not_pageable",
|
|
3839
|
+
"dataset_not_searchable",
|
|
3840
|
+
"dataset_not_segmented",
|
|
3841
|
+
"index_not_found",
|
|
3842
|
+
"key_parse_error"
|
|
3843
|
+
]);
|
|
3844
|
+
const NO_VALUE_ERRORS = /* @__PURE__ */ new Set(["dataset_unassigned", "dataset_null"]);
|
|
3845
|
+
function toSelector(indexArg, joinArg) {
|
|
3846
|
+
const index2 = indexArg;
|
|
3847
|
+
return {
|
|
3848
|
+
index: index2 !== void 0 && index2.type === "some" ? index2.value : null,
|
|
3849
|
+
join: joinArg === true
|
|
3850
|
+
};
|
|
3851
|
+
}
|
|
3852
|
+
function checkDeclared(allowed, path2) {
|
|
3853
|
+
if (allowed === null) return;
|
|
3854
|
+
const pathStr = datasetPathToString(path2);
|
|
3855
|
+
if (!allowed.has(pathStr)) {
|
|
3856
|
+
throw new Error(
|
|
3857
|
+
`Data.bindPaged: source path "${pathStr}" not declared in manifest — bind it in the task body so derivation records it`
|
|
3858
|
+
);
|
|
3859
|
+
}
|
|
3860
|
+
}
|
|
3861
|
+
function errorCode(err) {
|
|
3701
3862
|
const code = err == null ? void 0 : err.code;
|
|
3702
|
-
return typeof code === "string"
|
|
3863
|
+
return typeof code === "string" ? code : void 0;
|
|
3864
|
+
}
|
|
3865
|
+
function isPermanentPageError(err) {
|
|
3866
|
+
const code = errorCode(err);
|
|
3867
|
+
return code !== void 0 && PERMANENT_PAGE_ERRORS.has(code);
|
|
3868
|
+
}
|
|
3869
|
+
function failureOf(path2, err) {
|
|
3870
|
+
const code = errorCode(err);
|
|
3871
|
+
const details = err == null ? void 0 : err.details;
|
|
3872
|
+
const reason = code === void 0 ? err instanceof Error ? err.message : String(err) : typeof details === "string" && details !== "" ? `${code}: ${details}` : code;
|
|
3873
|
+
return `Data.bindPaged: ${datasetPathToString(path2)}: ${reason}`;
|
|
3703
3874
|
}
|
|
3704
3875
|
function keyTypeOf(sourceType) {
|
|
3705
3876
|
if (sourceType.type === "Dict") return sourceType.value.key;
|
|
3706
3877
|
if (sourceType.type === "Set") return sourceType.value;
|
|
3707
3878
|
return null;
|
|
3708
3879
|
}
|
|
3709
|
-
function buildSeek(sourceType, T2, pathExpr, platform) {
|
|
3710
|
-
if (keyTypeOf(sourceType) === null) return none$1;
|
|
3880
|
+
function buildSeek(sourceType, T2, pathExpr, indexExpr, joinExpr, selector2, platform) {
|
|
3881
|
+
if (selector2.index === null && keyTypeOf(sourceType) === null) return none$1;
|
|
3711
3882
|
const { seek } = DataPagedPrimitives;
|
|
3712
3883
|
return some(East.compile(
|
|
3713
3884
|
East.function([SeekQueryType], OptionType(SeekRangeType), ($3, query) => {
|
|
3714
|
-
$3.return(seek([T2], pathExpr, query));
|
|
3885
|
+
$3.return(seek([T2], pathExpr, indexExpr, joinExpr, query));
|
|
3715
3886
|
}),
|
|
3716
3887
|
platform
|
|
3717
3888
|
));
|
|
3718
3889
|
}
|
|
3719
|
-
function
|
|
3720
|
-
return `paged:${workspace}:${datasetPathToString(path2)}
|
|
3890
|
+
function pagedRevisionKey(workspace, path2) {
|
|
3891
|
+
return `paged:${workspace}:${datasetPathToString(path2)}#revision`;
|
|
3721
3892
|
}
|
|
3722
|
-
function
|
|
3723
|
-
return `paged:${workspace}:${datasetPathToString(path2)}
|
|
3893
|
+
function pagedWindowKey(workspace, path2, revision, offset, limit2, selector2 = NO_INDEX) {
|
|
3894
|
+
return `paged:${workspace}:${datasetPathToString(path2)}${selectorKey(selector2)}@${revision}#${offset}+${limit2}`;
|
|
3724
3895
|
}
|
|
3725
|
-
function
|
|
3726
|
-
|
|
3727
|
-
return `paged:${workspace}:${datasetPathToString(path2)}#seek:${q}`;
|
|
3896
|
+
function pagedTotalKey(workspace, path2, revision, selector2 = NO_INDEX) {
|
|
3897
|
+
return `paged:${workspace}:${datasetPathToString(path2)}${selectorKey(selector2)}@${revision}#total`;
|
|
3728
3898
|
}
|
|
3729
|
-
function
|
|
3899
|
+
function pagedSeekKey(workspace, path2, revision, query, selector2 = NO_INDEX) {
|
|
3900
|
+
const q = "key" in query ? `k=${query.key}` : "fields" in query ? `f=${query.fields.join("\0")}|p=${query.prefix ?? ""}` : "prefix" in query ? `p=${query.prefix}` : `r=${(query.from ?? []).join("\0")}|${(query.to ?? []).join("\0")}`;
|
|
3901
|
+
return `paged:${workspace}:${datasetPathToString(path2)}${selectorKey(selector2)}@${revision}#seek:${q}`;
|
|
3902
|
+
}
|
|
3903
|
+
function toFindQuery(query, selector2 = NO_INDEX) {
|
|
3730
3904
|
const q = query;
|
|
3731
|
-
|
|
3732
|
-
if (q.type === "
|
|
3905
|
+
const scope = selector2.index === null ? {} : { index: selector2.index };
|
|
3906
|
+
if (q.type === "key") return { key: q.value, ...scope };
|
|
3907
|
+
if (q.type === "prefix") return { prefix: q.value, ...scope };
|
|
3908
|
+
if (q.type === "range") {
|
|
3909
|
+
const r2 = q.value;
|
|
3910
|
+
const from2 = [...r2.from];
|
|
3911
|
+
const to = [...r2.to];
|
|
3912
|
+
if (from2.length === 0 && to.length === 0) {
|
|
3913
|
+
throw new Error("Data.bindPaged: a range seek names no end — give it a `from`, a `to`, or both");
|
|
3914
|
+
}
|
|
3915
|
+
return from2.length === 0 ? { to, ...scope } : to.length === 0 ? { from: from2, ...scope } : { from: from2, to, ...scope };
|
|
3916
|
+
}
|
|
3733
3917
|
const f2 = q.value;
|
|
3734
3918
|
const fields = [...f2.values];
|
|
3735
|
-
return f2.prefix.type === "some" ? { fields, prefix: f2.prefix.value } : { fields };
|
|
3919
|
+
return f2.prefix.type === "some" ? { fields, prefix: f2.prefix.value, ...scope } : { fields, ...scope };
|
|
3736
3920
|
}
|
|
3737
3921
|
class PagedRuntime extends TrackedChannelStore {
|
|
3738
3922
|
constructor() {
|
|
3739
3923
|
super(...arguments);
|
|
3740
3924
|
__publicField(this, "api", null);
|
|
3741
3925
|
__publicField(this, "workspace", null);
|
|
3742
|
-
// Compiled-handle cache (issue #106 perf): buildHandle compiles
|
|
3926
|
+
// Compiled-handle cache (issue #106 perf): buildHandle compiles several
|
|
3743
3927
|
// East.functions per bind, and binds re-run every reactive frame. The
|
|
3744
|
-
// method IR is a pure function of (sourceType,
|
|
3745
|
-
// resolve api/workspace LIVE, so a cached handle still
|
|
3928
|
+
// method IR is a pure function of (sourceType, path, selector, shape), and
|
|
3929
|
+
// the methods resolve api/workspace LIVE, so a cached handle still
|
|
3930
|
+
// re-binds.
|
|
3746
3931
|
//
|
|
3747
3932
|
// Keyed by TYPE first, then path — never by path alone. The window decoder
|
|
3748
3933
|
// is baked from `sourceType`, so a path re-bound at a different type (a
|
|
@@ -3757,6 +3942,10 @@ class PagedRuntime extends TrackedChannelStore {
|
|
|
3757
3942
|
/** Loaded window keys in least-recently-READ order (a Map preserves
|
|
3758
3943
|
* insertion order; a read re-inserts). Bounds the decoded-window cache. */
|
|
3759
3944
|
__publicField(this, "loadedWindows", /* @__PURE__ */ new Map());
|
|
3945
|
+
/** Each dataset's snapshot, by workspace and path. */
|
|
3946
|
+
__publicField(this, "snapshots", /* @__PURE__ */ new Map());
|
|
3947
|
+
/** Fetches launched so far — the source of every channel's `launchSeq`. */
|
|
3948
|
+
__publicField(this, "launches", 0);
|
|
3760
3949
|
}
|
|
3761
3950
|
/** Monotonic clock seam so tests can drive the retry gate. */
|
|
3762
3951
|
now() {
|
|
@@ -3767,17 +3956,33 @@ class PagedRuntime extends TrackedChannelStore {
|
|
|
3767
3956
|
}
|
|
3768
3957
|
// ----- wiring ----------------------------------------------------------
|
|
3769
3958
|
/** Install the API adapter + workspace — called by the React provider
|
|
3770
|
-
* (or a test/showcase harness) before any handle is used.
|
|
3959
|
+
* (or a test/showcase harness) before any handle is used. Another adapter
|
|
3960
|
+
* or workspace starts from nothing: no snapshot of the old one's carries
|
|
3961
|
+
* over. */
|
|
3771
3962
|
initialize(api3, workspace) {
|
|
3963
|
+
if (this.api !== api3 || this.workspace !== workspace) this.reset();
|
|
3772
3964
|
this.api = api3;
|
|
3773
3965
|
this.workspace = workspace;
|
|
3774
3966
|
}
|
|
3775
|
-
/**
|
|
3776
|
-
|
|
3967
|
+
/**
|
|
3968
|
+
* Tear down the adapter and all window state.
|
|
3969
|
+
*
|
|
3970
|
+
* @param api - Clear only while this is the installed adapter, so a
|
|
3971
|
+
* provider tearing down after another installed its own leaves that one
|
|
3972
|
+
* in place
|
|
3973
|
+
*/
|
|
3974
|
+
clear(api3) {
|
|
3975
|
+
if (api3 !== void 0 && this.api !== api3) return;
|
|
3777
3976
|
this.api = null;
|
|
3778
3977
|
this.workspace = null;
|
|
3779
|
-
this.
|
|
3978
|
+
this.reset();
|
|
3780
3979
|
this.handleCache.clear();
|
|
3980
|
+
}
|
|
3981
|
+
/** Stop following every dataset, and drop what every snapshot delivered. */
|
|
3982
|
+
reset() {
|
|
3983
|
+
for (const snapshot of this.snapshots.values()) snapshot.unwatch();
|
|
3984
|
+
this.snapshots.clear();
|
|
3985
|
+
this.clearChannels();
|
|
3781
3986
|
this.loadedWindows.clear();
|
|
3782
3987
|
}
|
|
3783
3988
|
resolveWorkspace() {
|
|
@@ -3788,7 +3993,178 @@ class PagedRuntime extends TrackedChannelStore {
|
|
|
3788
3993
|
}
|
|
3789
3994
|
return this.workspace;
|
|
3790
3995
|
}
|
|
3791
|
-
// -----
|
|
3996
|
+
// ----- snapshots -------------------------------------------------------
|
|
3997
|
+
/** A dataset's snapshot, followed from its first read until the runtime
|
|
3998
|
+
* is cleared. */
|
|
3999
|
+
snapshotOf(workspace, path2) {
|
|
4000
|
+
const key = `${workspace}:${datasetPathToString(path2)}`;
|
|
4001
|
+
const existing = this.snapshots.get(key);
|
|
4002
|
+
if (existing !== void 0) return existing;
|
|
4003
|
+
const snapshot = {
|
|
4004
|
+
key,
|
|
4005
|
+
revision: void 0,
|
|
4006
|
+
moves: 0,
|
|
4007
|
+
findSeq: 0,
|
|
4008
|
+
finding: false,
|
|
4009
|
+
channels: /* @__PURE__ */ new Set(),
|
|
4010
|
+
unwatch: () => {
|
|
4011
|
+
}
|
|
4012
|
+
};
|
|
4013
|
+
this.snapshots.set(key, snapshot);
|
|
4014
|
+
if (this.api !== null) {
|
|
4015
|
+
snapshot.unwatch = this.api.watchRevision(workspace, path2, (hash2) => this.moveTo(workspace, path2, snapshot, hash2));
|
|
4016
|
+
}
|
|
4017
|
+
return snapshot;
|
|
4018
|
+
}
|
|
4019
|
+
/** Whether a snapshot is still the runtime's, rather than one a clear or a
|
|
4020
|
+
* re-initialization dropped. */
|
|
4021
|
+
isLive(snapshot) {
|
|
4022
|
+
return this.snapshots.get(snapshot.key) === snapshot;
|
|
4023
|
+
}
|
|
4024
|
+
/** Whether a live snapshot is still pinned to `revision`. */
|
|
4025
|
+
pinnedTo(snapshot, revision) {
|
|
4026
|
+
return this.isLive(snapshot) && snapshot.revision === revision;
|
|
4027
|
+
}
|
|
4028
|
+
/**
|
|
4029
|
+
* The revision a read of `path` is pinned to — a hash, `null` while the
|
|
4030
|
+
* dataset has no value, or `undefined` while it is being found — tracked so
|
|
4031
|
+
* the read re-fires when the source moves.
|
|
4032
|
+
*
|
|
4033
|
+
* @throws The failed lookup's reason, until a read after the retry gap
|
|
4034
|
+
* looks again
|
|
4035
|
+
*/
|
|
4036
|
+
revisionFor(workspace, path2) {
|
|
4037
|
+
this.track(pagedRevisionKey(workspace, path2));
|
|
4038
|
+
const snapshot = this.snapshotOf(workspace, path2);
|
|
4039
|
+
if (snapshot.revision !== void 0 || snapshot.finding) return snapshot.revision;
|
|
4040
|
+
if (snapshot.findError !== void 0 && this.now() - (snapshot.findFailedAtMs ?? 0) < RETRY_AFTER_MS) {
|
|
4041
|
+
throw new Error(snapshot.findError);
|
|
4042
|
+
}
|
|
4043
|
+
this.find(workspace, path2, snapshot);
|
|
4044
|
+
return void 0;
|
|
4045
|
+
}
|
|
4046
|
+
/**
|
|
4047
|
+
* Ask the server which content the dataset holds, and move there — unless
|
|
4048
|
+
* a move lands first, which came from something no older than the answer.
|
|
4049
|
+
*/
|
|
4050
|
+
find(workspace, path2, snapshot) {
|
|
4051
|
+
const seq = ++snapshot.findSeq;
|
|
4052
|
+
const moves = snapshot.moves;
|
|
4053
|
+
snapshot.finding = true;
|
|
4054
|
+
const api3 = this.api;
|
|
4055
|
+
void (async () => {
|
|
4056
|
+
let revision;
|
|
4057
|
+
try {
|
|
4058
|
+
if (api3 === null) throw new Error("no PagedApi installed");
|
|
4059
|
+
revision = await api3.getRevision(workspace, path2);
|
|
4060
|
+
} catch (err) {
|
|
4061
|
+
if (!this.isLive(snapshot) || snapshot.findSeq !== seq) return;
|
|
4062
|
+
snapshot.finding = false;
|
|
4063
|
+
if (snapshot.revision !== void 0) return;
|
|
4064
|
+
snapshot.findError = failureOf(path2, err);
|
|
4065
|
+
snapshot.findFailedAtMs = this.now();
|
|
4066
|
+
console.error(`Data.bindPaged: could not find which content ${datasetPathToString(path2)} holds:`, err);
|
|
4067
|
+
this.notify(pagedRevisionKey(workspace, path2));
|
|
4068
|
+
return;
|
|
4069
|
+
}
|
|
4070
|
+
if (!this.isLive(snapshot) || snapshot.findSeq !== seq) return;
|
|
4071
|
+
snapshot.finding = false;
|
|
4072
|
+
if (snapshot.moves !== moves) return;
|
|
4073
|
+
this.moveTo(workspace, path2, snapshot, revision);
|
|
4074
|
+
})();
|
|
4075
|
+
}
|
|
4076
|
+
/**
|
|
4077
|
+
* Move a dataset's source to `revision`: drop what the old snapshot
|
|
4078
|
+
* delivered and re-fire every read of the dataset, so the windows and
|
|
4079
|
+
* searches still in use are fetched again, pinned to the new one. A move to
|
|
4080
|
+
* the revision the source already has changes nothing.
|
|
4081
|
+
*/
|
|
4082
|
+
moveTo(workspace, path2, snapshot, revision) {
|
|
4083
|
+
if (!this.isLive(snapshot) || snapshot.revision === revision) return;
|
|
4084
|
+
snapshot.revision = revision;
|
|
4085
|
+
snapshot.moves += 1;
|
|
4086
|
+
delete snapshot.findError;
|
|
4087
|
+
delete snapshot.findFailedAtMs;
|
|
4088
|
+
for (const key of snapshot.channels) {
|
|
4089
|
+
this.entries.delete(key);
|
|
4090
|
+
this.loadedWindows.delete(key);
|
|
4091
|
+
}
|
|
4092
|
+
snapshot.channels.clear();
|
|
4093
|
+
this.notify(pagedRevisionKey(workspace, path2));
|
|
4094
|
+
}
|
|
4095
|
+
/**
|
|
4096
|
+
* Handle what a pinned fetch threw when it is not the read's failure: a
|
|
4097
|
+
* refusal naming other content moves the source there, and "no value"
|
|
4098
|
+
* moves it to no snapshot. Returns whether the error was one of those, or
|
|
4099
|
+
* arrived after the source had already moved on.
|
|
4100
|
+
*/
|
|
4101
|
+
followed(workspace, path2, snapshot, revision, err) {
|
|
4102
|
+
if (!this.pinnedTo(snapshot, revision)) return true;
|
|
4103
|
+
if (err instanceof DatasetHashMismatchError) {
|
|
4104
|
+
if (err.currentHash !== null && err.currentHash !== revision) {
|
|
4105
|
+
this.moveTo(workspace, path2, snapshot, err.currentHash);
|
|
4106
|
+
return true;
|
|
4107
|
+
}
|
|
4108
|
+
this.find(workspace, path2, snapshot);
|
|
4109
|
+
return false;
|
|
4110
|
+
}
|
|
4111
|
+
const code = errorCode(err);
|
|
4112
|
+
if (code !== void 0 && NO_VALUE_ERRORS.has(code)) {
|
|
4113
|
+
this.moveTo(workspace, path2, snapshot, null);
|
|
4114
|
+
return true;
|
|
4115
|
+
}
|
|
4116
|
+
return false;
|
|
4117
|
+
}
|
|
4118
|
+
// ----- channels ----------------------------------------------------------
|
|
4119
|
+
/** A channel of the snapshot's current revision, dropped when it moves. */
|
|
4120
|
+
channel(snapshot, key) {
|
|
4121
|
+
snapshot.channels.add(key);
|
|
4122
|
+
return this.entry(key);
|
|
4123
|
+
}
|
|
4124
|
+
/** Whether a channel is due a fetch: never fetched, evicted, or failed
|
|
4125
|
+
* for a reason a retry can fix, longer ago than the retry gap. */
|
|
4126
|
+
due(entry) {
|
|
4127
|
+
if (entry.status === "idle") return true;
|
|
4128
|
+
if (entry.status !== "failed" || entry.permanent === true) return false;
|
|
4129
|
+
return this.now() - (entry.failedAtMs ?? 0) >= RETRY_AFTER_MS;
|
|
4130
|
+
}
|
|
4131
|
+
/**
|
|
4132
|
+
* Mark a channel's fetch as started, returning the fetch's sequence number.
|
|
4133
|
+
*
|
|
4134
|
+
* Deliberately does NOT notify — the read that triggers it runs inside a
|
|
4135
|
+
* render pass, and notifying there would re-enter the renderer. Only the
|
|
4136
|
+
* settle notifies.
|
|
4137
|
+
*/
|
|
4138
|
+
launch(entry) {
|
|
4139
|
+
entry.status = "running";
|
|
4140
|
+
entry.launchSeq = ++this.launches;
|
|
4141
|
+
return entry.launchSeq;
|
|
4142
|
+
}
|
|
4143
|
+
/** Apply a fetch's outcome if the channel still waits on it, re-firing the
|
|
4144
|
+
* channel's reads. Returns whether it applied. */
|
|
4145
|
+
settle(key, seq, mutate) {
|
|
4146
|
+
const entry = this.entries.get(key);
|
|
4147
|
+
if (entry === void 0 || entry.launchSeq !== seq) return false;
|
|
4148
|
+
mutate(entry);
|
|
4149
|
+
this.notify(key);
|
|
4150
|
+
return true;
|
|
4151
|
+
}
|
|
4152
|
+
/** Settle a fetch as failed, with the reason a read will throw. */
|
|
4153
|
+
fail(key, seq, reason, permanent) {
|
|
4154
|
+
this.settle(key, seq, (e3) => {
|
|
4155
|
+
e3.status = "failed";
|
|
4156
|
+
e3.error = reason;
|
|
4157
|
+
e3.failedAtMs = this.now();
|
|
4158
|
+
e3.permanent = permanent;
|
|
4159
|
+
});
|
|
4160
|
+
}
|
|
4161
|
+
/** What a read of a channel answers: its value once loaded, `none` while
|
|
4162
|
+
* in flight, or its failure, thrown. */
|
|
4163
|
+
answer(entry, value) {
|
|
4164
|
+
if (entry.status === "loaded" && value !== void 0) return some(value);
|
|
4165
|
+
if (entry.status === "failed") throw new Error(entry.error ?? "Data.bindPaged: the read failed");
|
|
4166
|
+
return none$1;
|
|
4167
|
+
}
|
|
3792
4168
|
/** Note a window as most-recently-read, and drop the coldest decoded
|
|
3793
4169
|
* windows once the cache exceeds its cap. An evicted window returns to
|
|
3794
4170
|
* `idle`, so the next read refetches it rather than reading a hole. */
|
|
@@ -3806,131 +4182,83 @@ class PagedRuntime extends TrackedChannelStore {
|
|
|
3806
4182
|
delete entry.window;
|
|
3807
4183
|
}
|
|
3808
4184
|
}
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
*
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
ensureWindow(sourceType, workspace, path2, offset, limit2) {
|
|
3817
|
-
const key = pagedWindowKey(workspace, path2, offset, limit2);
|
|
3818
|
-
const entry = this.entry(key);
|
|
3819
|
-
if (entry.status === "running" || entry.status === "loaded") return;
|
|
3820
|
-
if (entry.status === "failed") {
|
|
3821
|
-
if (entry.permanent) return;
|
|
3822
|
-
const since = this.now() - (entry.failedAtMs ?? 0);
|
|
3823
|
-
if (since < RETRY_AFTER_MS) return;
|
|
3824
|
-
}
|
|
3825
|
-
entry.status = "running";
|
|
3826
|
-
entry.launchSeq += 1;
|
|
3827
|
-
const mySeq = entry.launchSeq;
|
|
4185
|
+
// ----- window loading --------------------------------------------------
|
|
4186
|
+
/** Start the pinned fetch for a window if it is due one, returning its
|
|
4187
|
+
* channel. */
|
|
4188
|
+
ensureWindow(sourceType, workspace, path2, snapshot, revision, offset, limit2, selector2, key) {
|
|
4189
|
+
const entry = this.channel(snapshot, key);
|
|
4190
|
+
if (!this.due(entry)) return entry;
|
|
4191
|
+
const seq = this.launch(entry);
|
|
3828
4192
|
const api3 = this.api;
|
|
3829
4193
|
void (async () => {
|
|
3830
|
-
const settle = (mutate) => {
|
|
3831
|
-
const current = this.entries.get(key);
|
|
3832
|
-
if (!current || current.launchSeq !== mySeq) return;
|
|
3833
|
-
mutate(current);
|
|
3834
|
-
this.notify(key);
|
|
3835
|
-
};
|
|
3836
|
-
if (!api3) {
|
|
3837
|
-
settle((e3) => {
|
|
3838
|
-
e3.status = "failed";
|
|
3839
|
-
e3.failedAtMs = this.now();
|
|
3840
|
-
});
|
|
3841
|
-
console.error("Data.bindPaged: no PagedApi installed");
|
|
3842
|
-
return;
|
|
3843
|
-
}
|
|
3844
4194
|
let page;
|
|
3845
4195
|
try {
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
e3.permanent = permanent;
|
|
4196
|
+
if (api3 === null) throw new Error("no PagedApi installed");
|
|
4197
|
+
page = await api3.getPage(workspace, path2, {
|
|
4198
|
+
offset,
|
|
4199
|
+
limit: limit2,
|
|
4200
|
+
hash: revision,
|
|
4201
|
+
...selector2.index !== null && { index: selector2.index, join: selector2.join }
|
|
3853
4202
|
});
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
);
|
|
4203
|
+
} catch (err) {
|
|
4204
|
+
if (this.followed(workspace, path2, snapshot, revision, err)) return;
|
|
4205
|
+
this.fail(key, seq, failureOf(path2, err), isPermanentPageError(err));
|
|
4206
|
+
console.error(`Data.bindPaged: fetch failed for ${key}:`, err);
|
|
3858
4207
|
return;
|
|
3859
4208
|
}
|
|
4209
|
+
if (!this.pinnedTo(snapshot, revision)) return;
|
|
3860
4210
|
let decoded;
|
|
3861
4211
|
try {
|
|
3862
4212
|
decoded = decodeBeast2For(sourceType)(page.data);
|
|
3863
4213
|
} catch (err) {
|
|
3864
|
-
|
|
3865
|
-
e3.status = "failed";
|
|
3866
|
-
e3.failedAtMs = this.now();
|
|
3867
|
-
});
|
|
4214
|
+
this.fail(key, seq, `${failureOf(path2, err)} (the window does not decode as the source's type)`, true);
|
|
3868
4215
|
console.error(`Data.bindPaged: decode failed for ${key}:`, err);
|
|
3869
4216
|
return;
|
|
3870
4217
|
}
|
|
3871
|
-
settle((e3) => {
|
|
4218
|
+
const landed = this.settle(key, seq, (e3) => {
|
|
3872
4219
|
e3.status = "loaded";
|
|
3873
4220
|
e3.window = decoded;
|
|
3874
4221
|
e3.total = page.totalElements;
|
|
4222
|
+
delete e3.error;
|
|
3875
4223
|
});
|
|
4224
|
+
if (!landed) return;
|
|
3876
4225
|
this.touchWindow(key);
|
|
3877
|
-
const totalKey = pagedTotalKey(workspace, path2);
|
|
3878
|
-
const totalEntry = this.
|
|
4226
|
+
const totalKey = pagedTotalKey(workspace, path2, revision, selector2);
|
|
4227
|
+
const totalEntry = this.channel(snapshot, totalKey);
|
|
3879
4228
|
if (totalEntry.total !== page.totalElements) {
|
|
3880
4229
|
totalEntry.total = page.totalElements;
|
|
3881
4230
|
totalEntry.status = "loaded";
|
|
3882
4231
|
this.notify(totalKey);
|
|
3883
4232
|
}
|
|
3884
4233
|
})();
|
|
4234
|
+
return entry;
|
|
3885
4235
|
}
|
|
3886
|
-
/**
|
|
3887
|
-
*
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
const entry = this.entry(key);
|
|
3893
|
-
if (entry.status === "running" || entry.status === "loaded") return;
|
|
3894
|
-
if (entry.status === "failed") {
|
|
3895
|
-
if (entry.permanent) return;
|
|
3896
|
-
const since = this.now() - (entry.failedAtMs ?? 0);
|
|
3897
|
-
if (since < RETRY_AFTER_MS) return;
|
|
3898
|
-
}
|
|
3899
|
-
entry.status = "running";
|
|
3900
|
-
entry.launchSeq += 1;
|
|
3901
|
-
const mySeq = entry.launchSeq;
|
|
4236
|
+
/** Start the pinned fence search for one key query if it is due one,
|
|
4237
|
+
* returning its channel — the seek sibling of {@link ensureWindow}. */
|
|
4238
|
+
ensureSeek(workspace, path2, snapshot, revision, query, key) {
|
|
4239
|
+
const entry = this.channel(snapshot, key);
|
|
4240
|
+
if (!this.due(entry)) return entry;
|
|
4241
|
+
const seq = this.launch(entry);
|
|
3902
4242
|
const api3 = this.api;
|
|
3903
4243
|
void (async () => {
|
|
3904
|
-
|
|
3905
|
-
const current = this.entries.get(key);
|
|
3906
|
-
if (!current || current.launchSeq !== mySeq) return;
|
|
3907
|
-
mutate(current);
|
|
3908
|
-
this.notify(key);
|
|
3909
|
-
};
|
|
3910
|
-
if (!api3) {
|
|
3911
|
-
settle((e3) => {
|
|
3912
|
-
e3.status = "failed";
|
|
3913
|
-
e3.failedAtMs = this.now();
|
|
3914
|
-
});
|
|
3915
|
-
console.error("Data.bindPaged: no PagedApi installed");
|
|
3916
|
-
return;
|
|
3917
|
-
}
|
|
4244
|
+
let range;
|
|
3918
4245
|
try {
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
e3.status = "loaded";
|
|
3922
|
-
e3.range = range;
|
|
3923
|
-
});
|
|
4246
|
+
if (api3 === null) throw new Error("no PagedApi installed");
|
|
4247
|
+
range = await api3.findKey(workspace, path2, { ...query, hash: revision });
|
|
3924
4248
|
} catch (err) {
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
e3.status = "failed";
|
|
3928
|
-
e3.failedAtMs = this.now();
|
|
3929
|
-
e3.permanent = permanent;
|
|
3930
|
-
});
|
|
4249
|
+
if (this.followed(workspace, path2, snapshot, revision, err)) return;
|
|
4250
|
+
this.fail(key, seq, failureOf(path2, err), isPermanentPageError(err));
|
|
3931
4251
|
console.error(`Data.bindPaged: key search failed for ${key}:`, err);
|
|
4252
|
+
return;
|
|
3932
4253
|
}
|
|
4254
|
+
if (!this.pinnedTo(snapshot, revision)) return;
|
|
4255
|
+
this.settle(key, seq, (e3) => {
|
|
4256
|
+
e3.status = "loaded";
|
|
4257
|
+
e3.range = range;
|
|
4258
|
+
delete e3.error;
|
|
4259
|
+
});
|
|
3933
4260
|
})();
|
|
4261
|
+
return entry;
|
|
3934
4262
|
}
|
|
3935
4263
|
/**
|
|
3936
4264
|
* The low-level primitives backing handle methods, bound to THIS runtime.
|
|
@@ -3940,53 +4268,92 @@ class PagedRuntime extends TrackedChannelStore {
|
|
|
3940
4268
|
*/
|
|
3941
4269
|
buildPrimitives() {
|
|
3942
4270
|
return [
|
|
3943
|
-
DataPagedPrimitives.page.implement((sourceType) => (pathArg, offsetArg, limitArg) => {
|
|
4271
|
+
DataPagedPrimitives.page.implement((sourceType) => (pathArg, indexArg, joinArg, offsetArg, limitArg) => {
|
|
3944
4272
|
const workspace = this.resolveWorkspace();
|
|
3945
4273
|
const path2 = pathArg;
|
|
4274
|
+
const revision = this.revisionFor(workspace, path2);
|
|
4275
|
+
if (typeof revision !== "string") return none$1;
|
|
4276
|
+
const selector2 = toSelector(indexArg, joinArg);
|
|
3946
4277
|
const offset = Number(offsetArg);
|
|
3947
4278
|
const limit2 = Number(limitArg);
|
|
3948
|
-
const key = pagedWindowKey(workspace, path2, offset, limit2);
|
|
4279
|
+
const key = pagedWindowKey(workspace, path2, revision, offset, limit2, selector2);
|
|
3949
4280
|
this.track(key);
|
|
3950
|
-
this.ensureWindow(
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
4281
|
+
const entry = this.ensureWindow(
|
|
4282
|
+
sourceType,
|
|
4283
|
+
workspace,
|
|
4284
|
+
path2,
|
|
4285
|
+
this.snapshotOf(workspace, path2),
|
|
4286
|
+
revision,
|
|
4287
|
+
offset,
|
|
4288
|
+
limit2,
|
|
4289
|
+
selector2,
|
|
4290
|
+
key
|
|
4291
|
+
);
|
|
4292
|
+
if (entry.status === "loaded" && entry.window !== void 0) this.touchWindow(key);
|
|
4293
|
+
return this.answer(entry, entry.window);
|
|
3957
4294
|
}),
|
|
3958
|
-
DataPagedPrimitives.total.implement((_sourceType) => (pathArg) => {
|
|
4295
|
+
DataPagedPrimitives.total.implement((_sourceType) => (pathArg, indexArg, joinArg) => {
|
|
3959
4296
|
const workspace = this.resolveWorkspace();
|
|
3960
|
-
const
|
|
4297
|
+
const path2 = pathArg;
|
|
4298
|
+
const revision = this.revisionFor(workspace, path2);
|
|
4299
|
+
if (typeof revision !== "string") return none$1;
|
|
4300
|
+
const key = pagedTotalKey(workspace, path2, revision, toSelector(indexArg, joinArg));
|
|
3961
4301
|
this.track(key);
|
|
3962
|
-
const entry = this.
|
|
3963
|
-
return entry.total !== void 0 ?
|
|
4302
|
+
const entry = this.channel(this.snapshotOf(workspace, path2), key);
|
|
4303
|
+
return entry.total !== void 0 ? some(BigInt(entry.total)) : none$1;
|
|
3964
4304
|
}),
|
|
3965
|
-
DataPagedPrimitives.seek.implement((_sourceType) => (pathArg, queryArg) => {
|
|
4305
|
+
DataPagedPrimitives.seek.implement((_sourceType) => (pathArg, indexArg, joinArg, queryArg) => {
|
|
3966
4306
|
const workspace = this.resolveWorkspace();
|
|
3967
4307
|
const path2 = pathArg;
|
|
3968
|
-
const
|
|
3969
|
-
|
|
4308
|
+
const revision = this.revisionFor(workspace, path2);
|
|
4309
|
+
if (typeof revision !== "string") return none$1;
|
|
4310
|
+
const selector2 = toSelector(indexArg, joinArg);
|
|
4311
|
+
const query = toFindQuery(queryArg, selector2);
|
|
4312
|
+
const key = pagedSeekKey(workspace, path2, revision, query, selector2);
|
|
3970
4313
|
this.track(key);
|
|
3971
|
-
this.ensureSeek(workspace, path2, query, key);
|
|
3972
|
-
const
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
4314
|
+
const entry = this.ensureSeek(workspace, path2, this.snapshotOf(workspace, path2), revision, query, key);
|
|
4315
|
+
const range = entry.range;
|
|
4316
|
+
return this.answer(entry, range === void 0 ? void 0 : { found: range.found, row: BigInt(range.row), count: BigInt(range.count) });
|
|
4317
|
+
}),
|
|
4318
|
+
DataPagedPrimitives.revision.implement((_sourceType) => (pathArg, _indexArg, _joinArg) => {
|
|
4319
|
+
const revision = this.revisionFor(this.resolveWorkspace(), pathArg);
|
|
4320
|
+
return typeof revision === "string" ? some(revision) : none$1;
|
|
4321
|
+
}),
|
|
4322
|
+
DataPagedPrimitives.refresh.implement((_sourceType) => (pathArg, _indexArg, _joinArg, targetArg) => {
|
|
4323
|
+
const workspace = this.resolveWorkspace();
|
|
4324
|
+
const path2 = pathArg;
|
|
4325
|
+
const target = targetArg;
|
|
4326
|
+
queueMicrotask(() => {
|
|
4327
|
+
if (this.workspace !== workspace) return;
|
|
4328
|
+
const snapshot = this.snapshotOf(workspace, path2);
|
|
4329
|
+
if (target.type === "some") this.moveTo(workspace, path2, snapshot, target.value);
|
|
4330
|
+
else this.find(workspace, path2, snapshot);
|
|
4331
|
+
});
|
|
4332
|
+
return null;
|
|
3976
4333
|
})
|
|
3977
4334
|
];
|
|
3978
4335
|
}
|
|
3979
4336
|
/**
|
|
3980
|
-
* Build the handle value for one
|
|
3981
|
-
*
|
|
3982
|
-
*
|
|
3983
|
-
* type-arg) — so the handle is ordinary serializable East data (issue
|
|
4337
|
+
* Build the handle value for one paged bind. Every method is a thin
|
|
4338
|
+
* IR-bearing `East.function` over {@link buildPrimitives}, capturing only
|
|
4339
|
+
* the plain-data source path and selector (the value type rides as a
|
|
4340
|
+
* type-arg) — so the handle is ordinary serializable East data (issue
|
|
4341
|
+
* #106).
|
|
4342
|
+
*
|
|
4343
|
+
* @param sourceType - The dataset's type, or an index's window type
|
|
4344
|
+
* @param path - The dataset's path
|
|
4345
|
+
* @param selector - The rows the bind serves
|
|
4346
|
+
* @param shape - `released`: the handle `data_bind_paged` returns, without
|
|
4347
|
+
* `revision` or `refresh`; `pinned`: the handle `data_bind_paged_pinned`
|
|
4348
|
+
* returns. Both read through the same snapshot.
|
|
4349
|
+
* @returns The handle
|
|
3984
4350
|
*/
|
|
3985
|
-
buildHandle(sourceType, path2) {
|
|
3986
|
-
const
|
|
4351
|
+
buildHandle(sourceType, path2, selector2, shape) {
|
|
4352
|
+
const id3 = `${datasetPathToString(path2)}${selectorKey(selector2)}`;
|
|
4353
|
+
const cacheKey = `${id3}#${shape}`;
|
|
3987
4354
|
let byPath = this.handleCache.get(sourceType);
|
|
3988
4355
|
if (byPath) {
|
|
3989
|
-
const hit = byPath.get(
|
|
4356
|
+
const hit = byPath.get(cacheKey);
|
|
3990
4357
|
if (hit) return hit;
|
|
3991
4358
|
} else {
|
|
3992
4359
|
byPath = /* @__PURE__ */ new Map();
|
|
@@ -3994,24 +4361,27 @@ class PagedRuntime extends TrackedChannelStore {
|
|
|
3994
4361
|
}
|
|
3995
4362
|
const T2 = fromEastTypeValue(sourceType);
|
|
3996
4363
|
const pathExpr = East.value(path2, TreePathType);
|
|
4364
|
+
const indexExpr = East.value(selector2.index === null ? none$1 : some(selector2.index), OptionType(StringType));
|
|
4365
|
+
const joinExpr = East.value(selector2.join, BooleanType);
|
|
3997
4366
|
const platform = this.buildPrimitives();
|
|
3998
|
-
const { page, total } = DataPagedPrimitives;
|
|
4367
|
+
const { page, total, revision, refresh } = DataPagedPrimitives;
|
|
3999
4368
|
const handle = {
|
|
4000
4369
|
// The comparable identity east-ui's `PagedSourceType` requires:
|
|
4001
4370
|
// East compares every function as EQUAL, so a struct of nothing but
|
|
4002
4371
|
// closures is indistinguishable from any other and a memoized
|
|
4003
4372
|
// component would never re-render on a source swap (#567 D4). The
|
|
4004
|
-
// dataset path
|
|
4005
|
-
|
|
4373
|
+
// dataset path and selector are the natural identity — same path,
|
|
4374
|
+
// same rows. The snapshot they serve is `revision`'s, not the id's.
|
|
4375
|
+
id: id3,
|
|
4006
4376
|
page: East.compile(
|
|
4007
4377
|
East.function([IntegerType, IntegerType], OptionType(T2), ($3, offset, limit2) => {
|
|
4008
|
-
$3.return(page([T2], pathExpr, offset, limit2));
|
|
4378
|
+
$3.return(page([T2], pathExpr, indexExpr, joinExpr, offset, limit2));
|
|
4009
4379
|
}),
|
|
4010
4380
|
platform
|
|
4011
4381
|
),
|
|
4012
4382
|
total: East.compile(
|
|
4013
4383
|
East.function([], OptionType(IntegerType), ($3) => {
|
|
4014
|
-
$3.return(total([T2], pathExpr));
|
|
4384
|
+
$3.return(total([T2], pathExpr, indexExpr, joinExpr));
|
|
4015
4385
|
}),
|
|
4016
4386
|
platform
|
|
4017
4387
|
),
|
|
@@ -4020,28 +4390,50 @@ class PagedRuntime extends TrackedChannelStore {
|
|
|
4020
4390
|
// segments) against the stored fences; an Array's stream order has
|
|
4021
4391
|
// nothing to search. Resolved at bind time from the dataset's own
|
|
4022
4392
|
// type, so a component renders the affordance only when it works.
|
|
4023
|
-
seek: buildSeek(sourceType, T2, pathExpr, platform)
|
|
4393
|
+
seek: buildSeek(sourceType, T2, pathExpr, indexExpr, joinExpr, selector2, platform)
|
|
4024
4394
|
};
|
|
4025
|
-
|
|
4395
|
+
if (shape === "pinned") {
|
|
4396
|
+
handle.revision = East.compile(
|
|
4397
|
+
East.function([], OptionType(StringType), ($3) => {
|
|
4398
|
+
$3.return(revision([T2], pathExpr, indexExpr, joinExpr));
|
|
4399
|
+
}),
|
|
4400
|
+
platform
|
|
4401
|
+
);
|
|
4402
|
+
handle.refresh = East.compile(
|
|
4403
|
+
East.function([OptionType(StringType)], NullType, ($3, target) => {
|
|
4404
|
+
$3.return(refresh([T2], pathExpr, indexExpr, joinExpr, target));
|
|
4405
|
+
}),
|
|
4406
|
+
platform
|
|
4407
|
+
);
|
|
4408
|
+
}
|
|
4409
|
+
byPath.set(cacheKey, handle);
|
|
4026
4410
|
return handle;
|
|
4027
4411
|
}
|
|
4028
4412
|
// ----- platform building -------------------------------------------------
|
|
4029
|
-
/** Build
|
|
4030
|
-
*
|
|
4031
|
-
*
|
|
4413
|
+
/** Build the PlatformFunction behind `data_bind_paged` — the bind a UI
|
|
4414
|
+
* exported before pinned reads calls — bound to this runtime. Its handle
|
|
4415
|
+
* has no `revision` or `refresh`, but its reads are pinned, follow the
|
|
4416
|
+
* dataset and fail visibly all the same. Pass `allowed=null` for an
|
|
4417
|
+
* unscoped impl, or a Set of path strings for manifest scoping. */
|
|
4032
4418
|
buildPlatform(allowed) {
|
|
4033
4419
|
return bindPagedPlatformFn.implement(
|
|
4034
4420
|
(sourceType) => (pathArg) => {
|
|
4035
4421
|
const path2 = pathArg;
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4422
|
+
checkDeclared(allowed, path2);
|
|
4423
|
+
return this.buildHandle(sourceType, path2, NO_INDEX, "released");
|
|
4424
|
+
}
|
|
4425
|
+
);
|
|
4426
|
+
}
|
|
4427
|
+
/** Build the PlatformFunction behind `data_bind_paged_pinned` — what
|
|
4428
|
+
* `Data.bindPaged` emits, for a dataset's own rows or a record's index —
|
|
4429
|
+
* bound to this runtime and scoped by `allowed` exactly as
|
|
4430
|
+
* {@link buildPlatform} is: an index read is a read of the record's path. */
|
|
4431
|
+
buildPinnedPlatform(allowed) {
|
|
4432
|
+
return bindPagedPinnedPlatformFn.implement(
|
|
4433
|
+
(sourceType) => (pathArg, indexArg, joinArg) => {
|
|
4434
|
+
const path2 = pathArg;
|
|
4435
|
+
checkDeclared(allowed, path2);
|
|
4436
|
+
return this.buildHandle(sourceType, path2, toSelector(indexArg, joinArg), "pinned");
|
|
4045
4437
|
}
|
|
4046
4438
|
);
|
|
4047
4439
|
}
|
|
@@ -4050,17 +4442,19 @@ const defaultPagedRuntime = new PagedRuntime();
|
|
|
4050
4442
|
function initializePagedApi(api3, workspace) {
|
|
4051
4443
|
defaultPagedRuntime.initialize(api3, workspace);
|
|
4052
4444
|
}
|
|
4053
|
-
function clearPagedApi() {
|
|
4054
|
-
defaultPagedRuntime.clear();
|
|
4445
|
+
function clearPagedApi(api3) {
|
|
4446
|
+
defaultPagedRuntime.clear(api3);
|
|
4055
4447
|
}
|
|
4056
4448
|
const PagedPlatform = [
|
|
4057
4449
|
defaultPagedRuntime.buildPlatform(null),
|
|
4450
|
+
defaultPagedRuntime.buildPinnedPlatform(null),
|
|
4058
4451
|
...defaultPagedRuntime.buildPrimitives()
|
|
4059
4452
|
];
|
|
4060
4453
|
function createScopedPagedPlatform(pages) {
|
|
4061
4454
|
const allowed = new Set(pages.map((p2) => datasetPathToString(p2)));
|
|
4062
4455
|
return [
|
|
4063
4456
|
defaultPagedRuntime.buildPlatform(allowed),
|
|
4457
|
+
defaultPagedRuntime.buildPinnedPlatform(allowed),
|
|
4064
4458
|
...defaultPagedRuntime.buildPrimitives()
|
|
4065
4459
|
];
|
|
4066
4460
|
}
|
|
@@ -4186,8 +4580,15 @@ class FuncRuntime extends TrackedChannelStore {
|
|
|
4186
4580
|
this.api = api3;
|
|
4187
4581
|
this.workspace = workspace;
|
|
4188
4582
|
}
|
|
4189
|
-
/**
|
|
4190
|
-
|
|
4583
|
+
/**
|
|
4584
|
+
* Tear down the adapter and all call state.
|
|
4585
|
+
*
|
|
4586
|
+
* @param api - Clear only while this is the installed adapter, so a
|
|
4587
|
+
* provider tearing down after another installed its own leaves that one
|
|
4588
|
+
* in place
|
|
4589
|
+
*/
|
|
4590
|
+
clear(api3) {
|
|
4591
|
+
if (api3 !== void 0 && this.api !== api3) return;
|
|
4191
4592
|
this.api = null;
|
|
4192
4593
|
this.workspace = null;
|
|
4193
4594
|
this.clearChannels();
|
|
@@ -4420,8 +4821,8 @@ const defaultFuncRuntime = new FuncRuntime();
|
|
|
4420
4821
|
function initializeFunctionApi(api3, workspace) {
|
|
4421
4822
|
defaultFuncRuntime.initialize(api3, workspace);
|
|
4422
4823
|
}
|
|
4423
|
-
function clearFunctionApi() {
|
|
4424
|
-
defaultFuncRuntime.clear();
|
|
4824
|
+
function clearFunctionApi(api3) {
|
|
4825
|
+
defaultFuncRuntime.clear(api3);
|
|
4425
4826
|
}
|
|
4426
4827
|
const FuncPlatform = [
|
|
4427
4828
|
defaultFuncRuntime.buildPlatform(null),
|
|
@@ -8194,12 +8595,6 @@ function errorOfMutationResult(result) {
|
|
|
8194
8595
|
message: `reducer exited with code ${outcome.value.exitCode}`,
|
|
8195
8596
|
stderr: outcome.value.stderr
|
|
8196
8597
|
};
|
|
8197
|
-
case "too_large":
|
|
8198
|
-
return {
|
|
8199
|
-
kind: variant("too_large", { bytes: outcome.value.bytes, limit: outcome.value.limit }),
|
|
8200
|
-
message: `new state too large (${outcome.value.bytes} bytes, limit ${outcome.value.limit})`,
|
|
8201
|
-
stderr: outcome.value.stderr
|
|
8202
|
-
};
|
|
8203
8598
|
case "timed_out":
|
|
8204
8599
|
return {
|
|
8205
8600
|
kind: variant("timed_out", { ms: outcome.value.ms }),
|
|
@@ -8259,8 +8654,15 @@ class RecordRuntime extends TrackedChannelStore {
|
|
|
8259
8654
|
this.cache = cache3;
|
|
8260
8655
|
this.workspace = workspace;
|
|
8261
8656
|
}
|
|
8262
|
-
/**
|
|
8263
|
-
|
|
8657
|
+
/**
|
|
8658
|
+
* Tear down the adapter and all record state.
|
|
8659
|
+
*
|
|
8660
|
+
* @param api - Clear only while this is the installed adapter, so a
|
|
8661
|
+
* provider tearing down after another installed its own leaves that one
|
|
8662
|
+
* in place
|
|
8663
|
+
*/
|
|
8664
|
+
clear(api3) {
|
|
8665
|
+
if (api3 !== void 0 && this.api !== api3) return;
|
|
8264
8666
|
this.api = null;
|
|
8265
8667
|
this.cache = null;
|
|
8266
8668
|
this.workspace = null;
|
|
@@ -8568,8 +8970,8 @@ const defaultRecordRuntime = new RecordRuntime();
|
|
|
8568
8970
|
function initializeRecordApi(api3, cache3, workspace) {
|
|
8569
8971
|
defaultRecordRuntime.initialize(api3, cache3, workspace);
|
|
8570
8972
|
}
|
|
8571
|
-
function clearRecordApi() {
|
|
8572
|
-
defaultRecordRuntime.clear();
|
|
8973
|
+
function clearRecordApi(api3) {
|
|
8974
|
+
defaultRecordRuntime.clear(api3);
|
|
8573
8975
|
}
|
|
8574
8976
|
const RecordPlatform = [
|
|
8575
8977
|
defaultRecordRuntime.buildPlatform(null),
|
|
@@ -8595,7 +8997,8 @@ function createInMemoryRecordApi(cache3, workspace, defs2) {
|
|
|
8595
8997
|
state: `${def.name}-state-0`.padEnd(64, "0"),
|
|
8596
8998
|
mutation: "$init",
|
|
8597
8999
|
actor: "memory",
|
|
8598
|
-
at: /* @__PURE__ */ new Date(0)
|
|
9000
|
+
at: /* @__PURE__ */ new Date(0),
|
|
9001
|
+
delta: none$1
|
|
8599
9002
|
};
|
|
8600
9003
|
compiled.set(def.name, { stateType, mutations, commits: [genesis], seq: 0 });
|
|
8601
9004
|
void cache3.write(workspace, recordPath(def.name), encodeBeast2For(stateType)(def.initial));
|
|
@@ -8627,7 +9030,8 @@ function createInMemoryRecordApi(cache3, workspace, defs2) {
|
|
|
8627
9030
|
state: `${record}-state-${c2.seq}`.padEnd(64, "0"),
|
|
8628
9031
|
mutation,
|
|
8629
9032
|
actor: "memory",
|
|
8630
|
-
at: /* @__PURE__ */ new Date(0)
|
|
9033
|
+
at: /* @__PURE__ */ new Date(0),
|
|
9034
|
+
delta: none$1
|
|
8631
9035
|
});
|
|
8632
9036
|
return { outcome: variant("committed", { commitHash: hash2, stateHash: `${record}-state-${c2.seq}`.padEnd(64, "0") }) };
|
|
8633
9037
|
},
|
|
@@ -8676,68 +9080,49 @@ function ReactiveDatasetProvider({
|
|
|
8676
9080
|
children: children2
|
|
8677
9081
|
}) {
|
|
8678
9082
|
const e3 = useE3Config();
|
|
9083
|
+
const { apiUrl, workspace } = e3;
|
|
9084
|
+
const repo = e3.repo ?? "default";
|
|
8679
9085
|
const tokenRef = useRef(e3.token ?? null);
|
|
8680
9086
|
tokenRef.current = e3.token ?? null;
|
|
8681
|
-
const
|
|
8682
|
-
() => createDefaultDatasetApi(e3.apiUrl, e3.repo ?? "default", () => tokenRef.current),
|
|
8683
|
-
[e3.apiUrl, e3.repo]
|
|
8684
|
-
);
|
|
8685
|
-
const cache3 = useMemo(() => {
|
|
8686
|
-
const cfg = {};
|
|
8687
|
-
if (e3.workspace !== void 0) cfg.workspace = e3.workspace;
|
|
8688
|
-
return new ReactiveDatasetCache(cfg, api3);
|
|
8689
|
-
}, [api3, e3.workspace]);
|
|
8690
|
-
useMemo(() => {
|
|
8691
|
-
initializeReactiveDatasetCache(cache3);
|
|
8692
|
-
cache3.setScheduler((notify3) => queueMicrotask(notify3));
|
|
8693
|
-
}, [cache3]);
|
|
8694
|
-
useMemo(() => {
|
|
8695
|
-
if (e3.workspace !== void 0) {
|
|
8696
|
-
initializeFunctionApi(
|
|
8697
|
-
createDefaultFunctionApi(e3.apiUrl, e3.repo ?? "default", () => tokenRef.current),
|
|
8698
|
-
e3.workspace
|
|
8699
|
-
);
|
|
8700
|
-
}
|
|
8701
|
-
}, [e3.apiUrl, e3.repo, e3.workspace]);
|
|
8702
|
-
useMemo(() => {
|
|
8703
|
-
if (e3.workspace !== void 0) {
|
|
8704
|
-
initializePagedApi(
|
|
8705
|
-
createDefaultPagedApi(e3.apiUrl, e3.repo ?? "default", () => tokenRef.current),
|
|
8706
|
-
e3.workspace
|
|
8707
|
-
);
|
|
8708
|
-
}
|
|
8709
|
-
}, [e3.apiUrl, e3.repo, e3.workspace]);
|
|
8710
|
-
useMemo(() => {
|
|
8711
|
-
if (e3.workspace !== void 0) {
|
|
8712
|
-
initializeRecordApi(
|
|
8713
|
-
createDefaultRecordApi(e3.apiUrl, e3.repo ?? "default", () => tokenRef.current),
|
|
8714
|
-
cache3,
|
|
8715
|
-
e3.workspace
|
|
8716
|
-
);
|
|
8717
|
-
}
|
|
8718
|
-
}, [e3.apiUrl, e3.repo, e3.workspace, cache3]);
|
|
9087
|
+
const [installed, setInstalled] = useState(null);
|
|
8719
9088
|
useEffect(() => {
|
|
9089
|
+
const getToken = () => tokenRef.current;
|
|
9090
|
+
const cache22 = new ReactiveDatasetCache(
|
|
9091
|
+
workspace !== void 0 ? { workspace } : {},
|
|
9092
|
+
createDefaultDatasetApi(apiUrl, repo, getToken)
|
|
9093
|
+
);
|
|
9094
|
+
cache22.setScheduler((notify3) => queueMicrotask(notify3));
|
|
9095
|
+
initializeReactiveDatasetCache(cache22);
|
|
9096
|
+
const functionApi = createDefaultFunctionApi(apiUrl, repo, getToken);
|
|
9097
|
+
const pagedApi = createDefaultPagedApi(apiUrl, repo, getToken, cache22);
|
|
9098
|
+
const recordApi = createDefaultRecordApi(apiUrl, repo, getToken);
|
|
9099
|
+
if (workspace !== void 0) {
|
|
9100
|
+
initializeFunctionApi(functionApi, workspace);
|
|
9101
|
+
initializePagedApi(pagedApi, workspace);
|
|
9102
|
+
initializeRecordApi(recordApi, cache22, workspace);
|
|
9103
|
+
}
|
|
9104
|
+
const unscopeStaged = getStagedStore().setScope(JSON.stringify([apiUrl, repo]));
|
|
9105
|
+
setInstalled({ apiUrl, repo, workspace, cache: cache22 });
|
|
8720
9106
|
return () => {
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
if (
|
|
9107
|
+
clearReactiveDatasetCache(cache22);
|
|
9108
|
+
clearFunctionApi(functionApi);
|
|
9109
|
+
clearPagedApi(pagedApi);
|
|
9110
|
+
clearRecordApi(recordApi);
|
|
9111
|
+
unscopeStaged();
|
|
9112
|
+
cache22.destroy();
|
|
9113
|
+
if (workspace) clearBindingRegistry(workspace);
|
|
8728
9114
|
else clearBindingRegistry();
|
|
8729
9115
|
};
|
|
8730
|
-
}, [
|
|
9116
|
+
}, [apiUrl, repo, workspace]);
|
|
9117
|
+
const cache3 = installed !== null && installed.apiUrl === apiUrl && installed.repo === repo && installed.workspace === workspace ? installed.cache : null;
|
|
8731
9118
|
useEffect(() => {
|
|
8732
|
-
if (typeof window
|
|
8733
|
-
|
|
8734
|
-
}
|
|
9119
|
+
if (cache3 === null || typeof window === "undefined") return;
|
|
9120
|
+
window.__EAST_REACTIVE_DATASET_CACHE__ = cache3;
|
|
8735
9121
|
return () => {
|
|
8736
|
-
|
|
8737
|
-
delete window.__EAST_REACTIVE_DATASET_CACHE__;
|
|
8738
|
-
}
|
|
9122
|
+
delete window.__EAST_REACTIVE_DATASET_CACHE__;
|
|
8739
9123
|
};
|
|
8740
9124
|
}, [cache3]);
|
|
9125
|
+
if (cache3 === null) return null;
|
|
8741
9126
|
return /* @__PURE__ */ jsx$1(ReactiveDatasetCacheContext.Provider, { value: cache3, children: children2 });
|
|
8742
9127
|
}
|
|
8743
9128
|
function useReactiveDatasetCache() {
|
|
@@ -64189,6 +64574,7 @@ function useDatasetValue(apiUrl, repo, workspace, datasetPath, options2) {
|
|
|
64189
64574
|
const { requestOptions, queryOverrides, enabled = true, hash: hash2, platforms, type } = options2;
|
|
64190
64575
|
const platformImpls = platforms ?? defaultPlatformImplementations;
|
|
64191
64576
|
const reqOpts = requestOptions ?? { token: null };
|
|
64577
|
+
const queryClient = useQueryClient();
|
|
64192
64578
|
const pathParts = useMemo(
|
|
64193
64579
|
() => (datasetPath == null ? void 0 : datasetPath.split(".").filter(Boolean).map((v3) => variant("field", v3))) ?? [],
|
|
64194
64580
|
[datasetPath]
|
|
@@ -64198,8 +64584,14 @@ function useDatasetValue(apiUrl, repo, workspace, datasetPath, options2) {
|
|
|
64198
64584
|
queryFn: async () => {
|
|
64199
64585
|
const result = await datasetGet(apiUrl, repo, workspace, pathParts, reqOpts);
|
|
64200
64586
|
const decoded = decodeBeast2For(type, { platform: platformImpls })(result.data);
|
|
64201
|
-
|
|
64587
|
+
const value = { decoded, sizeBytes: result.data.length, hash: result.hash ?? hash2 ?? null };
|
|
64588
|
+
if (value.hash !== hash2) {
|
|
64589
|
+
queryClient.setQueryData(["datasetValue", apiUrl, repo, workspace, datasetPath, value.hash], value);
|
|
64590
|
+
void queryClient.invalidateQueries({ queryKey: ["datasetStatus", apiUrl, repo, workspace, datasetPath] });
|
|
64591
|
+
}
|
|
64592
|
+
return value;
|
|
64202
64593
|
},
|
|
64594
|
+
select: (value) => value.hash === (hash2 ?? null) ? value : void 0,
|
|
64203
64595
|
enabled: enabled && !!workspace && !!datasetPath && hash2 != null,
|
|
64204
64596
|
...queryOverrides
|
|
64205
64597
|
});
|
|
@@ -64265,14 +64657,6 @@ function useTaskDetails(apiUrl, repo, workspace, taskName, options2) {
|
|
|
64265
64657
|
...options2 == null ? void 0 : options2.queryOverrides
|
|
64266
64658
|
});
|
|
64267
64659
|
}
|
|
64268
|
-
function getTaskKind(details) {
|
|
64269
|
-
var _a2;
|
|
64270
|
-
return ((_a2 = details.kind) == null ? void 0 : _a2.type) === "some" ? details.kind.value : null;
|
|
64271
|
-
}
|
|
64272
|
-
function getTaskMetadata(details) {
|
|
64273
|
-
var _a2;
|
|
64274
|
-
return ((_a2 = details.metadata) == null ? void 0 : _a2.type) === "some" ? details.metadata.value : null;
|
|
64275
|
-
}
|
|
64276
64660
|
const variantStyles = {
|
|
64277
64661
|
// Mode-aware semantic tokens (the raw `red.50` / `gray.50` washes rendered
|
|
64278
64662
|
// as bright light boxes in dark mode — #362).
|
|
@@ -64456,17 +64840,21 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
|
|
|
64456
64840
|
const [error3, setError] = useState(null);
|
|
64457
64841
|
const [jumpRow, setJumpRow] = useState(void 0);
|
|
64458
64842
|
const inflightRef = useRef(/* @__PURE__ */ new Set());
|
|
64843
|
+
const shownRef = useRef({ path: path2, hash: hash2 });
|
|
64459
64844
|
useEffect(() => {
|
|
64460
64845
|
pagingDebug(`reset (path=${path2}, hash=${hash2.slice(0, 8)})`);
|
|
64846
|
+
shownRef.current = { path: path2, hash: hash2 };
|
|
64461
64847
|
setPages(/* @__PURE__ */ new Map());
|
|
64462
64848
|
setTotals(null);
|
|
64463
64849
|
setError(null);
|
|
64464
64850
|
setJumpRow(void 0);
|
|
64465
|
-
inflightRef.current
|
|
64851
|
+
inflightRef.current = /* @__PURE__ */ new Set();
|
|
64466
64852
|
}, [path2, hash2]);
|
|
64467
64853
|
const loadPage = useCallback((pageIdx) => {
|
|
64468
|
-
|
|
64469
|
-
|
|
64854
|
+
const inflight = inflightRef.current;
|
|
64855
|
+
if (inflight.has(pageIdx)) return;
|
|
64856
|
+
inflight.add(pageIdx);
|
|
64857
|
+
const current = () => shownRef.current.path === path2 && shownRef.current.hash === hash2;
|
|
64470
64858
|
setLoadingCount((n2) => n2 + 1);
|
|
64471
64859
|
pagingDebug(`fetch p${pageIdx} (offset=${pageIdx * PAGE_SIZE}, limit=${PAGE_SIZE}, hash=${hash2.slice(0, 8)})`);
|
|
64472
64860
|
const pathParts2 = path2.split(".").filter(Boolean).map((v3) => variant("field", v3));
|
|
@@ -64479,6 +64867,7 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
|
|
|
64479
64867
|
staleTime: Infinity
|
|
64480
64868
|
// pages of one content hash are immutable
|
|
64481
64869
|
}).then((page) => {
|
|
64870
|
+
if (!current()) return;
|
|
64482
64871
|
const decoded = decodeBeast2For(type)(page.data);
|
|
64483
64872
|
const rows = pageRows(type, decoded, page.offset);
|
|
64484
64873
|
pagingDebug(
|
|
@@ -64492,12 +64881,17 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
|
|
|
64492
64881
|
setPages((prev2) => new Map(prev2).set(pageIdx, rows));
|
|
64493
64882
|
}).catch((err) => {
|
|
64494
64883
|
pagingDebug(`p${pageIdx} FAILED:`, err);
|
|
64884
|
+
if (!current()) return;
|
|
64885
|
+
if (err instanceof DatasetHashMismatchError) {
|
|
64886
|
+
void queryClient.invalidateQueries({ queryKey: ["datasetStatus", apiUrl, repo, workspace, path2] });
|
|
64887
|
+
return;
|
|
64888
|
+
}
|
|
64495
64889
|
if (err instanceof ApiError && err.code === "dataset_not_indexed") {
|
|
64496
64890
|
onNotIndexed == null ? void 0 : onNotIndexed();
|
|
64497
64891
|
}
|
|
64498
64892
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
64499
64893
|
}).finally(() => {
|
|
64500
|
-
|
|
64894
|
+
inflight.delete(pageIdx);
|
|
64501
64895
|
setLoadingCount((n2) => n2 - 1);
|
|
64502
64896
|
});
|
|
64503
64897
|
}, [queryClient, apiUrl, repo, workspace, path2, hash2, requestOptions, type, onNotIndexed]);
|
|
@@ -64594,7 +64988,10 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
|
|
|
64594
64988
|
] }),
|
|
64595
64989
|
/* @__PURE__ */ jsx$1(Box, { flex: 1, minHeight: 0, overflow: "hidden", children: /* @__PURE__ */ jsx$1(EastChakraValueTree, { value: treeValue, storageKey: `${path2}:page`, paging }) })
|
|
64596
64990
|
] });
|
|
64597
|
-
}, (prev2, next2) =>
|
|
64991
|
+
}, (prev2, next2) => {
|
|
64992
|
+
var _a2, _b2;
|
|
64993
|
+
return prev2.apiUrl === next2.apiUrl && prev2.repo === next2.repo && prev2.workspace === next2.workspace && prev2.path === next2.path && prev2.hash === next2.hash && prev2.sizeBytes === next2.sizeBytes && ((_a2 = prev2.requestOptions) == null ? void 0 : _a2.token) === ((_b2 = next2.requestOptions) == null ? void 0 : _b2.token);
|
|
64994
|
+
});
|
|
64598
64995
|
const DEFAULT_SIZE_LIMIT = 200 * 1024;
|
|
64599
64996
|
function formatSize(bytes) {
|
|
64600
64997
|
if (bytes < 1024) return `${bytes} B`;
|
|
@@ -64654,12 +65051,29 @@ const DatasetPreview = memo(function DatasetPreview2({
|
|
|
64654
65051
|
const setMutation = useDatasetSet(apiUrl, repo, workspace, requestOptions);
|
|
64655
65052
|
const queryClient = useQueryClient();
|
|
64656
65053
|
const decoded = (_a2 = valueQuery.data) == null ? void 0 : _a2.decoded;
|
|
64657
|
-
const
|
|
64658
|
-
|
|
65054
|
+
const edited = useRef(null);
|
|
65055
|
+
const writing = useRef(0);
|
|
65056
|
+
const writes = useRef(Promise.resolve());
|
|
65057
|
+
useEffect(() => {
|
|
65058
|
+
if (writing.current === 0) edited.current = null;
|
|
65059
|
+
}, [decoded]);
|
|
65060
|
+
const write = useCallback((next2) => {
|
|
65061
|
+
if (workspace == null || path2 == null || type === void 0) return Promise.resolve();
|
|
64659
65062
|
const treePath = path2.split(".").filter(Boolean).map((p2) => variant("field", p2));
|
|
64660
65063
|
const data4 = encodeBeast2For(type)(next2);
|
|
64661
|
-
|
|
64662
|
-
|
|
65064
|
+
edited.current = { value: next2 };
|
|
65065
|
+
writing.current++;
|
|
65066
|
+
const run = writes.current.then(async () => {
|
|
65067
|
+
await setMutation.mutateAsync({ path: treePath, data: data4 });
|
|
65068
|
+
await queryClient.invalidateQueries({ queryKey: ["datasetStatus", apiUrl, repo, workspace, path2] });
|
|
65069
|
+
});
|
|
65070
|
+
writes.current = run.catch(() => void 0);
|
|
65071
|
+
return run.catch((err) => {
|
|
65072
|
+
edited.current = null;
|
|
65073
|
+
throw err;
|
|
65074
|
+
}).finally(() => {
|
|
65075
|
+
writing.current--;
|
|
65076
|
+
});
|
|
64663
65077
|
}, [apiUrl, repo, workspace, path2, type, setMutation, queryClient]);
|
|
64664
65078
|
const keyType = useMemo(() => type === void 0 ? null : type.type === "Dict" ? type.value.key : type.type === "Set" ? type.value : null, [type]);
|
|
64665
65079
|
const inlineKeys = useMemo(() => decoded === void 0 || type === void 0 ? null : type.type === "Dict" ? [...decoded.keys()] : type.type === "Set" ? [...decoded.values()] : null, [type, decoded]);
|
|
@@ -64695,11 +65109,12 @@ const DatasetPreview = memo(function DatasetPreview2({
|
|
|
64695
65109
|
const treeValue = useMemo(() => {
|
|
64696
65110
|
if (type === void 0 || decoded === void 0) return null;
|
|
64697
65111
|
const root2 = ValueTree.materialize(type, decoded);
|
|
65112
|
+
const base = () => edited.current !== null ? edited.current.value : decoded;
|
|
64698
65113
|
const wire = editable ? {
|
|
64699
|
-
onEdit: some((p2, leaf) => write(ValueTree.applyEdit(type,
|
|
64700
|
-
onInsert: some((p2) => write(ValueTree.applyEdit(type,
|
|
64701
|
-
onRemove: some((p2) => write(ValueTree.applyEdit(type,
|
|
64702
|
-
onTag: some((p2, tag) => write(ValueTree.applyEdit(type,
|
|
65114
|
+
onEdit: some((p2, leaf) => write(ValueTree.applyEdit(type, base(), p2, { kind: "edit", leaf }))),
|
|
65115
|
+
onInsert: some((p2) => write(ValueTree.applyEdit(type, base(), p2, { kind: "insert" }))),
|
|
65116
|
+
onRemove: some((p2) => write(ValueTree.applyEdit(type, base(), p2, { kind: "remove" }))),
|
|
65117
|
+
onTag: some((p2, tag) => write(ValueTree.applyEdit(type, base(), p2, { kind: "tag", tag })))
|
|
64703
65118
|
} : { onEdit: none$1, onInsert: none$1, onRemove: none$1, onTag: none$1 };
|
|
64704
65119
|
return { root: root2, ...wire, style: some({ height: some("100%"), maxHeight: none$1, openDepth: none$1, toolbar: some(true) }) };
|
|
64705
65120
|
}, [type, decoded, editable, write]);
|
|
@@ -64741,8 +65156,11 @@ const DatasetPreview = memo(function DatasetPreview2({
|
|
|
64741
65156
|
/* @__PURE__ */ jsx$1(DownloadButton, { onClick: download, label: "Download value" })
|
|
64742
65157
|
] });
|
|
64743
65158
|
}
|
|
65159
|
+
if (valueQuery.error) {
|
|
65160
|
+
const { message, details } = formatApiError(valueQuery.error);
|
|
65161
|
+
return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "error", title: "Load failed", message, details: details ?? formatError(valueQuery.error) });
|
|
65162
|
+
}
|
|
64744
65163
|
if (valueQuery.isLoading || !valueQuery.data) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "loading", title: "Loading..." });
|
|
64745
|
-
if (valueQuery.error) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "error", title: "Decode failed", message: valueQuery.error.message });
|
|
64746
65164
|
const count = type === void 0 || decoded === void 0 ? null : type.type === "Array" ? decoded.length : type.type === "Set" || type.type === "Dict" ? decoded.size : null;
|
|
64747
65165
|
const countText = count === null ? "" : `${count.toLocaleString()} ${(type == null ? void 0 : type.type) === "Dict" ? "entries" : "items"} · `;
|
|
64748
65166
|
return /* @__PURE__ */ jsxs(Flex, { direction: "column", height: "100%", overflow: "hidden", children: [
|
|
@@ -64813,19 +65231,15 @@ const UITaskPreview = memo(function UITaskPreview2({
|
|
|
64813
65231
|
const workspace = (config2 == null ? void 0 : config2.workspace) ?? (e3 == null ? void 0 : e3.workspace) ?? null;
|
|
64814
65232
|
const token2 = (config2 == null ? void 0 : config2.token) ?? (e3 == null ? void 0 : e3.token) ?? null;
|
|
64815
65233
|
const requestOptions = { token: token2 };
|
|
65234
|
+
const bound3 = cache3 == null ? void 0 : cache3.getConfig().workspace;
|
|
65235
|
+
const foreign = (config2 == null ? void 0 : config2.workspace) !== void 0 && bound3 !== void 0 && config2.workspace !== bound3;
|
|
64816
65236
|
const detailsQuery = useTaskDetails(apiUrl ?? "", repo, workspace, task, { requestOptions });
|
|
64817
65237
|
const details = detailsQuery.data;
|
|
64818
|
-
const
|
|
64819
|
-
const
|
|
64820
|
-
const manifest = useMemo(() => {
|
|
64821
|
-
if (!details || !isUI) return null;
|
|
64822
|
-
const meta3 = getTaskMetadata(details);
|
|
64823
|
-
return meta3 ? decodeManifest(meta3) : { paths: [], functions: [], records: [], pages: [] };
|
|
64824
|
-
}, [details, isUI]);
|
|
64825
|
-
const outputPath = details ? treePathToString$1(details.output) : null;
|
|
65238
|
+
const manifest = useMemo(() => (details == null ? void 0 : details.role.type) === "ui" ? details.role.value : null, [details]);
|
|
65239
|
+
const outputPath = details ? treePathToString$1(details.output.path) : null;
|
|
64826
65240
|
const preloads = useMemo(
|
|
64827
|
-
() => manifest && workspace ? manifest.paths.map((path2) => ({ workspace, path: path2 })) : [],
|
|
64828
|
-
[manifest, workspace]
|
|
65241
|
+
() => manifest && workspace && !foreign ? manifest.paths.map((path2) => ({ workspace, path: path2 })) : [],
|
|
65242
|
+
[manifest, workspace, foreign]
|
|
64829
65243
|
);
|
|
64830
65244
|
const { loading: preloading, error: preloadError } = usePreloadReactiveDatasets(preloads);
|
|
64831
65245
|
const scopedPlatforms = useMemo(
|
|
@@ -64851,7 +65265,7 @@ const UITaskPreview = memo(function UITaskPreview2({
|
|
|
64851
65265
|
[manifest]
|
|
64852
65266
|
);
|
|
64853
65267
|
useEffect(() => {
|
|
64854
|
-
if (!cache3 || !manifest || !workspace) return;
|
|
65268
|
+
if (!cache3 || !manifest || !workspace || foreign) return;
|
|
64855
65269
|
for (const path2 of manifest.paths) {
|
|
64856
65270
|
cache3.setRefetchInterval(workspace, path2, pollInterval);
|
|
64857
65271
|
}
|
|
@@ -64860,7 +65274,7 @@ const UITaskPreview = memo(function UITaskPreview2({
|
|
|
64860
65274
|
cache3.clearRefetchInterval(workspace, path2);
|
|
64861
65275
|
}
|
|
64862
65276
|
};
|
|
64863
|
-
}, [cache3, manifest, workspace, pollInterval]);
|
|
65277
|
+
}, [cache3, manifest, workspace, pollInterval, foreign]);
|
|
64864
65278
|
const statusQuery = useDatasetStatus(apiUrl ?? "", repo, workspace, outputPath, { requestOptions });
|
|
64865
65279
|
const valueQuery = useDatasetValue(apiUrl ?? "", repo, workspace, outputPath, {
|
|
64866
65280
|
requestOptions,
|
|
@@ -64870,16 +65284,20 @@ const UITaskPreview = memo(function UITaskPreview2({
|
|
|
64870
65284
|
});
|
|
64871
65285
|
const store = useMemo(() => createUIStore(), [task]);
|
|
64872
65286
|
if (!apiUrl) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "error", title: "Configuration error", message: "No apiUrl available — render UITaskPreview inside an <E3Provider> or pass a config prop." });
|
|
65287
|
+
if (foreign) {
|
|
65288
|
+
return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "error", title: "Workspace mismatch", message: `config names workspace "${config2 == null ? void 0 : config2.workspace}", and the data bindings read workspace "${bound3}", the one the surrounding <ReactiveDatasetProvider> serves: a page previews one workspace.` });
|
|
65289
|
+
}
|
|
64873
65290
|
if (detailsQuery.isLoading) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "loading", title: "Loading task..." });
|
|
64874
65291
|
if (detailsQuery.error) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "error", title: "Error", message: detailsQuery.error.message });
|
|
64875
65292
|
if (!details) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "info", title: "No task", message: `Task "${task}" not found` });
|
|
64876
|
-
if (!
|
|
65293
|
+
if (!manifest) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "error", title: "Not a UI task", message: `Task "${task}" is a ${details.role.type} task` });
|
|
64877
65294
|
if (preloadError) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "error", title: "Preload failed", message: preloadError.message });
|
|
64878
65295
|
if (preloading) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "loading", title: "Loading datasets..." });
|
|
65296
|
+
if (statusQuery.error) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "error", title: "Error", message: statusQuery.error.message });
|
|
64879
65297
|
if (statusQuery.isLoading || !statusQuery.data) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "loading", title: "Loading..." });
|
|
64880
65298
|
if (statusQuery.data.refType !== "value") return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "info", title: "No output yet", message: "Task has not produced a value" });
|
|
65299
|
+
if (valueQuery.error) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "error", title: "Load failed", message: valueQuery.error.message });
|
|
64881
65300
|
if (valueQuery.isLoading || !valueQuery.data) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "loading", title: "Loading..." });
|
|
64882
|
-
if (valueQuery.error) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "error", title: "Decode failed", message: valueQuery.error.message });
|
|
64883
65301
|
return /* @__PURE__ */ jsx$1(UIStoreProvider, { store, children: /* @__PURE__ */ jsx$1(ErrorBoundary, { children: /* @__PURE__ */ jsx$1(Box, { height: "100%", overflow: bare ? void 0 : "auto", p: bare ? void 0 : "4", minH: bare ? 0 : void 0, children: /* @__PURE__ */ jsx$1(
|
|
64884
65302
|
EastChakraComponent,
|
|
64885
65303
|
{
|
|
@@ -65336,7 +65754,7 @@ const DataTaskPreview = memo(function DataTaskPreview2({
|
|
|
65336
65754
|
const detailsQuery = useTaskDetails(apiUrl, repo, workspace, task, {
|
|
65337
65755
|
...requestOptions != null && { requestOptions }
|
|
65338
65756
|
});
|
|
65339
|
-
const outputPath = detailsQuery.data ? treePathToString(detailsQuery.data.output) : null;
|
|
65757
|
+
const outputPath = detailsQuery.data ? treePathToString(detailsQuery.data.output.path) : null;
|
|
65340
65758
|
return /* @__PURE__ */ jsxs(Box, { height: "100%", display: "flex", flexDirection: "column", overflow: "hidden", children: [
|
|
65341
65759
|
/* @__PURE__ */ jsx$1(
|
|
65342
65760
|
Flex,
|
|
@@ -65400,13 +65818,14 @@ const TaskPreview = memo(function TaskPreview2({
|
|
|
65400
65818
|
requestOptions,
|
|
65401
65819
|
bare = false
|
|
65402
65820
|
}) {
|
|
65821
|
+
var _a2;
|
|
65403
65822
|
const detailsQuery = useTaskDetails(apiUrl, repo, workspace, task, {
|
|
65404
65823
|
...requestOptions != null && { requestOptions }
|
|
65405
65824
|
});
|
|
65406
|
-
const
|
|
65825
|
+
const isUI = ((_a2 = detailsQuery.data) == null ? void 0 : _a2.role.type) === "ui";
|
|
65407
65826
|
return /* @__PURE__ */ jsxs(Box, { height: "100%", display: "flex", flexDirection: "column", overflow: "hidden", children: [
|
|
65408
65827
|
!bare && /* @__PURE__ */ jsx$1(Flex, { px: 4, py: 2, borderBottom: "1px solid", borderColor: "border.subtle", bg: "bg.surface", align: "center", flexShrink: 0, children: /* @__PURE__ */ jsx$1(Text, { fontSize: "sm", fontWeight: "medium", color: "fg", children: task }) }),
|
|
65409
|
-
/* @__PURE__ */ jsx$1(Box, { flex: 1, overflow: "hidden", minHeight: 0, children: detailsQuery.isLoading ? /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "loading", title: "Loading task..." }) : detailsQuery.error ? /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "error", title: "Error", message: detailsQuery.error.message }) :
|
|
65828
|
+
/* @__PURE__ */ jsx$1(Box, { flex: 1, overflow: "hidden", minHeight: 0, children: detailsQuery.isLoading ? /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "loading", title: "Loading task..." }) : detailsQuery.error ? /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "error", title: "Error", message: detailsQuery.error.message }) : isUI ? /* @__PURE__ */ jsx$1(
|
|
65410
65829
|
UITaskPreview,
|
|
65411
65830
|
{
|
|
65412
65831
|
task,
|
|
@@ -65424,7 +65843,10 @@ const TaskPreview = memo(function TaskPreview2({
|
|
|
65424
65843
|
}
|
|
65425
65844
|
) })
|
|
65426
65845
|
] });
|
|
65427
|
-
}, (prev2, next2) =>
|
|
65846
|
+
}, (prev2, next2) => {
|
|
65847
|
+
var _a2, _b2;
|
|
65848
|
+
return prev2.task === next2.task && prev2.apiUrl === next2.apiUrl && prev2.repo === next2.repo && prev2.workspace === next2.workspace && prev2.bare === next2.bare && ((_a2 = prev2.requestOptions) == null ? void 0 : _a2.token) === ((_b2 = next2.requestOptions) == null ? void 0 : _b2.token);
|
|
65849
|
+
});
|
|
65428
65850
|
function formatPrimitive(type, value) {
|
|
65429
65851
|
switch (type.type) {
|
|
65430
65852
|
case "Null":
|
|
@@ -65819,8 +66241,6 @@ export {
|
|
|
65819
66241
|
getBindingTypes,
|
|
65820
66242
|
getReactiveDatasetCache,
|
|
65821
66243
|
getStagedStore,
|
|
65822
|
-
getTaskKind,
|
|
65823
|
-
getTaskMetadata,
|
|
65824
66244
|
initializeFunctionApi,
|
|
65825
66245
|
initializePagedApi,
|
|
65826
66246
|
initializeReactiveDatasetCache,
|
|
@@ -65828,6 +66248,7 @@ export {
|
|
|
65828
66248
|
initializeStagedStore,
|
|
65829
66249
|
isBindingTracking,
|
|
65830
66250
|
onWriteError,
|
|
66251
|
+
pagedRevisionKey,
|
|
65831
66252
|
pagedTotalKey,
|
|
65832
66253
|
pagedWindowKey,
|
|
65833
66254
|
preloadReactiveDatasetList,
|