@ambasada/skills 0.5.0 → 0.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ambasada/skills",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Skills for Claude Code, Cursor and Codex: ambasada-product (build a product that sells in the Hack A Ton Village) and ambasada-payments (TON Checkout, receipts, webhooks).",
5
5
  "type": "module",
6
6
  "files": [
@@ -88,7 +88,7 @@ export async function buy() {
88
88
  ## Deliver: the webhook
89
89
 
90
90
  ```ts
91
- // app/api/webhook/route.ts (`ambasada webhook set https://<slug>.hackaton.ambasada.id/api/webhook`)
91
+ // app/api/webhook/route.ts (`ambasada webhook set https://<slug>.ambasada.dev/api/webhook`)
92
92
  import { ambasada } from "../../../lib/ambasada.ts";
93
93
 
94
94
  export async function POST(req: Request) {
@@ -9,7 +9,7 @@ The Village is the Hack A Ton market. Everything is paid in **TON**: a play curr
9
9
  bank, **not** the TON blockchain. Visitors spend TON from their Ambasada ID wallet; other teams' agents
10
10
  buy from you through the Gateway.
11
11
 
12
- A product is **one website** (one Cloudflare Worker) at `https://<your-slug>.hackaton.ambasada.id`, plus
12
+ A product is **one website** (one Cloudflare Worker) at `https://<your-slug>.ambasada.dev`, plus
13
13
  **your agent**, which runs the shop (prices, suppliers, deals) while you sleep.
14
14
 
15
15
  For payment details (Checkout, receipts, webhooks, `buy`/`need`, LLM and images) use the
@@ -35,6 +35,7 @@ All three have the same `ambasada.config.ts`, `agent/` folder and four endpoints
35
35
  | know where files go, what Next.js features are allowed, where to keep data and secrets | [reference/stack.md](reference/stack.md) |
36
36
  | run it locally, put it online, use their own Cloudflare account | [reference/dev-and-deploy.md](reference/dev-and-deploy.md) |
37
37
  | make it look good and sell (one page, one offer) | [reference/design.md](reference/design.md) |
38
+ | show up in the Ambasada app, send push notifications, sign people in inside the app | [reference/mini-app.md](reference/mini-app.md) |
38
39
  | build in ChatGPT, Lovable, Bolt or v0 and sell from there | [reference/build-elsewhere.md](reference/build-elsewhere.md) |
39
40
  | know if it is ready | [checklists/sellable.md](checklists/sellable.md) |
40
41
 
@@ -43,7 +43,7 @@ running, except the last section.
43
43
 
44
44
  ## Online (after `npx ambasada deploy`)
45
45
 
46
- - [ ] `https://<slug>.hackaton.ambasada.id` loads on a phone.
46
+ - [ ] `https://<slug>.ambasada.dev` loads on a phone.
47
47
  - [ ] `npx ambasada offerings list`: every endpoint starts with your public URL, none with `localhost`.
48
48
  - [ ] `npx ambasada webhook test` prints `delivered`.
49
49
  - [ ] One real payment by someone outside your team (members can't buy from their own company) shows up
@@ -24,7 +24,7 @@ Try a sale:
24
24
  `AMBASADA_API_URL=http://127.0.0.1:8788`, `AMBASADA_API_KEY=sk_test_dev` (already in the project's `.env`).
25
25
  More on the mock: the ambasada-payments skill, `reference/test-mode.md`.
26
26
 
27
- ## `ambasada deploy`: online at `<slug>.hackaton.ambasada.id`
27
+ ## `ambasada deploy`: online at `<slug>.ambasada.dev`
28
28
 
29
29
  Once, per laptop:
30
30
 
@@ -45,7 +45,7 @@ It does, in order:
45
45
  1. **build**: `opennextjs-cloudflare build` (Next), `vite build` (spa) or a bundle of the Worker (worker);
46
46
  2. **smoke test**: runs the built Worker locally in workerd and requests `/` and `/api/receipt`;
47
47
  a crash stops the deploy (skip with `--no-smoke` only if you know why it fails);
48
- 3. **upload** to the Village's hosting: the URL is `https://<your-company-slug>.hackaton.ambasada.id`,
48
+ 3. **upload** to the Village's hosting: the URL is `https://<your-company-slug>.ambasada.dev`,
49
49
  with `AMBASADA_API_KEY`, `AMBASADA_API_URL` and `AMBASADA_COMPANY` set for you;
50
50
  4. **agent and offerings**: pushes `agent/agent.md` + `agent/settings.json`, and lists your offerings at the new URL.
51
51
 
@@ -55,13 +55,29 @@ offerings list), `--dry-run` (print what it would push).
55
55
  After the first deploy, point the webhook at it and deploy again so the Worker gets the secret:
56
56
 
57
57
  ```sh
58
- npx ambasada webhook set https://<slug>.hackaton.ambasada.id/api/webhook
58
+ npx ambasada webhook set https://<slug>.ambasada.dev/api/webhook
59
59
  npx ambasada webhook test # should print "delivered"
60
60
  ```
61
61
 
62
62
  Limits on Village hosting: 10 MB compressed bundle, 1000 static files, short CPU time per request
63
63
  (waiting on `fetch` or the LLM does not count). Heavy work belongs in an API you call, not in the Worker.
64
64
 
65
+ ## `ambasada dev --tunnel`: your laptop, live in the Village
66
+
67
+ When real buyers, Checkout, webhooks or other teams' agents need to reach the version on your laptop
68
+ (before deploying, or to debug a sale), log in once, then:
69
+
70
+ ```sh
71
+ npx ambasada dev --tunnel # your dev server, against the real Village, at https://<slug>-dev.ambasada.dev
72
+ npx ambasada tunnel --port 5173 # or: only the tunnel, for a server you started yourself
73
+ ```
74
+
75
+ Until Ctrl+C, `https://<slug>-dev.ambasada.dev` is your product URL. Offerings and the webhook point
76
+ there, and the Shop tab shows "Live from your laptop". On Ctrl+C everything goes back to where it was.
77
+ There is no mock in this mode, so payments are real TON. The first time takes up to 2 minutes while
78
+ the address is published; after that it is instant. Use `--no-register` to share the URL without
79
+ moving offerings. Only one terminal per company at a time: `--force` takes it over. More: docs/TUNNEL.md.
80
+
65
81
  ## `ambasada deploy --own`: your own Cloudflare account
66
82
 
67
83
  Runs `wrangler deploy` into your account (you need `npx wrangler login` first), then
@@ -0,0 +1,75 @@
1
+ # The product inside the Ambasada app (mini app)
2
+
3
+ Every product on `https://<slug>.ambasada.dev` is also a **mini app**: it can open inside the Ambasada
4
+ mobile app, sign people in without a consent screen and send them push notifications. The template does
5
+ the wiring; this page says what is there and how to use it. Platform spec: docs/MINI-APPS.md in the repo.
6
+
7
+ ## Is it listed?
8
+
9
+ `ambasada deploy` registers the product with the Ambasada hub and checks it. It prints one line:
10
+
11
+ ```
12
+ ✓ in the Ambasada app: Listed for the event
13
+ ! in the Ambasada app: Unlisted · needs: icon, viewport
14
+ ```
15
+
16
+ Unlisted products work, but only the team sees them in the app. Fix what `needs` says and deploy again,
17
+ or run `npx ambasada check https://<slug>.ambasada.dev` (or `npx ambasada check` for the local folder).
18
+ The checks: `/.well-known/ambasada.json` valid, `icon.png` a 1024×1024 PNG with no transparency, the page
19
+ has `<meta name="viewport" content="width=device-width, initial-scale=1">`, no dark-only theme, the
20
+ first page answers in under 3 s, `/api/auth/callback` exists, the notifications webhook answers a signed ping.
21
+ Connected tools can do the same through MCP: `app_status`, `app_check`.
22
+
23
+ ## Look like the app: @ambasada/ui
24
+
25
+ The templates import `@ambasada/ui` (tokens, Inter + JetBrains Mono, `ui-card`, `ui-button`, `ui-row`,
26
+ `ui-pill`, `ui-sheet`, `ui-stepper`, `ui-empty`, `ui-skeleton`). Use those classes before writing CSS.
27
+ React: `import { Card, Button, Sheet } from "@ambasada/ui/react"`. Plain HTML: one
28
+ `<link rel="stylesheet" href="https://unpkg.com/@ambasada/ui@0.5/dist/ambasada-ui.css">`.
29
+ Leave space for the app's bar: the page uses `--ambasada-safe-area-*` and `--ambasada-host-bar`.
30
+ Light theme only; one red (primary) button per screen.
31
+
32
+ ## Notifications
33
+
34
+ Already wired in every template:
35
+
36
+ | Piece | Where |
37
+ |---|---|
38
+ | manifest: `"scopes": ["identity", "notifications"]`, `"notifications": { "webhook": "/api/ambasada/webhook" }`, `"privacy_url": "/privacy"` | `public/.well-known/ambasada.json` (`web/` in the worker template) |
39
+ | the webhook: verifies the hub's signature, saves `token ↔ Ambasada user id` in `ambasada.store` | `app/api/ambasada/webhook/route.ts` (Next), `api/ambasada-webhook.ts` (spa, worker) |
40
+ | `notifyUser(village, userId, { … })`: push to one person if they turned notifications on | `lib/notifications.ts` |
41
+ | the privacy page the scopes need | `app/privacy/page.tsx`, `public/privacy.html`, `web/privacy.html` |
42
+
43
+ Send one when something the person waits for happens (their order is ready), never as marketing:
44
+
45
+ ```ts
46
+ import { notifyUser } from "../lib/notifications.ts";
47
+
48
+ const user = await ambasada().auth.user(req); // signed in with Ambasada
49
+ if (user) await notifyUser(ambasada(), user.id, {
50
+ notification_id: `order-${id}-ready`, // unique per message; repeats are dropped for 24 h
51
+ title: "Your translation is ready", // ≤ 40 characters
52
+ body: "Tap to read it.", // ≤ 140
53
+ url: `/orders/${id}`, // a path on your site: where the tap opens
54
+ });
55
+ ```
56
+
57
+ People turn notifications on in the app (the app asks; the page can ask too with
58
+ `notifications.request()` from `@ambasada/miniapp`, from a button). The secret (`AMBASADA_APP_SECRET`) is
59
+ injected by `ambasada deploy`; never put it in the browser.
60
+
61
+ ## Signed in without a consent screen
62
+
63
+ Inside the Ambasada app the page signs in silently: `auth.signIn()` from `@ambasada/miniapp` gets a short
64
+ token from the app and POSTs it to `/api/auth/shell`, which sets the same session as "Sign in with
65
+ Ambasada". Server code doesn't change: `currentUser()` / `ambasada().auth.user(req)` work either way.
66
+ On the web, the button and consent screen stay. Silent sign-in needs the app to be Verified; until then
67
+ `signIn()` resolves `null` and the button shows.
68
+
69
+ ## Try it locally
70
+
71
+ `npx ambasada dev` plays the hub: when your product starts it sends a signed `ping` and
72
+ `notifications_enabled` to your webhook (the token lands in the store as
73
+ `ambasada/notifications/user_fake_visitor`), and its `/api/apps/notify` accepts pushes for that token
74
+ (they show in the terminal). Open `http://localhost:3000/?ambasada_shell=mock` to pretend to be inside the
75
+ app: the fake shell signs you in silently as "Fake Visitor".
@@ -14,9 +14,13 @@ my-shop/
14
14
  app/api/webhook/route.ts checkout.paid arrives here, signed: deliver here
15
15
  app/api/receipt/route.ts verifies a pay.js receipt from the browser
16
16
  app/api/translate/route.ts the paid offering: agents call it with a receipt
17
- app/api/auth/*/route.ts Sign in with Ambasada: login, callback, logout, me
17
+ app/api/auth/*/route.ts Sign in with Ambasada: login, callback, logout, me, shell (silent, in the app)
18
+ app/api/ambasada/webhook/ the Ambasada app's events: who turned notifications on (reference/mini-app.md)
18
19
  app/account.tsx the header: "Sign in with Ambasada", or the person's name and avatar
20
+ app/miniapp.tsx inside the Ambasada app: ready() and silent sign-in
21
+ app/privacy/page.tsx what you keep about people (the manifest's privacy_url)
19
22
  lib/ambasada.ts the Village client for server code (reads the Worker env)
23
+ lib/notifications.ts notifyUser(): a push to one person who turned notifications on
20
24
  offerings.ts what agents can buy: name, price, endpoint, input and output
21
25
  agent/agent.md your agent's instructions, in plain English
22
26
  agent/settings.json its model, how often it wakes, spending limits
@@ -112,8 +116,9 @@ File URLs are public: don't put private data in them.
112
116
 
113
117
  - Local: `.env` in the project (Cloudflare's `.dev.vars` works too). The template writes it with test
114
118
  values for `ambasada dev`. Both are in `.gitignore`; keep them there.
115
- - Deployed: `ambasada deploy` injects `AMBASADA_API_KEY`, `AMBASADA_API_URL`, `AMBASADA_COMPANY` and the
116
- Sign in with Ambasada credentials (`AMBASADA_AUTH_*`) for you.
119
+ - Deployed: `ambasada deploy` injects `AMBASADA_API_KEY`, `AMBASADA_API_URL`, `AMBASADA_COMPANY`, the
120
+ Sign in with Ambasada credentials (`AMBASADA_AUTH_*`) and the mini-app secret (`AMBASADA_APP_SECRET`,
121
+ with `AMBASADA_HUB_URL` and `AMBASADA_APP_ORIGIN`) for you.
117
122
  With `--own`, set them yourself: `npx wrangler secret put AMBASADA_API_KEY`.
118
123
  - Other services' keys (an OpenAI key, say): same place, read on the server only.
119
124
  - Anything named `NEXT_PUBLIC_*` is copied into the browser. Never put a key there.