@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.
Files changed (242) hide show
  1. package/README.md +454 -0
  2. package/dist/auth-headers.d.ts +8 -0
  3. package/dist/auth-headers.js +35 -0
  4. package/dist/diagnostics.d.ts +2 -0
  5. package/dist/diagnostics.js +1 -0
  6. package/dist/document.d.ts +8 -0
  7. package/dist/document.js +6 -0
  8. package/dist/identity.d.ts +23 -0
  9. package/dist/identity.js +73 -0
  10. package/dist/index.d.ts +7 -0
  11. package/dist/index.js +6 -0
  12. package/dist/internal/cache-engine/create.d.ts +5 -0
  13. package/dist/internal/cache-engine/create.js +7 -0
  14. package/dist/internal/cache-engine/engine.d.ts +32 -0
  15. package/dist/internal/cache-engine/engine.js +1287 -0
  16. package/dist/internal/cache-engine/errors.d.ts +5 -0
  17. package/dist/internal/cache-engine/errors.js +10 -0
  18. package/dist/internal/cache-engine/helpers.d.ts +55 -0
  19. package/dist/internal/cache-engine/helpers.js +545 -0
  20. package/dist/internal/cache-engine/index.d.ts +3 -0
  21. package/dist/internal/cache-engine/index.js +2 -0
  22. package/dist/internal/cache-engine/types.d.ts +300 -0
  23. package/dist/internal/cache-engine/types.js +1 -0
  24. package/dist/internal/cache-engine.d.ts +3 -0
  25. package/dist/internal/cache-engine.js +2 -0
  26. package/dist/lib/assert-name.d.ts +2 -0
  27. package/dist/lib/assert-name.js +6 -0
  28. package/dist/lib/compare-code-units.d.ts +2 -0
  29. package/dist/lib/compare-code-units.js +4 -0
  30. package/dist/lib/deep-equal.d.ts +2 -0
  31. package/dist/lib/deep-equal.js +24 -0
  32. package/dist/lib/freeze-record.d.ts +2 -0
  33. package/dist/lib/freeze-record.js +13 -0
  34. package/dist/lib/index.d.ts +6 -0
  35. package/dist/lib/index.js +6 -0
  36. package/dist/lib/is-plain-record.d.ts +2 -0
  37. package/dist/lib/is-plain-record.js +8 -0
  38. package/dist/lib/report.d.ts +7 -0
  39. package/dist/lib/report.js +26 -0
  40. package/dist/protocol.d.ts +179 -0
  41. package/dist/protocol.js +558 -0
  42. package/dist/react/context.d.ts +20 -0
  43. package/dist/react/context.js +24 -0
  44. package/dist/react/index.d.ts +2 -0
  45. package/dist/react/index.js +3 -0
  46. package/dist/react/query.d.ts +20 -0
  47. package/dist/react/query.js +99 -0
  48. package/dist/replica/command-id.d.ts +2 -0
  49. package/dist/replica/command-id.js +19 -0
  50. package/dist/replica/command-runtime/constants.d.ts +5 -0
  51. package/dist/replica/command-runtime/constants.js +5 -0
  52. package/dist/replica/command-runtime/create.d.ts +2 -0
  53. package/dist/replica/command-runtime/create.js +644 -0
  54. package/dist/replica/command-runtime/errors.d.ts +16 -0
  55. package/dist/replica/command-runtime/errors.js +41 -0
  56. package/dist/replica/command-runtime/index.d.ts +5 -0
  57. package/dist/replica/command-runtime/index.js +4 -0
  58. package/dist/replica/command-runtime/lib/binding.d.ts +4 -0
  59. package/dist/replica/command-runtime/lib/binding.js +64 -0
  60. package/dist/replica/command-runtime/lib/effects.d.ts +11 -0
  61. package/dist/replica/command-runtime/lib/effects.js +89 -0
  62. package/dist/replica/command-runtime/lib/index.d.ts +9 -0
  63. package/dist/replica/command-runtime/lib/index.js +9 -0
  64. package/dist/replica/command-runtime/lib/inventory.d.ts +10 -0
  65. package/dist/replica/command-runtime/lib/inventory.js +141 -0
  66. package/dist/replica/command-runtime/lib/output.d.ts +13 -0
  67. package/dist/replica/command-runtime/lib/output.js +190 -0
  68. package/dist/replica/command-runtime/lib/projection.d.ts +20 -0
  69. package/dist/replica/command-runtime/lib/projection.js +255 -0
  70. package/dist/replica/command-runtime/lib/status.d.ts +7 -0
  71. package/dist/replica/command-runtime/lib/status.js +127 -0
  72. package/dist/replica/command-runtime/lib/transport.d.ts +16 -0
  73. package/dist/replica/command-runtime/lib/transport.js +112 -0
  74. package/dist/replica/command-runtime/lib/util.d.ts +16 -0
  75. package/dist/replica/command-runtime/lib/util.js +127 -0
  76. package/dist/replica/command-runtime/lifecycle.d.ts +11 -0
  77. package/dist/replica/command-runtime/lifecycle.js +13 -0
  78. package/dist/replica/command-runtime/symbols.d.ts +30 -0
  79. package/dist/replica/command-runtime/symbols.js +30 -0
  80. package/dist/replica/command-runtime/types.d.ts +222 -0
  81. package/dist/replica/command-runtime/types.js +1 -0
  82. package/dist/replica/command-runtime.d.ts +3 -0
  83. package/dist/replica/command-runtime.js +2 -0
  84. package/dist/replica/commands/clone.d.ts +12 -0
  85. package/dist/replica/commands/clone.js +187 -0
  86. package/dist/replica/commands/constants.d.ts +6 -0
  87. package/dist/replica/commands/constants.js +6 -0
  88. package/dist/replica/commands/errors.d.ts +7 -0
  89. package/dist/replica/commands/errors.js +22 -0
  90. package/dist/replica/commands/implementation.d.ts +8 -0
  91. package/dist/replica/commands/implementation.js +8 -0
  92. package/dist/replica/commands/index.d.ts +5 -0
  93. package/dist/replica/commands/index.js +4 -0
  94. package/dist/replica/commands/prepare.d.ts +27 -0
  95. package/dist/replica/commands/prepare.js +77 -0
  96. package/dist/replica/commands/presets.d.ts +12 -0
  97. package/dist/replica/commands/presets.js +84 -0
  98. package/dist/replica/commands/receipt.d.ts +3 -0
  99. package/dist/replica/commands/receipt.js +36 -0
  100. package/dist/replica/commands/resolve.d.ts +11 -0
  101. package/dist/replica/commands/resolve.js +165 -0
  102. package/dist/replica/commands/types.d.ts +278 -0
  103. package/dist/replica/commands/types.js +2 -0
  104. package/dist/replica/commands/util.d.ts +21 -0
  105. package/dist/replica/commands/util.js +96 -0
  106. package/dist/replica/commands/validate.d.ts +18 -0
  107. package/dist/replica/commands/validate.js +477 -0
  108. package/dist/replica/commands.d.ts +3 -0
  109. package/dist/replica/commands.js +2 -0
  110. package/dist/replica/diagnostics/event-log.d.ts +4 -0
  111. package/dist/replica/diagnostics/event-log.js +463 -0
  112. package/dist/replica/diagnostics/implementation.d.ts +4 -0
  113. package/dist/replica/diagnostics/implementation.js +4 -0
  114. package/dist/replica/diagnostics/index.d.ts +2 -0
  115. package/dist/replica/diagnostics/index.js +1 -0
  116. package/dist/replica/diagnostics/inspect.d.ts +6 -0
  117. package/dist/replica/diagnostics/inspect.js +170 -0
  118. package/dist/replica/diagnostics/types.d.ts +295 -0
  119. package/dist/replica/diagnostics/types.js +2 -0
  120. package/dist/replica/diagnostics.d.ts +3 -0
  121. package/dist/replica/diagnostics.js +2 -0
  122. package/dist/replica/distributed-replica/clocks.d.ts +23 -0
  123. package/dist/replica/distributed-replica/clocks.js +156 -0
  124. package/dist/replica/distributed-replica/constants.d.ts +12 -0
  125. package/dist/replica/distributed-replica/constants.js +10 -0
  126. package/dist/replica/distributed-replica/helpers.d.ts +48 -0
  127. package/dist/replica/distributed-replica/helpers.js +445 -0
  128. package/dist/replica/distributed-replica/hydration.d.ts +19 -0
  129. package/dist/replica/distributed-replica/hydration.js +380 -0
  130. package/dist/replica/distributed-replica/impl-diagnostics.d.ts +22 -0
  131. package/dist/replica/distributed-replica/impl-diagnostics.js +189 -0
  132. package/dist/replica/distributed-replica/impl-fetch-live.d.ts +39 -0
  133. package/dist/replica/distributed-replica/impl-fetch-live.js +395 -0
  134. package/dist/replica/distributed-replica/impl-hydration-orchestrate.d.ts +56 -0
  135. package/dist/replica/distributed-replica/impl-hydration-orchestrate.js +299 -0
  136. package/dist/replica/distributed-replica/impl-optimistic.d.ts +31 -0
  137. package/dist/replica/distributed-replica/impl-optimistic.js +172 -0
  138. package/dist/replica/distributed-replica/impl-protocol.d.ts +53 -0
  139. package/dist/replica/distributed-replica/impl-protocol.js +108 -0
  140. package/dist/replica/distributed-replica/impl.d.ts +44 -0
  141. package/dist/replica/distributed-replica/impl.js +1776 -0
  142. package/dist/replica/distributed-replica/index.d.ts +2 -0
  143. package/dist/replica/distributed-replica/index.js +4 -0
  144. package/dist/replica/distributed-replica/optimistic.d.ts +30 -0
  145. package/dist/replica/distributed-replica/optimistic.js +221 -0
  146. package/dist/replica/distributed-replica/types.d.ts +147 -0
  147. package/dist/replica/distributed-replica/types.js +1 -0
  148. package/dist/replica/distributed-replica/watch.d.ts +19 -0
  149. package/dist/replica/distributed-replica/watch.js +95 -0
  150. package/dist/replica/distributed-replica.d.ts +2 -0
  151. package/dist/replica/distributed-replica.js +2 -0
  152. package/dist/replica/graphql-transport.d.ts +24 -0
  153. package/dist/replica/graphql-transport.js +122 -0
  154. package/dist/replica/identity/clone.d.ts +6 -0
  155. package/dist/replica/identity/clone.js +54 -0
  156. package/dist/replica/identity/codec.d.ts +48 -0
  157. package/dist/replica/identity/codec.js +789 -0
  158. package/dist/replica/identity/constants.d.ts +3 -0
  159. package/dist/replica/identity/constants.js +18 -0
  160. package/dist/replica/identity/implementation.d.ts +5 -0
  161. package/dist/replica/identity/implementation.js +5 -0
  162. package/dist/replica/identity/index.d.ts +3 -0
  163. package/dist/replica/identity/index.js +3 -0
  164. package/dist/replica/identity/keys.d.ts +29 -0
  165. package/dist/replica/identity/keys.js +173 -0
  166. package/dist/replica/identity.d.ts +2 -0
  167. package/dist/replica/identity.js +2 -0
  168. package/dist/replica/index-maintenance/engine.d.ts +84 -0
  169. package/dist/replica/index-maintenance/engine.js +677 -0
  170. package/dist/replica/index-maintenance/implementation.d.ts +4 -0
  171. package/dist/replica/index-maintenance/implementation.js +4 -0
  172. package/dist/replica/index-maintenance/index.d.ts +2 -0
  173. package/dist/replica/index-maintenance/index.js +1 -0
  174. package/dist/replica/index-maintenance/registry.d.ts +2 -0
  175. package/dist/replica/index-maintenance/registry.js +49 -0
  176. package/dist/replica/index-maintenance/types.d.ts +58 -0
  177. package/dist/replica/index-maintenance/types.js +1 -0
  178. package/dist/replica/index-maintenance.d.ts +3 -0
  179. package/dist/replica/index-maintenance.js +2 -0
  180. package/dist/replica/index.d.ts +17 -0
  181. package/dist/replica/index.js +9 -0
  182. package/dist/replica/materialize.d.ts +10 -0
  183. package/dist/replica/materialize.js +163 -0
  184. package/dist/replica/normalize.d.ts +27 -0
  185. package/dist/replica/normalize.js +298 -0
  186. package/dist/replica/operation-binding.d.ts +14 -0
  187. package/dist/replica/operation-binding.js +76 -0
  188. package/dist/replica/persistence/idb.d.ts +20 -0
  189. package/dist/replica/persistence/idb.js +193 -0
  190. package/dist/replica/persistence/implementation.d.ts +4 -0
  191. package/dist/replica/persistence/implementation.js +4 -0
  192. package/dist/replica/persistence/index.d.ts +2 -0
  193. package/dist/replica/persistence/index.js +1 -0
  194. package/dist/replica/persistence/state.d.ts +104 -0
  195. package/dist/replica/persistence/state.js +734 -0
  196. package/dist/replica/persistence/types.d.ts +54 -0
  197. package/dist/replica/persistence/types.js +1 -0
  198. package/dist/replica/persistence.d.ts +3 -0
  199. package/dist/replica/persistence.js +2 -0
  200. package/dist/replica/query-plan/constants.d.ts +13 -0
  201. package/dist/replica/query-plan/constants.js +7 -0
  202. package/dist/replica/query-plan/filter.d.ts +39 -0
  203. package/dist/replica/query-plan/filter.js +544 -0
  204. package/dist/replica/query-plan/index.d.ts +4 -0
  205. package/dist/replica/query-plan/index.js +3 -0
  206. package/dist/replica/query-plan/order.d.ts +11 -0
  207. package/dist/replica/query-plan/order.js +158 -0
  208. package/dist/replica/query-plan/pagination.d.ts +6 -0
  209. package/dist/replica/query-plan/pagination.js +90 -0
  210. package/dist/replica/query-plan/resolve.d.ts +14 -0
  211. package/dist/replica/query-plan/resolve.js +163 -0
  212. package/dist/replica/query-plan/types.d.ts +89 -0
  213. package/dist/replica/query-plan/types.js +1 -0
  214. package/dist/replica/query-plan/util.d.ts +13 -0
  215. package/dist/replica/query-plan/util.js +62 -0
  216. package/dist/replica/query-plan.d.ts +3 -0
  217. package/dist/replica/query-plan.js +2 -0
  218. package/dist/replica/revalidation.d.ts +9 -0
  219. package/dist/replica/revalidation.js +86 -0
  220. package/dist/replica/selection.d.ts +20 -0
  221. package/dist/replica/selection.js +109 -0
  222. package/dist/replica/types.d.ts +657 -0
  223. package/dist/replica/types.js +1 -0
  224. package/dist/request.d.ts +17 -0
  225. package/dist/request.js +123 -0
  226. package/dist/sveltekit/auth.d.ts +18 -0
  227. package/dist/sveltekit/auth.js +9 -0
  228. package/dist/sveltekit/context.d.ts +28 -0
  229. package/dist/sveltekit/context.js +58 -0
  230. package/dist/sveltekit/index.d.ts +4 -0
  231. package/dist/sveltekit/index.js +4 -0
  232. package/dist/sveltekit/replica.d.ts +145 -0
  233. package/dist/sveltekit/replica.js +491 -0
  234. package/dist/sveltekit/server-replica.d.ts +52 -0
  235. package/dist/sveltekit/server-replica.js +176 -0
  236. package/dist/sveltekit/vite.d.ts +103 -0
  237. package/dist/sveltekit/vite.js +878 -0
  238. package/dist/types.d.ts +33 -0
  239. package/dist/types.js +1 -0
  240. package/dist/websocket.d.ts +41 -0
  241. package/dist/websocket.js +187 -0
  242. package/package.json +95 -0
