@foldset/cloudflare 0.0.2 → 0.0.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.
Files changed (54) hide show
  1. package/dist/ai-crawlers/index.d.ts +15 -0
  2. package/dist/ai-crawlers/index.d.ts.map +1 -0
  3. package/dist/ai-crawlers/index.js +26 -0
  4. package/dist/config.d.ts +2 -0
  5. package/dist/config.d.ts.map +1 -0
  6. package/dist/config.js +1 -0
  7. package/dist/facilitators/index.d.ts +16 -0
  8. package/dist/facilitators/index.d.ts.map +1 -0
  9. package/dist/facilitators/index.js +35 -0
  10. package/dist/hono.d.ts +2 -0
  11. package/dist/hono.d.ts.map +1 -0
  12. package/dist/hono.js +1 -0
  13. package/dist/index.d.ts +8 -8
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +1 -163
  16. package/dist/payment/adapter.d.ts +16 -0
  17. package/dist/payment/adapter.d.ts.map +1 -0
  18. package/dist/payment/adapter.js +43 -0
  19. package/dist/payment/handler.d.ts +6 -0
  20. package/dist/payment/handler.d.ts.map +1 -0
  21. package/dist/payment/handler.js +86 -0
  22. package/dist/payment/paywall.d.ts +4 -0
  23. package/dist/payment/paywall.d.ts.map +1 -0
  24. package/dist/payment/paywall.js +99 -0
  25. package/dist/payment/routes.d.ts +5 -0
  26. package/dist/payment/routes.d.ts.map +1 -0
  27. package/dist/payment/routes.js +31 -0
  28. package/dist/payment/settlement.d.ts +8 -0
  29. package/dist/payment/settlement.d.ts.map +1 -0
  30. package/dist/payment/settlement.js +27 -0
  31. package/dist/payment/setup.d.ts +7 -0
  32. package/dist/payment/setup.d.ts.map +1 -0
  33. package/dist/payment/setup.js +85 -0
  34. package/dist/payment-methods/index.d.ts +18 -0
  35. package/dist/payment-methods/index.d.ts.map +1 -0
  36. package/dist/payment-methods/index.js +18 -0
  37. package/dist/restrictions/index.d.ts +16 -0
  38. package/dist/restrictions/index.d.ts.map +1 -0
  39. package/dist/restrictions/index.js +18 -0
  40. package/dist/telemetry/logging.d.ts +18 -0
  41. package/dist/telemetry/logging.d.ts.map +1 -0
  42. package/dist/telemetry/logging.js +47 -0
  43. package/dist/telemetry/sentry.d.ts +8 -0
  44. package/dist/telemetry/sentry.d.ts.map +1 -0
  45. package/dist/telemetry/sentry.js +19 -0
  46. package/dist/types.d.ts +5 -9
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/webhooks/index.d.ts +23 -0
  49. package/dist/webhooks/index.d.ts.map +1 -0
  50. package/dist/webhooks/index.js +50 -0
  51. package/package.json +21 -18
  52. package/README.md +0 -1
  53. package/dist/adapter.d.ts +0 -71
  54. package/dist/adapter.js +0 -99
