@xube/kit-aws-data-schema 0.2.12 → 0.2.14
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/decode/reading.d.ts +30 -28
- package/dist/decode/reading.d.ts.map +1 -1
- package/dist/decode/reading.js +25 -39
- package/package.json +7 -7
- package/src/decode/reading.test.ts +153 -103
- package/src/decode/reading.ts +32 -50
package/dist/decode/reading.d.ts
CHANGED
|
@@ -33,17 +33,6 @@ export declare const ReadingMetadataV1Schema: z.ZodObject<{
|
|
|
33
33
|
}, z.core.$strip>;
|
|
34
34
|
export type ReadingMetadataV1 = z.infer<typeof ReadingMetadataV1Schema>;
|
|
35
35
|
export declare const isReadingMetadataV1: (item: unknown) => item is ReadingMetadataV1;
|
|
36
|
-
export declare const ReadingV1Schema: z.ZodObject<{
|
|
37
|
-
type: z.ZodString;
|
|
38
|
-
s: z.ZodNumber;
|
|
39
|
-
us: z.ZodOptional<z.ZodNumber>;
|
|
40
|
-
data: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodObject<{}, z.core.$loose>]>;
|
|
41
|
-
id: z.ZodString;
|
|
42
|
-
component: z.ZodOptional<z.ZodString>;
|
|
43
|
-
v: z.ZodDefault<z.ZodLiteral<1>>;
|
|
44
|
-
}, z.core.$loose>;
|
|
45
|
-
export type ReadingV1 = z.infer<typeof ReadingV1Schema>;
|
|
46
|
-
export declare const isReadingV1: (item: unknown) => item is ReadingV1;
|
|
47
36
|
export declare const ReadingV2MetadataSchema: z.ZodObject<{
|
|
48
37
|
v: z.ZodLiteral<2>;
|
|
49
38
|
tm: z.ZodNumber;
|
|
@@ -52,34 +41,47 @@ export declare const ReadingV2MetadataSchema: z.ZodObject<{
|
|
|
52
41
|
}, z.core.$strip>;
|
|
53
42
|
export type ReadingV2Metadata = z.infer<typeof ReadingV2MetadataSchema>;
|
|
54
43
|
export declare const isReadingV2Metadata: (item: unknown) => item is ReadingV2Metadata;
|
|
55
|
-
export declare const
|
|
56
|
-
|
|
44
|
+
export declare const ReadingSchema: z.ZodObject<{
|
|
45
|
+
v: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>]>>;
|
|
57
46
|
id: z.ZodString;
|
|
58
47
|
component: z.ZodOptional<z.ZodString>;
|
|
59
|
-
|
|
60
|
-
|
|
48
|
+
type: z.ZodString;
|
|
49
|
+
s: z.ZodNumber;
|
|
50
|
+
us: z.ZodOptional<z.ZodNumber>;
|
|
51
|
+
data: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodObject<{}, z.core.$loose>]>;
|
|
61
52
|
bo: z.ZodOptional<z.ZodBoolean>;
|
|
62
53
|
so: z.ZodOptional<z.ZodBoolean>;
|
|
63
54
|
}, z.core.$loose>;
|
|
64
|
-
export type
|
|
65
|
-
export declare const
|
|
66
|
-
export declare const
|
|
55
|
+
export type Reading = z.infer<typeof ReadingSchema>;
|
|
56
|
+
export declare const isReading: (item: unknown) => item is Reading;
|
|
57
|
+
export declare const isReadingV1: (item: unknown) => item is Reading & {
|
|
58
|
+
v: typeof READING_VERSION_1;
|
|
59
|
+
};
|
|
60
|
+
export declare const isReadingV2: (item: unknown) => item is Reading & {
|
|
61
|
+
v: typeof READING_VERSION_2;
|
|
62
|
+
};
|
|
63
|
+
export declare const ReadingV1Schema: z.ZodObject<{
|
|
64
|
+
v: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>]>>;
|
|
65
|
+
id: z.ZodString;
|
|
66
|
+
component: z.ZodOptional<z.ZodString>;
|
|
67
67
|
type: z.ZodString;
|
|
68
68
|
s: z.ZodNumber;
|
|
69
69
|
us: z.ZodOptional<z.ZodNumber>;
|
|
70
70
|
data: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodObject<{}, z.core.$loose>]>;
|
|
71
|
+
bo: z.ZodOptional<z.ZodBoolean>;
|
|
72
|
+
so: z.ZodOptional<z.ZodBoolean>;
|
|
73
|
+
}, z.core.$loose>;
|
|
74
|
+
export type ReadingV1 = Reading;
|
|
75
|
+
export declare const ReadingV2Schema: z.ZodObject<{
|
|
76
|
+
v: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>]>>;
|
|
71
77
|
id: z.ZodString;
|
|
72
78
|
component: z.ZodOptional<z.ZodString>;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
component: z.ZodOptional<z.ZodString>;
|
|
78
|
-
v: z.ZodLiteral<2>;
|
|
79
|
-
tm: z.ZodNumber;
|
|
79
|
+
type: z.ZodString;
|
|
80
|
+
s: z.ZodNumber;
|
|
81
|
+
us: z.ZodOptional<z.ZodNumber>;
|
|
82
|
+
data: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodObject<{}, z.core.$loose>]>;
|
|
80
83
|
bo: z.ZodOptional<z.ZodBoolean>;
|
|
81
84
|
so: z.ZodOptional<z.ZodBoolean>;
|
|
82
|
-
}, z.core.$loose
|
|
83
|
-
export type
|
|
84
|
-
export declare const isReading: (item: unknown) => item is Reading;
|
|
85
|
+
}, z.core.$loose>;
|
|
86
|
+
export type ReadingV2 = Reading;
|
|
85
87
|
//# sourceMappingURL=reading.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reading.d.ts","sourceRoot":"","sources":["../../src/decode/reading.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,eAAO,MAAM,uBAAuB,IAAoB,CAAC;AAEzD,eAAO,MAAM,sBAAsB,+FAAyB,CAAC;AAE7D,eAAO,MAAM,6BAA6B;;;iBAGxC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAC3C,OAAO,6BAA6B,CACrC,CAAC;AACF,eAAO,MAAM,yBAAyB,SAC9B,OAAO,KACZ,IAAI,IAAI,uBAC4C,CAAC;AAExD,eAAO,MAAM,qBAAqB;;;;;;iBAGhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,eAAO,MAAM,iBAAiB,SAAU,OAAO,KAAG,IAAI,IAAI,eACX,CAAC;AAEhD,eAAO,MAAM,oBAAoB;;;;;;iBAAwB,CAAC;AAC1D,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACtE,eAAO,MAAM,oBAAoB,SACzB,OAAO,KACZ,IAAI,IAAI,kBAAkE,CAAC;AAE9E,eAAO,MAAM,uBAAuB;;;iBAAgC,CAAC;AACrE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACxE,eAAO,MAAM,mBAAmB,SAAU,OAAO,KAAG,IAAI,IAAI,iBACX,CAAC;
|
|
1
|
+
{"version":3,"file":"reading.d.ts","sourceRoot":"","sources":["../../src/decode/reading.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,eAAO,MAAM,uBAAuB,IAAoB,CAAC;AAEzD,eAAO,MAAM,sBAAsB,+FAAyB,CAAC;AAE7D,eAAO,MAAM,6BAA6B;;;iBAGxC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAC3C,OAAO,6BAA6B,CACrC,CAAC;AACF,eAAO,MAAM,yBAAyB,SAC9B,OAAO,KACZ,IAAI,IAAI,uBAC4C,CAAC;AAExD,eAAO,MAAM,qBAAqB;;;;;;iBAGhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,eAAO,MAAM,iBAAiB,SAAU,OAAO,KAAG,IAAI,IAAI,eACX,CAAC;AAEhD,eAAO,MAAM,oBAAoB;;;;;;iBAAwB,CAAC;AAC1D,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACtE,eAAO,MAAM,oBAAoB,SACzB,OAAO,KACZ,IAAI,IAAI,kBAAkE,CAAC;AAE9E,eAAO,MAAM,uBAAuB;;;iBAAgC,CAAC;AACrE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACxE,eAAO,MAAM,mBAAmB,SAAU,OAAO,KAAG,IAAI,IAAI,iBACX,CAAC;AAElD,eAAO,MAAM,uBAAuB;;;;;iBAKlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACxE,eAAO,MAAM,mBAAmB,SACxB,OAAO,KACZ,IAAI,IAAI,iBACsC,CAAC;AAElD,eAAO,MAAM,aAAa;;;;;;;;;;iBAYxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AACpD,eAAO,MAAM,SAAS,SAAU,OAAO,KAAG,IAAI,IAAI,OACX,CAAC;AAExC,eAAO,MAAM,WAAW,SAChB,OAAO,KACZ,IAAI,IAAI,OAAO,GAAG;IAAE,CAAC,EAAE,OAAO,iBAAiB,CAAA;CAGjD,CAAC;AAEF,eAAO,MAAM,WAAW,SAChB,OAAO,KACZ,IAAI,IAAI,OAAO,GAAG;IAAE,CAAC,EAAE,OAAO,iBAAiB,CAAA;CAGjD,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;iBAAgB,CAAC;AAC7C,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC;AAChC,eAAO,MAAM,eAAe;;;;;;;;;;iBAAgB,CAAC;AAC7C,MAAM,MAAM,SAAS,GAAG,OAAO,CAAC"}
|
package/dist/decode/reading.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.ReadingV2Schema = exports.ReadingV1Schema = exports.isReadingV2 = exports.isReadingV1 = exports.isReading = exports.ReadingSchema = exports.isReadingV2Metadata = exports.ReadingV2MetadataSchema = exports.isReadingMetadataV1 = exports.ReadingMetadataV1Schema = exports.isDeviceReadingTypes = exports.DeviceReadingSchemas = exports.isDeviceReadingV1 = exports.DeviceReadingV1Schema = exports.isDeviceReadingMetadataV1 = exports.DeviceReadingMetadataV1Schema = exports.ReadingDataTypesSchema = exports.DEFAULT_READING_VERSION = exports.READING_VERSION_2 = exports.READING_VERSION_1 = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const kit_schema_1 = require("@xube/kit-schema");
|
|
6
6
|
const constants_1 = require("../constants");
|
|
@@ -26,52 +26,38 @@ exports.isDeviceReadingTypes = isDeviceReadingTypes;
|
|
|
26
26
|
exports.ReadingMetadataV1Schema = exports.DeviceReadingMetadataV1Schema;
|
|
27
27
|
const isReadingMetadataV1 = (item) => exports.ReadingMetadataV1Schema.safeParse(item).success;
|
|
28
28
|
exports.isReadingMetadataV1 = isReadingMetadataV1;
|
|
29
|
-
|
|
29
|
+
exports.ReadingV2MetadataSchema = zod_1.z.object({
|
|
30
|
+
[constants_1.READING_VERSION_IDENTIFIER]: zod_1.z.literal(exports.READING_VERSION_2),
|
|
31
|
+
tm: zod_1.z.number().refine((tm) => tm > 0, { message: "tm must be positive" }),
|
|
32
|
+
bo: zod_1.z.boolean().optional(),
|
|
33
|
+
so: zod_1.z.boolean().optional(),
|
|
34
|
+
});
|
|
35
|
+
const isReadingV2Metadata = (item) => exports.ReadingV2MetadataSchema.safeParse(item).success;
|
|
36
|
+
exports.isReadingV2Metadata = isReadingV2Metadata;
|
|
37
|
+
exports.ReadingSchema = zod_1.z.looseObject({
|
|
38
|
+
[constants_1.READING_VERSION_IDENTIFIER]: zod_1.z
|
|
39
|
+
.union([zod_1.z.literal(exports.READING_VERSION_1), zod_1.z.literal(exports.READING_VERSION_2)])
|
|
40
|
+
.default(exports.DEFAULT_READING_VERSION),
|
|
30
41
|
id: zod_1.z.string(),
|
|
31
42
|
component: zod_1.z.string().optional(),
|
|
32
|
-
};
|
|
33
|
-
exports.ReadingV1Schema = zod_1.z.looseObject({
|
|
34
|
-
[constants_1.READING_VERSION_IDENTIFIER]: zod_1.z
|
|
35
|
-
.literal(exports.READING_VERSION_1)
|
|
36
|
-
.default(exports.READING_VERSION_1),
|
|
37
|
-
...ReadingCommonShape,
|
|
38
43
|
type: zod_1.z.string(),
|
|
39
44
|
s: zod_1.z.number(),
|
|
40
45
|
us: zod_1.z.number().optional(),
|
|
41
46
|
data: exports.ReadingDataTypesSchema,
|
|
42
|
-
});
|
|
43
|
-
const isReadingV1 = (item) => exports.ReadingV1Schema.safeParse(item).success;
|
|
44
|
-
exports.isReadingV1 = isReadingV1;
|
|
45
|
-
exports.ReadingV2MetadataSchema = zod_1.z.object({
|
|
46
|
-
[constants_1.READING_VERSION_IDENTIFIER]: zod_1.z.literal(exports.READING_VERSION_2),
|
|
47
|
-
tm: zod_1.z.number(),
|
|
48
47
|
bo: zod_1.z.boolean().optional(),
|
|
49
48
|
so: zod_1.z.boolean().optional(),
|
|
50
49
|
});
|
|
51
|
-
const isReadingV2Metadata = (item) => exports.ReadingV2MetadataSchema.safeParse(item).success;
|
|
52
|
-
exports.isReadingV2Metadata = isReadingV2Metadata;
|
|
53
|
-
exports.ReadingV2Schema = zod_1.z.looseObject({
|
|
54
|
-
...exports.ReadingV2MetadataSchema.shape,
|
|
55
|
-
...ReadingCommonShape,
|
|
56
|
-
data: zod_1.z.union([zod_1.z.instanceof(Uint8Array), zod_1.z.string()]),
|
|
57
|
-
});
|
|
58
|
-
const isReadingV2 = (item) => exports.ReadingV2Schema.safeParse(item).success;
|
|
59
|
-
exports.isReadingV2 = isReadingV2;
|
|
60
|
-
const injectDefaultVersionIfMissing = (item) => {
|
|
61
|
-
if (item === null ||
|
|
62
|
-
typeof item !== "object" ||
|
|
63
|
-
Array.isArray(item) ||
|
|
64
|
-
constants_1.READING_VERSION_IDENTIFIER in item) {
|
|
65
|
-
return item;
|
|
66
|
-
}
|
|
67
|
-
return {
|
|
68
|
-
...item,
|
|
69
|
-
[constants_1.READING_VERSION_IDENTIFIER]: exports.DEFAULT_READING_VERSION,
|
|
70
|
-
};
|
|
71
|
-
};
|
|
72
|
-
exports.ReadingSchema = zod_1.z.preprocess(injectDefaultVersionIfMissing, zod_1.z.discriminatedUnion(constants_1.READING_VERSION_IDENTIFIER, [
|
|
73
|
-
exports.ReadingV1Schema,
|
|
74
|
-
exports.ReadingV2Schema,
|
|
75
|
-
]));
|
|
76
50
|
const isReading = (item) => exports.ReadingSchema.safeParse(item).success;
|
|
77
51
|
exports.isReading = isReading;
|
|
52
|
+
const isReadingV1 = (item) => {
|
|
53
|
+
const result = exports.ReadingSchema.safeParse(item);
|
|
54
|
+
return result.success && result.data.v === exports.READING_VERSION_1;
|
|
55
|
+
};
|
|
56
|
+
exports.isReadingV1 = isReadingV1;
|
|
57
|
+
const isReadingV2 = (item) => {
|
|
58
|
+
const result = exports.ReadingSchema.safeParse(item);
|
|
59
|
+
return result.success && result.data.v === exports.READING_VERSION_2;
|
|
60
|
+
};
|
|
61
|
+
exports.isReadingV2 = isReadingV2;
|
|
62
|
+
exports.ReadingV1Schema = exports.ReadingSchema;
|
|
63
|
+
exports.ReadingV2Schema = exports.ReadingSchema;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xube/kit-aws-data-schema",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
},
|
|
19
19
|
"homepage": "https://github.com/XubeLtd/dev-kit#readme",
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@xube/kit-build": "^0.2.
|
|
21
|
+
"@xube/kit-build": "^0.2.14"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@xube/kit-aws-schema": "^0.2.
|
|
25
|
-
"@xube/kit-constants": "^0.2.
|
|
26
|
-
"@xube/kit-generator": "^0.2.
|
|
27
|
-
"@xube/kit-log": "^0.2.
|
|
28
|
-
"@xube/kit-schema": "^0.2.
|
|
24
|
+
"@xube/kit-aws-schema": "^0.2.14",
|
|
25
|
+
"@xube/kit-constants": "^0.2.14",
|
|
26
|
+
"@xube/kit-generator": "^0.2.14",
|
|
27
|
+
"@xube/kit-log": "^0.2.14",
|
|
28
|
+
"@xube/kit-schema": "^0.2.14",
|
|
29
29
|
"zod": "^4.4.3",
|
|
30
30
|
"zod-validation-error": "^5.0.0"
|
|
31
31
|
}
|
|
@@ -1,109 +1,133 @@
|
|
|
1
|
-
import { Buffer } from "buffer";
|
|
2
1
|
import {
|
|
3
2
|
DEFAULT_READING_VERSION,
|
|
4
3
|
READING_VERSION_1,
|
|
5
4
|
READING_VERSION_2,
|
|
5
|
+
Reading,
|
|
6
6
|
ReadingSchema,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
ReadingV2,
|
|
10
|
-
ReadingV2Schema,
|
|
7
|
+
ReadingV2Metadata,
|
|
8
|
+
ReadingV2MetadataSchema,
|
|
11
9
|
isReading,
|
|
12
10
|
isReadingV1,
|
|
13
11
|
isReadingV2,
|
|
12
|
+
isReadingV2Metadata,
|
|
14
13
|
} from "./reading";
|
|
15
14
|
|
|
16
|
-
const
|
|
17
|
-
|
|
15
|
+
const baseV1 = {
|
|
16
|
+
v: READING_VERSION_1,
|
|
17
|
+
id: "dev1",
|
|
18
|
+
component: "componentA",
|
|
19
|
+
type: "data",
|
|
18
20
|
s: 1697578841,
|
|
19
21
|
us: 214981,
|
|
20
|
-
|
|
21
|
-
id: "dev1",
|
|
22
|
-
component: "c",
|
|
23
|
-
};
|
|
24
|
-
const explicitV1 = { ...legacyV1, v: READING_VERSION_1 };
|
|
25
|
-
const blobV2Binary = {
|
|
26
|
-
v: READING_VERSION_2,
|
|
27
|
-
id: "dev1",
|
|
28
|
-
component: "c",
|
|
29
|
-
tm: 1780859506366,
|
|
30
|
-
bo: false,
|
|
31
|
-
so: false,
|
|
32
|
-
data: Buffer.from([0x01, 0x02, 0x03]),
|
|
22
|
+
data: "S,+000.30,+001.74,M,00,33",
|
|
33
23
|
};
|
|
34
|
-
|
|
24
|
+
|
|
25
|
+
const baseV2 = {
|
|
35
26
|
v: READING_VERSION_2,
|
|
36
27
|
id: "dev1",
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
28
|
+
component: "componentA",
|
|
29
|
+
type: "data",
|
|
30
|
+
s: 1780859506,
|
|
31
|
+
us: 366000,
|
|
32
|
+
data: "AQIDBA==",
|
|
41
33
|
};
|
|
42
34
|
|
|
43
|
-
describe("ReadingSchema (
|
|
44
|
-
describe("v1
|
|
45
|
-
it("parses a
|
|
46
|
-
const parsed = ReadingSchema.parse(
|
|
47
|
-
expect(parsed.v).toBe(DEFAULT_READING_VERSION);
|
|
35
|
+
describe("ReadingSchema (unified storage shape)", () => {
|
|
36
|
+
describe("v1 rows", () => {
|
|
37
|
+
it("parses a v1 row with neither bo nor so", () => {
|
|
38
|
+
const parsed = ReadingSchema.parse(baseV1) as Reading;
|
|
48
39
|
expect(parsed.v).toBe(READING_VERSION_1);
|
|
49
|
-
expect(parsed.
|
|
50
|
-
expect(parsed.
|
|
40
|
+
expect(parsed.s).toBe(baseV1.s);
|
|
41
|
+
expect(parsed.us).toBe(baseV1.us);
|
|
42
|
+
expect(parsed.bo).toBeUndefined();
|
|
43
|
+
expect(parsed.so).toBeUndefined();
|
|
51
44
|
});
|
|
52
45
|
|
|
53
|
-
it("parses
|
|
54
|
-
const parsed = ReadingSchema.parse(
|
|
55
|
-
expect(parsed).
|
|
46
|
+
it("parses a v1 row with only bo", () => {
|
|
47
|
+
const parsed = ReadingSchema.parse({ ...baseV1, bo: true }) as Reading;
|
|
48
|
+
expect(parsed.v).toBe(READING_VERSION_1);
|
|
49
|
+
expect(parsed.bo).toBe(true);
|
|
50
|
+
expect(parsed.so).toBeUndefined();
|
|
56
51
|
});
|
|
57
52
|
|
|
58
|
-
it("
|
|
59
|
-
const parsed = ReadingSchema.parse({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
expect(parsed.extra).toBe("passthrough");
|
|
53
|
+
it("parses a v1 row with only so", () => {
|
|
54
|
+
const parsed = ReadingSchema.parse({ ...baseV1, so: false }) as Reading;
|
|
55
|
+
expect(parsed.v).toBe(READING_VERSION_1);
|
|
56
|
+
expect(parsed.bo).toBeUndefined();
|
|
57
|
+
expect(parsed.so).toBe(false);
|
|
64
58
|
});
|
|
65
59
|
|
|
66
|
-
it("
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
it("parses a v1 row with both bo and so", () => {
|
|
61
|
+
const parsed = ReadingSchema.parse({
|
|
62
|
+
...baseV1,
|
|
63
|
+
bo: false,
|
|
64
|
+
so: true,
|
|
65
|
+
}) as Reading;
|
|
69
66
|
expect(parsed.v).toBe(READING_VERSION_1);
|
|
67
|
+
expect(parsed.bo).toBe(false);
|
|
68
|
+
expect(parsed.so).toBe(true);
|
|
70
69
|
});
|
|
71
70
|
});
|
|
72
71
|
|
|
73
|
-
describe("v2
|
|
74
|
-
it("parses a
|
|
75
|
-
const parsed = ReadingSchema.parse(
|
|
72
|
+
describe("v2 rows", () => {
|
|
73
|
+
it("parses a v2 row with neither bo nor so", () => {
|
|
74
|
+
const parsed = ReadingSchema.parse(baseV2) as Reading;
|
|
76
75
|
expect(parsed.v).toBe(READING_VERSION_2);
|
|
77
|
-
expect(parsed.
|
|
78
|
-
expect(parsed.
|
|
79
|
-
expect(
|
|
76
|
+
expect(parsed.s).toBe(baseV2.s);
|
|
77
|
+
expect(parsed.us).toBe(baseV2.us);
|
|
78
|
+
expect(parsed.bo).toBeUndefined();
|
|
79
|
+
expect(parsed.so).toBeUndefined();
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
it("parses a
|
|
83
|
-
|
|
82
|
+
it("parses a v2 row with only bo", () => {
|
|
83
|
+
const parsed = ReadingSchema.parse({ ...baseV2, bo: true }) as Reading;
|
|
84
|
+
expect(parsed.v).toBe(READING_VERSION_2);
|
|
85
|
+
expect(parsed.bo).toBe(true);
|
|
86
|
+
expect(parsed.so).toBeUndefined();
|
|
84
87
|
});
|
|
85
88
|
|
|
86
|
-
it("
|
|
87
|
-
const {
|
|
88
|
-
expect(
|
|
89
|
+
it("parses a v2 row with only so", () => {
|
|
90
|
+
const parsed = ReadingSchema.parse({ ...baseV2, so: false }) as Reading;
|
|
91
|
+
expect(parsed.v).toBe(READING_VERSION_2);
|
|
92
|
+
expect(parsed.bo).toBeUndefined();
|
|
93
|
+
expect(parsed.so).toBe(false);
|
|
89
94
|
});
|
|
90
95
|
|
|
91
|
-
it("
|
|
92
|
-
const
|
|
93
|
-
|
|
96
|
+
it("parses a v2 row with both bo and so", () => {
|
|
97
|
+
const parsed = ReadingSchema.parse({
|
|
98
|
+
...baseV2,
|
|
99
|
+
bo: false,
|
|
100
|
+
so: true,
|
|
101
|
+
}) as Reading;
|
|
102
|
+
expect(parsed.v).toBe(READING_VERSION_2);
|
|
103
|
+
expect(parsed.bo).toBe(false);
|
|
104
|
+
expect(parsed.so).toBe(true);
|
|
94
105
|
});
|
|
106
|
+
});
|
|
95
107
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
108
|
+
describe("legacy + default behaviour", () => {
|
|
109
|
+
it("parses a legacy row (no v field) and defaults to v1", () => {
|
|
110
|
+
const { v: _omit, ...legacy } = baseV1;
|
|
111
|
+
const parsed = ReadingSchema.parse(legacy) as Reading;
|
|
112
|
+
expect(parsed.v).toBe(DEFAULT_READING_VERSION);
|
|
113
|
+
expect(parsed.v).toBe(READING_VERSION_1);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("preserves passthrough fields (looseObject)", () => {
|
|
117
|
+
const parsed = ReadingSchema.parse({
|
|
118
|
+
...baseV1,
|
|
119
|
+
extra: "passthrough",
|
|
120
|
+
}) as Reading & { extra: string };
|
|
121
|
+
expect(parsed.extra).toBe("passthrough");
|
|
99
122
|
});
|
|
100
|
-
});
|
|
101
123
|
|
|
102
|
-
describe("invalid input", () => {
|
|
103
124
|
it("rejects an unknown v value", () => {
|
|
104
|
-
expect(ReadingSchema.safeParse({ v: 99
|
|
105
|
-
|
|
106
|
-
|
|
125
|
+
expect(ReadingSchema.safeParse({ ...baseV1, v: 99 }).success).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("rejects a row missing required core fields", () => {
|
|
129
|
+
const { id: _id, ...withoutId } = baseV1;
|
|
130
|
+
expect(ReadingSchema.safeParse(withoutId).success).toBe(false);
|
|
107
131
|
});
|
|
108
132
|
|
|
109
133
|
it.each([
|
|
@@ -116,66 +140,92 @@ describe("ReadingSchema (discriminated union)", () => {
|
|
|
116
140
|
])("rejects %s input without crashing", (_label, input) => {
|
|
117
141
|
expect(ReadingSchema.safeParse(input).success).toBe(false);
|
|
118
142
|
});
|
|
143
|
+
});
|
|
144
|
+
});
|
|
119
145
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
146
|
+
describe("type-narrowing predicates", () => {
|
|
147
|
+
const v1Both = { ...baseV1, bo: true, so: true };
|
|
148
|
+
const v2Both = { ...baseV2, bo: true, so: true };
|
|
149
|
+
|
|
150
|
+
it("isReading accepts any valid reading", () => {
|
|
151
|
+
expect(isReading(baseV1)).toBe(true);
|
|
152
|
+
expect(isReading(v1Both)).toBe(true);
|
|
153
|
+
expect(isReading(baseV2)).toBe(true);
|
|
154
|
+
expect(isReading(v2Both)).toBe(true);
|
|
155
|
+
expect(isReading({ foo: "bar" })).toBe(false);
|
|
156
|
+
expect(isReading(null)).toBe(false);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("isReadingV1 narrows to v=1 only", () => {
|
|
160
|
+
expect(isReadingV1(baseV1)).toBe(true);
|
|
161
|
+
expect(isReadingV1(v1Both)).toBe(true);
|
|
162
|
+
expect(isReadingV1(baseV2)).toBe(false);
|
|
163
|
+
expect(isReadingV1(v2Both)).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("isReadingV2 narrows to v=2 only", () => {
|
|
167
|
+
expect(isReadingV2(baseV2)).toBe(true);
|
|
168
|
+
expect(isReadingV2(v2Both)).toBe(true);
|
|
169
|
+
expect(isReadingV2(baseV1)).toBe(false);
|
|
170
|
+
expect(isReadingV2(v1Both)).toBe(false);
|
|
123
171
|
});
|
|
124
172
|
});
|
|
125
173
|
|
|
126
|
-
describe("
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
174
|
+
describe("ReadingV2MetadataSchema (wire-format header)", () => {
|
|
175
|
+
const minimal: ReadingV2Metadata = {
|
|
176
|
+
v: READING_VERSION_2,
|
|
177
|
+
tm: 1780859506366,
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
it("accepts minimal v2 metadata (no bo, no so)", () => {
|
|
181
|
+
expect(ReadingV2MetadataSchema.safeParse(minimal).success).toBe(true);
|
|
130
182
|
});
|
|
131
183
|
|
|
132
|
-
it("
|
|
184
|
+
it("accepts v2 metadata with only bo", () => {
|
|
133
185
|
expect(
|
|
134
|
-
|
|
135
|
-
).toBe(
|
|
186
|
+
ReadingV2MetadataSchema.safeParse({ ...minimal, bo: true }).success,
|
|
187
|
+
).toBe(true);
|
|
136
188
|
});
|
|
137
|
-
});
|
|
138
189
|
|
|
139
|
-
|
|
140
|
-
it("requires v=2 explicitly (no default)", () => {
|
|
190
|
+
it("accepts v2 metadata with only so", () => {
|
|
141
191
|
expect(
|
|
142
|
-
|
|
143
|
-
).toBe(
|
|
192
|
+
ReadingV2MetadataSchema.safeParse({ ...minimal, so: false }).success,
|
|
193
|
+
).toBe(true);
|
|
144
194
|
});
|
|
145
195
|
|
|
146
|
-
it("accepts
|
|
147
|
-
expect(
|
|
196
|
+
it("accepts v2 metadata with both bo and so", () => {
|
|
197
|
+
expect(
|
|
198
|
+
ReadingV2MetadataSchema.safeParse({
|
|
199
|
+
...minimal,
|
|
200
|
+
bo: false,
|
|
201
|
+
so: true,
|
|
202
|
+
}).success,
|
|
203
|
+
).toBe(true);
|
|
148
204
|
});
|
|
149
|
-
});
|
|
150
205
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
expect(
|
|
206
|
+
it("rejects v2 metadata with tm = 0 or negative", () => {
|
|
207
|
+
expect(ReadingV2MetadataSchema.safeParse({ ...minimal, tm: 0 }).success).toBe(
|
|
208
|
+
false,
|
|
209
|
+
);
|
|
210
|
+
expect(
|
|
211
|
+
ReadingV2MetadataSchema.safeParse({ ...minimal, tm: -1 }).success,
|
|
212
|
+
).toBe(false);
|
|
156
213
|
});
|
|
157
214
|
|
|
158
|
-
it("
|
|
159
|
-
|
|
160
|
-
expect(
|
|
161
|
-
expect(isReadingV2(legacyV1)).toBe(false);
|
|
162
|
-
expect(isReadingV2(explicitV1)).toBe(false);
|
|
215
|
+
it("rejects v2 metadata missing tm", () => {
|
|
216
|
+
const { tm: _tm, ...noTm } = minimal;
|
|
217
|
+
expect(ReadingV2MetadataSchema.safeParse(noTm).success).toBe(false);
|
|
163
218
|
});
|
|
164
219
|
|
|
165
|
-
it("
|
|
166
|
-
expect(
|
|
167
|
-
expect(
|
|
168
|
-
expect(
|
|
169
|
-
expect(isReading(blobV2String)).toBe(true);
|
|
170
|
-
expect(isReading({ foo: "bar" })).toBe(false);
|
|
171
|
-
expect(isReading(null)).toBe(false);
|
|
220
|
+
it("isReadingV2Metadata matches the schema", () => {
|
|
221
|
+
expect(isReadingV2Metadata(minimal)).toBe(true);
|
|
222
|
+
expect(isReadingV2Metadata({ ...minimal, bo: true, so: false })).toBe(true);
|
|
223
|
+
expect(isReadingV2Metadata({ v: 1, tm: 1 })).toBe(false);
|
|
172
224
|
});
|
|
173
225
|
});
|
|
174
226
|
|
|
175
227
|
describe("DEFAULT_READING_VERSION", () => {
|
|
176
228
|
it("currently equals READING_VERSION_1", () => {
|
|
177
|
-
// If this fails, the preprocess no longer assumes legacy-records-are-v1 —
|
|
178
|
-
// make sure all consumers and the migration story are aware before flipping.
|
|
179
229
|
expect(DEFAULT_READING_VERSION).toBe(READING_VERSION_1);
|
|
180
230
|
});
|
|
181
231
|
});
|
package/src/decode/reading.ts
CHANGED
|
@@ -40,28 +40,9 @@ export type ReadingMetadataV1 = z.infer<typeof ReadingMetadataV1Schema>;
|
|
|
40
40
|
export const isReadingMetadataV1 = (item: unknown): item is ReadingMetadataV1 =>
|
|
41
41
|
ReadingMetadataV1Schema.safeParse(item).success;
|
|
42
42
|
|
|
43
|
-
const ReadingCommonShape = {
|
|
44
|
-
id: z.string(),
|
|
45
|
-
component: z.string().optional(),
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export const ReadingV1Schema = z.looseObject({
|
|
49
|
-
[READING_VERSION_IDENTIFIER]: z
|
|
50
|
-
.literal(READING_VERSION_1)
|
|
51
|
-
.default(READING_VERSION_1),
|
|
52
|
-
...ReadingCommonShape,
|
|
53
|
-
type: z.string(),
|
|
54
|
-
s: z.number(),
|
|
55
|
-
us: z.number().optional(),
|
|
56
|
-
data: ReadingDataTypesSchema,
|
|
57
|
-
});
|
|
58
|
-
export type ReadingV1 = z.infer<typeof ReadingV1Schema>;
|
|
59
|
-
export const isReadingV1 = (item: unknown): item is ReadingV1 =>
|
|
60
|
-
ReadingV1Schema.safeParse(item).success;
|
|
61
|
-
|
|
62
43
|
export const ReadingV2MetadataSchema = z.object({
|
|
63
44
|
[READING_VERSION_IDENTIFIER]: z.literal(READING_VERSION_2),
|
|
64
|
-
tm: z.number(),
|
|
45
|
+
tm: z.number().refine((tm) => tm > 0, { message: "tm must be positive" }),
|
|
65
46
|
bo: z.boolean().optional(),
|
|
66
47
|
so: z.boolean().optional(),
|
|
67
48
|
});
|
|
@@ -71,37 +52,38 @@ export const isReadingV2Metadata = (
|
|
|
71
52
|
): item is ReadingV2Metadata =>
|
|
72
53
|
ReadingV2MetadataSchema.safeParse(item).success;
|
|
73
54
|
|
|
74
|
-
export const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
55
|
+
export const ReadingSchema = z.looseObject({
|
|
56
|
+
[READING_VERSION_IDENTIFIER]: z
|
|
57
|
+
.union([z.literal(READING_VERSION_1), z.literal(READING_VERSION_2)])
|
|
58
|
+
.default(DEFAULT_READING_VERSION),
|
|
59
|
+
id: z.string(),
|
|
60
|
+
component: z.string().optional(),
|
|
61
|
+
type: z.string(),
|
|
62
|
+
s: z.number(),
|
|
63
|
+
us: z.number().optional(),
|
|
64
|
+
data: ReadingDataTypesSchema,
|
|
65
|
+
bo: z.boolean().optional(),
|
|
66
|
+
so: z.boolean().optional(),
|
|
78
67
|
});
|
|
79
|
-
export type ReadingV2 = z.infer<typeof ReadingV2Schema>;
|
|
80
|
-
export const isReadingV2 = (item: unknown): item is ReadingV2 =>
|
|
81
|
-
ReadingV2Schema.safeParse(item).success;
|
|
82
|
-
|
|
83
|
-
const injectDefaultVersionIfMissing = (item: unknown): unknown => {
|
|
84
|
-
if (
|
|
85
|
-
item === null ||
|
|
86
|
-
typeof item !== "object" ||
|
|
87
|
-
Array.isArray(item) ||
|
|
88
|
-
READING_VERSION_IDENTIFIER in item
|
|
89
|
-
) {
|
|
90
|
-
return item;
|
|
91
|
-
}
|
|
92
|
-
return {
|
|
93
|
-
...item,
|
|
94
|
-
[READING_VERSION_IDENTIFIER]: DEFAULT_READING_VERSION,
|
|
95
|
-
};
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
export const ReadingSchema = z.preprocess(
|
|
99
|
-
injectDefaultVersionIfMissing,
|
|
100
|
-
z.discriminatedUnion(READING_VERSION_IDENTIFIER, [
|
|
101
|
-
ReadingV1Schema,
|
|
102
|
-
ReadingV2Schema,
|
|
103
|
-
]),
|
|
104
|
-
);
|
|
105
68
|
export type Reading = z.infer<typeof ReadingSchema>;
|
|
106
69
|
export const isReading = (item: unknown): item is Reading =>
|
|
107
70
|
ReadingSchema.safeParse(item).success;
|
|
71
|
+
|
|
72
|
+
export const isReadingV1 = (
|
|
73
|
+
item: unknown,
|
|
74
|
+
): item is Reading & { v: typeof READING_VERSION_1 } => {
|
|
75
|
+
const result = ReadingSchema.safeParse(item);
|
|
76
|
+
return result.success && result.data.v === READING_VERSION_1;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const isReadingV2 = (
|
|
80
|
+
item: unknown,
|
|
81
|
+
): item is Reading & { v: typeof READING_VERSION_2 } => {
|
|
82
|
+
const result = ReadingSchema.safeParse(item);
|
|
83
|
+
return result.success && result.data.v === READING_VERSION_2;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const ReadingV1Schema = ReadingSchema;
|
|
87
|
+
export type ReadingV1 = Reading;
|
|
88
|
+
export const ReadingV2Schema = ReadingSchema;
|
|
89
|
+
export type ReadingV2 = Reading;
|