@xnetjs/sqlite 0.1.0 → 0.1.2

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.
@@ -591,6 +591,9 @@ var ElectronSQLiteAdapter = class {
591
591
  for (const property of input.properties) {
592
592
  ops.push(
593
593
  () => this.getOrPrepare(
594
+ // Full LWW ordering triple (lamport → wallTime → author), matching
595
+ // `shouldReplace` in @xnetjs/data. A lamport-only guard let arrival
596
+ // order decide same-lamport conflicts, diverging replicas (0272).
594
597
  `INSERT INTO node_properties
595
598
  (node_id, property_key, value, lamport_time, updated_by, updated_at)
596
599
  VALUES (?, ?, ?, ?, ?, ?)
@@ -599,7 +602,11 @@ var ElectronSQLiteAdapter = class {
599
602
  lamport_time = excluded.lamport_time,
600
603
  updated_by = excluded.updated_by,
601
604
  updated_at = excluded.updated_at
602
- WHERE excluded.lamport_time > node_properties.lamport_time`
605
+ WHERE excluded.lamport_time > node_properties.lamport_time
606
+ OR (excluded.lamport_time = node_properties.lamport_time
607
+ AND (excluded.updated_at > node_properties.updated_at
608
+ OR (excluded.updated_at = node_properties.updated_at
609
+ AND excluded.updated_by > node_properties.updated_by)))`
603
610
  ).run(
604
611
  property.nodeId,
605
612
  property.propertyKey,
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  createWebSQLiteAdapter,
7
7
  resetWebSQLiteOpfsStorage
8
- } from "../chunk-BBZDKLA3.js";
8
+ } from "../chunk-4RB2QHGD.js";
9
9
  import "../chunk-SV475UL5.js";
10
10
  import {
11
11
  bootLogMessage
@@ -3,7 +3,7 @@ import {
3
3
  createWebSQLiteAdapter,
4
4
  resetWebSQLiteOpfsStorage,
5
5
  stepIncrementalVacuumToCompletion
6
- } from "../chunk-BBZDKLA3.js";
6
+ } from "../chunk-4RB2QHGD.js";
7
7
  import "../chunk-SV475UL5.js";
8
8
  import "../chunk-CBU263LI.js";
9
9
  import "../chunk-W3L4FXU5.js";
@@ -489,6 +489,9 @@ var WebSQLiteAdapter = class {
489
489
  }
490
490
  for (const property of input.properties) {
491
491
  await this.run(
492
+ // Full LWW ordering triple (lamport → wallTime → author), matching
493
+ // `shouldReplace` in @xnetjs/data. A lamport-only guard let arrival
494
+ // order decide same-lamport conflicts, diverging replicas (0272).
492
495
  `INSERT INTO node_properties
493
496
  (node_id, property_key, value, lamport_time, updated_by, updated_at)
494
497
  VALUES (?, ?, ?, ?, ?, ?)
@@ -497,7 +500,11 @@ var WebSQLiteAdapter = class {
497
500
  lamport_time = excluded.lamport_time,
498
501
  updated_by = excluded.updated_by,
499
502
  updated_at = excluded.updated_at
500
- WHERE excluded.lamport_time > node_properties.lamport_time`,
503
+ WHERE excluded.lamport_time > node_properties.lamport_time
504
+ OR (excluded.lamport_time = node_properties.lamport_time
505
+ AND (excluded.updated_at > node_properties.updated_at
506
+ OR (excluded.updated_at = node_properties.updated_at
507
+ AND excluded.updated_by > node_properties.updated_by)))`,
501
508
  [
502
509
  property.nodeId,
503
510
  property.propertyKey,
package/dist/index.d.ts CHANGED
@@ -163,8 +163,9 @@ interface SQLiteRuntimeCapabilities {
163
163
  /**
164
164
  * Get information about all indexes in the database. Cached per adapter and keyed
165
165
  * on `PRAGMA schema_version`, so repeated calls between DDL changes pay one cheap
166
- * version probe instead of `sqlite_master` + N `PRAGMA index_info` round-trips
167
- * (exploration 0253).
166
+ * version probe instead of a rebuild (exploration 0253). Concurrent callers share
167
+ * a single in-flight probe+build, and a cold build is a single batched statement
168
+ * — worst case one diagnostic run costs 2 worker round-trips, not 1 + 1 + N.
168
169
  */
169
170
  declare function getIndexInfo(db: SQLiteAdapter): Promise<IndexInfo[]>;
170
171
  /**
package/dist/index.js CHANGED
@@ -79,12 +79,35 @@ async function readSchemaVersion(db) {
79
79
  return 0;
80
80
  }
81
81
  }
82
- async function getIndexInfo(db) {
83
- const schemaVersion = await readSchemaVersion(db);
84
- const cached = indexInfoCache.get(db);
85
- if (cached && cached.schemaVersion === schemaVersion) {
86
- return cached.indexes;
82
+ async function fetchIndexInfoBatched(db) {
83
+ const rows = await db.query(
84
+ `SELECT m.name AS index_name, m.tbl_name AS table_name, m.sql AS index_sql,
85
+ ii.seqno AS seqno, ii.name AS column_name
86
+ FROM sqlite_master AS m
87
+ LEFT JOIN pragma_index_info(m.name) AS ii
88
+ WHERE m.type = 'index' AND m.name NOT LIKE 'sqlite_%'
89
+ ORDER BY m.name, ii.seqno`
90
+ );
91
+ const byName = /* @__PURE__ */ new Map();
92
+ for (const row of rows) {
93
+ let info = byName.get(row.index_name);
94
+ if (!info) {
95
+ info = {
96
+ name: row.index_name,
97
+ tableName: row.table_name,
98
+ unique: row.index_sql?.includes("UNIQUE") ?? false,
99
+ columns: [],
100
+ partial: row.index_sql?.includes("WHERE") ?? false
101
+ };
102
+ byName.set(row.index_name, info);
103
+ }
104
+ if (row.seqno !== null) {
105
+ info.columns.push(row.column_name);
106
+ }
87
107
  }
108
+ return [...byName.values()];
109
+ }
110
+ async function fetchIndexInfoPerIndex(db) {
88
111
  const indexes = await db.query(
89
112
  "SELECT name, tbl_name, sql FROM sqlite_master WHERE type='index' AND name NOT LIKE 'sqlite_%'"
90
113
  );
@@ -99,9 +122,39 @@ async function getIndexInfo(db) {
99
122
  partial: idx.sql?.includes("WHERE") ?? false
100
123
  });
101
124
  }
102
- indexInfoCache.set(db, { schemaVersion, indexes: result });
103
125
  return result;
104
126
  }
127
+ async function getIndexInfo(db) {
128
+ let entry = indexInfoCache.get(db);
129
+ if (!entry) {
130
+ entry = {};
131
+ indexInfoCache.set(db, entry);
132
+ }
133
+ if (entry.inFlight) {
134
+ return entry.inFlight;
135
+ }
136
+ const cacheEntry = entry;
137
+ const inFlight = (async () => {
138
+ const schemaVersion = await readSchemaVersion(db);
139
+ if (cacheEntry.resolved && cacheEntry.resolved.schemaVersion === schemaVersion) {
140
+ return cacheEntry.resolved.indexes;
141
+ }
142
+ let indexes;
143
+ try {
144
+ indexes = await fetchIndexInfoBatched(db);
145
+ } catch {
146
+ indexes = await fetchIndexInfoPerIndex(db);
147
+ }
148
+ cacheEntry.resolved = { schemaVersion, indexes };
149
+ return indexes;
150
+ })();
151
+ entry.inFlight = inFlight;
152
+ try {
153
+ return await inFlight;
154
+ } finally {
155
+ cacheEntry.inFlight = void 0;
156
+ }
157
+ }
105
158
  async function analyzeQuery(db, sql, params) {
106
159
  const plan = await db.query(`EXPLAIN QUERY PLAN ${sql}`, params);
107
160
  const steps = plan.map((row) => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xnetjs/sqlite",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Unified SQLite adapter for xNet across all platforms",
5
5
  "license": "MIT",
6
6
  "repository": {