@@ -0,0 +1,27 @@
1
+ import * as Sentry from "@sentry/cloudflare";
2
+ export async function handleSettlement(c, httpServer, paymentPayload, paymentRequirements, res) {
3
+ if (res.status >= 400) {
4
+ return res;
5
+ }
6
+ try {
7
+ const settleResult = await httpServer.processSettlement(paymentPayload, paymentRequirements);
8
+ if (!settleResult.success) {
9
+ Sentry.captureException(new Error(`Settlement failed: ${settleResult.errorReason}`));
10
+ return c.json({
11
+ error: "Settlement failed",
12
+ details: settleResult.errorReason,
13
+ }, 402);
14
+ }
15
+ Object.entries(settleResult.headers).forEach(([key, value]) => {
16
+ res.headers.set(key, value);
17
+ });
18
+ return res;
19
+ }
20
+ catch (error) {
21
+ Sentry.captureException(error);
22
+ return c.json({
23
+ error: "Settlement failed",
24
+ details: error instanceof Error ? error.message : "Unknown error",
25
+ }, 402);
26
+ }
27
+ }
@@ -0,0 +1,7 @@
1
+ import type { Context } from "hono";
2
+ import { x402HTTPResourceServer } from "@x402/hono";
3
+ import type { Env } from "../types";
4
+ export declare function getHttpServer(c: Context<{
5
+ Bindings: Env;
6
+ }>): Promise<x402HTTPResourceServer | null>;
7
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/payment/setup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAEL,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAMpB,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AA+DpC,wBAAsB,aAAa,CACjC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,GAAG,CAAA;CAAE,CAAC,GAC5B,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CA0CxC"}
@@ -0,0 +1,85 @@
1
+ import { x402ResourceServer, x402HTTPResourceServer, } from "@x402/hono";
2
+ import { registerExactEvmScheme } from "@x402/evm/exact/server";
3
+ import { registerExactSvmScheme } from "@x402/svm/exact/server";
4
+ import { getRestrictions } from "../restrictions";
5
+ import { getPaymentMethods } from "../payment-methods";
6
+ import { buildRoutesConfig } from "./routes";
7
+ import { getFacilitator } from "../facilitators";
8
+ import { generateHtml } from "./paywall";
9
+ const paywallProvider = {
10
+ generateHtml
11
+ };
12
+ let cachedHttpServer = null;
13
+ let cachedRestrictions = null;
14
+ let cachedPaymentMethods = null;
15
+ /**
16
+ * Custom createHTTPResponse implementation for Foldset
17
+ * Monkey-patched onto x402HTTPResourceServer instances
18
+ */
19
+ function createFoldsetHTTPResponse(paymentRequired, isWebBrowser, paywallConfig, customHtml, unpaidResponse) {
20
+ // @ts-expect-error - accessing private method
21
+ const html = this.generatePaywallHTML(paymentRequired, paywallConfig, customHtml);
22
+ // Always generate and provide
23
+ // if (isWebBrowser) {
24
+ // // @ts-expect-error - accessing private method
25
+ // const html = this.generatePaywallHTML(paymentRequired, paywallConfig, customHtml);
26
+ // return {
27
+ // status: 402,
28
+ // headers: { "Content-Type": "text/html" },
29
+ // body: html,
30
+ // isHtml: true,
31
+ // };
32
+ // }
33
+ // @ts-expect-error - accessing private method
34
+ const response = this.createHTTPPaymentRequiredResponse(paymentRequired);
35
+ // We don't provide a callback
36
+ // Use callback result if provided, otherwise default to JSON with empty object
37
+ // const contentType = unpaidResponse ? unpaidResponse.contentType : "application/json";
38
+ // const body = unpaidResponse ? unpaidResponse.body : {};
39
+ // Status should be 402 but we return 200 so AI crawlers view the payment instructions
40
+ return {
41
+ status: 200,
42
+ headers: {
43
+ "Content-Type": "text/html",
44
+ ...response.headers,
45
+ },
46
+ body: html,
47
+ isHtml: true,
48
+ };
49
+ }
50
+ // Maybe this function is never needed and can just updated cachedHttpServer on changes to upstream configs
51
+ // ie consider changing to a chained pattern
52
+ export async function getHttpServer(c) {
53
+ const restrictions = await getRestrictions(c);
54
+ const paymentMethods = await getPaymentMethods(c);
55
+ if (restrictions === null || paymentMethods === null) {
56
+ return null;
57
+ }
58
+ if (cachedHttpServer &&
59
+ restrictions === cachedRestrictions &&
60
+ paymentMethods === cachedPaymentMethods) {
61
+ return cachedHttpServer;
62
+ }
63
+ const facilitator = await getFacilitator(c);
64
+ if (facilitator === null) {
65
+ return null;
66
+ }
67
+ // This could be pulled out
68
+ const server = new x402ResourceServer(facilitator);
69
+ registerExactEvmScheme(server);
70
+ registerExactSvmScheme(server);
71
+ const routesConfig = buildRoutesConfig(restrictions, paymentMethods);
72
+ const httpServer = new x402HTTPResourceServer(server, routesConfig);
73
+ // Monkey-patch createHTTPResponse with our custom implementation
74
+ // @ts-expect-error - overriding private method
75
+ httpServer.createHTTPResponse = createFoldsetHTTPResponse;
76
+ // TODO rfradkin: This is probably the slowest part of the cold start. Figure out how to speed this up.
77
+ // Also this is slow on every request where its updated.
78
+ // Consider looking into creating a serverless facilitator so don't have to request outside the serverless environment
79
+ await httpServer.initialize();
80
+ httpServer.registerPaywallProvider(paywallProvider);
81
+ cachedHttpServer = httpServer;
82
+ cachedRestrictions = restrictions;
83
+ cachedPaymentMethods = paymentMethods;
84
+ return httpServer;
85
+ }
@@ -0,0 +1,18 @@
1
+ import type { Context } from "hono";
2
+ import type { Env } from "../types";
3
+ export interface PaymentMethod {
4
+ caip2_id: string;
5
+ decimals: number;
6
+ contract_address: string;
7
+ circle_wallet_address: string;
8
+ extra?: Record<string, string>;
9
+ chain_display_name: string;
10
+ asset_display_name: string;
11
+ }
12
+ export declare function getPaymentMethods(c: Context<{
13
+ Bindings: Env;
14
+ }>): Promise<PaymentMethod[] | null>;
15
+ export declare function storePaymentMethods(c: Context<{
16
+ Bindings: Env;
17
+ }>, paymentMethods: PaymentMethod[]): Promise<void>;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/payment-methods/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAOD,wBAAsB,iBAAiB,CACrC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,GAAG,CAAA;CAAE,CAAC,GAC5B,OAAO,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,CAUjC;AAED,wBAAsB,mBAAmB,CACvC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,GAAG,CAAA;CAAE,CAAC,EAC7B,cAAc,EAAE,aAAa,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC,CAIf"}
@@ -0,0 +1,18 @@
1
+ const CACHE_TTL_MS = 30_000;
2
+ let cachedPaymentMethods = null;
3
+ let cacheTimestamp = 0;
4
+ export async function getPaymentMethods(c) {
5
+ const now = Date.now();
6
+ if (cachedPaymentMethods !== null && now - cacheTimestamp < CACHE_TTL_MS) {
7
+ return cachedPaymentMethods;
8
+ }
9
+ const response = await c.env.FOLDSET_CONFIG.get("payment-methods");
10
+ cachedPaymentMethods = response ? JSON.parse(response) : null;
11
+ cacheTimestamp = now;
12
+ return cachedPaymentMethods;
13
+ }
14
+ export async function storePaymentMethods(c, paymentMethods) {
15
+ await c.env.FOLDSET_CONFIG.put("payment-methods", JSON.stringify(paymentMethods), {
16
+ expirationTtl: 60 * 60 * 3 + 60 * 30, // 3 hours + 30 minutes
17
+ });
18
+ }
@@ -0,0 +1,16 @@
1
+ import type { Context } from "hono";
2
+ import type { Env } from "../types";
3
+ export interface Restriction {
4
+ host: string;
5
+ path: string;
6
+ description: string;
7
+ price: number;
8
+ scheme: string;
9
+ }
10
+ export declare function getRestrictions(c: Context<{
11
+ Bindings: Env;
12
+ }>): Promise<Restriction[] | null>;
13
+ export declare function storeRestrictions(c: Context<{
14
+ Bindings: Env;
15
+ }>, restrictions: Restriction[]): Promise<void>;
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/restrictions/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAOD,wBAAsB,eAAe,CACnC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,GAAG,CAAA;CAAE,CAAC,GAC5B,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,CAU/B;AAED,wBAAsB,iBAAiB,CACrC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,GAAG,CAAA;CAAE,CAAC,EAC7B,YAAY,EAAE,WAAW,EAAE,GAC1B,OAAO,CAAC,IAAI,CAAC,CAIf"}
@@ -0,0 +1,18 @@
1
+ const CACHE_TTL_MS = 30_000;
2
+ let cachedRestrictions = null;
3
+ let cacheTimestamp = 0;
4
+ export async function getRestrictions(c) {
5
+ const now = Date.now();
6
+ if (cachedRestrictions !== null && now - cacheTimestamp < CACHE_TTL_MS) {
7
+ return cachedRestrictions;
8
+ }
9
+ const response = await c.env.FOLDSET_CONFIG.get("restrictions");
10
+ cachedRestrictions = response ? JSON.parse(response) : null;
11
+ cacheTimestamp = now;
12
+ return cachedRestrictions;
13
+ }
14
+ export async function storeRestrictions(c, restrictions) {
15
+ await c.env.FOLDSET_CONFIG.put("restrictions", JSON.stringify(restrictions), {
16
+ expirationTtl: 60 * 60 * 3 + 60 * 30, // 3 hours + 30 minutes
17
+ });
18
+ }
@@ -0,0 +1,18 @@
1
+ import type { Context } from "hono";
2
+ import type { Env } from "../types";
3
+ export type EventPayload = {
4
+ method: string;
5
+ status_code: number;
6
+ user_agent: string | null;
7
+ referer?: string | null;
8
+ href: string;
9
+ hostname: string;
10
+ pathname: string;
11
+ search: string;
12
+ ip_address?: string | null;
13
+ payment_response?: string;
14
+ };
15
+ export declare function logVisitEvent(c: Context<{
16
+ Bindings: Env;
17
+ }>, response: Response): void;
18
+ //# sourceMappingURL=logging.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../src/telemetry/logging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAIpC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAIpC,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,GAAG,CAAA;CAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,QA8C9E"}
@@ -0,0 +1,47 @@
1
+ import * as Sentry from "@sentry/cloudflare";
2
+ import { API_BASE_URL } from "../config";
3
+ const PAYMENT_RESPONSE_HEADER = "PAYMENT-RESPONSE";
4
+ export function logVisitEvent(c, response) {
5
+ const url = new URL(c.req.url);
6
+ const ipAddressHeader = c.req.header("cf-connecting-ip") || c.req.header("x-forwarded-for");
7
+ const ipAddress = ipAddressHeader?.split(",")[0]?.trim() || null;
8
+ const paymentResponse = response.headers.get(PAYMENT_RESPONSE_HEADER) || undefined;
9
+ const payload = {
10
+ method: c.req.method,
11
+ status_code: response.status,
12
+ user_agent: c.req.header("user-agent") || null,
13
+ referer: c.req.header("referer") || null,
14
+ href: url.href,
15
+ hostname: url.hostname,
16
+ pathname: url.pathname,
17
+ search: url.search,
18
+ ip_address: ipAddress,
19
+ ...(paymentResponse ? { payment_response: paymentResponse } : {}),
20
+ };
21
+ const requestPromise = fetch(`${API_BASE_URL}/events`, {
22
+ method: "POST",
23
+ headers: {
24
+ Authorization: `Bearer ${c.env.FOLDSET_API_KEY}`,
25
+ "Content-Type": "application/json",
26
+ Accept: "application/json",
27
+ },
28
+ body: JSON.stringify(payload),
29
+ }).catch((error) => {
30
+ Sentry.captureException(error, {
31
+ extra: {
32
+ method: "POST",
33
+ url: `${API_BASE_URL}/events`,
34
+ headers: {
35
+ Authorization: `Bearer ${c.env.FOLDSET_API_KEY}`,
36
+ "Content-Type": "application/json",
37
+ Accept: "application/json",
38
+ },
39
+ body: JSON.stringify(payload),
40
+ },
41
+ tags: {
42
+ endpoint: "/events",
43
+ },
44
+ });
45
+ });
46
+ c.executionCtx.waitUntil(requestPromise);
47
+ }
@@ -0,0 +1,8 @@
1
+ import type { ExecutionContext } from "@cloudflare/workers-types";
2
+ type SentryWrapperArgs = {
3
+ request: Request;
4
+ context: ExecutionContext;
5
+ };
6
+ export declare const wrappedPaymentHandler: (wrapperArgs: SentryWrapperArgs, handler: () => Promise<Response>) => Promise<Response>;
7
+ export {};
8
+ //# sourceMappingURL=sentry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentry.d.ts","sourceRoot":"","sources":["../../src/telemetry/sentry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAIlE,KAAK,iBAAiB,GAAG;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,gBAAgB,CAAC;CAC3B,CAAC;AAuBF,eAAO,MAAM,qBAAqB,gBAnBX,iBAAiB,WAAW,MAAM,OAAO,CAAC,QAAQ,CAAC,sBAmBE,CAAC"}
@@ -0,0 +1,19 @@
1
+ import * as Sentry from "@sentry/cloudflare";
2
+ const SENTRY_DSN = "https://f68380669974dab9bbcf5aec9414bcb8@o4510648631296000.ingest.us.sentry.io/4510718170038272";
3
+ // TODO rfradkin: Add webhook support for updating this
4
+ function createWrappedPaymentHandler(dsn) {
5
+ return (wrapperArgs, handler) => {
6
+ if (!dsn) {
7
+ return handler();
8
+ }
9
+ return Sentry.wrapRequestHandler({
10
+ options: {
11
+ dsn,
12
+ sendDefaultPii: true,
13
+ },
14
+ request: wrapperArgs.request,
15
+ context: wrapperArgs.context,
16
+ }, handler);
17
+ };
18
+ }
19
+ export const wrappedPaymentHandler = createWrappedPaymentHandler(SENTRY_DSN);
package/dist/types.d.ts CHANGED
@@ -1,10 +1,6 @@
1
- export type Price = number;
2
- export type Pathname = string;
3
- export type Restriction = {
4
- price: Price;
5
- pathname: Pathname;
6
- };
7
- export type Restrictions = Record<Pathname, Price>;
8
- export type AddressResponse = {
9
- address: string;
1
+ import type { KVNamespace } from "@cloudflare/workers-types";
2
+ export type Env = {
3
+ FOLDSET_API_KEY: string;
4
+ FOLDSET_CONFIG: KVNamespace;
10
5
  };
6
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,MAAM,GAAG,GAAG;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,WAAW,CAAC;CAC7B,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { Context } from "hono";
2
+ import type { Env } from "../types";
3
+ import { type Restriction } from "../restrictions";
4
+ import { type PaymentMethod } from "../payment-methods";
5
+ import { type AiCrawler } from "../ai-crawlers";
6
+ import { type FacilitatorConfig } from "../facilitators";
7
+ export type FoldsetWebhook = {
8
+ event_type: "restrictions";
9
+ event_object: Restriction[];
10
+ } | {
11
+ event_type: "payment-methods";
12
+ event_object: PaymentMethod[];
13
+ } | {
14
+ event_type: "ai-crawlers";
15
+ event_object: AiCrawler[];
16
+ } | {
17
+ event_type: "facilitator";
18
+ event_object: FacilitatorConfig;
19
+ };
20
+ export declare function handleWebhook(c: Context<{
21
+ Bindings: Env;
22
+ }>): Promise<Response>;
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/webhooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,KAAK,aAAa,EAAuB,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,KAAK,iBAAiB,EAAoB,MAAM,iBAAiB,CAAC;AAE3E,MAAM,MAAM,cAAc,GACtB;IAAE,UAAU,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,WAAW,EAAE,CAAA;CAAE,GAC3D;IAAE,UAAU,EAAE,iBAAiB,CAAC;IAAC,YAAY,EAAE,aAAa,EAAE,CAAA;CAAE,GAChE;IAAE,UAAU,EAAE,aAAa,CAAC;IAAC,YAAY,EAAE,SAAS,EAAE,CAAA;CAAE,GACxD;IAAE,UAAU,EAAE,aAAa,CAAC;IAAC,YAAY,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAgCnE,wBAAsB,aAAa,CAAC,CAAC,EAAE,OAAO,CAAC;IAAE,QAAQ,EAAE,GAAG,CAAA;CAAE,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0BpF"}
@@ -0,0 +1,50 @@
1
+ import { storeRestrictions } from "../restrictions";
2
+ import { storePaymentMethods } from "../payment-methods";
3
+ import { storeAiCrawlers } from "../ai-crawlers";
4
+ import { storeFacilitator } from "../facilitators";
5
+ async function verifySignature(body, signature, apiKey) {
6
+ const encoder = new TextEncoder();
7
+ const keyHashBuffer = await crypto.subtle.digest("SHA-256", encoder.encode(apiKey));
8
+ const hashedKeyHex = Array.from(new Uint8Array(keyHashBuffer))
9
+ .map((b) => b.toString(16).padStart(2, "0"))
10
+ .join("");
11
+ const hmacKey = await crypto.subtle.importKey("raw", encoder.encode(hashedKeyHex), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
12
+ const expectedSig = await crypto.subtle.sign("HMAC", hmacKey, encoder.encode(body));
13
+ const expectedHex = Array.from(new Uint8Array(expectedSig))
14
+ .map((b) => b.toString(16).padStart(2, "0"))
15
+ .join("");
16
+ // Timing-safe comparison
17
+ if (signature.length !== expectedHex.length)
18
+ return false;
19
+ let result = 0;
20
+ for (let i = 0; i < signature.length; i++) {
21
+ result |= signature.charCodeAt(i) ^ expectedHex.charCodeAt(i);
22
+ }
23
+ return result === 0;
24
+ }
25
+ export async function handleWebhook(c) {
26
+ const signature = c.req.header("X-Foldset-Signature");
27
+ if (!signature) {
28
+ return new Response("Missing signature", { status: 401 });
29
+ }
30
+ const body = await c.req.text();
31
+ const isValid = await verifySignature(body, signature, c.env.FOLDSET_API_KEY);
32
+ if (!isValid) {
33
+ return new Response("Invalid signature", { status: 401 });
34
+ }
35
+ const webhook = JSON.parse(body);
36
+ // Fails the entire webhook if the put fails. Not standard but think it makes sense for now
37
+ if (webhook.event_type === "restrictions") {
38
+ await storeRestrictions(c, webhook.event_object);
39
+ }
40
+ else if (webhook.event_type === "payment-methods") {
41
+ await storePaymentMethods(c, webhook.event_object);
42
+ }
43
+ else if (webhook.event_type === "ai-crawlers") {
44
+ await storeAiCrawlers(c, webhook.event_object);
45
+ }
46
+ else if (webhook.event_type === "facilitator") {
47
+ await storeFacilitator(c, webhook.event_object);
48
+ }
49
+ return new Response("Ok", { status: 200 });
50
+ }
package/package.json CHANGED
@@ -1,34 +1,37 @@
1
1
  {
2
2
  "name": "@foldset/cloudflare",
3
- "version": "0.0.2",
4
- "description": "SDK for creating Foldset-enabled Cloudflare Workers",
5
- "type": "module",
3
+ "version": "0.0.3",
4
+ "private": false,
6
5
  "main": "./dist/index.js",
7
6
  "types": "./dist/index.d.ts",
8
7
  "exports": {
9
8
  ".": {
10
9
  "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
10
+ "default": "./dist/index.js"
11
+ },
12
+ "./hono": {
13
+ "types": "./dist/hono.d.ts",
14
+ "default": "./dist/hono.js"
12
15
  }
13
16
  },
14
17
  "files": [
15
18
  "dist"
16
19
  ],
17
- "keywords": [
18
- "foldset",
19
- "cloudflare",
20
- "workers",
21
- "x402"
22
- ],
23
- "license": "MIT",
20
+ "scripts": {
21
+ "typegen": "wrangler types --path types/worker-configuration.d.ts",
22
+ "build": "tsc -p tsconfig.json --noEmit false --outDir dist --rootDir src"
23
+ },
24
24
  "dependencies": {
25
- "@x402/core": "^2.1.0",
26
- "@x402/evm": "^2.1.0",
27
- "@x402/hono": "^2.1.0",
28
- "hono": "^4.11.3",
29
- "p-memoize": "^8.0.0"
25
+ "@cloudflare/workers-types": "^4.20260117.0",
26
+ "@sentry/cloudflare": "^10.34.0",
27
+ "@x402/core": "^2.2.0",
28
+ "@x402/evm": "^2.2.0",
29
+ "@x402/hono": "^2.2.0",
30
+ "@x402/svm": "^2.2.0",
31
+ "hono": "^4.11.4"
30
32
  },
31
- "scripts": {
32
- "build": "tsc"
33
+ "devDependencies": {
34
+ "typescript": "^5.9.3",
35
+ "wrangler": "^4.59.1"
33
36
  }
34
37
  }
package/README.md DELETED
@@ -1 +0,0 @@
1
- # Typescript library for foldset?
package/dist/adapter.d.ts DELETED
@@ -1,71 +0,0 @@
1
- import { HTTPAdapter } from "@x402/core/server";
2
- import { Context } from "hono";
3
- /**
4
- * Hono adapter implementation
5
- */
6
- export declare class HonoAdapter implements HTTPAdapter {
7
- private c;
8
- /**
9
- * Creates a new HonoAdapter instance.
10
- *
11
- * @param c - The Hono context object
12
- */
13
- constructor(c: Context);
14
- /**
15
- * Gets a header value from the request.
16
- *
17
- * @param name - The header name
18
- * @returns The header value or undefined
19
- */
20
- getHeader(name: string): string | undefined;
21
- /**
22
- * Gets the HTTP method of the request.
23
- *
24
- * @returns The HTTP method
25
- */
26
- getMethod(): string;
27
- /**
28
- * Gets the path of the request.
29
- *
30
- * @returns The request path
31
- */
32
- getPath(): string;
33
- /**
34
- * Gets the full URL of the request.
35
- *
36
- * @returns The full request URL
37
- */
38
- getUrl(): string;
39
- /**
40
- * Gets the Accept header from the request.
41
- *
42
- * @returns The Accept header value or empty string
43
- */
44
- getAcceptHeader(): string;
45
- /**
46
- * Gets the User-Agent header from the request.
47
- *
48
- * @returns The User-Agent header value or empty string
49
- */
50
- getUserAgent(): string;
51
- /**
52
- * Gets all query parameters from the request URL.
53
- *
54
- * @returns Record of query parameter key-value pairs
55
- */
56
- getQueryParams(): Record<string, string | string[]>;
57
- /**
58
- * Gets a specific query parameter by name.
59
- *
60
- * @param name - The query parameter name
61
- * @returns The query parameter value(s) or undefined
62
- */
63
- getQueryParam(name: string): string | string[] | undefined;
64
- /**
65
- * Gets the parsed request body.
66
- * Requires appropriate body parsing middleware.
67
- *
68
- * @returns The parsed request body
69
- */
70
- getBody(): Promise<unknown>;
71
- }
package/dist/adapter.js DELETED
@@ -1,99 +0,0 @@
1
- /**
2
- * Hono adapter implementation
3
- */
4
- export class HonoAdapter {
5
- /**
6
- * Creates a new HonoAdapter instance.
7
- *
8
- * @param c - The Hono context object
9
- */
10
- constructor(c) {
11
- this.c = c;
12
- }
13
- /**
14
- * Gets a header value from the request.
15
- *
16
- * @param name - The header name
17
- * @returns The header value or undefined
18
- */
19
- getHeader(name) {
20
- return this.c.req.header(name);
21
- }
22
- /**
23
- * Gets the HTTP method of the request.
24
- *
25
- * @returns The HTTP method
26
- */
27
- getMethod() {
28
- return this.c.req.method;
29
- }
30
- /**
31
- * Gets the path of the request.
32
- *
33
- * @returns The request path
34
- */
35
- getPath() {
36
- return this.c.req.path;
37
- }
38
- /**
39
- * Gets the full URL of the request.
40
- *
41
- * @returns The full request URL
42
- */
43
- getUrl() {
44
- return this.c.req.url;
45
- }
46
- /**
47
- * Gets the Accept header from the request.
48
- *
49
- * @returns The Accept header value or empty string
50
- */
51
- getAcceptHeader() {
52
- return this.c.req.header("Accept") || "";
53
- }
54
- /**
55
- * Gets the User-Agent header from the request.
56
- *
57
- * @returns The User-Agent header value or empty string
58
- */
59
- getUserAgent() {
60
- return this.c.req.header("User-Agent") || "";
61
- }
62
- /**
63
- * Gets all query parameters from the request URL.
64
- *
65
- * @returns Record of query parameter key-value pairs
66
- */
67
- getQueryParams() {
68
- const query = this.c.req.query();
69
- // Convert single values to match the interface
70
- const result = {};
71
- for (const [key, value] of Object.entries(query)) {
72
- result[key] = value;
73
- }
74
- return result;
75
- }
76
- /**
77
- * Gets a specific query parameter by name.
78
- *
79
- * @param name - The query parameter name
80
- * @returns The query parameter value(s) or undefined
81
- */
82
- getQueryParam(name) {
83
- return this.c.req.query(name);
84
- }
85
- /**
86
- * Gets the parsed request body.
87
- * Requires appropriate body parsing middleware.
88
- *
89
- * @returns The parsed request body
90
- */
91
- async getBody() {
92
- try {
93
- return await this.c.req.json();
94
- }
95
- catch {
96
- return undefined;
97
- }
98
- }
99
- }