@pluv/persistence-cloudflare-transactional-storage 5.0.0 → 5.0.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.
package/dist/index.d.mts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { AbstractPersistence } from "@pluv/io";
2
2
  import { JsonObject } from "@pluv/types";
3
-
4
3
  //#region src/PersistenceCloudflareTransactionalStorage.d.ts
5
4
  interface PersistenceCloudflareTransactionalStorageConfig {
6
5
  mode: "kv" | "sqlite";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/PersistenceCloudflareTransactionalStorage.ts"],"mappings":";;;;UAiBiB,+CAAA;EACb,IAAI;AAAA;AAAA,cAEK,yCAAA,SAAkD,mBAAA;EAAA,QACnD,KAAA;EAAA,QACA,MAAA;EAAA,QACA,YAAA;cAEI,MAAA,EAAQ,+CAAA;EASP,OAAA,CACT,IAAA,UACA,YAAA,UACA,IAAA,EAAM,UAAA,UACP,OAAA;EAkCU,kBAAA,CAAmB,IAAA,WAAe,OAAA;EAoBlC,UAAA,CAAW,IAAA,UAAc,YAAA,WAAuB,OAAA;EAuBhD,WAAA,CAAY,IAAA,WAAe,OAAA;EAqC3B,eAAA,CAAgB,IAAA,WAAe,OAAA;EA6B/B,OAAA,CAAQ,IAAA,UAAc,YAAA,WAAuB,OAAA,CAAQ,UAAA;EAmCrD,QAAA,CACT,IAAA,WACD,OAAA,CAAQ,GAAA,EAAK,YAAA,cAA0B,UAAA;EAwC7B,YAAA,CAAa,IAAA,WAAe,OAAA;EAgClC,UAAA,CAAW,WAAA;IAAe,KAAA,EAAO,kBAAA;EAAA;EA8B3B,eAAA,CAAgB,IAAA,UAAc,KAAA,WAAgB,OAAA;EAAA,QA+CnD,cAAA;EAAA,QAQA,WAAA;AAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/PersistenceCloudflareTransactionalStorage.ts"],"mappings":";;;UAiBiB;EACb;;cAES,kDAAkD;UACnD;UACA;UACA;EAEI,YAAA,QAAQ;EASP,QACT,cACA,sBACA,MAAM,oBACP;EAkCU,mBAAmB,eAAe;EAoBlC,WAAW,cAAc,uBAAuB;EAuBhD,YAAY,eAAe;EAqC3B,gBAAgB,eAAe;EA6B/B,QAAQ,cAAc,uBAAuB,QAAQ;EAmCrD,SACT,eACD,QAAQ,KAAK,0BAA0B;EAwC7B,aAAa,eAAe;EAgClC,WAAW;IAAe,OAAO;;EA8B3B,gBAAgB,cAAc,gBAAgB;UA+CnD;UAQA"}
package/dist/index.mjs CHANGED
@@ -7,7 +7,9 @@ const castNumber = (value) => {
7
7
  //#region src/utils/partitionByLength.ts
8
8
  const partitionByLength = (arr, length) => {
9
9
  if (!arr.length) return [];
10
- return [arr.slice(0, length), ...partitionByLength(arr.slice(length), length)];
10
+ const head = arr.slice(0, length);
11
+ const tail = arr.slice(length);
12
+ return [head, ...partitionByLength(tail, length)];
11
13
  };
12
14
  //#endregion
13
15
  //#region src/utils/sql.ts
@@ -173,7 +175,8 @@ var PersistenceCloudflareTransactionalStorage = class PersistenceCloudflareTrans
173
175
  WHERE room = ?;
174
176
  `, room);
175
177
  try {
176
- return castNumber(cursor.one().count);
178
+ const result = cursor.one();
179
+ return castNumber(result.count);
177
180
  } catch {
178
181
  return 0;
179
182
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/utils/castNumber.ts","../src/utils/partitionByLength.ts","../src/utils/sql.ts","../src/PersistenceCloudflareTransactionalStorage.ts"],"sourcesContent":["export const castNumber = (value: any): number => {\n return typeof value === \"number\"\n ? value\n : typeof value === \"string\"\n ? Number.parseInt(value, 10)\n : Number(value);\n};\n","export const partitionByLength = <T>(\n arr: readonly T[] | T[],\n length: number,\n): readonly (readonly T[])[] => {\n if (!arr.length) return [];\n\n const head = arr.slice(0, length);\n const tail = arr.slice(length);\n\n return [head, ...partitionByLength(tail, length)];\n};\n","export const sql = (strings: TemplateStringsArray, ...values: any[]): string => {\n return strings\n .reduce((result, str, i) => {\n // Compresses the string to a single line (not including the interpolated values)\n const cleaned = str.replace(/(\\n[ \\t]*)+/g, \" \");\n\n return result + cleaned + (i < values.length ? values[i] : \"\");\n }, \"\")\n .trim();\n};\n","import { AbstractPersistence } from \"@pluv/io\";\nimport type { JsonObject } from \"@pluv/types\";\nimport { castNumber, partitionByLength, sql } from \"./utils\";\n\n/**\n * !HACK\n * @description The max amount of keys a Cloudflare transactional storage may delete at once\n * @see https://developers.cloudflare.com/durable-objects/api/transactional-storage-api/#delete\n * @date July 8, 2024\n */\nconst KV_CLOUDFLARE_DELETE_BATCH_LIMIT = 128;\nconst KV_STORAGE_PREFIX = \"$PLUV_STORAGE;\";\nconst KV_USER_PREFIX = \"$PLUV_USER\";\n\nconst SQLITE_STORAGE_TABLE = \"__pluv_storage\";\nconst SQLITE_USER_TABLE = \"__pluv_user\";\n\nexport interface PersistenceCloudflareTransactionalStorageConfig {\n mode: \"kv\" | \"sqlite\";\n}\nexport class PersistenceCloudflareTransactionalStorage extends AbstractPersistence {\n private _mode: \"kv\" | \"sqlite\";\n private _state: DurableObjectState | null = null;\n private _initialized: Promise<true> | null = null;\n\n constructor(config: PersistenceCloudflareTransactionalStorageConfig) {\n super();\n\n const { mode } = config;\n\n this._initialized = (config as any)._initialized;\n this._mode = mode;\n }\n\n public async addUser(\n room: string,\n connectionId: string,\n user: JsonObject | null,\n ): Promise<void> {\n if (!this._initialized) return;\n if (!this._state) return;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n await this._state.storage.put(this._getUserKey(room, connectionId), user);\n return;\n }\n\n const result = this._state.storage.sql.exec<{ count: 0 }>(\n sql`\n SELECT id\n FROM ${SQLITE_USER_TABLE}\n WHERE id = ?;\n `,\n connectionId,\n );\n\n const existing = !!(result.toArray()[0]?.count ?? 0);\n\n if (existing) return;\n\n this._state.storage.sql.exec(\n sql`\n INSERT INTO ${SQLITE_USER_TABLE} VALUES (?, ?, ?);\n `,\n connectionId,\n JSON.stringify(user),\n room,\n );\n }\n\n public async deleteStorageState(room: string): Promise<void> {\n if (!this._initialized) return;\n if (!this._state) return;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n await this._state.storage.delete(this._getStorageKey(room));\n return;\n }\n\n this._state.storage.sql.exec(\n sql`\n DELETE FROM ${SQLITE_STORAGE_TABLE}\n WHERE room = ?;\n `,\n room,\n );\n }\n\n public async deleteUser(room: string, connectionId: string): Promise<void> {\n if (!this._initialized) return;\n if (!this._state) return;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n await this._state.storage.delete(this._getUserKey(room, connectionId));\n\n return;\n }\n\n this._state.storage.sql.exec(\n sql`\n DELETE FROM ${SQLITE_USER_TABLE}\n WHERE room = ?\n AND id = ?;\n `,\n room,\n connectionId,\n );\n }\n\n public async deleteUsers(room: string): Promise<void> {\n if (!this._initialized) return;\n if (!this._state) return;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n const map = await this._state.storage.list({\n allowConcurrency: true,\n noCache: true,\n prefix: `${KV_USER_PREFIX}::${room}`,\n });\n\n const partitions = partitionByLength(\n Array.from(map.keys()),\n KV_CLOUDFLARE_DELETE_BATCH_LIMIT,\n );\n\n await this._state.storage.transaction(async (tx) => {\n await partitions.reduce(async (promise, partition) => {\n await promise;\n await tx.delete(partition as string[]);\n }, Promise.resolve());\n });\n\n return;\n }\n\n this._state.storage.sql.exec(\n sql`\n DELETE FROM ${SQLITE_USER_TABLE}\n WHERE room = ?;\n `,\n room,\n );\n }\n\n public async getStorageState(room: string): Promise<string | null> {\n if (!this._initialized) return null;\n if (!this._state) return null;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n const storage = await this._state.storage.get<string>(this._getStorageKey(room));\n return storage ?? null;\n }\n\n const cursor = this._state.storage.sql.exec<{ room: string; data: string }>(\n sql`\n SELECT room, data\n FROM ${SQLITE_STORAGE_TABLE}\n WHERE room = ?;\n `,\n room,\n );\n\n try {\n const result = cursor.one();\n\n return result.data;\n } catch {\n return null;\n }\n }\n\n public async getUser(room: string, connectionId: string): Promise<JsonObject | null> {\n if (!this._initialized) return null;\n if (!this._state) return null;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n const user = await this._state.storage.get<JsonObject | null>(\n this._getUserKey(room, connectionId),\n );\n\n return user ?? null;\n }\n\n const cursor = this._state.storage.sql.exec<{ id: string; data: string; room: string }>(\n sql`\n SELECT id, data, room\n FROM ${SQLITE_USER_TABLE}\n WHERE room = ?\n AND id = ?;\n `,\n room,\n connectionId,\n );\n\n try {\n const result = cursor.one();\n const user = JSON.parse(result.data);\n\n return user;\n } catch {\n return null;\n }\n }\n\n public async getUsers(\n room: string,\n ): Promise<Map<[connectionId: string][0], JsonObject | null>> {\n if (!this._initialized) return new Map();\n if (!this._state) return new Map();\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n const entries = await this._state.storage\n .list<JsonObject | null>({\n prefix: `${KV_USER_PREFIX}::${room}`,\n })\n .then((map) => Array.from(map.entries()));\n\n return entries.reduce((map, [key, user]) => {\n const connectionId = key.split(\"::\").slice(-1)[0];\n\n return !!connectionId ? map.set(connectionId, user) : map;\n }, new Map<string, JsonObject | null>());\n }\n\n const cursor = this._state.storage.sql.exec<{ id: string; data: string; room: string }>(\n sql`\n SELECT id, room, data\n FROM ${SQLITE_USER_TABLE}\n WHERE room = ?;\n `,\n room,\n );\n\n return cursor.toArray().reduce((map, { id, data }) => {\n try {\n const user = JSON.parse(data) as JsonObject;\n\n return map.set(id, user);\n } catch {\n return map;\n }\n }, new Map<string, JsonObject | null>());\n }\n\n public async getUsersSize(room: string): Promise<number> {\n if (!this._initialized) return 0;\n if (!this._state) return 0;\n\n await this._initialized;\n\n if (this._mode) {\n const storage = await this._state.storage.list({\n prefix: `${KV_USER_PREFIX}::${room}`,\n });\n\n return storage.size;\n }\n\n const cursor = this._state.storage.sql.exec<{ count: number }>(\n sql`\n SELECT COUNT(*) count\n FROM ${SQLITE_USER_TABLE}\n WHERE room = ?;\n `,\n room,\n );\n\n try {\n const result = cursor.one();\n\n return castNumber(result.count);\n } catch {\n return 0;\n }\n }\n\n public initialize(roomContext: { state: DurableObjectState }): typeof this {\n const initialized = (async () => {\n const { state } = roomContext;\n\n this._state = state;\n\n if (this._mode === \"sqlite\") {\n this._state.storage.sql.exec(sql`\n CREATE TABLE IF NOT EXISTS ${SQLITE_STORAGE_TABLE}(\n room TEXT PRIMARY KEY,\n data TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS ${SQLITE_USER_TABLE}(\n id TEXT PRIMARY KEY,\n data TEXT NOT NULL,\n room TEXT NOT NULL\n );\n CREATE INDEX IF NOT EXISTS ${SQLITE_USER_TABLE}_room ON ${SQLITE_USER_TABLE}(room);\n `);\n }\n\n return true as const;\n })();\n\n return new PersistenceCloudflareTransactionalStorage({\n mode: this._mode,\n ...{ _initialized: initialized },\n }) as typeof this;\n }\n\n public async setStorageState(room: string, state: string): Promise<void> {\n if (!this._initialized) return;\n if (!this._state) return;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n await this._state.storage.put(this._getStorageKey(room), state, {\n allowConcurrency: true,\n });\n return;\n }\n\n const result = this._state.storage.sql.exec<{ count: number }>(\n sql`\n SELECT COUNT(*) as count\n FROM ${SQLITE_STORAGE_TABLE}\n WHERE room = ?;\n `,\n room,\n );\n\n const existing = !!(result.toArray()[0]?.count ?? 0);\n\n if (existing) {\n this._state.storage.sql.exec(\n sql`\n UPDATE ${SQLITE_STORAGE_TABLE}\n SET data = ?\n WHERE room = ?;\n `,\n state,\n room,\n );\n\n return;\n }\n\n this._state.storage.sql.exec(\n sql`\n INSERT INTO ${SQLITE_STORAGE_TABLE} VALUES (?, ?);\n `,\n room,\n state,\n );\n }\n\n private _getStorageKey(room: string): string {\n if (this._mode === \"sqlite\") {\n throw new Error(\"Attempted to get kv key for sqlite storage\");\n }\n\n return `${KV_STORAGE_PREFIX}::${room}`;\n }\n\n private _getUserKey(room: string, connectionId: string): string {\n if (this._mode === \"sqlite\") {\n throw new Error(\"Attempted to get kv key for sqlite storage\");\n }\n\n return `${KV_USER_PREFIX}::${room}::${connectionId}`;\n }\n}\n"],"mappings":";;AAAA,MAAa,cAAc,UAAuB;CAC9C,OAAO,OAAO,UAAU,WAClB,QACA,OAAO,UAAU,WACf,OAAO,SAAS,OAAO,EAAE,IACzB,OAAO,KAAK;AACxB;;;ACNA,MAAa,qBACT,KACA,WAC4B;CAC5B,IAAI,CAAC,IAAI,QAAQ,OAAO,CAAC;CAKzB,OAAO,CAHM,IAAI,MAAM,GAAG,MAGf,GAAG,GAAG,kBAFJ,IAAI,MAAM,MAEe,GAAG,MAAM,CAAC;AACpD;;;ACVA,MAAa,OAAO,SAA+B,GAAG,WAA0B;CAC5E,OAAO,QACF,QAAQ,QAAQ,KAAK,MAAM;EAIxB,OAAO,SAFS,IAAI,QAAQ,gBAAgB,GAEtB,KAAK,IAAI,OAAO,SAAS,OAAO,KAAK;CAC/D,GAAG,EAAE,CAAC,CACL,KAAK;AACd;;;;;;;;;ACCA,MAAM,mCAAmC;AACzC,MAAM,oBAAoB;AAC1B,MAAM,iBAAiB;AAEvB,MAAM,uBAAuB;AAC7B,MAAM,oBAAoB;AAK1B,IAAa,4CAAb,MAAa,kDAAkD,oBAAoB;CAC/E;CACA,SAA4C;CAC5C,eAA6C;CAE7C,YAAY,QAAyD;EACjE,MAAM;EAEN,MAAM,EAAE,SAAS;EAEjB,KAAK,eAAgB,OAAe;EACpC,KAAK,QAAQ;CACjB;CAEA,MAAa,QACT,MACA,cACA,MACa;EACb,IAAI,CAAC,KAAK,cAAc;EACxB,IAAI,CAAC,KAAK,QAAQ;EAElB,MAAM,KAAK;EAEX,IAAI,KAAK,UAAU,MAAM;GACrB,MAAM,KAAK,OAAO,QAAQ,IAAI,KAAK,YAAY,MAAM,YAAY,GAAG,IAAI;GACxE;EACJ;EAaA,IAAI,CAFc,EATH,KAAK,OAAO,QAAQ,IAAI,KACnC,GAAG;;uBAEQ,kBAAkB;;eAG7B,YAGqB,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,SAAS,IAEpC;EAEd,KAAK,OAAO,QAAQ,IAAI,KACpB,GAAG;8BACe,kBAAkB;eAEpC,cACA,KAAK,UAAU,IAAI,GACnB,IACJ;CACJ;CAEA,MAAa,mBAAmB,MAA6B;EACzD,IAAI,CAAC,KAAK,cAAc;EACxB,IAAI,CAAC,KAAK,QAAQ;EAElB,MAAM,KAAK;EAEX,IAAI,KAAK,UAAU,MAAM;GACrB,MAAM,KAAK,OAAO,QAAQ,OAAO,KAAK,eAAe,IAAI,CAAC;GAC1D;EACJ;EAEA,KAAK,OAAO,QAAQ,IAAI,KACpB,GAAG;8BACe,qBAAqB;;eAGvC,IACJ;CACJ;CAEA,MAAa,WAAW,MAAc,cAAqC;EACvE,IAAI,CAAC,KAAK,cAAc;EACxB,IAAI,CAAC,KAAK,QAAQ;EAElB,MAAM,KAAK;EAEX,IAAI,KAAK,UAAU,MAAM;GACrB,MAAM,KAAK,OAAO,QAAQ,OAAO,KAAK,YAAY,MAAM,YAAY,CAAC;GAErE;EACJ;EAEA,KAAK,OAAO,QAAQ,IAAI,KACpB,GAAG;8BACe,kBAAkB;;;eAIpC,MACA,YACJ;CACJ;CAEA,MAAa,YAAY,MAA6B;EAClD,IAAI,CAAC,KAAK,cAAc;EACxB,IAAI,CAAC,KAAK,QAAQ;EAElB,MAAM,KAAK;EAEX,IAAI,KAAK,UAAU,MAAM;GACrB,MAAM,MAAM,MAAM,KAAK,OAAO,QAAQ,KAAK;IACvC,kBAAkB;IAClB,SAAS;IACT,QAAQ,GAAG,eAAe,IAAI;GAClC,CAAC;GAED,MAAM,aAAa,kBACf,MAAM,KAAK,IAAI,KAAK,CAAC,GACrB,gCACJ;GAEA,MAAM,KAAK,OAAO,QAAQ,YAAY,OAAO,OAAO;IAChD,MAAM,WAAW,OAAO,OAAO,SAAS,cAAc;KAClD,MAAM;KACN,MAAM,GAAG,OAAO,SAAqB;IACzC,GAAG,QAAQ,QAAQ,CAAC;GACxB,CAAC;GAED;EACJ;EAEA,KAAK,OAAO,QAAQ,IAAI,KACpB,GAAG;8BACe,kBAAkB;;eAGpC,IACJ;CACJ;CAEA,MAAa,gBAAgB,MAAsC;EAC/D,IAAI,CAAC,KAAK,cAAc,OAAO;EAC/B,IAAI,CAAC,KAAK,QAAQ,OAAO;EAEzB,MAAM,KAAK;EAEX,IAAI,KAAK,UAAU,MAEf,OAAO,MADe,KAAK,OAAO,QAAQ,IAAY,KAAK,eAAe,IAAI,CAAC,KAC7D;EAGtB,MAAM,SAAS,KAAK,OAAO,QAAQ,IAAI,KACnC,GAAG;;uBAEQ,qBAAqB;;eAGhC,IACJ;EAEA,IAAI;GAGA,OAFe,OAAO,IAEV,CAAC,CAAC;EAClB,QAAQ;GACJ,OAAO;EACX;CACJ;CAEA,MAAa,QAAQ,MAAc,cAAkD;EACjF,IAAI,CAAC,KAAK,cAAc,OAAO;EAC/B,IAAI,CAAC,KAAK,QAAQ,OAAO;EAEzB,MAAM,KAAK;EAEX,IAAI,KAAK,UAAU,MAKf,OAAO,MAJY,KAAK,OAAO,QAAQ,IACnC,KAAK,YAAY,MAAM,YAAY,CACvC,KAEe;EAGnB,MAAM,SAAS,KAAK,OAAO,QAAQ,IAAI,KACnC,GAAG;;uBAEQ,kBAAkB;;;eAI7B,MACA,YACJ;EAEA,IAAI;GACA,MAAM,SAAS,OAAO,IAAI;GAG1B,OAFa,KAAK,MAAM,OAAO,IAErB;EACd,QAAQ;GACJ,OAAO;EACX;CACJ;CAEA,MAAa,SACT,MAC0D;EAC1D,IAAI,CAAC,KAAK,cAAc,uBAAO,IAAI,IAAI;EACvC,IAAI,CAAC,KAAK,QAAQ,uBAAO,IAAI,IAAI;EAEjC,MAAM,KAAK;EAEX,IAAI,KAAK,UAAU,MAOf,QAAO,MANe,KAAK,OAAO,QAC7B,KAAwB,EACrB,QAAQ,GAAG,eAAe,IAAI,OAClC,CAAC,CAAC,CACD,MAAM,QAAQ,MAAM,KAAK,IAAI,QAAQ,CAAC,CAAC,EAAA,CAE7B,QAAQ,KAAK,CAAC,KAAK,UAAU;GACxC,MAAM,eAAe,IAAI,MAAM,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;GAE/C,OAAO,CAAC,CAAC,eAAe,IAAI,IAAI,cAAc,IAAI,IAAI;EAC1D,mBAAG,IAAI,IAA+B,CAAC;EAY3C,OATe,KAAK,OAAO,QAAQ,IAAI,KACnC,GAAG;;uBAEQ,kBAAkB;;eAG7B,IAGQ,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,KAAK,EAAE,IAAI,WAAW;GAClD,IAAI;IACA,MAAM,OAAO,KAAK,MAAM,IAAI;IAE5B,OAAO,IAAI,IAAI,IAAI,IAAI;GAC3B,QAAQ;IACJ,OAAO;GACX;EACJ,mBAAG,IAAI,IAA+B,CAAC;CAC3C;CAEA,MAAa,aAAa,MAA+B;EACrD,IAAI,CAAC,KAAK,cAAc,OAAO;EAC/B,IAAI,CAAC,KAAK,QAAQ,OAAO;EAEzB,MAAM,KAAK;EAEX,IAAI,KAAK,OAKL,QAAO,MAJe,KAAK,OAAO,QAAQ,KAAK,EAC3C,QAAQ,GAAG,eAAe,IAAI,OAClC,CAAC,EAAA,CAEc;EAGnB,MAAM,SAAS,KAAK,OAAO,QAAQ,IAAI,KACnC,GAAG;;uBAEQ,kBAAkB;;eAG7B,IACJ;EAEA,IAAI;GAGA,OAAO,WAFQ,OAAO,IAEC,CAAC,CAAC,KAAK;EAClC,QAAQ;GACJ,OAAO;EACX;CACJ;CAEA,WAAkB,aAAyD;EACvE,MAAM,eAAe,YAAY;GAC7B,MAAM,EAAE,UAAU;GAElB,KAAK,SAAS;GAEd,IAAI,KAAK,UAAU,UACf,KAAK,OAAO,QAAQ,IAAI,KAAK,GAAG;iDACC,qBAAqB;;;;iDAIrB,kBAAkB;;;;;iDAKlB,kBAAkB,WAAW,kBAAkB;iBAC/E;GAGL,OAAO;EACX,EAAA,CAAG;EAEH,OAAO,IAAI,0CAA0C;GACjD,MAAM,KAAK;GACN,cAAc;EACvB,CAAC;CACL;CAEA,MAAa,gBAAgB,MAAc,OAA8B;EACrE,IAAI,CAAC,KAAK,cAAc;EACxB,IAAI,CAAC,KAAK,QAAQ;EAElB,MAAM,KAAK;EAEX,IAAI,KAAK,UAAU,MAAM;GACrB,MAAM,KAAK,OAAO,QAAQ,IAAI,KAAK,eAAe,IAAI,GAAG,OAAO,EAC5D,kBAAkB,KACtB,CAAC;GACD;EACJ;EAaA,IAAI,CAFc,EATH,KAAK,OAAO,QAAQ,IAAI,KACnC,GAAG;;uBAEQ,qBAAqB;;eAGhC,IAGqB,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,SAAS,IAEpC;GACV,KAAK,OAAO,QAAQ,IAAI,KACpB,GAAG;6BACU,qBAAqB;;;mBAIlC,OACA,IACJ;GAEA;EACJ;EAEA,KAAK,OAAO,QAAQ,IAAI,KACpB,GAAG;8BACe,qBAAqB;eAEvC,MACA,KACJ;CACJ;CAEA,eAAuB,MAAsB;EACzC,IAAI,KAAK,UAAU,UACf,MAAM,IAAI,MAAM,4CAA4C;EAGhE,OAAO,GAAG,kBAAkB,IAAI;CACpC;CAEA,YAAoB,MAAc,cAA8B;EAC5D,IAAI,KAAK,UAAU,UACf,MAAM,IAAI,MAAM,4CAA4C;EAGhE,OAAO,GAAG,eAAe,IAAI,KAAK,IAAI;CAC1C;AACJ"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/utils/castNumber.ts","../src/utils/partitionByLength.ts","../src/utils/sql.ts","../src/PersistenceCloudflareTransactionalStorage.ts"],"sourcesContent":["export const castNumber = (value: any): number => {\n return typeof value === \"number\"\n ? value\n : typeof value === \"string\"\n ? Number.parseInt(value, 10)\n : Number(value);\n};\n","export const partitionByLength = <T>(\n arr: readonly T[] | T[],\n length: number,\n): readonly (readonly T[])[] => {\n if (!arr.length) return [];\n\n const head = arr.slice(0, length);\n const tail = arr.slice(length);\n\n return [head, ...partitionByLength(tail, length)];\n};\n","export const sql = (strings: TemplateStringsArray, ...values: any[]): string => {\n return strings\n .reduce((result, str, i) => {\n // Compresses the string to a single line (not including the interpolated values)\n const cleaned = str.replace(/(\\n[ \\t]*)+/g, \" \");\n\n return result + cleaned + (i < values.length ? values[i] : \"\");\n }, \"\")\n .trim();\n};\n","import { AbstractPersistence } from \"@pluv/io\";\nimport type { JsonObject } from \"@pluv/types\";\nimport { castNumber, partitionByLength, sql } from \"./utils\";\n\n/**\n * !HACK\n * @description The max amount of keys a Cloudflare transactional storage may delete at once\n * @see https://developers.cloudflare.com/durable-objects/api/transactional-storage-api/#delete\n * @date July 8, 2024\n */\nconst KV_CLOUDFLARE_DELETE_BATCH_LIMIT = 128;\nconst KV_STORAGE_PREFIX = \"$PLUV_STORAGE;\";\nconst KV_USER_PREFIX = \"$PLUV_USER\";\n\nconst SQLITE_STORAGE_TABLE = \"__pluv_storage\";\nconst SQLITE_USER_TABLE = \"__pluv_user\";\n\nexport interface PersistenceCloudflareTransactionalStorageConfig {\n mode: \"kv\" | \"sqlite\";\n}\nexport class PersistenceCloudflareTransactionalStorage extends AbstractPersistence {\n private _mode: \"kv\" | \"sqlite\";\n private _state: DurableObjectState | null = null;\n private _initialized: Promise<true> | null = null;\n\n constructor(config: PersistenceCloudflareTransactionalStorageConfig) {\n super();\n\n const { mode } = config;\n\n this._initialized = (config as any)._initialized;\n this._mode = mode;\n }\n\n public async addUser(\n room: string,\n connectionId: string,\n user: JsonObject | null,\n ): Promise<void> {\n if (!this._initialized) return;\n if (!this._state) return;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n await this._state.storage.put(this._getUserKey(room, connectionId), user);\n return;\n }\n\n const result = this._state.storage.sql.exec<{ count: 0 }>(\n sql`\n SELECT id\n FROM ${SQLITE_USER_TABLE}\n WHERE id = ?;\n `,\n connectionId,\n );\n\n const existing = !!(result.toArray()[0]?.count ?? 0);\n\n if (existing) return;\n\n this._state.storage.sql.exec(\n sql`\n INSERT INTO ${SQLITE_USER_TABLE} VALUES (?, ?, ?);\n `,\n connectionId,\n JSON.stringify(user),\n room,\n );\n }\n\n public async deleteStorageState(room: string): Promise<void> {\n if (!this._initialized) return;\n if (!this._state) return;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n await this._state.storage.delete(this._getStorageKey(room));\n return;\n }\n\n this._state.storage.sql.exec(\n sql`\n DELETE FROM ${SQLITE_STORAGE_TABLE}\n WHERE room = ?;\n `,\n room,\n );\n }\n\n public async deleteUser(room: string, connectionId: string): Promise<void> {\n if (!this._initialized) return;\n if (!this._state) return;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n await this._state.storage.delete(this._getUserKey(room, connectionId));\n\n return;\n }\n\n this._state.storage.sql.exec(\n sql`\n DELETE FROM ${SQLITE_USER_TABLE}\n WHERE room = ?\n AND id = ?;\n `,\n room,\n connectionId,\n );\n }\n\n public async deleteUsers(room: string): Promise<void> {\n if (!this._initialized) return;\n if (!this._state) return;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n const map = await this._state.storage.list({\n allowConcurrency: true,\n noCache: true,\n prefix: `${KV_USER_PREFIX}::${room}`,\n });\n\n const partitions = partitionByLength(\n Array.from(map.keys()),\n KV_CLOUDFLARE_DELETE_BATCH_LIMIT,\n );\n\n await this._state.storage.transaction(async (tx) => {\n await partitions.reduce(async (promise, partition) => {\n await promise;\n await tx.delete(partition as string[]);\n }, Promise.resolve());\n });\n\n return;\n }\n\n this._state.storage.sql.exec(\n sql`\n DELETE FROM ${SQLITE_USER_TABLE}\n WHERE room = ?;\n `,\n room,\n );\n }\n\n public async getStorageState(room: string): Promise<string | null> {\n if (!this._initialized) return null;\n if (!this._state) return null;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n const storage = await this._state.storage.get<string>(this._getStorageKey(room));\n return storage ?? null;\n }\n\n const cursor = this._state.storage.sql.exec<{ room: string; data: string }>(\n sql`\n SELECT room, data\n FROM ${SQLITE_STORAGE_TABLE}\n WHERE room = ?;\n `,\n room,\n );\n\n try {\n const result = cursor.one();\n\n return result.data;\n } catch {\n return null;\n }\n }\n\n public async getUser(room: string, connectionId: string): Promise<JsonObject | null> {\n if (!this._initialized) return null;\n if (!this._state) return null;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n const user = await this._state.storage.get<JsonObject | null>(\n this._getUserKey(room, connectionId),\n );\n\n return user ?? null;\n }\n\n const cursor = this._state.storage.sql.exec<{ id: string; data: string; room: string }>(\n sql`\n SELECT id, data, room\n FROM ${SQLITE_USER_TABLE}\n WHERE room = ?\n AND id = ?;\n `,\n room,\n connectionId,\n );\n\n try {\n const result = cursor.one();\n const user = JSON.parse(result.data);\n\n return user;\n } catch {\n return null;\n }\n }\n\n public async getUsers(\n room: string,\n ): Promise<Map<[connectionId: string][0], JsonObject | null>> {\n if (!this._initialized) return new Map();\n if (!this._state) return new Map();\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n const entries = await this._state.storage\n .list<JsonObject | null>({\n prefix: `${KV_USER_PREFIX}::${room}`,\n })\n .then((map) => Array.from(map.entries()));\n\n return entries.reduce((map, [key, user]) => {\n const connectionId = key.split(\"::\").slice(-1)[0];\n\n return !!connectionId ? map.set(connectionId, user) : map;\n }, new Map<string, JsonObject | null>());\n }\n\n const cursor = this._state.storage.sql.exec<{ id: string; data: string; room: string }>(\n sql`\n SELECT id, room, data\n FROM ${SQLITE_USER_TABLE}\n WHERE room = ?;\n `,\n room,\n );\n\n return cursor.toArray().reduce((map, { id, data }) => {\n try {\n const user = JSON.parse(data) as JsonObject;\n\n return map.set(id, user);\n } catch {\n return map;\n }\n }, new Map<string, JsonObject | null>());\n }\n\n public async getUsersSize(room: string): Promise<number> {\n if (!this._initialized) return 0;\n if (!this._state) return 0;\n\n await this._initialized;\n\n if (this._mode) {\n const storage = await this._state.storage.list({\n prefix: `${KV_USER_PREFIX}::${room}`,\n });\n\n return storage.size;\n }\n\n const cursor = this._state.storage.sql.exec<{ count: number }>(\n sql`\n SELECT COUNT(*) count\n FROM ${SQLITE_USER_TABLE}\n WHERE room = ?;\n `,\n room,\n );\n\n try {\n const result = cursor.one();\n\n return castNumber(result.count);\n } catch {\n return 0;\n }\n }\n\n public initialize(roomContext: { state: DurableObjectState }): typeof this {\n const initialized = (async () => {\n const { state } = roomContext;\n\n this._state = state;\n\n if (this._mode === \"sqlite\") {\n this._state.storage.sql.exec(sql`\n CREATE TABLE IF NOT EXISTS ${SQLITE_STORAGE_TABLE}(\n room TEXT PRIMARY KEY,\n data TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS ${SQLITE_USER_TABLE}(\n id TEXT PRIMARY KEY,\n data TEXT NOT NULL,\n room TEXT NOT NULL\n );\n CREATE INDEX IF NOT EXISTS ${SQLITE_USER_TABLE}_room ON ${SQLITE_USER_TABLE}(room);\n `);\n }\n\n return true as const;\n })();\n\n return new PersistenceCloudflareTransactionalStorage({\n mode: this._mode,\n ...{ _initialized: initialized },\n }) as typeof this;\n }\n\n public async setStorageState(room: string, state: string): Promise<void> {\n if (!this._initialized) return;\n if (!this._state) return;\n\n await this._initialized;\n\n if (this._mode === \"kv\") {\n await this._state.storage.put(this._getStorageKey(room), state, {\n allowConcurrency: true,\n });\n return;\n }\n\n const result = this._state.storage.sql.exec<{ count: number }>(\n sql`\n SELECT COUNT(*) as count\n FROM ${SQLITE_STORAGE_TABLE}\n WHERE room = ?;\n `,\n room,\n );\n\n const existing = !!(result.toArray()[0]?.count ?? 0);\n\n if (existing) {\n this._state.storage.sql.exec(\n sql`\n UPDATE ${SQLITE_STORAGE_TABLE}\n SET data = ?\n WHERE room = ?;\n `,\n state,\n room,\n );\n\n return;\n }\n\n this._state.storage.sql.exec(\n sql`\n INSERT INTO ${SQLITE_STORAGE_TABLE} VALUES (?, ?);\n `,\n room,\n state,\n );\n }\n\n private _getStorageKey(room: string): string {\n if (this._mode === \"sqlite\") {\n throw new Error(\"Attempted to get kv key for sqlite storage\");\n }\n\n return `${KV_STORAGE_PREFIX}::${room}`;\n }\n\n private _getUserKey(room: string, connectionId: string): string {\n if (this._mode === \"sqlite\") {\n throw new Error(\"Attempted to get kv key for sqlite storage\");\n }\n\n return `${KV_USER_PREFIX}::${room}::${connectionId}`;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluv/persistence-cloudflare-transactional-storage",
3
- "version": "5.0.0",
3
+ "version": "5.0.2",
4
4
  "description": "@pluv/io crdt storage persistence for cloudflare via transactional storage",
5
5
  "author": {
6
6
  "email": "david@pluv.io",
@@ -16,20 +16,23 @@
16
16
  },
17
17
  "type": "module",
18
18
  "types": "./dist/index.d.mts",
19
+ "files": [
20
+ "dist"
21
+ ],
19
22
  "publishConfig": {
20
23
  "access": "public"
21
24
  },
22
25
  "dependencies": {
23
- "@pluv/io": "^5.0.0",
24
- "@pluv/types": "^5.0.0"
26
+ "@pluv/io": "^5.0.2",
27
+ "@pluv/types": "^5.0.2"
25
28
  },
26
29
  "devDependencies": {
27
- "@cloudflare/workers-types": "^4.20260613.1",
28
- "eslint": "^10.5.0",
29
- "tsdown": "0.22.3",
30
- "typescript": "^5.9.3",
31
- "@pluv/tsconfig": "^5.0.0",
32
- "eslint-config-pluv": "^5.0.0"
30
+ "@cloudflare/workers-types": "^5.20260823.1",
31
+ "@pluv/tsconfig": "^5.0.2",
32
+ "eslint": "^10.9.0",
33
+ "eslint-config-pluv": "^5.0.2",
34
+ "tsdown": "0.22.14",
35
+ "typescript": "^5.9.3"
33
36
  },
34
37
  "exports": {
35
38
  ".": "./dist/index.mjs",
@@ -1,16 +0,0 @@
1
- $ tsdown
2
- ℹ tsdown v0.22.3 powered by rolldown v1.1.2
3
- ℹ config file: /home/runner/work/pluv/pluv/packages/persistence-cloudflare-transactional-storage/tsdown.config.ts
4
- ℹ entry: src/index.ts
5
- ℹ target: esnext
6
- ℹ tsconfig: tsconfig.json
7
-
8
-  WARN  `external` is deprecated. Use `deps.neverBundle` instead.
9
-
10
- ℹ Build start
11
- ℹ dist/index.mjs  8.22 kB │ gzip: 1.93 kB
12
- ℹ dist/index.mjs.map 17.34 kB │ gzip: 3.91 kB
13
- ℹ dist/index.d.mts.map  0.73 kB │ gzip: 0.37 kB
14
- ℹ dist/index.d.mts  1.32 kB │ gzip: 0.46 kB
15
- ℹ 4 files, total: 27.61 kB
16
- ✔ Build complete in 2279ms