@tesser-payments/sdk-ts 0.0.3 → 0.1.0
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/README.md +56 -38
- package/dist/index.d.ts +1 -1
- package/dist/index.js +349 -26
- package/dist/internal/errors.d.ts +5 -5
- package/dist/internal/types.d.ts +11 -1
- package/dist/internal/version.d.ts +1 -0
- package/dist/signer.d.ts +21 -5
- package/dist/signing/create-wallet.d.ts +2 -1
- package/dist/signing/network-type.d.ts +3 -0
- package/dist/signing/unsigned-payload.d.ts +15 -0
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
# @tesser-payments/sdk-ts
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
it. Bring your own client.
|
|
3
|
+
TypeScript SDK for the Tesser API: sign `signCreateWallet` and `signStep`
|
|
4
|
+
requests locally with your signing key. The SDK does not handle OAuth or submit
|
|
5
|
+
requests for you; bring your own client.
|
|
7
6
|
|
|
8
7
|
## Install
|
|
9
8
|
|
|
@@ -12,9 +11,7 @@ bun add @tesser-payments/sdk-ts @tesser-payments/types
|
|
|
12
11
|
```
|
|
13
12
|
|
|
14
13
|
`@tesser-payments/types` is a peer dependency — install it alongside the SDK.
|
|
15
|
-
|
|
16
|
-
`signCreateWallet` and `signStep` activities) and is installed automatically;
|
|
17
|
-
its Apache-2.0 license aligns with the SDK's. Apache 2.0 licensed.
|
|
14
|
+
Apache 2.0 licensed.
|
|
18
15
|
|
|
19
16
|
## Quick start
|
|
20
17
|
|
|
@@ -25,8 +22,9 @@ const signer = new LocalSigner({
|
|
|
25
22
|
signing: {
|
|
26
23
|
publicKey: process.env.SIGNING_PUBLIC_KEY!, // 33-byte compressed P-256
|
|
27
24
|
privateKey: process.env.SIGNING_PRIVATE_KEY!,
|
|
28
|
-
enclaveId: process.env.SIGNING_ENCLAVE_ID!,
|
|
25
|
+
enclaveId: process.env.SIGNING_ENCLAVE_ID!,
|
|
29
26
|
},
|
|
27
|
+
apiBaseUrl: 'https://api.tesser.xyz', // sandbox: https://api-sandbox.tesser.xyz
|
|
30
28
|
});
|
|
31
29
|
|
|
32
30
|
const { signature } = await signer.signCreateWallet({
|
|
@@ -52,6 +50,15 @@ const res = await fetch(`${API_BASE_URL}/v1/accounts/wallets`, {
|
|
|
52
50
|
`signature` is `base64(JSON.stringify({ body, stamp }))` — drop it into the
|
|
53
51
|
Tesser API request body as the documented `signature` field.
|
|
54
52
|
|
|
53
|
+
`LocalSigner` requires the Tesser API base URL (`https://api.tesser.xyz` or
|
|
54
|
+
`https://api-sandbox.tesser.xyz`); a trailing `/` or `/v1` is removed. Pass an
|
|
55
|
+
optional `fetch` implementation to configure a proxy.
|
|
56
|
+
|
|
57
|
+
`signCreateWallet` signs a wallet-creation request. For `stablecoin_ethereum`,
|
|
58
|
+
it first fetches the request to sign from the Tesser API and checks that it
|
|
59
|
+
matches your parameters. The private key never leaves your process. Tesser
|
|
60
|
+
currently supports managed wallets for `stablecoin_ethereum` only.
|
|
61
|
+
|
|
55
62
|
**Private-key handling.** `signer.signing` exposes only `{ publicKey, enclaveId }`.
|
|
56
63
|
The private key lives on the instance as an ECMA private field and is not
|
|
57
64
|
reachable via property access, `console.log`, or `JSON.stringify`. The SDK still
|
|
@@ -59,8 +66,7 @@ uses it internally to stamp activities — you just can't pull it back out.
|
|
|
59
66
|
|
|
60
67
|
## `signStep`
|
|
61
68
|
|
|
62
|
-
`signStep`
|
|
63
|
-
single rebalance step. Pass the unsigned transaction Tesser returned, the
|
|
69
|
+
`signStep` signs a single rebalance step. Pass the unsigned transaction Tesser returned, the
|
|
64
70
|
on-chain `signWith` address, and the network — that's all the SDK needs to
|
|
65
71
|
produce a signature:
|
|
66
72
|
|
|
@@ -71,8 +77,7 @@ const step: StepForSigning = {
|
|
|
71
77
|
unsignedTransaction: '0x02...', // hex-encoded raw tx Tesser returned
|
|
72
78
|
signWith: '0xabc...', // account.crypto_wallet_address from
|
|
73
79
|
// GET /v1/accounts/{from_account_id}
|
|
74
|
-
network: 'BASE_SEPOLIA',
|
|
75
|
-
// POLYGON | POLYGON_AMOY | SOLANA
|
|
80
|
+
network: 'BASE_SEPOLIA',
|
|
76
81
|
};
|
|
77
82
|
|
|
78
83
|
const signed = await signer.signStep(step);
|
|
@@ -91,29 +96,54 @@ await fetch(
|
|
|
91
96
|
```
|
|
92
97
|
|
|
93
98
|
`signStep` returns `{ signature, metadata }`. The `signature` field is what
|
|
94
|
-
the Tesser API needs; `metadata` carries the
|
|
95
|
-
|
|
99
|
+
the Tesser API needs; `metadata` carries the signed body and stamp header value
|
|
100
|
+
for debugging.
|
|
96
101
|
|
|
97
102
|
The `network` field is typed as `SupportedNetwork`, derived from the SDK's
|
|
98
|
-
network
|
|
103
|
+
supported-network table — so a typo like `'BASE-SEPOLIA'` (hyphen) is a
|
|
99
104
|
compile-time error. If you're pulling the value out of a webhook payload or
|
|
100
105
|
env var, cast it at that boundary.
|
|
101
106
|
|
|
107
|
+
Supported networks are `BASE`, `BASE_SEPOLIA`, `ETHEREUM`, `ETHEREUM_SEPOLIA`,
|
|
108
|
+
`POLYGON`, `POLYGON_AMOY`, `SOLANA`, `TEMPO`, and `TEMPO_MODERATO`.
|
|
109
|
+
|
|
110
|
+
### Tempo transfers
|
|
111
|
+
|
|
112
|
+
1. Pass the Tempo transaction Tesser provides (`0x76...`), your wallet
|
|
113
|
+
address, and `TEMPO` or `TEMPO_MODERATO` to `signStep`.
|
|
114
|
+
2. The SDK authorizes the transaction with your API key, without changing
|
|
115
|
+
it. Submit the returned `signature` to the Tesser signing endpoint.
|
|
116
|
+
3. Tesser completes the transfer, broadcasts it, and pays the network fee.
|
|
117
|
+
|
|
118
|
+
Unknown networks raise `TesserConfigError` before anything is signed.
|
|
119
|
+
|
|
102
120
|
## Error handling
|
|
103
121
|
|
|
104
122
|
The SDK mirrors Tesser's documented error envelope
|
|
105
123
|
(<https://docs.tesser.xyz/overviews/errors>) rather than inventing a custom
|
|
106
|
-
HTTP-status taxonomy
|
|
107
|
-
errors are exported:
|
|
124
|
+
HTTP-status taxonomy:
|
|
108
125
|
|
|
109
126
|
```
|
|
110
127
|
TesserError (base; .cause set on all)
|
|
111
128
|
├── TesserConfigError bad input at construction or call site
|
|
112
|
-
|
|
113
|
-
|
|
129
|
+
├── TesserAPIError Tesser answered with an error status or
|
|
130
|
+
│ an invalid response
|
|
131
|
+
├── TesserConnectionError the request to Tesser failed at the network level
|
|
132
|
+
├── TesserTimeoutError the request to Tesser timed out
|
|
133
|
+
└── TesserSigningError signing failure, or a fetched request that
|
|
134
|
+
│ does not match your parameters
|
|
135
|
+
└── StampError the signing key could not sign
|
|
114
136
|
```
|
|
115
137
|
|
|
116
|
-
|
|
138
|
+
`TesserAPIError`, `TesserConnectionError`, and `TesserTimeoutError` come from
|
|
139
|
+
the request `signCreateWallet` makes to Tesser for `stablecoin_ethereum`.
|
|
140
|
+
`TesserAPIError` carries `status`, `headers`, `requestId`, and the parsed
|
|
141
|
+
`errors[]` (with `errorCode` for the first one). `TesserConnectionError`,
|
|
142
|
+
`TesserTimeoutError`, and a `TesserAPIError` with status 429 or 5xx are safe to
|
|
143
|
+
retry; a `TesserAPIError` with any other 4xx status fails the same way on
|
|
144
|
+
retry.
|
|
145
|
+
|
|
146
|
+
Each error carries the original failure as `.cause` and can be discriminated via
|
|
117
147
|
`instanceof` or the static `.is()` guard:
|
|
118
148
|
|
|
119
149
|
```typescript
|
|
@@ -123,7 +153,7 @@ try {
|
|
|
123
153
|
await signer.signStep(step);
|
|
124
154
|
} catch (err) {
|
|
125
155
|
if (StampError.is(err)) {
|
|
126
|
-
//
|
|
156
|
+
// The key could not sign — usually a key-format problem.
|
|
127
157
|
}
|
|
128
158
|
if (TesserError.is(err)) {
|
|
129
159
|
console.error('Signing failed', { name: err.name, cause: err.cause });
|
|
@@ -132,29 +162,19 @@ try {
|
|
|
132
162
|
}
|
|
133
163
|
```
|
|
134
164
|
|
|
135
|
-
HTTP-side errors (`TesserAPIError`, `TesserConnectionError`,
|
|
136
|
-
`TesserTimeoutError`) will return when the optional bundled client lands in a
|
|
137
|
-
future version. Until then, model HTTP failures with whatever your `fetch`
|
|
138
|
-
wrapper produces.
|
|
139
|
-
|
|
140
165
|
## Setup notes
|
|
141
166
|
|
|
142
|
-
`signing.publicKey` must be the **33-byte compressed** form
|
|
167
|
+
`signing.publicKey` must be the **33-byte compressed** form Tesser uses for
|
|
143
168
|
API-key auth lookups (66 hex chars, prefix `02` or `03`). Dashboards that
|
|
144
169
|
display the 65-byte uncompressed form need to be compressed before use:
|
|
145
170
|
|
|
146
171
|
```sh
|
|
147
|
-
|
|
148
|
-
'const c = require("@turnkey/crypto"); \
|
|
149
|
-
const u = process.argv[1].replace(/^0x/i,""); \
|
|
150
|
-
const b = Buffer.from(u, "hex"); \
|
|
151
|
-
console.log(Buffer.from(c.compressRawPublicKey(b)).toString("hex"))' \
|
|
172
|
+
node -e 'const u = process.argv[1].replace(/^0x/i, ""); console.log(require("node:crypto").ECDH.convertKey(u, "prime256v1", "hex", "hex", "compressed"))' \
|
|
152
173
|
04...your-uncompressed-key...
|
|
153
174
|
```
|
|
154
175
|
|
|
155
|
-
If a key is registered
|
|
156
|
-
|
|
157
|
-
correct — re-register the key in compressed form to fix.
|
|
176
|
+
If a key is registered in uncompressed form, signing is rejected even when the
|
|
177
|
+
keypair is logically correct — re-register the key in compressed form to fix.
|
|
158
178
|
|
|
159
179
|
## Examples
|
|
160
180
|
|
|
@@ -172,9 +192,7 @@ copy [`.env.example`](./.env.example) and fill in the values first.
|
|
|
172
192
|
## Out of scope
|
|
173
193
|
|
|
174
194
|
- **`TesserClient`** — the previous bundled HTTP client (`getAccountAddress`,
|
|
175
|
-
retry/timeout/logger plumbing) is intentionally not
|
|
176
|
-
re-add it later as an opt-in `LocalSignerOptions.client` field; that change
|
|
177
|
-
is purely additive and will not break v0.0.1 call sites.
|
|
195
|
+
retry/timeout/logger plumbing) is intentionally not included.
|
|
178
196
|
- **Webhook signature verification** — the header name and HMAC algorithm
|
|
179
197
|
aren't currently documented in public Tesser docs.
|
|
180
198
|
- **Solana / Stellar `signCreateWallet`** — exported as `@experimental` types;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ export { LocalSigner } from './signer.js';
|
|
|
2
2
|
export type { PublicSigningInfo } from './signer.js';
|
|
3
3
|
export type { CreateWalletParams, LocalSignerOptions, SignedResult, SignedResultMetadata, SignedStepResult, SignedStepResultMetadata, SigningConfig, StepForSigning, WalletType, } from './internal/types.js';
|
|
4
4
|
export type { SupportedNetwork } from './signing/network-type.js';
|
|
5
|
-
export { StampError, TesserConfigError, TesserError, TesserSigningError, } from './internal/errors.js';
|
|
5
|
+
export { StampError, TesserAPIError, TesserConfigError, TesserConnectionError, TesserError, TesserSigningError, TesserTimeoutError, } from './internal/errors.js';
|
|
6
6
|
export type { TesserErrorDetail } from './internal/errors.js';
|
package/dist/index.js
CHANGED
|
@@ -18273,6 +18273,47 @@ class TesserConfigError extends TesserError {
|
|
|
18273
18273
|
return err instanceof TesserConfigError;
|
|
18274
18274
|
}
|
|
18275
18275
|
}
|
|
18276
|
+
|
|
18277
|
+
class TesserAPIError extends TesserError {
|
|
18278
|
+
name = "TesserAPIError";
|
|
18279
|
+
status;
|
|
18280
|
+
headers;
|
|
18281
|
+
requestId;
|
|
18282
|
+
errors;
|
|
18283
|
+
constructor(message, options) {
|
|
18284
|
+
super(message, { cause: options.cause });
|
|
18285
|
+
this.status = options.status;
|
|
18286
|
+
if (options.headers !== undefined)
|
|
18287
|
+
this.headers = options.headers;
|
|
18288
|
+
if (options.requestId !== undefined)
|
|
18289
|
+
this.requestId = options.requestId;
|
|
18290
|
+
this.errors = options.errors ?? [];
|
|
18291
|
+
}
|
|
18292
|
+
get errorCode() {
|
|
18293
|
+
return this.errors[0]?.errorCode;
|
|
18294
|
+
}
|
|
18295
|
+
hasCode(...codes) {
|
|
18296
|
+
return this.errors.some((e) => codes.includes(e.errorCode));
|
|
18297
|
+
}
|
|
18298
|
+
static is(err) {
|
|
18299
|
+
return err instanceof TesserAPIError;
|
|
18300
|
+
}
|
|
18301
|
+
}
|
|
18302
|
+
|
|
18303
|
+
class TesserConnectionError extends TesserError {
|
|
18304
|
+
name = "TesserConnectionError";
|
|
18305
|
+
static is(err) {
|
|
18306
|
+
return err instanceof TesserConnectionError;
|
|
18307
|
+
}
|
|
18308
|
+
}
|
|
18309
|
+
|
|
18310
|
+
class TesserTimeoutError extends TesserError {
|
|
18311
|
+
name = "TesserTimeoutError";
|
|
18312
|
+
static is(err) {
|
|
18313
|
+
return err instanceof TesserTimeoutError;
|
|
18314
|
+
}
|
|
18315
|
+
}
|
|
18316
|
+
|
|
18276
18317
|
class TesserSigningError extends TesserError {
|
|
18277
18318
|
name = "TesserSigningError";
|
|
18278
18319
|
static is(err) {
|
|
@@ -19814,7 +19855,7 @@ var DNS = "dns";
|
|
|
19814
19855
|
var DN = "dn";
|
|
19815
19856
|
var EMAIL = "email";
|
|
19816
19857
|
var IP = "ip";
|
|
19817
|
-
var
|
|
19858
|
+
var URL2 = "url";
|
|
19818
19859
|
var GUID = "guid";
|
|
19819
19860
|
var UPN = "upn";
|
|
19820
19861
|
var REGISTERED_ID = "id";
|
|
@@ -19870,7 +19911,7 @@ class GeneralName extends AsnData {
|
|
|
19870
19911
|
});
|
|
19871
19912
|
break;
|
|
19872
19913
|
}
|
|
19873
|
-
case
|
|
19914
|
+
case URL2:
|
|
19874
19915
|
name = new asn1X509__namespace.GeneralName({ uniformResourceIdentifier: args[1] });
|
|
19875
19916
|
break;
|
|
19876
19917
|
default:
|
|
@@ -19894,7 +19935,7 @@ class GeneralName extends AsnData {
|
|
|
19894
19935
|
this.type = IP;
|
|
19895
19936
|
this.value = asn.iPAddress;
|
|
19896
19937
|
} else if (asn.uniformResourceIdentifier != null) {
|
|
19897
|
-
this.type =
|
|
19938
|
+
this.type = URL2;
|
|
19898
19939
|
this.value = asn.uniformResourceIdentifier;
|
|
19899
19940
|
} else if (asn.registeredID != null) {
|
|
19900
19941
|
this.type = REGISTERED_ID;
|
|
@@ -19941,7 +19982,7 @@ class GeneralName extends AsnData {
|
|
|
19941
19982
|
case IP:
|
|
19942
19983
|
case REGISTERED_ID:
|
|
19943
19984
|
case UPN:
|
|
19944
|
-
case
|
|
19985
|
+
case URL2:
|
|
19945
19986
|
type = this.type.toUpperCase();
|
|
19946
19987
|
break;
|
|
19947
19988
|
case EMAIL:
|
|
@@ -21431,16 +21472,273 @@ async function stamp(keys, body) {
|
|
|
21431
21472
|
}
|
|
21432
21473
|
}
|
|
21433
21474
|
|
|
21475
|
+
// src/internal/version.ts
|
|
21476
|
+
var SDK_VERSION = "0.1.0";
|
|
21477
|
+
|
|
21478
|
+
// src/signing/unsigned-payload.ts
|
|
21479
|
+
var UNSIGNED_PAYLOAD_PATH = "/v1/accounts/wallets/unsigned-payload";
|
|
21480
|
+
var CREATE_WALLET_ACCOUNTS_ACTIVITY_TYPE = "ACTIVITY_TYPE_CREATE_WALLET_ACCOUNTS";
|
|
21481
|
+
var ETHEREUM_ADDRESS_FORMAT = "ADDRESS_FORMAT_ETHEREUM";
|
|
21482
|
+
var UNSIGNED_PAYLOAD_TIMEOUT_MS = 1e4;
|
|
21483
|
+
var LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
21484
|
+
var MAX_FAILURE_CHAIN_DEPTH = 10;
|
|
21485
|
+
function createTesserApiConnection(options) {
|
|
21486
|
+
return {
|
|
21487
|
+
baseUrl: normalizeApiBaseUrl(options.apiBaseUrl),
|
|
21488
|
+
fetch: resolveFetchImplementation(options.fetch)
|
|
21489
|
+
};
|
|
21490
|
+
}
|
|
21491
|
+
function resolveFetchImplementation(injectedFetch) {
|
|
21492
|
+
if (injectedFetch !== undefined) {
|
|
21493
|
+
return injectedFetch;
|
|
21494
|
+
}
|
|
21495
|
+
return globalThis.fetch;
|
|
21496
|
+
}
|
|
21497
|
+
function normalizeApiBaseUrl(apiBaseUrl) {
|
|
21498
|
+
if (typeof apiBaseUrl !== "string") {
|
|
21499
|
+
throw invalidApiBaseUrlError();
|
|
21500
|
+
}
|
|
21501
|
+
const withoutTrailingSlash = removeSuffix(apiBaseUrl.trim(), "/");
|
|
21502
|
+
const normalized = removeSuffix(removeSuffix(withoutTrailingSlash, "/v1"), "/");
|
|
21503
|
+
if (!isHttpsOrLoopbackHttpUrl(normalized)) {
|
|
21504
|
+
throw invalidApiBaseUrlError();
|
|
21505
|
+
}
|
|
21506
|
+
return normalized;
|
|
21507
|
+
}
|
|
21508
|
+
function invalidApiBaseUrlError() {
|
|
21509
|
+
return new TesserConfigError("LocalSigner: apiBaseUrl must be an https URL, for example https://api.tesser.xyz");
|
|
21510
|
+
}
|
|
21511
|
+
function removeSuffix(value, suffix) {
|
|
21512
|
+
if (value.endsWith(suffix)) {
|
|
21513
|
+
return value.slice(0, value.length - suffix.length);
|
|
21514
|
+
}
|
|
21515
|
+
return value;
|
|
21516
|
+
}
|
|
21517
|
+
function isHttpsOrLoopbackHttpUrl(value) {
|
|
21518
|
+
const url = parseUrl(value);
|
|
21519
|
+
if (url === undefined || url.hostname === "") {
|
|
21520
|
+
return false;
|
|
21521
|
+
}
|
|
21522
|
+
if (url.protocol === "https:") {
|
|
21523
|
+
return true;
|
|
21524
|
+
}
|
|
21525
|
+
return url.protocol === "http:" && LOOPBACK_HOSTS.has(url.hostname.toLowerCase());
|
|
21526
|
+
}
|
|
21527
|
+
function parseUrl(value) {
|
|
21528
|
+
try {
|
|
21529
|
+
return new URL(value);
|
|
21530
|
+
} catch {
|
|
21531
|
+
return;
|
|
21532
|
+
}
|
|
21533
|
+
}
|
|
21534
|
+
async function fetchCheckedCreateWalletAccountsBody(options) {
|
|
21535
|
+
const { api, signing, params } = options;
|
|
21536
|
+
const query = buildUnsignedPayloadQuery(signing, params);
|
|
21537
|
+
const stamped = await stamp({ publicKey: signing.publicKey, privateKey: signing.privateKey }, buildCanonicalUnsignedPayloadMessage(query));
|
|
21538
|
+
const response = await sendUnsignedPayloadRequest(api, buildUnsignedPayloadUrl(api, query), stamped);
|
|
21539
|
+
const body = parseUnsignedPayloadBody(response);
|
|
21540
|
+
assertUnsignedPayloadMatchesRequest(body, signing, params);
|
|
21541
|
+
return body;
|
|
21542
|
+
}
|
|
21543
|
+
function buildUnsignedPayloadQuery(signing, params) {
|
|
21544
|
+
return {
|
|
21545
|
+
organizationId: signing.enclaveId,
|
|
21546
|
+
name: params.name,
|
|
21547
|
+
type: params.type,
|
|
21548
|
+
timestampMs: String(Date.now())
|
|
21549
|
+
};
|
|
21550
|
+
}
|
|
21551
|
+
function buildCanonicalUnsignedPayloadMessage(query) {
|
|
21552
|
+
return JSON.stringify({
|
|
21553
|
+
organizationId: query.organizationId,
|
|
21554
|
+
name: query.name,
|
|
21555
|
+
type: query.type,
|
|
21556
|
+
timestampMs: query.timestampMs
|
|
21557
|
+
});
|
|
21558
|
+
}
|
|
21559
|
+
function buildUnsignedPayloadUrl(api, query) {
|
|
21560
|
+
const queryEntries = [
|
|
21561
|
+
["organizationId", query.organizationId],
|
|
21562
|
+
["name", query.name],
|
|
21563
|
+
["type", query.type],
|
|
21564
|
+
["timestampMs", query.timestampMs]
|
|
21565
|
+
];
|
|
21566
|
+
const queryString = queryEntries.map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join("&");
|
|
21567
|
+
return `${api.baseUrl}${UNSIGNED_PAYLOAD_PATH}?${queryString}`;
|
|
21568
|
+
}
|
|
21569
|
+
async function sendUnsignedPayloadRequest(api, url, stamped) {
|
|
21570
|
+
const fetchImplementation = api.fetch;
|
|
21571
|
+
try {
|
|
21572
|
+
const response = await fetchImplementation(url, {
|
|
21573
|
+
method: "GET",
|
|
21574
|
+
headers: {
|
|
21575
|
+
Accept: "application/json",
|
|
21576
|
+
[stamped.stampHeaderName]: stamped.stampHeaderValue,
|
|
21577
|
+
"User-Agent": `tesser-sdk-ts/${SDK_VERSION}`
|
|
21578
|
+
},
|
|
21579
|
+
signal: AbortSignal.timeout(UNSIGNED_PAYLOAD_TIMEOUT_MS)
|
|
21580
|
+
});
|
|
21581
|
+
const text = await response.text();
|
|
21582
|
+
return { status: response.status, headers: response.headers, text };
|
|
21583
|
+
} catch (cause) {
|
|
21584
|
+
throw toTransportError(cause);
|
|
21585
|
+
}
|
|
21586
|
+
}
|
|
21587
|
+
function toTransportError(cause) {
|
|
21588
|
+
if (isTimeoutFailure(cause)) {
|
|
21589
|
+
return new TesserTimeoutError(`Unsigned payload request timed out after ${UNSIGNED_PAYLOAD_TIMEOUT_MS} ms`, { cause });
|
|
21590
|
+
}
|
|
21591
|
+
return new TesserConnectionError(`Unsigned payload request failed: ${describeTransportFailure(cause)}`, { cause });
|
|
21592
|
+
}
|
|
21593
|
+
function isTimeoutFailure(cause) {
|
|
21594
|
+
return readErrorName(cause) === "TimeoutError";
|
|
21595
|
+
}
|
|
21596
|
+
function describeTransportFailure(cause) {
|
|
21597
|
+
const failureChain = collectFailureChain(cause);
|
|
21598
|
+
const messages = failureChain.map(readErrorMessage).filter(isNonBlank);
|
|
21599
|
+
if (messages.length > 0) {
|
|
21600
|
+
return [...new Set(messages)].join(": ");
|
|
21601
|
+
}
|
|
21602
|
+
const names2 = failureChain.map(readErrorName).filter(isNonBlank);
|
|
21603
|
+
return names2[names2.length - 1] ?? "Unknown transport failure";
|
|
21604
|
+
}
|
|
21605
|
+
function collectFailureChain(cause) {
|
|
21606
|
+
const failureChain = [];
|
|
21607
|
+
let current = cause;
|
|
21608
|
+
while (isObject(current) && failureChain.length < MAX_FAILURE_CHAIN_DEPTH) {
|
|
21609
|
+
if (failureChain.includes(current)) {
|
|
21610
|
+
break;
|
|
21611
|
+
}
|
|
21612
|
+
failureChain.push(current);
|
|
21613
|
+
current = current.cause;
|
|
21614
|
+
}
|
|
21615
|
+
return failureChain;
|
|
21616
|
+
}
|
|
21617
|
+
function readErrorMessage(failure) {
|
|
21618
|
+
return readStringField(failure, "message");
|
|
21619
|
+
}
|
|
21620
|
+
function readErrorName(failure) {
|
|
21621
|
+
return readStringField(failure, "name");
|
|
21622
|
+
}
|
|
21623
|
+
function readStringField(source, key) {
|
|
21624
|
+
if (!isObject(source)) {
|
|
21625
|
+
return;
|
|
21626
|
+
}
|
|
21627
|
+
const value = source[key];
|
|
21628
|
+
if (typeof value !== "string") {
|
|
21629
|
+
return;
|
|
21630
|
+
}
|
|
21631
|
+
return value;
|
|
21632
|
+
}
|
|
21633
|
+
function isNonBlank(value) {
|
|
21634
|
+
return value !== undefined && value.trim() !== "";
|
|
21635
|
+
}
|
|
21636
|
+
function isObject(value) {
|
|
21637
|
+
return typeof value === "object" && value !== null;
|
|
21638
|
+
}
|
|
21639
|
+
function readGatewayRequestId(headers) {
|
|
21640
|
+
return headers.get("zp-rid") ?? headers.get("x-request-id") ?? undefined;
|
|
21641
|
+
}
|
|
21642
|
+
function parseUnsignedPayloadBody(response) {
|
|
21643
|
+
if (response.status < 200 || response.status > 299) {
|
|
21644
|
+
throw buildUnsignedPayloadApiError(response);
|
|
21645
|
+
}
|
|
21646
|
+
const body = readResponseDataBody(response.text);
|
|
21647
|
+
if (body === undefined) {
|
|
21648
|
+
throw new TesserAPIError("Unsigned payload response is not valid: data.body is missing", buildApiErrorOptions(response, []));
|
|
21649
|
+
}
|
|
21650
|
+
return body;
|
|
21651
|
+
}
|
|
21652
|
+
function readResponseDataBody(text) {
|
|
21653
|
+
const envelope = parseJsonObject(text);
|
|
21654
|
+
if (envelope === undefined || !isObject(envelope.data)) {
|
|
21655
|
+
return;
|
|
21656
|
+
}
|
|
21657
|
+
return readStringField(envelope.data, "body");
|
|
21658
|
+
}
|
|
21659
|
+
function buildUnsignedPayloadApiError(response) {
|
|
21660
|
+
return new TesserAPIError(`Unsigned payload request returned HTTP ${response.status}: ${response.text}`, buildApiErrorOptions(response, parseErrorDetails(response.text)));
|
|
21661
|
+
}
|
|
21662
|
+
function buildApiErrorOptions(response, errors) {
|
|
21663
|
+
const requestId = readGatewayRequestId(response.headers);
|
|
21664
|
+
if (requestId === undefined) {
|
|
21665
|
+
return { status: response.status, headers: response.headers, errors };
|
|
21666
|
+
}
|
|
21667
|
+
return { status: response.status, headers: response.headers, requestId, errors };
|
|
21668
|
+
}
|
|
21669
|
+
function parseErrorDetails(text) {
|
|
21670
|
+
const envelope = parseJsonObject(text);
|
|
21671
|
+
if (envelope === undefined || !Array.isArray(envelope.errors)) {
|
|
21672
|
+
return [];
|
|
21673
|
+
}
|
|
21674
|
+
return envelope.errors.flatMap(toErrorDetail);
|
|
21675
|
+
}
|
|
21676
|
+
function toErrorDetail(entry) {
|
|
21677
|
+
const errorCode = readStringField(entry, "error_code");
|
|
21678
|
+
const errorMessage = readStringField(entry, "error_message");
|
|
21679
|
+
if (errorCode === undefined || errorMessage === undefined) {
|
|
21680
|
+
return [];
|
|
21681
|
+
}
|
|
21682
|
+
const uiMessage = readStringField(entry, "ui_message");
|
|
21683
|
+
if (uiMessage === undefined) {
|
|
21684
|
+
return [{ errorCode, errorMessage }];
|
|
21685
|
+
}
|
|
21686
|
+
return [{ errorCode, errorMessage, uiMessage }];
|
|
21687
|
+
}
|
|
21688
|
+
function parseJsonObject(text) {
|
|
21689
|
+
try {
|
|
21690
|
+
const parsed = JSON.parse(text);
|
|
21691
|
+
if (isObject(parsed) && !Array.isArray(parsed)) {
|
|
21692
|
+
return parsed;
|
|
21693
|
+
}
|
|
21694
|
+
return;
|
|
21695
|
+
} catch {
|
|
21696
|
+
return;
|
|
21697
|
+
}
|
|
21698
|
+
}
|
|
21699
|
+
function assertUnsignedPayloadMatchesRequest(body, signing, params) {
|
|
21700
|
+
const payload = parseJsonObject(body);
|
|
21701
|
+
if (payload === undefined) {
|
|
21702
|
+
throw rejectUnsignedPayload("body is not a JSON object");
|
|
21703
|
+
}
|
|
21704
|
+
if (readStringField(payload, "type") !== CREATE_WALLET_ACCOUNTS_ACTIVITY_TYPE) {
|
|
21705
|
+
throw rejectUnsignedPayload(`type is not ${CREATE_WALLET_ACCOUNTS_ACTIVITY_TYPE}`);
|
|
21706
|
+
}
|
|
21707
|
+
if (readStringField(payload, "organizationId") !== signing.enclaveId) {
|
|
21708
|
+
throw rejectUnsignedPayload("organizationId does not match the signing enclaveId");
|
|
21709
|
+
}
|
|
21710
|
+
const account = readSingleAccount(payload);
|
|
21711
|
+
if (readStringField(account, "name") !== params.name) {
|
|
21712
|
+
throw rejectUnsignedPayload("account name does not match the requested wallet name");
|
|
21713
|
+
}
|
|
21714
|
+
if (readStringField(account, "addressFormat") !== ETHEREUM_ADDRESS_FORMAT) {
|
|
21715
|
+
throw rejectUnsignedPayload(`account addressFormat is not ${ETHEREUM_ADDRESS_FORMAT}`);
|
|
21716
|
+
}
|
|
21717
|
+
}
|
|
21718
|
+
function readSingleAccount(payload) {
|
|
21719
|
+
const parameters = payload.parameters;
|
|
21720
|
+
if (!isObject(parameters)) {
|
|
21721
|
+
throw rejectUnsignedPayload("parameters is missing");
|
|
21722
|
+
}
|
|
21723
|
+
const accounts = parameters.accounts;
|
|
21724
|
+
if (!Array.isArray(accounts)) {
|
|
21725
|
+
throw rejectUnsignedPayload("parameters.accounts is missing");
|
|
21726
|
+
}
|
|
21727
|
+
if (accounts.length !== 1) {
|
|
21728
|
+
throw rejectUnsignedPayload(`expected exactly one account, got ${accounts.length}`);
|
|
21729
|
+
}
|
|
21730
|
+
const account = accounts[0];
|
|
21731
|
+
if (!isObject(account) || Array.isArray(account)) {
|
|
21732
|
+
throw rejectUnsignedPayload("account is not a JSON object");
|
|
21733
|
+
}
|
|
21734
|
+
return account;
|
|
21735
|
+
}
|
|
21736
|
+
function rejectUnsignedPayload(reason) {
|
|
21737
|
+
return new TesserSigningError(`Unsigned payload rejected: ${reason}`);
|
|
21738
|
+
}
|
|
21739
|
+
|
|
21434
21740
|
// src/signing/create-wallet.ts
|
|
21435
21741
|
var WALLET_TYPE_ACCOUNTS = {
|
|
21436
|
-
stablecoin_ethereum: [
|
|
21437
|
-
{
|
|
21438
|
-
curve: "CURVE_SECP256K1",
|
|
21439
|
-
pathFormat: "PATH_FORMAT_BIP32",
|
|
21440
|
-
path: "m/44'/60'/0'/0/0",
|
|
21441
|
-
addressFormat: "ADDRESS_FORMAT_ETHEREUM"
|
|
21442
|
-
}
|
|
21443
|
-
],
|
|
21444
21742
|
stablecoin_solana: [
|
|
21445
21743
|
{
|
|
21446
21744
|
curve: "CURVE_ED25519",
|
|
@@ -21458,21 +21756,16 @@ var WALLET_TYPE_ACCOUNTS = {
|
|
|
21458
21756
|
}
|
|
21459
21757
|
]
|
|
21460
21758
|
};
|
|
21461
|
-
var VALID_WALLET_TYPES =
|
|
21462
|
-
|
|
21759
|
+
var VALID_WALLET_TYPES = [
|
|
21760
|
+
"stablecoin_ethereum",
|
|
21761
|
+
"stablecoin_solana",
|
|
21762
|
+
"stablecoin_stellar"
|
|
21763
|
+
];
|
|
21764
|
+
async function signCreateWallet(signing, params, api) {
|
|
21463
21765
|
if (!VALID_WALLET_TYPES.includes(params.type)) {
|
|
21464
21766
|
throw new TesserConfigError(`signCreateWallet: type '${String(params.type)}' is not a valid WalletType. ` + `Valid values: ${VALID_WALLET_TYPES.join(", ")}.`);
|
|
21465
21767
|
}
|
|
21466
|
-
const
|
|
21467
|
-
const body = JSON.stringify({
|
|
21468
|
-
type: "ACTIVITY_TYPE_CREATE_WALLET",
|
|
21469
|
-
timestampMs: String(Date.now()),
|
|
21470
|
-
organizationId: signing.enclaveId,
|
|
21471
|
-
parameters: {
|
|
21472
|
-
walletName: params.name,
|
|
21473
|
-
accounts
|
|
21474
|
-
}
|
|
21475
|
-
});
|
|
21768
|
+
const body = await resolveCreateWalletBody({ signing, params, api });
|
|
21476
21769
|
const result = await stamp({ publicKey: signing.publicKey, privateKey: signing.privateKey }, body);
|
|
21477
21770
|
const signature = Buffer.from(JSON.stringify({ body, stamp: result.stampHeaderValue })).toString("base64");
|
|
21478
21771
|
return {
|
|
@@ -21484,15 +21777,40 @@ async function signCreateWallet(signing, params) {
|
|
|
21484
21777
|
}
|
|
21485
21778
|
};
|
|
21486
21779
|
}
|
|
21780
|
+
async function resolveCreateWalletBody(options) {
|
|
21781
|
+
const { signing, params, api } = options;
|
|
21782
|
+
if (params.type === "stablecoin_ethereum") {
|
|
21783
|
+
return fetchCheckedCreateWalletAccountsBody({ api, signing, params });
|
|
21784
|
+
}
|
|
21785
|
+
return buildCreateWalletBody({
|
|
21786
|
+
enclaveId: signing.enclaveId,
|
|
21787
|
+
name: params.name,
|
|
21788
|
+
type: params.type
|
|
21789
|
+
});
|
|
21790
|
+
}
|
|
21791
|
+
function buildCreateWalletBody(options) {
|
|
21792
|
+
return JSON.stringify({
|
|
21793
|
+
type: "ACTIVITY_TYPE_CREATE_WALLET",
|
|
21794
|
+
timestampMs: String(Date.now()),
|
|
21795
|
+
organizationId: options.enclaveId,
|
|
21796
|
+
parameters: {
|
|
21797
|
+
walletName: options.name,
|
|
21798
|
+
accounts: WALLET_TYPE_ACCOUNTS[options.type]
|
|
21799
|
+
}
|
|
21800
|
+
});
|
|
21801
|
+
}
|
|
21487
21802
|
|
|
21488
21803
|
// src/signing/network-type.ts
|
|
21489
21804
|
var NETWORK_TO_TURNKEY_TYPE = {
|
|
21490
21805
|
BASE: "TRANSACTION_TYPE_ETHEREUM",
|
|
21491
21806
|
BASE_SEPOLIA: "TRANSACTION_TYPE_ETHEREUM",
|
|
21492
21807
|
ETHEREUM: "TRANSACTION_TYPE_ETHEREUM",
|
|
21808
|
+
ETHEREUM_SEPOLIA: "TRANSACTION_TYPE_ETHEREUM",
|
|
21493
21809
|
POLYGON: "TRANSACTION_TYPE_ETHEREUM",
|
|
21494
21810
|
POLYGON_AMOY: "TRANSACTION_TYPE_ETHEREUM",
|
|
21495
|
-
SOLANA: "TRANSACTION_TYPE_SOLANA"
|
|
21811
|
+
SOLANA: "TRANSACTION_TYPE_SOLANA",
|
|
21812
|
+
TEMPO: "TRANSACTION_TYPE_TEMPO",
|
|
21813
|
+
TEMPO_MODERATO: "TRANSACTION_TYPE_TEMPO"
|
|
21496
21814
|
};
|
|
21497
21815
|
function networkToTurnkeyType(network) {
|
|
21498
21816
|
const turnkeyType = NETWORK_TO_TURNKEY_TYPE[network];
|
|
@@ -21533,11 +21851,13 @@ async function signStep(signing, step) {
|
|
|
21533
21851
|
class LocalSigner {
|
|
21534
21852
|
signing;
|
|
21535
21853
|
#privateKey;
|
|
21854
|
+
#api;
|
|
21536
21855
|
constructor(options) {
|
|
21537
21856
|
const s = options.signing;
|
|
21538
21857
|
if (!s || !s.publicKey || !s.privateKey || !s.enclaveId) {
|
|
21539
21858
|
throw new TesserConfigError("LocalSigner: signing.publicKey, signing.privateKey, and signing.enclaveId are required");
|
|
21540
21859
|
}
|
|
21860
|
+
this.#api = createTesserApiConnection({ apiBaseUrl: options.apiBaseUrl, fetch: options.fetch });
|
|
21541
21861
|
this.signing = { publicKey: s.publicKey, enclaveId: s.enclaveId };
|
|
21542
21862
|
this.#privateKey = s.privateKey;
|
|
21543
21863
|
}
|
|
@@ -21546,7 +21866,7 @@ class LocalSigner {
|
|
|
21546
21866
|
publicKey: this.signing.publicKey,
|
|
21547
21867
|
privateKey: this.#privateKey,
|
|
21548
21868
|
enclaveId: this.signing.enclaveId
|
|
21549
|
-
}, params);
|
|
21869
|
+
}, params, this.#api);
|
|
21550
21870
|
}
|
|
21551
21871
|
signStep(step) {
|
|
21552
21872
|
return signStep({
|
|
@@ -21557,9 +21877,12 @@ class LocalSigner {
|
|
|
21557
21877
|
}
|
|
21558
21878
|
}
|
|
21559
21879
|
export {
|
|
21880
|
+
TesserTimeoutError,
|
|
21560
21881
|
TesserSigningError,
|
|
21561
21882
|
TesserError,
|
|
21883
|
+
TesserConnectionError,
|
|
21562
21884
|
TesserConfigError,
|
|
21885
|
+
TesserAPIError,
|
|
21563
21886
|
StampError,
|
|
21564
21887
|
LocalSigner
|
|
21565
21888
|
};
|
|
@@ -28,11 +28,11 @@ export interface TesserAPIErrorOptions {
|
|
|
28
28
|
errors?: readonly TesserErrorDetail[];
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
-
* Thrown
|
|
32
|
-
* `errors[]` envelope so consumers can branch on Tesser's
|
|
33
|
-
* codes (e.g. `accounts-3005`, `idempotency-1001`) rather
|
|
34
|
-
* alone. For responses that are not Tesser-shaped (e.g., a
|
|
35
|
-
* page), `errors` is the empty array.
|
|
31
|
+
* Thrown when Tesser answers with an error status or an invalid response.
|
|
32
|
+
* Carries the parsed `errors[]` envelope so consumers can branch on Tesser's
|
|
33
|
+
* documented error codes (e.g. `accounts-3005`, `idempotency-1001`) rather
|
|
34
|
+
* than HTTP status alone. For responses that are not Tesser-shaped (e.g., a
|
|
35
|
+
* Cloudflare 502 page), `errors` is the empty array.
|
|
36
36
|
*/
|
|
37
37
|
export declare class TesserAPIError extends TesserError {
|
|
38
38
|
readonly name: string;
|
package/dist/internal/types.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export interface StepForSigning {
|
|
|
34
34
|
unsignedTransaction: string;
|
|
35
35
|
/** On-chain address from GET /v1/accounts/{id} → crypto_wallet_address */
|
|
36
36
|
signWith: string;
|
|
37
|
-
/** Network identifier; one of the supported
|
|
37
|
+
/** Network identifier; one of the supported networks. */
|
|
38
38
|
network: SupportedNetwork;
|
|
39
39
|
}
|
|
40
40
|
export interface SignedStepResultMetadata {
|
|
@@ -49,4 +49,14 @@ export interface SignedStepResult {
|
|
|
49
49
|
}
|
|
50
50
|
export interface LocalSignerOptions {
|
|
51
51
|
signing: SigningConfig;
|
|
52
|
+
/**
|
|
53
|
+
* Tesser API base URL: `https://api.tesser.xyz` in production,
|
|
54
|
+
* `https://api-sandbox.tesser.xyz` in sandbox. A trailing `/` or `/v1` is removed.
|
|
55
|
+
*/
|
|
56
|
+
apiBaseUrl: string;
|
|
57
|
+
/**
|
|
58
|
+
* `fetch` implementation used for requests to Tesser. Inject one to configure a
|
|
59
|
+
* proxy. Defaults to the global `fetch`.
|
|
60
|
+
*/
|
|
61
|
+
fetch?: typeof fetch;
|
|
52
62
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SDK_VERSION = "0.1.0";
|
package/dist/signer.d.ts
CHANGED
|
@@ -11,9 +11,8 @@ export interface PublicSigningInfo {
|
|
|
11
11
|
/**
|
|
12
12
|
* Produces locally-signed activity payloads for Tesser API operations.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* the addition is purely additive and does not break existing call sites.
|
|
14
|
+
* Supports `signCreateWallet` and `signStep`. Construction validates that the
|
|
15
|
+
* signing keys are non-blank and that `apiBaseUrl` is an https URL.
|
|
17
16
|
*
|
|
18
17
|
* Key handling: the private key is stored in an ECMA private field (`#privateKey`)
|
|
19
18
|
* and is not reachable via `signer.signing.privateKey` or any other public
|
|
@@ -27,8 +26,25 @@ export declare class LocalSigner {
|
|
|
27
26
|
#private;
|
|
28
27
|
readonly signing: PublicSigningInfo;
|
|
29
28
|
constructor(options: LocalSignerOptions);
|
|
30
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Signs a wallet-creation request.
|
|
31
|
+
*
|
|
32
|
+
* For `stablecoin_ethereum` the SDK first fetches the request to sign from the
|
|
33
|
+
* Tesser API and checks that it matches your parameters. Other wallet types are
|
|
34
|
+
* signed locally without a request to Tesser. The private key never leaves the
|
|
35
|
+
* process.
|
|
36
|
+
*
|
|
37
|
+
* @throws {TesserConfigError} if the wallet type is not valid.
|
|
38
|
+
* @throws {TesserSigningError} if signing fails or the request fetched from
|
|
39
|
+
* Tesser does not match your parameters.
|
|
40
|
+
* @throws {TesserAPIError} if Tesser answers with an error status or an
|
|
41
|
+
* invalid response. Safe to retry for status 429 or 5xx; other 4xx statuses
|
|
42
|
+
* fail the same way on retry.
|
|
43
|
+
* @throws {TesserConnectionError} if the request to Tesser fails at the
|
|
44
|
+
* network level. Safe to retry.
|
|
45
|
+
* @throws {TesserTimeoutError} if the request to Tesser times out. Safe to retry.
|
|
46
|
+
*/
|
|
31
47
|
signCreateWallet(params: CreateWalletParams): Promise<SignedResult>;
|
|
32
|
-
/**
|
|
48
|
+
/** Signs a single transfer step. The private key never leaves the process. */
|
|
33
49
|
signStep(step: StepForSigning): Promise<SignedStepResult>;
|
|
34
50
|
}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import type { CreateWalletParams, SignedResult, SigningConfig } from '../internal/types.js';
|
|
2
|
-
|
|
2
|
+
import { type TesserApiConnection } from './unsigned-payload.js';
|
|
3
|
+
export declare function signCreateWallet(signing: SigningConfig, params: CreateWalletParams, api: TesserApiConnection): Promise<SignedResult>;
|
|
@@ -2,9 +2,12 @@ declare const NETWORK_TO_TURNKEY_TYPE: {
|
|
|
2
2
|
readonly BASE: "TRANSACTION_TYPE_ETHEREUM";
|
|
3
3
|
readonly BASE_SEPOLIA: "TRANSACTION_TYPE_ETHEREUM";
|
|
4
4
|
readonly ETHEREUM: "TRANSACTION_TYPE_ETHEREUM";
|
|
5
|
+
readonly ETHEREUM_SEPOLIA: "TRANSACTION_TYPE_ETHEREUM";
|
|
5
6
|
readonly POLYGON: "TRANSACTION_TYPE_ETHEREUM";
|
|
6
7
|
readonly POLYGON_AMOY: "TRANSACTION_TYPE_ETHEREUM";
|
|
7
8
|
readonly SOLANA: "TRANSACTION_TYPE_SOLANA";
|
|
9
|
+
readonly TEMPO: "TRANSACTION_TYPE_TEMPO";
|
|
10
|
+
readonly TEMPO_MODERATO: "TRANSACTION_TYPE_TEMPO";
|
|
8
11
|
};
|
|
9
12
|
export type SupportedNetwork = keyof typeof NETWORK_TO_TURNKEY_TYPE;
|
|
10
13
|
export declare function networkToTurnkeyType(network: string): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CreateWalletParams, SigningConfig } from '../internal/types.js';
|
|
2
|
+
export interface TesserApiConnection {
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
fetch: typeof fetch;
|
|
5
|
+
}
|
|
6
|
+
export declare function createTesserApiConnection(options: {
|
|
7
|
+
apiBaseUrl: unknown;
|
|
8
|
+
fetch: typeof fetch | undefined;
|
|
9
|
+
}): TesserApiConnection;
|
|
10
|
+
export declare function normalizeApiBaseUrl(apiBaseUrl: unknown): string;
|
|
11
|
+
export declare function fetchCheckedCreateWalletAccountsBody(options: {
|
|
12
|
+
api: TesserApiConnection;
|
|
13
|
+
signing: SigningConfig;
|
|
14
|
+
params: CreateWalletParams;
|
|
15
|
+
}): Promise<string>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tesser-payments/sdk-ts",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript SDK for Tesser API: sign signCreateWallet and signStep requests locally. No OAuth — bring your own client.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
@@ -39,12 +39,19 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@turnkey/api-key-stamper": "^0.6.5"
|
|
41
41
|
},
|
|
42
|
+
"overrides": {
|
|
43
|
+
"ws": "^8.21.0",
|
|
44
|
+
"vite": "^6.4.5",
|
|
45
|
+
"postcss": "^8.5.18",
|
|
46
|
+
"source-map-js": "^1.2.2",
|
|
47
|
+
"zod": "^4.6.6"
|
|
48
|
+
},
|
|
42
49
|
"devDependencies": {
|
|
43
50
|
"@biomejs/biome": "^1.9",
|
|
44
51
|
"@tesser-payments/types": "*",
|
|
45
52
|
"@types/node": "^20",
|
|
46
53
|
"typescript": "^5.4",
|
|
47
|
-
"vitest": "^
|
|
54
|
+
"vitest": "^4.1.12"
|
|
48
55
|
},
|
|
49
56
|
"trustedDependencies": []
|
|
50
57
|
}
|