@clawcash/forge 0.1.8 → 0.2.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/dist/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- import { Application, Router, Request, Response, NextFunction } from 'express';
2
-
3
1
  type SchemaFieldType = "string" | "url" | "number" | "boolean";
4
2
  type InputSchema = Record<string, SchemaFieldType>;
5
3
  type OutputSchema = Record<string, SchemaFieldType>;
@@ -32,73 +30,6 @@ interface DefinedAgentService<TInput extends Record<string, unknown> = Record<st
32
30
  readonly __forge: true;
33
31
  path: string;
34
32
  }
35
- interface FacilitatorAuthHeaders {
36
- verify: Record<string, string>;
37
- settle: Record<string, string>;
38
- supported: Record<string, string>;
39
- bazaar?: Record<string, string>;
40
- }
41
- interface ForgePayToSource {
42
- owner: string;
43
- repo: string;
44
- /** Forge web base URL. Optional — uses FORGE_URL env when set. */
45
- baseUrl?: string;
46
- }
47
- interface MountOptions {
48
- /**
49
- * Recipient wallet. Prefer omitting and letting `forge` + baked fallback
50
- * resolve automatically so merchants never set PAY_TO on their host.
51
- * Still honored as override when set (or via process.env.PAY_TO).
52
- */
53
- payTo?: string;
54
- /**
55
- * Baked-in Forge wallet from codegen. Used when live Forge fetch is
56
- * unavailable. Required unless skipPayment or payTo is set.
57
- */
58
- payToFallback?: string;
59
- /**
60
- * Auto-resolve payTo from Forge public API (no merchant env required).
61
- */
62
- forge?: ForgePayToSource;
63
- /**
64
- * Facilitator URL. Defaults to XPay (`https://facilitator.xpay.sh`) —
65
- * Base mainnet, no API keys. Override with CDP or others if needed.
66
- */
67
- facilitatorUrl?: string;
68
- /** Optional auth header factory (e.g. CDP JWT). Not required for XPay. */
69
- createAuthHeaders?: () => Promise<FacilitatorAuthHeaders>;
70
- /** Path prefix for agent routes. Defaults to /agent */
71
- basePath?: string;
72
- /** Skip x402 (local dev only). Defaults to false. */
73
- skipPayment?: boolean;
74
- /**
75
- * Gateway heartbeat after mount. Only FORGE_API_KEY is required as env;
76
- * the URL defaults to the ClawCash gateway, the handle is baked by Forge
77
- * codegen, and the public base URL is resolved from platform vars or
78
- * inferred (self-verified) from the first inbound probe.
79
- */
80
- gateway?: {
81
- /** Defaults to https://gateway.clawca.sh (or GATEWAY_URL env). */
82
- url?: string;
83
- /** Merchant handle — baked by Forge codegen (or FORGE_HANDLE env). */
84
- handle?: string;
85
- /** @deprecated Prefer FORGE_API_KEY env — per-project key from Forge dashboard. */
86
- registerSecret?: string;
87
- /** Merchant public base URL. Usually omitted — resolved automatically. */
88
- publicBaseUrl?: string;
89
- };
90
- /**
91
- * Path prefix for private fulfillment (gateway → merchant after x402).
92
- * Defaults to /forge/fulfill. Not end-user / x402 routes.
93
- */
94
- fulfillPath?: string;
95
- }
96
- interface SkillMeta {
97
- name: string;
98
- description: string;
99
- baseUrl: string;
100
- homepage?: string;
101
- }
102
33
 
103
34
  declare function waitUntil<T>(options: WaitUntilOptions<T>): Promise<T>;
104
35
  declare function createContext(): AgentServiceContext;
@@ -106,95 +37,82 @@ declare function createContext(): AgentServiceContext;
106
37
  declare function toKebabCase(name: string): string;
107
38
  declare function defineAgentService<TInput extends Record<string, unknown> = Record<string, unknown>, TOutput extends Record<string, unknown> = Record<string, unknown>>(config: AgentServiceConfig<TInput, TOutput>): DefinedAgentService<TInput, TOutput>;
108
39
 
