@steemit/steem-js 1.0.17 → 1.0.18

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,37 @@
1
+ /**
2
+ * Chain-safe JSON normalization for account_update operations.
3
+ * Matches steem::protocol::account_update_operation and authority (FC_REFLECT).
4
+ * Broadcast via JSON-RPC uses fc::from_variant; malformed shapes cause bad_cast_exception.
5
+ */
6
+ export type ChainAuthority = {
7
+ weight_threshold: number;
8
+ account_auths: [string, number][];
9
+ key_auths: [string, number][];
10
+ };
11
+ export type AccountUpdatePayload = {
12
+ account: string;
13
+ owner: ChainAuthority;
14
+ active: ChainAuthority;
15
+ posting: ChainAuthority;
16
+ memo_key: string;
17
+ json_metadata: string;
18
+ };
19
+ export type OperationTuple = [string, Record<string, unknown>];
20
+ /** Steem broadcast JSON requires json_metadata to be a string (not object/array). */
21
+ export declare function normalizeChainJsonMetadata(value: unknown): string;
22
+ /** Normalize API authority data (handles object-maps and malformed arrays). */
23
+ export declare function normalizeAuthoritySource(source: unknown): ChainAuthority;
24
+ /** Coerce account_update operation payload to chain-safe JSON (for signing and broadcast). */
25
+ export declare function sanitizeAccountUpdatePayload(payload: Record<string, unknown>): AccountUpdatePayload;
26
+ /**
27
+ * Normalize an operation tuple before signing or JSON broadcast.
28
+ * Only account_update is rewritten; other operations pass through unchanged.
29
+ */
30
+ export declare function normalizeOperationForBroadcast(operation: unknown): unknown;
31
+ /** Normalize transaction operations/extensions for JSON broadcast after signing. */
32
+ export declare function normalizeTransactionForBroadcast(trx: Record<string, unknown>): Record<string, unknown>;
33
+ /**
34
+ * Authority value for binary serialization (fail-fast on array mistaken for object).
35
+ * Mirrors steem wallet_api::update_account which assigns authority structs, not key_auths arrays.
36
+ */
37
+ export declare function resolveAuthorityForSerialize(auth: unknown, field: string): Record<string, unknown>;
@@ -1,3 +1,5 @@
1
+ export { normalizeOperationForBroadcast, normalizeTransactionForBroadcast, normalizeChainJsonMetadata, sanitizeAccountUpdatePayload, normalizeAuthoritySource, resolveAuthorityForSerialize, } from './account-update-chain';
2
+ export type { ChainAuthority, AccountUpdatePayload, OperationTuple } from './account-update-chain';
1
3
  export interface KeyPair {
2
4
  privateKey: string;
3
5
  publicKey: string;
@@ -25300,6 +25300,132 @@ if (typeof BigInt === "function") {
25300
25300
  };
25301
25301
  }
25302
25302
 
