@pikku/skills 0.12.40 → 0.12.42

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.
@@ -1,6 +1,5 @@
1
1
  # Pikku Function Versioning
2
2
 
3
-
4
3
  ## Before You Start
5
4
 
6
5
  ```bash
@@ -122,28 +121,86 @@ the manifest alone. Fix the contract or bump the version, then run it again.
122
121
  4. If intentional: pin the old contract as `…V1` with `version: 1`, bump the
123
122
  live function to `version: 2`, then `pikku versions update`
124
123
 
125
- ## The `pikku semver` command
124
+ ## The `pikku release` command
126
125
 
127
- `versions check` and `semver` answer different questions and share no state.
126
+ `versions check` and `release` answer different questions and share no state.
128
127
  `check` is a within-repo gate — "you changed a contract without bumping
129
- `version:`". `semver` is a release question — "what does this build owe the
130
- clients of the one already deployed?" — and needs an **external baseline**,
131
- which is why the answer is always relative to an environment rather than to
132
- the previous commit.
128
+ `version:`". `release` is a release question — "what does this build owe the
129
+ clients of the last release, and how do we ship it?". The baseline is
130
+ `surface.pikku.json`, the snapshot committed by the previous release.
133
131
 
134
132
  ```bash
135
- npx pikku semver --against https://api.acme.com/surface.json # vs production
136
- npx pikku semver --against ../other-app/.pikku # vs a checkout
137
- npx pikku semver --emit --out surface.json # publish a baseline
138
- npx pikku semver --against ... --fail-on major # CI gate
133
+ npx pikku release init # first run: snapshot + CHANGELOG.md
134
+ npx pikku release diff # vs surface.pikku.json
135
+ npx pikku release diff --against https://api.acme.com/surface.json # vs any baseline
136
+ npx pikku release diff --fail-on major # PR gate
137
+ npx pikku release snapshot --out surface.json # write a snapshot
138
+ npx pikku release prepare # bump package.json, write changelog + snapshot
139
139
  ```
140
140
 
141
141
  `--against` takes three things and tells them apart itself: a directory is read
142
142
  as a `.pikku` tree, an `http(s)` URL is fetched as a published snapshot, and any
143
- other file is read as a snapshot. `--emit` produces the snapshot; **use `--out`**
144
- — plain `--emit` writes to stdout _after_ the CLI banner, so a bare `> file.json`
145
- captures the banner too. Publish the snapshot from CI on deploy and it becomes
146
- the baseline everyone else compares against.
143
+ other file is read as a snapshot. `snapshot` without `--out` writes to stdout
144
+ _after_ the CLI banner, so a bare `> file.json` captures the banner too.
145
+ `pikku semver` is a deprecated alias for `release diff` / `release snapshot`.
146
+
147
+ ### Shipping a release
148
+
149
+ Work lands on the trunk branch (default `staging`); production (default `main`)
150
+ only ever fast-forwards to a release commit. pikku works the release out and
151
+ writes it; it never commits, tags or pushes. Who does that is your call — you
152
+ with plain git, or a platform with its own credentials.
153
+
154
+ `prepare` runs on a checkout of `origin/staging` after `pikku all`. It diffs the
155
+ surface against `surface.pikku.json`, reads the commits production does not have
156
+ yet, bumps `package.json`, prepends a `CHANGELOG.md` section and rewrites the
157
+ snapshot. No commits since the last release means nothing to release. It
158
+ refuses when `main` has commits `staging` lacks (merge `main` into `staging`
159
+ with a merge commit first). `.pikku/release.gen.json` records the version, the
160
+ changelog section, the trunk sha it was prepared on and the files it wrote,
161
+ named from the repository root.
162
+
163
+ Shipping is then one commit on top of that trunk sha:
164
+
165
+ ```bash
166
+ npx pikku release prepare
167
+ git add package.json CHANGELOG.md surface.pikku.json
168
+ git commit -m "release: v0.4.0"
169
+ git tag v0.4.0
170
+ git push --atomic origin HEAD:staging HEAD:main v0.4.0
171
+ ```
172
+
173
+ The push only fast-forwards, so if `staging` moved since prepare it is rejected
174
+ and you prepare again.
175
+
176
+ The bump comes from the surface diff alone — there is no manual override. A
177
+ release whose surface did not move is a patch. Below 1.0 a breaking change
178
+ is a minor, like any other surface change; from 1.0 it is a major. 1.0.0 is
179
+ never reached by a diff: `pikku release prepare --go-live` releases it once,
180
+ when the app is live. The changelog lists the surface changes and nothing
181
+ else from the code; a behaviour change behind an unchanged API only shows up
182
+ if a commit carries a `Release-Note: …` trailer, which adds a line to Notes.
183
+ A release with neither says it holds internal changes only. Branch names are configurable in `pikku.config.json`:
184
+
185
+ ```json
186
+ {
187
+ "release": {
188
+ "trunk": "staging",
189
+ "production": "main",
190
+ "branch": "release/next",
191
+ "remote": "origin"
192
+ }
193
+ }
194
+ ```
195
+
196
+ `branch` is not used by pikku itself; it is passed through in
197
+ `release.gen.json` as the name a platform gives the prepared release commit
198
+ while it waits to ship.
199
+
200
+ Functions and wirings defined under a `scaffold/` directory or in a generated
201
+ `*.gen.*` file are platform plumbing (auth, console, a host's injected shims)
202
+ and are left out of the surface, so the same app diffs the same locally and in
203
+ a platform's build.
147
204
 
148
205
  The verdict, in order:
149
206
 
@@ -179,7 +236,7 @@ the wiring level only `auth` going from absent/false to true is classified as
179
236
  breaking; every other metadata change is reported as compatible, because there
180
237
  is no general way to tell a cosmetic wiring edit from a restricting one.
181
238
 
182
- Output is `.pikku/changes.gen.json` (override with `--out`), so it rides the
239
+ `release diff` writes `.pikku/changes.gen.json` (override with `--out`), so it rides the
183
240
  same meta pipeline as `audit.json`:
184
241
 
185
242
  ```json
