@alepha/protobuf 0.5.0 → 0.5.1

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/index.cjs ADDED
@@ -0,0 +1,124 @@
1
+ 'use strict';
2
+
3
+ var core = require('@alepha/core');
4
+ var protobufjs = require('protobufjs');
5
+
6
+ class ProtobufProvider {
7
+ alepha = core.$inject(core.Alepha);
8
+ schemas = /* @__PURE__ */ new Map();
9
+ protobuf = protobufjs;
10
+ /**
11
+ * Encode an object to a Uint8Array.
12
+ *
13
+ * @param schema - TypeBox schema used to generate the Protobuf schema.
14
+ * @param data - Object to encode. Can be any object or string.
15
+ */
16
+ encode(schema, data) {
17
+ return this.parse(schema).encode(this.alepha.parse(schema, data)).finish();
18
+ }
19
+ /**
20
+ * Decode a Uint8Array to an object.
21
+ *
22
+ * @param schema
23
+ * @param data
24
+ */
25
+ decode(schema, data) {
26
+ return this.alepha.parse(schema, this.parse(schema).decode(data));
27
+ }
28
+ /**
29
+ * Parse a TypeBox schema to a Protobuf Type schema ready for encoding/decoding.
30
+ *
31
+ * @param schema
32
+ * @param typeName
33
+ */
34
+ parse(schema, typeName = "root.Target") {
35
+ const exists = this.schemas.get(schema);
36
+ if (exists) return exists;
37
+ const pbSchema = typeof schema === "string" ? schema : this.createProtobufSchema(schema);
38
+ const result = this.protobuf.parse(pbSchema);
39
+ const type = result.root.lookupType(typeName);
40
+ this.schemas.set(schema, type);
41
+ return type;
42
+ }
43
+ /**
44
+ * Convert a TypeBox schema to a Protobuf schema as a string.
45
+ *
46
+ * @param schema
47
+ * @param options
48
+ */
49
+ createProtobufSchema(schema, options = {}) {
50
+ const { rootName = "root", mainMessageName = "Target" } = options;
51
+ const context = {
52
+ proto: `package ${rootName};
53
+ syntax = "proto3";
54
+
55
+ `,
56
+ fieldIndex: 1
57
+ };
58
+ if (core.TypeGuard.IsObject(schema)) {
59
+ const proto = this.parseObject(schema, mainMessageName, context);
60
+ context.proto += proto;
61
+ }
62
+ return context.proto;
63
+ }
64
+ /**
65
+ * Parse an object schema to a Protobuf message.
66
+ *
67
+ * @param obj
68
+ * @param parentName
69
+ * @param context
70
+ * @protected
71
+ */
72
+ parseObject(obj, parentName, context) {
73
+ if (!core.TypeGuard.IsObject(obj)) {
74
+ return "";
75
+ }
76
+ const fields = [];
77
+ for (const [key, value] of Object.entries(obj.properties)) {
78
+ if (core.TypeGuard.IsArray(value)) {
79
+ if (core.TypeGuard.IsObject(value.items)) {
80
+ const subMessageName = value.items.title ?? `${parentName}_${key}`;
81
+ context.proto += this.parseObject(value.items, subMessageName, {
82
+ ...context,
83
+ fieldIndex: 1
84
+ });
85
+ fields.push(
86
+ ` repeated ${subMessageName} ${key} = ${context.fieldIndex++};`
87
+ );
88
+ continue;
89
+ }
90
+ const itemType = this.convertType(value.items);
91
+ fields.push(` repeated ${itemType} ${key} = ${context.fieldIndex++};`);
92
+ continue;
93
+ }
94
+ if (core.TypeGuard.IsObject(value)) {
95
+ const subMessageName = `${parentName}_${key}`;
96
+ context.proto += this.parseObject(value, subMessageName, context);
97
+ fields.push(` ${subMessageName} ${key} = ${context.fieldIndex++};`);
98
+ continue;
99
+ }
100
+ fields.push(
101
+ ` ${this.convertType(value)} ${key} = ${context.fieldIndex++};`
102
+ );
103
+ }
104
+ return `message ${parentName} {
105
+ ${fields.join("\n")}
106
+ }
107
+ `;
108
+ }
109
+ /**
110
+ * Convert a primitive TypeBox schema type to a Protobuf spec type.
111
+ *
112
+ * @param schema
113
+ * @protected
114
+ */
115
+ convertType(schema) {
116
+ if (core.TypeGuard.IsInteger(schema)) return "int32";
117
+ if (core.TypeGuard.IsNumber(schema)) return "double";
118
+ if (core.TypeGuard.IsString(schema)) return "string";
119
+ if (core.TypeGuard.IsBoolean(schema)) return "bool";
120
+ throw new Error(`Unsupported type: ${JSON.stringify(schema)}`);
121
+ }
122
+ }
123
+
124
+ exports.ProtobufProvider = ProtobufProvider;
@@ -0,0 +1,103 @@
1
+ import { Alepha, TObject, Static, TSchema as TSchema$1 } from '@alepha/core';
2
+ import protobufjs, { Type } from 'protobufjs';
3
+
4
+ /** Symbol key applied to readonly types */
5
+ declare const ReadonlyKind: unique symbol;
6
+ /** Symbol key applied to optional types */
7
+ declare const OptionalKind: unique symbol;
8
+ /** Symbol key applied to types */
9
+ declare const Hint: unique symbol;
10
+ /** Symbol key applied to types */
11
+ declare const Kind: unique symbol;
12
+
13
+ type TPropertyKey = string | number;
14
+ type TProperties = Record<TPropertyKey, TSchema>;
15
+
16
+ interface SchemaOptions {
17
+ $schema?: string;
18
+ /** Id for this schema */
19
+ $id?: string;
20
+ /** Title of this schema */
21
+ title?: string;
22
+ /** Description of this schema */
23
+ description?: string;
24
+ /** Default value for this schema */
25
+ default?: any;
26
+ /** Example values matching this schema */
27
+ examples?: any;
28
+ /** Optional annotation for readOnly */
29
+ readOnly?: boolean;
30
+ /** Optional annotation for writeOnly */
31
+ writeOnly?: boolean;
32
+ [prop: string]: any;
33
+ }
34
+ interface TKind {
35
+ [Kind]: string;
36
+ }
37
+ interface TSchema extends TKind, SchemaOptions {
38
+ [ReadonlyKind]?: string;
39
+ [OptionalKind]?: string;
40
+ [Hint]?: string;
41
+ params: unknown[];
42
+ static: unknown;
43
+ }
44
+
45
+ declare class ProtobufProvider {
46
+ protected readonly alepha: Alepha;
47
+ protected readonly schemas: Map<string | TObject<TProperties>, Type>;
48
+ protected readonly protobuf: typeof protobufjs;
49
+ /**
50
+ * Encode an object to a Uint8Array.
51
+ *
52
+ * @param schema - TypeBox schema used to generate the Protobuf schema.
53
+ * @param data - Object to encode. Can be any object or string.
54
+ */
55
+ encode(schema: TObject, data: any): Uint8Array;
56
+ /**
57
+ * Decode a Uint8Array to an object.
58
+ *
59
+ * @param schema
60
+ * @param data
61
+ */
62
+ decode<T extends TObject>(schema: T, data: Uint8Array): Static<T>;
63
+ /**
64
+ * Parse a TypeBox schema to a Protobuf Type schema ready for encoding/decoding.
65
+ *
66
+ * @param schema
67
+ * @param typeName
68
+ */
69
+ parse(schema: ProtobufSchema | TObject, typeName?: string): Type;
70
+ /**
71
+ * Convert a TypeBox schema to a Protobuf schema as a string.
72
+ *
73
+ * @param schema
74
+ * @param options
75
+ */
76
+ createProtobufSchema(schema: TSchema$1, options?: CreateProtobufSchemaOptions): string;
77
+ /**
78
+ * Parse an object schema to a Protobuf message.
79
+ *
80
+ * @param obj
81
+ * @param parentName
82
+ * @param context
83
+ * @protected
84
+ */
85
+ protected parseObject(obj: TSchema$1, parentName: string, context: {
86
+ proto: string;
87
+ fieldIndex: number;
88
+ }): string;
89
+ /**
90
+ * Convert a primitive TypeBox schema type to a Protobuf spec type.
91
+ *
92
+ * @param schema
93
+ * @protected
94
+ */
95
+ protected convertType(schema: TSchema$1): string;
96
+ }
97
+ type ProtobufSchema = string;
98
+ interface CreateProtobufSchemaOptions {
99
+ rootName?: string;
100
+ mainMessageName?: string;
101
+ }
102
+
103
+ export { type CreateProtobufSchemaOptions, ProtobufProvider, type ProtobufSchema };
@@ -0,0 +1,103 @@
1
+ import { Alepha, TObject, Static, TSchema as TSchema$1 } from '@alepha/core';
2
+ import protobufjs, { Type } from 'protobufjs';
3
+
4
+ /** Symbol key applied to readonly types */
5
+ declare const ReadonlyKind: unique symbol;
6
+ /** Symbol key applied to optional types */
7
+ declare const OptionalKind: unique symbol;
8
+ /** Symbol key applied to types */
9
+ declare const Hint: unique symbol;
10
+ /** Symbol key applied to types */
11
+ declare const Kind: unique symbol;
12
+
13
+ type TPropertyKey = string | number;
14
+ type TProperties = Record<TPropertyKey, TSchema>;
15
+
16
+ interface SchemaOptions {
17
+ $schema?: string;
18
+ /** Id for this schema */
19
+ $id?: string;
20
+ /** Title of this schema */
21
+ title?: string;
22
+ /** Description of this schema */
23
+ description?: string;
24
+ /** Default value for this schema */
25
+ default?: any;
26
+ /** Example values matching this schema */
27
+ examples?: any;
28
+ /** Optional annotation for readOnly */
29
+ readOnly?: boolean;
30
+ /** Optional annotation for writeOnly */
31
+ writeOnly?: boolean;
32
+ [prop: string]: any;
33
+ }
34
+ interface TKind {
35
+ [Kind]: string;
36
+ }
37
+ interface TSchema extends TKind, SchemaOptions {
38
+ [ReadonlyKind]?: string;
39
+ [OptionalKind]?: string;
40
+ [Hint]?: string;
41
+ params: unknown[];
42
+ static: unknown;
43
+ }
44
+
45
+ declare class ProtobufProvider {
46
+ protected readonly alepha: Alepha;
47
+ protected readonly schemas: Map<string | TObject<TProperties>, Type>;
48
+ protected readonly protobuf: typeof protobufjs;
49
+ /**
50
+ * Encode an object to a Uint8Array.
51
+ *
52
+ * @param schema - TypeBox schema used to generate the Protobuf schema.
53
+ * @param data - Object to encode. Can be any object or string.
54
+ */
55
+ encode(schema: TObject, data: any): Uint8Array;
56
+ /**
57
+ * Decode a Uint8Array to an object.
58
+ *
59
+ * @param schema
60
+ * @param data
61
+ */
62
+ decode<T extends TObject>(schema: T, data: Uint8Array): Static<T>;
63
+ /**
64
+ * Parse a TypeBox schema to a Protobuf Type schema ready for encoding/decoding.
65
+ *
66
+ * @param schema
67
+ * @param typeName
68
+ */
69
+ parse(schema: ProtobufSchema | TObject, typeName?: string): Type;
70
+ /**
71
+ * Convert a TypeBox schema to a Protobuf schema as a string.
72
+ *
73
+ * @param schema
74
+ * @param options
75
+ */
76
+ createProtobufSchema(schema: TSchema$1, options?: CreateProtobufSchemaOptions): string;
77
+ /**
78
+ * Parse an object schema to a Protobuf message.
79
+ *
80
+ * @param obj
81
+ * @param parentName
82
+ * @param context
83
+ * @protected
84
+ */
85
+ protected parseObject(obj: TSchema$1, parentName: string, context: {
86
+ proto: string;
87
+ fieldIndex: number;
88
+ }): string;
89
+ /**
90
+ * Convert a primitive TypeBox schema type to a Protobuf spec type.
91
+ *
92
+ * @param schema
93
+ * @protected
94
+ */
95
+ protected convertType(schema: TSchema$1): string;
96
+ }
97
+ type ProtobufSchema = string;
98
+ interface CreateProtobufSchemaOptions {
99
+ rootName?: string;
100
+ mainMessageName?: string;
101
+ }
102
+
103
+ export { type CreateProtobufSchemaOptions, ProtobufProvider, type ProtobufSchema };
package/dist/index.mjs ADDED
@@ -0,0 +1,122 @@
1
+ import { $inject, Alepha, TypeGuard } from '@alepha/core';
2
+ import protobufjs from 'protobufjs';
3
+
4
+ class ProtobufProvider {
5
+ alepha = $inject(Alepha);
6
+ schemas = /* @__PURE__ */ new Map();
7
+ protobuf = protobufjs;
8
+ /**
9
+ * Encode an object to a Uint8Array.
10
+ *
11
+ * @param schema - TypeBox schema used to generate the Protobuf schema.
12
+ * @param data - Object to encode. Can be any object or string.
13
+ */
14
+ encode(schema, data) {
15
+ return this.parse(schema).encode(this.alepha.parse(schema, data)).finish();
16
+ }
17
+ /**
18
+ * Decode a Uint8Array to an object.
19
+ *
20
+ * @param schema
21
+ * @param data
22
+ */
23
+ decode(schema, data) {
24
+ return this.alepha.parse(schema, this.parse(schema).decode(data));
25
+ }
26
+ /**
27
+ * Parse a TypeBox schema to a Protobuf Type schema ready for encoding/decoding.
28
+ *
29
+ * @param schema
30
+ * @param typeName
31
+ */
32
+ parse(schema, typeName = "root.Target") {
33
+ const exists = this.schemas.get(schema);
34
+ if (exists) return exists;
35
+ const pbSchema = typeof schema === "string" ? schema : this.createProtobufSchema(schema);
36
+ const result = this.protobuf.parse(pbSchema);
37
+ const type = result.root.lookupType(typeName);
38
+ this.schemas.set(schema, type);
39
+ return type;
40
+ }
41
+ /**
42
+ * Convert a TypeBox schema to a Protobuf schema as a string.
43
+ *
44
+ * @param schema
45
+ * @param options
46
+ */
47
+ createProtobufSchema(schema, options = {}) {
48
+ const { rootName = "root", mainMessageName = "Target" } = options;
49
+ const context = {
50
+ proto: `package ${rootName};
51
+ syntax = "proto3";
52
+
53
+ `,
54
+ fieldIndex: 1
55
+ };
56
+ if (TypeGuard.IsObject(schema)) {
57
+ const proto = this.parseObject(schema, mainMessageName, context);
58
+ context.proto += proto;
59
+ }
60
+ return context.proto;
61
+ }
62
+ /**
63
+ * Parse an object schema to a Protobuf message.
64
+ *
65
+ * @param obj
66
+ * @param parentName
67
+ * @param context
68
+ * @protected
69
+ */
70
+ parseObject(obj, parentName, context) {
71
+ if (!TypeGuard.IsObject(obj)) {
72
+ return "";
73
+ }
74
+ const fields = [];
75
+ for (const [key, value] of Object.entries(obj.properties)) {
76
+ if (TypeGuard.IsArray(value)) {
77
+ if (TypeGuard.IsObject(value.items)) {
78
+ const subMessageName = value.items.title ?? `${parentName}_${key}`;
79
+ context.proto += this.parseObject(value.items, subMessageName, {
80
+ ...context,
81
+ fieldIndex: 1
82
+ });
83
+ fields.push(
84
+ ` repeated ${subMessageName} ${key} = ${context.fieldIndex++};`
85
+ );
86
+ continue;
87
+ }
88
+ const itemType = this.convertType(value.items);
89
+ fields.push(` repeated ${itemType} ${key} = ${context.fieldIndex++};`);
90
+ continue;
91
+ }
92
+ if (TypeGuard.IsObject(value)) {
93
+ const subMessageName = `${parentName}_${key}`;
94
+ context.proto += this.parseObject(value, subMessageName, context);
95
+ fields.push(` ${subMessageName} ${key} = ${context.fieldIndex++};`);
96
+ continue;
97
+ }
98
+ fields.push(
99
+ ` ${this.convertType(value)} ${key} = ${context.fieldIndex++};`
100
+ );
101
+ }
102
+ return `message ${parentName} {
103
+ ${fields.join("\n")}
104
+ }
105
+ `;
106
+ }
107
+ /**
108
+ * Convert a primitive TypeBox schema type to a Protobuf spec type.
109
+ *
110
+ * @param schema
111
+ * @protected
112
+ */
113
+ convertType(schema) {
114
+ if (TypeGuard.IsInteger(schema)) return "int32";
115
+ if (TypeGuard.IsNumber(schema)) return "double";
116
+ if (TypeGuard.IsString(schema)) return "string";
117
+ if (TypeGuard.IsBoolean(schema)) return "bool";
118
+ throw new Error(`Unsupported type: ${JSON.stringify(schema)}`);
119
+ }
120
+ }
121
+
122
+ export { ProtobufProvider };
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@alepha/protobuf",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.mjs",
8
8
  "types": "./dist/index.d.cts",
