@quereus/sync-coordinator 0.5.0 → 0.6.0
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quereus/sync-coordinator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Standalone coordinator backend for Quereus Sync - production-ready sync server",
|
|
6
6
|
"keywords": [
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@fastify/cors": "^10.0.2",
|
|
47
47
|
"@fastify/websocket": "^11.0.2",
|
|
48
|
-
"@quereus/plugin-leveldb": "^0.
|
|
49
|
-
"@quereus/quereus": "^0.10.
|
|
50
|
-
"@quereus/store": "^0.
|
|
51
|
-
"@quereus/sync": "^0.
|
|
48
|
+
"@quereus/plugin-leveldb": "^0.4.0",
|
|
49
|
+
"@quereus/quereus": "^0.10.5",
|
|
50
|
+
"@quereus/store": "^0.5.0",
|
|
51
|
+
"@quereus/sync": "^0.5.0",
|
|
52
52
|
"commander": "^14.0.0",
|
|
53
53
|
"debug": "^4.4.0",
|
|
54
54
|
"fastify": "^5.2.1"
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database ID utilities for multi-tenant sync
|
|
3
|
-
*
|
|
4
|
-
* NOTE: This is an application-specific format used by the quoomb app.
|
|
5
|
-
* Other applications can provide their own database ID format and validation
|
|
6
|
-
* via the StoreManagerHooks interface. These utilities are exported as
|
|
7
|
-
* examples and can be used directly if the format fits your needs.
|
|
8
|
-
*
|
|
9
|
-
* Database ID format: {accountId}-{dbType}{dbNum}
|
|
10
|
-
* - accountId: Short system-assigned ID (e.g., 'a1', 'b7', 'z42', 'local')
|
|
11
|
-
* - dbType: 's' for scenario, 'd' for dynamics, 'a' for account
|
|
12
|
-
* - dbNum: Short numeric ID scoped under account (e.g., '1', '42')
|
|
13
|
-
*
|
|
14
|
-
* Examples:
|
|
15
|
-
* - 'local-s1' = local account's scenario 1
|
|
16
|
-
* - 'a1-s1' = account a1's scenario 1
|
|
17
|
-
* - 'a1-d1' = account a1's dynamics 1 (same site as s1)
|
|
18
|
-
* - 'a1-acc' = account a1's account database
|
|
19
|
-
* - 'b7-s42' = account b7's scenario 42
|
|
20
|
-
*/
|
|
21
|
-
/**
|
|
22
|
-
* Parse a database ID into its components.
|
|
23
|
-
*/
|
|
24
|
-
export interface ParsedDatabaseId {
|
|
25
|
-
accountId: string;
|
|
26
|
-
dbType: 'scenario' | 'dynamics' | 'account';
|
|
27
|
-
dbNum?: number;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Parse a database ID string.
|
|
31
|
-
* @throws if the format is invalid
|
|
32
|
-
*/
|
|
33
|
-
export declare function parseDatabaseId(databaseId: string): ParsedDatabaseId;
|
|
34
|
-
/**
|
|
35
|
-
* Format a database ID from components.
|
|
36
|
-
*/
|
|
37
|
-
export declare function formatDatabaseId(accountId: string, dbType: 'scenario' | 'dynamics' | 'account', dbNum?: number): string;
|
|
38
|
-
/**
|
|
39
|
-
* Encode a number as a short base62 string.
|
|
40
|
-
* e.g., 0 -> 'a', 61 -> '9', 62 -> 'ba'
|
|
41
|
-
*/
|
|
42
|
-
export declare function numberToBase62(num: number): string;
|
|
43
|
-
/**
|
|
44
|
-
* Decode a base62 string to a number.
|
|
45
|
-
*/
|
|
46
|
-
export declare function base62ToNumber(str: string): number;
|
|
47
|
-
/**
|
|
48
|
-
* Generate a short account ID.
|
|
49
|
-
* Format: single letter prefix + base62 number
|
|
50
|
-
* e.g., 'a1', 'a42', 'b1', 'z999'
|
|
51
|
-
*
|
|
52
|
-
* The counter should be stored and incremented by the coordinator.
|
|
53
|
-
*/
|
|
54
|
-
export declare function generateAccountId(counter: number): string;
|
|
55
|
-
/**
|
|
56
|
-
* Get storage path for a database.
|
|
57
|
-
* Returns the directory path relative to the data root.
|
|
58
|
-
*/
|
|
59
|
-
export declare function getDatabaseStoragePath(databaseId: string): string;
|
|
60
|
-
/**
|
|
61
|
-
* Validate a database ID format.
|
|
62
|
-
*/
|
|
63
|
-
export declare function isValidDatabaseId(databaseId: string): boolean;
|
|
64
|
-
//# sourceMappingURL=database-ids.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"database-ids.d.ts","sourceRoot":"","sources":["../../../src/service/database-ids.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAmCpE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,EAC3C,KAAK,CAAC,EAAE,MAAM,GACb,MAAM,CASR;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAOzD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAO7D"}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database ID utilities for multi-tenant sync
|
|
3
|
-
*
|
|
4
|
-
* NOTE: This is an application-specific format used by the quoomb app.
|
|
5
|
-
* Other applications can provide their own database ID format and validation
|
|
6
|
-
* via the StoreManagerHooks interface. These utilities are exported as
|
|
7
|
-
* examples and can be used directly if the format fits your needs.
|
|
8
|
-
*
|
|
9
|
-
* Database ID format: {accountId}-{dbType}{dbNum}
|
|
10
|
-
* - accountId: Short system-assigned ID (e.g., 'a1', 'b7', 'z42', 'local')
|
|
11
|
-
* - dbType: 's' for scenario, 'd' for dynamics, 'a' for account
|
|
12
|
-
* - dbNum: Short numeric ID scoped under account (e.g., '1', '42')
|
|
13
|
-
*
|
|
14
|
-
* Examples:
|
|
15
|
-
* - 'local-s1' = local account's scenario 1
|
|
16
|
-
* - 'a1-s1' = account a1's scenario 1
|
|
17
|
-
* - 'a1-d1' = account a1's dynamics 1 (same site as s1)
|
|
18
|
-
* - 'a1-acc' = account a1's account database
|
|
19
|
-
* - 'b7-s42' = account b7's scenario 42
|
|
20
|
-
*/
|
|
21
|
-
// Base62 alphabet for short IDs (lowercase first for nicer URLs)
|
|
22
|
-
const BASE62 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
23
|
-
/**
|
|
24
|
-
* Parse a database ID string.
|
|
25
|
-
* @throws if the format is invalid
|
|
26
|
-
*/
|
|
27
|
-
export function parseDatabaseId(databaseId) {
|
|
28
|
-
const parts = databaseId.split('-');
|
|
29
|
-
if (parts.length !== 2) {
|
|
30
|
-
throw new Error(`Invalid database ID format: ${databaseId}`);
|
|
31
|
-
}
|
|
32
|
-
const [accountId, dbPart] = parts;
|
|
33
|
-
if (!accountId || accountId.length === 0) {
|
|
34
|
-
throw new Error(`Invalid account ID in database ID: ${databaseId}`);
|
|
35
|
-
}
|
|
36
|
-
// Account database: "acc"
|
|
37
|
-
if (dbPart === 'acc') {
|
|
38
|
-
return { accountId, dbType: 'account' };
|
|
39
|
-
}
|
|
40
|
-
// Scenario or dynamics: "s1", "d42", etc.
|
|
41
|
-
const typeChar = dbPart[0];
|
|
42
|
-
const numStr = dbPart.slice(1);
|
|
43
|
-
if (typeChar !== 's' && typeChar !== 'd') {
|
|
44
|
-
throw new Error(`Invalid database type in database ID: ${databaseId}`);
|
|
45
|
-
}
|
|
46
|
-
const dbNum = parseInt(numStr, 10);
|
|
47
|
-
if (isNaN(dbNum) || dbNum < 1) {
|
|
48
|
-
throw new Error(`Invalid database number in database ID: ${databaseId}`);
|
|
49
|
-
}
|
|
50
|
-
return {
|
|
51
|
-
accountId,
|
|
52
|
-
dbType: typeChar === 's' ? 'scenario' : 'dynamics',
|
|
53
|
-
dbNum,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Format a database ID from components.
|
|
58
|
-
*/
|
|
59
|
-
export function formatDatabaseId(accountId, dbType, dbNum) {
|
|
60
|
-
if (dbType === 'account') {
|
|
61
|
-
return `${accountId}-acc`;
|
|
62
|
-
}
|
|
63
|
-
if (dbNum === undefined) {
|
|
64
|
-
throw new Error(`dbNum required for ${dbType} database`);
|
|
65
|
-
}
|
|
66
|
-
const typeChar = dbType === 'scenario' ? 's' : 'd';
|
|
67
|
-
return `${accountId}-${typeChar}${dbNum}`;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Encode a number as a short base62 string.
|
|
71
|
-
* e.g., 0 -> 'a', 61 -> '9', 62 -> 'ba'
|
|
72
|
-
*/
|
|
73
|
-
export function numberToBase62(num) {
|
|
74
|
-
if (num < 0)
|
|
75
|
-
throw new Error('Number must be non-negative');
|
|
76
|
-
if (num === 0)
|
|
77
|
-
return BASE62[0];
|
|
78
|
-
let result = '';
|
|
79
|
-
while (num > 0) {
|
|
80
|
-
result = BASE62[num % 62] + result;
|
|
81
|
-
num = Math.floor(num / 62);
|
|
82
|
-
}
|
|
83
|
-
return result;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Decode a base62 string to a number.
|
|
87
|
-
*/
|
|
88
|
-
export function base62ToNumber(str) {
|
|
89
|
-
let num = 0;
|
|
90
|
-
for (const char of str) {
|
|
91
|
-
const idx = BASE62.indexOf(char);
|
|
92
|
-
if (idx === -1)
|
|
93
|
-
throw new Error(`Invalid base62 character: ${char}`);
|
|
94
|
-
num = num * 62 + idx;
|
|
95
|
-
}
|
|
96
|
-
return num;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Generate a short account ID.
|
|
100
|
-
* Format: single letter prefix + base62 number
|
|
101
|
-
* e.g., 'a1', 'a42', 'b1', 'z999'
|
|
102
|
-
*
|
|
103
|
-
* The counter should be stored and incremented by the coordinator.
|
|
104
|
-
*/
|
|
105
|
-
export function generateAccountId(counter) {
|
|
106
|
-
// Use lowercase letter prefix (a-z) based on counter / 1000
|
|
107
|
-
// This gives us 26,000 accounts per letter, expandable
|
|
108
|
-
const prefixIdx = Math.floor(counter / 1000) % 26;
|
|
109
|
-
const prefix = String.fromCharCode(97 + prefixIdx); // 'a' = 97
|
|
110
|
-
const suffix = counter % 1000;
|
|
111
|
-
return `${prefix}${suffix + 1}`; // +1 to make it 1-based
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Get storage path for a database.
|
|
115
|
-
* Returns the directory path relative to the data root.
|
|
116
|
-
*/
|
|
117
|
-
export function getDatabaseStoragePath(databaseId) {
|
|
118
|
-
const parsed = parseDatabaseId(databaseId);
|
|
119
|
-
// Store under account ID directory
|
|
120
|
-
return `${parsed.accountId}/${databaseId}`;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Validate a database ID format.
|
|
124
|
-
*/
|
|
125
|
-
export function isValidDatabaseId(databaseId) {
|
|
126
|
-
try {
|
|
127
|
-
parseDatabaseId(databaseId);
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
catch {
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
//# sourceMappingURL=database-ids.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"database-ids.js","sourceRoot":"","sources":["../../../src/service/database-ids.ts"],"names":[],"mappings":"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"}
|