@ambasada/skills 0.5.0 → 0.6.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.
|
|
3
|
+
"version": "0.6.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": [
|
|
@@ -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
|
|
|
@@ -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
|
|
116
|
-
Sign in with Ambasada credentials (`AMBASADA_AUTH_*`)
|
|
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.
|