@ambasada/village 0.0.0-stage → 0.8.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 +56 -2
- package/dist/cli.mjs +3697 -0
- package/dist/client.d.ts +148 -0
- package/dist/define.d.ts +44 -0
- package/dist/errors.d.ts +19 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +2497 -0
- package/dist/receipt.d.ts +50 -0
- package/dist/sdk/apps.d.ts +110 -0
- package/dist/sdk/auth.d.ts +132 -0
- package/dist/sdk/client.d.ts +106 -0
- package/dist/sdk/define.d.ts +19 -0
- package/dist/sdk/errors.d.ts +94 -0
- package/dist/sdk/headers.d.ts +3 -0
- package/dist/sdk/platform.d.ts +20 -0
- package/dist/sdk/types.d.ts +40 -0
- package/dist/types.d.ts +307 -0
- package/dist/webhook.d.ts +30 -0
- package/package.json +57 -3
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { Ambasada, type AmbasadaOptions } from "./sdk/platform.js";
|
|
2
|
+
import { type IncomingRequest } from "./receipt.js";
|
|
3
|
+
import type { AgentConfigInput, BuyOptions, BuyResult, ChatRequest, ChatResponse, CheckoutInput, CheckoutReceiptClaims, CheckoutSession, ImageRequest, ImageResult, LedgerPage, Listing, ListingInput, MarketOffering, PaidCall, PaymentLink, PaymentLinkInput, ToolListing, ToolResult, TranscriptEntry, TransferOptions, Wallet, WebhookDelivery, WebhookEvent } from "./types.js";
|
|
4
|
+
/** The Hack A Ton API. The platform API (`@ambasada/sdk`) is https://api.ambasada.dev. */
|
|
5
|
+
export declare const DEFAULT_VILLAGE_API_URL = "https://hackaton.ambasada.id";
|
|
6
|
+
export declare const DEFAULT_MODEL = "deepseek-v4.1-flash";
|
|
7
|
+
export interface VillageOptions extends AmbasadaOptions {
|
|
8
|
+
/** Team key (`sk_live_…`, from the village app → Developers). Default: `AMBASADA_API_KEY`. */
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Default: `AMBASADA_VILLAGE_API_URL`, else `AMBASADA_API_URL` when it is not the platform host (0.7
|
|
12
|
+
* projects, `ambasada dev`), else https://hackaton.ambasada.id.
|
|
13
|
+
*/
|
|
14
|
+
apiUrl?: string;
|
|
15
|
+
/** Your company id, for receipt checks. Default: `AMBASADA_COMPANY`, else looked up once with the API key. */
|
|
16
|
+
company?: string;
|
|
17
|
+
/** Webhook signing secret (`whsec_…`). Default: `AMBASADA_WEBHOOK_SECRET`. */
|
|
18
|
+
webhookSecret?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface VerifyReceiptOptions {
|
|
21
|
+
/** Pin the offering name (`translate`), so a receipt for another of your offerings is refused. */
|
|
22
|
+
offering?: string;
|
|
23
|
+
/** Refuse a second use of the same receipt in this process (default true). Persist call ids yourself across instances. */
|
|
24
|
+
replayGuard?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export type SellHandler<Input, Output> = (input: Input, call: PaidCall<Input>, req: Request) => Output | Response | Promise<Output | Response>;
|
|
27
|
+
/**
|
|
28
|
+
* The village client: the platform client (`auth`, `apps`, `store`, `files`) plus money, AI, the agent and
|
|
29
|
+
* the market. `import { village } from "@ambasada/village"` gives one configured from the environment;
|
|
30
|
+
* `createVillage({ env })` makes another (e.g. from a Worker's `env`).
|
|
31
|
+
*/
|
|
32
|
+
export declare class Village extends Ambasada {
|
|
33
|
+
private readonly villageOptions;
|
|
34
|
+
private companyPromise?;
|
|
35
|
+
private readonly replays;
|
|
36
|
+
constructor(options?: VillageOptions);
|
|
37
|
+
get apiUrl(): string;
|
|
38
|
+
/** Your company id (from options, `AMBASADA_COMPANY`, or the wallet the API key belongs to). */
|
|
39
|
+
company(): Promise<string>;
|
|
40
|
+
private keySource;
|
|
41
|
+
/**
|
|
42
|
+
* Verifies that a request to your endpoint was paid through the Gateway and returns the receipt
|
|
43
|
+
* with the parsed JSON `input`. Throws `ReceiptInvalidError` (status 402) otherwise.
|
|
44
|
+
* Works with a fetch `Request` (not consumed) or a Node/Express request with a raw body.
|
|
45
|
+
*/
|
|
46
|
+
verifyReceipt<Input = any>(req: IncomingRequest, options?: VerifyReceiptOptions): Promise<PaidCall<Input>>;
|
|
47
|
+
/**
|
|
48
|
+
* Wraps a paid offering as a fetch handler: verifies the receipt (402 if missing or bad), runs
|
|
49
|
+
* `handler(input, call, req)` and answers JSON. A thrown `AmbasadaError` keeps its status (the
|
|
50
|
+
* Gateway then refunds the buyer).
|
|
51
|
+
*
|
|
52
|
+
* export default village.sell("translate", async ({ text, to }) => ({ text: await village.llm(`…`) }));
|
|
53
|
+
*/
|
|
54
|
+
sell<Input = any, Output = unknown>(offering: string, handler: SellHandler<Input, Output>): (req: Request) => Promise<Response>;
|
|
55
|
+
/** Verifies a signed webhook (`checkout.paid`, `webhook.test`) and returns the event. Throws `WebhookInvalidError`. */
|
|
56
|
+
verifyWebhook<Data = any>(req: IncomingRequest, secret?: string): Promise<WebhookEvent<Data>>;
|
|
57
|
+
/** Verifies a checkout receipt (pay.js `village:paid` → `e.detail.receipt`, or `session.receipt`). */
|
|
58
|
+
verifyCheckoutReceipt(token: string | null | undefined, options?: {
|
|
59
|
+
session?: string;
|
|
60
|
+
}): Promise<CheckoutReceiptClaims>;
|
|
61
|
+
/** Creates a Checkout session; redirect the person to `session.url`. Deliver on the webhook or `getCheckout(id).status === "paid"`. */
|
|
62
|
+
checkout(session: CheckoutInput, options?: {
|
|
63
|
+
idempotencyKey?: string;
|
|
64
|
+
}): Promise<CheckoutSession>;
|
|
65
|
+
getCheckout(id: string): Promise<CheckoutSession>;
|
|
66
|
+
/** A reusable payment link for static pages (`<button data-village-pay="pl_…">` with pay.js). */
|
|
67
|
+
createPaymentLink(link: PaymentLinkInput): Promise<PaymentLink>;
|
|
68
|
+
/** Cancels an open session (`POST /v1/checkout/sessions/:id/expire`). */
|
|
69
|
+
expireCheckout(id: string): Promise<CheckoutSession>;
|
|
70
|
+
listPaymentLinks(): Promise<PaymentLink[]>;
|
|
71
|
+
deactivatePaymentLink(id: string): Promise<PaymentLink>;
|
|
72
|
+
/** Where checkout webhooks go. Returns the signing secret (the same one until `rotateSecret`). */
|
|
73
|
+
setWebhook(url: string, options?: {
|
|
74
|
+
rotateSecret?: boolean;
|
|
75
|
+
}): Promise<{
|
|
76
|
+
url: string;
|
|
77
|
+
secret: string;
|
|
78
|
+
}>;
|
|
79
|
+
/** The webhook URL, its secret and the last deliveries. */
|
|
80
|
+
getWebhook(): Promise<{
|
|
81
|
+
url: string | null;
|
|
82
|
+
secret: string | null;
|
|
83
|
+
deliveries: WebhookDelivery[];
|
|
84
|
+
}>;
|
|
85
|
+
deleteWebhook(): Promise<{
|
|
86
|
+
deleted: true;
|
|
87
|
+
}>;
|
|
88
|
+
/** Sends a `webhook.test` event now and returns the delivery. */
|
|
89
|
+
testWebhook(): Promise<WebhookDelivery>;
|
|
90
|
+
retryWebhookDelivery(id: string): Promise<WebhookDelivery>;
|
|
91
|
+
/** Buys one call of `company/offering` through the Gateway. Money moves only if the seller answers 2xx with valid output. */
|
|
92
|
+
buy<Output = any>(offering: string, input: unknown, options?: BuyOptions): Promise<BuyResult<Output>>;
|
|
93
|
+
/**
|
|
94
|
+
* Buys whatever your agent routed the need `name` to (or the best offering within `maxPrice` if it
|
|
95
|
+
* has not routed it yet), with fallbacks (EXCHANGE.md §4.3). Prefer this over hardcoding a supplier.
|
|
96
|
+
*/
|
|
97
|
+
need<Output = any>(name: string, input: unknown, options?: BuyOptions): Promise<BuyResult<Output>>;
|
|
98
|
+
private paid;
|
|
99
|
+
/**
|
|
100
|
+
* `village.llm("prompt")` → the answer text; `village.llm.chat(req)` → the full OpenAI-style response.
|
|
101
|
+
* Default model: deepseek-v4.1-flash.
|
|
102
|
+
*/
|
|
103
|
+
readonly llm: ((prompt: string, options?: Omit<ChatRequest, "messages"> & {
|
|
104
|
+
system?: string;
|
|
105
|
+
}) => Promise<string>) & {
|
|
106
|
+
chat(req: ChatRequest): Promise<ChatResponse>;
|
|
107
|
+
};
|
|
108
|
+
readonly images: {
|
|
109
|
+
/** Generates an image; the URL is re-hosted in the village files store. Default model: nano_banana. */
|
|
110
|
+
generate: (req: ImageRequest) => Promise<ImageResult>;
|
|
111
|
+
};
|
|
112
|
+
readonly tools: {
|
|
113
|
+
/** The curated LLMOK tool catalog with TON prices. */
|
|
114
|
+
list: () => Promise<ToolListing[]>;
|
|
115
|
+
/** Runs one tool; debits your wallet only on success. Replays with the same idempotency key are free. */
|
|
116
|
+
call: <Output = any>(id: string, input: unknown, options?: {
|
|
117
|
+
idempotencyKey?: string;
|
|
118
|
+
}) => Promise<ToolResult<Output>>;
|
|
119
|
+
};
|
|
120
|
+
readonly listings: {
|
|
121
|
+
/** Creates or updates an offering (price changes are versioned). */
|
|
122
|
+
put: (name: string, def: ListingInput) => Promise<Listing>;
|
|
123
|
+
list: () => Promise<Listing[]>;
|
|
124
|
+
};
|
|
125
|
+
wallet(): Promise<Wallet>;
|
|
126
|
+
ledger(since?: number, limit?: number): Promise<LedgerPage>;
|
|
127
|
+
transfer(to: string, amount: number, options?: TransferOptions): Promise<{
|
|
128
|
+
entry: unknown;
|
|
129
|
+
}>;
|
|
130
|
+
readonly market: {
|
|
131
|
+
search: (query: string) => Promise<MarketOffering[]>;
|
|
132
|
+
};
|
|
133
|
+
readonly agent: {
|
|
134
|
+
/** Replaces the agent's prompt (`agent.md`) and settings (`settings.json`). */
|
|
135
|
+
config: (config: AgentConfigInput) => Promise<{
|
|
136
|
+
config: unknown;
|
|
137
|
+
limits?: unknown;
|
|
138
|
+
}>;
|
|
139
|
+
/** A message the agent answers on its next wake. */
|
|
140
|
+
steer: (text: string) => Promise<unknown>;
|
|
141
|
+
transcript: (since?: number, limit?: number) => Promise<{
|
|
142
|
+
entries: TranscriptEntry[];
|
|
143
|
+
next_since: number;
|
|
144
|
+
}>;
|
|
145
|
+
state: () => Promise<Record<string, unknown>>;
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
export declare function createVillage(options?: VillageOptions): Village;
|
package/dist/define.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The village keys of `ambasada.config.ts` (docs/PLATFORM.md §5). They only add types and checks; the CLI
|
|
3
|
+
* reads the values (`ambasada deploy`, `ambasada village offerings sync`, `ambasada dev`).
|
|
4
|
+
*
|
|
5
|
+
* export default defineCompany(defineApp({ id, name, product }), { idea, offerings, agent });
|
|
6
|
+
*/
|
|
7
|
+
import type { AppConfig } from "./sdk/platform.js";
|
|
8
|
+
import type { FieldSchema } from "./types.js";
|
|
9
|
+
export interface VillageConfig {
|
|
10
|
+
/** Locked Fri 20:00. */
|
|
11
|
+
idea: {
|
|
12
|
+
title: string;
|
|
13
|
+
category?: string;
|
|
14
|
+
pitch?: string;
|
|
15
|
+
};
|
|
16
|
+
/** Path to the offerings module (default `./product/offerings.ts`). */
|
|
17
|
+
offerings?: string;
|
|
18
|
+
/** Agent folder with agent.md and settings.json (default `./agent`). */
|
|
19
|
+
agent?: {
|
|
20
|
+
dir?: string;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/** An app (`id` is your company id in the village) with the village keys. */
|
|
24
|
+
export interface CompanyConfig extends AppConfig, VillageConfig {
|
|
25
|
+
}
|
|
26
|
+
/** `defineCompany(defineApp({ … }), { idea, offerings, agent })`, or the 0.7 form `defineCompany({ id, name, idea, … })`. */
|
|
27
|
+
export declare function defineCompany(app: AppConfig, village: VillageConfig): CompanyConfig;
|
|
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,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Village errors. Every failure is an `AmbasadaError` (`@ambasada/sdk`) with a code from
|
|
3
|
+
* `@ambasada/protocol`; `VillageError` is the same class under its 0.7 name (kept through 1.x):
|
|
4
|
+
*
|
|
5
|
+
* try { await village.buy("inkwell/poem", input, { maxPrice: 2 }) }
|
|
6
|
+
* catch (e) { if (isVillageError(e, "PRICE_ABOVE_MAX")) … }
|
|
7
|
+
*/
|
|
8
|
+
import { AmbasadaError, isAmbasadaError } from "./sdk/platform.js";
|
|
9
|
+
/** `AmbasadaError` under its 0.7 name. */
|
|
10
|
+
export declare const VillageError: typeof AmbasadaError;
|
|
11
|
+
export type VillageError = AmbasadaError;
|
|
12
|
+
/** `isAmbasadaError` under its 0.7 name. */
|
|
13
|
+
export declare const isVillageError: typeof isAmbasadaError;
|
|
14
|
+
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";
|
|
15
|
+
/** The request is not paid: no receipt, a forged or expired one, or one for another seller / offering / body. */
|
|
16
|
+
export declare class ReceiptInvalidError extends AmbasadaError {
|
|
17
|
+
readonly reason: ReceiptFailure;
|
|
18
|
+
constructor(reason: ReceiptFailure, message: string);
|
|
19
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ambasada/village: the Hack A Ton add-on. Accept and spend TON in the village, on top of the
|
|
3
|
+
* Ambasada platform client (`@ambasada/sdk`).
|
|
4
|
+
*
|
|
5
|
+
* import { village } from "@ambasada/village"; // AMBASADA_API_KEY, AMBASADA_VILLAGE_API_URL from the env
|
|
6
|
+
* const { url } = await village.checkout({ amount: 3, description: "Coffee", success_url });
|
|
7
|
+
* export const POST = village.sell("translate", async ({ text, to }) => ({ text: await village.llm(`Translate to ${to}: ${text}`) }));
|
|
8
|
+
* const user = await village.auth.user(req); // the platform client's methods work too
|
|
9
|
+
*
|
|
10
|
+
* Works in Node ≥ 22, Bun, Cloudflare Workers (`createVillage({ env })`) and Next.js route handlers.
|
|
11
|
+
*/
|
|
12
|
+
import { Village } from "./client.js";
|
|
13
|
+
export { Village, createVillage, DEFAULT_VILLAGE_API_URL, DEFAULT_MODEL } from "./client.js";
|
|
14
|
+
export type { VillageOptions, VerifyReceiptOptions, SellHandler } from "./client.js";
|
|
15
|
+
export { VillageError, isVillageError, ReceiptInvalidError } from "./errors.js";
|
|
16
|
+
export type { ReceiptFailure } from "./errors.js";
|
|
17
|
+
export type * from "./types.js";
|
|
18
|
+
export { verifyWebhookPayload, webhookHeaders, generateWebhookSecret, WEBHOOK_HEADERS } from "./webhook.js";
|
|
19
|
+
export { RECEIPT_HEADER, readIncoming, verifyCallReceipt, verifyCheckoutReceiptToken } from "./receipt.js";
|
|
20
|
+
export type { IncomingRequest } from "./receipt.js";
|
|
21
|
+
export { defineCompany, offering } from "./define.js";
|
|
22
|
+
export type { CompanyConfig, OfferingDef, VillageConfig } from "./define.js";
|
|
23
|
+
export { Ambasada, AmbasadaError, isAmbasadaError, defineApp, ERROR_STATUS, WebhookInvalidError } from "./sdk/platform.js";
|
|
24
|
+
export type { AmbasadaUser, AppConfig, ErrorCode, ErrorDetails, Jwk, StoredFile, StoreList, StoreWrite, WebhookFailure } from "./sdk/platform.js";
|
|
25
|
+
/** The default client, configured from the environment at call time. */
|
|
26
|
+
export declare const village: Village;
|
|
27
|
+
export default village;
|