@ghostgate/sdk 0.1.2 → 0.1.3

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
@@ -38,6 +38,9 @@ const sdk = new GhostAgent({
38
38
  privateKey: process.env.GHOST_SIGNER_PRIVATE_KEY as `0x${string}`,
39
39
  baseUrl: process.env.GHOST_BASE_URL,
40
40
  serviceSlug: "agent-18755",
41
+ // Optional x402 compatibility mode:
42
+ // authMode: "x402",
43
+ // x402Scheme: "ghost-eip712-credit-v1",
41
44
  });
42
45
 
43
46
  await sdk.connect();
package/dist/index.d.ts CHANGED
@@ -9,6 +9,8 @@ export type GhostAgentConfig = {
9
9
  chainId?: number;
10
10
  serviceSlug?: string;
11
11
  creditCost?: number;
12
+ authMode?: "ghost-eip712" | "x402";
13
+ x402Scheme?: string;
12
14
  };
13
15
  export type ConnectResult = {
14
16
  connected: boolean;
@@ -16,6 +18,10 @@ export type ConnectResult = {
16
18
  endpoint: string;
17
19
  status: number;
18
20
  payload: unknown;
21
+ x402?: {
22
+ paymentRequired: unknown | null;
23
+ paymentResponse: unknown | null;
24
+ };
19
25
  };
20
26
  export type TelemetryResult = {
21
27
  ok: boolean;
@@ -48,6 +54,44 @@ export type CanaryPayload = {
48
54
  };
49
55
  export type GhostMerchantConfig = GhostFulfillmentMerchantConfig & {
50
56
  serviceSlug: string;
57
+ ownerPrivateKey?: `0x${string}`;
58
+ };
59
+ type MerchantGatewayConfigResponse = {
60
+ configured: boolean;
61
+ config: {
62
+ ownerAddress: string;
63
+ readinessStatus: "UNCONFIGURED" | "CONFIGURED" | "LIVE" | "DEGRADED";
64
+ };
65
+ };
66
+ type MerchantGatewayVerifyResponse = {
67
+ verified?: boolean;
68
+ readinessStatus?: "UNCONFIGURED" | "CONFIGURED" | "LIVE" | "DEGRADED";
69
+ error?: string;
70
+ canaryUrl?: string;
71
+ statusCode?: number | null;
72
+ latencyMs?: number | null;
73
+ };
74
+ type MerchantGatewayDelegatedSignerRegisterResponse = {
75
+ ok?: boolean;
76
+ created?: boolean;
77
+ alreadyActive?: boolean;
78
+ error?: string;
79
+ };
80
+ export type MerchantActivateOptions = {
81
+ agentId: string;
82
+ serviceSlug: string;
83
+ endpointUrl: string;
84
+ canaryPath?: string;
85
+ canaryMethod?: string;
86
+ signerLabel?: string;
87
+ };
88
+ export type ActivateResult = {
89
+ status: "LIVE";
90
+ readiness: "LIVE";
91
+ config: MerchantGatewayConfigResponse["config"];
92
+ verify: MerchantGatewayVerifyResponse;
93
+ signerRegistration: MerchantGatewayDelegatedSignerRegisterResponse;
94
+ heartbeat: HeartbeatController;
51
95
  };
52
96
  export declare const buildCanaryPayload: (serviceSlug: string) => CanaryPayload;
53
97
  export declare const createCanaryHandler: (serviceSlug: string) => (_req?: unknown, res?: unknown) => unknown;
@@ -60,6 +104,8 @@ export declare class GhostAgent {
60
104
  private readonly telemetryServiceSlug;
61
105
  private readonly serviceSlug;
62
106
  private readonly creditCost;
107
+ private readonly authMode;
108
+ private readonly x402Scheme;
63
109
  constructor(config?: GhostAgentConfig);
64
110
  connect(apiKey?: string): Promise<ConnectResult>;
65
111
  pulse(input?: PulseInput): Promise<TelemetryResult>;
@@ -70,9 +116,18 @@ export declare class GhostAgent {
70
116
  }
71
117
  export declare class GhostMerchant extends GhostFulfillmentMerchant {
72
118
  private readonly merchantServiceSlug;
119
+ private readonly merchantBaseUrl;
120
+ private readonly ownerPrivateKey;
121
+ private readonly ownerAddress;
122
+ private readonly delegatedSignerAddress;
123
+ private heartbeatController;
73
124
  constructor(config: GhostMerchantConfig);
74
125
  canaryPayload(): CanaryPayload;
75
126
  canaryHandler(): (_req?: unknown, res?: unknown) => unknown;
127
+ activate(options: MerchantActivateOptions): Promise<ActivateResult>;
128
+ private fetchGatewayOwnerConfig;
129
+ private postMerchantSignedWrite;
130
+ private extractApiErrorMessage;
76
131
  }
77
132
  export default GhostAgent;
78
133
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -7,6 +7,13 @@ const DEFAULT_CHAIN_ID = 8453;
7
7
  const DEFAULT_SERVICE_SLUG = "connect";
8
8
  const DEFAULT_CREDIT_COST = 1;
9
9
  const DEFAULT_HEARTBEAT_INTERVAL_MS = 60000;
10
+ const DEFAULT_AUTH_MODE = "ghost-eip712";
11
+ const DEFAULT_X402_SCHEME = "ghost-eip712-credit-v1";
12
+ const DEFAULT_ACTIVATE_CANARY_PATH = "/health";
13
+ const DEFAULT_ACTIVATE_CANARY_METHOD = "GET";
14
+ const DEFAULT_ACTIVATE_SIGNER_LABEL = "sdk-auto";
15
+ const MERCHANT_GATEWAY_AUTH_SCOPE = "agent_gateway";
16
+ const MERCHANT_GATEWAY_AUTH_VERSION = "1";
10
17
  const ACCESS_TYPES = {
11
18
  Access: [
12
19
  { name: "service", type: "string" },
@@ -32,6 +39,18 @@ const parsePayload = async (response) => {
32
39
  return null;
33
40
  }
34
41
  };
42
+ const encodeBase64Json = (value) => Buffer.from(JSON.stringify(value), "utf8").toString("base64");
43
+ const decodeBase64Json = (value) => {
44
+ if (!value)
45
+ return null;
46
+ try {
47
+ const decoded = Buffer.from(value, "base64").toString("utf8");
48
+ return JSON.parse(decoded);
49
+ }
50
+ catch {
51
+ return null;
52
+ }
53
+ };
35
54
  const deriveAgentId = (serviceSlug) => {
36
55
  if (!serviceSlug)
37
56
  return null;
@@ -56,6 +75,36 @@ const buildCanaryHeaders = () => ({
56
75
  "cache-control": "no-store",
57
76
  "content-type": "application/json; charset=utf-8",
58
77
  });
78
+ const assertPrivateKey = (value, name) => {
79
+ if (!value || !/^0x[a-fA-F0-9]{64}$/.test(value)) {
80
+ throw new Error(`${name} must be a 0x-prefixed 32-byte hex private key.`);
81
+ }
82
+ return value;
83
+ };
84
+ const normalizeAddressLower = (value) => value.trim().toLowerCase();
85
+ const createMerchantGatewayAuthPayload = (input) => ({
86
+ scope: MERCHANT_GATEWAY_AUTH_SCOPE,
87
+ version: MERCHANT_GATEWAY_AUTH_VERSION,
88
+ action: input.action,
89
+ agentId: input.agentId,
90
+ ownerAddress: normalizeAddressLower(input.ownerAddress),
91
+ actorAddress: normalizeAddressLower(input.actorAddress),
92
+ serviceSlug: input.serviceSlug,
93
+ nonce: randomUUID().replace(/-/g, ""),
94
+ issuedAt: Math.floor(Date.now() / 1000),
95
+ });
96
+ const buildMerchantGatewayAuthMessage = (payload) => [
97
+ "Ghost Protocol Merchant Gateway Authorization",
98
+ `scope:${payload.scope}`,
99
+ `version:${payload.version}`,
100
+ `action:${payload.action}`,
101
+ `agentId:${payload.agentId}`,
102
+ `serviceSlug:${payload.serviceSlug}`,
103
+ `ownerAddress:${payload.ownerAddress}`,
104
+ `actorAddress:${payload.actorAddress}`,
105
+ `issuedAt:${payload.issuedAt}`,
106
+ `nonce:${payload.nonce}`,
107
+ ].join("\n");
59
108
  export const buildCanaryPayload = (serviceSlug) => {
60
109
  const normalized = normalizeOptionalString(serviceSlug);
61
110
  if (!normalized)
@@ -103,6 +152,8 @@ export class GhostAgent {
103
152
  this.creditCost = Number.isFinite(config.creditCost) && (config.creditCost ?? 0) > 0
104
153
  ? Math.trunc(config.creditCost)
105
154
  : DEFAULT_CREDIT_COST;
155
+ this.authMode = config.authMode ?? DEFAULT_AUTH_MODE;
156
+ this.x402Scheme = normalizeOptionalString(config.x402Scheme) ?? DEFAULT_X402_SCHEME;
106
157
  }
107
158
  async connect(apiKey) {
108
159
  const normalizedApiKey = normalizeOptionalString(apiKey) ?? this.apiKey;
@@ -135,17 +186,31 @@ export class GhostAgent {
135
186
  message: signedPayload,
136
187
  });
137
188
  const endpoint = `${this.baseUrl}/api/gate/${encodeURIComponent(this.serviceSlug)}`;
189
+ const gateHeaders = {
190
+ accept: "application/json, text/plain;q=0.9, */*;q=0.8",
191
+ };
192
+ if (this.authMode === "x402") {
193
+ gateHeaders["payment-signature"] = encodeBase64Json({
194
+ x402Version: 2,
195
+ scheme: this.x402Scheme,
196
+ network: `eip155:${this.chainId}`,
197
+ payload: headerPayload,
198
+ signature,
199
+ });
200
+ }
201
+ else {
202
+ gateHeaders["x-ghost-sig"] = signature;
203
+ gateHeaders["x-ghost-payload"] = JSON.stringify(headerPayload);
204
+ gateHeaders["x-ghost-credit-cost"] = String(this.creditCost);
205
+ }
138
206
  const response = await fetch(endpoint, {
139
207
  method: "POST",
140
- headers: {
141
- "x-ghost-sig": signature,
142
- "x-ghost-payload": JSON.stringify(headerPayload),
143
- "x-ghost-credit-cost": String(this.creditCost),
144
- accept: "application/json, text/plain;q=0.9, */*;q=0.8",
145
- },
208
+ headers: gateHeaders,
146
209
  cache: "no-store",
147
210
  });
148
211
  const responsePayload = await parsePayload(response);
212
+ const paymentRequired = decodeBase64Json(response.headers.get("payment-required"));
213
+ const paymentResponse = decodeBase64Json(response.headers.get("payment-response"));
149
214
  if (response.ok) {
150
215
  this.apiKey = normalizedApiKey;
151
216
  }
@@ -155,6 +220,14 @@ export class GhostAgent {
155
220
  endpoint,
156
221
  status: response.status,
157
222
  payload: responsePayload,
223
+ ...(this.authMode === "x402" || paymentRequired || paymentResponse
224
+ ? {
225
+ x402: {
226
+ paymentRequired,
227
+ paymentResponse,
228
+ },
229
+ }
230
+ : {}),
158
231
  };
159
232
  }
160
233
  async pulse(input = {}) {
@@ -261,11 +334,18 @@ export class GhostAgent {
261
334
  export class GhostMerchant extends GhostFulfillmentMerchant {
262
335
  constructor(config) {
263
336
  super(config);
337
+ this.heartbeatController = null;
264
338
  const normalizedServiceSlug = normalizeOptionalString(config.serviceSlug);
265
339
  if (!normalizedServiceSlug) {
266
340
  throw new Error("GhostMerchant.serviceSlug is required.");
267
341
  }
268
342
  this.merchantServiceSlug = normalizedServiceSlug;
343
+ this.merchantBaseUrl = normalizeBaseUrl(config.baseUrl ?? DEFAULT_BASE_URL);
344
+ this.ownerPrivateKey = config.ownerPrivateKey ? assertPrivateKey(config.ownerPrivateKey, "ownerPrivateKey") : null;
345
+ this.ownerAddress = this.ownerPrivateKey ? privateKeyToAccount(this.ownerPrivateKey).address.toLowerCase() : null;
346
+ this.delegatedSignerAddress = config.delegatedPrivateKey
347
+ ? privateKeyToAccount(assertPrivateKey(config.delegatedPrivateKey, "delegatedPrivateKey")).address.toLowerCase()
348
+ : null;
269
349
  }
270
350
  canaryPayload() {
271
351
  return buildCanaryPayload(this.merchantServiceSlug);
@@ -273,5 +353,171 @@ export class GhostMerchant extends GhostFulfillmentMerchant {
273
353
  canaryHandler() {
274
354
  return createCanaryHandler(this.merchantServiceSlug);
275
355
  }
356
+ async activate(options) {
357
+ const agentId = normalizeOptionalString(options.agentId);
358
+ const serviceSlug = normalizeOptionalString(options.serviceSlug);
359
+ const endpointUrl = normalizeOptionalString(options.endpointUrl);
360
+ const canaryPath = normalizeOptionalString(options.canaryPath) ?? DEFAULT_ACTIVATE_CANARY_PATH;
361
+ const canaryMethod = (normalizeOptionalString(options.canaryMethod) ?? DEFAULT_ACTIVATE_CANARY_METHOD).toUpperCase();
362
+ const signerLabel = normalizeOptionalString(options.signerLabel) ?? DEFAULT_ACTIVATE_SIGNER_LABEL;
363
+ if (!agentId)
364
+ throw new Error("[activate:validate] agentId is required.");
365
+ if (!serviceSlug)
366
+ throw new Error("[activate:validate] serviceSlug is required.");
367
+ if (!endpointUrl)
368
+ throw new Error("[activate:validate] endpointUrl is required.");
369
+ if (!canaryPath.startsWith("/")) {
370
+ throw new Error("[activate:validate] canaryPath must start with '/'.");
371
+ }
372
+ if (canaryMethod !== "GET") {
373
+ throw new Error("[activate:validate] canaryMethod must be GET.");
374
+ }
375
+ if (!this.ownerPrivateKey || !this.ownerAddress) {
376
+ throw new Error("[activate:owner] ownerPrivateKey is required on GhostMerchant config and must match the indexed agent owner.");
377
+ }
378
+ const ownerConfig = await this.fetchGatewayOwnerConfig(agentId);
379
+ const indexedOwnerAddress = normalizeAddressLower(ownerConfig.config.ownerAddress);
380
+ if (indexedOwnerAddress !== this.ownerAddress) {
381
+ throw new Error(`[activate:owner] ownerPrivateKey address ${this.ownerAddress} does not match indexed owner ${indexedOwnerAddress} for agent ${agentId}.`);
382
+ }
383
+ const configPayload = (await this.postMerchantSignedWrite("config", {
384
+ path: "/api/agent-gateway/config",
385
+ agentId,
386
+ serviceSlug,
387
+ ownerAddress: indexedOwnerAddress,
388
+ body: {
389
+ endpointUrl,
390
+ canaryPath,
391
+ canaryMethod: "GET",
392
+ },
393
+ }));
394
+ const verifyPayload = (await this.postMerchantSignedWrite("verify", {
395
+ path: "/api/agent-gateway/verify",
396
+ agentId,
397
+ serviceSlug,
398
+ ownerAddress: indexedOwnerAddress,
399
+ body: {},
400
+ }));
401
+ const readiness = verifyPayload.readinessStatus;
402
+ if (verifyPayload.verified !== true || readiness !== "LIVE") {
403
+ const detailParts = [
404
+ verifyPayload.error ? `error=${verifyPayload.error}` : null,
405
+ verifyPayload.canaryUrl ? `canaryUrl=${verifyPayload.canaryUrl}` : null,
406
+ typeof verifyPayload.statusCode === "number" ? `statusCode=${verifyPayload.statusCode}` : null,
407
+ typeof verifyPayload.latencyMs === "number" ? `latencyMs=${verifyPayload.latencyMs}` : null,
408
+ ].filter(Boolean);
409
+ throw new Error(`[activate:verify] canary verification did not reach LIVE readiness${detailParts.length ? ` (${detailParts.join(", ")})` : ""}.`);
410
+ }
411
+ const signerAddress = this.delegatedSignerAddress ?? indexedOwnerAddress;
412
+ const signerRegistration = (await this.postMerchantSignedWrite("delegated_signer_register", {
413
+ path: "/api/agent-gateway/delegated-signers/register",
414
+ agentId,
415
+ serviceSlug,
416
+ ownerAddress: indexedOwnerAddress,
417
+ body: {
418
+ signerAddress,
419
+ label: signerLabel,
420
+ },
421
+ }));
422
+ this.heartbeatController?.stop();
423
+ const heartbeatAgent = new GhostAgent({
424
+ baseUrl: this.merchantBaseUrl,
425
+ agentId,
426
+ serviceSlug,
427
+ });
428
+ this.heartbeatController = heartbeatAgent.startHeartbeat({
429
+ agentId,
430
+ serviceSlug,
431
+ immediate: false,
432
+ });
433
+ return {
434
+ status: "LIVE",
435
+ readiness: "LIVE",
436
+ config: configPayload.config ?? ownerConfig.config,
437
+ verify: verifyPayload,
438
+ signerRegistration,
439
+ heartbeat: this.heartbeatController,
440
+ };
441
+ }
442
+ async fetchGatewayOwnerConfig(agentId) {
443
+ const params = new URLSearchParams({ agentId });
444
+ const endpoint = `${this.merchantBaseUrl}/api/agent-gateway/config?${params.toString()}`;
445
+ const response = await fetch(endpoint, {
446
+ method: "GET",
447
+ headers: {
448
+ accept: "application/json, text/plain;q=0.9, */*;q=0.8",
449
+ },
450
+ cache: "no-store",
451
+ });
452
+ const payload = await parsePayload(response);
453
+ if (!response.ok) {
454
+ const message = this.extractApiErrorMessage(payload, "Failed to load gateway owner config.");
455
+ throw new Error(`[activate:config_lookup] ${message}`);
456
+ }
457
+ const config = typeof payload === "object" &&
458
+ payload !== null &&
459
+ "config" in payload &&
460
+ typeof payload.config === "object" &&
461
+ payload.config !== null
462
+ ? (payload.config)
463
+ : null;
464
+ if (!config || !normalizeOptionalString(config.ownerAddress)) {
465
+ throw new Error("[activate:config_lookup] gateway config response missing ownerAddress.");
466
+ }
467
+ return {
468
+ configured: typeof payload === "object" && payload !== null && "configured" in payload
469
+ ? Boolean(payload.configured)
470
+ : false,
471
+ config,
472
+ };
473
+ }
474
+ async postMerchantSignedWrite(action, input) {
475
+ const ownerKey = assertPrivateKey(this.ownerPrivateKey, "ownerPrivateKey");
476
+ const ownerAddress = normalizeAddressLower(input.ownerAddress);
477
+ const authPayload = createMerchantGatewayAuthPayload({
478
+ action,
479
+ agentId: input.agentId,
480
+ ownerAddress,
481
+ actorAddress: ownerAddress,
482
+ serviceSlug: input.serviceSlug,
483
+ });
484
+ const account = privateKeyToAccount(ownerKey);
485
+ const authSignature = await account.signMessage({
486
+ message: buildMerchantGatewayAuthMessage(authPayload),
487
+ });
488
+ const endpoint = `${this.merchantBaseUrl}${input.path}`;
489
+ const response = await fetch(endpoint, {
490
+ method: "POST",
491
+ headers: {
492
+ "content-type": "application/json",
493
+ accept: "application/json, text/plain;q=0.9, */*;q=0.8",
494
+ },
495
+ body: JSON.stringify({
496
+ agentId: input.agentId,
497
+ ownerAddress,
498
+ actorAddress: ownerAddress,
499
+ serviceSlug: input.serviceSlug,
500
+ authPayload,
501
+ authSignature,
502
+ ...input.body,
503
+ }),
504
+ cache: "no-store",
505
+ });
506
+ const payload = await parsePayload(response);
507
+ if (!response.ok) {
508
+ const message = this.extractApiErrorMessage(payload, `Request failed for ${action}.`);
509
+ throw new Error(`[activate:${action}] ${message}`);
510
+ }
511
+ return payload;
512
+ }
513
+ extractApiErrorMessage(payload, fallback) {
514
+ if (typeof payload === "object" && payload !== null && "error" in payload) {
515
+ const maybeError = payload.error;
516
+ if (typeof maybeError === "string" && maybeError.trim().length > 0) {
517
+ return maybeError.trim();
518
+ }
519
+ }
520
+ return fallback;
521
+ }
276
522
  }
277
523
  export default GhostAgent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghostgate/sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Ghost Protocol Node.js SDK for gate access, fulfillment, telemetry, and canary helpers.",
5
5
  "author": "Ghost Protocol",
6
6
  "license": "MIT",