9
9
  "dependencies": {
10
- "@alepha/core": "0.5.0",
10
+ "@alepha/core": "0.5.1",
11
11
  "protobufjs": "^7.4.0"
12
12
  },
13
13
  "devDependencies": {
@@ -1,41 +0,0 @@
1
- import { Alepha, t } from "@alepha/core";
2
- import { test } from "vitest";
3
- import { ProtobufProvider } from "../src";
4
-
5
- const protobuf = Alepha.create().get(ProtobufProvider);
6
- const userSchema = t.object({
7
- username: t.string(),
8
- createdAt: t.datetime(),
9
- age: t.int(),
10
- isActive: t.boolean(),
11
- });
12
-
13
- test("ProtobufProvider#typeboxToProtobuf", async ({ expect }) => {
14
- const schema = protobuf.createProtobufSchema(userSchema);
15
- expect(schema).toBe(
16
- `package root;
17
- syntax = "proto3";
18
-
19
- message Target {
20
- string username = 1;
21
- string createdAt = 2;
22
- int32 age = 3;
23
- bool isActive = 4;
24
- }
25
- `,
26
- );
27
- });
28
-
29
- test("ProtobufProvider#encode", async ({ expect }) => {
30
- const data = {
31
- username: "John Doe",
32
- createdAt: new Date().toISOString(),
33
- age: 30,
34
- isActive: true,
35
- };
36
- const buf = protobuf.encode(userSchema, data);
37
- expect(buf).toBeInstanceOf(Uint8Array);
38
-
39
- const user = protobuf.decode(userSchema, buf);
40
- expect(user).toEqual(data);
41
- });
package/tsconfig.json DELETED
@@ -1,6 +0,0 @@
1
- {
2
- "extends": "../../../tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "lib"
5
- }
6
- }