hikoutei 0.4.2 → 0.4.5

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 (172) hide show
  1. package/README.md +20 -0
  2. package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmMappedObservation.d.ts +2 -2
  3. package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmMappedObservation.js +2 -2
  4. package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPolling.js +1 -0
  5. package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPolling.js.map +1 -1
  6. package/dist/api/Hikoutei.d.ts +56 -10
  7. package/dist/api/Hikoutei.d.ts.map +1 -1
  8. package/dist/api/Hikoutei.js +84 -13
  9. package/dist/api/Hikoutei.js.map +1 -1
  10. package/dist/api/entity.d.ts +17 -1
  11. package/dist/api/entity.d.ts.map +1 -1
  12. package/dist/api/entity.js +34 -2
  13. package/dist/api/entity.js.map +1 -1
  14. package/dist/api/errors.d.ts +24 -0
  15. package/dist/api/errors.d.ts.map +1 -1
  16. package/dist/api/errors.js +24 -0
  17. package/dist/api/errors.js.map +1 -1
  18. package/dist/application/orm/api/contracts.d.ts +1 -1
  19. package/dist/application/orm/api/contracts.d.ts.map +1 -1
  20. package/dist/application/orm/persistence/flush/flushCoordinator.d.ts.map +1 -1
  21. package/dist/application/orm/persistence/flush/flushCoordinator.js +2 -0
  22. package/dist/application/orm/persistence/flush/flushCoordinator.js.map +1 -1
  23. package/dist/application/sync/inbound/autoSystemConflictResolution.d.ts.map +1 -1
  24. package/dist/application/sync/inbound/autoSystemConflictResolution.js +3 -0
  25. package/dist/application/sync/inbound/autoSystemConflictResolution.js.map +1 -1
  26. package/dist/application/sync/outbound/SheetsEffectDispatcher.d.ts +64 -0
  27. package/dist/application/sync/outbound/SheetsEffectDispatcher.d.ts.map +1 -0
  28. package/dist/application/sync/outbound/SheetsEffectDispatcher.js +440 -0
  29. package/dist/application/sync/outbound/SheetsEffectDispatcher.js.map +1 -0
  30. package/dist/application/sync/service/SyncServiceBootstrap.d.ts +3 -4
  31. package/dist/application/sync/service/SyncServiceBootstrap.d.ts.map +1 -1
  32. package/dist/application/sync/service/SyncServiceBootstrap.js +91 -6
  33. package/dist/application/sync/service/SyncServiceBootstrap.js.map +1 -1
  34. package/dist/application/sync/service/syncAutoStart.d.ts +127 -0
  35. package/dist/application/sync/service/syncAutoStart.d.ts.map +1 -0
  36. package/dist/application/sync/service/syncAutoStart.js +280 -0
  37. package/dist/application/sync/service/syncAutoStart.js.map +1 -0
  38. package/dist/application/sync/sheets/conflictProjectionRegistration.d.ts.map +1 -1
  39. package/dist/application/sync/sheets/conflictProjectionRegistration.js +1 -0
  40. package/dist/application/sync/sheets/conflictProjectionRegistration.js.map +1 -1
  41. package/dist/application/sync/telemetry/syncTiming.d.ts +20 -33
  42. package/dist/application/sync/telemetry/syncTiming.d.ts.map +1 -1
  43. package/dist/application/sync/telemetry/syncTiming.js +14 -12
  44. package/dist/application/sync/telemetry/syncTiming.js.map +1 -1
  45. package/dist/infrastructure/storage/errors.d.ts +10 -5
  46. package/dist/infrastructure/storage/errors.d.ts.map +1 -1
  47. package/dist/infrastructure/storage/errors.js +10 -7
  48. package/dist/infrastructure/storage/errors.js.map +1 -1
  49. package/dist/infrastructure/storage/index.d.ts +6 -4
  50. package/dist/infrastructure/storage/index.d.ts.map +1 -1
  51. package/dist/infrastructure/storage/index.js +3 -2
  52. package/dist/infrastructure/storage/index.js.map +1 -1
  53. package/dist/infrastructure/storage/sqlite/schema.d.ts +12 -11
  54. package/dist/infrastructure/storage/sqlite/schema.d.ts.map +1 -1
  55. package/dist/infrastructure/storage/sqlite/schema.js +17 -109
  56. package/dist/infrastructure/storage/sqlite/schema.js.map +1 -1
  57. package/dist/infrastructure/storage/state/canonical/canonicalCommit.d.ts +2 -2
  58. package/dist/infrastructure/storage/state/canonical/canonicalCommit.d.ts.map +1 -1
  59. package/dist/infrastructure/storage/state/canonical/canonicalCommit.js +2 -2
  60. package/dist/infrastructure/storage/state/canonical/canonicalCommit.js.map +1 -1
  61. package/dist/infrastructure/storage/state/mapped/mappedPersistenceContext.d.ts +1 -2
  62. package/dist/infrastructure/storage/state/mapped/mappedPersistenceContext.d.ts.map +1 -1
  63. package/dist/infrastructure/storage/state/mapped/mappedPersistenceContext.js +2 -2
  64. package/dist/infrastructure/storage/state/mapped/mappedPersistenceContext.js.map +1 -1
  65. package/dist/infrastructure/storage/state/observation/observationCanonical.d.ts +1 -1
  66. package/dist/infrastructure/storage/state/observation/observationCanonical.d.ts.map +1 -1
  67. package/dist/infrastructure/storage/state/observation/observationQuarantine.d.ts +1 -1
  68. package/dist/infrastructure/storage/state/observation/observationQuarantine.d.ts.map +1 -1
  69. package/dist/infrastructure/storage/state/observation/observationQuarantine.js +1 -1
  70. package/dist/infrastructure/storage/state/observation/observationQuarantine.js.map +1 -1
  71. package/dist/infrastructure/storage/state/observation/observationTypes.d.ts +1 -1
  72. package/dist/infrastructure/storage/state/observation/observationTypes.d.ts.map +1 -1
  73. package/dist/infrastructure/storage/state/observation/observationValidation.d.ts +1 -1
  74. package/dist/infrastructure/storage/state/observation/observationValidation.d.ts.map +1 -1
  75. package/dist/infrastructure/storage/state/observation/observationWriter.d.ts +1 -1
  76. package/dist/infrastructure/storage/state/observation/observationWriter.d.ts.map +1 -1
  77. package/dist/infrastructure/storage/state/observation/observationWriter.js +1 -2
  78. package/dist/infrastructure/storage/state/observation/observationWriter.js.map +1 -1
  79. package/dist/infrastructure/storage/state/resolution/resolutionWriter.d.ts +1 -2
  80. package/dist/infrastructure/storage/state/resolution/resolutionWriter.d.ts.map +1 -1
  81. package/dist/infrastructure/storage/state/resolution/resolutionWriter.js +1 -2
  82. package/dist/infrastructure/storage/state/resolution/resolutionWriter.js.map +1 -1
  83. package/dist/infrastructure/storage/state/resolution/resolutionWriterContracts.d.ts +1 -1
  84. package/dist/infrastructure/storage/state/resolution/resolutionWriterContracts.d.ts.map +1 -1
  85. package/dist/infrastructure/storage/state/resolution/resolutionWriterHelpers.d.ts +1 -1
  86. package/dist/infrastructure/storage/state/resolution/resolutionWriterHelpers.d.ts.map +1 -1
  87. package/dist/infrastructure/storage/state/resolution/resolutionWriterHelpers.js +1 -1
  88. package/dist/infrastructure/storage/state/resolution/resolutionWriterHelpers.js.map +1 -1
  89. package/dist/infrastructure/storage/state/resolution/resolutionWriterSql.d.ts +1 -1
  90. package/dist/infrastructure/storage/state/resolution/resolutionWriterSql.d.ts.map +1 -1
  91. package/dist/infrastructure/storage/state/resolution/resolutionWriterSql.js +2 -2
  92. package/dist/infrastructure/storage/state/resolution/resolutionWriterSql.js.map +1 -1
  93. package/dist/infrastructure/storage/sync/shared/spreadsheetAuthority.d.ts +1 -1
  94. package/dist/infrastructure/storage/sync/shared/spreadsheetAuthority.d.ts.map +1 -1
  95. package/dist/infrastructure/storage/sync/shared/spreadsheetAuthority.js +1 -1
  96. package/dist/infrastructure/storage/sync/shared/spreadsheetAuthority.js.map +1 -1
  97. package/dist/infrastructure/storage/sync/shared/syncRegistry.d.ts +1 -1
  98. package/dist/infrastructure/storage/sync/shared/syncRegistry.js +1 -1
  99. package/package.json +13 -7
  100. package/dist/application/sync/outbound/effects/AdaptiveEffectBatchController.d.ts +0 -66
  101. package/dist/application/sync/outbound/effects/AdaptiveEffectBatchController.d.ts.map +0 -1
  102. package/dist/application/sync/outbound/effects/AdaptiveEffectBatchController.js +0 -123
  103. package/dist/application/sync/outbound/effects/AdaptiveEffectBatchController.js.map +0 -1
  104. package/dist/application/sync/outbound/effects/SyncEffectSupervisor.d.ts +0 -111
  105. package/dist/application/sync/outbound/effects/SyncEffectSupervisor.d.ts.map +0 -1
  106. package/dist/application/sync/outbound/effects/SyncEffectSupervisor.js +0 -369
  107. package/dist/application/sync/outbound/effects/SyncEffectSupervisor.js.map +0 -1
  108. package/dist/application/sync/outbound/effects/SyncEffectWorker.d.ts +0 -127
  109. package/dist/application/sync/outbound/effects/SyncEffectWorker.d.ts.map +0 -1
  110. package/dist/application/sync/outbound/effects/SyncEffectWorker.js +0 -552
  111. package/dist/application/sync/outbound/effects/SyncEffectWorker.js.map +0 -1
  112. package/dist/application/sync/outbound/effects/SyncEffectWorkerConstants.d.ts +0 -85
  113. package/dist/application/sync/outbound/effects/SyncEffectWorkerConstants.d.ts.map +0 -1
  114. package/dist/application/sync/outbound/effects/SyncEffectWorkerConstants.js +0 -74
  115. package/dist/application/sync/outbound/effects/SyncEffectWorkerConstants.js.map +0 -1
  116. package/dist/application/sync/outbound/effects/SyncEffectWorkerDispatch.d.ts +0 -31
  117. package/dist/application/sync/outbound/effects/SyncEffectWorkerDispatch.d.ts.map +0 -1
  118. package/dist/application/sync/outbound/effects/SyncEffectWorkerDispatch.js +0 -222
  119. package/dist/application/sync/outbound/effects/SyncEffectWorkerDispatch.js.map +0 -1
  120. package/dist/application/sync/outbound/effects/SyncEffectWorkerHelpers.d.ts +0 -14
  121. package/dist/application/sync/outbound/effects/SyncEffectWorkerHelpers.d.ts.map +0 -1
  122. package/dist/application/sync/outbound/effects/SyncEffectWorkerHelpers.js +0 -25
  123. package/dist/application/sync/outbound/effects/SyncEffectWorkerHelpers.js.map +0 -1
  124. package/dist/application/sync/outbound/effects/SyncEffectWorkerRouting.d.ts +0 -61
  125. package/dist/application/sync/outbound/effects/SyncEffectWorkerRouting.d.ts.map +0 -1
  126. package/dist/application/sync/outbound/effects/SyncEffectWorkerRouting.js +0 -296
  127. package/dist/application/sync/outbound/effects/SyncEffectWorkerRouting.js.map +0 -1
  128. package/dist/application/sync/outbound/effects/SyncEffectWorkerTiming.d.ts +0 -17
  129. package/dist/application/sync/outbound/effects/SyncEffectWorkerTiming.d.ts.map +0 -1
  130. package/dist/application/sync/outbound/effects/SyncEffectWorkerTiming.js +0 -80
  131. package/dist/application/sync/outbound/effects/SyncEffectWorkerTiming.js.map +0 -1
  132. package/dist/application/sync/outbound/effects/SyncEffectWorkerTransitions.d.ts +0 -13
  133. package/dist/application/sync/outbound/effects/SyncEffectWorkerTransitions.d.ts.map +0 -1
  134. package/dist/application/sync/outbound/effects/SyncEffectWorkerTransitions.js +0 -248
  135. package/dist/application/sync/outbound/effects/SyncEffectWorkerTransitions.js.map +0 -1
  136. package/dist/infrastructure/storage/sync/outbound/effectOutbox.d.ts +0 -141
  137. package/dist/infrastructure/storage/sync/outbound/effectOutbox.d.ts.map +0 -1
  138. package/dist/infrastructure/storage/sync/outbound/effectOutbox.js +0 -318
  139. package/dist/infrastructure/storage/sync/outbound/effectOutbox.js.map +0 -1
  140. package/dist/infrastructure/storage/sync/outbound/effectOutboxContracts.d.ts +0 -143
  141. package/dist/infrastructure/storage/sync/outbound/effectOutboxContracts.d.ts.map +0 -1
  142. package/dist/infrastructure/storage/sync/outbound/effectOutboxContracts.js +0 -16
  143. package/dist/infrastructure/storage/sync/outbound/effectOutboxContracts.js.map +0 -1
  144. package/dist/infrastructure/storage/sync/outbound/effectOutboxSql.d.ts +0 -33
  145. package/dist/infrastructure/storage/sync/outbound/effectOutboxSql.d.ts.map +0 -1
  146. package/dist/infrastructure/storage/sync/outbound/effectOutboxSql.js +0 -259
  147. package/dist/infrastructure/storage/sync/outbound/effectOutboxSql.js.map +0 -1
  148. package/dist/infrastructure/storage/sync/outbound/effectOutboxSupport.d.ts +0 -27
  149. package/dist/infrastructure/storage/sync/outbound/effectOutboxSupport.d.ts.map +0 -1
  150. package/dist/infrastructure/storage/sync/outbound/effectOutboxSupport.js +0 -316
  151. package/dist/infrastructure/storage/sync/outbound/effectOutboxSupport.js.map +0 -1
  152. package/dist/infrastructure/storage/sync/shared/writerLease.d.ts +0 -76
  153. package/dist/infrastructure/storage/sync/shared/writerLease.d.ts.map +0 -1
  154. package/dist/infrastructure/storage/sync/shared/writerLease.js +0 -189
  155. package/dist/infrastructure/storage/sync/shared/writerLease.js.map +0 -1
  156. package/docs/advanced-sheets-gateway-concurrency-problem.md +0 -434
  157. package/docs/architecture.md +0 -224
  158. package/docs/ci.md +0 -293
  159. package/docs/code-guidelines.md +0 -248
  160. package/docs/development.md +0 -74
  161. package/docs/gateway-removal-inventory.md +0 -147
  162. package/docs/git-workflow.md +0 -224
  163. package/docs/google-sheets-sync-scaling-strategy.md +0 -459
  164. package/docs/mikro-orm-adapter-spike.md +0 -89
  165. package/docs/quick-start.md +0 -137
  166. package/docs/sql-layer-plan.md +0 -59
  167. package/docs/sync-bulk-write-benchmark.md +0 -2117
  168. package/docs/sync-observability.md +0 -100
  169. package/docs/task-queue-write-model.md +0 -640
  170. package/docs/typed-sheets-mvp-scope-2026-06-29.md +0 -490
  171. package/docs/typed-sheets-plan.md +0 -417
  172. package/docs/write-and-synchronization-flow.md +0 -179
