hikoutei 0.5.3 → 0.5.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/dist/adapter/sheets/providers/google-sheets-api/constants.d.ts +26 -7
- package/dist/adapter/sheets/providers/google-sheets-api/constants.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/constants.js +26 -7
- package/dist/adapter/sheets/providers/google-sheets-api/constants.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/batchBuilder.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/batchBuilder.js +19 -13
- package/dist/adapter/sheets/providers/google-sheets-api/model/batchBuilder.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/observation.d.ts +15 -8
- package/dist/adapter/sheets/providers/google-sheets-api/model/observation.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/observation.js +40 -14
- package/dist/adapter/sheets/providers/google-sheets-api/model/observation.js.map +1 -1
- 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 +5 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/planner.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/postcondition.js +3 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/postcondition.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflight.d.ts +9 -6
- 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 +8 -5
- 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 +7 -7
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightContext.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightContext.js +10 -5
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightContext.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightFields.d.ts +7 -7
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightFields.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightFields.js +7 -10
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightFields.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightHeaders.d.ts +12 -3
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightHeaders.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightHeaders.js +41 -10
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightHeaders.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightParsing.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightParsing.js +1 -39
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightParsing.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightRows.d.ts +26 -11
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightRows.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightRows.js +77 -31
- package/dist/adapter/sheets/providers/google-sheets-api/model/preflightRows.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/tableRead.d.ts +5 -2
- package/dist/adapter/sheets/providers/google-sheets-api/model/tableRead.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/model/tableRead.js +9 -4
- package/dist/adapter/sheets/providers/google-sheets-api/model/tableRead.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/operations/anchors.d.ts +12 -9
- package/dist/adapter/sheets/providers/google-sheets-api/operations/anchors.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/operations/anchors.js +23 -15
- package/dist/adapter/sheets/providers/google-sheets-api/operations/anchors.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/operations/preflightOp.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/operations/preflightOp.js +3 -0
- package/dist/adapter/sheets/providers/google-sheets-api/operations/preflightOp.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/operations/provisioning.d.ts +6 -4
- package/dist/adapter/sheets/providers/google-sheets-api/operations/provisioning.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/operations/provisioning.js +61 -19
- package/dist/adapter/sheets/providers/google-sheets-api/operations/provisioning.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/operations/readRows.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/operations/readRows.js +13 -6
- package/dist/adapter/sheets/providers/google-sheets-api/operations/readRows.js.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/transport/googleSheetsApiTransport.d.ts +0 -7
- package/dist/adapter/sheets/providers/google-sheets-api/transport/googleSheetsApiTransport.d.ts.map +1 -1
- package/dist/adapter/sheets/providers/google-sheets-api/transport/googleSheetsApiTransport.js +0 -21
- package/dist/adapter/sheets/providers/google-sheets-api/transport/googleSheetsApiTransport.js.map +1 -1
- package/dist/application/sync/outbound/reconciliation/ReconciliationScanner.d.ts.map +1 -1
- package/dist/application/sync/outbound/reconciliation/ReconciliationScanner.js +2 -1
- package/dist/application/sync/outbound/reconciliation/ReconciliationScanner.js.map +1 -1
- package/dist/application/sync/service/syncAutoStart.d.ts +4 -3
- package/dist/application/sync/service/syncAutoStart.d.ts.map +1 -1
- package/dist/application/sync/service/syncAutoStart.js +6 -4
- package/dist/application/sync/service/syncAutoStart.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
* Preflight row normalization, indexes, and sheet/grid lookup.
|
|
3
3
|
*
|
|
4
4
|
* Nonblank target rows are normalized into typed `PreflightRow` values with
|
|
5
|
-
* their anchor evidence and visible identity; the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* their anchor evidence and visible identity; the identity index fails closed
|
|
6
|
+
* on duplicates while the anchor index keeps only the FIRST row per anchor
|
|
7
|
+
* value (duplicated anchors are evidence, never rewritten), and both derive
|
|
8
|
+
* the next append row. Sheet and grid lookup helpers resolve titles to
|
|
9
|
+
* validated grids for the preflight data read and the observation/
|
|
10
|
+
* provisioning readers.
|
|
9
11
|
*/
|
|
10
12
|
import { presentValue, absentValue } from "../../../../../shared/state/index.js";
|
|
11
|
-
import {
|
|
13
|
+
import { SYNC_PROJECTIONS } from "../../../../../application/sync/sheetsContract/constants.js";
|
|
12
14
|
import { invalidProviderState } from "../errors.js";
|
|
13
|
-
import {
|
|
15
|
+
import { apiStringValue } from "./preflightParsing.js";
|
|
16
|
+
import { identityFromNormalizedCell, isBlankApiCell, normalizedCellFromApiValue, parseRegisteredRange, } from "./valueNormalization.js";
|
|
14
17
|
export function requireSheetByTitle(sheets, title) {
|
|
15
18
|
const sheet = findSheetByTitle(sheets, title);
|
|
16
19
|
if (sheet === undefined) {
|
|
@@ -41,8 +44,11 @@ export function requireGridDataByTitle(document, sheets, title) {
|
|
|
41
44
|
return { sheet, grid };
|
|
42
45
|
}
|
|
43
46
|
/** Normalizes nonblank grid rows into typed preflight rows. */
|
|
44
|
-
export function readRows(data, range, headers, identityField) {
|
|
45
|
-
const anchorsByRow = readAnchorIndex(data);
|
|
47
|
+
export function readRows(data, range, headers, identityField, anchorColumn) {
|
|
48
|
+
const anchorsByRow = readAnchorIndex(data, anchorColumn);
|
|
49
|
+
const userFieldCount = anchorColumn === undefined
|
|
50
|
+
? range.columnCount
|
|
51
|
+
: range.columnCount - 1;
|
|
46
52
|
const rows = [];
|
|
47
53
|
for (let rowIndex = 0; rowIndex < data.rowData.length; rowIndex += 1) {
|
|
48
54
|
const rowNumber = data.startRow + 1 + rowIndex;
|
|
@@ -52,7 +58,10 @@ export function readRows(data, range, headers, identityField) {
|
|
|
52
58
|
if (rawRow === undefined)
|
|
53
59
|
continue;
|
|
54
60
|
const values = gridRowCells(data, rowNumber, range.startColumn, range.columnCount);
|
|
55
|
-
|
|
61
|
+
// The system row-id column is invisible to the blank-row rule: a row
|
|
62
|
+
// whose user fields are all blank stays blank even when the anchor cell
|
|
63
|
+
// still holds its UUID (same semantics as metadata anchors).
|
|
64
|
+
if (values.slice(0, userFieldCount).every((value) => isBlankApiCell(value)))
|
|
56
65
|
continue;
|
|
57
66
|
const cells = {};
|
|
58
67
|
headers.forEach((header, columnIndex) => {
|
|
@@ -84,34 +93,67 @@ export function readRows(data, range, headers, identityField) {
|
|
|
84
93
|
return rows;
|
|
85
94
|
}
|
|
86
95
|
/**
|
|
87
|
-
* Builds the row -> anchor-list index from
|
|
96
|
+
* Builds the row -> anchor-list index from the system row-id column.
|
|
88
97
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
98
|
+
* The anchor is the LAST column cell value of the user_input registered
|
|
99
|
+
* range: any non-empty string value counts as the row's anchor (the column
|
|
100
|
+
* position is the identity proof; the `sync-anchor:` prefix is the format of
|
|
101
|
+
* observation- and append-assigned anchors, but flush-derived anchors keep
|
|
102
|
+
* the mapping's deterministic format such as `entity:<id>`). The header row
|
|
103
|
+
* is skipped so the `__hikoutei_row_id` header cell never becomes a
|
|
104
|
+
* pseudo-anchor. Blank cells, whitespace-only cells, empty strings, and
|
|
105
|
+
* non-string values are not anchors and are treated as missing by the
|
|
106
|
+
* caller. `anchorColumn` is 1-based; projections without a system column
|
|
107
|
+
* pass `undefined` and yield no anchors.
|
|
92
108
|
*/
|
|
93
|
-
export function readAnchorIndex(data) {
|
|
109
|
+
export function readAnchorIndex(data, anchorColumn) {
|
|
94
110
|
const byRow = new Map();
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
111
|
+
if (anchorColumn === undefined)
|
|
112
|
+
return byRow;
|
|
113
|
+
for (let rowIndex = 0; rowIndex < data.rowData.length; rowIndex += 1) {
|
|
114
|
+
const rowNumber = data.startRow + 1 + rowIndex;
|
|
115
|
+
if (rowNumber < 2)
|
|
116
|
+
continue;
|
|
117
|
+
const [value] = gridRowCells(data, rowNumber, anchorColumn, 1);
|
|
118
|
+
const anchor = anchorFromColumnValue(value);
|
|
119
|
+
if (anchor !== undefined)
|
|
120
|
+
byRow.set(rowNumber, [anchor]);
|
|
121
|
+
}
|
|
103
122
|
return byRow;
|
|
104
123
|
}
|
|
105
|
-
|
|
124
|
+
/** Extracts one anchor value from a system-column cell, if any. */
|
|
125
|
+
function anchorFromColumnValue(value) {
|
|
126
|
+
const raw = apiStringValue(value);
|
|
127
|
+
// Whitespace-only cells count as missing (re-anchored), mirroring the
|
|
128
|
+
// header validation's trim rule for the system column.
|
|
129
|
+
if (raw === undefined || raw.trim().length === 0)
|
|
130
|
+
return undefined;
|
|
131
|
+
return raw;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Returns the 1-based system row-id column of one registered range, or
|
|
135
|
+
* `undefined` for projections without a system column (only user_input tabs
|
|
136
|
+
* carry one, always as the LAST column of the registered range).
|
|
137
|
+
*/
|
|
138
|
+
export function anchorColumnFor(registeredRange, projection) {
|
|
139
|
+
if (projection !== SYNC_PROJECTIONS.USER_INPUT)
|
|
140
|
+
return undefined;
|
|
141
|
+
const range = parseRegisteredRange(registeredRange);
|
|
142
|
+
return range.startColumn + range.columnCount - 1;
|
|
143
|
+
}
|
|
144
|
+
export function indexRows(rows) {
|
|
106
145
|
const byAnchor = new Map();
|
|
107
146
|
const byIdentity = new Map();
|
|
108
147
|
for (const row of rows) {
|
|
109
148
|
if (row.physicalAnchor.kind === "present") {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
149
|
+
// Duplicated anchors are evidence, never rewritten: a human copy-paste
|
|
150
|
+
// copies the UUID cell, so only the FIRST row carrying each anchor
|
|
151
|
+
// value enters the index and later rows fall back to identity/targetId
|
|
152
|
+
// lookup in findWorkingRow. The duplicate itself is still reported by
|
|
153
|
+
// the observation/anchor-ensure evidence path.
|
|
154
|
+
if (!byAnchor.has(row.physicalAnchor.value)) {
|
|
155
|
+
byAnchor.set(row.physicalAnchor.value, row);
|
|
113
156
|
}
|
|
114
|
-
byAnchor.set(row.physicalAnchor.value, row);
|
|
115
157
|
}
|
|
116
158
|
if (row.identity.kind === "present") {
|
|
117
159
|
const existing = byIdentity.get(row.identity.value);
|
|
@@ -121,10 +163,14 @@ export function indexRows(rows, data) {
|
|
|
121
163
|
byIdentity.set(row.identity.value, row);
|
|
122
164
|
}
|
|
123
165
|
}
|
|
124
|
-
// The API omits trailing empty rows from grid data, so the last
|
|
125
|
-
// the sheet's last content row; appends start one row below it
|
|
126
|
-
// matching the Apps Script nextAppendRow = max(lastRow + 1, 2)).
|
|
127
|
-
|
|
166
|
+
// The API omits trailing empty rows from grid data, so the last nonblank
|
|
167
|
+
// row is the sheet's last content row; appends start one row below it
|
|
168
|
+
// (min row 2, matching the Apps Script nextAppendRow = max(lastRow + 1, 2)).
|
|
169
|
+
// Computed from the normalized rows (not grid rowData) so a row whose only
|
|
170
|
+
// remaining content is the system anchor cell does not extend the append
|
|
171
|
+
// position, exactly like the metadata-anchor era.
|
|
172
|
+
const lastRow = rows.length === 0 ? undefined : rows[rows.length - 1]?.rowNumber;
|
|
173
|
+
const lastContentRow = lastRow === undefined ? 0 : lastRow;
|
|
128
174
|
return {
|
|
129
175
|
byAnchor,
|
|
130
176
|
byIdentity,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preflightRows.js","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/model/preflightRows.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"preflightRows.js","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/model/preflightRows.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,11 +16,14 @@ export interface TableReadTarget {
|
|
|
16
16
|
readonly registeredRange: string;
|
|
17
17
|
readonly headers: readonly string[];
|
|
18
18
|
readonly checkboxHeaders: readonly string[];
|
|
19
|
+
/** 1-based system row-id column; undefined for projections without one. */
|
|
20
|
+
readonly anchorColumn: number | undefined;
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
23
|
* Builds the nonblank rows of one validated grid as normalized table rows.
|
|
22
|
-
* Header validation is strict (exact match, non-empty, no duplicates
|
|
23
|
-
*
|
|
24
|
+
* Header validation is strict (exact match, non-empty, no duplicates; the
|
|
25
|
+
* system row-id column must close a user_input range) and blank rows are
|
|
26
|
+
* skipped with the checkbox-false rule, ignoring the system column.
|
|
24
27
|
*/
|
|
25
28
|
export declare function buildTableRowsFromGrid(grid: ParsedGridData, target: TableReadTarget): readonly SyncTableRow[];
|
|
26
29
|
//# sourceMappingURL=tableRead.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tableRead.d.ts","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/model/tableRead.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAC;
|
|
1
|
+
{"version":3,"file":"tableRead.d.ts","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/model/tableRead.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8DAA8D,CAAC;AAKjG,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAOxB,8DAA8D;AAC9D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,2EAA2E;IAC3E,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,eAAe,GACtB,SAAS,YAAY,EAAE,CAgCzB"}
|
|
@@ -9,25 +9,30 @@
|
|
|
9
9
|
* checkbox rule. Unsupported cell shapes fail closed, exactly like the Apps
|
|
10
10
|
* Script source throws.
|
|
11
11
|
*/
|
|
12
|
+
import { GOOGLE_SHEETS_API_ROW_ID_HEADER, } from "../constants.js";
|
|
12
13
|
import { invalidProviderState } from "../errors.js";
|
|
13
14
|
import { apiCellNumberFormat, gridRowCells, readRegisteredHeaders, } from "./preflight.js";
|
|
14
15
|
import { computedValueFromApiCell, isComputedBlankCell, parseRegisteredRange, } from "./valueNormalization.js";
|
|
15
16
|
/**
|
|
16
17
|
* Builds the nonblank rows of one validated grid as normalized table rows.
|
|
17
|
-
* Header validation is strict (exact match, non-empty, no duplicates
|
|
18
|
-
*
|
|
18
|
+
* Header validation is strict (exact match, non-empty, no duplicates; the
|
|
19
|
+
* system row-id column must close a user_input range) and blank rows are
|
|
20
|
+
* skipped with the checkbox-false rule, ignoring the system column.
|
|
19
21
|
*/
|
|
20
22
|
export function buildTableRowsFromGrid(grid, target) {
|
|
21
23
|
const range = parseRegisteredRange(target.registeredRange);
|
|
22
|
-
const headers = readRegisteredHeaders(grid, range, target.headers);
|
|
24
|
+
const headers = readRegisteredHeaders(grid, range, target.headers, target.anchorColumn === undefined ? undefined : GOOGLE_SHEETS_API_ROW_ID_HEADER);
|
|
23
25
|
const checkboxIndexes = checkboxColumnIndexes(headers, target.checkboxHeaders);
|
|
26
|
+
const userFieldCount = target.anchorColumn === undefined
|
|
27
|
+
? range.columnCount
|
|
28
|
+
: range.columnCount - 1;
|
|
24
29
|
const rows = [];
|
|
25
30
|
for (let rowIndex = 0; rowIndex < grid.rowData.length; rowIndex += 1) {
|
|
26
31
|
const rowNumber = grid.startRow + 1 + rowIndex;
|
|
27
32
|
if (rowNumber < 2)
|
|
28
33
|
continue;
|
|
29
34
|
const values = gridRowCells(grid, rowNumber, range.startColumn, range.columnCount);
|
|
30
|
-
if (values.every((value, index) => isComputedBlankCell(value, checkboxIndexes.has(index)))) {
|
|
35
|
+
if (values.slice(0, userFieldCount).every((value, index) => isComputedBlankCell(value, checkboxIndexes.has(index)))) {
|
|
31
36
|
continue;
|
|
32
37
|
}
|
|
33
38
|
const fields = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tableRead.js","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/model/tableRead.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,qBAAqB,GAEtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"tableRead.js","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/model/tableRead.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Row-anchor assignment for the Google Sheets API sync provider.
|
|
3
3
|
*
|
|
4
|
-
* Ensures every nonblank row of one registered tab carries
|
|
5
|
-
*
|
|
6
|
-
* batchUpdate. Rows with more than one anchor
|
|
7
|
-
* across rows are reported as evidence.
|
|
4
|
+
* Ensures every nonblank row of one registered tab carries an anchor in the
|
|
5
|
+
* tab's LAST system column (a `sync-anchor:<uuid>` cell value), writing all
|
|
6
|
+
* planned anchors in ONE atomic batchUpdate. Rows with more than one anchor
|
|
7
|
+
* fail closed; duplicate anchors across rows are reported as evidence. A
|
|
8
|
+
* user_input tab without the system column fails closed (legacy format); a
|
|
9
|
+
* user-edited system cell is simply reassigned a fresh anchor. No re-read is
|
|
10
|
+
* performed.
|
|
8
11
|
*/
|
|
9
12
|
import type { EnsureSyncRowAnchorsRequest, EnsureSyncRowAnchorsResult } from "../../../../../application/sync/sheetsContract/syncSheets.js";
|
|
10
13
|
import { type AnchorPlanResult, type ObservedTab } from "../model/observation.js";
|
|
11
14
|
import { type GoogleSheetsApiProviderDeps } from "./shared.js";
|
|
12
15
|
/**
|
|
13
|
-
* Ensures every nonblank row of one registered tab carries a
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
16
|
+
* Ensures every nonblank row of one registered tab carries a system-column
|
|
17
|
+
* anchor, writing all planned anchors in ONE atomic batchUpdate. Rows with
|
|
18
|
+
* more than one anchor fail closed; duplicate anchors across rows are
|
|
19
|
+
* reported as evidence. No re-read is performed.
|
|
17
20
|
*/
|
|
18
21
|
export declare function ensureRowAnchors(deps: GoogleSheetsApiProviderDeps, request: EnsureSyncRowAnchorsRequest): Promise<EnsureSyncRowAnchorsResult>;
|
|
19
22
|
/** Writes every planned anchor of one tab in one atomic batch. */
|
|
20
|
-
export declare function writeAnchors(deps: GoogleSheetsApiProviderDeps, tab: ObservedTab, plan: AnchorPlanResult): Promise<void>;
|
|
23
|
+
export declare function writeAnchors(deps: GoogleSheetsApiProviderDeps, tab: ObservedTab, plan: AnchorPlanResult, anchorColumn: number | undefined): Promise<void>;
|
|
21
24
|
//# sourceMappingURL=anchors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anchors.d.ts","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/operations/anchors.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"anchors.d.ts","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/operations/anchors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,2BAA2B,EAC3B,0BAA0B,EAC3B,MAAM,8DAA8D,CAAC;AAGtE,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAKL,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAC;AAGrB;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,2BAA2B,EACjC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,0BAA0B,CAAC,CAuBrC;AAED,kEAAkE;AAClE,wBAAsB,YAAY,CAChC,IAAI,EAAE,2BAA2B,EACjC,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,gBAAgB,EACtB,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,OAAO,CAAC,IAAI,CAAC,CAgBf"}
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Row-anchor assignment for the Google Sheets API sync provider.
|
|
3
3
|
*
|
|
4
|
-
* Ensures every nonblank row of one registered tab carries
|
|
5
|
-
*
|
|
6
|
-
* batchUpdate. Rows with more than one anchor
|
|
7
|
-
* across rows are reported as evidence.
|
|
4
|
+
* Ensures every nonblank row of one registered tab carries an anchor in the
|
|
5
|
+
* tab's LAST system column (a `sync-anchor:<uuid>` cell value), writing all
|
|
6
|
+
* planned anchors in ONE atomic batchUpdate. Rows with more than one anchor
|
|
7
|
+
* fail closed; duplicate anchors across rows are reported as evidence. A
|
|
8
|
+
* user_input tab without the system column fails closed (legacy format); a
|
|
9
|
+
* user-edited system cell is simply reassigned a fresh anchor. No re-read is
|
|
10
|
+
* performed.
|
|
8
11
|
*/
|
|
9
|
-
import { GOOGLE_SHEETS_API_ANCHOR_KEY } from "../constants.js";
|
|
10
12
|
import { invalidProviderState } from "../errors.js";
|
|
11
13
|
import { planRowAnchors, } from "../model/observation.js";
|
|
14
|
+
import { anchorColumnFor } from "../model/preflightRows.js";
|
|
12
15
|
import { definitionForPhysicalSheet, requireValidBatchUpdateReply, runWrite, validateRoute, } from "./shared.js";
|
|
13
16
|
import { readObservedTabs } from "./readRows.js";
|
|
14
17
|
/**
|
|
15
|
-
* Ensures every nonblank row of one registered tab carries a
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
18
|
+
* Ensures every nonblank row of one registered tab carries a system-column
|
|
19
|
+
* anchor, writing all planned anchors in ONE atomic batchUpdate. Rows with
|
|
20
|
+
* more than one anchor fail closed; duplicate anchors across rows are
|
|
21
|
+
* reported as evidence. No re-read is performed.
|
|
19
22
|
*/
|
|
20
23
|
export async function ensureRowAnchors(deps, request) {
|
|
21
24
|
const definition = definitionForPhysicalSheet(deps, request.physicalSheetId);
|
|
@@ -25,13 +28,15 @@ export async function ensureRowAnchors(deps, request) {
|
|
|
25
28
|
if (tab === undefined) {
|
|
26
29
|
invalidProviderState(`Registered sync sheet does not exist: ${request.sheetName}`);
|
|
27
30
|
}
|
|
31
|
+
const anchorColumn = anchorColumnFor(request.registeredRange, request.projection);
|
|
28
32
|
const plan = planRowAnchors(tab, {
|
|
29
33
|
registeredRange: request.registeredRange,
|
|
30
34
|
headers: definition.headers,
|
|
31
35
|
checkboxHeaders: definition.checkboxHeaders ?? [],
|
|
36
|
+
anchorColumn,
|
|
32
37
|
});
|
|
33
38
|
if (plan.planned.length > 0) {
|
|
34
|
-
await writeAnchors(deps, tab, plan);
|
|
39
|
+
await writeAnchors(deps, tab, plan, anchorColumn);
|
|
35
40
|
}
|
|
36
41
|
return {
|
|
37
42
|
assigned: plan.assigned,
|
|
@@ -40,13 +45,16 @@ export async function ensureRowAnchors(deps, request) {
|
|
|
40
45
|
};
|
|
41
46
|
}
|
|
42
47
|
/** Writes every planned anchor of one tab in one atomic batch. */
|
|
43
|
-
export async function writeAnchors(deps, tab, plan) {
|
|
48
|
+
export async function writeAnchors(deps, tab, plan, anchorColumn) {
|
|
49
|
+
if (anchorColumn === undefined)
|
|
50
|
+
return;
|
|
44
51
|
const requests = plan.planned.map((planned) => ({
|
|
45
|
-
kind: "
|
|
52
|
+
kind: "updateCells",
|
|
46
53
|
sheetId: tab.sheetId,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
startRowIndex: planned.rowIndex,
|
|
55
|
+
startColumnIndex: anchorColumn - 1,
|
|
56
|
+
rows: [[{ userEnteredValue: { stringValue: planned.anchor } }]],
|
|
57
|
+
fields: "userEnteredValue",
|
|
50
58
|
}));
|
|
51
59
|
const response = await runWrite(deps, () => deps.transport.batchUpdate({
|
|
52
60
|
spreadsheetId: deps.spreadsheetId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anchors.js","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/operations/anchors.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"anchors.js","sourceRoot":"","sources":["../../../../../../src/adapter/sheets/providers/google-sheets-api/operations/anchors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EACL,cAAc,GAGf,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EACL,0BAA0B,EAC1B,4BAA4B,EAC5B,QAAQ,EACR,aAAa,GAEd,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAiC,EACjC,OAAoC;IAEpC,MAAM,UAAU,GAAG,0BAA0B,CAAC,IAAI,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAC7E,aAAa,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,oBAAoB,CAAC,yCAAyC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACrF,CAAC;IACD,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC,eAAe,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAClF,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,EAAE;QAC/B,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,eAAe,EAAE,UAAU,CAAC,eAAe,IAAI,EAAE;QACjD,YAAY;KACb,CAAC,CAAC;IACH,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;IACpD,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;KACxC,CAAC;AACJ,CAAC;AAED,kEAAkE;AAClE,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAiC,EACjC,GAAgB,EAChB,IAAsB,EACtB,YAAgC;IAEhC,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO;IACvC,MAAM,QAAQ,GAAkC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC7E,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,aAAa,EAAE,OAAO,CAAC,QAAQ;QAC/B,gBAAgB,EAAE,YAAY,GAAG,CAAC;QAClC,IAAI,EAAE,CAAC,CAAC,EAAE,gBAAgB,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC/D,MAAM,EAAE,kBAAkB;KAC3B,CAAC,CAAC,CAAC;IACJ,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,CACzC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;QACzB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,QAAQ;KACT,CAAC,CAAC,CAAC;IACN,4BAA4B,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC1D,CAAC"}
|
|
@@ -1 +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,8DAA8D,CAAC;AAO5G,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,sEAAsE,CAAC;AAC/H,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAErE,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;
|
|
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,8DAA8D,CAAC;AAO5G,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,sEAAsE,CAAC;AAC/H,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAErE,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AAE/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,CAe3B;AAED,yEAAyE;AACzE,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,2BAA2B,EACjC,OAAO,EAAE,uBAAuB,GAC/B,mBAAmB,CA+BrB"}
|
|
@@ -13,6 +13,7 @@ import { SYNC_SNAPSHOT_READ_MODES, SYNC_PROJECTIONS, } from "../../../../../appl
|
|
|
13
13
|
import { SYNC_SHEETS_ERROR_CODES } from "../../../../../application/sync/sheetsContract/errors.js";
|
|
14
14
|
import { invalidProviderRequest } from "../errors.js";
|
|
15
15
|
import { enumerateSheetProperties, readPreflightData, } from "../model/preflight.js";
|
|
16
|
+
import { anchorColumnFor } from "../model/preflightRows.js";
|
|
16
17
|
import { definitionForPhysicalSheet, runRead, validateRoute, } from "./shared.js";
|
|
17
18
|
/** Reads the target and receipt tabs for one route through the read lane. */
|
|
18
19
|
export async function readPreflight(deps, request, definition, routeOptions) {
|
|
@@ -26,6 +27,7 @@ export async function readPreflight(deps, request, definition, routeOptions) {
|
|
|
26
27
|
headers: definition.headers,
|
|
27
28
|
identityField: routeOptions.identityField,
|
|
28
29
|
checkboxHeaders: routeOptions.checkboxHeaders,
|
|
30
|
+
projection: definition.sheet.projection,
|
|
29
31
|
}, sheets, deps.readTimeoutMs));
|
|
30
32
|
}
|
|
31
33
|
/** Validates one observation request and derives its snapshot target. */
|
|
@@ -49,6 +51,7 @@ export function observationTargetFor(deps, request) {
|
|
|
49
51
|
headers: definition.headers,
|
|
50
52
|
checkboxHeaders: definition.checkboxHeaders ?? [],
|
|
51
53
|
readMode,
|
|
54
|
+
anchorColumn: anchorColumnFor(request.registeredRange, request.projection),
|
|
52
55
|
};
|
|
53
56
|
}
|
|
54
57
|
//# sourceMappingURL=preflightOp.js.map
|
|
@@ -1 +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,8DAA8D,CAAC;AAC3G,OAAO,EACL,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,6DAA6D,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0DAA0D,CAAC;AAGnG,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EACL,wBAAwB,EACxB,iBAAiB,GAElB,MAAM,uBAAuB,CAAC;
|
|
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,8DAA8D,CAAC;AAC3G,OAAO,EACL,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,6DAA6D,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0DAA0D,CAAC;AAGnG,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EACL,wBAAwB,EACxB,iBAAiB,GAElB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,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;QAC7C,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,UAAU;KACxC,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;QACR,YAAY,EAAE,eAAe,CAAC,OAAO,CAAC,eAAe,EAAE,OAAO,CAAC,UAAU,CAAC;KAC3E,CAAC;AACJ,CAAC"}
|
|
@@ -15,10 +15,12 @@ import { type GoogleSheetsApiProviderDeps } from "./shared.js";
|
|
|
15
15
|
* Creates missing tabs and their header rows, or verifies existing tabs,
|
|
16
16
|
* in ONE atomic batchUpdate. An existing tab with no content anywhere in
|
|
17
17
|
* its used grid gets its headers initialized; an existing tab with content
|
|
18
|
-
* must match the registered headers exactly (order, duplicates, width
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* must match the registered headers exactly (order, duplicates, width;
|
|
19
|
+
* user_input tabs additionally require the `__hikoutei_row_id` system
|
|
20
|
+
* column as the last header), otherwise provisioning fails closed BEFORE
|
|
21
|
+
* any mutation. The operation is idempotent: a retry after a lost response
|
|
22
|
+
* re-enumerates, sees the exact headers, and succeeds without rewriting
|
|
23
|
+
* anything.
|
|
22
24
|
*/
|
|
23
25
|
export declare function provisionRegistry(deps: GoogleSheetsApiProviderDeps, registrations: readonly SyncSheetsProvisionRoute[]): Promise<{
|
|
24
26
|
readonly registrations: readonly Omit<SyncSheetsProvisionRoute, "headers">[];
|
|
@@ -1 +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,sEAAsE,CAAC;
|
|
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,sEAAsE,CAAC;AAmBrH,OAAO,EAIL,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;GAUG;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,CAgHD"}
|
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
* a retry after a lost response re-enumerates, sees the exact headers, and
|
|
10
10
|
* succeeds without rewriting anything.
|
|
11
11
|
*/
|
|
12
|
+
import { SYNC_PROJECTIONS } from "../../../../../application/sync/sheetsContract/constants.js";
|
|
12
13
|
import { GOOGLE_SHEETS_API_PROVISION_ENUMERATION_FIELDS, GOOGLE_SHEETS_API_PROVISION_FIELDS, gridHeaderCells, parseSpreadsheetDocument, } from "../model/preflight.js";
|
|
14
|
+
import { SYSTEM_COLUMN_REPROVISION_MESSAGE } from "../model/preflightHeaders.js";
|
|
15
|
+
import { GOOGLE_SHEETS_API_ROW_ID_HEADER } from "../constants.js";
|
|
13
16
|
import { invalidProviderRequest, invalidProviderState } from "../errors.js";
|
|
14
17
|
import { allocateSheetId } from "../model/sheetIdAllocator.js";
|
|
15
18
|
import { columnLetters, parseRegisteredRange, quoteA1SheetName, } from "../model/valueNormalization.js";
|
|
@@ -18,10 +21,12 @@ import { requireValidBatchUpdateReply, runRead, runWrite, } from "./shared.js";
|
|
|
18
21
|
* Creates missing tabs and their header rows, or verifies existing tabs,
|
|
19
22
|
* in ONE atomic batchUpdate. An existing tab with no content anywhere in
|
|
20
23
|
* its used grid gets its headers initialized; an existing tab with content
|
|
21
|
-
* must match the registered headers exactly (order, duplicates, width
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
24
|
+
* must match the registered headers exactly (order, duplicates, width;
|
|
25
|
+
* user_input tabs additionally require the `__hikoutei_row_id` system
|
|
26
|
+
* column as the last header), otherwise provisioning fails closed BEFORE
|
|
27
|
+
* any mutation. The operation is idempotent: a retry after a lost response
|
|
28
|
+
* re-enumerates, sees the exact headers, and succeeds without rewriting
|
|
29
|
+
* anything.
|
|
25
30
|
*/
|
|
26
31
|
export async function provisionRegistry(deps, registrations) {
|
|
27
32
|
validateProvisionRegistrations(registrations);
|
|
@@ -75,9 +80,7 @@ export async function provisionRegistry(deps, registrations) {
|
|
|
75
80
|
for (const registration of registrations) {
|
|
76
81
|
const range = parseRegisteredRange(registration.registeredRange);
|
|
77
82
|
const existing = existingByTitle.get(registration.sheetName);
|
|
78
|
-
const headerCells = registration
|
|
79
|
-
userEnteredValue: { stringValue: header },
|
|
80
|
-
}));
|
|
83
|
+
const headerCells = provisionHeaderCells(registration);
|
|
81
84
|
if (existing === undefined) {
|
|
82
85
|
const sheetId = allocateSheetId(usedSheetIds);
|
|
83
86
|
usedSheetIds.add(sheetId);
|
|
@@ -142,7 +145,9 @@ function validateProvisionRegistrations(registrations) {
|
|
|
142
145
|
}
|
|
143
146
|
tabNames.add(registration.sheetName);
|
|
144
147
|
const range = parseRegisteredRange(registration.registeredRange);
|
|
145
|
-
|
|
148
|
+
const expectedColumnCount = registration.headers.length +
|
|
149
|
+
(registration.projection === SYNC_PROJECTIONS.USER_INPUT ? 1 : 0);
|
|
150
|
+
if (range.columnCount !== expectedColumnCount) {
|
|
146
151
|
invalidProviderRequest("provisioning", `headers do not match registeredRange for ${registration.sheetName}`);
|
|
147
152
|
}
|
|
148
153
|
if (registration.headers.length === 0 ||
|
|
@@ -152,8 +157,24 @@ function validateProvisionRegistrations(registrations) {
|
|
|
152
157
|
if (new Set(registration.headers).size !== registration.headers.length) {
|
|
153
158
|
invalidProviderRequest("provisioning", `headers must not contain duplicates for ${registration.sheetName}`);
|
|
154
159
|
}
|
|
160
|
+
if (registration.projection === SYNC_PROJECTIONS.USER_INPUT &&
|
|
161
|
+
registration.headers.includes(GOOGLE_SHEETS_API_ROW_ID_HEADER)) {
|
|
162
|
+
invalidProviderRequest("provisioning", `header ${GOOGLE_SHEETS_API_ROW_ID_HEADER} collides with the system row-id column for ${registration.sheetName}`);
|
|
163
|
+
}
|
|
155
164
|
}
|
|
156
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Builds the header cells written for one registration, appending the
|
|
168
|
+
* reserved system row-id header on user_input tabs.
|
|
169
|
+
*/
|
|
170
|
+
function provisionHeaderCells(registration) {
|
|
171
|
+
const headers = registration.projection === SYNC_PROJECTIONS.USER_INPUT
|
|
172
|
+
? [...registration.headers, GOOGLE_SHEETS_API_ROW_ID_HEADER]
|
|
173
|
+
: registration.headers;
|
|
174
|
+
return headers.map((header) => ({
|
|
175
|
+
userEnteredValue: { stringValue: header },
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
157
178
|
/**
|
|
158
179
|
* Builds the provisioning data-read end column: the sheet's actual grid
|
|
159
180
|
* width when the enumeration supplied it (so content anywhere in the tab
|
|
@@ -203,27 +224,48 @@ function cellHasEnteredValue(value) {
|
|
|
203
224
|
/**
|
|
204
225
|
* Verifies one content tab's header row against the registered schema:
|
|
205
226
|
* exact order, non-empty strings, no duplicates, and full registered-range
|
|
206
|
-
* coverage.
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
227
|
+
* coverage. user_input tabs additionally require the system row-id header
|
|
228
|
+
* as the last column; a legacy tab (provisioned without it) fails closed
|
|
229
|
+
* with a re-provision message. Any drift fails closed BEFORE any mutation,
|
|
230
|
+
* mirroring the Apps Script "operational provisioning header mismatch"
|
|
231
|
+
* behavior (including a blank header row on a tab whose content lives
|
|
232
|
+
* outside the registered range).
|
|
210
233
|
*/
|
|
211
234
|
function assertProvisioningHeaders(grid, registration) {
|
|
212
235
|
const range = parseRegisteredRange(registration.registeredRange);
|
|
213
236
|
const headerValues = gridHeaderCells(grid, range);
|
|
214
|
-
const
|
|
215
|
-
|
|
237
|
+
const systemColumn = registration.projection === SYNC_PROJECTIONS.USER_INPUT
|
|
238
|
+
? GOOGLE_SHEETS_API_ROW_ID_HEADER
|
|
239
|
+
: undefined;
|
|
240
|
+
const expectedCount = registration.headers.length + (systemColumn === undefined ? 0 : 1);
|
|
241
|
+
const actual = [];
|
|
242
|
+
for (let index = 0; index < headerValues.length; index += 1) {
|
|
243
|
+
const isSystemPosition = systemColumn !== undefined &&
|
|
244
|
+
index === registration.headers.length;
|
|
245
|
+
const raw = provisioningHeaderString(headerValues[index]);
|
|
216
246
|
if (raw === null) {
|
|
247
|
+
if (isSystemPosition) {
|
|
248
|
+
invalidProviderState(`operational provisioning header mismatch: ${registration.sheetName}` +
|
|
249
|
+
` (${SYSTEM_COLUMN_REPROVISION_MESSAGE})`);
|
|
250
|
+
}
|
|
217
251
|
invalidProviderState(`operational provisioning header mismatch: ${registration.sheetName}` +
|
|
218
252
|
` (header is missing at column ${index + 1})`);
|
|
219
253
|
}
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
|
|
254
|
+
actual.push(raw);
|
|
255
|
+
}
|
|
256
|
+
const userHeaders = actual.slice(0, registration.headers.length);
|
|
257
|
+
if (new Set(userHeaders).size !== userHeaders.length) {
|
|
223
258
|
invalidProviderState(`operational provisioning header mismatch: ${registration.sheetName} (duplicate header)`);
|
|
224
259
|
}
|
|
225
|
-
if (actual.length !==
|
|
226
|
-
|
|
260
|
+
if (actual.length !== expectedCount ||
|
|
261
|
+
userHeaders.some((header, index) => header !== registration.headers[index]) ||
|
|
262
|
+
(systemColumn !== undefined && actual[registration.headers.length] !== systemColumn)) {
|
|
263
|
+
if (systemColumn !== undefined &&
|
|
264
|
+
(actual.length !== expectedCount ||
|
|
265
|
+
actual[registration.headers.length] !== systemColumn)) {
|
|
266
|
+
invalidProviderState(`operational provisioning header mismatch: ${registration.sheetName}` +
|
|
267
|
+
` (${SYSTEM_COLUMN_REPROVISION_MESSAGE})`);
|
|
268
|
+
}
|
|
227
269
|
invalidProviderState(`operational provisioning header mismatch: ${registration.sheetName}`);
|
|
228
270
|
}
|
|
229
271
|
}
|