@forgeintel/sdk 0.5.0-beta.5 → 0.5.0-beta.7

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
@@ -10,9 +10,9 @@ The Forge SDK for x402 paid APIs. Paid responses carry a `feedback_id`, the 402
10
10
  import { createForge } from "@forgeintel/sdk";
11
11
 
12
12
  const forge = createForge({
13
- apiKey: process.env.FORGE_API_KEY, // from your Forge project's Agents page
14
- backendUrl: process.env.FORGE_BACKEND_URL, // Forge: <API origin>/api/sdk/v2
15
- publicUrl: "https://api.example.com", // your public origin (never taken from the Host header)
13
+ apiKey: process.env.FORGE_API_KEY,
14
+ agentContext: false,
15
+ feedback: true,
16
16
  });
17
17
 
18
18
  app.use(forge.middleware()); // 1. first: before payments and your /openapi.json route
@@ -26,7 +26,7 @@ Works with `@x402/express` (v2) and `x402-express` (v1), on Express 4.21+ or 5.
26
26
  ```ts
27
27
  import { createForge } from "@forgeintel/sdk/hono";
28
28
 
29
- const forge = createForge({ apiKey, backendUrl, publicUrl });
29
+ const forge = createForge({ apiKey, agentContext: false, feedback: true });
30
30
  app.use(forge.middleware()); // before paymentMiddleware from @x402/hono
31
31
  app.use(paymentMiddleware(routes, resourceServer));
32
32
  ```
@@ -36,7 +36,7 @@ app.use(paymentMiddleware(routes, resourceServer));
36
36
  ```ts
37
37
  import { createForge } from "@forgeintel/sdk/next";
38
38
 
39
- export const forge = createForge({ apiKey, backendUrl, publicUrl });
39
+ export const forge = createForge({ apiKey, agentContext: false, feedback: true });
40
40
  // app/api/…/route.ts: Forge outermost, around @x402/next's withX402
41
41
  export const POST = forge.withForge(withX402(handler, route, resourceServer));
42
42
  // app/feedback/[[...path]]/route.ts: Forge's own routes
@@ -84,8 +84,8 @@ OpenAPI: Swagger 2.0 and OpenAPI 3.0, 3.1 and 3.2. Additive only; shared compone
84
84
  | Option | Default | |
85
85
  | --- | --- | --- |
86
86
  | `apiKey` | required | Merchant key. Also the HMAC key for IDs. |
87
- | `backendUrl` | required | Forge backend origin. |
88
- | `publicUrl` | required | This service's public origin. Used in rating URLs. |
87
+ | `backendUrl` | `https://dev-api.forgeintel.co/api/sdk/v2` | Optional collector override. |
88
+ | `publicUrl` | Same-origin paths | Optional public origin for absolute rating URLs. Never infer it from request headers. |
89
89
  | `feedback` | `true` | Master switch for rating prompts, IDs, response additions and feedback routes. `false` leaves telemetry, client headers and independent agent context on. |
90
90
  | `basePath` | `/feedback` | Feedback routes (`/feedback`, `/feedback/rate`, `/feedback/summary`). |
91
91
  | `tone` | `"soft"` | `"lifecycle"` describes this service's flow as four steps (402, pay, response, rate). Both stay soft asks. |
@@ -114,8 +114,6 @@ Client headers are captured automatically at discovery, challenge, payment, and
114
114
  ```ts
115
115
  const forge = createForge({
116
116
  apiKey: process.env.FORGE_API_KEY!,
117
- backendUrl: "https://your-forge-backend.example/api/sdk/v2",
118
- publicUrl: "https://api.example.com",
119
117
  agentContext: true,
120
118
  });
121
119
  ```
