@v3finance/core-sdk 0.2.3 → 0.2.4

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/CHANGELOG.md CHANGED
@@ -3,6 +3,24 @@
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.4 — 2026-11-12
7
+
8
+ Spec snapshot refreshed from the live API (commit `5e8f3e3`,
9
+ [v3-finance/policy-engine#24](https://github.com/v3-finance/policy-engine/pull/24)). No operation
10
+ was added or removed, no type changed, and no code in this package changed: the API now refuses a
11
+ counterparty address that belongs to the vault itself.
12
+
13
+ ### Fixed
14
+
15
+ - `counterparties.create()` and `counterparties.addAddress()` — an address that is one of this
16
+ vault's own addresses on the same network is refused with 409 `ADDRESS_IS_VAULT_ADDRESS`, and
17
+ `details` is `{address, network}`. Nothing is created or added. It used to be accepted, and the
18
+ retro-match then tagged internal transfers on that address as operations with the counterparty —
19
+ irreversibly, since removing the address does not untag them. Inside a chain or in the apply of
20
+ an approved request the code stays the chain's (`CHAIN_FAILED_ROLLED_BACK`, or `APPLY_FAILED` in
21
+ `applyError`), with the same sentence in `message`.
22
+ - `docs/errors.md`: the code in the counterparty table, and where it arrives under another code.
23
+
6
24
  ## 0.2.3 — 2026-11-12
7
25
 
8
26
  Spec snapshot refreshed from the live API (commit `031d7bf`,
@@ -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: 1f0f2a38668572c443a84cb0207d4070b419a16c293b8e975f5e21c68e85b15a
13
+ // Spec sha256: 1f2a93f5a31a423e3301b4bfa103ad3db26723285cae060d2e8a904a2b3bffe0
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.OPERATIONS = void 0;
16
16
  exports.isAdminOperation = isAdminOperation;
@@ -1,5 +1,5 @@
1
1
  /** SDK version, sent in the `user-agent` header. */
2
- export declare const SDK_VERSION = "0.2.3";
2
+ export declare const SDK_VERSION = "0.2.4";
3
3
  /** Default API base URL. */
4
4
  export declare const DEFAULT_BASE_URL = "https://policy-engine-rest.ezig.workers.dev";
5
5
  //# sourceMappingURL=version.d.ts.map
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEFAULT_BASE_URL = exports.SDK_VERSION = void 0;
4
4
  /** SDK version, sent in the `user-agent` header. */
5
- exports.SDK_VERSION = '0.2.3';
5
+ exports.SDK_VERSION = '0.2.4';
6
6
  /** Default API base URL. */
7
7
  exports.DEFAULT_BASE_URL = 'https://policy-engine-rest.ezig.workers.dev';
8
8
  //# sourceMappingURL=version.js.map
@@ -9,7 +9,7 @@
9
9
  // the API does not slip in unclassified.
10
10
  //
11
11
  // Operations: 171 · admin: 40 · both: 1 · member: 127 · service: 3
12
- // Spec sha256: 1f0f2a38668572c443a84cb0207d4070b419a16c293b8e975f5e21c68e85b15a
12
+ // Spec sha256: 1f2a93f5a31a423e3301b4bfa103ad3db26723285cae060d2e8a904a2b3bffe0
13
13
  export const OPERATIONS = {
14
14
  "DELETE /api/v1/me/push-tokens/{token}": {
15
15
  "method": "delete",
@@ -1,5 +1,5 @@
1
1
  /** SDK version, sent in the `user-agent` header. */
2
- export declare const SDK_VERSION = "0.2.3";
2
+ export declare const SDK_VERSION = "0.2.4";
3
3
  /** Default API base URL. */
4
4
  export declare const DEFAULT_BASE_URL = "https://policy-engine-rest.ezig.workers.dev";
5
5
  //# sourceMappingURL=version.d.ts.map
@@ -1,5 +1,5 @@
1
1
  /** SDK version, sent in the `user-agent` header. */
2
- export const SDK_VERSION = '0.2.3';
2
+ export const SDK_VERSION = '0.2.4';
3
3
  /** Default API base URL. */
4
4
  export const DEFAULT_BASE_URL = 'https://policy-engine-rest.ezig.workers.dev';
5
5
  //# sourceMappingURL=version.js.map
package/docs/errors.md CHANGED
@@ -329,18 +329,21 @@ Category keys and field keys and types are **immutable** after creation, and any
329
329
 
330
330
  ## Counterparties
331
331
 
332
- Note the statuses: conflicts in this domain answer **400**, not 409.
332
+ Note the statuses: conflicts in this domain answer **400**, not 409 — all but `ADDRESS_IS_VAULT_ADDRESS`, which is a 409.
333
333
 
334
334
  | Code | Status | When | What to do |
335
335
  |---|---|---|---|
336
336
  | `NAME_TAKEN` | 400 | A counterparty with that name already exists in the vault. | Ask for a different name. |
337
337
  | `ADDRESS_TAKEN` | 400 | One of the addresses already belongs to another counterparty here. `message` names it when it can be resolved. | Show which address collides; the user must remove it from the other counterparty first. |
338
+ | `ADDRESS_IS_VAULT_ADDRESS` | 409 | An address is one of this vault's own addresses on the same network — from `counterparties.create()` with `addresses`, or `counterparties.addAddress()`. It used to be accepted, and then the retro-match tagged past transfers and deposits on that address with the counterparty, matching tagged new ones, and removing the address does not untag them: internal transfers became operations with a counterparty in reports. Checked before anything is written — nothing was created or added. `details` is `{address, network}`: the first such address, trimmed, with the network lowercased. An EVM-shaped address matches regardless of letter case; an address of another vault is accepted. | Terminal, not a retry. Mark the address field from `details` and say it belongs to the vault itself. |
338
339
  | `NETWORK_NOT_REGISTERED` | 400 | An address names a network missing from the registry. `message` lists them. | Terminal for a non-admin: an administrator must register the network. |
339
340
  | `VALIDATION` | 400 | A required field (`name`, `address`, `code`) is empty after trimming. | Normal form validation. |
340
341
  | `CODE_TAKEN` | 400 | A counterparty **group** with that code already exists in the vault. | Ask for a different code. |
341
342
  | `ALREADY_MEMBER` | 400 | The counterparty is already in the group. | Benign. Treat as success and refresh. |
342
343
  | `NOT_FOUND` | 404 | The counterparty or group does not exist in this vault. | Refresh. (Arrives as a status-derived `NOT_FOUND` — see [Declared but never returned](#declared-but-never-returned).) |
343
344
 
345
+ `ADDRESS_IS_VAULT_ADDRESS` arrives under its own code only from those two calls answered directly. When the same check fails inside a chain or in the apply of an approved request, the code is the chain's or the apply's, and the sentence travels in `message`, without `details.address` / `details.network`: a chain that needed no signatures — `counterparties.create()` with `groupId` or `newGroup`, or `approvals.createComposite()` — throws 400 `CHAIN_FAILED_ROLLED_BACK` (`CHAIN_FAILED_PARTIAL` if an earlier step could not be rolled back) with `Step N failed: …` and `details.stepIndex`; an approved request answers the vote with 200 and `applyError.code` `APPLY_FAILED` (a single request, the bare sentence) or `APPLY_FAILED_ROLLED_BACK` / `APPLY_FAILED_PARTIAL` (a composite one, with the `Step N failed:` prefix). The check comes first in the step as well: a `counterparty_update` that also renames the counterparty leaves the name untouched.
346
+
344
347
  Changing a group's membership is scoped to its own vault, and that is checked at the write, including when it arrives via an approved request. A cross-vault attempt fails as a plain 404, not with a distinct code.
345
348
 
346
349
  Group membership also gates destination whitelists: archiving a counterparty group revokes the whitelist it backs, because membership resolves over non-archived groups only. There is no error for this — transfers simply start being denied with `POLICY_DENIED`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@v3finance/core-sdk",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "The official TypeScript SDK for the V3 Finance Core API — custodial addresses, transfers under policy control, approvals, shared access, labelling and reports",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -9,7 +9,7 @@
9
9
  // the API does not slip in unclassified.
10
10
  //
11
11
  // Operations: 171 · admin: 40 · both: 1 · member: 127 · service: 3
12
- // Spec sha256: 1f0f2a38668572c443a84cb0207d4070b419a16c293b8e975f5e21c68e85b15a
12
+ // Spec sha256: 1f2a93f5a31a423e3301b4bfa103ad3db26723285cae060d2e8a904a2b3bffe0
13
13
 
14
14
  export type Audience = 'member' | 'admin' | 'service' | 'both' | 'unknown'
15
15
 
package/src/version.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** SDK version, sent in the `user-agent` header. */
2
- export const SDK_VERSION = '0.2.3'
2
+ export const SDK_VERSION = '0.2.4'
3
3
 
4
4
  /** Default API base URL. */
5
5
  export const DEFAULT_BASE_URL = 'https://policy-engine-rest.ezig.workers.dev'