@@ -0,0 +1,440 @@
1
+ /**
2
+ * Sheets dispatcher: the host implementation of the package worker's
3
+ * `Dispatcher` boundary over the Google Sheets sync provider.
4
+ *
5
+ * The worker owns selection, claiming, grouping, lease refresh, transitions,
6
+ * and recovery. This dispatcher owns every payload-derived decision: route
7
+ * keys, fast-append candidacy, payload validation, the User_Input candidate
8
+ * gate (via the active-candidate guard SQL), remote evidence validation
9
+ * against effect targets, and transport-outcome classification.
10
+ */
11
+ import { NON_NEGATIVE_SAFE_INTEGER_MINIMUM, } from "../../../domain/index.js";
12
+ import { DispatchTransportError, } from "@hikoutei/outbox";
13
+ import { CONFLICT_STATUSES, EFFECT_KINDS, EFFECT_TARGET_KINDS, } from "../../../domain/model/constants.js";
14
+ import { absentValue, presentValue, } from "../../../shared/state/index.js";
15
+ import { stableHash } from "../../../shared/encoding/stableEncode.js";
16
+ import { hasActiveUserInputCandidateWithSql, } from "../../../infrastructure/storage/sync/outbound/effectWorkerSql.js";
17
+ import { ensureSpreadsheetAuthorityWithAdapter, } from "../../../infrastructure/storage/sync/shared/spreadsheetAuthority.js";
18
+ import { parseSyncProjectionEffectPayload, } from "../sheets/syncSheets.js";
19
+ import { SYNC_EFFECT_RESULT_STATUSES, SYNC_FAST_APPEND_STATUSES, SYNC_POSTCONDITION_DISPOSITIONS, SYNC_POSTCONDITION_MODES, SYNC_POSTCONDITION_STATUSES, SYNC_PROJECTIONS, } from "../sheets/constants.js";
20
+ import { classifyTransportOutcome, TRANSPORT_OUTCOME_KINDS, } from "../sheets/transportOutcome.js";
21
+ import { fromSqlNullable } from "../../../infrastructure/storage/sqlite/sqlState.js";
22
+ /**
23
+ * Builds the stable grouping key shared by all provider operations on one
24
+ * route. The route includes payload-derived tab/range/schema fields, so one
25
+ * dispatched group always maps to exactly one provider request.
26
+ */
27
+ export function sheetsRouteKeyFor(effect) {
28
+ const payload = parseSyncProjectionEffectPayload(effect.payload_json);
29
+ return [
30
+ effect.physical_sheet_id,
31
+ payload.sheetName,
32
+ payload.registeredRange,
33
+ effect.projection,
34
+ payload.schemaVersion,
35
+ ].join("\u0000");
36
+ }
37
+ /** Validates the opaque payload of one pending effect for the worker. */
38
+ export function sheetsPayloadValidationError(effect) {
39
+ try {
40
+ toProviderEffect(effect);
41
+ return absentValue();
42
+ }
43
+ catch (error) {
44
+ return presentValue(safeProviderErrorMessage(error));
45
+ }
46
+ }
47
+ /**
48
+ * Classifies one pending effect as an append-only fast candidate.
49
+ *
50
+ * A fast append requires an empty visible baseline (`createIfMissing` with
51
+ * revision 0 and an empty visible hash) plus a new System_State entity row or
52
+ * a new Sync_Conflicts resolution row.
53
+ */
54
+ export function isSheetsFastAppendCandidate(effect) {
55
+ try {
56
+ return isFastAppendEffect(toProviderEffect(effect));
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
62
+ /** Classifies one converted provider effect as an append-only fast candidate. */
63
+ export function isFastAppendEffect(effect) {
64
+ const emptyVisibleBaseline = effect.payload.createIfMissing &&
65
+ effect.expectedVisibleRevision === NON_NEGATIVE_SAFE_INTEGER_MINIMUM &&
66
+ effect.expectedVisibleHash === "";
67
+ if (!emptyVisibleBaseline)
68
+ return false;
69
+ return (effect.effectKind === EFFECT_KINDS.SYSTEM_PROJECTION &&
70
+ effect.projection === SYNC_PROJECTIONS.SYSTEM_STATE &&
71
+ effect.targetKind === EFFECT_TARGET_KINDS.ENTITY) || (effect.effectKind === EFFECT_KINDS.RESOLUTION_PROJECTION &&
72
+ effect.projection === SYNC_PROJECTIONS.SYNC_CONFLICTS &&
73
+ effect.targetKind === EFFECT_TARGET_KINDS.CONFLICT);
74
+ }
75
+ /**
76
+ * Dispatcher over a `SyncEffectWorkerProvider` and the host storage adapter.
77
+ *
78
+ * The storage adapter backs the candidate gate and the dispatch authority
79
+ * claim; both are optional host extensions the worker may skip.
80
+ */
81
+ export class SheetsEffectDispatcher {
82
+ provider;
83
+ storage;
84
+ constructor(options) {
85
+ this.provider = options.provider;
86
+ this.storage = options.storage;
87
+ }
88
+ routeKeyFor(effect) {
89
+ return sheetsRouteKeyFor(effect);
90
+ }
91
+ isFastAppendCandidate(effect) {
92
+ return isSheetsFastAppendCandidate(effect);
93
+ }
94
+ payloadValidationError(effect) {
95
+ return sheetsPayloadValidationError(effect);
96
+ }
97
+ /** Dispatches append-only rows through the idempotent provider batch operation. */
98
+ async fastAppend(request) {
99
+ const providerRequest = buildFastAppendRowsRequest(request.effects);
100
+ let response;
101
+ try {
102
+ response = await this.provider.fastAppendRows(providerRequest);
103
+ }
104
+ catch (error) {
105
+ throw toDispatchTransportError(error);
106
+ }
107
+ const byEffect = new Map(request.effects.map((effect) => [effect.effect_id, effect]));
108
+ const results = [];
109
+ for (const result of response.results) {
110
+ const pending = byEffect.get(result.effectId);
111
+ if (pending === undefined)
112
+ continue;
113
+ const effect = toProviderEffect(pending);
114
+ const evidence = receiptEvidence(result);
115
+ if (evidence === undefined) {
116
+ results.push({
117
+ effectId: result.effectId,
118
+ status: "delivery_uncertain",
119
+ reason: presentValue("Fast append did not return receipt-backed visible evidence."),
120
+ });
121
+ continue;
122
+ }
123
+ if (evidence.visibleHash !== effect.payload.targetVisibleHash) {
124
+ // The append receipt did not match the effect target: the remote row
125
+ // does not carry the acknowledged state, so the worker closes the
126
+ // effect as failed rather than trusting the receipt.
127
+ results.push({ effectId: result.effectId, status: "applied_target_mismatch" });
128
+ continue;
129
+ }
130
+ results.push({
131
+ effectId: result.effectId,
132
+ status: "applied",
133
+ visibleRevision: evidence.visibleRevision,
134
+ visibleHash: evidence.visibleHash,
135
+ fieldHashes: fieldHashesFor(effect),
136
+ });
137
+ }
138
+ return { results, hasMore: response.hasMore, ...(response.timing === undefined ? {} : { timing: response.timing }) };
139
+ }
140
+ /** Dispatches one regular effect batch through the provider. */
141
+ async apply(request) {
142
+ const effects = request.effects.map((pending) => toProviderEffect(pending));
143
+ const providerRequest = {
144
+ physicalSheetId: effects[0].physicalSheetId,
145
+ sheetName: effects[0].payload.sheetName,
146
+ registeredRange: effects[0].payload.registeredRange,
147
+ projection: effects[0].projection,
148
+ schemaVersion: effects[0].payload.schemaVersion,
149
+ postconditionMode: SYNC_POSTCONDITION_MODES.DEFERRED,
150
+ effects,
151
+ };
152
+ let response;
153
+ try {
154
+ response = await this.provider.applyEffects(providerRequest);
155
+ }
156
+ catch (error) {
157
+ throw toDispatchTransportError(error);
158
+ }
159
+ const byEffect = new Map(effects.map((effect) => [effect.effectId, effect]));
160
+ const results = [];
161
+ for (const result of response.results) {
162
+ results.push(translateApplyResult(result, byEffect.get(result.effectId)));
163
+ }
164
+ return { results, hasMore: response.hasMore, ...(response.timing === undefined ? {} : { timing: response.timing }) };
165
+ }
166
+ /** Reads back response-loss effects so the worker can settle them safely. */
167
+ async readPostconditions(request) {
168
+ const effects = request.effects.map((pending) => toProviderEffect(pending));
169
+ const providerRequest = {
170
+ physicalSheetId: effects[0].physicalSheetId,
171
+ sheetName: effects[0].payload.sheetName,
172
+ registeredRange: effects[0].payload.registeredRange,
173
+ projection: effects[0].projection,
174
+ schemaVersion: effects[0].payload.schemaVersion,
175
+ effects,
176
+ };
177
+ let response;
178
+ try {
179
+ response = await this.provider.readEffectPostconditions(providerRequest);
180
+ }
181
+ catch (error) {
182
+ throw toDispatchTransportError(error);
183
+ }
184
+ const byEffect = new Map(effects.map((effect) => [effect.effectId, effect]));
185
+ const results = response.map((result) => ({
186
+ effectId: result.effectId,
187
+ payloadHash: result.payloadHash,
188
+ postcondition: translatePostcondition(result.postcondition, byEffect.get(result.effectId)),
189
+ }));
190
+ return { results };
191
+ }
192
+ /**
193
+ * Preserves active User_Input candidates before remote dispatch: reconcile
194
+ * or delete effects that would overwrite a candidate-owned field are
195
+ * blocked locally before any remote compare-and-set runs.
196
+ */
197
+ async gate(items) {
198
+ const allowed = [];
199
+ const blocked = [];
200
+ for (const item of items) {
201
+ let effect;
202
+ try {
203
+ effect = toProviderEffect(item.pending);
204
+ }
205
+ catch {
206
+ allowed.push(item.pending.effect_id);
207
+ continue;
208
+ }
209
+ if (!isCandidateProtectingUserInputEffect(effect)) {
210
+ allowed.push(item.pending.effect_id);
211
+ continue;
212
+ }
213
+ const rowBinding = effect.rowBindingId;
214
+ if (rowBinding.kind !== "present") {
215
+ allowed.push(item.pending.effect_id);
216
+ continue;
217
+ }
218
+ const fieldNames = Object.keys(effect.payload.fields);
219
+ const blockedByCandidate = await this.storage.read(({ sql }) => hasActiveUserInputCandidateWithSql(sql, {
220
+ physicalSheetId: effect.physicalSheetId,
221
+ projection: SYNC_PROJECTIONS.USER_INPUT,
222
+ rowBindingId: rowBinding.value,
223
+ fieldNames,
224
+ openConflictStatus: CONFLICT_STATUSES.OPEN,
225
+ rebasedConflictStatus: CONFLICT_STATUSES.NEEDS_REBASE,
226
+ }));
227
+ if (blockedByCandidate)
228
+ blocked.push(item.pending.effect_id);
229
+ else
230
+ allowed.push(item.pending.effect_id);
231
+ }
232
+ return { allowed, blocked };
233
+ }
234
+ /** Refreshes the dispatch authority claim for one physical sheet. */
235
+ async ensureAuthority(fence, physicalSheetId, ownerId) {
236
+ const result = await ensureSpreadsheetAuthorityWithAdapter(this.storage, {
237
+ ...fence,
238
+ physicalSheetId,
239
+ ownerId,
240
+ });
241
+ return result.kind === "claimed";
242
+ }
243
+ }
244
+ function buildFastAppendRowsRequest(effects) {
245
+ const converted = effects.map((pending) => toProviderEffect(pending));
246
+ const first = converted[0];
247
+ return {
248
+ physicalSheetId: first.physicalSheetId,
249
+ sheetName: first.payload.sheetName,
250
+ registeredRange: first.payload.registeredRange,
251
+ projection: first.projection,
252
+ schemaVersion: first.payload.schemaVersion,
253
+ rows: converted.map((effect) => ({
254
+ effectId: effect.effectId,
255
+ payloadHash: effect.payloadHash,
256
+ anchor: effect.payload.targetAnchor,
257
+ fields: effect.payload.fields,
258
+ })),
259
+ };
260
+ }
261
+ function translateApplyResult(result, effect) {
262
+ const base = {
263
+ effectId: result.effectId,
264
+ payloadHash: result.payloadHash,
265
+ };
266
+ if ((result.status === SYNC_EFFECT_RESULT_STATUSES.APPLIED ||
267
+ result.status === SYNC_EFFECT_RESULT_STATUSES.ALREADY_APPLIED)) {
268
+ const evidence = verifiedSuccessEvidence(result, effect);
269
+ if (evidence !== undefined) {
270
+ return {
271
+ ...base,
272
+ status: result.status,
273
+ visibleRevision: evidence.visibleRevision,
274
+ visibleHash: evidence.visibleHash,
275
+ fieldHashes: evidence.fieldHashes,
276
+ };
277
+ }
278
+ // A success label without the acknowledged target state is not enough to
279
+ // close a durable effect; the worker treats it like a lost response and
280
+ // reads back first.
281
+ return {
282
+ ...base,
283
+ status: "delivery_uncertain",
284
+ reason: presentValue("Provider applied result did not include receipt-backed visible evidence."),
285
+ };
286
+ }
287
+ if (result.status === SYNC_EFFECT_RESULT_STATUSES.SUPERSEDED) {
288
+ return { ...base, status: "superseded", reason: result.reason };
289
+ }
290
+ if (result.status === SYNC_EFFECT_RESULT_STATUSES.GUARD_MISMATCH) {
291
+ return { ...base, status: "guard_mismatch", reason: result.reason };
292
+ }
293
+ if (result.status === SYNC_EFFECT_RESULT_STATUSES.REPAIR_REOBSERVE) {
294
+ return { ...base, status: "repair_reobserve", reason: result.reason };
295
+ }
296
+ return {
297
+ ...base,
298
+ status: result.status === SYNC_EFFECT_RESULT_STATUSES.SCHEMA_ERROR
299
+ ? "schema_error"
300
+ : "retryable_error",
301
+ reason: result.reason,
302
+ };
303
+ }
304
+ function translatePostcondition(postcondition, effect) {
305
+ if (postcondition.disposition === SYNC_POSTCONDITION_DISPOSITIONS.APPLIED &&
306
+ postcondition.visibleRevision.kind === "present" &&
307
+ postcondition.visibleHash.kind === "present" &&
308
+ effect !== undefined &&
309
+ postcondition.visibleHash.value === effect.payload.targetVisibleHash) {
310
+ return {
311
+ disposition: "applied",
312
+ visibleRevision: postcondition.visibleRevision.value,
313
+ visibleHash: postcondition.visibleHash.value,
314
+ fieldHashes: fieldHashesFor(effect),
315
+ };
316
+ }
317
+ if (postcondition.disposition === SYNC_POSTCONDITION_DISPOSITIONS.APPLIED) {
318
+ if (effect !== undefined &&
319
+ postcondition.visibleRevision.kind === "present" &&
320
+ postcondition.visibleHash.kind === "present") {
321
+ return { disposition: "applied_target_mismatch" };
322
+ }
323
+ return { disposition: "applied_without_visible_state" };
324
+ }
325
+ if (postcondition.disposition === SYNC_POSTCONDITION_DISPOSITIONS.CHANGED) {
326
+ return {
327
+ disposition: "changed",
328
+ ...(postcondition.reason === undefined ? {} : { reason: postcondition.reason }),
329
+ };
330
+ }
331
+ if (postcondition.disposition === SYNC_POSTCONDITION_DISPOSITIONS.UNAPPLIED) {
332
+ return {
333
+ disposition: "unapplied",
334
+ ...(postcondition.reason === undefined ? {} : { reason: postcondition.reason }),
335
+ };
336
+ }
337
+ return {
338
+ disposition: "unavailable",
339
+ ...(postcondition.reason === undefined ? {} : { reason: postcondition.reason }),
340
+ };
341
+ }
342
+ /**
343
+ * Returns verified success evidence only when the provider's success label
344
+ * carries the acknowledged target state: a verified/acknowledged postcondition
345
+ * plus a visible revision and hash that match the effect target.
346
+ */
347
+ function verifiedSuccessEvidence(result, effect) {
348
+ if (result.postcondition !== SYNC_POSTCONDITION_STATUSES.VERIFIED &&
349
+ result.postcondition !== SYNC_POSTCONDITION_STATUSES.ACKNOWLEDGED) {
350
+ return undefined;
351
+ }
352
+ if (result.visibleRevision.kind !== "present" ||
353
+ result.visibleHash.kind !== "present") {
354
+ return undefined;
355
+ }
356
+ if (effect === undefined ||
357
+ result.visibleHash.value !== effect.payload.targetVisibleHash) {
358
+ return undefined;
359
+ }
360
+ return {
361
+ visibleRevision: result.visibleRevision.value,
362
+ visibleHash: result.visibleHash.value,
363
+ fieldHashes: fieldHashesFor(effect),
364
+ };
365
+ }
366
+ function receiptEvidence(result) {
367
+ if (result.status !== SYNC_FAST_APPEND_STATUSES.APPLIED ||
368
+ typeof result.visibleRevision !== "number" ||
369
+ !Number.isSafeInteger(result.visibleRevision) ||
370
+ result.visibleRevision < 1 ||
371
+ typeof result.visibleHash !== "string" ||
372
+ result.visibleHash.length === 0) {
373
+ return undefined;
374
+ }
375
+ return { visibleRevision: result.visibleRevision, visibleHash: result.visibleHash };
376
+ }
377
+ function fieldHashesFor(effect) {
378
+ return Object.fromEntries(Object.entries(effect.payload.fields)
379
+ .map(([fieldName, value]) => [fieldName, stableHash(value)]));
380
+ }
381
+ function isCandidateProtectingUserInputEffect(effect) {
382
+ return effect.effectKind === EFFECT_KINDS.CANDIDATE_RECONCILE ||
383
+ effect.effectKind === EFFECT_KINDS.USER_INPUT_DELETE;
384
+ }
385
+ /** Validates and converts one durable outbox row into a provider effect. */
386
+ function toProviderEffect(effect) {
387
+ if (!isSyncEffectKind(effect.effect_kind)) {
388
+ throw new Error("unsupported sync effect kind: " + effect.effect_kind);
389
+ }
390
+ if (!isSyncProjection(effect.projection)) {
391
+ throw new Error("unsupported sync projection: " + effect.projection);
392
+ }
393
+ if (!isEffectTargetKind(effect.target_kind)) {
394
+ throw new Error("unsupported sync effect target kind: " + effect.target_kind);
395
+ }
396
+ return {
397
+ effectId: effect.effect_id,
398
+ payloadHash: effect.payload_hash,
399
+ effectKind: effect.effect_kind,
400
+ physicalSheetId: effect.physical_sheet_id,
401
+ projection: effect.projection,
402
+ targetKind: effect.target_kind,
403
+ targetId: effect.target_id,
404
+ rowBindingId: fromSqlNullable(effect.row_binding_id),
405
+ conflictId: fromSqlNullable(effect.conflict_id),
406
+ expectedVisibleRevision: effect.expected_visible_revision,
407
+ expectedVisibleHash: effect.expected_visible_hash,
408
+ repairGuardHash: fromSqlNullable(effect.repair_guard_hash),
409
+ payload: parseSyncProjectionEffectPayload(effect.payload_json),
410
+ };
411
+ }
412
+ function isSyncEffectKind(value) {
413
+ return value === EFFECT_KINDS.SYSTEM_PROJECTION ||
414
+ value === EFFECT_KINDS.CANDIDATE_RECONCILE ||
415
+ value === EFFECT_KINDS.SYSTEM_REPAIR ||
416
+ value === EFFECT_KINDS.RESOLUTION_PROJECTION ||
417
+ value === EFFECT_KINDS.RESOLUTION_DELETE ||
418
+ value === EFFECT_KINDS.USER_INPUT_DELETE;
419
+ }
420
+ function isSyncProjection(value) {
421
+ return value === SYNC_PROJECTIONS.USER_INPUT ||
422
+ value === SYNC_PROJECTIONS.SYSTEM_STATE ||
423
+ value === SYNC_PROJECTIONS.SYNC_CONFLICTS;
424
+ }
425
+ function isEffectTargetKind(value) {
426
+ return value === EFFECT_TARGET_KINDS.ENTITY ||
427
+ value === EFFECT_TARGET_KINDS.ROW_BINDING ||
428
+ value === EFFECT_TARGET_KINDS.PROJECTION_ROW ||
429
+ value === EFFECT_TARGET_KINDS.CONFLICT;
430
+ }
431
+ function toDispatchTransportError(error) {
432
+ const outcome = classifyTransportOutcome(error);
433
+ return new DispatchTransportError(outcome.kind === TRANSPORT_OUTCOME_KINDS.EXPLICIT_REMOTE_FAILURE
434
+ ? "explicit_remote_failure"
435
+ : "delivery_uncertain", outcome.message);
436
+ }
437
+ function safeProviderErrorMessage(error) {
438
+ return error instanceof Error ? error.message.slice(0, 500) : "unknown sync provider failure";
439
+ }
440
+ //# sourceMappingURL=SheetsEffectDispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SheetsEffectDispatcher.js","sourceRoot":"","sources":["../../../../src/application/sync/outbound/SheetsEffectDispatcher.ts"],"names":[],"mappings":"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"}
@@ -18,8 +18,7 @@ import type { SyncSheetsProvisioner, RegisteredSyncProjectionDefinition } from "
18
18
  import type { SyncSheetsProvider, SyncSheetsTableReader } from "../sheets/syncSheets.js";
19
19
  import type { CoordinatorLaneEvent } from "../sheets/mutationCoordinator/laneTelemetry.js";
20
20
  import { type GoogleSheetsApiProviderOptions } from "../../../adapter/sheets/providers/google-sheets-api/index.js";
21
- import { type SyncEffectWorkerSupervisor } from "../outbound/effects/SyncEffectSupervisor.js";
22
- import type { SyncEffectWorkerReport } from "../outbound/effects/SyncEffectWorker.js";
21
+ import { type EffectWorkerSupervisor, type WorkerReport } from "@hikoutei/outbox";
23
22
  import { type MappedUserInputPollingReport } from "../../../adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPolling.js";
24
23
  import { SyncPollingSupervisor } from "./SyncPollingSupervisor.js";
25
24
  import type { SyncTimingSink } from "../telemetry/syncTiming.js";
@@ -53,7 +52,7 @@ export interface InternalSyncServiceOptions {
53
52
  readonly effectLeaseDurationMs?: number;
54
53
  readonly effectIdleIntervalMs?: number;
55
54
  readonly onTiming?: SyncTimingSink;
56
- readonly onEffectReport?: (report: SyncEffectWorkerReport) => void;
55
+ readonly onEffectReport?: (report: WorkerReport) => void;
57
56
  readonly onEffectError?: (error: unknown) => void;
58
57
  readonly pollingIntervalMs?: number;
59
58
  /** Maximum interval between metadata-preserving safety scans. */
@@ -75,7 +74,7 @@ export interface InternalSyncService {
75
74
  readonly projectionDefinitions: readonly RegisteredSyncProjectionDefinition[];
76
75
  /** Retries durable OPEN system-wins commands after predecessors settle. */
77
76
  readonly retryDeferredConflicts: () => Promise<number>;
78
- readonly effectSupervisor: SyncEffectWorkerSupervisor;
77
+ readonly effectSupervisor: EffectWorkerSupervisor;
79
78
  readonly pollingSupervisor: SyncPollingSupervisor<MappedUserInputPollingReport>;
80
79
  stop(): Promise<void>;
81
80
  close(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"SyncServiceBootstrap.d.ts","sourceRoot":"","sources":["../../../../src/application/sync/service/SyncServiceBootstrap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SyncServiceBootstrap.d.ts","sourceRoot":"","sources":["../../../../src/application/sync/service/SyncServiceBootstrap.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,8 @@
14
14
  import { randomUUID } from "node:crypto";
15
15
  import { createInternalHikoutei, } from "../../../api/Hikoutei.js";
16
16
  import { getEntityDescriptor, HikouteiEntity as HikouteiEntityToken } from "../../../api/entity.js";
17
+ import { readWriterLeaseWithAdapter, releaseWriterLeaseWithAdapter, } from "../../../infrastructure/storage/index.js";
18
+ import { DEFAULT_MAPPED_WRITER_ROLE, } from "../../orm/persistence/support/contracts.js";
17
19
  import { initializeMappedTypedSheetsRuntime, } from "../../../adapter/persistence/providers/mikro-orm/engine/MikroOrmMappedTypedSheets.js";
18
20
  import { createMikroOrmScalarRuntime, } from "../../../adapter/persistence/providers/mikro-orm/engine/MikroOrmScalarRuntime.js";
19
21
  import { MikroOrmScalarPersistenceProvider, } from "../../../adapter/persistence/providers/mikro-orm/api/MikroOrmScalarPersistenceProvider.js";
@@ -24,11 +26,11 @@ import { autoResolveExistingMappedConflictsWithAdapter, retryOpenMappedConflicts
24
26
  import { CoordinatedSheetsProvider, } from "../sheets/mutationCoordinator/CoordinatedSheetsProvider.js";
25
27
  import { GoogleSheetsApiSyncProvider, } from "../../../adapter/sheets/providers/google-sheets-api/index.js";
26
28
  import { GOOGLE_SHEETS_API_DEFAULTS } from "../../../adapter/sheets/providers/google-sheets-api/constants.js";
27
- import { createSyncEffectWorkerSupervisor, } from "../outbound/effects/SyncEffectSupervisor.js";
29
+ import { createEffectWorkerSupervisor, APPEND_DISPATCH_THROTTLE_INTERVAL_MS, DEFAULT_EFFECT_LEASE_DURATION_MS, DEFAULT_WORKER_ROLE, DEFAULT_WRITER_LEASE_DURATION_MS, EFFECT_LEASE_PROVIDER_HEADROOM_MS, FAST_APPEND_BATCH_CANDIDATE_LIMIT, LOOKUP_RESULT_KINDS, safeErrorMessage, } from "@hikoutei/outbox";
30
+ import { SheetsEffectDispatcher } from "../outbound/SheetsEffectDispatcher.js";
28
31
  import { MAPPED_USER_INPUT_POLL_MODES, pollMappedUserInputWithMikroOrm, } from "../../../adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPolling.js";
29
32
  import { SyncPollingSupervisor } from "./SyncPollingSupervisor.js";
30
33
  import { SYNC_SERVICE_ERROR_CODES, SyncServiceError, } from "./errors.js";
31
- import { APPEND_DISPATCH_THROTTLE_INTERVAL_MS, DEFAULT_EFFECT_LEASE_DURATION_MS, DEFAULT_WRITER_LEASE_DURATION_MS, EFFECT_LEASE_PROVIDER_HEADROOM_MS, FAST_APPEND_BATCH_CANDIDATE_LIMIT, } from "../outbound/effects/SyncEffectWorkerConstants.js";
32
34
  const DEFAULT_POLLING_FULL_SCAN_INTERVAL_MS = 60_000;
33
35
  /**
34
36
  * Opens, provisions, and starts one internal sync service.
@@ -41,6 +43,11 @@ export async function createInternalSyncService(options) {
41
43
  validateServiceOptions(options, descriptors);
42
44
  const generated = createMikroOrmScalarRuntime(options.entities, options.projections);
43
45
  const writer = createWriterOptions(options);
46
+ // The effect worker claims its own lease role with the same runtime identity
47
+ // as the mapped writer unless the caller pinned an explicit worker id; one
48
+ // resolved identity is reused by the supervisor and by the graceful-shutdown
49
+ // lease release so both roles expire together on stop().
50
+ const effectWorkerId = options.workerId ?? writer.writerId;
44
51
  const runtime = await initializeMappedTypedSheetsRuntime({
45
52
  dbName: options.dbName,
46
53
  entities: generated.entities,
@@ -55,10 +62,14 @@ export async function createInternalSyncService(options) {
55
62
  const remote = createRemoteProvider(options, projectionDefinitions);
56
63
  await provisionRegisteredSyncSheets(remote.provisioner, projectionDefinitions);
57
64
  await autoResolveExistingMappedConflictsWithAdapter(runtime.storage, runtime.mappings.mappings, resolveTypedSheetsEntityWriterOptions(writer));
58
- const effectSupervisor = createSyncEffectWorkerSupervisor({
65
+ const effectSupervisor = createEffectWorkerSupervisor({
59
66
  storage: runtime.storage,
60
- provider: remote.provider,
67
+ dispatcher: new SheetsEffectDispatcher({
68
+ provider: remote.provider,
69
+ storage: runtime.storage,
70
+ }),
61
71
  ...optionalWorkerOptions(options),
72
+ workerId: effectWorkerId,
62
73
  });
63
74
  const pollingFullScanIntervalMs = options.pollingFullScanIntervalMs
64
75
  ?? DEFAULT_POLLING_FULL_SCAN_INTERVAL_MS;
@@ -107,8 +118,24 @@ export async function createInternalSyncService(options) {
107
118
  // Stop inbound reads first, then the outbound worker. Both supervisors
108
119
  // drain manual and background passes before SQLite is closed.
109
120
  stopPromise = (async () => {
110
- await pollingSupervisor.stop();
111
- await effectSupervisor.stop();
121
+ try {
122
+ await pollingSupervisor.stop();
123
+ await effectSupervisor.stop();
124
+ }
125
+ finally {
126
+ // Graceful-shutdown handoff: expire this runtime's own leases so the
127
+ // next runtime on the same SQLite file claims immediately through the
128
+ // TAKEOVER path. Abnormal exits keep the full lease window, and the
129
+ // row is never deleted so authority epoch ordering stays monotonic.
130
+ // The release ALWAYS runs, even when a supervisor stop fails, so a
131
+ // restart inside the lease window never fails with
132
+ // WRITER_LEASE_UNAVAILABLE; a failing release only logs and never
133
+ // masks the supervisor error. `stopped` still flips only when both
134
+ // supervisor stops complete, so a rejected stop leaves a retryable
135
+ // close() that re-runs the stops and the release.
136
+ await expireRuntimeWriterLeases(runtime.storage, writer, effectWorkerId)
137
+ .catch(() => undefined);
138
+ }
112
139
  stopped = true;
113
140
  stopPromise = undefined;
114
141
  })().catch((error) => {
@@ -133,6 +160,15 @@ export async function createInternalSyncService(options) {
133
160
  };
134
161
  }
135
162
  catch (error) {
163
+ // Conflict-route registration claims this runtime's mapped-role writer
164
+ // lease before remote provisioning runs; a provisioning failure would
165
+ // otherwise leave the claim valid for the full lease window and every
166
+ // immediate retry would fail at the same claim with
167
+ // WRITER_LEASE_UNAVAILABLE. Expire the claimed leases (CAS-guarded,
168
+ // warn-and-continue) so the retry takes over at once; the extra guard
169
+ // ensures this can never mask the original startup error.
170
+ await expireRuntimeWriterLeases(runtime.storage, writer, effectWorkerId)
171
+ .catch(() => undefined);
136
172
  await runtime.storage.close(true).catch(() => undefined);
137
173
  throw error;
138
174
  }
@@ -270,6 +306,55 @@ function createWriterOptions(options) {
270
306
  ...(options.onTiming === undefined ? {} : { onTiming: options.onTiming }),
271
307
  };
272
308
  }
309
+ /**
310
+ * Expires this runtime's own writer leases on graceful shutdown.
311
+ *
312
+ * Each release is CAS-guarded on the exact lease row this runtime holds
313
+ * (role, writer id, epoch, fencing token), so a concurrent takeover or a
314
+ * previously crashed runtime's stale row is never expired. The observation
315
+ * poller and the auto conflict resolver claim under the mapped writer role
316
+ * with the same writer id, so the single mapped-role release covers them.
317
+ * A failing release only logs a classified warning and never aborts stop().
318
+ */
319
+ async function expireRuntimeWriterLeases(storage, writer, effectWorkerId) {
320
+ const now = writer.now?.() ?? Date.now();
321
+ // Every claim site wired into the bootstrap must be mirrored here:
322
+ // conflict route registration (registerSyncConflictProjectionRoutes), auto
323
+ // conflict resolution (autoSystemConflictResolution), mapped flush planning
324
+ // and projection registration (flushCoordinator,
325
+ // mappedPersistenceContext), and observation polling
326
+ // (MikroOrmUserInputPolling) claim under the mapped writer role with
327
+ // writer.writerId; the effect worker supervisor claims under
328
+ // DEFAULT_WORKER_ROLE with effectWorkerId. A claim added elsewhere must be
329
+ // added to this list, or graceful close leaves it leased for the window.
330
+ const ownLeases = [
331
+ { role: DEFAULT_MAPPED_WRITER_ROLE, writerId: writer.writerId },
332
+ { role: DEFAULT_WORKER_ROLE, writerId: effectWorkerId },
333
+ ];
334
+ for (const { role, writerId } of ownLeases) {
335
+ try {
336
+ const found = await readWriterLeaseWithAdapter(storage, role);
337
+ if (found.kind !== LOOKUP_RESULT_KINDS.FOUND || found.value.writerId !== writerId) {
338
+ // No row, or the lease was already taken over by a newer writer:
339
+ // nothing this runtime owns to expire.
340
+ continue;
341
+ }
342
+ const released = await releaseWriterLeaseWithAdapter(storage, {
343
+ role,
344
+ writerId,
345
+ writerEpoch: found.value.writerEpoch,
346
+ fencingToken: found.value.fencingToken,
347
+ now,
348
+ });
349
+ if (!released) {
350
+ console.warn(`[sync-service] writer lease for role "${role}" changed ownership during shutdown; skipping release.`);
351
+ }
352
+ }
353
+ catch (error) {
354
+ console.warn(`[sync-service] writer lease release failed for role "${role}": ${safeErrorMessage(error)}`);
355
+ }
356
+ }
357
+ }
273
358
  function optionalWorkerOptions(options) {
274
359
  // The knobs are tied to the ACTIVE provider: the full direct Google
275
360
  // provider's timeouts (its defaults when omitted). The worker provider