@syncular/core 0.0.1 → 0.0.2-126
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 +24 -0
- package/dist/blobs.d.ts +9 -4
- package/dist/blobs.d.ts.map +1 -1
- package/dist/blobs.js +0 -12
- package/dist/blobs.js.map +1 -1
- package/dist/column-codecs.d.ts +55 -0
- package/dist/column-codecs.d.ts.map +1 -0
- package/dist/column-codecs.js +124 -0
- package/dist/column-codecs.js.map +1 -0
- package/dist/index.d.ts +11 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -7
- package/dist/index.js.map +1 -1
- package/dist/kysely-serialize.d.ts +1 -1
- package/dist/kysely-serialize.d.ts.map +1 -1
- package/dist/logger.d.ts +7 -32
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +6 -40
- package/dist/logger.js.map +1 -1
- package/dist/proxy/types.d.ts +0 -9
- package/dist/proxy/types.d.ts.map +1 -1
- package/dist/schemas/index.js +3 -3
- package/dist/schemas/sync.d.ts +120 -6
- package/dist/schemas/sync.d.ts.map +1 -1
- package/dist/schemas/sync.js +17 -3
- package/dist/schemas/sync.js.map +1 -1
- package/dist/scopes/index.d.ts +39 -64
- package/dist/scopes/index.d.ts.map +1 -1
- package/dist/scopes/index.js +9 -154
- package/dist/scopes/index.js.map +1 -1
- package/dist/snapshot-chunks.d.ts +26 -0
- package/dist/snapshot-chunks.d.ts.map +1 -0
- package/dist/snapshot-chunks.js +89 -0
- package/dist/snapshot-chunks.js.map +1 -0
- package/dist/telemetry.d.ts +114 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +113 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +12 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/id.d.ts +2 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js +8 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/object.d.ts +2 -0
- package/dist/utils/object.d.ts.map +1 -0
- package/dist/utils/object.js +4 -0
- package/dist/utils/object.js.map +1 -0
- package/package.json +28 -8
- package/src/__tests__/telemetry.test.ts +170 -0
- package/src/__tests__/utils.test.ts +27 -0
- package/src/blobs.ts +15 -14
- package/src/column-codecs.ts +228 -0
- package/src/index.ts +15 -41
- package/src/kysely-serialize.ts +1 -1
- package/src/logger.ts +10 -68
- package/src/proxy/types.ts +0 -10
- package/src/schemas/sync.ts +27 -3
- package/src/scopes/index.ts +72 -200
- package/src/snapshot-chunks.ts +112 -0
- package/src/telemetry.ts +238 -0
- package/src/types.ts +14 -18
- package/src/utils/id.ts +7 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/object.ts +3 -0
package/src/telemetry.ts
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/core - Runtime telemetry abstraction
|
|
3
|
+
*
|
|
4
|
+
* Provides vendor-neutral logging, tracing, and metrics interfaces so
|
|
5
|
+
* Syncular libraries can emit telemetry without coupling to a specific SDK.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Supported log levels.
|
|
10
|
+
*/
|
|
11
|
+
export type SyncTelemetryLevel =
|
|
12
|
+
| 'trace'
|
|
13
|
+
| 'debug'
|
|
14
|
+
| 'info'
|
|
15
|
+
| 'warn'
|
|
16
|
+
| 'error'
|
|
17
|
+
| 'fatal';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Primitive attribute value used by traces and metrics.
|
|
21
|
+
*/
|
|
22
|
+
export type SyncTelemetryAttributeValue = string | number | boolean;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Attribute bag used by traces and metrics.
|
|
26
|
+
*/
|
|
27
|
+
export type SyncTelemetryAttributes = Record<
|
|
28
|
+
string,
|
|
29
|
+
SyncTelemetryAttributeValue
|
|
30
|
+
>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Structured sync log event.
|
|
34
|
+
*/
|
|
35
|
+
export interface SyncTelemetryEvent {
|
|
36
|
+
event: string;
|
|
37
|
+
level?: SyncTelemetryLevel;
|
|
38
|
+
userId?: string;
|
|
39
|
+
durationMs?: number;
|
|
40
|
+
rowCount?: number;
|
|
41
|
+
resetRequired?: boolean;
|
|
42
|
+
error?: string;
|
|
43
|
+
[key: string]: unknown;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Span creation options.
|
|
48
|
+
*/
|
|
49
|
+
export interface SyncSpanOptions {
|
|
50
|
+
name: string;
|
|
51
|
+
op?: string;
|
|
52
|
+
attributes?: SyncTelemetryAttributes;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Span API exposed to Syncular internals.
|
|
57
|
+
*/
|
|
58
|
+
export interface SyncSpan {
|
|
59
|
+
setAttribute(name: string, value: SyncTelemetryAttributeValue): void;
|
|
60
|
+
setAttributes(attributes: SyncTelemetryAttributes): void;
|
|
61
|
+
setStatus(status: 'ok' | 'error'): void;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Tracing interface.
|
|
66
|
+
*/
|
|
67
|
+
export interface SyncTracer {
|
|
68
|
+
startSpan<T>(options: SyncSpanOptions, callback: (span: SyncSpan) => T): T;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Metric record options.
|
|
73
|
+
*/
|
|
74
|
+
export interface SyncMetricOptions {
|
|
75
|
+
attributes?: SyncTelemetryAttributes;
|
|
76
|
+
unit?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Metrics interface.
|
|
81
|
+
*/
|
|
82
|
+
export interface SyncMetrics {
|
|
83
|
+
count(name: string, value?: number, options?: SyncMetricOptions): void;
|
|
84
|
+
gauge(name: string, value: number, options?: SyncMetricOptions): void;
|
|
85
|
+
distribution(name: string, value: number, options?: SyncMetricOptions): void;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Unified telemetry interface.
|
|
90
|
+
*/
|
|
91
|
+
export interface SyncTelemetry {
|
|
92
|
+
log(event: SyncTelemetryEvent): void;
|
|
93
|
+
tracer: SyncTracer;
|
|
94
|
+
metrics: SyncMetrics;
|
|
95
|
+
captureException(error: unknown, context?: Record<string, unknown>): void;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const noopSpan: SyncSpan = {
|
|
99
|
+
setAttribute() {},
|
|
100
|
+
setAttributes() {},
|
|
101
|
+
setStatus() {},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const noopTracer: SyncTracer = {
|
|
105
|
+
startSpan(_options, callback) {
|
|
106
|
+
return callback(noopSpan);
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const noopMetrics: SyncMetrics = {
|
|
111
|
+
count() {},
|
|
112
|
+
gauge() {},
|
|
113
|
+
distribution() {},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
function createConsoleLogger(): (event: SyncTelemetryEvent) => void {
|
|
117
|
+
const isNode =
|
|
118
|
+
typeof globalThis !== 'undefined' &&
|
|
119
|
+
typeof globalThis.setImmediate === 'function';
|
|
120
|
+
|
|
121
|
+
const defer = isNode
|
|
122
|
+
? (fn: () => void) => globalThis.setImmediate(fn)
|
|
123
|
+
: (fn: () => void) => setTimeout(fn, 0);
|
|
124
|
+
|
|
125
|
+
return (event: SyncTelemetryEvent) => {
|
|
126
|
+
defer(() => {
|
|
127
|
+
const level = event.level ?? (event.error ? 'error' : 'info');
|
|
128
|
+
const payload = {
|
|
129
|
+
timestamp: new Date().toISOString(),
|
|
130
|
+
level,
|
|
131
|
+
...event,
|
|
132
|
+
};
|
|
133
|
+
console.log(JSON.stringify(payload));
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Create console-backed default telemetry (logs only; no-op tracing/metrics).
|
|
140
|
+
*/
|
|
141
|
+
export function createDefaultSyncTelemetry(): SyncTelemetry {
|
|
142
|
+
const logger = createConsoleLogger();
|
|
143
|
+
return {
|
|
144
|
+
log(event) {
|
|
145
|
+
logger(event);
|
|
146
|
+
},
|
|
147
|
+
tracer: noopTracer,
|
|
148
|
+
metrics: noopMetrics,
|
|
149
|
+
captureException(error, context) {
|
|
150
|
+
const message =
|
|
151
|
+
error instanceof Error
|
|
152
|
+
? error.message
|
|
153
|
+
: `Unknown error: ${String(error)}`;
|
|
154
|
+
logger({
|
|
155
|
+
event: 'sync.exception',
|
|
156
|
+
level: 'error',
|
|
157
|
+
error: message,
|
|
158
|
+
...(context ?? {}),
|
|
159
|
+
});
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let activeSyncTelemetry: SyncTelemetry = createDefaultSyncTelemetry();
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get currently configured telemetry backend.
|
|
168
|
+
*/
|
|
169
|
+
export function getSyncTelemetry(): SyncTelemetry {
|
|
170
|
+
return activeSyncTelemetry;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Replace active telemetry backend.
|
|
175
|
+
*/
|
|
176
|
+
export function configureSyncTelemetry(telemetry: SyncTelemetry): void {
|
|
177
|
+
activeSyncTelemetry = telemetry;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Reset telemetry backend to default console implementation.
|
|
182
|
+
*/
|
|
183
|
+
export function resetSyncTelemetry(): void {
|
|
184
|
+
activeSyncTelemetry = createDefaultSyncTelemetry();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Capture an exception through the active telemetry backend.
|
|
189
|
+
*/
|
|
190
|
+
export function captureSyncException(
|
|
191
|
+
error: unknown,
|
|
192
|
+
context?: Record<string, unknown>
|
|
193
|
+
): void {
|
|
194
|
+
activeSyncTelemetry.captureException(error, context);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Start a span through the active telemetry backend.
|
|
199
|
+
*/
|
|
200
|
+
export function startSyncSpan<T>(
|
|
201
|
+
options: SyncSpanOptions,
|
|
202
|
+
callback: (span: SyncSpan) => T
|
|
203
|
+
): T {
|
|
204
|
+
return activeSyncTelemetry.tracer.startSpan(options, callback);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Record a counter metric through the active telemetry backend.
|
|
209
|
+
*/
|
|
210
|
+
export function countSyncMetric(
|
|
211
|
+
name: string,
|
|
212
|
+
value?: number,
|
|
213
|
+
options?: SyncMetricOptions
|
|
214
|
+
): void {
|
|
215
|
+
activeSyncTelemetry.metrics.count(name, value, options);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Record a gauge metric through the active telemetry backend.
|
|
220
|
+
*/
|
|
221
|
+
export function gaugeSyncMetric(
|
|
222
|
+
name: string,
|
|
223
|
+
value: number,
|
|
224
|
+
options?: SyncMetricOptions
|
|
225
|
+
): void {
|
|
226
|
+
activeSyncTelemetry.metrics.gauge(name, value, options);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Record a distribution metric through the active telemetry backend.
|
|
231
|
+
*/
|
|
232
|
+
export function distributionSyncMetric(
|
|
233
|
+
name: string,
|
|
234
|
+
value: number,
|
|
235
|
+
options?: SyncMetricOptions
|
|
236
|
+
): void {
|
|
237
|
+
activeSyncTelemetry.metrics.distribution(name, value, options);
|
|
238
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -5,12 +5,7 @@
|
|
|
5
5
|
* Protocol types (SyncOp, SyncPushRequest, etc.) live in ./schemas/sync.ts
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type {
|
|
9
|
-
SyncPullRequest,
|
|
10
|
-
SyncPullResponse,
|
|
11
|
-
SyncPushRequest,
|
|
12
|
-
SyncPushResponse,
|
|
13
|
-
} from './schemas/sync';
|
|
8
|
+
import type { SyncCombinedRequest, SyncCombinedResponse } from './schemas/sync';
|
|
14
9
|
|
|
15
10
|
// ============================================================================
|
|
16
11
|
// Conflict Detection Types
|
|
@@ -126,30 +121,31 @@ export interface SyncTransportBlobs {
|
|
|
126
121
|
*/
|
|
127
122
|
export interface SyncTransport {
|
|
128
123
|
/**
|
|
129
|
-
*
|
|
124
|
+
* Combined push+pull in a single round-trip.
|
|
130
125
|
*/
|
|
131
|
-
|
|
132
|
-
request:
|
|
126
|
+
sync(
|
|
127
|
+
request: SyncCombinedRequest,
|
|
133
128
|
options?: SyncTransportOptions
|
|
134
|
-
): Promise<
|
|
129
|
+
): Promise<SyncCombinedResponse>;
|
|
135
130
|
|
|
136
131
|
/**
|
|
137
|
-
*
|
|
132
|
+
* Download an encoded bootstrap snapshot chunk.
|
|
138
133
|
*/
|
|
139
|
-
|
|
140
|
-
request:
|
|
134
|
+
fetchSnapshotChunk(
|
|
135
|
+
request: { chunkId: string },
|
|
141
136
|
options?: SyncTransportOptions
|
|
142
|
-
): Promise<
|
|
137
|
+
): Promise<Uint8Array>;
|
|
143
138
|
|
|
144
139
|
/**
|
|
145
|
-
*
|
|
140
|
+
* Optional streaming snapshot chunk download.
|
|
146
141
|
*
|
|
147
|
-
*
|
|
142
|
+
* When implemented, clients can decode and apply large bootstrap chunks
|
|
143
|
+
* incrementally without materializing the entire chunk in memory.
|
|
148
144
|
*/
|
|
149
|
-
|
|
145
|
+
fetchSnapshotChunkStream?(
|
|
150
146
|
request: { chunkId: string },
|
|
151
147
|
options?: SyncTransportOptions
|
|
152
|
-
): Promise<Uint8Array
|
|
148
|
+
): Promise<ReadableStream<Uint8Array>>;
|
|
153
149
|
|
|
154
150
|
/**
|
|
155
151
|
* Optional blob operations.
|
package/src/utils/id.ts
ADDED