@ambasada/village 0.8.4 → 0.8.5

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/dist/client.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Ambasada, type AmbasadaOptions } from "@ambasada/sdk/platform";
2
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, ChatLine, ChatProposal, ChatTurn, TransferOptions, Wallet, WebhookDelivery, WebhookEvent } from "./types.js";
3
+ import type { AgentConfigInput, BuyOptions, BuyResult, ChatRequest, ChatResponse, CheckoutInput, CheckoutReceiptClaims, CheckoutDelivery, CheckoutDeliveryInput, CheckoutSession, ImageRequest, ImageResult, LedgerPage, Listing, ListingInput, MarketOffering, PaidCall, PaymentLink, PaymentLinkInput, ToolListing, ToolResult, TranscriptEntry, ChatLine, ChatProposal, ChatTurn, TransferOptions, Wallet, WebhookDelivery, WebhookEvent } from "./types.js";
4
4
  /** The Hack A Ton API. The platform API (`@ambasada/sdk`) is https://api.ambasada.dev. */
5
5
  export declare const DEFAULT_VILLAGE_API_URL = "https://hackaton.ambasada.id";
6
6
  export declare const DEFAULT_MODEL = "deepseek-v4.1-flash";
@@ -63,6 +63,20 @@ export declare class Village extends Ambasada {
63
63
  idempotencyKey?: string;
64
64
  }): Promise<CheckoutSession>;
65
65
  getCheckout(id: string): Promise<CheckoutSession>;
66
+ /** Your latest Checkout sessions (newest first, default 20, at most 100), each with what you said you delivered. */
67
+ listCheckouts(options?: {
68
+ limit?: number;
69
+ status?: "open" | "paid" | "expired";
70
+ }): Promise<{
71
+ sessions: (CheckoutSession & {
72
+ delivery: Omit<CheckoutDelivery, "session"> | null;
73
+ })[];
74
+ }>;
75
+ /**
76
+ * Tells the village what a paid checkout delivered (`text` ≤ 4000 chars, an https `url`, or both): the person sees it
77
+ * with the purchase in their app and can rate it. Again for the same session replaces it. CONFLICT before it is paid.
78
+ */
79
+ deliverCheckout(id: string, delivery: CheckoutDeliveryInput): Promise<CheckoutDelivery>;
66
80
  /** A reusable payment link for static pages (`<button data-village-pay="pl_…">` with pay.js). */
67
81
  createPaymentLink(link: PaymentLinkInput): Promise<PaymentLink>;
68
82
  /** Cancels an open session (`POST /v1/checkout/sessions/:id/expire`). */
package/dist/define.d.ts CHANGED
@@ -38,6 +38,7 @@ export interface OfferingDef {
38
38
  output?: FieldSchema;
39
39
  /** Allow a free sample (`market.preview`). */
40
40
  preview?: boolean;
41
+ /** How long the Gateway waits for your answer, ms: 100–30000 (default 30000, the most). Longer work: answer fast, finish later. */
41
42
  timeout_ms?: number;
42
43
  status?: "open" | "paused";
43
44
  }