109
- /**
110
- * Mount Forge agent services on an Express app.
111
- * - GET /forge/health, GET /forge/status, GET /.well-known/clawcash.json — liveliness
112
- * - POST {basePath}/{kebab-name} — optional public x402 agent surface
113
- * - POST /forge/fulfill/{kebab-name} private gateway fulfillment after payment
114
- *
115
- * payTo resolves automatically: PAY_TO env (optional) → Forge API → baked fallback.
116
- */
117
- declare function mountAgentServices(app: Application, services: DefinedAgentService[], options: MountOptions): Promise<Router>;
118
- declare function createForgeRouter(services: DefinedAgentService[], options: MountOptions): (app: Application) => Promise<Router>;
119
-
120
- /**
121
- * Generate a SKILL.md document for agents from defined Forge services.
122
- */
123
- declare function generateSkillMarkdown(services: DefinedAgentService[], meta: SkillMeta): string;
40
+ interface ForgeWorkerOptions {
41
+ services: DefinedAgentService[];
42
+ /** Merchant handle. Defaults to FORGE_HANDLE env. */
43
+ handle?: string;
44
+ /** Per-project key from the Forge dashboard. Defaults to FORGE_API_KEY env. */
45
+ apiKey?: string;
46
+ /** Defaults to https://gateway.clawca.sh (or GATEWAY_URL env). */
47
+ gatewayUrl?: string;
48
+ /** Shown in gateway job rows. Defaults to hostname-pid. */
49
+ workerId?: string;
50
+ /** Long-poll window per claim request. Defaults to 20s (gateway caps at 25s). */
51
+ waitMs?: number;
52
+ onError?: (error: Error) => void;
53
+ }
54
+ interface ForgeWorkerHandle {
55
+ stop: () => void;
56
+ readonly running: boolean;
57
+ }
58
+ declare function forgeWorker(options: ForgeWorkerOptions): ForgeWorkerHandle;
124
59
 
125
- declare function isZeroAddress(address: string | undefined | null): boolean;
126
60
  /**
127
- * Resolve merchant payTo with minimal host config:
128
- * 1. `PAY_TO` env (optional override)
129
- * 2. Live address from Forge public API (when reachable)
130
- * 3. Baked-in fallback from the Forge PR
61
+ * Web-standard fetch handler mount Forge fulfillment + liveliness on any
62
+ * runtime that speaks (Request) => Response: Next.js route handlers, Hono,
63
+ * Fastify (via adapter), Bun, Deno, plain node:http (via adapter).
64
+ *
65
+ * This surface is for gateway-push (fulfillment.mode=sdk) merchants and
66
+ * deploy probes. Payment lives on the gateway; prefer forgeWorker() when the
67
+ * merchant can run an outbound worker instead.
68
+ *
69
+ * Routes handled (anything else returns null from tryHandleForgeRequest, or
70
+ * 404 from the plain handler):
71
+ * - GET /forge/health
72
+ * - GET /forge/status
73
+ * - GET /.well-known/clawcash.json
74
+ * - POST {fulfillPath}/{action-path} (requires FORGE_API_KEY auth)
131
75
  */
132
- declare function resolvePayTo(opts: {
133
- /** Baked-in address from Forge codegen (required fallback). */
134
- fallback: string;
135
- /** Optional explicit override (usually process.env.PAY_TO). */
136
- payTo?: string;
137
- forge?: ForgePayToSource;
138
- /** Fetch timeout ms. Defaults to 2500. */
139
- timeoutMs?: number;
140
- }): Promise<string>;
141
-
76
+ interface ForgeHandlerOptions {
77
+ /** Merchant handle FORGE_HANDLE env when omitted. */
78
+ handle?: string;
79
+ /** Per-project key. FORGE_API_KEY env when omitted. */
80
+ apiKey?: string;
81
+ /** Defaults to /forge/fulfill. */
82
+ fulfillPath?: string;
83
+ /** Reported in /forge/status. Optional. */
84
+ publicBaseUrl?: string;
85
+ /** Reported in /forge/status. Defaults to GATEWAY_URL env or the ClawCash gateway. */
86
+ gatewayUrl?: string;
87
+ }
88
+ type ForgeFetchHandler = (request: Request) => Promise<Response>;
142
89
  /**
143
- * Public base URL resolution, in trust order:
144
- * 1. PUBLIC_BASE_URL env explicit override.
145
- * 2. Platform-provided vars (Railway, Render, Vercel, Fly, Heroku) — set by
146
- * the host, not by request input, so safe to trust as-is.
147
- * 3. Lazy inference from the first inbound request to the Forge surface
148
- * (X-Forwarded-Proto + Host). Host is attacker-controlled, so a candidate
149
- * is only accepted after self-verification: we fetch our own
150
- * /forge/health at the candidate URL and check it returns this
151
- * instance's boot nonce.
90
+ * Returns a Response when the request targets a Forge route, else null so
91
+ * the host app can fall through to its own routing.
152
92
  */
