@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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @pluv/persistence-cloudflare-transactional-storage@1.0.0 build /home/runner/work/pluv/pluv/packages/persistence-cloudflare-transactional-storage
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
  CLI Building entry: src/index.ts
@@ -8,11 +8,11 @@
8
8
  CLI Target: es6
9
9
  ESM Build start
10
10
  CJS Build start
11
- CJS dist/index.js 10.29 KB
12
- CJS ⚡️ Build success in 69ms
13
- ESM dist/index.mjs 9.23 KB
14
- ESM ⚡️ Build success in 73ms
11
+ ESM dist/index.mjs 10.28 KB
12
+ ESM ⚡️ Build success in 72ms
13
+ CJS dist/index.js 11.34 KB
14
+ CJS ⚡️ Build success in 74ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 3082ms
16
+ DTS ⚡️ Build success in 3214ms
17
17
  DTS dist/index.d.mts 1.21 KB
18
18
  DTS dist/index.d.ts 1.21 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @pluv/persistence-cloudflare-transactional-storage
2
2
 
3
+ ## 1.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [c583be9]
8
+ - @pluv/io@1.0.1
9
+ - @pluv/types@1.0.1
10
+
3
11
  ## 1.0.0
4
12
 
5
13
  ### Major Changes
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(Array.from(map.keys()), KV_CLOUDFLARE_DELETE_BATCH_LIMIT);
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(this._getUserKey(room, connectionId));
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({ prefix: `${KV_USER_PREFIX}::${room}` });
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, { allowConcurrency: true });
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(Array.from(map.keys()), KV_CLOUDFLARE_DELETE_BATCH_LIMIT);
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(this._getUserKey(room, connectionId));
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({ prefix: `${KV_USER_PREFIX}::${room}` });
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, { allowConcurrency: true });
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.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.0",
21
- "@pluv/types": "^1.0.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.0",
29
- "eslint-config-pluv": "^1.0.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(room: string, connectionId: string, user: JsonObject | null): Promise<void> {
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(Array.from(map.keys()), KV_CLOUDFLARE_DELETE_BATCH_LIMIT);
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>(this._getUserKey(room, connectionId));
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(room: string): Promise<Map<[connectionId: string][0], JsonObject | null>> {
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({ prefix: `${KV_USER_PREFIX}::${room}` });
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, { allowConcurrency: true });
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
 
@@ -1,3 +1,7 @@
1
1
  export const castNumber = (value: any): number => {
2
- return typeof value === "number" ? value : typeof value === "string" ? Number.parseInt(value, 10) : Number(value);
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>(arr: readonly T[] | T[], length: number): readonly (readonly 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);