@@ -0,0 +1,644 @@
1
+ import { parseGraphqlResponseExtensions } from '../../protocol.js';
2
+ import { matchReplicaTrustedPresetInventory, prepareReplicaCommandWithTrustedPresets, verifyReplicaCommandReceipt } from '../commands.js';
3
+ import { applyOptimisticEffects, attachAuthorityAbort, callerProjectedPromise, cloneScope, commandOutput, commandStatusArtifact, commandStatusRequest, commandSurfaceContract, commandTransportRequest, confirmDirectProjection, defineBoundCommand, dispatchPrepared, failTrackedProjection, freezeCommandTree, graphqlCommandRejection, linkAbortSignals, monitorPendingProjection, normalizeInventory, normalizeRetries, pendingProjection, preparedSemanticChanges, requireCommandEnvelope, requireCommandRejectionEnvelope, requireStatusEnvelope, sameScope, settleProjectionFailure, settleProjectionSuccess, settleTrackedProjection, validateStatusProgression, waitForCommandOperation } from './lib/index.js';
4
+ import { ReplicaCommandRuntimeError } from './errors.js';
5
+ import { replicaCommandAuthority, replicaCommandProjectedLifecycle, replicaResultObservation } from './symbols.js';
6
+ export function createReplicaCommandRuntime(replica, transport, entries, options = {}) {
7
+ const inventory = normalizeInventory(entries);
8
+ if (options.diagnostics !== undefined) {
9
+ for (const { artifact } of inventory) {
10
+ try {
11
+ options.diagnostics.command(artifact);
12
+ }
13
+ catch (error) {
14
+ options.onBackgroundError?.(error);
15
+ }
16
+ }
17
+ }
18
+ const contract = commandSurfaceContract(inventory.map(({ artifact }) => artifact), options.status?.protocol.trustedPresets);
19
+ const statusArtifact = options.status === undefined
20
+ ? undefined
21
+ : commandStatusArtifact(options.status, contract);
22
+ const replicaRevalidate = typeof replica.revalidate === 'function'
23
+ ? replica.revalidate.bind(replica)
24
+ : undefined;
25
+ if (statusArtifact !== undefined && transport.status === undefined) {
26
+ throw new TypeError('generated command status artifact requires transport.status');
27
+ }
28
+ if (replicaRevalidate === undefined &&
29
+ inventory.some(({ artifact }) => artifact.revalidation.required)) {
30
+ throw new TypeError('generated command revalidation plan requires replica.revalidate');
31
+ }
32
+ const registration = replica[replicaCommandAuthority]?.(contract);
33
+ const pending = new Map();
34
+ const unmanagedLayers = new Set();
35
+ const runtimeAbort = new AbortController();
36
+ let disposed = false;
37
+ const rejectUnmanagedLayer = (commandId) => {
38
+ unmanagedLayers.delete(commandId);
39
+ return replica.rejectOptimisticLayer(commandId);
40
+ };
41
+ const retireLayerAfterAuthoritativeRevalidation = (commandId) => {
42
+ if (!replica.markOptimisticLayerAccepted(commandId)) {
43
+ // The authoritative result may already have retired this layer.
44
+ unmanagedLayers.delete(commandId);
45
+ return false;
46
+ }
47
+ replica.confirmOptimisticLayer(commandId, () => undefined);
48
+ unmanagedLayers.delete(commandId);
49
+ return true;
50
+ };
51
+ const authoritySnapshot = () => registration?.read() ?? {
52
+ generation: replica.authorizationGeneration,
53
+ scope: replica.scope,
54
+ trustedPresets: Object.freeze([])
55
+ };
56
+ const currentAuthority = () => {
57
+ if (disposed) {
58
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_DISPOSED');
59
+ }
60
+ const snapshot = authoritySnapshot();
61
+ const scope = snapshot.scope;
62
+ if (scope === undefined ||
63
+ scope.protocolVersion !== contract.protocolVersion ||
64
+ scope.schemaHash !== contract.schemaHash) {
65
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_AUTHORITY_UNAVAILABLE');
66
+ }
67
+ const matched = matchReplicaTrustedPresetInventory(contract.trustedPresets, snapshot.trustedPresets);
68
+ return Object.freeze({
69
+ generation: snapshot.generation,
70
+ scope: cloneScope(scope),
71
+ trustedPresets: matched.values,
72
+ ...(snapshot.signal === undefined ? {} : { signal: snapshot.signal })
73
+ });
74
+ };
75
+ const stillCurrent = (captured) => {
76
+ const current = authoritySnapshot();
77
+ return (!disposed &&
78
+ current.generation === captured.generation &&
79
+ current.scope !== undefined &&
80
+ sameScope(current.scope, captured.scope));
81
+ };
82
+ const revalidate = async (prepared, authoritySignal) => {
83
+ if (replicaRevalidate === undefined)
84
+ return false;
85
+ const revalidationSignals = linkAbortSignals([
86
+ authoritySignal,
87
+ runtimeAbort.signal
88
+ ]);
89
+ try {
90
+ await waitForCommandOperation(replicaRevalidate(prepared.revalidation), revalidationSignals.signal);
91
+ return true;
92
+ }
93
+ catch (error) {
94
+ if (!disposed && authoritySignal?.aborted !== true) {
95
+ options.onBackgroundError?.(error);
96
+ }
97
+ throw error;
98
+ }
99
+ finally {
100
+ revalidationSignals.dispose();
101
+ }
102
+ };
103
+ const revalidateInBackground = (prepared, authority) => {
104
+ void revalidate(prepared, authority?.signal).catch(() => undefined);
105
+ };
106
+ const revalidateAndConfirmUnmanagedInBackground = (prepared, authority) => {
107
+ void revalidate(prepared, authority.signal)
108
+ .then((refreshed) => {
109
+ if (refreshed &&
110
+ stillCurrent(authority) &&
111
+ unmanagedLayers.has(prepared.commandId)) {
112
+ /*
113
+ * A generated required revalidation is the canonical base
114
+ * fence for commands without a finite observation contract.
115
+ * Retire their accepted overlay only after that fetch settles.
116
+ */
117
+ retireLayerAfterAuthoritativeRevalidation(prepared.commandId);
118
+ }
119
+ })
120
+ .catch(() => undefined);
121
+ };
122
+ const statusReader = (prepared, authority, tracker) => {
123
+ const read = async () => {
124
+ if (disposed) {
125
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_DISPOSED', {
126
+ commandId: prepared.commandId
127
+ });
128
+ }
129
+ if (statusArtifact === undefined || transport.status === undefined) {
130
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_STATUS_UNAVAILABLE', { commandId: prepared.commandId });
131
+ }
132
+ if (!stillCurrent(authority)) {
133
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_SCOPE_INVALIDATED', { commandId: prepared.commandId });
134
+ }
135
+ let result;
136
+ const statusSignals = linkAbortSignals([
137
+ authority.signal,
138
+ runtimeAbort.signal
139
+ ]);
140
+ try {
141
+ result = await waitForCommandOperation(transport.status(commandStatusRequest(statusArtifact, prepared.commandId, statusSignals.signal)), statusSignals.signal);
142
+ }
143
+ catch (error) {
144
+ if (disposed) {
145
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_DISPOSED', { commandId: prepared.commandId, cause: error });
146
+ }
147
+ throw new ReplicaCommandRuntimeError(authority.signal?.aborted
148
+ ? 'REPLICA_COMMAND_SCOPE_INVALIDATED'
149
+ : 'REPLICA_COMMAND_TRANSPORT_AMBIGUOUS', { commandId: prepared.commandId, cause: error });
150
+ }
151
+ finally {
152
+ statusSignals.dispose();
153
+ }
154
+ if (!stillCurrent(authority)) {
155
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_SCOPE_INVALIDATED', { commandId: prepared.commandId });
156
+ }
157
+ let status;
158
+ try {
159
+ status = requireStatusEnvelope(result, statusArtifact, prepared, authority, contract);
160
+ validateStatusProgression(tracker.state, tracker.metadata, status);
161
+ }
162
+ catch (error) {
163
+ revalidateInBackground(prepared, authority);
164
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_PROTOCOL_INVALID', { commandId: prepared.commandId, cause: error });
165
+ }
166
+ tracker.state = status.state;
167
+ if (status.metadata !== undefined) {
168
+ tracker.metadata = status.metadata;
169
+ if (tracker.pending !== undefined) {
170
+ tracker.pending.metadata = status.metadata;
171
+ }
172
+ }
173
+ switch (status.state) {
174
+ case 'rejected':
175
+ rejectUnmanagedLayer(prepared.commandId);
176
+ failTrackedProjection(tracker, pending, new ReplicaCommandRuntimeError('REPLICA_COMMAND_REJECTED', {
177
+ commandId: prepared.commandId,
178
+ state: status.state
179
+ }));
180
+ break;
181
+ case 'projection_failed':
182
+ case 'expired':
183
+ rejectUnmanagedLayer(prepared.commandId);
184
+ revalidateInBackground(prepared, authority);
185
+ failTrackedProjection(tracker, pending, new ReplicaCommandRuntimeError('REPLICA_COMMAND_PROJECTION_FAILED', {
186
+ commandId: prepared.commandId,
187
+ state: status.state
188
+ }));
189
+ break;
190
+ case 'accepted':
191
+ case 'accepted_pending_projection':
192
+ case 'projected': {
193
+ const metadata = status.metadata;
194
+ const remainsPending = replica.markOptimisticLayerAccepted(prepared.commandId, metadata);
195
+ if (!remainsPending) {
196
+ unmanagedLayers.delete(prepared.commandId);
197
+ if (tracker.pending !== undefined) {
198
+ settleTrackedProjection(tracker, pending);
199
+ }
200
+ }
201
+ else if (metadata.state === 'projected' ||
202
+ (metadata.state === 'accepted' &&
203
+ prepared.confirmations === undefined &&
204
+ prepared.revalidation.required)) {
205
+ /*
206
+ * Status is causal truth, but it carries no canonical
207
+ * query payload. `projected` fences asynchronous
208
+ * projection; `accepted` is terminal when the generated
209
+ * contract has no confirmations. In both cases, only a
210
+ * query started after that fence may retire optimism.
211
+ */
212
+ let refreshed = false;
213
+ try {
214
+ refreshed = await revalidate(prepared, authority.signal);
215
+ }
216
+ catch (error) {
217
+ if (disposed) {
218
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_DISPOSED', {
219
+ commandId: prepared.commandId,
220
+ cause: error
221
+ });
222
+ }
223
+ if (authority.signal?.aborted ||
224
+ !stillCurrent(authority)) {
225
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_SCOPE_INVALIDATED', {
226
+ commandId: prepared.commandId,
227
+ cause: error
228
+ });
229
+ }
230
+ // Keep the accepted layer and let the background
231
+ // status monitor retry the exact generated plan.
232
+ }
233
+ if (disposed) {
234
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_DISPOSED', { commandId: prepared.commandId });
235
+ }
236
+ if (authority.signal?.aborted ||
237
+ !stillCurrent(authority)) {
238
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_SCOPE_INVALIDATED', { commandId: prepared.commandId });
239
+ }
240
+ const controller = tracker.pending;
241
+ if (refreshed) {
242
+ if (controller !== undefined &&
243
+ !controller.settled &&
244
+ pending.get(prepared.commandId) === controller) {
245
+ retireLayerAfterAuthoritativeRevalidation(prepared.commandId);
246
+ settleTrackedProjection(tracker, pending);
247
+ }
248
+ else if (unmanagedLayers.has(prepared.commandId)) {
249
+ /*
250
+ * Recovery receipts and commands without a
251
+ * finite projection awaitable have no
252
+ * PendingProjection controller. The same
253
+ * post-status canonical fetch still owns
254
+ * retirement of their retained overlay.
255
+ */
256
+ retireLayerAfterAuthoritativeRevalidation(prepared.commandId);
257
+ }
258
+ }
259
+ }
260
+ break;
261
+ }
262
+ case 'unknown':
263
+ case 'in_progress':
264
+ break;
265
+ }
266
+ return status;
267
+ };
268
+ return () => {
269
+ if (tracker.inFlight !== undefined)
270
+ return tracker.inFlight;
271
+ let current;
272
+ current = read().finally(() => {
273
+ if (tracker.inFlight === current)
274
+ tracker.inFlight = undefined;
275
+ });
276
+ tracker.inFlight = current;
277
+ return current;
278
+ };
279
+ };
280
+ const invoke = async (artifact, input, callOptions) => {
281
+ const authority = currentAuthority();
282
+ const prepared = prepareReplicaCommandWithTrustedPresets(artifact, input, authority.trustedPresets, callOptions);
283
+ const transportRetries = normalizeRetries(callOptions.transportRetries);
284
+ const semanticChanges = preparedSemanticChanges(prepared);
285
+ const requestSignals = linkAbortSignals([
286
+ authority.signal,
287
+ callOptions.signal,
288
+ runtimeAbort.signal
289
+ ]);
290
+ const request = commandTransportRequest(prepared, requestSignals.signal);
291
+ if (request.signal?.aborted) {
292
+ requestSignals.dispose();
293
+ throw new ReplicaCommandRuntimeError(stillCurrent(authority)
294
+ ? 'REPLICA_COMMAND_ABORTED'
295
+ : 'REPLICA_COMMAND_SCOPE_INVALIDATED', { commandId: prepared.commandId, cause: request.signal.reason });
296
+ }
297
+ try {
298
+ replica.createOptimisticLayer(prepared.commandId, (writer) => applyOptimisticEffects(writer, prepared.optimistic.operations), semanticChanges);
299
+ }
300
+ catch (error) {
301
+ requestSignals.dispose();
302
+ throw error;
303
+ }
304
+ unmanagedLayers.add(prepared.commandId);
305
+ const statusTracker = {
306
+ state: undefined,
307
+ metadata: undefined,
308
+ inFlight: undefined
309
+ };
310
+ const readStatus = statusReader(prepared, authority, statusTracker);
311
+ const recovery = Object.freeze({
312
+ commandId: prepared.commandId,
313
+ status: readStatus
314
+ });
315
+ const recoveryForRetainedLayer = (revalidateOnRollback = false) => {
316
+ if (statusArtifact !== undefined)
317
+ return recovery;
318
+ /*
319
+ * A manual status-less runtime cannot make an ambiguous layer
320
+ * reachable again. Roll it back and let generated revalidation
321
+ * restore canonical truth instead of leaking optimism forever.
322
+ */
323
+ rejectUnmanagedLayer(prepared.commandId);
324
+ if (revalidateOnRollback) {
325
+ revalidateInBackground(prepared, authority);
326
+ }
327
+ return undefined;
328
+ };
329
+ let result;
330
+ let dispatchAttempted = false;
331
+ try {
332
+ result = await dispatchPrepared(transport, request, transportRetries, () => {
333
+ dispatchAttempted = true;
334
+ });
335
+ }
336
+ catch (error) {
337
+ if (disposed) {
338
+ rejectUnmanagedLayer(prepared.commandId);
339
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_DISPOSED', { commandId: prepared.commandId, cause: error });
340
+ }
341
+ if (!dispatchAttempted) {
342
+ rejectUnmanagedLayer(prepared.commandId);
343
+ throw new ReplicaCommandRuntimeError(stillCurrent(authority)
344
+ ? 'REPLICA_COMMAND_ABORTED'
345
+ : 'REPLICA_COMMAND_SCOPE_INVALIDATED', { commandId: prepared.commandId, cause: error });
346
+ }
347
+ if (!stillCurrent(authority)) {
348
+ rejectUnmanagedLayer(prepared.commandId);
349
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_SCOPE_INVALIDATED', { commandId: prepared.commandId, cause: error });
350
+ }
351
+ throw new ReplicaCommandRuntimeError(request.signal?.aborted
352
+ ? 'REPLICA_COMMAND_ABORTED'
353
+ : 'REPLICA_COMMAND_TRANSPORT_AMBIGUOUS', {
354
+ commandId: prepared.commandId,
355
+ cause: error,
356
+ recovery: recoveryForRetainedLayer(true)
357
+ });
358
+ }
359
+ finally {
360
+ requestSignals.dispose();
361
+ }
362
+ if (!stillCurrent(authority)) {
363
+ rejectUnmanagedLayer(prepared.commandId);
364
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_SCOPE_INVALIDATED', { commandId: prepared.commandId });
365
+ }
366
+ const rejection = graphqlCommandRejection(result);
367
+ if (rejection !== undefined) {
368
+ try {
369
+ const rejectionEnvelope = requireCommandRejectionEnvelope(result, prepared, authority);
370
+ matchReplicaTrustedPresetInventory(contract.trustedPresets, rejectionEnvelope.trustedPresets);
371
+ }
372
+ catch (error) {
373
+ revalidateInBackground(prepared, authority);
374
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_PROTOCOL_INVALID', {
375
+ commandId: prepared.commandId,
376
+ cause: error,
377
+ recovery: recoveryForRetainedLayer()
378
+ });
379
+ }
380
+ rejectUnmanagedLayer(prepared.commandId);
381
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_REJECTED', {
382
+ commandId: prepared.commandId,
383
+ cause: new Error(rejection.message)
384
+ });
385
+ }
386
+ let distributed;
387
+ try {
388
+ distributed = requireCommandEnvelope(result, prepared, authority);
389
+ matchReplicaTrustedPresetInventory(contract.trustedPresets, distributed.trustedPresets);
390
+ }
391
+ catch (error) {
392
+ revalidateInBackground(prepared, authority);
393
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_PROTOCOL_INVALID', {
394
+ commandId: prepared.commandId,
395
+ cause: error,
396
+ recovery: recoveryForRetainedLayer()
397
+ });
398
+ }
399
+ const metadata = distributed.command;
400
+ statusTracker.state = metadata.state;
401
+ statusTracker.metadata = metadata;
402
+ if (metadata.state === 'rejected') {
403
+ rejectUnmanagedLayer(prepared.commandId);
404
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_REJECTED', {
405
+ commandId: prepared.commandId,
406
+ state: metadata.state
407
+ });
408
+ }
409
+ if (metadata.state === 'expired') {
410
+ rejectUnmanagedLayer(prepared.commandId);
411
+ revalidateInBackground(prepared, authority);
412
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_PROJECTION_FAILED', { commandId: prepared.commandId, state: metadata.state });
413
+ }
414
+ if (metadata.state === 'unknown' || metadata.state === 'in_progress') {
415
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_OUTCOME_PENDING', {
416
+ commandId: prepared.commandId,
417
+ state: metadata.state,
418
+ recovery: recoveryForRetainedLayer(true)
419
+ });
420
+ }
421
+ if (metadata.state === 'projection_failed') {
422
+ rejectUnmanagedLayer(prepared.commandId);
423
+ revalidateInBackground(prepared, authority);
424
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_PROJECTION_FAILED', { commandId: prepared.commandId, state: metadata.state });
425
+ }
426
+ if ((result.errors?.length ?? 0) > 0) {
427
+ let retainedRecovery;
428
+ if (prepared.confirmations?.kind === 'finite') {
429
+ replica.markOptimisticLayerAccepted(prepared.commandId, metadata);
430
+ retainedRecovery = recoveryForRetainedLayer();
431
+ }
432
+ else {
433
+ rejectUnmanagedLayer(prepared.commandId);
434
+ }
435
+ revalidateInBackground(prepared, authority);
436
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_PROTOCOL_INVALID', { commandId: prepared.commandId, recovery: retainedRecovery });
437
+ }
438
+ let output;
439
+ try {
440
+ output = commandOutput(artifact, result.data, prepared.transport.mutationField);
441
+ }
442
+ catch (error) {
443
+ let retainedRecovery;
444
+ if (prepared.consistency === 'projected' ||
445
+ prepared.confirmations?.kind !== 'finite') {
446
+ rejectUnmanagedLayer(prepared.commandId);
447
+ }
448
+ else {
449
+ replica.markOptimisticLayerAccepted(prepared.commandId, metadata);
450
+ retainedRecovery = recoveryForRetainedLayer();
451
+ }
452
+ revalidateInBackground(prepared, authority);
453
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_PROTOCOL_INVALID', {
454
+ commandId: prepared.commandId,
455
+ cause: error,
456
+ recovery: retainedRecovery
457
+ });
458
+ }
459
+ let projected;
460
+ let projectionLifecycle;
461
+ if (prepared.consistency === 'projected') {
462
+ if (metadata.state !== 'projected') {
463
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_OUTCOME_PENDING', {
464
+ commandId: prepared.commandId,
465
+ state: metadata.state,
466
+ recovery: recoveryForRetainedLayer(true)
467
+ });
468
+ }
469
+ try {
470
+ confirmDirectProjection(replica, prepared, output, metadata);
471
+ unmanagedLayers.delete(prepared.commandId);
472
+ }
473
+ catch (error) {
474
+ rejectUnmanagedLayer(prepared.commandId);
475
+ revalidateInBackground(prepared, authority);
476
+ throw new ReplicaCommandRuntimeError('REPLICA_COMMAND_PROTOCOL_INVALID', { commandId: prepared.commandId, cause: error });
477
+ }
478
+ projected = Promise.resolve(Object.freeze({
479
+ commandId: prepared.commandId,
480
+ state: 'projected',
481
+ result: output,
482
+ metadata
483
+ }));
484
+ }
485
+ else {
486
+ const remainsPending = replica.markOptimisticLayerAccepted(prepared.commandId, metadata);
487
+ if (prepared.confirmations?.kind === 'finite') {
488
+ const controller = pendingProjection(authority, metadata, prepared);
489
+ statusTracker.pending = controller;
490
+ if (!remainsPending) {
491
+ unmanagedLayers.delete(prepared.commandId);
492
+ settleProjectionSuccess(controller);
493
+ }
494
+ else {
495
+ /*
496
+ * Receipt/status observations prove durable causality, not
497
+ * that canonical query data was atomically ingested. Keep
498
+ * the layer and await DistributedReplica retirement even
499
+ * when every observation is already present here.
500
+ */
501
+ pending.set(prepared.commandId, controller);
502
+ unmanagedLayers.delete(prepared.commandId);
503
+ attachAuthorityAbort(controller, () => pending.delete(prepared.commandId));
504
+ if (statusArtifact !== undefined &&
505
+ replicaRevalidate !== undefined) {
506
+ monitorPendingProjection(controller, readStatus, () => pending.get(prepared.commandId) === controller, options.onBackgroundError);
507
+ }
508
+ }
509
+ projectionLifecycle =
510
+ controller.promise;
511
+ projected = callerProjectedPromise(controller, callOptions.signal);
512
+ }
513
+ }
514
+ if (prepared.revalidation.required) {
515
+ revalidateAndConfirmUnmanagedInBackground(prepared, authority);
516
+ }
517
+ const receiptValue = {
518
+ commandId: prepared.commandId,
519
+ state: metadata.state,
520
+ result: output,
521
+ metadata,
522
+ status: readStatus,
523
+ ...(projected === undefined ? {} : { projected })
524
+ };
525
+ if (projectionLifecycle !== undefined) {
526
+ Object.defineProperty(receiptValue, replicaCommandProjectedLifecycle, {
527
+ value: projectionLifecycle,
528
+ enumerable: false,
529
+ configurable: false,
530
+ writable: false
531
+ });
532
+ }
533
+ const receipt = Object.freeze(receiptValue);
534
+ try {
535
+ await callOptions.onAccepted?.(receipt);
536
+ }
537
+ catch (error) {
538
+ options.onBackgroundError?.(error);
539
+ }
540
+ return receipt;
541
+ };
542
+ const commands = Object.create(null);
543
+ for (const { key, artifact } of inventory) {
544
+ defineBoundCommand(commands, key, artifact.input.kind === 'none'
545
+ ? (callOptions = {}) => invoke(artifact, undefined, callOptions)
546
+ : (input, callOptions = {}) => invoke(artifact, input, callOptions));
547
+ }
548
+ freezeCommandTree(commands);
549
+ const observeResult = (envelope) => {
550
+ if (disposed || pending.size === 0)
551
+ return;
552
+ let distributed;
553
+ try {
554
+ distributed = parseGraphqlResponseExtensions(envelope.extensions)
555
+ ?.distributed;
556
+ }
557
+ catch (error) {
558
+ options.onBackgroundError?.(error);
559
+ return;
560
+ }
561
+ if (distributed === undefined)
562
+ return;
563
+ for (const [commandId, controller] of pending) {
564
+ if (!stillCurrent(controller.authority)) {
565
+ settleProjectionFailure(controller, new ReplicaCommandRuntimeError('REPLICA_COMMAND_SCOPE_INVALIDATED', { commandId }));
566
+ pending.delete(commandId);
567
+ continue;
568
+ }
569
+ if (distributed.schemaHash !== controller.authority.scope.schemaHash ||
570
+ distributed.cacheScope !== controller.authority.scope.cacheScope) {
571
+ continue;
572
+ }
573
+ const command = distributed.command;
574
+ if (command?.commandId === commandId) {
575
+ try {
576
+ verifyReplicaCommandReceipt(controller.prepared, command);
577
+ }
578
+ catch (error) {
579
+ revalidateInBackground(controller.prepared, controller.authority);
580
+ settleProjectionFailure(controller, new ReplicaCommandRuntimeError('REPLICA_COMMAND_PROTOCOL_INVALID', { commandId, cause: error }));
581
+ pending.delete(commandId);
582
+ continue;
583
+ }
584
+ if (command.causationId !== controller.causationId) {
585
+ settleProjectionFailure(controller, new ReplicaCommandRuntimeError('REPLICA_COMMAND_PROTOCOL_INVALID', { commandId }));
586
+ pending.delete(commandId);
587
+ continue;
588
+ }
589
+ controller.metadata = command;
590
+ if (command.state === 'projection_failed') {
591
+ replica.rejectOptimisticLayer(commandId);
592
+ revalidateInBackground(controller.prepared, controller.authority);
593
+ settleProjectionFailure(controller, new ReplicaCommandRuntimeError('REPLICA_COMMAND_PROJECTION_FAILED', { commandId, state: command.state }));
594
+ pending.delete(commandId);
595
+ continue;
596
+ }
597
+ if (command.state === 'rejected' ||
598
+ command.state === 'expired') {
599
+ replica.rejectOptimisticLayer(commandId);
600
+ revalidateInBackground(controller.prepared, controller.authority);
601
+ settleProjectionFailure(controller, new ReplicaCommandRuntimeError(command.state === 'rejected'
602
+ ? 'REPLICA_COMMAND_REJECTED'
603
+ : 'REPLICA_COMMAND_PROJECTION_FAILED', { commandId, state: command.state }));
604
+ pending.delete(commandId);
605
+ continue;
606
+ }
607
+ }
608
+ /*
609
+ * DistributedReplica is the authority on whether this frame's
610
+ * snapshot/observations were admissible. This callback runs only
611
+ * after that exact frame committed.
612
+ */
613
+ const remainsPending = replica.markOptimisticLayerAccepted(commandId);
614
+ if (!remainsPending) {
615
+ settleProjectionSuccess(controller);
616
+ pending.delete(commandId);
617
+ }
618
+ }
619
+ };
620
+ const observationRegistration = replica[replicaResultObservation]?.(observeResult);
621
+ return Object.freeze({
622
+ commands: commands,
623
+ observeResult,
624
+ dispose() {
625
+ if (disposed)
626
+ return;
627
+ disposed = true;
628
+ runtimeAbort.abort(new ReplicaCommandRuntimeError('REPLICA_COMMAND_DISPOSED'));
629
+ observationRegistration?.dispose();
630
+ registration?.dispose();
631
+ for (const commandId of unmanagedLayers) {
632
+ replica.rejectOptimisticLayer(commandId);
633
+ }
634
+ unmanagedLayers.clear();
635
+ for (const [commandId, controller] of pending) {
636
+ replica.rejectOptimisticLayer(commandId);
637
+ settleProjectionFailure(controller, new ReplicaCommandRuntimeError('REPLICA_COMMAND_DISPOSED', {
638
+ commandId
639
+ }));
640
+ }
641
+ pending.clear();
642
+ }
643
+ });
644
+ }
@@ -0,0 +1,16 @@
1
+ import type { DistributedCommandState } from '../../protocol.js';
2
+ import type { ReplicaCommandRecoveryReceipt, ReplicaCommandRuntimeErrorCode } from './types.js';
3
+ export declare function commandRuntimeErrorMessage(code: ReplicaCommandRuntimeErrorCode): string;
4
+ /** Redacted typed failure from the integrated generated-command lifecycle. */
5
+ export declare class ReplicaCommandRuntimeError extends Error {
6
+ readonly code: ReplicaCommandRuntimeErrorCode;
7
+ readonly commandId?: string;
8
+ readonly state?: DistributedCommandState;
9
+ readonly recovery?: ReplicaCommandRecoveryReceipt;
10
+ constructor(code: ReplicaCommandRuntimeErrorCode, options?: Readonly<{
11
+ commandId?: string;
12
+ state?: DistributedCommandState;
13
+ cause?: unknown;
14
+ recovery?: ReplicaCommandRecoveryReceipt;
15
+ }>);
16
+ }