package/dist/core.d.ts CHANGED
@@ -16,12 +16,12 @@ export interface ForgeOptions {
16
16
  /** Merchant API key issued by the Forge backend. Also the HMAC key for feedback IDs. */
17
17
  apiKey: string;
18
18
  /**
19
- * Where events and ratings go. An origin (https://backend.example.com) uses its /v1/events, /v1/feedback and
20
- * /v1/summary routes; a URL with a path (https://api.forgeintel.co/api/sdk/v2) uses {path}/events, and so on.
19
+ * Optional collector override. Defaults to Forge's production /api/sdk/v2 collector.
20
+ * An origin-only override uses its /v1 routes; a URL with a path uses {path}/events and so on.
21
21
  */
22
- backendUrl: string;
23
- /** This service's public origin, e.g. https://pixels.gateway.clawca.sh. Never derived from the Host header. */
24
- publicUrl: string;
22
+ backendUrl?: string;
23
+ /** Optional public origin for absolute feedback links. By default links use same-origin paths. Never derived from the Host header. */
24
+ publicUrl?: string;
25
25
  /** Enable rating prompts, feedback IDs and feedback routes. Default true. Telemetry and agent context are independent. */
26
26
  feedback?: boolean;
27
27
  /** Path for the feedback routes. Default "/feedback" (quick rating at "/feedback/rate"). */
@@ -178,6 +178,7 @@ export declare const FEEDBACK_HEADERS: {
178
178
  export declare const BODY_LIMIT: number;
179
179
  /** Max OpenAPI document an adapter should buffer for enrichment. */
180
180
  export declare const SPEC_LIMIT: number;
181
+ export declare const DEFAULT_BACKEND_URL = "https://dev-api.forgeintel.co/api/sdk/v2";
181
182
  /**
182
183
  * Check options without throwing. Invalid required options are errors (Forge runs disabled);
183
184
  * invalid optional values are warnings and fall back to their defaults.
package/dist/core.js CHANGED
@@ -14,6 +14,7 @@ export const FEEDBACK_HEADERS = { "Cache-Control": "no-store", "X-Robots-Tag": "
14
14
  export const BODY_LIMIT = 8 * 1024;
15
15
  /** Max OpenAPI document an adapter should buffer for enrichment. */
16
16
  export const SPEC_LIMIT = 10 * 1024 * 1024;
17
+ export const DEFAULT_BACKEND_URL = "https://dev-api.forgeintel.co/api/sdk/v2";
17
18
  /**
18
19
  * Check options without throwing. Invalid required options are errors (Forge runs disabled);
19
20
  * invalid optional values are warnings and fall back to their defaults.
@@ -36,10 +37,12 @@ export function checkOptions(input) {
36
37
  };
37
38
  if (typeof raw.apiKey !== "string" || !raw.apiKey.trim())
38
39
  errors.push("apiKey is missing (set it to your merchant key, ffk_…)");
39
- if (!absoluteUrl(raw.backendUrl))
40
+ if (raw.backendUrl === undefined)
41
+ options.backendUrl = DEFAULT_BACKEND_URL;
42
+ else if (!absoluteUrl(raw.backendUrl))
40
43
  errors.push(`backendUrl must be an absolute http(s) URL (got ${JSON.stringify(raw.backendUrl ?? null)})`);
41
- if (!absoluteUrl(raw.publicUrl))
42
- errors.push(`publicUrl must be an absolute http(s) URL, this service's public origin (got ${JSON.stringify(raw.publicUrl ?? null)})`);
44
+ if (raw.publicUrl !== undefined && !absoluteUrl(raw.publicUrl))
45
+ errors.push(`publicUrl must be an absolute http(s) URL (got ${JSON.stringify(raw.publicUrl ?? null)})`);
43
46
  const fallback = (key, ok, expected) => {
44
47
  if (raw[key] === undefined || ok)
45
48
  return;
@@ -156,17 +159,19 @@ export function createForgeCore(input) {
156
159
  }
157
160
  }
158
161
  function enabledCore(options, configWarnings) {
159
- const { apiKey, backendUrl, publicUrl } = options;
162
+ const { apiKey, publicUrl } = options;
163
+ const backendUrl = options.backendUrl ?? DEFAULT_BACKEND_URL;
160
164
  // Feedback IDs are signed with a key derived from the API key, never with the API key itself.
161
165
  const signingKey = deriveSigningKey(apiKey);
162
166
  const backendPath = new URL(backendUrl).pathname.replace(/\/+$/, "") || "/v1";
163
167
  const backend = (name) => new URL(`${backendPath}/${name}`, backendUrl).href;
164
168
  const basePath = (options.basePath ?? "/feedback").replace(/\/+$/, "");
165
169
  const ratePath = `${basePath}/rate`;
166
- const rateUrl = new URL(ratePath, publicUrl).href;
167
- const formUrl = new URL(basePath, publicUrl).href;
170
+ const sameOriginUrl = (path) => publicUrl ? new URL(path, publicUrl).href : path;
171
+ const rateUrl = sameOriginUrl(ratePath);
172
+ const formUrl = sameOriginUrl(basePath);
168
173
  const summaryPath = `${basePath}/summary`;
169
- const summaryUrl = new URL(summaryPath, publicUrl).href;
174
+ const summaryUrl = sameOriginUrl(summaryPath);
170
175
  const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
171
176
  const fetchImpl = options.fetch ?? fetch;
172
177
  const feedback = options.feedback !== false;
package/dist/openapi.d.ts CHANGED
@@ -4,8 +4,8 @@ export type ResponseSupport = "extended" | "incompatible" | "undocumented";
4
4
  export interface EnrichOptions {
5
5
  /** Disable all feedback additions while retaining enabled agent context. */
6
6
  feedback?: boolean;
7
- /** Merchant public origin, e.g. https://api.example.com */
8
- publicUrl: string;
7
+ /** Optional merchant public origin. Without it, feedback links use same-origin paths. */
8
+ publicUrl?: string;
9
9
  /** Public path of the feedback routes, e.g. /feedback */
10
10
  basePath: string;
11
11
  /** Sentence appended to x-guidance and paid operation descriptions. */
package/dist/openapi.js CHANGED
@@ -46,7 +46,7 @@ function feedbackProperties(rateUrl, hintField = false) {
46
46
  },
47
47
  feedback_url: {
48
48
  type: "string",
49
- format: "uri",
49
+ format: "uri-reference",
50
50
  description: `Quick-rating URL with outcome left blank; outcome values: ${Object.keys(OUTCOMES).join(", ")}. Base: ${rateUrl}`,
51
51
  },
52
52
  };
@@ -170,20 +170,21 @@ function appendSentence(text, sentence, marker) {
170
170
  }
171
171
  /** Work out the path prefix document paths are relative to, and whether it's this service's origin. */
172
172
  function serverBase(doc, version, publicUrl) {
173
- const origin = new URL(publicUrl).origin;
173
+ const origin = publicUrl ? new URL(publicUrl).origin : undefined;
174
+ const baseUrl = publicUrl ?? "https://forge.invalid";
174
175
  try {
175
176
  if (version === "2.0") {
176
- const scheme = Array.isArray(doc.schemes) && doc.schemes[0] ? doc.schemes[0] : new URL(publicUrl).protocol.slice(0, -1);
177
+ const scheme = Array.isArray(doc.schemes) && doc.schemes[0] ? doc.schemes[0] : new URL(baseUrl).protocol.slice(0, -1);
177
178
  const base = typeof doc.basePath === "string" ? doc.basePath : "";
178
- const url = typeof doc.host === "string" ? new URL(`${scheme}://${doc.host}${base}`) : new URL(base || "/", publicUrl);
179
- return { prefix: url.pathname.replace(/\/+$/, ""), sameOrigin: url.origin === origin };
179
+ const url = typeof doc.host === "string" ? new URL(`${scheme}://${doc.host}${base}`) : new URL(base || "/", baseUrl);
180
+ return { prefix: url.pathname.replace(/\/+$/, ""), sameOrigin: !origin || url.origin === origin };
180
181
  }
181
182
  const server = Array.isArray(doc.servers) ? doc.servers[0] : undefined;
182
183
  if (!isObj(server) || typeof server.url !== "string")
183
184
  return { prefix: "", sameOrigin: true };
184
185
  const raw = server.url.replace(/\{([^}]+)\}/g, (_, name) => server.variables?.[name]?.default ?? "");
185
- const url = new URL(raw, publicUrl);
186
- return { prefix: url.pathname.replace(/\/+$/, ""), sameOrigin: url.origin === origin };
186
+ const url = new URL(raw, baseUrl);
187
+ return { prefix: url.pathname.replace(/\/+$/, ""), sameOrigin: !origin || url.origin === origin };
187
188
  }
188
189
  catch {
189
190
  return { prefix: "", sameOrigin: false };
@@ -262,7 +263,7 @@ export function enrichOpenApi(input, options) {
262
263
  }
263
264
  try {
264
265
  const doc = clone(original);
265
- const origin = new URL(options.publicUrl).origin;
266
+ const origin = options.publicUrl ? new URL(options.publicUrl).origin : "";
266
267
  const base = options.basePath.replace(/\/+$/, "");
267
268
  const rateUrl = `${origin}${base}/rate`;
268
269
  const formUrl = `${origin}${base}`;
@@ -377,7 +378,7 @@ export function enrichOpenApi(input, options) {
377
378
  }
378
379
  else {
379
380
  const ops = feedbackOperations(version, formUrl, rateUrl, operationIds);
380
- const servers = inPrefix ? {} : { servers: [{ url: origin }] };
381
+ const servers = inPrefix ? {} : { servers: [{ url: origin || "/" }] };
381
382
  paths[docBase] = { ...servers, get: ops.form, post: ops.submit };
382
383
  paths[`${docBase}/rate`] = { ...servers, get: ops.rate };
383
384
  paths[`${docBase}/summary`] = { ...servers, get: ops.summary };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgeintel/sdk",
3
- "version": "0.5.0-beta.5",
3
+ "version": "0.5.0-beta.7",
4
4
  "description": "The Forge SDK for x402 paid APIs: agent feedback, required agent context, OpenAPI and challenge enrichment, and passive call signals. Express, Hono, Next.js and fetch handlers. No Forge network request on the merchant response path.",
5
5
  "license": "MIT",
6
6
  "type": "module",