apiblaze 0.21.44 → 0.21.45

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.
Files changed (2) hide show
  1. package/dist/index.js +25 -125
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ var __toESM = (mod, isNodeMode, target2) => (target2 = mod != null ? __create(__
34
34
  var version;
35
35
  var init_package = __esm({
36
36
  "package.json"() {
37
- version = "0.21.44";
37
+ version = "0.21.45";
38
38
  }
39
39
  });
40
40
 
@@ -8923,7 +8923,7 @@ async function claimJourney(work, checks, env) {
8923
8923
  if (res.claimed) {
8924
8924
  try {
8925
8925
  await admin({ method: "DELETE", path: `/teams/${encodeURIComponent(teamId)}`, summary: "delete the promoted demo team" });
8926
- for (let i = 0; i < 60 && !gone; i++) {
8926
+ for (let i = 0; i < 180 && !gone; i++) {
8927
8927
  try {
8928
8928
  await admin({ method: "GET", path: `/teams/${encodeURIComponent(teamId)}` });
8929
8929
  } catch (e) {
@@ -8931,7 +8931,7 @@ async function claimJourney(work, checks, env) {
8931
8931
  }
8932
8932
  if (!gone) await new Promise((r) => setTimeout(r, 1e3));
8933
8933
  }
8934
- detail = gone ? "cascade done" : "still present after 60 s";
8934
+ detail = gone ? "cascade done" : "still present after 180 s";
8935
8935
  } catch (e) {
8936
8936
  detail = `delete \u2192 ${fail7(e).status} ${fail7(e).error}`;
8937
8937
  }
@@ -9108,13 +9108,26 @@ async function defaultName(openapi, teamId) {
9108
9108
  }
9109
9109
  return randomProxyName();
9110
9110
  }
9111
+ function saltedName(name) {
9112
+ return `${name}${Math.random().toString(36).slice(2, 6)}`;
9113
+ }
9111
9114
  async function chooseName(opts, openapi, teamId, interactive2) {
9112
9115
  if (opts.name !== void 0) {
9113
9116
  const name = normalizeName2(opts.name);
9114
9117
  if (name.length < 3) throw new Error(`${cap(B.thingShort)} name must be at least 3 characters (letters and digits only).`);
9115
9118
  const check = await checkProxyName(name, teamId).catch(() => null);
9116
9119
  if (check && (!check.canUseProjectName || !check.canUseApiVersion)) {
9117
- throw new Error(`${cap(B.thingShort)} name "${name}" is not available${check.message ? ` \u2014 ${check.message}` : ""}.`);
9120
+ if (opts.auto || !interactive2) {
9121
+ for (let attempt = 0; attempt < 4; attempt++) {
9122
+ const candidate = saltedName(name);
9123
+ const again = await checkProxyName(candidate, teamId).catch(() => null);
9124
+ if (!again || again.canUseProjectName && again.canUseApiVersion) {
9125
+ console.log(import_chalk20.default.dim(` "${name}" is taken (names are global) \u2014 using "${candidate}" instead.`));
9126
+ return candidate;
9127
+ }
9128
+ }
9129
+ }
9130
+ throw new Error(`${cap(B.thingShort)} name "${name}" is not available${check.message ? ` \u2014 ${check.message}` : ""}. Omit --name and a free one is chosen for you.`);
9118
9131
  }
9119
9132
  return name;
9120
9133
  }
@@ -9972,7 +9985,6 @@ their own app).
9972
9985
  }
9973
9986
  function shipMarkdown() {
9974
9987
  const legacy = legacySkillMarkdown();
9975
- const at = legacy.indexOf("## Adopt");
9976
9988
  const backendRules = `## What their backend does \u2014 and nothing else
9977
9989
 
9978
9990
  The gateway does sign-in, keys, tenancy and single-record ownership. The backend does only:
@@ -9993,7 +10005,7 @@ No code yet? Write the smallest plain backend that does exactly that, plus its \
9993
10005
  return withLatest(`# Put ${B.product} in front of their app
9994
10006
 
9995
10007
  ${backendRules}${blockedMarkdown()}
9996
- ${at >= 0 ? legacy.slice(at) : legacy}`);
10008
+ ${legacy}`);
9997
10009
  }
9998
10010
  function skillMarkdown() {
9999
10011
  return `${heroMarkdown()}
@@ -10003,121 +10015,7 @@ function legacySkillMarkdown() {
10003
10015
  const P = B.product;
10004
10016
  const cli = B.cli;
10005
10017
  const LIB = "apiblaze";
10006
- const other = BRAND === "mcpblaze" ? "APIblaze" : "MCPblaze";
10007
- const doors = BRAND === "mcpblaze" ? `${P} ships your code to agents (an MCP server); ${other} ships the same code to users (API keys + sign-in).` : `${P} ships your code to users (API keys + sign-in); ${other} ships the same code to agents (an MCP server).`;
10008
- return `---
10009
- name: ${SKILL_NAME}
10010
- description: Use when the user asks what ${P} (or ${cli}) does or can do for them; says yes to a demo or asks to see / try / demo it; wants to ship, share, expose or make an API public; says "serve my backend behind a proxy and MCP"; wants auth, API keys, sign-in, multi-tenant registration, users and groups, rate limits (throttling), quotas or spend caps; wants agents to use the API through an MCP; or says users can reach each other's records or admin functions. Puts the ${P} gateway in front of the API instead of hand-rolling auth and tenancy in the backend.
10011
- ---
10012
-
10013
- # Ship safely with ${P}
10014
-
10015
- One gateway, two doors. ${doors}
10016
- Same rules, one command. Nothing about auth, tenancy or ownership goes into the backend's
10017
- business logic: the gateway sits in front of the code and enforces it.
10018
-
10019
- ## Which mode \u2014 decide this first
10020
-
10021
- - They ask what ${P} does or can do \u2192 **Explain**. Glance at the workspace first (see
10022
- Explain), answer, then offer either the demo or their own app. Run no \`npx ${cli}\`
10023
- command \u2014 the whole answer is in this file.
10024
- - They say yes to the demo, or ask to see / try / demo it \u2192 **Demo app**. It lives in its own
10025
- folder and never touches their code.
10026
- - They say yes to "can I read the code" \u2192 **Adopt**: scan their app, ask only what the scan
10027
- could not find, then ship it through the Ship steps.
10028
- - They have a backend, just wrote one, or ask you to BUILD one and then ship it \u2192 **Ship**.
10029
- No code yet? First write the smallest plain backend that serves the resources they named,
10030
- plus its \`openapi.yaml\`, start it on their port, then continue at Ship \xA71. Do NOT build
10031
- the Demo app for this. The gateway does auth, tenancy and item ownership; the backend does
10032
- only these three things:
10033
- - stamp each new row's \`tenant\` with the \`x-abz-tenant-id\` header and its \`owner\` with
10034
- the \`x-abz-user-id\` header;
10035
- - filter every collection GET to rows whose \`tenant\` AND \`owner\` match those headers (the
10036
- gateway's rules lock single records, never lists \u2014 a list route has no one record to
10037
- check). Both, always: a user id is not unique across tenants ("ana" at one customer and
10038
- "ana" at another are two people);
10039
- - answer 401 to any call whose \`x-target-api-key\` is not \`process.env.TARGET_SERVER_SECRET\`
10040
- (generate it with \`openssl rand -hex 24\`, put it in \`.env.local\`, start the backend with
10041
- it; Ship \xA73b makes the proxy send it). If they say "use
10042
- ${cli} on this" or "ship it with ${cli}" and point at a backend, skip any pitch and run it.
10043
-
10044
- Tie-breaks: a question ("what can it do", "what is it") is always **Explain**, whatever else the
10045
- message names. Mentioning \`npx ${cli} skills\` is NOT a request to run anything \u2014 it is the
10046
- command that installed this file. If a message fits two modes, the earliest bullet wins.
10047
-
10048
- ## Explain
10049
-
10050
- Say this, in these words or close to them, then stop:
10051
-
10052
- "${P} puts a gateway in front of your backend in one command: a proxy (every request passes
10053
- through it first) and an MCP server (the same API, callable by AI agents like Claude). No auth
10054
- or ownership logic goes into your code \u2014 your backend only has to trust one header. Each of
10055
- your customers \u2014 a tenant \u2014 gets their own API key, created from a widget you drop into your
10056
- site. People and agents sign in with hosted GitHub, or your own OAuth app. Each user can only
10057
- touch the records they created; those rules come from your OpenAPI spec (the file listing your
10058
- endpoints), and if you have none I draft one from your routes and show it to you first. One
10059
- more command sets a rate limit, a daily quota and a spend cap. In dev it tunnels to localhost;
10060
- in prod it points at your deploy."
10061
-
10062
- Before answering, look at the workspace \u2014 file names and \`package.json\` only, no reading of
10063
- code yet. It "has an app" if ANY of these is present: an \`openapi.*\` / \`swagger.*\` file; a
10064
- server framework (express, fastify, hono, koa, nest, fastapi, flask, django, rails, gin, chi,
10065
- net/http); or a frontend (next, react, vue, svelte, remix, nuxt) whose \`.env*\` file NAMES an
10066
- API base-URL variable (\`API_URL\`, \`NEXT_PUBLIC_API_URL\`, \`VITE_API_URL\`, or similar) \u2014
10067
- \`grep -l\` the env files, open nothing else. Then end with exactly one of these two lines:
10068
-
10069
- - No app \u2192 **"Would you like me to spin up a demo app?"**
10070
- - An app \u2192 **"I see you have an app already coded. Can I read the code to see how to ready it
10071
- for human and agent traffic with ${P}?"**
10072
-
10073
- ## Demo app \u2014 the same reservation system, before and after
10074
-
10075
- One Next.js app on port 3000. Two routes, same UI, same data: \`/before\` is how most apps
10076
- ship; \`/\` is the same thing behind ${P}. Narrate each step in one line and show every
10077
- \`npx ${cli}\` command \u2014 the commands are the product. Everything goes in \`${cli}-demo/\`.
10078
-
10079
- 1. **Scaffold.** \`npx create-next-app@latest ${cli}-demo\` (TypeScript, App Router). Then
10080
- \`npm i hono ${LIB}\`.
10081
- 2. **The backend.** Hono mounted at \`app/api/[[...route]]/route.ts\` (\`import { handle } from
10082
- 'hono/vercel'\`). Three resources \u2014 restaurants, tables, reservations \u2014 in an in-memory Map,
10083
- every row stamped with \`owner\` = the \`x-abz-user-id\` header (${P} sets it on every call it
10084
- forwards). Every route requires \`X-Api-Secret: demo-secret\` OR an \`x-abz-user-id\` header \u2014
10085
- the first is how /before gets in, the second is how the gateway gets in. Write
10086
- \`openapi.yaml\` at the repo root: every path and method, and the \`id\` each POST returns \u2014
10087
- the ownership rules are read from it.
10088
- 3. **/before.** \`app/before/page.tsx\`: list and create reservations through one server route,
10089
- \`app/before/api/route.ts\`, which holds \`demo-secret\` and calls \`/api/...\` directly. Put the
10090
- caption on the page: "Before \u2014 one shared secret, anyone holding it can do anything."
10091
- 4. **Put ${P} in front.** In the BACKGROUND, and leave it running \u2014 it is the tunnel:
10092
- \`npx ${cli} dev --port 3000 --openapi ./openapi.yaml --name demo --auto\`
10093
- It prints the API URL, the MCP URL, the tenant, and the bootstrap key ONCE. Write them to
10094
- \`.env.local\` as \`APIBLAZE_URL\`, \`APIBLAZE_SERVER_KEY\`, \`APIBLAZE_TENANT\`. \`--auto\` locks
10095
- all three resources to their creator \u2014 say so.
10096
- 5. **Users and groups.** Turn them on and make the group the demo is about:
10097
- \`npx ${cli} iam demo on\`
10098
- \`npx ${cli} group create reservationists --tenant <tenant>\`
10099
- \`npx ${cli} group add-user <the demo user> reservationists --tenant <tenant>\`
10100
- \`npx ${cli} admins add <the user's email> --tenant <tenant>\` (so the widget has an admin).
10101
- Optional, billed per turn: \`npx ${cli} rule demo "only members of reservationists can create
10102
- or change reservations"\`. If the user is logged out or their wallet has nothing available
10103
- (\`npx ${cli} billing balance\`), keep the free creator-lock rules and say so \u2014 do not pretend
10104
- the group rule applied.
10105
- 6. **/.** \`app/page.tsx\`: the same UI, plus a **user picker** (ana \xB7 ben \xB7 admin \u2014 a select, no
10106
- real login; the demo is about authorization, not building sign-in). Its server route calls
10107
- \`process.env.APIBLAZE_URL\` with \`X-API-Key: APIBLAZE_SERVER_KEY\` and \`X-End-User-Id: <the
10108
- picked user>\`. Add the three widgets from \`${LIB}/react\`, each with its server route:
10109
- - \`<ApiKeyWidget />\` + \`app/api/apiblaze/keys/route.ts\` (\`createApiblazeKeys\` from \`${LIB}/server\`)
10110
- - \`<UsersGroupsWidget />\` + \`app/api/apiblaze/groups/route.ts\` (\`createApiblazeGroups\` \u2014
10111
- the keys route with one word changed)
10112
- - \`<ChatWidget />\` + \`app/api/apiblaze/chat/route.ts\` (\`createApiblazeChat\`)
10113
- Exact snippets for the keys and chat pair: \`npx ${cli} integration demo --stack nextjs\`.
10114
- Caption: "After \u2014 a key per tenant, every call names its user, and ${P} decides."
10115
- 7. **Prove it, in the browser.** \`npm run dev\`, open \`http://localhost:3000/before\` then
10116
- \`http://localhost:3000/\`. On \`/\`: create a reservation as ana, switch to ben, try to cancel
10117
- it \u2014 show the 403 in the UI. Open the groups widget: reservationists is there. Ask the chat
10118
- widget to list reservations. Then say what each \`npx ${cli}\` command did, in order.
10119
-
10120
- ## Adopt \u2014 reading their code first
10018
+ return `## Adopt \u2014 reading their code first
10121
10019
 
10122
10020
  They said yes. Scan properly now (routes, env files, auth, network calls), classify, then ask
10123
10021
  ONLY for what the scan could not find \u2014 one short list of questions, not an interview.
@@ -10178,12 +10076,14 @@ ONLY for what the scan could not find \u2014 one short list of questions, not an
10178
10076
  the report. Only ask "where do your users sign in today?" when they mention an existing
10179
10077
  login. Their own OAuth app \u2192 \`--apikey --oauth '{"provider":"auth0","clientId":"\u2026","clientSecret":"\u2026"}'\`
10180
10078
  (both doors: keys for tenants, their login for people and agents). Shapes below.
10181
- 3. **Local code** \u2192 \`npx ${cli} dev --port <port> --openapi ./openapi.yaml --name <name> --auto <door flags>\`,
10079
+ 3. **Local code** \u2192 \`npx ${cli} dev --port <port> --openapi ./openapi.yaml --auto <door flags>\`,
10182
10080
  left running \u2014 it is the tunnel. Start it as its own detached process, never \`cmd &\` inside
10183
10081
  a shell call that ends: \`nohup npx ${cli} dev \u2026 > ${cli}-dev.log 2>&1 < /dev/null &\`, then
10184
- read the log. If it stops, re-run the SAME command: the same \`--name\` reattaches and
10185
- creates nothing. Never pick a new name to get it back \u2014 that is a second proxy. **Deployed code** \u2192
10186
- \`npx ${cli} create --target <url-or-spec> --name <name> --auto <door flags>\`. Both print the
10082
+ read the log. Leave \`--name\` out: names are global, so a free one is chosen and printed
10083
+ (\`--name\` only for a name the user asked for; a taken one is salted). If the tunnel stops,
10084
+ run the \`--project <name>\` line it printed: that reattaches and creates nothing. Never start
10085
+ a new name to get it back \u2014 that is a second proxy. **Deployed code** \u2192
10086
+ \`npx ${cli} create --target <url-or-spec> --auto <door flags>\`. Both print the
10187
10087
  URL, the MCP URL (the "agents:" line) and what is locked. Run by you (no terminal), \`dev\`
10188
10088
  saves the bootstrap key to \`.env.local\` as \`APIBLAZE_SERVER_KEY\` and never prints it;
10189
10089
  \`create\` prints it ONCE \u2014 save it there yourself. Either way say only "saved your key to
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apiblaze",
3
- "version": "0.21.44",
3
+ "version": "0.21.45",
4
4
  "description": "APIblaze CLI — Chat with your APIs, Manage your API keys, users and groups with the APIblaze serverless proxy",
5
5
  "keywords": [
6
6
  "apiblaze",