@pnpm/store.index 1100.0.0 → 1100.1.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/lib/index.d.ts CHANGED
@@ -13,6 +13,28 @@ export declare function storeIndexKey(integrity: string, pkgId: string): string;
13
13
  export declare function gitHostedStoreIndexKey(pkgId: string, opts: {
14
14
  built: boolean;
15
15
  }): string;
16
+ /**
17
+ * Pick the store index key for a tarball-shaped resolution.
18
+ *
19
+ * Git-hosted tarballs (`resolution.gitHosted === true`) are addressed by
20
+ * `gitHostedStoreIndexKey(pkgId, { built })` — their cached content depends
21
+ * on whether build scripts ran during fetch (`preparePackage`), so the
22
+ * `built` dimension is part of the key. The integrity-only key would
23
+ * collapse the built/not-built variants into one slot.
24
+ *
25
+ * Tarballs with integrity that aren't git-hosted are addressed by
26
+ * `storeIndexKey(integrity, pkgId)`.
27
+ *
28
+ * Resolutions that have neither flag fall through to
29
+ * `gitHostedStoreIndexKey` — these are typically lockfile entries written
30
+ * by older pnpm versions that lacked integrity.
31
+ */
32
+ export declare function pickStoreIndexKey(resolution: {
33
+ gitHosted?: boolean;
34
+ integrity?: string;
35
+ }, pkgId: string, opts: {
36
+ built: boolean;
37
+ }): string;
16
38
  /**
17
39
  * Close all open StoreIndex instances.
18
40
  * Useful in tests that need to remove the store directory.
@@ -28,9 +50,14 @@ export declare class StoreIndex {
28
50
  private stmtDel;
29
51
  private stmtHas;
30
52
  private stmtAll;
53
+ private stmtKeys;
31
54
  private readonly exitHandler;
32
55
  constructor(storeDir: string);
33
56
  get(key: string): unknown | undefined;
57
+ /**
58
+ * Get the raw msgpack-encoded buffer for a key without decoding.
59
+ */
60
+ getRaw(key: string): Uint8Array | undefined;
34
61
  set(key: string, data: unknown): void;
35
62
  delete(key: string): boolean;
36
63
  has(key: string): boolean;
@@ -39,6 +66,11 @@ export declare class StoreIndex {
39
66
  * Yields [key, data] pairs where key is `integrity\tpkgId`.
40
67
  */
41
68
  entries(): IterableIterator<[string, unknown]>;
69
+ /**
70
+ * Iterate over all index keys without decoding values.
71
+ * Much faster than entries() when only keys are needed.
72
+ */
73
+ keys(): IterableIterator<string>;
42
74
  /**
43
75
  * Queue pre-packed writes to be flushed on the next tick.
44
76
  * Used by the fetch phase for throughput.
@@ -64,5 +96,6 @@ export declare class StoreIndex {
64
96
  * then VACUUM to reclaim disk space.
65
97
  */
66
98
  deleteMany(keys: string[]): void;
99
+ checkpoint(): void;
67
100
  close(): void;
68
101
  }