153
- declare function resolveBaseUrlFromEnv(explicit?: string): string | null;
154
- declare class PublicBaseUrlResolver {
155
- /** Per-boot nonce, echoed by /forge/health for self-verification. */
156
- readonly instanceNonce: string;
157
- private resolved;
158
- private verifying;
159
- private rejected;
160
- private attempts;
161
- private onResolved;
162
- constructor(opts: {
163
- /** URL already known from env/platform vars (trusted, no verification). */
164
- initial: string | null;
165
- /** Called once when a base URL first becomes known via inference. */
166
- onResolved?: (baseUrl: string) => void;
167
- });
168
- get(): string | null;
169
- /**
170
- * Feed an inbound Forge-surface request. No-op once resolved. Kicks off
171
- * async self-verification of the candidate URL derived from the request.
172
- */
173
- considerRequest(req: Request): void;
174
- /** Fetch our own /forge/health at the candidate and match the boot nonce. */
175
- private verify;
176
- }
93
+ declare function createForgeRequestMatcher(services: DefinedAgentService[], options?: ForgeHandlerOptions): (request: Request) => Promise<Response | null>;
94
+ /** Like createForgeRequestMatcher, but 404s instead of returning null. */
95
+ declare function createForgeHandler(services: DefinedAgentService[], options?: ForgeHandlerOptions): ForgeFetchHandler;
177
96
 
178
97
  /**
179
- * Notify ClawCash gateway of this merchant's live public base URL.
180
- * Full action registration still happens from Forge "Go live".
98
+ * Framework-free input validation shared by every execution surface
99
+ * (Express mount, fetch handler, worker).
181
100
  */
182
- declare function heartbeatGateway(opts: {
183
- gatewayUrl: string;
184
- handle: string;
185
- baseUrl: string;
186
- registerSecret: string;
187
- }): Promise<void>;
101
+ type ValidationResult = {
102
+ ok: true;
103
+ value: Record<string, unknown>;
104
+ } | {
105
+ ok: false;
106
+ error: string;
107
+ };
108
+ declare function validateInput(body: unknown, schema: InputSchema): ValidationResult;
109
+ declare function checkType(key: string, value: unknown, type: SchemaFieldType): string | null;
188
110
 
189
111
  /**
190
- * Merchant-side Forge surface status — public probes for deploy / go-live checks.
112
+ * Merchant-side Forge surface status — public probes for deploy / go-live
113
+ * checks when running the fetch handler. Worker-mode merchants report
114
+ * liveness by polling the gateway instead.
191
115
  */
