@ocap/message 1.28.9 → 1.29.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/README.md +0 -1
- package/esm/_virtual/rolldown_runtime.mjs +8 -0
- package/esm/index.d.mts +3 -0
- package/esm/index.mjs +10 -0
- package/esm/message.d.mts +144 -0
- package/esm/message.mjs +484 -0
- package/esm/package.mjs +87 -0
- package/esm/patch.d.mts +1 -0
- package/esm/patch.mjs +40 -0
- package/esm/provider.d.mts +27 -0
- package/esm/provider.mjs +42 -0
- package/lib/_virtual/rolldown_runtime.cjs +31 -0
- package/lib/index.cjs +26 -0
- package/lib/index.d.cts +3 -0
- package/lib/message.cjs +500 -0
- package/lib/message.d.cts +144 -0
- package/lib/package.cjs +90 -0
- package/lib/patch.cjs +41 -0
- package/lib/patch.d.cts +1 -0
- package/lib/provider.cjs +49 -0
- package/lib/provider.d.cts +27 -0
- package/package.json +32 -11
- package/index.d.ts +0 -5
- package/index.js +0 -7
- package/lib/message.d.ts +0 -138
- package/lib/message.js +0 -605
- package/lib/patch.d.ts +0 -1
- package/lib/patch.js +0 -57
- package/lib/provider.d.ts +0 -12
- package/lib/provider.js +0 -68
package/README.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|

