@v3finance/core-sdk 0.2.1 → 0.2.3

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +2 -1
  3. package/dist/cjs/generated/operations.js +1 -1
  4. package/dist/cjs/generated/types.d.ts +13 -7
  5. package/dist/cjs/generated/types.d.ts.map +1 -1
  6. package/dist/cjs/resources/approvals.d.ts +22 -0
  7. package/dist/cjs/resources/approvals.d.ts.map +1 -1
  8. package/dist/cjs/resources/approvals.js +22 -0
  9. package/dist/cjs/resources/approvals.js.map +1 -1
  10. package/dist/cjs/resources/transfers.d.ts +64 -16
  11. package/dist/cjs/resources/transfers.d.ts.map +1 -1
  12. package/dist/cjs/resources/transfers.js +64 -16
  13. package/dist/cjs/resources/transfers.js.map +1 -1
  14. package/dist/cjs/version.d.ts +1 -1
  15. package/dist/cjs/version.js +1 -1
  16. package/dist/esm/generated/operations.js +1 -1
  17. package/dist/esm/generated/types.d.ts +13 -7
  18. package/dist/esm/generated/types.d.ts.map +1 -1
  19. package/dist/esm/resources/approvals.d.ts +22 -0
  20. package/dist/esm/resources/approvals.d.ts.map +1 -1
  21. package/dist/esm/resources/approvals.js +22 -0
  22. package/dist/esm/resources/approvals.js.map +1 -1
  23. package/dist/esm/resources/transfers.d.ts +64 -16
  24. package/dist/esm/resources/transfers.d.ts.map +1 -1
  25. package/dist/esm/resources/transfers.js +64 -16
  26. package/dist/esm/resources/transfers.js.map +1 -1
  27. package/dist/esm/version.d.ts +1 -1
  28. package/dist/esm/version.js +1 -1
  29. package/docs/concepts.md +2 -1
  30. package/docs/errors.md +36 -16
  31. package/package.json +1 -1
  32. package/src/generated/operations.ts +1 -1
  33. package/src/generated/types.ts +13 -7
  34. package/src/resources/approvals.ts +22 -0
  35. package/src/resources/transfers.ts +64 -16
  36. package/src/version.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,55 @@
3
3
  All notable changes to this package are documented in this file. The format is based on
4
4
  [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).
5
5
 
