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