@photostructure/sqlite 0.0.1 → 0.2.1

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +38 -2
  2. package/README.md +47 -483
  3. package/SECURITY.md +27 -83
  4. package/binding.gyp +69 -22
  5. package/dist/index.cjs +185 -18
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.cts +552 -100
  8. package/dist/index.d.mts +552 -100
  9. package/dist/index.d.ts +552 -100
  10. package/dist/index.mjs +183 -18
  11. package/dist/index.mjs.map +1 -1
  12. package/package.json +51 -41
  13. package/prebuilds/darwin-arm64/@photostructure+sqlite.glibc.node +0 -0
  14. package/prebuilds/darwin-x64/@photostructure+sqlite.glibc.node +0 -0
  15. package/prebuilds/linux-arm64/@photostructure+sqlite.glibc.node +0 -0
  16. package/prebuilds/linux-arm64/@photostructure+sqlite.musl.node +0 -0
  17. package/prebuilds/linux-x64/@photostructure+sqlite.glibc.node +0 -0
  18. package/prebuilds/linux-x64/@photostructure+sqlite.musl.node +0 -0
  19. package/prebuilds/test_extension.so +0 -0
  20. package/prebuilds/win32-arm64/@photostructure+sqlite.glibc.node +0 -0
  21. package/prebuilds/win32-x64/@photostructure+sqlite.glibc.node +0 -0
  22. package/src/aggregate_function.cpp +503 -235
  23. package/src/aggregate_function.h +57 -42
  24. package/src/binding.cpp +117 -14
  25. package/src/dirname.ts +1 -1
  26. package/src/index.ts +122 -332
  27. package/src/lru-cache.ts +84 -0
  28. package/src/shims/env-inl.h +6 -15
  29. package/src/shims/node_errors.h +7 -1
  30. package/src/shims/sqlite_errors.h +168 -0
  31. package/src/shims/util.h +29 -4
  32. package/src/sql-tag-store.ts +140 -0
  33. package/src/sqlite_exception.h +49 -0
  34. package/src/sqlite_impl.cpp +736 -129
  35. package/src/sqlite_impl.h +84 -6
  36. package/src/{stack_path.ts → stack-path.ts} +7 -1
  37. package/src/types/aggregate-options.ts +22 -0
  38. package/src/types/changeset-apply-options.ts +18 -0
  39. package/src/types/database-sync-instance.ts +203 -0
  40. package/src/types/database-sync-options.ts +69 -0
  41. package/src/types/session-options.ts +10 -0
  42. package/src/types/sql-tag-store-instance.ts +51 -0
  43. package/src/types/sqlite-authorization-actions.ts +77 -0
  44. package/src/types/sqlite-authorization-results.ts +15 -0
  45. package/src/types/sqlite-changeset-conflict-types.ts +19 -0
  46. package/src/types/sqlite-changeset-resolution.ts +15 -0
  47. package/src/types/sqlite-open-flags.ts +50 -0
  48. package/src/types/statement-sync-instance.ts +73 -0
  49. package/src/types/user-functions-options.ts +14 -0
  50. package/src/upstream/node_sqlite.cc +960 -259
  51. package/src/upstream/node_sqlite.h +127 -2
  52. package/src/upstream/sqlite.js +1 -14
  53. package/src/upstream/sqlite3.c +4510 -1411
  54. package/src/upstream/sqlite3.h +390 -195
  55. package/src/upstream/sqlite3ext.h +7 -0
  56. package/src/user_function.cpp +88 -36
  57. package/src/user_function.h +2 -1
package/SECURITY.md CHANGED
@@ -2,113 +2,57 @@
2
2
 
3
3
  ## Supported Versions
4
4
 
5
- Currently, we support security updates for the following versions:
6
-
7
- | Version | Supported |
8
- | ------- | ------------------ |
9
- | 0.1.x | :white_check_mark: |
10
- | < 0.1 | :x: |
5
+ Security updates are provided for the latest released version only.
11
6
 
12
7
  ## Reporting a Vulnerability
13
8
 
14
- We take the security of @photostructure/sqlite seriously. If you believe you have found a security vulnerability, please report it to us as described below.
15
-
16
- ### How to Report
17
-
18
- **Please do not report security vulnerabilities through public GitHub issues.**
19
-
20
- Instead, please report them via one of the following methods:
9
+ **Do not report security vulnerabilities through public GitHub issues.**
21
10
 
22
- 1. Email us at security@photostructure.com
23
- 2. Use GitHub's private vulnerability reporting feature (if available)
11
+ Report via:
24
12
 
25
- ### What to Include
13
+ - Email: security@photostructure.com
14
+ - GitHub's private vulnerability reporting
26
15
 
27
- Please include the following information in your report:
16
+ Include: issue type, affected source files, reproduction steps, and potential impact.
28
17
 
29
- - Type of issue (e.g., buffer overflow, SQL injection, cross-site scripting, etc.)
30
- - Full paths of source file(s) related to the manifestation of the issue
31
- - The location of the affected source code (tag/branch/commit or direct URL)
32
- - Any special configuration required to reproduce the issue
33
- - Step-by-step instructions to reproduce the issue
34
- - Proof-of-concept or exploit code (if possible)
35
- - Impact of the issue, including how an attacker might exploit it
36
-
37
- ### Response Timeline
38
-
39
- - We will acknowledge receipt of your vulnerability report within 48 hours
40
- - We will provide a more detailed response within 7 days
41
- - We will work on fixes and coordinate disclosure timeline with you
18
+ We acknowledge reports within 48 hours and provide detailed response within 7 days.
42
19
 
43
20
  ## Security Measures
44
21
 
45
- ### Automated Security Scanning
46
-
47
- This project employs multiple layers of automated security scanning:
48
-
49
- 1. **npm audit** - Scans for known vulnerabilities in dependencies
50
- 2. **Snyk** - Advanced vulnerability detection and remediation
51
- 3. **OSV Scanner** - Google's Open Source Vulnerabilities scanner
52
- 4. **CodeQL** - GitHub's semantic code analysis for both JavaScript/TypeScript and C++
53
- 5. **TruffleHog** - Secrets detection in code
22
+ ### Automated Scanning
54
23
 
55
- These scans run automatically on:
24
+ - **npm audit** and **OSV Scanner** for dependency vulnerabilities
25
+ - **CodeQL** for JS/TS and C++ semantic analysis
26
+ - **TruffleHog** for secrets detection
27
+ - **ESLint Security Plugin** for static analysis
56
28
 
57
- - Every push to the main branch
58
- - Every pull request
59
- - Weekly scheduled scans
60
- - Manual workflow dispatch
61
-
62
- ### Development Practices
63
-
64
- - All dependencies are regularly updated via Dependabot
65
- - Security patches are prioritized and released quickly
66
- - Native C++ code is analyzed with clang-tidy and ASAN
67
- - Memory safety is validated through comprehensive testing
29
+ Scans run on every push, PR, and weekly.
68
30
 
69
31
  ### Native Code Security
70
32
 
71
- Since this package includes native C++ bindings to SQLite:
72
-
73
- - We use the official SQLite amalgamation source
74
- - SQLite is compiled with recommended security flags
75
- - Buffer overflows are prevented through careful memory management
76
- - All user inputs are properly validated before passing to SQLite
33
+ - Uses official SQLite amalgamation source with recommended security flags
34
+ - C++ code analyzed with clang-tidy and ASAN
35
+ - Memory safety validated through comprehensive testing
77
36
 
78
37
  ## Security Configuration
79
38
 
80
- ### SQLite Security Features
81
-
82
- The following SQLite security features are available:
83
-
84
39
  ```javascript
85
- // Restrict file access to read-only
86
- const db = new DatabaseSync("database.db", {
87
- readonly: true,
88
- });
89
-
90
- // Disable extension loading by default
91
- // Extensions must be explicitly enabled
92
- db.allowExtension(); // Required first
93
- db.enableLoadExtension(true); // Then enable
40
+ // Read-only mode
41
+ const db = new DatabaseSync("database.db", { readonly: true });
42
+
43
+ // Extension loading (disabled by default)
44
+ db.allowExtension();
45
+ db.enableLoadExtension(true);
94
46
  db.loadExtension("path/to/extension");
95
47
  ```
