@opengeni/artifact-tool 0.2.10 → 0.3.4-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-ZCJYRJGB.js → chunk-4XJE7NRA.js} +2 -2
- package/dist/{chunk-N2IHNWBS.js → chunk-4YYYUZQH.js} +15 -6
- package/dist/chunk-4YYYUZQH.js.map +1 -0
- package/dist/{chunk-U5G2BKM2.js → chunk-LMLPFF3S.js} +12 -6
- package/dist/{chunk-U5G2BKM2.js.map → chunk-LMLPFF3S.js.map} +1 -1
- package/dist/{chunk-B2ZJRZDA.js → chunk-LVPFJH2Z.js} +7 -5
- package/dist/chunk-LVPFJH2Z.js.map +1 -0
- package/dist/{chunk-QZI5POCC.js → chunk-OVXX4G35.js} +2 -2
- package/dist/{chunk-6PBM7FKI.js → chunk-QA3NXBAG.js} +8 -7
- package/dist/chunk-QA3NXBAG.js.map +1 -0
- package/dist/{chunk-XT2EJFCU.js → chunk-SYFNJGH5.js} +30 -8
- package/dist/chunk-SYFNJGH5.js.map +1 -0
- package/dist/{chunk-RU5G3HNF.js → chunk-XAZTHG6W.js} +20 -9
- package/dist/chunk-XAZTHG6W.js.map +1 -0
- package/dist/index.js +4 -4
- package/dist/kernel.d.ts +0 -19
- package/dist/materializer-cli-entry.js +7 -7
- package/dist/materializer-cli.d.ts +4 -3
- package/dist/materializer-cli.js +7 -7
- package/dist/native.d.ts +1 -1
- package/dist/native.js +2 -2
- package/dist/office-import.d.ts +15 -5
- package/dist/office-import.js +25 -8
- package/dist/office-import.js.map +1 -1
- package/dist/production-document.js +4 -4
- package/dist/production-presentation.js +4 -4
- package/dist/production-spreadsheet.js +4 -4
- package/dist/reference.js +1 -365
- package/dist/reference.js.map +1 -1
- package/dist/runtime-cli-entry.js +3 -3
- package/dist/runtime-cli.js +2 -2
- package/dist/runtime-development.js +3 -3
- package/dist/runtime-receipt.d.ts +3 -2
- package/dist/runtime.d.ts +8 -6
- package/dist/runtime.js +1 -1
- package/dist/snapshot.d.ts +13 -6
- package/dist/snapshot.js +23 -11
- package/dist/snapshot.js.map +1 -1
- package/dist/spreadsheet-xlsx-codec.js +2 -2
- package/dist/spreadsheet.js +1 -1
- package/package.json +5 -5
- package/src/kernel.ts +1 -397
- package/src/materializer-cli.ts +20 -9
- package/src/native.ts +7 -5
- package/src/office-import.ts +47 -18
- package/src/production-spreadsheet-native.ts +4 -3
- package/src/runtime-receipt.ts +16 -5
- package/src/runtime.ts +22 -10
- package/src/snapshot.ts +39 -17
- package/src/spreadsheet-formula.ts +35 -7
- package/dist/chunk-6PBM7FKI.js.map +0 -1
- package/dist/chunk-B2ZJRZDA.js.map +0 -1
- package/dist/chunk-N2IHNWBS.js.map +0 -1
- package/dist/chunk-RU5G3HNF.js.map +0 -1
- package/dist/chunk-XT2EJFCU.js.map +0 -1
- /package/dist/{chunk-ZCJYRJGB.js.map → chunk-4XJE7NRA.js.map} +0 -0
- /package/dist/{chunk-QZI5POCC.js.map → chunk-OVXX4G35.js.map} +0 -0
package/src/office-import.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { decodeEditableArtifactCausalFrontier } from "@opengeni/contracts/editable-artifact-causal-frontier";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
EDITABLE_ARTIFACT_PRODUCT_MAX_SNAPSHOT_BYTES,
|
|
5
|
+
currentEditableArtifactCompatibility,
|
|
6
|
+
} from "@opengeni/contracts/editable-artifacts";
|
|
7
|
+
import {
|
|
8
|
+
COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
9
|
+
DOCUMENT_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
10
|
+
PRESENTATION_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
11
|
+
SPREADSHEET_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
12
|
+
SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION,
|
|
13
|
+
} from "@opengeni/contracts/editable-artifact-versions";
|
|
4
14
|
import type { ArtifactSnapshot } from "./snapshot";
|
|
5
15
|
|
|
6
16
|
export type ArtifactOfficeModality = "spreadsheet" | "document" | "presentation";
|
|
@@ -23,19 +33,29 @@ export type PreparedArtifactOfficeImport = Readonly<{
|
|
|
23
33
|
byteSize: number;
|
|
24
34
|
contentHash: `sha256:${string}`;
|
|
25
35
|
stateHash: `sha256:${string}`;
|
|
26
|
-
modelSchemaVersion:
|
|
36
|
+
modelSchemaVersion: typeof SPREADSHEET_ARTIFACT_MODEL_SCHEMA_VERSION;
|
|
27
37
|
kernelVersion: string;
|
|
28
38
|
coveredCausalFrontier: readonly Readonly<{ replicaId: string; counter: number }>[];
|
|
29
|
-
operationProtocolVersion:
|
|
30
|
-
crdtStateVersion:
|
|
39
|
+
operationProtocolVersion: typeof COMMITTED_TRANSACTION_PROTOCOL_VERSION;
|
|
40
|
+
crdtStateVersion: typeof SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION;
|
|
31
41
|
}>
|
|
32
42
|
| Readonly<{
|
|
33
|
-
modality: "document"
|
|
43
|
+
modality: "document";
|
|
34
44
|
bytes: Uint8Array;
|
|
35
45
|
byteSize: number;
|
|
36
46
|
contentHash: `sha256:${string}`;
|
|
37
47
|
stateHash: `sha256:${string}`;
|
|
38
|
-
modelSchemaVersion:
|
|
48
|
+
modelSchemaVersion: typeof DOCUMENT_ARTIFACT_MODEL_SCHEMA_VERSION;
|
|
49
|
+
kernelVersion: string;
|
|
50
|
+
nativeRevision: number;
|
|
51
|
+
}>
|
|
52
|
+
| Readonly<{
|
|
53
|
+
modality: "presentation";
|
|
54
|
+
bytes: Uint8Array;
|
|
55
|
+
byteSize: number;
|
|
56
|
+
contentHash: `sha256:${string}`;
|
|
57
|
+
stateHash: `sha256:${string}`;
|
|
58
|
+
modelSchemaVersion: typeof PRESENTATION_ARTIFACT_MODEL_SCHEMA_VERSION;
|
|
39
59
|
kernelVersion: string;
|
|
40
60
|
nativeRevision: number;
|
|
41
61
|
}>;
|
|
@@ -119,13 +139,14 @@ function validateSnapshot(
|
|
|
119
139
|
expectedKernelVersion: string,
|
|
120
140
|
): PreparedArtifactOfficeImport["snapshot"] {
|
|
121
141
|
const snapshot = exactNamespace(value, "artifact snapshot") as unknown as ArtifactSnapshot;
|
|
142
|
+
const current = currentEditableArtifactCompatibility(modality);
|
|
122
143
|
if (
|
|
123
144
|
snapshot.schemaVersion !== 1 ||
|
|
124
145
|
snapshot.modality !== modality ||
|
|
125
146
|
snapshot.runtimeTarget !== expectedRuntimeTarget ||
|
|
126
147
|
snapshot.kernelVersion !== expectedKernelVersion ||
|
|
127
|
-
snapshot.modelSchemaVersion !==
|
|
128
|
-
snapshot.snapshotVersion !==
|
|
148
|
+
snapshot.modelSchemaVersion !== current.modelSchemaVersion ||
|
|
149
|
+
snapshot.snapshotVersion !== current.snapshotVersion ||
|
|
129
150
|
!/^sha256:[0-9a-f]{64}$/u.test(snapshot.stateHash)
|
|
130
151
|
) {
|
|
131
152
|
throw new TypeError("Imported snapshot differs from the verified native runtime boundary");
|
|
@@ -143,35 +164,43 @@ function validateSnapshot(
|
|
|
143
164
|
byteSize: bytes.byteLength,
|
|
144
165
|
contentHash: sha256(bytes),
|
|
145
166
|
stateHash: snapshot.stateHash as `sha256:${string}`,
|
|
146
|
-
modelSchemaVersion: 1 as const,
|
|
147
167
|
kernelVersion: snapshot.kernelVersion,
|
|
148
168
|
};
|
|
149
169
|
if (snapshot.modality === "spreadsheet") {
|
|
150
170
|
if (
|
|
151
171
|
!(snapshot.coveredCausalFrontierBytes instanceof Uint8Array) ||
|
|
152
|
-
snapshot.operationProtocolVersion !==
|
|
153
|
-
snapshot.crdtStateVersion !==
|
|
172
|
+
snapshot.operationProtocolVersion !== COMMITTED_TRANSACTION_PROTOCOL_VERSION ||
|
|
173
|
+
snapshot.crdtStateVersion !== SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION
|
|
154
174
|
) {
|
|
155
175
|
throw new TypeError("Imported spreadsheet snapshot coverage is invalid");
|
|
156
176
|
}
|
|
157
177
|
return Object.freeze({
|
|
158
178
|
...common,
|
|
159
179
|
modality: "spreadsheet" as const,
|
|
180
|
+
modelSchemaVersion: SPREADSHEET_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
160
181
|
coveredCausalFrontier: decodeEditableArtifactCausalFrontier(
|
|
161
182
|
snapshot.coveredCausalFrontierBytes,
|
|
162
183
|
),
|
|
163
|
-
operationProtocolVersion:
|
|
164
|
-
crdtStateVersion:
|
|
184
|
+
operationProtocolVersion: COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
185
|
+
crdtStateVersion: SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION,
|
|
165
186
|
});
|
|
166
187
|
}
|
|
167
188
|
if (!Number.isSafeInteger(snapshot.nativeRevision) || snapshot.nativeRevision < 0) {
|
|
168
189
|
throw new TypeError("Imported serialized snapshot revision is invalid");
|
|
169
190
|
}
|
|
170
|
-
return
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
191
|
+
return snapshot.modality === "document"
|
|
192
|
+
? Object.freeze({
|
|
193
|
+
...common,
|
|
194
|
+
modality: "document" as const,
|
|
195
|
+
modelSchemaVersion: DOCUMENT_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
196
|
+
nativeRevision: snapshot.nativeRevision,
|
|
197
|
+
})
|
|
198
|
+
: Object.freeze({
|
|
199
|
+
...common,
|
|
200
|
+
modality: "presentation" as const,
|
|
201
|
+
modelSchemaVersion: PRESENTATION_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
202
|
+
nativeRevision: snapshot.nativeRevision,
|
|
203
|
+
});
|
|
175
204
|
}
|
|
176
205
|
|
|
177
206
|
function officeImporter(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
SPREADSHEET_ARTIFACT_COMMAND_VERSION,
|
|
2
3
|
SPREADSHEET_ARTIFACT_PROJECTION_MAX_BYTES,
|
|
3
4
|
SPREADSHEET_ARTIFACT_VIEWPORT_MAX_CELLS,
|
|
4
5
|
decodeSpreadsheetMetadataKernelProjection,
|
|
@@ -292,7 +293,7 @@ function nativeFormula(value: unknown): SpreadsheetCellInput {
|
|
|
292
293
|
throw new TypeError("Spreadsheet formulas must be strings or null");
|
|
293
294
|
const trimmed = value.trim();
|
|
294
295
|
if (trimmed.length === 0) return null;
|
|
295
|
-
return { formula: trimmed.startsWith("=") ? trimmed : `=${trimmed}
|
|
296
|
+
return { formula: trimmed.startsWith("=") ? trimmed : `=${trimmed}` };
|
|
296
297
|
}
|
|
297
298
|
|
|
298
299
|
function normalizedSheetName(value: unknown): string {
|
|
@@ -485,7 +486,7 @@ class SpreadsheetProjectionAuthor {
|
|
|
485
486
|
: [{ replicaId: this.#replicaId, counter: this.#transactionCounter }],
|
|
486
487
|
selectiveUndoOperationIds: [],
|
|
487
488
|
},
|
|
488
|
-
commands: { version:
|
|
489
|
+
commands: { version: SPREADSHEET_ARTIFACT_COMMAND_VERSION, commands },
|
|
489
490
|
resolvedBaseBytes: this.#session.frontier(),
|
|
490
491
|
});
|
|
491
492
|
this.#transactionCounter = counter;
|
|
@@ -578,7 +579,7 @@ function* cellCommands(
|
|
|
578
579
|
}
|
|
579
580
|
|
|
580
581
|
function nativeCell(cell: SerializedCell): SpreadsheetCellInput {
|
|
581
|
-
if (cell.formula !== null) return { formula: cell.formula
|
|
582
|
+
if (cell.formula !== null) return { formula: cell.formula };
|
|
582
583
|
const value = cell.value;
|
|
583
584
|
if (typeof value === "object" && value !== null) {
|
|
584
585
|
if ("type" in value && value.type === "date") {
|
package/src/runtime-receipt.ts
CHANGED
|
@@ -19,8 +19,8 @@ const WASM_RUNTIME_FILES = [
|
|
|
19
19
|
const MAX_CAPABILITIES_BYTES = 1024 * 1024;
|
|
20
20
|
|
|
21
21
|
export type ArtifactKernelBuildReceipt = Readonly<{
|
|
22
|
-
schemaVersion:
|
|
23
|
-
producer: "opengeni-artifact-kernel-smoke-
|
|
22
|
+
schemaVersion: 2;
|
|
23
|
+
producer: "opengeni-artifact-kernel-smoke-v2";
|
|
24
24
|
target: ArtifactRuntimeTarget;
|
|
25
25
|
kind: "native" | "wasm";
|
|
26
26
|
buildIdentity: string;
|
|
@@ -28,6 +28,7 @@ export type ArtifactKernelBuildReceipt = Readonly<{
|
|
|
28
28
|
bytes: number;
|
|
29
29
|
sha256: `sha256:${string}`;
|
|
30
30
|
}>;
|
|
31
|
+
spreadsheetFormulaProjectionCorpusSha256: `sha256:${string}`;
|
|
31
32
|
runtimeFiles: readonly Readonly<{
|
|
32
33
|
path: string;
|
|
33
34
|
bytes: number;
|
|
@@ -48,11 +49,12 @@ export function validateArtifactKernelBuildReceipt(
|
|
|
48
49
|
"kind",
|
|
49
50
|
"buildIdentity",
|
|
50
51
|
"capabilities",
|
|
52
|
+
"spreadsheetFormulaProjectionCorpusSha256",
|
|
51
53
|
"runtimeFiles",
|
|
52
54
|
],
|
|
53
55
|
"target build receipt",
|
|
54
56
|
);
|
|
55
|
-
if (record.schemaVersion !==
|
|
57
|
+
if (record.schemaVersion !== 2 || record.producer !== "opengeni-artifact-kernel-smoke-v2") {
|
|
56
58
|
invalid("target build receipt schema/producer is invalid");
|
|
57
59
|
}
|
|
58
60
|
if (
|
|
@@ -77,6 +79,13 @@ export function validateArtifactKernelBuildReceipt(
|
|
|
77
79
|
if (capabilities.bytes > MAX_CAPABILITIES_BYTES) {
|
|
78
80
|
invalid("target build capabilities exceed their maximum size");
|
|
79
81
|
}
|
|
82
|
+
const spreadsheetFormulaProjectionCorpusSha256 = record.spreadsheetFormulaProjectionCorpusSha256;
|
|
83
|
+
if (
|
|
84
|
+
typeof spreadsheetFormulaProjectionCorpusSha256 !== "string" ||
|
|
85
|
+
!/^sha256:[0-9a-f]{64}$/u.test(spreadsheetFormulaProjectionCorpusSha256)
|
|
86
|
+
) {
|
|
87
|
+
invalid("target build formula projection corpus digest is invalid");
|
|
88
|
+
}
|
|
80
89
|
if (
|
|
81
90
|
!Array.isArray(record.runtimeFiles) ||
|
|
82
91
|
record.runtimeFiles.length === 0 ||
|
|
@@ -97,12 +106,14 @@ export function validateArtifactKernelBuildReceipt(
|
|
|
97
106
|
invalid("target build receipt runtimeFiles do not match the target package");
|
|
98
107
|
}
|
|
99
108
|
return {
|
|
100
|
-
schemaVersion:
|
|
101
|
-
producer: "opengeni-artifact-kernel-smoke-
|
|
109
|
+
schemaVersion: 2,
|
|
110
|
+
producer: "opengeni-artifact-kernel-smoke-v2",
|
|
102
111
|
target: descriptor.target,
|
|
103
112
|
kind: descriptor.kind,
|
|
104
113
|
buildIdentity: record.buildIdentity,
|
|
105
114
|
capabilities: { bytes: capabilities.bytes, sha256: capabilities.sha256 },
|
|
115
|
+
spreadsheetFormulaProjectionCorpusSha256:
|
|
116
|
+
spreadsheetFormulaProjectionCorpusSha256 as `sha256:${string}`,
|
|
106
117
|
runtimeFiles,
|
|
107
118
|
};
|
|
108
119
|
}
|
package/src/runtime.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
3
|
+
SPREADSHEET_ARTIFACT_COMMAND_VERSION,
|
|
4
|
+
SPREADSHEET_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
5
|
+
SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION,
|
|
6
|
+
SPREADSHEET_KERNEL_COMMAND_VERSION,
|
|
7
|
+
SPREADSHEET_KERNEL_SNAPSHOT_VERSION,
|
|
8
|
+
} from "@opengeni/contracts/editable-artifact-versions";
|
|
9
|
+
|
|
1
10
|
/**
|
|
2
11
|
* Exact artifact-kernel distribution and runtime boundary.
|
|
3
12
|
*
|
|
@@ -163,13 +172,14 @@ export type ArtifactRuntimeKernelDependencies = Pick<
|
|
|
163
172
|
export type ArtifactKernelCapabilities = {
|
|
164
173
|
readonly abiVersion: 1;
|
|
165
174
|
readonly buildIdentityFormat: "utf8";
|
|
166
|
-
readonly commandSchemaVersion:
|
|
167
|
-
readonly spreadsheetCommandVersion:
|
|
168
|
-
readonly
|
|
175
|
+
readonly commandSchemaVersion: typeof SPREADSHEET_KERNEL_COMMAND_VERSION;
|
|
176
|
+
readonly spreadsheetCommandVersion: typeof SPREADSHEET_ARTIFACT_COMMAND_VERSION;
|
|
177
|
+
readonly spreadsheetModelSchemaVersion: typeof SPREADSHEET_ARTIFACT_MODEL_SCHEMA_VERSION;
|
|
178
|
+
readonly kernelSnapshotVersion: typeof SPREADSHEET_KERNEL_SNAPSHOT_VERSION;
|
|
169
179
|
readonly receiptSchemaVersion: 1;
|
|
170
|
-
readonly collaborationSnapshotVersion:
|
|
180
|
+
readonly collaborationSnapshotVersion: typeof SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION;
|
|
171
181
|
readonly editableArtifactIntentVersion: 1;
|
|
172
|
-
readonly committedTransactionVersion:
|
|
182
|
+
readonly committedTransactionVersion: typeof COMMITTED_TRANSACTION_PROTOCOL_VERSION;
|
|
173
183
|
readonly queryVersion: 1;
|
|
174
184
|
readonly queryResponseVersion: 1;
|
|
175
185
|
readonly collaboration: true;
|
|
@@ -237,6 +247,7 @@ export type ArtifactRuntimeErrorCode =
|
|
|
237
247
|
| "ARTIFACT_RUNTIME_INCOMPATIBLE"
|
|
238
248
|
| "ARTIFACT_RUNTIME_INTEGRITY"
|
|
239
249
|
| "ARTIFACT_RUNTIME_MANIFEST_INVALID"
|
|
250
|
+
| "ARTIFACT_RUNTIME_PROJECTION_PARITY"
|
|
240
251
|
| "ARTIFACT_RUNTIME_UNAVAILABLE"
|
|
241
252
|
| "ARTIFACT_RUNTIME_UNSUPPORTED_TARGET";
|
|
242
253
|
|
|
@@ -1208,13 +1219,14 @@ function parseCapabilities(value: unknown): ArtifactKernelCapabilities {
|
|
|
1208
1219
|
const required = {
|
|
1209
1220
|
abiVersion: 1,
|
|
1210
1221
|
buildIdentityFormat: "utf8",
|
|
1211
|
-
commandSchemaVersion:
|
|
1212
|
-
spreadsheetCommandVersion:
|
|
1213
|
-
|
|
1222
|
+
commandSchemaVersion: SPREADSHEET_KERNEL_COMMAND_VERSION,
|
|
1223
|
+
spreadsheetCommandVersion: SPREADSHEET_ARTIFACT_COMMAND_VERSION,
|
|
1224
|
+
spreadsheetModelSchemaVersion: SPREADSHEET_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
1225
|
+
kernelSnapshotVersion: SPREADSHEET_KERNEL_SNAPSHOT_VERSION,
|
|
1214
1226
|
receiptSchemaVersion: 1,
|
|
1215
|
-
collaborationSnapshotVersion:
|
|
1227
|
+
collaborationSnapshotVersion: SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION,
|
|
1216
1228
|
editableArtifactIntentVersion: 1,
|
|
1217
|
-
committedTransactionVersion:
|
|
1229
|
+
committedTransactionVersion: COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
1218
1230
|
queryVersion: 1,
|
|
1219
1231
|
queryResponseVersion: 1,
|
|
1220
1232
|
collaboration: true,
|
package/src/snapshot.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
DOCUMENT_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
4
|
+
DOCUMENT_ARTIFACT_SNAPSHOT_VERSION,
|
|
5
|
+
PRESENTATION_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
6
|
+
PRESENTATION_ARTIFACT_SNAPSHOT_VERSION,
|
|
7
|
+
SPREADSHEET_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
8
|
+
SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION,
|
|
5
9
|
} from "@opengeni/contracts/editable-artifact-versions";
|
|
6
10
|
import type { Document } from "./document";
|
|
7
11
|
import {
|
|
@@ -15,11 +19,8 @@ import type { Workbook } from "./spreadsheet";
|
|
|
15
19
|
|
|
16
20
|
type ArtifactSnapshotCommon = Readonly<{
|
|
17
21
|
schemaVersion: 1;
|
|
18
|
-
modality: "spreadsheet" | "document" | "presentation";
|
|
19
22
|
runtimeTarget: string;
|
|
20
23
|
kernelVersion: string;
|
|
21
|
-
modelSchemaVersion: 1;
|
|
22
|
-
snapshotVersion: 1;
|
|
23
24
|
stateHash: string;
|
|
24
25
|
snapshotBytes: Uint8Array;
|
|
25
26
|
}>;
|
|
@@ -29,13 +30,24 @@ export type ArtifactSnapshot =
|
|
|
29
30
|
| (ArtifactSnapshotCommon &
|
|
30
31
|
Readonly<{
|
|
31
32
|
modality: "spreadsheet";
|
|
33
|
+
modelSchemaVersion: typeof SPREADSHEET_ARTIFACT_MODEL_SCHEMA_VERSION;
|
|
34
|
+
snapshotVersion: typeof SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION;
|
|
32
35
|
coveredCausalFrontierBytes: Uint8Array;
|
|
33
|
-
operationProtocolVersion:
|
|
34
|
-
crdtStateVersion:
|
|
36
|
+
operationProtocolVersion: typeof COMMITTED_TRANSACTION_PROTOCOL_VERSION;
|
|
37
|
+
crdtStateVersion: typeof SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION;
|
|
35
38
|
}>)
|
|
36
39
|
| (ArtifactSnapshotCommon &
|
|
37
40
|
Readonly<{
|
|
38
|
-
modality: "document"
|
|
41
|
+
modality: "document";
|
|
42
|
+
modelSchemaVersion: typeof DOCUMENT_ARTIFACT_MODEL_SCHEMA_VERSION;
|
|
43
|
+
snapshotVersion: typeof DOCUMENT_ARTIFACT_SNAPSHOT_VERSION;
|
|
44
|
+
nativeRevision: number;
|
|
45
|
+
}>)
|
|
46
|
+
| (ArtifactSnapshotCommon &
|
|
47
|
+
Readonly<{
|
|
48
|
+
modality: "presentation";
|
|
49
|
+
modelSchemaVersion: typeof PRESENTATION_ARTIFACT_MODEL_SCHEMA_VERSION;
|
|
50
|
+
snapshotVersion: typeof PRESENTATION_ARTIFACT_SNAPSHOT_VERSION;
|
|
39
51
|
nativeRevision: number;
|
|
40
52
|
}>);
|
|
41
53
|
|
|
@@ -47,11 +59,8 @@ export function createArtifactSnapshot(
|
|
|
47
59
|
const native = state.native;
|
|
48
60
|
const common = {
|
|
49
61
|
schemaVersion: 1 as const,
|
|
50
|
-
modality: state.modality,
|
|
51
62
|
runtimeTarget: native.target,
|
|
52
63
|
kernelVersion: native.buildIdentity,
|
|
53
|
-
modelSchemaVersion: EDITABLE_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
54
|
-
snapshotVersion: EDITABLE_ARTIFACT_SNAPSHOT_VERSION,
|
|
55
64
|
stateHash: native.stateHash(),
|
|
56
65
|
snapshotBytes: Uint8Array.from(native.snapshot()),
|
|
57
66
|
};
|
|
@@ -62,9 +71,11 @@ export function createArtifactSnapshot(
|
|
|
62
71
|
return Object.freeze({
|
|
63
72
|
...common,
|
|
64
73
|
modality: "spreadsheet" as const,
|
|
74
|
+
modelSchemaVersion: SPREADSHEET_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
75
|
+
snapshotVersion: SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION,
|
|
65
76
|
coveredCausalFrontierBytes: Uint8Array.from(native.frontier()),
|
|
66
77
|
operationProtocolVersion: COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
67
|
-
crdtStateVersion:
|
|
78
|
+
crdtStateVersion: SPREADSHEET_COLLABORATION_SNAPSHOT_VERSION,
|
|
68
79
|
});
|
|
69
80
|
}
|
|
70
81
|
if (
|
|
@@ -73,11 +84,22 @@ export function createArtifactSnapshot(
|
|
|
73
84
|
) {
|
|
74
85
|
throw new Error("Serialized composite does not own its expected native session");
|
|
75
86
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
87
|
+
const nativeRevision = safeNativeRevision(native.revision());
|
|
88
|
+
return state.modality === "document"
|
|
89
|
+
? Object.freeze({
|
|
90
|
+
...common,
|
|
91
|
+
modality: "document" as const,
|
|
92
|
+
modelSchemaVersion: DOCUMENT_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
93
|
+
snapshotVersion: DOCUMENT_ARTIFACT_SNAPSHOT_VERSION,
|
|
94
|
+
nativeRevision,
|
|
95
|
+
})
|
|
96
|
+
: Object.freeze({
|
|
97
|
+
...common,
|
|
98
|
+
modality: "presentation" as const,
|
|
99
|
+
modelSchemaVersion: PRESENTATION_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
100
|
+
snapshotVersion: PRESENTATION_ARTIFACT_SNAPSHOT_VERSION,
|
|
101
|
+
nativeRevision,
|
|
102
|
+
});
|
|
81
103
|
}
|
|
82
104
|
|
|
83
105
|
function safeNativeRevision(value: bigint): number {
|
|
@@ -509,7 +509,9 @@ class FormulaParser {
|
|
|
509
509
|
if (this.isOperator("^")) {
|
|
510
510
|
this.consume();
|
|
511
511
|
const right = this.withNesting(() => this.power());
|
|
512
|
-
left = calculate(left, right, (a, b) =>
|
|
512
|
+
left = calculate(left, right, (a, b) =>
|
|
513
|
+
finiteNumber(deterministicIntegerPower(numeric(a), numeric(b))),
|
|
514
|
+
);
|
|
513
515
|
}
|
|
514
516
|
return left;
|
|
515
517
|
}
|
|
@@ -974,24 +976,24 @@ function callFunction(name: string, args: Evaluated[], budget: FormulaEvaluation
|
|
|
974
976
|
return Math.abs(numeric(args[0] ?? 0));
|
|
975
977
|
case "ROUND": {
|
|
976
978
|
const digits = numeric(args[1] ?? 0);
|
|
977
|
-
const factor = 10
|
|
979
|
+
const factor = deterministicIntegerPower(10, digits);
|
|
978
980
|
const value = numeric(args[0] ?? 0) * factor;
|
|
979
981
|
return (Math.sign(value) * Math.round(Math.abs(value))) / factor;
|
|
980
982
|
}
|
|
981
983
|
case "ROUNDUP": {
|
|
982
984
|
const digits = numeric(args[1] ?? 0);
|
|
983
|
-
const factor = 10
|
|
985
|
+
const factor = deterministicIntegerPower(10, digits);
|
|
984
986
|
const value = numeric(args[0] ?? 0) * factor;
|
|
985
987
|
return (Math.sign(value) * Math.ceil(Math.abs(value))) / factor;
|
|
986
988
|
}
|
|
987
989
|
case "ROUNDDOWN": {
|
|
988
990
|
const digits = numeric(args[1] ?? 0);
|
|
989
|
-
const factor = 10
|
|
991
|
+
const factor = deterministicIntegerPower(10, digits);
|
|
990
992
|
const value = numeric(args[0] ?? 0) * factor;
|
|
991
993
|
return (Math.sign(value) * Math.floor(Math.abs(value))) / factor;
|
|
992
994
|
}
|
|
993
995
|
case "POWER":
|
|
994
|
-
return finiteNumber(
|
|
996
|
+
return finiteNumber(deterministicIntegerPower(numeric(args[0] ?? 0), numeric(args[1] ?? 0)));
|
|
995
997
|
case "SQRT": {
|
|
996
998
|
const value = numeric(args[0] ?? 0);
|
|
997
999
|
if (value < 0) throw new FormulaFault("#NUM!");
|
|
@@ -1067,7 +1069,30 @@ function dateValue(value: Evaluated | undefined): Date {
|
|
|
1067
1069
|
|
|
1068
1070
|
function finiteNumber(value: number): number {
|
|
1069
1071
|
if (!Number.isFinite(value)) throw new FormulaFault("#NUM!");
|
|
1070
|
-
return value;
|
|
1072
|
+
return value === 0 ? 0 : value;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
/** Mirrors the kernel's explicitly ordered path for exact integer exponents. */
|
|
1076
|
+
function deterministicIntegerPower(base: number, exponent: number): number {
|
|
1077
|
+
if (
|
|
1078
|
+
Number.isFinite(exponent) &&
|
|
1079
|
+
Number.isInteger(exponent) &&
|
|
1080
|
+
Math.abs(exponent) <= Number.MAX_SAFE_INTEGER
|
|
1081
|
+
) {
|
|
1082
|
+
const reciprocal = exponent < 0;
|
|
1083
|
+
let remaining = Math.abs(exponent);
|
|
1084
|
+
// Match the kernel at underflow boundaries: forming the positive power
|
|
1085
|
+
// first can overflow before a representable reciprocal is taken.
|
|
1086
|
+
let factor = reciprocal ? 1 / base : base;
|
|
1087
|
+
let result = 1;
|
|
1088
|
+
while (remaining !== 0) {
|
|
1089
|
+
if (remaining % 2 === 1) result *= factor;
|
|
1090
|
+
remaining = Math.floor(remaining / 2);
|
|
1091
|
+
if (remaining !== 0) factor *= factor;
|
|
1092
|
+
}
|
|
1093
|
+
return result;
|
|
1094
|
+
}
|
|
1095
|
+
return Math.pow(base, exponent);
|
|
1071
1096
|
}
|
|
1072
1097
|
|
|
1073
1098
|
function boundedText(value: string, maximum: number): string {
|
|
@@ -1079,7 +1104,10 @@ function boundedText(value: string, maximum: number): string {
|
|
|
1079
1104
|
|
|
1080
1105
|
function boundedScalar(value: Scalar, maximum: number): Scalar {
|
|
1081
1106
|
if (typeof value === "string") return boundedText(value, maximum);
|
|
1082
|
-
if (typeof value === "number"
|
|
1107
|
+
if (typeof value === "number") {
|
|
1108
|
+
if (!Number.isFinite(value)) throw new FormulaFault("#NUM!");
|
|
1109
|
+
return value === 0 ? 0 : value;
|
|
1110
|
+
}
|
|
1083
1111
|
return value;
|
|
1084
1112
|
}
|
|
1085
1113
|
|