192
- type ForgeHeartbeatState = {
193
- attempted: boolean;
194
- ok: boolean | null;
195
- at: string | null;
196
- error: string | null;
197
- };
198
116
  type ForgeSurfaceStatus = {
199
117
  ok: boolean;
200
118
  forge: true;
@@ -202,42 +120,29 @@ type ForgeSurfaceStatus = {
202
120
  handle: string | null;
203
121
  publicBaseUrl: string | null;
204
122
  gatewayUrl: string | null;
205
- /** True when FORGE_API_KEY is set so /forge/fulfill is mounted. */
123
+ /** True when FORGE_API_KEY is set so fulfillment is accepted. */
206
124
  fulfillMounted: boolean;
207
125
  fulfillPath: string;
208
- agentBasePath: string;
209
- skipPayment: boolean;
210
126
  actions: Array<{
211
127
  name: string;
212
128
  path: string;
213
129
  price: string;
214
130
  }>;
215
- /** Env + fulfill ready — merchant can accept gateway fulfillment. */
131
+ /** Key + actions present — merchant can accept gateway fulfillment. */
216
132
  ready: boolean;
217
- heartbeat: ForgeHeartbeatState;
218
133
  endpoints: {
219
134
  health: string;
220
135
  status: string;
221
136
  wellKnown: string;
222
137
  fulfill: string;
223
- agent: string;
224
138
  };
225
139
  };
226
- declare function recordHeartbeatResult(result: {
227
- ok: true;
228
- } | {
229
- ok: false;
230
- error: string;
231
- }): void;
232
- declare function getLastHeartbeat(): ForgeHeartbeatState;
233
140
  declare function buildForgeSurfaceStatus(opts: {
234
141
  handle: string | null;
235
142
  publicBaseUrl: string | null;
236
143
  gatewayUrl: string | null;
237
144
  fulfillMounted: boolean;
238
145
  fulfillPath: string;
239
- agentBasePath: string;
240
- skipPayment: boolean;
241
146
  actions: Array<{
242
147
  name: string;
243
148
  path: string;
@@ -255,20 +160,19 @@ declare function buildWellKnownDocument(status: ForgeSurfaceStatus): {
255
160
  declare function forgeSdkVersion(): string;
256
161
 
257
162
  /**
258
- * Per-project Forge API key for gateway → merchant fulfillment.
259
- * Merchants set FORGE_API_KEY from the Forge dashboard (never the shared
260
- * GATEWAY_REGISTER_SECRET that is Forge↔gateway platform auth only).
163
+ * Per-project Forge API key helpers framework-free.
164
+ *
165
+ * Merchants set FORGE_API_KEY from the Forge dashboard. The worker uses it
166
+ * to claim jobs from the gateway; the fetch handler uses it to gate
167
+ * gateway-push fulfillment; execute() can use forgeGatewayLoopbackHeaders()
168
+ * so the merchant's own API middleware can recognize fulfillment traffic.
261
169
  *
262
170
  * GATEWAY_REGISTER_SECRET is accepted as a deprecated fallback for older deploys.
263
171
  */
264
172
  declare function getForgeApiKey(explicit?: string | null): string | null;
265
- /** @deprecated Use getForgeApiKey */
266
- declare function getForgeGatewaySecret(explicit?: string | null): string | null;
267
- declare function isForgeGatewayRequest(req: Request, secret?: string | null): boolean;
268
- /** Synthetic user id for DB rows created by gateway-driven fulfillment. */
173
+ /** Synthetic user id for DB rows created by fulfillment traffic. */
269
174
  declare const FORGE_GATEWAY_USER_ID = "forge_gateway_agent";
270
- declare function requireForgeGateway(secret?: string | null): (req: Request, res: Response, next: NextFunction) => void;
271
175
  /** Headers merchant execute() should send on loopback calls during fulfillment. */
272
176
  declare function forgeGatewayLoopbackHeaders(secret?: string | null): Record<string, string>;
273
177
 
274
- export { type AgentServiceConfig, type AgentServiceContext, type DefinedAgentService, FORGE_GATEWAY_USER_ID, type ForgeHeartbeatState, type ForgePayToSource, type ForgeSurfaceStatus, type InputSchema, type MountOptions, type OutputSchema, type PaymentConfig, PublicBaseUrlResolver, type SchemaFieldType, type SkillMeta, type WaitUntilOptions, buildForgeSurfaceStatus, buildWellKnownDocument, createContext, createForgeRouter, defineAgentService, forgeGatewayLoopbackHeaders, forgeSdkVersion, generateSkillMarkdown, getForgeApiKey, getForgeGatewaySecret, getLastHeartbeat, heartbeatGateway, isForgeGatewayRequest, isZeroAddress, mountAgentServices, recordHeartbeatResult, requireForgeGateway, resolveBaseUrlFromEnv, resolvePayTo, toKebabCase, waitUntil };
178
+ export { type AgentServiceConfig, type AgentServiceContext, type DefinedAgentService, FORGE_GATEWAY_USER_ID, type ForgeFetchHandler, type ForgeHandlerOptions, type ForgeSurfaceStatus, type ForgeWorkerHandle, type ForgeWorkerOptions, type InputSchema, type OutputSchema, type PaymentConfig, type SchemaFieldType, type ValidationResult, type WaitUntilOptions, buildForgeSurfaceStatus, buildWellKnownDocument, checkType, createContext, createForgeHandler, createForgeRequestMatcher, defineAgentService, forgeGatewayLoopbackHeaders, forgeSdkVersion, forgeWorker, getForgeApiKey, toKebabCase, validateInput, waitUntil };