@agoric/swing-store 0.9.2-u13.0 → 0.9.2-u16.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/CHANGELOG.md CHANGED
@@ -3,50 +3,29 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ### [0.9.2-u13.0](https://github.com/Agoric/agoric-sdk/compare/@agoric/swing-store@0.9.2-u12.0...@agoric/swing-store@0.9.2-u13.0) (2023-12-07)
6
+ ### [0.9.2-u16.0](https://github.com/Agoric/agoric-sdk/compare/@agoric/swing-store@0.9.1...@agoric/swing-store@0.9.2-u16.0) (2024-07-02)
7
7
 
8
8
 
9
9
  ### Features
10
10
 
11
- * add exporter.getHostKV() API ([16435d2](https://github.com/Agoric/agoric-sdk/commit/16435d20e9ede86916a54c7bae54ecfc59e4c950)), closes [#8523](https://github.com/Agoric/agoric-sdk/issues/8523)
12
-
13
-
14
-
15
- ### [0.9.2-u12.0](https://github.com/Agoric/agoric-sdk/compare/@agoric/swing-store@0.9.2-u11wf.0...@agoric/swing-store@0.9.2-u12.0) (2023-11-10)
16
-
17
-
18
- ### Features
19
-
20
- * **swing-store:** faster import of swing-store ([35aef87](https://github.com/Agoric/agoric-sdk/commit/35aef87ec0f10b7f0cdce462ac0509296e8bd752))
21
- * **swing-store:** prevent SwingSet usage of imported swing-store ([03f642d](https://github.com/Agoric/agoric-sdk/commit/03f642d39f90ef9465a439723c3a69beef73bd61))
22
-
23
-
24
- ### Bug Fixes
25
-
26
- * **swing-store:** ensure crank savepoint is wrapped in transaction ([8d738c6](https://github.com/Agoric/agoric-sdk/commit/8d738c65ed37b9159e94fbcf291ed7fe8478ee5a))
27
-
28
-
29
-
30
- ### [0.9.2-u11wf.0](https://github.com/Agoric/agoric-sdk/compare/@agoric/swing-store@0.9.2-u11.0...@agoric/swing-store@0.9.2-u11wf.0) (2023-09-23)
31
-
32
- **Note:** Version bump only for package @agoric/swing-store
33
-
34
-
35
-
36
-
37
-
38
- ### [0.9.2-u11.0](https://github.com/Agoric/agoric-sdk/compare/@agoric/swing-store@0.9.1...@agoric/swing-store@0.9.2-u11.0) (2023-08-24)
39
-
40
-
41
- ### Features
42
-
43
- * **swingstore:** add repairMetadata() ([5b2d19d](https://github.com/Agoric/agoric-sdk/commit/5b2d19d1153a23c118afb14ca4ed80e175640f62)), closes [#8025](https://github.com/Agoric/agoric-sdk/issues/8025) [#8025](https://github.com/Agoric/agoric-sdk/issues/8025)
11
+ * add exporter.getHostKV() API ([eb564f9](https://github.com/Agoric/agoric-sdk/commit/eb564f9635397c0706e1f8255b3e125681e2d031)), closes [#8523](https://github.com/Agoric/agoric-sdk/issues/8523)
12
+ * **swing-store:** faster import of swing-store ([0170568](https://github.com/Agoric/agoric-sdk/commit/0170568d66748af76f0bd24a4acdaa34b9c79cca))
13
+ * **swing-store:** prevent SwingSet usage of imported swing-store ([6a833eb](https://github.com/Agoric/agoric-sdk/commit/6a833ebda2b2ff0e72040ca8186f93ae91567add))
14
+ * **swingstore:** add repairMetadata() ([33b5c1c](https://github.com/Agoric/agoric-sdk/commit/33b5c1c1fefd5278a24cd5f06630b238439e2891)), closes [#8025](https://github.com/Agoric/agoric-sdk/issues/8025) [#8025](https://github.com/Agoric/agoric-sdk/issues/8025)
15
+ * tool for auditing dangling kindID references ([eeadc46](https://github.com/Agoric/agoric-sdk/commit/eeadc462d8fb09449e4ea6f0118ae8654e0c8e9b)), closes [#7655](https://github.com/Agoric/agoric-sdk/issues/7655)
44
16
 
45
17
 
46
18
  ### Bug Fixes
47
19
 
48
- * **swing-store:** add 'replay' artifactMode, make export more strict ([d46c8e2](https://github.com/Agoric/agoric-sdk/commit/d46c8e2d270999ccba552e0072cb5e0926922f28)), closes [#8105](https://github.com/Agoric/agoric-sdk/issues/8105)
49
- * rewrite importSwingStore to preserve metadata properly ([03e323a](https://github.com/Agoric/agoric-sdk/commit/03e323a55ffeb98dcc84a57050a5d3fc881899b8)), closes [#8025](https://github.com/Agoric/agoric-sdk/issues/8025)
20
+ * misc runtime robustness found by typecheck ([a033f26](https://github.com/Agoric/agoric-sdk/commit/a033f2638f9f11e19d94d7931e4e0614773b1f60))
21
+ * performance.now() binding ([4a3b59b](https://github.com/Agoric/agoric-sdk/commit/4a3b59b486c0cb916e531d5de390fbf90e4421ad))
22
+ * rewrite importSwingStore to preserve metadata properly ([38c9efc](https://github.com/Agoric/agoric-sdk/commit/38c9efce10957e0eb245e25ae5f9f45792eb58ad)), closes [#8025](https://github.com/Agoric/agoric-sdk/issues/8025)
23
+ * **swing-store:** add 'replay' artifactMode, make export more strict ([9939ea6](https://github.com/Agoric/agoric-sdk/commit/9939ea699bb1fd0b711f950679b432eef9054fda)), closes [#8105](https://github.com/Agoric/agoric-sdk/issues/8105)
24
+ * **swing-store:** ensure crank savepoint is wrapped in transaction ([9d2dd3f](https://github.com/Agoric/agoric-sdk/commit/9d2dd3f9966940961a4c21351d256fa3615715d7))
25
+ * **swing-store:** explicitly harden prototypes ([86c128a](https://github.com/Agoric/agoric-sdk/commit/86c128a29b5ed61764a67644c3734b0c05df2993))
26
+ * **swing-store:** no completeness check when creating exporter ([d4df073](https://github.com/Agoric/agoric-sdk/commit/d4df073ffcc48b0f0e62bac107ee8edf21150ad9))
27
+ * **types:** template syntax ([279b903](https://github.com/Agoric/agoric-sdk/commit/279b903a559710511d69f1614badddeab801b90d))
28
+ * update for `[@jessie](https://github.com/jessie).js/safe-await-separator` ([94c6b3c](https://github.com/Agoric/agoric-sdk/commit/94c6b3c83a5326594f1e2886ae01d6a703a7a68f))
50
29
 
51
30
 
52
31
 
@@ -39,30 +39,41 @@ The exporter is created by calling `makeSwingStoreExporter(dirpath)`, passing it
39
39
  After calling `hostStorage.commit()`, the host application can extract the first-stage export data, and then the second-stage export artifacts:
40
40
 
41
41
  ```js
42
- import { buffer } from 'node:stream/consumers';
43
-
44
- const dirPath = '.../swing-store';
45
- const swingStore = openSwingStore(dirPath);
46
- ...
47
- await controller.run();
48
- hostStorage.commit();
49
- // spawn a child process
50
-
51
- // child process does:
52
- const exporter = makeSwingStoreExporter(dirPath);
53
- // exporter now has a txn, parent process is free to proceed forward
54
- const exportData = new Map();
55
- for (const [key, value] of exporter.getExportData()) {
56
- exportData.set(key, value);
42
+ const dirPath = '.../swing-store';
43
+ const swingStore = openSwingStore(dirPath);
44
+ ...
45
+ await controller.run();
46
+ hostStorage.commit();
47
+ // spawn a child process and wait for it to open a transaction
48
+ const started = makePromiseKit();
49
+ const child = fork(path, args);
50
+ child.on('error', started.reject);
51
+ child.on('exit', started.reject);
52
+ child.on('message', msg => {
53
+ if (msg?.type === 'started') {
54
+ started.resolve();
57
55
  }
58
- const exportArtifacts = new Map();
59
- for (const name of exporter.getArtifactNames()) {
60
- const reader = exporter.getArtifact(name);
61
- // reader is an async iterable of Uint8Array, e.g. a stream
62
- const data = await buffer(reader);
63
- exportArtifacts.set(name, data);
64
- }
65
- // export is 'exportData' and 'exportArtifacts'
56
+ });
57
+ await started.promise;
58
+ ...
59
+
60
+ // child process does:
61
+ import { buffer } from 'node:stream/consumers';
62
+ const exporter = makeSwingStoreExporter(dirPath);
63
+ // exporter now has a txn, so parent process is free to proceed forward
64
+ process.send({ type: 'started' });
65
+ const exportData = new Map();
66
+ for (const [key, value] of exporter.getExportData()) {
67
+ exportData.set(key, value);
68
+ }
69
+ const exportArtifacts = new Map();
70
+ for (const name of exporter.getArtifactNames()) {
71
+ const reader = exporter.getArtifact(name);
72
+ // reader is an async iterable of Uint8Array, e.g. a stream
73
+ const data = await buffer(reader);
74
+ exportArtifacts.set(name, data);
75
+ }
76
+ // export is the combination of 'exportData' and 'exportArtifacts'
66
77
  ```
67
78
 
68
79
  ![image 3](./images/data-export-3.jpg)
@@ -92,35 +103,51 @@ Then, on the few occasions when the application needs to build a full state-sync
92
103
  ![image 4](./images/data-export-4.jpg)
93
104
 
94
105
  ```js
95
- const dirPath = '.../swing-store';
96
- const iavl = ...;
97
- function exportCallback(key, value) {
98
- const iavlKey = `ssed.${key}`; // 'ssed' is short for SwingStoreExportData
99
- if (value) {
100
- iavl.set(iavlKey, value);
101
- } else {
102
- iavl.delete(iavlKey); // value===undefined means delete
103
- }
104
- }
105
- const swingStore = openSwingStore(dirPath, { exportCallback });
106
- ...
107
- await controller.run();
108
- hostStorage.commit();
109
-
110
- // now, if the validator is configured to publish state-sync snapshots,
111
- // and if this block height is one of the publishing points,
112
- // do the following:
113
-
114
- // spawn a child process
115
-
116
- // child process does:
117
- const exporter = makeSwingStoreExporter(dirPath);
118
- // note: no exporter.getExportData(), the first-stage data is already in IAVL
119
- const artifacts = new Map();
120
- for (const name of exporter.getArtifactNames()) {
121
- artifacts.set(name, exporter.getArtifact(name));
106
+ const dirPath = '.../swing-store';
107
+ const iavl = ...;
108
+ function exportCallback(key, value) {
109
+ const iavlKey = `ssed.${key}`; // 'ssed' is short for SwingStoreExportData
110
+ if (value === undefined) {
111
+ iavl.delete(iavlKey);
112
+ } else {
113
+ iavl.set(iavlKey, value);
114
+ }
115
+ }
116
+ const swingStore = openSwingStore(dirPath, { exportCallback });
117
+ ...
118
+ await controller.run();
119
+ hostStorage.commit();
120
+
121
+ // now, if the validator is configured to publish state-sync snapshots,
122
+ // and if this block height is one of the publishing points,
123
+ // do the following:
124
+
125
+ // spawn a child process and wait for it to open a transaction
126
+ const started = makePromiseKit();
127
+ const child = fork(path, args);
128
+ child.on('error', started.reject);
129
+ child.on('exit', started.reject);
130
+ child.on('message', msg => {
131
+ if (msg?.type === 'started') {
132
+ started.resolve();
122
133
  }
123
- // instruct cosmos-sdk to include 'artifacts' in the state-sync snapshot
134
+ });
135
+ try {
136
+ await started.promise;
137
+ } catch (err) {
138
+ ...
139
+ }
140
+ ...
141
+
142
+ // child process does:
143
+ const exporter = makeSwingStoreExporter(dirPath);
144
+ process.send({ type: 'started' });
145
+ // note: no exporter.getExportData(), the first-stage data is already in IAVL
146
+ const artifacts = new Map();
147
+ for (const name of exporter.getArtifactNames()) {
148
+ artifacts.set(name, exporter.getArtifact(name));
149
+ }
150
+ // instruct cosmos-sdk to include 'artifacts' in the state-sync snapshot
124
151
  ```
125
152
 
126
153
  ## Import
@@ -202,7 +229,7 @@ SwingStore contains components to accommodate all the various kinds of state tha
202
229
  * `kvStore`, a general-purpose string/string key-value table
203
230
  * `transcriptStore`: append-only vat deliveries, broken into "spans", delimited by heap snapshot events
204
231
  * `snapshotStore`: binary blobs containing JS engine heap state, to limit transcript replay depth
205
- * `bundleStore`: code bundles that can be imported with `@endo/import-bundle`
232
+ * `bundleStore`: code bundles that can be imported with [@endo/import-bundle](https://www.npmjs.com/package/@endo/import-bundle)
206
233
 
207
234
  Currently, the SwingStore treats transcript spans, heap snapshots, and bundles as export artifacts, with hashes recorded in the export data for validation (and to remember exactly which artifacts are necessary). The `kvStore` is copied one-to-one into the export data (i.e. we keep a full shadow copy in IAVL), because that is the fastest way to ensure the `kvStore` data is fully available and validated.
208
235
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/swing-store",
3
- "version": "0.9.2-u13.0",
3
+ "version": "0.9.2-u16.0",
4
4
  "description": "Persistent storage for SwingSet",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -17,23 +17,23 @@
17
17
  "test:xs": "exit 0",
18
18
  "lint-fix": "yarn lint:eslint --fix",
19
19
  "lint": "run-s --continue-on-error lint:*",
20
- "lint:types": "tsc -p jsconfig.json",
20
+ "lint:types": "tsc",
21
21
  "lint:eslint": "eslint ."
22
22
  },
23
23
  "dependencies": {
24
- "@agoric/assert": "^0.6.1-u11wf.0",
25
- "@agoric/internal": "^0.4.0-u13.0",
26
- "@endo/base64": "0.2.31",
27
- "@endo/bundle-source": "2.5.2-upstream-rollup",
28
- "@endo/check-bundle": "0.2.18",
29
- "@endo/nat": "4.1.27",
30
- "better-sqlite3": "^8.2.0"
24
+ "@agoric/assert": "^0.6.1-u16.0",
25
+ "@agoric/internal": "^0.4.0-u16.0",
26
+ "@endo/base64": "^1.0.5",
27
+ "@endo/bundle-source": "^3.2.3",
28
+ "@endo/check-bundle": "^1.0.7",
29
+ "@endo/nat": "^5.0.7",
30
+ "better-sqlite3": "^9.1.1"
31
31
  },
32
32
  "devDependencies": {
33
- "@endo/init": "0.5.56",
34
- "@types/better-sqlite3": "^7.5.0",
35
- "ava": "^5.2.0",
36
- "c8": "^7.13.0",
33
+ "@endo/init": "^1.1.2",
34
+ "@types/better-sqlite3": "^7.6.9",
35
+ "ava": "^5.3.0",
36
+ "c8": "^9.1.0",
37
37
  "tmp": "^0.2.1"
38
38
  },
39
39
  "publishConfig": {
@@ -41,9 +41,15 @@
41
41
  },
42
42
  "ava": {
43
43
  "files": [
44
- "test/**/test-*.js"
44
+ "test/**/*.test.*"
45
+ ],
46
+ "require": [
47
+ "@endo/init/debug.js"
45
48
  ],
46
49
  "timeout": "2m"
47
50
  },
48
- "gitHead": "5a6cdeb0c18ae9700d706445acf402f8d1e873c3"
51
+ "typeCoverage": {
52
+ "atLeast": 76.31
53
+ },
54
+ "gitHead": "bbdf652c3f413381cb352a8a360db1063974fafd"
49
55
  }
@@ -15,7 +15,7 @@ import { createSHA256 } from './hasher.js';
15
15
  * @typedef { EndoZipBase64Bundle | GetExportBundle | NestedEvaluateBundle } Bundle
16
16
  */
17
17
  /**
18
- * @typedef { import('./exporter').SwingStoreExporter } SwingStoreExporter
18
+ * @typedef { import('./exporter.js').SwingStoreExporter } SwingStoreExporter
19
19
  * @typedef { import('./internal.js').ArtifactMode } ArtifactMode
20
20
  *
21
21
  * @typedef {{
@@ -267,6 +267,7 @@ export function makeBundleStore(db, ensureTxn, noteExport = () => {}) {
267
267
  const rawBundle = row.bundle || Fail`bundle ${q(bundleID)} pruned`;
268
268
  yield* Readable.from(Buffer.from(rawBundle));
269
269
  }
270
+ harden(exportBundle);
270
271
 
271
272
  const sqlGetBundleIDs = db.prepare(`
272
273
  SELECT bundleID
@@ -286,12 +287,14 @@ export function makeBundleStore(db, ensureTxn, noteExport = () => {}) {
286
287
  yield [bundleArtifactName(bundleID), bundleID];
287
288
  }
288
289
  }
290
+ harden(getExportRecords);
289
291
 
290
292
  async function* getArtifactNames() {
291
293
  for (const bundleID of sqlGetBundleIDs.iterate()) {
292
294
  yield bundleArtifactName(bundleID);
293
295
  }
294
296
  }
297
+ harden(getArtifactNames);
295
298
 
296
299
  function computeSha512(bytes) {
297
300
  const hash = createHash('sha512');
@@ -328,7 +331,6 @@ export function makeBundleStore(db, ensureTxn, noteExport = () => {}) {
328
331
  endoZipBase64: encodeBase64(data),
329
332
  });
330
333
  // Assert that the bundle contents match the ID and hash
331
- // eslint-disable-next-line @jessie.js/no-nested-await
332
334
  await checkBundle(bundle, computeSha512, bundleID);
333
335
  populateBundle(bundleID, serializeBundle(bundleID, bundle));
334
336
  } else {
@@ -365,6 +367,7 @@ export function makeBundleStore(db, ensureTxn, noteExport = () => {}) {
365
367
  function* getBundleIDs() {
366
368
  yield* sqlListBundleIDs.iterate();
367
369
  }
370
+ harden(getBundleIDs);
368
371
 
369
372
  return harden({
370
373
  importBundleRecord,
package/src/exporter.js CHANGED
@@ -13,11 +13,11 @@ import { validateArtifactMode } from './internal.js';
13
13
 
14
14
  /**
15
15
  * @template T
16
- * @typedef { Iterable<T> | AsyncIterable<T> } AnyIterable<T>
16
+ * @typedef { Iterable<T> | AsyncIterable<T> } AnyIterable
17
17
  */
18
18
  /**
19
19
  * @template T
20
- * @typedef { IterableIterator<T> | AsyncIterableIterator<T> } AnyIterableIterator<T>
20
+ * @typedef { IterableIterator<T> | AsyncIterableIterator<T> } AnyIterableIterator
21
21
  */
22
22
 
23
23
  /**
@@ -111,12 +111,6 @@ export function makeSwingStoreExporter(dirPath, options = {}) {
111
111
  const bundleStore = makeBundleStore(db, ensureTxn);
112
112
  const transcriptStore = makeTranscriptStore(db, ensureTxn, () => {});
113
113
 
114
- if (artifactMode !== 'debug') {
115
- // throw early if this DB will not be able to create all the desired artifacts
116
- const internal = { snapStore, bundleStore, transcriptStore };
117
- assertComplete(internal, artifactMode);
118
- }
119
-
120
114
  const sqlKVGet = db.prepare(`
121
115
  SELECT value
122
116
  FROM kvStore
@@ -141,9 +135,11 @@ export function makeSwingStoreExporter(dirPath, options = {}) {
141
135
  function getHostKV(key) {
142
136
  typeof key === 'string' || Fail`key must be a string`;
143
137
  getKeyType(key) === 'host' || Fail`getHostKV requires host keys`;
138
+ // @ts-expect-error unknown
144
139
  return sqlKVGet.get(key);
145
140
  }
146
141
 
142
+ /** @type {any} */
147
143
  const sqlGetAllKVData = db.prepare(`
148
144
  SELECT key, value
149
145
  FROM kvStore
@@ -164,16 +160,27 @@ export function makeSwingStoreExporter(dirPath, options = {}) {
164
160
  yield* transcriptStore.getExportRecords(true);
165
161
  yield* bundleStore.getExportRecords();
166
162
  }
163
+ harden(getExportData);
167
164
 
168
- /**
169
- * @returns {AsyncIterableIterator<string>}
170
- * @yields {string}
171
- */
172
- async function* getArtifactNames() {
165
+ /** @yields {string} */
166
+ async function* artifactNames() {
173
167
  yield* snapStore.getArtifactNames(artifactMode);
174
168
  yield* transcriptStore.getArtifactNames(artifactMode);
175
169
  yield* bundleStore.getArtifactNames();
176
170
  }
171
+ harden(artifactNames);
172
+
173
+ /**
174
+ * @returns {AsyncIterableIterator<string>}
175
+ */
176
+ function getArtifactNames() {
177
+ if (artifactMode !== 'debug') {
178
+ // throw if this DB will not be able to yield all the desired artifacts
179
+ const internal = { snapStore, bundleStore, transcriptStore };
180
+ assertComplete(internal, artifactMode);
181
+ }
182
+ return artifactNames();
183
+ }
177
184
 
178
185
  /**
179
186
  * @param {string} name
package/src/importer.js CHANGED
@@ -17,10 +17,10 @@ import { assertComplete } from './assertComplete.js';
17
17
  * returned swingStore is not suitable for execution, and thus only contains
18
18
  * the host facet for committing the populated swingStore.
19
19
  *
20
- * @param {import('./exporter').SwingStoreExporter} exporter
20
+ * @param {import('./exporter.js').SwingStoreExporter} exporter
21
21
  * @param {string | null} [dirPath]
22
22
  * @param {ImportSwingStoreOptions} [options]
23
- * @returns {Promise<Pick<import('./swingStore').SwingStore, 'hostStorage' | 'debug'>>}
23
+ * @returns {Promise<Pick<import('./swingStore.js').SwingStore, 'hostStorage' | 'debug'>>}
24
24
  */
25
25
  export async function importSwingStore(exporter, dirPath = null, options = {}) {
26
26
  if (dirPath && typeof dirPath !== 'string') {
package/src/internal.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { Fail, q } from '@agoric/assert';
2
2
 
3
3
  /**
4
- * @typedef { import('./snapStore').SnapStoreInternal } SnapStoreInternal
5
- * @typedef { import('./transcriptStore').TranscriptStoreInternal } TranscriptStoreInternal
6
- * @typedef { import('./bundleStore').BundleStoreInternal } BundleStoreInternal
4
+ * @typedef { import('./snapStore.js').SnapStoreInternal } SnapStoreInternal
5
+ * @typedef { import('./transcriptStore.js').TranscriptStoreInternal } TranscriptStoreInternal
6
+ * @typedef { import('./bundleStore.js').BundleStoreInternal } BundleStoreInternal
7
7
  *
8
8
  * @typedef {{
9
9
  * transcriptStore: TranscriptStoreInternal,
@@ -25,7 +25,7 @@ import { assertComplete } from './assertComplete.js';
25
25
  * `hostStorage.commit()` when they are ready.
26
26
  *
27
27
  * @param {import('./internal.js').SwingStoreInternal} internal
28
- * @param {import('./exporter').SwingStoreExporter} exporter
28
+ * @param {import('./exporter.js').SwingStoreExporter} exporter
29
29
  * @returns {Promise<void>}
30
30
  */
31
31
  export async function doRepairMetadata(internal, exporter) {
package/src/snapStore.js CHANGED
@@ -4,7 +4,10 @@ import { finished as finishedCallback, PassThrough, Readable } from 'stream';
4
4
  import { promisify } from 'util';
5
5
  import { createGzip, createGunzip } from 'zlib';
6
6
  import { Fail, q } from '@agoric/assert';
7
- import { aggregateTryFinally, PromiseAllOrErrors } from '@agoric/internal';
7
+ import {
8
+ aggregateTryFinally,
9
+ PromiseAllOrErrors,
10
+ } from '@agoric/internal/src/node/utils.js';
8
11
  import { buffer } from './util.js';
9
12
 
10
13
  /**
@@ -25,12 +28,11 @@ import { buffer } from './util.js';
25
28
  */
26
29
 
27
30
  /**
28
- * @template T
29
- * @typedef { import('./exporter').AnyIterableIterator<T> } AnyIterableIterator<T>
31
+ * @import {AnyIterableIterator} from './exporter.js'
30
32
  */
31
33
 
32
34
  /**
33
- * @typedef { import('./exporter').SwingStoreExporter } SwingStoreExporter
35
+ * @typedef { import('./exporter.js').SwingStoreExporter } SwingStoreExporter
34
36
  * @typedef { import('./internal.js').ArtifactMode } ArtifactMode
35
37
  *
36
38
  * @typedef {{
@@ -306,6 +308,7 @@ export function makeSnapStore(
306
308
  const snapshotReader = gzReader.pipe(unzipper);
307
309
  yield* snapshotReader;
308
310
  }
311
+ harden(exporter);
309
312
  return exporter();
310
313
  }
311
314
 
@@ -333,17 +336,18 @@ export function makeSnapStore(
333
336
  snapReader.pipe(hashStream);
334
337
  snapReader.pipe(output);
335
338
 
339
+ await null;
336
340
  try {
337
341
  yield* output;
338
342
  } finally {
339
343
  gzReader.destroy();
340
- // eslint-disable-next-line @jessie.js/no-nested-await
341
344
  await finished(gzReader);
342
345
  const hash = hashStream.digest('hex');
343
346
  hash === snapshotID ||
344
347
  Fail`actual hash ${q(hash)} !== expected ${q(snapshotID)}`;
345
348
  }
346
349
  }
350
+ harden(loadSnapshot);
347
351
 
348
352
  const sqlDeleteVatSnapshots = db.prepare(`
349
353
  DELETE FROM snapshots
@@ -481,6 +485,7 @@ export function makeSnapStore(
481
485
  }
482
486
  }
483
487
  }
488
+ harden(getExportRecords);
484
489
 
485
490
  async function* getArtifactNames(artifactMode) {
486
491
  for (const rec of sqlGetAvailableSnapshots.iterate(1)) {
@@ -492,6 +497,7 @@ export function makeSnapStore(
492
497
  }
493
498
  }
494
499
  }
500
+ harden(getArtifactNames);
495
501
 
496
502
  const sqlAddSnapshotRecord = db.prepare(`
497
503
  INSERT INTO snapshots (vatID, snapPos, hash, inUse)
@@ -640,6 +646,7 @@ export function makeSnapStore(
640
646
  function* listAllSnapshots() {
641
647
  yield* sqlListAllSnapshots.iterate();
642
648
  }
649
+ harden(listAllSnapshots);
643
650
 
644
651
  const sqlDumpCurrentSnapshots = db.prepare(`
645
652
  SELECT vatID, snapPos, hash, compressedSnapshot, inUse
@@ -3,6 +3,6 @@ import { makeMeasureSeconds } from '@agoric/internal';
3
3
 
4
4
  export function makeSnapStoreIO() {
5
5
  return {
6
- measureSeconds: makeMeasureSeconds(performance.now),
6
+ measureSeconds: makeMeasureSeconds(performance.now.bind(performance)),
7
7
  };
8
8
  }
package/src/swingStore.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // @ts-check
2
2
  /* global Buffer */
3
- import fs from 'fs';
4
- import path from 'path';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
5
 
6
6
  import sqlite3 from 'better-sqlite3';
7
7
 
@@ -17,18 +17,18 @@ import { makeSnapStoreIO } from './snapStoreIO.js';
17
17
  import { doRepairMetadata } from './repairMetadata.js';
18
18
 
19
19
  /**
20
- * @typedef { import('./kvStore').KVStore } KVStore
20
+ * @typedef { import('./kvStore.js').KVStore } KVStore
21
21
  *
22
- * @typedef { import('./snapStore').SnapStore } SnapStore
23
- * @typedef { import('./snapStore').SnapshotResult } SnapshotResult
22
+ * @typedef { import('./snapStore.js').SnapStore } SnapStore
23
+ * @typedef { import('./snapStore.js').SnapshotResult } SnapshotResult
24
24
  *
25
- * @typedef { import('./transcriptStore').TranscriptStore } TranscriptStore
26
- * @typedef { import('./transcriptStore').TranscriptStoreDebug } TranscriptStoreDebug
25
+ * @typedef { import('./transcriptStore.js').TranscriptStore } TranscriptStore
26
+ * @typedef { import('./transcriptStore.js').TranscriptStoreDebug } TranscriptStoreDebug
27
27
  *
28
- * @typedef { import('./bundleStore').BundleStore } BundleStore
29
- * @typedef { import('./bundleStore').BundleStoreDebug } BundleStoreDebug
28
+ * @typedef { import('./bundleStore.js').BundleStore } BundleStore
29
+ * @typedef { import('./bundleStore.js').BundleStoreDebug } BundleStoreDebug
30
30
  *
31
- * @typedef { import('./exporter').KVPair } KVPair
31
+ * @typedef { import('./exporter.js').KVPair } KVPair
32
32
  *
33
33
  * @typedef {{
34
34
  * kvStore: KVStore, // a key-value API object to load and store data on behalf of the kernel
@@ -49,7 +49,7 @@ import { doRepairMetadata } from './repairMetadata.js';
49
49
  * close: () => Promise<void>, // shutdown the store, abandoning any uncommitted changes
50
50
  * diskUsage?: () => number, // optional stats method
51
51
  * setExportCallback: (cb: (updates: KVPair[]) => void) => void, // Set a callback invoked by swingStore when new serializable data is available for export
52
- * repairMetadata: (exporter: import('./exporter').SwingStoreExporter) => Promise<void>,
52
+ * repairMetadata: (exporter: import('./exporter.js').SwingStoreExporter) => Promise<void>,
53
53
  * }} SwingStoreHostStorage
54
54
  */
55
55
 
@@ -543,6 +543,10 @@ export function makeSwingStore(dirPath, forceReset, options = {}) {
543
543
  });
544
544
  }
545
545
 
546
+ function getDatabase() {
547
+ return db;
548
+ }
549
+
546
550
  const transcriptStorePublic = {
547
551
  initTranscript: transcriptStore.initTranscript,
548
552
  rolloverSpan: transcriptStore.rolloverSpan,
@@ -592,6 +596,7 @@ export function makeSwingStore(dirPath, forceReset, options = {}) {
592
596
  const debug = {
593
597
  serialize,
594
598
  dump,
599
+ getDatabase,
595
600
  };
596
601
 
597
602
  return harden({
@@ -43,6 +43,7 @@ import { createSHA256 } from './hasher.js';
43
43
  function* empty() {
44
44
  // Yield nothing
45
45
  }
46
+ harden(empty);
46
47
 
47
48
  /**
48
49
  * @param {number} position
@@ -158,6 +159,7 @@ export function makeTranscriptStore(
158
159
  }
159
160
  }
160
161
  }
162
+ harden(readFullVatTranscript);
161
163
 
162
164
  function spanArtifactName(rec) {
163
165
  return `transcript.${rec.vatID}.${rec.startPos}.${rec.endPos}`;
@@ -393,6 +395,7 @@ export function makeTranscriptStore(
393
395
  }
394
396
  }
395
397
  }
398
+ harden(getExportRecords);
396
399
 
397
400
  const sqlCountSpanItems = db.prepare(`
398
401
  SELECT COUNT(*) FROM transcriptItems
@@ -447,6 +450,7 @@ export function makeTranscriptStore(
447
450
  }
448
451
  }
449
452
  }
453
+ harden(getArtifactNames);
450
454
 
451
455
  const sqlGetSpanEndPos = db.prepare(`
452
456
  SELECT endPos
@@ -501,6 +505,7 @@ export function makeTranscriptStore(
501
505
  expectedCount,
502
506
  )})`;
503
507
  }
508
+ harden(reader);
504
509
 
505
510
  if (startPos === endPos) {
506
511
  return empty();
@@ -541,6 +546,7 @@ export function makeTranscriptStore(
541
546
  yield Buffer.from(`${entry}\n`);
542
547
  }
543
548
  }
549
+ harden(exportSpan);
544
550
 
545
551
  const sqlAddItem = db.prepare(`
546
552
  INSERT INTO transcriptItems (vatID, item, position, incarnation)
package/src/util.js CHANGED
@@ -6,7 +6,7 @@ import { Buffer } from 'buffer';
6
6
  * 'stream/consumers' package, which unfortunately only exists in newer versions
7
7
  * of Node.
8
8
  *
9
- * @param {import('./exporter').AnyIterable<Uint8Array>} inStream
9
+ * @param {import('./exporter.js').AnyIterable<Uint8Array>} inStream
10
10
  */
11
11
  export const buffer = async inStream => {
12
12
  const chunks = [];
@@ -1,5 +1,4 @@
1
1
  // @ts-check
2
- import '@endo/init/debug.js';
3
2
  import test from 'ava';
4
3
  import tmp from 'tmp';
5
4
  import { Buffer } from 'buffer';
@@ -162,7 +161,7 @@ test('unknown format', t => {
162
161
  const { kernelStorage } = initSwingStore();
163
162
  const { bundleStore } = kernelStorage;
164
163
  const unknownID = 'b1999-whoa-futuristic';
165
- /** @typedef {import('../src/bundleStore.js').Bundle} Bundle */
164
+ /** @import {Bundle} from '../src/bundleStore.js' */
166
165
  t.throws(() => bundleStore.addBundle(unknownID, /** @type {Bundle} */ ({})), {
167
166
  message: /unsupported BundleID/,
168
167
  });
@@ -1,12 +1,12 @@
1
1
  // @ts-check
2
2
  import test from 'ava';
3
- import '@endo/init/debug.js';
4
3
  import { Buffer } from 'node:buffer';
5
4
  import { initSwingStore } from '../src/swingStore.js';
6
5
 
7
6
  async function* getSnapshotStream() {
8
7
  yield Buffer.from('abc');
9
8
  }
9
+ harden(getSnapshotStream);
10
10
 
11
11
  test('delete snapshots with export callback', async t => {
12
12
  const exportLog = [];
@@ -1,5 +1,3 @@
1
- import '@endo/init/debug.js';
2
-
3
1
  import test from 'ava';
4
2
 
5
3
  import { buffer } from '../src/util.js';
@@ -83,7 +81,7 @@ const exportTest = test.macro(async (t, mode) => {
83
81
  // historical transcript spans, and no historical snapshots
84
82
 
85
83
  assert.typeof(mode, 'string');
86
- /** @typedef {import('../src/internal.js').ArtifactMode} ArtifactMode */
84
+ /** @import {ArtifactMode} from '../src/internal.js' */
87
85
  let artifactMode = /** @type {ArtifactMode} */ (mode);
88
86
  if (mode === 'debug-on-pruned') {
89
87
  artifactMode = 'debug';
@@ -1,11 +1,8 @@
1
1
  // @ts-check
2
2
 
3
- import '@endo/init/debug.js';
4
3
  import { Buffer } from 'node:buffer';
5
4
 
6
- // eslint-disable-next-line import/no-extraneous-dependencies
7
5
  import test from 'ava';
8
- // eslint-disable-next-line import/no-extraneous-dependencies
9
6
  import tmp from 'tmp';
10
7
  import bundleSource from '@endo/bundle-source';
11
8
 
@@ -55,7 +52,7 @@ async function embundle(filename) {
55
52
  const bundleFile = new URL(filename, import.meta.url).pathname;
56
53
  const bundle = await bundleSource(bundleFile);
57
54
  const bundleID = `b1-${bundle.endoZipBase64Sha512}`;
58
- return [bundleID, bundle];
55
+ return /** @type {const} */ ([bundleID, bundle]);
59
56
  }
60
57
 
61
58
  function actLikeAVatRunningACrank(vat, ks, crank, doFail) {
@@ -86,6 +83,7 @@ async function fakeAVatSnapshot(vat, ks) {
86
83
  async function* getSnapshotStream() {
87
84
  yield Buffer.from(`snapshot of vat ${vat.vatID} as of ${vat.endPos}`);
88
85
  }
86
+ harden(getSnapshotStream);
89
87
  await ks.snapStore.saveSnapshot(vat.vatID, vat.endPos, getSnapshotStream());
90
88
  ks.transcriptStore.addItem(vat.vatID, 'save-snapshot');
91
89
  vat.endPos += 1;
@@ -122,7 +120,6 @@ test('crank abort leaves no debris in export log', async t => {
122
120
  crankNum % 3 === 0,
123
121
  );
124
122
  }
125
- // eslint-disable-next-line no-await-in-loop
126
123
  await ssOut.hostStorage.commit();
127
124
  }
128
125
 
@@ -218,22 +215,21 @@ async function testExportImport(
218
215
  actLikeAVatRunningACrank(vat, kernelStorage, crankNum);
219
216
  }
220
217
  if (block < 3) {
221
- // eslint-disable-next-line no-await-in-loop
222
218
  await fakeAVatSnapshot(vats[block % 2], kernelStorage);
223
219
  }
224
- // eslint-disable-next-line no-await-in-loop
225
220
  await ssOut.hostStorage.commit();
226
221
  }
227
222
 
223
+ // the exporter may be broken (the swingstore may be incomplete), but that is
224
+ // signaled during `getArtifactNames()`, not during construction (which must
225
+ // finish quickly, without scanning the whole DB)
226
+ const exporter = makeSwingStoreExporter(dbDir, { artifactMode: exportMode });
227
+
228
228
  const incomplete = 'incomplete archival transcript: 3 vs 12';
229
- function doExport() {
230
- return makeSwingStoreExporter(dbDir, { artifactMode: exportMode });
231
- }
232
229
  if (failureMode === 'export') {
233
- await t.throws(doExport, { message: incomplete });
230
+ await t.throws(() => exporter.getArtifactNames(), { message: incomplete });
234
231
  return;
235
232
  }
236
- const exporter = doExport();
237
233
 
238
234
  const exportData = [];
239
235
  for await (const elem of exporter.getExportData()) {
@@ -0,0 +1,102 @@
1
+ import { Buffer } from 'buffer';
2
+ import { makeB0ID } from './util.js';
3
+
4
+ export const snapshotData = 'snapshot data';
5
+ // this snapHash was computed manually
6
+ export const snapHash =
7
+ 'e7dee7266896538616b630a5da40a90e007726a383e005a9c9c5dd0c2daf9329';
8
+
9
+ /** @type {import('../src/bundleStore.js').Bundle} */
10
+ export const bundle0 = { moduleFormat: 'nestedEvaluate', source: '1+1' };
11
+ export const bundle0ID = makeB0ID(bundle0);
12
+
13
+ export function buildData() {
14
+ // build an export manually
15
+ const exportData = new Map();
16
+ const artifacts = new Map();
17
+
18
+ // shadow kvStore
19
+ exportData.set('kv.key1', 'value1');
20
+
21
+ // now add artifacts and metadata in pairs
22
+
23
+ artifacts.set(`bundle.${bundle0ID}`, JSON.stringify(bundle0));
24
+ exportData.set(`bundle.${bundle0ID}`, bundle0ID);
25
+
26
+ const sbase = { vatID: 'v1', hash: snapHash, inUse: 0 };
27
+ const tbase = { vatID: 'v1', startPos: 0, isCurrent: 0, incarnation: 1 };
28
+ const addTS = (key, obj) =>
29
+ exportData.set(key, JSON.stringify({ ...tbase, ...obj }));
30
+ const t0hash =
31
+ '5bee0f44eca02f23eab03703e84ed2647d5d117fed99e1c30a3b424b7f082ab9';
32
+ const t2hash =
33
+ '57152efdd7fdf75c03371d2b4f1088d5bf3eae7fe643babce527ff81df38998c';
34
+ const t5hash =
35
+ '1947001e78e01bd1e773feb22b4ffc530447373b9de9274d5d5fbda3f23dbf2b';
36
+ const t8hash =
37
+ 'e6b42c6a3fb94285a93162f25a9fc0145fd4c5bb144917dc572c50ae2d02ee69';
38
+
39
+ addTS(`transcript.v1.0`, { incarnation: 0, endPos: 2, hash: t0hash });
40
+ artifacts.set(`transcript.v1.0.2`, 'start-worker\nshutdown-worker\n');
41
+
42
+ addTS(`transcript.v1.2`, { startPos: 2, endPos: 5, hash: t2hash });
43
+ artifacts.set(
44
+ `transcript.v1.2.5`,
45
+ 'start-worker\ndelivery1\nsave-snapshot\n',
46
+ );
47
+ exportData.set(`snapshot.v1.4`, JSON.stringify({ ...sbase, snapPos: 4 }));
48
+ artifacts.set(`snapshot.v1.4`, snapshotData);
49
+
50
+ addTS(`transcript.v1.5`, { startPos: 5, endPos: 8, hash: t5hash });
51
+ artifacts.set(
52
+ 'transcript.v1.5.8',
53
+ 'load-snapshot\ndelivery2\nsave-snapshot\n',
54
+ );
55
+ exportData.set(
56
+ `snapshot.v1.7`,
57
+ JSON.stringify({ ...sbase, snapPos: 7, inUse: 1 }),
58
+ );
59
+ artifacts.set(`snapshot.v1.7`, snapshotData);
60
+
61
+ artifacts.set('transcript.v1.8.10', 'load-snapshot\ndelivery3\n');
62
+ exportData.set(`snapshot.v1.current`, 'snapshot.v1.7');
63
+ addTS(`transcript.v1.current`, {
64
+ startPos: 8,
65
+ endPos: 10,
66
+ isCurrent: 1,
67
+ hash: t8hash,
68
+ });
69
+
70
+ return { exportData, artifacts, t0hash, t2hash, t5hash, t8hash };
71
+ }
72
+
73
+ /**
74
+ * @param { Map<string, string | null> } exportData
75
+ * @param { Map<string, string> } artifacts
76
+ */
77
+ export function makeExporter(exportData, artifacts) {
78
+ return {
79
+ getHostKV(_key) {
80
+ return undefined;
81
+ },
82
+ async *getExportData() {
83
+ for (const [key, value] of exportData.entries()) {
84
+ /** @type { import('../src/exporter.js').KVPair } */
85
+ const pair = [key, value];
86
+ yield pair;
87
+ }
88
+ },
89
+ async *getArtifactNames() {
90
+ for (const name of artifacts.keys()) {
91
+ yield name;
92
+ }
93
+ },
94
+ async *getArtifact(name) {
95
+ const data = artifacts.get(name);
96
+ assert(data, `missing artifact ${name}`);
97
+ yield Buffer.from(data);
98
+ },
99
+ // eslint-disable-next-line no-empty-function
100
+ async close() {},
101
+ };
102
+ }
@@ -1,7 +1,5 @@
1
- import '@endo/init/debug.js';
2
1
  import test from 'ava';
3
2
 
4
- // eslint-disable-next-line import/order
5
3
  import { createSHA256 } from '../src/hasher.js';
6
4
 
7
5
  test('createSHA256', t => {
@@ -1,7 +1,5 @@
1
1
  // @ts-check
2
2
 
3
- import '@endo/init/debug.js';
4
-
5
3
  import path from 'path';
6
4
  import { createGunzip } from 'zlib';
7
5
  import { Readable } from 'stream';
@@ -14,7 +12,15 @@ import { decodeBase64 } from '@endo/base64';
14
12
  import { buffer } from '../src/util.js';
15
13
  import { importSwingStore, makeSwingStoreExporter } from '../src/index.js';
16
14
 
17
- import { tmpDir, makeB0ID } from './util.js';
15
+ import { tmpDir } from './util.js';
16
+ import {
17
+ buildData,
18
+ bundle0,
19
+ bundle0ID,
20
+ makeExporter,
21
+ snapHash,
22
+ snapshotData,
23
+ } from './exports.js';
18
24
 
19
25
  const rank = {
20
26
  operational: 1,
@@ -23,15 +29,6 @@ const rank = {
23
29
  debug: 4,
24
30
  };
25
31
 
26
- const snapshotData = 'snapshot data';
27
- // this snapHash was computed manually
28
- const snapHash =
29
- 'e7dee7266896538616b630a5da40a90e007726a383e005a9c9c5dd0c2daf9329';
30
-
31
- /** @type {import('../src/bundleStore.js').Bundle} */
32
- const bundle0 = { moduleFormat: 'nestedEvaluate', source: '1+1' };
33
- const bundle0ID = makeB0ID(bundle0);
34
-
35
32
  function convert(orig) {
36
33
  const bundles = Object.fromEntries(
37
34
  Object.entries(orig.bundles).map(([bundleID, encBundle]) => {
@@ -44,41 +41,6 @@ function convert(orig) {
44
41
  return { ...orig, bundles };
45
42
  }
46
43
 
47
- /**
48
- * @typedef { import('../src/exporter').KVPair } KVPair
49
- */
50
-
51
- /**
52
- * @param { Map<string, string | null> } exportData
53
- * @param { Map<string, string> } artifacts
54
- */
55
- export function makeExporter(exportData, artifacts) {
56
- return {
57
- getHostKV(_key) {
58
- return undefined;
59
- },
60
- async *getExportData() {
61
- for (const [key, value] of exportData.entries()) {
62
- /** @type { KVPair } */
63
- const pair = [key, value];
64
- yield pair;
65
- }
66
- },
67
- async *getArtifactNames() {
68
- for (const name of artifacts.keys()) {
69
- yield name;
70
- }
71
- },
72
- async *getArtifact(name) {
73
- const data = artifacts.get(name);
74
- assert(data, `missing artifact ${name}`);
75
- yield Buffer.from(data);
76
- },
77
- // eslint-disable-next-line no-empty-function
78
- async close() {},
79
- };
80
- }
81
-
82
44
  test('import empty', async t => {
83
45
  const [dbDir, cleanup] = await tmpDir('testdb');
84
46
  t.teardown(cleanup);
@@ -95,68 +57,8 @@ test('import empty', async t => {
95
57
  });
96
58
  });
97
59
 
98
- export function buildData() {
99
- // build an export manually
100
- const exportData = new Map();
101
- const artifacts = new Map();
102
-
103
- // shadow kvStore
104
- exportData.set('kv.key1', 'value1');
105
-
106
- // now add artifacts and metadata in pairs
107
-
108
- artifacts.set(`bundle.${bundle0ID}`, JSON.stringify(bundle0));
109
- exportData.set(`bundle.${bundle0ID}`, bundle0ID);
110
-
111
- const sbase = { vatID: 'v1', hash: snapHash, inUse: 0 };
112
- const tbase = { vatID: 'v1', startPos: 0, isCurrent: 0, incarnation: 1 };
113
- const addTS = (key, obj) =>
114
- exportData.set(key, JSON.stringify({ ...tbase, ...obj }));
115
- const t0hash =
116
- '5bee0f44eca02f23eab03703e84ed2647d5d117fed99e1c30a3b424b7f082ab9';
117
- const t2hash =
118
- '57152efdd7fdf75c03371d2b4f1088d5bf3eae7fe643babce527ff81df38998c';
119
- const t5hash =
120
- '1947001e78e01bd1e773feb22b4ffc530447373b9de9274d5d5fbda3f23dbf2b';
121
- const t8hash =
122
- 'e6b42c6a3fb94285a93162f25a9fc0145fd4c5bb144917dc572c50ae2d02ee69';
123
-
124
- addTS(`transcript.v1.0`, { incarnation: 0, endPos: 2, hash: t0hash });
125
- artifacts.set(`transcript.v1.0.2`, 'start-worker\nshutdown-worker\n');
126
-
127
- addTS(`transcript.v1.2`, { startPos: 2, endPos: 5, hash: t2hash });
128
- artifacts.set(
129
- `transcript.v1.2.5`,
130
- 'start-worker\ndelivery1\nsave-snapshot\n',
131
- );
132
- exportData.set(`snapshot.v1.4`, JSON.stringify({ ...sbase, snapPos: 4 }));
133
- artifacts.set(`snapshot.v1.4`, snapshotData);
134
-
135
- addTS(`transcript.v1.5`, { startPos: 5, endPos: 8, hash: t5hash });
136
- artifacts.set(
137
- 'transcript.v1.5.8',
138
- 'load-snapshot\ndelivery2\nsave-snapshot\n',
139
- );
140
- exportData.set(
141
- `snapshot.v1.7`,
142
- JSON.stringify({ ...sbase, snapPos: 7, inUse: 1 }),
143
- );
144
- artifacts.set(`snapshot.v1.7`, snapshotData);
145
-
146
- artifacts.set('transcript.v1.8.10', 'load-snapshot\ndelivery3\n');
147
- exportData.set(`snapshot.v1.current`, 'snapshot.v1.7');
148
- addTS(`transcript.v1.current`, {
149
- startPos: 8,
150
- endPos: 10,
151
- isCurrent: 1,
152
- hash: t8hash,
153
- });
154
-
155
- return { exportData, artifacts, t0hash, t2hash, t5hash, t8hash };
156
- }
157
-
158
60
  const importTest = test.macro(async (t, mode) => {
159
- /** @typedef {import('../src/internal.js').ArtifactMode} ArtifactMode */
61
+ /** @import {ArtifactMode} from '../src/internal.js' */
160
62
  const artifactMode = /** @type {ArtifactMode} */ (mode);
161
63
 
162
64
  const [dbDir, cleanup] = await tmpDir('testdb');
@@ -254,6 +156,7 @@ const importTest = test.macro(async (t, mode) => {
254
156
  ...db.prepare('SELECT * FROM transcriptSpans ORDER BY startPos').iterate(),
255
157
  ];
256
158
  t.deepEqual(
159
+ // @ts-expect-error unknown
257
160
  spanRows.map(sr => sr.startPos),
258
161
  [0, 2, 5, 8],
259
162
  );
@@ -1,14 +1,12 @@
1
1
  // @ts-check
2
2
 
3
- import '@endo/init/debug.js';
4
-
5
3
  import path from 'path';
6
4
  import test from 'ava';
7
5
  import sqlite3 from 'better-sqlite3';
8
6
 
9
7
  import { importSwingStore, openSwingStore } from '../src/index.js';
10
8
 
11
- import { makeExporter, buildData } from './test-import.js';
9
+ import { makeExporter, buildData } from './exports.js';
12
10
  import { tmpDir } from './util.js';
13
11
 
14
12
  test('repair metadata', async t => {
@@ -1,13 +1,10 @@
1
1
  // @ts-check
2
2
 
3
- import '@endo/init/debug.js';
4
3
  import { Buffer } from 'node:buffer';
5
4
  import zlib from 'zlib';
6
5
  import sqlite3 from 'better-sqlite3';
7
6
 
8
- // eslint-disable-next-line import/no-extraneous-dependencies
9
7
  import test from 'ava';
10
- // eslint-disable-next-line import/no-extraneous-dependencies
11
8
  import { makeMeasureSeconds } from '@agoric/internal';
12
9
  import { makeSnapStore } from '../src/snapStore.js';
13
10
 
@@ -29,6 +26,7 @@ function ensureTxn() {}
29
26
  async function* getSnapshotStream(payload) {
30
27
  yield Buffer.from(payload);
31
28
  }
29
+ harden(getSnapshotStream);
32
30
 
33
31
  test('compress to cache file; closes snapshot stream', async t => {
34
32
  const db = sqlite3(':memory:');
@@ -83,6 +81,7 @@ test('compress to cache file; closes snapshot stream', async t => {
83
81
  sqlGetSnapshot.pluck(true);
84
82
  const snapshotGZ = sqlGetSnapshot.get(hash);
85
83
  t.truthy(snapshotGZ);
84
+ // @ts-expect-error unknown
86
85
  const contents = zlib.gunzipSync(snapshotGZ);
87
86
  t.is(contents.toString(), 'abc', 'gunzip(contents) matches original');
88
87
  const logInfo = { vatID: 'fakeVatID', ...exportInfo };
@@ -103,7 +102,6 @@ test('snapStore prepare / commit delete is robust', async t => {
103
102
 
104
103
  const hashes = [];
105
104
  for (let i = 0; i < 5; i += 1) {
106
- // eslint-disable-next-line no-await-in-loop
107
105
  const { hash } = await store.saveSnapshot(
108
106
  'fakeVatID2',
109
107
  i,
@@ -133,7 +131,6 @@ test('snapStore prepare / commit delete is robust', async t => {
133
131
  t.is(sqlCountSnapshots.get(), 0);
134
132
 
135
133
  for (let i = 0; i < 5; i += 1) {
136
- // eslint-disable-next-line no-await-in-loop
137
134
  const { hash } = await store.saveSnapshot(
138
135
  'fakeVatID4',
139
136
  i,
@@ -1,7 +1,5 @@
1
1
  // @ts-check
2
2
 
3
- import '@endo/init/debug.js';
4
-
5
3
  import tmp from 'tmp';
6
4
  import test from 'ava';
7
5
 
@@ -32,7 +30,7 @@ async function embundle(filename) {
32
30
  const bundleFile = new URL(filename, import.meta.url).pathname;
33
31
  const bundle = await bundleSource(bundleFile);
34
32
  const bundleID = `b1-${bundle.endoZipBase64Sha512}`;
35
- return [bundleID, bundle];
33
+ return /** @type {const} */ ([bundleID, bundle]);
36
34
  }
37
35
 
38
36
  function* iterate(kvStore, start, end) {
@@ -49,6 +47,7 @@ function* iterate(kvStore, start, end) {
49
47
  prev = next;
50
48
  }
51
49
  }
50
+ harden(iterate);
52
51
 
53
52
  function makeExportLog() {
54
53
  const exportLog = [];
package/test/util.js CHANGED
@@ -20,6 +20,7 @@ export const tmpDir = prefix =>
20
20
  export async function* getSnapshotStream(contents) {
21
21
  yield Buffer.from(contents);
22
22
  }
23
+ harden(getSnapshotStream);
23
24
 
24
25
  export function makeB0ID(bundle) {
25
26
  return `b0-${createSHA256(JSON.stringify(bundle)).finish()}`;
@@ -1,6 +1,7 @@
1
1
  // This file can contain .js-specific Typescript compiler config.
2
2
  {
3
3
  "extends": "../../tsconfig.json",
4
+ "compilerOptions": {},
4
5
  "include": [
5
6
  "src/**/*.js",
6
7
  "test/**/*.js",