package/dist/index.js CHANGED
@@ -37,6 +37,7 @@ __export(src_exports, {
37
37
  HEADERS: () => HEADERS,
38
38
  HOSTED_MANIFEST: () => HOSTED_MANIFEST,
39
39
  ICON_SIZE: () => ICON_SIZE,
40
+ MANIFEST_AGE_RATINGS: () => MANIFEST_AGE_RATINGS,
40
41
  MANIFEST_CATEGORIES: () => MANIFEST_CATEGORIES,
41
42
  MANIFEST_ID: () => MANIFEST_ID,
42
43
  MANIFEST_KINDS: () => MANIFEST_KINDS,
@@ -49,6 +50,7 @@ __export(src_exports, {
49
50
  MIN_PRICE_NANO: () => MIN_PRICE_NANO,
50
51
  NANO_PER_TON: () => NANO_PER_TON,
51
52
  NOTIFY_LIMITS: () => NOTIFY_LIMITS,
53
+ OFFERING_TIMEOUT_MS: () => OFFERING_TIMEOUT_MS,
52
54
  RECEIPT_HEADER: () => RECEIPT_HEADER,
53
55
  ReceiptError: () => ReceiptError,
54
56
  SHELL_TOKEN_TTL_S: () => SHELL_TOKEN_TTL_S,
@@ -82,6 +84,7 @@ __export(src_exports, {
82
84
  leafHash: () => leafHash,
83
85
  listingLine: () => listingLine,
84
86
  nodeHash: () => nodeHash,
87
+ offeringTimeoutProblem: () => offeringTimeoutProblem,
85
88
  parseCheckpoint: () => parseCheckpoint,
86
89
  parseVerifierKey: () => parseVerifierKey,
87
90
  pngInfo: () => pngInfo,
@@ -1143,6 +1146,7 @@ var MANIFEST_SCHEMA = 2;
1143
1146
  var MANIFEST_KINDS = ["product", "event", "tool", "assistant"];
1144
1147
  var MANIFEST_CATEGORIES = ["shopping", "food", "events", "tools", "learning", "community", "games", "finance", "other"];
1145
1148
  var MANIFEST_VISIBILITY = ["public", "builders", "unlisted"];
1149
+ var MANIFEST_AGE_RATINGS = ["4+", "9+", "12+", "17+"];
1146
1150
  var MANIFEST_LIMITS = { id: 32, name: 32, subtitle: 40, description: 170, tags: 5, screenshots: 3 };
1147
1151
  var MANIFEST_ID = /^[a-z0-9-]{3,32}$/;
1148
1152
  var HOSTED_MANIFEST = /^https:\/\/hub\.ambasada\.id\/api\/apps\/([a-z0-9-]+)\/manifest$/;
@@ -1203,6 +1207,15 @@ function validateManifest(json) {
1203
1207
  const color = splash?.color;
1204
1208
  if (!splash || color !== void 0 && (typeof color !== "string" || !HEX_COLOR.test(color))) problem("splash_color", `"splash.color" must be a #RRGGBB colour (got ${JSON.stringify(color ?? m.splash)})`);
1205
1209
  }
1210
+ const age = str("age_rating");
1211
+ if (m.age_rating === void 0) {
1212
+ if (m.schema === MANIFEST_SCHEMA) problem("age_rating", `"age_rating" is required: one of ${MANIFEST_AGE_RATINGS.join(", ")} (the hub refuses to register an app without it)`);
1213
+ } else if (!age || !MANIFEST_AGE_RATINGS.includes(age)) {
1214
+ problem("age_rating", `"age_rating" must be one of ${MANIFEST_AGE_RATINGS.join(", ")} (got ${JSON.stringify(m.age_rating)})`);
1215
+ }
1216
+ if (m.support !== void 0 && (typeof m.support !== "string" || !/^(mailto:[^@\s]+@[^@\s]+|https:\/\/\S+)$/.test(m.support))) {
1217
+ problem("support", `"support" must be a mailto: address or an https URL (got ${JSON.stringify(m.support)})`);
1218
+ }
1206
1219
  const kind = str("kind");
1207
1220
  if (m.kind !== void 0 && (!kind || !MANIFEST_KINDS.includes(kind))) warn("kind", `unknown "kind" ${JSON.stringify(m.kind)}: the app knows ${MANIFEST_KINDS.join(", ")} and shows this one as a product`);
1208
1221
  const category = str("category");
@@ -1464,6 +1477,12 @@ var HEADERS = {
1464
1477
  idempotentReplay: "idempotent-replayed"
1465
1478
  };
1466
1479
  var MAX_DEPTH = 4;
1480
+ var OFFERING_TIMEOUT_MS = { min: 100, max: 3e4 };
1481
+ function offeringTimeoutProblem(value) {
1482
+ if (value === void 0) return null;
1483
+ const n = Number(value);
1484
+ return Number.isInteger(n) && n >= OFFERING_TIMEOUT_MS.min && n <= OFFERING_TIMEOUT_MS.max ? null : `timeout_ms must be between ${OFFERING_TIMEOUT_MS.min} and ${OFFERING_TIMEOUT_MS.max} (got ${JSON.stringify(value)})`;
1485
+ }
1467
1486
 
1468
1487
  // src/receipt.ts
1469
1488
  import { AmbasadaError as AmbasadaError2, getHeader } from "@ambasada/sdk/platform";
@@ -1700,6 +1719,20 @@ var Village = class extends Ambasada {
1700
1719
  getCheckout(id) {
1701
1720
  return this.call("GET", `/v1/checkout/sessions/${encodeURIComponent(id)}`);
1702
1721
  }
1722
+ /** Your latest Checkout sessions (newest first, default 20, at most 100), each with what you said you delivered. */
1723
+ listCheckouts(options = {}) {
1724
+ const q = new URLSearchParams();
1725
+ if (options.limit !== void 0) q.set("limit", String(options.limit));
1726
+ if (options.status) q.set("status", options.status);
1727
+ return this.call("GET", `/v1/checkout/sessions${q.size ? `?${q}` : ""}`);
1728
+ }
1729
+ /**
1730
+ * Tells the village what a paid checkout delivered (`text` ≤ 4000 chars, an https `url`, or both): the person sees it
1731
+ * with the purchase in their app and can rate it. Again for the same session replaces it. CONFLICT before it is paid.
1732
+ */
1733
+ deliverCheckout(id, delivery) {
1734
+ return this.call("POST", `/v1/checkout/sessions/${encodeURIComponent(id)}/delivery`, { body: delivery });
1735
+ }
1703
1736
  /** A reusable payment link for static pages (`<button data-village-pay="pl_…">` with pay.js). */
1704
1737
  createPaymentLink(link) {
1705
1738
  return this.call("POST", "/v1/checkout/links", { body: link });
@@ -1873,6 +1906,8 @@ function defineCompany(app, village2) {
1873
1906
  function offering(def) {
1874
1907
  if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(def.name)) throw new Error(`offering name "${def.name}" must be a slug (a-z, 0-9, _, -)`);
1875
1908
  if (!(def.price >= 0.1 && def.price <= 500)) throw new Error(`offering ${def.name}: price must be between 0.1 and 500 TON`);
1909
+ const timeout = offeringTimeoutProblem(def.timeout_ms);
1910
+ if (timeout) throw new Error(`offering ${def.name}: ${timeout}`);
1876
1911
  return def;
1877
1912
  }
1878
1913
 
package/dist/types.d.ts CHANGED
@@ -55,6 +55,17 @@ export interface CheckoutInput {
55
55
  /** Seconds, 300–86400 (default 3600). */
56
56
  expires_in?: number;
57
57
  }
58
+ /** What a paid checkout delivered (`POST /v1/checkout/sessions/:id/delivery`): text, an https URL, or both. */
59
+ export interface CheckoutDeliveryInput {
60
+ text?: string;
61
+ url?: string;
62
+ }
63
+ export interface CheckoutDelivery {
64
+ session: string;
65
+ text: string | null;
66
+ url: string | null;
67
+ at: string;
68
+ }
58
69
  export interface CheckoutSession {
59
70
  id: string;
60
71
  object: "checkout.session";
@@ -142,7 +153,8 @@ export interface BuyResult<Output = any> {
142
153
  /** For `need()`: which offering served it (`company/name`), if the Gateway says. */
143
154
  offering: string | null;
144
155
  }
145
- export type ChatModel = "deepseek-v4.1-flash" | "deepseek-v4-pro" | "glm-5.3-flash" | (string & {});
156
+ /** What the village sells (apps/api/config/pricing.json); any other model is refused. */
157
+ export type ChatModel = "deepseek-v4.1-flash" | (string & {});
146
158
  export interface ChatMessage {
147
159
  role: "system" | "user" | "assistant" | "tool";
148
160
  content: string;
@@ -258,7 +270,7 @@ export interface TransferOptions {
258
270
  }
259
271
  /** `agent/settings.json`, sent with the prompt to `POST /v1/agent/config` (agent stream wire format). */
260
272
  export interface AgentSettings {
261
- model?: "deepseek-v4.1-flash" | "deepseek-v4-pro";
273
+ model?: "deepseek-v4.1-flash";
262
274
  enabled?: boolean;
263
275
  wake?: {
264
276
  interval_minutes?: number;
@@ -272,7 +284,12 @@ export interface AgentSettings {
272
284
  };
273
285
  /** Agent tools offered to the model (default: all). */
274
286
  tools?: string[];
275
- /** Company wallet spend limits, TON. Over `auto_per_payment` an agent payment needs the team's approval. */
287
+ /**
288
+ * The whole company's spend limits, TON: the product's own LLM and image calls count too, not only the agent's
289
+ * purchases. Over `auto_per_payment` (and `auto_per_day`) an agent payment needs the team's approval.
290
+ */
291
+ company_limits?: AgentSettings["limits"];
292
+ /** @deprecated The 0.8 name of `company_limits` (they were always the company's, not only the agent's). */
276
293
  limits?: {
277
294
  per_payment?: number;
278
295
  per_hour?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ambasada/village",
3
- "version": "0.8.4",
3
+ "version": "0.8.5",
4
4
  "description": "The Hack A Ton add-on for Ambasada apps: TON checkout, receipts, offerings, LLM, the agent, the market; CLI commands and the local bank.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -27,7 +27,7 @@
27
27
  "node": ">=22"
28
28
  },
29
29
  "dependencies": {
30
- "@ambasada/sdk": "^0.8.4"
30
+ "@ambasada/sdk": "^0.8.5"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^22.20.5",
@@ -35,7 +35,7 @@
35
35
  "typescript": "~5.9.3",
36
36
  "vitest": "^4.1.12",
37
37
  "@ambasada/protocol": "0.1.0",
38
- "@ambasada/cli": "0.8.4"
38
+ "@ambasada/cli": "0.8.5"
39
39
  },
40
40
  "author": "CENTYSO (https://centyso.com)",
41
41
  "homepage": "https://ambasada.id",