hikoutei 0.5.0 → 0.5.2
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/dist/adapter/sheets/providers/google-sheets-api/GoogleSheetsApiSyncProvider.d.ts +5 -15
- package/dist/adapter/sheets/providers/google-sheets-api/GoogleSheetsApiSyncProvider.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/GoogleSheetsApiSyncProvider.js +33 -945
- package/dist/adapter/sheets/providers/google-sheets-api/GoogleSheetsApiSyncProvider.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/planner.d.ts +14 -20
- package/dist/adapter/sheets/providers/google-sheets-api/model/planner.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/planner.js +16 -200
- package/dist/adapter/sheets/providers/google-sheets-api/model/planner.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/plannerDeletion.d.ts +14 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/plannerDeletion.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/plannerDeletion.js +37 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/plannerDeletion.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/plannerReceipt.d.ts +19 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/plannerReceipt.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/plannerReceipt.js +76 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/plannerReceipt.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/plannerWorkingRow.d.ts +23 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/plannerWorkingRow.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/plannerWorkingRow.js +122 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/plannerWorkingRow.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflight.d.ts +15 -222
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflight.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflight.js +14 -687
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflight.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightContext.d.ts +125 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightContext.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightContext.js +161 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightContext.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightFields.d.ts +67 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightFields.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightFields.js +94 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightFields.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightHeaders.d.ts +24 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightHeaders.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightHeaders.js +52 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightHeaders.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightParsing.d.ts +23 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightParsing.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightParsing.js +239 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightParsing.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightRows.d.ts +53 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightRows.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightRows.js +198 -0
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightRows.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/anchors.d.ts +21 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/anchors.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/anchors.js +57 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/anchors.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/applyEffects.d.ts +19 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/applyEffects.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/applyEffects.js +188 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/applyEffects.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/fastAppend.d.ts +13 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/fastAppend.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/fastAppend.js +229 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/fastAppend.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/preflightOp.d.ts +27 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/preflightOp.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/preflightOp.js +54 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/preflightOp.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/provisioning.d.ts +28 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/provisioning.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/provisioning.js +256 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/provisioning.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/readRows.d.ts +40 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/readRows.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/readRows.js +186 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/readRows.js.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/shared.d.ts +57 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/shared.d.ts.map +1 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/shared.js +130 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/shared.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply-effects operation for the Google Sheets API sync provider.
|
|
3
|
+
*
|
|
4
|
+
* Applies regular update/delete/create effects through one atomic batch:
|
|
5
|
+
* schema-error effects sit before the included run, rejected plans
|
|
6
|
+
* (guard/schema/repair outcomes) contribute no requests, inline mode
|
|
7
|
+
* verifies written rows with a re-read, and deferred mode relies on the
|
|
8
|
+
* atomic target+receipt batch. Response-loss recovery classifies effects
|
|
9
|
+
* through a fresh target+receipt read.
|
|
10
|
+
*/
|
|
11
|
+
import type { ApplySyncEffectsRequest, ApplySyncEffectsResult, ReadSyncEffectPostconditionsRequest, SyncEffectPostcondition, SyncEffectPostconditionResult, SyncProjectionEffect } from "../../../../../application/sync/sheets/syncSheets.js";
|
|
12
|
+
import { type GoogleSheetsApiProviderDeps } from "./shared.js";
|
|
13
|
+
/** Applies regular update/delete/create effects through one atomic batch. */
|
|
14
|
+
export declare function applyEffects(deps: GoogleSheetsApiProviderDeps, request: ApplySyncEffectsRequest): Promise<ApplySyncEffectsResult>;
|
|
15
|
+
/** Classifies one response-loss effect through a fresh target+receipt read. */
|
|
16
|
+
export declare function readEffectPostcondition(deps: GoogleSheetsApiProviderDeps, effect: SyncProjectionEffect): Promise<SyncEffectPostcondition>;
|
|
17
|
+
/** Classifies a recovery batch with one shared target+receipt read. */
|
|
18
|
+
export declare function readEffectPostconditions(deps: GoogleSheetsApiProviderDeps, request: ReadSyncEffectPostconditionsRequest): Promise<readonly SyncEffectPostconditionResult[]>;
|
|
19
|
+
//# sourceMappingURL=applyEffects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyEffects.d.ts","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/operations/applyEffects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,uBAAuB,EACvB,sBAAsB,EACtB,mCAAmC,EACnC,uBAAuB,EACvB,6BAA6B,EAE7B,oBAAoB,EACrB,MAAM,sDAAsD,CAAC;AAqB9D,OAAO,EAML,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAC;AAGrB,6EAA6E;AAC7E,wBAAsB,YAAY,CAChC,IAAI,EAAE,2BAA2B,EACjC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,sBAAsB,CAAC,CAyHjC;AAED,+EAA+E;AAC/E,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,2BAA2B,EACjC,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,uBAAuB,CAAC,CAalC;AAED,uEAAuE;AACvE,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,2BAA2B,EACjC,OAAO,EAAE,mCAAmC,GAC3C,OAAO,CAAC,SAAS,6BAA6B,EAAE,CAAC,CAanD"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply-effects operation for the Google Sheets API sync provider.
|
|
3
|
+
*
|
|
4
|
+
* Applies regular update/delete/create effects through one atomic batch:
|
|
5
|
+
* schema-error effects sit before the included run, rejected plans
|
|
6
|
+
* (guard/schema/repair outcomes) contribute no requests, inline mode
|
|
7
|
+
* verifies written rows with a re-read, and deferred mode relies on the
|
|
8
|
+
* atomic target+receipt batch. Response-loss recovery classifies effects
|
|
9
|
+
* through a fresh target+receipt read.
|
|
10
|
+
*/
|
|
11
|
+
import { SYNC_POSTCONDITION_MODES } from "../../../../../application/sync/sheets/constants.js";
|
|
12
|
+
import { presentValue, absentValue } from "../../../../../shared/state/index.js";
|
|
13
|
+
import { GOOGLE_SHEETS_API_DEFAULTS, GOOGLE_SHEETS_API_EFFECT_REASONS } from "../constants.js";
|
|
14
|
+
import { invalidProviderRequest, invalidProviderState } from "../errors.js";
|
|
15
|
+
import { currentHash, encodeOutcomeResult, encodeSchemaErrorResult, planEffectBatch, withDeferredPostcondition, } from "../model/planner.js";
|
|
16
|
+
import { buildAppendBatchRequests, buildApplyBatchRequests, resolveApplyBatchBudget, } from "../model/batchBuilder.js";
|
|
17
|
+
import { classifyPostcondition } from "../model/postcondition.js";
|
|
18
|
+
import { definitionForPhysicalSheet, effectRouteOptions, requireValidBatchUpdateReply, runWrite, validateRoute, } from "./shared.js";
|
|
19
|
+
import { readPreflight } from "./preflightOp.js";
|
|
20
|
+
/** Applies regular update/delete/create effects through one atomic batch. */
|
|
21
|
+
export async function applyEffects(deps, request) {
|
|
22
|
+
const definition = definitionForPhysicalSheet(deps, request.physicalSheetId);
|
|
23
|
+
validateRoute(request, definition);
|
|
24
|
+
if (request.effects.length === 0) {
|
|
25
|
+
invalidProviderRequest("apply effects", "effects must not be empty");
|
|
26
|
+
}
|
|
27
|
+
const bounded = request.effects.slice(0, GOOGLE_SHEETS_API_DEFAULTS.MAX_EFFECTS_PER_REQUEST);
|
|
28
|
+
const postconditionMode = request.postconditionMode ?? SYNC_POSTCONDITION_MODES.INLINE;
|
|
29
|
+
if (postconditionMode !== SYNC_POSTCONDITION_MODES.INLINE &&
|
|
30
|
+
postconditionMode !== SYNC_POSTCONDITION_MODES.DEFERRED) {
|
|
31
|
+
invalidProviderRequest("apply effects", "postconditionMode must be inline or deferred");
|
|
32
|
+
}
|
|
33
|
+
const routeOptions = effectRouteOptions(definition);
|
|
34
|
+
const context = await readPreflight(deps, request, definition, routeOptions);
|
|
35
|
+
const plans = planEffectBatch({ ...request, effects: bounded }, context);
|
|
36
|
+
const includeReceipts = postconditionMode === SYNC_POSTCONDITION_MODES.DEFERRED;
|
|
37
|
+
const updatedAt = new Date(deps.now()).toISOString();
|
|
38
|
+
const resolution = resolveApplyBatchBudget(context, plans, {
|
|
39
|
+
maxBatchBytes: deps.maxBatchBytes,
|
|
40
|
+
includeReceipts,
|
|
41
|
+
updatedAt,
|
|
42
|
+
});
|
|
43
|
+
const schemaErrorIndices = new Set(resolution.schemaErrorIndices);
|
|
44
|
+
// Schema-error effects sit BEFORE the included run; the batch only carries
|
|
45
|
+
// the plans after them, up to the resolved include count. The included
|
|
46
|
+
// effects are re-planned so appended rows start at the sheet's first free
|
|
47
|
+
// row (the full-plan row numbers would leave blank gaps for excluded
|
|
48
|
+
// effects). The planner is deterministic over the unchanged context, so
|
|
49
|
+
// outcomes and receipts are identical to the budget-resolution plans.
|
|
50
|
+
const includedStart = resolution.schemaErrorIndices.length;
|
|
51
|
+
const includedEffects = bounded.slice(includedStart, resolution.includeCount);
|
|
52
|
+
const included = planEffectBatch({ ...request, effects: includedEffects }, context);
|
|
53
|
+
if (included.length > 0) {
|
|
54
|
+
const batch = buildApplyBatchRequests(context, included, { updatedAt, includeReceipts });
|
|
55
|
+
// Rejected plans (guard/schema/repair outcomes) contribute no requests;
|
|
56
|
+
// never send an empty batchUpdate for an all-rejected prefix.
|
|
57
|
+
if (batch.requests.length > 0) {
|
|
58
|
+
const response = await runWrite(deps, () => deps.transport.batchUpdate({
|
|
59
|
+
spreadsheetId: deps.spreadsheetId,
|
|
60
|
+
requests: batch.requests,
|
|
61
|
+
}));
|
|
62
|
+
requireValidBatchUpdateReply(response, batch.requests.length);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Inline verification reads the written rows back and demotes any hash
|
|
66
|
+
// mismatch to retryable_error, mirroring the Apps Script inline path. The
|
|
67
|
+
// worker always uses deferred mode, where the atomic batch already carries
|
|
68
|
+
// target mutations and receipts together.
|
|
69
|
+
const verified = new Set();
|
|
70
|
+
if (postconditionMode === SYNC_POSTCONDITION_MODES.INLINE && included.length > 0) {
|
|
71
|
+
const verifyContext = await readPreflight(deps, request, definition, routeOptions);
|
|
72
|
+
included.forEach((plan, index) => {
|
|
73
|
+
if (!plan.verify || plan.mutation === undefined || plan.mutation.kind === "delete")
|
|
74
|
+
return;
|
|
75
|
+
const row = findProbeRowInContext(verifyContext, plan);
|
|
76
|
+
const current = row === undefined ? undefined : currentHash(row, plan.outcome.effect.payload.fields);
|
|
77
|
+
if (current === plan.outcome.effect.payload.targetVisibleHash) {
|
|
78
|
+
verified.add(index);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
const verifyReceipts = [];
|
|
82
|
+
included.forEach((plan, index) => {
|
|
83
|
+
if (plan.receipt === undefined)
|
|
84
|
+
return;
|
|
85
|
+
// Replay receipts are already stored in the sheet; never rewrite them.
|
|
86
|
+
if (context.receipts.has(plan.receipt.effectId))
|
|
87
|
+
return;
|
|
88
|
+
if (plan.outcome.kind === "applied" && !plan.outcome.deletion && !verified.has(index))
|
|
89
|
+
return;
|
|
90
|
+
verifyReceipts.push(plan.receipt);
|
|
91
|
+
});
|
|
92
|
+
if (verifyReceipts.length > 0) {
|
|
93
|
+
const receiptBatch = buildAppendBatchRequests(context, [], verifyReceipts, { updatedAt });
|
|
94
|
+
const response = await runWrite(deps, () => deps.transport.batchUpdate({
|
|
95
|
+
spreadsheetId: deps.spreadsheetId,
|
|
96
|
+
requests: receiptBatch.requests,
|
|
97
|
+
}));
|
|
98
|
+
requireValidBatchUpdateReply(response, receiptBatch.requests.length);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const results = [];
|
|
102
|
+
let includedCursor = 0;
|
|
103
|
+
bounded.forEach((effect, index) => {
|
|
104
|
+
if (schemaErrorIndices.has(index)) {
|
|
105
|
+
results.push(encodeSchemaErrorResult(effect, GOOGLE_SHEETS_API_EFFECT_REASONS.EFFECT_PAYLOAD_TOO_LARGE));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (index >= resolution.includeCount)
|
|
109
|
+
return;
|
|
110
|
+
const planIndex = includedCursor;
|
|
111
|
+
includedCursor += 1;
|
|
112
|
+
const plan = included[planIndex];
|
|
113
|
+
if (plan === undefined)
|
|
114
|
+
return;
|
|
115
|
+
let result = encodeOutcomeResult(plan.outcome);
|
|
116
|
+
if (postconditionMode === SYNC_POSTCONDITION_MODES.INLINE &&
|
|
117
|
+
plan.outcome.kind === "applied" &&
|
|
118
|
+
!plan.outcome.deletion &&
|
|
119
|
+
!verified.has(planIndex)) {
|
|
120
|
+
result = {
|
|
121
|
+
...result,
|
|
122
|
+
status: "retryable_error",
|
|
123
|
+
visibleRevision: absentValue(),
|
|
124
|
+
visibleHash: absentValue(),
|
|
125
|
+
reason: presentValue(GOOGLE_SHEETS_API_EFFECT_REASONS.POSTCONDITION_HASH_MISMATCH),
|
|
126
|
+
postcondition: "unavailable",
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
else if (postconditionMode === SYNC_POSTCONDITION_MODES.DEFERRED) {
|
|
130
|
+
result = withDeferredPostcondition(result);
|
|
131
|
+
}
|
|
132
|
+
results.push(result);
|
|
133
|
+
});
|
|
134
|
+
return {
|
|
135
|
+
results,
|
|
136
|
+
snapshotHash: absentValue(),
|
|
137
|
+
hasMore: bounded.length < request.effects.length || results.length < bounded.length,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/** Classifies one response-loss effect through a fresh target+receipt read. */
|
|
141
|
+
export async function readEffectPostcondition(deps, effect) {
|
|
142
|
+
const [result] = await readEffectPostconditions(deps, {
|
|
143
|
+
physicalSheetId: effect.physicalSheetId,
|
|
144
|
+
sheetName: effect.payload.sheetName,
|
|
145
|
+
registeredRange: effect.payload.registeredRange,
|
|
146
|
+
projection: effect.projection,
|
|
147
|
+
schemaVersion: effect.payload.schemaVersion,
|
|
148
|
+
effects: [effect],
|
|
149
|
+
});
|
|
150
|
+
if (result === undefined) {
|
|
151
|
+
invalidProviderState("postcondition read returned no result");
|
|
152
|
+
}
|
|
153
|
+
return result.postcondition;
|
|
154
|
+
}
|
|
155
|
+
/** Classifies a recovery batch with one shared target+receipt read. */
|
|
156
|
+
export async function readEffectPostconditions(deps, request) {
|
|
157
|
+
const definition = definitionForPhysicalSheet(deps, request.physicalSheetId);
|
|
158
|
+
validateRoute(request, definition);
|
|
159
|
+
if (request.effects.length === 0) {
|
|
160
|
+
invalidProviderRequest("postcondition reads", "effects must not be empty");
|
|
161
|
+
}
|
|
162
|
+
const routeOptions = effectRouteOptions(definition);
|
|
163
|
+
const context = await readPreflight(deps, request, definition, routeOptions);
|
|
164
|
+
return request.effects.map((effect) => ({
|
|
165
|
+
effectId: effect.effectId,
|
|
166
|
+
payloadHash: effect.payloadHash,
|
|
167
|
+
postcondition: classifyPostcondition(context, effect, context.receipts),
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
170
|
+
/** Locates one planned write's row in a fresh verification context. */
|
|
171
|
+
function findProbeRowInContext(context, plan) {
|
|
172
|
+
const mutation = plan.mutation;
|
|
173
|
+
if (mutation === undefined)
|
|
174
|
+
return undefined;
|
|
175
|
+
if (mutation.kind === "append") {
|
|
176
|
+
return context.rows.find((row) => row.rowNumber === mutation.row.rowNumber);
|
|
177
|
+
}
|
|
178
|
+
const anchor = mutation.row.anchor;
|
|
179
|
+
if (anchor.kind === "present") {
|
|
180
|
+
return context.rows.find((row) => row.physicalAnchor.kind === "present" && row.physicalAnchor.value === anchor.value);
|
|
181
|
+
}
|
|
182
|
+
const identity = mutation.row.identity;
|
|
183
|
+
if (identity.kind === "present") {
|
|
184
|
+
return context.rows.find((row) => row.identity.kind === "present" && row.identity.value === identity.value);
|
|
185
|
+
}
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=applyEffects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyEffects.js","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/operations/applyEffects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAWH,OAAO,EAAE,wBAAwB,EAAE,MAAM,qDAAqD,CAAC;AAC/F,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,EAAE,0BAA0B,EAAE,gCAAgC,EAAE,MAAM,iBAAiB,CAAC;AAC/F,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAE5E,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,uBAAuB,EACvB,eAAe,EACf,yBAAyB,GAG1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EACL,0BAA0B,EAC1B,kBAAkB,EAClB,4BAA4B,EAC5B,QAAQ,EACR,aAAa,GAEd,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAiC,EACjC,OAAgC;IAEhC,MAAM,UAAU,GAAG,0BAA0B,CAAC,IAAI,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC7E,aAAa,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACnC,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,sBAAsB,CAAC,eAAe,EAAE,2BAA2B,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,0BAA0B,CAAC,uBAAuB,CAAC,CAAC;IAC7F,MAAM,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,IAAI,wBAAwB,CAAC,MAAM,CAAC;IACvF,IACE,iBAAiB,KAAK,wBAAwB,CAAC,MAAM;QACrD,iBAAiB,KAAK,wBAAwB,CAAC,QAAQ,EACvD,CAAC;QACD,sBAAsB,CAAC,eAAe,EAAE,8CAA8C,CAAC,CAAC;IAC1F,CAAC;IACD,MAAM,YAAY,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,eAAe,CAAC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;IACzE,MAAM,eAAe,GAAG,iBAAiB,KAAK,wBAAwB,CAAC,QAAQ,CAAC;IAChF,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACrD,MAAM,UAAU,GAAG,uBAAuB,CAAC,OAAO,EAAE,KAAK,EAAE;QACzD,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,eAAe;QACf,SAAS;KACV,CAAC,CAAC;IACH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;IAClE,2EAA2E;IAC3E,uEAAuE;IACvE,0EAA0E;IAC1E,qEAAqE;IACrE,wEAAwE;IACxE,sEAAsE;IACtE,MAAM,aAAa,GAAG,UAAU,CAAC,kBAAkB,CAAC,MAAM,CAAC;IAC3D,MAAM,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IAC9E,MAAM,QAAQ,GAAG,eAAe,CAAC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,OAAO,CAAC,CAAC;IACpF,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,uBAAuB,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,CAAC;QACzF,wEAAwE;QACxE,8DAA8D;QAC9D,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,CACzC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;gBACzB,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,QAAQ,EAAE,KAAK,CAAC,QAAQ;aACzB,CAAC,CAAC,CAAC;YACN,4BAA4B,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,uEAAuE;IACvE,0EAA0E;IAC1E,2EAA2E;IAC3E,0CAA0C;IAC1C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,IAAI,iBAAiB,KAAK,wBAAwB,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjF,MAAM,aAAa,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;QACnF,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAC/B,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO;YAC3F,MAAM,GAAG,GAAG,qBAAqB,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;YACvD,MAAM,OAAO,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACrG,IAAI,OAAO,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC;gBAC9D,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;QACH,CAAC,CAAC,CAAC;QACH,MAAM,cAAc,GAAqB,EAAE,CAAC;QAC5C,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAC/B,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;gBAAE,OAAO;YACvC,uEAAuE;YACvE,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;gBAAE,OAAO;YACxD,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,OAAO;YAC9F,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QACH,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,YAAY,GAAG,wBAAwB,CAAC,OAAO,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;YAC1F,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,CACzC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;gBACzB,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,QAAQ,EAAE,YAAY,CAAC,QAAQ;aAChC,CAAC,CAAC,CAAC;YACN,4BAA4B,CAAC,QAAQ,EAAE,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QAChC,IAAI,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CACV,uBAAuB,CAAC,MAAM,EAAE,gCAAgC,CAAC,wBAAwB,CAAC,CAC3F,CAAC;YACF,OAAO;QACT,CAAC;QACD,IAAI,KAAK,IAAI,UAAU,CAAC,YAAY;YAAE,OAAO;QAC7C,MAAM,SAAS,GAAG,cAAc,CAAC;QACjC,cAAc,IAAI,CAAC,CAAC;QACpB,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;QACjC,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO;QAC/B,IAAI,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/C,IACE,iBAAiB,KAAK,wBAAwB,CAAC,MAAM;YACrD,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS;YAC/B,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ;YACtB,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,EACxB,CAAC;YACD,MAAM,GAAG;gBACP,GAAG,MAAM;gBACT,MAAM,EAAE,iBAAiB;gBACzB,eAAe,EAAE,WAAW,EAAE;gBAC9B,WAAW,EAAE,WAAW,EAAE;gBAC1B,MAAM,EAAE,YAAY,CAAC,gCAAgC,CAAC,2BAA2B,CAAC;gBAClF,aAAa,EAAE,aAAa;aAC7B,CAAC;QACJ,CAAC;aAAM,IAAI,iBAAiB,KAAK,wBAAwB,CAAC,QAAQ,EAAE,CAAC;YACnE,MAAM,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IACH,OAAO;QACL,OAAO;QACP,YAAY,EAAE,WAAW,EAAE;QAC3B,OAAO,EAAE,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM;KACpF,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,IAAiC,EACjC,MAA4B;IAE5B,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,wBAAwB,CAAC,IAAI,EAAE;QACpD,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS;QACnC,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,eAAe;QAC/C,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,aAAa;QAC3C,OAAO,EAAE,CAAC,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,oBAAoB,CAAC,uCAAuC,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,MAAM,CAAC,aAAa,CAAC;AAC9B,CAAC;AAED,uEAAuE;AACvE,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,IAAiC,EACjC,OAA4C;IAE5C,MAAM,UAAU,GAAG,0BAA0B,CAAC,IAAI,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC7E,aAAa,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACnC,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,sBAAsB,CAAC,qBAAqB,EAAE,2BAA2B,CAAC,CAAC;IAC7E,CAAC;IACD,MAAM,YAAY,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;IAC7E,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACtC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,aAAa,EAAE,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC;KACxE,CAAC,CAAC,CAAC;AACN,CAAC;AAED,uEAAuE;AACvE,SAAS,qBAAqB,CAAC,OAAyB,EAAE,IAAgB;IACxE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAC/B,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC7C,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC;IACnC,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAC/B,GAAG,CAAC,cAAc,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,cAAc,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC;IACxF,CAAC;IACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;IACvC,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAC/B,GAAG,CAAC,QAAQ,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,KAAK,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fast-append operation for the Google Sheets API sync provider.
|
|
3
|
+
*
|
|
4
|
+
* Appends rows through one idempotent, atomic target+receipt batch: replay
|
|
5
|
+
* rows are recognized through the receipt tab and verified against the
|
|
6
|
+
* visible identity, pending rows pass the identity preflight, and a
|
|
7
|
+
* byte-budget deferral commits only a prefix of the pending rows.
|
|
8
|
+
*/
|
|
9
|
+
import { type FastAppendRowsRequest, type FastAppendRowsResult } from "../../../../../application/sync/sheets/syncSheets.js";
|
|
10
|
+
import { type GoogleSheetsApiProviderDeps } from "./shared.js";
|
|
11
|
+
/** Appends rows through one idempotent, atomic target+receipt batch. */
|
|
12
|
+
export declare function fastAppendRows(deps: GoogleSheetsApiProviderDeps, request: FastAppendRowsRequest): Promise<FastAppendRowsResult>;
|
|
13
|
+
//# sourceMappingURL=fastAppend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastAppend.d.ts","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/operations/fastAppend.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EAG1B,MAAM,sDAAsD,CAAC;AAiB9D,OAAO,EAML,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAC;AAGrB,wEAAwE;AACxE,wBAAsB,cAAc,CAClC,IAAI,EAAE,2BAA2B,EACjC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAiI/B"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fast-append operation for the Google Sheets API sync provider.
|
|
3
|
+
*
|
|
4
|
+
* Appends rows through one idempotent, atomic target+receipt batch: replay
|
|
5
|
+
* rows are recognized through the receipt tab and verified against the
|
|
6
|
+
* visible identity, pending rows pass the identity preflight, and a
|
|
7
|
+
* byte-budget deferral commits only a prefix of the pending rows.
|
|
8
|
+
*/
|
|
9
|
+
import { computeSyncVisibleHash, } from "../../../../../application/sync/sheets/syncSheets.js";
|
|
10
|
+
import { SYNC_SHEETS_ERROR_CODES, SyncSheetsContractError, } from "../../../../../application/sync/sheets/errors.js";
|
|
11
|
+
import { SYNC_FAST_APPEND_STATUSES } from "../../../../../application/sync/sheets/constants.js";
|
|
12
|
+
import { absentValue } from "../../../../../shared/state/index.js";
|
|
13
|
+
import { isNormalizedCell } from "../../../../../shared/encoding/index.js";
|
|
14
|
+
import { GOOGLE_SHEETS_API_DEFAULTS } from "../constants.js";
|
|
15
|
+
import { invalidProviderRequest, invalidProviderState } from "../errors.js";
|
|
16
|
+
import { identityFromNormalizedCell } from "../model/valueNormalization.js";
|
|
17
|
+
import { buildAppendBatchRequests, resolveAppendBudget, } from "../model/batchBuilder.js";
|
|
18
|
+
import { definitionForPhysicalSheet, effectRouteOptions, requireValidBatchUpdateReply, runWrite, validateRoute, } from "./shared.js";
|
|
19
|
+
import { readPreflight } from "./preflightOp.js";
|
|
20
|
+
/** Appends rows through one idempotent, atomic target+receipt batch. */
|
|
21
|
+
export async function fastAppendRows(deps, request) {
|
|
22
|
+
const definition = definitionForPhysicalSheet(deps, request.physicalSheetId);
|
|
23
|
+
validateRoute(request, definition);
|
|
24
|
+
const routeOptions = effectRouteOptions(definition);
|
|
25
|
+
if (routeOptions.identityField.kind !== "present") {
|
|
26
|
+
// The fast path never materializes anchor metadata, so a route without
|
|
27
|
+
// a registered identity cannot locate or guard its rows on replay.
|
|
28
|
+
throw new SyncSheetsContractError(SYNC_SHEETS_ERROR_CODES.INVALID_EFFECT_PAYLOAD, "fast append requires a registered identityField for route " + request.physicalSheetId);
|
|
29
|
+
}
|
|
30
|
+
if (request.rows.length === 0) {
|
|
31
|
+
invalidProviderRequest("fast append", "rows must not be empty");
|
|
32
|
+
}
|
|
33
|
+
const bounded = request.rows.slice(0, GOOGLE_SHEETS_API_DEFAULTS.MAX_APPEND_ROWS_PER_REQUEST);
|
|
34
|
+
validateAppendRows(bounded);
|
|
35
|
+
const context = await readPreflight(deps, request, definition, routeOptions);
|
|
36
|
+
validateAppendRowsAgainstHeaders(bounded, context.headers);
|
|
37
|
+
const identityField = routeOptions.identityField.value;
|
|
38
|
+
// Replay rows are recognized through the receipt tab and verified against
|
|
39
|
+
// the visible identity; pending rows go through the identity preflight.
|
|
40
|
+
const pending = [];
|
|
41
|
+
const resultsById = new Map();
|
|
42
|
+
const pendingReceipts = [];
|
|
43
|
+
for (const row of bounded) {
|
|
44
|
+
// The worker always supplies the outbox payload hash; fail closed when
|
|
45
|
+
// it is absent instead of silently falling back to the effect ID.
|
|
46
|
+
const payloadHash = row.payloadHash;
|
|
47
|
+
if (payloadHash === undefined || payloadHash.length === 0) {
|
|
48
|
+
invalidProviderRequest("fast append", `payloadHash is required for effectId: ${row.effectId}`);
|
|
49
|
+
}
|
|
50
|
+
const existing = context.receipts.get(row.effectId);
|
|
51
|
+
if (existing !== undefined) {
|
|
52
|
+
if (existing.payloadHash !== payloadHash) {
|
|
53
|
+
invalidProviderRequest("fast append", `effect ID cannot be reused with another payload: ${row.effectId}`);
|
|
54
|
+
}
|
|
55
|
+
const identity = appendIdentity(row, identityField);
|
|
56
|
+
const existingRow = findRowByIdentity(context, identity);
|
|
57
|
+
if (existingRow === undefined) {
|
|
58
|
+
invalidProviderRequest("fast append", `receipt postcondition row is unavailable for effectId: ${row.effectId}`);
|
|
59
|
+
}
|
|
60
|
+
if (computeSyncVisibleHash(existingRow.cells) !== existing.visibleHash) {
|
|
61
|
+
invalidProviderRequest("fast append", `receipt postcondition changed for effectId: ${row.effectId}`);
|
|
62
|
+
}
|
|
63
|
+
resultsById.set(row.effectId, {
|
|
64
|
+
effectId: row.effectId,
|
|
65
|
+
status: SYNC_FAST_APPEND_STATUSES.APPLIED,
|
|
66
|
+
visibleHash: existing.visibleHash,
|
|
67
|
+
visibleRevision: existing.visibleRevision,
|
|
68
|
+
});
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
pending.push(row);
|
|
72
|
+
pendingReceipts.push(makeAppendReceipt(row.effectId, payloadHash, computeSyncVisibleHash(row.fields)));
|
|
73
|
+
}
|
|
74
|
+
// Mirror the built-in append identity preflight: the registered identity
|
|
75
|
+
// must exist and be unique across the sheet and the pending batch; replay
|
|
76
|
+
// entries are exempt exactly like the real provider.
|
|
77
|
+
let deferredSuffix = false;
|
|
78
|
+
if (pending.length > 0) {
|
|
79
|
+
assertAppendIdentityAvailability(context, identityField, pending);
|
|
80
|
+
const pendingRows = pending.map((row, index) => toAppendWorkingRow(row, context.nextAppendRow + index));
|
|
81
|
+
const updatedAt = new Date(deps.now()).toISOString();
|
|
82
|
+
const resolution = resolveAppendBudget(pendingRows, (count) => buildAppendBatchRequests(context, pendingRows.slice(0, count), pendingReceipts.slice(0, count), { updatedAt }), deps.maxBatchBytes);
|
|
83
|
+
deferredSuffix = resolution.includeCount < pending.length;
|
|
84
|
+
if (resolution.includeCount > 0) {
|
|
85
|
+
const batch = buildAppendBatchRequests(context, pendingRows.slice(0, resolution.includeCount), pendingReceipts.slice(0, resolution.includeCount), { updatedAt });
|
|
86
|
+
const response = await runWrite(deps, () => deps.transport.batchUpdate({
|
|
87
|
+
spreadsheetId: deps.spreadsheetId,
|
|
88
|
+
requests: batch.requests,
|
|
89
|
+
}));
|
|
90
|
+
requireValidBatchUpdateReply(response, batch.requests.length);
|
|
91
|
+
pendingReceipts.slice(0, resolution.includeCount).forEach((receipt) => {
|
|
92
|
+
resultsById.set(receipt.effectId, {
|
|
93
|
+
effectId: receipt.effectId,
|
|
94
|
+
status: SYNC_FAST_APPEND_STATUSES.APPLIED,
|
|
95
|
+
visibleHash: receipt.visibleHash,
|
|
96
|
+
visibleRevision: receipt.visibleRevision,
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// A byte-budget deferral commits only a prefix of the pending rows, so
|
|
102
|
+
// results cover exactly the processed rows: receipt-matched replays plus
|
|
103
|
+
// the included prefix. Rows beyond the included prefix are intentionally
|
|
104
|
+
// absent from results; the worker releases them (releaseUnprocessedEffect)
|
|
105
|
+
// for the next pass when hasMore is true.
|
|
106
|
+
const results = [];
|
|
107
|
+
for (const row of bounded) {
|
|
108
|
+
const result = resultsById.get(row.effectId);
|
|
109
|
+
if (result === undefined)
|
|
110
|
+
continue;
|
|
111
|
+
results.push(result);
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
results,
|
|
115
|
+
hasMore: bounded.length < request.rows.length || deferredSuffix,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** Builds the fixed-shape receipt record used by the fast-append path. */
|
|
119
|
+
function makeAppendReceipt(effectId, payloadHash, visibleHash) {
|
|
120
|
+
return {
|
|
121
|
+
effectId,
|
|
122
|
+
payloadHash,
|
|
123
|
+
status: "applied",
|
|
124
|
+
visibleHash,
|
|
125
|
+
visibleRevision: 1,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/** Validates the append rows before any remote read or write. */
|
|
129
|
+
function validateAppendRows(rows) {
|
|
130
|
+
const seenEffectIds = new Set();
|
|
131
|
+
for (const row of rows) {
|
|
132
|
+
if (row.effectId.length === 0 || seenEffectIds.has(row.effectId)) {
|
|
133
|
+
invalidProviderRequest("fast append", "effectIds must be non-empty and unique");
|
|
134
|
+
}
|
|
135
|
+
seenEffectIds.add(row.effectId);
|
|
136
|
+
const payloadHash = row.payloadHash;
|
|
137
|
+
if (payloadHash === undefined || payloadHash.length === 0) {
|
|
138
|
+
invalidProviderRequest("fast append", "payloadHash is required");
|
|
139
|
+
}
|
|
140
|
+
if (row.anchor !== undefined && row.anchor.length === 0) {
|
|
141
|
+
invalidProviderRequest("fast append", "row anchor must be non-empty");
|
|
142
|
+
}
|
|
143
|
+
const fields = row.fields;
|
|
144
|
+
if (fields === null || typeof fields !== "object" || Array.isArray(fields)) {
|
|
145
|
+
invalidProviderRequest("fast append", "row fields must be an object");
|
|
146
|
+
}
|
|
147
|
+
if (Object.keys(fields).length === 0) {
|
|
148
|
+
invalidProviderRequest("fast append", "row fields are required");
|
|
149
|
+
}
|
|
150
|
+
for (const value of Object.values(fields)) {
|
|
151
|
+
if (!isNormalizedCell(value)) {
|
|
152
|
+
invalidProviderRequest("fast append", "row fields contain an invalid normalized cell");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/** Append rows must cover exactly the registered headers (batch append rule). */
|
|
158
|
+
function validateAppendRowsAgainstHeaders(rows, headers) {
|
|
159
|
+
const expected = [...headers].sort();
|
|
160
|
+
for (const row of rows) {
|
|
161
|
+
const actual = Object.keys(row.fields).sort();
|
|
162
|
+
if (actual.length !== expected.length ||
|
|
163
|
+
actual.some((field, index) => field !== expected[index])) {
|
|
164
|
+
invalidProviderRequest("fast append", "rows must contain exactly the registered headers");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Derives the append identity from the row's identity field cell, using the
|
|
170
|
+
* canonical identity rule (non-empty string or finite number) shared with
|
|
171
|
+
* the append/replay paths.
|
|
172
|
+
*/
|
|
173
|
+
function appendIdentity(row, identityField) {
|
|
174
|
+
const cell = row.fields[identityField] ?? null;
|
|
175
|
+
const identity = identityFromNormalizedCell(cell);
|
|
176
|
+
if (identity === null) {
|
|
177
|
+
invalidProviderRequest("fast append", `sync identity is required for append: ${identityField}`);
|
|
178
|
+
}
|
|
179
|
+
return identity;
|
|
180
|
+
}
|
|
181
|
+
/** Finds a preflight row by its visible identity (single match or fail closed). */
|
|
182
|
+
function findRowByIdentity(context, identity) {
|
|
183
|
+
const matches = context.rows.filter((row) => row.identity.kind === "present" && row.identity.value === identity);
|
|
184
|
+
if (matches.length > 1) {
|
|
185
|
+
invalidProviderState(`sync identity is duplicated: ${identity}`);
|
|
186
|
+
}
|
|
187
|
+
return matches[0];
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Mirrors the built-in append identity preflight: every existing data row
|
|
191
|
+
* needs a unique identity, and every pending non-replay row needs a fresh,
|
|
192
|
+
* non-empty identity.
|
|
193
|
+
*/
|
|
194
|
+
function assertAppendIdentityAvailability(context, identityField, pending) {
|
|
195
|
+
const existing = new Map();
|
|
196
|
+
context.rows.forEach((row) => {
|
|
197
|
+
if (row.identity.kind !== "present") {
|
|
198
|
+
invalidProviderState(`sync identity is missing at row ${row.rowNumber}`);
|
|
199
|
+
}
|
|
200
|
+
const location = existing.get(row.identity.value);
|
|
201
|
+
if (location !== undefined) {
|
|
202
|
+
invalidProviderState(`sync identity is duplicated: ${row.identity.value} at rows ${location} and ${row.rowNumber}`);
|
|
203
|
+
}
|
|
204
|
+
existing.set(row.identity.value, String(row.rowNumber));
|
|
205
|
+
});
|
|
206
|
+
for (const row of pending) {
|
|
207
|
+
const identity = appendIdentity(row, identityField);
|
|
208
|
+
const location = existing.get(identity);
|
|
209
|
+
if (location !== undefined) {
|
|
210
|
+
invalidProviderState(`sync identity already exists: ${identity} at ${location}`);
|
|
211
|
+
}
|
|
212
|
+
existing.set(identity, "pending");
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/** Builds a working row for one pending append at its reserved position. */
|
|
216
|
+
function toAppendWorkingRow(row, rowNumber) {
|
|
217
|
+
// The fast path never materializes anchor metadata (the Apps Script batch
|
|
218
|
+
// append path ignores the advisory row anchor); the row replays by identity.
|
|
219
|
+
return {
|
|
220
|
+
rowNumber,
|
|
221
|
+
anchor: absentValue(),
|
|
222
|
+
cells: { ...row.fields },
|
|
223
|
+
identity: absentValue(),
|
|
224
|
+
appended: true,
|
|
225
|
+
deleted: false,
|
|
226
|
+
writeFields: {},
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=fastAppend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastAppend.js","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/operations/fastAppend.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preflight and observation-target operations for the Google Sheets API
|
|
3
|
+
* sync provider.
|
|
4
|
+
*
|
|
5
|
+
* `readPreflight` performs the two paced transport calls every outbound
|
|
6
|
+
* effect operation needs (range-less sheet enumeration for hidden receipt
|
|
7
|
+
* tab discovery, plus one bounded data read of the target and receipt tabs).
|
|
8
|
+
* `observationTargetFor` validates one observation request and derives its
|
|
9
|
+
* snapshot build target, failing closed on unknown read modes.
|
|
10
|
+
*/
|
|
11
|
+
import type { ReadSyncSnapshotRequest } from "../../../../../application/sync/sheets/syncSheets.js";
|
|
12
|
+
import type { RegisteredSyncProjectionDefinition } from "../../../../../application/sync/sheets/sheetsProvisioning.js";
|
|
13
|
+
import type { Presence } from "../../../../../shared/state/index.js";
|
|
14
|
+
import { type PreflightContext } from "../model/preflight.js";
|
|
15
|
+
import type { SnapshotBuildTarget } from "../model/observation.js";
|
|
16
|
+
import { type GoogleSheetsApiProviderDeps } from "./shared.js";
|
|
17
|
+
/** Reads the target and receipt tabs for one route through the read lane. */
|
|
18
|
+
export declare function readPreflight(deps: GoogleSheetsApiProviderDeps, request: {
|
|
19
|
+
readonly sheetName: string;
|
|
20
|
+
readonly registeredRange: string;
|
|
21
|
+
}, definition: RegisteredSyncProjectionDefinition, routeOptions: {
|
|
22
|
+
readonly identityField: Presence<string>;
|
|
23
|
+
readonly checkboxHeaders: readonly string[];
|
|
24
|
+
}): Promise<PreflightContext>;
|
|
25
|
+
/** Validates one observation request and derives its snapshot target. */
|
|
26
|
+
export declare function observationTargetFor(deps: GoogleSheetsApiProviderDeps, request: ReadSyncSnapshotRequest): SnapshotBuildTarget;
|
|
27
|
+
//# sourceMappingURL=preflightOp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflightOp.d.ts","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/operations/preflightOp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sDAAsD,CAAC;AAOpG,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,8DAA8D,CAAC;AACvH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAErE,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAIL,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAC;AAErB,6EAA6E;AAC7E,wBAAsB,aAAa,CACjC,IAAI,EAAE,2BAA2B,EACjC,OAAO,EAAE;IACP,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC,EACD,UAAU,EAAE,kCAAkC,EAC9C,YAAY,EAAE;IACZ,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C,GACA,OAAO,CAAC,gBAAgB,CAAC,CAc3B;AAED,yEAAyE;AACzE,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,2BAA2B,EACjC,OAAO,EAAE,uBAAuB,GAC/B,mBAAmB,CA8BrB"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preflight and observation-target operations for the Google Sheets API
|
|
3
|
+
* sync provider.
|
|
4
|
+
*
|
|
5
|
+
* `readPreflight` performs the two paced transport calls every outbound
|
|
6
|
+
* effect operation needs (range-less sheet enumeration for hidden receipt
|
|
7
|
+
* tab discovery, plus one bounded data read of the target and receipt tabs).
|
|
8
|
+
* `observationTargetFor` validates one observation request and derives its
|
|
9
|
+
* snapshot build target, failing closed on unknown read modes.
|
|
10
|
+
*/
|
|
11
|
+
import { requireSyncSnapshotReadMode } from "../../../../../application/sync/sheets/validation.js";
|
|
12
|
+
import { SYNC_SNAPSHOT_READ_MODES, SYNC_PROJECTIONS, } from "../../../../../application/sync/sheets/constants.js";
|
|
13
|
+
import { SYNC_SHEETS_ERROR_CODES } from "../../../../../application/sync/sheets/errors.js";
|
|
14
|
+
import { invalidProviderRequest } from "../errors.js";
|
|
15
|
+
import { enumerateSheetProperties, readPreflightData, } from "../model/preflight.js";
|
|
16
|
+
import { definitionForPhysicalSheet, runRead, validateRoute, } from "./shared.js";
|
|
17
|
+
/** Reads the target and receipt tabs for one route through the read lane. */
|
|
18
|
+
export async function readPreflight(deps, request, definition, routeOptions) {
|
|
19
|
+
// Each preflight performs two paced transport calls: a range-less sheet
|
|
20
|
+
// enumeration (hidden receipt tab discovery) plus one ranged data read.
|
|
21
|
+
const sheets = await runRead(deps, () => enumerateSheetProperties(deps.transport, deps.spreadsheetId, deps.readTimeoutMs));
|
|
22
|
+
return runRead(deps, () => readPreflightData(deps.transport, {
|
|
23
|
+
spreadsheetId: deps.spreadsheetId,
|
|
24
|
+
sheetName: request.sheetName,
|
|
25
|
+
registeredRange: request.registeredRange,
|
|
26
|
+
headers: definition.headers,
|
|
27
|
+
identityField: routeOptions.identityField,
|
|
28
|
+
checkboxHeaders: routeOptions.checkboxHeaders,
|
|
29
|
+
}, sheets, deps.readTimeoutMs));
|
|
30
|
+
}
|
|
31
|
+
/** Validates one observation request and derives its snapshot target. */
|
|
32
|
+
export function observationTargetFor(deps, request) {
|
|
33
|
+
const definition = definitionForPhysicalSheet(deps, request.physicalSheetId);
|
|
34
|
+
validateRoute(request, definition);
|
|
35
|
+
// Fail closed on unknown readMode strings (same shared guard as the Apps
|
|
36
|
+
// Script observation operation) instead of silently reading in full mode.
|
|
37
|
+
const readMode = request.readMode === undefined
|
|
38
|
+
? SYNC_SNAPSHOT_READ_MODES.FULL
|
|
39
|
+
: requireSyncSnapshotReadMode(request.readMode, "Google Sheets API observation readMode", SYNC_SHEETS_ERROR_CODES.INVALID_EFFECT_PAYLOAD);
|
|
40
|
+
if (readMode === SYNC_SNAPSHOT_READ_MODES.USER_INPUT &&
|
|
41
|
+
request.projection !== SYNC_PROJECTIONS.USER_INPUT) {
|
|
42
|
+
invalidProviderRequest("observation", "user_input readMode requires the user_input projection");
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
sheetName: request.sheetName,
|
|
46
|
+
registeredRange: request.registeredRange,
|
|
47
|
+
projection: request.projection,
|
|
48
|
+
schemaVersion: request.schemaVersion,
|
|
49
|
+
headers: definition.headers,
|
|
50
|
+
checkboxHeaders: definition.checkboxHeaders ?? [],
|
|
51
|
+
readMode,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=preflightOp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflightOp.js","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/operations/preflightOp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,2BAA2B,EAAE,MAAM,sDAAsD,CAAC;AACnG,OAAO,EACL,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,qDAAqD,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,kDAAkD,CAAC;AAG3F,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EACL,wBAAwB,EACxB,iBAAiB,GAElB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,0BAA0B,EAC1B,OAAO,EACP,aAAa,GAEd,MAAM,aAAa,CAAC;AAErB,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAiC,EACjC,OAGC,EACD,UAA8C,EAC9C,YAGC;IAED,wEAAwE;IACxE,wEAAwE;IACxE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,CACtC,wBAAwB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;IACpF,OAAO,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,CACxB,iBAAiB,CAAC,IAAI,CAAC,SAAS,EAAE;QAChC,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,aAAa,EAAE,YAAY,CAAC,aAAa;QACzC,eAAe,EAAE,YAAY,CAAC,eAAe;KAC9C,EAAE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,oBAAoB,CAClC,IAAiC,EACjC,OAAgC;IAEhC,MAAM,UAAU,GAAG,0BAA0B,CAAC,IAAI,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC7E,aAAa,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACnC,yEAAyE;IACzE,0EAA0E;IAC1E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,KAAK,SAAS;QAC7C,CAAC,CAAC,wBAAwB,CAAC,IAAI;QAC/B,CAAC,CAAC,2BAA2B,CAC3B,OAAO,CAAC,QAAQ,EAChB,wCAAwC,EACxC,uBAAuB,CAAC,sBAAsB,CAC/C,CAAC;IACJ,IACE,QAAQ,KAAK,wBAAwB,CAAC,UAAU;QAChD,OAAO,CAAC,UAAU,KAAK,gBAAgB,CAAC,UAAU,EAClD,CAAC;QACD,sBAAsB,CACpB,aAAa,EACb,wDAAwD,CACzD,CAAC;IACJ,CAAC;IACD,OAAO;QACL,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,eAAe,EAAE,UAAU,CAAC,eAAe,IAAI,EAAE;QACjD,QAAQ;KACT,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projection provisioning for the Google Sheets API sync provider.
|
|
3
|
+
*
|
|
4
|
+
* Creates missing tabs and their header rows, or verifies existing tabs, in
|
|
5
|
+
* ONE atomic batchUpdate. An existing tab with no content anywhere in its
|
|
6
|
+
* used grid gets its headers initialized; an existing tab with content must
|
|
7
|
+
* match the registered headers exactly (order, duplicates, width), otherwise
|
|
8
|
+
* provisioning fails closed BEFORE any mutation. The operation is idempotent:
|
|
9
|
+
* a retry after a lost response re-enumerates, sees the exact headers, and
|
|
10
|
+
* succeeds without rewriting anything.
|
|
11
|
+
*/
|
|
12
|
+
import type { SyncSheetsProvisionRoute } from "../../../../../application/sync/sheets/sheetsProvisioning.js";
|
|
13
|
+
import { type GoogleSheetsApiProviderDeps } from "./shared.js";
|
|
14
|
+
/**
|
|
15
|
+
* Creates missing tabs and their header rows, or verifies existing tabs,
|
|
16
|
+
* in ONE atomic batchUpdate. An existing tab with no content anywhere in
|
|
17
|
+
* its used grid gets its headers initialized; an existing tab with content
|
|
18
|
+
* must match the registered headers exactly (order, duplicates, width),
|
|
19
|
+
* otherwise provisioning fails closed BEFORE any mutation. The operation
|
|
20
|
+
* is idempotent: a retry after a lost response re-enumerates, sees the
|
|
21
|
+
* exact headers, and succeeds without rewriting anything.
|
|
22
|
+
*/
|
|
23
|
+
export declare function provisionRegistry(deps: GoogleSheetsApiProviderDeps, registrations: readonly SyncSheetsProvisionRoute[]): Promise<{
|
|
24
|
+
readonly registrations: readonly Omit<SyncSheetsProvisionRoute, "headers">[];
|
|
25
|
+
readonly createdSheets: readonly string[];
|
|
26
|
+
readonly initializedHeaders: readonly string[];
|
|
27
|
+
}>;
|
|
28
|
+
//# sourceMappingURL=provisioning.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provisioning.d.ts","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/operations/provisioning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,8DAA8D,CAAC;AAgB7G,OAAO,EAIL,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAC;AAErB;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,2BAA2B,EACjC,aAAa,EAAE,SAAS,wBAAwB,EAAE,GACjD,OAAO,CAAC;IACT,QAAQ,CAAC,aAAa,EAAE,SAAS,IAAI,CAAC,wBAAwB,EAAE,SAAS,CAAC,EAAE,CAAC;IAC7E,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;CAChD,CAAC,CAkHD"}
|