@a2afoundation/ans-registrar-sdk 0.0.0-stage → 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 CHANGED
@@ -1,3 +1,69 @@
1
- # Temporary Holding Version
1
+ # @a2afoundation/ans-registrar-sdk
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Registrar SDK for the A2A Agent Name Service. Channel calls use the registrar's issued credential key. Names belong to the customer's ANS account; a participant ID is only a resolution target.
4
+
5
+ ## 生成凭证密钥对
6
+
7
+ 在注册商自己的系统中运行以下 Node.js 示例。`generateKeypair()` 返回 `privateKey`、`publicKey` 和 `participantId`。私钥只保存在注册商自己的安全存储中,不要提交到代码库,不要上传到 ANS。示例只输出公钥标识。
8
+
9
+ ```ts
10
+ import { generateKeypair } from '@a2afoundation/ans-registrar-sdk';
11
+
12
+ const keypair = await generateKeypair();
13
+ // Keep keypair.privateKey only in your own secure system.
14
+ // Never commit it to a repository or upload it to ANS.
15
+ // Paste only this public identifier into the console Credentials page:
16
+ console.log(keypair.participantId);
17
+ ```
18
+
19
+ 把 `participantId` 填入注册商控制台「凭证」页的「公钥(participant_id)」字段。ANS 只保存公钥。后续请求签名时,从注册商自己的安全存储加载密钥对。
20
+
21
+ ## 调用渠道接口
22
+
23
+ ```ts
24
+ import { AnsRegistrarClient } from '@a2afoundation/ans-registrar-sdk';
25
+
26
+ const client = new AnsRegistrarClient({
27
+ baseUrl: 'https://a2ans.io',
28
+ signingKey: registrarCredentialKeypair, // Load securely; never embed the private key.
29
+ });
30
+
31
+ // Fund the registrar prepaid balance first. International: email; China: +86 phone.
32
+ const registered = await client.registerForCustomer(
33
+ 'customername',
34
+ { email: 'alice@example.com' },
35
+ { durationYears: 1, idempotencyKey: 'registration-order-123' },
36
+ );
37
+ console.log(registered.tx_id, registered.charged, registered.balance_after);
38
+
39
+ // Reuse the same key AND request on retry. Use fresh keys for different operations.
40
+ const retried = await client.registerForCustomer(
41
+ 'customername',
42
+ { email: 'alice@example.com' },
43
+ { durationYears: 1, idempotencyKey: registered.idempotencyKey },
44
+ );
45
+
46
+ const renewed = await client.renewForCustomer('customername', { durationYears: 1 });
47
+ // Automatically generated keys are returned for reuse on retry.
48
+ console.log(renewed.idempotencyKey);
49
+ await client.setNameTarget('customername', null);
50
+
51
+ const page = await client.listNames({ limit: 20 });
52
+ if (page.next_cursor) await client.listNames({ cursor: page.next_cursor, limit: 20 });
53
+ await client.getName('customername');
54
+ await client.getBalance();
55
+ await client.listLedger({ limit: 20 });
56
+ await client.listInvoices({ limit: 20 });
57
+ ```
58
+
59
+ `registerForCustomer` takes `{ email }` on the international site or `{ phone: '+8613812341234' }` on the China site. `participantId` is optional in its options. The old customer participant-ID argument and `paymentProofRef` option are replaced. The server debits prepaid balance at the registrar purchase price and returns no customer account ID or account-creation flag. Only ordinary names are available.
60
+
61
+ All channel writes require an 8–128 visible ASCII `Idempotency-Key`. Write methods generate a random key if omitted and return it as `idempotencyKey`. Errors also carry `idempotencyKey`, including network failures; retain it when retrying. `AnsRegistrarError` carries `status`, `errorCode`, and the raw response `body`. Reusing a key with different request content returns HTTP 409 `IDEMPOTENCY_CONFLICT`.
62
+
63
+ An optional `targetConsent: { privateKey, publicKey }` on `registerForCustomer` or `setNameTarget` produces the independent target cosignature headers. Omit it to leave the target unconfirmed. Keep target private keys under the target owner's control; target consent is optional and requires that owner's authorization.
64
+
65
+ Read methods sign the path including encoded query parameters and send no GET body. Pages accept `cursor` and `limit` (1–100, default 20); `next_cursor: null` ends the list. Amounts are decimal strings in CNY or USD. Name responses contain masked customer contact details.
66
+
67
+ The existing self-service `register`, `renew`, `bind`, `release`, and transfer methods keep their contracts. The SDK uses the registry's `A2A-ANS-v1` canonical signing format and depends only on `@noble/*` and `@scure/base`.
68
+
69
+ Run `npm run sdk:pack` and `npm run sdk:smoke` from the repository root to verify the package locally. These commands do not publish to npm. Full channel/admin contracts and financial transaction rules: [docs/23](../../docs/23-registrar-billing-and-channel-api.md).
@@ -0,0 +1,190 @@
1
+ type FetchResponse = {
2
+ ok: boolean;
3
+ status: number;
4
+ text(): Promise<string>;
5
+ };
6
+ type FetchLike = (url: string, init: {
7
+ method: string;
8
+ headers: Record<string, string>;
9
+ body?: string;
10
+ }) => Promise<FetchResponse>;
11
+ export interface AnsRegistrarClientOptions {
12
+ /** ANS 注册局基址,如 https://a2ans.io 。 */
13
+ baseUrl: string;
14
+ /** 签名密钥:名字持有者自己的密钥,或注册商的渠道凭证密钥。 */
15
+ signingKey: {
16
+ privateKey: Uint8Array;
17
+ publicKey: Uint8Array;
18
+ };
19
+ fetchImpl?: FetchLike;
20
+ /** 当前 Unix 秒(测试可注入)。 */
21
+ now?: () => number;
22
+ }
23
+ export declare class AnsRegistrarError extends Error {
24
+ readonly status: number;
25
+ readonly errorCode: string;
26
+ readonly body: string;
27
+ idempotencyKey?: string | undefined;
28
+ constructor(status: number, errorCode: string, body: string, idempotencyKey?: string | undefined);
29
+ }
30
+ export type RegistrarCustomer = {
31
+ email: string;
32
+ phone?: never;
33
+ } | {
34
+ phone: string;
35
+ email?: never;
36
+ };
37
+ export interface RegistrarMoney {
38
+ amount: string;
39
+ currency: 'CNY' | 'USD';
40
+ }
41
+ export interface IdempotentResult {
42
+ idempotencyKey: string;
43
+ }
44
+ export interface RegistrarPageOptions {
45
+ cursor?: string;
46
+ limit?: number;
47
+ }
48
+ export interface TargetConsent {
49
+ privateKey: Uint8Array;
50
+ publicKey: Uint8Array;
51
+ }
52
+ export interface RegistrarRenewal {
53
+ name: string;
54
+ expires_at: string;
55
+ registrar_id: string;
56
+ tx_id: string;
57
+ charged: RegistrarMoney;
58
+ balance_after: RegistrarMoney;
59
+ }
60
+ export interface RegistrarRegistration extends RegistrarRenewal {
61
+ tier: 'standard';
62
+ target: string | null;
63
+ target_confirmed: boolean;
64
+ }
65
+ export interface RegistrarName {
66
+ name: string;
67
+ status: string;
68
+ registered_at: string;
69
+ expires_at: string;
70
+ target: string | null;
71
+ target_confirmed: boolean;
72
+ customer: {
73
+ email?: string;
74
+ phone?: string;
75
+ };
76
+ }
77
+ export interface RegistrarLedgerItem {
78
+ entry_id: string;
79
+ type: 'topup_online' | 'topup_offline' | 'register_debit' | 'renew_debit' | 'refund_credit' | 'adjustment' | 'exit_refund';
80
+ amount: string;
81
+ currency: string;
82
+ balance_after: string;
83
+ ref_id: string;
84
+ actor: string;
85
+ reason: string;
86
+ created_at: string;
87
+ }
88
+ export interface RegistrarInvoice {
89
+ tx_id: string;
90
+ txId: string;
91
+ kind: string;
92
+ amount: string;
93
+ currency: string;
94
+ registrarId?: string;
95
+ label?: string;
96
+ createdAt: string;
97
+ [key: string]: unknown;
98
+ }
99
+ export declare class AnsRegistrarClient {
100
+ /** 本客户端签名身份(自助=持有者;代客=注册商渠道凭证)。 */
101
+ readonly participantId: string;
102
+ private readonly baseUrl;
103
+ private readonly privateKey;
104
+ private readonly fetchImpl;
105
+ private readonly now;
106
+ constructor(opts: AnsRegistrarClientOptions);
107
+ /** 便捷构造:从 32 字节私钥种子派生公钥。 */
108
+ static fromPrivateKey(baseUrl: string, privateKey: Uint8Array, fetchImpl?: FetchLike): Promise<AnsRegistrarClient>;
109
+ private handle;
110
+ private send;
111
+ /** 注册名字。`target` 缺省 = 自绑定到本签名身份(自助注册)。`paymentProofRef` = D 组支付承诺存证引用。 */
112
+ register(name: string, opts: {
113
+ durationYears: number;
114
+ paymentProofRef: string;
115
+ target?: string;
116
+ }): Promise<unknown>;
117
+ /** Registrar prepaid registration. The customer contact owns the name; participantId is only its target. */
118
+ registerForCustomer(name: string, customer: RegistrarCustomer, opts: {
119
+ durationYears: number;
120
+ participantId?: string;
121
+ idempotencyKey?: string;
122
+ targetConsent?: TargetConsent;
123
+ }): Promise<RegistrarRegistration & IdempotentResult>;
124
+ renewForCustomer(name: string, opts: {
125
+ durationYears: number;
126
+ idempotencyKey?: string;
127
+ }): Promise<RegistrarRenewal & IdempotentResult>;
128
+ setNameTarget(name: string, participantId: string | null, opts?: {
129
+ idempotencyKey?: string;
130
+ targetConsent?: TargetConsent;
131
+ }): Promise<{
132
+ name: string;
133
+ target: string | null;
134
+ target_confirmed: boolean;
135
+ } & IdempotentResult>;
136
+ private channelWrite;
137
+ private pagePath;
138
+ listNames(options?: RegistrarPageOptions): Promise<{
139
+ names: RegistrarName[];
140
+ next_cursor: string | null;
141
+ }>;
142
+ getName(name: string): Promise<RegistrarName>;
143
+ getBalance(): Promise<{
144
+ registrar_id: string;
145
+ balance: RegistrarMoney;
146
+ purchase_price: RegistrarMoney;
147
+ }>;
148
+ listLedger(options?: RegistrarPageOptions): Promise<{
149
+ entries: RegistrarLedgerItem[];
150
+ next_cursor: string | null;
151
+ }>;
152
+ listInvoices(options?: RegistrarPageOptions): Promise<{
153
+ registrar_id: string;
154
+ count: number;
155
+ invoices: RegistrarInvoice[];
156
+ next_cursor: string | null;
157
+ }>;
158
+ /** 设置/解除解析目标(target=null 解绑)。 */
159
+ bind(name: string, target: string | null): Promise<unknown>;
160
+ /** 续费。 */
161
+ renew(name: string, opts: {
162
+ durationYears: number;
163
+ paymentProofRef: string;
164
+ }): Promise<unknown>;
165
+ /** 释放(已付费用不退)。 */
166
+ release(name: string): Promise<unknown>;
167
+ /**
168
+ * 即时双签过户(key↔key):当前 owner(本客户端)+ 新 owner 共签。
169
+ * 需要新 owner 的密钥来共签(新 owner 对同一 nonce/timestamp/body 以自身 pid 再签)。
170
+ * 已绑 2FA 的 owner 须传 twofa 动态码(FR-AUTH-6)。
171
+ */
172
+ transfer(name: string, newOwner: {
173
+ privateKey: Uint8Array;
174
+ publicKey: Uint8Array;
175
+ }, opts?: {
176
+ twofa?: string;
177
+ }): Promise<unknown>;
178
+ /** 两步过户·发起(M2,支持账号收件人):指定收件人邮箱或 participant_id;返回 transfer_id。 */
179
+ initiateTransfer(name: string, to: {
180
+ toEmail?: string;
181
+ toParticipantId?: string;
182
+ }, opts?: {
183
+ twofa?: string;
184
+ }): Promise<unknown>;
185
+ /** 两步过户·接受(本客户端 = 收件人)。 */
186
+ acceptTransfer(transferId: string): Promise<unknown>;
187
+ /** 两步过户·取消(发起方或收件人均可)。 */
188
+ cancelTransfer(transferId: string): Promise<unknown>;
189
+ }
190
+ export {};
package/dist/client.js ADDED
@@ -0,0 +1,197 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ /**
3
+ * 注册方 SDK 客户端:封装「签名 + 调 ANS 注册局写端点」,让注册商/名字持有者不必手搓签名。
4
+ *
5
+ * 两类用法:
6
+ * - 名字持有者自助:register / bind / renew / release(用自己的密钥签)。
7
+ * - 注册服务商代客注册:registerForCustomer(用注册商渠道凭证签名,提交客户联系方式,
8
+ * 服务端按进货价扣预存款;客户账号持有,participant_id 只作解析目标;见 docs/23)。
9
+ *
10
+ * 校验不过/被拒一律抛 AnsRegistrarError(含服务端 error_code)。
11
+ */
12
+ import { getPublicKeyAsync } from '@noble/ed25519';
13
+ import { encodeParticipantId, signRequest, cosignRequest } from './signing.js';
14
+ export class AnsRegistrarError extends Error {
15
+ status;
16
+ errorCode;
17
+ body;
18
+ idempotencyKey;
19
+ constructor(status, errorCode, body, idempotencyKey) {
20
+ super(`${errorCode} (HTTP ${status})`);
21
+ this.status = status;
22
+ this.errorCode = errorCode;
23
+ this.body = body;
24
+ this.idempotencyKey = idempotencyKey;
25
+ this.name = 'AnsRegistrarError';
26
+ }
27
+ }
28
+ export class AnsRegistrarClient {
29
+ /** 本客户端签名身份(自助=持有者;代客=注册商渠道凭证)。 */
30
+ participantId;
31
+ baseUrl;
32
+ privateKey;
33
+ fetchImpl;
34
+ now;
35
+ constructor(opts) {
36
+ this.baseUrl = opts.baseUrl.replace(/\/$/, '');
37
+ this.privateKey = opts.signingKey.privateKey;
38
+ this.participantId = encodeParticipantId(opts.signingKey.publicKey);
39
+ this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetch(url, init));
40
+ this.now = opts.now;
41
+ }
42
+ /** 便捷构造:从 32 字节私钥种子派生公钥。 */
43
+ static async fromPrivateKey(baseUrl, privateKey, fetchImpl) {
44
+ const publicKey = await getPublicKeyAsync(privateKey);
45
+ return new AnsRegistrarClient({ baseUrl, signingKey: { privateKey, publicKey }, ...(fetchImpl ? { fetchImpl } : {}) });
46
+ }
47
+ async handle(res) {
48
+ const text = await res.text();
49
+ if (!res.ok) {
50
+ let errorCode = `HTTP_${res.status}`;
51
+ try {
52
+ errorCode = JSON.parse(text).error_code ?? errorCode;
53
+ }
54
+ catch {
55
+ /* non-JSON body */
56
+ }
57
+ throw new AnsRegistrarError(res.status, errorCode, text);
58
+ }
59
+ return text ? JSON.parse(text) : {};
60
+ }
61
+ async send(method, path, bodyObj, extraHeaders = {}) {
62
+ const body = method === 'GET' ? '' : JSON.stringify(bodyObj ?? {});
63
+ const bodyBytes = new TextEncoder().encode(body);
64
+ const headers = await signRequest({
65
+ method,
66
+ path,
67
+ bodyBytes,
68
+ privateKey: this.privateKey,
69
+ participantId: this.participantId,
70
+ ...(this.now ? { nowEpochSec: this.now() } : {}),
71
+ });
72
+ const res = await this.fetchImpl(this.baseUrl + path, {
73
+ method,
74
+ headers: { 'content-type': 'application/json', ...headers, ...extraHeaders },
75
+ ...(method === 'GET' ? {} : { body }),
76
+ });
77
+ return this.handle(res);
78
+ }
79
+ /** 注册名字。`target` 缺省 = 自绑定到本签名身份(自助注册)。`paymentProofRef` = D 组支付承诺存证引用。 */
80
+ async register(name, opts) {
81
+ return this.send('POST', '/v1/ans/register', { name, participant_id: opts.target ?? this.participantId, duration_years: opts.durationYears }, { 'x-ans-payment-proof': opts.paymentProofRef });
82
+ }
83
+ /** Registrar prepaid registration. The customer contact owns the name; participantId is only its target. */
84
+ async registerForCustomer(name, customer, opts) {
85
+ const body = { name, customer, duration_years: opts.durationYears, ...(opts.participantId ? { participant_id: opts.participantId } : {}) };
86
+ return this.channelWrite('POST', '/v1/channel/register', body, opts);
87
+ }
88
+ async renewForCustomer(name, opts) {
89
+ return this.channelWrite('POST', '/v1/channel/renew', { name, duration_years: opts.durationYears }, opts);
90
+ }
91
+ async setNameTarget(name, participantId, opts = {}) {
92
+ return this.channelWrite('PUT', `/v1/channel/names/${encodeURIComponent(name)}/target`, { participant_id: participantId }, opts);
93
+ }
94
+ async channelWrite(method, path, body, opts) {
95
+ const key = opts.idempotencyKey ?? randomBytes(24).toString('hex');
96
+ if (!/^[!-~]{8,128}$/.test(key))
97
+ throw new Error('idempotencyKey must be 8–128 visible ASCII characters');
98
+ const headers = { 'idempotency-key': key };
99
+ if (opts.targetConsent) {
100
+ const consent = await signRequest({ method, path, bodyBytes: new TextEncoder().encode(JSON.stringify(body)), privateKey: opts.targetConsent.privateKey, participantId: encodeParticipantId(opts.targetConsent.publicKey), ...(this.now ? { nowEpochSec: this.now() } : {}) });
101
+ headers['x-ans-cosign-participant'] = consent['x-ans-participant'];
102
+ headers['x-ans-cosign-nonce'] = consent['x-ans-nonce'];
103
+ headers['x-ans-cosign-timestamp'] = consent['x-ans-timestamp'];
104
+ headers['x-ans-cosign-signature'] = consent['x-ans-signature'];
105
+ }
106
+ try {
107
+ return { ...await this.send(method, path, body, headers), idempotencyKey: key };
108
+ }
109
+ catch (error) {
110
+ // Keep the generated key available even when the network failed before a response.
111
+ if (error && typeof error === 'object')
112
+ Object.assign(error, { idempotencyKey: key });
113
+ throw error;
114
+ }
115
+ }
116
+ pagePath(path, options) {
117
+ const query = new URLSearchParams();
118
+ if (options.cursor !== undefined)
119
+ query.set('cursor', options.cursor);
120
+ if (options.limit !== undefined)
121
+ query.set('limit', String(options.limit));
122
+ return query.size ? `${path}?${query.toString()}` : path;
123
+ }
124
+ async listNames(options = {}) {
125
+ return await this.send('GET', this.pagePath('/v1/channel/names', options), undefined);
126
+ }
127
+ async getName(name) { return await this.send('GET', `/v1/channel/names/${encodeURIComponent(name)}`, undefined); }
128
+ async getBalance() {
129
+ return await this.send('GET', '/v1/channel/balance', undefined);
130
+ }
131
+ async listLedger(options = {}) {
132
+ return await this.send('GET', this.pagePath('/v1/channel/ledger', options), undefined);
133
+ }
134
+ async listInvoices(options = {}) {
135
+ return await this.send('GET', this.pagePath('/v1/channel/invoices', options), undefined);
136
+ }
137
+ /** 设置/解除解析目标(target=null 解绑)。 */
138
+ async bind(name, target) {
139
+ return this.send('POST', '/v1/ans/bind', { name, target });
140
+ }
141
+ /** 续费。 */
142
+ async renew(name, opts) {
143
+ return this.send('POST', '/v1/ans/renew', { name, duration_years: opts.durationYears }, { 'x-ans-payment-proof': opts.paymentProofRef });
144
+ }
145
+ /** 释放(已付费用不退)。 */
146
+ async release(name) {
147
+ return this.send('DELETE', '/v1/ans/release', { name });
148
+ }
149
+ /**
150
+ * 即时双签过户(key↔key):当前 owner(本客户端)+ 新 owner 共签。
151
+ * 需要新 owner 的密钥来共签(新 owner 对同一 nonce/timestamp/body 以自身 pid 再签)。
152
+ * 已绑 2FA 的 owner 须传 twofa 动态码(FR-AUTH-6)。
153
+ */
154
+ async transfer(name, newOwner, opts = {}) {
155
+ const method = 'POST';
156
+ const path = '/v1/ans/transfer';
157
+ const newOwnerPid = encodeParticipantId(newOwner.publicKey);
158
+ const body = JSON.stringify({ name, new_owner: newOwnerPid });
159
+ const bodyBytes = new TextEncoder().encode(body);
160
+ const primary = await signRequest({
161
+ method,
162
+ path,
163
+ bodyBytes,
164
+ privateKey: this.privateKey,
165
+ participantId: this.participantId,
166
+ ...(this.now ? { nowEpochSec: this.now() } : {}),
167
+ });
168
+ const cosign = await cosignRequest({
169
+ method,
170
+ path,
171
+ bodyBytes,
172
+ cosignerPrivateKey: newOwner.privateKey,
173
+ cosignerParticipantId: newOwnerPid,
174
+ nonce: primary['x-ans-nonce'], // 共签复用主签的 nonce/timestamp
175
+ timestamp: primary['x-ans-timestamp'],
176
+ });
177
+ const res = await this.fetchImpl(this.baseUrl + path, {
178
+ method,
179
+ headers: { 'content-type': 'application/json', ...primary, ...cosign, ...(opts.twofa ? { 'x-ans-2fa': opts.twofa } : {}) },
180
+ body,
181
+ });
182
+ return this.handle(res);
183
+ }
184
+ /** 两步过户·发起(M2,支持账号收件人):指定收件人邮箱或 participant_id;返回 transfer_id。 */
185
+ async initiateTransfer(name, to, opts = {}) {
186
+ return this.send('POST', '/v1/ans/transfer/initiate', { name, ...(to.toEmail ? { to_email: to.toEmail } : {}), ...(to.toParticipantId ? { to_participant_id: to.toParticipantId } : {}) }, opts.twofa ? { 'x-ans-2fa': opts.twofa } : {});
187
+ }
188
+ /** 两步过户·接受(本客户端 = 收件人)。 */
189
+ async acceptTransfer(transferId) {
190
+ return this.send('POST', '/v1/ans/transfer/accept', { transfer_id: transferId });
191
+ }
192
+ /** 两步过户·取消(发起方或收件人均可)。 */
193
+ async cancelTransfer(transferId) {
194
+ return this.send('POST', '/v1/ans/transfer/cancel', { transfer_id: transferId });
195
+ }
196
+ }
197
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/sdk/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * ANS 注册方 SDK(@noble/@scure 自包含):请求签名 + AnsRegistrarClient(注册/绑定/续费/释放/代客注册)。
3
+ * 解析+校验是另一侧能力,见 ans-resolver 的客户端 SDK(`ans-resolver/client`)。
4
+ */
5
+ export * from './signing.js';
6
+ export * from './client.js';
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * ANS 注册方 SDK(@noble/@scure 自包含):请求签名 + AnsRegistrarClient(注册/绑定/续费/释放/代客注册)。
3
+ * 解析+校验是另一侧能力,见 ans-resolver 的客户端 SDK(`ans-resolver/client`)。
4
+ */
5
+ export * from './signing.js';
6
+ export * from './client.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sdk/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * 注册方 SDK —— 请求签名(OQ-5,与服务端 auth/signing.ts 同 canonical 格式 A2A-ANS-v1)。
3
+ *
4
+ * 自包含:仅依赖 @noble/@scure,不引入服务端任何模块(config/store 等),便于外部注册商安装即用。
5
+ * 格式正确性由 test/sdk/registrar.test.ts 用服务端真实 verifyRequestSignature 交叉校验守护,杜绝漂移。
6
+ */
7
+ /** 32 字节原始公钥 → participant_id(`a2a:z…`)。 */
8
+ export declare function encodeParticipantId(publicKey: Uint8Array): string;
9
+ export interface Keypair {
10
+ privateKey: Uint8Array;
11
+ publicKey: Uint8Array;
12
+ participantId: string;
13
+ }
14
+ /** 生成一对新 Ed25519 密钥(私钥 32 字节种子)。 */
15
+ export declare function generateKeypair(): Promise<Keypair>;
16
+ /** 构造规范化请求字节(与服务端逐字节一致)。 */
17
+ export declare function canonicalRequest(input: {
18
+ method: string;
19
+ path: string;
20
+ bodyBytes: Uint8Array;
21
+ participantId: string;
22
+ nonce: string;
23
+ timestamp: string;
24
+ }): Uint8Array;
25
+ /** 请求签名头(附到 HTTP 请求)。 */
26
+ export interface SignedHeaders {
27
+ 'x-ans-participant': string;
28
+ 'x-ans-nonce': string;
29
+ 'x-ans-timestamp': string;
30
+ 'x-ans-signature': string;
31
+ }
32
+ /** 用私钥对请求签名,返回 x-ans-* 头。nonce/timestamp 可注入(测试),否则随机/当前。 */
33
+ export declare function signRequest(input: {
34
+ method: string;
35
+ path: string;
36
+ bodyBytes: Uint8Array;
37
+ privateKey: Uint8Array;
38
+ participantId: string;
39
+ nowEpochSec?: number;
40
+ nonce?: string;
41
+ }): Promise<SignedHeaders>;
42
+ /** 共签头(transfer 双签:新 owner 对**同一** nonce/timestamp/body 的 canonical 以自身 pid 再签)。 */
43
+ export interface CosignHeaders {
44
+ 'x-ans-cosign-participant': string;
45
+ 'x-ans-cosign-signature': string;
46
+ }
47
+ export declare function cosignRequest(input: {
48
+ method: string;
49
+ path: string;
50
+ bodyBytes: Uint8Array;
51
+ cosignerPrivateKey: Uint8Array;
52
+ cosignerParticipantId: string;
53
+ nonce: string;
54
+ timestamp: string;
55
+ }): Promise<CosignHeaders>;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * 注册方 SDK —— 请求签名(OQ-5,与服务端 auth/signing.ts 同 canonical 格式 A2A-ANS-v1)。
3
+ *
4
+ * 自包含:仅依赖 @noble/@scure,不引入服务端任何模块(config/store 等),便于外部注册商安装即用。
5
+ * 格式正确性由 test/sdk/registrar.test.ts 用服务端真实 verifyRequestSignature 交叉校验守护,杜绝漂移。
6
+ */
7
+ import { getPublicKeyAsync, signAsync } from '@noble/ed25519';
8
+ import { sha256 } from '@noble/hashes/sha256';
9
+ import { bytesToHex } from '@noble/hashes/utils';
10
+ import { base58 } from '@scure/base';
11
+ import { randomBytes } from 'node:crypto';
12
+ const PARTICIPANT_PREFIX = 'a2a:z';
13
+ const CANONICAL_VERSION = 'A2A-ANS-v1';
14
+ const UTF8 = new TextEncoder();
15
+ /** 32 字节原始公钥 → participant_id(`a2a:z…`)。 */
16
+ export function encodeParticipantId(publicKey) {
17
+ return PARTICIPANT_PREFIX + base58.encode(publicKey);
18
+ }
19
+ /** 生成一对新 Ed25519 密钥(私钥 32 字节种子)。 */
20
+ export async function generateKeypair() {
21
+ const privateKey = Uint8Array.from(randomBytes(32));
22
+ const publicKey = await getPublicKeyAsync(privateKey);
23
+ return { privateKey, publicKey, participantId: encodeParticipantId(publicKey) };
24
+ }
25
+ /** 构造规范化请求字节(与服务端逐字节一致)。 */
26
+ export function canonicalRequest(input) {
27
+ return UTF8.encode(`${CANONICAL_VERSION}\n${input.method.toUpperCase()}\n${input.path}\n${bytesToHex(sha256(input.bodyBytes))}\n${input.participantId}\n${input.nonce}\n${input.timestamp}`);
28
+ }
29
+ /** 用私钥对请求签名,返回 x-ans-* 头。nonce/timestamp 可注入(测试),否则随机/当前。 */
30
+ export async function signRequest(input) {
31
+ const timestamp = String(input.nowEpochSec ?? Math.floor(Date.now() / 1000));
32
+ const nonce = input.nonce ?? base58.encode(Uint8Array.from(randomBytes(16)));
33
+ const sig = await signAsync(canonicalRequest({ method: input.method, path: input.path, bodyBytes: input.bodyBytes, participantId: input.participantId, nonce, timestamp }), input.privateKey);
34
+ return {
35
+ 'x-ans-participant': input.participantId,
36
+ 'x-ans-nonce': nonce,
37
+ 'x-ans-timestamp': timestamp,
38
+ 'x-ans-signature': Buffer.from(sig).toString('base64'),
39
+ };
40
+ }
41
+ export async function cosignRequest(input) {
42
+ const sig = await signAsync(canonicalRequest({ method: input.method, path: input.path, bodyBytes: input.bodyBytes, participantId: input.cosignerParticipantId, nonce: input.nonce, timestamp: input.timestamp }), input.cosignerPrivateKey);
43
+ return { 'x-ans-cosign-participant': input.cosignerParticipantId, 'x-ans-cosign-signature': Buffer.from(sig).toString('base64') };
44
+ }
45
+ //# sourceMappingURL=signing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signing.js","sourceRoot":"","sources":["../../../src/sdk/signing.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,36 @@
1
1
  {
2
2
  "name": "@a2afoundation/ans-registrar-sdk",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Registrar SDK for the A2A Agent Name Service.",
5
+ "type": "module",
6
+ "private": false,
7
+ "sideEffects": false,
8
+ "engines": {
9
+ "node": ">=20"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "types": "./dist/index.d.ts",
18
+ "main": "./dist/index.js",
19
+ "files": [
20
+ "dist",
21
+ "README.md"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsc -p tsconfig.json",
25
+ "pack:dry-run": "npm pack --dry-run",
26
+ "prepack": "npm run build"
27
+ },
28
+ "dependencies": {
29
+ "@noble/ed25519": "^2.1.0",
30
+ "@noble/hashes": "^1.4.0",
31
+ "@scure/base": "^1.1.6"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ }
36
+ }