@hops-ops/distributed 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +454 -0
- package/dist/auth-headers.d.ts +8 -0
- package/dist/auth-headers.js +35 -0
- package/dist/diagnostics.d.ts +2 -0
- package/dist/diagnostics.js +1 -0
- package/dist/document.d.ts +8 -0
- package/dist/document.js +6 -0
- package/dist/identity.d.ts +23 -0
- package/dist/identity.js +73 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +6 -0
- package/dist/internal/cache-engine/create.d.ts +5 -0
- package/dist/internal/cache-engine/create.js +7 -0
- package/dist/internal/cache-engine/engine.d.ts +32 -0
- package/dist/internal/cache-engine/engine.js +1287 -0
- package/dist/internal/cache-engine/errors.d.ts +5 -0
- package/dist/internal/cache-engine/errors.js +10 -0
- package/dist/internal/cache-engine/helpers.d.ts +55 -0
- package/dist/internal/cache-engine/helpers.js +545 -0
- package/dist/internal/cache-engine/index.d.ts +3 -0
- package/dist/internal/cache-engine/index.js +2 -0
- package/dist/internal/cache-engine/types.d.ts +300 -0
- package/dist/internal/cache-engine/types.js +1 -0
- package/dist/internal/cache-engine.d.ts +3 -0
- package/dist/internal/cache-engine.js +2 -0
- package/dist/lib/assert-name.d.ts +2 -0
- package/dist/lib/assert-name.js +6 -0
- package/dist/lib/compare-code-units.d.ts +2 -0
- package/dist/lib/compare-code-units.js +4 -0
- package/dist/lib/deep-equal.d.ts +2 -0
- package/dist/lib/deep-equal.js +24 -0
- package/dist/lib/freeze-record.d.ts +2 -0
- package/dist/lib/freeze-record.js +13 -0
- package/dist/lib/index.d.ts +6 -0
- package/dist/lib/index.js +6 -0
- package/dist/lib/is-plain-record.d.ts +2 -0
- package/dist/lib/is-plain-record.js +8 -0
- package/dist/lib/report.d.ts +7 -0
- package/dist/lib/report.js +26 -0
- package/dist/protocol.d.ts +179 -0
- package/dist/protocol.js +558 -0
- package/dist/react/context.d.ts +20 -0
- package/dist/react/context.js +24 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.js +3 -0
- package/dist/react/query.d.ts +20 -0
- package/dist/react/query.js +99 -0
- package/dist/replica/command-id.d.ts +2 -0
- package/dist/replica/command-id.js +19 -0
- package/dist/replica/command-runtime/constants.d.ts +5 -0
- package/dist/replica/command-runtime/constants.js +5 -0
- package/dist/replica/command-runtime/create.d.ts +2 -0
- package/dist/replica/command-runtime/create.js +644 -0
- package/dist/replica/command-runtime/errors.d.ts +16 -0
- package/dist/replica/command-runtime/errors.js +41 -0
- package/dist/replica/command-runtime/index.d.ts +5 -0
- package/dist/replica/command-runtime/index.js +4 -0
- package/dist/replica/command-runtime/lib/binding.d.ts +4 -0
- package/dist/replica/command-runtime/lib/binding.js +64 -0
- package/dist/replica/command-runtime/lib/effects.d.ts +11 -0
- package/dist/replica/command-runtime/lib/effects.js +89 -0
- package/dist/replica/command-runtime/lib/index.d.ts +9 -0
- package/dist/replica/command-runtime/lib/index.js +9 -0
- package/dist/replica/command-runtime/lib/inventory.d.ts +10 -0
- package/dist/replica/command-runtime/lib/inventory.js +141 -0
- package/dist/replica/command-runtime/lib/output.d.ts +13 -0
- package/dist/replica/command-runtime/lib/output.js +190 -0
- package/dist/replica/command-runtime/lib/projection.d.ts +20 -0
- package/dist/replica/command-runtime/lib/projection.js +255 -0
- package/dist/replica/command-runtime/lib/status.d.ts +7 -0
- package/dist/replica/command-runtime/lib/status.js +127 -0
- package/dist/replica/command-runtime/lib/transport.d.ts +16 -0
- package/dist/replica/command-runtime/lib/transport.js +112 -0
- package/dist/replica/command-runtime/lib/util.d.ts +16 -0
- package/dist/replica/command-runtime/lib/util.js +127 -0
- package/dist/replica/command-runtime/lifecycle.d.ts +11 -0
- package/dist/replica/command-runtime/lifecycle.js +13 -0
- package/dist/replica/command-runtime/symbols.d.ts +30 -0
- package/dist/replica/command-runtime/symbols.js +30 -0
- package/dist/replica/command-runtime/types.d.ts +222 -0
- package/dist/replica/command-runtime/types.js +1 -0
- package/dist/replica/command-runtime.d.ts +3 -0
- package/dist/replica/command-runtime.js +2 -0
- package/dist/replica/commands/clone.d.ts +12 -0
- package/dist/replica/commands/clone.js +187 -0
- package/dist/replica/commands/constants.d.ts +6 -0
- package/dist/replica/commands/constants.js +6 -0
- package/dist/replica/commands/errors.d.ts +7 -0
- package/dist/replica/commands/errors.js +22 -0
- package/dist/replica/commands/implementation.d.ts +8 -0
- package/dist/replica/commands/implementation.js +8 -0
- package/dist/replica/commands/index.d.ts +5 -0
- package/dist/replica/commands/index.js +4 -0
- package/dist/replica/commands/prepare.d.ts +27 -0
- package/dist/replica/commands/prepare.js +77 -0
- package/dist/replica/commands/presets.d.ts +12 -0
- package/dist/replica/commands/presets.js +84 -0
- package/dist/replica/commands/receipt.d.ts +3 -0
- package/dist/replica/commands/receipt.js +36 -0
- package/dist/replica/commands/resolve.d.ts +11 -0
- package/dist/replica/commands/resolve.js +165 -0
- package/dist/replica/commands/types.d.ts +278 -0
- package/dist/replica/commands/types.js +2 -0
- package/dist/replica/commands/util.d.ts +21 -0
- package/dist/replica/commands/util.js +96 -0
- package/dist/replica/commands/validate.d.ts +18 -0
- package/dist/replica/commands/validate.js +477 -0
- package/dist/replica/commands.d.ts +3 -0
- package/dist/replica/commands.js +2 -0
- package/dist/replica/diagnostics/event-log.d.ts +4 -0
- package/dist/replica/diagnostics/event-log.js +463 -0
- package/dist/replica/diagnostics/implementation.d.ts +4 -0
- package/dist/replica/diagnostics/implementation.js +4 -0
- package/dist/replica/diagnostics/index.d.ts +2 -0
- package/dist/replica/diagnostics/index.js +1 -0
- package/dist/replica/diagnostics/inspect.d.ts +6 -0
- package/dist/replica/diagnostics/inspect.js +170 -0
- package/dist/replica/diagnostics/types.d.ts +295 -0
- package/dist/replica/diagnostics/types.js +2 -0
- package/dist/replica/diagnostics.d.ts +3 -0
- package/dist/replica/diagnostics.js +2 -0
- package/dist/replica/distributed-replica/clocks.d.ts +23 -0
- package/dist/replica/distributed-replica/clocks.js +156 -0
- package/dist/replica/distributed-replica/constants.d.ts +12 -0
- package/dist/replica/distributed-replica/constants.js +10 -0
- package/dist/replica/distributed-replica/helpers.d.ts +48 -0
- package/dist/replica/distributed-replica/helpers.js +445 -0
- package/dist/replica/distributed-replica/hydration.d.ts +19 -0
- package/dist/replica/distributed-replica/hydration.js +380 -0
- package/dist/replica/distributed-replica/impl-diagnostics.d.ts +22 -0
- package/dist/replica/distributed-replica/impl-diagnostics.js +189 -0
- package/dist/replica/distributed-replica/impl-fetch-live.d.ts +39 -0
- package/dist/replica/distributed-replica/impl-fetch-live.js +395 -0
- package/dist/replica/distributed-replica/impl-hydration-orchestrate.d.ts +56 -0
- package/dist/replica/distributed-replica/impl-hydration-orchestrate.js +299 -0
- package/dist/replica/distributed-replica/impl-optimistic.d.ts +31 -0
- package/dist/replica/distributed-replica/impl-optimistic.js +172 -0
- package/dist/replica/distributed-replica/impl-protocol.d.ts +53 -0
- package/dist/replica/distributed-replica/impl-protocol.js +108 -0
- package/dist/replica/distributed-replica/impl.d.ts +44 -0
- package/dist/replica/distributed-replica/impl.js +1776 -0
- package/dist/replica/distributed-replica/index.d.ts +2 -0
- package/dist/replica/distributed-replica/index.js +4 -0
- package/dist/replica/distributed-replica/optimistic.d.ts +30 -0
- package/dist/replica/distributed-replica/optimistic.js +221 -0
- package/dist/replica/distributed-replica/types.d.ts +147 -0
- package/dist/replica/distributed-replica/types.js +1 -0
- package/dist/replica/distributed-replica/watch.d.ts +19 -0
- package/dist/replica/distributed-replica/watch.js +95 -0
- package/dist/replica/distributed-replica.d.ts +2 -0
- package/dist/replica/distributed-replica.js +2 -0
- package/dist/replica/graphql-transport.d.ts +24 -0
- package/dist/replica/graphql-transport.js +122 -0
- package/dist/replica/identity/clone.d.ts +6 -0
- package/dist/replica/identity/clone.js +54 -0
- package/dist/replica/identity/codec.d.ts +48 -0
- package/dist/replica/identity/codec.js +789 -0
- package/dist/replica/identity/constants.d.ts +3 -0
- package/dist/replica/identity/constants.js +18 -0
- package/dist/replica/identity/implementation.d.ts +5 -0
- package/dist/replica/identity/implementation.js +5 -0
- package/dist/replica/identity/index.d.ts +3 -0
- package/dist/replica/identity/index.js +3 -0
- package/dist/replica/identity/keys.d.ts +29 -0
- package/dist/replica/identity/keys.js +173 -0
- package/dist/replica/identity.d.ts +2 -0
- package/dist/replica/identity.js +2 -0
- package/dist/replica/index-maintenance/engine.d.ts +84 -0
- package/dist/replica/index-maintenance/engine.js +677 -0
- package/dist/replica/index-maintenance/implementation.d.ts +4 -0
- package/dist/replica/index-maintenance/implementation.js +4 -0
- package/dist/replica/index-maintenance/index.d.ts +2 -0
- package/dist/replica/index-maintenance/index.js +1 -0
- package/dist/replica/index-maintenance/registry.d.ts +2 -0
- package/dist/replica/index-maintenance/registry.js +49 -0
- package/dist/replica/index-maintenance/types.d.ts +58 -0
- package/dist/replica/index-maintenance/types.js +1 -0
- package/dist/replica/index-maintenance.d.ts +3 -0
- package/dist/replica/index-maintenance.js +2 -0
- package/dist/replica/index.d.ts +17 -0
- package/dist/replica/index.js +9 -0
- package/dist/replica/materialize.d.ts +10 -0
- package/dist/replica/materialize.js +163 -0
- package/dist/replica/normalize.d.ts +27 -0
- package/dist/replica/normalize.js +298 -0
- package/dist/replica/operation-binding.d.ts +14 -0
- package/dist/replica/operation-binding.js +76 -0
- package/dist/replica/persistence/idb.d.ts +20 -0
- package/dist/replica/persistence/idb.js +193 -0
- package/dist/replica/persistence/implementation.d.ts +4 -0
- package/dist/replica/persistence/implementation.js +4 -0
- package/dist/replica/persistence/index.d.ts +2 -0
- package/dist/replica/persistence/index.js +1 -0
- package/dist/replica/persistence/state.d.ts +104 -0
- package/dist/replica/persistence/state.js +734 -0
- package/dist/replica/persistence/types.d.ts +54 -0
- package/dist/replica/persistence/types.js +1 -0
- package/dist/replica/persistence.d.ts +3 -0
- package/dist/replica/persistence.js +2 -0
- package/dist/replica/query-plan/constants.d.ts +13 -0
- package/dist/replica/query-plan/constants.js +7 -0
- package/dist/replica/query-plan/filter.d.ts +39 -0
- package/dist/replica/query-plan/filter.js +544 -0
- package/dist/replica/query-plan/index.d.ts +4 -0
- package/dist/replica/query-plan/index.js +3 -0
- package/dist/replica/query-plan/order.d.ts +11 -0
- package/dist/replica/query-plan/order.js +158 -0
- package/dist/replica/query-plan/pagination.d.ts +6 -0
- package/dist/replica/query-plan/pagination.js +90 -0
- package/dist/replica/query-plan/resolve.d.ts +14 -0
- package/dist/replica/query-plan/resolve.js +163 -0
- package/dist/replica/query-plan/types.d.ts +89 -0
- package/dist/replica/query-plan/types.js +1 -0
- package/dist/replica/query-plan/util.d.ts +13 -0
- package/dist/replica/query-plan/util.js +62 -0
- package/dist/replica/query-plan.d.ts +3 -0
- package/dist/replica/query-plan.js +2 -0
- package/dist/replica/revalidation.d.ts +9 -0
- package/dist/replica/revalidation.js +86 -0
- package/dist/replica/selection.d.ts +20 -0
- package/dist/replica/selection.js +109 -0
- package/dist/replica/types.d.ts +657 -0
- package/dist/replica/types.js +1 -0
- package/dist/request.d.ts +17 -0
- package/dist/request.js +123 -0
- package/dist/sveltekit/auth.d.ts +18 -0
- package/dist/sveltekit/auth.js +9 -0
- package/dist/sveltekit/context.d.ts +28 -0
- package/dist/sveltekit/context.js +58 -0
- package/dist/sveltekit/index.d.ts +4 -0
- package/dist/sveltekit/index.js +4 -0
- package/dist/sveltekit/replica.d.ts +145 -0
- package/dist/sveltekit/replica.js +491 -0
- package/dist/sveltekit/server-replica.d.ts +52 -0
- package/dist/sveltekit/server-replica.js +176 -0
- package/dist/sveltekit/vite.d.ts +103 -0
- package/dist/sveltekit/vite.js +878 -0
- package/dist/types.d.ts +33 -0
- package/dist/types.js +1 -0
- package/dist/websocket.d.ts +41 -0
- package/dist/websocket.js +187 -0
- package/package.json +95 -0
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
import {} from '../../internal/cache-engine.js';
|
|
2
|
+
import { isDistributedTrustedPresetCodec } from '../../protocol.js';
|
|
3
|
+
import { canonicalVariables, cloneJsonValue, replicaIndexKey, replicaRecordKey, resolveArguments } from '../identity.js';
|
|
4
|
+
import {} from '../index-maintenance.js';
|
|
5
|
+
import { validateReplicaOperationBinding as validatedArtifactBinding } from '../operation-binding.js';
|
|
6
|
+
import { embeddedRecordKey, runtimeRoot } from '../selection.js';
|
|
7
|
+
import { deepEqual, modelFromRecordKey, protocolInvalid, responsePathKey } from './clocks.js';
|
|
8
|
+
import { EMPTY_ERRORS, SHA256 } from './constants.js';
|
|
9
|
+
import { reportSafely, reportUnhandledError } from '../../lib/report.js';
|
|
10
|
+
export { deepEqual } from './clocks.js';
|
|
11
|
+
export function prepareRecordEvidence(snapshot, commandRecords) {
|
|
12
|
+
const byPath = new Map();
|
|
13
|
+
const tombstones = [];
|
|
14
|
+
const pathless = [];
|
|
15
|
+
const livePaths = new Set();
|
|
16
|
+
for (const evidence of snapshot.records) {
|
|
17
|
+
if (evidence.path === undefined) {
|
|
18
|
+
if (evidence.tombstone)
|
|
19
|
+
tombstones.push(evidence);
|
|
20
|
+
else
|
|
21
|
+
pathless.push(evidence);
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const key = responsePathKey(evidence.path);
|
|
25
|
+
if (byPath.has(key)) {
|
|
26
|
+
protocolInvalid('extensions.distributed.snapshot.records.path');
|
|
27
|
+
}
|
|
28
|
+
byPath.set(key, evidence);
|
|
29
|
+
if (evidence.tombstone)
|
|
30
|
+
tombstones.push(evidence);
|
|
31
|
+
else
|
|
32
|
+
livePaths.add(key);
|
|
33
|
+
}
|
|
34
|
+
for (const evidence of commandRecords) {
|
|
35
|
+
if (evidence.tombstone)
|
|
36
|
+
tombstones.push(evidence);
|
|
37
|
+
else
|
|
38
|
+
pathless.push(evidence);
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
byPath,
|
|
42
|
+
tombstones: Object.freeze(tombstones),
|
|
43
|
+
pathless: Object.freeze(pathless),
|
|
44
|
+
livePaths
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export function replicaResultIndexKeys(artifact, variables, envelope, snapshot) {
|
|
48
|
+
const keys = new Set();
|
|
49
|
+
if (envelope.data === undefined ||
|
|
50
|
+
envelope.data === null ||
|
|
51
|
+
!isReplicaResultObject(envelope.data) ||
|
|
52
|
+
(envelope.errors ?? []).some((error) => !Array.isArray(error.path) || error.path.length === 0)) {
|
|
53
|
+
return keys;
|
|
54
|
+
}
|
|
55
|
+
const errorPaths = (envelope.errors ?? []).flatMap((error) => Array.isArray(error.path) && error.path.length > 0
|
|
56
|
+
? [error.path]
|
|
57
|
+
: []);
|
|
58
|
+
const evidencePaths = new Set(snapshot.records.flatMap((record) => record.path === undefined || record.tombstone
|
|
59
|
+
? []
|
|
60
|
+
: [responsePathKey(record.path)]));
|
|
61
|
+
for (const artifactRoot of artifact.roots) {
|
|
62
|
+
const root = runtimeRoot(artifactRoot);
|
|
63
|
+
const rootPath = [root.responseKey];
|
|
64
|
+
const rootKey = replicaIndexKey({
|
|
65
|
+
field: root.field,
|
|
66
|
+
arguments: resolveArguments(root.arguments, variables, root.coverage)
|
|
67
|
+
});
|
|
68
|
+
keys.add(rootKey);
|
|
69
|
+
if (resultPathBlocked(errorPaths, rootPath) ||
|
|
70
|
+
!Object.prototype.hasOwnProperty.call(envelope.data, root.responseKey)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const value = envelope.data[root.responseKey];
|
|
74
|
+
if (value === null &&
|
|
75
|
+
resultPathHasErrors(errorPaths, rootPath)) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
collectResultBranchIndexKeys(artifact.id, root, value, rootPath, rootKey, variables, errorPaths, evidencePaths, keys);
|
|
79
|
+
}
|
|
80
|
+
return keys;
|
|
81
|
+
}
|
|
82
|
+
export function collectResultBranchIndexKeys(artifactId, selection, value, path, enclosingIndexKey, variables, errorPaths, evidencePaths, keys) {
|
|
83
|
+
if (value === null || value === undefined)
|
|
84
|
+
return;
|
|
85
|
+
if (selection.cardinality === 'one') {
|
|
86
|
+
collectResultObjectIndexKeys(artifactId, selection.selection, value, path, enclosingIndexKey, undefined, variables, errorPaths, evidencePaths, keys);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (!Array.isArray(value))
|
|
90
|
+
return;
|
|
91
|
+
for (const [ordinal, entry] of value.entries()) {
|
|
92
|
+
if (entry === null || entry === undefined)
|
|
93
|
+
continue;
|
|
94
|
+
collectResultObjectIndexKeys(artifactId, selection.selection, entry, [...path, ordinal], enclosingIndexKey, ordinal, variables, errorPaths, evidencePaths, keys);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export function collectResultObjectIndexKeys(artifactId, selection, value, path, enclosingIndexKey, ordinal, variables, errorPaths, evidencePaths, keys) {
|
|
98
|
+
if (resultPathBlocked(errorPaths, path) || !isReplicaResultObject(value)) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const fields = new Map();
|
|
102
|
+
for (const member of selection.members) {
|
|
103
|
+
if (member.kind !== 'scalar')
|
|
104
|
+
continue;
|
|
105
|
+
const fieldPath = [...path, member.responseKey];
|
|
106
|
+
if (resultPathBlocked(errorPaths, fieldPath) ||
|
|
107
|
+
!Object.prototype.hasOwnProperty.call(value, member.responseKey)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const rawValue = value[member.responseKey];
|
|
111
|
+
if (rawValue === null && !member.nullable)
|
|
112
|
+
continue;
|
|
113
|
+
if (!fields.has(member.field)) {
|
|
114
|
+
fields.set(member.field, cloneJsonValue(rawValue));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
let parentKey;
|
|
118
|
+
if (selection.storage.kind === 'normalized' &&
|
|
119
|
+
evidencePaths.has(responsePathKey(path.map(String)))) {
|
|
120
|
+
const identity = selection.storage.identityFields.flatMap((field) => {
|
|
121
|
+
const value = fields.get(field);
|
|
122
|
+
return value === undefined || value === null ? [] : [value];
|
|
123
|
+
});
|
|
124
|
+
if (identity.length !== selection.storage.identityFields.length)
|
|
125
|
+
return;
|
|
126
|
+
parentKey = replicaRecordKey({
|
|
127
|
+
id: selection.storage.model,
|
|
128
|
+
identityFields: selection.storage.identityFields
|
|
129
|
+
}, identity);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
parentKey = embeddedRecordKey(artifactId, enclosingIndexKey, ordinal);
|
|
133
|
+
}
|
|
134
|
+
for (const member of selection.members) {
|
|
135
|
+
if (member.kind !== 'branch')
|
|
136
|
+
continue;
|
|
137
|
+
const branchPath = [...path, member.responseKey];
|
|
138
|
+
const branchKey = replicaIndexKey({
|
|
139
|
+
parent: parentKey,
|
|
140
|
+
field: member.field,
|
|
141
|
+
arguments: resolveArguments(member.arguments, variables, member.coverage)
|
|
142
|
+
});
|
|
143
|
+
keys.add(branchKey);
|
|
144
|
+
if (resultPathBlocked(errorPaths, branchPath) ||
|
|
145
|
+
!Object.prototype.hasOwnProperty.call(value, member.responseKey)) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const branchValue = value[member.responseKey];
|
|
149
|
+
if (branchValue === null &&
|
|
150
|
+
resultPathHasErrors(errorPaths, branchPath)) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
collectResultBranchIndexKeys(artifactId, member, branchValue, branchPath, branchKey, variables, errorPaths, evidencePaths, keys);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
export function resultPathBlocked(errorPaths, path) {
|
|
157
|
+
return errorPaths.some((errorPath) => resultPathPrefix(errorPath, path));
|
|
158
|
+
}
|
|
159
|
+
export function resultPathHasErrors(errorPaths, path) {
|
|
160
|
+
return errorPaths.some((errorPath) => resultPathPrefix(path, errorPath) ||
|
|
161
|
+
resultPathPrefix(errorPath, path));
|
|
162
|
+
}
|
|
163
|
+
export function resultPathPrefix(prefix, value) {
|
|
164
|
+
return (prefix.length <= value.length &&
|
|
165
|
+
prefix.every((entry, index) => entry === value[index]));
|
|
166
|
+
}
|
|
167
|
+
export function isReplicaResultObject(value) {
|
|
168
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
169
|
+
}
|
|
170
|
+
export function indexMaintenanceSnapshot(confirmed) {
|
|
171
|
+
return Object.freeze({
|
|
172
|
+
records: Object.freeze(confirmed.records.flatMap((record) => {
|
|
173
|
+
if (record.tombstoneRevision !== undefined)
|
|
174
|
+
return [];
|
|
175
|
+
const model = modelFromRecordKey(record.key);
|
|
176
|
+
if (model === undefined)
|
|
177
|
+
return [];
|
|
178
|
+
return [
|
|
179
|
+
Object.freeze({
|
|
180
|
+
key: record.key,
|
|
181
|
+
model,
|
|
182
|
+
fields: Object.freeze(Object.fromEntries(Object.entries(record.fields).map(([name, field]) => [
|
|
183
|
+
name,
|
|
184
|
+
field.value
|
|
185
|
+
])))
|
|
186
|
+
})
|
|
187
|
+
];
|
|
188
|
+
})),
|
|
189
|
+
indexes: Object.freeze(confirmed.indexes.flatMap((index) => {
|
|
190
|
+
if (index.deleted || index.metadata === undefined)
|
|
191
|
+
return [];
|
|
192
|
+
return [
|
|
193
|
+
Object.freeze({
|
|
194
|
+
key: index.key,
|
|
195
|
+
records: index.records,
|
|
196
|
+
complete: index.complete,
|
|
197
|
+
metadata: index.metadata
|
|
198
|
+
})
|
|
199
|
+
];
|
|
200
|
+
}))
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
export function indexSemanticLayer(layer) {
|
|
204
|
+
const context = layer.context;
|
|
205
|
+
if (context === null ||
|
|
206
|
+
Array.isArray(context) ||
|
|
207
|
+
typeof context !== 'object') {
|
|
208
|
+
throw new TypeError(`optimistic layer ${layer.id} has invalid index-maintenance context`);
|
|
209
|
+
}
|
|
210
|
+
const record = context;
|
|
211
|
+
if (record.id !== layer.id || !Array.isArray(record.changes)) {
|
|
212
|
+
throw new TypeError(`optimistic layer ${layer.id} has invalid index-maintenance context`);
|
|
213
|
+
}
|
|
214
|
+
return Object.freeze({
|
|
215
|
+
id: layer.id,
|
|
216
|
+
changes: record.changes
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
export function baseWriter(writer) {
|
|
220
|
+
return Object.freeze({
|
|
221
|
+
writeRecord(model, identity, revision, patch) {
|
|
222
|
+
return writer.writeRecord({
|
|
223
|
+
key: replicaRecordKey(model, identity),
|
|
224
|
+
revision,
|
|
225
|
+
...patch
|
|
226
|
+
});
|
|
227
|
+
},
|
|
228
|
+
tombstoneRecord(model, identity, revision) {
|
|
229
|
+
return writer.tombstoneRecord(replicaRecordKey(model, identity), revision);
|
|
230
|
+
},
|
|
231
|
+
writeIndex(target, records, revision) {
|
|
232
|
+
return writer.writeIndex({
|
|
233
|
+
key: indexKeyFromTarget(target),
|
|
234
|
+
revision,
|
|
235
|
+
records,
|
|
236
|
+
complete: target.complete ?? false,
|
|
237
|
+
metadata: metadataFromTarget(target)
|
|
238
|
+
});
|
|
239
|
+
},
|
|
240
|
+
deleteIndex(target, revision) {
|
|
241
|
+
return writer.deleteIndex(indexKeyFromTarget(target), revision);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
export function metadataFromTarget(target) {
|
|
246
|
+
const dependencies = [...new Set(target.dependencies ?? [])].sort();
|
|
247
|
+
return Object.freeze({
|
|
248
|
+
...(target.parent === undefined ? {} : { parent: target.parent }),
|
|
249
|
+
field: target.field,
|
|
250
|
+
arguments: target.arguments ?? Object.freeze({}),
|
|
251
|
+
coverage: target.coverage ?? { kind: 'unknown' },
|
|
252
|
+
dependencies: Object.freeze(dependencies),
|
|
253
|
+
...(target.staleReason === undefined ? {} : { staleReason: target.staleReason }),
|
|
254
|
+
...(target.nullValue === undefined ? {} : { nullValue: target.nullValue })
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
export function indexKeyFromTarget(target) {
|
|
258
|
+
return replicaIndexKey({
|
|
259
|
+
...(target.parent === undefined ? {} : { parent: target.parent }),
|
|
260
|
+
field: target.field,
|
|
261
|
+
arguments: target.arguments ?? {}
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
export function replicaClientRequestExtensions(artifact) {
|
|
265
|
+
validatedArtifactBinding(artifact);
|
|
266
|
+
const protocol = artifact.protocol;
|
|
267
|
+
const surface = protocol.surface.kind === 'role'
|
|
268
|
+
? Object.freeze({
|
|
269
|
+
kind: 'role',
|
|
270
|
+
name: protocol.surface.name
|
|
271
|
+
})
|
|
272
|
+
: Object.freeze({
|
|
273
|
+
kind: 'application',
|
|
274
|
+
name: protocol.surface.name,
|
|
275
|
+
roles: Object.freeze([...protocol.surface.roles])
|
|
276
|
+
});
|
|
277
|
+
return Object.freeze({
|
|
278
|
+
extensions: Object.freeze({
|
|
279
|
+
distributed: Object.freeze({
|
|
280
|
+
client: Object.freeze({
|
|
281
|
+
surface,
|
|
282
|
+
schemaHash: protocol.schemaHash
|
|
283
|
+
})
|
|
284
|
+
})
|
|
285
|
+
})
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
export function validatedCommandAuthorityContract(value) {
|
|
289
|
+
if (value === null ||
|
|
290
|
+
typeof value !== 'object' ||
|
|
291
|
+
value.protocolVersion !== 1 ||
|
|
292
|
+
typeof value.schemaHash !== 'string' ||
|
|
293
|
+
!SHA256.test(value.schemaHash) ||
|
|
294
|
+
typeof value.protocolHash !== 'string' ||
|
|
295
|
+
!SHA256.test(value.protocolHash) ||
|
|
296
|
+
!Array.isArray(value.trustedPresets)) {
|
|
297
|
+
throw new TypeError('replica command authority contract is invalid');
|
|
298
|
+
}
|
|
299
|
+
const surfaceIdentity = validatedSurfaceIdentity(value.surface);
|
|
300
|
+
const names = new Set();
|
|
301
|
+
const trustedPresets = Object.freeze(value.trustedPresets
|
|
302
|
+
.map((descriptor) => {
|
|
303
|
+
if (descriptor === null ||
|
|
304
|
+
typeof descriptor !== 'object' ||
|
|
305
|
+
typeof descriptor.name !== 'string' ||
|
|
306
|
+
descriptor.name.length === 0 ||
|
|
307
|
+
descriptor.name.length > 128 ||
|
|
308
|
+
descriptor.name.trim() !== descriptor.name ||
|
|
309
|
+
/[\u0000-\u001f\u007f-\u009f]/.test(descriptor.name) ||
|
|
310
|
+
names.has(descriptor.name) ||
|
|
311
|
+
!isDistributedTrustedPresetCodec(descriptor.codec)) {
|
|
312
|
+
throw new TypeError('replica command trusted preset contract is invalid');
|
|
313
|
+
}
|
|
314
|
+
names.add(descriptor.name);
|
|
315
|
+
return Object.freeze({
|
|
316
|
+
name: descriptor.name,
|
|
317
|
+
codec: descriptor.codec
|
|
318
|
+
});
|
|
319
|
+
})
|
|
320
|
+
.sort(({ name: left }, { name: right }) => left < right ? -1 : left > right ? 1 : 0));
|
|
321
|
+
const fingerprint = JSON.stringify([
|
|
322
|
+
2,
|
|
323
|
+
value.schemaHash,
|
|
324
|
+
value.protocolHash,
|
|
325
|
+
surfaceIdentity,
|
|
326
|
+
trustedPresets
|
|
327
|
+
]);
|
|
328
|
+
return Object.freeze({
|
|
329
|
+
schemaHash: value.schemaHash,
|
|
330
|
+
protocolHash: value.protocolHash,
|
|
331
|
+
surfaceIdentity,
|
|
332
|
+
trustedPresets,
|
|
333
|
+
fingerprint
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
export function canonicalTrustedPresets(value) {
|
|
337
|
+
return Object.freeze([...value].sort(({ name: left }, { name: right }) => left < right ? -1 : left > right ? 1 : 0));
|
|
338
|
+
}
|
|
339
|
+
export function trustedPresetInventoryFingerprint(value) {
|
|
340
|
+
return JSON.stringify(canonicalTrustedPresets(value));
|
|
341
|
+
}
|
|
342
|
+
export function trustedPresetDescriptorFingerprint(value) {
|
|
343
|
+
return JSON.stringify(value);
|
|
344
|
+
}
|
|
345
|
+
export function operationKey(artifact, variables) {
|
|
346
|
+
const binding = validatedArtifactBinding(artifact);
|
|
347
|
+
const artifactIdentity = JSON.stringify([
|
|
348
|
+
binding.version,
|
|
349
|
+
binding.schemaHash,
|
|
350
|
+
binding.surfaceIdentity,
|
|
351
|
+
binding.operation,
|
|
352
|
+
artifact.id
|
|
353
|
+
]);
|
|
354
|
+
return `protocol:${artifactIdentity}:${canonicalVariables(variables)}`;
|
|
355
|
+
}
|
|
356
|
+
export function validatedSurfaceIdentity(value) {
|
|
357
|
+
if (value === null ||
|
|
358
|
+
typeof value !== 'object' ||
|
|
359
|
+
typeof value.name !== 'string' ||
|
|
360
|
+
value.name.length === 0) {
|
|
361
|
+
throw new TypeError('replica artifact client surface is invalid');
|
|
362
|
+
}
|
|
363
|
+
if (value.kind === 'role') {
|
|
364
|
+
return JSON.stringify(['role', value.name]);
|
|
365
|
+
}
|
|
366
|
+
if (value.kind !== 'application' ||
|
|
367
|
+
!Array.isArray(value.roles) ||
|
|
368
|
+
value.roles.length === 0 ||
|
|
369
|
+
value.roles.some((role) => typeof role !== 'string' || role.length === 0) ||
|
|
370
|
+
new Set(value.roles).size !== value.roles.length ||
|
|
371
|
+
[...value.roles].sort().some((role, index) => role !== value.roles[index])) {
|
|
372
|
+
throw new TypeError('replica artifact client surface is invalid');
|
|
373
|
+
}
|
|
374
|
+
return JSON.stringify(['application', value.name, value.roles]);
|
|
375
|
+
}
|
|
376
|
+
export function snapshotFrom(materialized, state) {
|
|
377
|
+
const status = state.errors.length > 0
|
|
378
|
+
? 'error'
|
|
379
|
+
: materialized.stale
|
|
380
|
+
? 'stale'
|
|
381
|
+
: materialized.complete
|
|
382
|
+
? 'ready'
|
|
383
|
+
: 'loading';
|
|
384
|
+
const snapshot = Object.freeze({
|
|
385
|
+
data: materialized.data,
|
|
386
|
+
status,
|
|
387
|
+
fetching: state.fetching,
|
|
388
|
+
stale: materialized.stale,
|
|
389
|
+
complete: materialized.complete,
|
|
390
|
+
errors: state.errors,
|
|
391
|
+
live: state.live
|
|
392
|
+
});
|
|
393
|
+
// `materializeReplicaOperation` only reports complete after every generated
|
|
394
|
+
// selection is present; that runtime invariant is what promotes sparse data
|
|
395
|
+
// to the generated result type in ReplicaSnapshot's discriminated union.
|
|
396
|
+
return snapshot;
|
|
397
|
+
}
|
|
398
|
+
export function snapshotEqual(left, right) {
|
|
399
|
+
return (left.data === right.data &&
|
|
400
|
+
left.status === right.status &&
|
|
401
|
+
left.fetching === right.fetching &&
|
|
402
|
+
left.stale === right.stale &&
|
|
403
|
+
left.complete === right.complete &&
|
|
404
|
+
left.errors === right.errors &&
|
|
405
|
+
left.live === right.live);
|
|
406
|
+
}
|
|
407
|
+
export function freezeErrors(errors) {
|
|
408
|
+
if (errors.length === 0)
|
|
409
|
+
return EMPTY_ERRORS;
|
|
410
|
+
return Object.freeze(errors.map((error) => Object.freeze({
|
|
411
|
+
message: error.message,
|
|
412
|
+
...(error.locations === undefined
|
|
413
|
+
? {}
|
|
414
|
+
: {
|
|
415
|
+
locations: Object.freeze(error.locations.map((location) => Object.freeze({ ...location })))
|
|
416
|
+
}),
|
|
417
|
+
...(error.path === undefined ? {} : { path: Object.freeze([...error.path]) }),
|
|
418
|
+
...(error.extensions === undefined
|
|
419
|
+
? {}
|
|
420
|
+
: {
|
|
421
|
+
extensions: cloneJsonValue(error.extensions)
|
|
422
|
+
})
|
|
423
|
+
})));
|
|
424
|
+
}
|
|
425
|
+
export function stableErrors(current, next) {
|
|
426
|
+
if (next.length === 0)
|
|
427
|
+
return EMPTY_ERRORS;
|
|
428
|
+
return deepEqual(current, next) ? current : freezeErrors(next);
|
|
429
|
+
}
|
|
430
|
+
export function graphqlError(error) {
|
|
431
|
+
return Object.freeze({
|
|
432
|
+
message: error instanceof Error ? error.message : String(error),
|
|
433
|
+
extensions: Object.freeze({ code: 'REPLICA_TRANSPORT' })
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
export function assertWriteSource(source) {
|
|
437
|
+
if (!['network', 'live', 'ssr', 'restore', 'projected'].includes(source)) {
|
|
438
|
+
throw new TypeError(`unsupported replica write source: ${source}`);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
export function protocolOperationSource(source) {
|
|
442
|
+
return source === 'live' ? 'live' : 'query';
|
|
443
|
+
}
|
|
444
|
+
export { reportSafely };
|
|
445
|
+
export const reportUnhandledObserverError = reportUnhandledError;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type DistributedDecimalString, type DistributedOpaqueString } from '../../protocol.js';
|
|
2
|
+
import type { OperationProtocolGroup, OperationProtocolSource, OperationProtocolState, ParsedReplicaHydration, ProtocolGeneration, RecordProtocolClock, SerializedOperationProtocolGroup, SerializedOperationProtocolState } from './types.js';
|
|
3
|
+
export declare function serializeOperationProtocolGroup(key: string, group: OperationProtocolGroup, generation: number): SerializedOperationProtocolGroup;
|
|
4
|
+
export declare function serializeOperationProtocolState(state: OperationProtocolState): SerializedOperationProtocolState;
|
|
5
|
+
export declare function parseAuthoritativeScope(value: unknown): ProtocolGeneration | undefined;
|
|
6
|
+
export declare function hydrationMetadataConsistent(parsed: ParsedReplicaHydration): boolean;
|
|
7
|
+
export declare function parseReplicaHydration(value: unknown): ParsedReplicaHydration | undefined;
|
|
8
|
+
export declare function parseOperationProtocolState(value: unknown, path: string): OperationProtocolState;
|
|
9
|
+
export declare function parseRecordClock(value: unknown, path: string): RecordProtocolClock;
|
|
10
|
+
export declare function hydrationRecord(value: unknown, path: string, allowed: readonly string[], required?: readonly string[]): Record<string, unknown>;
|
|
11
|
+
export declare function isHydrationRecord(value: unknown): value is Record<string, unknown>;
|
|
12
|
+
export declare function hydrationArray(value: unknown, path: string): unknown[];
|
|
13
|
+
export declare function hydrationPair(value: unknown, path: string): readonly [unknown, unknown];
|
|
14
|
+
export declare function hydrationString(value: unknown, path: string): string;
|
|
15
|
+
export declare function hydrationOpaque(value: unknown, path: string): DistributedOpaqueString;
|
|
16
|
+
export declare function hydrationDecimal(value: unknown, path: string): DistributedDecimalString;
|
|
17
|
+
export declare function hydrationGeneration(value: unknown, path: string): number;
|
|
18
|
+
export declare function hydrationOperationSource(value: unknown, path: string): OperationProtocolSource;
|
|
19
|
+
export declare function hydrationInvalid(path: string): never;
|