6
+ ## 0.2.3 — 2026-11-12
7
+
8
+ Spec snapshot refreshed from the live API (commit `031d7bf`,
9
+ [v3-finance/policy-engine#23](https://github.com/v3-finance/policy-engine/pull/23)). No operation
10
+ was added or removed, no type changed, and no code in this package changed: two failures that used
11
+ to answer 500 `INTERNAL_ERROR` now answer 409 with a code of their own.
12
+
13
+ ### Fixed
14
+
15
+ - `folders.update()` — renaming a folder to a name its owner already uses for another folder is a
16
+ 409 `GROUP_NAME_CONFLICT`, the same answer `folders.create()` gives. It used to be a 500
17
+ `INTERNAL_ERROR`.
18
+ - `addresses.create()` — when `create_address` requires signatures but fewer people can give them
19
+ than the threshold asks for, the call throws 409 `APPROVAL_UNSATISFIABLE` (no `details`); nothing
20
+ was created, and there is no 202. Do not retry: an administrator has to change the policy or the
21
+ approver group. Any other failure to create the approval request is 409 `APPROVAL_FAILED`. Both
22
+ used to be a 500 `INTERNAL_ERROR`.
23
+ - `docs/errors.md`: these codes in the address and folder tables.
24
+
25
+ ## 0.2.2 — 2026-11-12
26
+
27
+ Spec snapshot refreshed from the live API (commit `3ca1538`,
28
+ [v3-finance/policy-engine#22](https://github.com/v3-finance/policy-engine/pull/22)). No operation
29
+ was added or removed, and no code in this package changed: the API's money path did.
30
+
31
+ ### Changed
32
+
33
+ - `transfers.send()` — when the signing service gives no definite answer, the transfer is no
34
+ longer failed: it stays `pending` with its funds reserved, the call throws 502
35
+ `TRANSFER_OUTCOME_UNKNOWN` (`details.transactionId`), and an administrator's reconciliation
36
+ settles it. Retry only with the same `idempotencyKey`. `WALLET_SERVICE_ERROR` on a transfer is
37
+ now only the 400 of a definite refusal; the documented 502 "retry with a new key" is gone.
38
+ - `transfers.send()` — the same key with different parameters is 409 `IDEMPOTENCY_KEY_REUSED`, not
39
+ the earlier transfer; `toAddress` is checked against the network before anything is reserved,
40
+ 400 `INVALID_DESTINATION_ADDRESS`.
41
+ - `transfers.vote()` and `approvals.vote()` — an unknown outcome is not an error: `pending` with
42
+ `executionError: null`, or `APPROVED` with `finalized: false` and `applyError: null`. That answer
43
+ does not establish the outcome; read the transfer. Repeating the same vote on an open request
44
+ finishes it instead of answering 409 `ALREADY_VOTED`.
45
+ - `transfers.reconcile()` — `ReconcileTransferResult.status` gains `rejected` and `cancelled`
46
+ (a closed transfer whose reserve is still held: the reserve is returned, the status stays). An
47
+ exhaustiveness check over `confirmed | failed` stops compiling. A `pending` transfer that holds a
48
+ hash from the signing service is settled only by that hash, sent explicitly.
49
+ - `failureReason` is `null` on every status except `failed`, `rejected` and `cancelled`.
50
+ - `docs/errors.md`: the new codes — `TRANSFER_OUTCOME_UNKNOWN`, `TRANSFER_BROADCAST_UNRECORDED`,
51
+ `IDEMPOTENCY_KEY_REUSED`, `INVALID_DESTINATION_ADDRESS`, `REQUEST_INCOMPLETE`, and for
52
+ reconciliation `TRANSFER_BROADCAST`, `TXHASH_MISMATCH`, `TXHASH_IN_USE`, `TRANSFER_NOT_EXECUTED`,
53
+ `RESERVE_MISSING`, `RESERVE_RELEASED`.
54
+
6
55
  ## 0.2.1 — 2026-11-12
7
56
 
8
57
  ### Added
package/README.md CHANGED
@@ -127,7 +127,8 @@ switch (result.outcome) {
127
127
  Reporting "sent" on `pending` tells a person their money has gone when it is frozen. `replayed` is
128
128
  not "sent" either: it means a transfer with this key already existed, and its `status` says whether
129
129
  it went out (`confirmed` or `submitted`), is waiting for signatures (`awaiting_approval`), is still
130
- executing (`pending`) or did not go out (`failed`, `rejected`, `cancelled`).
130
+ executing or waiting for an administrator to reconcile it (`pending`) or did not go out (`failed`,
131
+ `rejected`, `cancelled`).
131
132
 
132
133
  **Always pass `idempotencyKey`** on a transfer and keep it until you have an answer: after a
133
134
  timeout it is the only way to retry without sending money twice. The key is read from the request
@@ -10,7 +10,7 @@
10
10
  // the API does not slip in unclassified.
11
11
  //
12
12
  // Operations: 171 · admin: 40 · both: 1 · member: 127 · service: 3
13
- // Spec sha256: 017bae30075b232ab4efdcfb7785335020be3060b46e3569b1cd887fcf037597
13
+ // Spec sha256: 1f0f2a38668572c443a84cb0207d4070b419a16c293b8e975f5e21c68e85b15a
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.OPERATIONS = void 0;
16
16
  exports.isAdminOperation = isAdminOperation;
@@ -297,6 +297,7 @@ export interface OutgoingTxSummary {
297
297
  status: string;
298
298
  txHash: string | null;
299
299
  fee: string | null;
300
+ /** Причина закрытия — только у failed/rejected/cancelled. У остальных статусов (awaiting_approval, pending, submitted, confirmed) — ВСЕГДА null: у незакрытого перевода причины отказа нет. Неясный исход исполнения (pending, транзакция могла уйти в сеть) здесь не показывается — его признак pending дольше 10 минут по updatedAt («ждёт сверки администратором») */
300
301
  failureReason: string | null;
301
302
  /** format: date-time */
302
303
  createdAt: string;
@@ -1625,7 +1626,7 @@ export interface CreateTransactionResult {
1625
1626
  amountDecimal: string;
1626
1627
  asset: string;
1627
1628
  network: string;
1628
- /** confirmed — новый успешный перевод; pending/failed возможны при replay по idempotencyKey */
1629
+ /** 201 — confirmed (исполнен сейчас); редко pending с заполненным txHash (транзакция ушла в сеть, а учёт не записался — доводит сверка, повторять перевод нельзя); 202 — awaiting_approval; 200 (replay по idempotencyKey) — ТЕКУЩИЙ статус перевода, любой: pending (первый запрос ещё исполняется — или его исход неизвестен: первый ответ был 502 TRANSFER_OUTCOME_UNKNOWN; повтор НЕ исполняет перевод заново, исход устанавливает сверка), awaiting_approval, confirmed, failed, rejected, cancelled */
1629
1630
  status: string;
1630
1631
  txHash: string | null;
1631
1632
  fee: string | null;
@@ -1639,12 +1640,13 @@ export interface CreateTransactionResult {
1639
1640
  }
1640
1641
  export interface CreateTransferBody {
1641
1642
  fromAddressId: string;
1643
+ /** Адрес получателя. Формат проверяется по типу сети адреса-отправителя ДО резерва средств: TRON — base58check (34 символа, «T…», контрольная сумма), EVM — 0x + 40 hex (смешанный регистр — контрольная сумма EIP-55). Не подошёл — 400 INVALID_DESTINATION_ADDRESS. Строка проверяется как есть, пробелы по краям — ошибка формата */
1642
1644
  toAddress: string;
1643
1645
  /** DECIMAL строка — конвертируется по token.decimals */
1644
1646
  amount: string;
1645
1647
  asset: string;
1646
1648
  /**
1647
- * Уникальный ключ попытки перевода (рекомендуется: uuid). Повторный запрос с тем же ключом вернёт существующую транзакцию без второго broadcast. Для новой попытки после failed — новый ключ.
1649
+ * Уникальный ключ попытки перевода (рекомендуется: uuid). Повторный запрос с тем же ключом и теми же параметрами вернёт 200 с существующим переводом — без второго broadcast, без повторной оценки политик. Тот же ключ с другими параметрами — 409 IDEMPOTENCY_KEY_REUSED. Для новой попытки после failed — новый ключ.
1648
1650
  *
1649
1651
  * length: 8..128
1650
1652
  */
@@ -1915,6 +1917,7 @@ export interface HistoryOutItem {
1915
1917
  asset: string;
1916
1918
  assetSymbol: string;
1917
1919
  fee: string | null;
1920
+ /** Причина закрытия — только у failed/rejected/cancelled. У остальных статусов (awaiting_approval, pending, submitted, confirmed) — ВСЕГДА null: у незакрытого перевода причины отказа нет. Неясный исход исполнения (pending, транзакция могла уйти в сеть) здесь не показывается — его признак pending дольше 10 минут по updatedAt («ждёт сверки администратором») */
1918
1921
  failureReason: string | null;
1919
1922
  fromAddress: {
1920
1923
  id: string;
@@ -2991,7 +2994,7 @@ export interface RatesResponse {
2991
2994
  }>;
2992
2995
  }
2993
2996
  export interface ReconcileTransferBody {
2994
- /** Хеш от подписывающего сервиса. ЕСТЬ — транзакция ушла в сеть, перевод доводится до confirmed. НЕТ (или null) — считаем, что broadcast'а не было, и возвращаем резерв (failed) */
2997
+ /** Хеш от подписывающего сервиса. ЕСТЬ — транзакция ушла в сеть, перевод доводится до confirmed. НЕТ (или null) — сверяющий утверждает, что broadcast'а не было, и резерв возвращается (failed). Для pending с неясным исходом (у pending без txHash его не отличить по ответам API — failureReason у незакрытого перевода null) это утверждение нужно ПРОВЕРИТЬ по сети: возврат за ушедшую транзакцию печатает деньги. Если у pending-перевода хеш уже сохранён (broadcast прошёл), он обязателен: без него — 409 TRANSFER_BROADCAST, с другим — 409 TXHASH_MISMATCH (сохранённый — в error.details.txHash) */
2995
2998
  txHash?: string | null;
2996
2999
  /** Комиссия, если известна */
2997
3000
  fee?: string | null;
@@ -2999,7 +3002,8 @@ export interface ReconcileTransferBody {
2999
3002
  reason?: string | null;
3000
3003
  }
3001
3004
  export interface ReconcileTransferResult {
3002
- status: "confirmed" | "failed";
3005
+ /** Статус перевода после сверки: confirmed (по хешу) | failed (резерв возвращён). rejected/cancelled — у закрытого перевода с невозвращённым резервом: резерв возвращён, статус прежний */
3006
+ status: "confirmed" | "failed" | "rejected" | "cancelled";
3003
3007
  txHash: string | null;
3004
3008
  }
3005
3009
  export interface RegisterPushTokenBody {
@@ -3018,8 +3022,9 @@ export interface RequestVoteResult {
3018
3022
  approvals: number;
3019
3023
  /** range: -9007199254740991..9007199254740991 */
3020
3024
  threshold: number;
3021
- /** true — этот голос финализировал заявку (применена/отклонена) */
3025
+ /** true — этот голос финализировал заявку (применена/отклонена). У заявки на перевод status=APPROVED при finalized=false значит, что исход рассчитал НЕ этот вызов: applyError пуст — перевод исполняет (исполнил) параллельный запрос ЛИБО исполнение, начатое другим вызовом, оборвалось (сам перевод тогда не закроется); исход — только по GET /transfers/{id}: confirmed/failed, а pending дольше 10 минут по updatedAt — ждёт сверки (admin). applyError TRANSFER_EXECUTION_FAILED — к моменту одобрения перевод уже не ждал подписей. finalized=false с пустым applyError приходит и тогда, когда одобрил ЭТОТ голос, но исход перевода им не установлен (перевод pending: подписывающий сервис не дал определённого ответа, транзакция могла уйти в сеть, а могла и нет): показывайте «голос учтён», не «применено». finalized=true с пустым applyError у перевода — исполнен этим вызовом (confirmed) */
3022
3026
  finalized: boolean;
3027
+ /** Голос финализировал заявку, а применение не дало результата; status при этом итоговый. Коды: STALE — цель изменилась (status=REJECTED); APPLY_FAILED / APPLY_FAILED_ROLLED_BACK / APPLY_FAILED_PARTIAL — мутация не применена (целиком / цепочка откатана / частично). У action=transfer финальный approve ИСПОЛНЯЕТ перевод, status=APPROVED: TRANSFER_EXECUTION_FAILED — перевод не исполнен (обычно failed, резерв возвращён; точный статус — GET /transfers/{id}; при finalized=false — перевод уже не ждал подписей, одобрение его не исполняло). Неясный исход перевода (подписывающий сервис не дал определённого ответа, перевод pending, средства зарезервированы, транзакция могла уйти в сеть, исход установит сверка, admin) ошибкой НЕ отдаётся: applyError null, status APPROVED, finalized=false. Кода TRANSFER_OUTCOME_UNKNOWN здесь нет — он только у POST /transfers */
3023
3028
  applyError: {
3024
3029
  code: string;
3025
3030
  message: string;
@@ -3179,6 +3184,7 @@ export interface TransactionDetail {
3179
3184
  decisionPolicyCode: string | null;
3180
3185
  /** Человеческое название решающей политики (для UI вместо кода) */
3181
3186
  decisionPolicyName: string | null;
3187
+ /** Причина закрытия — только у failed/rejected/cancelled. У остальных статусов (awaiting_approval, pending, submitted, confirmed) — ВСЕГДА null: у незакрытого перевода причины отказа нет. Неясный исход исполнения (pending, транзакция могла уйти в сеть) здесь не показывается — его признак pending дольше 10 минут по updatedAt («ждёт сверки администратором») */
3182
3188
  failureReason: string | null;
3183
3189
  /** format: date-time */
3184
3190
  createdAt: string;
@@ -3496,7 +3502,7 @@ export interface VoteRequestBody {
3496
3502
  comment?: string;
3497
3503
  }
3498
3504
  export interface VoteResult {
3499
- /** Статус перевода ПОСЛЕ голоса: awaiting_approval (голосов мало) | rejected | confirmed/failed (финальный approve исполняет сразу) */
3505
+ /** Статус перевода ПОСЛЕ голоса: awaiting_approval (голосов мало) | rejected | confirmed/failed (финальный approve исполняет сразу). pending — исполнение не закончено, повторять перевод нельзя; executionError у pending всегда null, исход этим ответом НЕ установлен, ждать его «через секунды» нельзя. Так отдаётся и неясный исход (подписывающий сервис не дал определённого ответа, транзакция могла уйти в сеть, резерв стоит — доводит сверка, admin), и: txHash в GET /transfers/{id} есть — транзакция ушла в сеть, а учёт не записался, доводит сверка (admin) по этому хешу; перевод исполняет параллельный запрос (одновременный голос другого подписанта или исходный вызов при повторе голоса) ЛИБО исполнение оборвалось (клиент, который его начал, отключился — сам перевод тогда не закроется). Различает только время: перечитывайте GET; confirmed/failed — исход; pending дольше 10 минут по updatedAt — «ждёт сверки администратором» */
3500
3506
  status: string;
3501
3507
  /**
3502
3508
  * Собрано approve-голосов
@@ -3506,7 +3512,7 @@ export interface VoteResult {
3506
3512
  approvals: number;
3507
3513
  /** range: -9007199254740991..9007199254740991 */
3508
3514
  threshold: number;
3509
- /** Если финальный approve запустил исполнение и оно упало (средства возвращены) */
3515
+ /** Финальный approve запустил исполнение, и оно перевод НЕ исполнило. code: TRANSFER_EXECUTION_FAILED — не исполнен (status=failed, средства возвращены; исключения: failed с txHash у перевода, см. описание ручки, и status=pending, если сам возврат резерва не записался — тогда перевод доводит сверка). Тот же код — если к моменту одобрения перевод уже не ждал подписей (status — его фактический: failed/rejected/cancelled): одобрение его не исполнило. Неясный исход (подписывающий сервис не дал определённого ответа, транзакция могла уйти в сеть) ошибкой НЕ отдаётся: status=pending, executionError=null — показывайте «исполняется, исход уточняется». Кода TRANSFER_OUTCOME_UNKNOWN в голосе нет, он только у POST /transfers */
3510
3516
  executionError: {
3511
3517
  code: string;
3512
3518
  message: string;