96
48
 
97
49
  ### Best Practices
98
50
 
99
- 1. **Always validate and sanitize user input** before using in SQL queries
100
- 2. **Use parameterized queries** to prevent SQL injection
101
- 3. **Run with minimal permissions** when possible
102
- 4. **Keep dependencies updated** regularly
103
- 5. **Monitor security advisories** for SQLite and Node.js
51
+ 1. Use parameterized queries to prevent SQL injection
52
+ 2. Validate user input before use in queries
53
+ 3. Run with minimal permissions
54
+ 4. Keep dependencies updated
104
55
 
105
56
  ## Disclosure Policy
106
57
 
107
- When we receive a security report, we will:
108
-
109
- 1. Confirm the problem and determine affected versions
110
- 2. Audit code to find similar problems
111
- 3. Prepare fixes for all supported versions
112
- 4. Coordinate disclosure with the reporter
113
-
114
- We aim to disclose vulnerabilities responsibly, balancing the need for users to be informed with giving them time to update.
58
+ Upon receiving a report, we confirm the issue, audit for similar problems, prepare fixes, and coordinate disclosure with the reporter.
package/binding.gyp CHANGED
@@ -19,13 +19,15 @@
19
19
  "dependencies": [
20
20
  "<!(node -p \"require('node-addon-api').gyp\")"
21
21
  ],
22
+ # SQLite build flags - see doc/build-flags.md for comprehensive documentation
23
+ # including comparison with Node.js configuration and rationale for our choices
22
24
  "defines": [
23
25
  "NAPI_CPP_EXCEPTIONS",
24
26
  "HAVE_STDINT_H=1",
25
27
  "HAVE_USLEEP=1",
26
- "SQLITE_DEFAULT_CACHE_SIZE=-16000",
28
+ # "SQLITE_DEFAULT_CACHE_SIZE=-16000", # Default is 2000.
27
29
  "SQLITE_DEFAULT_FOREIGN_KEYS=1",
28
- # "SQLITE_DEFAULT_MEMSTATUS=0", https://www.sqlite.org/forum/forumpost/c1cc8b057a
30
+ "SQLITE_DEFAULT_MEMSTATUS=0", # See https://www.sqlite.org/forum/forumpost/c1cc8b057a
29
31
  "SQLITE_DEFAULT_WAL_SYNCHRONOUS=1",
30
32
  "SQLITE_DQS=0",
31
33
  "SQLITE_ENABLE_COLUMN_METADATA",
@@ -49,7 +51,8 @@
49
51
  "SQLITE_OMIT_DEPRECATED",
50
52
  "SQLITE_OMIT_SHARED_CACHE",
51
53
  "SQLITE_SOUNDEX",
52
- "SQLITE_THREADSAFE=2"
54
+ # "SQLITE_THREADSAFE=2", # default is SQLITE_THREADSAFE=1 (serialized)
55
+ "SQLITE_USE_URI=1" # https://www.sqlite.org/uri.html
53
56
  ],
54
57
  # cflags apply only to C files (not C++), so these warnings suppressions
55
58
  # are specific to SQLite's C code and don't affect our C++ code:
@@ -70,25 +73,69 @@
70
73
  "CLANG_CXX_LIBRARY": "libc++",
71
74
  "MACOSX_DEPLOYMENT_TARGET": "10.15"
72
75
  },
73
- "msvs_settings": {
74
- "VCCLCompilerTool": {
75
- "AdditionalOptions": [
76
- "/Qspectre",
77
- "/guard:cf",
78
- "/ZH:SHA_256",
79
- "/sdl"
80
- ],
81
- "ExceptionHandling": 1,
82
- "RuntimeTypeInfo": "true"
83
- },
84
- "VCLinkerTool": {
85
- "AdditionalOptions": [
86
- "/guard:cf",
87
- "/DYNAMICBASE",
88
- "/CETCOMPAT"
89
- ]
90
- }
91
- }
76
+ "conditions": [
77
+ [
78
+ "OS=='win'",
79
+ {
80
+ "conditions": [
81
+ [
82
+ "target_arch=='x64'",
83
+ {
84
+ "defines": [
85
+ "_M_X64",
86
+ "_WIN64"
87
+ ],
88
+ "msvs_settings": {
89
+ "VCCLCompilerTool": {
90
+ "AdditionalOptions": [
91
+ "/Qspectre",
92
+ "/guard:cf",
93
+ "/ZH:SHA_256",
94
+ "/sdl"
95
+ ],
96
+ "ExceptionHandling": 1,
97
+ "RuntimeTypeInfo": "true"
98
+ },
99
+ "VCLinkerTool": {
100
+ "AdditionalOptions": [
101
+ "/guard:cf",
102
+ "/DYNAMICBASE",
103
+ "/CETCOMPAT"
104
+ ]
105
+ }
106
+ }
107
+ }
108
+ ],
109
+ [
110
+ "target_arch=='arm64'",
111
+ {
112
+ "defines": [
113
+ "_M_ARM64",
114
+ "_WIN64"
115
+ ],
116
+ "msvs_settings": {
117
+ "VCCLCompilerTool": {
118
+ "AdditionalOptions": [
119
+ "/guard:cf",
120
+ "/ZH:SHA_256",
121
+ "/sdl"
122
+ ],
123
+ "ExceptionHandling": 1,
124
+ "RuntimeTypeInfo": "true"
125
+ },
126
+ "VCLinkerTool": {
127
+ "AdditionalOptions": [
128
+ "/guard:cf",
129
+ "/DYNAMICBASE"
130
+ ]
131
+ }
132
+ }
133
+ }
134
+ ]
135
+ ]
136
+ }
137
+ ]
138
+ ]
92
139
  }
93
140
  ]
94
141
  }
package/dist/index.cjs CHANGED
@@ -31,8 +31,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  DatabaseSync: () => DatabaseSync,
34
+ SQLTagStore: () => SQLTagStore,
34
35
  Session: () => Session,
35
36
  StatementSync: () => StatementSync,
37
+ backup: () => backup,
36
38
  constants: () => constants,
37
39
  default: () => index_default
38
40
  });
@@ -40,7 +42,7 @@ module.exports = __toCommonJS(index_exports);
40
42
  var import_node_gyp_build = __toESM(require("node-gyp-build"));
41
43
  var import_node_path2 = require("path");
42
44
 
43
- // src/stack_path.ts
45
+ // src/stack-path.ts
44
46
  var import_node_path = require("path");
