hikoutei 0.3.2 → 0.3.4
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 +12 -2
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmMappedObservation.d.ts +2 -0
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmMappedObservation.d.ts.map +1 -1
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmMappedObservation.js +5 -0
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmMappedObservation.js.map +1 -1
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPolling.d.ts +52 -0
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPolling.d.ts.map +1 -1
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPolling.js +195 -13
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPolling.js.map +1 -1
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPollingFastPath.d.ts +24 -0
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPollingFastPath.d.ts.map +1 -0
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPollingFastPath.js +124 -0
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPollingFastPath.js.map +1 -0
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPollingInspection.js +1 -1
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPollingInspection.js.map +1 -1
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPollingPersistence.d.ts +15 -2
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPollingPersistence.d.ts.map +1 -1
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPollingPersistence.js +27 -3
- package/dist/adapter/persistence/providers/mikro-orm/observation/MikroOrmUserInputPollingPersistence.js.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/errors.d.ts +1 -0
- package/dist/adapter/sheets/providers/apps-script-gateway/errors.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/errors.js +1 -0
- package/dist/adapter/sheets/providers/apps-script-gateway/errors.js.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/index.d.ts +2 -0
- package/dist/adapter/sheets/providers/apps-script-gateway/index.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/index.js +1 -0
- package/dist/adapter/sheets/providers/apps-script-gateway/index.js.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/effect/effectOperation.d.ts +3 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/effect/effectOperation.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/effect/effectOperation.js +9 -0
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/effect/effectOperation.js.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/effect/effectOperationScript.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/effect/effectOperationScript.js +137 -20
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/effect/effectOperationScript.js.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/observation/observationOperation.js +82 -34
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/observation/observationOperation.js.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/write/batchAppendOperation.d.ts +31 -0
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/write/batchAppendOperation.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/write/batchAppendOperation.js +567 -0
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/write/batchAppendOperation.js.map +1 -0
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/write/fastAppendOperation.d.ts +12 -17
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/write/fastAppendOperation.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/write/fastAppendOperation.js +27 -213
- package/dist/adapter/sheets/providers/apps-script-gateway/operations/write/fastAppendOperation.js.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/transport/operationClient.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/transport/operationClient.js +81 -8
- package/dist/adapter/sheets/providers/apps-script-gateway/transport/operationClient.js.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/transport/operationSyncGateway.d.ts +1 -6
- package/dist/adapter/sheets/providers/apps-script-gateway/transport/operationSyncGateway.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/apps-script-gateway/transport/operationSyncGateway.js +15 -9
- package/dist/adapter/sheets/providers/apps-script-gateway/transport/operationSyncGateway.js.map +1 -1
- package/dist/application/orm/mapping/projection.js +1 -1
- package/dist/application/orm/mapping/projection.js.map +1 -1
- package/dist/application/orm/persistence/flush/flushCoordinator.d.ts.map +1 -1
- package/dist/application/orm/persistence/flush/flushCoordinator.js +1 -0
- package/dist/application/orm/persistence/flush/flushCoordinator.js.map +1 -1
- package/dist/application/orm/persistence/lifecycle/entityLifecycle.js +1 -1
- package/dist/application/orm/persistence/lifecycle/entityLifecycle.js.map +1 -1
- package/dist/application/sync/gateway/SyncGatewayBootstrap.d.ts +3 -1
- package/dist/application/sync/gateway/SyncGatewayBootstrap.d.ts.map +1 -1
- package/dist/application/sync/gateway/SyncGatewayBootstrap.js +3 -1
- package/dist/application/sync/gateway/SyncGatewayBootstrap.js.map +1 -1
- package/dist/application/sync/gateway/conflictProjection.d.ts +13 -0
- package/dist/application/sync/gateway/conflictProjection.d.ts.map +1 -0
- package/dist/application/sync/gateway/conflictProjection.js +58 -0
- package/dist/application/sync/gateway/conflictProjection.js.map +1 -0
- package/dist/application/sync/gateway/conflictProjectionRegistration.d.ts +11 -0
- package/dist/application/sync/gateway/conflictProjectionRegistration.d.ts.map +1 -0
- package/dist/application/sync/gateway/conflictProjectionRegistration.js +70 -0
- package/dist/application/sync/gateway/conflictProjectionRegistration.js.map +1 -0
- package/dist/application/sync/gateway/coordinator/CoordinatedSyncGateway.d.ts +102 -0
- package/dist/application/sync/gateway/coordinator/CoordinatedSyncGateway.d.ts.map +1 -0
- package/dist/application/sync/gateway/coordinator/CoordinatedSyncGateway.js +221 -0
- package/dist/application/sync/gateway/coordinator/CoordinatedSyncGateway.js.map +1 -0
- package/dist/application/sync/gateway/coordinator/asyncMutex.d.ts +51 -0
- package/dist/application/sync/gateway/coordinator/asyncMutex.d.ts.map +1 -0
- package/dist/application/sync/gateway/coordinator/asyncMutex.js +65 -0
- package/dist/application/sync/gateway/coordinator/asyncMutex.js.map +1 -0
- package/dist/application/sync/gateway/coordinator/coordinatorTelemetry.d.ts +31 -0
- package/dist/application/sync/gateway/coordinator/coordinatorTelemetry.d.ts.map +1 -0
- package/dist/application/sync/gateway/coordinator/coordinatorTelemetry.js +13 -0
- package/dist/application/sync/gateway/coordinator/coordinatorTelemetry.js.map +1 -0
- package/dist/application/sync/gateway/syncGateway.d.ts +26 -6
- package/dist/application/sync/gateway/syncGateway.d.ts.map +1 -1
- package/dist/application/sync/gateway/syncGateway.js +10 -2
- package/dist/application/sync/gateway/syncGateway.js.map +1 -1
- package/dist/application/sync/gateway/transportClassification.d.ts +62 -0
- package/dist/application/sync/gateway/transportClassification.d.ts.map +1 -0
- package/dist/application/sync/gateway/transportClassification.js +133 -0
- package/dist/application/sync/gateway/transportClassification.js.map +1 -0
- package/dist/application/sync/inbound/autoSystemConflictResolution.d.ts +26 -0
- package/dist/application/sync/inbound/autoSystemConflictResolution.d.ts.map +1 -0
- package/dist/application/sync/inbound/autoSystemConflictResolution.js +335 -0
- package/dist/application/sync/inbound/autoSystemConflictResolution.js.map +1 -0
- package/dist/application/sync/outbound/effects/AdaptiveEffectBatchController.d.ts +50 -0
- package/dist/application/sync/outbound/effects/AdaptiveEffectBatchController.d.ts.map +1 -0
- package/dist/application/sync/outbound/effects/AdaptiveEffectBatchController.js +97 -0
- package/dist/application/sync/outbound/effects/AdaptiveEffectBatchController.js.map +1 -0
- package/dist/application/sync/outbound/effects/SyncEffectSupervisor.d.ts +4 -1
- package/dist/application/sync/outbound/effects/SyncEffectSupervisor.d.ts.map +1 -1
- package/dist/application/sync/outbound/effects/SyncEffectSupervisor.js +35 -1
- package/dist/application/sync/outbound/effects/SyncEffectSupervisor.js.map +1 -1
- package/dist/application/sync/outbound/effects/SyncEffectWorker.d.ts +14 -2
- package/dist/application/sync/outbound/effects/SyncEffectWorker.d.ts.map +1 -1
- package/dist/application/sync/outbound/effects/SyncEffectWorker.js +190 -31
- package/dist/application/sync/outbound/effects/SyncEffectWorker.js.map +1 -1
- package/dist/application/sync/outbound/effects/SyncEffectWorkerConstants.d.ts +25 -2
- package/dist/application/sync/outbound/effects/SyncEffectWorkerConstants.d.ts.map +1 -1
- package/dist/application/sync/outbound/effects/SyncEffectWorkerConstants.js +25 -2
- package/dist/application/sync/outbound/effects/SyncEffectWorkerConstants.js.map +1 -1
- package/dist/application/sync/outbound/effects/SyncEffectWorkerDispatch.d.ts +14 -7
- package/dist/application/sync/outbound/effects/SyncEffectWorkerDispatch.d.ts.map +1 -1
- package/dist/application/sync/outbound/effects/SyncEffectWorkerDispatch.js +118 -14
- package/dist/application/sync/outbound/effects/SyncEffectWorkerDispatch.js.map +1 -1
- package/dist/application/sync/outbound/effects/SyncEffectWorkerRouting.d.ts +30 -9
- package/dist/application/sync/outbound/effects/SyncEffectWorkerRouting.d.ts.map +1 -1
- package/dist/application/sync/outbound/effects/SyncEffectWorkerRouting.js +102 -18
- package/dist/application/sync/outbound/effects/SyncEffectWorkerRouting.js.map +1 -1
- package/dist/application/sync/outbound/effects/SyncEffectWorkerTransitions.d.ts.map +1 -1
- package/dist/application/sync/outbound/effects/SyncEffectWorkerTransitions.js +49 -14
- package/dist/application/sync/outbound/effects/SyncEffectWorkerTransitions.js.map +1 -1
- package/dist/application/sync/outbound/reconciliation/ReconciliationScanner.d.ts.map +1 -1
- package/dist/application/sync/outbound/reconciliation/ReconciliationScanner.js +97 -17
- package/dist/application/sync/outbound/reconciliation/ReconciliationScanner.js.map +1 -1
- package/dist/application/sync/service/SyncServiceBootstrap.d.ts +17 -0
- package/dist/application/sync/service/SyncServiceBootstrap.d.ts.map +1 -1
- package/dist/application/sync/service/SyncServiceBootstrap.js +125 -10
- package/dist/application/sync/service/SyncServiceBootstrap.js.map +1 -1
- package/dist/application/sync/service/contracts.d.ts +2 -0
- package/dist/application/sync/service/contracts.d.ts.map +1 -1
- package/dist/application/sync/telemetry/syncTiming.d.ts +6 -0
- package/dist/application/sync/telemetry/syncTiming.d.ts.map +1 -1
- package/dist/application/sync/telemetry/syncTiming.js +2 -0
- package/dist/application/sync/telemetry/syncTiming.js.map +1 -1
- package/dist/domain/conflict/index.d.ts +1 -1
- package/dist/domain/conflict/index.d.ts.map +1 -1
- package/dist/domain/conflict/index.js +1 -1
- package/dist/domain/conflict/index.js.map +1 -1
- package/dist/domain/conflict/transitions.d.ts +3 -0
- package/dist/domain/conflict/transitions.d.ts.map +1 -1
- package/dist/domain/conflict/transitions.js +3 -2
- package/dist/domain/conflict/transitions.js.map +1 -1
- package/dist/domain/model/constants.d.ts +1 -0
- package/dist/domain/model/constants.d.ts.map +1 -1
- package/dist/domain/model/constants.js +1 -0
- package/dist/domain/model/constants.js.map +1 -1
- package/dist/infrastructure/storage/index.d.ts +4 -2
- package/dist/infrastructure/storage/index.d.ts.map +1 -1
- package/dist/infrastructure/storage/index.js +2 -1
- package/dist/infrastructure/storage/index.js.map +1 -1
- package/dist/infrastructure/storage/sqlite/migrateSchema.d.ts.map +1 -1
- package/dist/infrastructure/storage/sqlite/migrateSchema.js +59 -1
- package/dist/infrastructure/storage/sqlite/migrateSchema.js.map +1 -1
- package/dist/infrastructure/storage/sqlite/schema.d.ts +12 -1
- package/dist/infrastructure/storage/sqlite/schema.d.ts.map +1 -1
- package/dist/infrastructure/storage/sqlite/schema.js +47 -3
- package/dist/infrastructure/storage/sqlite/schema.js.map +1 -1
- package/dist/infrastructure/storage/sqlite/schemaTypes.d.ts +2 -2
- package/dist/infrastructure/storage/sqlite/schemaTypes.d.ts.map +1 -1
- package/dist/infrastructure/storage/state/canonical/canonicalCommit.js +1 -1
- package/dist/infrastructure/storage/state/canonical/canonicalCommit.js.map +1 -1
- package/dist/infrastructure/storage/state/mapped/mappedPersistenceSql.d.ts +1 -0
- package/dist/infrastructure/storage/state/mapped/mappedPersistenceSql.d.ts.map +1 -1
- package/dist/infrastructure/storage/state/mapped/mappedPersistenceSql.js +1 -1
- package/dist/infrastructure/storage/state/mapped/mappedPersistenceSql.js.map +1 -1
- package/dist/infrastructure/storage/state/observation/observationAudit.js +5 -1
- package/dist/infrastructure/storage/state/observation/observationAudit.js.map +1 -1
- package/dist/infrastructure/storage/state/resolution/resolutionWriter.d.ts +10 -0
- package/dist/infrastructure/storage/state/resolution/resolutionWriter.d.ts.map +1 -1
- package/dist/infrastructure/storage/state/resolution/resolutionWriter.js +106 -20
- package/dist/infrastructure/storage/state/resolution/resolutionWriter.js.map +1 -1
- package/dist/infrastructure/storage/state/resolution/resolutionWriterContracts.d.ts +9 -1
- package/dist/infrastructure/storage/state/resolution/resolutionWriterContracts.d.ts.map +1 -1
- package/dist/infrastructure/storage/state/resolution/resolutionWriterContracts.js +3 -0
- package/dist/infrastructure/storage/state/resolution/resolutionWriterContracts.js.map +1 -1
- package/dist/infrastructure/storage/state/resolution/resolutionWriterSql.d.ts +11 -0
- package/dist/infrastructure/storage/state/resolution/resolutionWriterSql.d.ts.map +1 -1
- package/dist/infrastructure/storage/state/resolution/resolutionWriterSql.js +35 -0
- package/dist/infrastructure/storage/state/resolution/resolutionWriterSql.js.map +1 -1
- package/dist/infrastructure/storage/sync/outbound/effectOutbox.d.ts +12 -4
- package/dist/infrastructure/storage/sync/outbound/effectOutbox.d.ts.map +1 -1
- package/dist/infrastructure/storage/sync/outbound/effectOutbox.js +46 -15
- package/dist/infrastructure/storage/sync/outbound/effectOutbox.js.map +1 -1
- package/dist/infrastructure/storage/sync/outbound/effectOutboxContracts.d.ts +24 -0
- package/dist/infrastructure/storage/sync/outbound/effectOutboxContracts.d.ts.map +1 -1
- package/dist/infrastructure/storage/sync/outbound/effectOutboxContracts.js +1 -0
- package/dist/infrastructure/storage/sync/outbound/effectOutboxContracts.js.map +1 -1
- package/dist/infrastructure/storage/sync/outbound/effectOutboxSql.d.ts +9 -7
- package/dist/infrastructure/storage/sync/outbound/effectOutboxSql.d.ts.map +1 -1
- package/dist/infrastructure/storage/sync/outbound/effectOutboxSql.js +44 -8
- package/dist/infrastructure/storage/sync/outbound/effectOutboxSql.js.map +1 -1
- package/dist/infrastructure/storage/sync/outbound/effectOutboxSupport.d.ts +3 -1
- package/dist/infrastructure/storage/sync/outbound/effectOutboxSupport.d.ts.map +1 -1
- package/dist/infrastructure/storage/sync/outbound/effectOutboxSupport.js +35 -2
- package/dist/infrastructure/storage/sync/outbound/effectOutboxSupport.js.map +1 -1
- package/dist/infrastructure/storage/sync/outbound/reconciliationSql.js +1 -0
- package/dist/infrastructure/storage/sync/outbound/reconciliationSql.js.map +1 -1
- package/dist/infrastructure/storage/sync/shared/spreadsheetAuthority.d.ts +31 -0
- package/dist/infrastructure/storage/sync/shared/spreadsheetAuthority.d.ts.map +1 -0
- package/dist/infrastructure/storage/sync/shared/spreadsheetAuthority.js +92 -0
- package/dist/infrastructure/storage/sync/shared/spreadsheetAuthority.js.map +1 -0
- package/dist/infrastructure/storage/sync/shared/writerLease.js +3 -1
- package/dist/infrastructure/storage/sync/shared/writerLease.js.map +1 -1
- package/docs/advanced-sheets-gateway-concurrency-problem.md +434 -0
- package/docs/architecture.md +53 -11
- package/docs/ci.md +31 -14
- package/docs/google-sheets-sync-scaling-strategy.md +459 -0
- package/docs/quick-start.md +15 -1
- package/docs/sync-bulk-write-benchmark.md +520 -0
- package/docs/sync-observability.md +39 -3
- package/docs/write-and-synchronization-flow.md +76 -17
- package/package.json +1 -1
package/dist/adapter/sheets/providers/apps-script-gateway/operations/write/batchAppendOperation.js
ADDED
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
/** Idempotent append operation executed through the Apps Script eval gateway. */
|
|
2
|
+
import { SYNC_GATEWAY_FAST_APPEND_STATUSES } from "../../../../../../application/sync/gateway/constants.js";
|
|
3
|
+
import { decodeOptionalSyncGatewayTiming } from "../../protocol/timing.js";
|
|
4
|
+
import { invalidOperationRequest, invalidOperationResponse } from "../../errors.js";
|
|
5
|
+
import { isNormalizedCell } from "../../../../../../shared/encoding/normalizedCell.js";
|
|
6
|
+
import { isRecord } from "../../../../../../shared/encoding/typeGuards.js";
|
|
7
|
+
/**
|
|
8
|
+
* Builds an idempotent append operation backed by built-in Apps Script
|
|
9
|
+
* services only (SpreadsheetApp, LockService, PropertiesService, Utilities);
|
|
10
|
+
* no Advanced Sheets dependency is required. The data rows and their Gateway
|
|
11
|
+
* receipts are written under one script lock, but the target write and the
|
|
12
|
+
* receipt write are separate flush() calls, so a crash between them can leave
|
|
13
|
+
* a target row without a receipt; this is not a cross-request atomic batch.
|
|
14
|
+
* A lost HTTP response is recovered by replaying the same effect ID: the
|
|
15
|
+
* replay verifies the target row postcondition and returns applied without
|
|
16
|
+
* adding another row, while a reused effect ID with a different payload hash
|
|
17
|
+
* fails closed.
|
|
18
|
+
*
|
|
19
|
+
* The registered identityField is required because this path never
|
|
20
|
+
* materializes anchor metadata: replay and postcondition verification locate
|
|
21
|
+
* the target row through the identity column and fail closed when the
|
|
22
|
+
* identity is missing or ambiguous instead of guessing at a position.
|
|
23
|
+
*/
|
|
24
|
+
export function createBatchAppendRowsOperation(request) {
|
|
25
|
+
validateBatchAppendRequest(request);
|
|
26
|
+
return {
|
|
27
|
+
fn: BATCH_APPEND_OPERATION_SOURCE,
|
|
28
|
+
args: request,
|
|
29
|
+
decode: (value) => decodeBatchAppendResult(value, request.rows),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** Self-contained V8 source restored by Code.gs with eval. */
|
|
33
|
+
const BATCH_APPEND_OPERATION_SOURCE = String.raw `function (spreadsheet, args) {
|
|
34
|
+
var RECEIPT_SHEET_NAME = "__typed_sheets_internal_effect_receipts";
|
|
35
|
+
var RECEIPT_HEADERS = ["effectId", "payloadHash", "status", "visibleHash", "visibleRevision", "updatedAt"];
|
|
36
|
+
var phases = [];
|
|
37
|
+
validateInput_();
|
|
38
|
+
var lockStartedAt = Date.now();
|
|
39
|
+
var lock = LockService.getScriptLock();
|
|
40
|
+
if (!lock.tryLock(20000)) throw new Error("Could not acquire the sync effect gateway lock");
|
|
41
|
+
try {
|
|
42
|
+
var result = run_();
|
|
43
|
+
appendPhase_(result, "script_lock", Date.now() - lockStartedAt);
|
|
44
|
+
return result;
|
|
45
|
+
} finally {
|
|
46
|
+
lock.releaseLock();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function run_() {
|
|
50
|
+
var startedAt = Date.now();
|
|
51
|
+
validateInput_();
|
|
52
|
+
assertAuthority_(spreadsheet);
|
|
53
|
+
phase_("validate_input", startedAt);
|
|
54
|
+
|
|
55
|
+
var lookupStartedAt = Date.now();
|
|
56
|
+
var sheet = spreadsheet.getSheetByName(args.sheetName);
|
|
57
|
+
if (sheet === null) throw new Error("batch append sheet was not found: " + args.sheetName);
|
|
58
|
+
var range = parseRange_(args.registeredRange);
|
|
59
|
+
if (range.columnCount !== args.headers.length) throw new Error("batch append headers do not match registeredRange");
|
|
60
|
+
var remoteHeaders = sheet.getRange(1, range.startColumn, 1, range.columnCount).getValues()[0];
|
|
61
|
+
args.headers.forEach(function (header, index) {
|
|
62
|
+
if (String(remoteHeaders[index]) !== String(header)) {
|
|
63
|
+
throw new Error("batch append remote headers do not match registered schema at column " + (index + 1));
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
var receiptSheet = ensureReceiptSheet_(spreadsheet);
|
|
67
|
+
phase_("sheet_and_receipt_lookup", lookupStartedAt);
|
|
68
|
+
|
|
69
|
+
var receiptReadStartedAt = Date.now();
|
|
70
|
+
var receipts = readReceipts_(receiptSheet);
|
|
71
|
+
phase_("receipt_read", receiptReadStartedAt);
|
|
72
|
+
|
|
73
|
+
var pending = [];
|
|
74
|
+
var resultsById = Object.create(null);
|
|
75
|
+
args.rows.forEach(function (row) {
|
|
76
|
+
var payloadHash = String(row.payloadHash);
|
|
77
|
+
var existing = receipts[row.effectId];
|
|
78
|
+
if (existing !== undefined) {
|
|
79
|
+
if (existing.payloadHash !== payloadHash) {
|
|
80
|
+
throw new Error("effect ID cannot be reused with another payload: " + row.effectId);
|
|
81
|
+
}
|
|
82
|
+
assertReceiptPostcondition_(sheet, range, existing, row);
|
|
83
|
+
resultsById[row.effectId] = {
|
|
84
|
+
effectId: row.effectId,
|
|
85
|
+
status: "applied",
|
|
86
|
+
visibleHash: existing.visibleHash,
|
|
87
|
+
visibleRevision: existing.visibleRevision,
|
|
88
|
+
};
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
pending.push({ row: row, payloadHash: payloadHash, visibleHash: visibleHash_(row.fields) });
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (pending.length > 0) {
|
|
95
|
+
var rangeStartedAt = Date.now();
|
|
96
|
+
var lastRow = sheet.getLastRow();
|
|
97
|
+
var startRow = Math.max(lastRow + 1, 2);
|
|
98
|
+
var receiptStartRow = Math.max(receiptSheet.getLastRow() + 1, 2);
|
|
99
|
+
assertIdentityAvailability_(sheet, range, lastRow, pending);
|
|
100
|
+
phase_("append_range_lookup", rangeStartedAt);
|
|
101
|
+
|
|
102
|
+
var appendStartedAt = Date.now();
|
|
103
|
+
writeAppendRows_(sheet, range, startRow, pending);
|
|
104
|
+
phase_("append_write", appendStartedAt);
|
|
105
|
+
var appendFlushStartedAt = Date.now();
|
|
106
|
+
SpreadsheetApp.flush();
|
|
107
|
+
phase_("append_flush", appendFlushStartedAt);
|
|
108
|
+
|
|
109
|
+
// The target-row write and the receipt write are two separate flush()
|
|
110
|
+
// calls: a crash between them can leave a target row without a receipt.
|
|
111
|
+
// This operation is not cross-request atomic, so a replay of that effect
|
|
112
|
+
// fails closed on the duplicate identity guard instead of being silently
|
|
113
|
+
// re-applied, and the response-loss probe contract treats a missing
|
|
114
|
+
// receipt as unapplied. Receipt-backed evidence is returned only after
|
|
115
|
+
// the postcondition check below re-verifies the target rows.
|
|
116
|
+
var receiptStartedAt = Date.now();
|
|
117
|
+
writeReceipts_(receiptSheet, receiptStartRow, pending);
|
|
118
|
+
phase_("receipt_write", receiptStartedAt);
|
|
119
|
+
var receiptFlushStartedAt = Date.now();
|
|
120
|
+
SpreadsheetApp.flush();
|
|
121
|
+
phase_("receipt_flush", receiptFlushStartedAt);
|
|
122
|
+
|
|
123
|
+
var postconditionStartedAt = Date.now();
|
|
124
|
+
assertAppendPostcondition_(sheet, range, pending);
|
|
125
|
+
phase_("postcondition", postconditionStartedAt);
|
|
126
|
+
pending.forEach(function (entry) {
|
|
127
|
+
resultsById[entry.row.effectId] = {
|
|
128
|
+
effectId: entry.row.effectId,
|
|
129
|
+
status: "applied",
|
|
130
|
+
visibleHash: entry.visibleHash,
|
|
131
|
+
visibleRevision: 1,
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
var resultStartedAt = Date.now();
|
|
137
|
+
var results = args.rows.map(function (row) {
|
|
138
|
+
var result = resultsById[row.effectId];
|
|
139
|
+
if (result === undefined) throw new Error("batch append result is missing an effect");
|
|
140
|
+
return result;
|
|
141
|
+
});
|
|
142
|
+
phase_("result", resultStartedAt);
|
|
143
|
+
return {
|
|
144
|
+
results: results,
|
|
145
|
+
hasMore: false,
|
|
146
|
+
timing: {
|
|
147
|
+
operationKinds: ["append"],
|
|
148
|
+
operationCounts: { append: results.length, update: 0, delete: 0 },
|
|
149
|
+
durationMs: Date.now() - startedAt,
|
|
150
|
+
phases: phases
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function validateInput_() {
|
|
156
|
+
if (!args || typeof args.sheetName !== "string" || args.sheetName.length === 0) {
|
|
157
|
+
throw new Error("batch append sheetName is required");
|
|
158
|
+
}
|
|
159
|
+
if (typeof args.registeredRange !== "string" || !/^[A-Z]+:[A-Z]+$/.test(args.registeredRange)) {
|
|
160
|
+
throw new Error("batch append registeredRange is invalid");
|
|
161
|
+
}
|
|
162
|
+
if (!Array.isArray(args.headers) || args.headers.length === 0) {
|
|
163
|
+
throw new Error("batch append headers are required");
|
|
164
|
+
}
|
|
165
|
+
if (args.identityField === undefined || typeof args.identityField !== "string" || args.identityField.length === 0) {
|
|
166
|
+
throw new Error("batch append identityField is required");
|
|
167
|
+
}
|
|
168
|
+
if (args.headers.indexOf(args.identityField) < 0) {
|
|
169
|
+
throw new Error("batch append identityField is not a registered header");
|
|
170
|
+
}
|
|
171
|
+
var seenHeaders = Object.create(null);
|
|
172
|
+
args.headers.forEach(function (header) {
|
|
173
|
+
if (typeof header !== "string" || header.length === 0 || seenHeaders[header]) {
|
|
174
|
+
throw new Error("batch append headers are invalid or duplicated");
|
|
175
|
+
}
|
|
176
|
+
seenHeaders[header] = true;
|
|
177
|
+
});
|
|
178
|
+
if (!Array.isArray(args.rows)) throw new Error("batch append rows must be an array");
|
|
179
|
+
var seenEffectIds = Object.create(null);
|
|
180
|
+
var expected = args.headers.slice().sort();
|
|
181
|
+
args.rows.forEach(function (row) {
|
|
182
|
+
if (!row || typeof row.effectId !== "string" || row.effectId.length === 0) {
|
|
183
|
+
throw new Error("batch append effectId is required");
|
|
184
|
+
}
|
|
185
|
+
if (seenEffectIds[row.effectId] === true) {
|
|
186
|
+
throw new Error("batch append effectIds must be non-empty and unique");
|
|
187
|
+
}
|
|
188
|
+
seenEffectIds[row.effectId] = true;
|
|
189
|
+
if (typeof row.payloadHash !== "string" || row.payloadHash.length === 0) {
|
|
190
|
+
throw new Error("batch append payloadHash is required");
|
|
191
|
+
}
|
|
192
|
+
if (row.anchor !== undefined && (typeof row.anchor !== "string" || row.anchor.length === 0)) {
|
|
193
|
+
throw new Error("batch append row anchor is invalid");
|
|
194
|
+
}
|
|
195
|
+
if (!row.fields || typeof row.fields !== "object") throw new Error("batch append fields are required");
|
|
196
|
+
var actual = Object.keys(row.fields).sort();
|
|
197
|
+
if (actual.length !== expected.length || actual.some(function (field, index) { return field !== expected[index]; })) {
|
|
198
|
+
throw new Error("batch append row fields do not match headers");
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function assertAuthority_(targetSpreadsheet) {
|
|
204
|
+
if (args.authority === undefined) return;
|
|
205
|
+
if (!args.authority || typeof args.authority.epoch !== "number" ||
|
|
206
|
+
Math.floor(args.authority.epoch) !== args.authority.epoch || args.authority.epoch < 1 ||
|
|
207
|
+
typeof args.authority.token !== "string" || args.authority.token.length === 0) {
|
|
208
|
+
throw new Error("batch append authority is invalid");
|
|
209
|
+
}
|
|
210
|
+
var key = "typed_sheets_authority:" + targetSpreadsheet.getId();
|
|
211
|
+
var properties = PropertiesService.getScriptProperties();
|
|
212
|
+
var raw = properties.getProperty(key);
|
|
213
|
+
var current = raw === null ? null : JSON.parse(raw);
|
|
214
|
+
if (current !== null && (current.epoch > args.authority.epoch ||
|
|
215
|
+
current.epoch === args.authority.epoch && current.token !== args.authority.token)) {
|
|
216
|
+
throw new Error("batch append authority fence is stale");
|
|
217
|
+
}
|
|
218
|
+
if (current === null || args.authority.epoch > current.epoch) {
|
|
219
|
+
properties.setProperty(key, JSON.stringify({ epoch: args.authority.epoch, token: args.authority.token }));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function ensureReceiptSheet_(targetSpreadsheet) {
|
|
224
|
+
var target = targetSpreadsheet.getSheetByName(RECEIPT_SHEET_NAME);
|
|
225
|
+
if (target === null) target = targetSpreadsheet.insertSheet(RECEIPT_SHEET_NAME);
|
|
226
|
+
if (target.getLastRow() === 0 && target.getLastColumn() === 0) {
|
|
227
|
+
target.getRange(1, 1, 1, RECEIPT_HEADERS.length).setValues([RECEIPT_HEADERS]);
|
|
228
|
+
}
|
|
229
|
+
var actual = target.getRange(1, 1, 1, RECEIPT_HEADERS.length).getValues()[0];
|
|
230
|
+
RECEIPT_HEADERS.forEach(function (header, index) {
|
|
231
|
+
if (String(actual[index]) !== header) throw new Error("receipt sheet headers do not match");
|
|
232
|
+
});
|
|
233
|
+
try { if (!target.isSheetHidden()) target.hideSheet(); } catch (error) {}
|
|
234
|
+
return target;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function readReceipts_(target) {
|
|
238
|
+
var parsed = Object.create(null);
|
|
239
|
+
var lastRow = target.getLastRow();
|
|
240
|
+
if (lastRow < 2) return parsed;
|
|
241
|
+
target.getRange(2, 1, lastRow - 1, RECEIPT_HEADERS.length).getValues().forEach(function (row) {
|
|
242
|
+
if (row[0] === "" || row[0] === null) return;
|
|
243
|
+
var effectId = String(row[0]);
|
|
244
|
+
if (parsed[effectId] !== undefined) throw new Error("receipt sheet contains duplicate effectId: " + effectId);
|
|
245
|
+
var payloadHash = String(row[1]);
|
|
246
|
+
var status = String(row[2]);
|
|
247
|
+
var visibleHash = String(row[3]);
|
|
248
|
+
var visibleRevision = Number(row[4]);
|
|
249
|
+
if (payloadHash.length === 0 || status !== "applied" || visibleHash.length === 0 ||
|
|
250
|
+
!isFinite(visibleRevision) || Math.floor(visibleRevision) !== visibleRevision || visibleRevision < 1) {
|
|
251
|
+
throw new Error("receipt sheet contains an invalid receipt for effectId: " + effectId);
|
|
252
|
+
}
|
|
253
|
+
parsed[effectId] = {
|
|
254
|
+
payloadHash: payloadHash,
|
|
255
|
+
visibleHash: visibleHash,
|
|
256
|
+
visibleRevision: visibleRevision,
|
|
257
|
+
};
|
|
258
|
+
});
|
|
259
|
+
return parsed;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function assertReceiptPostcondition_(targetSheet, targetRange, receipt, row) {
|
|
263
|
+
var rowNumber = findReceiptRowNumber_(targetSheet, targetRange, row);
|
|
264
|
+
if (rowNumber === null) {
|
|
265
|
+
throw new Error("receipt postcondition row is unavailable for effectId: " + row.effectId);
|
|
266
|
+
}
|
|
267
|
+
var values = targetSheet.getRange(rowNumber, targetRange.startColumn, 1, targetRange.columnCount).getValues()[0];
|
|
268
|
+
var fields = Object.create(null);
|
|
269
|
+
args.headers.forEach(function (header, index) {
|
|
270
|
+
fields[header] = normalizedCellFromSheetValue_(values[index]);
|
|
271
|
+
});
|
|
272
|
+
if (visibleHash_(fields) !== receipt.visibleHash) {
|
|
273
|
+
throw new Error("receipt postcondition changed for effectId: " + row.effectId);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function findReceiptRowNumber_(targetSheet, targetRange, row) {
|
|
278
|
+
// The MVP append path never materializes anchors as Developer Metadata;
|
|
279
|
+
// a previously appended row is located through the registered identity
|
|
280
|
+
// field, which this operation contract requires. A missing or empty
|
|
281
|
+
// identity cell returns null so replay verification fails closed instead
|
|
282
|
+
// of guessing at a position.
|
|
283
|
+
var identityColumn = args.headers.indexOf(args.identityField);
|
|
284
|
+
var identityCell = row.fields[args.identityField];
|
|
285
|
+
var identity = identityCell === null || identityCell === undefined || identityCell.value === undefined
|
|
286
|
+
? ""
|
|
287
|
+
: String(identityCell.value);
|
|
288
|
+
if (identity.length === 0) return null;
|
|
289
|
+
var lastRow = targetSheet.getLastRow();
|
|
290
|
+
var matches = [];
|
|
291
|
+
if (lastRow >= 2) {
|
|
292
|
+
targetSheet.getRange(2, targetRange.startColumn + identityColumn, lastRow - 1, 1).getValues().forEach(function (value, index) {
|
|
293
|
+
if (value[0] !== "" && value[0] !== null && String(value[0]) === identity) matches.push(index + 2);
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
if (matches.length > 1) {
|
|
297
|
+
throw new Error("sync identity is duplicated: " + identity + " at rows " + matches.join(", "));
|
|
298
|
+
}
|
|
299
|
+
return matches.length === 0 ? null : matches[0];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function normalizedCellFromSheetValue_(value) {
|
|
303
|
+
if (value === "" || value === null) return null;
|
|
304
|
+
if (isDate_(value)) return { kind: "date", value: value.toISOString() };
|
|
305
|
+
if (typeof value === "string") return { kind: "string", value: normalizeScalarString_(value) };
|
|
306
|
+
if (typeof value === "number" && isFinite(value)) return { kind: "number", value: value };
|
|
307
|
+
if (typeof value === "boolean") return { kind: "boolean", value: value };
|
|
308
|
+
throw new Error("Sheet cell cannot be normalized");
|
|
309
|
+
}
|
|
310
|
+
function isDate_(value) { return Object.prototype.toString.call(value) === "[object Date]" && !isNaN(value.getTime()); }
|
|
311
|
+
|
|
312
|
+
function visibleHash_(fields) {
|
|
313
|
+
return stableHash_({ fields: Object.keys(fields).sort().map(function (fieldName) {
|
|
314
|
+
return { fieldName: fieldName, value: fields[fieldName] };
|
|
315
|
+
}) });
|
|
316
|
+
}
|
|
317
|
+
function stableHash_(value) { return sha256Hex_(stableEncode_(value)); }
|
|
318
|
+
function stableEncode_(value) {
|
|
319
|
+
if (value === null) return "n";
|
|
320
|
+
if (value === true) return "b1";
|
|
321
|
+
if (value === false) return "b0";
|
|
322
|
+
if (typeof value === "number") return stableEncodeNumber_(value);
|
|
323
|
+
if (typeof value === "string") return stableEncodeString_(value);
|
|
324
|
+
if (isObject_(value) && value.kind === "date" && isCanonicalDate_(value.value)) return "d24:" + value.value;
|
|
325
|
+
if (Array.isArray(value)) return "a" + value.length + "[" + value.map(stableEncode_).join("") + "]";
|
|
326
|
+
if (isObject_(value)) {
|
|
327
|
+
var entries = Object.keys(value).map(function (key) {
|
|
328
|
+
var normalized = normalizeScalarString_(key);
|
|
329
|
+
return { key: normalized, bytes: utf8Bytes_(normalized), value: value[key] };
|
|
330
|
+
});
|
|
331
|
+
entries.sort(function (left, right) { return compareBytes_(left.bytes, right.bytes); });
|
|
332
|
+
return "o" + entries.length + "{" + entries.map(function (entry) {
|
|
333
|
+
return "s" + entry.bytes.length + ":" + entry.key + stableEncode_(entry.value);
|
|
334
|
+
}).join("") + "}";
|
|
335
|
+
}
|
|
336
|
+
throw new Error("stable value is unsupported");
|
|
337
|
+
}
|
|
338
|
+
function stableEncodeNumber_(value) {
|
|
339
|
+
if (!isFinite(value)) throw new Error("stable number is not finite");
|
|
340
|
+
var decimal = value === 0 ? "0" : String(value).replace(/e\+/, "e").replace(/e(-?)0+(\d+)/, "e$1$2");
|
|
341
|
+
return "f" + utf8ByteLength_(decimal) + ":" + decimal;
|
|
342
|
+
}
|
|
343
|
+
function stableEncodeString_(value) {
|
|
344
|
+
var normalized = normalizeScalarString_(value);
|
|
345
|
+
return "s" + utf8ByteLength_(normalized) + ":" + normalized;
|
|
346
|
+
}
|
|
347
|
+
function sha256Hex_(value) {
|
|
348
|
+
return Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, value, Utilities.Charset.UTF_8).map(function (byte) {
|
|
349
|
+
var unsigned = byte < 0 ? byte + 256 : byte;
|
|
350
|
+
return ("0" + unsigned.toString(16)).slice(-2);
|
|
351
|
+
}).join("");
|
|
352
|
+
}
|
|
353
|
+
function utf8Bytes_(value) { return Utilities.newBlob(value).getBytes(); }
|
|
354
|
+
function utf8ByteLength_(value) { return utf8Bytes_(value).length; }
|
|
355
|
+
function compareBytes_(left, right) {
|
|
356
|
+
var count = Math.min(left.length, right.length);
|
|
357
|
+
for (var index = 0; index < count; index += 1) {
|
|
358
|
+
var a = left[index] < 0 ? left[index] + 256 : left[index];
|
|
359
|
+
var b = right[index] < 0 ? right[index] + 256 : right[index];
|
|
360
|
+
if (a !== b) return a - b;
|
|
361
|
+
}
|
|
362
|
+
return left.length - right.length;
|
|
363
|
+
}
|
|
364
|
+
function isObject_(value) { return value !== null && typeof value === "object" && !Array.isArray(value); }
|
|
365
|
+
function normalizeScalarString_(value) { return value.normalize("NFC"); }
|
|
366
|
+
function isCanonicalDate_(value) {
|
|
367
|
+
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value)) return false;
|
|
368
|
+
var parsed = new Date(value);
|
|
369
|
+
return !isNaN(parsed.getTime()) && parsed.toISOString() === value;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function assertIdentityAvailability_(targetSheet, range, lastRow, pendingRows) {
|
|
373
|
+
var identityColumn = args.headers.indexOf(args.identityField);
|
|
374
|
+
var existing = Object.create(null);
|
|
375
|
+
if (lastRow >= 2) {
|
|
376
|
+
targetSheet.getRange(2, range.startColumn + identityColumn, lastRow - 1, 1).getValues().forEach(function (row, index) {
|
|
377
|
+
var value = row[0] === "" || row[0] === null ? null : String(row[0]);
|
|
378
|
+
if (value === null) {
|
|
379
|
+
throw new Error("sync identity is missing at row " + (index + 2));
|
|
380
|
+
}
|
|
381
|
+
if (existing[value] !== undefined) {
|
|
382
|
+
throw new Error("sync identity is duplicated: " + value + " at rows " + existing[value] + " and " + (index + 2));
|
|
383
|
+
}
|
|
384
|
+
existing[value] = index + 2;
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
pendingRows.forEach(function (entry) {
|
|
388
|
+
var cell = entry.row.fields[args.identityField];
|
|
389
|
+
var value = cell === null || cell === undefined || cell.value === undefined ? "" : String(cell.value);
|
|
390
|
+
if (value.length === 0) throw new Error("sync identity is required for append: " + args.identityField);
|
|
391
|
+
if (existing[value] !== undefined) {
|
|
392
|
+
var location = existing[value] === "pending" ? "a pending row" : "row " + existing[value];
|
|
393
|
+
throw new Error("sync identity already exists: " + value + " at " + location);
|
|
394
|
+
}
|
|
395
|
+
existing[value] = "pending";
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function writeAppendRows_(targetSheet, range, startRow, pending) {
|
|
400
|
+
// Reserve the rows through the spreadsheet mutation API before writing
|
|
401
|
+
// values so a concurrent human append is shifted rather than overwritten.
|
|
402
|
+
targetSheet.insertRowsAfter(startRow - 1, pending.length);
|
|
403
|
+
targetSheet.getRange(startRow, range.startColumn, pending.length, range.columnCount).setValues(pending.map(function (entry) {
|
|
404
|
+
return args.headers.map(function (header) { return toSheetValue_(entry.row.fields[header]); });
|
|
405
|
+
}));
|
|
406
|
+
setDateNumberFormats_(targetSheet, range, startRow, pending);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function writeReceipts_(target, startRow, pending) {
|
|
410
|
+
target.insertRowsAfter(startRow - 1, pending.length);
|
|
411
|
+
var updatedAt = new Date().toISOString();
|
|
412
|
+
target.getRange(startRow, 1, pending.length, RECEIPT_HEADERS.length).setValues(pending.map(function (entry) {
|
|
413
|
+
return [entry.row.effectId, entry.payloadHash, "applied", entry.visibleHash, 1, updatedAt];
|
|
414
|
+
}));
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function setDateNumberFormats_(targetSheet, range, startRow, pending) {
|
|
418
|
+
args.headers.forEach(function (header, columnIndex) {
|
|
419
|
+
var isDateColumn = pending.every(function (entry) {
|
|
420
|
+
var cell = entry.row.fields[header];
|
|
421
|
+
return cell === null || cell === undefined || cell.kind === "date";
|
|
422
|
+
});
|
|
423
|
+
if (isDateColumn) {
|
|
424
|
+
targetSheet.getRange(startRow, range.startColumn + columnIndex, pending.length, 1)
|
|
425
|
+
.setNumberFormat("yyyy\"-\"mm\"-\"dd\"T\"hh:mm:ss.000\"Z\"");
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function assertAppendPostcondition_(targetSheet, range, pending) {
|
|
431
|
+
pending.forEach(function (entry) {
|
|
432
|
+
var rowNumber = findReceiptRowNumber_(targetSheet, range, entry.row);
|
|
433
|
+
if (rowNumber === null) {
|
|
434
|
+
throw new Error("append postcondition row is unavailable for effectId: " + entry.row.effectId);
|
|
435
|
+
}
|
|
436
|
+
var values = targetSheet.getRange(rowNumber, range.startColumn, 1, range.columnCount).getValues()[0];
|
|
437
|
+
var fields = Object.create(null);
|
|
438
|
+
args.headers.forEach(function (header, headerIndex) {
|
|
439
|
+
fields[header] = normalizedCellFromSheetValue_(values[headerIndex]);
|
|
440
|
+
});
|
|
441
|
+
if (visibleHash_(fields) !== entry.visibleHash) {
|
|
442
|
+
throw new Error("append postcondition changed for effectId: " + entry.row.effectId);
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function toSheetValue_(value) {
|
|
448
|
+
if (value === null || value === undefined) return "";
|
|
449
|
+
if (value.kind === "date") return new Date(value.value);
|
|
450
|
+
return value.value;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function parseRange_(value) {
|
|
454
|
+
var parts = value.split(":");
|
|
455
|
+
var startColumn = columnNumber_(parts[0]);
|
|
456
|
+
var endColumn = columnNumber_(parts[1]);
|
|
457
|
+
if (endColumn < startColumn) throw new Error("batch append range is invalid");
|
|
458
|
+
return { startColumn: startColumn, columnCount: endColumn - startColumn + 1 };
|
|
459
|
+
}
|
|
460
|
+
function columnNumber_(letters) {
|
|
461
|
+
var value = 0;
|
|
462
|
+
for (var index = 0; index < letters.length; index += 1) value = value * 26 + letters.charCodeAt(index) - 64;
|
|
463
|
+
return value;
|
|
464
|
+
}
|
|
465
|
+
function phase_(name, startedAt) { phases.push({ phase: name, durationMs: Date.now() - startedAt }); }
|
|
466
|
+
function appendPhase_(result, name, durationMs) {
|
|
467
|
+
if (!result || !result.timing) return;
|
|
468
|
+
// Keep the script-lock wait/hold duration as a diagnostic phase, but do
|
|
469
|
+
// not fold it into the total: durationMs already measures the whole
|
|
470
|
+
// operation including the lock wait, so adding the nested phase would
|
|
471
|
+
// double-count the elapsed time.
|
|
472
|
+
result.timing.phases.push({ phase: name, durationMs: durationMs });
|
|
473
|
+
}
|
|
474
|
+
}`;
|
|
475
|
+
function validateBatchAppendRequest(request) {
|
|
476
|
+
if (request.authority !== undefined &&
|
|
477
|
+
(!Number.isSafeInteger(request.authority.epoch) || request.authority.epoch < 1 ||
|
|
478
|
+
request.authority.token.trim().length === 0)) {
|
|
479
|
+
invalidOperationRequest("batch append operation", "authority is invalid");
|
|
480
|
+
}
|
|
481
|
+
if (request.sheetName.trim().length === 0) {
|
|
482
|
+
invalidOperationRequest("batch append operation", "sheetName is required");
|
|
483
|
+
}
|
|
484
|
+
if (!/^[A-Z]+:[A-Z]+$/.test(request.registeredRange)) {
|
|
485
|
+
invalidOperationRequest("batch append operation", "registeredRange is invalid");
|
|
486
|
+
}
|
|
487
|
+
if (request.headers.length === 0 || request.headers.some((header) => header.trim().length === 0)) {
|
|
488
|
+
invalidOperationRequest("batch append operation", "headers must contain non-empty names");
|
|
489
|
+
}
|
|
490
|
+
if (new Set(request.headers).size !== request.headers.length) {
|
|
491
|
+
invalidOperationRequest("batch append operation", "headers must not contain duplicates");
|
|
492
|
+
}
|
|
493
|
+
if (request.identityField === undefined || request.identityField.trim().length === 0) {
|
|
494
|
+
invalidOperationRequest("batch append operation", "identityField is required");
|
|
495
|
+
}
|
|
496
|
+
if (!request.headers.includes(request.identityField)) {
|
|
497
|
+
invalidOperationRequest("batch append operation", "identityField must be a registered header");
|
|
498
|
+
}
|
|
499
|
+
const [start, end] = request.registeredRange.split(":");
|
|
500
|
+
if (columnNumber(end) < columnNumber(start) || columnNumber(end) - columnNumber(start) + 1 !== request.headers.length) {
|
|
501
|
+
invalidOperationRequest("batch append operation", "headers must match registeredRange");
|
|
502
|
+
}
|
|
503
|
+
const effectIds = new Set();
|
|
504
|
+
const expectedFieldNames = [...request.headers].sort();
|
|
505
|
+
for (const row of request.rows) {
|
|
506
|
+
if (row.effectId.trim().length === 0 || effectIds.has(row.effectId)) {
|
|
507
|
+
invalidOperationRequest("batch append operation", "effectIds must be non-empty and unique");
|
|
508
|
+
}
|
|
509
|
+
effectIds.add(row.effectId);
|
|
510
|
+
const fieldNames = Object.keys(row.fields).sort();
|
|
511
|
+
if (fieldNames.length !== expectedFieldNames.length || fieldNames.some((field, index) => field !== expectedFieldNames[index])) {
|
|
512
|
+
invalidOperationRequest("batch append operation", "rows must contain exactly the registered headers");
|
|
513
|
+
}
|
|
514
|
+
if (row.payloadHash === undefined || row.payloadHash.trim().length === 0) {
|
|
515
|
+
invalidOperationRequest("batch append operation", "every row needs a payloadHash");
|
|
516
|
+
}
|
|
517
|
+
if (row.anchor !== undefined && row.anchor.trim().length === 0) {
|
|
518
|
+
invalidOperationRequest("batch append operation", "row anchor must be non-empty");
|
|
519
|
+
}
|
|
520
|
+
for (const cell of Object.values(row.fields)) {
|
|
521
|
+
if (!isNormalizedCell(cell))
|
|
522
|
+
invalidOperationRequest("batch append operation", "rows contain an invalid normalized cell");
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
function columnNumber(value) {
|
|
527
|
+
if (value === undefined || value.length === 0)
|
|
528
|
+
return 0;
|
|
529
|
+
let result = 0;
|
|
530
|
+
for (const letter of value)
|
|
531
|
+
result = result * 26 + letter.charCodeAt(0) - 64;
|
|
532
|
+
return result;
|
|
533
|
+
}
|
|
534
|
+
function decodeBatchAppendResult(value, expectedRows) {
|
|
535
|
+
if (!isRecord(value) || !Array.isArray(value.results) || value.results.length !== expectedRows.length || value.hasMore !== false) {
|
|
536
|
+
return invalidOperationResponse("batch append operation", "result must contain all rows and hasMore=false");
|
|
537
|
+
}
|
|
538
|
+
const timing = decodeOptionalSyncGatewayTiming(value.timing, "batch append timing");
|
|
539
|
+
const results = value.results.map((entry) => {
|
|
540
|
+
if (!isRecord(entry) || typeof entry.effectId !== "string" || entry.status !== SYNC_GATEWAY_FAST_APPEND_STATUSES.APPLIED) {
|
|
541
|
+
return invalidOperationResponse("batch append operation", "result contains an invalid row");
|
|
542
|
+
}
|
|
543
|
+
const hasVisibleHash = Object.prototype.hasOwnProperty.call(entry, "visibleHash");
|
|
544
|
+
const hasVisibleRevision = Object.prototype.hasOwnProperty.call(entry, "visibleRevision");
|
|
545
|
+
if (hasVisibleHash !== hasVisibleRevision ||
|
|
546
|
+
(hasVisibleHash && (typeof entry.visibleHash !== "string" || entry.visibleHash.length === 0 ||
|
|
547
|
+
typeof entry.visibleRevision !== "number" || !Number.isSafeInteger(entry.visibleRevision) || entry.visibleRevision < 1))) {
|
|
548
|
+
return invalidOperationResponse("batch append operation", "result contains invalid receipt evidence");
|
|
549
|
+
}
|
|
550
|
+
return hasVisibleHash
|
|
551
|
+
? {
|
|
552
|
+
effectId: entry.effectId,
|
|
553
|
+
status: SYNC_GATEWAY_FAST_APPEND_STATUSES.APPLIED,
|
|
554
|
+
visibleHash: entry.visibleHash,
|
|
555
|
+
visibleRevision: entry.visibleRevision,
|
|
556
|
+
}
|
|
557
|
+
: { effectId: entry.effectId, status: SYNC_GATEWAY_FAST_APPEND_STATUSES.APPLIED };
|
|
558
|
+
});
|
|
559
|
+
const expectedIds = new Set(expectedRows.map((row) => row.effectId));
|
|
560
|
+
const actualIds = new Set(results.map((row) => row.effectId));
|
|
561
|
+
if (actualIds.size !== results.length || actualIds.size !== expectedIds.size || results.some((row) => !expectedIds.has(row.effectId))) {
|
|
562
|
+
return invalidOperationResponse("batch append operation", "result effectIds do not match submitted rows");
|
|
563
|
+
}
|
|
564
|
+
const result = { results, hasMore: false };
|
|
565
|
+
return timing === undefined ? result : { ...result, timing };
|
|
566
|
+
}
|
|
567
|
+
//# sourceMappingURL=batchAppendOperation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batchAppendOperation.js","sourceRoot":"","sources":["../../../../../../../src/adapter/sheets/providers/apps-script-gateway/operations/write/batchAppendOperation.ts"],"names":[],"mappings":"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"}
|
package/dist/adapter/sheets/providers/apps-script-gateway/operations/write/fastAppendOperation.d.ts
CHANGED
|
@@ -1,24 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
import {
|
|
1
|
+
/** Compatibility name for the idempotent built-in Apps Script append operation. */
|
|
2
|
+
import type { FastAppendRowsResult } from "../../../../../../application/sync/gateway/syncGateway.js";
|
|
3
3
|
import type { AppsScriptOperationDefinition } from "../../transport/operationClient.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
readonly headers: readonly string[];
|
|
9
|
-
readonly rows: readonly FastAppendRow[];
|
|
10
|
-
};
|
|
11
|
-
/** Input required to create one thin-Gateway fast-append operation. */
|
|
12
|
-
export interface AppsScriptFastAppendOperationRequest extends AppsScriptFastAppendOperationArgs {
|
|
13
|
-
}
|
|
14
|
-
/** A typed operation definition for one contiguous Sheet range write. */
|
|
4
|
+
import { type AppsScriptBatchAppendOperationArgs } from "./batchAppendOperation.js";
|
|
5
|
+
/** Arguments retained for callers of the historical fast-append name. */
|
|
6
|
+
export type AppsScriptFastAppendOperationArgs = AppsScriptBatchAppendOperationArgs;
|
|
7
|
+
export type AppsScriptFastAppendOperationRequest = AppsScriptFastAppendOperationArgs;
|
|
15
8
|
export type AppsScriptFastAppendOperation = AppsScriptOperationDefinition<AppsScriptFastAppendOperationArgs, FastAppendRowsResult>;
|
|
16
9
|
/**
|
|
17
|
-
* Builds
|
|
10
|
+
* Builds the current idempotent built-in Apps Script append operation.
|
|
11
|
+
* The old name remains internal compatibility only; transport callers now use
|
|
12
|
+
* createBatchAppendRowsOperation directly.
|
|
18
13
|
*
|
|
19
|
-
* The
|
|
20
|
-
*
|
|
21
|
-
*
|
|
14
|
+
* The registered identityField is required: the built-in append path never
|
|
15
|
+
* materializes anchor metadata, so replay locates the target row through the
|
|
16
|
+
* identity column and fails closed when it is missing.
|
|
22
17
|
*/
|
|
23
18
|
export declare function createFastAppendRowsOperation(request: AppsScriptFastAppendOperationRequest): AppsScriptFastAppendOperation;
|
|
24
19
|
//# sourceMappingURL=fastAppendOperation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fastAppendOperation.d.ts","sourceRoot":"","sources":["../../../../../../../src/adapter/sheets/providers/apps-script-gateway/operations/write/fastAppendOperation.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"fastAppendOperation.d.ts","sourceRoot":"","sources":["../../../../../../../src/adapter/sheets/providers/apps-script-gateway/operations/write/fastAppendOperation.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAEnF,OAAO,KAAK,EAEV,oBAAoB,EACrB,MAAM,2DAA2D,CAAC;AAInE,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACxF,OAAO,EAEL,KAAK,kCAAkC,EACxC,MAAM,2BAA2B,CAAC;AAEnC,yEAAyE;AACzE,MAAM,MAAM,iCAAiC,GAAG,kCAAkC,CAAC;AACnF,MAAM,MAAM,oCAAoC,GAAG,iCAAiC,CAAC;AACrF,MAAM,MAAM,6BAA6B,GAAG,6BAA6B,CACvE,iCAAiC,EACjC,oBAAoB,CACrB,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,oCAAoC,GAC5C,6BAA6B,CAa/B"}
|