25303
+ /**
25304
+ * Chain-safe JSON normalization for account_update operations.
25305
+ * Matches steem::protocol::account_update_operation and authority (FC_REFLECT).
25306
+ * Broadcast via JSON-RPC uses fc::from_variant; malformed shapes cause bad_cast_exception.
25307
+ */
25308
+ /** Steem broadcast JSON requires json_metadata to be a string (not object/array). */
25309
+ function normalizeChainJsonMetadata(value) {
25310
+ if (typeof value === 'string')
25311
+ return value;
25312
+ if (value == null)
25313
+ return '';
25314
+ if (Array.isArray(value))
25315
+ return value.length === 0 ? '' : JSON.stringify(value);
25316
+ if (typeof value === 'object')
25317
+ return JSON.stringify(value);
25318
+ return String(value);
25319
+ }
25320
+ function toAuthPairs(raw) {
25321
+ if (Array.isArray(raw)) {
25322
+ return raw
25323
+ .filter((entry) => Array.isArray(entry) && entry.length >= 2)
25324
+ .map(([key, weight]) => [String(key), Number(weight)])
25325
+ .filter(([, weight]) => Number.isFinite(weight));
25326
+ }
25327
+ if (raw && typeof raw === 'object') {
25328
+ return Object.entries(raw)
25329
+ .map(([key, weight]) => [String(key), Number(weight)])
25330
+ .filter(([, weight]) => Number.isFinite(weight));
25331
+ }
25332
+ return [];
25333
+ }
25334
+ function toKeyAuthPairs(raw) {
25335
+ if (Array.isArray(raw)) {
25336
+ return raw
25337
+ .filter((entry) => Array.isArray(entry) && entry.length >= 2)
25338
+ .map(([key, weight]) => [String(key), Number(weight)])
25339
+ .filter(([key, weight]) => key.startsWith('STM') && Number.isFinite(weight));
25340
+ }
25341
+ if (raw && typeof raw === 'object') {
25342
+ return Object.entries(raw)
25343
+ .map(([key, weight]) => [String(key), Number(weight)])
25344
+ .filter(([key, weight]) => key.startsWith('STM') && Number.isFinite(weight));
25345
+ }
25346
+ return [];
25347
+ }
25348
+ /** Normalize API authority data (handles object-maps and malformed arrays). */
25349
+ function normalizeAuthoritySource(source) {
25350
+ if (Array.isArray(source) || !source || typeof source !== 'object') {
25351
+ return { weight_threshold: 1, account_auths: [], key_auths: [] };
25352
+ }
25353
+ const obj = source;
25354
+ const weight_threshold = Math.max(1, Number(obj.weight_threshold) || 1);
25355
+ return {
25356
+ weight_threshold,
25357
+ account_auths: toAuthPairs(obj.account_auths),
25358
+ key_auths: toKeyAuthPairs(obj.key_auths),
25359
+ };
25360
+ }
25361
+ function sanitizeAuthority(value, field) {
25362
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
25363
+ throw new Error(`Invalid ${field} authority: expected object with weight_threshold, account_auths, key_auths`);
25364
+ }
25365
+ const obj = value;
25366
+ const weight_threshold = Math.max(1, Number(obj.weight_threshold) || 1);
25367
+ const account_auths = toAuthPairs(obj.account_auths);
25368
+ const key_auths = toKeyAuthPairs(obj.key_auths);
25369
+ if (key_auths.length === 0) {
25370
+ throw new Error(`Invalid ${field} authority: key_auths is empty or malformed`);
25371
+ }
25372
+ return { weight_threshold, account_auths, key_auths };
25373
+ }
25374
+ /** Coerce account_update operation payload to chain-safe JSON (for signing and broadcast). */
25375
+ function sanitizeAccountUpdatePayload(payload) {
25376
+ return {
25377
+ account: String(payload.account || ''),
25378
+ owner: sanitizeAuthority(payload.owner, 'owner'),
25379
+ active: sanitizeAuthority(payload.active, 'active'),
25380
+ posting: sanitizeAuthority(payload.posting, 'posting'),
25381
+ memo_key: String(payload.memo_key || ''),
25382
+ json_metadata: normalizeChainJsonMetadata(payload.json_metadata),
25383
+ };
25384
+ }
25385
+ /**
25386
+ * Normalize an operation tuple before signing or JSON broadcast.
25387
+ * Only account_update is rewritten; other operations pass through unchanged.
25388
+ */
25389
+ function normalizeOperationForBroadcast(operation) {
25390
+ if (!Array.isArray(operation) || operation.length !== 2) {
25391
+ return operation;
25392
+ }
25393
+ const [opType, opData] = operation;
25394
+ if (opType !== 'account_update') {
25395
+ return operation;
25396
+ }
25397
+ if (!opData || typeof opData !== 'object' || Array.isArray(opData)) {
25398
+ throw new Error('account_update payload must be an object');
25399
+ }
25400
+ return ['account_update', sanitizeAccountUpdatePayload(opData)];
25401
+ }
25402
+ /** Normalize transaction operations/extensions for JSON broadcast after signing. */
25403
+ function normalizeTransactionForBroadcast(trx) {
25404
+ const operations = Array.isArray(trx.operations) ? trx.operations : [];
25405
+ const extensions = Array.isArray(trx.extensions) ? trx.extensions : [];
25406
+ return {
25407
+ ...trx,
25408
+ operations: operations.map((op) => normalizeOperationForBroadcast(op)),
25409
+ extensions,
25410
+ };
25411
+ }
25412
+ /**
25413
+ * Authority value for binary serialization (fail-fast on array mistaken for object).
25414
+ * Mirrors steem wallet_api::update_account which assigns authority structs, not key_auths arrays.
25415
+ */
25416
+ function resolveAuthorityForSerialize(auth, field) {
25417
+ if (auth == null || auth === '') {
25418
+ throw new Error(`Invalid ${field} authority: value is required`);
25419
+ }
25420
+ if (Array.isArray(auth)) {
25421
+ throw new Error(`Invalid ${field} authority: expected object, got array (wrap key_auths inside an authority object)`);
25422
+ }
25423
+ if (typeof auth !== 'object') {
25424
+ throw new Error(`Invalid ${field} authority: expected object`);
25425
+ }
25426
+ return auth;
25427
+ }
25428
+
25303
25429
  /**
25304
25430
  * Serialize a transaction to binary format for Steem blockchain
25305
25431
  * This is a simplified implementation that handles the basic structure
@@ -25666,21 +25792,21 @@ function serializeAccountUpdate(bb, data) {
25666
25792
  // Optional authorities: 0 = not present, 1 = present then serialize authority
25667
25793
  if (dataObj.owner != null && dataObj.owner !== '') {
25668
25794
  bb.writeUint8(1);
25669
- serializeAuthority(bb, typeof dataObj.owner === 'object' ? dataObj.owner : { weight_threshold: 1, account_auths: [], key_auths: [] });
25795
+ serializeAuthority(bb, resolveAuthorityForSerialize(dataObj.owner, 'owner'));
25670
25796
  }
25671
25797
  else {
25672
25798
  bb.writeUint8(0);
25673
25799
  }
25674
25800
  if (dataObj.active != null && dataObj.active !== '') {
25675
25801
  bb.writeUint8(1);
25676
- serializeAuthority(bb, typeof dataObj.active === 'object' ? dataObj.active : { weight_threshold: 1, account_auths: [], key_auths: [] });
25802
+ serializeAuthority(bb, resolveAuthorityForSerialize(dataObj.active, 'active'));
25677
25803
  }
25678
25804
  else {
25679
25805
  bb.writeUint8(0);
25680
25806
  }
25681
25807
  if (dataObj.posting != null && dataObj.posting !== '') {
25682
25808
  bb.writeUint8(1);
25683
- serializeAuthority(bb, typeof dataObj.posting === 'object' ? dataObj.posting : { weight_threshold: 1, account_auths: [], key_auths: [] });
25809
+ serializeAuthority(bb, resolveAuthorityForSerialize(dataObj.posting, 'posting'));
25684
25810
  }
25685
25811
  else {
25686
25812
  bb.writeUint8(0);
@@ -26328,6 +26454,12 @@ function serializeCustomJson(bb, data) {
26328
26454
  * Serialize Authority
26329
26455
  */
