@waffo/pancake-ts 0.1.1 → 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/CHANGELOG.md ADDED
@@ -0,0 +1,47 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@waffo/pancake-ts` will be documented in this file.
4
+
5
+ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.1.3] - 2026-03-11
8
+
9
+ ### Added
10
+
11
+ - **Private key normalization** — `privateKey` is automatically normalized at construction time. Accepts literal `\n` from environment variables, Windows `\r\n` line endings, raw base64 without PEM headers, single-line base64, and PKCS#1 (`BEGIN RSA PRIVATE KEY`) format. Invalid or empty keys throw a descriptive error immediately instead of failing on the first API call.
12
+ - **Checkout integration guide** in README — Step-by-step instructions (Issue Token → Create Session → Open Checkout Page) with recommendation to open the checkout URL in a new browser tab.
13
+
14
+ ## [0.1.2] - 2026-03-11
15
+
16
+ ### Fixed
17
+
18
+ - **Signing** — Body hash encoding changed from `hex` to `base64` to match auth-service canonical request format
19
+
20
+ ## [0.1.1] - 2026-03-10
21
+
22
+ ### Changed
23
+
24
+ - **Build** — Switch from `tsc` to `tsup`, output ESM + CJS dual format
25
+ - **Package** — Rename from `@waffo-pancake/sdk` to `@waffo/pancake-ts`
26
+ - **CI/CD** — Add GitHub Actions workflow (`ci-cd.yml`) with lint, test, coverage, build, and npm publish on `v*` tag
27
+ - **Node** — Minimum Node version raised from 18 to 20 (`@vitest/coverage-v8` requires `node:inspector/promises`)
28
+
29
+ ## [0.1.0] - 2026-03-10
30
+
31
+ ### Added
32
+
33
+ - **Client** — `WaffoPancake` SDK client with RSA-SHA256 request signing and deterministic idempotency key (`X-Idempotency-Key = SHA256(merchantId:path:body)`)
34
+ - **Auth** — `client.auth.issueSessionToken()` for buyer session token issuance
35
+ - **Stores** — `client.stores.create()` / `update()` / `delete()` for store management (webhook, notification, checkout settings)
36
+ - **Store Merchants** — `client.storeMerchants.add()` / `remove()` / `updateRole()` (endpoints return 501, coming soon)
37
+ - **Onetime Products** — `client.onetimeProducts.create()` / `update()` / `publish()` / `updateStatus()` with multi-currency pricing
38
+ - **Subscription Products** — `client.subscriptionProducts.create()` / `update()` / `publish()` / `updateStatus()` with billing period support
39
+ - **Subscription Product Groups** — `client.subscriptionProductGroups.create()` / `update()` / `delete()` / `publish()` for shared trial and plan switching
40
+ - **Orders** — `client.orders.cancelSubscription()` with status machine (pending→canceled, active→canceling)
41
+ - **Checkout** — `client.checkout.createSession()` with trial toggle, billing detail, price snapshot, and metadata
42
+ - **GraphQL** — `client.graphql.query<T>()` for typed GraphQL queries (Query only, no Mutations)
43
+ - **Webhooks** — `verifyWebhook()` with embedded RSA-SHA256 public keys (test/prod), auto environment detection, and replay protection (default 5min tolerance)
44
+ - **Error handling** — `WaffoPancakeError` with HTTP status and call-stack-ordered `errors` array
45
+ - **Types** — 15 runtime enums, 40+ TypeScript interfaces covering all API resources
46
+ - **Engineering** — ESLint 9 (TypeScript ESLint + import order + naming convention + JSDoc), Vitest 4 with v8 coverage, `tsconfig.build.json` for clean `dist/` output
47
+ - **Documentation** — Split into focused documents: README (project intro), `docs/api-reference.md` (complete API reference), `docs/graphql-guide.md` (GraphQL usage guide), `docs/webhook-guide.md` (webhook verification guide)
package/README.md CHANGED
@@ -56,10 +56,32 @@ const result = await client.graphql.query<{ stores: Array<{ id: string; name: st
56
56
  | Parameter | Type | Required | Description |
57
57
  |-----------|------|----------|-------------|
58
58
  | `merchantId` | `string` | Yes | Merchant ID, sent as `X-Merchant-Id` header |
59
- | `privateKey` | `string` | Yes | RSA private key in PEM format for request signing |
59
+ | `privateKey` | `string` | Yes | RSA private key (see [Private Key Formats](#private-key-formats) below) |
60
60
  | `baseUrl` | `string` | No | API base URL (default: `https://waffo-pancake-auth-service.vercel.app`) |
61
61
  | `fetch` | `typeof fetch` | No | Custom fetch implementation |
62
62
 
63
+ ### Private Key Formats
64
+
65
+ The SDK automatically normalizes `privateKey` at construction time, so all of the following formats are accepted:
66
+
67
+ | Format | Example | Notes |
68
+ |--------|---------|-------|
69
+ | Standard PKCS#8 PEM | `-----BEGIN PRIVATE KEY-----\n...` | Recommended |
70
+ | PKCS#1 PEM | `-----BEGIN RSA PRIVATE KEY-----\n...` | Also accepted |
71
+ | Literal `\n` (env vars) | `"-----BEGIN PRIVATE KEY-----\\nMIIE..."` | Common when stored in `.env` or CI secrets |
72
+ | Windows line endings | `\r\n` | Converted to `\n` |
73
+ | Raw base64 (no headers) | `MIIEvQIBADANBgkqhki...` | Wrapped with PKCS#8 headers automatically |
74
+ | Single-line base64 with headers | Header + all base64 on one line + footer | Re-wrapped to 64-char lines |
75
+
76
+ If the key is invalid or empty, the constructor throws a descriptive error immediately rather than failing silently on the first API call.
77
+
78
+ ```typescript
79
+ // All of these work:
80
+ new WaffoPancake({ merchantId: "m_1", privateKey: process.env.PRIVATE_KEY! }); // .env with literal \n
81
+ new WaffoPancake({ merchantId: "m_1", privateKey: fs.readFileSync("key.pem", "utf8") }); // file read
82
+ new WaffoPancake({ merchantId: "m_1", privateKey: rawBase64String }); // raw base64
83
+ ```
84
+
63
85
  ## Resources
64
86
 
65
87
  | Namespace | Methods | Description |
