@pnpm/store.index 1000.0.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
@@ -1,5 +1,5 @@
1
- import { createRequire } from 'module';
2
- import fs from 'fs';
1
+ import fs from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
3
  import { Packr } from 'msgpackr';
4
4
  // Use createRequire to load node:sqlite because it is a prefix-only builtin
5
5
  // that Jest's ESM module resolver cannot handle.
@@ -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,7 +128,15 @@ 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();
133
+ // Multiple StoreIndex instances may be created (e.g. in tests), each adding
134
+ // an exit listener. Raise the limit to avoid MaxListenersExceededWarning.
135
+ // Skip when maxListeners is 0 (unlimited).
136
+ const currentMax = process.getMaxListeners();
137
+ if (currentMax !== 0 && currentMax < openInstances.size + 11) {
138
+ process.setMaxListeners(Math.max(currentMax + 10, openInstances.size + 11));
139
+ }
109
140
  process.on('exit', this.exitHandler);
110
141
  openInstances.add(this);
111
142
  }
@@ -116,6 +147,13 @@ export class StoreIndex {
116
147
  }
117
148
  return undefined;
118
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
+ }
119
157
  set(key, data) {
120
158
  const buffer = packr.pack(data);
121
159
  sqliteRetry(() => {
@@ -141,6 +179,15 @@ export class StoreIndex {
141
179
  yield [row.key, packr.unpack(row.data)];
142
180
  }
143
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
+ }
144
191
  /**
145
192
  * Queue pre-packed writes to be flushed on the next tick.
146
193
  * Used by the fetch phase for throughput.
@@ -230,6 +277,14 @@ export class StoreIndex {
230
277
  });
231
278
  this.db.exec('VACUUM');
232
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
+ }
233
288
  close() {
234
289
  if (this.closed)
235
290
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/store.index",
3
- "version": "1000.0.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",
@@ -25,12 +25,13 @@
25
25
  "!*.map"
26
26
  ],
27
27
  "dependencies": {
28
- "msgpackr": "^1.11.2"
28
+ "msgpackr": "1.11.8"
29
29
  },
30
30
  "devDependencies": {
31
- "@types/node": "^22.19.11",
31
+ "@jest/globals": "30.3.0",
32
+ "@types/node": "^22.19.17",
32
33
  "tempy": "3.0.0",
33
- "@pnpm/store.index": "1000.0.0-0"
34
+ "@pnpm/store.index": "1100.1.0"
34
35
  },
35
36
  "engines": {
36
37
  "node": ">=22.13"
@@ -40,8 +41,8 @@
40
41
  },
41
42
  "scripts": {
42
43
  "lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
43
- "_test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest",
44
- "test": "pnpm run compile && pnpm run _test",
45
- "compile": "tsgo --build && pnpm run lint --fix"
44
+ "test": "pn compile && pn .test",
45
+ "compile": "tsgo --build && pn lint --fix",
46
+ ".test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169\" jest"
46
47
  }
47
48
  }