@powersync/service-types 0.16.1 → 0.18.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/CHANGELOG.md +20 -0
- package/dist/codecs.d.ts +29 -0
- package/dist/codecs.js +85 -0
- package/dist/codecs.js.map +1 -0
- package/dist/config/PowerSyncConfig.d.ts +28 -12
- package/dist/config/PowerSyncConfig.js +29 -21
- package/dist/config/PowerSyncConfig.js.map +1 -1
- package/dist/definitions.d.ts +10 -6
- package/dist/definitions.js +6 -1
- package/dist/definitions.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/metrics.d.ts +6 -1
- package/dist/metrics.js +6 -0
- package/dist/metrics.js.map +1 -1
- package/dist/routes.d.ts +10 -5
- package/dist/routes.js +3 -2
- package/dist/routes.js.map +1 -1
- package/package.json +6 -2
- package/src/codecs.ts +112 -0
- package/src/config/PowerSyncConfig.ts +31 -21
- package/src/definitions.ts +6 -1
- package/src/index.ts +1 -0
- package/src/metrics.ts +7 -1
- package/src/routes.ts +3 -2
- package/test/codecs.test.ts +77 -0
- package/tsconfig.tsbuildinfo +1 -1
package/dist/metrics.d.ts
CHANGED
|
@@ -13,6 +13,11 @@ export declare enum ReplicationMetric {
|
|
|
13
13
|
}
|
|
14
14
|
export declare enum StorageMetric {
|
|
15
15
|
REPLICATION_SIZE_BYTES = "powersync_replication_storage_size_bytes",
|
|
16
|
+
ATTRIBUTED_SOURCE_RECORDS_BYTES = "powersync_attributed_source_records_bytes",
|
|
16
17
|
OPERATION_SIZE_BYTES = "powersync_operation_storage_size_bytes",
|
|
17
|
-
|
|
18
|
+
ATTRIBUTED_BUCKET_DATA_BYTES = "powersync_attributed_bucket_data_bytes",
|
|
19
|
+
PARAMETER_SIZE_BYTES = "powersync_parameter_storage_size_bytes",
|
|
20
|
+
ATTRIBUTED_PARAMETER_INDEXES_BYTES = "powersync_attributed_parameter_indexes_bytes",
|
|
21
|
+
OBJECT_STORAGE_SIZE_BYTES = "powersync_object_storage_size_bytes",
|
|
22
|
+
ATTRIBUTED_OBJECT_STORAGE_BYTES = "powersync_attributed_object_storage_bytes"
|
|
18
23
|
}
|
package/dist/metrics.js
CHANGED
|
@@ -27,9 +27,15 @@ export var StorageMetric;
|
|
|
27
27
|
(function (StorageMetric) {
|
|
28
28
|
// Size of current replication data stored in PowerSync
|
|
29
29
|
StorageMetric["REPLICATION_SIZE_BYTES"] = "powersync_replication_storage_size_bytes";
|
|
30
|
+
StorageMetric["ATTRIBUTED_SOURCE_RECORDS_BYTES"] = "powersync_attributed_source_records_bytes";
|
|
30
31
|
// Size of operations data stored in PowerSync
|
|
31
32
|
StorageMetric["OPERATION_SIZE_BYTES"] = "powersync_operation_storage_size_bytes";
|
|
33
|
+
StorageMetric["ATTRIBUTED_BUCKET_DATA_BYTES"] = "powersync_attributed_bucket_data_bytes";
|
|
32
34
|
// Size of parameter data stored in PowerSync
|
|
33
35
|
StorageMetric["PARAMETER_SIZE_BYTES"] = "powersync_parameter_storage_size_bytes";
|
|
36
|
+
StorageMetric["ATTRIBUTED_PARAMETER_INDEXES_BYTES"] = "powersync_attributed_parameter_indexes_bytes";
|
|
37
|
+
// Size of active S3 object-storage references stored in PowerSync
|
|
38
|
+
StorageMetric["OBJECT_STORAGE_SIZE_BYTES"] = "powersync_object_storage_size_bytes";
|
|
39
|
+
StorageMetric["ATTRIBUTED_OBJECT_STORAGE_BYTES"] = "powersync_attributed_object_storage_bytes";
|
|
34
40
|
})(StorageMetric || (StorageMetric = {}));
|
|
35
41
|
//# sourceMappingURL=metrics.js.map
|
package/dist/metrics.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,SASX;AATD,WAAY,SAAS;IACnB,6DAA6D;IAC7D,oEAAuD,CAAA;IACvD,qEAAqE;IACrE,gEAAmD,CAAA;IACnD,8BAA8B;IAC9B,oEAAuD,CAAA;IACvD,wCAAwC;IACxC,wEAA2D,CAAA;AAC7D,CAAC,EATW,SAAS,KAAT,SAAS,QASpB;AAED,MAAM,CAAN,IAAY,iBAYX;AAZD,WAAY,iBAAiB;IAC3B,qEAAqE;IACrE,oFAA+D,CAAA;IAC/D,yDAAyD;IACzD,wEAAmD,CAAA;IACnD,iEAAiE;IACjE,wFAAmE,CAAA;IACnE,4DAA4D;IAC5D,4EAAuD,CAAA;IACvD,kFAAkF;IAClF,uDAAuD;IACvD,kFAA6D,CAAA;AAC/D,CAAC,EAZW,iBAAiB,KAAjB,iBAAiB,QAY5B;AAED,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,SASX;AATD,WAAY,SAAS;IACnB,6DAA6D;IAC7D,oEAAuD,CAAA;IACvD,qEAAqE;IACrE,gEAAmD,CAAA;IACnD,8BAA8B;IAC9B,oEAAuD,CAAA;IACvD,wCAAwC;IACxC,wEAA2D,CAAA;AAC7D,CAAC,EATW,SAAS,KAAT,SAAS,QASpB;AAED,MAAM,CAAN,IAAY,iBAYX;AAZD,WAAY,iBAAiB;IAC3B,qEAAqE;IACrE,oFAA+D,CAAA;IAC/D,yDAAyD;IACzD,wEAAmD,CAAA;IACnD,iEAAiE;IACjE,wFAAmE,CAAA;IACnE,4DAA4D;IAC5D,4EAAuD,CAAA;IACvD,kFAAkF;IAClF,uDAAuD;IACvD,kFAA6D,CAAA;AAC/D,CAAC,EAZW,iBAAiB,KAAjB,iBAAiB,QAY5B;AAED,MAAM,CAAN,IAAY,aAaX;AAbD,WAAY,aAAa;IACvB,uDAAuD;IACvD,oFAAmE,CAAA;IACnE,8FAA6E,CAAA;IAC7E,8CAA8C;IAC9C,gFAA+D,CAAA;IAC/D,wFAAuE,CAAA;IACvE,6CAA6C;IAC7C,gFAA+D,CAAA;IAC/D,oGAAmF,CAAA;IACnF,kEAAkE;IAClE,kFAAiE,CAAA;IACjE,8FAA6E,CAAA;AAC/E,CAAC,EAbW,aAAa,KAAb,aAAa,QAaxB"}
|
package/dist/routes.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export declare const ExecuteSqlRequest: t.ObjectCodec<{
|
|
|
28
28
|
connection_id: t.OptionalCodec<t.Codec<string, string, string, t.CodecProps>>;
|
|
29
29
|
sql: t.ObjectCodec<{
|
|
30
30
|
query: t.IdentityCodec<t.CodecType.String>;
|
|
31
|
-
args: t.ArrayCodec<t.
|
|
31
|
+
args: t.ArrayCodec<t.Codec<string | number | boolean, string | number | boolean>>;
|
|
32
32
|
}>;
|
|
33
33
|
}>;
|
|
34
34
|
export type ExecuteSqlRequest = t.Encoded<typeof ExecuteSqlRequest>;
|
|
@@ -36,7 +36,7 @@ export declare const ExecuteSqlResponse: t.ObjectCodec<{
|
|
|
36
36
|
success: t.IdentityCodec<t.CodecType.Boolean>;
|
|
37
37
|
results: t.ObjectCodec<{
|
|
38
38
|
columns: t.ArrayCodec<t.IdentityCodec<t.CodecType.String>>;
|
|
39
|
-
rows: t.ArrayCodec<t.ArrayCodec<t.
|
|
39
|
+
rows: t.ArrayCodec<t.ArrayCodec<t.Codec<string | number | boolean | null, string | number | boolean | null>>>;
|
|
40
40
|
}>;
|
|
41
41
|
/** Set if success = false */
|
|
42
42
|
error: t.OptionalCodec<t.Codec<string, string, string, t.CodecProps>>;
|
|
@@ -55,7 +55,7 @@ export declare const DiagnosticsResponse: t.ObjectCodec<{
|
|
|
55
55
|
postgres_uri: t.IdentityCodec<t.CodecType.String>;
|
|
56
56
|
connected: t.IdentityCodec<t.CodecType.Boolean>;
|
|
57
57
|
errors: t.ArrayCodec<t.ObjectCodec<{
|
|
58
|
-
level: t.
|
|
58
|
+
level: t.Codec<"warning" | "fatal", "warning" | "fatal">;
|
|
59
59
|
message: t.IdentityCodec<t.CodecType.String>;
|
|
60
60
|
location: t.OptionalCodec<t.Codec<{
|
|
61
61
|
start_offset: number;
|
|
@@ -112,6 +112,7 @@ export declare const DiagnosticsResponse: t.ObjectCodec<{
|
|
|
112
112
|
safe_wal_size?: number | undefined;
|
|
113
113
|
max_slot_wal_keep_size?: number | undefined;
|
|
114
114
|
}[];
|
|
115
|
+
version_label?: string | null | undefined;
|
|
115
116
|
content?: string | undefined;
|
|
116
117
|
}, {
|
|
117
118
|
errors: {
|
|
@@ -153,6 +154,7 @@ export declare const DiagnosticsResponse: t.ObjectCodec<{
|
|
|
153
154
|
safe_wal_size?: number | undefined;
|
|
154
155
|
max_slot_wal_keep_size?: number | undefined;
|
|
155
156
|
}[];
|
|
157
|
+
version_label?: string | null | undefined;
|
|
156
158
|
content?: string | undefined;
|
|
157
159
|
}, string, t.CodecProps>>;
|
|
158
160
|
/**
|
|
@@ -202,6 +204,7 @@ export declare const DiagnosticsResponse: t.ObjectCodec<{
|
|
|
202
204
|
safe_wal_size?: number | undefined;
|
|
203
205
|
max_slot_wal_keep_size?: number | undefined;
|
|
204
206
|
}[];
|
|
207
|
+
version_label?: string | null | undefined;
|
|
205
208
|
content?: string | undefined;
|
|
206
209
|
}, {
|
|
207
210
|
errors: {
|
|
@@ -243,6 +246,7 @@ export declare const DiagnosticsResponse: t.ObjectCodec<{
|
|
|
243
246
|
safe_wal_size?: number | undefined;
|
|
244
247
|
max_slot_wal_keep_size?: number | undefined;
|
|
245
248
|
}[];
|
|
249
|
+
version_label?: string | null | undefined;
|
|
246
250
|
content?: string | undefined;
|
|
247
251
|
}, string, t.CodecProps>>;
|
|
248
252
|
}>;
|
|
@@ -262,6 +266,7 @@ export declare const ValidateRequest: t.ObjectCodec<{
|
|
|
262
266
|
}>;
|
|
263
267
|
export type ValidateRequest = t.Encoded<typeof ValidateRequest>;
|
|
264
268
|
export declare const ValidateResponse: t.ObjectCodec<{
|
|
269
|
+
version_label: t.OptionalCodec<t.Codec<string | null, string | null, string, t.CodecProps>>;
|
|
265
270
|
content: t.OptionalCodec<t.Codec<string, string, string, t.CodecProps>>;
|
|
266
271
|
connections: t.ArrayCodec<t.ObjectCodec<{
|
|
267
272
|
id: t.IdentityCodec<t.CodecType.String>;
|
|
@@ -283,7 +288,7 @@ export declare const ValidateResponse: t.ObjectCodec<{
|
|
|
283
288
|
data_queries: t.IdentityCodec<t.CodecType.Boolean>;
|
|
284
289
|
parameter_queries: t.IdentityCodec<t.CodecType.Boolean>;
|
|
285
290
|
errors: t.ArrayCodec<t.ObjectCodec<{
|
|
286
|
-
level: t.
|
|
291
|
+
level: t.Codec<"warning" | "fatal", "warning" | "fatal">;
|
|
287
292
|
message: t.IdentityCodec<t.CodecType.String>;
|
|
288
293
|
location: t.OptionalCodec<t.Codec<{
|
|
289
294
|
start_offset: number;
|
|
@@ -297,7 +302,7 @@ export declare const ValidateResponse: t.ObjectCodec<{
|
|
|
297
302
|
}>>;
|
|
298
303
|
}>>;
|
|
299
304
|
errors: t.ArrayCodec<t.ObjectCodec<{
|
|
300
|
-
level: t.
|
|
305
|
+
level: t.Codec<"warning" | "fatal", "warning" | "fatal">;
|
|
301
306
|
message: t.IdentityCodec<t.CodecType.String>;
|
|
302
307
|
location: t.OptionalCodec<t.Codec<{
|
|
303
308
|
start_offset: number;
|
package/dist/routes.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as t from 'ts-codec';
|
|
2
|
+
import { anyPrimitive } from './codecs.js';
|
|
2
3
|
import { ConnectionStatus, InstanceSchema, SyncRulesStatus } from './definitions.js';
|
|
3
4
|
export const GetSchemaRequest = t.object({});
|
|
4
5
|
export const GetSchemaResponse = InstanceSchema;
|
|
@@ -6,14 +7,14 @@ export const ExecuteSqlRequest = t.object({
|
|
|
6
7
|
connection_id: t.string.optional(),
|
|
7
8
|
sql: t.object({
|
|
8
9
|
query: t.string,
|
|
9
|
-
args: t.array(
|
|
10
|
+
args: t.array(anyPrimitive({ string: true, number: true, boolean: true }))
|
|
10
11
|
})
|
|
11
12
|
});
|
|
12
13
|
export const ExecuteSqlResponse = t.object({
|
|
13
14
|
success: t.boolean,
|
|
14
15
|
results: t.object({
|
|
15
16
|
columns: t.array(t.string),
|
|
16
|
-
rows: t.array(t.array(
|
|
17
|
+
rows: t.array(t.array(anyPrimitive({ string: true, number: true, boolean: true, null: true })))
|
|
17
18
|
}),
|
|
18
19
|
/** Set if success = false */
|
|
19
20
|
error: t.string.optional()
|
package/dist/routes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAErF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAG7C,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAGhD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;IAClC,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC;QACZ,KAAK,EAAE,CAAC,CAAC,MAAM;QACf,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAErF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAG7C,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAGhD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;IAClC,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC;QACZ,KAAK,EAAE,CAAC,CAAC,MAAM;QACf,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;KAC3E,CAAC;CACH,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC,OAAO;IAClB,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;QAChB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QAC1B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;KAChG,CAAC;IACF,6BAA6B;IAC7B,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;CAC3B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,kBAAkB,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE;CACzC,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C;;OAEG;IACH,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;IAEtC;;;;OAIG;IACH,iBAAiB,EAAE,eAAe,CAAC,QAAQ,EAAE;IAE7C;;;;;;OAMG;IACH,oBAAoB,EAAE,eAAe,CAAC,QAAQ,EAAE;CACjD,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAG7C,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,WAAW,EAAE,CAAC,CAAC,KAAK,CAClB,CAAC,CAAC,MAAM,CAAC;QACP,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;QACvB,GAAG,EAAE,CAAC,CAAC,MAAM;QACb,SAAS,EAAE,CAAC,CAAC,MAAM;KACpB,CAAC,CACH;CACF,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,UAAU,EAAE,CAAC,CAAC,MAAM;CACrB,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,gBAAgB,GAAG,eAAe,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powersync/service-types",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"exports": "./dist/index.js",
|
|
5
5
|
"license": "FSL-1.1-ALv2",
|
|
6
6
|
"type": "module",
|
|
@@ -13,8 +13,12 @@
|
|
|
13
13
|
"ts-codec": "^1.3.0",
|
|
14
14
|
"uri-js": "^4.4.1"
|
|
15
15
|
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"vitest": "^4.1.5"
|
|
18
|
+
},
|
|
16
19
|
"scripts": {
|
|
17
20
|
"clean": "rm -r ./dist && tsc -b --clean",
|
|
18
|
-
"build": "tsc -b"
|
|
21
|
+
"build": "tsc -b",
|
|
22
|
+
"test": "vitest"
|
|
19
23
|
}
|
|
20
24
|
}
|
package/src/codecs.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { AnyCodec, Codec, Ix, Ox, Union } from 'ts-codec';
|
|
2
|
+
import * as t from 'ts-codec';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* An optimized codec equivalent to `type.or(Null)`.
|
|
6
|
+
*/
|
|
7
|
+
export function orNull<T extends AnyCodec>(type: T): Codec<Ix<T> | null, Ox<T> | null> {
|
|
8
|
+
return t.codec(
|
|
9
|
+
t.CodecType.Union,
|
|
10
|
+
(data) => {
|
|
11
|
+
if (data === null) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
return type.encode(data);
|
|
15
|
+
},
|
|
16
|
+
(data) => {
|
|
17
|
+
if (data === null) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
return type.decode(data);
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
codecs: [type, t.Null]
|
|
24
|
+
} satisfies Union<T, typeof t.Null>['props']
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A codec parsing a static enumeration of literals.
|
|
30
|
+
*
|
|
31
|
+
* `enumLiteral('foo', 'bar')` is an equivalent but more efficient implementation of
|
|
32
|
+
* `literal('foo').or(literal('bar'))`
|
|
33
|
+
*/
|
|
34
|
+
export function enumLiteral<T extends string>(...values: T[]): Codec<T, T> {
|
|
35
|
+
function validate(source: unknown): T {
|
|
36
|
+
function invalid(): never {
|
|
37
|
+
const allowed = values.join(', ');
|
|
38
|
+
throw new t.TransformError(`Expected one of ${allowed}, but got ${source}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (typeof source !== 'string') invalid();
|
|
42
|
+
if (!values.includes(source as T)) invalid();
|
|
43
|
+
|
|
44
|
+
return source as T;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return t.codec(t.CodecType.Enum, validate, validate, {
|
|
48
|
+
enum: values
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type NamedPrimitiveTypes = {
|
|
53
|
+
string: string;
|
|
54
|
+
number: number;
|
|
55
|
+
boolean: boolean;
|
|
56
|
+
null: null;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const primitiveCodecs: Record<keyof NamedPrimitiveTypes, AnyCodec> = {
|
|
60
|
+
string: t.string,
|
|
61
|
+
number: t.number,
|
|
62
|
+
boolean: t.boolean,
|
|
63
|
+
null: t.Null
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
type EnabledKeys<T> = {
|
|
67
|
+
[K in keyof T]: T[K] extends true ? K : never;
|
|
68
|
+
}[keyof T];
|
|
69
|
+
|
|
70
|
+
type PrimitiveUnion<T extends Partial<Record<keyof NamedPrimitiveTypes, boolean>>> = NamedPrimitiveTypes[Extract<
|
|
71
|
+
EnabledKeys<T>,
|
|
72
|
+
keyof NamedPrimitiveTypes
|
|
73
|
+
>];
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Parses multiple primitive types.
|
|
77
|
+
*
|
|
78
|
+
* `anyPrimitive({ boolean: true, string: true })` behaves identical to `boolean.or(string)`, but is more efficient.
|
|
79
|
+
*/
|
|
80
|
+
export function anyPrimitive<const T extends Partial<Record<keyof NamedPrimitiveTypes, boolean>>>(
|
|
81
|
+
allowedPrimitives: T
|
|
82
|
+
): Codec<PrimitiveUnion<T>, PrimitiveUnion<T>> {
|
|
83
|
+
function validate(source: unknown): PrimitiveUnion<T> {
|
|
84
|
+
switch (typeof source) {
|
|
85
|
+
case 'string':
|
|
86
|
+
if (allowedPrimitives.string) return source as PrimitiveUnion<T>;
|
|
87
|
+
break;
|
|
88
|
+
case 'number':
|
|
89
|
+
if (allowedPrimitives.number) return source as PrimitiveUnion<T>;
|
|
90
|
+
break;
|
|
91
|
+
case 'boolean':
|
|
92
|
+
if (allowedPrimitives.boolean) return source as PrimitiveUnion<T>;
|
|
93
|
+
break;
|
|
94
|
+
case 'object':
|
|
95
|
+
if (allowedPrimitives.null && source === null) return source as PrimitiveUnion<T>;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
throw new t.TransformError(`Primitive value ${source} is not allowed.`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const codecsForSchema: AnyCodec[] = [];
|
|
103
|
+
for (const [key, value] of Object.entries(allowedPrimitives)) {
|
|
104
|
+
if (value) {
|
|
105
|
+
codecsForSchema.push(primitiveCodecs[key as keyof NamedPrimitiveTypes]);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return t.codec(t.CodecType.Union, validate, validate, {
|
|
110
|
+
codecs: codecsForSchema
|
|
111
|
+
} satisfies Union<AnyCodec, AnyCodec>['props']);
|
|
112
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import dedent from 'dedent';
|
|
2
2
|
import * as t from 'ts-codec';
|
|
3
|
+
import { anyPrimitive, enumLiteral } from '../codecs.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* The meta tags here are used in the generated JSON schema.
|
|
@@ -96,10 +97,7 @@ export const jwkRSA = t
|
|
|
96
97
|
e: t.string.meta({
|
|
97
98
|
description: 'RSA exponent, Base64 URL encoded.'
|
|
98
99
|
}),
|
|
99
|
-
alg:
|
|
100
|
-
.literal('RS256')
|
|
101
|
-
.or(t.literal('RS384'))
|
|
102
|
-
.or(t.literal('RS512'))
|
|
100
|
+
alg: enumLiteral('RS256', 'RS384', 'RS512')
|
|
103
101
|
.meta({
|
|
104
102
|
description: 'The algorithm intended for use with this key (RS256, RS384, or RS512).'
|
|
105
103
|
})
|
|
@@ -128,7 +126,7 @@ export const jwkHmac = t
|
|
|
128
126
|
k: t.string.meta({
|
|
129
127
|
description: 'The HMAC key value, Base64 URL encoded.'
|
|
130
128
|
}),
|
|
131
|
-
alg:
|
|
129
|
+
alg: enumLiteral('HS256', 'HS384', 'HS512').meta({
|
|
132
130
|
description: 'The algorithm intended for use with this key (HS256, HS384, or HS512).'
|
|
133
131
|
}),
|
|
134
132
|
use: t.string
|
|
@@ -152,7 +150,7 @@ export const jwkOKP = t
|
|
|
152
150
|
})
|
|
153
151
|
.optional(),
|
|
154
152
|
/** Other curves have security issues so only these two are supported. */
|
|
155
|
-
crv:
|
|
153
|
+
crv: enumLiteral('Ed25519', 'Ed448').meta({
|
|
156
154
|
description: 'The cryptographic curve used with this key. Only Ed25519 and Ed448 are supported.'
|
|
157
155
|
}),
|
|
158
156
|
x: t.string.meta({
|
|
@@ -182,7 +180,7 @@ export const jwkEC = t
|
|
|
182
180
|
description: 'Key ID, a unique identifier for the key.'
|
|
183
181
|
})
|
|
184
182
|
.optional(),
|
|
185
|
-
crv:
|
|
183
|
+
crv: enumLiteral('P-256', 'P-384', 'P-521').meta({
|
|
186
184
|
description: 'The cryptographic curve used with this key (P-256, P-384, or P-521).'
|
|
187
185
|
}),
|
|
188
186
|
x: t.string.meta({
|
|
@@ -191,7 +189,7 @@ export const jwkEC = t
|
|
|
191
189
|
y: t.string.meta({
|
|
192
190
|
description: 'The y coordinate for the Elliptic Curve point, Base64 URL encoded.'
|
|
193
191
|
}),
|
|
194
|
-
alg:
|
|
192
|
+
alg: enumLiteral('ES256', 'ES384', 'ES512').meta({
|
|
195
193
|
description: 'The algorithm intended for use with this key (ES256, ES384, or ES512).'
|
|
196
194
|
}),
|
|
197
195
|
use: t.string
|
|
@@ -204,7 +202,7 @@ export const jwkEC = t
|
|
|
204
202
|
description: 'JSON Web Key (JWK) representation of an Elliptic Curve key.'
|
|
205
203
|
});
|
|
206
204
|
|
|
207
|
-
const jwk =
|
|
205
|
+
const jwk = jwkRSA.or(jwkHmac).or(jwkOKP).or(jwkEC).meta({
|
|
208
206
|
description: 'A JSON Web Key (JWK) representing a cryptographic key. Can be RSA, HMAC, OKP, or EC key types.'
|
|
209
207
|
});
|
|
210
208
|
|
|
@@ -222,21 +220,12 @@ export type StrictJwk = t.Decoded<typeof jwk>;
|
|
|
222
220
|
|
|
223
221
|
export const LoggingConfig = t
|
|
224
222
|
.object({
|
|
225
|
-
level:
|
|
226
|
-
.literal('silly')
|
|
227
|
-
.or(t.literal('debug'))
|
|
228
|
-
.or(t.literal('verbose'))
|
|
229
|
-
.or(t.literal('http'))
|
|
230
|
-
.or(t.literal('info'))
|
|
231
|
-
.or(t.literal('warn'))
|
|
232
|
-
.or(t.literal('error'))
|
|
223
|
+
level: enumLiteral('silly', 'debug', 'verbose', 'http', 'info', 'warn', 'error')
|
|
233
224
|
.meta({
|
|
234
225
|
description: 'Log level for the service logs.'
|
|
235
226
|
})
|
|
236
227
|
.optional(),
|
|
237
|
-
format:
|
|
238
|
-
.literal('json')
|
|
239
|
-
.or(t.literal('text'))
|
|
228
|
+
format: enumLiteral('json', 'text')
|
|
240
229
|
.meta({
|
|
241
230
|
description: 'Log output format.'
|
|
242
231
|
})
|
|
@@ -257,6 +246,12 @@ export const BaseStorageConfig = t
|
|
|
257
246
|
.meta({
|
|
258
247
|
description: 'Maximum number of connections to the storage database, per process. Defaults to 8.'
|
|
259
248
|
})
|
|
249
|
+
.optional(),
|
|
250
|
+
default_storage_version: t.number
|
|
251
|
+
.meta({
|
|
252
|
+
description:
|
|
253
|
+
'Storage version to use when deploying a sync config that does not specify storage_version. Defaults to 2.'
|
|
254
|
+
})
|
|
260
255
|
.optional()
|
|
261
256
|
})
|
|
262
257
|
.meta({
|
|
@@ -276,6 +271,11 @@ export type GenericStorageConfig = t.Encoded<typeof GenericStorageConfig>;
|
|
|
276
271
|
|
|
277
272
|
export const SyncConfig = t
|
|
278
273
|
.object({
|
|
274
|
+
version_label: t.string
|
|
275
|
+
.meta({
|
|
276
|
+
description: 'Optional label identifying this deployed sync config version.'
|
|
277
|
+
})
|
|
278
|
+
.optional(),
|
|
279
279
|
path: t.string
|
|
280
280
|
.meta({
|
|
281
281
|
description: 'Path to the sync config YAML file.'
|
|
@@ -409,6 +409,16 @@ export const powerSyncConfig = t
|
|
|
409
409
|
})
|
|
410
410
|
.optional(),
|
|
411
411
|
|
|
412
|
+
checkpoint_request_retention_minutes: t.number
|
|
413
|
+
.meta({
|
|
414
|
+
description: dedent`
|
|
415
|
+
Number of minutes to keep client-requested write checkpoint records.
|
|
416
|
+
Expired records are removed by the compact job.
|
|
417
|
+
Must be a positive integer. Default of 60.
|
|
418
|
+
`
|
|
419
|
+
})
|
|
420
|
+
.optional(),
|
|
421
|
+
|
|
412
422
|
bucket_count_cache_ttl_minutes: t.number
|
|
413
423
|
.meta({
|
|
414
424
|
description: dedent`
|
|
@@ -528,7 +538,7 @@ export const powerSyncConfig = t
|
|
|
528
538
|
.optional(),
|
|
529
539
|
|
|
530
540
|
parameters: t
|
|
531
|
-
.record(
|
|
541
|
+
.record(anyPrimitive({ null: true, number: true, string: true, boolean: true }))
|
|
532
542
|
.meta({
|
|
533
543
|
description: 'Global parameters that can be referenced in sync config and other configurations.'
|
|
534
544
|
})
|
package/src/definitions.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as t from 'ts-codec';
|
|
2
|
+
import { enumLiteral, orNull } from './codecs.js';
|
|
2
3
|
|
|
3
4
|
export const SourceSpan = t.object({
|
|
4
5
|
start_offset: t.number,
|
|
@@ -8,7 +9,7 @@ export type SourceSpan = t.Encoded<typeof SourceSpan>;
|
|
|
8
9
|
|
|
9
10
|
export const ReplicationError = t.object({
|
|
10
11
|
/** Warning: Could indicate an issue. Fatal: Prevents replicating. */
|
|
11
|
-
level:
|
|
12
|
+
level: enumLiteral('warning', 'fatal'),
|
|
12
13
|
message: t.string,
|
|
13
14
|
location: SourceSpan.optional(),
|
|
14
15
|
ts: t.string.optional()
|
|
@@ -35,6 +36,10 @@ export const TableInfo = t.object({
|
|
|
35
36
|
export type TableInfo = t.Encoded<typeof TableInfo>;
|
|
36
37
|
|
|
37
38
|
export const SyncRulesStatus = t.object({
|
|
39
|
+
/**
|
|
40
|
+
* Optional label identifying this deployed sync config version.
|
|
41
|
+
*/
|
|
42
|
+
version_label: orNull(t.string).optional(),
|
|
38
43
|
content: t.string.optional(),
|
|
39
44
|
connections: t.array(
|
|
40
45
|
t.object({
|
package/src/index.ts
CHANGED
package/src/metrics.ts
CHANGED
|
@@ -26,8 +26,14 @@ export enum ReplicationMetric {
|
|
|
26
26
|
export enum StorageMetric {
|
|
27
27
|
// Size of current replication data stored in PowerSync
|
|
28
28
|
REPLICATION_SIZE_BYTES = 'powersync_replication_storage_size_bytes',
|
|
29
|
+
ATTRIBUTED_SOURCE_RECORDS_BYTES = 'powersync_attributed_source_records_bytes',
|
|
29
30
|
// Size of operations data stored in PowerSync
|
|
30
31
|
OPERATION_SIZE_BYTES = 'powersync_operation_storage_size_bytes',
|
|
32
|
+
ATTRIBUTED_BUCKET_DATA_BYTES = 'powersync_attributed_bucket_data_bytes',
|
|
31
33
|
// Size of parameter data stored in PowerSync
|
|
32
|
-
PARAMETER_SIZE_BYTES = 'powersync_parameter_storage_size_bytes'
|
|
34
|
+
PARAMETER_SIZE_BYTES = 'powersync_parameter_storage_size_bytes',
|
|
35
|
+
ATTRIBUTED_PARAMETER_INDEXES_BYTES = 'powersync_attributed_parameter_indexes_bytes',
|
|
36
|
+
// Size of active S3 object-storage references stored in PowerSync
|
|
37
|
+
OBJECT_STORAGE_SIZE_BYTES = 'powersync_object_storage_size_bytes',
|
|
38
|
+
ATTRIBUTED_OBJECT_STORAGE_BYTES = 'powersync_attributed_object_storage_bytes'
|
|
33
39
|
}
|
package/src/routes.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as t from 'ts-codec';
|
|
2
|
+
import { anyPrimitive } from './codecs.js';
|
|
2
3
|
import { ConnectionStatus, InstanceSchema, SyncRulesStatus } from './definitions.js';
|
|
3
4
|
|
|
4
5
|
export const GetSchemaRequest = t.object({});
|
|
@@ -11,7 +12,7 @@ export const ExecuteSqlRequest = t.object({
|
|
|
11
12
|
connection_id: t.string.optional(),
|
|
12
13
|
sql: t.object({
|
|
13
14
|
query: t.string,
|
|
14
|
-
args: t.array(
|
|
15
|
+
args: t.array(anyPrimitive({ string: true, number: true, boolean: true }))
|
|
15
16
|
})
|
|
16
17
|
});
|
|
17
18
|
export type ExecuteSqlRequest = t.Encoded<typeof ExecuteSqlRequest>;
|
|
@@ -20,7 +21,7 @@ export const ExecuteSqlResponse = t.object({
|
|
|
20
21
|
success: t.boolean,
|
|
21
22
|
results: t.object({
|
|
22
23
|
columns: t.array(t.string),
|
|
23
|
-
rows: t.array(t.array(
|
|
24
|
+
rows: t.array(t.array(anyPrimitive({ string: true, number: true, boolean: true, null: true })))
|
|
24
25
|
}),
|
|
25
26
|
/** Set if success = false */
|
|
26
27
|
error: t.string.optional()
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as t from 'ts-codec';
|
|
2
|
+
import { describe, expect, test } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { anyPrimitive, enumLiteral, orNull } from '../src/codecs.js';
|
|
5
|
+
|
|
6
|
+
test('orNull', () => {
|
|
7
|
+
const codec = orNull(t.literal('allowed'));
|
|
8
|
+
|
|
9
|
+
expect(codec.encode('allowed')).toStrictEqual('allowed');
|
|
10
|
+
expect(codec.decode('allowed')).toStrictEqual('allowed');
|
|
11
|
+
expect(codec.encode(null)).toStrictEqual(null);
|
|
12
|
+
expect(codec.decode(null)).toStrictEqual(null);
|
|
13
|
+
|
|
14
|
+
expect(() => codec.encode('invalid' as any)).throws();
|
|
15
|
+
expect(() => codec.decode('invalid' as any)).throws();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('enumLiteral', () => {
|
|
19
|
+
const codec = enumLiteral('foo', 'bar', 'baz');
|
|
20
|
+
|
|
21
|
+
for (const value of ['foo', 'bar', 'baz'] as const) {
|
|
22
|
+
expect(codec.encode(value)).toStrictEqual(value);
|
|
23
|
+
expect(codec.decode(value)).toStrictEqual(value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
expect(() => codec.encode('invalid' as any)).throws();
|
|
27
|
+
expect(() => codec.decode('invalid' as any)).throws();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('anyPrimitive', () => {
|
|
31
|
+
test('allows only the configured types', () => {
|
|
32
|
+
const codec = anyPrimitive({ string: true, number: true }) as t.AnyCodec;
|
|
33
|
+
|
|
34
|
+
expect(codec.decode('foo')).toStrictEqual('foo');
|
|
35
|
+
expect(codec.decode(42)).toStrictEqual(42);
|
|
36
|
+
expect(codec.encode('foo')).toStrictEqual('foo');
|
|
37
|
+
expect(codec.encode(42)).toStrictEqual(42);
|
|
38
|
+
|
|
39
|
+
expect(() => codec.decode(true)).throws();
|
|
40
|
+
expect(() => codec.decode(null)).throws();
|
|
41
|
+
expect(() => codec.decode(undefined)).throws();
|
|
42
|
+
expect(() => codec.decode({})).throws();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('allows null', () => {
|
|
46
|
+
const codec = anyPrimitive({ null: true }) as t.AnyCodec;
|
|
47
|
+
|
|
48
|
+
expect(codec.decode(null)).toStrictEqual(null);
|
|
49
|
+
expect(codec.encode(null)).toStrictEqual(null);
|
|
50
|
+
|
|
51
|
+
expect(() => codec.decode('foo')).throws();
|
|
52
|
+
expect(() => codec.decode(undefined)).throws();
|
|
53
|
+
expect(() => codec.decode({})).throws();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('rejects types not in the configuration, even when other types are allowed', () => {
|
|
57
|
+
const codec = anyPrimitive({ boolean: true }) as t.AnyCodec;
|
|
58
|
+
|
|
59
|
+
expect(codec.decode(true)).toStrictEqual(true);
|
|
60
|
+
expect(codec.decode(false)).toStrictEqual(false);
|
|
61
|
+
|
|
62
|
+
expect(() => codec.decode('foo')).throws();
|
|
63
|
+
expect(() => codec.decode(1)).throws();
|
|
64
|
+
expect(() => codec.decode(null)).throws();
|
|
65
|
+
expect(() => codec.decode(undefined)).throws();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('with no allowed types rejects everything', () => {
|
|
69
|
+
const codec = anyPrimitive({}) as any as t.AnyCodec;
|
|
70
|
+
|
|
71
|
+
expect(() => codec.decode('foo')).throws();
|
|
72
|
+
expect(() => codec.decode(1)).throws();
|
|
73
|
+
expect(() => codec.decode(true)).throws();
|
|
74
|
+
expect(() => codec.decode(null)).throws();
|
|
75
|
+
expect(() => codec.decode(undefined)).throws();
|
|
76
|
+
});
|
|
77
|
+
});
|