@alstate/sqlite 0.1.0 → 0.1.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.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Alstate contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alstate contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -3,13 +3,63 @@
3
3
  Experimental SQLite persistence adapter for `@alstate/core`, implemented with
4
4
  Node.js `node:sqlite`.
5
5
 
6
+ ## Requirements and install
7
+
8
+ Node.js 22.13 or later is required.
9
+
10
+ ```bash
11
+ npm install @alstate/core @alstate/sqlite
12
+ ```
13
+
14
+ Add a scheduling algorithm separately; `@alstate/fsrs` is the first-party
15
+ choice.
16
+
17
+ ## Use
18
+
6
19
  ```ts
20
+ import { LearningEngine } from "@alstate/core";
21
+ import { FsrsAlgorithm } from "@alstate/fsrs";
7
22
  import { SqliteLearningStore } from "@alstate/sqlite";
8
23
 
9
- const store = new SqliteLearningStore("learning.db");
24
+ const engine = await LearningEngine.create({
25
+ store: new SqliteLearningStore("data/learning.db"),
26
+ algorithm: new FsrsAlgorithm(),
27
+ });
28
+
29
+ try {
30
+ const item = await engine.add({ prompt: "2 + 2", answer: "4" });
31
+ await engine.review(item.id, "good");
32
+ } finally {
33
+ engine.close();
34
+ }
10
35
  ```
11
36
 
