@pluv/persistence-cloudflare-transactional-storage 1.0.0 → 1.0.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/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @pluv/persistence-cloudflare-transactional-storage@1.0.
|
|
2
|
+
> @pluv/persistence-cloudflare-transactional-storage@1.0.1 build /home/runner/work/pluv/pluv/packages/persistence-cloudflare-transactional-storage
|
|
3
3
|
> tsup src/index.ts --format esm,cjs --dts
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
[34mCLI[39m Target: es6
|
|
9
9
|
[34mESM[39m Build start
|
|
10
10
|
[34mCJS[39m Build start
|
|
11
|
-
[
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[
|
|
11
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m10.28 KB[39m
|
|
12
|
+
[32mESM[39m ⚡️ Build success in 72ms
|
|
13
|
+
[32mCJS[39m [1mdist/index.js [22m[32m11.34 KB[39m
|
|
14
|
+
[32mCJS[39m ⚡️ Build success in 74ms
|
|
15
15
|
[34mDTS[39m Build start
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 3214ms
|
|
17
17
|
[32mDTS[39m [1mdist/index.d.mts [22m[32m1.21 KB[39m
|
|
18
18
|
[32mDTS[39m [1mdist/index.d.ts [22m[32m1.21 KB[39m
|
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -84,6 +84,7 @@ var PersistenceCloudflareTransactionalStorage = class extends import_io.Abstract
|
|
|
84
84
|
}
|
|
85
85
|
addUser(room, connectionId, user) {
|
|
86
86
|
return __async(this, null, function* () {
|
|
87
|
+
var _a, _b;
|
|
87
88
|
if (!this._initialized) return;
|
|
88
89
|
if (!this._state) return;
|
|
89
90
|
yield this._initialized;
|
|
@@ -91,6 +92,16 @@ var PersistenceCloudflareTransactionalStorage = class extends import_io.Abstract
|
|
|
91
92
|
yield this._state.storage.put(this._getUserKey(room, connectionId), user);
|
|
92
93
|
return;
|
|
93
94
|
}
|
|
95
|
+
const result = this._state.storage.sql.exec(
|
|
96
|
+
sql`
|
|
97
|
+
SELECT id
|
|
98
|
+
FROM ${SQLITE_USER_TABLE}
|
|
99
|
+
WHERE id = ?;
|
|
100
|
+
`,
|
|
101
|
+
connectionId
|
|
102
|
+
);
|
|
103
|
+
const existing = !!((_b = (_a = result.toArray()[0]) == null ? void 0 : _a.count) != null ? _b : 0);
|
|
104
|
+
if (existing) return;
|
|
94
105
|
this._state.storage.sql.exec(
|
|
95
106
|
sql`
|
|
96
107
|
INSERT INTO ${SQLITE_USER_TABLE} VALUES (?, ?, ?);
|
|
@@ -150,7 +161,10 @@ var PersistenceCloudflareTransactionalStorage = class extends import_io.Abstract
|
|
|
150
161
|
noCache: true,
|
|
151
162
|
prefix: `${KV_USER_PREFIX}::${room}`
|
|
152
163
|
});
|
|
153
|
-
const partitions = partitionByLength(
|
|
164
|
+
const partitions = partitionByLength(
|
|
165
|
+
Array.from(map.keys()),
|
|
166
|
+
KV_CLOUDFLARE_DELETE_BATCH_LIMIT
|
|
167
|
+
);
|
|
154
168
|
yield this._state.storage.transaction((tx) => __async(this, null, function* () {
|
|
155
169
|
yield partitions.reduce((promise, partition) => __async(this, null, function* () {
|
|
156
170
|
yield promise;
|
|
@@ -199,7 +213,9 @@ var PersistenceCloudflareTransactionalStorage = class extends import_io.Abstract
|
|
|
199
213
|
if (!this._state) return null;
|
|
200
214
|
yield this._initialized;
|
|
201
215
|
if (this._mode === "kv") {
|
|
202
|
-
const user = yield this._state.storage.get(
|
|
216
|
+
const user = yield this._state.storage.get(
|
|
217
|
+
this._getUserKey(room, connectionId)
|
|
218
|
+
);
|
|
203
219
|
return user != null ? user : null;
|
|
204
220
|
}
|
|
205
221
|
const cursor = this._state.storage.sql.exec(
|
|
@@ -259,7 +275,9 @@ var PersistenceCloudflareTransactionalStorage = class extends import_io.Abstract
|
|
|
259
275
|
if (!this._state) return 0;
|
|
260
276
|
yield this._initialized;
|
|
261
277
|
if (this._mode) {
|
|
262
|
-
const storage = yield this._state.storage.list({
|
|
278
|
+
const storage = yield this._state.storage.list({
|
|
279
|
+
prefix: `${KV_USER_PREFIX}::${room}`
|
|
280
|
+
});
|
|
263
281
|
return storage.size;
|
|
264
282
|
}
|
|
265
283
|
const cursor = this._state.storage.sql.exec(
|
|
@@ -302,11 +320,35 @@ var PersistenceCloudflareTransactionalStorage = class extends import_io.Abstract
|
|
|
302
320
|
}
|
|
303
321
|
setStorageState(room, state) {
|
|
304
322
|
return __async(this, null, function* () {
|
|
323
|
+
var _a, _b;
|
|
305
324
|
if (!this._initialized) return;
|
|
306
325
|
if (!this._state) return;
|
|
307
326
|
yield this._initialized;
|
|
308
327
|
if (this._mode === "kv") {
|
|
309
|
-
yield this._state.storage.put(this._getStorageKey(room), state, {
|
|
328
|
+
yield this._state.storage.put(this._getStorageKey(room), state, {
|
|
329
|
+
allowConcurrency: true
|
|
330
|
+
});
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const result = this._state.storage.sql.exec(
|
|
334
|
+
sql`
|
|
335
|
+
SELECT COUNT(*) as count
|
|
336
|
+
FROM ${SQLITE_STORAGE_TABLE}
|
|
337
|
+
WHERE room = ?;
|
|
338
|
+
`,
|
|
339
|
+
room
|
|
340
|
+
);
|
|
341
|
+
const existing = !!((_b = (_a = result.toArray()[0]) == null ? void 0 : _a.count) != null ? _b : 0);
|
|
342
|
+
if (existing) {
|
|
343
|
+
this._state.storage.sql.exec(
|
|
344
|
+
sql`
|
|
345
|
+
UPDATE ${SQLITE_STORAGE_TABLE}
|
|
346
|
+
SET data = ?
|
|
347
|
+
WHERE room = ?;
|
|
348
|
+
`,
|
|
349
|
+
state,
|
|
350
|
+
room
|
|
351
|
+
);
|
|
310
352
|
return;
|
|
311
353
|
}
|
|
312
354
|
this._state.storage.sql.exec(
|
package/dist/index.mjs
CHANGED
|
@@ -59,6 +59,7 @@ var PersistenceCloudflareTransactionalStorage = class extends AbstractPersistenc
|
|
|
59
59
|
}
|
|
60
60
|
addUser(room, connectionId, user) {
|
|
61
61
|
return __async(this, null, function* () {
|
|
62
|
+
var _a, _b;
|
|
62
63
|
if (!this._initialized) return;
|
|
63
64
|
if (!this._state) return;
|
|
64
65
|
yield this._initialized;
|
|
@@ -66,6 +67,16 @@ var PersistenceCloudflareTransactionalStorage = class extends AbstractPersistenc
|
|
|
66
67
|
yield this._state.storage.put(this._getUserKey(room, connectionId), user);
|
|
67
68
|
return;
|
|
68
69
|
}
|
|
70
|
+
const result = this._state.storage.sql.exec(
|
|
71
|
+
sql`
|
|
72
|
+
SELECT id
|
|
73
|
+
FROM ${SQLITE_USER_TABLE}
|
|
74
|
+
WHERE id = ?;
|
|
75
|
+
`,
|
|
76
|
+
connectionId
|
|
77
|
+
);
|
|
78
|
+
const existing = !!((_b = (_a = result.toArray()[0]) == null ? void 0 : _a.count) != null ? _b : 0);
|
|
79
|
+
if (existing) return;
|
|
69
80
|
this._state.storage.sql.exec(
|
|
70
81
|
sql`
|
|
71
82
|
INSERT INTO ${SQLITE_USER_TABLE} VALUES (?, ?, ?);
|
|
@@ -125,7 +136,10 @@ var PersistenceCloudflareTransactionalStorage = class extends AbstractPersistenc
|
|
|
125
136
|
noCache: true,
|
|
126
137
|
prefix: `${KV_USER_PREFIX}::${room}`
|
|
127
138
|
});
|
|
128
|
-
const partitions = partitionByLength(
|
|
139
|
+
const partitions = partitionByLength(
|
|
140
|
+
Array.from(map.keys()),
|
|
141
|
+
KV_CLOUDFLARE_DELETE_BATCH_LIMIT
|
|
142
|
+
);
|
|
129
143
|
yield this._state.storage.transaction((tx) => __async(this, null, function* () {
|
|
130
144
|
yield partitions.reduce((promise, partition) => __async(this, null, function* () {
|
|
131
145
|
yield promise;
|
|
@@ -174,7 +188,9 @@ var PersistenceCloudflareTransactionalStorage = class extends AbstractPersistenc
|
|
|
174
188
|
if (!this._state) return null;
|
|
175
189
|
yield this._initialized;
|
|
176
190
|
if (this._mode === "kv") {
|
|
177
|
-
const user = yield this._state.storage.get(
|
|
191
|
+
const user = yield this._state.storage.get(
|
|
192
|
+
this._getUserKey(room, connectionId)
|
|
193
|
+
);
|
|
178
194
|
return user != null ? user : null;
|
|
179
195
|
}
|
|
180
196
|
const cursor = this._state.storage.sql.exec(
|
|
@@ -234,7 +250,9 @@ var PersistenceCloudflareTransactionalStorage = class extends AbstractPersistenc
|
|
|
234
250
|
if (!this._state) return 0;
|
|
235
251
|
yield this._initialized;
|
|
236
252
|
if (this._mode) {
|
|
237
|
-
const storage = yield this._state.storage.list({
|
|
253
|
+
const storage = yield this._state.storage.list({
|
|
254
|
+
prefix: `${KV_USER_PREFIX}::${room}`
|
|
255
|
+
});
|
|
238
256
|
return storage.size;
|
|
239
257
|
}
|
|
240
258
|
const cursor = this._state.storage.sql.exec(
|
|
@@ -277,11 +295,35 @@ var PersistenceCloudflareTransactionalStorage = class extends AbstractPersistenc
|
|
|
277
295
|
}
|
|
278
296
|
setStorageState(room, state) {
|
|
279
297
|
return __async(this, null, function* () {
|
|
298
|
+
var _a, _b;
|
|
280
299
|
if (!this._initialized) return;
|
|
281
300
|
if (!this._state) return;
|
|
282
301
|
yield this._initialized;
|
|
283
302
|
if (this._mode === "kv") {
|
|
284
|
-
yield this._state.storage.put(this._getStorageKey(room), state, {
|
|
303
|
+
yield this._state.storage.put(this._getStorageKey(room), state, {
|
|
304
|
+
allowConcurrency: true
|
|
305
|
+
});
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
const result = this._state.storage.sql.exec(
|
|
309
|
+
sql`
|
|
310
|
+
SELECT COUNT(*) as count
|
|
311
|
+
FROM ${SQLITE_STORAGE_TABLE}
|
|
312
|
+
WHERE room = ?;
|
|
313
|
+
`,
|
|
314
|
+
room
|
|
315
|
+
);
|
|
316
|
+
const existing = !!((_b = (_a = result.toArray()[0]) == null ? void 0 : _a.count) != null ? _b : 0);
|
|
317
|
+
if (existing) {
|
|
318
|
+
this._state.storage.sql.exec(
|
|
319
|
+
sql`
|
|
320
|
+
UPDATE ${SQLITE_STORAGE_TABLE}
|
|
321
|
+
SET data = ?
|
|
322
|
+
WHERE room = ?;
|
|
323
|
+
`,
|
|
324
|
+
state,
|
|
325
|
+
room
|
|
326
|
+
);
|
|
285
327
|
return;
|
|
286
328
|
}
|
|
287
329
|
this._state.storage.sql.exec(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/persistence-cloudflare-transactional-storage",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "@pluv/io crdt storage persistence for cloudflare via transactional storage",
|
|
5
5
|
"author": "leedavidcs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,16 +17,16 @@
|
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@pluv/io": "^1.0.
|
|
21
|
-
"@pluv/types": "^1.0.
|
|
20
|
+
"@pluv/io": "^1.0.1",
|
|
21
|
+
"@pluv/types": "^1.0.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@cloudflare/workers-types": "^4.20250430.0",
|
|
25
25
|
"eslint": "^9.25.1",
|
|
26
26
|
"tsup": "^8.4.0",
|
|
27
27
|
"typescript": "^5.8.3",
|
|
28
|
-
"@pluv/tsconfig": "^1.0.
|
|
29
|
-
"eslint-config-pluv": "^1.0.
|
|
28
|
+
"@pluv/tsconfig": "^1.0.1",
|
|
29
|
+
"eslint-config-pluv": "^1.0.1"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
@@ -31,7 +31,11 @@ export class PersistenceCloudflareTransactionalStorage extends AbstractPersisten
|
|
|
31
31
|
this._mode = mode;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
public async addUser(
|
|
34
|
+
public async addUser(
|
|
35
|
+
room: string,
|
|
36
|
+
connectionId: string,
|
|
37
|
+
user: JsonObject | null,
|
|
38
|
+
): Promise<void> {
|
|
35
39
|
if (!this._initialized) return;
|
|
36
40
|
if (!this._state) return;
|
|
37
41
|
|
|
@@ -42,6 +46,19 @@ export class PersistenceCloudflareTransactionalStorage extends AbstractPersisten
|
|
|
42
46
|
return;
|
|
43
47
|
}
|
|
44
48
|
|
|
49
|
+
const result = this._state.storage.sql.exec<{ count: 0 }>(
|
|
50
|
+
sql`
|
|
51
|
+
SELECT id
|
|
52
|
+
FROM ${SQLITE_USER_TABLE}
|
|
53
|
+
WHERE id = ?;
|
|
54
|
+
`,
|
|
55
|
+
connectionId,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const existing = !!(result.toArray()[0]?.count ?? 0);
|
|
59
|
+
|
|
60
|
+
if (existing) return;
|
|
61
|
+
|
|
45
62
|
this._state.storage.sql.exec(
|
|
46
63
|
sql`
|
|
47
64
|
INSERT INTO ${SQLITE_USER_TABLE} VALUES (?, ?, ?);
|
|
@@ -108,7 +125,10 @@ export class PersistenceCloudflareTransactionalStorage extends AbstractPersisten
|
|
|
108
125
|
prefix: `${KV_USER_PREFIX}::${room}`,
|
|
109
126
|
});
|
|
110
127
|
|
|
111
|
-
const partitions = partitionByLength(
|
|
128
|
+
const partitions = partitionByLength(
|
|
129
|
+
Array.from(map.keys()),
|
|
130
|
+
KV_CLOUDFLARE_DELETE_BATCH_LIMIT,
|
|
131
|
+
);
|
|
112
132
|
|
|
113
133
|
await this._state.storage.transaction(async (tx) => {
|
|
114
134
|
await partitions.reduce(async (promise, partition) => {
|
|
@@ -165,7 +185,9 @@ export class PersistenceCloudflareTransactionalStorage extends AbstractPersisten
|
|
|
165
185
|
await this._initialized;
|
|
166
186
|
|
|
167
187
|
if (this._mode === "kv") {
|
|
168
|
-
const user = await this._state.storage.get<JsonObject | null>(
|
|
188
|
+
const user = await this._state.storage.get<JsonObject | null>(
|
|
189
|
+
this._getUserKey(room, connectionId),
|
|
190
|
+
);
|
|
169
191
|
|
|
170
192
|
return user ?? null;
|
|
171
193
|
}
|
|
@@ -191,7 +213,9 @@ export class PersistenceCloudflareTransactionalStorage extends AbstractPersisten
|
|
|
191
213
|
}
|
|
192
214
|
}
|
|
193
215
|
|
|
194
|
-
public async getUsers(
|
|
216
|
+
public async getUsers(
|
|
217
|
+
room: string,
|
|
218
|
+
): Promise<Map<[connectionId: string][0], JsonObject | null>> {
|
|
195
219
|
if (!this._initialized) return new Map();
|
|
196
220
|
if (!this._state) return new Map();
|
|
197
221
|
|
|
@@ -238,7 +262,9 @@ export class PersistenceCloudflareTransactionalStorage extends AbstractPersisten
|
|
|
238
262
|
await this._initialized;
|
|
239
263
|
|
|
240
264
|
if (this._mode) {
|
|
241
|
-
const storage = await this._state.storage.list({
|
|
265
|
+
const storage = await this._state.storage.list({
|
|
266
|
+
prefix: `${KV_USER_PREFIX}::${room}`,
|
|
267
|
+
});
|
|
242
268
|
|
|
243
269
|
return storage.size;
|
|
244
270
|
}
|
|
@@ -295,7 +321,34 @@ export class PersistenceCloudflareTransactionalStorage extends AbstractPersisten
|
|
|
295
321
|
await this._initialized;
|
|
296
322
|
|
|
297
323
|
if (this._mode === "kv") {
|
|
298
|
-
await this._state.storage.put(this._getStorageKey(room), state, {
|
|
324
|
+
await this._state.storage.put(this._getStorageKey(room), state, {
|
|
325
|
+
allowConcurrency: true,
|
|
326
|
+
});
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const result = this._state.storage.sql.exec<{ count: number }>(
|
|
331
|
+
sql`
|
|
332
|
+
SELECT COUNT(*) as count
|
|
333
|
+
FROM ${SQLITE_STORAGE_TABLE}
|
|
334
|
+
WHERE room = ?;
|
|
335
|
+
`,
|
|
336
|
+
room,
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
const existing = !!(result.toArray()[0]?.count ?? 0);
|
|
340
|
+
|
|
341
|
+
if (existing) {
|
|
342
|
+
this._state.storage.sql.exec(
|
|
343
|
+
sql`
|
|
344
|
+
UPDATE ${SQLITE_STORAGE_TABLE}
|
|
345
|
+
SET data = ?
|
|
346
|
+
WHERE room = ?;
|
|
347
|
+
`,
|
|
348
|
+
state,
|
|
349
|
+
room,
|
|
350
|
+
);
|
|
351
|
+
|
|
299
352
|
return;
|
|
300
353
|
}
|
|
301
354
|
|
package/src/utils/castNumber.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
export const castNumber = (value: any): number => {
|
|
2
|
-
return typeof value === "number"
|
|
2
|
+
return typeof value === "number"
|
|
3
|
+
? value
|
|
4
|
+
: typeof value === "string"
|
|
5
|
+
? Number.parseInt(value, 10)
|
|
6
|
+
: Number(value);
|
|
3
7
|
};
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
export const partitionByLength = <T>(
|
|
1
|
+
export const partitionByLength = <T>(
|
|
2
|
+
arr: readonly T[] | T[],
|
|
3
|
+
length: number,
|
|
4
|
+
): readonly (readonly T[])[] => {
|
|
2
5
|
if (!arr.length) return [];
|
|
3
6
|
|
|
4
7
|
const head = arr.slice(0, length);
|