|
|
2
2
|
|
|
3
|
-
[](https://github.com/prettier/prettier)
|
|
4
3
|
[](https://docs.arcblock.io)
|
|
5
4
|
[](https://gitter.im/ArcBlock/community?utm_source=badge\&utm_medium=badge\&utm_campaign=pr-badge)
|
|
6
5
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
//#region rolldown:runtime
|
|
4
|
+
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
5
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
6
|
+
|
|
7
|
+
//#endregion
|
|
8
|
+
export { __commonJSMin, __require };
|
package/esm/index.d.mts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { addProvider, fromTypeUrl, getMessageType, toTypeUrl } from "./provider.mjs";
|
|
2
|
+
import { AnyData, attachExampleFn, attachFormatFn, createMessage, decodeAny, decodeBigInt, decodeTimestamp, encodeAny, encodeBigInt, encodeTimestamp, fakeMessage, formatMessage } from "./message.mjs";
|
|
3
|
+
export { type AnyData, addProvider, attachExampleFn, attachFormatFn, createMessage, decodeAny, decodeBigInt, decodeTimestamp, encodeAny, encodeBigInt, encodeTimestamp, fakeMessage, formatMessage, fromTypeUrl, getMessageType, toTypeUrl };
|
package/esm/index.mjs
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import "./patch.mjs";
|
|
2
|
+
import { addProvider, fromTypeUrl, getMessageType, toTypeUrl } from "./provider.mjs";
|
|
3
|
+
import { attachExampleFn, attachFormatFn, createMessage, decodeAny, decodeBigInt, decodeTimestamp, encodeAny, encodeBigInt, encodeTimestamp, fakeMessage, formatMessage } from "./message.mjs";
|
|
4
|
+
import forge from "@ocap/proto";
|
|
5
|
+
|
|
6
|
+
//#region src/index.ts
|
|
7
|
+
addProvider(forge);
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
export { addProvider, attachExampleFn, attachFormatFn, createMessage, decodeAny, decodeBigInt, decodeTimestamp, encodeAny, encodeBigInt, encodeTimestamp, fakeMessage, formatMessage, fromTypeUrl, getMessageType, toTypeUrl };
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { addProvider, fromTypeUrl, getMessageType, toTypeUrl } from "./provider.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/message.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @fileOverview Contains basic helper methods to encode/format/mock a protobuf message
|
|
7
|
+
* @module @ocap/message
|
|
8
|
+
* @requires @ocap/util
|
|
9
|
+
* @requires @ocap/proto
|
|
10
|
+
* @example
|
|
11
|
+
* bun add @ocap/message
|
|
12
|
+
*
|
|
13
|
+
* const { createMessage, fakeMessage, formatMessage } = require('@ocap/message');
|
|
14
|
+
*/
|
|
15
|
+
declare const Any: any;
|
|
16
|
+
declare const Timestamp: any;
|
|
17
|
+
interface AnyData {
|
|
18
|
+
type?: string;
|
|
19
|
+
typeUrl?: string;
|
|
20
|
+
value?: unknown;
|
|
21
|
+
}
|
|
22
|
+
interface TimestampData {
|
|
23
|
+
seconds?: number;
|
|
24
|
+
nanos?: number;
|
|
25
|
+
}
|
|
26
|
+
interface BigIntData {
|
|
27
|
+
value?: Uint8Array;
|
|
28
|
+
minus?: boolean;
|
|
29
|
+
}
|
|
30
|
+
interface ProtobufMessage {
|
|
31
|
+
toObject(): Record<string, unknown>;
|
|
32
|
+
serializeBinary(): Uint8Array;
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Generated a fake message for a type, the message can be RPC request/response
|
|
37
|
+
*
|
|
38
|
+
* @public
|
|
39
|
+
* @static
|
|
40
|
+
* @param type - Message type string, should be defined in forge-abi or forge-core-protocol
|
|
41
|
+
* @returns object
|
|
42
|
+
*/
|
|
43
|
+
declare function fakeMessage(type?: string): unknown;
|
|
44
|
+
/**
|
|
45
|
+
* Format an message from RPC to UI friendly
|
|
46
|
+
*
|
|
47
|
+
* @public
|
|
48
|
+
* @static
|
|
49
|
+
* @param type - input type
|
|
50
|
+
* @param data - input data
|
|
51
|
+
* @returns object [almost same structure as input]
|
|
52
|
+
*/
|
|
53
|
+
declare function formatMessage(type: string, data: Record<string, unknown>): Record<string, unknown>;
|
|
54
|
+
/**
|
|
55
|
+
* Create an protobuf encoded Typed message with specified data, ready to send to rpc server
|
|
56
|
+
*
|
|
57
|
+
* @public
|
|
58
|
+
* @static
|
|
59
|
+
* @param type - message type defined in forge-proto
|
|
60
|
+
* @param params - message content
|
|
61
|
+
* @returns Message instance
|
|
62
|
+
*/
|
|
63
|
+
declare function createMessage(type: string, params?: Record<string, unknown>): ProtobufMessage | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Decode an google.protobuf.Any%{ typeUrl, value } => { type, value }
|
|
66
|
+
*
|
|
67
|
+
* @public
|
|
68
|
+
* @static
|
|
69
|
+
* @param data - encoded data object
|
|
70
|
+
* @returns Object { type, value }
|
|
71
|
+
*/
|
|
72
|
+
declare function decodeAny(data: AnyData | null): AnyData;
|
|
73
|
+
/**
|
|
74
|
+
* Encode { type, value } => google.protobuf.Any%{ typeUrl, value }
|
|
75
|
+
* Does nothing on already encoded message
|
|
76
|
+
*
|
|
77
|
+
* @public
|
|
78
|
+
* @static
|
|
79
|
+
* @param data
|
|
80
|
+
* @returns google.protobuf.Any
|
|
81
|
+
*/
|
|
82
|
+
declare function encodeAny(data: AnyData | undefined): typeof Any | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* Convert an { seconds, nanos } | date-string to google.protobuf.Timestamp object
|
|
85
|
+
*
|
|
86
|
+
* @public
|
|
87
|
+
* @static
|
|
88
|
+
* @param value
|
|
89
|
+
* @returns instanceof google.protobuf.Timestamp
|
|
90
|
+
*/
|
|
91
|
+
declare function encodeTimestamp(value: string | TimestampData | undefined): typeof Timestamp | undefined;
|
|
92
|
+
/**
|
|
93
|
+
* Decode google.protobuf.Timestamp message to ISO Date String
|
|
94
|
+
*
|
|
95
|
+
* FIXME: node strictly equal because we rounded the `nanos` field
|
|
96
|
+
*
|
|
97
|
+
* @public
|
|
98
|
+
* @static
|
|
99
|
+
* @param data
|
|
100
|
+
* @returns String timestamp
|
|
101
|
+
*/
|
|
102
|
+
declare function decodeTimestamp(data: TimestampData): string;
|
|
103
|
+
interface BigIntProtobufMessage extends ProtobufMessage {
|
|
104
|
+
setValue(v: Uint8Array): void;
|
|
105
|
+
setMinus(v: boolean): void;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Encode BigUint and BigSint types defined in forge-sdk, double encoding is avoided
|
|
109
|
+
*
|
|
110
|
+
* @public
|
|
111
|
+
* @static
|
|
112
|
+
* @param value - value to encode
|
|
113
|
+
* @param type - type names defined in forge-proto
|
|
114
|
+
* @returns Message
|
|
115
|
+
*/
|
|
116
|
+
declare function encodeBigInt(value: unknown, type: string): BigIntProtobufMessage;
|
|
117
|
+
/**
|
|
118
|
+
* Convert BigUint and BigSint to string representation of numbers
|
|
119
|
+
*
|
|
120
|
+
* @public
|
|
121
|
+
* @static
|
|
122
|
+
* @link https://stackoverflow.com/questions/23948278/how-to-convert-byte-array-into-a-signed-big-integer-in-javascript
|
|
123
|
+
* @param data - usually from encodeBigInt
|
|
124
|
+
* @returns human readable number
|
|
125
|
+
*/
|
|
126
|
+
declare function decodeBigInt(data: BigIntData): string;
|
|
127
|
+
/**
|
|
128
|
+
* Attach an $format method to rpc response
|
|
129
|
+
*
|
|
130
|
+
* @private
|
|
131
|
+
* @param data
|
|
132
|
+
* @param type
|
|
133
|
+
*/
|
|
134
|
+
declare function attachFormatFn(type: string, data: Record<string, unknown>, key?: string): void;
|
|
135
|
+
/**
|
|
136
|
+
* Attach an example method to
|
|
137
|
+
*
|
|
138
|
+
* @private
|
|
139
|
+
* @param data
|
|
140
|
+
* @param type
|
|
141
|
+
*/
|
|
142
|
+
declare function attachExampleFn(type: string, host: Record<string, unknown>, key: string): void;
|
|
143
|
+
//#endregion
|
|
144
|
+
export { AnyData, addProvider, attachExampleFn, attachFormatFn, createMessage, decodeAny, decodeBigInt, decodeTimestamp, encodeAny, encodeBigInt, encodeTimestamp, fakeMessage, formatMessage, fromTypeUrl, getMessageType, toTypeUrl };
|
package/esm/message.mjs
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
import { __require } from "./_virtual/rolldown_runtime.mjs";
|
|
2
|
+
import { addProvider, enums, fromTypeUrl, getMessageType, messages, toTypeUrl } from "./provider.mjs";
|
|
3
|
+
import createDebug from "debug";
|
|
4
|
+
import camelCase from "lodash/camelCase.js";
|
|
5
|
+
import { bytesToHex, isUint8Array, toBN, toUint8Array } from "@ocap/util";
|
|
6
|
+
|
|
7
|
+
//#region src/message.ts
|
|
8
|
+
/**
|
|
9
|
+
* @fileOverview Contains basic helper methods to encode/format/mock a protobuf message
|
|
10
|
+
* @module @ocap/message
|
|
11
|
+
* @requires @ocap/util
|
|
12
|
+
* @requires @ocap/proto
|
|
13
|
+
* @example
|
|
14
|
+
* bun add @ocap/message
|
|
15
|
+
*
|
|
16
|
+
* const { createMessage, fakeMessage, formatMessage } = require('@ocap/message');
|
|
17
|
+
*/
|
|
18
|
+
const jspb = __require("google-protobuf");
|
|
19
|
+
const { Any } = __require("google-protobuf/google/protobuf/any_pb");
|
|
20
|
+
const { Timestamp } = __require("google-protobuf/google/protobuf/timestamp_pb");
|
|
21
|
+
const debug = createDebug("@ocap/message");
|
|
22
|
+
const getEnumTypes = () => Object.keys(enums);
|
|
23
|
+
const scalarTypes = [
|
|
24
|
+
"bool",
|
|
25
|
+
"bytes",
|
|
26
|
+
"string",
|
|
27
|
+
"double",
|
|
28
|
+
"float",
|
|
29
|
+
"sint32",
|
|
30
|
+
"uint32",
|
|
31
|
+
"sfixed32",
|
|
32
|
+
"sint64",
|
|
33
|
+
"uint64",
|
|
34
|
+
"sfixed64"
|
|
35
|
+
];
|
|
36
|
+
const fakeValues = {
|
|
37
|
+
bool: true,
|
|
38
|
+
sint32: 1,
|
|
39
|
+
uint32: 2,
|
|
40
|
+
sfixed32: 3,
|
|
41
|
+
sint64: 4,
|
|
42
|
+
uint64: 5,
|
|
43
|
+
sfixed64: 6,
|
|
44
|
+
BigUint: () => "1234",
|
|
45
|
+
BigSint: () => "4567",
|
|
46
|
+
float: "12.2",
|
|
47
|
+
double: "12.3",
|
|
48
|
+
string: "arcblock",
|
|
49
|
+
bytes: new Uint8Array(),
|
|
50
|
+
enums: (type) => type ? Object.values(enums[type])[0] : void 0
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Generated a fake message for a type, the message can be RPC request/response
|
|
54
|
+
*
|
|
55
|
+
* @public
|
|
56
|
+
* @static
|
|
57
|
+
* @param type - Message type string, should be defined in forge-abi or forge-core-protocol
|
|
58
|
+
* @returns object
|
|
59
|
+
*/
|
|
60
|
+
function fakeMessage(type) {
|
|
61
|
+
if (!type) return;
|
|
62
|
+
if (fakeValues[type]) return fakeValues[type];
|
|
63
|
+
const { fields, oneofs } = getMessageType(type);
|
|
64
|
+
if (!fields) return;
|
|
65
|
+
let selectedFields = fields;
|
|
66
|
+
if (oneofs?.value && Array.isArray(oneofs.value.oneof)) {
|
|
67
|
+
const selectedField = oneofs.value.oneof[0];
|
|
68
|
+
selectedFields = { [selectedField]: fields[selectedField] };
|
|
69
|
+
}
|
|
70
|
+
const result = {};
|
|
71
|
+
Object.keys(selectedFields).forEach((key) => {
|
|
72
|
+
const { type: subType, keyType, rule } = selectedFields[key];
|
|
73
|
+
if (rule === "repeated") {
|
|
74
|
+
result[key] = [1, 2].map(() => fakeMessage(subType));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (keyType) {
|
|
78
|
+
result[key] = { [fakeValues[keyType]]: fakeMessage(subType) };
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (getEnumTypes().includes(subType)) {
|
|
82
|
+
result[key] = fakeValues.enums(subType);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if ([
|
|
86
|
+
"hash",
|
|
87
|
+
"appHash",
|
|
88
|
+
"txHash",
|
|
89
|
+
"address",
|
|
90
|
+
"from",
|
|
91
|
+
"to",
|
|
92
|
+
"proposer"
|
|
93
|
+
].includes(key)) {
|
|
94
|
+
result[key] = "F2D072CBD4954A20F26280730795D91AC1039996CEB6E24A31E9CE548DCB5E55";
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (fakeValues[subType]) result[key] = fakeValues[subType];
|
|
98
|
+
if (subType === "google.protobuf.Timestamp") {
|
|
99
|
+
result[key] = (/* @__PURE__ */ new Date()).toISOString();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (subType === "google.protobuf.Any") {
|
|
103
|
+
result[key] = {
|
|
104
|
+
type: "string",
|
|
105
|
+
value: "ABCD 1234"
|
|
106
|
+
};
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
result[key] = fakeMessage(subType);
|
|
110
|
+
});
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Format an message from RPC to UI friendly
|
|
115
|
+
*
|
|
116
|
+
* @public
|
|
117
|
+
* @static
|
|
118
|
+
* @param type - input type
|
|
119
|
+
* @param data - input data
|
|
120
|
+
* @returns object [almost same structure as input]
|
|
121
|
+
*/
|
|
122
|
+
function formatMessage(type, data) {
|
|
123
|
+
if (!type) return data;
|
|
124
|
+
if (["json", "vc"].includes(type)) return data;
|
|
125
|
+
if (typeof data !== "object") return data;
|
|
126
|
+
if (scalarTypes.includes(type)) return data;
|
|
127
|
+
const result = {};
|
|
128
|
+
const { fields } = getMessageType(type);
|
|
129
|
+
if (!fields) {
|
|
130
|
+
console.log({
|
|
131
|
+
type,
|
|
132
|
+
data
|
|
133
|
+
});
|
|
134
|
+
throw new Error(`Cannot get fields for type ${type}`);
|
|
135
|
+
}
|
|
136
|
+
Object.keys(fields).forEach((key) => {
|
|
137
|
+
const { type: subType, keyType, rule } = fields[key];
|
|
138
|
+
let value = data[key];
|
|
139
|
+
if (rule === "repeated") value = data[camelCase(`${key}_list`)] || data[key];
|
|
140
|
+
if (keyType) value = data[camelCase(`${key}_map`)] || data[key];
|
|
141
|
+
if (value === void 0) return;
|
|
142
|
+
if (rule === "repeated") {
|
|
143
|
+
result[key] = value.map((x) => formatMessage(subType, x));
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (keyType) {
|
|
147
|
+
debug("formatMessage.map", {
|
|
148
|
+
type,
|
|
149
|
+
subType,
|
|
150
|
+
keyType,
|
|
151
|
+
value
|
|
152
|
+
});
|
|
153
|
+
result[key] = (value || []).reduce((acc, [k, v]) => {
|
|
154
|
+
acc[k] = formatMessage(subType, v);
|
|
155
|
+
return acc;
|
|
156
|
+
}, {});
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (getEnumTypes().includes(subType)) {
|
|
160
|
+
result[key] = messages[subType][value];
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (["BigUint", "BigSint"].includes(subType)) {
|
|
164
|
+
result[key] = decodeBigInt(value);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (isUint8Array(value)) {
|
|
168
|
+
if (["appHash", "blockHash"].includes(key)) result[key] = Buffer.from(value).toString("hex");
|
|
169
|
+
if ([
|
|
170
|
+
"signature",
|
|
171
|
+
"pk",
|
|
172
|
+
"sk"
|
|
173
|
+
].includes(key)) result[key] = Buffer.from(value).toString("base64");
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (subType === "google.protobuf.Timestamp") {
|
|
177
|
+
result[key] = decodeTimestamp(value);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (subType === "google.protobuf.Any") {
|
|
181
|
+
if (value) {
|
|
182
|
+
const decoded = decodeAny(value);
|
|
183
|
+
result[key] = {
|
|
184
|
+
type: decoded.type || value.typeUrl,
|
|
185
|
+
value: formatMessage(decoded.type || value.typeUrl || "", decoded.value)
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (value && typeof value === "object") {
|
|
191
|
+
result[key] = formatMessage(subType, value);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
result[key] = value;
|
|
195
|
+
});
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Create an protobuf encoded Typed message with specified data, ready to send to rpc server
|
|
200
|
+
*
|
|
201
|
+
* @public
|
|
202
|
+
* @static
|
|
203
|
+
* @param type - message type defined in forge-proto
|
|
204
|
+
* @param params - message content
|
|
205
|
+
* @returns Message instance
|
|
206
|
+
*/
|
|
207
|
+
function createMessage(type, params) {
|
|
208
|
+
if (!type && !params) {
|
|
209
|
+
console.log({
|
|
210
|
+
type,
|
|
211
|
+
params
|
|
212
|
+
});
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const { fn: Message, fields } = getMessageType(type);
|
|
216
|
+
if (!Message || !fields) {
|
|
217
|
+
console.error({
|
|
218
|
+
type,
|
|
219
|
+
params,
|
|
220
|
+
fields,
|
|
221
|
+
Message
|
|
222
|
+
});
|
|
223
|
+
throw new Error(`Unsupported messageType: ${type}`);
|
|
224
|
+
}
|
|
225
|
+
const message = new Message();
|
|
226
|
+
if (!params) return message;
|
|
227
|
+
Object.keys(fields).forEach((key) => {
|
|
228
|
+
const { type: subType, keyType, rule, id } = fields[key];
|
|
229
|
+
const value = params[key] || params[camelCase(`${key}_list`)];
|
|
230
|
+
if (value === void 0) return;
|
|
231
|
+
if (keyType) {
|
|
232
|
+
const keys = Object.keys(value);
|
|
233
|
+
if (keys.length) {
|
|
234
|
+
const fn$1 = camelCase(`get_${key}_map`);
|
|
235
|
+
const map = message[fn$1]();
|
|
236
|
+
debug("createMessage.map", {
|
|
237
|
+
type,
|
|
238
|
+
subType,
|
|
239
|
+
keyType,
|
|
240
|
+
id,
|
|
241
|
+
fn: fn$1,
|
|
242
|
+
keys
|
|
243
|
+
});
|
|
244
|
+
keys.forEach((k) => {
|
|
245
|
+
map.set(k, createMessage(subType, value[k]));
|
|
246
|
+
});
|
|
247
|
+
jspb.Message.setField(message, id, map);
|
|
248
|
+
}
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const fn = camelCase(rule === "repeated" ? `add_${key}` : `set_${key}`);
|
|
252
|
+
if (typeof message[fn] !== "function") throw new Error(`Unexpected field names ${JSON.stringify({
|
|
253
|
+
type,
|
|
254
|
+
key,
|
|
255
|
+
subType,
|
|
256
|
+
fn,
|
|
257
|
+
rule
|
|
258
|
+
})}`);
|
|
259
|
+
const values = rule === "repeated" ? value : [value];
|
|
260
|
+
try {
|
|
261
|
+
values.forEach((v) => {
|
|
262
|
+
if (getEnumTypes().includes(subType)) {
|
|
263
|
+
message[fn](v);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (["BigUint", "BigSint"].includes(subType)) {
|
|
267
|
+
message[fn](encodeBigInt(v, subType));
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (subType === "google.protobuf.Timestamp") {
|
|
271
|
+
debug(`createMessage.${subType}`, { v });
|
|
272
|
+
message[fn](encodeTimestamp(v));
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (subType === "google.protobuf.Any") {
|
|
276
|
+
message[fn](encodeAny(v));
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (subType === "bytes") {
|
|
280
|
+
message[fn](toUint8Array(v));
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const { fn: SubMessage, fields: subFields } = getMessageType(subType);
|
|
284
|
+
if (SubMessage && subFields) {
|
|
285
|
+
debug(`createMessage.${subType}`, {
|
|
286
|
+
type,
|
|
287
|
+
subType,
|
|
288
|
+
key
|
|
289
|
+
});
|
|
290
|
+
const subMessage = createMessage(subType, v);
|
|
291
|
+
message[fn](subMessage);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
message[fn](v);
|
|
295
|
+
});
|
|
296
|
+
} catch (err) {
|
|
297
|
+
debug("createMessage.processField.error", {
|
|
298
|
+
type,
|
|
299
|
+
key,
|
|
300
|
+
subType,
|
|
301
|
+
fn,
|
|
302
|
+
rule,
|
|
303
|
+
values,
|
|
304
|
+
err
|
|
305
|
+
});
|
|
306
|
+
throw err;
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
return message;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Decode an google.protobuf.Any%{ typeUrl, value } => { type, value }
|
|
313
|
+
*
|
|
314
|
+
* @public
|
|
315
|
+
* @static
|
|
316
|
+
* @param data - encoded data object
|
|
317
|
+
* @returns Object { type, value }
|
|
318
|
+
*/
|
|
319
|
+
function decodeAny(data) {
|
|
320
|
+
if (!data) return {
|
|
321
|
+
type: "Unknown",
|
|
322
|
+
value: ""
|
|
323
|
+
};
|
|
324
|
+
if (data.type && data.value) return data;
|
|
325
|
+
const { typeUrl, value } = data;
|
|
326
|
+
if (typeUrl && ["json", "vc"].includes(typeUrl)) return {
|
|
327
|
+
type: typeUrl,
|
|
328
|
+
value: JSON.parse(Buffer.from(value, "base64").toString())
|
|
329
|
+
};
|
|
330
|
+
const type = fromTypeUrl(typeUrl);
|
|
331
|
+
const { fn: Message } = getMessageType(type);
|
|
332
|
+
if (!Message) return data;
|
|
333
|
+
const buffer = Buffer.isBuffer(value) ? value : Buffer.from(value, "base64");
|
|
334
|
+
return {
|
|
335
|
+
type,
|
|
336
|
+
value: Message.deserializeBinary(new Uint8Array(buffer)).toObject()
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Encode { type, value } => google.protobuf.Any%{ typeUrl, value }
|
|
341
|
+
* Does nothing on already encoded message
|
|
342
|
+
*
|
|
343
|
+
* @public
|
|
344
|
+
* @static
|
|
345
|
+
* @param data
|
|
346
|
+
* @returns google.protobuf.Any
|
|
347
|
+
*/
|
|
348
|
+
function encodeAny(data) {
|
|
349
|
+
if (!data) return;
|
|
350
|
+
const anyMessage = new Any();
|
|
351
|
+
try {
|
|
352
|
+
if (data.typeUrl && data.value && !data.type) {
|
|
353
|
+
anyMessage.setTypeUrl(data.typeUrl);
|
|
354
|
+
if (data.typeUrl === "fg:x:address") anyMessage.setValue(data.value);
|
|
355
|
+
else if (["json", "vc"].includes(data.typeUrl)) anyMessage.setValue(new Uint8Array(Buffer.from(JSON.stringify(data.value))));
|
|
356
|
+
else anyMessage.setValue(new Uint8Array(Buffer.from(data.value, "base64")));
|
|
357
|
+
} else {
|
|
358
|
+
const { value: anyValue, type: anyType } = data;
|
|
359
|
+
const typeUrl = toTypeUrl(anyType);
|
|
360
|
+
anyMessage.setTypeUrl(typeUrl);
|
|
361
|
+
if (["json", "vc"].includes(typeUrl)) anyMessage.setValue(new Uint8Array(Buffer.from(JSON.stringify(anyValue))));
|
|
362
|
+
else {
|
|
363
|
+
const anyValueBinary = createMessage(anyType, anyValue);
|
|
364
|
+
anyMessage.setValue(anyValueBinary.serializeBinary());
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
} catch (err) {
|
|
368
|
+
console.error("error encode any type", data);
|
|
369
|
+
throw err;
|
|
370
|
+
}
|
|
371
|
+
return anyMessage;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Convert an { seconds, nanos } | date-string to google.protobuf.Timestamp object
|
|
375
|
+
*
|
|
376
|
+
* @public
|
|
377
|
+
* @static
|
|
378
|
+
* @param value
|
|
379
|
+
* @returns instanceof google.protobuf.Timestamp
|
|
380
|
+
*/
|
|
381
|
+
function encodeTimestamp(value) {
|
|
382
|
+
if (!value) return;
|
|
383
|
+
const timestamp = new Timestamp();
|
|
384
|
+
if (typeof value === "string") {
|
|
385
|
+
const millionSeconds = Date.parse(value);
|
|
386
|
+
if (Number.isNaN(millionSeconds) === false) {
|
|
387
|
+
timestamp.setSeconds(Math.floor(millionSeconds / 1e3));
|
|
388
|
+
timestamp.setNanos(Math.floor(millionSeconds % 1e3 * 1e6));
|
|
389
|
+
}
|
|
390
|
+
} else {
|
|
391
|
+
const { seconds, nanos = 0 } = value;
|
|
392
|
+
timestamp.setSeconds(seconds);
|
|
393
|
+
timestamp.setNanos(nanos);
|
|
394
|
+
}
|
|
395
|
+
return timestamp;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Decode google.protobuf.Timestamp message to ISO Date String
|
|
399
|
+
*
|
|
400
|
+
* FIXME: node strictly equal because we rounded the `nanos` field
|
|
401
|
+
*
|
|
402
|
+
* @public
|
|
403
|
+
* @static
|
|
404
|
+
* @param data
|
|
405
|
+
* @returns String timestamp
|
|
406
|
+
*/
|
|
407
|
+
function decodeTimestamp(data) {
|
|
408
|
+
if (data?.seconds) {
|
|
409
|
+
const date = /* @__PURE__ */ new Date();
|
|
410
|
+
date.setTime(data.seconds * 1e3 + Math.ceil((data.nanos || 0) / 1e6));
|
|
411
|
+
return date.toISOString();
|
|
412
|
+
}
|
|
413
|
+
return "";
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Encode BigUint and BigSint types defined in forge-sdk, double encoding is avoided
|
|
417
|
+
*
|
|
418
|
+
* @public
|
|
419
|
+
* @static
|
|
420
|
+
* @param value - value to encode
|
|
421
|
+
* @param type - type names defined in forge-proto
|
|
422
|
+
* @returns Message
|
|
423
|
+
*/
|
|
424
|
+
function encodeBigInt(value, type) {
|
|
425
|
+
const { fn: BigIntMessageClass } = getMessageType(type);
|
|
426
|
+
if (!BigIntMessageClass) throw new Error(`Unknown BigInt type: ${type}`);
|
|
427
|
+
const message = new BigIntMessageClass();
|
|
428
|
+
if (value && typeof value === "object" && "value" in value && isUint8Array(value.value)) {
|
|
429
|
+
message.setValue(value.value);
|
|
430
|
+
if (type === "BigSint") message.setMinus(value.minus);
|
|
431
|
+
return message;
|
|
432
|
+
}
|
|
433
|
+
const number = toBN(value);
|
|
434
|
+
const zero = toBN(0);
|
|
435
|
+
message.setValue(new Uint8Array(number.toArray()));
|
|
436
|
+
if (type === "BigSint") message.setMinus(number.lt(zero));
|
|
437
|
+
return message;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Convert BigUint and BigSint to string representation of numbers
|
|
441
|
+
*
|
|
442
|
+
* @public
|
|
443
|
+
* @static
|
|
444
|
+
* @link https://stackoverflow.com/questions/23948278/how-to-convert-byte-array-into-a-signed-big-integer-in-javascript
|
|
445
|
+
* @param data - usually from encodeBigInt
|
|
446
|
+
* @returns human readable number
|
|
447
|
+
*/
|
|
448
|
+
function decodeBigInt(data) {
|
|
449
|
+
const bn = toBN(bytesToHex(data.value));
|
|
450
|
+
return `${data.minus ? "-" : ""}${bn.toString(10)}`;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Attach an $format method to rpc response
|
|
454
|
+
*
|
|
455
|
+
* @private
|
|
456
|
+
* @param data
|
|
457
|
+
* @param type
|
|
458
|
+
*/
|
|
459
|
+
function attachFormatFn(type, data, key = "$format") {
|
|
460
|
+
Object.defineProperty(data, key, {
|
|
461
|
+
writable: false,
|
|
462
|
+
enumerable: false,
|
|
463
|
+
configurable: false,
|
|
464
|
+
value: () => formatMessage(type, data)
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Attach an example method to
|
|
469
|
+
*
|
|
470
|
+
* @private
|
|
471
|
+
* @param data
|
|
472
|
+
* @param type
|
|
473
|
+
*/
|
|
474
|
+
function attachExampleFn(type, host, key) {
|
|
475
|
+
Object.defineProperty(host, key, {
|
|
476
|
+
writable: false,
|
|
477
|
+
enumerable: false,
|
|
478
|
+
configurable: false,
|
|
479
|
+
value: () => fakeMessage(type)
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
//#endregion
|
|
484
|
+
export { addProvider, attachExampleFn, attachFormatFn, createMessage, decodeAny, decodeBigInt, decodeTimestamp, encodeAny, encodeBigInt, encodeTimestamp, fakeMessage, formatMessage, fromTypeUrl, getMessageType, toTypeUrl };
|