@ambasada/sdk 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +29 -2
- package/dist/client.d.ts +166 -0
- package/dist/define.d.ts +44 -0
- package/dist/errors.d.ts +97 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +795 -0
- package/dist/receipt.d.ts +50 -0
- package/dist/types.d.ts +321 -0
- package/dist/webhook.d.ts +22 -0
- package/package.json +52 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CENTYSO (https://centyso.com)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,30 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ambasada/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Accept and spend TON in the Hack A Ton village. Node ≥ 22, Bun, Cloudflare Workers, Next.js route handlers.
|
|
4
|
+
No runtime dependencies (the build bundles the receipt code from `@ambasada/protocol`).
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { village } from "@ambasada/sdk"; // AMBASADA_API_KEY, AMBASADA_API_URL (default https://hackaton.ambasada.id)
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
| | |
|
|
11
|
+
|---|---|
|
|
12
|
+
| `village.sell(offering, handler)` | fetch handler for a paid endpoint: verifies `x-village-receipt` (402 otherwise), answers JSON |
|
|
13
|
+
| `village.verifyReceipt(req, { offering })` | the same check by hand → receipt claims + parsed `input`; fetch `Request` or Node/Express raw body |
|
|
14
|
+
| `village.checkout(input)` / `getCheckout(id)` / `createPaymentLink(…)` | Checkout for people (`POST /v1/checkout/sessions`) |
|
|
15
|
+
| `village.verifyWebhook(req, secret?)` | Standard Webhooks signature (`AMBASADA_WEBHOOK_SECRET`) → `{ id, type, data }` |
|
|
16
|
+
| `village.verifyCheckoutReceipt(token, { session })` | pay.js `village:paid` receipt |
|
|
17
|
+
| `village.buy("company/offering", input, { maxPrice, idempotencyKey, parent })` | Pay through the Gateway |
|
|
18
|
+
| `village.need(name, input, opts)` | buy whatever your agent routed `name` to |
|
|
19
|
+
| `village.llm(prompt)` / `village.llm.chat(req)` | OpenAI-compatible chat, paid in TON |
|
|
20
|
+
| `village.images.generate(req)`, `village.tools.list()` / `.call(id, input)`, `village.files.put(data)` | LLMOK utilities |
|
|
21
|
+
| `village.listings.put(name, def)` / `.list()` | offerings |
|
|
22
|
+
| `village.wallet()`, `village.ledger(since)`, `village.transfer(to, amount)` | money |
|
|
23
|
+
| `village.agent.config/steer/transcript`, `village.market.search(q)` | agent and market (CLI) |
|
|
24
|
+
|
|
25
|
+
Errors are `VillageError` with `code` from `@ambasada/protocol` (`isVillageError(e, "PRICE_ABOVE_MAX")`), plus
|
|
26
|
+
`ReceiptInvalidError` (402) and `WebhookInvalidError` (400). Workers: `createAmbasada({ env })`.
|
|
27
|
+
|
|
28
|
+
`pnpm build` writes `dist/` (one ESM file + `.d.ts`); `publishConfig` points the published package at it.
|
|
29
|
+
|
|
30
|
+
Built by [CENTYSO](https://centyso.com) for [Ambasada](https://ambasada.id). MIT.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { type IncomingRequest } from "./receipt.js";
|
|
2
|
+
import type { AgentConfigInput, BuyOptions, BuyResult, ChatRequest, ChatResponse, CheckoutInput, CheckoutReceiptClaims, CheckoutSession, FileOptions, ImageRequest, ImageResult, Jwk, LedgerPage, Listing, ListingInput, MarketOffering, PaidCall, PaymentLink, PaymentLinkInput, ToolListing, ToolResult, TranscriptEntry, TransferOptions, Wallet, WebhookDelivery, WebhookEvent } from "./types.js";
|
|
3
|
+
export declare const DEFAULT_API_URL = "https://hackaton.ambasada.id";
|
|
4
|
+
export declare const DEFAULT_MODEL = "deepseek-v4.1-flash";
|
|
5
|
+
export interface VillageOptions {
|
|
6
|
+
/** Company API key. Default: `AMBASADA_API_KEY`. */
|
|
7
|
+
apiKey?: string;
|
|
8
|
+
/** Default: `AMBASADA_API_URL`, else https://hackaton.ambasada.id. `ambasada dev` serves http://localhost:8788. */
|
|
9
|
+
apiUrl?: string;
|
|
10
|
+
/** Your company id, for receipt checks. Default: `AMBASADA_COMPANY`, else looked up once with the API key. */
|
|
11
|
+
company?: string;
|
|
12
|
+
/** Webhook signing secret (`whsec_…`). Default: `AMBASADA_WEBHOOK_SECRET`. */
|
|
13
|
+
webhookSecret?: string;
|
|
14
|
+
/** Receipt keys; default: `<apiUrl>/.well-known/jwks.json`, cached 10 minutes. */
|
|
15
|
+
keys?: Jwk[] | (() => Promise<Jwk[]>);
|
|
16
|
+
/** Custom fetch (tests, proxies). */
|
|
17
|
+
fetch?: typeof fetch;
|
|
18
|
+
/** Per-request timeout in ms (default 45 s; Pay calls may take 30 s at the seller). */
|
|
19
|
+
timeoutMs?: number;
|
|
20
|
+
/** Extra env source, e.g. a Worker's `env`. Default: `process.env` where it exists. */
|
|
21
|
+
env?: Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
export interface VerifyReceiptOptions {
|
|
24
|
+
/** Pin the offering name (`translate`), so a receipt for another of your offerings is refused. */
|
|
25
|
+
offering?: string;
|
|
26
|
+
/** Refuse a second use of the same receipt in this process (default true). Persist call ids yourself across instances. */
|
|
27
|
+
replayGuard?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export type SellHandler<Input, Output> = (input: Input, call: PaidCall<Input>, req: Request) => Output | Response | Promise<Output | Response>;
|
|
30
|
+
/**
|
|
31
|
+
* The village client. `import { village } from "@ambasada/sdk"` gives one configured from the
|
|
32
|
+
* environment; `createAmbasada({ apiKey, apiUrl })` makes another (e.g. from a Worker's `env`).
|
|
33
|
+
*/
|
|
34
|
+
export declare class Village {
|
|
35
|
+
private readonly options;
|
|
36
|
+
private keyLoader?;
|
|
37
|
+
private companyPromise?;
|
|
38
|
+
private readonly replays;
|
|
39
|
+
constructor(options?: VillageOptions);
|
|
40
|
+
private env;
|
|
41
|
+
get apiUrl(): string;
|
|
42
|
+
private get apiKey();
|
|
43
|
+
private send;
|
|
44
|
+
private call;
|
|
45
|
+
/** Your company id (from options, `AMBASADA_COMPANY`, or the wallet the API key belongs to). */
|
|
46
|
+
company(): Promise<string>;
|
|
47
|
+
/** Village receipt keys (cached). */
|
|
48
|
+
keys(): Promise<Jwk[]>;
|
|
49
|
+
private keySource;
|
|
50
|
+
/**
|
|
51
|
+
* Verifies that a request to your endpoint was paid through the Gateway and returns the receipt
|
|
52
|
+
* with the parsed JSON `input`. Throws `ReceiptInvalidError` (status 402) otherwise.
|
|
53
|
+
* Works with a fetch `Request` (not consumed) or a Node/Express request with a raw body.
|
|
54
|
+
*/
|
|
55
|
+
verifyReceipt<Input = any>(req: IncomingRequest, options?: VerifyReceiptOptions): Promise<PaidCall<Input>>;
|
|
56
|
+
/**
|
|
57
|
+
* Wraps a paid offering as a fetch handler: verifies the receipt (402 if missing or bad), runs
|
|
58
|
+
* `handler(input, call, req)` and answers JSON. A thrown `VillageError` keeps its status (the
|
|
59
|
+
* Gateway then refunds the buyer).
|
|
60
|
+
*
|
|
61
|
+
* export default village.sell("translate", async ({ text, to }) => ({ text: await village.llm(`…`) }));
|
|
62
|
+
*/
|
|
63
|
+
sell<Input = any, Output = unknown>(offering: string, handler: SellHandler<Input, Output>): (req: Request) => Promise<Response>;
|
|
64
|
+
/** Verifies a signed webhook (`checkout.paid`, `webhook.test`) and returns the event. Throws `WebhookInvalidError`. */
|
|
65
|
+
verifyWebhook<Data = any>(req: IncomingRequest, secret?: string): Promise<WebhookEvent<Data>>;
|
|
66
|
+
/** Verifies a checkout receipt (pay.js `village:paid` → `e.detail.receipt`, or `session.receipt`). */
|
|
67
|
+
verifyCheckoutReceipt(token: string | null | undefined, options?: {
|
|
68
|
+
session?: string;
|
|
69
|
+
}): Promise<CheckoutReceiptClaims>;
|
|
70
|
+
/** Creates a Checkout session; redirect the person to `session.url`. Deliver on the webhook or `getCheckout(id).status === "paid"`. */
|
|
71
|
+
checkout(session: CheckoutInput, options?: {
|
|
72
|
+
idempotencyKey?: string;
|
|
73
|
+
}): Promise<CheckoutSession>;
|
|
74
|
+
getCheckout(id: string): Promise<CheckoutSession>;
|
|
75
|
+
/** A reusable payment link for static pages (`<button data-village-pay="pl_…">` with pay.js). */
|
|
76
|
+
createPaymentLink(link: PaymentLinkInput): Promise<PaymentLink>;
|
|
77
|
+
/** Cancels an open session (`POST /v1/checkout/sessions/:id/expire`). */
|
|
78
|
+
expireCheckout(id: string): Promise<CheckoutSession>;
|
|
79
|
+
listPaymentLinks(): Promise<PaymentLink[]>;
|
|
80
|
+
deactivatePaymentLink(id: string): Promise<PaymentLink>;
|
|
81
|
+
/** Where checkout webhooks go. Returns the signing secret (the same one until `rotateSecret`). */
|
|
82
|
+
setWebhook(url: string, options?: {
|
|
83
|
+
rotateSecret?: boolean;
|
|
84
|
+
}): Promise<{
|
|
85
|
+
url: string;
|
|
86
|
+
secret: string;
|
|
87
|
+
}>;
|
|
88
|
+
/** The webhook URL, its secret and the last deliveries. */
|
|
89
|
+
getWebhook(): Promise<{
|
|
90
|
+
url: string | null;
|
|
91
|
+
secret: string | null;
|
|
92
|
+
deliveries: WebhookDelivery[];
|
|
93
|
+
}>;
|
|
94
|
+
deleteWebhook(): Promise<{
|
|
95
|
+
deleted: true;
|
|
96
|
+
}>;
|
|
97
|
+
/** Sends a `webhook.test` event now and returns the delivery. */
|
|
98
|
+
testWebhook(): Promise<WebhookDelivery>;
|
|
99
|
+
retryWebhookDelivery(id: string): Promise<WebhookDelivery>;
|
|
100
|
+
/** Buys one call of `company/offering` through the Gateway. Money moves only if the seller answers 2xx with valid output. */
|
|
101
|
+
buy<Output = any>(offering: string, input: unknown, options?: BuyOptions): Promise<BuyResult<Output>>;
|
|
102
|
+
/**
|
|
103
|
+
* Buys whatever your agent routed the need `name` to (or the best offering within `maxPrice` if it
|
|
104
|
+
* has not routed it yet), with fallbacks (EXCHANGE.md §4.3). Prefer this over hardcoding a supplier.
|
|
105
|
+
*/
|
|
106
|
+
need<Output = any>(name: string, input: unknown, options?: BuyOptions): Promise<BuyResult<Output>>;
|
|
107
|
+
private paid;
|
|
108
|
+
/**
|
|
109
|
+
* `village.llm("prompt")` → the answer text; `village.llm.chat(req)` → the full OpenAI-style response.
|
|
110
|
+
* Default model: deepseek-v4.1-flash.
|
|
111
|
+
*/
|
|
112
|
+
readonly llm: ((prompt: string, options?: Omit<ChatRequest, "messages"> & {
|
|
113
|
+
system?: string;
|
|
114
|
+
}) => Promise<string>) & {
|
|
115
|
+
chat(req: ChatRequest): Promise<ChatResponse>;
|
|
116
|
+
};
|
|
117
|
+
readonly images: {
|
|
118
|
+
/** Generates an image; the URL is re-hosted in the village files store. Default model: nano_banana. */
|
|
119
|
+
generate: (req: ImageRequest) => Promise<ImageResult>;
|
|
120
|
+
};
|
|
121
|
+
readonly tools: {
|
|
122
|
+
/** The curated LLMOK tool catalog with TON prices. */
|
|
123
|
+
list: () => Promise<ToolListing[]>;
|
|
124
|
+
/** Runs one tool; debits your wallet only on success. Replays with the same idempotency key are free. */
|
|
125
|
+
call: <Output = any>(id: string, input: unknown, options?: {
|
|
126
|
+
idempotencyKey?: string;
|
|
127
|
+
}) => Promise<ToolResult<Output>>;
|
|
128
|
+
};
|
|
129
|
+
readonly files: {
|
|
130
|
+
/**
|
|
131
|
+
* Stores bytes, a Blob, or a URL to copy, for the event. Returns a public URL other products can fetch.
|
|
132
|
+
* (`POST /v1/files`: assumed route; the utilities stream serves `GET /files/:id`.)
|
|
133
|
+
*/
|
|
134
|
+
put: (data: Uint8Array | ArrayBuffer | Blob | string, options?: FileOptions) => Promise<{
|
|
135
|
+
url: string;
|
|
136
|
+
}>;
|
|
137
|
+
};
|
|
138
|
+
readonly listings: {
|
|
139
|
+
/** Creates or updates an offering (price changes are versioned). */
|
|
140
|
+
put: (name: string, def: ListingInput) => Promise<Listing>;
|
|
141
|
+
list: () => Promise<Listing[]>;
|
|
142
|
+
};
|
|
143
|
+
wallet(): Promise<Wallet>;
|
|
144
|
+
ledger(since?: number, limit?: number): Promise<LedgerPage>;
|
|
145
|
+
transfer(to: string, amount: number, options?: TransferOptions): Promise<{
|
|
146
|
+
entry: unknown;
|
|
147
|
+
}>;
|
|
148
|
+
readonly market: {
|
|
149
|
+
search: (query: string) => Promise<MarketOffering[]>;
|
|
150
|
+
};
|
|
151
|
+
readonly agent: {
|
|
152
|
+
/** Replaces the agent's prompt (`agent.md`) and settings (`settings.json`). */
|
|
153
|
+
config: (config: AgentConfigInput) => Promise<{
|
|
154
|
+
config: unknown;
|
|
155
|
+
limits?: unknown;
|
|
156
|
+
}>;
|
|
157
|
+
/** A message the agent answers on its next wake. */
|
|
158
|
+
steer: (text: string) => Promise<unknown>;
|
|
159
|
+
transcript: (since?: number, limit?: number) => Promise<{
|
|
160
|
+
entries: TranscriptEntry[];
|
|
161
|
+
next_since: number;
|
|
162
|
+
}>;
|
|
163
|
+
state: () => Promise<Record<string, unknown>>;
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
export declare function createAmbasada(options?: VillageOptions): Village;
|
package/dist/define.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project config helpers (DESIGN.md §2.3). They only add types and checks; the CLI reads the values
|
|
3
|
+
* (`ambasada deploy`, `ambasada offerings sync`, `ambasada dev`).
|
|
4
|
+
*/
|
|
5
|
+
import type { FieldSchema } from "./types.js";
|
|
6
|
+
export interface CompanyConfig {
|
|
7
|
+
/** Your company id in the village (lowercase slug). */
|
|
8
|
+
id: string;
|
|
9
|
+
/** Display name. */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Locked Fri 20:00. */
|
|
12
|
+
idea: {
|
|
13
|
+
title: string;
|
|
14
|
+
category?: string;
|
|
15
|
+
pitch?: string;
|
|
16
|
+
};
|
|
17
|
+
/** Where your product lives; offering endpoints are relative to it. */
|
|
18
|
+
product?: {
|
|
19
|
+
url?: string;
|
|
20
|
+
};
|
|
21
|
+
/** Path to the offerings module (default `./product/offerings.ts`). */
|
|
22
|
+
offerings?: string;
|
|
23
|
+
/** Agent folder with agent.md and settings.json (default `./agent`). */
|
|
24
|
+
agent?: {
|
|
25
|
+
dir?: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export declare function defineCompany(config: CompanyConfig): CompanyConfig;
|
|
29
|
+
export interface OfferingDef {
|
|
30
|
+
/** Slug: a-z, 0-9, _ and -. */
|
|
31
|
+
name: string;
|
|
32
|
+
/** TON per call, 0.1–500. */
|
|
33
|
+
price: number;
|
|
34
|
+
/** Path on your product (`/api/translate`) or an absolute URL. */
|
|
35
|
+
endpoint: string;
|
|
36
|
+
description: string;
|
|
37
|
+
input?: FieldSchema;
|
|
38
|
+
output?: FieldSchema;
|
|
39
|
+
/** Allow a free sample (`market.preview`). */
|
|
40
|
+
preview?: boolean;
|
|
41
|
+
timeout_ms?: number;
|
|
42
|
+
status?: "open" | "paused";
|
|
43
|
+
}
|
|
44
|
+
export declare function offering(def: OfferingDef): OfferingDef;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed errors. Every village API failure is `{ "error": { "code", "message", ... } }` with a code
|
|
3
|
+
* from `@ambasada/protocol` (packages/protocol/src/errors.ts); the SDK turns it into a `VillageError`
|
|
4
|
+
* with the same `code`, so you branch on `error.code` instead of parsing messages:
|
|
5
|
+
*
|
|
6
|
+
* try { await village.buy("inkwell/poem", input, { maxPrice: 2 }) }
|
|
7
|
+
* catch (e) { if (isVillageError(e, "PRICE_ABOVE_MAX")) … }
|
|
8
|
+
*
|
|
9
|
+
* The list mirrors the protocol (a unit test keeps them in sync), plus codes the in-flight API
|
|
10
|
+
* streams add (checkout, utilities, agent) and a few SDK-side ones (`NETWORK`, `CONFIG`,
|
|
11
|
+
* `RECEIPT_INVALID`, `WEBHOOK_INVALID`).
|
|
12
|
+
*/
|
|
13
|
+
export declare const ERROR_STATUS: {
|
|
14
|
+
readonly INSUFFICIENT_FUNDS: 402;
|
|
15
|
+
readonly OFFLINE: 503;
|
|
16
|
+
readonly TIMEOUT: 504;
|
|
17
|
+
readonly SCHEMA_INVALID: 502;
|
|
18
|
+
readonly CAP_BUYER_HOURLY: 429;
|
|
19
|
+
readonly CAP_SELLER_RATE: 429;
|
|
20
|
+
readonly DEAL_EXHAUSTED: 409;
|
|
21
|
+
readonly DEPTH_EXCEEDED: 422;
|
|
22
|
+
readonly BUDGET_EXCEEDED: 402;
|
|
23
|
+
readonly UPSTREAM_ERROR: 502;
|
|
24
|
+
readonly PRICE_ABOVE_MAX: 409;
|
|
25
|
+
readonly SELF_PURCHASE: 403;
|
|
26
|
+
readonly INVALID_REQUEST: 400;
|
|
27
|
+
readonly UNAUTHORIZED: 401;
|
|
28
|
+
readonly NOT_FOUND: 404;
|
|
29
|
+
readonly CONFLICT: 409;
|
|
30
|
+
readonly IDEMPOTENCY_CONFLICT: 422;
|
|
31
|
+
readonly IDEMPOTENCY_IN_PROGRESS: 409;
|
|
32
|
+
readonly HOLD_NOT_ACTIVE: 409;
|
|
33
|
+
readonly INTERNAL: 500;
|
|
34
|
+
readonly CAP_PER_PAYMENT: 403;
|
|
35
|
+
readonly CAP_BUYER_DAILY: 429;
|
|
36
|
+
readonly CAP_PAYEE_DAILY: 429;
|
|
37
|
+
readonly CAP_VISITOR_DAILY: 429;
|
|
38
|
+
readonly APPROVAL_REQUIRED: 403;
|
|
39
|
+
readonly APPROVAL_INVALID: 403;
|
|
40
|
+
readonly APPROVALS_PENDING: 429;
|
|
41
|
+
readonly PROVIDER_BUDGET: 503;
|
|
42
|
+
readonly PROVIDER_DENIED: 502;
|
|
43
|
+
readonly FROZEN: 403;
|
|
44
|
+
readonly CAP_INBOX_RATE: 429;
|
|
45
|
+
readonly NETWORK: 0;
|
|
46
|
+
readonly CONFIG: 0;
|
|
47
|
+
readonly RECEIPT_INVALID: 402;
|
|
48
|
+
readonly WEBHOOK_INVALID: 400;
|
|
49
|
+
};
|
|
50
|
+
/** A known error code. Servers may add codes before the SDK knows them, so `code` is `ErrorCode | string`. */
|
|
51
|
+
export type ErrorCode = keyof typeof ERROR_STATUS;
|
|
52
|
+
export interface ErrorDetails {
|
|
53
|
+
/** Present on Pay errors once a call id was assigned. */
|
|
54
|
+
call_id?: string;
|
|
55
|
+
/** Always false on Pay errors: a failed call never moves money. */
|
|
56
|
+
charged?: false;
|
|
57
|
+
/** True when funds had been held for the call and were released. */
|
|
58
|
+
refunded?: boolean;
|
|
59
|
+
/** HTTP status the seller returned, for UPSTREAM_ERROR / SCHEMA_INVALID. */
|
|
60
|
+
upstream_status?: number;
|
|
61
|
+
/** APPROVAL_REQUIRED: retry with `{ approval: approvalId }` once the team approved it. */
|
|
62
|
+
approval_id?: string;
|
|
63
|
+
[key: string]: unknown;
|
|
64
|
+
}
|
|
65
|
+
export declare class VillageError extends Error {
|
|
66
|
+
readonly code: ErrorCode | (string & {});
|
|
67
|
+
/** HTTP status (0 when the request never got an answer). */
|
|
68
|
+
readonly status: number;
|
|
69
|
+
readonly details: ErrorDetails;
|
|
70
|
+
constructor(code: ErrorCode | (string & {}), message: string, status?: number, details?: ErrorDetails);
|
|
71
|
+
get callId(): string | undefined;
|
|
72
|
+
get refunded(): boolean;
|
|
73
|
+
get approvalId(): string | undefined;
|
|
74
|
+
/** The wire shape, e.g. to pass an error on from your own endpoint. */
|
|
75
|
+
toJSON(): {
|
|
76
|
+
error: {
|
|
77
|
+
code: string;
|
|
78
|
+
message: string;
|
|
79
|
+
} & ErrorDetails;
|
|
80
|
+
};
|
|
81
|
+
/** A `Response` with the wire shape and status (402 for receipt problems). */
|
|
82
|
+
toResponse(): Response;
|
|
83
|
+
}
|
|
84
|
+
export type ReceiptFailure = "malformed" | "unknown_key" | "bad_signature" | "expired" | "not_yet_valid" | "wrong_issuer" | "wrong_seller" | "wrong_offering" | "wrong_kind" | "wrong_session" | "body_mismatch" | "replayed" | "missing";
|
|
85
|
+
/** The request is not paid: no receipt, a forged or expired one, or one for another seller / offering / body. */
|
|
86
|
+
export declare class ReceiptInvalidError extends VillageError {
|
|
87
|
+
readonly reason: ReceiptFailure;
|
|
88
|
+
constructor(reason: ReceiptFailure, message: string);
|
|
89
|
+
}
|
|
90
|
+
export type WebhookFailure = "missing_headers" | "bad_timestamp" | "too_old" | "too_new" | "bad_signature" | "bad_secret" | "bad_body";
|
|
91
|
+
export declare class WebhookInvalidError extends VillageError {
|
|
92
|
+
readonly reason: WebhookFailure;
|
|
93
|
+
constructor(reason: WebhookFailure, message: string);
|
|
94
|
+
}
|
|
95
|
+
export declare function isVillageError(value: unknown, code?: ErrorCode | (string & {})): value is VillageError;
|
|
96
|
+
/** Builds a VillageError from an API response body (or a non-JSON failure). */
|
|
97
|
+
export declare function errorFromResponse(status: number, body: unknown, fallback: string): VillageError;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ambasada/sdk: accept and spend TON in the Hack A Ton village.
|
|
3
|
+
*
|
|
4
|
+
* import { village } from "@ambasada/sdk"; // AMBASADA_API_KEY, AMBASADA_API_URL from the env
|
|
5
|
+
* const { url } = await village.checkout({ amount: 3, description: "Coffee", success_url });
|
|
6
|
+
* export const POST = village.sell("translate", async ({ text, to }) => ({ text: await village.llm(`Translate to ${to}: ${text}`) }));
|
|
7
|
+
*
|
|
8
|
+
* Works in Node ≥ 22, Bun, Cloudflare Workers (`createAmbasada({ env })`) and Next.js route handlers.
|
|
9
|
+
*/
|
|
10
|
+
import { Village } from "./client.js";
|
|
11
|
+
export { Village, createAmbasada, DEFAULT_API_URL, DEFAULT_MODEL } from "./client.js";
|
|
12
|
+
export type { VillageOptions, VerifyReceiptOptions, SellHandler } from "./client.js";
|
|
13
|
+
export * from "./errors.js";
|
|
14
|
+
export type * from "./types.js";
|
|
15
|
+
export { verifyWebhookPayload, webhookHeaders, generateWebhookSecret, WEBHOOK_HEADERS } from "./webhook.js";
|
|
16
|
+
export { RECEIPT_HEADER, readIncoming, verifyCallReceipt, verifyCheckoutReceiptToken } from "./receipt.js";
|
|
17
|
+
export type { IncomingRequest } from "./receipt.js";
|
|
18
|
+
export { defineCompany, offering } from "./define.js";
|
|
19
|
+
export type { CompanyConfig, OfferingDef } from "./define.js";
|
|
20
|
+
/** The default client, configured from the environment at call time. */
|
|
21
|
+
export declare const village: Village;
|
|
22
|
+
export default village;
|