26330
26456
  function serializeAuthority(bb, auth) {
26457
+ if (Array.isArray(auth)) {
26458
+ throw new Error('Invalid authority: expected object, got array');
26459
+ }
26460
+ if (auth == null || typeof auth !== 'object') {
26461
+ throw new Error('Invalid authority: expected object');
26462
+ }
26331
26463
  const authObj = auth;
26332
26464
  bb.writeUint32(authObj.weight_threshold || 1);
26333
26465
  // Account auths (map<string, uint16>)
@@ -26663,17 +26795,18 @@ const Auth = {
26663
26795
  if (Array.isArray(trxObjWithSigs.signatures)) {
26664
26796
  signatures.push(...trxObjWithSigs.signatures.map((sig) => bufferExports.Buffer.isBuffer(sig) ? sig.toString('hex') : String(sig)));
26665
26797
  }
26798
+ const trxObj = trx;
26799
+ const normalizedTrx = normalizeTransactionForBroadcast(trxObj);
26666
26800
  const chainId = getConfig().get('chain_id') || '';
26667
26801
  const cid = bufferExports.Buffer.from(chainId, 'hex');
26668
- const buf = transaction.toBuffer(trx);
26802
+ const buf = transaction.toBuffer(normalizedTrx);
26669
26803
  for (const key of keys) {
26670
26804
  const sig = Signature.signBuffer(bufferExports.Buffer.concat([cid, buf]), key);
26671
26805
  // Use toBuffer() to match old-steem-js behavior
26672
26806
  // The serializer will convert Buffer to hex string when needed
26673
26807
  signatures.push(sig.toBuffer().toString('hex'));
26674
26808
  }
26675
- const trxObj = trx;
26676
- return signed_transaction.toObject(Object.assign(trxObj, { signatures }));
26809
+ return signed_transaction.toObject(Object.assign({}, normalizedTrx, { signatures }));
26677
26810
  }
26678
26811
  };
26679
26812
  // Export individual functions
@@ -26753,6 +26886,12 @@ const auth = /*#__PURE__*/Object.freeze({
26753
26886
  getPublicKey: getPublicKey,
26754
26887
  isPubkey: isPubkey,
26755
26888
  isWif: isWif,
26889
+ normalizeAuthoritySource: normalizeAuthoritySource,
26890
+ normalizeChainJsonMetadata: normalizeChainJsonMetadata,
26891
+ normalizeOperationForBroadcast: normalizeOperationForBroadcast,
26892
+ normalizeTransactionForBroadcast: normalizeTransactionForBroadcast,
26893
+ resolveAuthorityForSerialize: resolveAuthorityForSerialize,
26894
+ sanitizeAccountUpdatePayload: sanitizeAccountUpdatePayload,
26756
26895
  sign: sign$1,
26757
26896
  signTransaction: signTransaction,
26758
26897
  toWif: toWif,
@@ -29561,7 +29700,7 @@ const steem = {
29561
29700
  memo,
29562
29701
  operations,
29563
29702
  utils: utils$3,
29564
- version: '1.0.17',
29703
+ version: '1.0.18',
29565
29704
  config: {
29566
29705
  set: (options) => {
29567
29706
  // If nodes is provided, extract the first node as url for API