@flowgram.ai/history-storage 0.4.6 → 0.4.8

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/esm/index.js CHANGED
@@ -260,7 +260,7 @@ var createHistoryStoragePlugin = definePluginCreator({
260
260
  });
261
261
 
262
262
  // src/use-storage-hisotry-items.tsx
263
- import { groupBy } from "lodash";
263
+ import { groupBy } from "lodash-es";
264
264
  import { useLiveQuery } from "dexie-react-hooks";
265
265
  import { HistoryStack } from "@flowgram.ai/history";
266
266
  function useStorageHistoryItems(historyStorageManager, resourceURI) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/create-history-storage-plugin.ts","../../src/history-storage-manager.ts","../../src/history-database.ts","../../src/history-storage-container-module.ts","../../src/use-storage-hisotry-items.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { definePluginCreator } from '@flowgram.ai/core';\n\nimport { HistoryStoragePluginOptions } from './types';\nimport { HistoryStorageManager } from './history-storage-manager';\nimport { HistoryStorageContainerModule } from './history-storage-container-module';\n\nexport const createHistoryStoragePlugin = definePluginCreator<HistoryStoragePluginOptions>({\n onBind: ({ bind, rebind }) => {},\n onInit(ctx, opts): void {\n const historyStorageManager = ctx.get<HistoryStorageManager>(HistoryStorageManager);\n historyStorageManager.onInit(ctx, opts);\n },\n onDispose(ctx) {\n const historyStorageManager = ctx.get<HistoryStorageManager>(HistoryStorageManager);\n historyStorageManager.dispose();\n },\n containerModules: [HistoryStorageContainerModule],\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { inject, injectable } from 'inversify';\nimport { DisposableCollection } from '@flowgram.ai/utils';\nimport {\n HistoryItem,\n HistoryManager,\n HistoryOperation,\n HistoryStackChangeType,\n HistoryService,\n HistoryStackAddOperationEvent,\n HistoryStackUpdateOperationEvent,\n} from '@flowgram.ai/history';\nimport { PluginContext } from '@flowgram.ai/core';\n\nimport { HistoryOperationRecord, HistoryRecord, HistoryStoragePluginOptions } from './types';\nimport { HistoryDatabase } from './history-database';\n\n/**\n * 历史存储管理\n */\n@injectable()\nexport class HistoryStorageManager {\n private _toDispose = new DisposableCollection();\n\n db: HistoryDatabase;\n\n @inject(HistoryManager)\n protected historyManager: HistoryManager;\n\n /**\n * 初始化\n * @param ctx\n */\n onInit(_ctx: PluginContext, opts: HistoryStoragePluginOptions) {\n this.db = new HistoryDatabase(opts?.databaseName);\n\n if (opts?.resourceStorageLimit) {\n this.db.resourceStorageLimit = opts.resourceStorageLimit;\n }\n\n this._toDispose.push(\n this.historyManager.historyStack.onChange(event => {\n if (event.type === HistoryStackChangeType.ADD) {\n const [history, operations] = this.historyItemToRecord(event.service, event.value);\n this.db.addHistoryRecord(history, operations).catch(console.error);\n }\n\n // operation merge的时候需要更新snapshot\n if (\n [HistoryStackChangeType.ADD_OPERATION, HistoryStackChangeType.UPDATE_OPERATION].includes(\n event.type,\n )\n ) {\n const {\n service,\n value: { historyItem },\n } = event as HistoryStackAddOperationEvent | HistoryStackUpdateOperationEvent;\n // 更新快照\n this.db\n .updateHistoryByUUID(historyItem.id, {\n resourceJSON: service.getSnapshot() || '',\n })\n .catch(console.error);\n }\n\n if (event.type === HistoryStackChangeType.ADD_OPERATION) {\n const operationRecord: HistoryOperationRecord = this.historyOperationToRecord(\n event.value.historyItem,\n event.value.operation,\n );\n this.db.addOperationRecord(operationRecord).catch(console.error);\n }\n if (event.type === HistoryStackChangeType.UPDATE_OPERATION) {\n const operationRecord: HistoryOperationRecord = this.historyOperationToRecord(\n event.value.historyItem,\n event.value.operation,\n );\n this.db.updateOperationRecord(operationRecord).catch(console.error);\n }\n }),\n );\n }\n\n /**\n * 内存历史转数据表记录\n * @param historyItem\n * @returns\n */\n historyItemToRecord(\n historyService: HistoryService,\n historyItem: HistoryItem,\n ): [HistoryRecord, HistoryOperationRecord[]] {\n const operations = historyItem.operations.map(op =>\n this.historyOperationToRecord(historyItem, op),\n );\n\n return [\n {\n uuid: historyItem.id,\n timestamp: historyItem.timestamp,\n type: historyItem.type,\n resourceURI: historyItem.uri?.toString() || '',\n resourceJSON: historyService.getSnapshot() || '',\n },\n operations,\n ];\n }\n\n /**\n * 内存操作转数据表操作\n * @param historyItem\n * @param op\n * @returns\n */\n historyOperationToRecord(historyItem: HistoryItem, op: HistoryOperation): HistoryOperationRecord {\n return {\n uuid: op.id,\n type: op.type,\n timestamp: op.timestamp,\n label: op.label || '',\n uri: op?.uri?.toString() || '',\n resourceURI: historyItem.uri?.toString() || '',\n description: op.description || '',\n value: JSON.stringify(op.value),\n historyId: historyItem.id,\n };\n }\n\n /**\n * 销毁\n */\n dispose() {\n this._toDispose.dispose();\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport Dexie, { type Table } from 'dexie';\n\nimport { HistoryOperationRecord, HistoryRecord } from './types';\n\n/**\n * 历史数据库\n */\nexport class HistoryDatabase extends Dexie {\n readonly history: Table<HistoryRecord>;\n\n readonly operation: Table<HistoryOperationRecord>;\n\n resourceStorageLimit: number = 100;\n\n constructor(databaseName: string = 'ide-history-storage') {\n super(databaseName);\n this.version(1).stores({\n history: '++id, &uuid, resourceURI',\n operation: '++id, &uuid, historyId, uri, resourceURI',\n });\n }\n\n /**\n * 某个uri下所有的history记录\n * @param resourceURI 资源uri\n * @returns\n */\n allHistoryByResourceURI(resourceURI: string) {\n return this.history.where({ resourceURI }).toArray();\n }\n\n /**\n * 根据uuid获取历史\n * @param uuid\n * @returns\n */\n getHistoryByUUID(uuid: string) {\n return this.history.get({ uuid });\n }\n\n /**\n * 某个uri下所有的operation记录\n * @param resourceURI 资源uri\n * @returns\n */\n allOperationByResourceURI(resourceURI: string) {\n return this.operation.where({ resourceURI }).toArray();\n }\n\n /**\n * 添加历史记录\n * @param history 历史记录\n * @param operations 操作记录\n * @returns\n */\n addHistoryRecord(history: HistoryRecord, operations: HistoryOperationRecord[]) {\n return this.transaction('rw', this.history, this.operation, async () => {\n const count = await this.history.where({ resourceURI: history.resourceURI }).count();\n if (count >= this.resourceStorageLimit) {\n const limit = count - this.resourceStorageLimit;\n const items = await this.history\n .where({ resourceURI: history.resourceURI })\n .limit(limit)\n .toArray();\n const ids = items.map(i => i.id);\n const uuid = items.map(i => i.uuid);\n await Promise.all([\n this.history.bulkDelete(ids),\n ...uuid.map(async uuid => {\n await this.operation.where({ historyId: uuid }).delete();\n }),\n ]);\n }\n\n return Promise.all([this.history.add(history), this.operation.bulkAdd(operations)]);\n });\n }\n\n /**\n * 更新历史记录\n * @param historyRecord\n * @returns\n */\n async updateHistoryByUUID(uuid: string, historyRecord: Partial<HistoryRecord>) {\n const history = await this.getHistoryByUUID(uuid);\n if (!history) {\n console.warn('no history record found');\n return;\n }\n return this.history.update(history.id, historyRecord);\n }\n\n /**\n * 添加操作记录\n * @param record 操作记录\n * @returns\n */\n addOperationRecord(record: HistoryOperationRecord) {\n return this.operation.add(record);\n }\n\n /**\n * 更新操作记录\n * @param record 操作记录\n * @returns\n */\n async updateOperationRecord(record: HistoryOperationRecord) {\n const op = await this.operation.where({ uuid: record.uuid }).first();\n if (!op) {\n console.warn('no operation record found');\n return;\n }\n return this.operation.put({\n id: op.id,\n ...record,\n });\n }\n\n /**\n * 重置数据库\n * @returns\n */\n reset() {\n return this.transaction('rw', this.history, this.operation, async () => {\n await Promise.all(this.tables.map(table => table.clear()));\n });\n }\n\n /**\n * 清空某个资源下所有的数据\n * @param resourceURI\n * @returns\n */\n resetByResourceURI(resourceURI: string) {\n return this.transaction('rw', this.history, this.operation, async () => {\n await Promise.all(this.tables.map(table => table.where({ resourceURI }).delete()));\n });\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { ContainerModule } from 'inversify';\n\nimport { HistoryStorageManager } from './history-storage-manager';\n\nexport const HistoryStorageContainerModule = new ContainerModule(bind => {\n bind(HistoryStorageManager).toSelf().inSingletonScope();\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { groupBy } from 'lodash';\nimport { useLiveQuery } from 'dexie-react-hooks';\nimport { HistoryItem, HistoryOperation, HistoryStack } from '@flowgram.ai/history';\n\nimport { HistoryStorageManager } from './history-storage-manager';\nexport function useStorageHistoryItems(\n historyStorageManager: HistoryStorageManager,\n resourceURI: string\n): {\n items: HistoryItem[];\n} {\n const items: HistoryItem[] =\n useLiveQuery(async () => {\n const [historyItems, operations] = await Promise.all([\n historyStorageManager.db.allHistoryByResourceURI(resourceURI),\n historyStorageManager.db.allOperationByResourceURI(resourceURI),\n ]);\n\n const grouped = groupBy<HistoryOperation>(\n operations.map((o) => ({\n id: o.uuid,\n timestamp: o.timestamp,\n type: o.type,\n label: o.label,\n description: o.description,\n value: o.value ? JSON.parse(o.value) : undefined,\n uri: o.uri,\n historyId: o.historyId,\n })),\n 'historyId'\n );\n return historyItems\n .sort((a, b) => (b.id as number) - (a.id as number))\n .map(\n (historyItem) =>\n ({\n id: historyItem.uuid,\n type: historyItem.type,\n timestamp: historyItem.timestamp,\n operations: grouped[historyItem.uuid] || [],\n time: HistoryStack.dateFormat(historyItem.timestamp),\n uri: historyItem.resourceURI,\n } as HistoryItem)\n );\n }, [resourceURI]) || [];\n\n return {\n items,\n };\n}\n"],"mappings":";;;;;;;;;;;;AAKA,SAAS,2BAA2B;;;ACApC,SAAS,QAAQ,kBAAkB;AACnC,SAAS,4BAA4B;AACrC;AAAA,EAEE;AAAA,EAEA;AAAA,OAIK;;;ACVP,OAAO,WAA2B;AAO3B,IAAM,kBAAN,cAA8B,MAAM;AAAA,EAOzC,YAAY,eAAuB,uBAAuB;AACxD,UAAM,YAAY;AAHpB,gCAA+B;AAI7B,SAAK,QAAQ,CAAC,EAAE,OAAO;AAAA,MACrB,SAAS;AAAA,MACT,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,wBAAwB,aAAqB;AAC3C,WAAO,KAAK,QAAQ,MAAM,EAAE,YAAY,CAAC,EAAE,QAAQ;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAiB,MAAc;AAC7B,WAAO,KAAK,QAAQ,IAAI,EAAE,KAAK,CAAC;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,0BAA0B,aAAqB;AAC7C,WAAO,KAAK,UAAU,MAAM,EAAE,YAAY,CAAC,EAAE,QAAQ;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,iBAAiB,SAAwB,YAAsC;AAC7E,WAAO,KAAK,YAAY,MAAM,KAAK,SAAS,KAAK,WAAW,YAAY;AACtE,YAAM,QAAQ,MAAM,KAAK,QAAQ,MAAM,EAAE,aAAa,QAAQ,YAAY,CAAC,EAAE,MAAM;AACnF,UAAI,SAAS,KAAK,sBAAsB;AACtC,cAAM,QAAQ,QAAQ,KAAK;AAC3B,cAAM,QAAQ,MAAM,KAAK,QACtB,MAAM,EAAE,aAAa,QAAQ,YAAY,CAAC,EAC1C,MAAM,KAAK,EACX,QAAQ;AACX,cAAM,MAAM,MAAM,IAAI,OAAK,EAAE,EAAE;AAC/B,cAAM,OAAO,MAAM,IAAI,OAAK,EAAE,IAAI;AAClC,cAAM,QAAQ,IAAI;AAAA,UAChB,KAAK,QAAQ,WAAW,GAAG;AAAA,UAC3B,GAAG,KAAK,IAAI,OAAMA,UAAQ;AACxB,kBAAM,KAAK,UAAU,MAAM,EAAE,WAAWA,MAAK,CAAC,EAAE,OAAO;AAAA,UACzD,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAEA,aAAO,QAAQ,IAAI,CAAC,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,UAAU,QAAQ,UAAU,CAAC,CAAC;AAAA,IACpF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,oBAAoB,MAAc,eAAuC;AAC7E,UAAM,UAAU,MAAM,KAAK,iBAAiB,IAAI;AAChD,QAAI,CAAC,SAAS;AACZ,cAAQ,KAAK,yBAAyB;AACtC;AAAA,IACF;AACA,WAAO,KAAK,QAAQ,OAAO,QAAQ,IAAI,aAAa;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAAmB,QAAgC;AACjD,WAAO,KAAK,UAAU,IAAI,MAAM;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,sBAAsB,QAAgC;AAC1D,UAAM,KAAK,MAAM,KAAK,UAAU,MAAM,EAAE,MAAM,OAAO,KAAK,CAAC,EAAE,MAAM;AACnE,QAAI,CAAC,IAAI;AACP,cAAQ,KAAK,2BAA2B;AACxC;AAAA,IACF;AACA,WAAO,KAAK,UAAU,IAAI;AAAA,MACxB,IAAI,GAAG;AAAA,MACP,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ;AACN,WAAO,KAAK,YAAY,MAAM,KAAK,SAAS,KAAK,WAAW,YAAY;AACtE,YAAM,QAAQ,IAAI,KAAK,OAAO,IAAI,WAAS,MAAM,MAAM,CAAC,CAAC;AAAA,IAC3D,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAAmB,aAAqB;AACtC,WAAO,KAAK,YAAY,MAAM,KAAK,SAAS,KAAK,WAAW,YAAY;AACtE,YAAM,QAAQ,IAAI,KAAK,OAAO,IAAI,WAAS,MAAM,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;AAAA,IACnF,CAAC;AAAA,EACH;AACF;;;ADtHO,IAAM,wBAAN,MAA4B;AAAA,EAA5B;AACL,SAAQ,aAAa,IAAI,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW9C,OAAO,MAAqB,MAAmC;AAC7D,SAAK,KAAK,IAAI,gBAAgB,MAAM,YAAY;AAEhD,QAAI,MAAM,sBAAsB;AAC9B,WAAK,GAAG,uBAAuB,KAAK;AAAA,IACtC;AAEA,SAAK,WAAW;AAAA,MACd,KAAK,eAAe,aAAa,SAAS,WAAS;AACjD,YAAI,MAAM,SAAS,uBAAuB,KAAK;AAC7C,gBAAM,CAAC,SAAS,UAAU,IAAI,KAAK,oBAAoB,MAAM,SAAS,MAAM,KAAK;AACjF,eAAK,GAAG,iBAAiB,SAAS,UAAU,EAAE,MAAM,QAAQ,KAAK;AAAA,QACnE;AAGA,YACE,CAAC,uBAAuB,eAAe,uBAAuB,gBAAgB,EAAE;AAAA,UAC9E,MAAM;AAAA,QACR,GACA;AACA,gBAAM;AAAA,YACJ;AAAA,YACA,OAAO,EAAE,YAAY;AAAA,UACvB,IAAI;AAEJ,eAAK,GACF,oBAAoB,YAAY,IAAI;AAAA,YACnC,cAAc,QAAQ,YAAY,KAAK;AAAA,UACzC,CAAC,EACA,MAAM,QAAQ,KAAK;AAAA,QACxB;AAEA,YAAI,MAAM,SAAS,uBAAuB,eAAe;AACvD,gBAAM,kBAA0C,KAAK;AAAA,YACnD,MAAM,MAAM;AAAA,YACZ,MAAM,MAAM;AAAA,UACd;AACA,eAAK,GAAG,mBAAmB,eAAe,EAAE,MAAM,QAAQ,KAAK;AAAA,QACjE;AACA,YAAI,MAAM,SAAS,uBAAuB,kBAAkB;AAC1D,gBAAM,kBAA0C,KAAK;AAAA,YACnD,MAAM,MAAM;AAAA,YACZ,MAAM,MAAM;AAAA,UACd;AACA,eAAK,GAAG,sBAAsB,eAAe,EAAE,MAAM,QAAQ,KAAK;AAAA,QACpE;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,oBACE,gBACA,aAC2C;AAC3C,UAAM,aAAa,YAAY,WAAW;AAAA,MAAI,QAC5C,KAAK,yBAAyB,aAAa,EAAE;AAAA,IAC/C;AAEA,WAAO;AAAA,MACL;AAAA,QACE,MAAM,YAAY;AAAA,QAClB,WAAW,YAAY;AAAA,QACvB,MAAM,YAAY;AAAA,QAClB,aAAa,YAAY,KAAK,SAAS,KAAK;AAAA,QAC5C,cAAc,eAAe,YAAY,KAAK;AAAA,MAChD;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,yBAAyB,aAA0B,IAA8C;AAC/F,WAAO;AAAA,MACL,MAAM,GAAG;AAAA,MACT,MAAM,GAAG;AAAA,MACT,WAAW,GAAG;AAAA,MACd,OAAO,GAAG,SAAS;AAAA,MACnB,KAAK,IAAI,KAAK,SAAS,KAAK;AAAA,MAC5B,aAAa,YAAY,KAAK,SAAS,KAAK;AAAA,MAC5C,aAAa,GAAG,eAAe;AAAA,MAC/B,OAAO,KAAK,UAAU,GAAG,KAAK;AAAA,MAC9B,WAAW,YAAY;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AACR,SAAK,WAAW,QAAQ;AAAA,EAC1B;AACF;AA3GY;AAAA,EADT,OAAO,cAAc;AAAA,GALX,sBAMD;AANC,wBAAN;AAAA,EADN,WAAW;AAAA,GACC;;;AEpBb,SAAS,uBAAuB;AAIzB,IAAM,gCAAgC,IAAI,gBAAgB,UAAQ;AACvE,OAAK,qBAAqB,EAAE,OAAO,EAAE,iBAAiB;AACxD,CAAC;;;AHAM,IAAM,6BAA6B,oBAAiD;AAAA,EACzF,QAAQ,CAAC,EAAE,MAAM,OAAO,MAAM;AAAA,EAAC;AAAA,EAC/B,OAAO,KAAK,MAAY;AACtB,UAAM,wBAAwB,IAAI,IAA2B,qBAAqB;AAClF,0BAAsB,OAAO,KAAK,IAAI;AAAA,EACxC;AAAA,EACA,UAAU,KAAK;AACb,UAAM,wBAAwB,IAAI,IAA2B,qBAAqB;AAClF,0BAAsB,QAAQ;AAAA,EAChC;AAAA,EACA,kBAAkB,CAAC,6BAA6B;AAClD,CAAC;;;AIjBD,SAAS,eAAe;AACxB,SAAS,oBAAoB;AAC7B,SAAwC,oBAAoB;AAGrD,SAAS,uBACd,uBACA,aAGA;AACA,QAAM,QACJ,aAAa,YAAY;AACvB,UAAM,CAAC,cAAc,UAAU,IAAI,MAAM,QAAQ,IAAI;AAAA,MACnD,sBAAsB,GAAG,wBAAwB,WAAW;AAAA,MAC5D,sBAAsB,GAAG,0BAA0B,WAAW;AAAA,IAChE,CAAC;AAED,UAAM,UAAU;AAAA,MACd,WAAW,IAAI,CAAC,OAAO;AAAA,QACrB,IAAI,EAAE;AAAA,QACN,WAAW,EAAE;AAAA,QACb,MAAM,EAAE;AAAA,QACR,OAAO,EAAE;AAAA,QACT,aAAa,EAAE;AAAA,QACf,OAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,KAAK,IAAI;AAAA,QACvC,KAAK,EAAE;AAAA,QACP,WAAW,EAAE;AAAA,MACf,EAAE;AAAA,MACF;AAAA,IACF;AACA,WAAO,aACJ,KAAK,CAAC,GAAG,MAAO,EAAE,KAAiB,EAAE,EAAa,EAClD;AAAA,MACC,CAAC,iBACE;AAAA,QACC,IAAI,YAAY;AAAA,QAChB,MAAM,YAAY;AAAA,QAClB,WAAW,YAAY;AAAA,QACvB,YAAY,QAAQ,YAAY,IAAI,KAAK,CAAC;AAAA,QAC1C,MAAM,aAAa,WAAW,YAAY,SAAS;AAAA,QACnD,KAAK,YAAY;AAAA,MACnB;AAAA,IACJ;AAAA,EACJ,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC;AAExB,SAAO;AAAA,IACL;AAAA,EACF;AACF;","names":["uuid"]}
1
+ {"version":3,"sources":["../../src/create-history-storage-plugin.ts","../../src/history-storage-manager.ts","../../src/history-database.ts","../../src/history-storage-container-module.ts","../../src/use-storage-hisotry-items.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { definePluginCreator } from '@flowgram.ai/core';\n\nimport { HistoryStoragePluginOptions } from './types';\nimport { HistoryStorageManager } from './history-storage-manager';\nimport { HistoryStorageContainerModule } from './history-storage-container-module';\n\nexport const createHistoryStoragePlugin = definePluginCreator<HistoryStoragePluginOptions>({\n onBind: ({ bind, rebind }) => {},\n onInit(ctx, opts): void {\n const historyStorageManager = ctx.get<HistoryStorageManager>(HistoryStorageManager);\n historyStorageManager.onInit(ctx, opts);\n },\n onDispose(ctx) {\n const historyStorageManager = ctx.get<HistoryStorageManager>(HistoryStorageManager);\n historyStorageManager.dispose();\n },\n containerModules: [HistoryStorageContainerModule],\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { inject, injectable } from 'inversify';\nimport { DisposableCollection } from '@flowgram.ai/utils';\nimport {\n HistoryItem,\n HistoryManager,\n HistoryOperation,\n HistoryStackChangeType,\n HistoryService,\n HistoryStackAddOperationEvent,\n HistoryStackUpdateOperationEvent,\n} from '@flowgram.ai/history';\nimport { PluginContext } from '@flowgram.ai/core';\n\nimport { HistoryOperationRecord, HistoryRecord, HistoryStoragePluginOptions } from './types';\nimport { HistoryDatabase } from './history-database';\n\n/**\n * 历史存储管理\n */\n@injectable()\nexport class HistoryStorageManager {\n private _toDispose = new DisposableCollection();\n\n db: HistoryDatabase;\n\n @inject(HistoryManager)\n protected historyManager: HistoryManager;\n\n /**\n * 初始化\n * @param ctx\n */\n onInit(_ctx: PluginContext, opts: HistoryStoragePluginOptions) {\n this.db = new HistoryDatabase(opts?.databaseName);\n\n if (opts?.resourceStorageLimit) {\n this.db.resourceStorageLimit = opts.resourceStorageLimit;\n }\n\n this._toDispose.push(\n this.historyManager.historyStack.onChange(event => {\n if (event.type === HistoryStackChangeType.ADD) {\n const [history, operations] = this.historyItemToRecord(event.service, event.value);\n this.db.addHistoryRecord(history, operations).catch(console.error);\n }\n\n // operation merge的时候需要更新snapshot\n if (\n [HistoryStackChangeType.ADD_OPERATION, HistoryStackChangeType.UPDATE_OPERATION].includes(\n event.type,\n )\n ) {\n const {\n service,\n value: { historyItem },\n } = event as HistoryStackAddOperationEvent | HistoryStackUpdateOperationEvent;\n // 更新快照\n this.db\n .updateHistoryByUUID(historyItem.id, {\n resourceJSON: service.getSnapshot() || '',\n })\n .catch(console.error);\n }\n\n if (event.type === HistoryStackChangeType.ADD_OPERATION) {\n const operationRecord: HistoryOperationRecord = this.historyOperationToRecord(\n event.value.historyItem,\n event.value.operation,\n );\n this.db.addOperationRecord(operationRecord).catch(console.error);\n }\n if (event.type === HistoryStackChangeType.UPDATE_OPERATION) {\n const operationRecord: HistoryOperationRecord = this.historyOperationToRecord(\n event.value.historyItem,\n event.value.operation,\n );\n this.db.updateOperationRecord(operationRecord).catch(console.error);\n }\n }),\n );\n }\n\n /**\n * 内存历史转数据表记录\n * @param historyItem\n * @returns\n */\n historyItemToRecord(\n historyService: HistoryService,\n historyItem: HistoryItem,\n ): [HistoryRecord, HistoryOperationRecord[]] {\n const operations = historyItem.operations.map(op =>\n this.historyOperationToRecord(historyItem, op),\n );\n\n return [\n {\n uuid: historyItem.id,\n timestamp: historyItem.timestamp,\n type: historyItem.type,\n resourceURI: historyItem.uri?.toString() || '',\n resourceJSON: historyService.getSnapshot() || '',\n },\n operations,\n ];\n }\n\n /**\n * 内存操作转数据表操作\n * @param historyItem\n * @param op\n * @returns\n */\n historyOperationToRecord(historyItem: HistoryItem, op: HistoryOperation): HistoryOperationRecord {\n return {\n uuid: op.id,\n type: op.type,\n timestamp: op.timestamp,\n label: op.label || '',\n uri: op?.uri?.toString() || '',\n resourceURI: historyItem.uri?.toString() || '',\n description: op.description || '',\n value: JSON.stringify(op.value),\n historyId: historyItem.id,\n };\n }\n\n /**\n * 销毁\n */\n dispose() {\n this._toDispose.dispose();\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport Dexie, { type Table } from 'dexie';\n\nimport { HistoryOperationRecord, HistoryRecord } from './types';\n\n/**\n * 历史数据库\n */\nexport class HistoryDatabase extends Dexie {\n readonly history: Table<HistoryRecord>;\n\n readonly operation: Table<HistoryOperationRecord>;\n\n resourceStorageLimit: number = 100;\n\n constructor(databaseName: string = 'ide-history-storage') {\n super(databaseName);\n this.version(1).stores({\n history: '++id, &uuid, resourceURI',\n operation: '++id, &uuid, historyId, uri, resourceURI',\n });\n }\n\n /**\n * 某个uri下所有的history记录\n * @param resourceURI 资源uri\n * @returns\n */\n allHistoryByResourceURI(resourceURI: string) {\n return this.history.where({ resourceURI }).toArray();\n }\n\n /**\n * 根据uuid获取历史\n * @param uuid\n * @returns\n */\n getHistoryByUUID(uuid: string) {\n return this.history.get({ uuid });\n }\n\n /**\n * 某个uri下所有的operation记录\n * @param resourceURI 资源uri\n * @returns\n */\n allOperationByResourceURI(resourceURI: string) {\n return this.operation.where({ resourceURI }).toArray();\n }\n\n /**\n * 添加历史记录\n * @param history 历史记录\n * @param operations 操作记录\n * @returns\n */\n addHistoryRecord(history: HistoryRecord, operations: HistoryOperationRecord[]) {\n return this.transaction('rw', this.history, this.operation, async () => {\n const count = await this.history.where({ resourceURI: history.resourceURI }).count();\n if (count >= this.resourceStorageLimit) {\n const limit = count - this.resourceStorageLimit;\n const items = await this.history\n .where({ resourceURI: history.resourceURI })\n .limit(limit)\n .toArray();\n const ids = items.map(i => i.id);\n const uuid = items.map(i => i.uuid);\n await Promise.all([\n this.history.bulkDelete(ids),\n ...uuid.map(async uuid => {\n await this.operation.where({ historyId: uuid }).delete();\n }),\n ]);\n }\n\n return Promise.all([this.history.add(history), this.operation.bulkAdd(operations)]);\n });\n }\n\n /**\n * 更新历史记录\n * @param historyRecord\n * @returns\n */\n async updateHistoryByUUID(uuid: string, historyRecord: Partial<HistoryRecord>) {\n const history = await this.getHistoryByUUID(uuid);\n if (!history) {\n console.warn('no history record found');\n return;\n }\n return this.history.update(history.id, historyRecord);\n }\n\n /**\n * 添加操作记录\n * @param record 操作记录\n * @returns\n */\n addOperationRecord(record: HistoryOperationRecord) {\n return this.operation.add(record);\n }\n\n /**\n * 更新操作记录\n * @param record 操作记录\n * @returns\n */\n async updateOperationRecord(record: HistoryOperationRecord) {\n const op = await this.operation.where({ uuid: record.uuid }).first();\n if (!op) {\n console.warn('no operation record found');\n return;\n }\n return this.operation.put({\n id: op.id,\n ...record,\n });\n }\n\n /**\n * 重置数据库\n * @returns\n */\n reset() {\n return this.transaction('rw', this.history, this.operation, async () => {\n await Promise.all(this.tables.map(table => table.clear()));\n });\n }\n\n /**\n * 清空某个资源下所有的数据\n * @param resourceURI\n * @returns\n */\n resetByResourceURI(resourceURI: string) {\n return this.transaction('rw', this.history, this.operation, async () => {\n await Promise.all(this.tables.map(table => table.where({ resourceURI }).delete()));\n });\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { ContainerModule } from 'inversify';\n\nimport { HistoryStorageManager } from './history-storage-manager';\n\nexport const HistoryStorageContainerModule = new ContainerModule(bind => {\n bind(HistoryStorageManager).toSelf().inSingletonScope();\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { groupBy } from 'lodash-es';\nimport { useLiveQuery } from 'dexie-react-hooks';\nimport { HistoryItem, HistoryOperation, HistoryStack } from '@flowgram.ai/history';\n\nimport { HistoryStorageManager } from './history-storage-manager';\nexport function useStorageHistoryItems(\n historyStorageManager: HistoryStorageManager,\n resourceURI: string\n): {\n items: HistoryItem[];\n} {\n const items: HistoryItem[] =\n useLiveQuery(async () => {\n const [historyItems, operations] = await Promise.all([\n historyStorageManager.db.allHistoryByResourceURI(resourceURI),\n historyStorageManager.db.allOperationByResourceURI(resourceURI),\n ]);\n\n const grouped = groupBy<HistoryOperation>(\n operations.map((o) => ({\n id: o.uuid,\n timestamp: o.timestamp,\n type: o.type,\n label: o.label,\n description: o.description,\n value: o.value ? JSON.parse(o.value) : undefined,\n uri: o.uri,\n historyId: o.historyId,\n })),\n 'historyId'\n );\n return historyItems\n .sort((a, b) => (b.id as number) - (a.id as number))\n .map(\n (historyItem) =>\n ({\n id: historyItem.uuid,\n type: historyItem.type,\n timestamp: historyItem.timestamp,\n operations: grouped[historyItem.uuid] || [],\n time: HistoryStack.dateFormat(historyItem.timestamp),\n uri: historyItem.resourceURI,\n } as HistoryItem)\n );\n }, [resourceURI]) || [];\n\n return {\n items,\n };\n}\n"],"mappings":"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","names":["uuid"]}
package/dist/index.js CHANGED
@@ -294,7 +294,7 @@ var createHistoryStoragePlugin = (0, import_core.definePluginCreator)({
294
294
  });
295
295
 
296
296
  // src/use-storage-hisotry-items.tsx
297
- var import_lodash = require("lodash");
297
+ var import_lodash_es = require("lodash-es");
298
298
  var import_dexie_react_hooks = require("dexie-react-hooks");
299
299
  var import_history2 = require("@flowgram.ai/history");
300
300
  function useStorageHistoryItems(historyStorageManager, resourceURI) {
@@ -303,7 +303,7 @@ function useStorageHistoryItems(historyStorageManager, resourceURI) {
303
303
  historyStorageManager.db.allHistoryByResourceURI(resourceURI),
304
304
  historyStorageManager.db.allOperationByResourceURI(resourceURI)
305
305
  ]);
306
- const grouped = (0, import_lodash.groupBy)(
306
+ const grouped = (0, import_lodash_es.groupBy)(
307
307
  operations.map((o) => ({
308
308
  id: o.uuid,
309
309
  timestamp: o.timestamp,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/create-history-storage-plugin.ts","../src/history-storage-manager.ts","../src/history-database.ts","../src/history-storage-container-module.ts","../src/use-storage-hisotry-items.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport * from './create-history-storage-plugin';\nexport * from './use-storage-hisotry-items';\nexport * from './types';\nexport * from './history-database';\nexport * from './history-storage-container-module';\nexport * from './history-storage-manager';\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { definePluginCreator } from '@flowgram.ai/core';\n\nimport { HistoryStoragePluginOptions } from './types';\nimport { HistoryStorageManager } from './history-storage-manager';\nimport { HistoryStorageContainerModule } from './history-storage-container-module';\n\nexport const createHistoryStoragePlugin = definePluginCreator<HistoryStoragePluginOptions>({\n onBind: ({ bind, rebind }) => {},\n onInit(ctx, opts): void {\n const historyStorageManager = ctx.get<HistoryStorageManager>(HistoryStorageManager);\n historyStorageManager.onInit(ctx, opts);\n },\n onDispose(ctx) {\n const historyStorageManager = ctx.get<HistoryStorageManager>(HistoryStorageManager);\n historyStorageManager.dispose();\n },\n containerModules: [HistoryStorageContainerModule],\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { inject, injectable } from 'inversify';\nimport { DisposableCollection } from '@flowgram.ai/utils';\nimport {\n HistoryItem,\n HistoryManager,\n HistoryOperation,\n HistoryStackChangeType,\n HistoryService,\n HistoryStackAddOperationEvent,\n HistoryStackUpdateOperationEvent,\n} from '@flowgram.ai/history';\nimport { PluginContext } from '@flowgram.ai/core';\n\nimport { HistoryOperationRecord, HistoryRecord, HistoryStoragePluginOptions } from './types';\nimport { HistoryDatabase } from './history-database';\n\n/**\n * 历史存储管理\n */\n@injectable()\nexport class HistoryStorageManager {\n private _toDispose = new DisposableCollection();\n\n db: HistoryDatabase;\n\n @inject(HistoryManager)\n protected historyManager: HistoryManager;\n\n /**\n * 初始化\n * @param ctx\n */\n onInit(_ctx: PluginContext, opts: HistoryStoragePluginOptions) {\n this.db = new HistoryDatabase(opts?.databaseName);\n\n if (opts?.resourceStorageLimit) {\n this.db.resourceStorageLimit = opts.resourceStorageLimit;\n }\n\n this._toDispose.push(\n this.historyManager.historyStack.onChange(event => {\n if (event.type === HistoryStackChangeType.ADD) {\n const [history, operations] = this.historyItemToRecord(event.service, event.value);\n this.db.addHistoryRecord(history, operations).catch(console.error);\n }\n\n // operation merge的时候需要更新snapshot\n if (\n [HistoryStackChangeType.ADD_OPERATION, HistoryStackChangeType.UPDATE_OPERATION].includes(\n event.type,\n )\n ) {\n const {\n service,\n value: { historyItem },\n } = event as HistoryStackAddOperationEvent | HistoryStackUpdateOperationEvent;\n // 更新快照\n this.db\n .updateHistoryByUUID(historyItem.id, {\n resourceJSON: service.getSnapshot() || '',\n })\n .catch(console.error);\n }\n\n if (event.type === HistoryStackChangeType.ADD_OPERATION) {\n const operationRecord: HistoryOperationRecord = this.historyOperationToRecord(\n event.value.historyItem,\n event.value.operation,\n );\n this.db.addOperationRecord(operationRecord).catch(console.error);\n }\n if (event.type === HistoryStackChangeType.UPDATE_OPERATION) {\n const operationRecord: HistoryOperationRecord = this.historyOperationToRecord(\n event.value.historyItem,\n event.value.operation,\n );\n this.db.updateOperationRecord(operationRecord).catch(console.error);\n }\n }),\n );\n }\n\n /**\n * 内存历史转数据表记录\n * @param historyItem\n * @returns\n */\n historyItemToRecord(\n historyService: HistoryService,\n historyItem: HistoryItem,\n ): [HistoryRecord, HistoryOperationRecord[]] {\n const operations = historyItem.operations.map(op =>\n this.historyOperationToRecord(historyItem, op),\n );\n\n return [\n {\n uuid: historyItem.id,\n timestamp: historyItem.timestamp,\n type: historyItem.type,\n resourceURI: historyItem.uri?.toString() || '',\n resourceJSON: historyService.getSnapshot() || '',\n },\n operations,\n ];\n }\n\n /**\n * 内存操作转数据表操作\n * @param historyItem\n * @param op\n * @returns\n */\n historyOperationToRecord(historyItem: HistoryItem, op: HistoryOperation): HistoryOperationRecord {\n return {\n uuid: op.id,\n type: op.type,\n timestamp: op.timestamp,\n label: op.label || '',\n uri: op?.uri?.toString() || '',\n resourceURI: historyItem.uri?.toString() || '',\n description: op.description || '',\n value: JSON.stringify(op.value),\n historyId: historyItem.id,\n };\n }\n\n /**\n * 销毁\n */\n dispose() {\n this._toDispose.dispose();\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport Dexie, { type Table } from 'dexie';\n\nimport { HistoryOperationRecord, HistoryRecord } from './types';\n\n/**\n * 历史数据库\n */\nexport class HistoryDatabase extends Dexie {\n readonly history: Table<HistoryRecord>;\n\n readonly operation: Table<HistoryOperationRecord>;\n\n resourceStorageLimit: number = 100;\n\n constructor(databaseName: string = 'ide-history-storage') {\n super(databaseName);\n this.version(1).stores({\n history: '++id, &uuid, resourceURI',\n operation: '++id, &uuid, historyId, uri, resourceURI',\n });\n }\n\n /**\n * 某个uri下所有的history记录\n * @param resourceURI 资源uri\n * @returns\n */\n allHistoryByResourceURI(resourceURI: string) {\n return this.history.where({ resourceURI }).toArray();\n }\n\n /**\n * 根据uuid获取历史\n * @param uuid\n * @returns\n */\n getHistoryByUUID(uuid: string) {\n return this.history.get({ uuid });\n }\n\n /**\n * 某个uri下所有的operation记录\n * @param resourceURI 资源uri\n * @returns\n */\n allOperationByResourceURI(resourceURI: string) {\n return this.operation.where({ resourceURI }).toArray();\n }\n\n /**\n * 添加历史记录\n * @param history 历史记录\n * @param operations 操作记录\n * @returns\n */\n addHistoryRecord(history: HistoryRecord, operations: HistoryOperationRecord[]) {\n return this.transaction('rw', this.history, this.operation, async () => {\n const count = await this.history.where({ resourceURI: history.resourceURI }).count();\n if (count >= this.resourceStorageLimit) {\n const limit = count - this.resourceStorageLimit;\n const items = await this.history\n .where({ resourceURI: history.resourceURI })\n .limit(limit)\n .toArray();\n const ids = items.map(i => i.id);\n const uuid = items.map(i => i.uuid);\n await Promise.all([\n this.history.bulkDelete(ids),\n ...uuid.map(async uuid => {\n await this.operation.where({ historyId: uuid }).delete();\n }),\n ]);\n }\n\n return Promise.all([this.history.add(history), this.operation.bulkAdd(operations)]);\n });\n }\n\n /**\n * 更新历史记录\n * @param historyRecord\n * @returns\n */\n async updateHistoryByUUID(uuid: string, historyRecord: Partial<HistoryRecord>) {\n const history = await this.getHistoryByUUID(uuid);\n if (!history) {\n console.warn('no history record found');\n return;\n }\n return this.history.update(history.id, historyRecord);\n }\n\n /**\n * 添加操作记录\n * @param record 操作记录\n * @returns\n */\n addOperationRecord(record: HistoryOperationRecord) {\n return this.operation.add(record);\n }\n\n /**\n * 更新操作记录\n * @param record 操作记录\n * @returns\n */\n async updateOperationRecord(record: HistoryOperationRecord) {\n const op = await this.operation.where({ uuid: record.uuid }).first();\n if (!op) {\n console.warn('no operation record found');\n return;\n }\n return this.operation.put({\n id: op.id,\n ...record,\n });\n }\n\n /**\n * 重置数据库\n * @returns\n */\n reset() {\n return this.transaction('rw', this.history, this.operation, async () => {\n await Promise.all(this.tables.map(table => table.clear()));\n });\n }\n\n /**\n * 清空某个资源下所有的数据\n * @param resourceURI\n * @returns\n */\n resetByResourceURI(resourceURI: string) {\n return this.transaction('rw', this.history, this.operation, async () => {\n await Promise.all(this.tables.map(table => table.where({ resourceURI }).delete()));\n });\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { ContainerModule } from 'inversify';\n\nimport { HistoryStorageManager } from './history-storage-manager';\n\nexport const HistoryStorageContainerModule = new ContainerModule(bind => {\n bind(HistoryStorageManager).toSelf().inSingletonScope();\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { groupBy } from 'lodash';\nimport { useLiveQuery } from 'dexie-react-hooks';\nimport { HistoryItem, HistoryOperation, HistoryStack } from '@flowgram.ai/history';\n\nimport { HistoryStorageManager } from './history-storage-manager';\nexport function useStorageHistoryItems(\n historyStorageManager: HistoryStorageManager,\n resourceURI: string\n): {\n items: HistoryItem[];\n} {\n const items: HistoryItem[] =\n useLiveQuery(async () => {\n const [historyItems, operations] = await Promise.all([\n historyStorageManager.db.allHistoryByResourceURI(resourceURI),\n historyStorageManager.db.allOperationByResourceURI(resourceURI),\n ]);\n\n const grouped = groupBy<HistoryOperation>(\n operations.map((o) => ({\n id: o.uuid,\n timestamp: o.timestamp,\n type: o.type,\n label: o.label,\n description: o.description,\n value: o.value ? JSON.parse(o.value) : undefined,\n uri: o.uri,\n historyId: o.historyId,\n })),\n 'historyId'\n );\n return historyItems\n .sort((a, b) => (b.id as number) - (a.id as number))\n .map(\n (historyItem) =>\n ({\n id: historyItem.uuid,\n type: historyItem.type,\n timestamp: historyItem.timestamp,\n operations: grouped[historyItem.uuid] || [],\n time: HistoryStack.dateFormat(historyItem.timestamp),\n uri: historyItem.resourceURI,\n } as HistoryItem)\n );\n }, [resourceURI]) || [];\n\n return {\n items,\n };\n}\n"],"mappings":"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","names":["Dexie","uuid","import_inversify","import_history"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/create-history-storage-plugin.ts","../src/history-storage-manager.ts","../src/history-database.ts","../src/history-storage-container-module.ts","../src/use-storage-hisotry-items.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport * from './create-history-storage-plugin';\nexport * from './use-storage-hisotry-items';\nexport * from './types';\nexport * from './history-database';\nexport * from './history-storage-container-module';\nexport * from './history-storage-manager';\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { definePluginCreator } from '@flowgram.ai/core';\n\nimport { HistoryStoragePluginOptions } from './types';\nimport { HistoryStorageManager } from './history-storage-manager';\nimport { HistoryStorageContainerModule } from './history-storage-container-module';\n\nexport const createHistoryStoragePlugin = definePluginCreator<HistoryStoragePluginOptions>({\n onBind: ({ bind, rebind }) => {},\n onInit(ctx, opts): void {\n const historyStorageManager = ctx.get<HistoryStorageManager>(HistoryStorageManager);\n historyStorageManager.onInit(ctx, opts);\n },\n onDispose(ctx) {\n const historyStorageManager = ctx.get<HistoryStorageManager>(HistoryStorageManager);\n historyStorageManager.dispose();\n },\n containerModules: [HistoryStorageContainerModule],\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { inject, injectable } from 'inversify';\nimport { DisposableCollection } from '@flowgram.ai/utils';\nimport {\n HistoryItem,\n HistoryManager,\n HistoryOperation,\n HistoryStackChangeType,\n HistoryService,\n HistoryStackAddOperationEvent,\n HistoryStackUpdateOperationEvent,\n} from '@flowgram.ai/history';\nimport { PluginContext } from '@flowgram.ai/core';\n\nimport { HistoryOperationRecord, HistoryRecord, HistoryStoragePluginOptions } from './types';\nimport { HistoryDatabase } from './history-database';\n\n/**\n * 历史存储管理\n */\n@injectable()\nexport class HistoryStorageManager {\n private _toDispose = new DisposableCollection();\n\n db: HistoryDatabase;\n\n @inject(HistoryManager)\n protected historyManager: HistoryManager;\n\n /**\n * 初始化\n * @param ctx\n */\n onInit(_ctx: PluginContext, opts: HistoryStoragePluginOptions) {\n this.db = new HistoryDatabase(opts?.databaseName);\n\n if (opts?.resourceStorageLimit) {\n this.db.resourceStorageLimit = opts.resourceStorageLimit;\n }\n\n this._toDispose.push(\n this.historyManager.historyStack.onChange(event => {\n if (event.type === HistoryStackChangeType.ADD) {\n const [history, operations] = this.historyItemToRecord(event.service, event.value);\n this.db.addHistoryRecord(history, operations).catch(console.error);\n }\n\n // operation merge的时候需要更新snapshot\n if (\n [HistoryStackChangeType.ADD_OPERATION, HistoryStackChangeType.UPDATE_OPERATION].includes(\n event.type,\n )\n ) {\n const {\n service,\n value: { historyItem },\n } = event as HistoryStackAddOperationEvent | HistoryStackUpdateOperationEvent;\n // 更新快照\n this.db\n .updateHistoryByUUID(historyItem.id, {\n resourceJSON: service.getSnapshot() || '',\n })\n .catch(console.error);\n }\n\n if (event.type === HistoryStackChangeType.ADD_OPERATION) {\n const operationRecord: HistoryOperationRecord = this.historyOperationToRecord(\n event.value.historyItem,\n event.value.operation,\n );\n this.db.addOperationRecord(operationRecord).catch(console.error);\n }\n if (event.type === HistoryStackChangeType.UPDATE_OPERATION) {\n const operationRecord: HistoryOperationRecord = this.historyOperationToRecord(\n event.value.historyItem,\n event.value.operation,\n );\n this.db.updateOperationRecord(operationRecord).catch(console.error);\n }\n }),\n );\n }\n\n /**\n * 内存历史转数据表记录\n * @param historyItem\n * @returns\n */\n historyItemToRecord(\n historyService: HistoryService,\n historyItem: HistoryItem,\n ): [HistoryRecord, HistoryOperationRecord[]] {\n const operations = historyItem.operations.map(op =>\n this.historyOperationToRecord(historyItem, op),\n );\n\n return [\n {\n uuid: historyItem.id,\n timestamp: historyItem.timestamp,\n type: historyItem.type,\n resourceURI: historyItem.uri?.toString() || '',\n resourceJSON: historyService.getSnapshot() || '',\n },\n operations,\n ];\n }\n\n /**\n * 内存操作转数据表操作\n * @param historyItem\n * @param op\n * @returns\n */\n historyOperationToRecord(historyItem: HistoryItem, op: HistoryOperation): HistoryOperationRecord {\n return {\n uuid: op.id,\n type: op.type,\n timestamp: op.timestamp,\n label: op.label || '',\n uri: op?.uri?.toString() || '',\n resourceURI: historyItem.uri?.toString() || '',\n description: op.description || '',\n value: JSON.stringify(op.value),\n historyId: historyItem.id,\n };\n }\n\n /**\n * 销毁\n */\n dispose() {\n this._toDispose.dispose();\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport Dexie, { type Table } from 'dexie';\n\nimport { HistoryOperationRecord, HistoryRecord } from './types';\n\n/**\n * 历史数据库\n */\nexport class HistoryDatabase extends Dexie {\n readonly history: Table<HistoryRecord>;\n\n readonly operation: Table<HistoryOperationRecord>;\n\n resourceStorageLimit: number = 100;\n\n constructor(databaseName: string = 'ide-history-storage') {\n super(databaseName);\n this.version(1).stores({\n history: '++id, &uuid, resourceURI',\n operation: '++id, &uuid, historyId, uri, resourceURI',\n });\n }\n\n /**\n * 某个uri下所有的history记录\n * @param resourceURI 资源uri\n * @returns\n */\n allHistoryByResourceURI(resourceURI: string) {\n return this.history.where({ resourceURI }).toArray();\n }\n\n /**\n * 根据uuid获取历史\n * @param uuid\n * @returns\n */\n getHistoryByUUID(uuid: string) {\n return this.history.get({ uuid });\n }\n\n /**\n * 某个uri下所有的operation记录\n * @param resourceURI 资源uri\n * @returns\n */\n allOperationByResourceURI(resourceURI: string) {\n return this.operation.where({ resourceURI }).toArray();\n }\n\n /**\n * 添加历史记录\n * @param history 历史记录\n * @param operations 操作记录\n * @returns\n */\n addHistoryRecord(history: HistoryRecord, operations: HistoryOperationRecord[]) {\n return this.transaction('rw', this.history, this.operation, async () => {\n const count = await this.history.where({ resourceURI: history.resourceURI }).count();\n if (count >= this.resourceStorageLimit) {\n const limit = count - this.resourceStorageLimit;\n const items = await this.history\n .where({ resourceURI: history.resourceURI })\n .limit(limit)\n .toArray();\n const ids = items.map(i => i.id);\n const uuid = items.map(i => i.uuid);\n await Promise.all([\n this.history.bulkDelete(ids),\n ...uuid.map(async uuid => {\n await this.operation.where({ historyId: uuid }).delete();\n }),\n ]);\n }\n\n return Promise.all([this.history.add(history), this.operation.bulkAdd(operations)]);\n });\n }\n\n /**\n * 更新历史记录\n * @param historyRecord\n * @returns\n */\n async updateHistoryByUUID(uuid: string, historyRecord: Partial<HistoryRecord>) {\n const history = await this.getHistoryByUUID(uuid);\n if (!history) {\n console.warn('no history record found');\n return;\n }\n return this.history.update(history.id, historyRecord);\n }\n\n /**\n * 添加操作记录\n * @param record 操作记录\n * @returns\n */\n addOperationRecord(record: HistoryOperationRecord) {\n return this.operation.add(record);\n }\n\n /**\n * 更新操作记录\n * @param record 操作记录\n * @returns\n */\n async updateOperationRecord(record: HistoryOperationRecord) {\n const op = await this.operation.where({ uuid: record.uuid }).first();\n if (!op) {\n console.warn('no operation record found');\n return;\n }\n return this.operation.put({\n id: op.id,\n ...record,\n });\n }\n\n /**\n * 重置数据库\n * @returns\n */\n reset() {\n return this.transaction('rw', this.history, this.operation, async () => {\n await Promise.all(this.tables.map(table => table.clear()));\n });\n }\n\n /**\n * 清空某个资源下所有的数据\n * @param resourceURI\n * @returns\n */\n resetByResourceURI(resourceURI: string) {\n return this.transaction('rw', this.history, this.operation, async () => {\n await Promise.all(this.tables.map(table => table.where({ resourceURI }).delete()));\n });\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { ContainerModule } from 'inversify';\n\nimport { HistoryStorageManager } from './history-storage-manager';\n\nexport const HistoryStorageContainerModule = new ContainerModule(bind => {\n bind(HistoryStorageManager).toSelf().inSingletonScope();\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { groupBy } from 'lodash-es';\nimport { useLiveQuery } from 'dexie-react-hooks';\nimport { HistoryItem, HistoryOperation, HistoryStack } from '@flowgram.ai/history';\n\nimport { HistoryStorageManager } from './history-storage-manager';\nexport function useStorageHistoryItems(\n historyStorageManager: HistoryStorageManager,\n resourceURI: string\n): {\n items: HistoryItem[];\n} {\n const items: HistoryItem[] =\n useLiveQuery(async () => {\n const [historyItems, operations] = await Promise.all([\n historyStorageManager.db.allHistoryByResourceURI(resourceURI),\n historyStorageManager.db.allOperationByResourceURI(resourceURI),\n ]);\n\n const grouped = groupBy<HistoryOperation>(\n operations.map((o) => ({\n id: o.uuid,\n timestamp: o.timestamp,\n type: o.type,\n label: o.label,\n description: o.description,\n value: o.value ? JSON.parse(o.value) : undefined,\n uri: o.uri,\n historyId: o.historyId,\n })),\n 'historyId'\n );\n return historyItems\n .sort((a, b) => (b.id as number) - (a.id as number))\n .map(\n (historyItem) =>\n ({\n id: historyItem.uuid,\n type: historyItem.type,\n timestamp: historyItem.timestamp,\n operations: grouped[historyItem.uuid] || [],\n time: HistoryStack.dateFormat(historyItem.timestamp),\n uri: historyItem.resourceURI,\n } as HistoryItem)\n );\n }, [resourceURI]) || [];\n\n return {\n items,\n };\n}\n"],"mappings":"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","names":["Dexie","uuid","import_inversify","import_history"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowgram.ai/history-storage",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "homepage": "https://flowgram.ai/",
5
5
  "repository": "https://github.com/bytedance/flowgram.ai",
6
6
  "license": "MIT",
@@ -20,14 +20,14 @@
20
20
  "dexie-react-hooks": "1.1.7",
21
21
  "inversify": "^6.0.1",
22
22
  "reflect-metadata": "~0.2.2",
23
- "lodash": "^4.17.21",
23
+ "lodash-es": "^4.17.21",
24
24
  "nanoid": "^4.0.2",
25
- "@flowgram.ai/core": "0.4.6",
26
- "@flowgram.ai/utils": "0.4.6",
27
- "@flowgram.ai/history": "0.4.6"
25
+ "@flowgram.ai/core": "0.4.8",
26
+ "@flowgram.ai/history": "0.4.8",
27
+ "@flowgram.ai/utils": "0.4.8"
28
28
  },
29
29
  "devDependencies": {
30
- "@types/lodash": "^4.14.137",
30
+ "@types/lodash-es": "^4.17.12",
31
31
  "@vitest/coverage-v8": "^0.32.0",
32
32
  "eslint": "^8.54.0",
33
33
  "fake-indexeddb": "5.0.2",
@@ -35,8 +35,8 @@
35
35
  "tsup": "^8.0.1",
36
36
  "typescript": "^5.8.3",
37
37
  "vitest": "^0.34.6",
38
- "@flowgram.ai/ts-config": "0.4.6",
39
- "@flowgram.ai/eslint-config": "0.4.6"
38
+ "@flowgram.ai/eslint-config": "0.4.8",
39
+ "@flowgram.ai/ts-config": "0.4.8"
40
40
  },
41
41
  "publishConfig": {
42
42
  "access": "public",