@syncular/server 0.0.1-111 → 0.0.1-114
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/blobs/adapters/filesystem.d.ts +31 -0
- package/dist/blobs/adapters/filesystem.d.ts.map +1 -0
- package/dist/blobs/adapters/filesystem.js +140 -0
- package/dist/blobs/adapters/filesystem.js.map +1 -0
- package/dist/blobs/adapters/s3.d.ts +3 -2
- package/dist/blobs/adapters/s3.d.ts.map +1 -1
- package/dist/blobs/adapters/s3.js +49 -0
- package/dist/blobs/adapters/s3.js.map +1 -1
- package/dist/blobs/index.d.ts +1 -0
- package/dist/blobs/index.d.ts.map +1 -1
- package/dist/blobs/index.js +1 -0
- package/dist/blobs/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/notify.d.ts +47 -0
- package/dist/notify.d.ts.map +1 -0
- package/dist/notify.js +85 -0
- package/dist/notify.js.map +1 -0
- package/dist/pull.d.ts.map +1 -1
- package/dist/pull.js +40 -1
- package/dist/pull.js.map +1 -1
- package/dist/snapshot-chunks/index.d.ts +0 -1
- package/dist/snapshot-chunks/index.d.ts.map +1 -1
- package/dist/snapshot-chunks/index.js +0 -1
- package/dist/snapshot-chunks/index.js.map +1 -1
- package/package.json +2 -2
- package/src/blobs/adapters/filesystem.test.ts +132 -0
- package/src/blobs/adapters/filesystem.ts +189 -0
- package/src/blobs/adapters/s3.test.ts +522 -0
- package/src/blobs/adapters/s3.ts +55 -2
- package/src/blobs/index.ts +1 -0
- package/src/index.ts +1 -0
- package/src/notify.test.ts +516 -0
- package/src/notify.ts +131 -0
- package/src/pull.ts +56 -2
- package/src/snapshot-chunks/index.ts +0 -1
- package/dist/snapshot-chunks/adapters/s3.d.ts +0 -74
- package/dist/snapshot-chunks/adapters/s3.d.ts.map +0 -1
- package/dist/snapshot-chunks/adapters/s3.js +0 -50
- package/dist/snapshot-chunks/adapters/s3.js.map +0 -1
- package/src/snapshot-chunks/adapters/s3.ts +0 -68
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem blob storage adapter.
|
|
3
|
+
*
|
|
4
|
+
* Stores blobs as files on disk with 2-level hash-based subdirectories.
|
|
5
|
+
* Uploads/downloads go through the server's blob routes using signed tokens
|
|
6
|
+
* (same pattern as the database adapter).
|
|
7
|
+
*/
|
|
8
|
+
import type { BlobStorageAdapter } from '@syncular/core';
|
|
9
|
+
import type { BlobTokenSigner } from './database';
|
|
10
|
+
export interface FilesystemBlobStorageAdapterOptions {
|
|
11
|
+
/** Directory root for blob files */
|
|
12
|
+
basePath: string;
|
|
13
|
+
/** Server base URL for upload/download routes (e.g. "/api/sync") */
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
/** Token signer for authorization */
|
|
16
|
+
tokenSigner: BlobTokenSigner;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create a filesystem blob storage adapter.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const adapter = createFilesystemBlobStorageAdapter({
|
|
24
|
+
* basePath: '/data/blobs',
|
|
25
|
+
* baseUrl: 'https://api.example.com/api/sync',
|
|
26
|
+
* tokenSigner: createHmacTokenSigner(process.env.BLOB_SECRET!),
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function createFilesystemBlobStorageAdapter(options: FilesystemBlobStorageAdapterOptions): BlobStorageAdapter;
|
|
31
|
+
//# sourceMappingURL=filesystem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../../src/blobs/adapters/filesystem.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,KAAK,EAIV,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,mCAAmC;IAClD,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,WAAW,EAAE,eAAe,CAAC;CAC9B;AAeD;;;;;;;;;;;GAWG;AACH,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,mCAAmC,GAC3C,kBAAkB,CA8HpB"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem blob storage adapter.
|
|
3
|
+
*
|
|
4
|
+
* Stores blobs as files on disk with 2-level hash-based subdirectories.
|
|
5
|
+
* Uploads/downloads go through the server's blob routes using signed tokens
|
|
6
|
+
* (same pattern as the database adapter).
|
|
7
|
+
*/
|
|
8
|
+
import { mkdir, open, readFile, rename, stat, unlink, writeFile, } from 'node:fs/promises';
|
|
9
|
+
import { dirname, join } from 'node:path';
|
|
10
|
+
/**
|
|
11
|
+
* Resolve hash to a 2-level subdirectory path:
|
|
12
|
+
* `{basePath}/{hex[0..2]}/{hex[2..4]}/{hex}`
|
|
13
|
+
*/
|
|
14
|
+
function hashToFilePath(basePath, hash) {
|
|
15
|
+
const hex = hash.startsWith('sha256:') ? hash.slice(7) : hash;
|
|
16
|
+
return join(basePath, hex.slice(0, 2), hex.slice(2, 4), hex);
|
|
17
|
+
}
|
|
18
|
+
function tmpPath(filePath) {
|
|
19
|
+
return `${filePath}.${Date.now()}.tmp`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create a filesystem blob storage adapter.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const adapter = createFilesystemBlobStorageAdapter({
|
|
27
|
+
* basePath: '/data/blobs',
|
|
28
|
+
* baseUrl: 'https://api.example.com/api/sync',
|
|
29
|
+
* tokenSigner: createHmacTokenSigner(process.env.BLOB_SECRET!),
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function createFilesystemBlobStorageAdapter(options) {
|
|
34
|
+
const { basePath, tokenSigner } = options;
|
|
35
|
+
const normalizedBaseUrl = options.baseUrl.replace(/\/$/, '');
|
|
36
|
+
return {
|
|
37
|
+
name: 'filesystem',
|
|
38
|
+
async signUpload(opts) {
|
|
39
|
+
const expiresAt = Date.now() + opts.expiresIn * 1000;
|
|
40
|
+
const token = await tokenSigner.sign({ hash: opts.hash, action: 'upload', expiresAt }, opts.expiresIn);
|
|
41
|
+
const url = `${normalizedBaseUrl}/blobs/${encodeURIComponent(opts.hash)}/upload?token=${encodeURIComponent(token)}`;
|
|
42
|
+
return {
|
|
43
|
+
url,
|
|
44
|
+
method: 'PUT',
|
|
45
|
+
headers: {
|
|
46
|
+
'Content-Type': opts.mimeType,
|
|
47
|
+
'Content-Length': String(opts.size),
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
async signDownload(opts) {
|
|
52
|
+
const expiresAt = Date.now() + opts.expiresIn * 1000;
|
|
53
|
+
const token = await tokenSigner.sign({ hash: opts.hash, action: 'download', expiresAt }, opts.expiresIn);
|
|
54
|
+
return `${normalizedBaseUrl}/blobs/${encodeURIComponent(opts.hash)}/download?token=${encodeURIComponent(token)}`;
|
|
55
|
+
},
|
|
56
|
+
async exists(hash) {
|
|
57
|
+
try {
|
|
58
|
+
await stat(hashToFilePath(basePath, hash));
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
async delete(hash) {
|
|
66
|
+
try {
|
|
67
|
+
await unlink(hashToFilePath(basePath, hash));
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
if (err.code !== 'ENOENT')
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
async getMetadata(hash) {
|
|
75
|
+
try {
|
|
76
|
+
const s = await stat(hashToFilePath(basePath, hash));
|
|
77
|
+
return { size: s.size };
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
async put(hash, data) {
|
|
84
|
+
const filePath = hashToFilePath(basePath, hash);
|
|
85
|
+
const tmp = tmpPath(filePath);
|
|
86
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
87
|
+
await writeFile(tmp, data);
|
|
88
|
+
await rename(tmp, filePath);
|
|
89
|
+
},
|
|
90
|
+
async putStream(hash, stream) {
|
|
91
|
+
const filePath = hashToFilePath(basePath, hash);
|
|
92
|
+
const tmp = tmpPath(filePath);
|
|
93
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
94
|
+
const fh = await open(tmp, 'w');
|
|
95
|
+
try {
|
|
96
|
+
const reader = stream.getReader();
|
|
97
|
+
while (true) {
|
|
98
|
+
const { done, value } = await reader.read();
|
|
99
|
+
if (done)
|
|
100
|
+
break;
|
|
101
|
+
await fh.write(value);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
await fh.close();
|
|
106
|
+
}
|
|
107
|
+
await rename(tmp, filePath);
|
|
108
|
+
},
|
|
109
|
+
async get(hash) {
|
|
110
|
+
try {
|
|
111
|
+
const buf = await readFile(hashToFilePath(basePath, hash));
|
|
112
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
if (err.code === 'ENOENT')
|
|
116
|
+
return null;
|
|
117
|
+
throw err;
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
async getStream(hash) {
|
|
121
|
+
let data;
|
|
122
|
+
try {
|
|
123
|
+
data = await readFile(hashToFilePath(basePath, hash));
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
if (err.code === 'ENOENT')
|
|
127
|
+
return null;
|
|
128
|
+
throw err;
|
|
129
|
+
}
|
|
130
|
+
const bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
131
|
+
return new ReadableStream({
|
|
132
|
+
start(controller) {
|
|
133
|
+
controller.enqueue(bytes);
|
|
134
|
+
controller.close();
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=filesystem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../../../src/blobs/adapters/filesystem.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,9 +27,10 @@ export interface S3Commands {
|
|
|
27
27
|
PutObjectCommand: new (input: {
|
|
28
28
|
Bucket: string;
|
|
29
29
|
Key: string;
|
|
30
|
-
ContentLength
|
|
31
|
-
ContentType
|
|
30
|
+
ContentLength?: number;
|
|
31
|
+
ContentType?: string;
|
|
32
32
|
ChecksumSHA256?: string;
|
|
33
|
+
Body?: Uint8Array | ReadableStream<Uint8Array>;
|
|
33
34
|
}) => unknown;
|
|
34
35
|
GetObjectCommand: new (input: {
|
|
35
36
|
Bucket: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../../src/blobs/adapters/s3.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAIV,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AAExB;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1C;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,KAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;AAErB;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,gBAAgB,EAAE,KAAK,KAAK,EAAE;QAC5B,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,aAAa,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../../src/blobs/adapters/s3.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAIV,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AAExB;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1C;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,KAC3B,OAAO,CAAC,MAAM,CAAC,CAAC;AAErB;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,gBAAgB,EAAE,KAAK,KAAK,EAAE;QAC5B,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,IAAI,CAAC,EAAE,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;KAChD,KAAK,OAAO,CAAC;IACd,gBAAgB,EAAE,KAAK,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;IAC1E,iBAAiB,EAAE,KAAK,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;IAC3E,mBAAmB,EAAE,KAAK,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;CAC9E;AAED,MAAM,WAAW,2BAA2B;IAC1C,yBAAyB;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,qBAAqB;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,QAAQ,EAAE,UAAU,CAAC;IACrB,+DAA+D;IAC/D,YAAY,EAAE,cAAc,CAAC;IAC7B;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,2BAA2B,GACnC,kBAAkB,CAqLpB"}
|
|
@@ -118,6 +118,55 @@ export function createS3BlobStorageAdapter(options) {
|
|
|
118
118
|
throw err;
|
|
119
119
|
}
|
|
120
120
|
},
|
|
121
|
+
async put(hash, data) {
|
|
122
|
+
const key = getKey(hash);
|
|
123
|
+
const command = new commands.PutObjectCommand({
|
|
124
|
+
Bucket: bucket,
|
|
125
|
+
Key: key,
|
|
126
|
+
Body: data,
|
|
127
|
+
ContentLength: data.length,
|
|
128
|
+
ContentType: 'application/octet-stream',
|
|
129
|
+
});
|
|
130
|
+
await client.send(command);
|
|
131
|
+
},
|
|
132
|
+
async get(hash) {
|
|
133
|
+
const key = getKey(hash);
|
|
134
|
+
try {
|
|
135
|
+
const command = new commands.GetObjectCommand({
|
|
136
|
+
Bucket: bucket,
|
|
137
|
+
Key: key,
|
|
138
|
+
});
|
|
139
|
+
const response = (await client.send(command));
|
|
140
|
+
if (!response.Body)
|
|
141
|
+
return null;
|
|
142
|
+
return response.Body.transformToByteArray();
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
if (isNotFoundError(err)) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
throw err;
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
async getStream(hash) {
|
|
152
|
+
const key = getKey(hash);
|
|
153
|
+
try {
|
|
154
|
+
const command = new commands.GetObjectCommand({
|
|
155
|
+
Bucket: bucket,
|
|
156
|
+
Key: key,
|
|
157
|
+
});
|
|
158
|
+
const response = (await client.send(command));
|
|
159
|
+
if (!response.Body)
|
|
160
|
+
return null;
|
|
161
|
+
return response.Body.transformToWebStream();
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
if (isNotFoundError(err)) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
throw err;
|
|
168
|
+
}
|
|
169
|
+
},
|
|
121
170
|
};
|
|
122
171
|
}
|
|
123
172
|
function isNotFoundError(err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3.js","sourceRoot":"","sources":["../../../src/blobs/adapters/s3.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"s3.js","sourceRoot":"","sources":["../../../src/blobs/adapters/s3.ts"],"names":[],"mappings":"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"}
|
package/dist/blobs/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blobs/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/blobs/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
|
package/dist/blobs/index.js
CHANGED
package/dist/blobs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/blobs/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/blobs/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,gBAAgB,CAAC;AAE/B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,YAAY,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACpE,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,gBAAgB,CAAC;AAE/B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,YAAY,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACpE,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export * from './compaction.js';
|
|
|
14
14
|
export * from './dialect/index.js';
|
|
15
15
|
export * from './helpers/index.js';
|
|
16
16
|
export * from './migrate.js';
|
|
17
|
+
export * from './notify.js';
|
|
17
18
|
export * from './proxy/index.js';
|
|
18
19
|
export * from './prune.js';
|
|
19
20
|
export * from './pull.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,gBAAgB,CAAC;AAE/B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAElC,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,gBAAgB,CAAC;AAE/B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAElC,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC"}
|
package/dist/notify.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/server - External data change notification
|
|
3
|
+
*
|
|
4
|
+
* Creates synthetic commits to notify the sync framework about data changes
|
|
5
|
+
* made outside the normal push flow (e.g., pipeline imports, direct DB writes).
|
|
6
|
+
*
|
|
7
|
+
* The synthetic commit forces affected subscriptions to re-bootstrap on next pull,
|
|
8
|
+
* ensuring clients receive the updated data.
|
|
9
|
+
*/
|
|
10
|
+
import type { Kysely } from 'kysely';
|
|
11
|
+
import type { ServerSyncDialect } from './dialect/types';
|
|
12
|
+
import type { SyncCoreDb } from './schema';
|
|
13
|
+
/**
|
|
14
|
+
* Well-known client_id for external/synthetic commits.
|
|
15
|
+
* Used by the pull handler to detect external data changes.
|
|
16
|
+
*/
|
|
17
|
+
export declare const EXTERNAL_CLIENT_ID = "__external__";
|
|
18
|
+
export interface NotifyExternalDataChangeArgs<DB extends SyncCoreDb> {
|
|
19
|
+
db: Kysely<DB>;
|
|
20
|
+
dialect: ServerSyncDialect;
|
|
21
|
+
/** Table names that were externally modified. */
|
|
22
|
+
tables: string[];
|
|
23
|
+
/** Partition key. Defaults to 'default'. */
|
|
24
|
+
partitionId?: string;
|
|
25
|
+
/** Actor identifier for the synthetic commit. Defaults to '__external__'. */
|
|
26
|
+
actorId?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface NotifyExternalDataChangeResult {
|
|
29
|
+
/** The commit_seq of the synthetic commit. */
|
|
30
|
+
commitSeq: number;
|
|
31
|
+
/** Tables that were notified. */
|
|
32
|
+
tables: string[];
|
|
33
|
+
/** Number of snapshot chunks deleted. */
|
|
34
|
+
deletedChunks: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Notify the sync framework about external data changes.
|
|
38
|
+
*
|
|
39
|
+
* Inserts a synthetic commit (client_id = '__external__'), clears cached
|
|
40
|
+
* snapshot chunks for the affected tables, and inserts sync_table_commits
|
|
41
|
+
* entries so the pull handler can detect the change.
|
|
42
|
+
*
|
|
43
|
+
* On next pull, subscriptions for affected tables will trigger a re-bootstrap
|
|
44
|
+
* instead of an incremental pull.
|
|
45
|
+
*/
|
|
46
|
+
export declare function notifyExternalDataChange<DB extends SyncCoreDb>(args: NotifyExternalDataChangeArgs<DB>): Promise<NotifyExternalDataChangeResult>;
|
|
47
|
+
//# sourceMappingURL=notify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../src/notify.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAc,MAAM,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C;;;GAGG;AACH,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAEjD,MAAM,WAAW,4BAA4B,CAAC,EAAE,SAAS,UAAU;IACjE,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACf,OAAO,EAAE,iBAAiB,CAAC;IAC3B,iDAAiD;IACjD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,8BAA8B;IAC7C,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,yCAAyC;IACzC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAAC,EAAE,SAAS,UAAU,EAClE,IAAI,EAAE,4BAA4B,CAAC,EAAE,CAAC,GACrC,OAAO,CAAC,8BAA8B,CAAC,CA6EzC"}
|
package/dist/notify.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/server - External data change notification
|
|
3
|
+
*
|
|
4
|
+
* Creates synthetic commits to notify the sync framework about data changes
|
|
5
|
+
* made outside the normal push flow (e.g., pipeline imports, direct DB writes).
|
|
6
|
+
*
|
|
7
|
+
* The synthetic commit forces affected subscriptions to re-bootstrap on next pull,
|
|
8
|
+
* ensuring clients receive the updated data.
|
|
9
|
+
*/
|
|
10
|
+
import { randomUUID } from 'node:crypto';
|
|
11
|
+
/**
|
|
12
|
+
* Well-known client_id for external/synthetic commits.
|
|
13
|
+
* Used by the pull handler to detect external data changes.
|
|
14
|
+
*/
|
|
15
|
+
export const EXTERNAL_CLIENT_ID = '__external__';
|
|
16
|
+
/**
|
|
17
|
+
* Notify the sync framework about external data changes.
|
|
18
|
+
*
|
|
19
|
+
* Inserts a synthetic commit (client_id = '__external__'), clears cached
|
|
20
|
+
* snapshot chunks for the affected tables, and inserts sync_table_commits
|
|
21
|
+
* entries so the pull handler can detect the change.
|
|
22
|
+
*
|
|
23
|
+
* On next pull, subscriptions for affected tables will trigger a re-bootstrap
|
|
24
|
+
* instead of an incremental pull.
|
|
25
|
+
*/
|
|
26
|
+
export async function notifyExternalDataChange(args) {
|
|
27
|
+
const { db, dialect, tables } = args;
|
|
28
|
+
const partitionId = args.partitionId ?? 'default';
|
|
29
|
+
const actorId = args.actorId ?? EXTERNAL_CLIENT_ID;
|
|
30
|
+
if (tables.length === 0) {
|
|
31
|
+
throw new Error('notifyExternalDataChange: tables must not be empty');
|
|
32
|
+
}
|
|
33
|
+
return dialect.executeInTransaction(db, async (trx) => {
|
|
34
|
+
const syncTrx = trx;
|
|
35
|
+
const clientCommitId = `ext_${Date.now()}_${randomUUID()}`;
|
|
36
|
+
// 1. Insert synthetic commit
|
|
37
|
+
const commitRow = {
|
|
38
|
+
partition_id: partitionId,
|
|
39
|
+
actor_id: actorId,
|
|
40
|
+
client_id: EXTERNAL_CLIENT_ID,
|
|
41
|
+
client_commit_id: clientCommitId,
|
|
42
|
+
meta: null,
|
|
43
|
+
result_json: { ok: true, status: 'applied' },
|
|
44
|
+
change_count: 0,
|
|
45
|
+
affected_tables: dialect.arrayToDb(tables),
|
|
46
|
+
};
|
|
47
|
+
await syncTrx.insertInto('sync_commits').values(commitRow).execute();
|
|
48
|
+
// Read back the assigned commit_seq
|
|
49
|
+
const inserted = await syncTrx
|
|
50
|
+
.selectFrom('sync_commits')
|
|
51
|
+
.select(['commit_seq'])
|
|
52
|
+
.where('partition_id', '=', partitionId)
|
|
53
|
+
.where('client_id', '=', EXTERNAL_CLIENT_ID)
|
|
54
|
+
.where('client_commit_id', '=', clientCommitId)
|
|
55
|
+
.executeTakeFirstOrThrow();
|
|
56
|
+
const commitSeq = Number(inserted.commit_seq);
|
|
57
|
+
// 2. Insert sync_table_commits entries for each affected table
|
|
58
|
+
const tableCommits = tables.map((table) => ({
|
|
59
|
+
partition_id: partitionId,
|
|
60
|
+
table,
|
|
61
|
+
commit_seq: commitSeq,
|
|
62
|
+
}));
|
|
63
|
+
await syncTrx
|
|
64
|
+
.insertInto('sync_table_commits')
|
|
65
|
+
.values(tableCommits)
|
|
66
|
+
.onConflict((oc) => oc.columns(['partition_id', 'table', 'commit_seq']).doNothing())
|
|
67
|
+
.execute();
|
|
68
|
+
// 3. Delete cached snapshot chunks for affected tables
|
|
69
|
+
let deletedChunks = 0;
|
|
70
|
+
for (const table of tables) {
|
|
71
|
+
const result = await syncTrx
|
|
72
|
+
.deleteFrom('sync_snapshot_chunks')
|
|
73
|
+
.where('partition_id', '=', partitionId)
|
|
74
|
+
.where('scope', '=', table)
|
|
75
|
+
.executeTakeFirst();
|
|
76
|
+
deletedChunks += Number(result?.numDeletedRows ?? 0);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
commitSeq,
|
|
80
|
+
tables,
|
|
81
|
+
deletedChunks,
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=notify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify.js","sourceRoot":"","sources":["../src/notify.ts"],"names":[],"mappings":"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"}
|
package/dist/pull.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../src/pull.ts"],"names":[],"mappings":"AAGA,OAAO,EAML,KAAK,WAAW,EAMhB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EAItB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../src/pull.ts"],"names":[],"mappings":"AAGA,OAAO,EAML,KAAK,WAAW,EAMhB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EAItB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAc,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAErE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAKvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAiFpE,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B;;;OAGG;IACH,eAAe,EAAE,WAAW,CAAC;IAC7B,oFAAoF;IACpF,YAAY,EAAE,MAAM,CAAC;CACtB;AAqLD,wBAAsB,IAAI,CAAC,EAAE,SAAS,UAAU,EAAE,IAAI,EAAE;IACtD,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACf,OAAO,EAAE,iBAAiB,CAAC;IAC3B,MAAM,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,eAAe,CAAC;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACrC,GAAG,OAAO,CAAC,UAAU,CAAC,CAqlBtB"}
|
package/dist/pull.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createHash, randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { promisify } from 'node:util';
|
|
3
3
|
import { gzip, gzipSync } from 'node:zlib';
|
|
4
4
|
import { captureSyncException, countSyncMetric, distributionSyncMetric, encodeSnapshotRowFrames, encodeSnapshotRows, SYNC_SNAPSHOT_CHUNK_COMPRESSION, SYNC_SNAPSHOT_CHUNK_ENCODING, startSyncSpan, } from '@syncular/core';
|
|
5
|
+
import { EXTERNAL_CLIENT_ID } from './notify.js';
|
|
5
6
|
import { insertSnapshotChunk, readSnapshotChunkRefByPageKey, } from './snapshot-chunks.js';
|
|
6
7
|
import { resolveEffectiveScopesForSubscriptions } from './subscriptions/resolve.js';
|
|
7
8
|
const gzipAsync = promisify(gzip);
|
|
@@ -167,6 +168,25 @@ function recordPullMetrics(args) {
|
|
|
167
168
|
});
|
|
168
169
|
distributionSyncMetric('sync.server.pull.snapshot_pages', stats.snapshotPageCount, { attributes });
|
|
169
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Read synthetic commits created by notifyExternalDataChange() after a given cursor.
|
|
173
|
+
* Returns commit_seq and affected tables for each external change commit.
|
|
174
|
+
*/
|
|
175
|
+
async function readExternalDataChanges(trx, dialect, args) {
|
|
176
|
+
const executor = trx;
|
|
177
|
+
const rows = await executor
|
|
178
|
+
.selectFrom('sync_commits')
|
|
179
|
+
.select(['commit_seq', 'affected_tables'])
|
|
180
|
+
.where('partition_id', '=', args.partitionId)
|
|
181
|
+
.where('client_id', '=', EXTERNAL_CLIENT_ID)
|
|
182
|
+
.where('commit_seq', '>', args.afterCursor)
|
|
183
|
+
.orderBy('commit_seq', 'asc')
|
|
184
|
+
.execute();
|
|
185
|
+
return rows.map((row) => ({
|
|
186
|
+
commitSeq: Number(row.commit_seq),
|
|
187
|
+
tables: dialect.dbToArray(row.affected_tables),
|
|
188
|
+
}));
|
|
189
|
+
}
|
|
170
190
|
export async function pull(args) {
|
|
171
191
|
const { request, dialect } = args;
|
|
172
192
|
const db = args.db;
|
|
@@ -207,6 +227,24 @@ export async function pull(args) {
|
|
|
207
227
|
const subResponses = [];
|
|
208
228
|
const activeSubscriptions = [];
|
|
209
229
|
const nextCursors = [];
|
|
230
|
+
// Detect external data changes (synthetic commits from notifyExternalDataChange)
|
|
231
|
+
// Compute minimum cursor across all active subscriptions to scope the query.
|
|
232
|
+
let minSubCursor = Number.MAX_SAFE_INTEGER;
|
|
233
|
+
for (const sub of resolved) {
|
|
234
|
+
if (sub.status === 'revoked' ||
|
|
235
|
+
Object.keys(sub.scopes).length === 0)
|
|
236
|
+
continue;
|
|
237
|
+
const cursor = Math.max(-1, sub.cursor ?? -1);
|
|
238
|
+
if (cursor >= 0 && cursor < minSubCursor) {
|
|
239
|
+
minSubCursor = cursor;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const externalDataChanges = minSubCursor < Number.MAX_SAFE_INTEGER && minSubCursor >= 0
|
|
243
|
+
? await readExternalDataChanges(trx, dialect, {
|
|
244
|
+
partitionId,
|
|
245
|
+
afterCursor: minSubCursor,
|
|
246
|
+
})
|
|
247
|
+
: [];
|
|
210
248
|
for (const sub of resolved) {
|
|
211
249
|
const cursor = Math.max(-1, sub.cursor ?? -1);
|
|
212
250
|
// Validate shape exists (throws if not registered)
|
|
@@ -228,7 +266,8 @@ export async function pull(args) {
|
|
|
228
266
|
const needsBootstrap = sub.bootstrapState != null ||
|
|
229
267
|
cursor < 0 ||
|
|
230
268
|
cursor > maxCommitSeq ||
|
|
231
|
-
(minCommitSeq > 0 && cursor < minCommitSeq - 1)
|
|
269
|
+
(minCommitSeq > 0 && cursor < minCommitSeq - 1) ||
|
|
270
|
+
externalDataChanges.some((c) => c.commitSeq > cursor && c.tables.includes(sub.shape));
|
|
232
271
|
if (needsBootstrap) {
|
|
233
272
|
const tables = args.shapes
|
|
234
273
|
.getBootstrapOrderFor(sub.shape)
|