@pikku/cli 0.12.54 → 0.12.56
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/cli.schema.json +1 -1
- package/console-app/assets/{index-DYnbceYg.js → index-xN8LW0II.js} +155 -155
- package/console-app/index.html +1 -1
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +3 -3
- package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-channel.d.ts +6 -6
- package/dist/.pikku/cli/pikku-cli-channel.js +11 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.json +14 -0
- package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +29 -0
- package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
- package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +8 -31
- package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +1420 -1384
- package/dist/.pikku/function/pikku-functions.gen.js +3 -1
- package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
- package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
- package/dist/.pikku/pikku-meta-service.gen.js +1 -1
- package/dist/.pikku/pikku-services.gen.d.ts +4 -2
- package/dist/.pikku/pikku-services.gen.js +2 -0
- package/dist/.pikku/pikku-types.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.json +0 -248
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +69 -67
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
- package/dist/.pikku/schemas/register.gen.js +191 -185
- package/dist/.pikku/schemas/schemas/FabricAddonVerifyInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/FabricAddonVerifyOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuAuthInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
- package/dist/.pikku/workflow/meta/allWorkflow.gen.json +9 -3
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/bin/pikku-bin.mjs +2 -2
- package/dist/src/cli.wiring.js +15 -1
- package/dist/src/deploy/analyzer/analyzer.d.ts +6 -0
- package/dist/src/deploy/analyzer/analyzer.js +5 -4
- package/dist/src/deploy/build-pipeline.d.ts +5 -1
- package/dist/src/deploy/build-pipeline.js +5 -5
- package/dist/src/deploy/bundler/bun-bundler.d.ts +14 -0
- package/dist/src/deploy/bundler/bun-bundler.js +121 -0
- package/dist/src/deploy/bundler/bundler.d.ts +25 -30
- package/dist/src/deploy/bundler/bundler.interface.d.ts +54 -0
- package/dist/src/deploy/bundler/bundler.interface.js +11 -0
- package/dist/src/deploy/bundler/bundler.js +120 -190
- package/dist/src/deploy/bundler/dep-extractor.d.ts +11 -3
- package/dist/src/deploy/bundler/dep-extractor.js +12 -6
- package/dist/src/deploy/bundler/index.d.ts +5 -2
- package/dist/src/deploy/bundler/index.js +4 -2
- package/dist/src/deploy/bundler/node-bundler.d.ts +13 -0
- package/dist/src/deploy/bundler/node-bundler.js +80 -0
- package/dist/src/deploy/provider-adapter.d.ts +11 -0
- package/dist/src/deploy/server-entry.js +3 -1
- package/dist/src/fabric/fabric-commands.d.ts +109 -72
- package/dist/src/fabric/fabric-commands.js +8 -0
- package/dist/src/fabric/functions/add.function.d.ts +3 -3
- package/dist/src/fabric/functions/addon-verify.function.d.ts +54 -0
- package/dist/src/fabric/functions/addon-verify.function.js +153 -0
- package/dist/src/fabric/functions/db-schema.function.d.ts +3 -3
- package/dist/src/fabric/functions/deploy-list.function.d.ts +3 -3
- package/dist/src/fabric/functions/deploy-units.function.d.ts +3 -3
- package/dist/src/fabric/functions/deploy.function.d.ts +6 -6
- package/dist/src/fabric/functions/domains-add.function.d.ts +3 -3
- package/dist/src/fabric/functions/domains-list.function.d.ts +3 -3
- package/dist/src/fabric/functions/domains-remove.function.d.ts +3 -3
- package/dist/src/fabric/functions/errors.function.d.ts +3 -3
- package/dist/src/fabric/functions/init.function.d.ts +3 -3
- package/dist/src/fabric/functions/link.function.d.ts +3 -3
- package/dist/src/fabric/functions/llm-key.function.d.ts +3 -3
- package/dist/src/fabric/functions/llm-key.function.js +1 -1
- package/dist/src/fabric/functions/login.function.d.ts +3 -3
- package/dist/src/fabric/functions/logs.function.d.ts +3 -3
- package/dist/src/fabric/functions/metrics.function.d.ts +3 -3
- package/dist/src/fabric/functions/publish.function.d.ts +3 -3
- package/dist/src/fabric/functions/publish.function.js +8 -3
- package/dist/src/fabric/functions/rollback.function.d.ts +3 -3
- package/dist/src/fabric/functions/secrets-list.function.d.ts +3 -3
- package/dist/src/fabric/functions/secrets-set.function.d.ts +3 -3
- package/dist/src/fabric/functions/smoke.function.d.ts +3 -3
- package/dist/src/fabric/functions/status.function.d.ts +3 -3
- package/dist/src/fabric/functions/trace.function.d.ts +3 -3
- package/dist/src/fabric/functions/validate.function.d.ts +3 -3
- package/dist/src/functions/commands/all.d.ts +1 -1
- package/dist/src/functions/commands/all.js +19 -2
- package/dist/src/functions/commands/binary.d.ts +3 -3
- package/dist/src/functions/commands/bootstrap.d.ts +1 -1
- package/dist/src/functions/commands/bootstrap.js +3 -0
- package/dist/src/functions/commands/console.d.ts +3 -3
- package/dist/src/functions/commands/db-audit.d.ts +1 -1
- package/dist/src/functions/commands/db-generate.d.ts +1 -1
- package/dist/src/functions/commands/db-migrate.d.ts +1 -1
- package/dist/src/functions/commands/db-reset.d.ts +1 -1
- package/dist/src/functions/commands/db-seed.d.ts +1 -1
- package/dist/src/functions/commands/deploy-apply.d.ts +3 -3
- package/dist/src/functions/commands/deploy-apply.js +32 -1
- package/dist/src/functions/commands/deploy-info.d.ts +1 -1
- package/dist/src/functions/commands/deploy-plan.d.ts +3 -3
- package/dist/src/functions/commands/deploy-plan.js +3 -1
- package/dist/src/functions/commands/dev.d.ts +3 -3
- package/dist/src/functions/commands/dev.js +17 -45
- package/dist/src/functions/commands/emails-init.d.ts +1 -1
- package/dist/src/functions/commands/enable.d.ts +6 -5
- package/dist/src/functions/commands/enable.js +4 -0
- package/dist/src/functions/commands/info.d.ts +4 -4
- package/dist/src/functions/commands/login.d.ts +7 -7
- package/dist/src/functions/commands/meta.d.ts +31 -31
- package/dist/src/functions/commands/new-addon.d.ts +3 -3
- package/dist/src/functions/commands/new-function.d.ts +3 -3
- package/dist/src/functions/commands/new-middleware.d.ts +3 -3
- package/dist/src/functions/commands/new-permission.d.ts +3 -3
- package/dist/src/functions/commands/new-wiring.d.ts +3 -3
- package/dist/src/functions/commands/pikku-command-bootstrap.d.ts +1 -1
- package/dist/src/functions/commands/pikku-command-summary.d.ts +1 -1
- package/dist/src/functions/commands/pikku-command-summary.js +6 -1
- package/dist/src/functions/commands/skills.d.ts +6 -6
- package/dist/src/functions/commands/tests-coverage.d.ts +3 -3
- package/dist/src/functions/commands/tests-init.d.ts +3 -3
- package/dist/src/functions/commands/versions-check.d.ts +1 -1
- package/dist/src/functions/commands/versions-init.d.ts +3 -3
- package/dist/src/functions/commands/versions-update.d.ts +1 -1
- package/dist/src/functions/commands/watch.d.ts +3 -3
- package/dist/src/functions/commands/workspace-validate.d.ts +3 -3
- package/dist/src/functions/db/db-codegen.js +14 -0
- package/dist/src/functions/db/sqlite/sqlite-runtime-bun.js +10 -0
- package/dist/src/functions/runtimes/fetch/index.d.ts +1 -1
- package/dist/src/functions/runtimes/nextjs/pikku-command-nextjs.d.ts +1 -1
- package/dist/src/functions/runtimes/tanstack-start/pikku-command-tanstack-start.d.ts +1 -1
- package/dist/src/functions/runtimes/websocket/pikku-command-websocket-typed.d.ts +1 -1
- package/dist/src/functions/wirings/ai-agent/pikku-command-ai-agent-types.d.ts +1 -1
- package/dist/src/functions/wirings/ai-agent/pikku-command-ai-agent.d.ts +1 -1
- package/dist/src/functions/wirings/ai-agent/pikku-command-public-agent.d.ts +1 -1
- package/dist/src/functions/wirings/auth/pikku-command-auth.d.ts +7 -1
- package/dist/src/functions/wirings/auth/pikku-command-auth.js +14 -2
- package/dist/src/functions/wirings/auth/serialize-auth-types.d.ts +10 -0
- package/dist/src/functions/wirings/auth/serialize-auth-types.js +15 -0
- package/dist/src/functions/wirings/channels/pikku-channels.d.ts +1 -1
- package/dist/src/functions/wirings/channels/pikku-command-channel-types.d.ts +1 -1
- package/dist/src/functions/wirings/channels/pikku-command-channels-map.d.ts +1 -1
- package/dist/src/functions/wirings/channels/pikku-command-channels.d.ts +1 -1
- package/dist/src/functions/wirings/cli/pikku-command-cli-entry.d.ts +1 -1
- package/dist/src/functions/wirings/cli/pikku-command-cli-types.d.ts +1 -1
- package/dist/src/functions/wirings/cli/pikku-command-cli.d.ts +1 -1
- package/dist/src/functions/wirings/console/pikku-command-console-functions.d.ts +1 -1
- package/dist/src/functions/wirings/console/pikku-command-node-types.d.ts +1 -1
- package/dist/src/functions/wirings/console/pikku-command-nodes-meta.d.ts +1 -1
- package/dist/src/functions/wirings/credentials/pikku-command-credentials.d.ts +1 -1
- package/dist/src/functions/wirings/emails/pikku-command-emails.d.ts +1 -1
- package/dist/src/functions/wirings/functions/pikku-command-addon-types.d.ts +1 -1
- package/dist/src/functions/wirings/functions/pikku-command-function-types-split.d.ts +3 -3
- package/dist/src/functions/wirings/functions/pikku-command-function-types.d.ts +3 -3
- package/dist/src/functions/wirings/functions/pikku-command-function-types.js +10 -3
- package/dist/src/functions/wirings/functions/pikku-command-functions.d.ts +1 -1
- package/dist/src/functions/wirings/functions/pikku-command-services.d.ts +1 -1
- package/dist/src/functions/wirings/functions/schemas.d.ts +1 -1
- package/dist/src/functions/wirings/functions/serialize-function-types.js +6 -29
- package/dist/src/functions/wirings/gateway/pikku-command-gateway.d.ts +1 -1
- package/dist/src/functions/wirings/http/pikku-command-http-map.d.ts +1 -1
- package/dist/src/functions/wirings/http/pikku-command-http-routes.d.ts +1 -1
- package/dist/src/functions/wirings/http/pikku-command-http-types.d.ts +1 -1
- package/dist/src/functions/wirings/http/pikku-command-openapi.d.ts +1 -1
- package/dist/src/functions/wirings/http/pikku-http-routes.d.ts +1 -1
- package/dist/src/functions/wirings/mcp/pikku-command-mcp-json.d.ts +1 -1
- package/dist/src/functions/wirings/mcp/pikku-command-mcp-types.d.ts +1 -1
- package/dist/src/functions/wirings/mcp/pikku-command-mcp.d.ts +1 -1
- package/dist/src/functions/wirings/middleware/pikku-command-middleware.d.ts +1 -1
- package/dist/src/functions/wirings/package/pikku-command-package-types.d.ts +2 -2
- package/dist/src/functions/wirings/package/pikku-command-package.d.ts +1 -1
- package/dist/src/functions/wirings/permissions/pikku-command-permissions.d.ts +1 -1
- package/dist/src/functions/wirings/queue/pikku-command-queue-map.d.ts +1 -1
- package/dist/src/functions/wirings/queue/pikku-command-queue-service.d.ts +1 -1
- package/dist/src/functions/wirings/queue/pikku-command-queue-types.d.ts +1 -1
- package/dist/src/functions/wirings/queue/pikku-command-queue.d.ts +1 -1
- package/dist/src/functions/wirings/queue/pikku-queue-map.d.ts +1 -1
- package/dist/src/functions/wirings/queue/pikku-queue.d.ts +1 -1
- package/dist/src/functions/wirings/realtime/pikku-command-events-scaffold.d.ts +1 -1
- package/dist/src/functions/wirings/realtime/pikku-command-realtime.d.ts +1 -1
- package/dist/src/functions/wirings/rpc/pikku-command-public-rpc.d.ts +1 -1
- package/dist/src/functions/wirings/rpc/pikku-command-react-query.d.ts +1 -1
- package/dist/src/functions/wirings/rpc/pikku-command-remote-rpc.d.ts +1 -1
- package/dist/src/functions/wirings/rpc/pikku-command-rpc-client.d.ts +1 -1
- package/dist/src/functions/wirings/rpc/pikku-command-rpc-map.d.ts +2 -2
- package/dist/src/functions/wirings/rpc/pikku-command-rpc.d.ts +1 -1
- package/dist/src/functions/wirings/scheduler/pikku-command-scheduler-types.d.ts +1 -1
- package/dist/src/functions/wirings/scheduler/pikku-command-scheduler.d.ts +1 -1
- package/dist/src/functions/wirings/secrets/pikku-command-secrets.d.ts +1 -1
- package/dist/src/functions/wirings/triggers/pikku-command-trigger-types.d.ts +3 -3
- package/dist/src/functions/wirings/triggers/pikku-command-trigger.d.ts +1 -1
- package/dist/src/functions/wirings/variables/pikku-command-variables.d.ts +1 -1
- package/dist/src/functions/wirings/workflow/pikku-command-workflow-routes.d.ts +1 -1
- package/dist/src/functions/wirings/workflow/pikku-command-workflow.d.ts +1 -1
- package/dist/src/functions/workflows/all.workflow.js +6 -1
- package/dist/src/scaffold/rpc-remote.gen.d.ts +3 -3
- package/dist/src/scaffold/rpc-remote.gen.js +1 -1
- package/dist/src/server/bun-server-runner.d.ts +17 -0
- package/dist/src/server/bun-server-runner.js +25 -0
- package/dist/src/server/dev-server-runner.interface.d.ts +31 -0
- package/dist/src/server/dev-server-runner.interface.js +11 -0
- package/dist/src/server/node-server-runner.d.ts +12 -0
- package/dist/src/server/node-server-runner.js +30 -0
- package/dist/src/services/cli-logger.service.js +7 -1
- package/dist/src/services.js +18 -0
- package/dist/src/utils/detect-better-auth.d.ts +7 -0
- package/dist/src/utils/detect-better-auth.js +29 -0
- package/dist/src/utils/parse-cli-filters.d.ts +1 -0
- package/dist/src/utils/parse-cli-filters.js +1 -0
- package/dist/src/utils/pikku-cli-config.js +1 -1
- package/dist/src/utils/serialize-schemas.js +5 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/skills/pikku-addon/SKILL.md +25 -117
- package/skills/pikku-addon/references/addon-package-manifest.md +63 -0
- package/skills/pikku-cli/SKILL.md +7 -93
- package/skills/pikku-cli/references/complete-example.md +82 -0
- package/skills/pikku-concepts/SKILL.md +17 -69
- package/skills/pikku-concepts/references/concept-mapping.md +37 -13
- package/skills/pikku-concepts/references/packages.md +29 -0
- package/skills/pikku-http/SKILL.md +14 -105
- package/skills/pikku-http/references/http-options.md +57 -0
- package/skills/pikku-middleware/SKILL.md +11 -68
- package/skills/pikku-middleware/references/middleware-patterns.md +61 -0
- package/skills/pikku-realtime/SKILL.md +56 -105
- package/skills/pikku-realtime/references/other-routes.md +23 -0
- package/skills/pikku-services/SKILL.md +25 -108
- package/skills/pikku-services/references/audit-wire-service.md +34 -0
- package/skills/pikku-testing/SKILL.md +51 -359
- package/skills/pikku-testing/references/cucumber-bdd-testing.md +176 -0
- package/skills/pikku-workflow/SKILL.md +93 -259
- package/skills/pikku-workflow/references/workflow-reference.md +63 -0
|
@@ -77,20 +77,17 @@ wireHTTP({
|
|
|
77
77
|
|
|
78
78
|
## Global Middleware (`addGlobalMiddleware`)
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
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.
|
|
81
81
|
|
|
82
82
|
```typescript
|
|
83
83
|
import { addGlobalMiddleware } from '@pikku/core'
|
|
84
84
|
import { telemetryOuter, telemetryInner } from '@pikku/core/middleware'
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
addGlobalMiddleware([
|
|
88
|
-
|
|
89
|
-
// Inner telemetry: closest to the function body (lowest priority)
|
|
90
|
-
addGlobalMiddleware([telemetryInner({ environmentId: env.STAGE_ID })])
|
|
86
|
+
addGlobalMiddleware([telemetryOuter({ environmentId: env.STAGE_ID })]) // wraps the full call
|
|
87
|
+
addGlobalMiddleware([telemetryInner({ environmentId: env.STAGE_ID })]) // closest to the function body
|
|
91
88
|
```
|
|
92
89
|
|
|
93
|
-
`telemetryOuter` ships with `priority: 'highest'
|
|
90
|
+
`telemetryOuter` ships with `priority: 'highest'`, `telemetryInner` with `priority: 'lowest'` — so priority sorting places outer first regardless of array/call order.
|
|
94
91
|
|
|
95
92
|
## HTTP & Prefix Middleware (`addHTTPMiddleware`)
|
|
96
93
|
|
|
@@ -165,15 +162,13 @@ const earlyMiddleware = pikkuMiddleware({
|
|
|
165
162
|
})
|
|
166
163
|
```
|
|
167
164
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
## Common Patterns
|
|
165
|
+
Priority is the primary sort key; within the same level, registration order is preserved. Use priority when a middleware must run before/after others regardless of registration order (e.g. telemetry wrapping everything, session extraction before auth checks).
|
|
171
166
|
|
|
172
|
-
|
|
167
|
+
## Service-to-Service Bearer Auth (canonical pattern)
|
|
173
168
|
|
|
174
|
-
|
|
169
|
+
A server that exposes RPCs only to a trusted caller (e.g. an API calling a machine-agent). Auth lives in a tag middleware — NOT in the function body. Authorization/permission checks belong in the `permissions` field (see `pikku-permissions`), never inside `func`.
|
|
175
170
|
|
|
176
|
-
**On the server (the service being called):**
|
|
171
|
+
**On the server (the service being called):** tag the function, register a `pikkuMiddleware` that reads the `Authorization` header on that tag.
|
|
177
172
|
|
|
178
173
|
```typescript
|
|
179
174
|
// lib/host-token.ts
|
|
@@ -217,63 +212,11 @@ export const myFunc = pikkuSessionlessFunc({
|
|
|
217
212
|
})
|
|
218
213
|
```
|
|
219
214
|
|
|
220
|
-
**On the client (the caller):**
|
|
221
|
-
|
|
222
|
-
Use the generated `RPCInvoke` type from `.pikku/rpc/pikku-rpc-wirings-map.gen.d.ts` — never hand-write the input/output types:
|
|
223
|
-
|
|
224
|
-
```typescript
|
|
225
|
-
import type { RPCInvoke } from '../../backends/my-service/.pikku/rpc/pikku-rpc-wirings-map.gen.d.js'
|
|
226
|
-
|
|
227
|
-
export function getServiceRPC(baseUrl: string, token: string): RPCInvoke {
|
|
228
|
-
return async (name: string, data?: unknown) => {
|
|
229
|
-
const res = await fetch(`${baseUrl}/rpc/${String(name)}`, {
|
|
230
|
-
method: 'POST',
|
|
231
|
-
headers: {
|
|
232
|
-
'Content-Type': 'application/json',
|
|
233
|
-
Authorization: `Bearer ${token}`,
|
|
234
|
-
},
|
|
235
|
-
body: JSON.stringify({ data: data ?? {} }),
|
|
236
|
-
})
|
|
237
|
-
if (!res.ok) {
|
|
238
|
-
const text = await res.text().catch(() => '')
|
|
239
|
-
throw new Error(`rpc ${String(name)} failed: ${res.status} ${text}`)
|
|
240
|
-
}
|
|
241
|
-
return res.json()
|
|
242
|
-
} as RPCInvoke
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### Session-Setting Middleware
|
|
247
|
-
|
|
248
|
-
```typescript
|
|
249
|
-
const apiKeyAuth = pikkuMiddleware(async ({ kysely }, { http, setSession, session }, next) => {
|
|
250
|
-
if (session) return next() // already authenticated
|
|
251
|
-
|
|
252
|
-
const header = http?.request?.header?.('x-api-key')
|
|
253
|
-
if (!header) return next()
|
|
254
|
-
|
|
255
|
-
const row = await kysely.selectFrom('apiKey').select('userId').where('key', '=', header).executeTakeFirst()
|
|
256
|
-
if (row) setSession?.({ userId: row.userId })
|
|
257
|
-
|
|
258
|
-
return next()
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
addTagMiddleware('api-key-auth', [apiKeyAuth])
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
Functions tagged `'api-key-auth'` with `auth: true` reject requests without a valid key; those with `auth: false` can inspect the session but won't reject.
|
|
215
|
+
**On the client (the caller):** use the generated `RPCInvoke` type — never hand-write a `fetch` wrapper's types. See `references/middleware-patterns.md`.
|
|
265
216
|
|
|
266
|
-
|
|
217
|
+
## More patterns
|
|
267
218
|
|
|
268
|
-
|
|
269
|
-
const auditLog = pikkuMiddleware(async ({ logger, db }, wire, next) => {
|
|
270
|
-
const start = Date.now()
|
|
271
|
-
await next()
|
|
272
|
-
await db.createAuditLog({ duration: Date.now() - start })
|
|
273
|
-
})
|
|
274
|
-
|
|
275
|
-
addHTTPMiddleware('/admin/*', [auditLog])
|
|
276
|
-
```
|
|
219
|
+
`references/middleware-patterns.md` covers the client-side `RPCInvoke` caller, session-setting middleware (set a session from an API key), and request logging / audit middleware.
|
|
277
220
|
|
|
278
221
|
## After Changes
|
|
279
222
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Middleware Patterns (extended)
|
|
2
|
+
|
|
3
|
+
Detailed, less-common middleware recipes. The common-path bearer-auth pattern lives inline in SKILL.md; this file holds the client-side caller, session-setting, and audit recipes.
|
|
4
|
+
|
|
5
|
+
## Service-to-Service: the client (caller) side
|
|
6
|
+
|
|
7
|
+
Use the generated `RPCInvoke` type from `.pikku/rpc/pikku-rpc-wirings-map.gen.d.ts` — never hand-write the input/output types:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import type { RPCInvoke } from '../../backends/my-service/.pikku/rpc/pikku-rpc-wirings-map.gen.d.js'
|
|
11
|
+
|
|
12
|
+
export function getServiceRPC(baseUrl: string, token: string): RPCInvoke {
|
|
13
|
+
return async (name: string, data?: unknown) => {
|
|
14
|
+
const res = await fetch(`${baseUrl}/rpc/${String(name)}`, {
|
|
15
|
+
method: 'POST',
|
|
16
|
+
headers: {
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
Authorization: `Bearer ${token}`,
|
|
19
|
+
},
|
|
20
|
+
body: JSON.stringify({ data: data ?? {} }),
|
|
21
|
+
})
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
const text = await res.text().catch(() => '')
|
|
24
|
+
throw new Error(`rpc ${String(name)} failed: ${res.status} ${text}`)
|
|
25
|
+
}
|
|
26
|
+
return res.json()
|
|
27
|
+
} as RPCInvoke
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Session-Setting Middleware
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
const apiKeyAuth = pikkuMiddleware(async ({ kysely }, { http, setSession, session }, next) => {
|
|
35
|
+
if (session) return next() // already authenticated
|
|
36
|
+
|
|
37
|
+
const header = http?.request?.header?.('x-api-key')
|
|
38
|
+
if (!header) return next()
|
|
39
|
+
|
|
40
|
+
const row = await kysely.selectFrom('apiKey').select('userId').where('key', '=', header).executeTakeFirst()
|
|
41
|
+
if (row) setSession?.({ userId: row.userId })
|
|
42
|
+
|
|
43
|
+
return next()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
addTagMiddleware('api-key-auth', [apiKeyAuth])
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Functions tagged `'api-key-auth'` with `auth: true` reject requests without a valid key; those with `auth: false` can inspect the session but won't reject.
|
|
50
|
+
|
|
51
|
+
## Request Logging / Audit
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
const auditLog = pikkuMiddleware(async ({ logger, db }, wire, next) => {
|
|
55
|
+
const start = Date.now()
|
|
56
|
+
await next()
|
|
57
|
+
await db.createAuditLog({ duration: Date.now() - start })
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
addHTTPMiddleware('/admin/*', [auditLog])
|
|
61
|
+
```
|
|
@@ -16,16 +16,13 @@ Use this skill as an execution checklist, not reference material.
|
|
|
16
16
|
4. Validate with the narrowest relevant command first, then run `pikku-verify` or `pikku all` when functions, wirings, schemas, or generated clients may have changed.
|
|
17
17
|
5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
|
|
18
18
|
|
|
19
|
-
Most realtime UI is just typed pub/sub: a server pushes `todo-created`, the
|
|
20
|
-
|
|
19
|
+
Most realtime UI is just typed pub/sub: a server pushes `todo-created`, the client
|
|
20
|
+
renders it. Pikku ships exactly that, two ways — both use the same `EventHubService`
|
|
21
|
+
and the same publish call, so choose by transport, not by code shape:
|
|
21
22
|
|
|
22
23
|
- **WebSocket** at `/events` — one connection, many topic subscriptions.
|
|
23
|
-
- **SSE** at `GET /events/:topic` — one connection per topic, auto-cleanup
|
|
24
|
-
|
|
25
|
-
trivially streaming one topic.
|
|
26
|
-
|
|
27
|
-
Both transports use the same `EventHubService` and the same publish call.
|
|
28
|
-
Choose by transport, not by code shape.
|
|
24
|
+
- **SSE** at `GET /events/:topic` — one connection per topic, auto-cleanup on
|
|
25
|
+
disconnect. Good when WebSocket is blocked or for trivially streaming one topic.
|
|
29
26
|
|
|
30
27
|
## 1. Declare your topics
|
|
31
28
|
|
|
@@ -41,28 +38,24 @@ export type EventHubTopics = {
|
|
|
41
38
|
}
|
|
42
39
|
```
|
|
43
40
|
|
|
44
|
-
Reference it in `application-types.d.ts`:
|
|
41
|
+
Reference it in `application-types.d.ts` and instantiate it in `services.ts`:
|
|
45
42
|
|
|
46
43
|
```ts
|
|
44
|
+
// application-types.d.ts
|
|
47
45
|
import type { EventHubService } from '@pikku/core/channel'
|
|
48
46
|
import type { EventHubTopics } from './eventhub-topics.js'
|
|
49
47
|
|
|
50
48
|
export interface SingletonServices extends CoreSingletonServices<Config> {
|
|
51
49
|
eventHub?: EventHubService<EventHubTopics>
|
|
52
|
-
// ...
|
|
53
50
|
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
And instantiate it in `services.ts`:
|
|
57
51
|
|
|
58
|
-
|
|
52
|
+
// services.ts
|
|
59
53
|
import { LocalEventHubService } from '@pikku/core/channel'
|
|
60
|
-
// ...
|
|
61
54
|
const eventHub = new LocalEventHubService<EventHubTopics>()
|
|
62
55
|
```
|
|
63
56
|
|
|
64
|
-
|
|
65
|
-
`LambdaEventHubService` / `UWSEventHubService` instead — same interface.
|
|
57
|
+
For multi-instance deployments use `CloudflareEventHubService` /
|
|
58
|
+
`LambdaEventHubService` / `UWSEventHubService` instead — same interface.
|
|
66
59
|
|
|
67
60
|
## 2. Enable the server side
|
|
68
61
|
|
|
@@ -71,15 +64,13 @@ yarn pikku enable events # auth required by default
|
|
|
71
64
|
yarn pikku enable events --noAuth # public events
|
|
72
65
|
```
|
|
73
66
|
|
|
74
|
-
This sets `scaffold.events` in `pikku.config.json`. The next `pikku all`
|
|
75
|
-
|
|
67
|
+
This sets `scaffold.events` in `pikku.config.json`. The next `pikku all` generates
|
|
68
|
+
`events.gen.ts` in your scaffold dir, wiring (using whatever `eventHub` is in your
|
|
69
|
+
singletons — you write neither by hand):
|
|
76
70
|
|
|
77
71
|
- A WebSocket channel at `/events` handling `{action: 'subscribe' | 'unsubscribe', topic}` messages.
|
|
78
72
|
- An SSE handler at `GET /events/:topic`.
|
|
79
73
|
|
|
80
|
-
You don't write either by hand. They use whatever `eventHub` service is
|
|
81
|
-
in your singletons.
|
|
82
|
-
|
|
83
74
|
## 3. Generate the typed client
|
|
84
75
|
|
|
85
76
|
Add to `pikku.config.json`:
|
|
@@ -87,7 +78,6 @@ Add to `pikku.config.json`:
|
|
|
87
78
|
```jsonc
|
|
88
79
|
{
|
|
89
80
|
"clientFiles": {
|
|
90
|
-
// ...
|
|
91
81
|
"realtimeFile": "packages/sdk/src/pikku/realtime.gen.ts",
|
|
92
82
|
// Optional: full type inference for subscribe/unsubscribe
|
|
93
83
|
"realtimeEventHubTopicsImport": "../../../functions/types/eventhub-topics.js#EventHubTopics",
|
|
@@ -95,8 +85,8 @@ Add to `pikku.config.json`:
|
|
|
95
85
|
}
|
|
96
86
|
```
|
|
97
87
|
|
|
98
|
-
Run `pikku all` (or `pikku realtime` to regenerate just this file). The
|
|
99
|
-
|
|
88
|
+
Run `pikku all` (or `pikku realtime` to regenerate just this file). The generated
|
|
89
|
+
file exports two surfaces:
|
|
100
90
|
|
|
101
91
|
```ts
|
|
102
92
|
export class PikkuRealtime {
|
|
@@ -112,13 +102,15 @@ export function subscribeToTopicViaSSE<K extends keyof EventHubTopics>(
|
|
|
112
102
|
```
|
|
113
103
|
|
|
114
104
|
Without `realtimeEventHubTopicsImport`, the client falls back to
|
|
115
|
-
`Record<string, unknown>` — usable but untyped. Set the import for full
|
|
116
|
-
|
|
105
|
+
`Record<string, unknown>` — usable but untyped. Set the import for full typed
|
|
106
|
+
subscribe/unsubscribe.
|
|
117
107
|
|
|
118
108
|
## 4. Publish events from a function
|
|
119
109
|
|
|
120
|
-
The `/events` channel listens for client subscriptions; the eventHub fans
|
|
121
|
-
|
|
110
|
+
The `/events` channel listens for client subscriptions; the eventHub fans out
|
|
111
|
+
publishes. Envelope the payload with `topic` so the client dispatcher works; the
|
|
112
|
+
`null` channelId means "broadcast to all subscribers" (pass a specific channel id
|
|
113
|
+
to exclude/include a single connection):
|
|
122
114
|
|
|
123
115
|
```ts
|
|
124
116
|
import { pikkuFunc } from '#pikku'
|
|
@@ -128,47 +120,35 @@ export const createTodo = pikkuFunc({
|
|
|
128
120
|
output: CreateTodoOutput,
|
|
129
121
|
func: async ({ kysely, eventHub }, data) => {
|
|
130
122
|
const todo = await kysely
|
|
131
|
-
.insertInto('todos')
|
|
132
|
-
.values(data)
|
|
133
|
-
.returningAll()
|
|
123
|
+
.insertInto('todos').values(data).returningAll()
|
|
134
124
|
.executeTakeFirstOrThrow()
|
|
135
125
|
|
|
136
126
|
if (eventHub) {
|
|
137
|
-
// Envelope the payload with `topic` so the client dispatcher works.
|
|
138
127
|
await eventHub.publish('todo-created', null, {
|
|
139
128
|
topic: 'todo-created',
|
|
140
129
|
data: { todo },
|
|
141
130
|
})
|
|
142
131
|
}
|
|
143
|
-
|
|
144
132
|
return { id: todo.id }
|
|
145
133
|
},
|
|
146
134
|
})
|
|
147
135
|
```
|
|
148
136
|
|
|
149
|
-
The `null` channelId means "broadcast to all subscribers." Pass a
|
|
150
|
-
specific channel id to exclude/include a single connection.
|
|
151
|
-
|
|
152
137
|
A thin helper removes the duplication:
|
|
153
138
|
|
|
154
139
|
```ts
|
|
155
140
|
async function publishEvent<K extends keyof EventHubTopics>(
|
|
156
|
-
hub: EventHubService<EventHubTopics>,
|
|
157
|
-
topic: K,
|
|
158
|
-
data: EventHubTopics[K]
|
|
141
|
+
hub: EventHubService<EventHubTopics>, topic: K, data: EventHubTopics[K]
|
|
159
142
|
) {
|
|
160
143
|
return hub.publish(topic, null, { topic, data })
|
|
161
144
|
}
|
|
162
|
-
|
|
163
|
-
// usage:
|
|
164
|
-
await publishEvent(eventHub, 'todo-created', { todo })
|
|
145
|
+
// usage: await publishEvent(eventHub, 'todo-created', { todo })
|
|
165
146
|
```
|
|
166
147
|
|
|
167
148
|
## 5. Wire it up — share fetch with PikkuRPC
|
|
168
149
|
|
|
169
|
-
`PikkuRealtime` mirrors `PikkuRPC`: it wraps the same `PikkuFetch`, so
|
|
170
|
-
|
|
171
|
-
and realtime transports.
|
|
150
|
+
`PikkuRealtime` mirrors `PikkuRPC`: it wraps the same `PikkuFetch`, so server URL +
|
|
151
|
+
auth are configured **once** and shared across HTTP, RPC, and realtime transports.
|
|
172
152
|
|
|
173
153
|
```tsx
|
|
174
154
|
import { createPikku, PikkuProvider } from '@pikku/react'
|
|
@@ -185,9 +165,7 @@ const pikku = createPikku(
|
|
|
185
165
|
// pikku.fetch / pikku.rpc / pikku.realtime — all share the same fetch.
|
|
186
166
|
|
|
187
167
|
createRoot(document.getElementById('root')!).render(
|
|
188
|
-
<PikkuProvider pikku={pikku}>
|
|
189
|
-
<App />
|
|
190
|
-
</PikkuProvider>
|
|
168
|
+
<PikkuProvider pikku={pikku}><App /></PikkuProvider>
|
|
191
169
|
)
|
|
192
170
|
```
|
|
193
171
|
|
|
@@ -200,64 +178,38 @@ realtime.setPikkuFetch(pikku.fetch) // inherits serverUrl + auth
|
|
|
200
178
|
|
|
201
179
|
## 6. Subscribe from React
|
|
202
180
|
|
|
181
|
+
Subscribe inside `useEffect` (never the render path, or you create a subscription
|
|
182
|
+
per render). `subscribe` returns an unsubscribe function; SSE's `subscribeToTopic`
|
|
183
|
+
returns a handle with `close()`:
|
|
184
|
+
|
|
203
185
|
```tsx
|
|
204
186
|
import { useEffect, useState } from 'react'
|
|
205
187
|
|
|
206
188
|
function TodoList() {
|
|
207
|
-
const { realtime } = usePikku() //
|
|
189
|
+
const { realtime } = usePikku() // a hook over your context
|
|
208
190
|
const [todos, setTodos] = useState<Todo[]>([])
|
|
209
191
|
|
|
210
192
|
useEffect(() => {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
193
|
+
// WebSocket multi-topic:
|
|
194
|
+
const off = realtime.subscribe('todo-created', ({ todo }) =>
|
|
195
|
+
setTodos((prev) => [...prev, todo]))
|
|
214
196
|
return off
|
|
197
|
+
|
|
198
|
+
// Single-topic SSE (auto-cleanup on close) instead:
|
|
199
|
+
// const sub = realtime.subscribeToTopic('todo-created', ({ todo }) =>
|
|
200
|
+
// setTodos((prev) => [...prev, todo]))
|
|
201
|
+
// return () => sub.close()
|
|
215
202
|
}, [realtime])
|
|
216
203
|
|
|
217
|
-
return (
|
|
218
|
-
<ul>
|
|
219
|
-
{todos.map((t) => (
|
|
220
|
-
<li key={t.id}>{t.title}</li>
|
|
221
|
-
))}
|
|
222
|
-
</ul>
|
|
223
|
-
)
|
|
204
|
+
return <ul>{todos.map((t) => <li key={t.id}>{t.title}</li>)}</ul>
|
|
224
205
|
}
|
|
225
206
|
```
|
|
226
207
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
```tsx
|
|
230
|
-
useEffect(() => {
|
|
231
|
-
const sub = realtime.subscribeToTopic('todo-created', ({ todo }) => {
|
|
232
|
-
setTodos((prev) => [...prev, todo])
|
|
233
|
-
})
|
|
234
|
-
return () => sub.close()
|
|
235
|
-
}, [realtime])
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
## Subscribing to other SSE / WebSocket routes
|
|
239
|
-
|
|
240
|
-
Same client also handles generic SSE + channel routes — use the path,
|
|
241
|
-
the base URL is inherited from PikkuFetch:
|
|
242
|
-
|
|
243
|
-
```ts
|
|
244
|
-
// Any sse: true HTTP route
|
|
245
|
-
const sub = realtime.subscribeToSSE<{ progress: number }>(
|
|
246
|
-
`/workflow-run/${runId}/stream`,
|
|
247
|
-
(event) => setProgress(event.progress)
|
|
248
|
-
)
|
|
249
|
-
// later: sub.close()
|
|
250
|
-
|
|
251
|
-
// Any wireChannel — open a raw socket, wrap in PikkuWebSocket for typed I/O
|
|
252
|
-
const ws = realtime.connectToChannel('/ws/kanban')
|
|
253
|
-
const typed = new PikkuWebSocket<'kanban-live'>(ws)
|
|
254
|
-
typed.getRoute('command').subscribe('message', (data) => {
|
|
255
|
-
/* ... */
|
|
256
|
-
})
|
|
257
|
-
```
|
|
208
|
+
## Other SSE / WebSocket routes
|
|
258
209
|
|
|
259
|
-
|
|
260
|
-
|
|
210
|
+
The same client also subscribes to generic `sse: true` routes and raw `wireChannel`
|
|
211
|
+
sockets (`subscribeToSSE`, `connectToChannel`). See
|
|
212
|
+
[references/other-routes.md](references/other-routes.md).
|
|
261
213
|
|
|
262
214
|
## When to pick which transport
|
|
263
215
|
|
|
@@ -268,18 +220,17 @@ and any HTTP `sse: true` routes are listed there.
|
|
|
268
220
|
| Bidirectional (client also sends messages) | **PikkuRealtime** |
|
|
269
221
|
| WebSockets blocked by infra | **subscribeToTopicViaSSE** |
|
|
270
222
|
|
|
271
|
-
Both auto-clean on the server (the eventHub's `onChannelClosed` hook
|
|
272
|
-
|
|
273
|
-
|
|
223
|
+
Both auto-clean on the server (the eventHub's `onChannelClosed` hook unsubscribes
|
|
224
|
+
all topics for the dead channel id). Don't write manual cleanup unless you're
|
|
225
|
+
unsubscribing partway through a session.
|
|
274
226
|
|
|
275
227
|
## What NOT to do
|
|
276
228
|
|
|
277
|
-
- Don't call `eventHub.publish(topic, ..., rawData)` without the
|
|
278
|
-
|
|
279
|
-
- Don't create your own `/events` channel by hand — `pikku enable events`
|
|
280
|
-
|
|
281
|
-
- Don't subscribe inside the render path — use `useEffect`.
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
`as any` to subscribe to a string, declare the topic first.
|
|
229
|
+
- Don't call `eventHub.publish(topic, ..., rawData)` without the `{topic, data}`
|
|
230
|
+
envelope — clients use `topic` to dispatch handlers.
|
|
231
|
+
- Don't create your own `/events` channel by hand — `pikku enable events` already
|
|
232
|
+
does it correctly with disconnect cleanup.
|
|
233
|
+
- Don't subscribe inside the render path — use `useEffect`.
|
|
234
|
+
- Don't subscribe to topics that don't exist in `EventHubTopics`. The generated
|
|
235
|
+
client's types prevent it; if you reach for `as any` to subscribe to a string,
|
|
236
|
+
declare the topic first.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Subscribing to other SSE / WebSocket routes
|
|
2
|
+
|
|
3
|
+
The same `PikkuRealtime` client also handles generic SSE + channel routes (not just
|
|
4
|
+
`/events` topics). Use the path; the base URL is inherited from `PikkuFetch`.
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
// Any `sse: true` HTTP route
|
|
8
|
+
const sub = realtime.subscribeToSSE<{ progress: number }>(
|
|
9
|
+
`/workflow-run/${runId}/stream`,
|
|
10
|
+
(event) => setProgress(event.progress)
|
|
11
|
+
)
|
|
12
|
+
// later: sub.close()
|
|
13
|
+
|
|
14
|
+
// Any wireChannel — open a raw socket, wrap in PikkuWebSocket for typed I/O
|
|
15
|
+
const ws = realtime.connectToChannel('/ws/kanban')
|
|
16
|
+
const typed = new PikkuWebSocket<'kanban-live'>(ws)
|
|
17
|
+
typed.getRoute('command').subscribe('message', (data) => {
|
|
18
|
+
/* ... */
|
|
19
|
+
})
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Discover what's available with `pikku meta clients --json` — `channels` and any HTTP
|
|
23
|
+
`sse: true` routes are listed there.
|