@pikku/skills 0.12.63 → 0.12.66
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/skills.gen.js +1 -1
- package/package.json +1 -1
- package/skills/pikku-addon/SKILL.md +19 -7
- package/skills/pikku-addon/references/openapi.md +20 -3
- package/skills/pikku-concepts/references/concept-mapping.md +1 -1
- package/skills/pikku-meta/references/versioning.md +4 -4
- package/skills/pikku-middleware/SKILL.md +2 -2
- package/skills/pikku-react/references/client.md +18 -0
- package/skills/pikku-wiring/references/channel.md +1 -1
- package/skills/pikku-wiring/references/http.md +2 -2
package/package.json
CHANGED
|
@@ -200,7 +200,10 @@ npx pikku new addon stripe --display-name Stripe --category Payments --dir addon
|
|
|
200
200
|
```
|
|
201
201
|
|
|
202
202
|
**Handed an OpenAPI or Swagger spec?** Don't hand-write the functions —
|
|
203
|
-
`pikku new addon <name> --openapi <spec>` generates one function per operation
|
|
203
|
+
`pikku new addon <name> --openapi <spec>` generates one function per operation
|
|
204
|
+
(`<spec>` is a path, a URL, or a registry catalogue name such as
|
|
205
|
+
`amazonaws.com:applicationcostprofiler`; inside an app,
|
|
206
|
+
`pikku addons add <catalogue-name>` does the same and picks `--auth` for you),
|
|
204
207
|
with its schemas, service and credential. Read `references/openapi.md`.
|
|
205
208
|
|
|
206
209
|
This generates `package.json` (exports `.pikku/*` + `dist/`), `pikku.config.json` (`addon: true`), `tsconfig.json` (`#pikku` path mapping), `src/services.ts`, `src/functions/`, and `types/application-types.d.ts`. For the full file contents/exports you rarely hand-edit, read `references/addon-package-manifest.md`.
|
|
@@ -421,18 +424,27 @@ export default definePlugin({
|
|
|
421
424
|
addons only; Studio enforces that). `layout: 'bare'` renders without the shell.
|
|
422
425
|
- Titles are message keys in the addon's `messages/{locale}.json`, found by
|
|
423
426
|
convention next to its `package.json`; there is no field for them.
|
|
427
|
+
- `agent: 'name'` makes that agent answer in Studio's chat panel (a second tab
|
|
428
|
+
beside the general chat) while the screen is open. It resolves to
|
|
429
|
+
`agents/<name>.md` at the addon's package root: the agent's instructions,
|
|
430
|
+
which name the skills it follows (plain folders `skills/<name>/SKILL.md`).
|
|
431
|
+
`agent: 'studio:<name>'` instead picks an agent Studio ships; `pikku all` only
|
|
432
|
+
checks the format and looks up no file.
|
|
433
|
+
The file starts with frontmatter whose `title` and `description` are message
|
|
434
|
+
keys in `messages/en.json`. The name matches `/^[a-z][a-z0-9-]*$/`.
|
|
424
435
|
- `scopes` only hide the screen. The addon's functions must enforce the same
|
|
425
436
|
scopes.
|
|
426
437
|
|
|
427
438
|
The inspector reads every field statically, so each must be a literal.
|
|
428
439
|
`pikku all` fails on:
|
|
429
440
|
|
|
430
|
-
| Code | When
|
|
431
|
-
| ------ |
|
|
432
|
-
| PKU345 | a field is not a literal (variable, call, spread, bad value)
|
|
433
|
-
| PKU357 | two screens of the addon use the same path
|
|
434
|
-
| PKU358 | a title key is missing from `messages/en.json`
|
|
435
|
-
| PKU359 | `nav.badge` names no function of the addon
|
|
441
|
+
| Code | When |
|
|
442
|
+
| ------ | ---------------------------------------------------------------------------------------------------- |
|
|
443
|
+
| PKU345 | a field is not a literal (variable, call, spread, bad value) |
|
|
444
|
+
| PKU357 | two screens of the addon use the same path |
|
|
445
|
+
| PKU358 | a title or agent frontmatter key is missing from `messages/en.json` |
|
|
446
|
+
| PKU359 | `nav.badge` names no function of the addon |
|
|
447
|
+
| PKU365 | `agent` is neither a name nor `studio:<name>`, or a name has no non-empty `agents/<name>.md`, or no frontmatter `title` and `description` |
|
|
436
448
|
|
|
437
449
|
A key missing from another locale's catalog is a warning.
|
|
438
450
|
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
- 6 — Check the spec against the real API
|
|
12
12
|
- Then
|
|
13
13
|
|
|
14
|
-
When you are handed an OpenAPI or Swagger spec — a file,
|
|
14
|
+
When you are handed an OpenAPI or Swagger spec — a file, a URL to one, or the
|
|
15
|
+
name of one in the registry's catalogue (`https://www.pikku.dev/openapis`) — the
|
|
15
16
|
API it describes becomes an addon: one function per operation, each with its
|
|
16
17
|
input and output schemas, behind one service that makes the HTTP calls. Say so
|
|
17
18
|
before starting ("This is an OpenAPI spec — I'll turn it into an addon first"),
|
|
@@ -26,7 +27,23 @@ A JSON or YAML document with a top-level `openapi` key (3.x) or `swagger` key
|
|
|
26
27
|
|
|
27
28
|
## 1 — Look at the spec first
|
|
28
29
|
|
|
29
|
-
`--openapi` takes a path
|
|
30
|
+
`--openapi` takes a path, a URL, or a catalogue name such as
|
|
31
|
+
`amazonaws.com:applicationcostprofiler`. A name is anything that is neither a
|
|
32
|
+
URL, a path, nor a `.json`/`.yaml` file; it is looked up in the registry
|
|
33
|
+
(`--registry`, else `pikku.config.json`'s `registry`, else
|
|
34
|
+
`https://api.pikkustudio.app`) and generated from the entry's spec URL. A name
|
|
35
|
+
the registry does not know is refused before anything is written. On the
|
|
36
|
+
website the page URL is a slug (`amazonaws-com-applicationcostprofiler`); the
|
|
37
|
+
name to pass is the one the page's command shows, with its `.` and `:`.
|
|
38
|
+
|
|
39
|
+
For a catalogue entry inside an app, the short form is
|
|
40
|
+
`pikku addons add amazonaws.com:applicationcostprofiler`. It names the addon
|
|
41
|
+
after the entry (`amazonaws-applicationcostprofiler`) and takes `--auth` from
|
|
42
|
+
what the registry records: `none` for a public API, `user` for OAuth or a key
|
|
43
|
+
each user brings, `shared` for a key the app holds, and `user` when the registry
|
|
44
|
+
does not know. It prints the mode it picked; pass `--auth` to override it.
|
|
45
|
+
|
|
46
|
+
A spec published only to signed-in callers
|
|
30
47
|
takes the key the way the API reads it: `--openapi-header "NAME: value"`
|
|
31
48
|
(repeatable), or in the URL's query string when the API reads it there
|
|
32
49
|
(Dolibarr's explorer takes `?DOLAPIKEY=`). A 401 while fetching says which.
|
|
@@ -40,7 +57,7 @@ Keep a copy in `specs/` as the record of what the addon was generated from.
|
|
|
40
57
|
## 2 — Generate, from the app's root
|
|
41
58
|
|
|
42
59
|
```bash
|
|
43
|
-
bunx --bun pikku new addon <name> --openapi <path-or-
|
|
60
|
+
bunx --bun pikku new addon <name> --openapi <path-url-or-catalogue-name>
|
|
44
61
|
```
|
|
45
62
|
|
|
46
63
|
One command. Inside an app it writes `packages/addon-<name>` as
|
|
@@ -197,7 +197,7 @@ function authMiddleware(req, res, next) {
|
|
|
197
197
|
**Pikku:**
|
|
198
198
|
|
|
199
199
|
```typescript
|
|
200
|
-
import { authBearer } from '
|
|
200
|
+
import { authBearer } from '#pikku/middleware'
|
|
201
201
|
|
|
202
202
|
// One line - handles token extraction, JWT verification, session population
|
|
203
203
|
addHTTPMiddleware('*', [authBearer({})])
|
|
@@ -137,11 +137,11 @@ the manifest alone. Fix the contract or bump the version, then run it again.
|
|
|
137
137
|
`check` is a within-repo gate — "you changed a contract without bumping
|
|
138
138
|
`version:`". `release` is a release question — "what does this build owe the
|
|
139
139
|
clients of the last release, and how do we ship it?". The baseline is
|
|
140
|
-
`surface.
|
|
140
|
+
`pikku.surface.json`, the snapshot committed by the previous release.
|
|
141
141
|
|
|
142
142
|
```bash
|
|
143
143
|
npx pikku release init # first run: snapshot + CHANGELOG.md
|
|
144
|
-
npx pikku release diff # vs surface.
|
|
144
|
+
npx pikku release diff # vs pikku.surface.json
|
|
145
145
|
npx pikku release diff --against https://api.acme.com/surface.json # vs any baseline
|
|
146
146
|
npx pikku release diff --fail-on major # PR gate
|
|
147
147
|
npx pikku release snapshot --out surface.json # write a snapshot
|
|
@@ -162,7 +162,7 @@ writes it; it never commits, tags or pushes. Who does that is your call — you
|
|
|
162
162
|
with plain git, or a platform with its own credentials.
|
|
163
163
|
|
|
164
164
|
`prepare` runs on a checkout of `origin/staging` after `pikku all`. It diffs the
|
|
165
|
-
surface against `surface.
|
|
165
|
+
surface against `pikku.surface.json`, reads the commits production does not have
|
|
166
166
|
yet, bumps `package.json`, prepends a `CHANGELOG.md` section and rewrites the
|
|
167
167
|
snapshot. No commits since the last release means nothing to release. It
|
|
168
168
|
refuses when `main` has commits `staging` lacks (merge `main` into `staging`
|
|
@@ -174,7 +174,7 @@ Shipping is then one commit on top of that trunk sha:
|
|
|
174
174
|
|
|
175
175
|
```bash
|
|
176
176
|
npx pikku release prepare
|
|
177
|
-
git add package.json CHANGELOG.md surface.
|
|
177
|
+
git add package.json CHANGELOG.md pikku.surface.json
|
|
178
178
|
git commit -m "release: v0.4.0"
|
|
179
179
|
git tag v0.4.0
|
|
180
180
|
git push --atomic origin HEAD:staging HEAD:main v0.4.0
|
|
@@ -82,7 +82,7 @@ wireHTTP({
|
|
|
82
82
|
Runs before everything else, across every wire type: HTTP, Queue, Channel, Trigger, Scheduler, Workflow, Agent, CLI, MCP. Use it for cross-cutting concerns (e.g. telemetry) that must wrap every invocation regardless of transport.
|
|
83
83
|
|
|
84
84
|
```typescript
|
|
85
|
-
import { addGlobalMiddleware } from '
|
|
85
|
+
import { addGlobalMiddleware } from '#pikku/middleware'
|
|
86
86
|
import { telemetryOuter, telemetryInner } from '@pikku/core/middleware'
|
|
87
87
|
|
|
88
88
|
addGlobalMiddleware([telemetryOuter({ environmentId: env.STAGE_ID })]) // wraps the full call
|
|
@@ -95,7 +95,7 @@ addGlobalMiddleware([telemetryInner({ environmentId: env.STAGE_ID })]) // closes
|
|
|
95
95
|
|
|
96
96
|
```typescript
|
|
97
97
|
import { addHTTPMiddleware } from '@pikku/core/http'
|
|
98
|
-
import { cors, authBearer } from '
|
|
98
|
+
import { cors, authBearer } from '#pikku/middleware'
|
|
99
99
|
|
|
100
100
|
// All routes
|
|
101
101
|
addHTTPMiddleware('*', [
|
|
@@ -239,11 +239,29 @@ pikku.fetch.setHeader('x-tenant', tenantId)
|
|
|
239
239
|
`authHeaders.jwt` becomes `Authorization: Bearer …` and `authHeaders.apiKey`
|
|
240
240
|
becomes `X-API-KEY`; setting a JWT takes precedence over an API key.
|
|
241
241
|
|
|
242
|
+
## Generated client files
|
|
243
|
+
|
|
244
|
+
Name any of these under `clientFiles` in `pikku.config.json` and `pikku all` writes them, with
|
|
245
|
+
import paths computed from the config:
|
|
246
|
+
|
|
247
|
+
- `typesFile` — `RPCInput<'name'>`, `RPCOutput<'name'>`, `FlattenedRPCMap` (and `AnalyticsEvent`
|
|
248
|
+
when `scaffold.analytics` is on). Use these instead of reaching into the functions package.
|
|
249
|
+
- `envFile` — `apiUrl()`, `basePath()`, `appHref(path)`.
|
|
250
|
+
- `rpcFile` — `rpc()`, a client for code outside React such as a route `beforeLoad`. It forwards
|
|
251
|
+
the request cookie during SSR (TanStack Start). Needs `envFile`.
|
|
252
|
+
- `authClientFile` — the Better Auth client glue from `@pikku/better-auth/client`. Needs
|
|
253
|
+
`rpcFile`, `envFile` and a `getSession` function; `clientAuth` sets the login and home paths.
|
|
254
|
+
|
|
255
|
+
In `vite.config.ts`, `pikkuVite()` from `@pikku/vite` adds `testIds()` and, with Better Auth, the
|
|
256
|
+
dev cross-site session plugin. `pikku dev` runs every frontend that sets `dev.command`
|
|
257
|
+
(`--frontend a,b`, `--no-frontends`) and creates `BETTER_AUTH_SECRET` in `.env` on first run.
|
|
258
|
+
|
|
242
259
|
## What NOT to do
|
|
243
260
|
|
|
244
261
|
- Don't instantiate `PikkuFetch`/`PikkuRPC` inside a component — `createPikku`
|
|
245
262
|
goes once at the app root, the instance flows through Context.
|
|
246
263
|
- Don't call `usePikkuRPC()` outside a `<PikkuProvider>` — it throws.
|
|
264
|
+
- Don't copy a `rpc.ts` or `env.ts` between apps — generate them with `rpcFile` and `envFile`.
|
|
247
265
|
- Don't write a custom RPC client. The generated one already covers every
|
|
248
266
|
exposed function with full types.
|
|
249
267
|
- Don't hardcode user-facing strings. Every display string goes through an
|
|
@@ -44,7 +44,7 @@ permissions were removed in #972. Authorization lives on the function's own
|
|
|
44
44
|
### `pikkuChannelMiddleware(fn)`
|
|
45
45
|
|
|
46
46
|
```typescript
|
|
47
|
-
import { pikkuChannelMiddleware } from '
|
|
47
|
+
import { pikkuChannelMiddleware } from '#pikku/middleware'
|
|
48
48
|
|
|
49
49
|
const middleware = pikkuChannelMiddleware(async (services, event, next) => {
|
|
50
50
|
// Transform or filter events before/after
|
|
@@ -98,7 +98,7 @@ Authorization is not a wiring concern — declare it on the function via `permis
|
|
|
98
98
|
### Middleware
|
|
99
99
|
|
|
100
100
|
```typescript
|
|
101
|
-
import { cors, authBearer } from '
|
|
101
|
+
import { cors, authBearer } from '#pikku/middleware'
|
|
102
102
|
|
|
103
103
|
// Global middleware
|
|
104
104
|
addHTTPMiddleware('*', [
|
|
@@ -206,7 +206,7 @@ export const getBook = pikkuFunc({
|
|
|
206
206
|
|
|
207
207
|
// wirings/books.http.ts — same defineHTTPRoutes/wireHTTPRoutes shape as the Route Groups example above
|
|
208
208
|
import { addHTTPMiddleware } from '#pikku/middleware'
|
|
209
|
-
import { cors, authBearer } from '
|
|
209
|
+
import { cors, authBearer } from '#pikku/middleware'
|
|
210
210
|
|
|
211
211
|
addHTTPMiddleware('*', [cors(), authBearer()])
|
|
212
212
|
```
|