package/lib/index.js CHANGED
@@ -54,6 +54,28 @@ export function storeIndexKey(integrity, pkgId) {
54
54
  export function gitHostedStoreIndexKey(pkgId, opts) {
55
55
  return storeIndexKey(pkgId, opts.built ? 'built' : 'not-built');
56
56
  }
57
+ /**
58
+ * Pick the store index key for a tarball-shaped resolution.
59
+ *
60
+ * Git-hosted tarballs (`resolution.gitHosted === true`) are addressed by
61
+ * `gitHostedStoreIndexKey(pkgId, { built })` — their cached content depends
62
+ * on whether build scripts ran during fetch (`preparePackage`), so the
63
+ * `built` dimension is part of the key. The integrity-only key would
64
+ * collapse the built/not-built variants into one slot.
65
+ *
66
+ * Tarballs with integrity that aren't git-hosted are addressed by
67
+ * `storeIndexKey(integrity, pkgId)`.
68
+ *
69
+ * Resolutions that have neither flag fall through to
70
+ * `gitHostedStoreIndexKey` — these are typically lockfile entries written
71
+ * by older pnpm versions that lacked integrity.
72
+ */
73
+ export function pickStoreIndexKey(resolution, pkgId, opts) {
74
+ if (resolution.gitHosted || !resolution.integrity) {
75
+ return gitHostedStoreIndexKey(pkgId, opts);
76
+ }
77
+ return storeIndexKey(resolution.integrity, pkgId);
78
+ }
57
79
  const openInstances = new Set();
58
80
  /**
59
81
  * Close all open StoreIndex instances.
@@ -74,6 +96,7 @@ export class StoreIndex {
74
96
  stmtDel;
75
97
  stmtHas;
76
98
  stmtAll;
99
+ stmtKeys;
77
100
  exitHandler;
78
101
  constructor(storeDir) {
79
102
  const dbPath = `${storeDir}/index.db`;
@@ -105,6 +128,7 @@ export class StoreIndex {
105
128
  this.stmtDel = this.db.prepare('DELETE FROM package_index WHERE key = ?');
106
129
  this.stmtHas = this.db.prepare('SELECT 1 FROM package_index WHERE key = ?');
107
130
  this.stmtAll = this.db.prepare('SELECT key, data FROM package_index');
131
+ this.stmtKeys = this.db.prepare('SELECT key FROM package_index');
108
132
  this.exitHandler = () => this.close();
109
133
  // Multiple StoreIndex instances may be created (e.g. in tests), each adding
110
134
  // an exit listener. Raise the limit to avoid MaxListenersExceededWarning.
@@ -123,6 +147,13 @@ export class StoreIndex {
123
147
  }
124
148
  return undefined;
125
149
  }
150
+ /**
151
+ * Get the raw msgpack-encoded buffer for a key without decoding.
152
+ */
153
+ getRaw(key) {
154
+ const row = sqliteRetry(() => this.stmtGet.get(key));
155
+ return row?.data;
156
+ }
126
157
  set(key, data) {
127
158
  const buffer = packr.pack(data);
128
159
  sqliteRetry(() => {
@@ -148,6 +179,15 @@ export class StoreIndex {
148
179
  yield [row.key, packr.unpack(row.data)];
149
180
  }
150
181
  }
182
+ /**
183
+ * Iterate over all index keys without decoding values.
184
+ * Much faster than entries() when only keys are needed.
185
+ */
186
+ *keys() {
187
+ for (const row of this.stmtKeys.iterate()) {
188
+ yield row.key;
189
+ }
190
+ }
151
191
  /**
152
192
  * Queue pre-packed writes to be flushed on the next tick.
153
193
  * Used by the fetch phase for throughput.
@@ -237,6 +277,14 @@ export class StoreIndex {
237
277
  });
238
278
  this.db.exec('VACUUM');
239
279
  }
280
+ checkpoint() {
281
+ this.flush();
282
+ // wal_checkpoint can hit SQLITE_BUSY if another process is reading the
283
+ // same index.db concurrently. Retry for consistency with other ops here.
284
+ sqliteRetry(() => {
285
+ this.db.exec('PRAGMA wal_checkpoint(TRUNCATE)');
286
+ });
287
+ }
240
288
  close() {
241
289
  if (this.closed)
242
290
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/store.index",
3
- "version": "1100.0.0",
3
+ "version": "1100.1.0",
4
4
  "description": "SQLite-backed index for the pnpm content-addressable store",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -28,9 +28,10 @@
28
28
  "msgpackr": "1.11.8"
29
29
  },
30
30
  "devDependencies": {
31
- "@types/node": "^22.19.15",
31
+ "@jest/globals": "30.3.0",
32
+ "@types/node": "^22.19.17",
32
33
  "tempy": "3.0.0",
33
- "@pnpm/store.index": "1100.0.0"
34
+ "@pnpm/store.index": "1100.1.0"
34
35
  },
35
36
  "engines": {
36
37
  "node": ">=22.13"