@univerjs-pro/collaboration-database-sqlite 1.0.0-beta.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/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # @univerjs-pro/collaboration-database-sqlite
2
+
3
+ English | [简体中文](./README.zh-CN.md)
4
+
5
+ A persistent SQLite `IDatabaseAdapter` using the stable synchronous `libsql` API. Requires Node.js 22 or later.
6
+
7
+ ## Create the Adapter
8
+
9
+ ```bash
10
+ pnpm add \
11
+ @univerjs-pro/collaboration-service \
12
+ @univerjs-pro/collaboration-database-sqlite
13
+ ```
14
+
15
+ The caller must create the database parent directory first:
16
+
17
+ ```ts
18
+ import { mkdir } from 'node:fs/promises';
19
+ import { SQLiteDatabaseAdapter } from '@univerjs-pro/collaboration-database-sqlite';
20
+ import { UniverCollabService } from '@univerjs-pro/collaboration-service';
21
+
22
+ await mkdir('./data', { recursive: true });
23
+
24
+ const database = new SQLiteDatabaseAdapter({
25
+ filename: './data/collaboration.sqlite',
26
+ busyTimeoutMs: 5_000,
27
+ });
28
+ const service = new UniverCollabService({ dbAdapter: database });
29
+
30
+ await service.dispose();
31
+ await database.dispose();
32
+ ```
33
+
34
+ Pass the Adapter to `UniverCollabService` as `dbAdapter`.
35
+
36
+ ## Persistence guarantees
37
+
38
+ The Adapter uses foreign keys and `BEGIN IMMEDIATE` write transactions to guarantee:
39
+
40
+ - atomic creation of the initial snapshot and Sheet blocks;
41
+ - revision CAS with atomic changeset and head publication;
42
+ - a snapshot becomes visible to new reads only after all of its dependencies are complete;
43
+ - soft-delete, recovery, and hard-delete batches are all-or-nothing;
44
+ - hard delete keeps a permanent deletion marker that prevents Unit ID reuse.
45
+
46
+ It stores only core collaboration data. Product resources, users, ACLs, History, Comment, and Worktree are managed by the application or their respective Adapters.
47
+
48
+ ## SQLite behavior
49
+
50
+ - It does not change `journal_mode`; configure WAL, checkpointing, or backup policy before opening the Adapter when needed.
51
+ - Core tables use the `collaboration_` prefix.
52
+ - Schema version `('core', 1)` is stored in `collaboration_schema_versions`; `PRAGMA user_version` is not used.
53
+ - Changeset scalar columns and the submission unique constraint provide database-level integrity, while commits use revision CAS and do not query the submission key.
54
+ - An empty database is initialized automatically. Incomplete or unsupported core schemas are rejected.
55
+
56
+ This implementation suits local applications and small-to-medium single-Node deployments. Revision CAS still preserves collaboration-data correctness when multiple Service instances share the database file.
@@ -0,0 +1,61 @@
1
+ # @univerjs-pro/collaboration-database-sqlite
2
+
3
+ [English](./README.md) | [简体中文](./README.zh-CN.md)
4
+
5
+ 持久化 SQLite `IDatabaseAdapter`,使用稳定的 `libsql` 同步接口,支持 Node.js 22
6
+ 及以上版本。
7
+
8
+ ## 创建 Adapter
9
+
10
+ ```bash
11
+ pnpm add \
12
+ @univerjs-pro/collaboration-service \
13
+ @univerjs-pro/collaboration-database-sqlite
14
+ ```
15
+
16
+ 调用方需要先创建数据库父目录:
17
+
18
+ ```ts
19
+ import { mkdir } from 'node:fs/promises';
20
+ import { SQLiteDatabaseAdapter } from '@univerjs-pro/collaboration-database-sqlite';
21
+ import { UniverCollabService } from '@univerjs-pro/collaboration-service';
22
+
23
+ await mkdir('./data', { recursive: true });
24
+
25
+ const database = new SQLiteDatabaseAdapter({
26
+ filename: './data/collaboration.sqlite',
27
+ busyTimeoutMs: 5_000,
28
+ });
29
+ const service = new UniverCollabService({ dbAdapter: database });
30
+
31
+ await service.dispose();
32
+ await database.dispose();
33
+ ```
34
+
35
+ 将 Adapter 作为 `dbAdapter` 传给 `UniverCollabService`。
36
+
37
+ ## 持久化保证
38
+
39
+ Adapter 使用 foreign keys 和 `BEGIN IMMEDIATE` 写事务,保证:
40
+
41
+ - 初始 snapshot 与 Sheet blocks 原子创建;
42
+ - revision CAS 与 changeset/head 原子发布;
43
+ - snapshot 依赖完整后才对新读取可见;
44
+ - 软删除、恢复和 hard delete 批次全有或全无;
45
+ - hard delete 保留永久删除标记,禁止 Unit ID 复用。
46
+
47
+ 它只保存协同核心数据。产品资源、用户、ACL、History、Comment 和 Worktree 分别由应用
48
+ 或对应 Adapter 管理。
49
+
50
+ ## SQLite 行为
51
+
52
+ - 不主动修改 `journal_mode`;需要 WAL、checkpoint 或备份策略时由应用在打开前配置。
53
+ - 核心表使用 `collaboration_` 前缀。
54
+ - schema 版本以 `('core', 1)` 写入 `collaboration_schema_versions`,不占用
55
+ `PRAGMA user_version`。
56
+ - changeset 标量列和 submission unique constraint 提供数据库级完整性;提交只做 revision
57
+ CAS,不按 submission key 点查。
58
+ - 空库会自动初始化;不完整或不支持的核心 schema 会被拒绝。
59
+
60
+ 本实现适合本地应用和中小规模单 Node 部署。多个 Service 实例共享数据库文件时,
61
+ revision CAS 仍能保证协同数据正确性。
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ Object['defineProperty'](exports,Symbol['toStringTag'],{'value':'Module'});var e=Object['create'],t=Object['defineProperty'],n=Object['getOwnPropertyDescriptor'],r=Object['getOwnPropertyNames'],i=Object['getPrototypeOf'],a=Object['prototype']['hasOwnProperty'],o=(_0x2ae27d,_0x1bdf8f,_0x3a2218,_0x410086)=>{if(_0x1bdf8f&&typeof _0x1bdf8f=='object'||typeof _0x1bdf8f=='function'){for(var _0x456c04=r(_0x1bdf8f),_0x551492=0x0,_0x2b3129=_0x456c04['length'],_0x252713;_0x551492<_0x2b3129;_0x551492++)_0x252713=_0x456c04[_0x551492],!a['call'](_0x2ae27d,_0x252713)&&_0x252713!==_0x3a2218&&t(_0x2ae27d,_0x252713,{'get':(_0x3e22e2=>_0x1bdf8f[_0x3e22e2])['bind'](null,_0x252713),'enumerable':!(_0x410086=n(_0x1bdf8f,_0x252713))||_0x410086['enumerable']});}return _0x2ae27d;},s=(_0x2a92b2,_0x538c29,_0x203c5b)=>(_0x203c5b=_0x2a92b2==null?{}:e(i(_0x2a92b2)),o(_0x538c29||!_0x2a92b2||!_0x2a92b2['__esModule']?t(_0x203c5b,'default',{'value':_0x2a92b2,'enumerable':!0x0}):_0x203c5b,_0x2a92b2));let c=require('libsql');c=s(c,0x1);let l=require('@univerjs-pro/collaboration-service');var u=0x1388,d='__univerCollaborationBinary',f='core',p=0x1,m=['collaboration_units','collaboration_unit_tombstones','collaboration_snapshots','collaboration_changesets','collaboration_sheet_blocks','collaboration_resources'],h=class{['_database'];['_disposed']=!0x1;constructor(_0x292d95){g(_0x292d95),this['_database']=new c['default'](_0x292d95['filename'],{'timeout':_0x292d95['busyTimeoutMs']??u});try{this['_database']['exec']('PRAGMA\x20foreign_keys\x20=\x20ON;'),this['_database']['exec']('PRAGMA\x20busy_timeout\x20=\x20'+(_0x292d95['busyTimeoutMs']??u)+';'),this['_initializeSchema']();}catch(_0x153dd7){throw this['_database']['close'](),_0x153dd7;}}async['getUnit'](_0x261afa,_0xe212be){this['_assertOpen']();let _0x33da08=this['_database']['prepare']('SELECT\x20unit_id,\x20type,\x20head_revision,\x20soft_deleted_at_ms\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20collaboration_units\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20unit_id\x20=\x20?\x20AND\x20soft_deleted_at_ms\x20IS\x20NULL')['get'](_0xe212be);return _0x33da08?v(_0x33da08):null;}async['getSnapshot'](_0x48cead,_0x565bde,_0x53ffe1){this['_assertOpen']();let _0x41a5a9=_0x53ffe1?.['revision'];if(_0x41a5a9!==void 0x0&&_0x41a5a9<0x0)throw y('Snapshot\x20revision\x20cannot\x20be\x20negative');let _0x1c10a3=this['_getActiveUnitRow'](_0x565bde);if(!_0x1c10a3)return null;let _0x161809=_0x41a5a9===void 0x0||_0x41a5a9===0x0?_0x1c10a3['head_revision']:Math['min'](_0x41a5a9,_0x1c10a3['head_revision']),_0x154680=this['_database']['prepare']('SELECT\x20collaboration_snapshots.payload_json\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20collaboration_snapshots\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20JOIN\x20collaboration_units\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20collaboration_units.unit_id\x20=\x20collaboration_snapshots.unit_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20collaboration_snapshots.unit_id\x20=\x20?\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20collaboration_snapshots.revision\x20<=\x20?\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20collaboration_units.soft_deleted_at_ms\x20IS\x20NULL\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20ORDER\x20BY\x20collaboration_snapshots.revision\x20DESC\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20LIMIT\x201')['get'](_0x565bde,_0x161809);return _0x154680?C(_0x154680['payload_json']):null;}async['getChangesets'](_0x1d2be0,_0x1cf3d3,_0x5d64e3){if(this['_assertOpen'](),_0x5d64e3['from']<0x0||_0x5d64e3['to']<0x0)throw y('Changeset\x20range\x20revisions\x20cannot\x20be\x20negative');let _0xfb4a8e=this['_database']['prepare']('SELECT\x20collaboration_units.head_revision,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20collaboration_changesets.payload_json\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20collaboration_units\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20LEFT\x20JOIN\x20collaboration_changesets\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20collaboration_changesets.unit_id\x20=\x20collaboration_units.unit_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20collaboration_changesets.revision\x20>\x20?\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20collaboration_changesets.revision\x20<=\x20CASE\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHEN\x20?\x20=\x200\x20THEN\x20collaboration_units.head_revision\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ELSE\x20MIN(?,\x20collaboration_units.head_revision)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20END\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20collaboration_units.unit_id\x20=\x20?\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20collaboration_units.soft_deleted_at_ms\x20IS\x20NULL\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20ORDER\x20BY\x20collaboration_changesets.revision\x20ASC')['all'](_0x5d64e3['from'],_0x5d64e3['to'],_0x5d64e3['to'],_0x1cf3d3),_0x3995f2=_0xfb4a8e[0x0];return _0x3995f2?{'changesets':_0xfb4a8e['flatMap'](_0x338563=>_0x338563['payload_json']?[C(_0x338563['payload_json'])]:[]),'latestRevision':_0x3995f2['head_revision']}:{'changesets':[],'latestRevision':0x0};}async['createUnit'](_0xb1f782,_0x5d12ae){this['_assertOpen'](),_(_0x5d12ae);let _0x2ab26b=S(_0x5d12ae['snapshot']),_0x430693=(_0x5d12ae['sheetBlocks']??[])['map'](_0x5291a2=>({'id':_0x5291a2['id'],'payload':S(_0x5291a2)}));return this['_transaction'](()=>{if(this['_hasTombstone'](_0x5d12ae['record']['unitID']))throw y('Cannot\x20reuse\x20a\x20hard-deleted\x20unit\x20ID');let _0x704ed2=this['_getStoredUnitRow'](_0x5d12ae['record']['unitID']);if(_0x704ed2){if(_0x704ed2['soft_deleted_at_ms']!==null)throw y('Cannot\x20reuse\x20a\x20soft-deleted\x20unit\x20ID');return{'status':'already-exists','record':v(_0x704ed2)};}return this['_database']['prepare']('INSERT\x20INTO\x20collaboration_units\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(unit_id,\x20type,\x20head_revision,\x20soft_deleted_at_ms)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20(?,\x20?,\x201,\x20NULL)')['run'](_0x5d12ae['record']['unitID'],_0x5d12ae['record']['type']),this['_writeSheetBlocks'](_0x5d12ae['record']['unitID'],_0x430693),this['_database']['prepare']('INSERT\x20INTO\x20collaboration_snapshots\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(unit_id,\x20revision,\x20type,\x20payload_json)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20(?,\x201,\x20?,\x20?)')['run'](_0x5d12ae['record']['unitID'],_0x5d12ae['record']['type'],_0x2ab26b),{'status':'created','record':{..._0x5d12ae['record']}};});}async['deleteUnits'](_0x59d992,_0x41fd4f){return this['_assertOpen'](),this['_transaction'](()=>{let _0x3559f0=x(_0x41fd4f['unitIDs'])['map'](_0xf7bd36=>{let _0x179987=this['_getStoredUnitRow'](_0xf7bd36);if(!_0x179987){if(_0x41fd4f['hardDelete']&&this['_hasTombstone'](_0xf7bd36))return{'unitID':_0xf7bd36,'status':'already-hard-deleted'};throw new l['CollabError']('UNIT_NOT_FOUND','Cannot\x20delete\x20a\x20missing\x20unit');}return _0x41fd4f['hardDelete']?{'unitID':_0xf7bd36,'status':'hard-deleted'}:{'unitID':_0xf7bd36,'status':_0x179987['soft_deleted_at_ms']===null?'soft-deleted':'already-soft-deleted'};}),_0xc99572=this['_database']['prepare']('UPDATE\x20collaboration_units\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20SET\x20soft_deleted_at_ms\x20=\x20?\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20unit_id\x20=\x20?\x20AND\x20soft_deleted_at_ms\x20IS\x20NULL'),_0x1f95a6=this['_database']['prepare']('INSERT\x20INTO\x20collaboration_unit_tombstones\x20(unit_id,\x20purged_at)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20(?,\x20?)'),_0x2af672=this['_database']['prepare']('DELETE\x20FROM\x20collaboration_units\x20WHERE\x20unit_id\x20=\x20?'),_0x4f3194=Date['now']();for(let _0xa48de8 of _0x3559f0)_0xa48de8['status']==='soft-deleted'?_0xc99572['run'](_0x4f3194,_0xa48de8['unitID']):_0xa48de8['status']==='hard-deleted'&&(_0x1f95a6['run'](_0xa48de8['unitID'],_0x4f3194),_0x2af672['run'](_0xa48de8['unitID']));return{'units':_0x3559f0};});}async['recoverUnits'](_0x1bee12,_0xcf0f48){return this['_assertOpen'](),this['_transaction'](()=>{let _0x23009f=x(_0xcf0f48['unitIDs'])['map'](_0x4b5be8=>{let _0x3562ea=this['_getStoredUnitRow'](_0x4b5be8);if(!_0x3562ea)throw this['_hasTombstone'](_0x4b5be8)?y('Cannot\x20recover\x20a\x20hard-deleted\x20unit'):new l['CollabError']('UNIT_NOT_FOUND','Cannot\x20recover\x20a\x20missing\x20unit');return{'unitID':_0x4b5be8,'status':_0x3562ea['soft_deleted_at_ms']===null?'already-active':'recovered'};}),_0x54e015=this['_database']['prepare']('UPDATE\x20collaboration_units\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20SET\x20soft_deleted_at_ms\x20=\x20NULL\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20unit_id\x20=\x20?\x20AND\x20soft_deleted_at_ms\x20IS\x20NOT\x20NULL');for(let _0x577def of _0x23009f)_0x577def['status']==='recovered'&&_0x54e015['run'](_0x577def['unitID']);return{'units':_0x23009f};});}async['commitChangeset'](_0x2cdf93,_0x2d0b66){this['_assertOpen']();let _0x21f06c=S(_0x2d0b66['changeset']);return this['_transaction'](()=>{let {changeset:_0x182f21}=_0x2d0b66,_0x240dfc=this['_getActiveUnitRow'](_0x182f21['unitID']);if(!_0x240dfc)throw new l['CollabError']('UNIT_NOT_FOUND','Cannot\x20commit\x20to\x20a\x20missing\x20unit');if(_0x240dfc['head_revision']!==_0x182f21['revision']-0x1)return{'status':'revision-mismatch','actualHeadRevision':_0x240dfc['head_revision']};if(this['_database']['prepare']('INSERT\x20INTO\x20collaboration_changesets\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(unit_id,\x20revision,\x20base_revision,\x20sid,\x20req_id,\x20payload_json)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20(?,\x20?,\x20?,\x20?,\x20?,\x20?)')['run'](_0x182f21['unitID'],_0x182f21['revision'],_0x182f21['baseRev'],_0x182f21['sid'],_0x182f21['reqId'],_0x21f06c),this['_database']['prepare']('UPDATE\x20collaboration_units\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20SET\x20head_revision\x20=\x20?\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20unit_id\x20=\x20?\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20head_revision\x20=\x20?\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20soft_deleted_at_ms\x20IS\x20NULL')['run'](_0x182f21['revision'],_0x182f21['unitID'],_0x182f21['revision']-0x1)['changes']!==0x1)throw new l['CollabError']('INTERNAL_ERROR','SQLite\x20head\x20changed\x20inside\x20an\x20exclusive\x20write\x20transaction');return{'status':'committed','changeset':C(_0x21f06c),'headRevision':_0x182f21['revision']};});}async['saveSnapshot'](_0x5759b6,_0x412816){this['_assertOpen']();let _0xe9bdc1=S(_0x412816['snapshot']),_0x139f44=(_0x412816['sheetBlocks']??[])['map'](_0x337731=>({'id':_0x337731['id'],'payload':S(_0x337731)}));this['_transaction'](()=>{let _0x413bb4=this['_getActiveUnitRow'](_0x412816['snapshot']['unitID']);if(!_0x413bb4)throw new l['CollabError']('UNIT_NOT_FOUND','Cannot\x20snapshot\x20a\x20missing\x20unit');if(_0x412816['snapshot']['type']!==_0x413bb4['type']||_0x412816['snapshot']['rev']<0x1||_0x412816['snapshot']['rev']>_0x413bb4['head_revision'])throw y('Snapshot\x20does\x20not\x20match\x20the\x20stored\x20unit\x20head');this['_writeSheetBlocks'](_0x412816['snapshot']['unitID'],_0x139f44),this['_database']['prepare']('INSERT\x20INTO\x20collaboration_snapshots\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20(unit_id,\x20revision,\x20type,\x20payload_json)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20(?,\x20?,\x20?,\x20?)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT(unit_id,\x20revision)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type\x20=\x20excluded.type,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20payload_json\x20=\x20excluded.payload_json')['run'](_0x412816['snapshot']['unitID'],_0x412816['snapshot']['rev'],_0x412816['snapshot']['type'],_0xe9bdc1);});}async['getSheetBlock'](_0x3b0efd,_0x117a7d,_0x164f81){this['_assertOpen']();let _0x52fa94=this['_database']['prepare']('SELECT\x20collaboration_sheet_blocks.payload_json\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20collaboration_sheet_blocks\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20JOIN\x20collaboration_units\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20collaboration_units.unit_id\x20=\x20collaboration_sheet_blocks.unit_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20collaboration_sheet_blocks.unit_id\x20=\x20?\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20collaboration_sheet_blocks.block_id\x20=\x20?\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20collaboration_units.soft_deleted_at_ms\x20IS\x20NULL')['get'](_0x117a7d,_0x164f81);return _0x52fa94?C(_0x52fa94['payload_json']):null;}async['dispose'](){this['_disposed']||(this['_disposed']=!0x0,this['_database']['close']());}['_initializeSchema'](){this['_transaction'](()=>{if(!this['_hasTable']('collaboration_schema_versions')){if(this['_hasAnyCoreTable']())throw b('SQLite\x20collaboration\x20core\x20tables\x20exist\x20without\x20a\x20schema\x20version');this['_database']['exec']('\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20CREATE\x20TABLE\x20collaboration_schema_versions\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20component\x20TEXT\x20PRIMARY\x20KEY,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20version\x20INTEGER\x20NOT\x20NULL\x20CHECK\x20(version\x20>=\x201)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20);\x0a\x20\x20\x20\x20\x20\x20\x20\x20');}let _0x116a8a=this['_database']['prepare']('SELECT\x20version\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20collaboration_schema_versions\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20component\x20=\x20?')['get'](f);if(_0x116a8a){if(_0x116a8a['version']!==p)throw b('SQLite\x20collaboration\x20core\x20schema\x20version\x20'+_0x116a8a['version']+'\x20is\x20not\x20supported');let _0x284a8d=m['filter'](_0x8cb85=>!this['_hasTable'](_0x8cb85));if(_0x284a8d['length']>0x0)throw b('SQLite\x20collaboration\x20core\x20schema\x20v'+p+'\x20is\x20incomplete:\x20missing\x20'+_0x284a8d['join'](',\x20'));return;}if(this['_hasAnyCoreTable']())throw b('SQLite\x20collaboration\x20core\x20tables\x20exist\x20without\x20a\x20schema\x20version');this['_database']['exec']('\x0a\x20\x20\x20\x20\x20\x20\x20\x20CREATE\x20TABLE\x20collaboration_units\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20unit_id\x20TEXT\x20PRIMARY\x20KEY,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type\x20INTEGER\x20NOT\x20NULL,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20head_revision\x20INTEGER\x20NOT\x20NULL\x20CHECK\x20(head_revision\x20>=\x201),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20soft_deleted_at_ms\x20INTEGER\x0a\x20\x20\x20\x20\x20\x20\x20\x20);\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20CREATE\x20TABLE\x20collaboration_unit_tombstones\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20unit_id\x20TEXT\x20PRIMARY\x20KEY,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20purged_at\x20INTEGER\x20NOT\x20NULL\x0a\x20\x20\x20\x20\x20\x20\x20\x20);\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20CREATE\x20TABLE\x20collaboration_snapshots\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20unit_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20revision\x20INTEGER\x20NOT\x20NULL\x20CHECK\x20(revision\x20>=\x201),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20type\x20INTEGER\x20NOT\x20NULL,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20payload_json\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20PRIMARY\x20KEY\x20(unit_id,\x20revision),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FOREIGN\x20KEY\x20(unit_id)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20REFERENCES\x20collaboration_units(unit_id)\x20ON\x20DELETE\x20CASCADE\x0a\x20\x20\x20\x20\x20\x20\x20\x20);\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20CREATE\x20TABLE\x20collaboration_changesets\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20unit_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20revision\x20INTEGER\x20NOT\x20NULL\x20CHECK\x20(revision\x20>=\x202),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20base_revision\x20INTEGER\x20NOT\x20NULL\x20CHECK\x20(base_revision\x20>=\x201),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20sid\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20req_id\x20INTEGER\x20NOT\x20NULL\x20CHECK\x20(req_id\x20>=\x201),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20payload_json\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20PRIMARY\x20KEY\x20(unit_id,\x20revision),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20UNIQUE\x20(unit_id,\x20sid,\x20req_id),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FOREIGN\x20KEY\x20(unit_id)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20REFERENCES\x20collaboration_units(unit_id)\x20ON\x20DELETE\x20CASCADE\x0a\x20\x20\x20\x20\x20\x20\x20\x20);\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20CREATE\x20TABLE\x20collaboration_sheet_blocks\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20unit_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20block_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20payload_json\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20PRIMARY\x20KEY\x20(unit_id,\x20block_id),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FOREIGN\x20KEY\x20(unit_id)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20REFERENCES\x20collaboration_units(unit_id)\x20ON\x20DELETE\x20CASCADE\x0a\x20\x20\x20\x20\x20\x20\x20\x20);\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20CREATE\x20TABLE\x20collaboration_resources\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20unit_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20resource_id\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20payload_json\x20TEXT\x20NOT\x20NULL,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20PRIMARY\x20KEY\x20(unit_id,\x20resource_id),\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FOREIGN\x20KEY\x20(unit_id)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20REFERENCES\x20collaboration_units(unit_id)\x20ON\x20DELETE\x20CASCADE\x0a\x20\x20\x20\x20\x20\x20\x20\x20);\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20CREATE\x20INDEX\x20collaboration_snapshots_nearest_revision\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20collaboration_snapshots(unit_id,\x20revision\x20DESC);\x0a\x20\x20\x20\x20\x20\x20\x20\x20CREATE\x20INDEX\x20collaboration_changesets_revision_range\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ON\x20collaboration_changesets(unit_id,\x20revision\x20ASC);\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20INSERT\x20INTO\x20collaboration_schema_versions\x20(component,\x20version)\x0a\x20\x20\x20\x20\x20\x20\x20\x20VALUES\x20(\x27core\x27,\x201);\x0a\x20\x20\x20\x20\x20\x20');});}['_getActiveUnitRow'](_0x2711c7){return this['_database']['prepare']('SELECT\x20unit_id,\x20type,\x20head_revision,\x20soft_deleted_at_ms\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20collaboration_units\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20unit_id\x20=\x20?\x20AND\x20soft_deleted_at_ms\x20IS\x20NULL')['get'](_0x2711c7)??null;}['_getStoredUnitRow'](_0x428742){return this['_database']['prepare']('SELECT\x20unit_id,\x20type,\x20head_revision,\x20soft_deleted_at_ms\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20collaboration_units\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20unit_id\x20=\x20?')['get'](_0x428742)??null;}['_hasTombstone'](_0x1470cb){return!!this['_database']['prepare']('SELECT\x201\x20FROM\x20collaboration_unit_tombstones\x20WHERE\x20unit_id\x20=\x20?')['get'](_0x1470cb);}['_hasTable'](_0x5ca988){return!!this['_database']['prepare']('SELECT\x201\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20sqlite_schema\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20type\x20=\x20\x27table\x27\x20AND\x20name\x20=\x20?')['get'](_0x5ca988);}['_hasAnyCoreTable'](){return m['some'](_0x143407=>this['_hasTable'](_0x143407));}['_writeSheetBlocks'](_0x9dd194,_0x5ba774){let _0x19834a=this['_database']['prepare']('INSERT\x20INTO\x20collaboration_sheet_blocks\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20(unit_id,\x20block_id,\x20payload_json)\x0a\x20\x20\x20\x20\x20\x20\x20VALUES\x20(?,\x20?,\x20?)\x0a\x20\x20\x20\x20\x20\x20\x20ON\x20CONFLICT(unit_id,\x20block_id)\x20DO\x20UPDATE\x20SET\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20payload_json\x20=\x20excluded.payload_json');for(let _0x44c7df of _0x5ba774)_0x19834a['run'](_0x9dd194,_0x44c7df['id'],_0x44c7df['payload']);}['_transaction'](_0x45e5f4){this['_database']['exec']('BEGIN\x20IMMEDIATE;');try{let _0x50780b=_0x45e5f4();return this['_database']['exec']('COMMIT;'),_0x50780b;}catch(_0x1be0b5){throw this['_database']['inTransaction']&&this['_database']['exec']('ROLLBACK;'),_0x1be0b5;}}['_assertOpen'](){if(this['_disposed'])throw new l['CollabError']('INTERNAL_ERROR','SQLite\x20Database\x20Adapter\x20is\x20disposed');}};function g(_0x381172){if(!_0x381172['filename'])throw y('SQLite\x20filename\x20is\x20required');if(_0x381172['busyTimeoutMs']!==void 0x0&&(!Number['isSafeInteger'](_0x381172['busyTimeoutMs'])||_0x381172['busyTimeoutMs']<0x0))throw y('SQLite\x20busyTimeoutMs\x20must\x20be\x20a\x20non-negative\x20integer');}function _(_0x5b8c13){let {record:_0x48f9db,snapshot:_0x223839}=_0x5b8c13;if(_0x48f9db['headRevision']!==0x1||_0x223839['rev']!==0x1||_0x223839['unitID']!==_0x48f9db['unitID']||_0x223839['type']!==_0x48f9db['type'])throw y('Initial\x20unit\x20record\x20and\x20snapshot\x20must\x20match\x20at\x20revision\x201');}function v(_0xf8886c){return{'unitID':_0xf8886c['unit_id'],'type':_0xf8886c['type'],'headRevision':_0xf8886c['head_revision']};}function y(_0x241189){return new l['CollabError']('INVALID_REQUEST',_0x241189);}function b(_0x3b04ca){return new l['CollabError']('INTERNAL_ERROR',_0x3b04ca);}function x(_0x2397cf){return[...new Set(_0x2397cf)];}function S(_0x29e6c0){return JSON['stringify'](_0x29e6c0,(_0xa8a524,_0x597a52)=>_0x597a52 instanceof Uint8Array?{[d]:Buffer['from'](_0x597a52)['toString']('base64')}:_0x597a52);}function C(_0x19296e){return JSON['parse'](_0x19296e,(_0x365c12,_0x5cda29)=>w(_0x5cda29)?Uint8Array['from'](Buffer['from'](_0x5cda29[d],'base64')):_0x5cda29);}function w(_0x3b0bb1){return typeof _0x3b0bb1=='object'&&!!_0x3b0bb1&&Object['keys'](_0x3b0bb1)['length']===0x1&&typeof _0x3b0bb1[d]=='string';}exports['SQLiteDatabaseAdapter']=h;
@@ -0,0 +1,39 @@
1
+ import { ChangesetRange, CommitChangesetInput, CommitChangesetResult, CreateUnitDatabaseInput, CreateUnitDatabaseResult, DatabaseContext, DeleteUnitsDatabaseInput, DeleteUnitsDatabaseResult, IDatabaseAdapter, RecoverUnitsDatabaseInput, RecoverUnitsDatabaseResult, SaveSnapshotInput, UnitRecord } from "@univerjs-pro/collaboration-service";
2
+ import { ISheetBlock, ISnapshot } from "@univerjs/protocol";
3
+
4
+ //#region src/sqlite-database-adapter.d.ts
5
+ interface SQLiteDatabaseAdapterOptions {
6
+ readonly filename: string;
7
+ readonly busyTimeoutMs?: number;
8
+ }
9
+ declare class SQLiteDatabaseAdapter implements IDatabaseAdapter {
10
+ private readonly _database;
11
+ private _disposed;
12
+ constructor(options: SQLiteDatabaseAdapterOptions);
13
+ getUnit(_context: DatabaseContext, unitID: string): Promise<UnitRecord | null>;
14
+ getSnapshot(_context: DatabaseContext, unitID: string, options?: {
15
+ readonly revision?: number;
16
+ }): Promise<ISnapshot | null>;
17
+ getChangesets(_context: DatabaseContext, unitID: string, range: {
18
+ readonly from: number;
19
+ readonly to: number;
20
+ }): Promise<ChangesetRange>;
21
+ createUnit(_context: DatabaseContext, input: CreateUnitDatabaseInput): Promise<CreateUnitDatabaseResult>;
22
+ deleteUnits(_context: DatabaseContext, input: DeleteUnitsDatabaseInput): Promise<DeleteUnitsDatabaseResult>;
23
+ recoverUnits(_context: DatabaseContext, input: RecoverUnitsDatabaseInput): Promise<RecoverUnitsDatabaseResult>;
24
+ commitChangeset(_context: DatabaseContext, input: CommitChangesetInput): Promise<CommitChangesetResult>;
25
+ saveSnapshot(_context: DatabaseContext, input: SaveSnapshotInput): Promise<void>;
26
+ getSheetBlock(_context: DatabaseContext, unitID: string, blockID: string): Promise<ISheetBlock | null>;
27
+ dispose(): Promise<void>;
28
+ private _initializeSchema;
29
+ private _getActiveUnitRow;
30
+ private _getStoredUnitRow;
31
+ private _hasTombstone;
32
+ private _hasTable;
33
+ private _hasAnyCoreTable;
34
+ private _writeSheetBlocks;
35
+ private _transaction;
36
+ private _assertOpen;
37
+ }
38
+ //#endregion
39
+ export { SQLiteDatabaseAdapter, type SQLiteDatabaseAdapterOptions };
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ function _0x3185(_0x142ce3,_0x23d84d){_0x142ce3=_0x142ce3-0x11f;const _0x337709=_0x3377();let _0x3185d5=_0x337709[_0x142ce3];return _0x3185d5;}const _0x3d4cfc=_0x3185;(function(_0x2e3f5b,_0x32aba8){const _0x4dab0b=_0x3185,_0x59dd5e=_0x2e3f5b();while(!![]){try{const _0x1a87b9=-parseInt(_0x4dab0b(0x129))/0x1+parseInt(_0x4dab0b(0x126))/0x2*(-parseInt(_0x4dab0b(0x128))/0x3)+-parseInt(_0x4dab0b(0x127))/0x4*(-parseInt(_0x4dab0b(0x120))/0x5)+-parseInt(_0x4dab0b(0x125))/0x6*(-parseInt(_0x4dab0b(0x121))/0x7)+-parseInt(_0x4dab0b(0x11f))/0x8+parseInt(_0x4dab0b(0x124))/0x9*(-parseInt(_0x4dab0b(0x123))/0xa)+parseInt(_0x4dab0b(0x122))/0xb*(parseInt(_0x4dab0b(0x12b))/0xc);if(_0x1a87b9===_0x32aba8)break;else _0x59dd5e['push'](_0x59dd5e['shift']());}catch(_0x51493e){_0x59dd5e['push'](_0x59dd5e['shift']());}}}(_0x3377,0xd5f89));import _0x4f7c2f from'./index.cjs';const facadeExport0=_0x4f7c2f[_0x3d4cfc(0x12a)];function _0x3377(){const _0x5bab7d=['350NqAKek','61166JUYhli','1037014wpkxLJ','1385980zcvbcJ','81uIgzDl','228MvqLCi','4zblxZx','22340UuDtwX','313998GXrXDi','1317291rPqMLI','SQLiteDatabaseAdapter','468USPRJs','5994000ELrTjA'];_0x3377=function(){return _0x5bab7d;};return _0x3377();}export{facadeExport0 as SQLiteDatabaseAdapter};
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@univerjs-pro/collaboration-database-sqlite",
3
+ "type": "module",
4
+ "engines": {
5
+ "node": ">=22"
6
+ },
7
+ "version": "1.0.0-beta.2",
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.mjs",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.mjs",
15
+ "require": "./dist/index.cjs"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "dependencies": {
22
+ "@univerjs-pro/collaboration-service": "1.0.0-beta.2",
23
+ "@univerjs/protocol": "1.0.0-beta.2",
24
+ "libsql": "^0.5.29"
25
+ }
26
+ }