@honua/app-platform 0.1.12 → 0.1.13
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/columnar/apache-arrow.d.ts +17 -0
- package/columnar/apache-arrow.d.ts.map +1 -0
- package/columnar/apache-arrow.js +1036 -0
- package/columnar/batch-cache-conformance.d.ts +66 -0
- package/columnar/batch-cache-conformance.d.ts.map +1 -0
- package/columnar/batch-cache-conformance.js +317 -0
- package/columnar/batch-cache-indexeddb.d.ts +31 -0
- package/columnar/batch-cache-indexeddb.d.ts.map +1 -0
- package/columnar/batch-cache-indexeddb.js +148 -0
- package/columnar/batch-cache.d.ts +298 -0
- package/columnar/batch-cache.d.ts.map +1 -0
- package/columnar/batch-cache.js +757 -0
- package/columnar/geoarrow-aggregate.d.ts +178 -0
- package/columnar/geoarrow-aggregate.d.ts.map +1 -0
- package/columnar/geoarrow-aggregate.js +976 -0
- package/columnar/geoarrow-patch.d.ts +382 -0
- package/columnar/geoarrow-patch.d.ts.map +1 -0
- package/columnar/geoarrow-patch.js +1656 -0
- package/columnar/geoarrow-reproject.d.ts +22 -0
- package/columnar/geoarrow-reproject.d.ts.map +1 -0
- package/columnar/geoarrow-reproject.js +119 -0
- package/columnar/geoarrow-serialization.d.ts +68 -0
- package/columnar/geoarrow-serialization.d.ts.map +1 -0
- package/columnar/geoarrow-serialization.js +331 -0
- package/columnar/geoarrow-types.d.ts +271 -0
- package/columnar/geoarrow-types.d.ts.map +1 -0
- package/columnar/geoarrow-types.js +15 -0
- package/columnar/geoarrow.d.ts +52 -0
- package/columnar/geoarrow.d.ts.map +1 -0
- package/columnar/geoarrow.js +1469 -0
- package/columnar/index.d.ts +43 -0
- package/columnar/index.d.ts.map +1 -0
- package/columnar/index.js +29 -0
- package/columnar/operators.d.ts +70 -0
- package/columnar/operators.d.ts.map +1 -0
- package/columnar/operators.js +307 -0
- package/columnar/result.d.ts +369 -0
- package/columnar/result.d.ts.map +1 -0
- package/columnar/result.js +815 -0
- package/columnar/telemetry.d.ts +152 -0
- package/columnar/telemetry.d.ts.map +1 -0
- package/columnar/telemetry.js +265 -0
- package/columnar/transfer.d.ts +28 -0
- package/columnar/transfer.d.ts.map +1 -0
- package/columnar/transfer.js +669 -0
- package/columnar/types.d.ts +175 -0
- package/columnar/types.d.ts.map +1 -0
- package/columnar/types.js +22 -0
- package/columnar/worker.d.ts +157 -0
- package/columnar/worker.d.ts.map +1 -0
- package/columnar/worker.js +1059 -0
- package/contract/pmtiles.d.ts +6 -5
- package/contract/pmtiles.d.ts.map +1 -1
- package/contract/pmtiles.js +30 -5
- package/controls/catalog.d.ts.map +1 -1
- package/controls/catalog.js +110 -0
- package/controls/index.d.ts +1 -1
- package/controls/index.js +1 -1
- package/controls/types.d.ts +1 -1
- package/controls/types.js +1 -1
- package/core/client.d.ts.map +1 -1
- package/core/client.js +87 -19
- package/core/deprecation-notice.d.ts +28 -0
- package/core/deprecation-notice.d.ts.map +1 -0
- package/core/deprecation-notice.js +22 -0
- package/core/esri-geojson.d.ts.map +1 -1
- package/core/esri-geojson.js +10 -6
- package/core/optional-grpc-peer.d.ts +15 -0
- package/core/optional-grpc-peer.d.ts.map +1 -0
- package/core/optional-grpc-peer.js +60 -0
- package/esri-compat/basemap-gallery.d.ts +2 -0
- package/esri-compat/basemap-gallery.d.ts.map +1 -1
- package/esri-compat/basemap-gallery.js +12 -0
- package/esri-compat/basemap.d.ts +4 -0
- package/esri-compat/basemap.d.ts.map +1 -1
- package/esri-compat/basemap.js +70 -0
- package/esri-compat/bookmarks.d.ts +2 -0
- package/esri-compat/bookmarks.d.ts.map +1 -1
- package/esri-compat/bookmarks.js +12 -0
- package/esri-compat/controls.d.ts +18 -0
- package/esri-compat/controls.d.ts.map +1 -1
- package/esri-compat/controls.js +120 -57
- package/esri-compat/directions.d.ts +4 -0
- package/esri-compat/directions.d.ts.map +1 -1
- package/esri-compat/directions.js +30 -20
- package/esri-compat/editor.d.ts +4 -0
- package/esri-compat/editor.d.ts.map +1 -1
- package/esri-compat/editor.js +16 -0
- package/esri-compat/esri-config.d.ts +2 -1
- package/esri-compat/esri-config.d.ts.map +1 -1
- package/esri-compat/feature-effect.d.ts +23 -0
- package/esri-compat/feature-effect.d.ts.map +1 -0
- package/esri-compat/feature-effect.js +12 -0
- package/esri-compat/feature-form.d.ts +6 -0
- package/esri-compat/feature-form.d.ts.map +1 -1
- package/esri-compat/feature-form.js +63 -0
- package/esri-compat/feature-layer.d.ts +21 -2
- package/esri-compat/feature-layer.d.ts.map +1 -1
- package/esri-compat/feature-layer.js +172 -1
- package/esri-compat/feature-table.d.ts +5 -0
- package/esri-compat/feature-table.d.ts.map +1 -1
- package/esri-compat/feature-table.js +23 -0
- package/esri-compat/identity-manager.d.ts +1 -1
- package/esri-compat/identity-manager.js +1 -1
- package/esri-compat/legend.d.ts +2 -0
- package/esri-compat/legend.d.ts.map +1 -1
- package/esri-compat/legend.js +98 -0
- package/esri-compat/locator.d.ts +1 -1
- package/esri-compat/locator.js +1 -1
- package/esri-compat/map-view-mount.d.ts +1 -0
- package/esri-compat/map-view-mount.d.ts.map +1 -1
- package/esri-compat/map-view-mount.js +46 -25
- package/esri-compat/map-view.d.ts +13 -0
- package/esri-compat/map-view.d.ts.map +1 -1
- package/esri-compat/map-view.js +94 -8
- package/esri-compat/map.d.ts +5 -1
- package/esri-compat/map.d.ts.map +1 -1
- package/esri-compat/map.js +10 -0
- package/esri-compat/measurement.d.ts +2 -0
- package/esri-compat/measurement.d.ts.map +1 -1
- package/esri-compat/measurement.js +14 -0
- package/esri-compat/point.d.ts +7 -0
- package/esri-compat/point.d.ts.map +1 -1
- package/esri-compat/point.js +33 -3
- package/esri-compat/popup.d.ts +2 -0
- package/esri-compat/popup.d.ts.map +1 -1
- package/esri-compat/popup.js +12 -0
- package/esri-compat/portal.d.ts +1 -1
- package/esri-compat/portal.js +1 -1
- package/esri-compat/print.d.ts +3 -0
- package/esri-compat/print.d.ts.map +1 -1
- package/esri-compat/print.js +15 -0
- package/esri-compat/search.d.ts +4 -0
- package/esri-compat/search.d.ts.map +1 -1
- package/esri-compat/search.js +25 -28
- package/esri-compat/sketch.d.ts +2 -0
- package/esri-compat/sketch.d.ts.map +1 -1
- package/esri-compat/sketch.js +12 -0
- package/esri-compat/widget-host.d.ts +46 -17
- package/esri-compat/widget-host.d.ts.map +1 -1
- package/esri-compat/widget-host.js +84 -20
- package/esri-compat/widget-shell-hosts.d.ts +61 -0
- package/esri-compat/widget-shell-hosts.d.ts.map +1 -0
- package/esri-compat/widget-shell-hosts.js +76 -0
- package/kernel/renderer.d.ts +82 -0
- package/kernel/renderer.js +1 -0
- package/offline/conflict-resolution.d.ts +183 -0
- package/offline/conflict-resolution.d.ts.map +1 -0
- package/offline/conflict-resolution.js +286 -0
- package/offline/credential-screen.d.ts +34 -0
- package/offline/credential-screen.d.ts.map +1 -0
- package/offline/credential-screen.js +78 -0
- package/offline/digest.d.ts +15 -0
- package/offline/digest.d.ts.map +1 -0
- package/offline/digest.js +58 -0
- package/offline/edit-queue.d.ts +403 -0
- package/offline/edit-queue.d.ts.map +1 -0
- package/offline/edit-queue.js +1807 -0
- package/offline/edit-replay.d.ts +116 -0
- package/offline/edit-replay.d.ts.map +1 -0
- package/offline/edit-replay.js +392 -0
- package/offline/fetch-handler.d.ts +12 -0
- package/offline/fetch-handler.d.ts.map +1 -0
- package/offline/fetch-handler.js +65 -0
- package/offline/index.d.ts +52 -0
- package/offline/index.d.ts.map +1 -0
- package/offline/index.js +34 -0
- package/offline/indexeddb.d.ts +135 -0
- package/offline/indexeddb.d.ts.map +1 -0
- package/offline/indexeddb.js +888 -0
- package/offline/memory-store.d.ts +17 -0
- package/offline/memory-store.d.ts.map +1 -0
- package/offline/memory-store.js +183 -0
- package/offline/quota.d.ts +161 -0
- package/offline/quota.d.ts.map +1 -0
- package/offline/quota.js +370 -0
- package/offline/read-gate.d.ts +175 -0
- package/offline/read-gate.d.ts.map +1 -0
- package/offline/read-gate.js +252 -0
- package/offline/read-resource.d.ts +99 -0
- package/offline/read-resource.d.ts.map +1 -0
- package/offline/read-resource.js +156 -0
- package/offline/read.d.ts +50 -0
- package/offline/read.d.ts.map +1 -0
- package/offline/read.js +65 -0
- package/offline/region.d.ts +29 -0
- package/offline/region.d.ts.map +1 -0
- package/offline/region.js +1007 -0
- package/offline/replay-conflict.d.ts +183 -0
- package/offline/replay-conflict.d.ts.map +1 -0
- package/offline/replay-conflict.js +482 -0
- package/offline/selection.d.ts +140 -0
- package/offline/selection.d.ts.map +1 -0
- package/offline/selection.js +391 -0
- package/offline/snapshot.d.ts +132 -0
- package/offline/snapshot.d.ts.map +1 -0
- package/offline/snapshot.js +312 -0
- package/offline/status.d.ts +136 -0
- package/offline/status.d.ts.map +1 -0
- package/offline/status.js +479 -0
- package/offline/store-conformance.d.ts +48 -0
- package/offline/store-conformance.d.ts.map +1 -0
- package/offline/store-conformance.js +233 -0
- package/offline/tile-protocol.d.ts +81 -0
- package/offline/tile-protocol.d.ts.map +1 -0
- package/offline/tile-protocol.js +119 -0
- package/offline/types.d.ts +349 -0
- package/offline/types.d.ts.map +1 -0
- package/offline/types.js +75 -0
- package/package.json +14 -2
- package/scene-workspace/index.d.ts +2 -2
- package/scene-workspace/index.d.ts.map +1 -1
- package/scene-workspace/index.js +1 -1
- package/scene-workspace/scene-discovery.d.ts +111 -91
- package/scene-workspace/scene-discovery.d.ts.map +1 -1
- package/scene-workspace/scene-discovery.js +340 -92
- package/scene-workspace/scene-view.d.ts +6 -6
- package/scene-workspace/scene-view.d.ts.map +1 -1
- package/scene-workspace/scene-view.js +32 -6
- package/web-components/elements.d.ts +34 -0
- package/web-components/elements.d.ts.map +1 -1
- package/web-components/elements.js +82 -8
- package/web-components/index.d.ts +2 -0
- package/web-components/index.d.ts.map +1 -1
- package/web-components/index.js +3 -1
- package/web-components/map-chrome.d.ts +103 -0
- package/web-components/map-chrome.d.ts.map +1 -0
- package/web-components/map-chrome.js +325 -0
- package/web-components/widget-shell.d.ts +68 -0
- package/web-components/widget-shell.d.ts.map +1 -0
- package/web-components/widget-shell.js +224 -0
- package/widget-capabilities.d.ts +67 -0
- package/widget-capabilities.js +152 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../../src/offline/snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { normalizeDiscoveryEndpoint } from "../contract/discovery.js";
|
|
2
|
+
import { canonicalJson, compareCodeUnits, sha256 } from "./digest.js";
|
|
3
|
+
import { createOfflineRegionManifest } from "./region.js";
|
|
4
|
+
import { canonicalizeOfflineRegionQuery, offlineRegionAuthorizationScopeDigest, offlineRegionQueryFingerprint, offlineRegionResourceId, } from "./selection.js";
|
|
5
|
+
import { HonuaOfflineRegionError, } from "./types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Snapshot planning: turn a protocol-neutral selection into a downloadable region.
|
|
8
|
+
*
|
|
9
|
+
* The planner is the missing producer between the contract and the region store.
|
|
10
|
+
* It takes a source identity, a canonical {@link Query}, a bounded extent, and the
|
|
11
|
+
* payloads an application already holds, and emits a manifest whose resource
|
|
12
|
+
* identities are deterministic functions of those inputs — never of a signed or
|
|
13
|
+
* token-bearing request URL. The same identity function answers the later read,
|
|
14
|
+
* so a snapshot and a read agree without persisting any addressing state.
|
|
15
|
+
*
|
|
16
|
+
* @experimental
|
|
17
|
+
*/
|
|
18
|
+
export const HONUA_OFFLINE_REGION_SNAPSHOT_KIND = "honua.offline-region-snapshot";
|
|
19
|
+
export const HONUA_OFFLINE_REGION_SNAPSHOT_VERSION = "1.0";
|
|
20
|
+
export const HONUA_OFFLINE_FEATURE_BATCH_KIND = "honua.offline-feature-batch";
|
|
21
|
+
export const HONUA_OFFLINE_FEATURE_BATCH_VERSION = "1.0";
|
|
22
|
+
/** Default ceiling on how many resources one planned snapshot may contain. */
|
|
23
|
+
export const DEFAULT_OFFLINE_REGION_SNAPSHOT_MAX_CONTENTS = 10_000;
|
|
24
|
+
const encoder = new TextEncoder();
|
|
25
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
26
|
+
/**
|
|
27
|
+
* Plan one bounded snapshot of a source, a query, and an extent.
|
|
28
|
+
*
|
|
29
|
+
* Every resource identity is derived from the selection — source identity,
|
|
30
|
+
* authorization-scope digest, captured versions, extent, canonical query, and the
|
|
31
|
+
* resource's own kind and selector. Identities are therefore stable across runs
|
|
32
|
+
* and processes, contain no request URL, and cannot collide across authorization
|
|
33
|
+
* scopes.
|
|
34
|
+
*/
|
|
35
|
+
export async function planOfflineRegionSnapshot(selection) {
|
|
36
|
+
const record = plainRecord(selection, "selection");
|
|
37
|
+
const authorizationScopeDigest = await offlineRegionAuthorizationScopeDigest(record.authorizationScopeFingerprint);
|
|
38
|
+
// Pagination is accepted but never enters identity: a window is a property of
|
|
39
|
+
// the captured batch, not of the question. `createOfflineRegionFeatureBatch()`
|
|
40
|
+
// records the window that was actually captured, and the read path answers
|
|
41
|
+
// pagination from that record instead of from a second identity.
|
|
42
|
+
const scope = canonicalizeOfflineRegionQuery(selection.query, selection.sourceId);
|
|
43
|
+
const queryFingerprint = await offlineRegionQueryFingerprint(scope.canonical);
|
|
44
|
+
// Identity binds the *normalized* endpoint, so a caller passing a signed or
|
|
45
|
+
// unnormalized URL can never produce a different identity than the manifest.
|
|
46
|
+
const boundIdentity = {
|
|
47
|
+
sourceId: selection.sourceId,
|
|
48
|
+
endpoint: normalizeSelectionEndpoint(selection.endpoint),
|
|
49
|
+
authorizationScopeDigest,
|
|
50
|
+
sourceVersion: selection.sourceVersion,
|
|
51
|
+
schemaVersion: selection.schemaVersion,
|
|
52
|
+
planVersion: selection.planVersion,
|
|
53
|
+
bounds: selection.bounds,
|
|
54
|
+
...(selection.minZoom !== undefined ? { minZoom: selection.minZoom } : {}),
|
|
55
|
+
...(selection.maxZoom !== undefined ? { maxZoom: selection.maxZoom } : {}),
|
|
56
|
+
};
|
|
57
|
+
const maxContents = selection.limits?.maxContents ?? DEFAULT_OFFLINE_REGION_SNAPSHOT_MAX_CONTENTS;
|
|
58
|
+
const contents = selection.contents;
|
|
59
|
+
if (!Array.isArray(contents))
|
|
60
|
+
throw invalid("selection.contents must be an array.", "selection.contents");
|
|
61
|
+
if (contents.length > maxContents) {
|
|
62
|
+
throw new HonuaOfflineRegionError("resource-limit-exceeded", `selection.contents contains ${contents.length} entries; maximum is ${maxContents}.`, { path: "selection.contents" });
|
|
63
|
+
}
|
|
64
|
+
const payloads = new Map();
|
|
65
|
+
const entries = [];
|
|
66
|
+
const resources = [];
|
|
67
|
+
for (let index = 0; index < contents.length; index += 1) {
|
|
68
|
+
const content = contents[index];
|
|
69
|
+
const path = `selection.contents[${index}]`;
|
|
70
|
+
const bytes = ownedBytes(content?.bytes, path);
|
|
71
|
+
const id = await offlineRegionResourceId({
|
|
72
|
+
kind: requireKind(content?.kind, path),
|
|
73
|
+
selection: boundIdentity,
|
|
74
|
+
queryFingerprint,
|
|
75
|
+
...(content.selector !== undefined ? { selector: content.selector } : {}),
|
|
76
|
+
});
|
|
77
|
+
if (payloads.has(id)) {
|
|
78
|
+
throw invalid(`${path} repeats a resource identity already planned in this snapshot.`, path);
|
|
79
|
+
}
|
|
80
|
+
const integrity = await sha256(bytes);
|
|
81
|
+
payloads.set(id, bytes);
|
|
82
|
+
entries.push({
|
|
83
|
+
id,
|
|
84
|
+
kind: content.kind,
|
|
85
|
+
byteLength: bytes.byteLength,
|
|
86
|
+
integrity,
|
|
87
|
+
...(content.contentType ? { contentType: content.contentType } : {}),
|
|
88
|
+
});
|
|
89
|
+
resources.push({
|
|
90
|
+
id,
|
|
91
|
+
kind: content.kind,
|
|
92
|
+
byteLength: bytes.byteLength,
|
|
93
|
+
integrity,
|
|
94
|
+
...(content.contentType ? { contentType: content.contentType } : {}),
|
|
95
|
+
sourceVersion: selection.sourceVersion,
|
|
96
|
+
schemaVersion: selection.schemaVersion,
|
|
97
|
+
planVersion: selection.planVersion,
|
|
98
|
+
...(content.attributionIds ? { attributionIds: content.attributionIds } : {}),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
entries.sort((left, right) => compareCodeUnits(left.id, right.id));
|
|
102
|
+
const manifestInput = {
|
|
103
|
+
name: selection.name,
|
|
104
|
+
sourceId: selection.sourceId,
|
|
105
|
+
endpoint: selection.endpoint,
|
|
106
|
+
authorizationScopeFingerprint: selection.authorizationScopeFingerprint,
|
|
107
|
+
bounds: selection.bounds,
|
|
108
|
+
...(selection.minZoom !== undefined ? { minZoom: selection.minZoom } : {}),
|
|
109
|
+
...(selection.maxZoom !== undefined ? { maxZoom: selection.maxZoom } : {}),
|
|
110
|
+
sourceVersion: selection.sourceVersion,
|
|
111
|
+
schemaVersion: selection.schemaVersion,
|
|
112
|
+
planVersion: selection.planVersion,
|
|
113
|
+
observation: selection.observation,
|
|
114
|
+
...(selection.validator ? { validator: selection.validator } : {}),
|
|
115
|
+
...(selection.expiresAt ? { expiresAt: selection.expiresAt } : {}),
|
|
116
|
+
...(selection.attribution ? { attribution: selection.attribution } : {}),
|
|
117
|
+
resources,
|
|
118
|
+
...(selection.limits ? { limits: selection.limits } : {}),
|
|
119
|
+
};
|
|
120
|
+
const manifest = await createOfflineRegionManifest(manifestInput);
|
|
121
|
+
if (manifest.source.authorizationScopeDigest !== authorizationScopeDigest) {
|
|
122
|
+
throw invalid("Snapshot scope digest does not match the manifest it produced.", "authorizationScopeFingerprint");
|
|
123
|
+
}
|
|
124
|
+
return Object.freeze({
|
|
125
|
+
kind: HONUA_OFFLINE_REGION_SNAPSHOT_KIND,
|
|
126
|
+
version: HONUA_OFFLINE_REGION_SNAPSHOT_VERSION,
|
|
127
|
+
manifest,
|
|
128
|
+
selection: Object.freeze(boundIdentity),
|
|
129
|
+
query: scope.canonical,
|
|
130
|
+
queryFingerprint,
|
|
131
|
+
entries: Object.freeze(entries),
|
|
132
|
+
payloads,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Serve a planned snapshot's payloads to {@link downloadOfflineRegion}.
|
|
137
|
+
*
|
|
138
|
+
* The loader is offline by construction: it hands back the exact bytes the
|
|
139
|
+
* identities were computed from and refuses anything the plan does not name.
|
|
140
|
+
*/
|
|
141
|
+
export function createOfflineRegionSnapshotLoader(snapshot) {
|
|
142
|
+
const payloads = snapshot.payloads;
|
|
143
|
+
return async (resource) => {
|
|
144
|
+
const bytes = payloads.get(resource.id);
|
|
145
|
+
if (!bytes) {
|
|
146
|
+
throw new HonuaOfflineRegionError("resource-load-failed", `Planned snapshot does not carry a payload for resource "${resource.id}".`, { resourceId: resource.id });
|
|
147
|
+
}
|
|
148
|
+
return Uint8Array.from(bytes);
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/** Capture a `Result` as the durable batch envelope a later read answers from. */
|
|
152
|
+
export function createOfflineRegionFeatureBatch(result, options = {}) {
|
|
153
|
+
const features = result?.features;
|
|
154
|
+
if (!Array.isArray(features))
|
|
155
|
+
throw invalid("result.features must be an array.", "result.features");
|
|
156
|
+
const offset = options.pagination?.offset ?? 0;
|
|
157
|
+
if (!Number.isSafeInteger(offset) || offset < 0)
|
|
158
|
+
throw invalid("pagination.offset must be a non-negative safe integer.", "pagination.offset");
|
|
159
|
+
const limit = options.pagination?.limit;
|
|
160
|
+
if (limit !== undefined && (!Number.isSafeInteger(limit) || limit < 0)) {
|
|
161
|
+
throw invalid("pagination.limit must be a non-negative safe integer.", "pagination.limit");
|
|
162
|
+
}
|
|
163
|
+
if (limit !== undefined && features.length > limit) {
|
|
164
|
+
throw invalid("result.features exceeds the captured pagination limit.", "result.features");
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
kind: HONUA_OFFLINE_FEATURE_BATCH_KIND,
|
|
168
|
+
version: HONUA_OFFLINE_FEATURE_BATCH_VERSION,
|
|
169
|
+
pagination: { offset, ...(limit === undefined ? {} : { limit }) },
|
|
170
|
+
exceededTransferLimit: result.exceededTransferLimit === true,
|
|
171
|
+
features: features.map((feature, index) => canonicalFeature(feature, `result.features[${index}]`)),
|
|
172
|
+
...(result.totalCount === undefined ? {} : { totalCount: requireCount(result.totalCount) }),
|
|
173
|
+
...(result.fields === undefined ? {} : { fields: jsonClone(result.fields, "result.fields") }),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/** Encode a batch as the deterministic UTF-8 bytes the manifest pins. */
|
|
177
|
+
export function encodeOfflineRegionFeatureBatch(batch) {
|
|
178
|
+
return encoder.encode(canonicalJson(batch));
|
|
179
|
+
}
|
|
180
|
+
/** Decode and validate stored batch bytes. Anything unexpected fails closed. */
|
|
181
|
+
export function decodeOfflineRegionFeatureBatch(bytes) {
|
|
182
|
+
let parsed;
|
|
183
|
+
try {
|
|
184
|
+
parsed = JSON.parse(decoder.decode(bytes));
|
|
185
|
+
}
|
|
186
|
+
catch (cause) {
|
|
187
|
+
throw new HonuaOfflineRegionError("integrity-mismatch", "Stored offline feature batch is not valid UTF-8 JSON.", {
|
|
188
|
+
cause,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const record = plainRecord(parsed, "batch");
|
|
192
|
+
if (record.kind !== HONUA_OFFLINE_FEATURE_BATCH_KIND || record.version !== HONUA_OFFLINE_FEATURE_BATCH_VERSION) {
|
|
193
|
+
throw invalid("Stored offline feature batch has an unsupported kind or version.", "batch");
|
|
194
|
+
}
|
|
195
|
+
const pagination = plainRecord(record.pagination, "batch.pagination");
|
|
196
|
+
const offset = pagination.offset;
|
|
197
|
+
if (typeof offset !== "number" || !Number.isSafeInteger(offset) || offset < 0) {
|
|
198
|
+
throw invalid("batch.pagination.offset must be a non-negative safe integer.", "batch.pagination.offset");
|
|
199
|
+
}
|
|
200
|
+
const limit = pagination.limit;
|
|
201
|
+
if (limit !== undefined && (typeof limit !== "number" || !Number.isSafeInteger(limit) || limit < 0)) {
|
|
202
|
+
throw invalid("batch.pagination.limit must be a non-negative safe integer.", "batch.pagination.limit");
|
|
203
|
+
}
|
|
204
|
+
if (typeof record.exceededTransferLimit !== "boolean") {
|
|
205
|
+
throw invalid("batch.exceededTransferLimit must be a boolean.", "batch.exceededTransferLimit");
|
|
206
|
+
}
|
|
207
|
+
if (!Array.isArray(record.features))
|
|
208
|
+
throw invalid("batch.features must be an array.", "batch.features");
|
|
209
|
+
const features = record.features.map((feature, index) => canonicalFeature(feature, `batch.features[${index}]`));
|
|
210
|
+
if (limit !== undefined && features.length > limit) {
|
|
211
|
+
throw invalid("batch.features exceeds its recorded pagination limit.", "batch.features");
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
kind: HONUA_OFFLINE_FEATURE_BATCH_KIND,
|
|
215
|
+
version: HONUA_OFFLINE_FEATURE_BATCH_VERSION,
|
|
216
|
+
pagination: { offset, ...(limit === undefined ? {} : { limit: limit }) },
|
|
217
|
+
exceededTransferLimit: record.exceededTransferLimit,
|
|
218
|
+
features,
|
|
219
|
+
...(record.totalCount === undefined ? {} : { totalCount: requireCount(record.totalCount) }),
|
|
220
|
+
...(record.fields === undefined ? {} : { fields: jsonClone(record.fields, "batch.fields") }),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/** Reuse the one endpoint normalizer the manifest itself persists through. */
|
|
224
|
+
function normalizeSelectionEndpoint(endpoint) {
|
|
225
|
+
if (typeof endpoint !== "string" && !(endpoint instanceof URL)) {
|
|
226
|
+
throw invalid("selection.endpoint must be a string or URL.", "selection.endpoint");
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
return normalizeDiscoveryEndpoint(endpoint);
|
|
230
|
+
}
|
|
231
|
+
catch (cause) {
|
|
232
|
+
throw new HonuaOfflineRegionError("invalid-manifest", "selection.endpoint must be a valid absolute URL.", {
|
|
233
|
+
cause,
|
|
234
|
+
path: "selection.endpoint",
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function canonicalFeature(value, path) {
|
|
239
|
+
const record = plainRecord(value, path);
|
|
240
|
+
for (const key in record) {
|
|
241
|
+
if (Object.hasOwn(record, key) && key !== "attributes" && key !== "geometry") {
|
|
242
|
+
throw invalid(`${path}.${key} is not supported on a stored feature.`, `${path}.${key}`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const attributes = jsonClone(plainRecord(record.attributes, `${path}.attributes`), `${path}.attributes`);
|
|
246
|
+
const geometry = record.geometry;
|
|
247
|
+
return {
|
|
248
|
+
attributes: attributes,
|
|
249
|
+
...(geometry === undefined
|
|
250
|
+
? {}
|
|
251
|
+
: { geometry: geometry === null ? null : jsonClone(geometry, `${path}.geometry`) }),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function requireCount(value) {
|
|
255
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
256
|
+
throw invalid("totalCount must be a non-negative safe integer.", "totalCount");
|
|
257
|
+
}
|
|
258
|
+
return value;
|
|
259
|
+
}
|
|
260
|
+
function ownedBytes(value, path) {
|
|
261
|
+
if (value instanceof Uint8Array)
|
|
262
|
+
return Uint8Array.from(value);
|
|
263
|
+
if (value instanceof ArrayBuffer)
|
|
264
|
+
return new Uint8Array(value.slice(0));
|
|
265
|
+
throw invalid(`${path}.bytes must be a Uint8Array or ArrayBuffer.`, `${path}.bytes`);
|
|
266
|
+
}
|
|
267
|
+
function requireKind(value, path) {
|
|
268
|
+
if (value !== "metadata" &&
|
|
269
|
+
value !== "features" &&
|
|
270
|
+
value !== "tile" &&
|
|
271
|
+
value !== "asset" &&
|
|
272
|
+
value !== "attribution") {
|
|
273
|
+
throw invalid(`${path}.kind is invalid.`, `${path}.kind`);
|
|
274
|
+
}
|
|
275
|
+
return value;
|
|
276
|
+
}
|
|
277
|
+
function jsonClone(value, path, depth = 0) {
|
|
278
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
279
|
+
return value;
|
|
280
|
+
if (typeof value === "number") {
|
|
281
|
+
if (!Number.isFinite(value))
|
|
282
|
+
throw invalid(`${path} must be finite.`, path);
|
|
283
|
+
return Object.is(value, -0) ? 0 : value;
|
|
284
|
+
}
|
|
285
|
+
if (depth >= 32)
|
|
286
|
+
throw invalid(`${path} exceeds the stored nesting limit.`, path);
|
|
287
|
+
if (Array.isArray(value))
|
|
288
|
+
return value.map((entry, index) => jsonClone(entry, `${path}[${index}]`, depth + 1));
|
|
289
|
+
const record = plainRecord(value, path);
|
|
290
|
+
const out = {};
|
|
291
|
+
for (const key in record) {
|
|
292
|
+
if (!Object.hasOwn(record, key))
|
|
293
|
+
continue;
|
|
294
|
+
const child = record[key];
|
|
295
|
+
if (child === undefined)
|
|
296
|
+
continue;
|
|
297
|
+
out[key] = jsonClone(child, `${path}.${key}`, depth + 1);
|
|
298
|
+
}
|
|
299
|
+
return out;
|
|
300
|
+
}
|
|
301
|
+
function plainRecord(value, path) {
|
|
302
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
303
|
+
throw invalid(`${path} must be a plain object.`, path);
|
|
304
|
+
}
|
|
305
|
+
const prototype = Object.getPrototypeOf(value);
|
|
306
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
307
|
+
throw invalid(`${path} must be a plain object.`, path);
|
|
308
|
+
return value;
|
|
309
|
+
}
|
|
310
|
+
function invalid(message, path) {
|
|
311
|
+
return new HonuaOfflineRegionError("invalid-manifest", message, { path });
|
|
312
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { OfflineEditQueueStateCounts, OfflineQueuedEdit } from "./edit-queue.js";
|
|
2
|
+
import { type OfflineReplaySyncConflictBinding, type OfflineReplaySyncConflictProjectionV1 } from "./replay-conflict.js";
|
|
3
|
+
import { type OfflineRegionDiagnosticV1 } from "./types.js";
|
|
4
|
+
/** Stable discriminator and version for composed local-first status snapshots. */
|
|
5
|
+
export declare const HONUA_LOCAL_FIRST_STATUS_KIND: "honua.local-first-status";
|
|
6
|
+
export declare const HONUA_LOCAL_FIRST_STATUS_VERSION: "1.0";
|
|
7
|
+
/** Conservative ceilings applied before any input array is copied or sorted. */
|
|
8
|
+
export declare const DEFAULT_LOCAL_FIRST_MAX_REGIONS = 1000;
|
|
9
|
+
export declare const DEFAULT_LOCAL_FIRST_MAX_EDITS = 10000;
|
|
10
|
+
export declare const DEFAULT_LOCAL_FIRST_MAX_LISTED_EDIT_IDS = 100;
|
|
11
|
+
/**
|
|
12
|
+
* Reachability of the data endpoint, decided by the host. The SDK never reads
|
|
13
|
+
* `navigator.onLine`: link state is not origin reachability, so an `online`
|
|
14
|
+
* state the SDK cannot verify would be a claim rather than an observation.
|
|
15
|
+
*/
|
|
16
|
+
export type LocalFirstConnectivity = "online" | "offline";
|
|
17
|
+
/** The seven states an application renders for a local-first workflow. */
|
|
18
|
+
export type LocalFirstState = "online" | "offline" | "stale" | "partial" | "pending" | "conflicted" | "expired";
|
|
19
|
+
/** Stable machine explanation of the headline state. */
|
|
20
|
+
export type LocalFirstStateReason = "conflicted-edits" | "expired-regions" | "missing-regions" | "partial-regions" | "undelivered-edits" | "stale-regions" | "disconnected" | "connected";
|
|
21
|
+
export type LocalFirstReadAvailability = "live" | "cached" | "unavailable";
|
|
22
|
+
export type LocalFirstFreshness = "fresh" | "stale" | "expired";
|
|
23
|
+
export type LocalFirstCompleteness = "complete" | "partial" | "missing";
|
|
24
|
+
export type LocalFirstWriteState = "idle" | "pending" | "conflicted";
|
|
25
|
+
export type LocalFirstWriteCoverage = "complete" | "sampled";
|
|
26
|
+
type DiagnosticCacheReason = OfflineRegionDiagnosticV1["cache"]["reason"];
|
|
27
|
+
/** Secret-safe projection of one region diagnostic. */
|
|
28
|
+
export interface LocalFirstRegionSummary {
|
|
29
|
+
readonly regionId: string;
|
|
30
|
+
readonly sourceId: string;
|
|
31
|
+
/** Safe to expose; the originating scope fingerprint is never persisted or returned. */
|
|
32
|
+
readonly authorizationScopeDigest: `sha256:${string}`;
|
|
33
|
+
readonly state: "offline" | "missing";
|
|
34
|
+
readonly freshness: LocalFirstFreshness;
|
|
35
|
+
readonly completeness: LocalFirstCompleteness;
|
|
36
|
+
readonly reason: DiagnosticCacheReason;
|
|
37
|
+
readonly readable: boolean;
|
|
38
|
+
readonly observedAt: string;
|
|
39
|
+
readonly ageMs: number;
|
|
40
|
+
readonly expiresAt?: string;
|
|
41
|
+
readonly pinned: boolean;
|
|
42
|
+
}
|
|
43
|
+
export interface LocalFirstReads {
|
|
44
|
+
readonly availability: LocalFirstReadAvailability;
|
|
45
|
+
/** Worst-case across stored regions; `fresh` when nothing is stored. */
|
|
46
|
+
readonly freshness: LocalFirstFreshness;
|
|
47
|
+
/** Worst-case across every supplied region; `missing` when none were supplied. */
|
|
48
|
+
readonly completeness: LocalFirstCompleteness;
|
|
49
|
+
readonly regionCount: number;
|
|
50
|
+
readonly storedRegionCount: number;
|
|
51
|
+
readonly readableRegionCount: number;
|
|
52
|
+
readonly oldestObservedAt?: string;
|
|
53
|
+
readonly earliestExpiresAt?: string;
|
|
54
|
+
readonly regions: readonly LocalFirstRegionSummary[];
|
|
55
|
+
}
|
|
56
|
+
export interface LocalFirstWrites {
|
|
57
|
+
readonly state: LocalFirstWriteState;
|
|
58
|
+
/**
|
|
59
|
+
* `complete` when authoritative queue totals were supplied; `sampled` when
|
|
60
|
+
* the counts were derived from a bounded `edits` list, which `list` caps at
|
|
61
|
+
* 100 records without a cursor.
|
|
62
|
+
*/
|
|
63
|
+
readonly coverage: LocalFirstWriteCoverage;
|
|
64
|
+
readonly counts: OfflineEditQueueStateCounts;
|
|
65
|
+
/** `pending`, `leased`, and `retryable` work: local, durable, unacknowledged. */
|
|
66
|
+
readonly undeliveredCount: number;
|
|
67
|
+
readonly conflictedCount: number;
|
|
68
|
+
/** Bounded, code-unit ordered; `conflictedCount` remains the complete total. */
|
|
69
|
+
readonly conflictedEditIds: readonly `sha256:${string}`[];
|
|
70
|
+
readonly conflictedEditIdsTruncated: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* The same conflicted edits, projected onto the shipped sync-conflict
|
|
73
|
+
* contracts — one entry per `conflictedEditIds` id, in the same order. Empty
|
|
74
|
+
* unless `options.replica` supplied a replica binding, because a conflict
|
|
75
|
+
* cannot be attributed to a replica the SDK never saw. An entry may be a
|
|
76
|
+
* typed refusal; `conflictedEditIdsTruncated` still governs completeness.
|
|
77
|
+
*/
|
|
78
|
+
readonly syncConflicts: readonly OfflineReplaySyncConflictProjectionV1[];
|
|
79
|
+
readonly nextRetryAt?: string;
|
|
80
|
+
readonly oldestUndeliveredAt?: string;
|
|
81
|
+
}
|
|
82
|
+
/** Versioned, immutable, payload-free explanation of one local-first workflow. */
|
|
83
|
+
export interface LocalFirstStatusV1 {
|
|
84
|
+
readonly kind: typeof HONUA_LOCAL_FIRST_STATUS_KIND;
|
|
85
|
+
readonly version: typeof HONUA_LOCAL_FIRST_STATUS_VERSION;
|
|
86
|
+
readonly generatedAt: string;
|
|
87
|
+
readonly state: LocalFirstState;
|
|
88
|
+
readonly reason: LocalFirstStateReason;
|
|
89
|
+
readonly connectivity: LocalFirstConnectivity;
|
|
90
|
+
readonly reads: LocalFirstReads;
|
|
91
|
+
readonly writes: LocalFirstWrites;
|
|
92
|
+
}
|
|
93
|
+
/** Caller limits can tighten, but never raise, the SDK's conservative ceilings. */
|
|
94
|
+
export interface LocalFirstStatusLimits {
|
|
95
|
+
readonly maxRegions?: number;
|
|
96
|
+
readonly maxEdits?: number;
|
|
97
|
+
readonly maxListedEditIds?: number;
|
|
98
|
+
}
|
|
99
|
+
export interface CreateLocalFirstStatusOptions {
|
|
100
|
+
/** Host-owned reachability decision; the SDK never infers it. */
|
|
101
|
+
readonly connectivity: LocalFirstConnectivity;
|
|
102
|
+
/** Explicit clock input so a persisted status stays reproducible. */
|
|
103
|
+
readonly now: Date;
|
|
104
|
+
readonly regions?: readonly OfflineRegionDiagnosticV1[];
|
|
105
|
+
/**
|
|
106
|
+
* Bounded detail sample used for conflicted identities and timing. `list`
|
|
107
|
+
* caps at 100 records with no cursor, so supply `editCounts` whenever a
|
|
108
|
+
* partition can hold more work than the sample can show.
|
|
109
|
+
*/
|
|
110
|
+
readonly edits?: readonly OfflineQueuedEdit[];
|
|
111
|
+
/** Authoritative partition totals from `OfflineEditQueue.countByState`. */
|
|
112
|
+
readonly editCounts?: OfflineEditQueueStateCounts;
|
|
113
|
+
/**
|
|
114
|
+
* Replica identity used to project conflicted edits onto the shipped
|
|
115
|
+
* sync-conflict contracts. Omit it and `writes.syncConflicts` stays empty;
|
|
116
|
+
* nothing else about the status changes either way.
|
|
117
|
+
*/
|
|
118
|
+
readonly replica?: OfflineReplaySyncConflictBinding;
|
|
119
|
+
readonly limits?: LocalFirstStatusLimits;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Compose one local-first status from region diagnostics, durable queue state,
|
|
123
|
+
* and a host-supplied connectivity signal.
|
|
124
|
+
*
|
|
125
|
+
* The headline `state` is decided by a total precedence over cache and queue
|
|
126
|
+
* facets, with connectivity supplying only the base case:
|
|
127
|
+
*
|
|
128
|
+
* `conflicted` > `expired` > `partial` > `pending` > `stale` > `offline` > `online`
|
|
129
|
+
*
|
|
130
|
+
* Data problems therefore outrank undelivered work, which outranks mere
|
|
131
|
+
* staleness, which outranks being disconnected. Reads no payload bytes,
|
|
132
|
+
* performs no network or storage I/O, and mutates nothing.
|
|
133
|
+
*/
|
|
134
|
+
export declare function createLocalFirstStatus(options: CreateLocalFirstStatusOptions): LocalFirstStatusV1;
|
|
135
|
+
export {};
|
|
136
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/offline/status.ts"],"names":[],"mappings":"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"}
|