@@ -76,6 +98,114 @@ const result = await client.graphql.query<{ stores: Array<{ id: string; name: st
76
98
 
77
99
  See [API Reference](docs/api-reference.md) for complete parameter tables and return types.
78
100
 
101
+ ## Checkout Integration
102
+
103
+ Guide buyers from your site to the Waffo checkout page in three steps:
104
+
105
+ ```
106
+ 1. Issue Session Token → Obtain a buyer identity credential (JWT)
107
+ 2. Create Checkout Session → Create a session and get the checkout URL
108
+ 3. Open Checkout Page → Open the checkout in a new browser tab
109
+ ```
110
+
111
+ ### Step 1 — Issue a Session Token
112
+
113
+ Your backend requests a Session Token on behalf of the buyer. The token carries the buyer's identity and is used by the checkout page to load order details and place orders.
114
+
115
+ ```typescript
116
+ const { token } = await client.auth.issueSessionToken({
117
+ storeId: "store_xxx",
118
+ buyerIdentity: "customer@example.com",
119
+ });
120
+ ```
121
+
122
+ ### Step 2 — Create a Checkout Session
123
+
124
+ Create a checkout session with your API Key. The response includes a checkout URL with the token embedded in the URL fragment.
125
+
126
+ ```typescript
127
+ import { CheckoutSessionProductType } from "@waffo/pancake-ts";
128
+
129
+ const session = await client.checkout.createSession({
130
+ storeId: "store_xxx",
131
+ productId: "prod_xxx",
132
+ productType: CheckoutSessionProductType.Onetime,
133
+ currency: "USD",
134
+ buyerEmail: "customer@example.com",
135
+ successUrl: "https://example.com/thank-you",
136
+ });
137
+ // session.checkoutUrl format:
138
+ // https://waffo.ai/store/{slug}/checkout/{sessionId}#token={JWT}
139
+ ```
140
+
141
+ The token is passed via the URL fragment (after `#`), which is never sent to the server and never appears in the `Referer` header.
142
+
143
+ ### Step 3 — Open Checkout Page (New Tab)
144
+
145
+ **We recommend opening the checkout page in a new tab** rather than navigating in the current page. Benefits:
146
+
147
+ - Buyers can return to your site immediately after payment or if they close the checkout tab
148
+ - Merchant page state (cart, forms, scroll position) is preserved
149
+ - Payment flow is decoupled from the browsing experience, reducing checkout abandonment
150
+
151
+ ```typescript
152
+ // Frontend — recommended: open in a new tab
153
+ window.open(session.checkoutUrl, "_blank", "noopener,noreferrer");
154
+
155
+ // Or via an <a> tag
156
+ // <a href={checkoutUrl} target="_blank" rel="noopener noreferrer">Proceed to Checkout</a>
157
+ ```
158
+
159
+ > **Not recommended:** `window.location.href = session.checkoutUrl` replaces the current page, preventing buyers from returning to your site without browser back navigation.
160
+
161
+ ### Complete Example (Express)
162
+
163
+ ```typescript
164
+ import express from "express";
165
+ import { WaffoPancake, CheckoutSessionProductType } from "@waffo/pancake-ts";
166
+
167
+ const client = new WaffoPancake({
168
+ merchantId: process.env.WAFFO_MERCHANT_ID!,
169
+ privateKey: process.env.WAFFO_PRIVATE_KEY!,
170
+ });
171
+
172
+ const app = express();
173
+
174
+ app.post("/api/checkout", async (req, res) => {
175
+ const { productId, currency, buyerEmail } = req.body;
176
+
177
+ // Step 1: Issue session token
178
+ const { token } = await client.auth.issueSessionToken({
179
+ storeId: "store_xxx",
180
+ buyerIdentity: buyerEmail,
181
+ });
182
+
183
+ // Step 2: Create checkout session
184
+ const session = await client.checkout.createSession({
185
+ storeId: "store_xxx",
186
+ productId,
187
+ productType: CheckoutSessionProductType.Onetime,
188
+ currency,
189
+ buyerEmail,
190
+ successUrl: "https://example.com/thank-you",
191
+ });
192
+
193
+ // Return URL to frontend (frontend opens in new tab)
194
+ res.json({ checkoutUrl: session.checkoutUrl });
195
+ });
196
+ ```
197
+
198
+ ```typescript
199
+ // Frontend
200
+ const res = await fetch("/api/checkout", {
201
+ method: "POST",
202
+ headers: { "Content-Type": "application/json" },
203
+ body: JSON.stringify({ productId: "prod_xxx", currency: "USD", buyerEmail: "customer@example.com" }),
204
+ });
205
+ const { checkoutUrl } = await res.json();
206
+ window.open(checkoutUrl, "_blank", "noopener,noreferrer");
207
+ ```
208
+
79
209
  ## Usage Examples
80
210
 
81
211
  ### Auth — Issue a Buyer Session Token
package/dist/index.cjs CHANGED
@@ -59,8 +59,57 @@ var WaffoPancakeError = class extends Error {
59
59
 
60
60
  // src/signing.ts
61
61
  var import_node_crypto = require("crypto");
62
+ var PKCS8_HEADER = "-----BEGIN PRIVATE KEY-----";
63
+ var PKCS8_FOOTER = "-----END PRIVATE KEY-----";
64
+ var PKCS1_HEADER = "-----BEGIN RSA PRIVATE KEY-----";
65
+ var PKCS1_FOOTER = "-----END RSA PRIVATE KEY-----";
66
+ function normalizePrivateKey(raw) {
67
+ if (!raw || !raw.trim()) {
68
+ throw new Error(
69
+ "Private key is empty. Provide an RSA private key in PEM format."
70
+ );
71
+ }
72
+ let pem = raw.replace(/\\n/g, "\n").replace(/\r\n/g, "\n");
73
+ pem = pem.trim();
74
+ const hasPkcs8Header = pem.includes(PKCS8_HEADER);
75
+ const hasPkcs1Header = pem.includes(PKCS1_HEADER);
76
+ const hasHeader = hasPkcs8Header || hasPkcs1Header;
77
+ if (hasHeader) {
78
+ const base64 = pem.replace(/-----BEGIN (?:RSA )?PRIVATE KEY-----/g, "").replace(/-----END (?:RSA )?PRIVATE KEY-----/g, "").replace(/\s+/g, "");
79
+ if (!base64) {
80
+ throw new Error(
81
+ "Private key contains PEM headers but no key data. Check the key content."
82
+ );
83
+ }
84
+ const header = hasPkcs1Header ? PKCS1_HEADER : PKCS8_HEADER;
85
+ const footer = hasPkcs1Header ? PKCS1_FOOTER : PKCS8_FOOTER;
86
+ const wrapped = base64.match(/.{1,64}/g).join("\n");
87
+ pem = `${header}
88
+ ${wrapped}
89
+ ${footer}`;
90
+ } else {
91
+ const base64 = pem.replace(/\s+/g, "");
92
+ if (!/^[A-Za-z0-9+/]+=*$/.test(base64)) {
93
+ throw new Error(
94
+ "Private key is not valid PEM or base64. Expected an RSA private key in PEM format or raw base64."
95
+ );
96
+ }
97
+ const wrapped = base64.match(/.{1,64}/g).join("\n");
98
+ pem = `${PKCS8_HEADER}
99
+ ${wrapped}
100
+ ${PKCS8_FOOTER}`;
101
+ }
102
+ try {
103
+ (0, import_node_crypto.createPrivateKey)(pem);
104
+ } catch {
105
+ throw new Error(
106
+ "Private key could not be parsed. Ensure it is a valid RSA private key in PKCS#8 or PKCS#1 (PEM) format."
107
+ );
108
+ }
109
+ return pem;
110
+ }
62
111
  function signRequest(method, path, timestamp, body, privateKey) {
63
- const bodyHash = (0, import_node_crypto.createHash)("sha256").update(body).digest("hex");
112
+ const bodyHash = (0, import_node_crypto.createHash)("sha256").update(body).digest("base64");
64
113
  const canonicalRequest = `${method}
65
114
  ${path}
66
115
  ${timestamp}
@@ -79,7 +128,7 @@ var HttpClient = class {
79
128
  _fetch;
80
129
  constructor(config) {
81
130
  this.merchantId = config.merchantId;
82
- this.privateKey = config.privateKey;
131
+ this.privateKey = normalizePrivateKey(config.privateKey);
83
132
  this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
84
133
  this._fetch = config.fetch ?? fetch;
85
134
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/http-client.ts","../src/errors.ts","../src/signing.ts","../src/resources/auth.ts","../src/resources/checkout.ts","../src/resources/graphql.ts","../src/resources/onetime-products.ts","../src/resources/orders.ts","../src/resources/store-merchants.ts","../src/resources/stores.ts","../src/resources/subscription-product-groups.ts","../src/resources/subscription-products.ts","../src/client.ts","../src/webhooks.ts","../src/types.ts"],"sourcesContent":["// Client\nexport { WaffoPancake } from \"./client.js\";\n\n// Errors\nexport { WaffoPancakeError } from \"./errors.js\";\n\n// Webhooks\nexport { verifyWebhook } from \"./webhooks.js\";\n\n// Enums (runtime values)\nexport {\n BillingPeriod,\n CheckoutSessionProductType,\n EntityStatus,\n Environment,\n ErrorLayer,\n MediaType,\n OnetimeOrderStatus,\n PaymentStatus,\n ProductVersionStatus,\n RefundStatus,\n RefundTicketStatus,\n StoreRole,\n SubscriptionOrderStatus,\n TaxCategory,\n WebhookEventType,\n} from \"./types.js\";\n\n// Types (interfaces & type aliases)\nexport type {\n // Config\n WaffoPancakeConfig,\n\n // Response envelope\n ApiError,\n ApiErrorResponse,\n ApiResponse,\n ApiSuccessResponse,\n\n // Auth\n IssueSessionTokenParams,\n SessionToken,\n\n // Store\n CheckoutSettings,\n CheckoutThemeSettings,\n CreateStoreParams,\n DeleteStoreParams,\n NotificationSettings,\n Store,\n UpdateStoreParams,\n WebhookSettings,\n\n // Store Merchant\n AddMerchantParams,\n AddMerchantResult,\n RemoveMerchantParams,\n RemoveMerchantResult,\n UpdateRoleParams,\n UpdateRoleResult,\n\n // Product shared\n MediaItem,\n PriceInfo,\n Prices,\n\n // Onetime Product\n CreateOnetimeProductParams,\n OnetimeProductDetail,\n PublishOnetimeProductParams,\n UpdateOnetimeProductParams,\n UpdateOnetimeStatusParams,\n\n // Subscription Product\n CreateSubscriptionProductParams,\n PublishSubscriptionProductParams,\n SubscriptionProductDetail,\n UpdateSubscriptionProductParams,\n UpdateSubscriptionStatusParams,\n\n // Subscription Product Group\n CreateSubscriptionProductGroupParams,\n DeleteSubscriptionProductGroupParams,\n GroupRules,\n PublishSubscriptionProductGroupParams,\n SubscriptionProductGroup,\n UpdateSubscriptionProductGroupParams,\n\n // Order\n BillingDetail,\n CancelSubscriptionParams,\n CancelSubscriptionResult,\n CheckoutSessionResult,\n CreateCheckoutSessionParams,\n\n // GraphQL\n GraphQLParams,\n GraphQLResponse,\n\n // Webhook\n VerifyWebhookOptions,\n WebhookEvent,\n WebhookEventData,\n} from \"./types.js\";\n","import { createHash } from \"node:crypto\";\n\nimport { WaffoPancakeError } from \"./errors.js\";\nimport { signRequest } from \"./signing.js\";\n\nimport type { ApiResponse, WaffoPancakeConfig } from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://waffo-pancake-auth-service.vercel.app\";\n\n/**\n * Internal HTTP client that auto-signs requests and attaches idempotency keys.\n *\n * Not exported publicly — used by resource classes via {@link WaffoPancake}.\n */\nexport class HttpClient {\n private readonly merchantId: string;\n private readonly privateKey: string;\n private readonly baseUrl: string;\n private readonly _fetch: typeof fetch;\n\n constructor(config: WaffoPancakeConfig) {\n this.merchantId = config.merchantId;\n this.privateKey = config.privateKey;\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this._fetch = config.fetch ?? fetch;\n }\n\n /**\n * Send a signed POST request and return the parsed `data` field.\n *\n * Behavior:\n * - Generates a deterministic `X-Idempotency-Key` from `merchantId + path + body` (same request produces same key)\n * - Auto-builds RSA-SHA256 signature (`X-Merchant-Id` / `X-Timestamp` / `X-Signature`)\n * - Unwraps the response envelope: returns `data` on success, throws `WaffoPancakeError` on failure\n *\n * @param path - API path (e.g. `/v1/actions/store/create-store`)\n * @param body - Request body object\n * @returns Parsed `data` field from the response\n * @throws {WaffoPancakeError} When the API returns errors\n */\n async post<T>(path: string, body: object): Promise<T> {\n const bodyStr = JSON.stringify(body);\n const timestamp = Math.floor(Date.now() / 1000).toString();\n const signature = signRequest(\"POST\", path, timestamp, bodyStr, this.privateKey);\n\n const response = await this._fetch(`${this.baseUrl}${path}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Merchant-Id\": this.merchantId,\n \"X-Timestamp\": timestamp,\n \"X-Signature\": signature,\n \"X-Idempotency-Key\": createHash(\"sha256\")\n .update(`${this.merchantId}:${path}:${bodyStr}`)\n .digest(\"hex\"),\n },\n body: bodyStr,\n });\n\n const result = (await response.json()) as ApiResponse<T>;\n\n if (\"errors\" in result && result.errors) {\n throw new WaffoPancakeError(response.status, result.errors);\n }\n\n return result.data as T;\n }\n}\n","import type { ApiError } from \"./types.js\";\n\n/**\n * Error thrown when the API returns a non-success response.\n *\n * @example\n * try {\n * await client.stores.create({ name: \"My Store\" });\n * } catch (err) {\n * if (err instanceof WaffoPancakeError) {\n * console.log(err.status); // 400\n * console.log(err.errors[0]); // { message: \"...\", layer: \"store\" }\n * }\n * }\n */\nexport class WaffoPancakeError extends Error {\n readonly status: number;\n readonly errors: ApiError[];\n\n constructor(status: number, errors: ApiError[]) {\n const rootCause = errors[0]?.message ?? \"Unknown error\";\n super(rootCause);\n this.name = \"WaffoPancakeError\";\n this.status = status;\n this.errors = errors;\n }\n}\n","import { createHash, createSign } from \"node:crypto\";\n\n/**\n * Build canonical request string and sign with RSA-SHA256.\n *\n * Canonical request format:\n * METHOD\\nPATH\\nTIMESTAMP\\nSHA256(BODY)\n *\n * @param method - HTTP method (e.g. \"POST\")\n * @param path - Request path (e.g. \"/v1/actions/store/create-store\")\n * @param timestamp - Unix epoch seconds string\n * @param body - Serialized JSON body\n * @param privateKey - RSA private key in PEM format\n * @returns Base64-encoded RSA-SHA256 signature\n */\nexport function signRequest(\n method: string,\n path: string,\n timestamp: string,\n body: string,\n privateKey: string,\n): string {\n const bodyHash = createHash(\"sha256\").update(body).digest(\"hex\");\n const canonicalRequest = `${method}\\n${path}\\n${timestamp}\\n${bodyHash}`;\n\n const sign = createSign(\"sha256\");\n sign.update(canonicalRequest);\n return sign.sign(privateKey, \"base64\");\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { IssueSessionTokenParams, SessionToken } from \"../types.js\";\n\n/** Authentication resource — issue session tokens for buyers. */\nexport class AuthResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Issue a session token for a buyer.\n *\n * @param params - Token issuance parameters\n * @returns Issued session token with expiration\n *\n * @example\n * const { token, expiresAt } = await client.auth.issueSessionToken({\n * storeId: \"store_xxx\",\n * buyerIdentity: \"customer@example.com\",\n * });\n */\n async issueSessionToken(params: IssueSessionTokenParams): Promise<SessionToken> {\n return this.http.post<SessionToken>(\"/v1/actions/auth/issue-session-token\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { CheckoutSessionResult, CreateCheckoutSessionParams } from \"../types.js\";\n\n/** Checkout resource — create checkout sessions for payments. */\nexport class CheckoutResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a checkout session. Returns a URL to redirect the customer to.\n *\n * @param params - Checkout session parameters\n * @returns Session ID, checkout URL, and expiration\n *\n * @example\n * const session = await client.checkout.createSession({\n * storeId: \"store_xxx\",\n * productId: \"prod_xxx\",\n * productType: \"onetime\",\n * currency: \"USD\",\n * buyerEmail: \"customer@example.com\",\n * });\n * // Redirect to session.checkoutUrl\n */\n async createSession(params: CreateCheckoutSessionParams): Promise<CheckoutSessionResult> {\n return this.http.post<CheckoutSessionResult>(\"/v1/actions/checkout/create-session\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { GraphQLParams, GraphQLResponse } from \"../types.js\";\n\n/** GraphQL query resource (Query only, no Mutations). */\nexport class GraphQLResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Execute a GraphQL query (Query only, no Mutations).\n *\n * @param params - GraphQL query and optional variables\n * @returns GraphQL response with data and optional errors\n *\n * @example\n * const result = await client.graphql.query<{ stores: Array<{ id: string; name: string }> }>({\n * query: `query { stores { id name status } }`,\n * });\n * console.log(result.data?.stores);\n *\n * @example\n * const result = await client.graphql.query({\n * query: `query ($id: ID!) { onetimeProduct(id: $id) { id name prices } }`,\n * variables: { id: \"prod_xxx\" },\n * });\n */\n async query<T = Record<string, unknown>>(params: GraphQLParams): Promise<GraphQLResponse<T>> {\n return this.http.post<GraphQLResponse<T>>(\"/v1/graphql\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateOnetimeProductParams,\n OnetimeProductDetail,\n PublishOnetimeProductParams,\n UpdateOnetimeProductParams,\n UpdateOnetimeStatusParams,\n} from \"../types.js\";\n\n/** One-time product management resource. */\nexport class OnetimeProductsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a one-time product with multi-currency pricing.\n *\n * @param params - Product creation parameters\n * @returns Created product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.create({\n * storeId: \"store_xxx\",\n * name: \"E-Book\",\n * prices: { USD: { amount: 2900, taxIncluded: false, taxCategory: \"digital_goods\" } },\n * });\n */\n async create(params: CreateOnetimeProductParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/create-product\", params);\n }\n\n /**\n * Update a one-time product. Creates a new version; skips if unchanged.\n *\n * @param params - Product update parameters (all content fields required)\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.update({\n * id: \"prod_xxx\",\n * name: \"E-Book v2\",\n * prices: { USD: { amount: 3900, taxIncluded: false, taxCategory: \"digital_goods\" } },\n * });\n */\n async update(params: UpdateOnetimeProductParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/update-product\", params);\n }\n\n /**\n * Publish a one-time product's test version to production.\n *\n * @param params - Product to publish\n * @returns Published product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.publish({ id: \"prod_xxx\" });\n */\n async publish(params: PublishOnetimeProductParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/publish-product\", params);\n }\n\n /**\n * Update a one-time product's status (active/inactive).\n *\n * @param params - Status update parameters\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.updateStatus({\n * id: \"prod_xxx\",\n * status: ProductVersionStatus.Inactive,\n * });\n */\n async updateStatus(params: UpdateOnetimeStatusParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/update-status\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { CancelSubscriptionParams, CancelSubscriptionResult } from \"../types.js\";\n\n/** Order management resource. */\nexport class OrdersResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Cancel a subscription order.\n *\n * - pending -> canceled (immediate)\n * - active/trialing -> canceling (PSP cancel, webhook updates later)\n *\n * @param params - Order to cancel\n * @returns Order ID and resulting status\n *\n * @example\n * const { orderId, status } = await client.orders.cancelSubscription({\n * orderId: \"order_xxx\",\n * });\n * // status: \"canceled\" or \"canceling\"\n */\n async cancelSubscription(params: CancelSubscriptionParams): Promise<CancelSubscriptionResult> {\n return this.http.post<CancelSubscriptionResult>(\"/v1/actions/subscription-order/cancel-order\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n AddMerchantParams,\n AddMerchantResult,\n RemoveMerchantParams,\n RemoveMerchantResult,\n UpdateRoleParams,\n UpdateRoleResult,\n} from \"../types.js\";\n\n/** Store merchant management resource (coming soon — endpoints return 501). */\nexport class StoreMerchantsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Add a merchant to a store.\n *\n * @param params - Merchant addition parameters\n * @returns Added merchant details\n *\n * @example\n * const result = await client.storeMerchants.add({\n * storeId: \"store_xxx\",\n * email: \"member@example.com\",\n * role: \"admin\",\n * });\n */\n async add(params: AddMerchantParams): Promise<AddMerchantResult> {\n return this.http.post(\"/v1/actions/store-merchant/add-merchant\", params);\n }\n\n /**\n * Remove a merchant from a store.\n *\n * @param params - Merchant removal parameters\n * @returns Removal confirmation\n *\n * @example\n * const result = await client.storeMerchants.remove({\n * storeId: \"store_xxx\",\n * merchantId: \"merchant_xxx\",\n * });\n */\n async remove(params: RemoveMerchantParams): Promise<RemoveMerchantResult> {\n return this.http.post(\"/v1/actions/store-merchant/remove-merchant\", params);\n }\n\n /**\n * Update a merchant's role in a store.\n *\n * @param params - Role update parameters\n * @returns Updated role details\n *\n * @example\n * const result = await client.storeMerchants.updateRole({\n * storeId: \"store_xxx\",\n * merchantId: \"merchant_xxx\",\n * role: \"member\",\n * });\n */\n async updateRole(params: UpdateRoleParams): Promise<UpdateRoleResult> {\n return this.http.post(\"/v1/actions/store-merchant/update-role\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateStoreParams,\n DeleteStoreParams,\n Store,\n UpdateStoreParams,\n} from \"../types.js\";\n\n/** Store management resource — create, update, and delete stores. */\nexport class StoresResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a new store. Slug is auto-generated from the name.\n *\n * @param params - Store creation parameters\n * @returns Created store entity\n *\n * @example\n * const { store } = await client.stores.create({ name: \"My Store\" });\n */\n async create(params: CreateStoreParams): Promise<{ store: Store }> {\n return this.http.post(\"/v1/actions/store/create-store\", params);\n }\n\n /**\n * Update an existing store's settings.\n *\n * @param params - Fields to update (only provided fields are changed)\n * @returns Updated store entity\n *\n * @example\n * const { store } = await client.stores.update({\n * id: \"store_xxx\",\n * name: \"Updated Name\",\n * supportEmail: \"help@example.com\",\n * });\n */\n async update(params: UpdateStoreParams): Promise<{ store: Store }> {\n return this.http.post(\"/v1/actions/store/update-store\", params);\n }\n\n /**\n * Soft-delete a store. Only the owner can delete.\n *\n * @param params - Store to delete\n * @returns Deleted store entity (with `deletedAt` set)\n *\n * @example\n * const { store } = await client.stores.delete({ id: \"store_xxx\" });\n */\n async delete(params: DeleteStoreParams): Promise<{ store: Store }> {\n return this.http.post(\"/v1/actions/store/delete-store\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateSubscriptionProductGroupParams,\n DeleteSubscriptionProductGroupParams,\n PublishSubscriptionProductGroupParams,\n SubscriptionProductGroup,\n UpdateSubscriptionProductGroupParams,\n} from \"../types.js\";\n\n/** Subscription product group management resource (shared trial, plan switching). */\nexport class SubscriptionProductGroupsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a subscription product group for shared-trial or plan switching.\n *\n * @param params - Group creation parameters\n * @returns Created group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.create({\n * storeId: \"store_xxx\",\n * name: \"Pro Plans\",\n * rules: { sharedTrial: true },\n * productIds: [\"prod_aaa\", \"prod_bbb\"],\n * });\n */\n async create(params: CreateSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/create-group\", params);\n }\n\n /**\n * Update a subscription product group. `productIds` is a full replacement.\n *\n * @param params - Group update parameters\n * @returns Updated group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.update({\n * id: \"group_xxx\",\n * productIds: [\"prod_aaa\", \"prod_bbb\", \"prod_ccc\"],\n * });\n */\n async update(params: UpdateSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/update-group\", params);\n }\n\n /**\n * Hard-delete a subscription product group.\n *\n * @param params - Group to delete\n * @returns Deleted group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.delete({ id: \"group_xxx\" });\n */\n async delete(params: DeleteSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/delete-group\", params);\n }\n\n /**\n * Publish a test-environment group to production (upsert).\n *\n * @param params - Group to publish\n * @returns Published group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.publish({ id: \"group_xxx\" });\n */\n async publish(params: PublishSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/publish-group\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateSubscriptionProductParams,\n PublishSubscriptionProductParams,\n SubscriptionProductDetail,\n UpdateSubscriptionProductParams,\n UpdateSubscriptionStatusParams,\n} from \"../types.js\";\n\n/** Subscription product management resource. */\nexport class SubscriptionProductsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a subscription product with billing period and multi-currency pricing.\n *\n * @param params - Product creation parameters\n * @returns Created product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.create({\n * storeId: \"store_xxx\",\n * name: \"Pro Plan\",\n * billingPeriod: \"monthly\",\n * prices: { USD: { amount: 999, taxIncluded: false, taxCategory: \"saas\" } },\n * });\n */\n async create(params: CreateSubscriptionProductParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/create-product\", params);\n }\n\n /**\n * Update a subscription product. Creates a new version; skips if unchanged.\n *\n * @param params - Product update parameters (all content fields required)\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.update({\n * id: \"prod_xxx\",\n * name: \"Pro Plan v2\",\n * billingPeriod: \"monthly\",\n * prices: { USD: { amount: 1499, taxIncluded: false, taxCategory: \"saas\" } },\n * });\n */\n async update(params: UpdateSubscriptionProductParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/update-product\", params);\n }\n\n /**\n * Publish a subscription product's test version to production.\n *\n * @param params - Product to publish\n * @returns Published product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.publish({ id: \"prod_xxx\" });\n */\n async publish(params: PublishSubscriptionProductParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/publish-product\", params);\n }\n\n /**\n * Update a subscription product's status (active/inactive).\n *\n * @param params - Status update parameters\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.updateStatus({\n * id: \"prod_xxx\",\n * status: ProductVersionStatus.Active,\n * });\n */\n async updateStatus(params: UpdateSubscriptionStatusParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/update-status\", params);\n }\n}\n","import { HttpClient } from \"./http-client.js\";\nimport { AuthResource } from \"./resources/auth.js\";\nimport { CheckoutResource } from \"./resources/checkout.js\";\nimport { GraphQLResource } from \"./resources/graphql.js\";\nimport { OnetimeProductsResource } from \"./resources/onetime-products.js\";\nimport { OrdersResource } from \"./resources/orders.js\";\nimport { StoreMerchantsResource } from \"./resources/store-merchants.js\";\nimport { StoresResource } from \"./resources/stores.js\";\nimport { SubscriptionProductGroupsResource } from \"./resources/subscription-product-groups.js\";\nimport { SubscriptionProductsResource } from \"./resources/subscription-products.js\";\n\nimport type { WaffoPancakeConfig } from \"./types.js\";\n\n/**\n * Waffo Pancake TypeScript SDK client.\n *\n * Uses Merchant API Key (RSA-SHA256) authentication. All requests are\n * automatically signed — no manual header construction needed.\n *\n * @example\n * import { WaffoPancake } from \"@waffo/pancake-ts\";\n *\n * const client = new WaffoPancake({\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * });\n *\n * // Create a store\n * const { store } = await client.stores.create({ name: \"My Store\" });\n *\n * // Create a product\n * const { product } = await client.onetimeProducts.create({\n * storeId: store.id,\n * name: \"E-Book\",\n * prices: { USD: { amount: 2900, taxIncluded: false, taxCategory: \"digital_goods\" } },\n * });\n *\n * // Create a checkout session\n * const session = await client.checkout.createSession({\n * storeId: store.id,\n * productId: product.id,\n * productType: \"onetime\",\n * currency: \"USD\",\n * });\n * // => redirect customer to session.checkoutUrl\n *\n * // Query data via GraphQL\n * const result = await client.graphql.query({\n * query: `query { stores { id name status } }`,\n * });\n */\nexport class WaffoPancake {\n private readonly http: HttpClient;\n\n readonly auth: AuthResource;\n readonly stores: StoresResource;\n readonly storeMerchants: StoreMerchantsResource;\n readonly onetimeProducts: OnetimeProductsResource;\n readonly subscriptionProducts: SubscriptionProductsResource;\n readonly subscriptionProductGroups: SubscriptionProductGroupsResource;\n readonly orders: OrdersResource;\n readonly checkout: CheckoutResource;\n readonly graphql: GraphQLResource;\n\n constructor(config: WaffoPancakeConfig) {\n this.http = new HttpClient(config);\n\n this.auth = new AuthResource(this.http);\n this.stores = new StoresResource(this.http);\n this.storeMerchants = new StoreMerchantsResource(this.http);\n this.onetimeProducts = new OnetimeProductsResource(this.http);\n this.subscriptionProducts = new SubscriptionProductsResource(this.http);\n this.subscriptionProductGroups = new SubscriptionProductGroupsResource(this.http);\n this.orders = new OrdersResource(this.http);\n this.checkout = new CheckoutResource(this.http);\n this.graphql = new GraphQLResource(this.http);\n }\n}\n","import { createVerify } from \"node:crypto\";\n\nimport type { VerifyWebhookOptions, WebhookEvent } from \"./types.js\";\n\n/** Default tolerance: 5 minutes */\nconst DEFAULT_TOLERANCE_MS = 5 * 60 * 1000;\n\n/** Waffo Pancake test environment webhook verification public key. */\nconst TEST_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxnmRY6yMMA3lVqmAU6ZG\nb1sjL/+r/z6E+ZjkXaDAKiqOhk9rpazni0bNsGXwmftTPk9jy2wn+j6JHODD/WH/\nSCnSfvKkLIjy4Hk7BuCgB174C0ydan7J+KgXLkOwgCAxxB68t2tezldwo74ZpXgn\nF49opzMvQ9prEwIAWOE+kV9iK6gx/AckSMtHIHpUesoPDkldpmFHlB2qpf1vsFTZ\n5kD6DmGl+2GIVK01aChy2lk8pLv0yUMu18v44sLkO5M44TkGPJD9qG09wrvVG2wp\nOTVCn1n5pP8P+HRLcgzbUB3OlZVfdFurn6EZwtyL4ZD9kdkQ4EZE/9inKcp3c1h4\nxwIDAQAB\n-----END PUBLIC KEY-----`;\n\n/** Waffo Pancake production environment webhook verification public key. */\nconst PROD_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+xApdTIb4ua+DgZKQ54\niBsD82ybyhGCLRETONW4Jgbb3A8DUM1LqBk6r/CmTOCHqLalTQHNigvP3R5zkDNX\niRJz6gA4MJ/+8K0+mnEE2RISQzN+Qu65TNd6svb+INm/kMaftY4uIXr6y6kchtTJ\ndwnQhcKdAL2v7h7IFnkVelQsKxDdb2PqX8xX/qwd01iXvMcpCCaXovUwZsxH2QN5\nZKBTseJivbhUeyJCco4fdUyxOMHe2ybCVhyvim2uxAl1nkvL5L8RCWMCAV55LLo0\n9OhmLahz/DYNu13YLVP6dvIT09ZFBYU6Owj1NxdinTynlJCFS9VYwBgmftosSE1U\ndwIDAQAB\n-----END PUBLIC KEY-----`;\n\n/**\n * Parse `X-Waffo-Signature` header.\n *\n * Format: `t=<timestamp>,v1=<base64signature>`\n *\n * @returns Parsed `t` (timestamp string) and `v1` (base64 signature)\n */\nfunction parseSignatureHeader(header: string): { t: string; v1: string } {\n let t = \"\";\n let v1 = \"\";\n for (const pair of header.split(\",\")) {\n const eqIdx = pair.indexOf(\"=\");\n if (eqIdx === -1) continue;\n const key = pair.slice(0, eqIdx).trim();\n const value = pair.slice(eqIdx + 1).trim();\n if (key === \"t\") t = value;\n else if (key === \"v1\") v1 = value;\n }\n return { t, v1 };\n}\n\n/**\n * Verify RSA-SHA256 signature against a public key.\n *\n * @param signatureInput - The string to verify (`${t}.${rawBody}`)\n * @param v1 - Base64-encoded signature\n * @param publicKey - PEM public key\n * @returns Whether the signature is valid\n */\nfunction rsaVerify(signatureInput: string, v1: string, publicKey: string): boolean {\n const verifier = createVerify(\"RSA-SHA256\");\n verifier.update(signatureInput);\n return verifier.verify(publicKey, v1, \"base64\");\n}\n\n/**\n * Verify and parse an incoming Waffo Pancake webhook event.\n *\n * Uses built-in Waffo public keys (RSA-SHA256) for signature verification.\n * Test and production environments use different key pairs; both are embedded in the SDK.\n *\n * Behavior:\n * - Parses the `X-Waffo-Signature` header (`t=<timestamp>,v1=<base64sig>`)\n * - Builds signature input `${t}.${rawBody}` and verifies with RSA-SHA256\n * - When `environment` is not specified, tries prod key first, then test key\n * - Optional: checks timestamp to prevent replay attacks (default 5-minute tolerance)\n *\n * @param payload - Raw request body string (must be unparsed)\n * @param signatureHeader - Value of the `X-Waffo-Signature` header\n * @param options - Verification options\n * @returns Parsed webhook event\n * @throws Error if header is missing/malformed, signature is invalid, or timestamp is stale\n *\n * @example\n * // Express (use raw body!)\n * app.post(\"/webhooks\", express.raw({ type: \"application/json\" }), (req, res) => {\n * try {\n * const event = verifyWebhook(\n * req.body.toString(\"utf-8\"),\n * req.headers[\"x-waffo-signature\"] as string,\n * );\n * res.status(200).send(\"OK\");\n * handleEventAsync(event).catch(console.error);\n * } catch {\n * res.status(401).send(\"Invalid signature\");\n * }\n * });\n *\n * @example\n * // Next.js App Router\n * export async function POST(request: Request) {\n * const body = await request.text();\n * const sig = request.headers.get(\"x-waffo-signature\");\n * const event = verifyWebhook(body, sig);\n * // handle event ...\n * return new Response(\"OK\");\n * }\n *\n * @example\n * // Specify environment explicitly\n * const event = verifyWebhook(body, sig, { environment: \"prod\" });\n *\n * @example\n * // Disable replay protection\n * const event = verifyWebhook(body, sig, { toleranceMs: 0 });\n */\nexport function verifyWebhook<T = Record<string, unknown>>(\n payload: string,\n signatureHeader: string | undefined | null,\n options?: VerifyWebhookOptions,\n): WebhookEvent<T> {\n if (!signatureHeader) {\n throw new Error(\"Missing X-Waffo-Signature header\");\n }\n\n const { t, v1 } = parseSignatureHeader(signatureHeader);\n if (!t || !v1) {\n throw new Error(\"Malformed X-Waffo-Signature header: missing t or v1\");\n }\n\n // Replay protection\n const toleranceMs = options?.toleranceMs ?? DEFAULT_TOLERANCE_MS;\n if (toleranceMs > 0) {\n const timestampMs = Number(t);\n if (Number.isNaN(timestampMs)) {\n throw new Error(\"Invalid timestamp in X-Waffo-Signature header\");\n }\n if (Math.abs(Date.now() - timestampMs) > toleranceMs) {\n throw new Error(\"Webhook timestamp outside tolerance window (possible replay attack)\");\n }\n }\n\n // RSA-SHA256 verification\n const signatureInput = `${t}.${payload}`;\n const env = options?.environment;\n\n if (env === \"test\") {\n if (!rsaVerify(signatureInput, v1, TEST_PUBLIC_KEY)) {\n throw new Error(\"Invalid webhook signature (test key)\");\n }\n } else if (env === \"prod\") {\n if (!rsaVerify(signatureInput, v1, PROD_PUBLIC_KEY)) {\n throw new Error(\"Invalid webhook signature (prod key)\");\n }\n } else {\n // Auto-detect: try prod first, then test\n const prodValid = rsaVerify(signatureInput, v1, PROD_PUBLIC_KEY);\n if (!prodValid) {\n const testValid = rsaVerify(signatureInput, v1, TEST_PUBLIC_KEY);\n if (!testValid) {\n throw new Error(\"Invalid webhook signature (tried both prod and test keys)\");\n }\n }\n }\n\n return JSON.parse(payload) as WebhookEvent<T>;\n}\n","// ---------------------------------------------------------------------------\n// Client config\n// ---------------------------------------------------------------------------\n\nexport interface WaffoPancakeConfig {\n /** Merchant ID (X-Merchant-Id header) */\n merchantId: string;\n /** RSA private key in PEM format for request signing */\n privateKey: string;\n /** Base URL override (default: https://waffo-pancake-auth-service.vercel.app) */\n baseUrl?: string;\n /** Custom fetch implementation (default: global fetch) */\n fetch?: typeof fetch;\n}\n\n// ---------------------------------------------------------------------------\n// API response envelope\n// ---------------------------------------------------------------------------\n\n/**\n * Single error object within the `errors` array.\n *\n * @example\n * { message: \"Store slug already exists\", layer: \"store\" }\n */\nexport interface ApiError {\n /** Error message */\n message: string;\n /** Layer where the error originated */\n layer: `${ErrorLayer}`;\n}\n\n/** Successful API response envelope. */\nexport interface ApiSuccessResponse<T> {\n data: T;\n}\n\n/**\n * Error API response envelope.\n *\n * `errors` are ordered by call stack: `[0]` is the deepest layer, `[n]` is the outermost.\n */\nexport interface ApiErrorResponse {\n data: null;\n errors: ApiError[];\n}\n\n/** Union type of success and error API responses. */\nexport type ApiResponse<T> = ApiSuccessResponse<T> | ApiErrorResponse;\n\n// ---------------------------------------------------------------------------\n// Enums (runtime-accessible values)\n// ---------------------------------------------------------------------------\n\n/**\n * Environment type.\n * @see waffo-pancake-order-service/app/lib/types.ts\n */\nexport enum Environment {\n Test = \"test\",\n Prod = \"prod\",\n}\n\n/**\n * Tax category for products.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum TaxCategory {\n DigitalGoods = \"digital_goods\",\n SaaS = \"saas\",\n Software = \"software\",\n Ebook = \"ebook\",\n OnlineCourse = \"online_course\",\n Consulting = \"consulting\",\n ProfessionalService = \"professional_service\",\n}\n\n/**\n * Subscription billing period.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum BillingPeriod {\n Weekly = \"weekly\",\n Monthly = \"monthly\",\n Quarterly = \"quarterly\",\n Yearly = \"yearly\",\n}\n\n/**\n * Product version status.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum ProductVersionStatus {\n Active = \"active\",\n Inactive = \"inactive\",\n}\n\n/**\n * Store entity status.\n * @see waffo-pancake-store-service/app/lib/resources/store.ts\n */\nexport enum EntityStatus {\n Active = \"active\",\n Inactive = \"inactive\",\n Suspended = \"suspended\",\n}\n\n/**\n * Store member role.\n * @see waffo-pancake-store-service/app/lib/resources/store.ts\n */\nexport enum StoreRole {\n Owner = \"owner\",\n Admin = \"admin\",\n Member = \"member\",\n}\n\n/**\n * One-time order status.\n * @see waffo-pancake-order-service/app/lib/resources/onetime-order.ts\n */\nexport enum OnetimeOrderStatus {\n Pending = \"pending\",\n Completed = \"completed\",\n Canceled = \"canceled\",\n}\n\n/**\n * Subscription order status.\n *\n * State machine:\n * - pending -> active, canceled\n * - active -> canceling, past_due, canceled, expired\n * - canceling -> active, canceled\n * - past_due -> active, canceled\n * - canceled -> terminal\n * - expired -> terminal\n *\n * @see waffo-pancake-order-service/app/lib/resources/subscription-order.ts\n */\nexport enum SubscriptionOrderStatus {\n Pending = \"pending\",\n Active = \"active\",\n Canceling = \"canceling\",\n Canceled = \"canceled\",\n PastDue = \"past_due\",\n Expired = \"expired\",\n}\n\n/**\n * Payment status.\n * @see waffo-pancake-order-service/app/lib/resources/payment.ts\n */\nexport enum PaymentStatus {\n Pending = \"pending\",\n Succeeded = \"succeeded\",\n Failed = \"failed\",\n Canceled = \"canceled\",\n}\n\n/**\n * Refund ticket status.\n * @see waffo-pancake-order-service/app/lib/resources/refund-ticket.ts\n */\nexport enum RefundTicketStatus {\n Pending = \"pending\",\n Approved = \"approved\",\n Rejected = \"rejected\",\n Processing = \"processing\",\n Succeeded = \"succeeded\",\n Failed = \"failed\",\n}\n\n/**\n * Refund status.\n * @see waffo-pancake-order-service/app/lib/resources/refund.ts\n */\nexport enum RefundStatus {\n Succeeded = \"succeeded\",\n Failed = \"failed\",\n}\n\n/**\n * Media asset type.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum MediaType {\n Image = \"image\",\n Video = \"video\",\n}\n\n/**\n * Checkout session product type.\n * @see waffo-pancake-order-service/app/lib/types.ts\n */\nexport enum CheckoutSessionProductType {\n Onetime = \"onetime\",\n Subscription = \"subscription\",\n}\n\n/** Error layer identifier in the call stack. */\nexport enum ErrorLayer {\n Gateway = \"gateway\",\n User = \"user\",\n Store = \"store\",\n Product = \"product\",\n Order = \"order\",\n GraphQL = \"graphql\",\n Resource = \"resource\",\n Email = \"email\",\n}\n\n// ---------------------------------------------------------------------------\n// Auth\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for issuing a buyer session token.\n * @see waffo-pancake-user-service/app/lib/utils/jwt.ts IssueSessionTokenRequest\n */\nexport interface IssueSessionTokenParams {\n /** Buyer identity (email or any merchant-provided identifier string) */\n buyerIdentity: string;\n /** Store ID */\n storeId: string;\n}\n\n/**\n * Issued session token response.\n *\n * @example\n * { token: \"eyJhbGciOi...\", expiresAt: \"2026-03-10T09:00:00.000Z\" }\n */\nexport interface SessionToken {\n /** JWT token string */\n token: string;\n /** Expiration time (ISO 8601 UTC) */\n expiresAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// Store — from waffo-pancake-store-service\n// ---------------------------------------------------------------------------\n\n/**\n * Webhook configuration for test and production environments.\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface WebhookSettings {\n /** Test environment webhook URL */\n testWebhookUrl: string | null;\n /** Production environment webhook URL */\n prodWebhookUrl: string | null;\n /** Event types subscribed in test environment */\n testEvents: string[];\n /** Event types subscribed in production environment */\n prodEvents: string[];\n}\n\n/**\n * Notification settings (all default to true).\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface NotificationSettings {\n emailOrderConfirmation: boolean;\n emailSubscriptionConfirmation: boolean;\n emailSubscriptionCycled: boolean;\n emailSubscriptionCanceled: boolean;\n emailSubscriptionRevoked: boolean;\n emailSubscriptionPastDue: boolean;\n notifyNewOrders: boolean;\n notifyNewSubscriptions: boolean;\n}\n\n/**\n * Single-theme checkout page styling.\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface CheckoutThemeSettings {\n checkoutLogo: string | null;\n checkoutColorPrimary: string;\n checkoutColorBackground: string;\n checkoutColorCard: string;\n checkoutColorText: string;\n checkoutColorTextSecondary: string;\n checkoutBorderRadius: string;\n}\n\n/**\n * Checkout page configuration (light and dark themes).\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface CheckoutSettings {\n light: CheckoutThemeSettings;\n dark: CheckoutThemeSettings;\n}\n\n/**\n * Store entity.\n * @see waffo-pancake-store-service/app/lib/resources/store.ts\n */\nexport interface Store {\n id: string;\n name: string;\n status: EntityStatus;\n logo: string | null;\n supportEmail: string | null;\n website: string | null;\n slug: string | null;\n isPublic: boolean;\n prodEnabled: boolean;\n webhookSettings: WebhookSettings | null;\n notificationSettings: NotificationSettings | null;\n checkoutSettings: CheckoutSettings | null;\n deletedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Parameters for creating a store. */\nexport interface CreateStoreParams {\n /** Store name (slug is auto-generated) */\n name: string;\n}\n\n/** Parameters for updating a store. */\nexport interface UpdateStoreParams {\n /** Store ID */\n id: string;\n name?: string;\n status?: EntityStatus;\n logo?: string | null;\n supportEmail?: string | null;\n website?: string | null;\n isPublic?: boolean;\n webhookSettings?: WebhookSettings | null;\n notificationSettings?: NotificationSettings | null;\n checkoutSettings?: CheckoutSettings | null;\n}\n\n/** Parameters for deleting (soft-delete) a store. */\nexport interface DeleteStoreParams {\n /** Store ID */\n id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Store Merchant (coming soon — endpoints return 501)\n// ---------------------------------------------------------------------------\n\n/** Parameters for adding a merchant to a store. */\nexport interface AddMerchantParams {\n storeId: string;\n email: string;\n role: \"admin\" | \"member\";\n}\n\n/** Result of adding a merchant to a store. */\nexport interface AddMerchantResult {\n storeId: string;\n merchantId: string;\n email: string;\n role: string;\n status: string;\n addedAt: string;\n}\n\n/** Parameters for removing a merchant from a store. */\nexport interface RemoveMerchantParams {\n storeId: string;\n merchantId: string;\n}\n\n/** Result of removing a merchant from a store. */\nexport interface RemoveMerchantResult {\n message: string;\n removedAt: string;\n}\n\n/** Parameters for updating a merchant's role. */\nexport interface UpdateRoleParams {\n storeId: string;\n merchantId: string;\n role: \"admin\" | \"member\";\n}\n\n/** Result of updating a merchant's role. */\nexport interface UpdateRoleResult {\n storeId: string;\n merchantId: string;\n role: string;\n updatedAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// Product — shared types from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * Price for a single currency.\n *\n * Amounts are stored in the smallest currency unit (e.g. cents, yen)\n * to avoid floating-point precision issues.\n *\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n *\n * @example\n * // USD $9.99\n * { amount: 999, taxIncluded: true, taxCategory: \"saas\" }\n *\n * @example\n * // JPY ¥1000\n * { amount: 1000, taxIncluded: false, taxCategory: \"software\" }\n */\nexport interface PriceInfo {\n /** Price amount in smallest currency unit */\n amount: number;\n /** Whether the price is tax-inclusive */\n taxIncluded: boolean;\n /** Tax category */\n taxCategory: TaxCategory;\n}\n\n/**\n * Multi-currency prices (keyed by ISO 4217 currency code).\n *\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n *\n * @example\n * {\n * \"USD\": { amount: 999, taxIncluded: true, taxCategory: \"saas\" },\n * \"EUR\": { amount: 899, taxIncluded: true, taxCategory: \"saas\" }\n * }\n */\nexport type Prices = Record<string, PriceInfo>;\n\n/**\n * Media asset (image or video).\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport interface MediaItem {\n /** Media type */\n type: `${MediaType}`;\n /** Asset URL */\n url: string;\n /** Alt text */\n alt?: string;\n /** Thumbnail URL */\n thumbnail?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Onetime Product — from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * One-time product detail (public API shape).\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts OnetimeProductDetail\n */\nexport interface OnetimeProductDetail {\n id: string;\n storeId: string;\n name: string;\n description: string | null;\n prices: Prices;\n media: MediaItem[];\n successUrl: string | null;\n metadata: Record<string, unknown>;\n status: ProductVersionStatus;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Parameters for creating a one-time product.\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts CreateOnetimeProductRequestBody\n */\nexport interface CreateOnetimeProductParams {\n storeId: string;\n name: string;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parameters for updating a one-time product (creates a new version; skips if unchanged).\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts UpdateOnetimeProductContentRequestBody\n */\nexport interface UpdateOnetimeProductParams {\n id: string;\n name: string;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/** Parameters for publishing a one-time product's test version to production. */\nexport interface PublishOnetimeProductParams {\n /** Product ID */\n id: string;\n}\n\n/**\n * Parameters for updating a one-time product's status.\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts UpdateOnetimeStatusRequestBody\n */\nexport interface UpdateOnetimeStatusParams {\n id: string;\n status: ProductVersionStatus;\n}\n\n// ---------------------------------------------------------------------------\n// Subscription Product — from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * Subscription product detail (public API shape).\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts SubscriptionProductDetail\n */\nexport interface SubscriptionProductDetail {\n id: string;\n storeId: string;\n name: string;\n description: string | null;\n billingPeriod: BillingPeriod;\n prices: Prices;\n media: MediaItem[];\n successUrl: string | null;\n metadata: Record<string, unknown>;\n status: ProductVersionStatus;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Parameters for creating a subscription product.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts CreateSubscriptionProductRequestBody\n */\nexport interface CreateSubscriptionProductParams {\n storeId: string;\n name: string;\n billingPeriod: BillingPeriod;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parameters for updating a subscription product (creates a new version; skips if unchanged).\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts UpdateSubscriptionProductContentRequestBody\n */\nexport interface UpdateSubscriptionProductParams {\n id: string;\n name: string;\n billingPeriod: BillingPeriod;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/** Parameters for publishing a subscription product's test version to production. */\nexport interface PublishSubscriptionProductParams {\n /** Product ID */\n id: string;\n}\n\n/**\n * Parameters for updating a subscription product's status.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts UpdateSubscriptionStatusRequestBody\n */\nexport interface UpdateSubscriptionStatusParams {\n id: string;\n status: ProductVersionStatus;\n}\n\n// ---------------------------------------------------------------------------\n// Subscription Product Group — from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * Group rules for subscription product groups.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts\n */\nexport interface GroupRules {\n /** Whether trial period is shared across products in the group */\n sharedTrial: boolean;\n}\n\n/**\n * Subscription product group entity.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts\n */\nexport interface SubscriptionProductGroup {\n id: string;\n storeId: string;\n name: string;\n description: string | null;\n rules: GroupRules;\n productIds: string[];\n environment: Environment;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Parameters for creating a subscription product group.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts CreateGroupRequestBody\n */\nexport interface CreateSubscriptionProductGroupParams {\n storeId: string;\n name: string;\n description?: string;\n rules?: GroupRules;\n productIds?: string[];\n}\n\n/**\n * Parameters for updating a subscription product group (`productIds` is a full replacement).\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts UpdateGroupRequestBody\n */\nexport interface UpdateSubscriptionProductGroupParams {\n id: string;\n name?: string;\n description?: string;\n rules?: GroupRules;\n productIds?: string[];\n}\n\n/** Parameters for hard-deleting a subscription product group. */\nexport interface DeleteSubscriptionProductGroupParams {\n /** Group ID */\n id: string;\n}\n\n/** Parameters for publishing a test-environment group to production (upsert). */\nexport interface PublishSubscriptionProductGroupParams {\n /** Group ID */\n id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Order — from waffo-pancake-order-service\n// ---------------------------------------------------------------------------\n\n/** Parameters for canceling a subscription order. */\nexport interface CancelSubscriptionParams {\n /** Order ID */\n orderId: string;\n}\n\n/**\n * Result of canceling a subscription order.\n * @see waffo-pancake-order-service cancel-order route.ts\n */\nexport interface CancelSubscriptionResult {\n orderId: string;\n /** Status after cancellation (`\"canceled\"` or `\"canceling\"`) */\n status: `${SubscriptionOrderStatus}`;\n}\n\n/**\n * Buyer billing details for checkout.\n * @see waffo-pancake-order-service/app/lib/types.ts\n */\nexport interface BillingDetail {\n /** Country code (ISO 3166-1 alpha-2) */\n country: string;\n /** Whether this is a business purchase */\n isBusiness: boolean;\n /** Postal / ZIP code */\n postcode?: string;\n /** State / province code (required for US/CA) */\n state?: string;\n /** Business name (required when isBusiness=true) */\n businessName?: string;\n /** Tax ID (required for EU businesses) */\n taxId?: string;\n}\n\n/**\n * Parameters for creating a checkout session.\n * @see waffo-pancake-order-service/app/lib/types.ts CreateCheckoutSessionRequest\n */\nexport interface CreateCheckoutSessionParams {\n /** Store ID */\n storeId?: string;\n /** Product ID */\n productId: string;\n /** Product type */\n productType: `${CheckoutSessionProductType}`;\n /** Currency code (ISO 4217) */\n currency: string;\n /** Optional price snapshot override (reads from DB if omitted) */\n priceSnapshot?: PriceInfo;\n /** Trial toggle override (subscription only) */\n withTrial?: boolean;\n /** Pre-filled buyer email */\n buyerEmail?: string;\n /** Pre-filled billing details */\n billingDetail?: BillingDetail;\n /** Redirect URL after successful payment */\n successUrl?: string;\n /** Session expiration in seconds (default: 7 days) */\n expiresInSeconds?: number;\n /** Custom metadata */\n metadata?: Record<string, string>;\n}\n\n/** Result of creating a checkout session. */\nexport interface CheckoutSessionResult {\n /** Session ID */\n sessionId: string;\n /** URL to redirect the customer to */\n checkoutUrl: string;\n /** Session expiration time (ISO 8601 UTC) */\n expiresAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// GraphQL\n// ---------------------------------------------------------------------------\n\n/** Parameters for a GraphQL query. */\nexport interface GraphQLParams {\n /** GraphQL query string */\n query: string;\n /** Query variables */\n variables?: Record<string, unknown>;\n}\n\n/** GraphQL response envelope. */\nexport interface GraphQLResponse<T = Record<string, unknown>> {\n data: T | null;\n errors?: Array<{\n message: string;\n locations?: Array<{ line: number; column: number }>;\n path?: string[];\n }>;\n}\n\n// ---------------------------------------------------------------------------\n// Webhook\n// ---------------------------------------------------------------------------\n\n/**\n * Webhook event types.\n * @see docs/api-reference/webhooks.mdx\n */\nexport enum WebhookEventType {\n /** One-time order first payment succeeded */\n OrderCompleted = \"order.completed\",\n /** Subscription first payment succeeded (newly activated) */\n SubscriptionActivated = \"subscription.activated\",\n /** Subscription renewal payment succeeded */\n SubscriptionPaymentSucceeded = \"subscription.payment_succeeded\",\n /** Buyer initiated cancellation (expires at end of current period) */\n SubscriptionCanceling = \"subscription.canceling\",\n /** Buyer withdrew cancellation (subscription restored) */\n SubscriptionUncanceled = \"subscription.uncanceled\",\n /** Subscription product changed (upgrade/downgrade) */\n SubscriptionUpdated = \"subscription.updated\",\n /** Subscription fully terminated */\n SubscriptionCanceled = \"subscription.canceled\",\n /** Renewal payment failed (past due) */\n SubscriptionPastDue = \"subscription.past_due\",\n /** Refund succeeded */\n RefundSucceeded = \"refund.succeeded\",\n /** Refund failed */\n RefundFailed = \"refund.failed\",\n}\n\n/**\n * Common data fields in a webhook event payload.\n * @see docs/api-reference/webhooks.mdx\n */\nexport interface WebhookEventData {\n orderId: string;\n buyerEmail: string;\n currency: string;\n /** Amount in smallest currency unit */\n amount: number;\n /** Tax amount in smallest currency unit */\n taxAmount: number;\n productName: string;\n}\n\n/**\n * Webhook event payload.\n *\n * @see docs/api-reference/webhooks.mdx\n *\n * @example\n * {\n * id: \"550e8400-...\",\n * timestamp: \"2026-03-10T08:30:00.000Z\",\n * eventType: \"order.completed\",\n * eventId: \"pay_660e8400-...\",\n * storeId: \"770e8400-...\",\n * mode: \"prod\",\n * data: { orderId: \"...\", buyerEmail: \"...\", currency: \"USD\", amount: 2900, taxAmount: 290, productName: \"Pro Plan\" }\n * }\n */\nexport interface WebhookEvent<T = WebhookEventData> {\n /** Delivery record unique ID (UUID), usable for idempotent deduplication */\n id: string;\n /** Event timestamp (ISO 8601 UTC) */\n timestamp: string;\n /** Event type */\n eventType: `${WebhookEventType}` | (string & {});\n /** Business event ID (e.g. payment ID, order ID) */\n eventId: string;\n /** Store ID the event belongs to */\n storeId: string;\n /** Environment identifier */\n mode: `${Environment}`;\n /** Event data */\n data: T;\n}\n\n/** Options for {@link verifyWebhook}. */\nexport interface VerifyWebhookOptions {\n /**\n * Specify which environment's public key to use for verification.\n * When omitted, both keys are tried automatically (prod first).\n */\n environment?: `${Environment}`;\n /**\n * Timestamp tolerance window in milliseconds for replay protection.\n * Set to 0 to skip timestamp checking.\n * @default 300000 (5 minutes)\n */\n toleranceMs?: number;\n}\n"],"mappings":"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","names":["import_node_crypto","import_node_crypto","Environment","TaxCategory","BillingPeriod","ProductVersionStatus","EntityStatus","StoreRole","OnetimeOrderStatus","SubscriptionOrderStatus","PaymentStatus","RefundTicketStatus","RefundStatus","MediaType","CheckoutSessionProductType","ErrorLayer","WebhookEventType"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/http-client.ts","../src/errors.ts","../src/signing.ts","../src/resources/auth.ts","../src/resources/checkout.ts","../src/resources/graphql.ts","../src/resources/onetime-products.ts","../src/resources/orders.ts","../src/resources/store-merchants.ts","../src/resources/stores.ts","../src/resources/subscription-product-groups.ts","../src/resources/subscription-products.ts","../src/client.ts","../src/webhooks.ts","../src/types.ts"],"sourcesContent":["// Client\nexport { WaffoPancake } from \"./client.js\";\n\n// Errors\nexport { WaffoPancakeError } from \"./errors.js\";\n\n// Webhooks\nexport { verifyWebhook } from \"./webhooks.js\";\n\n// Enums (runtime values)\nexport {\n BillingPeriod,\n CheckoutSessionProductType,\n EntityStatus,\n Environment,\n ErrorLayer,\n MediaType,\n OnetimeOrderStatus,\n PaymentStatus,\n ProductVersionStatus,\n RefundStatus,\n RefundTicketStatus,\n StoreRole,\n SubscriptionOrderStatus,\n TaxCategory,\n WebhookEventType,\n} from \"./types.js\";\n\n// Types (interfaces & type aliases)\nexport type {\n // Config\n WaffoPancakeConfig,\n\n // Response envelope\n ApiError,\n ApiErrorResponse,\n ApiResponse,\n ApiSuccessResponse,\n\n // Auth\n IssueSessionTokenParams,\n SessionToken,\n\n // Store\n CheckoutSettings,\n CheckoutThemeSettings,\n CreateStoreParams,\n DeleteStoreParams,\n NotificationSettings,\n Store,\n UpdateStoreParams,\n WebhookSettings,\n\n // Store Merchant\n AddMerchantParams,\n AddMerchantResult,\n RemoveMerchantParams,\n RemoveMerchantResult,\n UpdateRoleParams,\n UpdateRoleResult,\n\n // Product shared\n MediaItem,\n PriceInfo,\n Prices,\n\n // Onetime Product\n CreateOnetimeProductParams,\n OnetimeProductDetail,\n PublishOnetimeProductParams,\n UpdateOnetimeProductParams,\n UpdateOnetimeStatusParams,\n\n // Subscription Product\n CreateSubscriptionProductParams,\n PublishSubscriptionProductParams,\n SubscriptionProductDetail,\n UpdateSubscriptionProductParams,\n UpdateSubscriptionStatusParams,\n\n // Subscription Product Group\n CreateSubscriptionProductGroupParams,\n DeleteSubscriptionProductGroupParams,\n GroupRules,\n PublishSubscriptionProductGroupParams,\n SubscriptionProductGroup,\n UpdateSubscriptionProductGroupParams,\n\n // Order\n BillingDetail,\n CancelSubscriptionParams,\n CancelSubscriptionResult,\n CheckoutSessionResult,\n CreateCheckoutSessionParams,\n\n // GraphQL\n GraphQLParams,\n GraphQLResponse,\n\n // Webhook\n VerifyWebhookOptions,\n WebhookEvent,\n WebhookEventData,\n} from \"./types.js\";\n","import { createHash } from \"node:crypto\";\n\nimport { WaffoPancakeError } from \"./errors.js\";\nimport { normalizePrivateKey, signRequest } from \"./signing.js\";\n\nimport type { ApiResponse, WaffoPancakeConfig } from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://waffo-pancake-auth-service.vercel.app\";\n\n/**\n * Internal HTTP client that auto-signs requests and attaches idempotency keys.\n *\n * Not exported publicly — used by resource classes via {@link WaffoPancake}.\n */\nexport class HttpClient {\n private readonly merchantId: string;\n private readonly privateKey: string;\n private readonly baseUrl: string;\n private readonly _fetch: typeof fetch;\n\n constructor(config: WaffoPancakeConfig) {\n this.merchantId = config.merchantId;\n this.privateKey = normalizePrivateKey(config.privateKey);\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this._fetch = config.fetch ?? fetch;\n }\n\n /**\n * Send a signed POST request and return the parsed `data` field.\n *\n * Behavior:\n * - Generates a deterministic `X-Idempotency-Key` from `merchantId + path + body` (same request produces same key)\n * - Auto-builds RSA-SHA256 signature (`X-Merchant-Id` / `X-Timestamp` / `X-Signature`)\n * - Unwraps the response envelope: returns `data` on success, throws `WaffoPancakeError` on failure\n *\n * @param path - API path (e.g. `/v1/actions/store/create-store`)\n * @param body - Request body object\n * @returns Parsed `data` field from the response\n * @throws {WaffoPancakeError} When the API returns errors\n */\n async post<T>(path: string, body: object): Promise<T> {\n const bodyStr = JSON.stringify(body);\n const timestamp = Math.floor(Date.now() / 1000).toString();\n const signature = signRequest(\"POST\", path, timestamp, bodyStr, this.privateKey);\n\n const response = await this._fetch(`${this.baseUrl}${path}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Merchant-Id\": this.merchantId,\n \"X-Timestamp\": timestamp,\n \"X-Signature\": signature,\n \"X-Idempotency-Key\": createHash(\"sha256\")\n .update(`${this.merchantId}:${path}:${bodyStr}`)\n .digest(\"hex\"),\n },\n body: bodyStr,\n });\n\n const result = (await response.json()) as ApiResponse<T>;\n\n if (\"errors\" in result && result.errors) {\n throw new WaffoPancakeError(response.status, result.errors);\n }\n\n return result.data as T;\n }\n}\n","import type { ApiError } from \"./types.js\";\n\n/**\n * Error thrown when the API returns a non-success response.\n *\n * @example\n * try {\n * await client.stores.create({ name: \"My Store\" });\n * } catch (err) {\n * if (err instanceof WaffoPancakeError) {\n * console.log(err.status); // 400\n * console.log(err.errors[0]); // { message: \"...\", layer: \"store\" }\n * }\n * }\n */\nexport class WaffoPancakeError extends Error {\n readonly status: number;\n readonly errors: ApiError[];\n\n constructor(status: number, errors: ApiError[]) {\n const rootCause = errors[0]?.message ?? \"Unknown error\";\n super(rootCause);\n this.name = \"WaffoPancakeError\";\n this.status = status;\n this.errors = errors;\n }\n}\n","import { createHash, createPrivateKey, createSign } from \"node:crypto\";\n\nconst PKCS8_HEADER = \"-----BEGIN PRIVATE KEY-----\";\nconst PKCS8_FOOTER = \"-----END PRIVATE KEY-----\";\nconst PKCS1_HEADER = \"-----BEGIN RSA PRIVATE KEY-----\";\nconst PKCS1_FOOTER = \"-----END RSA PRIVATE KEY-----\";\n\n/**\n * Normalize a PEM private key string into a valid PEM format.\n *\n * Handles common issues:\n * - Literal `\\n` from environment variables (e.g. `PRIVATE_KEY=\"-----BEGIN...\\\\n...\"`)\n * - Windows-style `\\r\\n` line endings\n * - Leading/trailing whitespace and blank lines\n * - Missing PEM header/footer (raw base64 input, assumed PKCS#8)\n * - Base64 content on a single line (re-wrapped to 64-char lines)\n * - PKCS#1 (`BEGIN RSA PRIVATE KEY`) accepted as-is\n *\n * @param raw - Private key string in any of the above formats\n * @returns A well-formed PEM string\n * @throws {Error} If the input is empty or contains no base64 content\n *\n * @example\n * // Env var with literal \\n\n * normalizePrivateKey(\"-----BEGIN PRIVATE KEY-----\\\\nMIIE...\\\\n-----END PRIVATE KEY-----\")\n *\n * @example\n * // Raw base64 without PEM wrapper\n * normalizePrivateKey(\"MIIEvQIBADANBgkqhki...\")\n */\nexport function normalizePrivateKey(raw: string): string {\n if (!raw || !raw.trim()) {\n throw new Error(\n \"Private key is empty. Provide an RSA private key in PEM format.\",\n );\n }\n\n // 1. Replace literal \\n / \\r\\n with real newlines\n let pem = raw.replace(/\\\\n/g, \"\\n\").replace(/\\r\\n/g, \"\\n\");\n\n // 2. Trim leading/trailing whitespace\n pem = pem.trim();\n\n // 3. Detect whether PEM headers are present\n const hasPkcs8Header = pem.includes(PKCS8_HEADER);\n const hasPkcs1Header = pem.includes(PKCS1_HEADER);\n const hasHeader = hasPkcs8Header || hasPkcs1Header;\n\n if (hasHeader) {\n // Strip headers/footers, extract pure base64\n const base64 = pem\n .replace(/-----BEGIN (?:RSA )?PRIVATE KEY-----/g, \"\")\n .replace(/-----END (?:RSA )?PRIVATE KEY-----/g, \"\")\n .replace(/\\s+/g, \"\");\n\n if (!base64) {\n throw new Error(\n \"Private key contains PEM headers but no key data. Check the key content.\",\n );\n }\n\n // Re-wrap to 64-char lines with the original header type\n const header = hasPkcs1Header ? PKCS1_HEADER : PKCS8_HEADER;\n const footer = hasPkcs1Header ? PKCS1_FOOTER : PKCS8_FOOTER;\n const wrapped = base64.match(/.{1,64}/g)!.join(\"\\n\");\n pem = `${header}\\n${wrapped}\\n${footer}`;\n } else {\n // No PEM header — treat as raw base64, wrap with PKCS#8 headers\n const base64 = pem.replace(/\\s+/g, \"\");\n\n if (!/^[A-Za-z0-9+/]+=*$/.test(base64)) {\n throw new Error(\n \"Private key is not valid PEM or base64. Expected an RSA private key in PEM format or raw base64.\",\n );\n }\n\n const wrapped = base64.match(/.{1,64}/g)!.join(\"\\n\");\n pem = `${PKCS8_HEADER}\\n${wrapped}\\n${PKCS8_FOOTER}`;\n }\n\n // 4. Validate the key is actually parseable by Node.js crypto\n try {\n createPrivateKey(pem);\n } catch {\n throw new Error(\n \"Private key could not be parsed. Ensure it is a valid RSA private key in PKCS#8 or PKCS#1 (PEM) format.\",\n );\n }\n\n return pem;\n}\n\n/**\n * Build canonical request string and sign with RSA-SHA256.\n *\n * Canonical request format:\n * METHOD\\nPATH\\nTIMESTAMP\\nSHA256(BODY)\n *\n * @param method - HTTP method (e.g. \"POST\")\n * @param path - Request path (e.g. \"/v1/actions/store/create-store\")\n * @param timestamp - Unix epoch seconds string\n * @param body - Serialized JSON body\n * @param privateKey - RSA private key in PEM format\n * @returns Base64-encoded RSA-SHA256 signature\n */\nexport function signRequest(\n method: string,\n path: string,\n timestamp: string,\n body: string,\n privateKey: string,\n): string {\n const bodyHash = createHash(\"sha256\").update(body).digest(\"base64\");\n const canonicalRequest = `${method}\\n${path}\\n${timestamp}\\n${bodyHash}`;\n\n const sign = createSign(\"sha256\");\n sign.update(canonicalRequest);\n return sign.sign(privateKey, \"base64\");\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { IssueSessionTokenParams, SessionToken } from \"../types.js\";\n\n/** Authentication resource — issue session tokens for buyers. */\nexport class AuthResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Issue a session token for a buyer.\n *\n * @param params - Token issuance parameters\n * @returns Issued session token with expiration\n *\n * @example\n * const { token, expiresAt } = await client.auth.issueSessionToken({\n * storeId: \"store_xxx\",\n * buyerIdentity: \"customer@example.com\",\n * });\n */\n async issueSessionToken(params: IssueSessionTokenParams): Promise<SessionToken> {\n return this.http.post<SessionToken>(\"/v1/actions/auth/issue-session-token\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { CheckoutSessionResult, CreateCheckoutSessionParams } from \"../types.js\";\n\n/** Checkout resource — create checkout sessions for payments. */\nexport class CheckoutResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a checkout session. Returns a URL to redirect the customer to.\n *\n * @param params - Checkout session parameters\n * @returns Session ID, checkout URL, and expiration\n *\n * @example\n * const session = await client.checkout.createSession({\n * storeId: \"store_xxx\",\n * productId: \"prod_xxx\",\n * productType: \"onetime\",\n * currency: \"USD\",\n * buyerEmail: \"customer@example.com\",\n * });\n * // Redirect to session.checkoutUrl\n */\n async createSession(params: CreateCheckoutSessionParams): Promise<CheckoutSessionResult> {\n return this.http.post<CheckoutSessionResult>(\"/v1/actions/checkout/create-session\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { GraphQLParams, GraphQLResponse } from \"../types.js\";\n\n/** GraphQL query resource (Query only, no Mutations). */\nexport class GraphQLResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Execute a GraphQL query (Query only, no Mutations).\n *\n * @param params - GraphQL query and optional variables\n * @returns GraphQL response with data and optional errors\n *\n * @example\n * const result = await client.graphql.query<{ stores: Array<{ id: string; name: string }> }>({\n * query: `query { stores { id name status } }`,\n * });\n * console.log(result.data?.stores);\n *\n * @example\n * const result = await client.graphql.query({\n * query: `query ($id: ID!) { onetimeProduct(id: $id) { id name prices } }`,\n * variables: { id: \"prod_xxx\" },\n * });\n */\n async query<T = Record<string, unknown>>(params: GraphQLParams): Promise<GraphQLResponse<T>> {\n return this.http.post<GraphQLResponse<T>>(\"/v1/graphql\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateOnetimeProductParams,\n OnetimeProductDetail,\n PublishOnetimeProductParams,\n UpdateOnetimeProductParams,\n UpdateOnetimeStatusParams,\n} from \"../types.js\";\n\n/** One-time product management resource. */\nexport class OnetimeProductsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a one-time product with multi-currency pricing.\n *\n * @param params - Product creation parameters\n * @returns Created product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.create({\n * storeId: \"store_xxx\",\n * name: \"E-Book\",\n * prices: { USD: { amount: 2900, taxIncluded: false, taxCategory: \"digital_goods\" } },\n * });\n */\n async create(params: CreateOnetimeProductParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/create-product\", params);\n }\n\n /**\n * Update a one-time product. Creates a new version; skips if unchanged.\n *\n * @param params - Product update parameters (all content fields required)\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.update({\n * id: \"prod_xxx\",\n * name: \"E-Book v2\",\n * prices: { USD: { amount: 3900, taxIncluded: false, taxCategory: \"digital_goods\" } },\n * });\n */\n async update(params: UpdateOnetimeProductParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/update-product\", params);\n }\n\n /**\n * Publish a one-time product's test version to production.\n *\n * @param params - Product to publish\n * @returns Published product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.publish({ id: \"prod_xxx\" });\n */\n async publish(params: PublishOnetimeProductParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/publish-product\", params);\n }\n\n /**\n * Update a one-time product's status (active/inactive).\n *\n * @param params - Status update parameters\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.updateStatus({\n * id: \"prod_xxx\",\n * status: ProductVersionStatus.Inactive,\n * });\n */\n async updateStatus(params: UpdateOnetimeStatusParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/update-status\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { CancelSubscriptionParams, CancelSubscriptionResult } from \"../types.js\";\n\n/** Order management resource. */\nexport class OrdersResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Cancel a subscription order.\n *\n * - pending -> canceled (immediate)\n * - active/trialing -> canceling (PSP cancel, webhook updates later)\n *\n * @param params - Order to cancel\n * @returns Order ID and resulting status\n *\n * @example\n * const { orderId, status } = await client.orders.cancelSubscription({\n * orderId: \"order_xxx\",\n * });\n * // status: \"canceled\" or \"canceling\"\n */\n async cancelSubscription(params: CancelSubscriptionParams): Promise<CancelSubscriptionResult> {\n return this.http.post<CancelSubscriptionResult>(\"/v1/actions/subscription-order/cancel-order\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n AddMerchantParams,\n AddMerchantResult,\n RemoveMerchantParams,\n RemoveMerchantResult,\n UpdateRoleParams,\n UpdateRoleResult,\n} from \"../types.js\";\n\n/** Store merchant management resource (coming soon — endpoints return 501). */\nexport class StoreMerchantsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Add a merchant to a store.\n *\n * @param params - Merchant addition parameters\n * @returns Added merchant details\n *\n * @example\n * const result = await client.storeMerchants.add({\n * storeId: \"store_xxx\",\n * email: \"member@example.com\",\n * role: \"admin\",\n * });\n */\n async add(params: AddMerchantParams): Promise<AddMerchantResult> {\n return this.http.post(\"/v1/actions/store-merchant/add-merchant\", params);\n }\n\n /**\n * Remove a merchant from a store.\n *\n * @param params - Merchant removal parameters\n * @returns Removal confirmation\n *\n * @example\n * const result = await client.storeMerchants.remove({\n * storeId: \"store_xxx\",\n * merchantId: \"merchant_xxx\",\n * });\n */\n async remove(params: RemoveMerchantParams): Promise<RemoveMerchantResult> {\n return this.http.post(\"/v1/actions/store-merchant/remove-merchant\", params);\n }\n\n /**\n * Update a merchant's role in a store.\n *\n * @param params - Role update parameters\n * @returns Updated role details\n *\n * @example\n * const result = await client.storeMerchants.updateRole({\n * storeId: \"store_xxx\",\n * merchantId: \"merchant_xxx\",\n * role: \"member\",\n * });\n */\n async updateRole(params: UpdateRoleParams): Promise<UpdateRoleResult> {\n return this.http.post(\"/v1/actions/store-merchant/update-role\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateStoreParams,\n DeleteStoreParams,\n Store,\n UpdateStoreParams,\n} from \"../types.js\";\n\n/** Store management resource — create, update, and delete stores. */\nexport class StoresResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a new store. Slug is auto-generated from the name.\n *\n * @param params - Store creation parameters\n * @returns Created store entity\n *\n * @example\n * const { store } = await client.stores.create({ name: \"My Store\" });\n */\n async create(params: CreateStoreParams): Promise<{ store: Store }> {\n return this.http.post(\"/v1/actions/store/create-store\", params);\n }\n\n /**\n * Update an existing store's settings.\n *\n * @param params - Fields to update (only provided fields are changed)\n * @returns Updated store entity\n *\n * @example\n * const { store } = await client.stores.update({\n * id: \"store_xxx\",\n * name: \"Updated Name\",\n * supportEmail: \"help@example.com\",\n * });\n */\n async update(params: UpdateStoreParams): Promise<{ store: Store }> {\n return this.http.post(\"/v1/actions/store/update-store\", params);\n }\n\n /**\n * Soft-delete a store. Only the owner can delete.\n *\n * @param params - Store to delete\n * @returns Deleted store entity (with `deletedAt` set)\n *\n * @example\n * const { store } = await client.stores.delete({ id: \"store_xxx\" });\n */\n async delete(params: DeleteStoreParams): Promise<{ store: Store }> {\n return this.http.post(\"/v1/actions/store/delete-store\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateSubscriptionProductGroupParams,\n DeleteSubscriptionProductGroupParams,\n PublishSubscriptionProductGroupParams,\n SubscriptionProductGroup,\n UpdateSubscriptionProductGroupParams,\n} from \"../types.js\";\n\n/** Subscription product group management resource (shared trial, plan switching). */\nexport class SubscriptionProductGroupsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a subscription product group for shared-trial or plan switching.\n *\n * @param params - Group creation parameters\n * @returns Created group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.create({\n * storeId: \"store_xxx\",\n * name: \"Pro Plans\",\n * rules: { sharedTrial: true },\n * productIds: [\"prod_aaa\", \"prod_bbb\"],\n * });\n */\n async create(params: CreateSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/create-group\", params);\n }\n\n /**\n * Update a subscription product group. `productIds` is a full replacement.\n *\n * @param params - Group update parameters\n * @returns Updated group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.update({\n * id: \"group_xxx\",\n * productIds: [\"prod_aaa\", \"prod_bbb\", \"prod_ccc\"],\n * });\n */\n async update(params: UpdateSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/update-group\", params);\n }\n\n /**\n * Hard-delete a subscription product group.\n *\n * @param params - Group to delete\n * @returns Deleted group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.delete({ id: \"group_xxx\" });\n */\n async delete(params: DeleteSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/delete-group\", params);\n }\n\n /**\n * Publish a test-environment group to production (upsert).\n *\n * @param params - Group to publish\n * @returns Published group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.publish({ id: \"group_xxx\" });\n */\n async publish(params: PublishSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/publish-group\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateSubscriptionProductParams,\n PublishSubscriptionProductParams,\n SubscriptionProductDetail,\n UpdateSubscriptionProductParams,\n UpdateSubscriptionStatusParams,\n} from \"../types.js\";\n\n/** Subscription product management resource. */\nexport class SubscriptionProductsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a subscription product with billing period and multi-currency pricing.\n *\n * @param params - Product creation parameters\n * @returns Created product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.create({\n * storeId: \"store_xxx\",\n * name: \"Pro Plan\",\n * billingPeriod: \"monthly\",\n * prices: { USD: { amount: 999, taxIncluded: false, taxCategory: \"saas\" } },\n * });\n */\n async create(params: CreateSubscriptionProductParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/create-product\", params);\n }\n\n /**\n * Update a subscription product. Creates a new version; skips if unchanged.\n *\n * @param params - Product update parameters (all content fields required)\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.update({\n * id: \"prod_xxx\",\n * name: \"Pro Plan v2\",\n * billingPeriod: \"monthly\",\n * prices: { USD: { amount: 1499, taxIncluded: false, taxCategory: \"saas\" } },\n * });\n */\n async update(params: UpdateSubscriptionProductParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/update-product\", params);\n }\n\n /**\n * Publish a subscription product's test version to production.\n *\n * @param params - Product to publish\n * @returns Published product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.publish({ id: \"prod_xxx\" });\n */\n async publish(params: PublishSubscriptionProductParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/publish-product\", params);\n }\n\n /**\n * Update a subscription product's status (active/inactive).\n *\n * @param params - Status update parameters\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.updateStatus({\n * id: \"prod_xxx\",\n * status: ProductVersionStatus.Active,\n * });\n */\n async updateStatus(params: UpdateSubscriptionStatusParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/update-status\", params);\n }\n}\n","import { HttpClient } from \"./http-client.js\";\nimport { AuthResource } from \"./resources/auth.js\";\nimport { CheckoutResource } from \"./resources/checkout.js\";\nimport { GraphQLResource } from \"./resources/graphql.js\";\nimport { OnetimeProductsResource } from \"./resources/onetime-products.js\";\nimport { OrdersResource } from \"./resources/orders.js\";\nimport { StoreMerchantsResource } from \"./resources/store-merchants.js\";\nimport { StoresResource } from \"./resources/stores.js\";\nimport { SubscriptionProductGroupsResource } from \"./resources/subscription-product-groups.js\";\nimport { SubscriptionProductsResource } from \"./resources/subscription-products.js\";\n\nimport type { WaffoPancakeConfig } from \"./types.js\";\n\n/**\n * Waffo Pancake TypeScript SDK client.\n *\n * Uses Merchant API Key (RSA-SHA256) authentication. All requests are\n * automatically signed — no manual header construction needed.\n *\n * @example\n * import { WaffoPancake } from \"@waffo/pancake-ts\";\n *\n * const client = new WaffoPancake({\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * });\n *\n * // Create a store\n * const { store } = await client.stores.create({ name: \"My Store\" });\n *\n * // Create a product\n * const { product } = await client.onetimeProducts.create({\n * storeId: store.id,\n * name: \"E-Book\",\n * prices: { USD: { amount: 2900, taxIncluded: false, taxCategory: \"digital_goods\" } },\n * });\n *\n * // Create a checkout session\n * const session = await client.checkout.createSession({\n * storeId: store.id,\n * productId: product.id,\n * productType: \"onetime\",\n * currency: \"USD\",\n * });\n * // => redirect customer to session.checkoutUrl\n *\n * // Query data via GraphQL\n * const result = await client.graphql.query({\n * query: `query { stores { id name status } }`,\n * });\n */\nexport class WaffoPancake {\n private readonly http: HttpClient;\n\n readonly auth: AuthResource;\n readonly stores: StoresResource;\n readonly storeMerchants: StoreMerchantsResource;\n readonly onetimeProducts: OnetimeProductsResource;\n readonly subscriptionProducts: SubscriptionProductsResource;\n readonly subscriptionProductGroups: SubscriptionProductGroupsResource;\n readonly orders: OrdersResource;\n readonly checkout: CheckoutResource;\n readonly graphql: GraphQLResource;\n\n constructor(config: WaffoPancakeConfig) {\n this.http = new HttpClient(config);\n\n this.auth = new AuthResource(this.http);\n this.stores = new StoresResource(this.http);\n this.storeMerchants = new StoreMerchantsResource(this.http);\n this.onetimeProducts = new OnetimeProductsResource(this.http);\n this.subscriptionProducts = new SubscriptionProductsResource(this.http);\n this.subscriptionProductGroups = new SubscriptionProductGroupsResource(this.http);\n this.orders = new OrdersResource(this.http);\n this.checkout = new CheckoutResource(this.http);\n this.graphql = new GraphQLResource(this.http);\n }\n}\n","import { createVerify } from \"node:crypto\";\n\nimport type { VerifyWebhookOptions, WebhookEvent } from \"./types.js\";\n\n/** Default tolerance: 5 minutes */\nconst DEFAULT_TOLERANCE_MS = 5 * 60 * 1000;\n\n/** Waffo Pancake test environment webhook verification public key. */\nconst TEST_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxnmRY6yMMA3lVqmAU6ZG\nb1sjL/+r/z6E+ZjkXaDAKiqOhk9rpazni0bNsGXwmftTPk9jy2wn+j6JHODD/WH/\nSCnSfvKkLIjy4Hk7BuCgB174C0ydan7J+KgXLkOwgCAxxB68t2tezldwo74ZpXgn\nF49opzMvQ9prEwIAWOE+kV9iK6gx/AckSMtHIHpUesoPDkldpmFHlB2qpf1vsFTZ\n5kD6DmGl+2GIVK01aChy2lk8pLv0yUMu18v44sLkO5M44TkGPJD9qG09wrvVG2wp\nOTVCn1n5pP8P+HRLcgzbUB3OlZVfdFurn6EZwtyL4ZD9kdkQ4EZE/9inKcp3c1h4\nxwIDAQAB\n-----END PUBLIC KEY-----`;\n\n/** Waffo Pancake production environment webhook verification public key. */\nconst PROD_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+xApdTIb4ua+DgZKQ54\niBsD82ybyhGCLRETONW4Jgbb3A8DUM1LqBk6r/CmTOCHqLalTQHNigvP3R5zkDNX\niRJz6gA4MJ/+8K0+mnEE2RISQzN+Qu65TNd6svb+INm/kMaftY4uIXr6y6kchtTJ\ndwnQhcKdAL2v7h7IFnkVelQsKxDdb2PqX8xX/qwd01iXvMcpCCaXovUwZsxH2QN5\nZKBTseJivbhUeyJCco4fdUyxOMHe2ybCVhyvim2uxAl1nkvL5L8RCWMCAV55LLo0\n9OhmLahz/DYNu13YLVP6dvIT09ZFBYU6Owj1NxdinTynlJCFS9VYwBgmftosSE1U\ndwIDAQAB\n-----END PUBLIC KEY-----`;\n\n/**\n * Parse `X-Waffo-Signature` header.\n *\n * Format: `t=<timestamp>,v1=<base64signature>`\n *\n * @returns Parsed `t` (timestamp string) and `v1` (base64 signature)\n */\nfunction parseSignatureHeader(header: string): { t: string; v1: string } {\n let t = \"\";\n let v1 = \"\";\n for (const pair of header.split(\",\")) {\n const eqIdx = pair.indexOf(\"=\");\n if (eqIdx === -1) continue;\n const key = pair.slice(0, eqIdx).trim();\n const value = pair.slice(eqIdx + 1).trim();\n if (key === \"t\") t = value;\n else if (key === \"v1\") v1 = value;\n }\n return { t, v1 };\n}\n\n/**\n * Verify RSA-SHA256 signature against a public key.\n *\n * @param signatureInput - The string to verify (`${t}.${rawBody}`)\n * @param v1 - Base64-encoded signature\n * @param publicKey - PEM public key\n * @returns Whether the signature is valid\n */\nfunction rsaVerify(signatureInput: string, v1: string, publicKey: string): boolean {\n const verifier = createVerify(\"RSA-SHA256\");\n verifier.update(signatureInput);\n return verifier.verify(publicKey, v1, \"base64\");\n}\n\n/**\n * Verify and parse an incoming Waffo Pancake webhook event.\n *\n * Uses built-in Waffo public keys (RSA-SHA256) for signature verification.\n * Test and production environments use different key pairs; both are embedded in the SDK.\n *\n * Behavior:\n * - Parses the `X-Waffo-Signature` header (`t=<timestamp>,v1=<base64sig>`)\n * - Builds signature input `${t}.${rawBody}` and verifies with RSA-SHA256\n * - When `environment` is not specified, tries prod key first, then test key\n * - Optional: checks timestamp to prevent replay attacks (default 5-minute tolerance)\n *\n * @param payload - Raw request body string (must be unparsed)\n * @param signatureHeader - Value of the `X-Waffo-Signature` header\n * @param options - Verification options\n * @returns Parsed webhook event\n * @throws Error if header is missing/malformed, signature is invalid, or timestamp is stale\n *\n * @example\n * // Express (use raw body!)\n * app.post(\"/webhooks\", express.raw({ type: \"application/json\" }), (req, res) => {\n * try {\n * const event = verifyWebhook(\n * req.body.toString(\"utf-8\"),\n * req.headers[\"x-waffo-signature\"] as string,\n * );\n * res.status(200).send(\"OK\");\n * handleEventAsync(event).catch(console.error);\n * } catch {\n * res.status(401).send(\"Invalid signature\");\n * }\n * });\n *\n * @example\n * // Next.js App Router\n * export async function POST(request: Request) {\n * const body = await request.text();\n * const sig = request.headers.get(\"x-waffo-signature\");\n * const event = verifyWebhook(body, sig);\n * // handle event ...\n * return new Response(\"OK\");\n * }\n *\n * @example\n * // Specify environment explicitly\n * const event = verifyWebhook(body, sig, { environment: \"prod\" });\n *\n * @example\n * // Disable replay protection\n * const event = verifyWebhook(body, sig, { toleranceMs: 0 });\n */\nexport function verifyWebhook<T = Record<string, unknown>>(\n payload: string,\n signatureHeader: string | undefined | null,\n options?: VerifyWebhookOptions,\n): WebhookEvent<T> {\n if (!signatureHeader) {\n throw new Error(\"Missing X-Waffo-Signature header\");\n }\n\n const { t, v1 } = parseSignatureHeader(signatureHeader);\n if (!t || !v1) {\n throw new Error(\"Malformed X-Waffo-Signature header: missing t or v1\");\n }\n\n // Replay protection\n const toleranceMs = options?.toleranceMs ?? DEFAULT_TOLERANCE_MS;\n if (toleranceMs > 0) {\n const timestampMs = Number(t);\n if (Number.isNaN(timestampMs)) {\n throw new Error(\"Invalid timestamp in X-Waffo-Signature header\");\n }\n if (Math.abs(Date.now() - timestampMs) > toleranceMs) {\n throw new Error(\"Webhook timestamp outside tolerance window (possible replay attack)\");\n }\n }\n\n // RSA-SHA256 verification\n const signatureInput = `${t}.${payload}`;\n const env = options?.environment;\n\n if (env === \"test\") {\n if (!rsaVerify(signatureInput, v1, TEST_PUBLIC_KEY)) {\n throw new Error(\"Invalid webhook signature (test key)\");\n }\n } else if (env === \"prod\") {\n if (!rsaVerify(signatureInput, v1, PROD_PUBLIC_KEY)) {\n throw new Error(\"Invalid webhook signature (prod key)\");\n }\n } else {\n // Auto-detect: try prod first, then test\n const prodValid = rsaVerify(signatureInput, v1, PROD_PUBLIC_KEY);\n if (!prodValid) {\n const testValid = rsaVerify(signatureInput, v1, TEST_PUBLIC_KEY);\n if (!testValid) {\n throw new Error(\"Invalid webhook signature (tried both prod and test keys)\");\n }\n }\n }\n\n return JSON.parse(payload) as WebhookEvent<T>;\n}\n","// ---------------------------------------------------------------------------\n// Client config\n// ---------------------------------------------------------------------------\n\nexport interface WaffoPancakeConfig {\n /** Merchant ID (X-Merchant-Id header) */\n merchantId: string;\n /** RSA private key in PEM format for request signing */\n privateKey: string;\n /** Base URL override (default: https://waffo-pancake-auth-service.vercel.app) */\n baseUrl?: string;\n /** Custom fetch implementation (default: global fetch) */\n fetch?: typeof fetch;\n}\n\n// ---------------------------------------------------------------------------\n// API response envelope\n// ---------------------------------------------------------------------------\n\n/**\n * Single error object within the `errors` array.\n *\n * @example\n * { message: \"Store slug already exists\", layer: \"store\" }\n */\nexport interface ApiError {\n /** Error message */\n message: string;\n /** Layer where the error originated */\n layer: `${ErrorLayer}`;\n}\n\n/** Successful API response envelope. */\nexport interface ApiSuccessResponse<T> {\n data: T;\n}\n\n/**\n * Error API response envelope.\n *\n * `errors` are ordered by call stack: `[0]` is the deepest layer, `[n]` is the outermost.\n */\nexport interface ApiErrorResponse {\n data: null;\n errors: ApiError[];\n}\n\n/** Union type of success and error API responses. */\nexport type ApiResponse<T> = ApiSuccessResponse<T> | ApiErrorResponse;\n\n// ---------------------------------------------------------------------------\n// Enums (runtime-accessible values)\n// ---------------------------------------------------------------------------\n\n/**\n * Environment type.\n * @see waffo-pancake-order-service/app/lib/types.ts\n */\nexport enum Environment {\n Test = \"test\",\n Prod = \"prod\",\n}\n\n/**\n * Tax category for products.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum TaxCategory {\n DigitalGoods = \"digital_goods\",\n SaaS = \"saas\",\n Software = \"software\",\n Ebook = \"ebook\",\n OnlineCourse = \"online_course\",\n Consulting = \"consulting\",\n ProfessionalService = \"professional_service\",\n}\n\n/**\n * Subscription billing period.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum BillingPeriod {\n Weekly = \"weekly\",\n Monthly = \"monthly\",\n Quarterly = \"quarterly\",\n Yearly = \"yearly\",\n}\n\n/**\n * Product version status.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum ProductVersionStatus {\n Active = \"active\",\n Inactive = \"inactive\",\n}\n\n/**\n * Store entity status.\n * @see waffo-pancake-store-service/app/lib/resources/store.ts\n */\nexport enum EntityStatus {\n Active = \"active\",\n Inactive = \"inactive\",\n Suspended = \"suspended\",\n}\n\n/**\n * Store member role.\n * @see waffo-pancake-store-service/app/lib/resources/store.ts\n */\nexport enum StoreRole {\n Owner = \"owner\",\n Admin = \"admin\",\n Member = \"member\",\n}\n\n/**\n * One-time order status.\n * @see waffo-pancake-order-service/app/lib/resources/onetime-order.ts\n */\nexport enum OnetimeOrderStatus {\n Pending = \"pending\",\n Completed = \"completed\",\n Canceled = \"canceled\",\n}\n\n/**\n * Subscription order status.\n *\n * State machine:\n * - pending -> active, canceled\n * - active -> canceling, past_due, canceled, expired\n * - canceling -> active, canceled\n * - past_due -> active, canceled\n * - canceled -> terminal\n * - expired -> terminal\n *\n * @see waffo-pancake-order-service/app/lib/resources/subscription-order.ts\n */\nexport enum SubscriptionOrderStatus {\n Pending = \"pending\",\n Active = \"active\",\n Canceling = \"canceling\",\n Canceled = \"canceled\",\n PastDue = \"past_due\",\n Expired = \"expired\",\n}\n\n/**\n * Payment status.\n * @see waffo-pancake-order-service/app/lib/resources/payment.ts\n */\nexport enum PaymentStatus {\n Pending = \"pending\",\n Succeeded = \"succeeded\",\n Failed = \"failed\",\n Canceled = \"canceled\",\n}\n\n/**\n * Refund ticket status.\n * @see waffo-pancake-order-service/app/lib/resources/refund-ticket.ts\n */\nexport enum RefundTicketStatus {\n Pending = \"pending\",\n Approved = \"approved\",\n Rejected = \"rejected\",\n Processing = \"processing\",\n Succeeded = \"succeeded\",\n Failed = \"failed\",\n}\n\n/**\n * Refund status.\n * @see waffo-pancake-order-service/app/lib/resources/refund.ts\n */\nexport enum RefundStatus {\n Succeeded = \"succeeded\",\n Failed = \"failed\",\n}\n\n/**\n * Media asset type.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum MediaType {\n Image = \"image\",\n Video = \"video\",\n}\n\n/**\n * Checkout session product type.\n * @see waffo-pancake-order-service/app/lib/types.ts\n */\nexport enum CheckoutSessionProductType {\n Onetime = \"onetime\",\n Subscription = \"subscription\",\n}\n\n/** Error layer identifier in the call stack. */\nexport enum ErrorLayer {\n Gateway = \"gateway\",\n User = \"user\",\n Store = \"store\",\n Product = \"product\",\n Order = \"order\",\n GraphQL = \"graphql\",\n Resource = \"resource\",\n Email = \"email\",\n}\n\n// ---------------------------------------------------------------------------\n// Auth\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for issuing a buyer session token.\n * @see waffo-pancake-user-service/app/lib/utils/jwt.ts IssueSessionTokenRequest\n */\nexport interface IssueSessionTokenParams {\n /** Buyer identity (email or any merchant-provided identifier string) */\n buyerIdentity: string;\n /** Store ID */\n storeId: string;\n}\n\n/**\n * Issued session token response.\n *\n * @example\n * { token: \"eyJhbGciOi...\", expiresAt: \"2026-03-10T09:00:00.000Z\" }\n */\nexport interface SessionToken {\n /** JWT token string */\n token: string;\n /** Expiration time (ISO 8601 UTC) */\n expiresAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// Store — from waffo-pancake-store-service\n// ---------------------------------------------------------------------------\n\n/**\n * Webhook configuration for test and production environments.\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface WebhookSettings {\n /** Test environment webhook URL */\n testWebhookUrl: string | null;\n /** Production environment webhook URL */\n prodWebhookUrl: string | null;\n /** Event types subscribed in test environment */\n testEvents: string[];\n /** Event types subscribed in production environment */\n prodEvents: string[];\n}\n\n/**\n * Notification settings (all default to true).\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface NotificationSettings {\n emailOrderConfirmation: boolean;\n emailSubscriptionConfirmation: boolean;\n emailSubscriptionCycled: boolean;\n emailSubscriptionCanceled: boolean;\n emailSubscriptionRevoked: boolean;\n emailSubscriptionPastDue: boolean;\n notifyNewOrders: boolean;\n notifyNewSubscriptions: boolean;\n}\n\n/**\n * Single-theme checkout page styling.\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface CheckoutThemeSettings {\n checkoutLogo: string | null;\n checkoutColorPrimary: string;\n checkoutColorBackground: string;\n checkoutColorCard: string;\n checkoutColorText: string;\n checkoutColorTextSecondary: string;\n checkoutBorderRadius: string;\n}\n\n/**\n * Checkout page configuration (light and dark themes).\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface CheckoutSettings {\n light: CheckoutThemeSettings;\n dark: CheckoutThemeSettings;\n}\n\n/**\n * Store entity.\n * @see waffo-pancake-store-service/app/lib/resources/store.ts\n */\nexport interface Store {\n id: string;\n name: string;\n status: EntityStatus;\n logo: string | null;\n supportEmail: string | null;\n website: string | null;\n slug: string | null;\n isPublic: boolean;\n prodEnabled: boolean;\n webhookSettings: WebhookSettings | null;\n notificationSettings: NotificationSettings | null;\n checkoutSettings: CheckoutSettings | null;\n deletedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Parameters for creating a store. */\nexport interface CreateStoreParams {\n /** Store name (slug is auto-generated) */\n name: string;\n}\n\n/** Parameters for updating a store. */\nexport interface UpdateStoreParams {\n /** Store ID */\n id: string;\n name?: string;\n status?: EntityStatus;\n logo?: string | null;\n supportEmail?: string | null;\n website?: string | null;\n isPublic?: boolean;\n webhookSettings?: WebhookSettings | null;\n notificationSettings?: NotificationSettings | null;\n checkoutSettings?: CheckoutSettings | null;\n}\n\n/** Parameters for deleting (soft-delete) a store. */\nexport interface DeleteStoreParams {\n /** Store ID */\n id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Store Merchant (coming soon — endpoints return 501)\n// ---------------------------------------------------------------------------\n\n/** Parameters for adding a merchant to a store. */\nexport interface AddMerchantParams {\n storeId: string;\n email: string;\n role: \"admin\" | \"member\";\n}\n\n/** Result of adding a merchant to a store. */\nexport interface AddMerchantResult {\n storeId: string;\n merchantId: string;\n email: string;\n role: string;\n status: string;\n addedAt: string;\n}\n\n/** Parameters for removing a merchant from a store. */\nexport interface RemoveMerchantParams {\n storeId: string;\n merchantId: string;\n}\n\n/** Result of removing a merchant from a store. */\nexport interface RemoveMerchantResult {\n message: string;\n removedAt: string;\n}\n\n/** Parameters for updating a merchant's role. */\nexport interface UpdateRoleParams {\n storeId: string;\n merchantId: string;\n role: \"admin\" | \"member\";\n}\n\n/** Result of updating a merchant's role. */\nexport interface UpdateRoleResult {\n storeId: string;\n merchantId: string;\n role: string;\n updatedAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// Product — shared types from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * Price for a single currency.\n *\n * Amounts are stored in the smallest currency unit (e.g. cents, yen)\n * to avoid floating-point precision issues.\n *\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n *\n * @example\n * // USD $9.99\n * { amount: 999, taxIncluded: true, taxCategory: \"saas\" }\n *\n * @example\n * // JPY ¥1000\n * { amount: 1000, taxIncluded: false, taxCategory: \"software\" }\n */\nexport interface PriceInfo {\n /** Price amount in smallest currency unit */\n amount: number;\n /** Whether the price is tax-inclusive */\n taxIncluded: boolean;\n /** Tax category */\n taxCategory: TaxCategory;\n}\n\n/**\n * Multi-currency prices (keyed by ISO 4217 currency code).\n *\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n *\n * @example\n * {\n * \"USD\": { amount: 999, taxIncluded: true, taxCategory: \"saas\" },\n * \"EUR\": { amount: 899, taxIncluded: true, taxCategory: \"saas\" }\n * }\n */\nexport type Prices = Record<string, PriceInfo>;\n\n/**\n * Media asset (image or video).\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport interface MediaItem {\n /** Media type */\n type: `${MediaType}`;\n /** Asset URL */\n url: string;\n /** Alt text */\n alt?: string;\n /** Thumbnail URL */\n thumbnail?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Onetime Product — from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * One-time product detail (public API shape).\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts OnetimeProductDetail\n */\nexport interface OnetimeProductDetail {\n id: string;\n storeId: string;\n name: string;\n description: string | null;\n prices: Prices;\n media: MediaItem[];\n successUrl: string | null;\n metadata: Record<string, unknown>;\n status: ProductVersionStatus;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Parameters for creating a one-time product.\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts CreateOnetimeProductRequestBody\n */\nexport interface CreateOnetimeProductParams {\n storeId: string;\n name: string;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parameters for updating a one-time product (creates a new version; skips if unchanged).\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts UpdateOnetimeProductContentRequestBody\n */\nexport interface UpdateOnetimeProductParams {\n id: string;\n name: string;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/** Parameters for publishing a one-time product's test version to production. */\nexport interface PublishOnetimeProductParams {\n /** Product ID */\n id: string;\n}\n\n/**\n * Parameters for updating a one-time product's status.\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts UpdateOnetimeStatusRequestBody\n */\nexport interface UpdateOnetimeStatusParams {\n id: string;\n status: ProductVersionStatus;\n}\n\n// ---------------------------------------------------------------------------\n// Subscription Product — from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * Subscription product detail (public API shape).\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts SubscriptionProductDetail\n */\nexport interface SubscriptionProductDetail {\n id: string;\n storeId: string;\n name: string;\n description: string | null;\n billingPeriod: BillingPeriod;\n prices: Prices;\n media: MediaItem[];\n successUrl: string | null;\n metadata: Record<string, unknown>;\n status: ProductVersionStatus;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Parameters for creating a subscription product.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts CreateSubscriptionProductRequestBody\n */\nexport interface CreateSubscriptionProductParams {\n storeId: string;\n name: string;\n billingPeriod: BillingPeriod;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parameters for updating a subscription product (creates a new version; skips if unchanged).\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts UpdateSubscriptionProductContentRequestBody\n */\nexport interface UpdateSubscriptionProductParams {\n id: string;\n name: string;\n billingPeriod: BillingPeriod;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/** Parameters for publishing a subscription product's test version to production. */\nexport interface PublishSubscriptionProductParams {\n /** Product ID */\n id: string;\n}\n\n/**\n * Parameters for updating a subscription product's status.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts UpdateSubscriptionStatusRequestBody\n */\nexport interface UpdateSubscriptionStatusParams {\n id: string;\n status: ProductVersionStatus;\n}\n\n// ---------------------------------------------------------------------------\n// Subscription Product Group — from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * Group rules for subscription product groups.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts\n */\nexport interface GroupRules {\n /** Whether trial period is shared across products in the group */\n sharedTrial: boolean;\n}\n\n/**\n * Subscription product group entity.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts\n */\nexport interface SubscriptionProductGroup {\n id: string;\n storeId: string;\n name: string;\n description: string | null;\n rules: GroupRules;\n productIds: string[];\n environment: Environment;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Parameters for creating a subscription product group.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts CreateGroupRequestBody\n */\nexport interface CreateSubscriptionProductGroupParams {\n storeId: string;\n name: string;\n description?: string;\n rules?: GroupRules;\n productIds?: string[];\n}\n\n/**\n * Parameters for updating a subscription product group (`productIds` is a full replacement).\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts UpdateGroupRequestBody\n */\nexport interface UpdateSubscriptionProductGroupParams {\n id: string;\n name?: string;\n description?: string;\n rules?: GroupRules;\n productIds?: string[];\n}\n\n/** Parameters for hard-deleting a subscription product group. */\nexport interface DeleteSubscriptionProductGroupParams {\n /** Group ID */\n id: string;\n}\n\n/** Parameters for publishing a test-environment group to production (upsert). */\nexport interface PublishSubscriptionProductGroupParams {\n /** Group ID */\n id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Order — from waffo-pancake-order-service\n// ---------------------------------------------------------------------------\n\n/** Parameters for canceling a subscription order. */\nexport interface CancelSubscriptionParams {\n /** Order ID */\n orderId: string;\n}\n\n/**\n * Result of canceling a subscription order.\n * @see waffo-pancake-order-service cancel-order route.ts\n */\nexport interface CancelSubscriptionResult {\n orderId: string;\n /** Status after cancellation (`\"canceled\"` or `\"canceling\"`) */\n status: `${SubscriptionOrderStatus}`;\n}\n\n/**\n * Buyer billing details for checkout.\n * @see waffo-pancake-order-service/app/lib/types.ts\n */\nexport interface BillingDetail {\n /** Country code (ISO 3166-1 alpha-2) */\n country: string;\n /** Whether this is a business purchase */\n isBusiness: boolean;\n /** Postal / ZIP code */\n postcode?: string;\n /** State / province code (required for US/CA) */\n state?: string;\n /** Business name (required when isBusiness=true) */\n businessName?: string;\n /** Tax ID (required for EU businesses) */\n taxId?: string;\n}\n\n/**\n * Parameters for creating a checkout session.\n * @see waffo-pancake-order-service/app/lib/types.ts CreateCheckoutSessionRequest\n */\nexport interface CreateCheckoutSessionParams {\n /** Store ID */\n storeId?: string;\n /** Product ID */\n productId: string;\n /** Product type */\n productType: `${CheckoutSessionProductType}`;\n /** Currency code (ISO 4217) */\n currency: string;\n /** Optional price snapshot override (reads from DB if omitted) */\n priceSnapshot?: PriceInfo;\n /** Trial toggle override (subscription only) */\n withTrial?: boolean;\n /** Pre-filled buyer email */\n buyerEmail?: string;\n /** Pre-filled billing details */\n billingDetail?: BillingDetail;\n /** Redirect URL after successful payment */\n successUrl?: string;\n /** Session expiration in seconds (default: 7 days) */\n expiresInSeconds?: number;\n /** Custom metadata */\n metadata?: Record<string, string>;\n}\n\n/** Result of creating a checkout session. */\nexport interface CheckoutSessionResult {\n /** Session ID */\n sessionId: string;\n /** URL to redirect the customer to */\n checkoutUrl: string;\n /** Session expiration time (ISO 8601 UTC) */\n expiresAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// GraphQL\n// ---------------------------------------------------------------------------\n\n/** Parameters for a GraphQL query. */\nexport interface GraphQLParams {\n /** GraphQL query string */\n query: string;\n /** Query variables */\n variables?: Record<string, unknown>;\n}\n\n/** GraphQL response envelope. */\nexport interface GraphQLResponse<T = Record<string, unknown>> {\n data: T | null;\n errors?: Array<{\n message: string;\n locations?: Array<{ line: number; column: number }>;\n path?: string[];\n }>;\n}\n\n// ---------------------------------------------------------------------------\n// Webhook\n// ---------------------------------------------------------------------------\n\n/**\n * Webhook event types.\n * @see docs/api-reference/webhooks.mdx\n */\nexport enum WebhookEventType {\n /** One-time order first payment succeeded */\n OrderCompleted = \"order.completed\",\n /** Subscription first payment succeeded (newly activated) */\n SubscriptionActivated = \"subscription.activated\",\n /** Subscription renewal payment succeeded */\n SubscriptionPaymentSucceeded = \"subscription.payment_succeeded\",\n /** Buyer initiated cancellation (expires at end of current period) */\n SubscriptionCanceling = \"subscription.canceling\",\n /** Buyer withdrew cancellation (subscription restored) */\n SubscriptionUncanceled = \"subscription.uncanceled\",\n /** Subscription product changed (upgrade/downgrade) */\n SubscriptionUpdated = \"subscription.updated\",\n /** Subscription fully terminated */\n SubscriptionCanceled = \"subscription.canceled\",\n /** Renewal payment failed (past due) */\n SubscriptionPastDue = \"subscription.past_due\",\n /** Refund succeeded */\n RefundSucceeded = \"refund.succeeded\",\n /** Refund failed */\n RefundFailed = \"refund.failed\",\n}\n\n/**\n * Common data fields in a webhook event payload.\n * @see docs/api-reference/webhooks.mdx\n */\nexport interface WebhookEventData {\n orderId: string;\n buyerEmail: string;\n currency: string;\n /** Amount in smallest currency unit */\n amount: number;\n /** Tax amount in smallest currency unit */\n taxAmount: number;\n productName: string;\n}\n\n/**\n * Webhook event payload.\n *\n * @see docs/api-reference/webhooks.mdx\n *\n * @example\n * {\n * id: \"550e8400-...\",\n * timestamp: \"2026-03-10T08:30:00.000Z\",\n * eventType: \"order.completed\",\n * eventId: \"pay_660e8400-...\",\n * storeId: \"770e8400-...\",\n * mode: \"prod\",\n * data: { orderId: \"...\", buyerEmail: \"...\", currency: \"USD\", amount: 2900, taxAmount: 290, productName: \"Pro Plan\" }\n * }\n */\nexport interface WebhookEvent<T = WebhookEventData> {\n /** Delivery record unique ID (UUID), usable for idempotent deduplication */\n id: string;\n /** Event timestamp (ISO 8601 UTC) */\n timestamp: string;\n /** Event type */\n eventType: `${WebhookEventType}` | (string & {});\n /** Business event ID (e.g. payment ID, order ID) */\n eventId: string;\n /** Store ID the event belongs to */\n storeId: string;\n /** Environment identifier */\n mode: `${Environment}`;\n /** Event data */\n data: T;\n}\n\n/** Options for {@link verifyWebhook}. */\nexport interface VerifyWebhookOptions {\n /**\n * Specify which environment's public key to use for verification.\n * When omitted, both keys are tried automatically (prod first).\n */\n environment?: `${Environment}`;\n /**\n * Timestamp tolerance window in milliseconds for replay protection.\n * Set to 0 to skip timestamp checking.\n * @default 300000 (5 minutes)\n */\n toleranceMs?: number;\n}\n"],"mappings":"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","names":["import_node_crypto","import_node_crypto","Environment","TaxCategory","BillingPeriod","ProductVersionStatus","EntityStatus","StoreRole","OnetimeOrderStatus","SubscriptionOrderStatus","PaymentStatus","RefundTicketStatus","RefundStatus","MediaType","CheckoutSessionProductType","ErrorLayer","WebhookEventType"]}
package/dist/index.js CHANGED
@@ -15,9 +15,58 @@ var WaffoPancakeError = class extends Error {
15
15
  };
16
16
 
17
17
  // src/signing.ts
18
- import { createHash, createSign } from "crypto";
18
+ import { createHash, createPrivateKey, createSign } from "crypto";
19
+ var PKCS8_HEADER = "-----BEGIN PRIVATE KEY-----";
20
+ var PKCS8_FOOTER = "-----END PRIVATE KEY-----";
21
+ var PKCS1_HEADER = "-----BEGIN RSA PRIVATE KEY-----";
22
+ var PKCS1_FOOTER = "-----END RSA PRIVATE KEY-----";
23
+ function normalizePrivateKey(raw) {
24
+ if (!raw || !raw.trim()) {
25
+ throw new Error(
26
+ "Private key is empty. Provide an RSA private key in PEM format."
27
+ );
28
+ }
29
+ let pem = raw.replace(/\\n/g, "\n").replace(/\r\n/g, "\n");
30
+ pem = pem.trim();
31
+ const hasPkcs8Header = pem.includes(PKCS8_HEADER);
32
+ const hasPkcs1Header = pem.includes(PKCS1_HEADER);
33
+ const hasHeader = hasPkcs8Header || hasPkcs1Header;
34
+ if (hasHeader) {
35
+ const base64 = pem.replace(/-----BEGIN (?:RSA )?PRIVATE KEY-----/g, "").replace(/-----END (?:RSA )?PRIVATE KEY-----/g, "").replace(/\s+/g, "");
36
+ if (!base64) {
37
+ throw new Error(
38
+ "Private key contains PEM headers but no key data. Check the key content."
39
+ );
40
+ }
41
+ const header = hasPkcs1Header ? PKCS1_HEADER : PKCS8_HEADER;
42
+ const footer = hasPkcs1Header ? PKCS1_FOOTER : PKCS8_FOOTER;
43
+ const wrapped = base64.match(/.{1,64}/g).join("\n");
44
+ pem = `${header}
45
+ ${wrapped}
46
+ ${footer}`;
47
+ } else {
48
+ const base64 = pem.replace(/\s+/g, "");
49
+ if (!/^[A-Za-z0-9+/]+=*$/.test(base64)) {
50
+ throw new Error(
51
+ "Private key is not valid PEM or base64. Expected an RSA private key in PEM format or raw base64."
52
+ );
53
+ }
54
+ const wrapped = base64.match(/.{1,64}/g).join("\n");
55
+ pem = `${PKCS8_HEADER}
56
+ ${wrapped}
57
+ ${PKCS8_FOOTER}`;
58
+ }
59
+ try {
60
+ createPrivateKey(pem);
61
+ } catch {
62
+ throw new Error(
63
+ "Private key could not be parsed. Ensure it is a valid RSA private key in PKCS#8 or PKCS#1 (PEM) format."
64
+ );
65
+ }
66
+ return pem;
67
+ }
19
68
  function signRequest(method, path, timestamp, body, privateKey) {
20
- const bodyHash = createHash("sha256").update(body).digest("hex");
69
+ const bodyHash = createHash("sha256").update(body).digest("base64");
21
70
  const canonicalRequest = `${method}
22
71
  ${path}
23
72
  ${timestamp}
@@ -36,7 +85,7 @@ var HttpClient = class {
36
85
  _fetch;
37
86
  constructor(config) {
38
87
  this.merchantId = config.merchantId;
39
- this.privateKey = config.privateKey;
88
+ this.privateKey = normalizePrivateKey(config.privateKey);
40
89
  this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
41
90
  this._fetch = config.fetch ?? fetch;
42
91
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/http-client.ts","../src/errors.ts","../src/signing.ts","../src/resources/auth.ts","../src/resources/checkout.ts","../src/resources/graphql.ts","../src/resources/onetime-products.ts","../src/resources/orders.ts","../src/resources/store-merchants.ts","../src/resources/stores.ts","../src/resources/subscription-product-groups.ts","../src/resources/subscription-products.ts","../src/client.ts","../src/webhooks.ts","../src/types.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\n\nimport { WaffoPancakeError } from \"./errors.js\";\nimport { signRequest } from \"./signing.js\";\n\nimport type { ApiResponse, WaffoPancakeConfig } from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://waffo-pancake-auth-service.vercel.app\";\n\n/**\n * Internal HTTP client that auto-signs requests and attaches idempotency keys.\n *\n * Not exported publicly — used by resource classes via {@link WaffoPancake}.\n */\nexport class HttpClient {\n private readonly merchantId: string;\n private readonly privateKey: string;\n private readonly baseUrl: string;\n private readonly _fetch: typeof fetch;\n\n constructor(config: WaffoPancakeConfig) {\n this.merchantId = config.merchantId;\n this.privateKey = config.privateKey;\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this._fetch = config.fetch ?? fetch;\n }\n\n /**\n * Send a signed POST request and return the parsed `data` field.\n *\n * Behavior:\n * - Generates a deterministic `X-Idempotency-Key` from `merchantId + path + body` (same request produces same key)\n * - Auto-builds RSA-SHA256 signature (`X-Merchant-Id` / `X-Timestamp` / `X-Signature`)\n * - Unwraps the response envelope: returns `data` on success, throws `WaffoPancakeError` on failure\n *\n * @param path - API path (e.g. `/v1/actions/store/create-store`)\n * @param body - Request body object\n * @returns Parsed `data` field from the response\n * @throws {WaffoPancakeError} When the API returns errors\n */\n async post<T>(path: string, body: object): Promise<T> {\n const bodyStr = JSON.stringify(body);\n const timestamp = Math.floor(Date.now() / 1000).toString();\n const signature = signRequest(\"POST\", path, timestamp, bodyStr, this.privateKey);\n\n const response = await this._fetch(`${this.baseUrl}${path}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Merchant-Id\": this.merchantId,\n \"X-Timestamp\": timestamp,\n \"X-Signature\": signature,\n \"X-Idempotency-Key\": createHash(\"sha256\")\n .update(`${this.merchantId}:${path}:${bodyStr}`)\n .digest(\"hex\"),\n },\n body: bodyStr,\n });\n\n const result = (await response.json()) as ApiResponse<T>;\n\n if (\"errors\" in result && result.errors) {\n throw new WaffoPancakeError(response.status, result.errors);\n }\n\n return result.data as T;\n }\n}\n","import type { ApiError } from \"./types.js\";\n\n/**\n * Error thrown when the API returns a non-success response.\n *\n * @example\n * try {\n * await client.stores.create({ name: \"My Store\" });\n * } catch (err) {\n * if (err instanceof WaffoPancakeError) {\n * console.log(err.status); // 400\n * console.log(err.errors[0]); // { message: \"...\", layer: \"store\" }\n * }\n * }\n */\nexport class WaffoPancakeError extends Error {\n readonly status: number;\n readonly errors: ApiError[];\n\n constructor(status: number, errors: ApiError[]) {\n const rootCause = errors[0]?.message ?? \"Unknown error\";\n super(rootCause);\n this.name = \"WaffoPancakeError\";\n this.status = status;\n this.errors = errors;\n }\n}\n","import { createHash, createSign } from \"node:crypto\";\n\n/**\n * Build canonical request string and sign with RSA-SHA256.\n *\n * Canonical request format:\n * METHOD\\nPATH\\nTIMESTAMP\\nSHA256(BODY)\n *\n * @param method - HTTP method (e.g. \"POST\")\n * @param path - Request path (e.g. \"/v1/actions/store/create-store\")\n * @param timestamp - Unix epoch seconds string\n * @param body - Serialized JSON body\n * @param privateKey - RSA private key in PEM format\n * @returns Base64-encoded RSA-SHA256 signature\n */\nexport function signRequest(\n method: string,\n path: string,\n timestamp: string,\n body: string,\n privateKey: string,\n): string {\n const bodyHash = createHash(\"sha256\").update(body).digest(\"hex\");\n const canonicalRequest = `${method}\\n${path}\\n${timestamp}\\n${bodyHash}`;\n\n const sign = createSign(\"sha256\");\n sign.update(canonicalRequest);\n return sign.sign(privateKey, \"base64\");\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { IssueSessionTokenParams, SessionToken } from \"../types.js\";\n\n/** Authentication resource — issue session tokens for buyers. */\nexport class AuthResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Issue a session token for a buyer.\n *\n * @param params - Token issuance parameters\n * @returns Issued session token with expiration\n *\n * @example\n * const { token, expiresAt } = await client.auth.issueSessionToken({\n * storeId: \"store_xxx\",\n * buyerIdentity: \"customer@example.com\",\n * });\n */\n async issueSessionToken(params: IssueSessionTokenParams): Promise<SessionToken> {\n return this.http.post<SessionToken>(\"/v1/actions/auth/issue-session-token\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { CheckoutSessionResult, CreateCheckoutSessionParams } from \"../types.js\";\n\n/** Checkout resource — create checkout sessions for payments. */\nexport class CheckoutResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a checkout session. Returns a URL to redirect the customer to.\n *\n * @param params - Checkout session parameters\n * @returns Session ID, checkout URL, and expiration\n *\n * @example\n * const session = await client.checkout.createSession({\n * storeId: \"store_xxx\",\n * productId: \"prod_xxx\",\n * productType: \"onetime\",\n * currency: \"USD\",\n * buyerEmail: \"customer@example.com\",\n * });\n * // Redirect to session.checkoutUrl\n */\n async createSession(params: CreateCheckoutSessionParams): Promise<CheckoutSessionResult> {\n return this.http.post<CheckoutSessionResult>(\"/v1/actions/checkout/create-session\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { GraphQLParams, GraphQLResponse } from \"../types.js\";\n\n/** GraphQL query resource (Query only, no Mutations). */\nexport class GraphQLResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Execute a GraphQL query (Query only, no Mutations).\n *\n * @param params - GraphQL query and optional variables\n * @returns GraphQL response with data and optional errors\n *\n * @example\n * const result = await client.graphql.query<{ stores: Array<{ id: string; name: string }> }>({\n * query: `query { stores { id name status } }`,\n * });\n * console.log(result.data?.stores);\n *\n * @example\n * const result = await client.graphql.query({\n * query: `query ($id: ID!) { onetimeProduct(id: $id) { id name prices } }`,\n * variables: { id: \"prod_xxx\" },\n * });\n */\n async query<T = Record<string, unknown>>(params: GraphQLParams): Promise<GraphQLResponse<T>> {\n return this.http.post<GraphQLResponse<T>>(\"/v1/graphql\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateOnetimeProductParams,\n OnetimeProductDetail,\n PublishOnetimeProductParams,\n UpdateOnetimeProductParams,\n UpdateOnetimeStatusParams,\n} from \"../types.js\";\n\n/** One-time product management resource. */\nexport class OnetimeProductsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a one-time product with multi-currency pricing.\n *\n * @param params - Product creation parameters\n * @returns Created product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.create({\n * storeId: \"store_xxx\",\n * name: \"E-Book\",\n * prices: { USD: { amount: 2900, taxIncluded: false, taxCategory: \"digital_goods\" } },\n * });\n */\n async create(params: CreateOnetimeProductParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/create-product\", params);\n }\n\n /**\n * Update a one-time product. Creates a new version; skips if unchanged.\n *\n * @param params - Product update parameters (all content fields required)\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.update({\n * id: \"prod_xxx\",\n * name: \"E-Book v2\",\n * prices: { USD: { amount: 3900, taxIncluded: false, taxCategory: \"digital_goods\" } },\n * });\n */\n async update(params: UpdateOnetimeProductParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/update-product\", params);\n }\n\n /**\n * Publish a one-time product's test version to production.\n *\n * @param params - Product to publish\n * @returns Published product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.publish({ id: \"prod_xxx\" });\n */\n async publish(params: PublishOnetimeProductParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/publish-product\", params);\n }\n\n /**\n * Update a one-time product's status (active/inactive).\n *\n * @param params - Status update parameters\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.updateStatus({\n * id: \"prod_xxx\",\n * status: ProductVersionStatus.Inactive,\n * });\n */\n async updateStatus(params: UpdateOnetimeStatusParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/update-status\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { CancelSubscriptionParams, CancelSubscriptionResult } from \"../types.js\";\n\n/** Order management resource. */\nexport class OrdersResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Cancel a subscription order.\n *\n * - pending -> canceled (immediate)\n * - active/trialing -> canceling (PSP cancel, webhook updates later)\n *\n * @param params - Order to cancel\n * @returns Order ID and resulting status\n *\n * @example\n * const { orderId, status } = await client.orders.cancelSubscription({\n * orderId: \"order_xxx\",\n * });\n * // status: \"canceled\" or \"canceling\"\n */\n async cancelSubscription(params: CancelSubscriptionParams): Promise<CancelSubscriptionResult> {\n return this.http.post<CancelSubscriptionResult>(\"/v1/actions/subscription-order/cancel-order\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n AddMerchantParams,\n AddMerchantResult,\n RemoveMerchantParams,\n RemoveMerchantResult,\n UpdateRoleParams,\n UpdateRoleResult,\n} from \"../types.js\";\n\n/** Store merchant management resource (coming soon — endpoints return 501). */\nexport class StoreMerchantsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Add a merchant to a store.\n *\n * @param params - Merchant addition parameters\n * @returns Added merchant details\n *\n * @example\n * const result = await client.storeMerchants.add({\n * storeId: \"store_xxx\",\n * email: \"member@example.com\",\n * role: \"admin\",\n * });\n */\n async add(params: AddMerchantParams): Promise<AddMerchantResult> {\n return this.http.post(\"/v1/actions/store-merchant/add-merchant\", params);\n }\n\n /**\n * Remove a merchant from a store.\n *\n * @param params - Merchant removal parameters\n * @returns Removal confirmation\n *\n * @example\n * const result = await client.storeMerchants.remove({\n * storeId: \"store_xxx\",\n * merchantId: \"merchant_xxx\",\n * });\n */\n async remove(params: RemoveMerchantParams): Promise<RemoveMerchantResult> {\n return this.http.post(\"/v1/actions/store-merchant/remove-merchant\", params);\n }\n\n /**\n * Update a merchant's role in a store.\n *\n * @param params - Role update parameters\n * @returns Updated role details\n *\n * @example\n * const result = await client.storeMerchants.updateRole({\n * storeId: \"store_xxx\",\n * merchantId: \"merchant_xxx\",\n * role: \"member\",\n * });\n */\n async updateRole(params: UpdateRoleParams): Promise<UpdateRoleResult> {\n return this.http.post(\"/v1/actions/store-merchant/update-role\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateStoreParams,\n DeleteStoreParams,\n Store,\n UpdateStoreParams,\n} from \"../types.js\";\n\n/** Store management resource — create, update, and delete stores. */\nexport class StoresResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a new store. Slug is auto-generated from the name.\n *\n * @param params - Store creation parameters\n * @returns Created store entity\n *\n * @example\n * const { store } = await client.stores.create({ name: \"My Store\" });\n */\n async create(params: CreateStoreParams): Promise<{ store: Store }> {\n return this.http.post(\"/v1/actions/store/create-store\", params);\n }\n\n /**\n * Update an existing store's settings.\n *\n * @param params - Fields to update (only provided fields are changed)\n * @returns Updated store entity\n *\n * @example\n * const { store } = await client.stores.update({\n * id: \"store_xxx\",\n * name: \"Updated Name\",\n * supportEmail: \"help@example.com\",\n * });\n */\n async update(params: UpdateStoreParams): Promise<{ store: Store }> {\n return this.http.post(\"/v1/actions/store/update-store\", params);\n }\n\n /**\n * Soft-delete a store. Only the owner can delete.\n *\n * @param params - Store to delete\n * @returns Deleted store entity (with `deletedAt` set)\n *\n * @example\n * const { store } = await client.stores.delete({ id: \"store_xxx\" });\n */\n async delete(params: DeleteStoreParams): Promise<{ store: Store }> {\n return this.http.post(\"/v1/actions/store/delete-store\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateSubscriptionProductGroupParams,\n DeleteSubscriptionProductGroupParams,\n PublishSubscriptionProductGroupParams,\n SubscriptionProductGroup,\n UpdateSubscriptionProductGroupParams,\n} from \"../types.js\";\n\n/** Subscription product group management resource (shared trial, plan switching). */\nexport class SubscriptionProductGroupsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a subscription product group for shared-trial or plan switching.\n *\n * @param params - Group creation parameters\n * @returns Created group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.create({\n * storeId: \"store_xxx\",\n * name: \"Pro Plans\",\n * rules: { sharedTrial: true },\n * productIds: [\"prod_aaa\", \"prod_bbb\"],\n * });\n */\n async create(params: CreateSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/create-group\", params);\n }\n\n /**\n * Update a subscription product group. `productIds` is a full replacement.\n *\n * @param params - Group update parameters\n * @returns Updated group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.update({\n * id: \"group_xxx\",\n * productIds: [\"prod_aaa\", \"prod_bbb\", \"prod_ccc\"],\n * });\n */\n async update(params: UpdateSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/update-group\", params);\n }\n\n /**\n * Hard-delete a subscription product group.\n *\n * @param params - Group to delete\n * @returns Deleted group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.delete({ id: \"group_xxx\" });\n */\n async delete(params: DeleteSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/delete-group\", params);\n }\n\n /**\n * Publish a test-environment group to production (upsert).\n *\n * @param params - Group to publish\n * @returns Published group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.publish({ id: \"group_xxx\" });\n */\n async publish(params: PublishSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/publish-group\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateSubscriptionProductParams,\n PublishSubscriptionProductParams,\n SubscriptionProductDetail,\n UpdateSubscriptionProductParams,\n UpdateSubscriptionStatusParams,\n} from \"../types.js\";\n\n/** Subscription product management resource. */\nexport class SubscriptionProductsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a subscription product with billing period and multi-currency pricing.\n *\n * @param params - Product creation parameters\n * @returns Created product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.create({\n * storeId: \"store_xxx\",\n * name: \"Pro Plan\",\n * billingPeriod: \"monthly\",\n * prices: { USD: { amount: 999, taxIncluded: false, taxCategory: \"saas\" } },\n * });\n */\n async create(params: CreateSubscriptionProductParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/create-product\", params);\n }\n\n /**\n * Update a subscription product. Creates a new version; skips if unchanged.\n *\n * @param params - Product update parameters (all content fields required)\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.update({\n * id: \"prod_xxx\",\n * name: \"Pro Plan v2\",\n * billingPeriod: \"monthly\",\n * prices: { USD: { amount: 1499, taxIncluded: false, taxCategory: \"saas\" } },\n * });\n */\n async update(params: UpdateSubscriptionProductParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/update-product\", params);\n }\n\n /**\n * Publish a subscription product's test version to production.\n *\n * @param params - Product to publish\n * @returns Published product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.publish({ id: \"prod_xxx\" });\n */\n async publish(params: PublishSubscriptionProductParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/publish-product\", params);\n }\n\n /**\n * Update a subscription product's status (active/inactive).\n *\n * @param params - Status update parameters\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.updateStatus({\n * id: \"prod_xxx\",\n * status: ProductVersionStatus.Active,\n * });\n */\n async updateStatus(params: UpdateSubscriptionStatusParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/update-status\", params);\n }\n}\n","import { HttpClient } from \"./http-client.js\";\nimport { AuthResource } from \"./resources/auth.js\";\nimport { CheckoutResource } from \"./resources/checkout.js\";\nimport { GraphQLResource } from \"./resources/graphql.js\";\nimport { OnetimeProductsResource } from \"./resources/onetime-products.js\";\nimport { OrdersResource } from \"./resources/orders.js\";\nimport { StoreMerchantsResource } from \"./resources/store-merchants.js\";\nimport { StoresResource } from \"./resources/stores.js\";\nimport { SubscriptionProductGroupsResource } from \"./resources/subscription-product-groups.js\";\nimport { SubscriptionProductsResource } from \"./resources/subscription-products.js\";\n\nimport type { WaffoPancakeConfig } from \"./types.js\";\n\n/**\n * Waffo Pancake TypeScript SDK client.\n *\n * Uses Merchant API Key (RSA-SHA256) authentication. All requests are\n * automatically signed — no manual header construction needed.\n *\n * @example\n * import { WaffoPancake } from \"@waffo/pancake-ts\";\n *\n * const client = new WaffoPancake({\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * });\n *\n * // Create a store\n * const { store } = await client.stores.create({ name: \"My Store\" });\n *\n * // Create a product\n * const { product } = await client.onetimeProducts.create({\n * storeId: store.id,\n * name: \"E-Book\",\n * prices: { USD: { amount: 2900, taxIncluded: false, taxCategory: \"digital_goods\" } },\n * });\n *\n * // Create a checkout session\n * const session = await client.checkout.createSession({\n * storeId: store.id,\n * productId: product.id,\n * productType: \"onetime\",\n * currency: \"USD\",\n * });\n * // => redirect customer to session.checkoutUrl\n *\n * // Query data via GraphQL\n * const result = await client.graphql.query({\n * query: `query { stores { id name status } }`,\n * });\n */\nexport class WaffoPancake {\n private readonly http: HttpClient;\n\n readonly auth: AuthResource;\n readonly stores: StoresResource;\n readonly storeMerchants: StoreMerchantsResource;\n readonly onetimeProducts: OnetimeProductsResource;\n readonly subscriptionProducts: SubscriptionProductsResource;\n readonly subscriptionProductGroups: SubscriptionProductGroupsResource;\n readonly orders: OrdersResource;\n readonly checkout: CheckoutResource;\n readonly graphql: GraphQLResource;\n\n constructor(config: WaffoPancakeConfig) {\n this.http = new HttpClient(config);\n\n this.auth = new AuthResource(this.http);\n this.stores = new StoresResource(this.http);\n this.storeMerchants = new StoreMerchantsResource(this.http);\n this.onetimeProducts = new OnetimeProductsResource(this.http);\n this.subscriptionProducts = new SubscriptionProductsResource(this.http);\n this.subscriptionProductGroups = new SubscriptionProductGroupsResource(this.http);\n this.orders = new OrdersResource(this.http);\n this.checkout = new CheckoutResource(this.http);\n this.graphql = new GraphQLResource(this.http);\n }\n}\n","import { createVerify } from \"node:crypto\";\n\nimport type { VerifyWebhookOptions, WebhookEvent } from \"./types.js\";\n\n/** Default tolerance: 5 minutes */\nconst DEFAULT_TOLERANCE_MS = 5 * 60 * 1000;\n\n/** Waffo Pancake test environment webhook verification public key. */\nconst TEST_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxnmRY6yMMA3lVqmAU6ZG\nb1sjL/+r/z6E+ZjkXaDAKiqOhk9rpazni0bNsGXwmftTPk9jy2wn+j6JHODD/WH/\nSCnSfvKkLIjy4Hk7BuCgB174C0ydan7J+KgXLkOwgCAxxB68t2tezldwo74ZpXgn\nF49opzMvQ9prEwIAWOE+kV9iK6gx/AckSMtHIHpUesoPDkldpmFHlB2qpf1vsFTZ\n5kD6DmGl+2GIVK01aChy2lk8pLv0yUMu18v44sLkO5M44TkGPJD9qG09wrvVG2wp\nOTVCn1n5pP8P+HRLcgzbUB3OlZVfdFurn6EZwtyL4ZD9kdkQ4EZE/9inKcp3c1h4\nxwIDAQAB\n-----END PUBLIC KEY-----`;\n\n/** Waffo Pancake production environment webhook verification public key. */\nconst PROD_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+xApdTIb4ua+DgZKQ54\niBsD82ybyhGCLRETONW4Jgbb3A8DUM1LqBk6r/CmTOCHqLalTQHNigvP3R5zkDNX\niRJz6gA4MJ/+8K0+mnEE2RISQzN+Qu65TNd6svb+INm/kMaftY4uIXr6y6kchtTJ\ndwnQhcKdAL2v7h7IFnkVelQsKxDdb2PqX8xX/qwd01iXvMcpCCaXovUwZsxH2QN5\nZKBTseJivbhUeyJCco4fdUyxOMHe2ybCVhyvim2uxAl1nkvL5L8RCWMCAV55LLo0\n9OhmLahz/DYNu13YLVP6dvIT09ZFBYU6Owj1NxdinTynlJCFS9VYwBgmftosSE1U\ndwIDAQAB\n-----END PUBLIC KEY-----`;\n\n/**\n * Parse `X-Waffo-Signature` header.\n *\n * Format: `t=<timestamp>,v1=<base64signature>`\n *\n * @returns Parsed `t` (timestamp string) and `v1` (base64 signature)\n */\nfunction parseSignatureHeader(header: string): { t: string; v1: string } {\n let t = \"\";\n let v1 = \"\";\n for (const pair of header.split(\",\")) {\n const eqIdx = pair.indexOf(\"=\");\n if (eqIdx === -1) continue;\n const key = pair.slice(0, eqIdx).trim();\n const value = pair.slice(eqIdx + 1).trim();\n if (key === \"t\") t = value;\n else if (key === \"v1\") v1 = value;\n }\n return { t, v1 };\n}\n\n/**\n * Verify RSA-SHA256 signature against a public key.\n *\n * @param signatureInput - The string to verify (`${t}.${rawBody}`)\n * @param v1 - Base64-encoded signature\n * @param publicKey - PEM public key\n * @returns Whether the signature is valid\n */\nfunction rsaVerify(signatureInput: string, v1: string, publicKey: string): boolean {\n const verifier = createVerify(\"RSA-SHA256\");\n verifier.update(signatureInput);\n return verifier.verify(publicKey, v1, \"base64\");\n}\n\n/**\n * Verify and parse an incoming Waffo Pancake webhook event.\n *\n * Uses built-in Waffo public keys (RSA-SHA256) for signature verification.\n * Test and production environments use different key pairs; both are embedded in the SDK.\n *\n * Behavior:\n * - Parses the `X-Waffo-Signature` header (`t=<timestamp>,v1=<base64sig>`)\n * - Builds signature input `${t}.${rawBody}` and verifies with RSA-SHA256\n * - When `environment` is not specified, tries prod key first, then test key\n * - Optional: checks timestamp to prevent replay attacks (default 5-minute tolerance)\n *\n * @param payload - Raw request body string (must be unparsed)\n * @param signatureHeader - Value of the `X-Waffo-Signature` header\n * @param options - Verification options\n * @returns Parsed webhook event\n * @throws Error if header is missing/malformed, signature is invalid, or timestamp is stale\n *\n * @example\n * // Express (use raw body!)\n * app.post(\"/webhooks\", express.raw({ type: \"application/json\" }), (req, res) => {\n * try {\n * const event = verifyWebhook(\n * req.body.toString(\"utf-8\"),\n * req.headers[\"x-waffo-signature\"] as string,\n * );\n * res.status(200).send(\"OK\");\n * handleEventAsync(event).catch(console.error);\n * } catch {\n * res.status(401).send(\"Invalid signature\");\n * }\n * });\n *\n * @example\n * // Next.js App Router\n * export async function POST(request: Request) {\n * const body = await request.text();\n * const sig = request.headers.get(\"x-waffo-signature\");\n * const event = verifyWebhook(body, sig);\n * // handle event ...\n * return new Response(\"OK\");\n * }\n *\n * @example\n * // Specify environment explicitly\n * const event = verifyWebhook(body, sig, { environment: \"prod\" });\n *\n * @example\n * // Disable replay protection\n * const event = verifyWebhook(body, sig, { toleranceMs: 0 });\n */\nexport function verifyWebhook<T = Record<string, unknown>>(\n payload: string,\n signatureHeader: string | undefined | null,\n options?: VerifyWebhookOptions,\n): WebhookEvent<T> {\n if (!signatureHeader) {\n throw new Error(\"Missing X-Waffo-Signature header\");\n }\n\n const { t, v1 } = parseSignatureHeader(signatureHeader);\n if (!t || !v1) {\n throw new Error(\"Malformed X-Waffo-Signature header: missing t or v1\");\n }\n\n // Replay protection\n const toleranceMs = options?.toleranceMs ?? DEFAULT_TOLERANCE_MS;\n if (toleranceMs > 0) {\n const timestampMs = Number(t);\n if (Number.isNaN(timestampMs)) {\n throw new Error(\"Invalid timestamp in X-Waffo-Signature header\");\n }\n if (Math.abs(Date.now() - timestampMs) > toleranceMs) {\n throw new Error(\"Webhook timestamp outside tolerance window (possible replay attack)\");\n }\n }\n\n // RSA-SHA256 verification\n const signatureInput = `${t}.${payload}`;\n const env = options?.environment;\n\n if (env === \"test\") {\n if (!rsaVerify(signatureInput, v1, TEST_PUBLIC_KEY)) {\n throw new Error(\"Invalid webhook signature (test key)\");\n }\n } else if (env === \"prod\") {\n if (!rsaVerify(signatureInput, v1, PROD_PUBLIC_KEY)) {\n throw new Error(\"Invalid webhook signature (prod key)\");\n }\n } else {\n // Auto-detect: try prod first, then test\n const prodValid = rsaVerify(signatureInput, v1, PROD_PUBLIC_KEY);\n if (!prodValid) {\n const testValid = rsaVerify(signatureInput, v1, TEST_PUBLIC_KEY);\n if (!testValid) {\n throw new Error(\"Invalid webhook signature (tried both prod and test keys)\");\n }\n }\n }\n\n return JSON.parse(payload) as WebhookEvent<T>;\n}\n","// ---------------------------------------------------------------------------\n// Client config\n// ---------------------------------------------------------------------------\n\nexport interface WaffoPancakeConfig {\n /** Merchant ID (X-Merchant-Id header) */\n merchantId: string;\n /** RSA private key in PEM format for request signing */\n privateKey: string;\n /** Base URL override (default: https://waffo-pancake-auth-service.vercel.app) */\n baseUrl?: string;\n /** Custom fetch implementation (default: global fetch) */\n fetch?: typeof fetch;\n}\n\n// ---------------------------------------------------------------------------\n// API response envelope\n// ---------------------------------------------------------------------------\n\n/**\n * Single error object within the `errors` array.\n *\n * @example\n * { message: \"Store slug already exists\", layer: \"store\" }\n */\nexport interface ApiError {\n /** Error message */\n message: string;\n /** Layer where the error originated */\n layer: `${ErrorLayer}`;\n}\n\n/** Successful API response envelope. */\nexport interface ApiSuccessResponse<T> {\n data: T;\n}\n\n/**\n * Error API response envelope.\n *\n * `errors` are ordered by call stack: `[0]` is the deepest layer, `[n]` is the outermost.\n */\nexport interface ApiErrorResponse {\n data: null;\n errors: ApiError[];\n}\n\n/** Union type of success and error API responses. */\nexport type ApiResponse<T> = ApiSuccessResponse<T> | ApiErrorResponse;\n\n// ---------------------------------------------------------------------------\n// Enums (runtime-accessible values)\n// ---------------------------------------------------------------------------\n\n/**\n * Environment type.\n * @see waffo-pancake-order-service/app/lib/types.ts\n */\nexport enum Environment {\n Test = \"test\",\n Prod = \"prod\",\n}\n\n/**\n * Tax category for products.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum TaxCategory {\n DigitalGoods = \"digital_goods\",\n SaaS = \"saas\",\n Software = \"software\",\n Ebook = \"ebook\",\n OnlineCourse = \"online_course\",\n Consulting = \"consulting\",\n ProfessionalService = \"professional_service\",\n}\n\n/**\n * Subscription billing period.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum BillingPeriod {\n Weekly = \"weekly\",\n Monthly = \"monthly\",\n Quarterly = \"quarterly\",\n Yearly = \"yearly\",\n}\n\n/**\n * Product version status.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum ProductVersionStatus {\n Active = \"active\",\n Inactive = \"inactive\",\n}\n\n/**\n * Store entity status.\n * @see waffo-pancake-store-service/app/lib/resources/store.ts\n */\nexport enum EntityStatus {\n Active = \"active\",\n Inactive = \"inactive\",\n Suspended = \"suspended\",\n}\n\n/**\n * Store member role.\n * @see waffo-pancake-store-service/app/lib/resources/store.ts\n */\nexport enum StoreRole {\n Owner = \"owner\",\n Admin = \"admin\",\n Member = \"member\",\n}\n\n/**\n * One-time order status.\n * @see waffo-pancake-order-service/app/lib/resources/onetime-order.ts\n */\nexport enum OnetimeOrderStatus {\n Pending = \"pending\",\n Completed = \"completed\",\n Canceled = \"canceled\",\n}\n\n/**\n * Subscription order status.\n *\n * State machine:\n * - pending -> active, canceled\n * - active -> canceling, past_due, canceled, expired\n * - canceling -> active, canceled\n * - past_due -> active, canceled\n * - canceled -> terminal\n * - expired -> terminal\n *\n * @see waffo-pancake-order-service/app/lib/resources/subscription-order.ts\n */\nexport enum SubscriptionOrderStatus {\n Pending = \"pending\",\n Active = \"active\",\n Canceling = \"canceling\",\n Canceled = \"canceled\",\n PastDue = \"past_due\",\n Expired = \"expired\",\n}\n\n/**\n * Payment status.\n * @see waffo-pancake-order-service/app/lib/resources/payment.ts\n */\nexport enum PaymentStatus {\n Pending = \"pending\",\n Succeeded = \"succeeded\",\n Failed = \"failed\",\n Canceled = \"canceled\",\n}\n\n/**\n * Refund ticket status.\n * @see waffo-pancake-order-service/app/lib/resources/refund-ticket.ts\n */\nexport enum RefundTicketStatus {\n Pending = \"pending\",\n Approved = \"approved\",\n Rejected = \"rejected\",\n Processing = \"processing\",\n Succeeded = \"succeeded\",\n Failed = \"failed\",\n}\n\n/**\n * Refund status.\n * @see waffo-pancake-order-service/app/lib/resources/refund.ts\n */\nexport enum RefundStatus {\n Succeeded = \"succeeded\",\n Failed = \"failed\",\n}\n\n/**\n * Media asset type.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum MediaType {\n Image = \"image\",\n Video = \"video\",\n}\n\n/**\n * Checkout session product type.\n * @see waffo-pancake-order-service/app/lib/types.ts\n */\nexport enum CheckoutSessionProductType {\n Onetime = \"onetime\",\n Subscription = \"subscription\",\n}\n\n/** Error layer identifier in the call stack. */\nexport enum ErrorLayer {\n Gateway = \"gateway\",\n User = \"user\",\n Store = \"store\",\n Product = \"product\",\n Order = \"order\",\n GraphQL = \"graphql\",\n Resource = \"resource\",\n Email = \"email\",\n}\n\n// ---------------------------------------------------------------------------\n// Auth\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for issuing a buyer session token.\n * @see waffo-pancake-user-service/app/lib/utils/jwt.ts IssueSessionTokenRequest\n */\nexport interface IssueSessionTokenParams {\n /** Buyer identity (email or any merchant-provided identifier string) */\n buyerIdentity: string;\n /** Store ID */\n storeId: string;\n}\n\n/**\n * Issued session token response.\n *\n * @example\n * { token: \"eyJhbGciOi...\", expiresAt: \"2026-03-10T09:00:00.000Z\" }\n */\nexport interface SessionToken {\n /** JWT token string */\n token: string;\n /** Expiration time (ISO 8601 UTC) */\n expiresAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// Store — from waffo-pancake-store-service\n// ---------------------------------------------------------------------------\n\n/**\n * Webhook configuration for test and production environments.\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface WebhookSettings {\n /** Test environment webhook URL */\n testWebhookUrl: string | null;\n /** Production environment webhook URL */\n prodWebhookUrl: string | null;\n /** Event types subscribed in test environment */\n testEvents: string[];\n /** Event types subscribed in production environment */\n prodEvents: string[];\n}\n\n/**\n * Notification settings (all default to true).\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface NotificationSettings {\n emailOrderConfirmation: boolean;\n emailSubscriptionConfirmation: boolean;\n emailSubscriptionCycled: boolean;\n emailSubscriptionCanceled: boolean;\n emailSubscriptionRevoked: boolean;\n emailSubscriptionPastDue: boolean;\n notifyNewOrders: boolean;\n notifyNewSubscriptions: boolean;\n}\n\n/**\n * Single-theme checkout page styling.\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface CheckoutThemeSettings {\n checkoutLogo: string | null;\n checkoutColorPrimary: string;\n checkoutColorBackground: string;\n checkoutColorCard: string;\n checkoutColorText: string;\n checkoutColorTextSecondary: string;\n checkoutBorderRadius: string;\n}\n\n/**\n * Checkout page configuration (light and dark themes).\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface CheckoutSettings {\n light: CheckoutThemeSettings;\n dark: CheckoutThemeSettings;\n}\n\n/**\n * Store entity.\n * @see waffo-pancake-store-service/app/lib/resources/store.ts\n */\nexport interface Store {\n id: string;\n name: string;\n status: EntityStatus;\n logo: string | null;\n supportEmail: string | null;\n website: string | null;\n slug: string | null;\n isPublic: boolean;\n prodEnabled: boolean;\n webhookSettings: WebhookSettings | null;\n notificationSettings: NotificationSettings | null;\n checkoutSettings: CheckoutSettings | null;\n deletedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Parameters for creating a store. */\nexport interface CreateStoreParams {\n /** Store name (slug is auto-generated) */\n name: string;\n}\n\n/** Parameters for updating a store. */\nexport interface UpdateStoreParams {\n /** Store ID */\n id: string;\n name?: string;\n status?: EntityStatus;\n logo?: string | null;\n supportEmail?: string | null;\n website?: string | null;\n isPublic?: boolean;\n webhookSettings?: WebhookSettings | null;\n notificationSettings?: NotificationSettings | null;\n checkoutSettings?: CheckoutSettings | null;\n}\n\n/** Parameters for deleting (soft-delete) a store. */\nexport interface DeleteStoreParams {\n /** Store ID */\n id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Store Merchant (coming soon — endpoints return 501)\n// ---------------------------------------------------------------------------\n\n/** Parameters for adding a merchant to a store. */\nexport interface AddMerchantParams {\n storeId: string;\n email: string;\n role: \"admin\" | \"member\";\n}\n\n/** Result of adding a merchant to a store. */\nexport interface AddMerchantResult {\n storeId: string;\n merchantId: string;\n email: string;\n role: string;\n status: string;\n addedAt: string;\n}\n\n/** Parameters for removing a merchant from a store. */\nexport interface RemoveMerchantParams {\n storeId: string;\n merchantId: string;\n}\n\n/** Result of removing a merchant from a store. */\nexport interface RemoveMerchantResult {\n message: string;\n removedAt: string;\n}\n\n/** Parameters for updating a merchant's role. */\nexport interface UpdateRoleParams {\n storeId: string;\n merchantId: string;\n role: \"admin\" | \"member\";\n}\n\n/** Result of updating a merchant's role. */\nexport interface UpdateRoleResult {\n storeId: string;\n merchantId: string;\n role: string;\n updatedAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// Product — shared types from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * Price for a single currency.\n *\n * Amounts are stored in the smallest currency unit (e.g. cents, yen)\n * to avoid floating-point precision issues.\n *\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n *\n * @example\n * // USD $9.99\n * { amount: 999, taxIncluded: true, taxCategory: \"saas\" }\n *\n * @example\n * // JPY ¥1000\n * { amount: 1000, taxIncluded: false, taxCategory: \"software\" }\n */\nexport interface PriceInfo {\n /** Price amount in smallest currency unit */\n amount: number;\n /** Whether the price is tax-inclusive */\n taxIncluded: boolean;\n /** Tax category */\n taxCategory: TaxCategory;\n}\n\n/**\n * Multi-currency prices (keyed by ISO 4217 currency code).\n *\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n *\n * @example\n * {\n * \"USD\": { amount: 999, taxIncluded: true, taxCategory: \"saas\" },\n * \"EUR\": { amount: 899, taxIncluded: true, taxCategory: \"saas\" }\n * }\n */\nexport type Prices = Record<string, PriceInfo>;\n\n/**\n * Media asset (image or video).\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport interface MediaItem {\n /** Media type */\n type: `${MediaType}`;\n /** Asset URL */\n url: string;\n /** Alt text */\n alt?: string;\n /** Thumbnail URL */\n thumbnail?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Onetime Product — from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * One-time product detail (public API shape).\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts OnetimeProductDetail\n */\nexport interface OnetimeProductDetail {\n id: string;\n storeId: string;\n name: string;\n description: string | null;\n prices: Prices;\n media: MediaItem[];\n successUrl: string | null;\n metadata: Record<string, unknown>;\n status: ProductVersionStatus;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Parameters for creating a one-time product.\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts CreateOnetimeProductRequestBody\n */\nexport interface CreateOnetimeProductParams {\n storeId: string;\n name: string;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parameters for updating a one-time product (creates a new version; skips if unchanged).\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts UpdateOnetimeProductContentRequestBody\n */\nexport interface UpdateOnetimeProductParams {\n id: string;\n name: string;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/** Parameters for publishing a one-time product's test version to production. */\nexport interface PublishOnetimeProductParams {\n /** Product ID */\n id: string;\n}\n\n/**\n * Parameters for updating a one-time product's status.\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts UpdateOnetimeStatusRequestBody\n */\nexport interface UpdateOnetimeStatusParams {\n id: string;\n status: ProductVersionStatus;\n}\n\n// ---------------------------------------------------------------------------\n// Subscription Product — from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * Subscription product detail (public API shape).\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts SubscriptionProductDetail\n */\nexport interface SubscriptionProductDetail {\n id: string;\n storeId: string;\n name: string;\n description: string | null;\n billingPeriod: BillingPeriod;\n prices: Prices;\n media: MediaItem[];\n successUrl: string | null;\n metadata: Record<string, unknown>;\n status: ProductVersionStatus;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Parameters for creating a subscription product.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts CreateSubscriptionProductRequestBody\n */\nexport interface CreateSubscriptionProductParams {\n storeId: string;\n name: string;\n billingPeriod: BillingPeriod;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parameters for updating a subscription product (creates a new version; skips if unchanged).\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts UpdateSubscriptionProductContentRequestBody\n */\nexport interface UpdateSubscriptionProductParams {\n id: string;\n name: string;\n billingPeriod: BillingPeriod;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/** Parameters for publishing a subscription product's test version to production. */\nexport interface PublishSubscriptionProductParams {\n /** Product ID */\n id: string;\n}\n\n/**\n * Parameters for updating a subscription product's status.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts UpdateSubscriptionStatusRequestBody\n */\nexport interface UpdateSubscriptionStatusParams {\n id: string;\n status: ProductVersionStatus;\n}\n\n// ---------------------------------------------------------------------------\n// Subscription Product Group — from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * Group rules for subscription product groups.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts\n */\nexport interface GroupRules {\n /** Whether trial period is shared across products in the group */\n sharedTrial: boolean;\n}\n\n/**\n * Subscription product group entity.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts\n */\nexport interface SubscriptionProductGroup {\n id: string;\n storeId: string;\n name: string;\n description: string | null;\n rules: GroupRules;\n productIds: string[];\n environment: Environment;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Parameters for creating a subscription product group.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts CreateGroupRequestBody\n */\nexport interface CreateSubscriptionProductGroupParams {\n storeId: string;\n name: string;\n description?: string;\n rules?: GroupRules;\n productIds?: string[];\n}\n\n/**\n * Parameters for updating a subscription product group (`productIds` is a full replacement).\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts UpdateGroupRequestBody\n */\nexport interface UpdateSubscriptionProductGroupParams {\n id: string;\n name?: string;\n description?: string;\n rules?: GroupRules;\n productIds?: string[];\n}\n\n/** Parameters for hard-deleting a subscription product group. */\nexport interface DeleteSubscriptionProductGroupParams {\n /** Group ID */\n id: string;\n}\n\n/** Parameters for publishing a test-environment group to production (upsert). */\nexport interface PublishSubscriptionProductGroupParams {\n /** Group ID */\n id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Order — from waffo-pancake-order-service\n// ---------------------------------------------------------------------------\n\n/** Parameters for canceling a subscription order. */\nexport interface CancelSubscriptionParams {\n /** Order ID */\n orderId: string;\n}\n\n/**\n * Result of canceling a subscription order.\n * @see waffo-pancake-order-service cancel-order route.ts\n */\nexport interface CancelSubscriptionResult {\n orderId: string;\n /** Status after cancellation (`\"canceled\"` or `\"canceling\"`) */\n status: `${SubscriptionOrderStatus}`;\n}\n\n/**\n * Buyer billing details for checkout.\n * @see waffo-pancake-order-service/app/lib/types.ts\n */\nexport interface BillingDetail {\n /** Country code (ISO 3166-1 alpha-2) */\n country: string;\n /** Whether this is a business purchase */\n isBusiness: boolean;\n /** Postal / ZIP code */\n postcode?: string;\n /** State / province code (required for US/CA) */\n state?: string;\n /** Business name (required when isBusiness=true) */\n businessName?: string;\n /** Tax ID (required for EU businesses) */\n taxId?: string;\n}\n\n/**\n * Parameters for creating a checkout session.\n * @see waffo-pancake-order-service/app/lib/types.ts CreateCheckoutSessionRequest\n */\nexport interface CreateCheckoutSessionParams {\n /** Store ID */\n storeId?: string;\n /** Product ID */\n productId: string;\n /** Product type */\n productType: `${CheckoutSessionProductType}`;\n /** Currency code (ISO 4217) */\n currency: string;\n /** Optional price snapshot override (reads from DB if omitted) */\n priceSnapshot?: PriceInfo;\n /** Trial toggle override (subscription only) */\n withTrial?: boolean;\n /** Pre-filled buyer email */\n buyerEmail?: string;\n /** Pre-filled billing details */\n billingDetail?: BillingDetail;\n /** Redirect URL after successful payment */\n successUrl?: string;\n /** Session expiration in seconds (default: 7 days) */\n expiresInSeconds?: number;\n /** Custom metadata */\n metadata?: Record<string, string>;\n}\n\n/** Result of creating a checkout session. */\nexport interface CheckoutSessionResult {\n /** Session ID */\n sessionId: string;\n /** URL to redirect the customer to */\n checkoutUrl: string;\n /** Session expiration time (ISO 8601 UTC) */\n expiresAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// GraphQL\n// ---------------------------------------------------------------------------\n\n/** Parameters for a GraphQL query. */\nexport interface GraphQLParams {\n /** GraphQL query string */\n query: string;\n /** Query variables */\n variables?: Record<string, unknown>;\n}\n\n/** GraphQL response envelope. */\nexport interface GraphQLResponse<T = Record<string, unknown>> {\n data: T | null;\n errors?: Array<{\n message: string;\n locations?: Array<{ line: number; column: number }>;\n path?: string[];\n }>;\n}\n\n// ---------------------------------------------------------------------------\n// Webhook\n// ---------------------------------------------------------------------------\n\n/**\n * Webhook event types.\n * @see docs/api-reference/webhooks.mdx\n */\nexport enum WebhookEventType {\n /** One-time order first payment succeeded */\n OrderCompleted = \"order.completed\",\n /** Subscription first payment succeeded (newly activated) */\n SubscriptionActivated = \"subscription.activated\",\n /** Subscription renewal payment succeeded */\n SubscriptionPaymentSucceeded = \"subscription.payment_succeeded\",\n /** Buyer initiated cancellation (expires at end of current period) */\n SubscriptionCanceling = \"subscription.canceling\",\n /** Buyer withdrew cancellation (subscription restored) */\n SubscriptionUncanceled = \"subscription.uncanceled\",\n /** Subscription product changed (upgrade/downgrade) */\n SubscriptionUpdated = \"subscription.updated\",\n /** Subscription fully terminated */\n SubscriptionCanceled = \"subscription.canceled\",\n /** Renewal payment failed (past due) */\n SubscriptionPastDue = \"subscription.past_due\",\n /** Refund succeeded */\n RefundSucceeded = \"refund.succeeded\",\n /** Refund failed */\n RefundFailed = \"refund.failed\",\n}\n\n/**\n * Common data fields in a webhook event payload.\n * @see docs/api-reference/webhooks.mdx\n */\nexport interface WebhookEventData {\n orderId: string;\n buyerEmail: string;\n currency: string;\n /** Amount in smallest currency unit */\n amount: number;\n /** Tax amount in smallest currency unit */\n taxAmount: number;\n productName: string;\n}\n\n/**\n * Webhook event payload.\n *\n * @see docs/api-reference/webhooks.mdx\n *\n * @example\n * {\n * id: \"550e8400-...\",\n * timestamp: \"2026-03-10T08:30:00.000Z\",\n * eventType: \"order.completed\",\n * eventId: \"pay_660e8400-...\",\n * storeId: \"770e8400-...\",\n * mode: \"prod\",\n * data: { orderId: \"...\", buyerEmail: \"...\", currency: \"USD\", amount: 2900, taxAmount: 290, productName: \"Pro Plan\" }\n * }\n */\nexport interface WebhookEvent<T = WebhookEventData> {\n /** Delivery record unique ID (UUID), usable for idempotent deduplication */\n id: string;\n /** Event timestamp (ISO 8601 UTC) */\n timestamp: string;\n /** Event type */\n eventType: `${WebhookEventType}` | (string & {});\n /** Business event ID (e.g. payment ID, order ID) */\n eventId: string;\n /** Store ID the event belongs to */\n storeId: string;\n /** Environment identifier */\n mode: `${Environment}`;\n /** Event data */\n data: T;\n}\n\n/** Options for {@link verifyWebhook}. */\nexport interface VerifyWebhookOptions {\n /**\n * Specify which environment's public key to use for verification.\n * When omitted, both keys are tried automatically (prod first).\n */\n environment?: `${Environment}`;\n /**\n * Timestamp tolerance window in milliseconds for replay protection.\n * Set to 0 to skip timestamp checking.\n * @default 300000 (5 minutes)\n */\n toleranceMs?: number;\n}\n"],"mappings":"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","names":["createHash","createHash","Environment","TaxCategory","BillingPeriod","ProductVersionStatus","EntityStatus","StoreRole","OnetimeOrderStatus","SubscriptionOrderStatus","PaymentStatus","RefundTicketStatus","RefundStatus","MediaType","CheckoutSessionProductType","ErrorLayer","WebhookEventType"]}
1
+ {"version":3,"sources":["../src/http-client.ts","../src/errors.ts","../src/signing.ts","../src/resources/auth.ts","../src/resources/checkout.ts","../src/resources/graphql.ts","../src/resources/onetime-products.ts","../src/resources/orders.ts","../src/resources/store-merchants.ts","../src/resources/stores.ts","../src/resources/subscription-product-groups.ts","../src/resources/subscription-products.ts","../src/client.ts","../src/webhooks.ts","../src/types.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\n\nimport { WaffoPancakeError } from \"./errors.js\";\nimport { normalizePrivateKey, signRequest } from \"./signing.js\";\n\nimport type { ApiResponse, WaffoPancakeConfig } from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://waffo-pancake-auth-service.vercel.app\";\n\n/**\n * Internal HTTP client that auto-signs requests and attaches idempotency keys.\n *\n * Not exported publicly — used by resource classes via {@link WaffoPancake}.\n */\nexport class HttpClient {\n private readonly merchantId: string;\n private readonly privateKey: string;\n private readonly baseUrl: string;\n private readonly _fetch: typeof fetch;\n\n constructor(config: WaffoPancakeConfig) {\n this.merchantId = config.merchantId;\n this.privateKey = normalizePrivateKey(config.privateKey);\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this._fetch = config.fetch ?? fetch;\n }\n\n /**\n * Send a signed POST request and return the parsed `data` field.\n *\n * Behavior:\n * - Generates a deterministic `X-Idempotency-Key` from `merchantId + path + body` (same request produces same key)\n * - Auto-builds RSA-SHA256 signature (`X-Merchant-Id` / `X-Timestamp` / `X-Signature`)\n * - Unwraps the response envelope: returns `data` on success, throws `WaffoPancakeError` on failure\n *\n * @param path - API path (e.g. `/v1/actions/store/create-store`)\n * @param body - Request body object\n * @returns Parsed `data` field from the response\n * @throws {WaffoPancakeError} When the API returns errors\n */\n async post<T>(path: string, body: object): Promise<T> {\n const bodyStr = JSON.stringify(body);\n const timestamp = Math.floor(Date.now() / 1000).toString();\n const signature = signRequest(\"POST\", path, timestamp, bodyStr, this.privateKey);\n\n const response = await this._fetch(`${this.baseUrl}${path}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Merchant-Id\": this.merchantId,\n \"X-Timestamp\": timestamp,\n \"X-Signature\": signature,\n \"X-Idempotency-Key\": createHash(\"sha256\")\n .update(`${this.merchantId}:${path}:${bodyStr}`)\n .digest(\"hex\"),\n },\n body: bodyStr,\n });\n\n const result = (await response.json()) as ApiResponse<T>;\n\n if (\"errors\" in result && result.errors) {\n throw new WaffoPancakeError(response.status, result.errors);\n }\n\n return result.data as T;\n }\n}\n","import type { ApiError } from \"./types.js\";\n\n/**\n * Error thrown when the API returns a non-success response.\n *\n * @example\n * try {\n * await client.stores.create({ name: \"My Store\" });\n * } catch (err) {\n * if (err instanceof WaffoPancakeError) {\n * console.log(err.status); // 400\n * console.log(err.errors[0]); // { message: \"...\", layer: \"store\" }\n * }\n * }\n */\nexport class WaffoPancakeError extends Error {\n readonly status: number;\n readonly errors: ApiError[];\n\n constructor(status: number, errors: ApiError[]) {\n const rootCause = errors[0]?.message ?? \"Unknown error\";\n super(rootCause);\n this.name = \"WaffoPancakeError\";\n this.status = status;\n this.errors = errors;\n }\n}\n","import { createHash, createPrivateKey, createSign } from \"node:crypto\";\n\nconst PKCS8_HEADER = \"-----BEGIN PRIVATE KEY-----\";\nconst PKCS8_FOOTER = \"-----END PRIVATE KEY-----\";\nconst PKCS1_HEADER = \"-----BEGIN RSA PRIVATE KEY-----\";\nconst PKCS1_FOOTER = \"-----END RSA PRIVATE KEY-----\";\n\n/**\n * Normalize a PEM private key string into a valid PEM format.\n *\n * Handles common issues:\n * - Literal `\\n` from environment variables (e.g. `PRIVATE_KEY=\"-----BEGIN...\\\\n...\"`)\n * - Windows-style `\\r\\n` line endings\n * - Leading/trailing whitespace and blank lines\n * - Missing PEM header/footer (raw base64 input, assumed PKCS#8)\n * - Base64 content on a single line (re-wrapped to 64-char lines)\n * - PKCS#1 (`BEGIN RSA PRIVATE KEY`) accepted as-is\n *\n * @param raw - Private key string in any of the above formats\n * @returns A well-formed PEM string\n * @throws {Error} If the input is empty or contains no base64 content\n *\n * @example\n * // Env var with literal \\n\n * normalizePrivateKey(\"-----BEGIN PRIVATE KEY-----\\\\nMIIE...\\\\n-----END PRIVATE KEY-----\")\n *\n * @example\n * // Raw base64 without PEM wrapper\n * normalizePrivateKey(\"MIIEvQIBADANBgkqhki...\")\n */\nexport function normalizePrivateKey(raw: string): string {\n if (!raw || !raw.trim()) {\n throw new Error(\n \"Private key is empty. Provide an RSA private key in PEM format.\",\n );\n }\n\n // 1. Replace literal \\n / \\r\\n with real newlines\n let pem = raw.replace(/\\\\n/g, \"\\n\").replace(/\\r\\n/g, \"\\n\");\n\n // 2. Trim leading/trailing whitespace\n pem = pem.trim();\n\n // 3. Detect whether PEM headers are present\n const hasPkcs8Header = pem.includes(PKCS8_HEADER);\n const hasPkcs1Header = pem.includes(PKCS1_HEADER);\n const hasHeader = hasPkcs8Header || hasPkcs1Header;\n\n if (hasHeader) {\n // Strip headers/footers, extract pure base64\n const base64 = pem\n .replace(/-----BEGIN (?:RSA )?PRIVATE KEY-----/g, \"\")\n .replace(/-----END (?:RSA )?PRIVATE KEY-----/g, \"\")\n .replace(/\\s+/g, \"\");\n\n if (!base64) {\n throw new Error(\n \"Private key contains PEM headers but no key data. Check the key content.\",\n );\n }\n\n // Re-wrap to 64-char lines with the original header type\n const header = hasPkcs1Header ? PKCS1_HEADER : PKCS8_HEADER;\n const footer = hasPkcs1Header ? PKCS1_FOOTER : PKCS8_FOOTER;\n const wrapped = base64.match(/.{1,64}/g)!.join(\"\\n\");\n pem = `${header}\\n${wrapped}\\n${footer}`;\n } else {\n // No PEM header — treat as raw base64, wrap with PKCS#8 headers\n const base64 = pem.replace(/\\s+/g, \"\");\n\n if (!/^[A-Za-z0-9+/]+=*$/.test(base64)) {\n throw new Error(\n \"Private key is not valid PEM or base64. Expected an RSA private key in PEM format or raw base64.\",\n );\n }\n\n const wrapped = base64.match(/.{1,64}/g)!.join(\"\\n\");\n pem = `${PKCS8_HEADER}\\n${wrapped}\\n${PKCS8_FOOTER}`;\n }\n\n // 4. Validate the key is actually parseable by Node.js crypto\n try {\n createPrivateKey(pem);\n } catch {\n throw new Error(\n \"Private key could not be parsed. Ensure it is a valid RSA private key in PKCS#8 or PKCS#1 (PEM) format.\",\n );\n }\n\n return pem;\n}\n\n/**\n * Build canonical request string and sign with RSA-SHA256.\n *\n * Canonical request format:\n * METHOD\\nPATH\\nTIMESTAMP\\nSHA256(BODY)\n *\n * @param method - HTTP method (e.g. \"POST\")\n * @param path - Request path (e.g. \"/v1/actions/store/create-store\")\n * @param timestamp - Unix epoch seconds string\n * @param body - Serialized JSON body\n * @param privateKey - RSA private key in PEM format\n * @returns Base64-encoded RSA-SHA256 signature\n */\nexport function signRequest(\n method: string,\n path: string,\n timestamp: string,\n body: string,\n privateKey: string,\n): string {\n const bodyHash = createHash(\"sha256\").update(body).digest(\"base64\");\n const canonicalRequest = `${method}\\n${path}\\n${timestamp}\\n${bodyHash}`;\n\n const sign = createSign(\"sha256\");\n sign.update(canonicalRequest);\n return sign.sign(privateKey, \"base64\");\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { IssueSessionTokenParams, SessionToken } from \"../types.js\";\n\n/** Authentication resource — issue session tokens for buyers. */\nexport class AuthResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Issue a session token for a buyer.\n *\n * @param params - Token issuance parameters\n * @returns Issued session token with expiration\n *\n * @example\n * const { token, expiresAt } = await client.auth.issueSessionToken({\n * storeId: \"store_xxx\",\n * buyerIdentity: \"customer@example.com\",\n * });\n */\n async issueSessionToken(params: IssueSessionTokenParams): Promise<SessionToken> {\n return this.http.post<SessionToken>(\"/v1/actions/auth/issue-session-token\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { CheckoutSessionResult, CreateCheckoutSessionParams } from \"../types.js\";\n\n/** Checkout resource — create checkout sessions for payments. */\nexport class CheckoutResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a checkout session. Returns a URL to redirect the customer to.\n *\n * @param params - Checkout session parameters\n * @returns Session ID, checkout URL, and expiration\n *\n * @example\n * const session = await client.checkout.createSession({\n * storeId: \"store_xxx\",\n * productId: \"prod_xxx\",\n * productType: \"onetime\",\n * currency: \"USD\",\n * buyerEmail: \"customer@example.com\",\n * });\n * // Redirect to session.checkoutUrl\n */\n async createSession(params: CreateCheckoutSessionParams): Promise<CheckoutSessionResult> {\n return this.http.post<CheckoutSessionResult>(\"/v1/actions/checkout/create-session\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { GraphQLParams, GraphQLResponse } from \"../types.js\";\n\n/** GraphQL query resource (Query only, no Mutations). */\nexport class GraphQLResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Execute a GraphQL query (Query only, no Mutations).\n *\n * @param params - GraphQL query and optional variables\n * @returns GraphQL response with data and optional errors\n *\n * @example\n * const result = await client.graphql.query<{ stores: Array<{ id: string; name: string }> }>({\n * query: `query { stores { id name status } }`,\n * });\n * console.log(result.data?.stores);\n *\n * @example\n * const result = await client.graphql.query({\n * query: `query ($id: ID!) { onetimeProduct(id: $id) { id name prices } }`,\n * variables: { id: \"prod_xxx\" },\n * });\n */\n async query<T = Record<string, unknown>>(params: GraphQLParams): Promise<GraphQLResponse<T>> {\n return this.http.post<GraphQLResponse<T>>(\"/v1/graphql\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateOnetimeProductParams,\n OnetimeProductDetail,\n PublishOnetimeProductParams,\n UpdateOnetimeProductParams,\n UpdateOnetimeStatusParams,\n} from \"../types.js\";\n\n/** One-time product management resource. */\nexport class OnetimeProductsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a one-time product with multi-currency pricing.\n *\n * @param params - Product creation parameters\n * @returns Created product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.create({\n * storeId: \"store_xxx\",\n * name: \"E-Book\",\n * prices: { USD: { amount: 2900, taxIncluded: false, taxCategory: \"digital_goods\" } },\n * });\n */\n async create(params: CreateOnetimeProductParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/create-product\", params);\n }\n\n /**\n * Update a one-time product. Creates a new version; skips if unchanged.\n *\n * @param params - Product update parameters (all content fields required)\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.update({\n * id: \"prod_xxx\",\n * name: \"E-Book v2\",\n * prices: { USD: { amount: 3900, taxIncluded: false, taxCategory: \"digital_goods\" } },\n * });\n */\n async update(params: UpdateOnetimeProductParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/update-product\", params);\n }\n\n /**\n * Publish a one-time product's test version to production.\n *\n * @param params - Product to publish\n * @returns Published product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.publish({ id: \"prod_xxx\" });\n */\n async publish(params: PublishOnetimeProductParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/publish-product\", params);\n }\n\n /**\n * Update a one-time product's status (active/inactive).\n *\n * @param params - Status update parameters\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.onetimeProducts.updateStatus({\n * id: \"prod_xxx\",\n * status: ProductVersionStatus.Inactive,\n * });\n */\n async updateStatus(params: UpdateOnetimeStatusParams): Promise<{ product: OnetimeProductDetail }> {\n return this.http.post(\"/v1/actions/onetime-product/update-status\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type { CancelSubscriptionParams, CancelSubscriptionResult } from \"../types.js\";\n\n/** Order management resource. */\nexport class OrdersResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Cancel a subscription order.\n *\n * - pending -> canceled (immediate)\n * - active/trialing -> canceling (PSP cancel, webhook updates later)\n *\n * @param params - Order to cancel\n * @returns Order ID and resulting status\n *\n * @example\n * const { orderId, status } = await client.orders.cancelSubscription({\n * orderId: \"order_xxx\",\n * });\n * // status: \"canceled\" or \"canceling\"\n */\n async cancelSubscription(params: CancelSubscriptionParams): Promise<CancelSubscriptionResult> {\n return this.http.post<CancelSubscriptionResult>(\"/v1/actions/subscription-order/cancel-order\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n AddMerchantParams,\n AddMerchantResult,\n RemoveMerchantParams,\n RemoveMerchantResult,\n UpdateRoleParams,\n UpdateRoleResult,\n} from \"../types.js\";\n\n/** Store merchant management resource (coming soon — endpoints return 501). */\nexport class StoreMerchantsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Add a merchant to a store.\n *\n * @param params - Merchant addition parameters\n * @returns Added merchant details\n *\n * @example\n * const result = await client.storeMerchants.add({\n * storeId: \"store_xxx\",\n * email: \"member@example.com\",\n * role: \"admin\",\n * });\n */\n async add(params: AddMerchantParams): Promise<AddMerchantResult> {\n return this.http.post(\"/v1/actions/store-merchant/add-merchant\", params);\n }\n\n /**\n * Remove a merchant from a store.\n *\n * @param params - Merchant removal parameters\n * @returns Removal confirmation\n *\n * @example\n * const result = await client.storeMerchants.remove({\n * storeId: \"store_xxx\",\n * merchantId: \"merchant_xxx\",\n * });\n */\n async remove(params: RemoveMerchantParams): Promise<RemoveMerchantResult> {\n return this.http.post(\"/v1/actions/store-merchant/remove-merchant\", params);\n }\n\n /**\n * Update a merchant's role in a store.\n *\n * @param params - Role update parameters\n * @returns Updated role details\n *\n * @example\n * const result = await client.storeMerchants.updateRole({\n * storeId: \"store_xxx\",\n * merchantId: \"merchant_xxx\",\n * role: \"member\",\n * });\n */\n async updateRole(params: UpdateRoleParams): Promise<UpdateRoleResult> {\n return this.http.post(\"/v1/actions/store-merchant/update-role\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateStoreParams,\n DeleteStoreParams,\n Store,\n UpdateStoreParams,\n} from \"../types.js\";\n\n/** Store management resource — create, update, and delete stores. */\nexport class StoresResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a new store. Slug is auto-generated from the name.\n *\n * @param params - Store creation parameters\n * @returns Created store entity\n *\n * @example\n * const { store } = await client.stores.create({ name: \"My Store\" });\n */\n async create(params: CreateStoreParams): Promise<{ store: Store }> {\n return this.http.post(\"/v1/actions/store/create-store\", params);\n }\n\n /**\n * Update an existing store's settings.\n *\n * @param params - Fields to update (only provided fields are changed)\n * @returns Updated store entity\n *\n * @example\n * const { store } = await client.stores.update({\n * id: \"store_xxx\",\n * name: \"Updated Name\",\n * supportEmail: \"help@example.com\",\n * });\n */\n async update(params: UpdateStoreParams): Promise<{ store: Store }> {\n return this.http.post(\"/v1/actions/store/update-store\", params);\n }\n\n /**\n * Soft-delete a store. Only the owner can delete.\n *\n * @param params - Store to delete\n * @returns Deleted store entity (with `deletedAt` set)\n *\n * @example\n * const { store } = await client.stores.delete({ id: \"store_xxx\" });\n */\n async delete(params: DeleteStoreParams): Promise<{ store: Store }> {\n return this.http.post(\"/v1/actions/store/delete-store\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateSubscriptionProductGroupParams,\n DeleteSubscriptionProductGroupParams,\n PublishSubscriptionProductGroupParams,\n SubscriptionProductGroup,\n UpdateSubscriptionProductGroupParams,\n} from \"../types.js\";\n\n/** Subscription product group management resource (shared trial, plan switching). */\nexport class SubscriptionProductGroupsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a subscription product group for shared-trial or plan switching.\n *\n * @param params - Group creation parameters\n * @returns Created group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.create({\n * storeId: \"store_xxx\",\n * name: \"Pro Plans\",\n * rules: { sharedTrial: true },\n * productIds: [\"prod_aaa\", \"prod_bbb\"],\n * });\n */\n async create(params: CreateSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/create-group\", params);\n }\n\n /**\n * Update a subscription product group. `productIds` is a full replacement.\n *\n * @param params - Group update parameters\n * @returns Updated group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.update({\n * id: \"group_xxx\",\n * productIds: [\"prod_aaa\", \"prod_bbb\", \"prod_ccc\"],\n * });\n */\n async update(params: UpdateSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/update-group\", params);\n }\n\n /**\n * Hard-delete a subscription product group.\n *\n * @param params - Group to delete\n * @returns Deleted group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.delete({ id: \"group_xxx\" });\n */\n async delete(params: DeleteSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/delete-group\", params);\n }\n\n /**\n * Publish a test-environment group to production (upsert).\n *\n * @param params - Group to publish\n * @returns Published group entity\n *\n * @example\n * const { group } = await client.subscriptionProductGroups.publish({ id: \"group_xxx\" });\n */\n async publish(params: PublishSubscriptionProductGroupParams): Promise<{ group: SubscriptionProductGroup }> {\n return this.http.post(\"/v1/actions/subscription-product-group/publish-group\", params);\n }\n}\n","import type { HttpClient } from \"../http-client.js\";\nimport type {\n CreateSubscriptionProductParams,\n PublishSubscriptionProductParams,\n SubscriptionProductDetail,\n UpdateSubscriptionProductParams,\n UpdateSubscriptionStatusParams,\n} from \"../types.js\";\n\n/** Subscription product management resource. */\nexport class SubscriptionProductsResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a subscription product with billing period and multi-currency pricing.\n *\n * @param params - Product creation parameters\n * @returns Created product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.create({\n * storeId: \"store_xxx\",\n * name: \"Pro Plan\",\n * billingPeriod: \"monthly\",\n * prices: { USD: { amount: 999, taxIncluded: false, taxCategory: \"saas\" } },\n * });\n */\n async create(params: CreateSubscriptionProductParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/create-product\", params);\n }\n\n /**\n * Update a subscription product. Creates a new version; skips if unchanged.\n *\n * @param params - Product update parameters (all content fields required)\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.update({\n * id: \"prod_xxx\",\n * name: \"Pro Plan v2\",\n * billingPeriod: \"monthly\",\n * prices: { USD: { amount: 1499, taxIncluded: false, taxCategory: \"saas\" } },\n * });\n */\n async update(params: UpdateSubscriptionProductParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/update-product\", params);\n }\n\n /**\n * Publish a subscription product's test version to production.\n *\n * @param params - Product to publish\n * @returns Published product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.publish({ id: \"prod_xxx\" });\n */\n async publish(params: PublishSubscriptionProductParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/publish-product\", params);\n }\n\n /**\n * Update a subscription product's status (active/inactive).\n *\n * @param params - Status update parameters\n * @returns Updated product detail\n *\n * @example\n * const { product } = await client.subscriptionProducts.updateStatus({\n * id: \"prod_xxx\",\n * status: ProductVersionStatus.Active,\n * });\n */\n async updateStatus(params: UpdateSubscriptionStatusParams): Promise<{ product: SubscriptionProductDetail }> {\n return this.http.post(\"/v1/actions/subscription-product/update-status\", params);\n }\n}\n","import { HttpClient } from \"./http-client.js\";\nimport { AuthResource } from \"./resources/auth.js\";\nimport { CheckoutResource } from \"./resources/checkout.js\";\nimport { GraphQLResource } from \"./resources/graphql.js\";\nimport { OnetimeProductsResource } from \"./resources/onetime-products.js\";\nimport { OrdersResource } from \"./resources/orders.js\";\nimport { StoreMerchantsResource } from \"./resources/store-merchants.js\";\nimport { StoresResource } from \"./resources/stores.js\";\nimport { SubscriptionProductGroupsResource } from \"./resources/subscription-product-groups.js\";\nimport { SubscriptionProductsResource } from \"./resources/subscription-products.js\";\n\nimport type { WaffoPancakeConfig } from \"./types.js\";\n\n/**\n * Waffo Pancake TypeScript SDK client.\n *\n * Uses Merchant API Key (RSA-SHA256) authentication. All requests are\n * automatically signed — no manual header construction needed.\n *\n * @example\n * import { WaffoPancake } from \"@waffo/pancake-ts\";\n *\n * const client = new WaffoPancake({\n * merchantId: process.env.WAFFO_MERCHANT_ID!,\n * privateKey: process.env.WAFFO_PRIVATE_KEY!,\n * });\n *\n * // Create a store\n * const { store } = await client.stores.create({ name: \"My Store\" });\n *\n * // Create a product\n * const { product } = await client.onetimeProducts.create({\n * storeId: store.id,\n * name: \"E-Book\",\n * prices: { USD: { amount: 2900, taxIncluded: false, taxCategory: \"digital_goods\" } },\n * });\n *\n * // Create a checkout session\n * const session = await client.checkout.createSession({\n * storeId: store.id,\n * productId: product.id,\n * productType: \"onetime\",\n * currency: \"USD\",\n * });\n * // => redirect customer to session.checkoutUrl\n *\n * // Query data via GraphQL\n * const result = await client.graphql.query({\n * query: `query { stores { id name status } }`,\n * });\n */\nexport class WaffoPancake {\n private readonly http: HttpClient;\n\n readonly auth: AuthResource;\n readonly stores: StoresResource;\n readonly storeMerchants: StoreMerchantsResource;\n readonly onetimeProducts: OnetimeProductsResource;\n readonly subscriptionProducts: SubscriptionProductsResource;\n readonly subscriptionProductGroups: SubscriptionProductGroupsResource;\n readonly orders: OrdersResource;\n readonly checkout: CheckoutResource;\n readonly graphql: GraphQLResource;\n\n constructor(config: WaffoPancakeConfig) {\n this.http = new HttpClient(config);\n\n this.auth = new AuthResource(this.http);\n this.stores = new StoresResource(this.http);\n this.storeMerchants = new StoreMerchantsResource(this.http);\n this.onetimeProducts = new OnetimeProductsResource(this.http);\n this.subscriptionProducts = new SubscriptionProductsResource(this.http);\n this.subscriptionProductGroups = new SubscriptionProductGroupsResource(this.http);\n this.orders = new OrdersResource(this.http);\n this.checkout = new CheckoutResource(this.http);\n this.graphql = new GraphQLResource(this.http);\n }\n}\n","import { createVerify } from \"node:crypto\";\n\nimport type { VerifyWebhookOptions, WebhookEvent } from \"./types.js\";\n\n/** Default tolerance: 5 minutes */\nconst DEFAULT_TOLERANCE_MS = 5 * 60 * 1000;\n\n/** Waffo Pancake test environment webhook verification public key. */\nconst TEST_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxnmRY6yMMA3lVqmAU6ZG\nb1sjL/+r/z6E+ZjkXaDAKiqOhk9rpazni0bNsGXwmftTPk9jy2wn+j6JHODD/WH/\nSCnSfvKkLIjy4Hk7BuCgB174C0ydan7J+KgXLkOwgCAxxB68t2tezldwo74ZpXgn\nF49opzMvQ9prEwIAWOE+kV9iK6gx/AckSMtHIHpUesoPDkldpmFHlB2qpf1vsFTZ\n5kD6DmGl+2GIVK01aChy2lk8pLv0yUMu18v44sLkO5M44TkGPJD9qG09wrvVG2wp\nOTVCn1n5pP8P+HRLcgzbUB3OlZVfdFurn6EZwtyL4ZD9kdkQ4EZE/9inKcp3c1h4\nxwIDAQAB\n-----END PUBLIC KEY-----`;\n\n/** Waffo Pancake production environment webhook verification public key. */\nconst PROD_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+xApdTIb4ua+DgZKQ54\niBsD82ybyhGCLRETONW4Jgbb3A8DUM1LqBk6r/CmTOCHqLalTQHNigvP3R5zkDNX\niRJz6gA4MJ/+8K0+mnEE2RISQzN+Qu65TNd6svb+INm/kMaftY4uIXr6y6kchtTJ\ndwnQhcKdAL2v7h7IFnkVelQsKxDdb2PqX8xX/qwd01iXvMcpCCaXovUwZsxH2QN5\nZKBTseJivbhUeyJCco4fdUyxOMHe2ybCVhyvim2uxAl1nkvL5L8RCWMCAV55LLo0\n9OhmLahz/DYNu13YLVP6dvIT09ZFBYU6Owj1NxdinTynlJCFS9VYwBgmftosSE1U\ndwIDAQAB\n-----END PUBLIC KEY-----`;\n\n/**\n * Parse `X-Waffo-Signature` header.\n *\n * Format: `t=<timestamp>,v1=<base64signature>`\n *\n * @returns Parsed `t` (timestamp string) and `v1` (base64 signature)\n */\nfunction parseSignatureHeader(header: string): { t: string; v1: string } {\n let t = \"\";\n let v1 = \"\";\n for (const pair of header.split(\",\")) {\n const eqIdx = pair.indexOf(\"=\");\n if (eqIdx === -1) continue;\n const key = pair.slice(0, eqIdx).trim();\n const value = pair.slice(eqIdx + 1).trim();\n if (key === \"t\") t = value;\n else if (key === \"v1\") v1 = value;\n }\n return { t, v1 };\n}\n\n/**\n * Verify RSA-SHA256 signature against a public key.\n *\n * @param signatureInput - The string to verify (`${t}.${rawBody}`)\n * @param v1 - Base64-encoded signature\n * @param publicKey - PEM public key\n * @returns Whether the signature is valid\n */\nfunction rsaVerify(signatureInput: string, v1: string, publicKey: string): boolean {\n const verifier = createVerify(\"RSA-SHA256\");\n verifier.update(signatureInput);\n return verifier.verify(publicKey, v1, \"base64\");\n}\n\n/**\n * Verify and parse an incoming Waffo Pancake webhook event.\n *\n * Uses built-in Waffo public keys (RSA-SHA256) for signature verification.\n * Test and production environments use different key pairs; both are embedded in the SDK.\n *\n * Behavior:\n * - Parses the `X-Waffo-Signature` header (`t=<timestamp>,v1=<base64sig>`)\n * - Builds signature input `${t}.${rawBody}` and verifies with RSA-SHA256\n * - When `environment` is not specified, tries prod key first, then test key\n * - Optional: checks timestamp to prevent replay attacks (default 5-minute tolerance)\n *\n * @param payload - Raw request body string (must be unparsed)\n * @param signatureHeader - Value of the `X-Waffo-Signature` header\n * @param options - Verification options\n * @returns Parsed webhook event\n * @throws Error if header is missing/malformed, signature is invalid, or timestamp is stale\n *\n * @example\n * // Express (use raw body!)\n * app.post(\"/webhooks\", express.raw({ type: \"application/json\" }), (req, res) => {\n * try {\n * const event = verifyWebhook(\n * req.body.toString(\"utf-8\"),\n * req.headers[\"x-waffo-signature\"] as string,\n * );\n * res.status(200).send(\"OK\");\n * handleEventAsync(event).catch(console.error);\n * } catch {\n * res.status(401).send(\"Invalid signature\");\n * }\n * });\n *\n * @example\n * // Next.js App Router\n * export async function POST(request: Request) {\n * const body = await request.text();\n * const sig = request.headers.get(\"x-waffo-signature\");\n * const event = verifyWebhook(body, sig);\n * // handle event ...\n * return new Response(\"OK\");\n * }\n *\n * @example\n * // Specify environment explicitly\n * const event = verifyWebhook(body, sig, { environment: \"prod\" });\n *\n * @example\n * // Disable replay protection\n * const event = verifyWebhook(body, sig, { toleranceMs: 0 });\n */\nexport function verifyWebhook<T = Record<string, unknown>>(\n payload: string,\n signatureHeader: string | undefined | null,\n options?: VerifyWebhookOptions,\n): WebhookEvent<T> {\n if (!signatureHeader) {\n throw new Error(\"Missing X-Waffo-Signature header\");\n }\n\n const { t, v1 } = parseSignatureHeader(signatureHeader);\n if (!t || !v1) {\n throw new Error(\"Malformed X-Waffo-Signature header: missing t or v1\");\n }\n\n // Replay protection\n const toleranceMs = options?.toleranceMs ?? DEFAULT_TOLERANCE_MS;\n if (toleranceMs > 0) {\n const timestampMs = Number(t);\n if (Number.isNaN(timestampMs)) {\n throw new Error(\"Invalid timestamp in X-Waffo-Signature header\");\n }\n if (Math.abs(Date.now() - timestampMs) > toleranceMs) {\n throw new Error(\"Webhook timestamp outside tolerance window (possible replay attack)\");\n }\n }\n\n // RSA-SHA256 verification\n const signatureInput = `${t}.${payload}`;\n const env = options?.environment;\n\n if (env === \"test\") {\n if (!rsaVerify(signatureInput, v1, TEST_PUBLIC_KEY)) {\n throw new Error(\"Invalid webhook signature (test key)\");\n }\n } else if (env === \"prod\") {\n if (!rsaVerify(signatureInput, v1, PROD_PUBLIC_KEY)) {\n throw new Error(\"Invalid webhook signature (prod key)\");\n }\n } else {\n // Auto-detect: try prod first, then test\n const prodValid = rsaVerify(signatureInput, v1, PROD_PUBLIC_KEY);\n if (!prodValid) {\n const testValid = rsaVerify(signatureInput, v1, TEST_PUBLIC_KEY);\n if (!testValid) {\n throw new Error(\"Invalid webhook signature (tried both prod and test keys)\");\n }\n }\n }\n\n return JSON.parse(payload) as WebhookEvent<T>;\n}\n","// ---------------------------------------------------------------------------\n// Client config\n// ---------------------------------------------------------------------------\n\nexport interface WaffoPancakeConfig {\n /** Merchant ID (X-Merchant-Id header) */\n merchantId: string;\n /** RSA private key in PEM format for request signing */\n privateKey: string;\n /** Base URL override (default: https://waffo-pancake-auth-service.vercel.app) */\n baseUrl?: string;\n /** Custom fetch implementation (default: global fetch) */\n fetch?: typeof fetch;\n}\n\n// ---------------------------------------------------------------------------\n// API response envelope\n// ---------------------------------------------------------------------------\n\n/**\n * Single error object within the `errors` array.\n *\n * @example\n * { message: \"Store slug already exists\", layer: \"store\" }\n */\nexport interface ApiError {\n /** Error message */\n message: string;\n /** Layer where the error originated */\n layer: `${ErrorLayer}`;\n}\n\n/** Successful API response envelope. */\nexport interface ApiSuccessResponse<T> {\n data: T;\n}\n\n/**\n * Error API response envelope.\n *\n * `errors` are ordered by call stack: `[0]` is the deepest layer, `[n]` is the outermost.\n */\nexport interface ApiErrorResponse {\n data: null;\n errors: ApiError[];\n}\n\n/** Union type of success and error API responses. */\nexport type ApiResponse<T> = ApiSuccessResponse<T> | ApiErrorResponse;\n\n// ---------------------------------------------------------------------------\n// Enums (runtime-accessible values)\n// ---------------------------------------------------------------------------\n\n/**\n * Environment type.\n * @see waffo-pancake-order-service/app/lib/types.ts\n */\nexport enum Environment {\n Test = \"test\",\n Prod = \"prod\",\n}\n\n/**\n * Tax category for products.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum TaxCategory {\n DigitalGoods = \"digital_goods\",\n SaaS = \"saas\",\n Software = \"software\",\n Ebook = \"ebook\",\n OnlineCourse = \"online_course\",\n Consulting = \"consulting\",\n ProfessionalService = \"professional_service\",\n}\n\n/**\n * Subscription billing period.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum BillingPeriod {\n Weekly = \"weekly\",\n Monthly = \"monthly\",\n Quarterly = \"quarterly\",\n Yearly = \"yearly\",\n}\n\n/**\n * Product version status.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum ProductVersionStatus {\n Active = \"active\",\n Inactive = \"inactive\",\n}\n\n/**\n * Store entity status.\n * @see waffo-pancake-store-service/app/lib/resources/store.ts\n */\nexport enum EntityStatus {\n Active = \"active\",\n Inactive = \"inactive\",\n Suspended = \"suspended\",\n}\n\n/**\n * Store member role.\n * @see waffo-pancake-store-service/app/lib/resources/store.ts\n */\nexport enum StoreRole {\n Owner = \"owner\",\n Admin = \"admin\",\n Member = \"member\",\n}\n\n/**\n * One-time order status.\n * @see waffo-pancake-order-service/app/lib/resources/onetime-order.ts\n */\nexport enum OnetimeOrderStatus {\n Pending = \"pending\",\n Completed = \"completed\",\n Canceled = \"canceled\",\n}\n\n/**\n * Subscription order status.\n *\n * State machine:\n * - pending -> active, canceled\n * - active -> canceling, past_due, canceled, expired\n * - canceling -> active, canceled\n * - past_due -> active, canceled\n * - canceled -> terminal\n * - expired -> terminal\n *\n * @see waffo-pancake-order-service/app/lib/resources/subscription-order.ts\n */\nexport enum SubscriptionOrderStatus {\n Pending = \"pending\",\n Active = \"active\",\n Canceling = \"canceling\",\n Canceled = \"canceled\",\n PastDue = \"past_due\",\n Expired = \"expired\",\n}\n\n/**\n * Payment status.\n * @see waffo-pancake-order-service/app/lib/resources/payment.ts\n */\nexport enum PaymentStatus {\n Pending = \"pending\",\n Succeeded = \"succeeded\",\n Failed = \"failed\",\n Canceled = \"canceled\",\n}\n\n/**\n * Refund ticket status.\n * @see waffo-pancake-order-service/app/lib/resources/refund-ticket.ts\n */\nexport enum RefundTicketStatus {\n Pending = \"pending\",\n Approved = \"approved\",\n Rejected = \"rejected\",\n Processing = \"processing\",\n Succeeded = \"succeeded\",\n Failed = \"failed\",\n}\n\n/**\n * Refund status.\n * @see waffo-pancake-order-service/app/lib/resources/refund.ts\n */\nexport enum RefundStatus {\n Succeeded = \"succeeded\",\n Failed = \"failed\",\n}\n\n/**\n * Media asset type.\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport enum MediaType {\n Image = \"image\",\n Video = \"video\",\n}\n\n/**\n * Checkout session product type.\n * @see waffo-pancake-order-service/app/lib/types.ts\n */\nexport enum CheckoutSessionProductType {\n Onetime = \"onetime\",\n Subscription = \"subscription\",\n}\n\n/** Error layer identifier in the call stack. */\nexport enum ErrorLayer {\n Gateway = \"gateway\",\n User = \"user\",\n Store = \"store\",\n Product = \"product\",\n Order = \"order\",\n GraphQL = \"graphql\",\n Resource = \"resource\",\n Email = \"email\",\n}\n\n// ---------------------------------------------------------------------------\n// Auth\n// ---------------------------------------------------------------------------\n\n/**\n * Parameters for issuing a buyer session token.\n * @see waffo-pancake-user-service/app/lib/utils/jwt.ts IssueSessionTokenRequest\n */\nexport interface IssueSessionTokenParams {\n /** Buyer identity (email or any merchant-provided identifier string) */\n buyerIdentity: string;\n /** Store ID */\n storeId: string;\n}\n\n/**\n * Issued session token response.\n *\n * @example\n * { token: \"eyJhbGciOi...\", expiresAt: \"2026-03-10T09:00:00.000Z\" }\n */\nexport interface SessionToken {\n /** JWT token string */\n token: string;\n /** Expiration time (ISO 8601 UTC) */\n expiresAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// Store — from waffo-pancake-store-service\n// ---------------------------------------------------------------------------\n\n/**\n * Webhook configuration for test and production environments.\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface WebhookSettings {\n /** Test environment webhook URL */\n testWebhookUrl: string | null;\n /** Production environment webhook URL */\n prodWebhookUrl: string | null;\n /** Event types subscribed in test environment */\n testEvents: string[];\n /** Event types subscribed in production environment */\n prodEvents: string[];\n}\n\n/**\n * Notification settings (all default to true).\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface NotificationSettings {\n emailOrderConfirmation: boolean;\n emailSubscriptionConfirmation: boolean;\n emailSubscriptionCycled: boolean;\n emailSubscriptionCanceled: boolean;\n emailSubscriptionRevoked: boolean;\n emailSubscriptionPastDue: boolean;\n notifyNewOrders: boolean;\n notifyNewSubscriptions: boolean;\n}\n\n/**\n * Single-theme checkout page styling.\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface CheckoutThemeSettings {\n checkoutLogo: string | null;\n checkoutColorPrimary: string;\n checkoutColorBackground: string;\n checkoutColorCard: string;\n checkoutColorText: string;\n checkoutColorTextSecondary: string;\n checkoutBorderRadius: string;\n}\n\n/**\n * Checkout page configuration (light and dark themes).\n * @see waffo-pancake-store-service/app/lib/types.ts\n */\nexport interface CheckoutSettings {\n light: CheckoutThemeSettings;\n dark: CheckoutThemeSettings;\n}\n\n/**\n * Store entity.\n * @see waffo-pancake-store-service/app/lib/resources/store.ts\n */\nexport interface Store {\n id: string;\n name: string;\n status: EntityStatus;\n logo: string | null;\n supportEmail: string | null;\n website: string | null;\n slug: string | null;\n isPublic: boolean;\n prodEnabled: boolean;\n webhookSettings: WebhookSettings | null;\n notificationSettings: NotificationSettings | null;\n checkoutSettings: CheckoutSettings | null;\n deletedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Parameters for creating a store. */\nexport interface CreateStoreParams {\n /** Store name (slug is auto-generated) */\n name: string;\n}\n\n/** Parameters for updating a store. */\nexport interface UpdateStoreParams {\n /** Store ID */\n id: string;\n name?: string;\n status?: EntityStatus;\n logo?: string | null;\n supportEmail?: string | null;\n website?: string | null;\n isPublic?: boolean;\n webhookSettings?: WebhookSettings | null;\n notificationSettings?: NotificationSettings | null;\n checkoutSettings?: CheckoutSettings | null;\n}\n\n/** Parameters for deleting (soft-delete) a store. */\nexport interface DeleteStoreParams {\n /** Store ID */\n id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Store Merchant (coming soon — endpoints return 501)\n// ---------------------------------------------------------------------------\n\n/** Parameters for adding a merchant to a store. */\nexport interface AddMerchantParams {\n storeId: string;\n email: string;\n role: \"admin\" | \"member\";\n}\n\n/** Result of adding a merchant to a store. */\nexport interface AddMerchantResult {\n storeId: string;\n merchantId: string;\n email: string;\n role: string;\n status: string;\n addedAt: string;\n}\n\n/** Parameters for removing a merchant from a store. */\nexport interface RemoveMerchantParams {\n storeId: string;\n merchantId: string;\n}\n\n/** Result of removing a merchant from a store. */\nexport interface RemoveMerchantResult {\n message: string;\n removedAt: string;\n}\n\n/** Parameters for updating a merchant's role. */\nexport interface UpdateRoleParams {\n storeId: string;\n merchantId: string;\n role: \"admin\" | \"member\";\n}\n\n/** Result of updating a merchant's role. */\nexport interface UpdateRoleResult {\n storeId: string;\n merchantId: string;\n role: string;\n updatedAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// Product — shared types from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * Price for a single currency.\n *\n * Amounts are stored in the smallest currency unit (e.g. cents, yen)\n * to avoid floating-point precision issues.\n *\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n *\n * @example\n * // USD $9.99\n * { amount: 999, taxIncluded: true, taxCategory: \"saas\" }\n *\n * @example\n * // JPY ¥1000\n * { amount: 1000, taxIncluded: false, taxCategory: \"software\" }\n */\nexport interface PriceInfo {\n /** Price amount in smallest currency unit */\n amount: number;\n /** Whether the price is tax-inclusive */\n taxIncluded: boolean;\n /** Tax category */\n taxCategory: TaxCategory;\n}\n\n/**\n * Multi-currency prices (keyed by ISO 4217 currency code).\n *\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n *\n * @example\n * {\n * \"USD\": { amount: 999, taxIncluded: true, taxCategory: \"saas\" },\n * \"EUR\": { amount: 899, taxIncluded: true, taxCategory: \"saas\" }\n * }\n */\nexport type Prices = Record<string, PriceInfo>;\n\n/**\n * Media asset (image or video).\n * @see waffo-pancake-product-service/app/lib/resources/types.ts\n */\nexport interface MediaItem {\n /** Media type */\n type: `${MediaType}`;\n /** Asset URL */\n url: string;\n /** Alt text */\n alt?: string;\n /** Thumbnail URL */\n thumbnail?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Onetime Product — from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * One-time product detail (public API shape).\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts OnetimeProductDetail\n */\nexport interface OnetimeProductDetail {\n id: string;\n storeId: string;\n name: string;\n description: string | null;\n prices: Prices;\n media: MediaItem[];\n successUrl: string | null;\n metadata: Record<string, unknown>;\n status: ProductVersionStatus;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Parameters for creating a one-time product.\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts CreateOnetimeProductRequestBody\n */\nexport interface CreateOnetimeProductParams {\n storeId: string;\n name: string;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parameters for updating a one-time product (creates a new version; skips if unchanged).\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts UpdateOnetimeProductContentRequestBody\n */\nexport interface UpdateOnetimeProductParams {\n id: string;\n name: string;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/** Parameters for publishing a one-time product's test version to production. */\nexport interface PublishOnetimeProductParams {\n /** Product ID */\n id: string;\n}\n\n/**\n * Parameters for updating a one-time product's status.\n * @see waffo-pancake-product-service/app/lib/resources/onetime-product.ts UpdateOnetimeStatusRequestBody\n */\nexport interface UpdateOnetimeStatusParams {\n id: string;\n status: ProductVersionStatus;\n}\n\n// ---------------------------------------------------------------------------\n// Subscription Product — from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * Subscription product detail (public API shape).\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts SubscriptionProductDetail\n */\nexport interface SubscriptionProductDetail {\n id: string;\n storeId: string;\n name: string;\n description: string | null;\n billingPeriod: BillingPeriod;\n prices: Prices;\n media: MediaItem[];\n successUrl: string | null;\n metadata: Record<string, unknown>;\n status: ProductVersionStatus;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Parameters for creating a subscription product.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts CreateSubscriptionProductRequestBody\n */\nexport interface CreateSubscriptionProductParams {\n storeId: string;\n name: string;\n billingPeriod: BillingPeriod;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Parameters for updating a subscription product (creates a new version; skips if unchanged).\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts UpdateSubscriptionProductContentRequestBody\n */\nexport interface UpdateSubscriptionProductParams {\n id: string;\n name: string;\n billingPeriod: BillingPeriod;\n prices: Prices;\n description?: string;\n media?: MediaItem[];\n successUrl?: string;\n metadata?: Record<string, unknown>;\n}\n\n/** Parameters for publishing a subscription product's test version to production. */\nexport interface PublishSubscriptionProductParams {\n /** Product ID */\n id: string;\n}\n\n/**\n * Parameters for updating a subscription product's status.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product.ts UpdateSubscriptionStatusRequestBody\n */\nexport interface UpdateSubscriptionStatusParams {\n id: string;\n status: ProductVersionStatus;\n}\n\n// ---------------------------------------------------------------------------\n// Subscription Product Group — from waffo-pancake-product-service\n// ---------------------------------------------------------------------------\n\n/**\n * Group rules for subscription product groups.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts\n */\nexport interface GroupRules {\n /** Whether trial period is shared across products in the group */\n sharedTrial: boolean;\n}\n\n/**\n * Subscription product group entity.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts\n */\nexport interface SubscriptionProductGroup {\n id: string;\n storeId: string;\n name: string;\n description: string | null;\n rules: GroupRules;\n productIds: string[];\n environment: Environment;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Parameters for creating a subscription product group.\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts CreateGroupRequestBody\n */\nexport interface CreateSubscriptionProductGroupParams {\n storeId: string;\n name: string;\n description?: string;\n rules?: GroupRules;\n productIds?: string[];\n}\n\n/**\n * Parameters for updating a subscription product group (`productIds` is a full replacement).\n * @see waffo-pancake-product-service/app/lib/resources/subscription-product-group.ts UpdateGroupRequestBody\n */\nexport interface UpdateSubscriptionProductGroupParams {\n id: string;\n name?: string;\n description?: string;\n rules?: GroupRules;\n productIds?: string[];\n}\n\n/** Parameters for hard-deleting a subscription product group. */\nexport interface DeleteSubscriptionProductGroupParams {\n /** Group ID */\n id: string;\n}\n\n/** Parameters for publishing a test-environment group to production (upsert). */\nexport interface PublishSubscriptionProductGroupParams {\n /** Group ID */\n id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Order — from waffo-pancake-order-service\n// ---------------------------------------------------------------------------\n\n/** Parameters for canceling a subscription order. */\nexport interface CancelSubscriptionParams {\n /** Order ID */\n orderId: string;\n}\n\n/**\n * Result of canceling a subscription order.\n * @see waffo-pancake-order-service cancel-order route.ts\n */\nexport interface CancelSubscriptionResult {\n orderId: string;\n /** Status after cancellation (`\"canceled\"` or `\"canceling\"`) */\n status: `${SubscriptionOrderStatus}`;\n}\n\n/**\n * Buyer billing details for checkout.\n * @see waffo-pancake-order-service/app/lib/types.ts\n */\nexport interface BillingDetail {\n /** Country code (ISO 3166-1 alpha-2) */\n country: string;\n /** Whether this is a business purchase */\n isBusiness: boolean;\n /** Postal / ZIP code */\n postcode?: string;\n /** State / province code (required for US/CA) */\n state?: string;\n /** Business name (required when isBusiness=true) */\n businessName?: string;\n /** Tax ID (required for EU businesses) */\n taxId?: string;\n}\n\n/**\n * Parameters for creating a checkout session.\n * @see waffo-pancake-order-service/app/lib/types.ts CreateCheckoutSessionRequest\n */\nexport interface CreateCheckoutSessionParams {\n /** Store ID */\n storeId?: string;\n /** Product ID */\n productId: string;\n /** Product type */\n productType: `${CheckoutSessionProductType}`;\n /** Currency code (ISO 4217) */\n currency: string;\n /** Optional price snapshot override (reads from DB if omitted) */\n priceSnapshot?: PriceInfo;\n /** Trial toggle override (subscription only) */\n withTrial?: boolean;\n /** Pre-filled buyer email */\n buyerEmail?: string;\n /** Pre-filled billing details */\n billingDetail?: BillingDetail;\n /** Redirect URL after successful payment */\n successUrl?: string;\n /** Session expiration in seconds (default: 7 days) */\n expiresInSeconds?: number;\n /** Custom metadata */\n metadata?: Record<string, string>;\n}\n\n/** Result of creating a checkout session. */\nexport interface CheckoutSessionResult {\n /** Session ID */\n sessionId: string;\n /** URL to redirect the customer to */\n checkoutUrl: string;\n /** Session expiration time (ISO 8601 UTC) */\n expiresAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// GraphQL\n// ---------------------------------------------------------------------------\n\n/** Parameters for a GraphQL query. */\nexport interface GraphQLParams {\n /** GraphQL query string */\n query: string;\n /** Query variables */\n variables?: Record<string, unknown>;\n}\n\n/** GraphQL response envelope. */\nexport interface GraphQLResponse<T = Record<string, unknown>> {\n data: T | null;\n errors?: Array<{\n message: string;\n locations?: Array<{ line: number; column: number }>;\n path?: string[];\n }>;\n}\n\n// ---------------------------------------------------------------------------\n// Webhook\n// ---------------------------------------------------------------------------\n\n/**\n * Webhook event types.\n * @see docs/api-reference/webhooks.mdx\n */\nexport enum WebhookEventType {\n /** One-time order first payment succeeded */\n OrderCompleted = \"order.completed\",\n /** Subscription first payment succeeded (newly activated) */\n SubscriptionActivated = \"subscription.activated\",\n /** Subscription renewal payment succeeded */\n SubscriptionPaymentSucceeded = \"subscription.payment_succeeded\",\n /** Buyer initiated cancellation (expires at end of current period) */\n SubscriptionCanceling = \"subscription.canceling\",\n /** Buyer withdrew cancellation (subscription restored) */\n SubscriptionUncanceled = \"subscription.uncanceled\",\n /** Subscription product changed (upgrade/downgrade) */\n SubscriptionUpdated = \"subscription.updated\",\n /** Subscription fully terminated */\n SubscriptionCanceled = \"subscription.canceled\",\n /** Renewal payment failed (past due) */\n SubscriptionPastDue = \"subscription.past_due\",\n /** Refund succeeded */\n RefundSucceeded = \"refund.succeeded\",\n /** Refund failed */\n RefundFailed = \"refund.failed\",\n}\n\n/**\n * Common data fields in a webhook event payload.\n * @see docs/api-reference/webhooks.mdx\n */\nexport interface WebhookEventData {\n orderId: string;\n buyerEmail: string;\n currency: string;\n /** Amount in smallest currency unit */\n amount: number;\n /** Tax amount in smallest currency unit */\n taxAmount: number;\n productName: string;\n}\n\n/**\n * Webhook event payload.\n *\n * @see docs/api-reference/webhooks.mdx\n *\n * @example\n * {\n * id: \"550e8400-...\",\n * timestamp: \"2026-03-10T08:30:00.000Z\",\n * eventType: \"order.completed\",\n * eventId: \"pay_660e8400-...\",\n * storeId: \"770e8400-...\",\n * mode: \"prod\",\n * data: { orderId: \"...\", buyerEmail: \"...\", currency: \"USD\", amount: 2900, taxAmount: 290, productName: \"Pro Plan\" }\n * }\n */\nexport interface WebhookEvent<T = WebhookEventData> {\n /** Delivery record unique ID (UUID), usable for idempotent deduplication */\n id: string;\n /** Event timestamp (ISO 8601 UTC) */\n timestamp: string;\n /** Event type */\n eventType: `${WebhookEventType}` | (string & {});\n /** Business event ID (e.g. payment ID, order ID) */\n eventId: string;\n /** Store ID the event belongs to */\n storeId: string;\n /** Environment identifier */\n mode: `${Environment}`;\n /** Event data */\n data: T;\n}\n\n/** Options for {@link verifyWebhook}. */\nexport interface VerifyWebhookOptions {\n /**\n * Specify which environment's public key to use for verification.\n * When omitted, both keys are tried automatically (prod first).\n */\n environment?: `${Environment}`;\n /**\n * Timestamp tolerance window in milliseconds for replay protection.\n * Set to 0 to skip timestamp checking.\n * @default 300000 (5 minutes)\n */\n toleranceMs?: number;\n}\n"],"mappings":"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","names":["createHash","createHash","Environment","TaxCategory","BillingPeriod","ProductVersionStatus","EntityStatus","StoreRole","OnetimeOrderStatus","SubscriptionOrderStatus","PaymentStatus","RefundTicketStatus","RefundStatus","MediaType","CheckoutSessionProductType","ErrorLayer","WebhookEventType"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waffo/pancake-ts",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "TypeScript SDK for Waffo Pancake API (Merchant API Key authentication)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -19,7 +19,8 @@
19
19
  }
20
20
  },
21
21
  "files": [
22
- "dist"
22
+ "dist",
23
+ "CHANGELOG.md"
23
24
  ],
24
25
  "scripts": {
25
26
  "build": "tsup",