@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.
- package/CHANGELOG.md +1 -1
- package/README.md +212 -26
- 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.
|
|
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
|
-
|
|
4
|
-
|
|
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
|
|
26
|
+
import type { OrgId } from "@sigcore/sdk";
|
|
19
27
|
|
|
20
|
-
|
|
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
|
-
|
|
40
|
+
// Token deadline passed — re-authenticate the user
|
|
41
|
+
redirectToLogin();
|
|
31
42
|
},
|
|
32
43
|
});
|
|
33
44
|
|
|
34
|
-
// Inject the
|
|
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
|
-
//
|
|
51
|
+
// 3. Use the client
|
|
44
52
|
const { wallet } = await client.createWallet({
|
|
45
|
-
orgId: "
|
|
53
|
+
orgId: "org_YOUR_ORG_ID" as OrgId,
|
|
46
54
|
name: "Treasury",
|
|
47
55
|
algorithm: "SECP256K1_ECDSA",
|
|
48
56
|
});
|
|
49
57
|
|
|
50
|
-
//
|
|
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:
|
|
53
|
-
walletId: "
|
|
126
|
+
orgId: "org_...",
|
|
127
|
+
walletId: "wal_...",
|
|
54
128
|
messageHex: "deadbeef" as HexString,
|
|
55
129
|
chain: "ethereum",
|
|
56
130
|
});
|
|
57
131
|
|
|
58
|
-
//
|
|
59
|
-
|
|
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
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
//
|
|
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.
|
|
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
|
-
"
|
|
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
|
}
|