45
47
  function getCallerDirname() {
46
48
  const e = new Error();
@@ -50,6 +52,10 @@ function getCallerDirname() {
50
52
  return (0, import_node_path.dirname)(extractCallerPath(e.stack));
51
53
  }
52
54
  var patterns = process.platform === "win32" ? [
55
+ // File URLs: "at functionName (file:///C:/path/file.js:1:1)"
56
+ /\bat\s.+?\((?<path>file:\/\/\/.+?):\d+:\d+\)$/,
57
+ // File URLs direct: "at file:///C:/path/file.js:1:1"
58
+ /\bat\s(?<path>file:\/\/\/.+?):\d+:\d+$/,
53
59
  // Standard: "at functionName (C:\path\file.js:1:1)"
54
60
  /\bat\s.+?\((?<path>[A-Z]:\\.+):\d+:\d+\)$/,
55
61
  // direct: "at C:\path\file.js:1:1"
@@ -62,7 +68,8 @@ var patterns = process.platform === "win32" ? [
62
68
  // Standard: "at functionName (/path/file.js:1:1)"
63
69
  /\bat\s.+?\((?<path>\/.+?):\d+:\d+\)$/,
64
70
  // Anonymous or direct: "at /path/file.js:1:1"
65
- /\bat\s(.+[^/]\s)?(?<path>\/.+?):\d+:\d+$/
71
+ // eslint-disable-next-line security/detect-unsafe-regex -- Pattern is safe: no nested quantifiers
72
+ /\bat\s(?:[^\s()]+\s)?(?<path>\/[^:]+):\d+:\d+$/
66
73
  ];
67
74
  var MaybeUrlRE = /^[a-z]{2,5}:\/\//i;
68
75
  function extractCallerPath(stack) {
@@ -101,34 +108,194 @@ function _dirname() {
101
108
  return getCallerDirname();
102
109
  }
103
110
 
104
- // src/index.ts
105
- var binding = (0, import_node_gyp_build.default)((0, import_node_path2.join)(_dirname(), ".."));
106
- if (binding.DatabaseSync && typeof Symbol.dispose !== "undefined") {
107
- binding.DatabaseSync.prototype[Symbol.dispose] = function() {
108
- try {
109
- this.close();
110
- } catch {
111
+ // src/lru-cache.ts
112
+ var LRUCache = class {
113
+ cache = /* @__PURE__ */ new Map();
114
+ maxCapacity;
115
+ constructor(capacity) {
116
+ if (capacity < 1) {
117
+ throw new RangeError("LRU cache capacity must be at least 1");
111
118
  }
112
- };
113
- }
114
- if (binding.StatementSync && typeof Symbol.dispose !== "undefined") {
115
- binding.StatementSync.prototype[Symbol.dispose] = function() {
116
- try {
117
- this.finalize();
118
- } catch {
119
+ this.maxCapacity = capacity;
120
+ }
121
+ /**
122
+ * Get a value from the cache.
123
+ * If found, moves the entry to the end (most recently used).
124
+ */
125
+ get(key) {
126
+ const value = this.cache.get(key);
127
+ if (value !== void 0) {
128
+ this.cache.delete(key);
129
+ this.cache.set(key, value);
119
130
  }
120
- };
121
- }
131
+ return value;
132
+ }
133
+ /**
134
+ * Set a value in the cache.
135
+ * If key exists, updates and moves to end.
136
+ * If at capacity, evicts the oldest entry first.
137
+ */
138
+ set(key, value) {
139
+ if (this.cache.has(key)) {
140
+ this.cache.delete(key);
141
+ } else if (this.cache.size >= this.maxCapacity) {
142
+ const oldestKey = this.cache.keys().next().value;
143
+ if (oldestKey !== void 0) {
144
+ this.cache.delete(oldestKey);
145
+ }
146
+ }
147
+ this.cache.set(key, value);
148
+ }
149
+ /**
150
+ * Delete an entry from the cache.
151
+ */
152
+ delete(key) {
153
+ return this.cache.delete(key);
154
+ }
155
+ /**
156
+ * Check if a key exists in the cache.
157
+ * Does NOT update recency.
158
+ */
159
+ has(key) {
160
+ return this.cache.has(key);
161
+ }
162
+ /**
163
+ * Clear all entries from the cache.
164
+ */
165
+ clear() {
166
+ this.cache.clear();
167
+ }
168
+ /**
169
+ * Get the current number of entries in the cache.
170
+ */
171
+ size() {
172
+ return this.cache.size;
173
+ }
174
+ /**
175
+ * Get the maximum capacity of the cache.
176
+ */
177
+ capacity() {
178
+ return this.maxCapacity;
179
+ }
180
+ };
181
+
182
+ // src/sql-tag-store.ts
183
+ var DEFAULT_CAPACITY = 1e3;
184
+ var SQLTagStore = class {
185
+ database;
186
+ cache;
187
+ maxCapacity;
188
+ constructor(db, capacity = DEFAULT_CAPACITY) {
189
+ if (!db.isOpen) {
190
+ throw new Error("Database is not open");
191
+ }
192
+ this.database = db;
193
+ this.maxCapacity = capacity;
194
+ this.cache = new LRUCache(capacity);
195
+ }
196
+ /**
197
+ * Returns the associated database instance.
198
+ */
199
+ get db() {
200
+ return this.database;
201
+ }
202
+ /**
203
+ * Returns the maximum capacity of the statement cache.
204
+ */
205
+ get capacity() {
206
+ return this.maxCapacity;
207
+ }
208
+ /**
209
+ * Returns the current number of cached statements.
210
+ */
211
+ size() {
212
+ return this.cache.size();
213
+ }
214
+ /**
215
+ * Clears all cached statements.
216
+ */
217
+ clear() {
218
+ this.cache.clear();
219
+ }
220
+ /**
221
+ * Execute an INSERT, UPDATE, DELETE or other statement that doesn't return rows.
222
+ * Returns an object with `changes` and `lastInsertRowid`.
223
+ */
224
+ run(strings, ...values) {
225
+ const stmt = this.getOrPrepare(strings);
226
+ return stmt.run(...values);
227
+ }
228
+ /**
229
+ * Execute a query and return the first row, or undefined if no rows.
230
+ */
231
+ get(strings, ...values) {
232
+ const stmt = this.getOrPrepare(strings);
233
+ return stmt.get(...values);
234
+ }
235
+ /**
236
+ * Execute a query and return all rows as an array.
237
+ */
238
+ all(strings, ...values) {
239
+ const stmt = this.getOrPrepare(strings);
240
+ return stmt.all(...values);
241
+ }
242
+ /**
243
+ * Execute a query and return an iterator over the rows.
244
+ */
245
+ iterate(strings, ...values) {
246
+ const stmt = this.getOrPrepare(strings);
247
+ return stmt.iterate(...values);
248
+ }
249
+ /**
250
+ * Get a cached statement or prepare a new one.
251
+ * If a cached statement has been finalized, it's evicted and a new one is prepared.
252
+ */
253
+ getOrPrepare(strings) {
254
+ if (!this.database.isOpen) {
255
+ throw new Error("Database is not open");
256
+ }
257
+ const sql = this.buildSQL(strings);
258
+ const cached = this.cache.get(sql);
259
+ if (cached) {
260
+ if (!cached.finalized) {
261
+ return cached;
262
+ }
263
+ this.cache.delete(sql);
264
+ }
265
+ const stmt = this.database.prepare(sql);
266
+ this.cache.set(sql, stmt);
267
+ return stmt;
268
+ }
269
+ /**
270
+ * Build the SQL string by joining template parts with `?` placeholders.
271
+ */
272
+ buildSQL(strings) {
273
+ let sql = strings[0] ?? "";
274
+ for (let i = 1; i < strings.length; i++) {
275
+ sql += "?" + (strings[i] ?? "");
276
+ }
277
+ return sql;
278
+ }
279
+ };
280
+
281
+ // src/index.ts
282
+ var binding = (0, import_node_gyp_build.default)((0, import_node_path2.join)(_dirname(), ".."));
122
283
  var DatabaseSync = binding.DatabaseSync;
284
+ DatabaseSync.prototype.createTagStore = function(capacity) {
285
+ return new SQLTagStore(this, capacity);
286
+ };
123
287
  var StatementSync = binding.StatementSync;
124
288
  var Session = binding.Session;
125
289
  var constants = binding.constants;
290
+ var backup = binding.backup;
126
291
  var index_default = binding;
127
292
  // Annotate the CommonJS export names for ESM import in node:
128
293
  0 && (module.exports = {
129
294
  DatabaseSync,
295
+ SQLTagStore,
130
296
  Session,
131
297
  StatementSync,
298
+ backup,
132
299
  constants
133
300
  });
134
301
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/stack_path.ts","../src/dirname.ts"],"sourcesContent":["// Load the native binding with support for both CJS and ESM\nimport nodeGypBuild from \"node-gyp-build\";\nimport { join } from \"node:path\";\nimport { _dirname } from \"./dirname\";\n\n// Use _dirname() helper that works in both CJS/ESM and Jest\nconst binding = nodeGypBuild(join(_dirname(), \"..\"));\n\n/**\n * Configuration options for opening a database.\n * This interface matches Node.js sqlite module's DatabaseSyncOptions.\n */\nexport interface DatabaseSyncOptions {\n /** Path to the database file. Use ':memory:' for an in-memory database. */\n readonly location?: string;\n /** If true, the database is opened in read-only mode. @default false */\n readonly readOnly?: boolean;\n /** If true, foreign key constraints are enforced. @default true */\n readonly enableForeignKeyConstraints?: boolean;\n /** \n * If true, double-quoted string literals are allowed. \n *\n * If enabled, double quotes can be misinterpreted as identifiers instead of\n * string literals, leading to confusing errors. \n *\n * **The SQLite documentation strongly recommends avoiding double-quoted\n * strings entirely.**\n\n * @see https://sqlite.org/quirks.html#dblquote\n * @default false \n */\n readonly enableDoubleQuotedStringLiterals?: boolean;\n /**\n * Sets the busy timeout in milliseconds.\n * @default 5000\n */\n readonly timeout?: number;\n /** If true, enables loading of SQLite extensions. @default false */\n readonly allowExtension?: boolean;\n}\n\n/**\n * Options for creating a prepared statement.\n */\nexport interface StatementOptions {\n /** If true, the prepared statement's expandedSQL property will contain the expanded SQL. @default false */\n readonly expandedSQL?: boolean;\n /** If true, anonymous parameters are enabled for the statement. @default false */\n readonly anonymousParameters?: boolean;\n}\n\n/**\n * A prepared SQL statement that can be executed multiple times with different parameters.\n * This interface represents an instance of the StatementSync class.\n */\nexport interface StatementSyncInstance {\n /** The original SQL source string. */\n readonly sourceSQL: string;\n /** The expanded SQL string with bound parameters, if expandedSQL option was set. */\n readonly expandedSQL: string | undefined;\n /**\n * This method executes a prepared statement and returns an object.\n * @param parameters Optional named and anonymous parameters to bind to the statement.\n * @returns An object with the number of changes and the last insert rowid.\n */\n run(...parameters: any[]): {\n changes: number;\n lastInsertRowid: number | bigint;\n };\n /**\n * This method executes a prepared statement and returns the first result row.\n * @param parameters Optional named and anonymous parameters to bind to the statement.\n * @returns The first row from the query results, or undefined if no rows.\n */\n get(...parameters: any[]): any;\n /**\n * This method executes a prepared statement and returns all results as an array.\n * @param parameters Optional named and anonymous parameters to bind to the statement.\n * @returns An array of row objects from the query results.\n */\n all(...parameters: any[]): any[];\n /**\n * This method executes a prepared statement and returns an iterable iterator of objects.\n * Each object represents a row from the query results.\n * @param parameters Optional named and anonymous parameters to bind to the statement.\n * @returns An iterable iterator of row objects.\n */\n iterate(...parameters: any[]): IterableIterator<any>;\n /**\n * Set whether to read integer values as JavaScript BigInt.\n * @param readBigInts If true, read integers as BigInts. @default false\n */\n setReadBigInts(readBigInts: boolean): void;\n /**\n * Set whether to allow bare named parameters in SQL.\n * @param allowBareNamedParameters If true, allows bare named parameters. @default false\n */\n setAllowBareNamedParameters(allowBareNamedParameters: boolean): void;\n /**\n * Set whether to return results as arrays rather than objects.\n * @param returnArrays If true, return results as arrays. @default false\n */\n setReturnArrays(returnArrays: boolean): void;\n /**\n * Returns an array of objects, each representing a column in the statement's result set.\n * Each object has a 'name' property for the column name and a 'type' property for the SQLite type.\n * @returns Array of column metadata objects.\n */\n columns(): Array<{ name: string; type?: string }>;\n /**\n * Finalizes the prepared statement and releases its resources.\n * Called automatically by Symbol.dispose.\n */\n finalize(): void;\n /** Dispose of the statement resources using the explicit resource management protocol. */\n [Symbol.dispose](): void;\n}\n\nexport interface UserFunctionOptions {\n /** If `true`, sets the `SQLITE_DETERMINISTIC` flag. @default false */\n readonly deterministic?: boolean;\n /** If `true`, sets the `SQLITE_DIRECTONLY` flag. @default false */\n readonly directOnly?: boolean;\n /** If `true`, converts integer arguments to `BigInt`s. @default false */\n readonly useBigIntArguments?: boolean;\n /** If `true`, allows function to be invoked with variable arguments. @default false */\n readonly varargs?: boolean;\n}\n\nexport interface AggregateOptions {\n /** The initial value for the aggregation. */\n readonly start?: any;\n /** Function called for each row to update the aggregate state. */\n readonly step: (accumulator: any, ...args: any[]) => any;\n /** Optional function for window function support to reverse a step. */\n readonly inverse?: (accumulator: any, ...args: any[]) => any;\n /** Optional function to compute the final result from the accumulator. */\n readonly result?: (accumulator: any) => any;\n /** If `true`, sets the `SQLITE_DETERMINISTIC` flag. @default false */\n readonly deterministic?: boolean;\n /** If `true`, sets the `SQLITE_DIRECTONLY` flag. @default false */\n readonly directOnly?: boolean;\n /** If `true`, converts integer arguments to `BigInt`s. @default false */\n readonly useBigIntArguments?: boolean;\n /** If `true`, allows function to be invoked with variable arguments. @default false */\n readonly varargs?: boolean;\n}\n\nexport interface SessionOptions {\n /** The table to track changes for. If omitted, all tables are tracked. */\n readonly table?: string;\n /** The database name. @default \"main\" */\n readonly db?: string;\n}\n\nexport interface Session {\n /**\n * Generate a changeset containing all changes recorded by the session.\n * @returns A Buffer containing the changeset data.\n */\n changeset(): Buffer;\n /**\n * Generate a patchset containing all changes recorded by the session.\n * @returns A Buffer containing the patchset data.\n */\n patchset(): Buffer;\n /**\n * Close the session and release its resources.\n */\n close(): void;\n}\n\nexport interface ChangesetApplyOptions {\n /**\n * Function called when a conflict is detected during changeset application.\n * @param conflictType The type of conflict (SQLITE_CHANGESET_CONFLICT, etc.)\n * @returns One of SQLITE_CHANGESET_OMIT, SQLITE_CHANGESET_REPLACE, or SQLITE_CHANGESET_ABORT\n */\n readonly onConflict?: (conflictType: number) => number;\n /**\n * Function called to filter which tables to apply changes to.\n * @param tableName The name of the table\n * @returns true to include the table, false to skip it\n */\n readonly filter?: (tableName: string) => boolean;\n}\n\n/**\n * Represents a SQLite database connection.\n * This interface represents an instance of the DatabaseSync class.\n */\nexport interface DatabaseSyncInstance {\n /** Indicates whether the database connection is open. */\n readonly isOpen: boolean;\n /** Indicates whether a transaction is currently active. */\n readonly isTransaction: boolean;\n\n /**\n * Opens a database connection. This method is called automatically when creating\n * a DatabaseSync instance, so typically should not be called directly.\n * @param configuration Optional configuration for opening the database.\n */\n open(configuration?: DatabaseSyncOptions): void;\n /**\n * Closes the database connection. This method should be called to ensure that\n * the database connection is properly cleaned up. Once a database is closed,\n * it cannot be used again.\n */\n close(): void;\n /**\n * Returns the location of the database file. For attached databases, you can specify\n * the database name. Returns null for in-memory databases.\n * @param dbName The name of the database. Defaults to 'main' (the primary database).\n * @returns The file path of the database, or null for in-memory databases.\n */\n location(dbName?: string): string | null;\n /**\n * Compiles an SQL statement and returns a StatementSyncInstance object.\n * @param sql The SQL statement to prepare.\n * @param options Optional configuration for the statement.\n * @returns A StatementSyncInstance object that can be executed multiple times.\n */\n prepare(sql: string, options?: StatementOptions): StatementSyncInstance;\n /**\n * This method allows one or more SQL statements to be executed without\n * returning any results. This is useful for commands like CREATE TABLE,\n * INSERT, UPDATE, or DELETE.\n * @param sql The SQL statement(s) to execute.\n */\n exec(sql: string): void;\n\n /**\n * This method creates SQLite user-defined functions, wrapping sqlite3_create_function_v2().\n * @param name The name of the SQLite function to create.\n * @param func The JavaScript function to call when the SQLite function is invoked.\n */\n function(name: string, func: Function): void;\n /**\n * This method creates SQLite user-defined functions, wrapping sqlite3_create_function_v2().\n * @param name The name of the SQLite function to create.\n * @param options Optional configuration settings.\n * @param func The JavaScript function to call when the SQLite function is invoked.\n */\n function(name: string, options: UserFunctionOptions, func: Function): void;\n\n /**\n * This method creates SQLite aggregate functions, wrapping sqlite3_create_window_function().\n * @param name The name of the SQLite aggregate function to create.\n * @param options Configuration object containing step function and other settings.\n */\n aggregate(name: string, options: AggregateOptions): void;\n /**\n * Create a new session to record database changes.\n * @param options Optional configuration for the session.\n * @returns A Session object for recording changes.\n */\n createSession(options?: SessionOptions): Session;\n /**\n * Apply a changeset to the database.\n * @param changeset The changeset data to apply.\n * @param options Optional configuration for applying the changeset.\n * @returns true if successful, false if aborted.\n */\n applyChangeset(changeset: Buffer, options?: ChangesetApplyOptions): boolean;\n /**\n * Enables or disables the loading of SQLite extensions.\n * @param enable If true, enables extension loading. If false, disables it.\n */\n enableLoadExtension(enable: boolean): void;\n /**\n * Loads an SQLite extension from the specified file path.\n * @param path The path to the extension library.\n * @param entryPoint Optional entry point function name. If not provided, uses the default entry point.\n */\n loadExtension(path: string, entryPoint?: string): void;\n\n /**\n * Makes a backup of the database. This method abstracts the sqlite3_backup_init(),\n * sqlite3_backup_step() and sqlite3_backup_finish() functions.\n *\n * The backed-up database can be used normally during the backup process. Mutations\n * coming from the same connection will be reflected in the backup right away.\n * However, mutations from other connections will cause the backup process to restart.\n *\n * @param path The path where the backup will be created. If the file already exists, the contents will be overwritten.\n * @param options Optional configuration for the backup operation.\n * @param options.rate Number of pages to be transmitted in each batch of the backup. @default 100\n * @param options.source Name of the source database. This can be 'main' (the default primary database) or any other database that have been added with ATTACH DATABASE. @default 'main'\n * @param options.target Name of the target database. This can be 'main' (the default primary database) or any other database that have been added with ATTACH DATABASE. @default 'main'\n * @param options.progress Callback function that will be called with the number of pages copied and the total number of pages.\n * @returns A promise that resolves when the backup is completed and rejects if an error occurs.\n *\n * @example\n * // Basic backup\n * await db.backup('./backup.db');\n *\n * @example\n * // Backup with progress\n * await db.backup('./backup.db', {\n * rate: 10,\n * progress: ({ totalPages, remainingPages }) => {\n * console.log(`Progress: ${totalPages - remainingPages}/${totalPages}`);\n * }\n * });\n */\n backup(\n path: string | Buffer | URL,\n options?: {\n rate?: number;\n source?: string;\n target?: string;\n progress?: (info: { totalPages: number; remainingPages: number }) => void;\n },\n ): Promise<number>;\n\n /** Dispose of the database resources using the explicit resource management protocol. */\n [Symbol.dispose](): void;\n}\n\n/**\n * The main SQLite module interface.\n */\nexport interface SqliteModule {\n /**\n * The DatabaseSync class represents a synchronous connection to a SQLite database.\n * All operations are performed synchronously, blocking until completion.\n */\n DatabaseSync: new (\n location?: string | Buffer | URL,\n options?: DatabaseSyncOptions,\n ) => DatabaseSyncInstance;\n /**\n * The StatementSync class represents a synchronous prepared statement.\n * This class should not be instantiated directly; use Database.prepare() instead.\n */\n StatementSync: new (\n database: DatabaseSyncInstance,\n sql: string,\n options?: StatementOptions,\n ) => StatementSyncInstance;\n /**\n * The Session class for recording database changes.\n * This class should not be instantiated directly; use Database.createSession() instead.\n */\n Session: new () => Session;\n /**\n * SQLite constants for various operations and flags.\n */\n constants: {\n /** Open database for reading only. */\n SQLITE_OPEN_READONLY: number;\n /** Open database for reading and writing. */\n SQLITE_OPEN_READWRITE: number;\n /** Create database if it doesn't exist. */\n SQLITE_OPEN_CREATE: number;\n // Changeset constants\n /** Skip conflicting changes. */\n SQLITE_CHANGESET_OMIT: number;\n /** Replace conflicting changes. */\n SQLITE_CHANGESET_REPLACE: number;\n /** Abort on conflict. */\n SQLITE_CHANGESET_ABORT: number;\n /** Data conflict type. */\n SQLITE_CHANGESET_DATA: number;\n /** Row not found conflict. */\n SQLITE_CHANGESET_NOTFOUND: number;\n /** General conflict. */\n SQLITE_CHANGESET_CONFLICT: number;\n /** Constraint violation. */\n SQLITE_CHANGESET_CONSTRAINT: number;\n /** Foreign key constraint violation. */\n SQLITE_CHANGESET_FOREIGN_KEY: number;\n // ... more constants\n };\n}\n\n// Add Symbol.dispose to the native classes\nif (binding.DatabaseSync && typeof Symbol.dispose !== \"undefined\") {\n binding.DatabaseSync.prototype[Symbol.dispose] = function () {\n try {\n this.close();\n } catch {\n // Ignore errors during disposal\n }\n };\n}\n\nif (binding.StatementSync && typeof Symbol.dispose !== \"undefined\") {\n binding.StatementSync.prototype[Symbol.dispose] = function () {\n try {\n this.finalize();\n } catch {\n // Ignore errors during disposal\n }\n };\n}\n\n// Export the native binding with TypeScript types\n\n/**\n * The DatabaseSync class represents a synchronous connection to a SQLite database.\n * All database operations are performed synchronously, blocking the thread until completion.\n *\n * @example\n * ```typescript\n * import { DatabaseSync } from '@photostructure/sqlite';\n *\n * // Create an in-memory database\n * const db = new DatabaseSync(':memory:');\n *\n * // Create a file-based database\n * const fileDb = new DatabaseSync('./mydata.db');\n *\n * // Create with options\n * const readOnlyDb = new DatabaseSync('./data.db', { readOnly: true });\n * ```\n */\nexport const DatabaseSync =\n binding.DatabaseSync as SqliteModule[\"DatabaseSync\"];\n\n/**\n * The StatementSync class represents a prepared SQL statement.\n * This class should not be instantiated directly; use DatabaseSync.prepare() instead.\n *\n * @example\n * ```typescript\n * const stmt = db.prepare('SELECT * FROM users WHERE id = ?');\n * const user = stmt.get(123);\n * stmt.finalize();\n * ```\n */\nexport const StatementSync =\n binding.StatementSync as SqliteModule[\"StatementSync\"];\n\n/**\n * The Session class for recording database changes.\n * This class should not be instantiated directly; use DatabaseSync.createSession() instead.\n *\n * @example\n * ```typescript\n * const session = db.createSession({ table: 'users' });\n * // Make some changes to the users table\n * const changeset = session.changeset();\n * session.close();\n * ```\n */\nexport const Session = binding.Session as SqliteModule[\"Session\"];\n\n/**\n * SQLite constants for various operations and flags.\n *\n * @example\n * ```typescript\n * import { constants } from '@photostructure/sqlite';\n *\n * const db = new DatabaseSync('./data.db', {\n * readOnly: true,\n * // Uses SQLITE_OPEN_READONLY internally\n * });\n * ```\n */\nexport const constants = binding.constants as SqliteModule[\"constants\"];\n\n// Default export for CommonJS compatibility\nexport default binding as SqliteModule;\n","import { dirname } from \"node:path\";\n\nexport function getCallerDirname(): string {\n const e = new Error();\n if (e.stack == null) {\n Error.captureStackTrace(e);\n }\n return dirname(extractCallerPath(e.stack as string));\n}\n\n// Comprehensive regex patterns for different stack frame formats\nconst patterns =\n process.platform === \"win32\"\n ? [\n // Standard: \"at functionName (C:\\path\\file.js:1:1)\"\n /\\bat\\s.+?\\((?<path>[A-Z]:\\\\.+):\\d+:\\d+\\)$/,\n // direct: \"at C:\\path\\file.js:1:1\"\n /\\bat\\s(?<path>[A-Z]:\\\\.+):\\d+:\\d+$/,\n // UNC: \"at functionName (\\\\server\\share\\path\\file.js:1:1)\"\n /\\bat\\s.+?\\((?<path>\\\\\\\\.+):\\d+:\\d+\\)$/,\n // direct: \"at \\\\server\\share\\path\\file.js:1:1\"\n /\\bat\\s(?<path>\\\\\\\\.+):\\d+:\\d+$/,\n ]\n : [\n // Standard: \"at functionName (/path/file.js:1:1)\"\n /\\bat\\s.+?\\((?<path>\\/.+?):\\d+:\\d+\\)$/,\n // Anonymous or direct: \"at /path/file.js:1:1\"\n /\\bat\\s(.+[^/]\\s)?(?<path>\\/.+?):\\d+:\\d+$/,\n ];\n\nconst MaybeUrlRE = /^[a-z]{2,5}:\\/\\//i;\n\n// only exposed for tests:\nexport function extractCallerPath(stack: string): string {\n const frames = stack.split(\"\\n\").filter(Boolean);\n\n // First find getCallerDirname() in the stack:\n const callerFrame = frames.findIndex((frame) =>\n frame.includes(\"getCallerDirname\"),\n );\n if (callerFrame === -1) {\n throw new Error(\"Invalid stack trace format: missing caller frame\");\n }\n for (let i = callerFrame + 1; i < frames.length; i++) {\n const frame = frames[i];\n for (const pattern of patterns) {\n const g = frame?.trim().match(pattern)?.groups;\n if (g != null && g[\"path\"]) {\n const path = g[\"path\"];\n // Windows requires us to check if it's a reasonable URL, as URL accepts\n // \"C:\\\\path\\\\file.txt\" as valid (!!)\n if (MaybeUrlRE.test(path)) {\n try {\n return new URL(path).pathname;\n } catch {\n // ignore\n }\n }\n return path;\n }\n }\n }\n throw new Error(\"Invalid stack trace format: no parsable frames\");\n}\n","import { getCallerDirname } from \"./stack_path\";\n\n// Thanks to tsup shims, __dirname should always be defined except when run by\n// jest (which will use the stack_path shim)\nexport function _dirname() {\n try {\n if (typeof __dirname !== \"undefined\") return __dirname;\n } catch {\n // ignore\n }\n // we must be in jest. Use the stack_path ~~hack~~ shim:\n return getCallerDirname();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,4BAAyB;AACzB,IAAAA,oBAAqB;;;ACFrB,uBAAwB;AAEjB,SAAS,mBAA2B;AACzC,QAAM,IAAI,IAAI,MAAM;AACpB,MAAI,EAAE,SAAS,MAAM;AACnB,UAAM,kBAAkB,CAAC;AAAA,EAC3B;AACA,aAAO,0BAAQ,kBAAkB,EAAE,KAAe,CAAC;AACrD;AAGA,IAAM,WACJ,QAAQ,aAAa,UACjB;AAAA;AAAA,EAEE;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AACF,IACA;AAAA;AAAA,EAEE;AAAA;AAAA,EAEA;AACF;AAEN,IAAM,aAAa;AAGZ,SAAS,kBAAkB,OAAuB;AACvD,QAAM,SAAS,MAAM,MAAM,IAAI,EAAE,OAAO,OAAO;AAG/C,QAAM,cAAc,OAAO;AAAA,IAAU,CAAC,UACpC,MAAM,SAAS,kBAAkB;AAAA,EACnC;AACA,MAAI,gBAAgB,IAAI;AACtB,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AACA,WAAS,IAAI,cAAc,GAAG,IAAI,OAAO,QAAQ,KAAK;AACpD,UAAM,QAAQ,OAAO,CAAC;AACtB,eAAW,WAAW,UAAU;AAC9B,YAAM,IAAI,OAAO,KAAK,EAAE,MAAM,OAAO,GAAG;AACxC,UAAI,KAAK,QAAQ,EAAE,MAAM,GAAG;AAC1B,cAAM,OAAO,EAAE,MAAM;AAGrB,YAAI,WAAW,KAAK,IAAI,GAAG;AACzB,cAAI;AACF,mBAAO,IAAI,IAAI,IAAI,EAAE;AAAA,UACvB,QAAQ;AAAA,UAER;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACA,QAAM,IAAI,MAAM,gDAAgD;AAClE;;;AC3DO,SAAS,WAAW;AACzB,MAAI;AACF,QAAI,OAAO,cAAc,YAAa,QAAO;AAAA,EAC/C,QAAQ;AAAA,EAER;AAEA,SAAO,iBAAiB;AAC1B;;;AFNA,IAAM,cAAU,sBAAAC,aAAa,wBAAK,SAAS,GAAG,IAAI,CAAC;AAmXnD,IAAI,QAAQ,gBAAgB,OAAO,OAAO,YAAY,aAAa;AACjE,UAAQ,aAAa,UAAU,OAAO,OAAO,IAAI,WAAY;AAC3D,QAAI;AACF,WAAK,MAAM;AAAA,IACb,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAEA,IAAI,QAAQ,iBAAiB,OAAO,OAAO,YAAY,aAAa;AAClE,UAAQ,cAAc,UAAU,OAAO,OAAO,IAAI,WAAY;AAC5D,QAAI;AACF,WAAK,SAAS;AAAA,IAChB,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAsBO,IAAM,eACX,QAAQ;AAaH,IAAM,gBACX,QAAQ;AAcH,IAAM,UAAU,QAAQ;AAexB,IAAM,YAAY,QAAQ;AAGjC,IAAO,gBAAQ;","names":["import_node_path","nodeGypBuild"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/stack-path.ts","../src/dirname.ts","../src/lru-cache.ts","../src/sql-tag-store.ts"],"sourcesContent":["// Load the native binding with support for both CJS and ESM\nimport nodeGypBuild from \"node-gyp-build\";\nimport { join } from \"node:path\";\nimport { _dirname } from \"./dirname\";\nimport { SQLTagStore } from \"./sql-tag-store\";\nimport { DatabaseSyncInstance } from \"./types/database-sync-instance\";\nimport { DatabaseSyncOptions } from \"./types/database-sync-options\";\nimport { SQLTagStoreInstance } from \"./types/sql-tag-store-instance\";\nimport { SqliteAuthorizationActions } from \"./types/sqlite-authorization-actions\";\nimport { SqliteAuthorizationResults } from \"./types/sqlite-authorization-results\";\nimport { SqliteChangesetConflictTypes } from \"./types/sqlite-changeset-conflict-types\";\nimport { SqliteChangesetResolution } from \"./types/sqlite-changeset-resolution\";\nimport { SqliteOpenFlags } from \"./types/sqlite-open-flags\";\nimport { StatementSyncInstance } from \"./types/statement-sync-instance\";\n\nexport type { AggregateOptions } from \"./types/aggregate-options\";\nexport type { ChangesetApplyOptions } from \"./types/changeset-apply-options\";\nexport type { DatabaseSyncInstance } from \"./types/database-sync-instance\";\nexport type { DatabaseSyncOptions } from \"./types/database-sync-options\";\nexport type { SessionOptions } from \"./types/session-options\";\nexport type { SQLTagStoreInstance } from \"./types/sql-tag-store-instance\";\nexport type { SqliteAuthorizationActions } from \"./types/sqlite-authorization-actions\";\nexport type { SqliteAuthorizationResults } from \"./types/sqlite-authorization-results\";\nexport type { SqliteChangesetConflictTypes } from \"./types/sqlite-changeset-conflict-types\";\nexport type { SqliteChangesetResolution } from \"./types/sqlite-changeset-resolution\";\nexport type { SqliteOpenFlags } from \"./types/sqlite-open-flags\";\nexport type { StatementSyncInstance } from \"./types/statement-sync-instance\";\nexport type { UserFunctionOptions } from \"./types/user-functions-options\";\n\n// Use _dirname() helper that works in both CJS/ESM and Jest\nconst binding = nodeGypBuild(join(_dirname(), \"..\"));\n\n/**\n * All SQLite constants exported by this module.\n *\n * This is a union of all constant category interfaces:\n * - {@link SqliteOpenFlags} - Database open flags (extension beyond `node:sqlite`)\n * - {@link SqliteChangesetResolution} - Changeset conflict resolution values\n * - {@link SqliteChangesetConflictTypes} - Changeset conflict type codes\n * - {@link SqliteAuthorizationResults} - Authorization return values\n * - {@link SqliteAuthorizationActions} - Authorization action codes\n *\n * **Note:** The categorized interfaces (`SqliteOpenFlags`, etc.) are extensions\n * provided by `@photostructure/sqlite`. The `node:sqlite` module exports only\n * a flat `constants` object without these type categories.\n */\nexport type SqliteConstants = SqliteOpenFlags &\n SqliteChangesetResolution &\n SqliteChangesetConflictTypes &\n SqliteAuthorizationResults &\n SqliteAuthorizationActions;\n\n/**\n * Options for creating a prepared statement.\n */\nexport interface StatementOptions {\n /** If true, the prepared statement's expandedSQL property will contain the expanded SQL. @default false */\n readonly expandedSQL?: boolean;\n /** If true, anonymous parameters are enabled for the statement. @default false */\n readonly anonymousParameters?: boolean;\n}\n\nexport interface Session {\n /**\n * Generate a changeset containing all changes recorded by the session.\n * @returns A Buffer containing the changeset data.\n */\n changeset(): Buffer;\n /**\n * Generate a patchset containing all changes recorded by the session.\n * @returns A Buffer containing the patchset data.\n */\n patchset(): Buffer;\n /**\n * Close the session and release its resources.\n */\n close(): void;\n}\n\n/**\n * The main SQLite module interface.\n */\nexport interface SqliteModule {\n /**\n * The DatabaseSync class represents a synchronous connection to a SQLite database.\n * All operations are performed synchronously, blocking until completion.\n */\n DatabaseSync: new (\n location?: string | Buffer | URL,\n options?: DatabaseSyncOptions,\n ) => DatabaseSyncInstance;\n /**\n * The StatementSync class represents a synchronous prepared statement.\n * This class should not be instantiated directly; use Database.prepare() instead.\n */\n StatementSync: new (\n database: DatabaseSyncInstance,\n sql: string,\n options?: StatementOptions,\n ) => StatementSyncInstance;\n /**\n * The Session class for recording database changes.\n * This class should not be instantiated directly; use Database.createSession() instead.\n */\n Session: new () => Session;\n /**\n * SQLite constants for various operations and flags.\n * @see {@link SqliteConstants} for the type definition\n * @see {@link SqliteOpenFlags} for database open flags (extension beyond `node:sqlite`)\n * @see {@link SqliteChangesetResolution} for changeset conflict resolution values\n * @see {@link SqliteChangesetConflictTypes} for changeset conflict type codes\n * @see {@link SqliteAuthorizationResults} for authorization return values\n * @see {@link SqliteAuthorizationActions} for authorization action codes\n */\n constants: SqliteConstants;\n}\n\n/**\n * The DatabaseSync class represents a synchronous connection to a SQLite database.\n * All database operations are performed synchronously, blocking the thread until completion.\n *\n * @example\n * ```typescript\n * import { DatabaseSync } from '@photostructure/sqlite';\n *\n * // Create an in-memory database\n * const db = new DatabaseSync(':memory:');\n *\n * // Create a file-based database\n * const fileDb = new DatabaseSync('./mydata.db');\n *\n * // Create with options\n * const readOnlyDb = new DatabaseSync('./data.db', { readOnly: true });\n * ```\n */\nexport const DatabaseSync =\n binding.DatabaseSync as SqliteModule[\"DatabaseSync\"];\n\n// node:sqlite implements createTagStore and SQLTagStore entirely in native C++.\n// We use a TypeScript implementation instead, attached via prototype extension.\n// This maintains API compatibility with node:sqlite while avoiding the complexity\n// of a native LRU cache. Performance is equivalent since the real cost is SQLite\n// execution, not cache lookups - V8's Map is highly optimized for string keys.\n(DatabaseSync.prototype as DatabaseSyncInstance).createTagStore = function (\n this: DatabaseSyncInstance,\n capacity?: number,\n): SQLTagStoreInstance {\n return new SQLTagStore(this, capacity);\n};\n\n/**\n * The StatementSync class represents a prepared SQL statement.\n * This class should not be instantiated directly; use DatabaseSync.prepare() instead.\n *\n * @example\n * ```typescript\n * const stmt = db.prepare('SELECT * FROM users WHERE id = ?');\n * const user = stmt.get(123);\n * stmt.finalize();\n * ```\n */\nexport const StatementSync =\n binding.StatementSync as SqliteModule[\"StatementSync\"];\n\n/**\n * The Session class for recording database changes.\n * This class should not be instantiated directly; use DatabaseSync.createSession() instead.\n *\n * @example\n * ```typescript\n * const session = db.createSession({ table: 'users' });\n * // Make some changes to the users table\n * const changeset = session.changeset();\n * session.close();\n * ```\n */\nexport const Session = binding.Session as SqliteModule[\"Session\"];\n\n/**\n * The SQLTagStore class for cached prepared statements via tagged template syntax.\n * This class should not be instantiated directly; use DatabaseSync.createTagStore() instead.\n *\n * @example\n * ```typescript\n * const sql = db.createTagStore();\n * sql.run`INSERT INTO users VALUES (${id}, ${name})`;\n * const user = sql.get`SELECT * FROM users WHERE id = ${id}`;\n * ```\n */\nexport { SQLTagStore };\n\n/**\n * SQLite constants for various operations and flags.\n *\n * @example\n * ```typescript\n * import { constants } from '@photostructure/sqlite';\n *\n * const db = new DatabaseSync('./data.db', {\n * readOnly: true,\n * // Uses SQLITE_OPEN_READONLY internally\n * });\n * ```\n */\nexport const constants: SqliteConstants = binding.constants;\n\n/**\n * Options for the backup() function.\n */\nexport interface BackupOptions {\n /** Number of pages to be transmitted in each batch of the backup. @default 100 */\n rate?: number;\n /** Name of the source database. Can be 'main' or any attached database. @default 'main' */\n source?: string;\n /** Name of the target database. Can be 'main' or any attached database. @default 'main' */\n target?: string;\n /** Callback function that will be called with progress information. */\n progress?: (info: { totalPages: number; remainingPages: number }) => void;\n}\n\n/**\n * Standalone function to make a backup of a database.\n *\n * This function matches the Node.js `node:sqlite` module API which exports\n * `backup()` as a standalone function in addition to the `db.backup()` method.\n *\n * @param sourceDb The database to backup from.\n * @param destination The path where the backup will be created.\n * @param options Optional configuration for the backup operation.\n * @returns A promise that resolves when the backup is completed.\n *\n * @example\n * ```typescript\n * import { DatabaseSync, backup } from '@photostructure/sqlite';\n *\n * const db = new DatabaseSync('./source.db');\n * await backup(db, './backup.db');\n *\n * // With options\n * await backup(db, './backup.db', {\n * rate: 10,\n * progress: ({ totalPages, remainingPages }) => {\n * console.log(`Progress: ${totalPages - remainingPages}/${totalPages}`);\n * }\n * });\n * ```\n */\nexport const backup: (\n sourceDb: DatabaseSyncInstance,\n destination: string | Buffer | URL,\n options?: BackupOptions,\n) => Promise<number> = binding.backup;\n\n// Default export for CommonJS compatibility\nexport default binding as SqliteModule;\n","import { dirname } from \"node:path\";\n\nexport function getCallerDirname(): string {\n const e = new Error();\n if (e.stack == null) {\n Error.captureStackTrace(e);\n }\n return dirname(extractCallerPath(e.stack as string));\n}\n\n// Comprehensive regex patterns for different stack frame formats\nconst patterns =\n process.platform === \"win32\"\n ? [\n // File URLs: \"at functionName (file:///C:/path/file.js:1:1)\"\n /\\bat\\s.+?\\((?<path>file:\\/\\/\\/.+?):\\d+:\\d+\\)$/,\n // File URLs direct: \"at file:///C:/path/file.js:1:1\"\n /\\bat\\s(?<path>file:\\/\\/\\/.+?):\\d+:\\d+$/,\n // Standard: \"at functionName (C:\\path\\file.js:1:1)\"\n /\\bat\\s.+?\\((?<path>[A-Z]:\\\\.+):\\d+:\\d+\\)$/,\n // direct: \"at C:\\path\\file.js:1:1\"\n /\\bat\\s(?<path>[A-Z]:\\\\.+):\\d+:\\d+$/,\n // UNC: \"at functionName (\\\\server\\share\\path\\file.js:1:1)\"\n /\\bat\\s.+?\\((?<path>\\\\\\\\.+):\\d+:\\d+\\)$/,\n // direct: \"at \\\\server\\share\\path\\file.js:1:1\"\n /\\bat\\s(?<path>\\\\\\\\.+):\\d+:\\d+$/,\n ]\n : [\n // Standard: \"at functionName (/path/file.js:1:1)\"\n /\\bat\\s.+?\\((?<path>\\/.+?):\\d+:\\d+\\)$/,\n // Anonymous or direct: \"at /path/file.js:1:1\"\n // eslint-disable-next-line security/detect-unsafe-regex -- Pattern is safe: no nested quantifiers\n /\\bat\\s(?:[^\\s()]+\\s)?(?<path>\\/[^:]+):\\d+:\\d+$/,\n ];\n\nconst MaybeUrlRE = /^[a-z]{2,5}:\\/\\//i;\n\n// only exposed for tests:\nexport function extractCallerPath(stack: string): string {\n const frames = stack.split(\"\\n\").filter(Boolean);\n\n // First find getCallerDirname() in the stack:\n const callerFrame = frames.findIndex((frame) =>\n frame.includes(\"getCallerDirname\"),\n );\n if (callerFrame === -1) {\n throw new Error(\"Invalid stack trace format: missing caller frame\");\n }\n for (let i = callerFrame + 1; i < frames.length; i++) {\n // eslint-disable-next-line security/detect-object-injection -- Index is from controlled for-loop\n const frame = frames[i];\n for (const pattern of patterns) {\n const g = frame?.trim().match(pattern)?.groups;\n if (g != null && g[\"path\"]) {\n const path = g[\"path\"];\n // Windows requires us to check if it's a reasonable URL, as URL accepts\n // \"C:\\\\path\\\\file.txt\" as valid (!!)\n if (MaybeUrlRE.test(path)) {\n try {\n return new URL(path).pathname;\n } catch {\n // ignore\n }\n }\n return path;\n }\n }\n }\n throw new Error(\"Invalid stack trace format: no parsable frames\");\n}\n","import { getCallerDirname } from \"./stack-path\";\n\n// Thanks to tsup shims, __dirname should always be defined except when run by\n// jest (which will use the stack_path shim)\nexport function _dirname() {\n try {\n if (typeof __dirname !== \"undefined\") return __dirname;\n } catch {\n // ignore\n }\n // we must be in jest. Use the stack_path ~~hack~~ shim:\n return getCallerDirname();\n}\n","/**\n * Simple LRU (Least Recently Used) cache implementation.\n * Uses Map's insertion order to track recency - first key is oldest.\n */\nexport class LRUCache<K, V> {\n private cache = new Map<K, V>();\n private readonly maxCapacity: number;\n\n constructor(capacity: number) {\n if (capacity < 1) {\n throw new RangeError(\"LRU cache capacity must be at least 1\");\n }\n this.maxCapacity = capacity;\n }\n\n /**\n * Get a value from the cache.\n * If found, moves the entry to the end (most recently used).\n */\n get(key: K): V | undefined {\n const value = this.cache.get(key);\n if (value !== undefined) {\n // Move to end (most recently used) by reinserting\n this.cache.delete(key);\n this.cache.set(key, value);\n }\n return value;\n }\n\n /**\n * Set a value in the cache.\n * If key exists, updates and moves to end.\n * If at capacity, evicts the oldest entry first.\n */\n set(key: K, value: V): void {\n if (this.cache.has(key)) {\n // Update existing - delete and reinsert at end\n this.cache.delete(key);\n } else if (this.cache.size >= this.maxCapacity) {\n // Evict oldest (first key in Map iteration order)\n const oldestKey = this.cache.keys().next().value;\n if (oldestKey !== undefined) {\n this.cache.delete(oldestKey);\n }\n }\n this.cache.set(key, value);\n }\n\n /**\n * Delete an entry from the cache.\n */\n delete(key: K): boolean {\n return this.cache.delete(key);\n }\n\n /**\n * Check if a key exists in the cache.\n * Does NOT update recency.\n */\n has(key: K): boolean {\n return this.cache.has(key);\n }\n\n /**\n * Clear all entries from the cache.\n */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Get the current number of entries in the cache.\n */\n size(): number {\n return this.cache.size;\n }\n\n /**\n * Get the maximum capacity of the cache.\n */\n capacity(): number {\n return this.maxCapacity;\n }\n}\n","import { LRUCache } from \"./lru-cache\";\nimport { DatabaseSyncInstance } from \"./types/database-sync-instance\";\nimport type { StatementSyncInstance } from \"./types/statement-sync-instance\";\n\n/**\n * Default capacity for the statement cache.\n * Matches Node.js SQLTagStore default.\n */\nconst DEFAULT_CAPACITY = 1000;\n\n/**\n * SQLTagStore provides cached prepared statements via tagged template syntax.\n *\n * @example\n * ```js\n * const sql = db.createTagStore();\n * sql.run`INSERT INTO users VALUES (${id}, ${name})`;\n * const user = sql.get`SELECT * FROM users WHERE id = ${id}`;\n * ```\n */\nexport class SQLTagStore {\n private readonly database: DatabaseSyncInstance;\n private readonly cache: LRUCache<string, StatementSyncInstance>;\n private readonly maxCapacity: number;\n\n constructor(db: DatabaseSyncInstance, capacity: number = DEFAULT_CAPACITY) {\n if (!db.isOpen) {\n throw new Error(\"Database is not open\");\n }\n this.database = db;\n this.maxCapacity = capacity;\n this.cache = new LRUCache(capacity);\n }\n\n /**\n * Returns the associated database instance.\n */\n get db(): DatabaseSyncInstance {\n return this.database;\n }\n\n /**\n * Returns the maximum capacity of the statement cache.\n */\n get capacity(): number {\n return this.maxCapacity;\n }\n\n /**\n * Returns the current number of cached statements.\n */\n size(): number {\n return this.cache.size();\n }\n\n /**\n * Clears all cached statements.\n */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Execute an INSERT, UPDATE, DELETE or other statement that doesn't return rows.\n * Returns an object with `changes` and `lastInsertRowid`.\n */\n run(\n strings: TemplateStringsArray,\n ...values: unknown[]\n ): { changes: number; lastInsertRowid: number | bigint } {\n const stmt = this.getOrPrepare(strings);\n return stmt.run(...values);\n }\n\n /**\n * Execute a query and return the first row, or undefined if no rows.\n */\n get(strings: TemplateStringsArray, ...values: unknown[]): unknown {\n const stmt = this.getOrPrepare(strings);\n return stmt.get(...values);\n }\n\n /**\n * Execute a query and return all rows as an array.\n */\n all(strings: TemplateStringsArray, ...values: unknown[]): unknown[] {\n const stmt = this.getOrPrepare(strings);\n return stmt.all(...values);\n }\n\n /**\n * Execute a query and return an iterator over the rows.\n */\n iterate(\n strings: TemplateStringsArray,\n ...values: unknown[]\n ): IterableIterator<unknown> {\n const stmt = this.getOrPrepare(strings);\n return stmt.iterate(...values);\n }\n\n /**\n * Get a cached statement or prepare a new one.\n * If a cached statement has been finalized, it's evicted and a new one is prepared.\n */\n private getOrPrepare(strings: TemplateStringsArray): StatementSyncInstance {\n if (!this.database.isOpen) {\n throw new Error(\"Database is not open\");\n }\n\n const sql = this.buildSQL(strings);\n\n // Check cache - evict if finalized\n const cached = this.cache.get(sql);\n if (cached) {\n if (!cached.finalized) {\n return cached;\n }\n // Statement was finalized externally - remove from cache\n this.cache.delete(sql);\n }\n\n // Prepare new statement and cache it\n const stmt = this.database.prepare(sql);\n this.cache.set(sql, stmt);\n return stmt;\n }\n\n /**\n * Build the SQL string by joining template parts with `?` placeholders.\n */\n private buildSQL(strings: TemplateStringsArray): string {\n let sql = strings[0] ?? \"\";\n for (let i = 1; i < strings.length; i++) {\n // eslint-disable-next-line security/detect-object-injection -- Index is from controlled for-loop\n sql += \"?\" + (strings[i] ?? \"\");\n }\n return sql;\n }\n}\n"],"mappings":"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","names":["import_node_path","nodeGypBuild"]}