@sigcore/sdk 0.1.5 → 0.1.6

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 (3) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +212 -26
  3. package/package.json +12 -3
package/CHANGELOG.md CHANGED
@@ -5,6 +5,6 @@ All notable changes to `@sigcore/sdk` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [0.1.5] - 2026-04-15
8
+ ## [0.1.6] - 2026-04-15
9
9
 
10
10
  Initial public release.
package/README.md CHANGED
@@ -1,7 +1,17 @@
1
1
  # @sigcore/sdk
2
2
 
3
- Sigcore Iframe SDK for secure, non-custodial wallet operations.
4
- Designed for SaaS clients to embed wallet management via an isolated iframe bridge.
3
+ TypeScript SDK for embedding [Sigcore](https://sigcore.io) wallet operations into your web application via a secure iframe bridge. Handles wallet creation, HD wallets, message signing, and token lifecycle — without ever exposing private keys to your frontend.
4
+
5
+ ## How it works
6
+
7
+ The SDK loads a hidden iframe from the Sigcore wallet origin. All cryptographic operations happen inside that iframe and are never accessible to your app's JavaScript. Communication uses a typed `postMessage` protocol over a strict origin allowlist.
8
+
9
+ ```
10
+ Your App Sigcore Bridge (iframe)
11
+ ─────────────────── ──────────────────────────
12
+ client.createWallet() ───> validates token + origin
13
+ <─── sends result via postMessage
14
+ ```
5
15
 
6
16
  ## Installation
7
17
 
@@ -11,15 +21,15 @@ npm install @sigcore/sdk
11
21
 
12
22
  ## Quick Start
13
23
 
14
- The recommended entry point is `loadSigcore()`, which creates a hidden iframe, waits for the bridge to become ready, and returns a connected client:
15
-
16
24
  ```ts
17
25
  import { loadSigcore } from "@sigcore/sdk";
18
- import type { OrgId, HexString } from "@sigcore/sdk";
26
+ import type { OrgId } from "@sigcore/sdk";
19
27
 
20
- const { client, bridgeVersion, protocolVersion, supportedActions, destroy } = await loadSigcore({
28
+ // 1. Load the bridge creates a hidden iframe and waits for it to be ready
29
+ const { client, destroy } = await loadSigcore({
21
30
  bridgeUrl: "https://wallet.sigcore.io/v1/bridge.html",
22
31
  onTokenExpiring: async () => {
32
+ // Called ~15s before expiry — refresh your token here
23
33
  const fresh = await yourBackend.mintSigcoreToken();
24
34
  await client.setSigcoreAccessToken({
25
35
  accessToken: fresh.access_token,
@@ -27,41 +37,159 @@ const { client, bridgeVersion, protocolVersion, supportedActions, destroy } = aw
27
37
  });
28
38
  },
29
39
  onTokenExpired: () => {
30
- console.warn("Sigcore token expired — re-authenticate");
40
+ // Token deadline passed — re-authenticate the user
41
+ redirectToLogin();
31
42
  },
32
43
  });
33
44
 
34
- // Inject the initial token (minted by your backend)
45
+ // 2. Inject the access token minted by your backend
35
46
  await client.setSigcoreAccessToken({
36
47
  accessToken: mintedToken.access_token,
37
- tokenType: mintedToken.token_type,
38
- audience: "urn:sigcore:sigcore:grpc",
39
- scope: mintedToken.scope,
40
48
  expiresIn: mintedToken.expires_in,
41
49
  });
42
50
 
43
- // Create a wallet
51
+ // 3. Use the client
44
52
  const { wallet } = await client.createWallet({
45
- orgId: "org_YOUR_ORG_ID_HERE" as OrgId,
53
+ orgId: "org_YOUR_ORG_ID" as OrgId,
46
54
  name: "Treasury",
47
55
  algorithm: "SECP256K1_ECDSA",
48
56
  });
49
57
 
50
- // Sign a message
58
+ // 4. Clean up when your component unmounts
59
+ destroy();
60
+ ```
61
+
62
+ ## Token Lifecycle
63
+
64
+ Sigcore access tokens are short-lived JWT bearer tokens minted by your backend. The SDK manages expiry automatically:
65
+
66
+ | Callback | When it fires |
67
+ |---|---|
68
+ | `onTokenExpiring` | `tokenRefreshBufferMs` before expiry (default 15s) |
69
+ | `onTokenExpired` | When the token deadline passes |
70
+
71
+ Always call `setSigcoreAccessToken()` with the new token inside `onTokenExpiring`. If the token expires before refresh, the bridge will reject all operations with `TOKEN_EXPIRED`.
72
+
73
+ ## API Reference
74
+
75
+ ### Wallets
76
+
77
+ ```ts
78
+ // Create a new wallet
79
+ const { wallet } = await client.createWallet({
80
+ orgId: "org_..." as OrgId,
81
+ name: "My Wallet",
82
+ algorithm: "SECP256K1_ECDSA", // or "ED25519"
83
+ });
84
+
85
+ // Import an existing private key
86
+ const { wallet } = await client.importWallet({
87
+ orgId: "org_...",
88
+ name: "Imported",
89
+ algorithm: "SECP256K1_ECDSA",
90
+ privateKeyHex: "...",
91
+ });
92
+
93
+ // Get wallet details
94
+ const { wallet } = await client.getWallet({
95
+ orgId: "org_...",
96
+ walletId: "wal_...",
97
+ });
98
+
99
+ // Update wallet name
100
+ const { wallet } = await client.updateWallet({
101
+ orgId: "org_...",
102
+ walletId: "wal_...",
103
+ name: "New Name",
104
+ walletType: "FLAT",
105
+ });
106
+
107
+ // Delete a wallet
108
+ const result = await client.deleteWallet({
109
+ orgId: "org_...",
110
+ walletId: "wal_...",
111
+ walletType: "FLAT",
112
+ });
113
+
114
+ // List wallets
115
+ const { wallets, nextCursor, totalCount } = await client.listWallets({
116
+ orgId: "org_...",
117
+ });
118
+ ```
119
+
120
+ ### Signing
121
+
122
+ ```ts
123
+ import type { HexString } from "@sigcore/sdk";
124
+
51
125
  const { intent, policyRuling } = await client.signMessage({
52
- orgId: wallet.orgId,
53
- walletId: "wal_YOUR_WALLET_ID_HERE",
126
+ orgId: "org_...",
127
+ walletId: "wal_...",
54
128
  messageHex: "deadbeef" as HexString,
55
129
  chain: "ethereum",
56
130
  });
57
131
 
58
- // Clean up when done
59
- destroy();
132
+ // policyRuling.decision is "ALLOW" | "DENY" | "PENDING"
133
+ ```
134
+
135
+ ### HD Wallets
136
+
137
+ ```ts
138
+ // Create (returns a BIP-39 mnemonic — store it securely)
139
+ const { wallet, mnemonic } = await client.createHDWallet({
140
+ orgId: "org_...",
141
+ name: "HD Treasury",
142
+ algorithm: "SECP256K1_ECDSA",
143
+ });
144
+
145
+ // Import from mnemonic
146
+ const { wallet } = await client.importHDWallet({
147
+ orgId: "org_...",
148
+ name: "Restored",
149
+ algorithm: "SECP256K1_ECDSA",
150
+ mnemonic: "word1 word2 ...",
151
+ });
152
+
153
+ // List HD wallets
154
+ const { wallets } = await client.listHDWallets({ orgId: "org_..." });
155
+ ```
156
+
157
+ ### Signing Intents (multi-party approval)
158
+
159
+ ```ts
160
+ // Request a signature (may be held for approval)
161
+ const { intent } = await client.createSigningIntent({
162
+ orgId: "org_...",
163
+ walletId: "wal_...",
164
+ payloadHex: "...",
165
+ chain: "ethereum",
166
+ });
167
+
168
+ // Approve or reject
169
+ await client.approveIntent(intent.id);
170
+ await client.rejectIntent(intent.id);
171
+ ```
172
+
173
+ ### Auth
174
+
175
+ ```ts
176
+ // Validate a public session token issued by your auth flow
177
+ const { session, email, status } = await client.validatePublicSession(token);
178
+
179
+ // Consume a DPoP action proof
180
+ const { proof } = await client.consumeActionProof({
181
+ organizationId: "org_...",
182
+ sessionId: "...",
183
+ actionKind: "wallet.sign",
184
+ requiredAssurance: "aal2",
185
+ httpMethod: "POST",
186
+ route: "/wallets/:id/sign",
187
+ });
60
188
  ```
61
189
 
62
190
  ## Error Handling
63
191
 
64
- All SDK errors are instances of `SigcoreError` with a machine-readable `code` and a categorized `type`:
192
+ All errors are instances of `SigcoreError`:
65
193
 
66
194
  ```ts
67
195
  import { SigcoreError, SigcoreErrorCode } from "@sigcore/sdk";
@@ -70,19 +198,77 @@ try {
70
198
  await client.createWallet(input);
71
199
  } catch (err) {
72
200
  if (err instanceof SigcoreError) {
73
- // Specific error code for fine-grained handling
74
- if (err.code === SigcoreErrorCode.REQUEST_TIMEOUT) {
75
- console.error("Request timed out");
201
+ switch (err.code) {
202
+ case SigcoreErrorCode.TOKEN_EXPIRED:
203
+ // prompt re-authentication
204
+ break;
205
+ case SigcoreErrorCode.REQUEST_TIMEOUT:
206
+ // retry
207
+ break;
208
+ case SigcoreErrorCode.INCOMPATIBLE_BRIDGE:
209
+ // bridge version mismatch — update the SDK
210
+ break;
76
211
  }
77
212
 
78
- // User-safe message (if provided by the server)
79
- if (err.displayMessage) {
80
- showToast(err.displayMessage);
81
- }
213
+ // Safe user-facing message when available
214
+ if (err.displayMessage) showToast(err.displayMessage);
82
215
  }
83
216
  }
84
217
  ```
85
218
 
219
+ ### Error types
220
+
221
+ | `err.type` | Meaning |
222
+ |---|---|
223
+ | `"authentication"` | Token missing, expired, or invalid |
224
+ | `"network"` | Could not reach the bridge backend |
225
+ | `"configuration"` | Bad SDK options or incompatible bridge |
226
+ | `"server"` | Backend returned an error |
227
+
228
+ ## Testing
229
+
230
+ A mock client is available for unit and integration tests — no iframe, no network:
231
+
232
+ ```ts
233
+ import { createMockClient } from "@sigcore/sdk/testing";
234
+
235
+ const client = createMockClient({
236
+ latencyMs: 50, // simulate network delay
237
+ failOnSign: false, // set true to test POLICY_DENIED paths
238
+ failAll: false, // set true to test full failure paths
239
+ });
240
+
241
+ const { wallet } = await client.createWallet({
242
+ orgId: "org_test" as OrgId,
243
+ name: "Test Wallet",
244
+ algorithm: "ED25519",
245
+ });
246
+
247
+ client.dispose();
248
+ ```
249
+
250
+ ## TypeScript
251
+
252
+ The SDK is written in TypeScript and ships full type declarations. All branded types (`OrgId`, `WalletId`, `HexString`, etc.) are exported and can be used in your own type signatures.
253
+
254
+ ```ts
255
+ import type {
256
+ OrgId,
257
+ WalletId,
258
+ WalletMetadata,
259
+ HexString,
260
+ SigcoreErrorType,
261
+ LoadSigcoreOptions,
262
+ } from "@sigcore/sdk";
263
+ ```
264
+
265
+ ## Security
266
+
267
+ - Private keys never leave the bridge iframe
268
+ - All `postMessage` messages are validated against a strict origin allowlist
269
+ - Bearer tokens are held in iframe memory only — never in `localStorage`, cookies, or the URL
270
+ - The bridge uses `credentials: "omit"` for all backend fetches
271
+
86
272
  ## License
87
273
 
88
274
  [MIT](./LICENSE) — Copyright (c) 2026 Sigcore
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigcore/sdk",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Iframe SDK for Sigcore wallet operations — secure key management for SaaS clients",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -57,7 +57,13 @@
57
57
  "typescript": "^5.8.2",
58
58
  "vitest": "^2.1.8"
59
59
  },
60
- "publishConfig": {
60
+ "author": {
61
+ "name": "Sigcore",
62
+ "email": "hello@sigcore.io",
63
+ "url": "https://sigcore.io"
64
+ },
65
+ "homepage": "https://sigcore.io",
66
+ "publishConfig": {
61
67
  "access": "public",
62
68
  "registry": "https://registry.npmjs.org/"
63
69
  },
@@ -68,6 +74,9 @@
68
74
  "iframe",
69
75
  "sdk",
70
76
  "crypto",
71
- "mpc"
77
+ "mpc",
78
+ "web3",
79
+ "signing",
80
+ "non-custodial"
72
81
  ]
73
82
  }