@pikku/cli 0.12.91 → 0.12.92
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/LICENSE +106 -0
- package/console-app/assets/{index-CpkvmAGb.js → index-DDpIMCpy.js} +149 -149
- 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 +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-channel.js +6 -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 +15 -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 +21 -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 +1 -1
- 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 +35 -40
- package/dist/.pikku/function/pikku-functions.gen.js +1 -3
- 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/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-scenarios.gen.d.ts +2 -1
- package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +2 -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 +1 -1
- 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.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 +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/schemas/register.gen.d.ts +4 -0
- package/dist/.pikku/scenarios/schemas/register.gen.js +4 -0
- 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 +5 -3
- package/dist/.pikku/schemas/schemas/FabricSecretsListOutput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/FabricSecretsRotateInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/FabricSecretsRotateOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/FabricSecretsSetOutput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/ScenarioRunInput.schema.json +1 -1
- package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
- package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
- package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +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 +2 -8
- package/dist/.pikku/workflow/pikku-scenario-actors.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-scenario-actors.gen.js +1 -1
- 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 +6 -0
- package/dist/src/deploy/analyzer/analyzer.js +22 -5
- package/dist/src/deploy/build-pipeline.js +5 -1
- package/dist/src/fabric/fabric-commands.d.ts +37 -9
- package/dist/src/fabric/fabric-commands.js +12 -0
- package/dist/src/fabric/functions/domains-add.function.d.ts +4 -4
- package/dist/src/fabric/functions/secrets-list.function.d.ts +16 -4
- package/dist/src/fabric/functions/secrets-list.function.js +12 -10
- package/dist/src/fabric/functions/secrets-rotate.function.d.ts +24 -0
- package/dist/src/fabric/functions/secrets-rotate.function.js +36 -0
- package/dist/src/fabric/functions/secrets-set.function.d.ts +8 -4
- package/dist/src/fabric/functions/secrets-set.function.js +18 -7
- package/dist/src/fabric/lib/http.d.ts +7 -1
- package/dist/src/fabric/lib/sealed-box.d.ts +16 -0
- package/dist/src/fabric/lib/sealed-box.js +72 -0
- package/dist/src/functions/commands/dev.js +9 -0
- package/dist/src/functions/commands/pikku-command-bootstrap.js +1 -0
- package/dist/src/functions/commands/scenario-browser.d.ts +17 -2
- package/dist/src/functions/commands/scenario-browser.js +16 -8
- package/dist/src/functions/commands/scenario-environment.d.ts +32 -0
- package/dist/src/functions/commands/scenario-environment.js +61 -0
- package/dist/src/functions/commands/scenario.d.ts +6 -0
- package/dist/src/functions/commands/scenario.js +14 -9
- package/dist/src/functions/commands/skills.js +27 -61
- package/dist/src/functions/db/db-codegen.d.ts +6 -0
- package/dist/src/functions/db/db-codegen.js +9 -0
- package/dist/src/functions/db/db-migrator.js +14 -0
- package/dist/src/functions/db/local-db.d.ts +8 -0
- package/dist/src/functions/db/local-db.js +24 -2
- package/dist/src/functions/db/migration-identifiers.d.ts +58 -0
- package/dist/src/functions/db/migration-identifiers.js +262 -0
- package/dist/src/functions/db/migration-provenance.d.ts +35 -0
- package/dist/src/functions/db/migration-provenance.js +80 -0
- package/dist/src/functions/db/schema-sql.d.ts +43 -0
- package/dist/src/functions/db/schema-sql.js +135 -0
- package/dist/src/functions/db/sqlite/sqlite-kysely.js +22 -2
- package/dist/src/functions/wirings/functions/schemas.js +13 -1
- package/dist/src/functions/wirings/rpc/pikku-command-rpc.js +6 -1
- package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.d.ts +10 -0
- package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.js +102 -0
- package/dist/src/functions/wirings/scenarios/scenario-partition.d.ts +13 -0
- package/dist/src/functions/wirings/scenarios/scenario-partition.js +15 -2
- package/dist/src/functions/wirings/scenarios/scenario-schema-partition.d.ts +33 -0
- package/dist/src/functions/wirings/scenarios/scenario-schema-partition.js +49 -0
- package/dist/src/functions/workflows/all.workflow.js +2 -7
- package/dist/src/utils/file-writer.js +14 -2
- package/dist/src/utils/pikku-cli-config.d.ts +14 -0
- package/dist/src/utils/pikku-cli-config.js +34 -0
- package/dist/src/utils/remove-legacy-scaffold-file.d.ts +14 -0
- package/dist/src/utils/remove-legacy-scaffold-file.js +23 -0
- package/dist/src/utils/serialize-schemas.d.ts +3 -1
- package/dist/src/utils/serialize-schemas.js +39 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/dist/.pikku/schemas/schemas/PikkuScenarioFunctionsOutput.schema.json +0 -1
- package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.d.ts +0 -1
- package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.js +0 -31
- package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.d.ts +0 -10
- package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.js +0 -104
- package/skills/pikku-addon/SKILL.md +0 -243
- package/skills/pikku-addon/references/addon-package-manifest.md +0 -63
- package/skills/pikku-ai-agent/SKILL.md +0 -231
- package/skills/pikku-ai-vercel/SKILL.md +0 -82
- package/skills/pikku-ai-voice/SKILL.md +0 -88
- package/skills/pikku-audit/SKILL.md +0 -175
- package/skills/pikku-aws/SKILL.md +0 -111
- package/skills/pikku-backblaze/SKILL.md +0 -71
- package/skills/pikku-better-auth/SKILL.md +0 -298
- package/skills/pikku-cli/SKILL.md +0 -198
- package/skills/pikku-cli/references/complete-example.md +0 -82
- package/skills/pikku-concepts/SKILL.md +0 -250
- package/skills/pikku-concepts/references/concept-mapping.md +0 -556
- package/skills/pikku-concepts/references/packages.md +0 -29
- package/skills/pikku-config/SKILL.md +0 -212
- package/skills/pikku-cron/SKILL.md +0 -214
- package/skills/pikku-deploy-azure/SKILL.md +0 -71
- package/skills/pikku-deploy-cloudflare/SKILL.md +0 -82
- package/skills/pikku-deploy-express/SKILL.md +0 -86
- package/skills/pikku-deploy-fastify/SKILL.md +0 -73
- package/skills/pikku-deploy-lambda/SKILL.md +0 -110
- package/skills/pikku-deploy-nextjs/SKILL.md +0 -78
- package/skills/pikku-deploy-uws/SKILL.md +0 -88
- package/skills/pikku-deps/SKILL.md +0 -98
- package/skills/pikku-emails/SKILL.md +0 -163
- package/skills/pikku-fabric/SKILL.md +0 -318
- package/skills/pikku-fabric-debug/SKILL.md +0 -112
- package/skills/pikku-feature/SKILL.md +0 -258
- package/skills/pikku-gateway-slack/SKILL.md +0 -115
- package/skills/pikku-http/SKILL.md +0 -220
- package/skills/pikku-http/references/http-options.md +0 -55
- package/skills/pikku-i18n/SKILL.md +0 -137
- package/skills/pikku-info/SKILL.md +0 -100
- package/skills/pikku-jose/SKILL.md +0 -105
- package/skills/pikku-kysely/SKILL.md +0 -219
- package/skills/pikku-machine-auth/SKILL.md +0 -183
- package/skills/pikku-mcp/SKILL.md +0 -241
- package/skills/pikku-middleware/SKILL.md +0 -231
- package/skills/pikku-middleware/references/middleware-patterns.md +0 -61
- package/skills/pikku-mongodb/SKILL.md +0 -105
- package/skills/pikku-n8n-import/SKILL.md +0 -109
- package/skills/pikku-n8n-import/SPEC.md +0 -84
- package/skills/pikku-n8n-import/references/addon-mapping.md +0 -121
- package/skills/pikku-n8n-import/references/code-translation.md +0 -121
- package/skills/pikku-n8n-import/references/loops-and-control.md +0 -87
- package/skills/pikku-paraglide/SKILL.md +0 -117
- package/skills/pikku-permissions/SKILL.md +0 -192
- package/skills/pikku-pino/SKILL.md +0 -79
- package/skills/pikku-product-second-opinion/README.md +0 -43
- package/skills/pikku-product-second-opinion/SKILL.md +0 -158
- package/skills/pikku-product-second-opinion/example/sample-report.md +0 -90
- package/skills/pikku-product-second-opinion/references/report-template.md +0 -73
- package/skills/pikku-queue/SKILL.md +0 -240
- package/skills/pikku-react/SKILL.md +0 -212
- package/skills/pikku-react-query/SKILL.md +0 -242
- package/skills/pikku-realtime/SKILL.md +0 -236
- package/skills/pikku-realtime/references/other-routes.md +0 -23
- package/skills/pikku-redis/SKILL.md +0 -90
- package/skills/pikku-rpc/SKILL.md +0 -171
- package/skills/pikku-rtl/SKILL.md +0 -219
- package/skills/pikku-scenario/SKILL.md +0 -382
- package/skills/pikku-schedule/SKILL.md +0 -57
- package/skills/pikku-schema-ajv/SKILL.md +0 -62
- package/skills/pikku-schema-cfworker/SKILL.md +0 -63
- package/skills/pikku-security/SKILL.md +0 -108
- package/skills/pikku-services/SKILL.md +0 -248
- package/skills/pikku-services/references/audit-wire-service.md +0 -34
- package/skills/pikku-software-archaeology/README.md +0 -70
- package/skills/pikku-software-archaeology/SKILL.md +0 -186
- package/skills/pikku-software-archaeology/references/blueprint.schema.json +0 -625
- package/skills/pikku-software-archaeology/references/pikku-mapping.md +0 -49
- package/skills/pikku-software-archaeology/scripts/validate.mjs +0 -173
- package/skills/pikku-tag-middleware/SKILL.md +0 -13
- package/skills/pikku-template-clone/SKILL.md +0 -40
- package/skills/pikku-trigger/SKILL.md +0 -181
- package/skills/pikku-versioning/SKILL.md +0 -173
- package/skills/pikku-websocket/SKILL.md +0 -243
- package/skills/pikku-workflow/SKILL.md +0 -172
- package/skills/pikku-workflow/references/workflow-reference.md +0 -63
- package/skills/pikku-workflows-client/SKILL.md +0 -150
- package/skills/pikku-ws/SKILL.md +0 -47
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: pikku-jose
|
|
3
|
-
description: >-
|
|
4
|
-
Use when setting up JWT authentication with the jose library in a Pikku app. Covers
|
|
5
|
-
JoseJWTService constructor, secret rotation, token encoding/decoding/verification. TRIGGER when:
|
|
6
|
-
code uses JoseJWTService, user asks about JWT setup, token signing, token verification, or
|
|
7
|
-
@pikku/jose. DO NOT TRIGGER when: user asks about session middleware (use pikku-security) or
|
|
8
|
-
general service setup (use pikku-services).
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# Pikku Jose (JWT Service)
|
|
12
|
-
|
|
13
|
-
## Agent Operating Procedure
|
|
14
|
-
|
|
15
|
-
Use this skill as an execution checklist, not reference material.
|
|
16
|
-
|
|
17
|
-
1. Discover before editing. Prefer OpenCode tools such as `pikku-meta` when available; otherwise run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
|
|
18
|
-
2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, vendored packages, or broad build artifacts.
|
|
19
|
-
3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
|
|
20
|
-
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.
|
|
21
|
-
5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
|
|
22
|
-
|
|
23
|
-
`@pikku/jose` provides JWT signing, verification, and decoding using the [jose](https://github.com/panva/jose) library. Implements the `JWTService` interface from `@pikku/core`.
|
|
24
|
-
|
|
25
|
-
## Installation
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
yarn add @pikku/jose
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## API Reference
|
|
32
|
-
|
|
33
|
-
### `JoseJWTService`
|
|
34
|
-
|
|
35
|
-
```typescript
|
|
36
|
-
import { JoseJWTService } from '@pikku/jose'
|
|
37
|
-
|
|
38
|
-
const jwt = new JoseJWTService(
|
|
39
|
-
getSecrets: () => Promise<Array<{ id: string; value: string }>>,
|
|
40
|
-
logger?: Logger
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
await jwt.init()
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
**Constructor Parameters:**
|
|
47
|
-
|
|
48
|
-
- `getSecrets` — Async function returning an array of `{ id, value }` key pairs. First key is used for signing; all keys are tried for verification (supports rotation).
|
|
49
|
-
- `logger` — Optional logger instance.
|
|
50
|
-
|
|
51
|
-
**Methods:**
|
|
52
|
-
|
|
53
|
-
- `init(): Promise<void>` — Fetch and cache secrets. Call at startup.
|
|
54
|
-
- `encode<T>(expiresIn: RelativeTimeInput, payload: T): Promise<string>` — Create a signed JWT.
|
|
55
|
-
- `decode<T>(token: string): Promise<T>` — Decode a JWT payload without verification.
|
|
56
|
-
- `verify(token: string): Promise<void>` — Verify a JWT signature and expiry.
|
|
57
|
-
|
|
58
|
-
## Usage Patterns
|
|
59
|
-
|
|
60
|
-
### Basic Setup
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
63
|
-
import { JoseJWTService } from '@pikku/jose'
|
|
64
|
-
|
|
65
|
-
const jwt = new JoseJWTService(
|
|
66
|
-
async () => [{ id: 'key-1', value: process.env.JWT_SECRET! }],
|
|
67
|
-
logger
|
|
68
|
-
)
|
|
69
|
-
await jwt.init()
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Secret Rotation
|
|
73
|
-
|
|
74
|
-
Supply multiple keys. The first is used for signing; all are tried for verification:
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
const jwt = new JoseJWTService(async () => [
|
|
78
|
-
{ id: 'key-2', value: NEW_SECRET }, // signs with this
|
|
79
|
-
{ id: 'key-1', value: OLD_SECRET }, // still verifies tokens signed with this
|
|
80
|
-
])
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### With Pikku Services
|
|
84
|
-
|
|
85
|
-
```typescript
|
|
86
|
-
const createSingletonServices = pikkuServices(async (config) => {
|
|
87
|
-
const logger = new ConsoleLogger()
|
|
88
|
-
const jwt = new JoseJWTService(
|
|
89
|
-
async () => [{ id: 'my-key', value: config.jwtSecret }],
|
|
90
|
-
logger
|
|
91
|
-
)
|
|
92
|
-
await jwt.init()
|
|
93
|
-
return { config, logger, jwt }
|
|
94
|
-
})
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### Encoding & Verifying Tokens
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
const token = await jwt.encode('1h', { userId: 'abc', role: 'admin' })
|
|
101
|
-
|
|
102
|
-
await jwt.verify(token) // throws if invalid/expired
|
|
103
|
-
|
|
104
|
-
const payload = await jwt.decode<{ userId: string; role: string }>(token)
|
|
105
|
-
```
|
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: pikku-kysely
|
|
3
|
-
description: >-
|
|
4
|
-
Use when WRITING KYSELY QUERIES (select/join/aggregate/insert/update/delete) inside a Pikku
|
|
5
|
-
function body, or when setting up SQL database services with Kysely. Covers the query builder
|
|
6
|
-
API (joins, aggregates + groupBy/having, returning, sql template, expression builder, $if,
|
|
7
|
-
transactions, jsonArrayFrom relation helpers) AND @pikku/kysely service setup (channel stores,
|
|
8
|
-
workflow services, secret services, AI storage, deployment services). TRIGGER when: writing any
|
|
9
|
-
non-trivial kysely query (a join, an aggregate/count/sum, groupBy, subquery, transaction, or
|
|
10
|
-
conditional query), the injected `kysely` service is used in a function body, or code uses
|
|
11
|
-
PikkuKysely, KyselyChannelStore, KyselyWorkflowService, KyselySecretService, or the user asks
|
|
12
|
-
about SQL setup with Pikku. DO NOT TRIGGER when: user asks about MongoDB (use pikku-mongodb) or
|
|
13
|
-
Redis (use pikku-redis).
|
|
14
|
-
installGroups: [core]
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
# Pikku Kysely (SQL Database Services)
|
|
18
|
-
|
|
19
|
-
## Agent Operating Procedure
|
|
20
|
-
|
|
21
|
-
Use this skill as an execution checklist, not reference material.
|
|
22
|
-
|
|
23
|
-
1. Discover before editing. Prefer OpenCode tools such as `pikku-meta` when available; otherwise run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
|
|
24
|
-
2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, vendored packages, or broad build artifacts.
|
|
25
|
-
3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
|
|
26
|
-
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.
|
|
27
|
-
5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
|
|
28
|
-
|
|
29
|
-
## Writing Queries — the Kysely query builder
|
|
30
|
-
|
|
31
|
-
In a Pikku function body the injected `kysely` IS the `Kysely<DB>` instance — query it directly. Pikku wires the **CamelCasePlugin**, so you write **camelCase everywhere in TS** (columns, aliases) and raw **snake_case ONLY inside a `` sql`` `` literal**. Kysely is a query builder, NOT an ORM — there are no relations; shape nested data with the JSON helpers below. Never hand-roll SQL strings; never annotate the return type (in Pikku the output zod schema IS the type).
|
|
32
|
-
|
|
33
|
-
```typescript
|
|
34
|
-
import { sql } from 'kysely'
|
|
35
|
-
// Relation helpers are ENGINE-SPECIFIC — import the matching path:
|
|
36
|
-
import { jsonArrayFrom, jsonObjectFrom } from 'kysely/helpers/sqlite' // SQLite / libSQL
|
|
37
|
-
// import { jsonArrayFrom, jsonObjectFrom } from 'kysely/helpers/postgres' // Postgres
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
```typescript
|
|
41
|
-
// SELECT + where/orderBy/limit/offset. Terminals: .execute() | .executeTakeFirst()
|
|
42
|
-
// | .executeTakeFirstOrThrow(() => new NotFoundError()) — pass an error factory.
|
|
43
|
-
const rows = await kysely.selectFrom('item')
|
|
44
|
-
.select(['id', 'name', 'quantity'])
|
|
45
|
-
.where('warehouseId', '=', warehouseId)
|
|
46
|
-
.orderBy('name').limit(50).execute()
|
|
47
|
-
|
|
48
|
-
// JOINS + aliased selects (qualify columns once a join exists)
|
|
49
|
-
await kysely.selectFrom('stock')
|
|
50
|
-
.innerJoin('item', 'item.id', 'stock.itemId')
|
|
51
|
-
.leftJoin('bin as b', 'b.id', 'stock.binId')
|
|
52
|
-
.select(['stock.id', 'item.name as itemName', 'b.code as binCode'])
|
|
53
|
-
.execute()
|
|
54
|
-
|
|
55
|
-
// AGGREGATES via the fn helper + groupBy/having. eb.fn.count returns string|number —
|
|
56
|
-
// cast if you need a JS number (SQLite: CAST(... AS INTEGER)).
|
|
57
|
-
await kysely.selectFrom('stock')
|
|
58
|
-
.select((eb) => ['itemId', eb.fn.sum<number>('quantity').as('onHand')])
|
|
59
|
-
.groupBy('itemId')
|
|
60
|
-
.having((eb) => eb.fn.sum('quantity'), '<', 10) // low-stock
|
|
61
|
-
.execute()
|
|
62
|
-
|
|
63
|
-
// INSERT + RETURNING (one round-trip; works on SQLite & Postgres)
|
|
64
|
-
const created = await kysely.insertInto('item')
|
|
65
|
-
.values({ name: input.name, warehouseId })
|
|
66
|
-
.returning(['id', 'name']).executeTakeFirstOrThrow()
|
|
67
|
-
|
|
68
|
-
// UPDATE + RETURNING, DELETE
|
|
69
|
-
await kysely.updateTable('item').set({ quantity: input.quantity })
|
|
70
|
-
.where('id', '=', input.id).returning(['id', 'quantity']).executeTakeFirstOrThrow()
|
|
71
|
-
await kysely.deleteFrom('item').where('id', '=', input.id).execute()
|
|
72
|
-
|
|
73
|
-
// EXPRESSION BUILDER for and/or; $if for conditional building; sql for raw fragments
|
|
74
|
-
await kysely.selectFrom('item')
|
|
75
|
-
.selectAll()
|
|
76
|
-
.where((eb) => eb.or([eb('quantity', '=', 0), eb('discontinued', '=', true)]))
|
|
77
|
-
.$if(!!input.search, (qb) => qb.where('name', 'like', `%${input.search}%`))
|
|
78
|
-
.select(sql<number>`quantity * unit_cost`.as('value')) // snake_case ok inside sql``
|
|
79
|
-
.execute()
|
|
80
|
-
|
|
81
|
-
// NESTED DATA (no relations) — jsonObjectFrom (one) / jsonArrayFrom (many)
|
|
82
|
-
await kysely.selectFrom('warehouse')
|
|
83
|
-
.select((eb) => ['warehouse.id', 'warehouse.name',
|
|
84
|
-
jsonArrayFrom(eb.selectFrom('bin').select(['bin.id', 'bin.code'])
|
|
85
|
-
.whereRef('bin.warehouseId', '=', 'warehouse.id')).as('bins')])
|
|
86
|
-
.execute()
|
|
87
|
-
|
|
88
|
-
// TRANSACTION — multi-write atomicity. Use trx (not kysely) inside.
|
|
89
|
-
await kysely.transaction().execute(async (trx) => {
|
|
90
|
-
await trx.updateTable('stock').set({ quantity: 0 }).where('itemId', '=', id).execute()
|
|
91
|
-
await trx.insertInto('stockMove').values({ itemId: id, delta: -qty }).execute()
|
|
92
|
-
})
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Pikku provides SQL database services through four packages:
|
|
96
|
-
|
|
97
|
-
- `@pikku/kysely` — Base service implementations (database-agnostic)
|
|
98
|
-
- `@pikku/kysely-postgres` — PostgreSQL-specific implementations + `PikkuKysely` connection wrapper
|
|
99
|
-
- `@pikku/kysely-mysql` — MySQL-specific implementations
|
|
100
|
-
- `@pikku/kysely-sqlite` — SQLite-specific implementations + `createSQLiteKysely` factory
|
|
101
|
-
|
|
102
|
-
All implement standard Pikku interfaces from `@pikku/core`.
|
|
103
|
-
|
|
104
|
-
## Installation
|
|
105
|
-
|
|
106
|
-
```bash
|
|
107
|
-
# Pick your database
|
|
108
|
-
yarn add @pikku/kysely @pikku/kysely-postgres # PostgreSQL
|
|
109
|
-
yarn add @pikku/kysely @pikku/kysely-mysql # MySQL
|
|
110
|
-
yarn add @pikku/kysely @pikku/kysely-sqlite # SQLite
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## API Reference
|
|
114
|
-
|
|
115
|
-
### PostgreSQL Connection — `PikkuKysely`
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
import { PikkuKysely } from '@pikku/kysely-postgres'
|
|
119
|
-
|
|
120
|
-
const db = new PikkuKysely<DB>(
|
|
121
|
-
logger: Logger,
|
|
122
|
-
connectionOrConfig: postgres.Sql | postgres.Options | string,
|
|
123
|
-
defaultSchemaName?: string
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
await db.init()
|
|
127
|
-
db.kysely // Kysely<DB> instance for queries
|
|
128
|
-
await db.close()
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### SQLite Factory — `createSQLiteKysely`
|
|
132
|
-
|
|
133
|
-
```typescript
|
|
134
|
-
import { createSQLiteKysely } from '@pikku/kysely-sqlite'
|
|
135
|
-
|
|
136
|
-
const kysely = createSQLiteKysely(database: SqliteDatabase | (() => Promise<SqliteDatabase>))
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### Available Services
|
|
140
|
-
|
|
141
|
-
Each database variant exports these services with a prefix (`Pg`, `MySQL`, `SQLite`, or base `Kysely`):
|
|
142
|
-
|
|
143
|
-
| Service | Interface | Purpose |
|
|
144
|
-
| --------------------- | ------------------------------------- | ---------------------------------------------- |
|
|
145
|
-
| `*ChannelStore` | `ChannelStore` | WebSocket channel state persistence |
|
|
146
|
-
| `*EventHubStore` | `EventHubStore` | Event hub state persistence |
|
|
147
|
-
| `*WorkflowService` | `PikkuWorkflowService` | Workflow definition storage |
|
|
148
|
-
| `*WorkflowRunService` | `WorkflowRunService` | Workflow execution tracking |
|
|
149
|
-
| `*DeploymentService` | `DeploymentService` | Deployment state management |
|
|
150
|
-
| `*AIStorageService` | `AIStorageService, AIRunStateService` | AI conversation/run storage |
|
|
151
|
-
| `*AgentRunService` | `AgentRunService` | Agent execution tracking |
|
|
152
|
-
| `*SecretService` | `SecretService` | Encrypted secret storage (envelope encryption) |
|
|
153
|
-
|
|
154
|
-
All services take a `Kysely<KyselyPikkuDB>` instance in their constructor and have an `init()` method that creates tables if needed.
|
|
155
|
-
|
|
156
|
-
### Secret Service
|
|
157
|
-
|
|
158
|
-
```typescript
|
|
159
|
-
import { PgKyselySecretService } from '@pikku/kysely-postgres'
|
|
160
|
-
|
|
161
|
-
const secrets = new PgKyselySecretService(db.kysely, {
|
|
162
|
-
kekSecret: 'your-key-encryption-key',
|
|
163
|
-
salt: 'your-salt',
|
|
164
|
-
})
|
|
165
|
-
await secrets.init()
|
|
166
|
-
|
|
167
|
-
await secrets.setSecret('api-key', { key: 'sk-...' })
|
|
168
|
-
const value = await secrets.getSecret<{ key: string }>('api-key')
|
|
169
|
-
await secrets.rotateKEK() // Re-encrypt all secrets with new KEK
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
## Usage Patterns
|
|
173
|
-
|
|
174
|
-
### PostgreSQL Setup
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
import {
|
|
178
|
-
PikkuKysely,
|
|
179
|
-
PgKyselyChannelStore,
|
|
180
|
-
PgKyselyWorkflowService,
|
|
181
|
-
} from '@pikku/kysely-postgres'
|
|
182
|
-
|
|
183
|
-
const createSingletonServices = pikkuServices(async (config) => {
|
|
184
|
-
const logger = new PinoLogger()
|
|
185
|
-
const db = new PikkuKysely(logger, config.databaseUrl)
|
|
186
|
-
await db.init()
|
|
187
|
-
|
|
188
|
-
const channelStore = new PgKyselyChannelStore(db.kysely)
|
|
189
|
-
await channelStore.init()
|
|
190
|
-
|
|
191
|
-
const workflowService = new PgKyselyWorkflowService(db.kysely)
|
|
192
|
-
await workflowService.init()
|
|
193
|
-
|
|
194
|
-
return { config, logger, database: db, channelStore, workflowService }
|
|
195
|
-
})
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### SQLite Setup
|
|
199
|
-
|
|
200
|
-
```typescript
|
|
201
|
-
import {
|
|
202
|
-
createSQLiteKysely,
|
|
203
|
-
SQLiteKyselyChannelStore,
|
|
204
|
-
} from '@pikku/kysely-sqlite'
|
|
205
|
-
import Database from 'better-sqlite3'
|
|
206
|
-
|
|
207
|
-
const kysely = createSQLiteKysely(new Database('app.db'))
|
|
208
|
-
const channelStore = new SQLiteKyselyChannelStore(kysely)
|
|
209
|
-
await channelStore.init()
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
### MySQL Setup
|
|
213
|
-
|
|
214
|
-
```typescript
|
|
215
|
-
import { MySQLKyselyWorkflowService } from '@pikku/kysely-mysql'
|
|
216
|
-
|
|
217
|
-
const workflowService = new MySQLKyselyWorkflowService(kyselyInstance)
|
|
218
|
-
await workflowService.init()
|
|
219
|
-
```
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: pikku-machine-auth
|
|
3
|
-
description: >-
|
|
4
|
-
Use when authenticating a CLI/agent/service against a Pikku server, adding machine-to-machine
|
|
5
|
-
(M2M) auth, issuing scoped API keys for sandboxes/agents/workers, or wiring better-auth sessions
|
|
6
|
-
into Pikku middleware. Covers `pikku login` (device-authorization), the better-auth API Key
|
|
7
|
-
plugin, machine identities, and `betterAuthSession` with the api-key branch. TRIGGER when: user
|
|
8
|
-
asks about CLI login, `pikku login`, machine agents, service-to-service auth, API keys, client
|
|
9
|
-
credentials, sandbox/worker tokens, or resolving a better-auth session in a Pikku function. DO
|
|
10
|
-
NOT TRIGGER when: user asks about end-user HTTP session/cookie auth only (use pikku-http + the
|
|
11
|
-
app betterAuth config) or about WebSocket channel mechanics (use pikku-websocket).
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
# Pikku Machine Auth
|
|
15
|
-
|
|
16
|
-
Unified authentication for humans **and** machines against a Pikku + better-auth
|
|
17
|
-
server. Two paths, two headers, one resolver:
|
|
18
|
-
|
|
19
|
-
| Caller | Credential | Header | Obtained by |
|
|
20
|
-
|---|---|---|---|
|
|
21
|
-
| **Human** (CLI, dev) | better-auth session token | `Authorization: Bearer <token>` | `pikku login` (device flow) → `~/.pikku/session.json` |
|
|
22
|
-
| **Machine** (agent, sandbox, worker) | scoped API key | `x-api-key: <key>` | `createApiKey` (server-side, at provision/spawn) |
|
|
23
|
-
|
|
24
|
-
Both resolve to a Pikku `UserSession` through one middleware:
|
|
25
|
-
`betterAuthSession({ mapSession, apiKey: { mapKey } })`.
|
|
26
|
-
|
|
27
|
-
> The literal OAuth `client_credentials` grant is **not** implemented in
|
|
28
|
-
> better-auth's oidc-provider. The API Key plugin gives the same capability (a
|
|
29
|
-
> baked secret a service presents for scoped access), not the wire protocol.
|
|
30
|
-
|
|
31
|
-
## Agent Operating Procedure
|
|
32
|
-
|
|
33
|
-
1. Discover before editing — inspect the app's `betterAuth({ plugins: [...] })`
|
|
34
|
-
config and existing middleware wiring before adding anything.
|
|
35
|
-
2. Server changes go in the auth factory + a middleware wiring file; never put
|
|
36
|
-
auth checks in a function body (use `permissions`).
|
|
37
|
-
3. The API Key plugin contributes an `apikey` table — add the matching SQL
|
|
38
|
-
migration and regenerate DB types before relying on it.
|
|
39
|
-
4. Validate with the narrowest command, then `pikku all`.
|
|
40
|
-
|
|
41
|
-
## Human path — `pikku login`
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
pikku login --url https://app.example.com # device-authorization flow
|
|
45
|
-
pikku whoami # show current session + expiry
|
|
46
|
-
pikku logout # remove stored session
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
`pikku login` runs the RFC 8628 device flow: it requests a code, opens the
|
|
50
|
-
browser to the verification URL, polls until you approve, then stores the
|
|
51
|
-
session token (keyed by base URL) at `~/.pikku/session.json` with its expiry.
|
|
52
|
-
|
|
53
|
-
**Server requirement** — enable the `deviceAuthorization` and `bearer` plugins:
|
|
54
|
-
|
|
55
|
-
```typescript
|
|
56
|
-
import { deviceAuthorization, bearer } from 'better-auth/plugins'
|
|
57
|
-
|
|
58
|
-
betterAuth({
|
|
59
|
-
// ...
|
|
60
|
-
plugins: [
|
|
61
|
-
deviceAuthorization({ expiresIn: '5min', interval: '5s', schema: {} }),
|
|
62
|
-
bearer(), // lets `Authorization: Bearer <session-token>` resolve a session
|
|
63
|
-
],
|
|
64
|
-
})
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
The browser approval is two steps the user's browser does automatically:
|
|
68
|
-
`GET /auth/device?user_code=XXXX` (claims the code while signed in) then
|
|
69
|
-
`POST /auth/device/approve`. The CLI only requests the code and polls
|
|
70
|
-
`POST /auth/device/token`.
|
|
71
|
-
|
|
72
|
-
## Machine path — API keys
|
|
73
|
-
|
|
74
|
-
Install the plugin (separate official package) and enable it:
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
yarn add @better-auth/api-key # peer: better-auth ^1.6.19
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
import { apiKey } from '@better-auth/api-key'
|
|
82
|
-
|
|
83
|
-
betterAuth({
|
|
84
|
-
plugins: [
|
|
85
|
-
apiKey({
|
|
86
|
-
enableMetadata: true, // REQUIRED to store scope on the key
|
|
87
|
-
enableSessionForAPIKeys: true, // lets a key resolve via getSession too
|
|
88
|
-
}),
|
|
89
|
-
],
|
|
90
|
-
})
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### Identity model
|
|
94
|
-
|
|
95
|
-
A **machine is an API key, not a throwaway user.** Keys are owned by a small set
|
|
96
|
-
of stable **service-user** identities you provision once (e.g. `orchestrator`,
|
|
97
|
-
`machine-agent`, `builder`, `sandbox-runtime`). Per-machine scope rides on the
|
|
98
|
-
key's `metadata`/`permissions`. A key requires a real owning user row — minting
|
|
99
|
-
one for a non-existent `userId` is created but will not resolve.
|
|
100
|
-
|
|
101
|
-
### Mint a scoped key (server-side, at spawn/provision)
|
|
102
|
-
|
|
103
|
-
```typescript
|
|
104
|
-
// `auth` is the better-auth instance (injected service)
|
|
105
|
-
const { key } = await auth.api.createApiKey({
|
|
106
|
-
body: {
|
|
107
|
-
userId: sandboxRuntimeUserId, // a stable service user
|
|
108
|
-
name: `sandbox:${sandboxId}`,
|
|
109
|
-
expiresIn: 60 * 60, // seconds
|
|
110
|
-
metadata: { sandboxId }, // keep only STABLE ids here
|
|
111
|
-
permissions: { sandbox: ['read', 'write'] },
|
|
112
|
-
},
|
|
113
|
-
})
|
|
114
|
-
// inject `key` into the machine's env; it sends it as `x-api-key`.
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
Rotate by minting a new key and expiring/deleting the old (`deleteApiKey`);
|
|
118
|
-
multiple active keys per identity allow zero-downtime rotation.
|
|
119
|
-
|
|
120
|
-
### Resolve scope — `verifyApiKey`, not `getSession`
|
|
121
|
-
|
|
122
|
-
`getSession(x-api-key)` returns only a bare mock session **without** the
|
|
123
|
-
metadata. Scope must come from `verifyApiKey`, which returns
|
|
124
|
-
`{ valid, key: { userId, metadata, permissions } }`. The
|
|
125
|
-
`betterAuthSession` api-key branch does this for you:
|
|
126
|
-
|
|
127
|
-
```typescript
|
|
128
|
-
import { betterAuthSession } from '@pikku/better-auth'
|
|
129
|
-
import { addHTTPMiddleware } from '@pikku/core/http'
|
|
130
|
-
|
|
131
|
-
addHTTPMiddleware([
|
|
132
|
-
betterAuthSession({
|
|
133
|
-
// human path: getSession result -> app session
|
|
134
|
-
mapSession: ({ user }) => ({ userId: user.id }),
|
|
135
|
-
// machine path: verified key -> app session. `services` lets you resolve
|
|
136
|
-
// CURRENT scope (e.g. look up the owning row) instead of trusting only the
|
|
137
|
-
// baked metadata.
|
|
138
|
-
apiKey: {
|
|
139
|
-
header: 'x-api-key', // default
|
|
140
|
-
mapKey: async (key, services) => {
|
|
141
|
-
const sandboxId = key.metadata?.sandboxId
|
|
142
|
-
if (!sandboxId) return null // reject
|
|
143
|
-
const row = await services.kysely
|
|
144
|
-
.selectFrom('sandboxInstance')
|
|
145
|
-
.innerJoin('sandbox', 'sandbox.id', 'sandboxInstance.sandboxId')
|
|
146
|
-
.select(['sandbox.orgId', 'sandbox.projectId'])
|
|
147
|
-
.where('sandboxInstance.sandboxId', '=', sandboxId)
|
|
148
|
-
.where('sandboxInstance.stoppedAt', 'is', null)
|
|
149
|
-
.executeTakeFirst()
|
|
150
|
-
if (!row) return null
|
|
151
|
-
return { userId: sandboxId, orgId: row.orgId, role: 'sandbox' }
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
}),
|
|
155
|
-
])
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
When the api-key header is present it is authoritative — the middleware never
|
|
159
|
-
falls through to `getSession` (a bare mock session would shadow the scoped one).
|
|
160
|
-
When it is absent, the human `getSession` path runs as normal.
|
|
161
|
-
|
|
162
|
-
### WebSocket channels authenticate on the upgrade handshake
|
|
163
|
-
|
|
164
|
-
Generated channel CLI clients attach the credential as a connection header
|
|
165
|
-
(`x-api-key` for `PIKKU_API_KEY`, else `Authorization: Bearer` from
|
|
166
|
-
`~/.pikku/session.json`). The `@pikku/ws` server copies the upgrade-request
|
|
167
|
-
headers into the channel's `http.request` and runs the inherited HTTP `*`
|
|
168
|
-
middleware during `runUpgradeMiddleware`, so `betterAuthSession` resolves the
|
|
169
|
-
session before the channel opens. For this to work the app must register
|
|
170
|
-
`betterAuthSession` via `addHTTPMiddleware([...])` (the `*` group) — not only on
|
|
171
|
-
specific routes — so it is inherited into the channel upgrade. Browser clients
|
|
172
|
-
cannot set WebSocket headers, so header-auth only covers the Node CLI path; a
|
|
173
|
-
browser channel needs a query-param/subprotocol vector instead.
|
|
174
|
-
|
|
175
|
-
## Gotchas
|
|
176
|
-
|
|
177
|
-
- `apiKey()` rejects `metadata` unless `enableMetadata: true`.
|
|
178
|
-
- `deviceAuthorization()` requires a `schema` option (pass `schema: {}`).
|
|
179
|
-
- Keep the two paths on **different headers** — `x-api-key` (machine) vs
|
|
180
|
-
`Authorization: Bearer` (human). One header for both reintroduces ambiguity.
|
|
181
|
-
- The `apikey` table is plugin-contributed — add the SQL migration + regen types.
|
|
182
|
-
- `~/.pikku/session.json` is written `0600` and stores the token + expiry; the
|
|
183
|
-
CLI uses the expiry to detect when a re-login is needed.
|