12
- Requires Node.js 22.13 or later. The adapter applies schema migrations on open,
13
- uses transactions for composite writes and rejects stale review revisions.
37
+ The constructor defaults to an in-memory database when no path is supplied:
38
+
39
+ ```ts
40
+ const store = new SqliteLearningStore(); // ":memory:"
41
+ ```
42
+
43
+ For a file path, missing parent directories are created automatically. The
44
+ adapter opens or creates the database, enables foreign keys, applies pending
45
+ schema migrations and sets a 5-second busy timeout.
46
+
47
+ ## Behavior
48
+
49
+ - item creation and initial-state creation share one transaction;
50
+ - state update and review insertion share one transaction;
51
+ - reviews compare and increment a state revision, rejecting stale writers with
52
+ `ConcurrentReviewError`;
53
+ - operations are scoped to the registered algorithm;
54
+ - deleting an item cascades to state and review history;
55
+ - items are ordered by ID, due items by due time then ID, and history newest
56
+ first;
57
+ - timestamps are persisted as ISO 8601 strings and returned as `Date` objects.
58
+
59
+ `engine.close()` closes its store. Do not reuse the connection afterward.
60
+
61
+ - [SQLite and FSRS adapter guide](https://github.com/laiqfun/alstate/blob/main/docs/adapters.md)
62
+ - [SQLite data model](https://github.com/laiqfun/alstate/blob/main/docs/data-model.md)
63
+ - [Core API reference](https://github.com/laiqfun/alstate/blob/main/docs/api-reference.md)
14
64
 
15
65
  MIT
@@ -2,80 +2,80 @@ const migrations = [
2
2
  {
3
3
  version: 1,
4
4
  name: "learning_engine_schema",
5
- sql: `
6
- CREATE TABLE engine_items (
7
- id INTEGER PRIMARY KEY,
8
- data_json TEXT NOT NULL CHECK (json_valid(data_json))
9
- ) STRICT;
10
-
11
- CREATE TABLE engine_algorithms (
12
- id INTEGER PRIMARY KEY,
13
- name TEXT NOT NULL UNIQUE CHECK (length(trim(name)) > 0),
14
- description TEXT,
15
- version TEXT NOT NULL CHECK (length(trim(version)) > 0),
16
- config_json TEXT NOT NULL CHECK (json_valid(config_json))
17
- ) STRICT;
18
-
19
- CREATE TABLE engine_states (
20
- id INTEGER PRIMARY KEY,
21
- learning_item_id INTEGER NOT NULL,
22
- algorithm_id INTEGER NOT NULL,
23
- due_at TEXT NOT NULL,
24
- state_json TEXT NOT NULL CHECK (json_valid(state_json)),
25
- UNIQUE (learning_item_id, algorithm_id),
26
- FOREIGN KEY (learning_item_id)
27
- REFERENCES engine_items (id) ON DELETE CASCADE,
28
- FOREIGN KEY (algorithm_id)
29
- REFERENCES engine_algorithms (id) ON DELETE RESTRICT
30
- ) STRICT;
31
-
32
- CREATE INDEX engine_states_due_idx
33
- ON engine_states (algorithm_id, due_at, learning_item_id);
34
-
35
- CREATE TABLE engine_reviews (
36
- id INTEGER PRIMARY KEY,
37
- learning_item_id INTEGER NOT NULL,
38
- algorithm_id INTEGER NOT NULL,
39
- rating TEXT NOT NULL CHECK (length(trim(rating)) > 0),
40
- review_json TEXT NOT NULL CHECK (json_valid(review_json)),
41
- response_time_ms INTEGER CHECK (
42
- response_time_ms IS NULL OR response_time_ms >= 0
43
- ),
44
- reviewed_at TEXT NOT NULL,
45
- FOREIGN KEY (learning_item_id)
46
- REFERENCES engine_items (id) ON DELETE CASCADE,
47
- FOREIGN KEY (algorithm_id)
48
- REFERENCES engine_algorithms (id) ON DELETE RESTRICT
49
- ) STRICT;
50
-
51
- CREATE INDEX engine_reviews_item_time_idx
52
- ON engine_reviews (learning_item_id, reviewed_at DESC, id DESC);
5
+ sql: `
6
+ CREATE TABLE engine_items (
7
+ id INTEGER PRIMARY KEY,
8
+ data_json TEXT NOT NULL CHECK (json_valid(data_json))
9
+ ) STRICT;
10
+
11
+ CREATE TABLE engine_algorithms (
12
+ id INTEGER PRIMARY KEY,
13
+ name TEXT NOT NULL UNIQUE CHECK (length(trim(name)) > 0),
14
+ description TEXT,
15
+ version TEXT NOT NULL CHECK (length(trim(version)) > 0),
16
+ config_json TEXT NOT NULL CHECK (json_valid(config_json))
17
+ ) STRICT;
18
+
19
+ CREATE TABLE engine_states (
20
+ id INTEGER PRIMARY KEY,
21
+ learning_item_id INTEGER NOT NULL,
22
+ algorithm_id INTEGER NOT NULL,
23
+ due_at TEXT NOT NULL,
24
+ state_json TEXT NOT NULL CHECK (json_valid(state_json)),
25
+ UNIQUE (learning_item_id, algorithm_id),
26
+ FOREIGN KEY (learning_item_id)
27
+ REFERENCES engine_items (id) ON DELETE CASCADE,
28
+ FOREIGN KEY (algorithm_id)
29
+ REFERENCES engine_algorithms (id) ON DELETE RESTRICT
30
+ ) STRICT;
31
+
32
+ CREATE INDEX engine_states_due_idx
33
+ ON engine_states (algorithm_id, due_at, learning_item_id);
34
+
35
+ CREATE TABLE engine_reviews (
36
+ id INTEGER PRIMARY KEY,
37
+ learning_item_id INTEGER NOT NULL,
38
+ algorithm_id INTEGER NOT NULL,
39
+ rating TEXT NOT NULL CHECK (length(trim(rating)) > 0),
40
+ review_json TEXT NOT NULL CHECK (json_valid(review_json)),
41
+ response_time_ms INTEGER CHECK (
42
+ response_time_ms IS NULL OR response_time_ms >= 0
43
+ ),
44
+ reviewed_at TEXT NOT NULL,
45
+ FOREIGN KEY (learning_item_id)
46
+ REFERENCES engine_items (id) ON DELETE CASCADE,
47
+ FOREIGN KEY (algorithm_id)
48
+ REFERENCES engine_algorithms (id) ON DELETE RESTRICT
49
+ ) STRICT;
50
+
51
+ CREATE INDEX engine_reviews_item_time_idx
52
+ ON engine_reviews (learning_item_id, reviewed_at DESC, id DESC);
53
53
  `,
54
54
  },
55
55
  {
56
56
  version: 2,
57
57
  name: "optimistic_review_concurrency",
58
- sql: `
59
- ALTER TABLE engine_states
60
- ADD COLUMN revision INTEGER NOT NULL DEFAULT 0
61
- CHECK (revision >= 0);
58
+ sql: `
59
+ ALTER TABLE engine_states
60
+ ADD COLUMN revision INTEGER NOT NULL DEFAULT 0
61
+ CHECK (revision >= 0);
62
62
  `,
63
63
  },
64
64
  ];
65
65
  export function migrateDatabase(database) {
66
- database.exec(`
67
- CREATE TABLE IF NOT EXISTS engine_schema_migrations (
68
- version INTEGER PRIMARY KEY,
69
- name TEXT NOT NULL UNIQUE,
70
- applied_at TEXT NOT NULL
71
- ) STRICT;
66
+ database.exec(`
67
+ CREATE TABLE IF NOT EXISTS engine_schema_migrations (
68
+ version INTEGER PRIMARY KEY,
69
+ name TEXT NOT NULL UNIQUE,
70
+ applied_at TEXT NOT NULL
71
+ ) STRICT;
72
72
  `);
73
73
  const applied = new Set(database
74
74
  .prepare("SELECT version FROM engine_schema_migrations")
75
75
  .all().map((row) => row.version));
76
- const record = database.prepare(`
77
- INSERT INTO engine_schema_migrations (version, name, applied_at)
78
- VALUES (?, ?, ?)
76
+ const record = database.prepare(`
77
+ INSERT INTO engine_schema_migrations (version, name, applied_at)
78
+ VALUES (?, ?, ?)
79
79
  `);
80
80
  for (const migration of migrations) {
81
81
  if (applied.has(migration.version)) {
@@ -21,10 +21,10 @@ export class SqliteLearningStore {
21
21
  requireNonBlank(registration.name, "algorithm name");
22
22
  requireNonBlank(registration.version, "algorithm version");
23
23
  const existing = this.#database
24
- .prepare(`
25
- SELECT id, name, version, description, config_json
26
- FROM engine_algorithms
27
- WHERE name = ?
24
+ .prepare(`
25
+ SELECT id, name, version, description, config_json
26
+ FROM engine_algorithms
27
+ WHERE name = ?
28
28
  `)
29
29
  .get(registration.name);
30
30
  if (existing !== undefined) {
@@ -37,10 +37,10 @@ export class SqliteLearningStore {
37
37
  return stored;
38
38
  }
39
39
  const result = this.#database
40
- .prepare(`
41
- INSERT INTO engine_algorithms
42
- (name, version, description, config_json)
43
- VALUES (?, ?, ?, ?)
40
+ .prepare(`
41
+ INSERT INTO engine_algorithms
42
+ (name, version, description, config_json)
43
+ VALUES (?, ?, ?, ?)
44
44
  `)
45
45
  .run(registration.name, registration.version, registration.description ?? null, JSON.stringify(registration.configuration));
46
46
  return Object.freeze({
@@ -55,10 +55,10 @@ export class SqliteLearningStore {
55
55
  .run(JSON.stringify(input.data));
56
56
  const id = learningItemId(toSafeInteger(itemResult.lastInsertRowid));
57
57
  this.#database
58
- .prepare(`
59
- INSERT INTO engine_states
60
- (learning_item_id, algorithm_id, due_at, state_json)
61
- VALUES (?, ?, ?, ?)
58
+ .prepare(`
59
+ INSERT INTO engine_states
60
+ (learning_item_id, algorithm_id, due_at, state_json)
61
+ VALUES (?, ?, ?, ?)
62
62
  `)
63
63
  .run(id, input.algorithmId, isoDate(input.dueAt, "initial due time"), JSON.stringify(input.stateData));
64
64
  return freezeItem({ id, data: input.data });
@@ -66,11 +66,11 @@ export class SqliteLearningStore {
66
66
  }
67
67
  async findItem(id, registeredAlgorithmId) {
68
68
  const row = this.#database
69
- .prepare(`
70
- SELECT item.id, item.data_json
71
- FROM engine_items item
72
- JOIN engine_states state ON state.learning_item_id = item.id
73
- WHERE item.id = ? AND state.algorithm_id = ?
69
+ .prepare(`
70
+ SELECT item.id, item.data_json
71
+ FROM engine_items item
72
+ JOIN engine_states state ON state.learning_item_id = item.id
73
+ WHERE item.id = ? AND state.algorithm_id = ?
74
74
  `)
75
75
  .get(id, registeredAlgorithmId);
76
76
  return row === undefined ? null : mapItem(row);
@@ -78,12 +78,12 @@ export class SqliteLearningStore {
78
78
  async listItems(registeredAlgorithmId, query = {}) {
79
79
  validatePage(query);
80
80
  const parameters = [registeredAlgorithmId];
81
- let sql = `
82
- SELECT item.id, item.data_json
83
- FROM engine_items item
84
- JOIN engine_states state ON state.learning_item_id = item.id
85
- WHERE state.algorithm_id = ?
86
- ORDER BY item.id
81
+ let sql = `
82
+ SELECT item.id, item.data_json
83
+ FROM engine_items item
84
+ JOIN engine_states state ON state.learning_item_id = item.id
85
+ WHERE state.algorithm_id = ?
86
+ ORDER BY item.id
87
87
  `;
88
88
  if (query.limit !== undefined) {
89
89
  sql += " LIMIT ?";
@@ -101,13 +101,13 @@ export class SqliteLearningStore {
101
101
  }
102
102
  async updateItem(id, registeredAlgorithmId, data) {
103
103
  const result = this.#database
104
- .prepare(`
105
- UPDATE engine_items SET data_json = ?
106
- WHERE id = ? AND EXISTS (
107
- SELECT 1 FROM engine_states state
108
- WHERE state.learning_item_id = engine_items.id
109
- AND state.algorithm_id = ?
110
- )
104
+ .prepare(`
105
+ UPDATE engine_items SET data_json = ?
106
+ WHERE id = ? AND EXISTS (
107
+ SELECT 1 FROM engine_states state
108
+ WHERE state.learning_item_id = engine_items.id
109
+ AND state.algorithm_id = ?
110
+ )
111
111
  `)
112
112
  .run(JSON.stringify(data), id, registeredAlgorithmId);
113
113
  return toSafeInteger(result.changes) === 0
@@ -116,23 +116,23 @@ export class SqliteLearningStore {
116
116
  }
117
117
  async deleteItem(id, registeredAlgorithmId) {
118
118
  const result = this.#database
119
- .prepare(`
120
- DELETE FROM engine_items
121
- WHERE id = ? AND EXISTS (
122
- SELECT 1 FROM engine_states state
123
- WHERE state.learning_item_id = engine_items.id
124
- AND state.algorithm_id = ?
125
- )
119
+ .prepare(`
120
+ DELETE FROM engine_items
121
+ WHERE id = ? AND EXISTS (
122
+ SELECT 1 FROM engine_states state
123
+ WHERE state.learning_item_id = engine_items.id
124
+ AND state.algorithm_id = ?
125
+ )
126
126
  `)
127
127
  .run(id, registeredAlgorithmId);
128
128
  return toSafeInteger(result.changes) > 0;
129
129
  }
130
130
  async findState(itemId, registeredAlgorithmId) {
131
131
  const row = this.#database
132
- .prepare(`
133
- SELECT id, learning_item_id, algorithm_id, revision, due_at, state_json
134
- FROM engine_states
135
- WHERE learning_item_id = ? AND algorithm_id = ?
132
+ .prepare(`
133
+ SELECT id, learning_item_id, algorithm_id, revision, due_at, state_json
134
+ FROM engine_states
135
+ WHERE learning_item_id = ? AND algorithm_id = ?
136
136
  `)
137
137
  .get(itemId, registeredAlgorithmId);
138
138
  return row === undefined ? null : mapState(row);
@@ -143,19 +143,19 @@ export class SqliteLearningStore {
143
143
  input.algorithmId,
144
144
  isoDate(input.dueAtOrBefore, "due query time"),
145
145
  ];
146
- let sql = `
147
- SELECT
148
- item.id AS item_id,
149
- item.data_json,
150
- state.id AS state_id,
151
- state.algorithm_id,
152
- state.revision,
153
- state.due_at,
154
- state.state_json
155
- FROM engine_states state
156
- JOIN engine_items item ON item.id = state.learning_item_id
157
- WHERE state.algorithm_id = ? AND state.due_at <= ?
158
- ORDER BY state.due_at, item.id
146
+ let sql = `
147
+ SELECT
148
+ item.id AS item_id,
149
+ item.data_json,
150
+ state.id AS state_id,
151
+ state.algorithm_id,
152
+ state.revision,
153
+ state.due_at,
154
+ state.state_json
155
+ FROM engine_states state
156
+ JOIN engine_items item ON item.id = state.learning_item_id
157
+ WHERE state.algorithm_id = ? AND state.due_at <= ?
158
+ ORDER BY state.due_at, item.id
159
159
  `;
160
160
  if (input.limit !== undefined) {
161
161
  sql += " LIMIT ?";
@@ -184,10 +184,10 @@ export class SqliteLearningStore {
184
184
  throw new TypeError("Review identity must match the state being updated.");
185
185
  }
186
186
  const update = this.#database
187
- .prepare(`
188
- UPDATE engine_states
189
- SET due_at = ?, state_json = ?, revision = revision + 1
190
- WHERE id = ? AND revision = ?
187
+ .prepare(`
188
+ UPDATE engine_states
189
+ SET due_at = ?, state_json = ?, revision = revision + 1
190
+ WHERE id = ? AND revision = ?
191
191
  `)
192
192
  .run(isoDate(input.state.dueAt, "next due time"), JSON.stringify(input.state.data), input.state.state.id, input.state.state.revision);
193
193
  if (toSafeInteger(update.changes) !== 1) {
@@ -196,13 +196,13 @@ export class SqliteLearningStore {
196
196
  const review = input.review;
197
197
  validateResponseTime(review.responseTimeMs);
198
198
  const result = this.#database
199
- .prepare(`
200
- INSERT INTO engine_reviews
201
- (
202
- learning_item_id, algorithm_id, rating, review_json,
203
- response_time_ms, reviewed_at
204
- )
205
- VALUES (?, ?, ?, ?, ?, ?)
199
+ .prepare(`
200
+ INSERT INTO engine_reviews
201
+ (
202
+ learning_item_id, algorithm_id, rating, review_json,
203
+ response_time_ms, reviewed_at
204
+ )
205
+ VALUES (?, ?, ?, ?, ?, ?)
206
206
  `)
207
207
  .run(review.learningItemId, review.algorithmId, requireNonBlank(review.rating, "rating"), JSON.stringify(review.data), review.responseTimeMs ?? null, isoDate(review.reviewedAt, "review time"));
208
208
  return freezeReview({
@@ -214,13 +214,13 @@ export class SqliteLearningStore {
214
214
  async listReviews(itemId, registeredAlgorithmId, query = {}) {
215
215
  validatePage(query);
216
216
  const parameters = [itemId, registeredAlgorithmId];
217
- let sql = `
218
- SELECT
219
- id, learning_item_id, algorithm_id, rating, review_json,
220
- response_time_ms, reviewed_at
221
- FROM engine_reviews
222
- WHERE learning_item_id = ? AND algorithm_id = ?
223
- ORDER BY reviewed_at DESC, id DESC
217
+ let sql = `
218
+ SELECT
219
+ id, learning_item_id, algorithm_id, rating, review_json,
220
+ response_time_ms, reviewed_at
221
+ FROM engine_reviews
222
+ WHERE learning_item_id = ? AND algorithm_id = ?
223
+ ORDER BY reviewed_at DESC, id DESC
224
224
  `;
225
225
  if (query.limit !== undefined) {
226
226
  sql += " LIMIT ?";
package/package.json CHANGED
@@ -1,34 +1,34 @@
1
- {
2
- "name": "@alstate/sqlite",
3
- "version": "0.1.0",
4
- "description": "SQLite persistence adapter for Alstate.",
5
- "keywords": ["learning", "scheduling", "sqlite", "spaced-repetition"],
6
- "type": "module",
7
- "main": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
9
- "exports": {
10
- ".": {
11
- "types": "./dist/index.d.ts",
12
- "import": "./dist/index.js"
13
- }
14
- },
15
- "files": ["dist", "README.md", "LICENSE"],
16
- "sideEffects": false,
17
- "scripts": {
18
- "build": "tsc --project tsconfig.build.json",
19
- "clean": "node --eval \"require('node:fs').rmSync('dist', { recursive: true, force: true }); require('node:fs').rmSync('.test-dist', { recursive: true, force: true })\"",
20
- "test": "tsc --project tsconfig.test.json && node --test \".test-dist/test/**/*.test.js\"",
21
- "typecheck": "tsc --project tsconfig.json --noEmit"
22
- },
23
- "dependencies": { "@alstate/core": "0.1.0" },
24
- "engines": { "node": ">=22.13.0" },
25
- "license": "MIT",
26
- "repository": {
27
- "type": "git",
28
- "url": "git+https://github.com/laiqfun/alstate.git",
29
- "directory": "packages/sqlite"
30
- },
31
- "homepage": "https://github.com/laiqfun/alstate#readme",
32
- "bugs": { "url": "https://github.com/laiqfun/alstate/issues" },
33
- "publishConfig": { "access": "public" }
34
- }
1
+ {
2
+ "name": "@alstate/sqlite",
3
+ "version": "0.1.1",
4
+ "description": "SQLite persistence adapter for Alstate.",
5
+ "keywords": ["learning", "scheduling", "sqlite", "spaced-repetition"],
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": ["dist", "README.md", "LICENSE"],
16
+ "sideEffects": false,
17
+ "scripts": {
18
+ "build": "tsc --project tsconfig.build.json",
19
+ "clean": "node --eval \"require('node:fs').rmSync('dist', { recursive: true, force: true }); require('node:fs').rmSync('.test-dist', { recursive: true, force: true })\"",
20
+ "test": "tsc --project tsconfig.test.json && node --test \".test-dist/test/**/*.test.js\"",
21
+ "typecheck": "tsc --project tsconfig.json --noEmit"
22
+ },
23
+ "dependencies": { "@alstate/core": "0.1.1" },
24
+ "engines": { "node": ">=22.13.0" },
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/laiqfun/alstate.git",
29
+ "directory": "packages/sqlite"
30
+ },
31
+ "homepage": "https://github.com/laiqfun/alstate#readme",
32
+ "bugs": { "url": "https://github.com/laiqfun/alstate/issues" },
33
+ "publishConfig": { "access": "public" }
34
+ }