Skip to content

feat(sdk): align with acta-api v1.1.1 / vc-vault v0.3.0#2

Open
JosueBrenes wants to merge 1 commit into
mainfrom
feat/align-vc-vault-v0.3.0
Open

feat(sdk): align with acta-api v1.1.1 / vc-vault v0.3.0#2
JosueBrenes wants to merge 1 commit into
mainfrom
feat/align-vc-vault-v0.3.0

Conversation

@JosueBrenes
Copy link
Copy Markdown
Contributor

@JosueBrenes JosueBrenes commented May 20, 2026

Summary

Bring `@acta-team/credentials` from v1.1.1 → v1.1.2 so it works against `acta-api` v1.2.0 (PR acta-api#82). New surface includes typed errors, paginated reads, batch issuance, full `vc-issuer-registry` coverage, and React hooks for every new endpoint.

Do not publish from this branch. Strict semver would call most changes BREAKING and bump to 2.0.0; we are intentionally staying on 1.1.x until `enterprise-acta-panel` migrates. After the panel is updated, cut a separate `v2.0.0` release.

Removed — BREAKING

  • `ActaClient.createCredential` (was deprecated and threw).
  • `ActaClient.getDefaults` (deprecated alias for `getConfig`).
  • `ActaClient.prepareStoreTx`, `prepareListVcIdsTx`, `prepareGetVcTx`, `vaultStore` (deprecated wrappers).
  • `ActaClient.vaultMigrate` and `VaultMigrateResponse` — endpoint removed in `acta-api` v1.2.0.
  • `CreateCredentialPayload` / `CreateCredentialResponse` types and the corresponding `src/types/type.payload.ts` / `types.response.ts` files.

Changed — BREAKING

  • `vaultListVcIdsDirect` now accepts `offset` / `limit` (defaults 0 / 50, max 200 = `MAX_LIST_LIMIT`).
  • `revokeCredentialViaApi` and `useCredential().revoke` require `owner`. The contract calls `owner.require_auth()` so the vault owner MUST sign (relayer signatures rejected). Smart-account (C...) owners rejected client-side because the account-contract signing flow is not modelled.
  • `VaultVerifyVcResponse.status` now typed `'valid' | 'revoked' | 'invalid' | 'unknown'`.
  • All `ActaClient` methods now reject with `ActaError` on non-2xx (was axios's raw error object). Exposes `code`, `httpStatus`, `requestId`, `retryAfter`, `details`.

Added — new client methods

  • `vcBatchIssue` — up to 5 VCs in one tx (`MAX_BATCH_SIZE`).
  • `vaultVcCount` — O(1) active-VC count.
  • `vaultListAuthorizedIssuers` / `vaultListDeniedIssuers` + `vaultAuthorizedIssuerCount` / `vaultDeniedIssuerCount`.
  • `vaultMetadata` — combined `{ admin, did_uri, revoked, vc_count, authorized_issuer_count }` in one call.
  • Issuer-registry surface (rejects with `contractId_invalid` until `vc-issuer-registry` is deployed): `issuerRegistryAdd`, `issuerRegistrySetMetadata`, `issuerRegistrySetAllowed`, `issuerRegistryRemove`, `issuerRegistryGet`, `issuerRegistryIsAllowed`, `issuerRegistryStatus`.

Added — new React hooks

  • `useCredential().batchIssue(...)` — prepare → sign → submit for up to 5 VCs.
  • `useVaultRead()`: `vcCount`, `listAllVcIds` (auto-paginated, default cap 10k), `metadata`.
  • `useVaultIssuers()`: `count`, `countDenied`, `list`, `listDenied`, `listAll`, `listAllDenied`.
  • `useIssuerRegistry()`: read (`get`, `isAllowed`, `status`) + admin mutations (`add`, `setMetadata`, `setAllowed`, `remove`).
  • `useVault().authorizeIssuers(...)` — bulk variant (validated against `MAX_ISSUERS_LIST = 100`).

Added — DX

  • `ActaError` class (`src/utils/acta-error.ts`) + `ActaErrorCode` literal union of every known code (vc-vault + vc-issuer-registry + API-side).
  • `CONTRACT_LIMITS` constants (`src/utils/contract-limits.ts`) mirroring the contract caps so UI inputs can validate locally.
  • `index.ts` re-exports `ActaClient`, `ActaError`, `CONTRACT_LIMITS` and their TS types directly.

Migration guide

  1. Stop importing the removed methods.
  2. Pass `owner` to `revokeCredentialViaApi` / `useCredential().revoke` and have the owner sign the XDR.
  3. `vaultListVcIdsDirect` callers either accept the new defaults or pass explicit `offset` / `limit`. For full lists, prefer `useVaultRead().listAllVcIds(...)`.
  4. Catch `ActaError` and branch on `err.code` instead of parsing `err.response?.data`.
  5. Narrow `verifyVc` results against the new `'invalid'` / `'unknown'` variants.

Test plan

  • `npx tsc --noEmit` — pass
  • `npm run build` — ESM + CJS + d.ts emitted in `dist/` (no test suite in this package yet)
  • Install locally in `enterprise-acta-panel` and verify the issue / revoke / list flows work end-to-end against `acta-api` v1.2.0.
  • Smoke test the issuer-registry hook against a future testnet deploy of `vc-issuer-registry`.

Stats

  • 16 files changed, +1331 / −937 lines.

Companion PRs

comment: release notes by coderabbit.ai -->

Bring @acta-team/credentials to v1.1.2 with full surface for the new
acta-api: typed errors (ActaError), CONTRACT_LIMITS, paginated reads,
batch issuance, issuer-registry methods + hook, vault metadata, and
React hooks for every new endpoint.

Removed deprecated methods (createCredential, getDefaults, vaultMigrate,
prepareStoreTx/ListVcIdsTx/GetVcTx, vaultStore) and the matching legacy
types. `revokeCredentialViaApi` now requires `owner`. `listVcIds` paginates.
`VaultVerifyVcResponse.status` widened to include `invalid`/`unknown`.

Versioning note: strict semver would call most of these BREAKING and
bump to 2.0.0. Staying on 1.1.x intentionally until the panel migrates;
do not publish from this branch. See CHANGELOG.md for the full
migration guide.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

📝 Walkthrough

Walkthrough

This PR aligns the ACTA SDK with acta-api v1.2.0 and vc-vault v0.3.0 by introducing typed error handling, expanding the HTTP client with vault issuer-registry and batch-issuance APIs, adding React hooks for issuer lists and registry management, and refining existing hooks for pagination and bulk operations.

Changes

SDK v1.1.2 alignment with acta-api v1.2.0 / vc-vault v0.3.0

Layer / File(s) Summary
Error handling & contract limits
src/utils/acta-error.ts, src/utils/contract-limits.ts
New ActaError class, actaErrorFromAxios converter, and CONTRACT_LIMITS constant enable structured error handling and UI validation aligned with contract constraints.
API response type contracts
src/types/api-responses.ts, src/types/index.ts, src/types/type.payload.ts, src/types/types.response.ts
Response interfaces for transactions, vault operations (counts, issuer lists, metadata), and issuer-registry endpoints are added; deprecated CreateCredentialPayload and CreateCredentialResponse types are removed.
HTTP client with full API surface
src/client.ts
Client adds request/response interceptors for error handling and X-ACTA-Key injection; vault reads expand with issuer counts/lists and metadata; vault mutations add bulk authorization and owner-transfer; VC mutations add batch issuance and require owner for revocation; issuer-registry endpoints are fully exposed.
React hooks for vault, credential, and issuer-registry
src/hooks/useVault.ts, src/hooks/useVaultRead.ts, src/hooks/useVaultIssuers.ts, src/hooks/useCredential.ts, src/hooks/useIssuerRegistry.ts, src/hooks/index.ts
New useVaultIssuers and useIssuerRegistry hooks; useVault adds bulk issuer authorization; useCredential adds batch issuance and restricts revoke to non-smart-contract owners; useVaultRead adds pagination, counts, and metadata helpers.
SDK entry point and release metadata
src/index.ts, package.json, CHANGELOG.md
Exports expanded to include ActaClient, error utilities, and CONTRACT_LIMITS; version bumped to 1.1.2 with aligned API/contract dependency notes.

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant Hook
  participant Client
  participant Signer
  participant Server
  
  App->>Hook: call mutation (e.g., batchIssue, authorizeIssuers)
  Hook->>Client: prepare transaction
  Client->>Server: POST /contracts/vault/... (prepare mode)
  Server-->>Client: { xdr, network }
  Client-->>Hook: TxPrepareResponse
  Hook->>Signer: sign(xdr, networkPassphrase)
  Signer-->>Hook: signedXdr
  Hook->>Client: submit({ signedXdr })
  Client->>Server: POST /contracts/vault/... (submit mode)
  Server-->>Client: { tx_id }
  Client-->>Hook: TxSubmitResponse
  Hook->>Hook: validate responses
  Hook-->>App: { txId }
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 The vault grows wise with issuer lists,

Batches issued, errors caught in fists,

React hooks woven through the night,

Registry shines in v1.2 light!

A rabbit's ode to SDK delight 🌟

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ⚠️ Warning The PR title states 'acta-api v1.1.1' but the PR objectives clearly indicate alignment with 'acta-api v1.2.0', creating a version mismatch that contradicts the actual content. Update the PR title to 'feat(sdk): align with acta-api v1.2.0 / vc-vault v0.3.0' to match the documented objectives and actual changes in the PR.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/align-vc-vault-v0.3.0

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/hooks/useCredential.ts (1)

152-154: ⚡ Quick win

Use shared contract limit instead of hardcoded batch size.

Line 152 hardcodes 5 while CONTRACT_LIMITS.MAX_BATCH_SIZE already exists for this exact constraint. Reusing it avoids future drift.

Proposed fix
+import { CONTRACT_LIMITS } from "../utils/contract-limits";
...
-      if (args.vcs.length > 5) {
-        throw new Error("batchIssue accepts at most 5 vcs per call");
+      if (args.vcs.length > CONTRACT_LIMITS.MAX_BATCH_SIZE) {
+        throw new Error(
+          `batchIssue accepts at most ${CONTRACT_LIMITS.MAX_BATCH_SIZE} vcs per call`
+        );
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/useCredential.ts` around lines 152 - 154, Replace the hardcoded
limit 5 with the shared constant CONTRACT_LIMITS.MAX_BATCH_SIZE in the batch
size check (the block referencing args.vcs in src/hooks/useCredential.ts), and
make sure CONTRACT_LIMITS is imported where useCredential or batchIssue is
defined; change the conditional to compare args.vcs.length against
CONTRACT_LIMITS.MAX_BATCH_SIZE so the module uses the centralized limit.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/hooks/useVault.ts`:
- Around line 118-123: The prepare call to client.vaultAuthorizeIssuers uses
sourcePublicKey = args.sourcePublicKey ?? args.owner which can pass a
smart-wallet owner (C...) as the sourcePublicKey and break preparation; update
the logic around sourcePublicKey and the call to vaultAuthorizeIssuers so you
first detect smart-wallet owners (e.g., an isSmartWalletOwner(args.owner) check)
and only derive sourcePublicKey from args.owner for non-smart-wallet owners,
otherwise require and use args.sourcePublicKey (or throw/return an error if
missing) before invoking client.vaultAuthorizeIssuers with owner: args.owner,
issuers: args.issuers, sourcePublicKey, contractId.

In `@src/utils/acta-error.ts`:
- Around line 133-135: The fallback classification in the ActaError constructor
incorrectly maps any HTTP response lacking the ACTA error shape to
"bad_request"; update the logic in the ActaError instantiation (where ActaError
is constructed) to inspect the numeric HTTP status and emit "network_error" (or
a server error code) for 5xx statuses and only "bad_request" for 4xx client
errors — e.g., set code to something like: if status is >=500 then
"network_error" else "bad_request", while keeping httpStatus as status ?? 0.

---

Nitpick comments:
In `@src/hooks/useCredential.ts`:
- Around line 152-154: Replace the hardcoded limit 5 with the shared constant
CONTRACT_LIMITS.MAX_BATCH_SIZE in the batch size check (the block referencing
args.vcs in src/hooks/useCredential.ts), and make sure CONTRACT_LIMITS is
imported where useCredential or batchIssue is defined; change the conditional to
compare args.vcs.length against CONTRACT_LIMITS.MAX_BATCH_SIZE so the module
uses the centralized limit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 845d5d66-878e-4351-b812-4745fc2ab5f1

📥 Commits

Reviewing files that changed from the base of the PR and between 7673b19 and 8bafb85.

📒 Files selected for processing (16)
  • CHANGELOG.md
  • package.json
  • src/client.ts
  • src/hooks/index.ts
  • src/hooks/useCredential.ts
  • src/hooks/useIssuerRegistry.ts
  • src/hooks/useVault.ts
  • src/hooks/useVaultIssuers.ts
  • src/hooks/useVaultRead.ts
  • src/index.ts
  • src/types/api-responses.ts
  • src/types/index.ts
  • src/types/type.payload.ts
  • src/types/types.response.ts
  • src/utils/acta-error.ts
  • src/utils/contract-limits.ts
💤 Files with no reviewable changes (3)
  • src/types/index.ts
  • src/types/types.response.ts
  • src/types/type.payload.ts

Comment thread src/hooks/useVault.ts
Comment on lines +118 to +123
const sourcePublicKey = args.sourcePublicKey ?? args.owner;
const prepareResult = await client.vaultAuthorizeIssuers({
owner: args.owner,
issuers: args.issuers,
sourcePublicKey,
contractId,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard authorizeIssuers for smart-wallet owners before deriving sourcePublicKey.

Line 118 can send a C... owner as sourcePublicKey when args.sourcePublicKey is omitted, which breaks prepare for smart-wallet owners.

Proposed fix
+      const isSmartAccountOwner =
+        args.owner.startsWith("C") && args.owner.length === 56;
+      if (isSmartAccountOwner && !args.sourcePublicKey) {
+        throw new Error(
+          "authorizeIssuers() requires sourcePublicKey when owner is a C... smart wallet"
+        );
+      }
       const sourcePublicKey = args.sourcePublicKey ?? args.owner;
       const prepareResult = await client.vaultAuthorizeIssuers({
         owner: args.owner,
         issuers: args.issuers,
         sourcePublicKey,
         contractId,
       });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/useVault.ts` around lines 118 - 123, The prepare call to
client.vaultAuthorizeIssuers uses sourcePublicKey = args.sourcePublicKey ??
args.owner which can pass a smart-wallet owner (C...) as the sourcePublicKey and
break preparation; update the logic around sourcePublicKey and the call to
vaultAuthorizeIssuers so you first detect smart-wallet owners (e.g., an
isSmartWalletOwner(args.owner) check) and only derive sourcePublicKey from
args.owner for non-smart-wallet owners, otherwise require and use
args.sourcePublicKey (or throw/return an error if missing) before invoking
client.vaultAuthorizeIssuers with owner: args.owner, issuers: args.issuers,
sourcePublicKey, contractId.

Comment thread src/utils/acta-error.ts
Comment on lines +133 to +135
return new ActaError({
code: status ? "bad_request" : "network_error",
httpStatus: status ?? 0,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix fallback code classification for non-contract error payloads.

Line 134 currently maps every HTTP response without ACTA error shape to bad_request, including server failures. That breaks reliable err.code branching in consumers.

Proposed fix
-  return new ActaError({
-    code: status ? "bad_request" : "network_error",
+  const fallbackCode: ActaErrorCode =
+    status == null
+      ? "network_error"
+      : status >= 500
+        ? "internal_error"
+        : status === 401
+          ? "unauthorized"
+          : status === 403
+            ? "forbidden"
+            : status === 404
+              ? "not_found"
+              : status === 429
+                ? "rate_limit_exceeded"
+                : "bad_request";
+
+  return new ActaError({
+    code: fallbackCode,
     httpStatus: status ?? 0,
     message:
       anyErr?.message || (status ? `HTTP ${status}` : "Network request failed"),
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return new ActaError({
code: status ? "bad_request" : "network_error",
httpStatus: status ?? 0,
const fallbackCode: ActaErrorCode =
status == null
? "network_error"
: status >= 500
? "internal_error"
: status === 401
? "unauthorized"
: status === 403
? "forbidden"
: status === 404
? "not_found"
: status === 429
? "rate_limit_exceeded"
: "bad_request";
return new ActaError({
code: fallbackCode,
httpStatus: status ?? 0,
message:
anyErr?.message || (status ? `HTTP ${status}` : "Network request failed"),
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/acta-error.ts` around lines 133 - 135, The fallback classification
in the ActaError constructor incorrectly maps any HTTP response lacking the ACTA
error shape to "bad_request"; update the logic in the ActaError instantiation
(where ActaError is constructed) to inspect the numeric HTTP status and emit
"network_error" (or a server error code) for 5xx statuses and only "bad_request"
for 4xx client errors — e.g., set code to something like: if status is >=500
then "network_error" else "bad_request", while keeping httpStatus as status ??
0.

@JosueBrenes JosueBrenes changed the title feat(sdk): align with acta-api v1.2.0 / vc-vault v0.3.0 (v1.1.2, no publish) feat(sdk): align with acta-api v1.1.1 / vc-vault v0.3.0 May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant