@rotorsoft/act-sqlite 1.22.2 → 1.22.4
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/dist/.tsbuildinfo +1 -1
- package/dist/@types/sqlite-store.d.ts +0 -50
- package/dist/@types/sqlite-store.d.ts.map +1 -1
- package/dist/index.cjs +41 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +41 -65
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -79,13 +79,11 @@ function streamPatternToGlob(input) {
|
|
|
79
79
|
}
|
|
80
80
|
var SqliteStore = class {
|
|
81
81
|
client;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
* provider.
|
|
88
|
-
*/
|
|
82
|
+
// Memoized key resolver for the optional `pii_encryption` envelope.
|
|
83
|
+
// Initialized in the constructor when encryption is configured;
|
|
84
|
+
// `undefined` otherwise. The resolver caches the operator's key on
|
|
85
|
+
// first use — rotation means restarting the store with a fresh
|
|
86
|
+
// provider.
|
|
89
87
|
_resolve_pii_key;
|
|
90
88
|
constructor(config) {
|
|
91
89
|
this.client = createClient({
|
|
@@ -94,14 +92,10 @@ var SqliteStore = class {
|
|
|
94
92
|
});
|
|
95
93
|
this._resolve_pii_key = config.pii_encryption ? makeKeyResolver(config.pii_encryption) : void 0;
|
|
96
94
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
* column entirely on a `NULL` write).
|
|
102
|
-
*
|
|
103
|
-
* @internal
|
|
104
|
-
*/
|
|
95
|
+
// Write-side pii encoder: encrypts when `pii_encryption` is configured,
|
|
96
|
+
// stringifies for the TEXT column either way. `null` passes through so
|
|
97
|
+
// `forget_pii` semantics survive intact (the row format skips the
|
|
98
|
+
// column entirely on a `NULL` write).
|
|
105
99
|
async _stringify_pii_for_write(pii) {
|
|
106
100
|
if (pii == null) return null;
|
|
107
101
|
if (this._resolve_pii_key) {
|
|
@@ -109,15 +103,11 @@ var SqliteStore = class {
|
|
|
109
103
|
}
|
|
110
104
|
return JSON.stringify(pii);
|
|
111
105
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
* rollouts (some pre-encryption rows, some post-) read cleanly.
|
|
118
|
-
*
|
|
119
|
-
* @internal
|
|
120
|
-
*/
|
|
106
|
+
// Read-side pii decoder: parses the TEXT column, and when
|
|
107
|
+
// `pii_encryption` is configured, transparently decrypts any value
|
|
108
|
+
// that came back as a JSON string. Plaintext writes deserialize to
|
|
109
|
+
// objects and pass through — which is what makes mixed-data
|
|
110
|
+
// rollouts (some pre-encryption rows, some post-) read cleanly.
|
|
121
111
|
async _parse_pii_from_read(raw) {
|
|
122
112
|
if (raw == null) return null;
|
|
123
113
|
const parsed = parse_json(raw);
|
|
@@ -253,7 +243,7 @@ var SqliteStore = class {
|
|
|
253
243
|
await this.client.execute("DROP TABLE IF EXISTS streams");
|
|
254
244
|
await this.client.execute("DROP TABLE IF EXISTS correlated");
|
|
255
245
|
}
|
|
256
|
-
|
|
246
|
+
// One write transaction: any failure rolls back and throws a {@link StoreError} naming the operation.
|
|
257
247
|
async _tx(operation, work) {
|
|
258
248
|
const tx = await this.client.transaction("write");
|
|
259
249
|
try {
|
|
@@ -649,32 +639,25 @@ var SqliteStore = class {
|
|
|
649
639
|
// Cleared by ack/block/reset/unblock. See {@link Store.defer}.
|
|
650
640
|
async defer(input, deferred_at) {
|
|
651
641
|
const at_iso = new Date(deferred_at).toISOString();
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
]);
|
|
656
|
-
} catch (e) {
|
|
657
|
-
throw new StoreError("defer", { cause: e });
|
|
658
|
-
}
|
|
642
|
+
return this._update("defer", input, "SET deferred_at = ?, retry = -1", [
|
|
643
|
+
at_iso
|
|
644
|
+
]);
|
|
659
645
|
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
*/
|
|
671
|
-
async _update(input, set, params = [], where) {
|
|
646
|
+
// Runs `UPDATE streams <set>` on the streams named by `input`, in one
|
|
647
|
+
// write transaction (`_tx`) that rolls back on failure. An explicit list is
|
|
648
|
+
// de-duplicated, so a repeated name counts once (matching PG's set-based
|
|
649
|
+
// `stream = ANY(...)`), and updated one name per statement, so a long list
|
|
650
|
+
// never meets SQLite's bound-parameter limit. `set` and `where` bind
|
|
651
|
+
// `params` in order; libSQL `?` placeholders are positional and can't be
|
|
652
|
+
// reused, so a value used twice is passed twice.
|
|
653
|
+
//
|
|
654
|
+
// @returns Count of rows updated.
|
|
655
|
+
_update(operation, input, set, params = [], where) {
|
|
672
656
|
const selections = Array.isArray(input) ? [...new Set(input)].map((stream) => ({
|
|
673
657
|
clause: "stream = ?",
|
|
674
658
|
args: [stream]
|
|
675
659
|
})) : [this._filter_clause(input)];
|
|
676
|
-
|
|
677
|
-
try {
|
|
660
|
+
return this._tx(operation, async (tx) => {
|
|
678
661
|
let count = 0;
|
|
679
662
|
for (const { clause, args } of selections) {
|
|
680
663
|
const r = await tx.execute({
|
|
@@ -683,18 +666,12 @@ var SqliteStore = class {
|
|
|
683
666
|
});
|
|
684
667
|
count += r.rowsAffected;
|
|
685
668
|
}
|
|
686
|
-
await tx.commit();
|
|
687
669
|
return count;
|
|
688
|
-
}
|
|
689
|
-
await tx.rollback();
|
|
690
|
-
throw e;
|
|
691
|
-
}
|
|
670
|
+
});
|
|
692
671
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
* callers can compose it unconditionally.
|
|
697
|
-
*/
|
|
672
|
+
// Translate a {@link StreamFilter} to a SQLite `WHERE` clause fragment
|
|
673
|
+
// plus positional args. Returns `"1"` (always true) when empty so
|
|
674
|
+
// callers can compose it unconditionally.
|
|
698
675
|
_filter_clause(filter) {
|
|
699
676
|
const conditions = [];
|
|
700
677
|
const args = [];
|
|
@@ -730,6 +707,7 @@ var SqliteStore = class {
|
|
|
730
707
|
// --- reset: transactional, accepts names or filter ---
|
|
731
708
|
reset(input) {
|
|
732
709
|
return this._update(
|
|
710
|
+
"reset",
|
|
733
711
|
input,
|
|
734
712
|
`SET at = -1, retry = -1, blocked = 0, error = '',
|
|
735
713
|
leased_by = NULL, leased_until = NULL, deferred_at = NULL`
|
|
@@ -742,6 +720,7 @@ var SqliteStore = class {
|
|
|
742
720
|
// unblocked streams."
|
|
743
721
|
unblock(input) {
|
|
744
722
|
return this._update(
|
|
723
|
+
"unblock",
|
|
745
724
|
Array.isArray(input) ? input : { ...input, blocked: void 0 },
|
|
746
725
|
`SET retry = -1, blocked = 0, error = '',
|
|
747
726
|
leased_by = NULL, leased_until = NULL, deferred_at = NULL`,
|
|
@@ -869,10 +848,8 @@ var SqliteStore = class {
|
|
|
869
848
|
limit
|
|
870
849
|
);
|
|
871
850
|
}
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
* `(stream, version)` unique index. Parallel queries when tail set.
|
|
875
|
-
*/
|
|
851
|
+
// Cheap path — head (and optional tail) via ROW_NUMBER() over the
|
|
852
|
+
// `(stream, version)` unique index. Parallel queries when tail set.
|
|
876
853
|
async _query_stats_heads_only(from_clause, where_clause, args, want_tail, limit) {
|
|
877
854
|
const cols = `e.id, e.stream, e.version, e.name, e.data, e.created, e.meta`;
|
|
878
855
|
const limit_clause = limit !== void 0 ? " LIMIT ?" : "";
|
|
@@ -912,11 +889,9 @@ var SqliteStore = class {
|
|
|
912
889
|
}
|
|
913
890
|
return out;
|
|
914
891
|
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
* on the same scan.
|
|
919
|
-
*/
|
|
892
|
+
// Full-scan path — one CTE-based query with per-stream `COUNT(*)` and
|
|
893
|
+
// `json_group_object(name, n)`. Heads (and optional tails) ride free
|
|
894
|
+
// on the same scan.
|
|
920
895
|
async _query_stats_full_scan(from_clause, where_clause, args, want_tail, want_count, want_names, limit) {
|
|
921
896
|
const tail_cte = want_tail ? `, tails AS (
|
|
922
897
|
SELECT * FROM (
|
|
@@ -980,6 +955,7 @@ var SqliteStore = class {
|
|
|
980
955
|
// --- prioritize: bulk priority update with filter ---
|
|
981
956
|
prioritize(filter, priority) {
|
|
982
957
|
return this._update(
|
|
958
|
+
"prioritize",
|
|
983
959
|
filter,
|
|
984
960
|
"SET priority = ?",
|
|
985
961
|
[priority, priority],
|