@@ -215,7 +272,7 @@ jobs:
215
272
  - run: npm ci
216
273
  - run: npx pikku versions check
217
274
  # Refuse to ship a breaking change to production unintentionally.
218
- - run: npx pikku semver --against https://api.acme.com/surface.json --fail-on major
275
+ - run: npx pikku release diff --fail-on major
219
276
  ```
220
277
 
221
278
  ## Complete Example
@@ -65,6 +65,10 @@ it to your project's service, session and middleware types; the `@pikku/core/*`
65
65
  export is the unbound generic. **Both compile.** Importing from core costs you
66
66
  exactly the typing that makes the wiring worth having, silently.
67
67
 
68
+ `pikku validate` reports it as the `coreImport` lint rule, an error by default,
69
+ naming the `#pikku` leaf to use instead. `@pikku/core/services` is the one
70
+ subpath it exempts — the service implementations bootstrap picks.
71
+
68
72
  | Wiring | Import from |
69
73
  | --- | --- |
70
74
  | `wireHTTP`, `defineHTTPRoutes`, `wireHTTPRoutes` | `#pikku/http` |
@@ -94,6 +94,60 @@ generated by the inspector, and it warns rather than throwing; the usual fix is
94
94
  the one the warning suggests — move the wiring into its own file so codegen
95
95
  picks it up.
96
96
 
97
+ ## Webhook sources
98
+
99
+ When the outside world pushes to you (Stripe, GitHub, Slack), the source is an
100
+ HTTP route, not a listener. `wireTriggerWebhookSource` declares it; triggers
101
+ subscribe to its events as `<source>:<event>`:
102
+
103
+ ```ts snippet:wireTriggerWebhookSource
104
+
105
+ ```
106
+
107
+ - The route is `POST /webhooks/<name>` unless `method`/`route` say otherwise.
108
+ It needs no session.
109
+ - `events` maps each event name to a schema. An event that fails its schema is
110
+ logged and dropped; so is one no `wireTrigger` listens for. Both still get a
111
+ `200`, so the provider does not retry forever.
112
+ - `receive(services, { body, headers, method, url, query })` gets the **raw
113
+ bytes** — verify the signature over those — and returns `{ events: [{ name,
114
+ id?, data }] }`, or `{ respond: { status, body } }` for a handshake. Throwing
115
+ rejects the request with the error's status (`UnauthorizedError` → 401).
116
+ Omitted, the JSON body becomes one event dispatched to a trigger named just
117
+ `<source>`.
118
+ - Every accepted event is queued on `pikku-incoming-webhooks` and run by a
119
+ generated worker, so the provider is answered quickly and a failing trigger is
120
+ retried by the queue. This needs a `queueService` and an
121
+ `incomingWebhookService: new IncomingWebhookService(queueService)` in your
122
+ singleton services. The event `id` becomes the job id.
123
+ - With a database, use `KyselyIncomingWebhookService(queueService, db)` from
124
+ `@pikku/kysely` instead (and `await service.init()`). It keeps a receipt per
125
+ event, so a provider's redelivery of an event already accepted is dropped
126
+ even on queues that ignore job ids, and records each attempt and its last
127
+ error. Its `webhookReceipt` table comes from `pikku db generate`; `pikku dev`
128
+ and `pikku serve` use it when a Kysely database is configured.
129
+ - `receive` sees singleton services without `secrets`: read the signing secret
130
+ in a service method, and declare it with `defineSecret`. Name it in `secret`
131
+ so deploy knows where `setup` should store it.
132
+
133
+ `check`, `setup` and `teardown` register the route with the provider. Each gets
134
+ `{ url, label, events, previous? }`, where `events` are only the ones some
135
+ trigger subscribes to. The CLI runs them:
136
+
137
+ ```bash
138
+ pikku webhooks status --url https://api.example.com --labelPrefix shop:prod
139
+ pikku webhooks setup --url https://api.example.com --labelPrefix shop:prod
140
+ pikku webhooks teardown --url https://api.example.com --labelPrefix shop:prod --previous state.json
141
+ ```
142
+
143
+ Each prints one JSON line per source (`ok`, `missing`, `drifted`, `created`,
144
+ `updated`, `unchanged`, `manual`, `deleted`, `absent`, `skipped`, `failed`). `setup` only
145
+ runs where `check` does not report `ok`, and a `setup` that returns a new signing
146
+ secret prints it with the `secret` name to store it under. In CI pass
147
+ `--secretsOut <file>`: secrets are written there (mode 600) as
148
+ `{ secretName: secret }` and left out of stdout. Any step can be
149
+ `ref('<addon>:<fn>')` to use an addon's implementation.
150
+
97
151
  ## Usage Patterns
98
152
 
99
153
  ### Redis Pub/Sub Source
@@ -139,7 +193,6 @@ wireTriggerSource({
139
193
  })
140
194
  ```
141
195
 
142
-
143
196
  ## Complete Example
144
197
 
145
198
  ```typescript