neozip-blockchain 0.7.2 → 1.0.2
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 +11 -14
- package/WHATS_NEW.md +68 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/token-service/TokenServiceAccountAuth.d.ts +97 -0
- package/dist/token-service/TokenServiceAccountAuth.d.ts.map +1 -0
- package/dist/token-service/TokenServiceAccountAuth.js +286 -0
- package/dist/token-service/TokenServiceAccountAuth.js.map +1 -0
- package/dist/token-service/TokenServiceFunding.d.ts +87 -0
- package/dist/token-service/TokenServiceFunding.d.ts.map +1 -0
- package/dist/token-service/TokenServiceFunding.js +143 -0
- package/dist/token-service/TokenServiceFunding.js.map +1 -0
- package/dist/token-service/TokenServiceIdentity.d.ts +96 -0
- package/dist/token-service/TokenServiceIdentity.d.ts.map +1 -0
- package/dist/token-service/TokenServiceIdentity.js +240 -0
- package/dist/token-service/TokenServiceIdentity.js.map +1 -0
- package/dist/token-service/http.d.ts +46 -0
- package/dist/token-service/http.d.ts.map +1 -0
- package/dist/token-service/http.js +119 -0
- package/dist/token-service/http.js.map +1 -0
- package/dist/token-service/index.d.ts +4 -0
- package/dist/token-service/index.d.ts.map +1 -1
- package/dist/token-service/index.js +42 -1
- package/dist/token-service/index.js.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* NeoZip Token Service funding API client.
|
|
4
|
+
*
|
|
5
|
+
* The Token Service can disburse small native-gas grants to the user's primary
|
|
6
|
+
* linked Data Wallet so on-chain operations (tokenization, timestamping) can pay
|
|
7
|
+
* for gas. The recipient is server-authoritative — a client may only request a
|
|
8
|
+
* grant, never redirect it.
|
|
9
|
+
*
|
|
10
|
+
* GET /funding/policy?chainId=<id> (no auth)
|
|
11
|
+
* GET /funding/status?chainId=<id> (Bearer)
|
|
12
|
+
* POST /funding/request (Bearer, optional Idempotency-Key)
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.FundingUnavailableError = void 0;
|
|
16
|
+
exports.getFundingPolicy = getFundingPolicy;
|
|
17
|
+
exports.getFundingStatus = getFundingStatus;
|
|
18
|
+
exports.requestFundingGrant = requestFundingGrant;
|
|
19
|
+
const http_1 = require("./http");
|
|
20
|
+
/** Thrown when the Token Service does not expose the funding endpoints (older deployment). */
|
|
21
|
+
class FundingUnavailableError extends Error {
|
|
22
|
+
constructor(message = 'Token Service does not support funding') {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = 'FundingUnavailableError';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.FundingUnavailableError = FundingUnavailableError;
|
|
28
|
+
/**
|
|
29
|
+
* Fetch the public funding policy for a chain (grant size, cooldown, low-balance
|
|
30
|
+
* threshold). No authentication required.
|
|
31
|
+
*
|
|
32
|
+
* @throws {FundingUnavailableError} when the endpoint returns 404.
|
|
33
|
+
* @throws {Error} on other failures or a malformed response.
|
|
34
|
+
*/
|
|
35
|
+
async function getFundingPolicy(baseUrl, chainId) {
|
|
36
|
+
const url = (0, http_1.normalizeServerUrl)(baseUrl);
|
|
37
|
+
let res;
|
|
38
|
+
try {
|
|
39
|
+
res = await fetch(`${url}/funding/policy?chainId=${encodeURIComponent(String(chainId))}`, {
|
|
40
|
+
method: 'GET',
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
throw new Error((0, http_1.formatTokenServiceFetchError)(url, err));
|
|
45
|
+
}
|
|
46
|
+
if (res.status === 404) {
|
|
47
|
+
throw new FundingUnavailableError();
|
|
48
|
+
}
|
|
49
|
+
const parsed = await (0, http_1.safeJson)(res);
|
|
50
|
+
if (!res.ok || !parsed || parsed.success !== true) {
|
|
51
|
+
throw new Error((0, http_1.extractError)(parsed, `Funding policy lookup failed (HTTP ${res.status})`));
|
|
52
|
+
}
|
|
53
|
+
const policy = parsed.policy;
|
|
54
|
+
if (!policy) {
|
|
55
|
+
throw new Error('Funding policy response missing policy');
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
chainId: typeof parsed.chainId === 'number' ? parsed.chainId : chainId,
|
|
59
|
+
network: typeof parsed.network === 'string' ? parsed.network : '',
|
|
60
|
+
policy,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Fetch the caller's funding status for a chain (recipient address, eligibility,
|
|
65
|
+
* recent grants). Requires a Bearer access token.
|
|
66
|
+
*
|
|
67
|
+
* @throws {FundingUnavailableError} when the endpoint returns 404.
|
|
68
|
+
* @throws {Error} on other failures (including 401/403) or a malformed response.
|
|
69
|
+
*/
|
|
70
|
+
async function getFundingStatus(baseUrl, accessToken, chainId) {
|
|
71
|
+
const url = (0, http_1.normalizeServerUrl)(baseUrl);
|
|
72
|
+
let res;
|
|
73
|
+
try {
|
|
74
|
+
res = await fetch(`${url}/funding/status?chainId=${encodeURIComponent(String(chainId))}`, {
|
|
75
|
+
method: 'GET',
|
|
76
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
throw new Error((0, http_1.formatTokenServiceFetchError)(url, err));
|
|
81
|
+
}
|
|
82
|
+
if (res.status === 404) {
|
|
83
|
+
throw new FundingUnavailableError();
|
|
84
|
+
}
|
|
85
|
+
const parsed = await (0, http_1.safeJson)(res);
|
|
86
|
+
if (!res.ok || !parsed || parsed.success !== true) {
|
|
87
|
+
throw new Error((0, http_1.extractError)(parsed, `Funding status lookup failed (HTTP ${res.status})`, {
|
|
88
|
+
status: res.status,
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
chainId: typeof parsed.chainId === 'number' ? parsed.chainId : chainId,
|
|
93
|
+
recipientAddress: typeof parsed.recipientAddress === 'string' ? parsed.recipientAddress : null,
|
|
94
|
+
enabled: parsed.enabled === true,
|
|
95
|
+
requiresPayment: parsed.requiresPayment === true,
|
|
96
|
+
lastGrantAt: typeof parsed.lastGrantAt === 'string' ? parsed.lastGrantAt : null,
|
|
97
|
+
nextEligibleAt: typeof parsed.nextEligibleAt === 'string' ? parsed.nextEligibleAt : null,
|
|
98
|
+
recentGrants: Array.isArray(parsed.recentGrants)
|
|
99
|
+
? parsed.recentGrants
|
|
100
|
+
: [],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Request a native-gas grant to the caller's primary Data Wallet. Requires a
|
|
105
|
+
* Bearer access token; an optional `idempotencyKey` makes retries safe.
|
|
106
|
+
*
|
|
107
|
+
* Returns the parsed result (which may itself report `success: false` with an
|
|
108
|
+
* `errorCode` such as a cooldown).
|
|
109
|
+
*
|
|
110
|
+
* @throws {FundingUnavailableError} when the endpoint returns 404.
|
|
111
|
+
* @throws {Error} when the response is non-JSON (e.g. auth failures).
|
|
112
|
+
*/
|
|
113
|
+
async function requestFundingGrant(baseUrl, accessToken, chainId, idempotencyKey) {
|
|
114
|
+
const url = (0, http_1.normalizeServerUrl)(baseUrl);
|
|
115
|
+
const headers = {
|
|
116
|
+
Authorization: `Bearer ${accessToken}`,
|
|
117
|
+
'content-type': 'application/json',
|
|
118
|
+
};
|
|
119
|
+
if (idempotencyKey) {
|
|
120
|
+
headers['Idempotency-Key'] = idempotencyKey;
|
|
121
|
+
}
|
|
122
|
+
let res;
|
|
123
|
+
try {
|
|
124
|
+
res = await fetch(`${url}/funding/request`, {
|
|
125
|
+
method: 'POST',
|
|
126
|
+
headers,
|
|
127
|
+
body: JSON.stringify({ chainId }),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
throw new Error((0, http_1.formatTokenServiceFetchError)(url, err));
|
|
132
|
+
}
|
|
133
|
+
if (res.status === 404) {
|
|
134
|
+
throw new FundingUnavailableError();
|
|
135
|
+
}
|
|
136
|
+
const parsed = await (0, http_1.safeJson)(res);
|
|
137
|
+
if (!parsed) {
|
|
138
|
+
// Auth failures and other non-JSON responses.
|
|
139
|
+
throw new Error((0, http_1.genericAuthErrorMessage)(res.status) ?? `Funding request failed (HTTP ${res.status})`);
|
|
140
|
+
}
|
|
141
|
+
return parsed;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=TokenServiceFunding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TokenServiceFunding.js","sourceRoot":"","sources":["../../src/token-service/TokenServiceFunding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NeoZip Token Service identity HTTP client.
|
|
3
|
+
*
|
|
4
|
+
* Stateless functions for linking an EVM data wallet to an account and managing
|
|
5
|
+
* its encrypted identity key:
|
|
6
|
+
*
|
|
7
|
+
* GET /crypto/coordinator-config (no auth)
|
|
8
|
+
* POST /identity/wallets/challenge (no auth)
|
|
9
|
+
* POST /identity/wallets/ensure (no auth)
|
|
10
|
+
* POST /identity/users/me/wallets/:id/attach/challenge (Bearer)
|
|
11
|
+
* POST /identity/users/me/wallets/:id/attach/complete (Bearer)
|
|
12
|
+
* GET /identity/wallets/:id/identity-key (Bearer)
|
|
13
|
+
* POST /identity/wallets/:id/identity-key/init/challenge (Bearer)
|
|
14
|
+
* POST /identity/wallets/:id/identity-key/init/complete (Bearer)
|
|
15
|
+
*
|
|
16
|
+
* These functions only speak HTTP; message signing with the wallet's private key
|
|
17
|
+
* is the responsibility of the calling application (CLI/Desktop), which composes
|
|
18
|
+
* the challenge/complete pairs around a local signer.
|
|
19
|
+
*/
|
|
20
|
+
/** Default ECIES suite advertised when registering an identity key. */
|
|
21
|
+
export declare const DEFAULT_RECIPIENT_SUITE = "ecies-x25519-aes256gcm";
|
|
22
|
+
/**
|
|
23
|
+
* Wrapped (encrypted) EVM private key bundle sent to the Token Service when
|
|
24
|
+
* registering an identity key. The wrap parameters describe how the X25519
|
|
25
|
+
* private key is sealed to the EOA so the server stores ciphertext only.
|
|
26
|
+
*/
|
|
27
|
+
export interface WrapBundle {
|
|
28
|
+
wrappedPrivateKeyB64: string;
|
|
29
|
+
wrapFormatVersion: number;
|
|
30
|
+
wrapKdfInfo: string;
|
|
31
|
+
wrapKdfSaltB64: string;
|
|
32
|
+
wrapAead: string;
|
|
33
|
+
wrapIvB64: string;
|
|
34
|
+
wrapAadB64: string;
|
|
35
|
+
}
|
|
36
|
+
/** Identity-key registration payload: a wrap bundle plus the X25519 public key. */
|
|
37
|
+
export interface IdentityKeyBundleBody extends WrapBundle {
|
|
38
|
+
x25519PublicKeyB64: string;
|
|
39
|
+
recipientSuites?: string[];
|
|
40
|
+
}
|
|
41
|
+
/** Thrown when an identity key already exists for a wallet (HTTP 409). */
|
|
42
|
+
export declare class IdentityKeyConflictError extends Error {
|
|
43
|
+
constructor(message: string);
|
|
44
|
+
}
|
|
45
|
+
/** Probe whether the Token Service exposes wallet-identity coordination. */
|
|
46
|
+
export declare function fetchCoordinatorConfig(baseUrl: string): Promise<boolean>;
|
|
47
|
+
/** Request a challenge proving control of `evmAddress` (no auth). */
|
|
48
|
+
export declare function requestWalletEnsureChallenge(baseUrl: string, evmAddress: string): Promise<{
|
|
49
|
+
challengeId: string;
|
|
50
|
+
message: string;
|
|
51
|
+
evmAddress: string;
|
|
52
|
+
}>;
|
|
53
|
+
/** Ensure a wallet record exists for the signed challenge (no auth). */
|
|
54
|
+
export declare function completeWalletEnsure(baseUrl: string, input: {
|
|
55
|
+
evmAddress: string;
|
|
56
|
+
challengeId: string;
|
|
57
|
+
evmSignature: string;
|
|
58
|
+
}): Promise<{
|
|
59
|
+
walletId: number;
|
|
60
|
+
evmAddress: string;
|
|
61
|
+
}>;
|
|
62
|
+
/** Request a challenge to attach a wallet to the authenticated account (Bearer). */
|
|
63
|
+
export declare function requestWalletAttachChallenge(baseUrl: string, accessToken: string, walletId: number): Promise<{
|
|
64
|
+
challengeId: string;
|
|
65
|
+
message: string;
|
|
66
|
+
walletId: number;
|
|
67
|
+
evmAddress: string;
|
|
68
|
+
}>;
|
|
69
|
+
/** Complete a wallet attach with a signature, linking it as primary (Bearer). */
|
|
70
|
+
export declare function completeWalletAttach(baseUrl: string, accessToken: string, walletId: number, input: {
|
|
71
|
+
challengeId: string;
|
|
72
|
+
evmSignature: string;
|
|
73
|
+
}): Promise<{
|
|
74
|
+
linkId: number;
|
|
75
|
+
}>;
|
|
76
|
+
/** Fetch the identity-key bundle for a wallet, or `{ found: false }` (Bearer). */
|
|
77
|
+
export declare function getIdentityKeyBundle(baseUrl: string, accessToken: string, walletId: number): Promise<{
|
|
78
|
+
found: false;
|
|
79
|
+
} | {
|
|
80
|
+
found: true;
|
|
81
|
+
identityKeyId: number;
|
|
82
|
+
x25519PublicKey: string;
|
|
83
|
+
}>;
|
|
84
|
+
/** Request a challenge to register an identity key for a wallet (Bearer). */
|
|
85
|
+
export declare function requestIdentityKeyInitChallenge(baseUrl: string, accessToken: string, walletId: number, bundle: IdentityKeyBundleBody): Promise<{
|
|
86
|
+
challengeId: string;
|
|
87
|
+
message: string;
|
|
88
|
+
evmAddress: string;
|
|
89
|
+
wrappedSha256Hex: string;
|
|
90
|
+
}>;
|
|
91
|
+
/** Complete identity-key registration with a signature (Bearer). */
|
|
92
|
+
export declare function completeIdentityKeyInit(baseUrl: string, accessToken: string, walletId: number, bundle: IdentityKeyBundleBody, challengeId: string, evmSignature: string): Promise<{
|
|
93
|
+
identityKeyId: number;
|
|
94
|
+
x25519PublicKey: string;
|
|
95
|
+
}>;
|
|
96
|
+
//# sourceMappingURL=TokenServiceIdentity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TokenServiceIdentity.d.ts","sourceRoot":"","sources":["../../src/token-service/TokenServiceIdentity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* NeoZip Token Service identity HTTP client.
|
|
4
|
+
*
|
|
5
|
+
* Stateless functions for linking an EVM data wallet to an account and managing
|
|
6
|
+
* its encrypted identity key:
|
|
7
|
+
*
|
|
8
|
+
* GET /crypto/coordinator-config (no auth)
|
|
9
|
+
* POST /identity/wallets/challenge (no auth)
|
|
10
|
+
* POST /identity/wallets/ensure (no auth)
|
|
11
|
+
* POST /identity/users/me/wallets/:id/attach/challenge (Bearer)
|
|
12
|
+
* POST /identity/users/me/wallets/:id/attach/complete (Bearer)
|
|
13
|
+
* GET /identity/wallets/:id/identity-key (Bearer)
|
|
14
|
+
* POST /identity/wallets/:id/identity-key/init/challenge (Bearer)
|
|
15
|
+
* POST /identity/wallets/:id/identity-key/init/complete (Bearer)
|
|
16
|
+
*
|
|
17
|
+
* These functions only speak HTTP; message signing with the wallet's private key
|
|
18
|
+
* is the responsibility of the calling application (CLI/Desktop), which composes
|
|
19
|
+
* the challenge/complete pairs around a local signer.
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.IdentityKeyConflictError = exports.DEFAULT_RECIPIENT_SUITE = void 0;
|
|
23
|
+
exports.fetchCoordinatorConfig = fetchCoordinatorConfig;
|
|
24
|
+
exports.requestWalletEnsureChallenge = requestWalletEnsureChallenge;
|
|
25
|
+
exports.completeWalletEnsure = completeWalletEnsure;
|
|
26
|
+
exports.requestWalletAttachChallenge = requestWalletAttachChallenge;
|
|
27
|
+
exports.completeWalletAttach = completeWalletAttach;
|
|
28
|
+
exports.getIdentityKeyBundle = getIdentityKeyBundle;
|
|
29
|
+
exports.requestIdentityKeyInitChallenge = requestIdentityKeyInitChallenge;
|
|
30
|
+
exports.completeIdentityKeyInit = completeIdentityKeyInit;
|
|
31
|
+
const ethers_1 = require("ethers");
|
|
32
|
+
const http_1 = require("./http");
|
|
33
|
+
/** Default ECIES suite advertised when registering an identity key. */
|
|
34
|
+
exports.DEFAULT_RECIPIENT_SUITE = 'ecies-x25519-aes256gcm';
|
|
35
|
+
/** Thrown when an identity key already exists for a wallet (HTTP 409). */
|
|
36
|
+
class IdentityKeyConflictError extends Error {
|
|
37
|
+
constructor(message) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.name = 'IdentityKeyConflictError';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.IdentityKeyConflictError = IdentityKeyConflictError;
|
|
43
|
+
function challengeBody(bundle) {
|
|
44
|
+
return {
|
|
45
|
+
x25519PublicKeyB64: bundle.x25519PublicKeyB64,
|
|
46
|
+
wrappedPrivateKeyB64: bundle.wrappedPrivateKeyB64,
|
|
47
|
+
wrapFormatVersion: bundle.wrapFormatVersion,
|
|
48
|
+
wrapKdfInfo: bundle.wrapKdfInfo,
|
|
49
|
+
wrapKdfSaltB64: bundle.wrapKdfSaltB64,
|
|
50
|
+
wrapAead: bundle.wrapAead,
|
|
51
|
+
wrapIvB64: bundle.wrapIvB64,
|
|
52
|
+
wrapAadB64: bundle.wrapAadB64,
|
|
53
|
+
recipientSuites: bundle.recipientSuites ?? [exports.DEFAULT_RECIPIENT_SUITE],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function authHeaders(accessToken) {
|
|
57
|
+
return {
|
|
58
|
+
Authorization: `Bearer ${accessToken}`,
|
|
59
|
+
'content-type': 'application/json',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** Probe whether the Token Service exposes wallet-identity coordination. */
|
|
63
|
+
async function fetchCoordinatorConfig(baseUrl) {
|
|
64
|
+
const url = (0, http_1.normalizeServerUrl)(baseUrl);
|
|
65
|
+
try {
|
|
66
|
+
const res = await fetch(`${url}/crypto/coordinator-config`, { method: 'GET' });
|
|
67
|
+
return res.ok;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Request a challenge proving control of `evmAddress` (no auth). */
|
|
74
|
+
async function requestWalletEnsureChallenge(baseUrl, evmAddress) {
|
|
75
|
+
const url = (0, http_1.normalizeServerUrl)(baseUrl);
|
|
76
|
+
const checksummed = (0, ethers_1.getAddress)(evmAddress.trim());
|
|
77
|
+
const res = await fetch(`${url}/identity/wallets/challenge`, {
|
|
78
|
+
method: 'POST',
|
|
79
|
+
headers: { 'content-type': 'application/json' },
|
|
80
|
+
body: JSON.stringify({ evmAddress: checksummed }),
|
|
81
|
+
});
|
|
82
|
+
const parsed = await (0, http_1.safeJson)(res);
|
|
83
|
+
if (!res.ok || !parsed || parsed.success !== true) {
|
|
84
|
+
throw new Error((0, http_1.extractError)(parsed, `Wallet challenge failed (HTTP ${res.status})`));
|
|
85
|
+
}
|
|
86
|
+
const challengeId = (0, http_1.pickString)(parsed, 'challengeId');
|
|
87
|
+
const message = (0, http_1.pickString)(parsed, 'message');
|
|
88
|
+
const addr = (0, http_1.pickString)(parsed, 'evmAddress');
|
|
89
|
+
if (!challengeId || !message || !addr) {
|
|
90
|
+
throw new Error('Wallet challenge response missing fields');
|
|
91
|
+
}
|
|
92
|
+
return { challengeId, message, evmAddress: addr };
|
|
93
|
+
}
|
|
94
|
+
/** Ensure a wallet record exists for the signed challenge (no auth). */
|
|
95
|
+
async function completeWalletEnsure(baseUrl, input) {
|
|
96
|
+
const url = (0, http_1.normalizeServerUrl)(baseUrl);
|
|
97
|
+
const checksummed = (0, ethers_1.getAddress)(input.evmAddress.trim());
|
|
98
|
+
const res = await fetch(`${url}/identity/wallets/ensure`, {
|
|
99
|
+
method: 'POST',
|
|
100
|
+
headers: { 'content-type': 'application/json' },
|
|
101
|
+
body: JSON.stringify({
|
|
102
|
+
evmAddress: checksummed,
|
|
103
|
+
challengeId: input.challengeId,
|
|
104
|
+
evmSignature: input.evmSignature,
|
|
105
|
+
}),
|
|
106
|
+
});
|
|
107
|
+
const parsed = await (0, http_1.safeJson)(res);
|
|
108
|
+
if (!res.ok || !parsed || parsed.success !== true) {
|
|
109
|
+
throw new Error((0, http_1.extractError)(parsed, `Wallet ensure failed (HTTP ${res.status})`));
|
|
110
|
+
}
|
|
111
|
+
const walletId = typeof parsed.walletId === 'number' ? parsed.walletId : Number(parsed.walletId);
|
|
112
|
+
const addr = (0, http_1.pickString)(parsed, 'evmAddress');
|
|
113
|
+
if (!Number.isFinite(walletId) || !addr) {
|
|
114
|
+
throw new Error('Wallet ensure response missing walletId');
|
|
115
|
+
}
|
|
116
|
+
return { walletId, evmAddress: addr };
|
|
117
|
+
}
|
|
118
|
+
/** Request a challenge to attach a wallet to the authenticated account (Bearer). */
|
|
119
|
+
async function requestWalletAttachChallenge(baseUrl, accessToken, walletId) {
|
|
120
|
+
const url = (0, http_1.normalizeServerUrl)(baseUrl);
|
|
121
|
+
const res = await fetch(`${url}/identity/users/me/wallets/${walletId}/attach/challenge`, { method: 'POST', headers: authHeaders(accessToken) });
|
|
122
|
+
const parsed = await (0, http_1.safeJson)(res);
|
|
123
|
+
if (!res.ok || !parsed || parsed.success !== true) {
|
|
124
|
+
throw new Error((0, http_1.extractError)(parsed, `Attach challenge failed (HTTP ${res.status})`, {
|
|
125
|
+
status: res.status,
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
const challengeId = (0, http_1.pickString)(parsed, 'challengeId');
|
|
129
|
+
const message = (0, http_1.pickString)(parsed, 'message');
|
|
130
|
+
const wid = typeof parsed.walletId === 'number' ? parsed.walletId : Number(parsed.walletId);
|
|
131
|
+
const addr = (0, http_1.pickString)(parsed, 'evmAddress');
|
|
132
|
+
if (!challengeId || !message || !Number.isFinite(wid) || !addr) {
|
|
133
|
+
throw new Error('Attach challenge response missing fields');
|
|
134
|
+
}
|
|
135
|
+
return { challengeId, message, walletId: wid, evmAddress: addr };
|
|
136
|
+
}
|
|
137
|
+
/** Complete a wallet attach with a signature, linking it as primary (Bearer). */
|
|
138
|
+
async function completeWalletAttach(baseUrl, accessToken, walletId, input) {
|
|
139
|
+
const url = (0, http_1.normalizeServerUrl)(baseUrl);
|
|
140
|
+
const res = await fetch(`${url}/identity/users/me/wallets/${walletId}/attach/complete`, {
|
|
141
|
+
method: 'POST',
|
|
142
|
+
headers: authHeaders(accessToken),
|
|
143
|
+
body: JSON.stringify({
|
|
144
|
+
challengeId: input.challengeId,
|
|
145
|
+
evmSignature: input.evmSignature,
|
|
146
|
+
setPrimary: true,
|
|
147
|
+
}),
|
|
148
|
+
});
|
|
149
|
+
const parsed = await (0, http_1.safeJson)(res);
|
|
150
|
+
if (!res.ok || !parsed || parsed.success !== true) {
|
|
151
|
+
throw new Error((0, http_1.extractError)(parsed, `Attach complete failed (HTTP ${res.status})`, {
|
|
152
|
+
status: res.status,
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
const linkId = typeof parsed.linkId === 'number' ? parsed.linkId : Number(parsed.linkId);
|
|
156
|
+
if (!Number.isFinite(linkId)) {
|
|
157
|
+
throw new Error('Attach complete response missing linkId');
|
|
158
|
+
}
|
|
159
|
+
return { linkId };
|
|
160
|
+
}
|
|
161
|
+
/** Fetch the identity-key bundle for a wallet, or `{ found: false }` (Bearer). */
|
|
162
|
+
async function getIdentityKeyBundle(baseUrl, accessToken, walletId) {
|
|
163
|
+
const url = (0, http_1.normalizeServerUrl)(baseUrl);
|
|
164
|
+
const res = await fetch(`${url}/identity/wallets/${walletId}/identity-key`, {
|
|
165
|
+
method: 'GET',
|
|
166
|
+
headers: authHeaders(accessToken),
|
|
167
|
+
});
|
|
168
|
+
if (res.status === 404)
|
|
169
|
+
return { found: false };
|
|
170
|
+
const parsed = await (0, http_1.safeJson)(res);
|
|
171
|
+
if (!res.ok || !parsed || parsed.success !== true) {
|
|
172
|
+
throw new Error((0, http_1.extractError)(parsed, `identity-key GET failed (HTTP ${res.status})`, {
|
|
173
|
+
status: res.status,
|
|
174
|
+
}));
|
|
175
|
+
}
|
|
176
|
+
const ik = parsed.identityKey;
|
|
177
|
+
if (!ik)
|
|
178
|
+
throw new Error('identity-key response missing identityKey');
|
|
179
|
+
const identityKeyId = typeof ik.identityKeyId === 'number' ? ik.identityKeyId : Number(ik.identityKeyId);
|
|
180
|
+
const x25519PublicKey = (0, http_1.pickString)(ik, 'x25519PublicKeyB64', 'x25519PublicKey');
|
|
181
|
+
if (!Number.isFinite(identityKeyId) || !x25519PublicKey) {
|
|
182
|
+
throw new Error('identity-key response incomplete');
|
|
183
|
+
}
|
|
184
|
+
return { found: true, identityKeyId, x25519PublicKey };
|
|
185
|
+
}
|
|
186
|
+
/** Request a challenge to register an identity key for a wallet (Bearer). */
|
|
187
|
+
async function requestIdentityKeyInitChallenge(baseUrl, accessToken, walletId, bundle) {
|
|
188
|
+
const url = (0, http_1.normalizeServerUrl)(baseUrl);
|
|
189
|
+
const res = await fetch(`${url}/identity/wallets/${walletId}/identity-key/init/challenge`, {
|
|
190
|
+
method: 'POST',
|
|
191
|
+
headers: authHeaders(accessToken),
|
|
192
|
+
body: JSON.stringify(challengeBody(bundle)),
|
|
193
|
+
});
|
|
194
|
+
const parsed = await (0, http_1.safeJson)(res);
|
|
195
|
+
if (!res.ok || !parsed || parsed.success !== true) {
|
|
196
|
+
throw new Error((0, http_1.extractError)(parsed, `init challenge failed (HTTP ${res.status})`, {
|
|
197
|
+
status: res.status,
|
|
198
|
+
}));
|
|
199
|
+
}
|
|
200
|
+
const challengeId = (0, http_1.pickString)(parsed, 'challengeId');
|
|
201
|
+
const message = (0, http_1.pickString)(parsed, 'message');
|
|
202
|
+
const evmAddress = (0, http_1.pickString)(parsed, 'evmAddress');
|
|
203
|
+
const wrappedSha256Hex = (0, http_1.pickString)(parsed, 'wrappedSha256Hex');
|
|
204
|
+
if (!challengeId || !message || !evmAddress || !wrappedSha256Hex) {
|
|
205
|
+
throw new Error('init challenge response missing fields');
|
|
206
|
+
}
|
|
207
|
+
return { challengeId, message, evmAddress, wrappedSha256Hex };
|
|
208
|
+
}
|
|
209
|
+
/** Complete identity-key registration with a signature (Bearer). */
|
|
210
|
+
async function completeIdentityKeyInit(baseUrl, accessToken, walletId, bundle, challengeId, evmSignature) {
|
|
211
|
+
const url = (0, http_1.normalizeServerUrl)(baseUrl);
|
|
212
|
+
const res = await fetch(`${url}/identity/wallets/${walletId}/identity-key/init/complete`, {
|
|
213
|
+
method: 'POST',
|
|
214
|
+
headers: authHeaders(accessToken),
|
|
215
|
+
body: JSON.stringify({
|
|
216
|
+
...challengeBody(bundle),
|
|
217
|
+
challengeId,
|
|
218
|
+
evmSignature,
|
|
219
|
+
}),
|
|
220
|
+
});
|
|
221
|
+
const parsed = await (0, http_1.safeJson)(res);
|
|
222
|
+
if (res.status === 409) {
|
|
223
|
+
throw new IdentityKeyConflictError((0, http_1.extractError)(parsed, 'Identity key already exists for this wallet.'));
|
|
224
|
+
}
|
|
225
|
+
if (!res.ok || !parsed || parsed.success !== true) {
|
|
226
|
+
throw new Error((0, http_1.extractError)(parsed, `init complete failed (HTTP ${res.status})`, {
|
|
227
|
+
status: res.status,
|
|
228
|
+
}));
|
|
229
|
+
}
|
|
230
|
+
const ik = parsed.identityKey;
|
|
231
|
+
if (!ik)
|
|
232
|
+
throw new Error('init complete missing identityKey');
|
|
233
|
+
const identityKeyId = typeof ik.identityKeyId === 'number' ? ik.identityKeyId : Number(ik.identityKeyId);
|
|
234
|
+
const x25519PublicKey = (0, http_1.pickString)(ik, 'x25519PublicKeyB64', 'x25519PublicKey');
|
|
235
|
+
if (!Number.isFinite(identityKeyId) || !x25519PublicKey) {
|
|
236
|
+
throw new Error('init complete response incomplete');
|
|
237
|
+
}
|
|
238
|
+
return { identityKeyId, x25519PublicKey };
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=TokenServiceIdentity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TokenServiceIdentity.js","sourceRoot":"","sources":["../../src/token-service/TokenServiceIdentity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared low-level HTTP utilities for the NeoZip Token Service account, funding,
|
|
3
|
+
* and identity client modules.
|
|
4
|
+
*
|
|
5
|
+
* These helpers are intentionally persistence-free and product-agnostic: they
|
|
6
|
+
* speak raw HTTP to the Token Service and surface **generic** errors. Higher
|
|
7
|
+
* layers (CLI / MCP / Desktop) own token storage and may map authentication
|
|
8
|
+
* failures (401/403) to product-specific recovery guidance.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Resolve and normalize a Token Service base URL.
|
|
12
|
+
*
|
|
13
|
+
* Resolution follows {@link getTokenServiceUrl} (explicit URL → env → default),
|
|
14
|
+
* then trailing slashes are stripped so callers can safely append `/path`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function normalizeServerUrl(serverUrl?: string): string;
|
|
17
|
+
/** Parse a JSON body, returning `null` for non-JSON or malformed responses. */
|
|
18
|
+
export declare function safeJson<T>(response: Response): Promise<T | null>;
|
|
19
|
+
/** Return the first non-empty string value among `keys`, else `null`. */
|
|
20
|
+
export declare function pickString(obj: Record<string, unknown>, ...keys: string[]): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Generic authentication-failure message for 401/403 responses. Returns `null`
|
|
23
|
+
* for any other status. Intentionally free of product-specific recovery
|
|
24
|
+
* commands — application layers should add their own guidance.
|
|
25
|
+
*/
|
|
26
|
+
export declare function genericAuthErrorMessage(status: number): string | null;
|
|
27
|
+
/**
|
|
28
|
+
* Extract a human-readable error from a parsed JSON body, preferring `error`
|
|
29
|
+
* then `message`. For 401/403 (when `options.status` is provided) a generic
|
|
30
|
+
* auth message is returned instead.
|
|
31
|
+
*/
|
|
32
|
+
export declare function extractError(parsed: unknown, fallback: string, options?: {
|
|
33
|
+
status?: number;
|
|
34
|
+
}): string;
|
|
35
|
+
/**
|
|
36
|
+
* Derive an access-token expiry (epoch milliseconds) from a verify/login
|
|
37
|
+
* response body. Supports both absolute `expiresAt` (seconds or ms) and
|
|
38
|
+
* relative `expiresIn` (seconds). Returns `null` when neither is present.
|
|
39
|
+
*/
|
|
40
|
+
export declare function parseAccessTokenExpiry(parsed: Record<string, unknown>): number | null;
|
|
41
|
+
/**
|
|
42
|
+
* Turn a thrown `fetch` error into a friendly, actionable message. Network-level
|
|
43
|
+
* failures point at the unreachable base URL; everything else is passed through.
|
|
44
|
+
*/
|
|
45
|
+
export declare function formatTokenServiceFetchError(baseUrl: string, err: unknown): string;
|
|
46
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/token-service/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,+EAA+E;AAC/E,wBAAsB,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAQvE;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,GAAG,IAAI,EAAE,MAAM,EAAE,GAChB,MAAM,GAAG,IAAI,CAMf;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGrE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5B,MAAM,CAUR;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,MAAM,GAAG,IAAI,CAUf;AAUD;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAalF"}
|