@pikku/kysely 0.13.37 → 0.13.39
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/bin/pikku-kysely-pure.js +0 -0
- package/dist/src/kysely-incoming-webhook-service.d.ts +1 -0
- package/dist/src/kysely-incoming-webhook-service.js +8 -0
- package/package.json +15 -9
- package/CHANGELOG.md +0 -2347
- package/knowledge/decisions/a-console-role-cannot-take-a-system-roles-name.md +0 -25
- package/knowledge/decisions/a-credential-with-no-user-is-one-row-per-name.md +0 -22
- package/knowledge/decisions/a-lease-is-taken-by-one-guarded-update.md +0 -30
- package/knowledge/decisions/a-virtual-users-schedule-starts-disabled.md +0 -23
- package/knowledge/decisions/classification-driven-encryption-happens-in-a-plugin.md +0 -71
- package/knowledge/decisions/grants-reference-declared-scopes-and-users-by-foreign-key.md +0 -29
- package/knowledge/decisions/index.md +0 -21
- package/knowledge/decisions/keks-are-scoped-by-purpose-as-well-as-version.md +0 -45
- package/knowledge/decisions/leases-are-judged-by-the-database-clock.md +0 -42
- package/knowledge/decisions/the-plugin-is-given-a-resolver-never-a-key.md +0 -45
- package/knowledge/decisions/the-secrets-audit-table-is-declared-even-when-auditing-is-off.md +0 -22
- package/knowledge/decisions/workflows-own-the-lease-table-too.md +0 -22
- package/knowledge/index.md +0 -19
- package/knowledge/questions/do-the-kysely-stores-check-who-calls-them.md +0 -27
- package/knowledge/questions/does-a-trigger-source-row-hold-only-provider-identifiers.md +0 -26
- package/knowledge/questions/index.md +0 -17
- package/knowledge/questions/should-pikku-user-sessions-expire-on-their-own.md +0 -21
- package/knowledge/questions/should-secret-and-credential-reads-be-audited-by-default.md +0 -32
- package/run-tests.sh +0 -61
package/CHANGELOG.md
DELETED
|
@@ -1,2347 +0,0 @@
|
|
|
1
|
-
## 0.13.37
|
|
2
|
-
|
|
3
|
-
### Patch Changes
|
|
4
|
-
|
|
5
|
-
- fdcc821: Fabric is gone from the open toolchain. The previous names are removed with no aliases.
|
|
6
|
-
|
|
7
|
-
The CLI group is `pikku cloud …` and the export is `@pikku/cli/cloud`. The project link is the `cloud` key of `pikku.config.json` (`cloud.projectId`), the CLI keeps its local state in `~/.pikkustudio` (run `pikku cloud login` again), and the project config file is `pikkustudio.config.json`.
|
|
8
|
-
|
|
9
|
-
Every environment variable drops the `FABRIC_` prefix for `PIKKUSTUDIO_` with the same suffix: `PIKKUSTUDIO_API_URL`, `PIKKUSTUDIO_PROJECT_ID`, `PIKKUSTUDIO_TOKEN`, `PIKKUSTUDIO_OPERATOR_TOKEN`, `PIKKUSTUDIO_AUTH_PUBLIC_KEY`, `PIKKUSTUDIO_STAGE_ID` and the rest. Rename them wherever you set them.
|
|
10
|
-
|
|
11
|
-
Wire ids: the operator sign-in route is `/sign-in/cloud`, the plugin and mode literal is `'cloud'`, the Better Auth plugin is `pikkuCloud`, its session field is `pikkustudioadmin`, and the signature header is `x-cloud-sig`. The cloud API calls are `getCloudLogs`, `getCloudLogsByStageKind`, `cloudCliProjects`, `cloudCliDeployments`, `providedByCloud` and `recordCloudAnalyticsEvents`. Addon packages are `@pikkustudio/*`, scaffolded files live under `scaffold/cloud` and `__cloud_*__`, and the API hosts are the `pikkustudio.app` and `pikkustudio.dev` domains.
|
|
12
|
-
|
|
13
|
-
`pikku skills install --fabric` is `--cloud`, the install group is `cloud`, and the skills are `pikku-cloud`, `pikku-cloud-debug`, `pikku-admin-to-cloud` and `pikku-blueprint-to-cloud`.
|
|
14
|
-
|
|
15
|
-
The stale analytics forwarder copies are removed from the online-shop example and the starter template.
|
|
16
|
-
|
|
17
|
-
The sealed-box salt stays `pikkufabric/sealed-box/v1`: it is a cryptographic constant that already-sealed secrets depend on.
|
|
18
|
-
|
|
19
|
-
- 33b102d: Virtual users now have one name everywhere. The id column of `virtual_user_run` and `virtual_user_schedule` is `virtual_user_id` (a migration renames it in place), the CLI group is `pikku virtual-user …`, and the declarations and imports live under `@pikku/core/virtual-user`. The previous names are removed with no aliases.
|
|
20
|
-
|
|
21
|
-
The default virtual user email domain is now `virtualuser.invalid`: apps that rely on the default domain get new accounts at the next provisioning (`pikku virtual-user sync`, deploy, or `pikku dev` start), and the old rows stay unused.
|
|
22
|
-
|
|
23
|
-
The sign-in surface carries the same name. The route is `/sign-in/virtual-user`, the environment variables are `PIKKU_ALLOW_VIRTUAL_USER_SIGN_IN` and the `PIKKU_DEV_VIRTUAL_USER_SIGN_IN` / `VITE_*` equivalents, the Better Auth plugin is `pikkuVirtualUser`, the scenario step option and wire member are `virtualUser` and `virtualUsers`, and the Better Auth user flag column is `virtual_user`. Rename the environment variables wherever you set them, and add a migration that renames the flag column on the `user` table. Nothing is aliased.
|
|
24
|
-
|
|
25
|
-
The conversation runner is now `@pikku/core/virtual-user/conversation`, replacing the old `-flow` subpath. Update the import; the old subpath is gone.
|
|
26
|
-
|
|
27
|
-
- Updated dependencies [fdcc821]
|
|
28
|
-
- Updated dependencies [33b102d]
|
|
29
|
-
- Updated dependencies [6a25c70]
|
|
30
|
-
- Updated dependencies [a084c3b]
|
|
31
|
-
- @pikku/core@0.12.142
|
|
32
|
-
|
|
33
|
-
## 0.13.36
|
|
34
|
-
|
|
35
|
-
### Patch Changes
|
|
36
|
-
|
|
37
|
-
- e0846b5: Saving an agent's tool messages skips a tool call whose result is undefined instead of writing it. When the browser driver for a scenario cannot be loaded, the error now includes the underlying cause and tells you to `bun add -D` it.
|
|
38
|
-
- 884a1b5: MySQL: the `@pikku/kysely` stores no longer emit postgres/sqlite-only SQL. Upserts use `on duplicate key update`, insert-or-ignore uses `insert ignore`, `returning` deletes read the rows first, the lease clock casts to `signed`, workflow JSON state uses `CAST(... AS JSON)`, the agent thread owner `LIKE` escapes with `!`, and timestamp columns are written as `Date`s instead of `Z`-suffixed ISO strings. `pikku db generate` now emits the `scope` schema when Better Auth's user model is a mapped table (for example a Rails `users` table), typing the key column from the real `users.id`.
|
|
39
|
-
- 51ec3ac: MySQL fixes found moving a Rails database onto pikku.
|
|
40
|
-
|
|
41
|
-
- The generated local services (`pikku db baseline`, `pikku dev`, `pikku all`, a local CLI) open MySQL: a `mysql://` `DATABASE_URL` or `mysqlUrl` in the config opens through a Kysely `MysqlDialect` on a `mysql2` pool (declare `mysql2` in the project), with `CamelCasePlugin` and the coercion map like the other dialects. A `mysql://` URL was read as a sqlite file path. `db/mysql` now counts as a project database, and `@pikku/kysely` re-exports `MysqlDialect`.
|
|
42
|
-
- MySQL migrations run with `FOREIGN_KEY_CHECKS` off, so a mysqldump whose tables reference ones created later applies as it is.
|
|
43
|
-
- `TINYINT(1)` is typed `boolean` and coerced at runtime (mysql2 returns 0/1); an explicit `tsType` in `db/annotations.ts` keeps it a number. `DECIMAL` is read as a number (`decimalNumbers`), as the generated types say. `BIGINT` stays `number`, exact to 2^53, which is mysql2's default.
|
|
44
|
-
- `pikku all` no longer throws "db/mysql exists but no mysqlUrl is configured": the server comes from createConfig's `mysqlUrl`, `db.mysqlUrl` or a `mysql://` `DATABASE_URL`, and with none the stub `DB` is written.
|
|
45
|
-
- Better Auth schema derivation follows the resolved database rather than the factory's `database.type`, so a factory declaring `type: 'sqlite'` no longer sends SQLite introspection (`pragma index_list`) to a MySQL server. Set `type: 'mysql'` in the factory too, so the runtime matches.
|
|
46
|
-
|
|
47
|
-
- Updated dependencies [f396538]
|
|
48
|
-
- @pikku/core@0.12.140
|
|
49
|
-
|
|
50
|
-
## 0.13.35
|
|
51
|
-
|
|
52
|
-
### Patch Changes
|
|
53
|
-
|
|
54
|
-
- 15c4968: The default runtime path no longer needs `node:*`, `Buffer` or an unguarded `process`, so it loads on edge runtimes (Web APIs only).
|
|
55
|
-
|
|
56
|
-
**Breaking:** `FileScenarioRunStore`, `scenarioArtifactContentType` and `scenarioRunSummary` leave the `@pikku/core/services` barrel because they use `node:fs`. Import them from `@pikku/core/services/file-scenario-run-store`. Pre-0.13 breaking changes still ship as a patch.
|
|
57
|
-
|
|
58
|
-
**Breaking:** the HMAC helpers in `@pikku/core/hmac` run on Web Crypto, which is async. `hmacSha256Hex`, `hmacDigest`, `verifyHmacSignature` and `verifyPublicKeySignature` now return a Promise; `timingSafeStringEqual` stays synchronous. `WebhookService.sign` and `WebhookService.verify` return a Promise, and so does `verifySlackSignature` in `@pikku/gateway-slack`: `await` them. A function-style `verify` on a webhook source may return a Promise as well. `verifyPublicKeySignature` accepts RSA and EC (P-256, P-384, P-521) PEM keys; Ed25519 and RSA-PSS keys verify as false.
|
|
59
|
-
|
|
60
|
-
`isProduction()` (and the `PIKKU_MODEL_ALIASES` and `PIKKU_ENV` reads) now ask the registered singleton services' `variables` service first, then `process.env` when `process` exists. With neither, `isProduction()` is true, so an edge deployment never exposes error details by accident. `LocalVariablesService` resolves its `process.env` default when constructed and falls back to an empty store without `process`.
|
|
61
|
-
|
|
62
|
-
Workflow invocation ids use a built-in SHA-1 and stay byte-identical. `@pikku/kysely` and the Cloudflare hibernation server use `globalThis.crypto.randomUUID()` and no `Buffer`; `@pikku/kysely` is marked `sideEffects: false`. `@pikku/ai-deepinfra` reads `DEEPINFRA_API_KEY` only when `process` exists and decodes base64 audio without `Buffer`.
|
|
63
|
-
|
|
64
|
-
Runtime tiers. A package declares where it can run in `package.json`: `"pikku": { "runtime": "edge" | "serverless" | "server" }`, with optional per-subpath overrides (`"exports": { "./dev": "server" }`). `server` is the default. `@pikku/core` and the default services are `edge` (core's Node-only subpaths are `server`), `@pikku/better-auth`, `@pikku/addon-admin` and `@pikku/cloudflare` are `serverless` (better-auth statically imports `node:crypto` scrypt), and `@pikku/addon-console` is `server` and must never land in a deployed unit.
|
|
65
|
-
|
|
66
|
-
`pikku deploy` now verifies each deployed unit before bundling it. The unit is bundled with esbuild (neutral platform, `workerd`/`worker`/`browser` conditions) under its tier's profile, ahead of the adapter's aliases and stubs so they cannot hide anything, and the build fails when the bundle holds a package declared above the unit's tier or a Node built-in the runtime does not provide. The error names the unit, package, import chain and the fix. A built-in the provider stubs is a warning. On an edge unit, a bundled `InMemory*` class also fails the build. The unit's tier is its `runtime`, else the project's own `pikku.runtime`, else the provider default (`serverless` on Cloudflare). Packages that declare nothing are judged by their imports only.
|
|
67
|
-
|
|
68
|
-
`ProviderAdapter.getRuntimeProfile(tier?)` returns the compat date, compat flags, the built-ins the runtime provides (keyed by compat date), the stubbed ones and the externals. The Cloudflare adapter derives `wrangler.toml`, the upload metadata and the bundle externals from it; `node:os` and `node:fs` are not provided before compat date 2025-09-15. The default is `nodejs_compat_v2` with compat date 2024-12-18, which is what `wrangler.toml` and Fabric's live workers already use, so Fabric deploys see no runtime change. Only the direct-API upload in `@pikku/deploy-cloudflare` (`createWorker`, used by its own `deploy()`) moves: it sent `nodejs_compat` with 2024-01-01 before. A newer date or flag is opt-in through the adapter option `new CloudflareProviderAdapter({ compatDate })` or `getCloudflareRuntimeProfile(tier, compatDate)`. From 2025-08-15 `node:http` and `node:https` exist, and from 2025-09-15 `node:os`, `node:fs` (stubbed by the build regardless) and `node:perf_hooks`; the verifier's allowed built-ins follow the effective date. A newer date changes the runtime of every worker deployed with it.
|
|
69
|
-
|
|
70
|
-
`declareScopes(['pikku:console'])` (from `@pikku/core/scope`) declares scopes by id without wiring anything. `wireAddon({ scopes })` only requires a scope of an addon's functions; the tree arrives with the addon's metadata, so a role granting `pikku:console` used to fail PKU124 unless the addon was wired, and a wired `@pikku/addon-console` lands in every unit carrying the `/rpc` catch-all. An app that grants the scope without the console now calls `declareScopes` and no longer needs the scaffold or the addon. When the addon is wired its tree and descriptions win and the bare id adds nothing.
|
|
71
|
-
|
|
72
|
-
More packages declare a tier after bundling each with the edge profile. `edge`: `@pikku/addon-graph`, `@pikku/pino`, `@pikku/jose`, `@pikku/ai-vercel`, `@pikku/ai-voice`. `serverless`: `@pikku/kysely-postgres` (postgres.js needs `node:buffer`, `stream`, `events`), `@pikku/backblaze` (`copyFile` reads a local file, which the build stubs), `@pikku/gateway-slack` (`@slack/web-api` imports `node:os` and `zlib`). `server`: `@pikku/schedule` (`cron` imports `child_process`), `@pikku/aws-services` (the AWS SDK's Node handler needs `node:http2`), `@pikku/browser` (puppeteer), and `@pikku/modelcontextprotocol` except its `./fetch` subpath, which is `edge`.
|
|
73
|
-
|
|
74
|
-
`@pikku/addon-graph` no longer needs `node:crypto` or `Buffer`: the Crypto function hashes and HMACs on Web Crypto (MD5 is built in, since Web Crypto has none) and encodes with `TextEncoder`/`atob`/`btoa`, with output unchanged.
|
|
75
|
-
|
|
76
|
-
- Updated dependencies [6f11bb5]
|
|
77
|
-
- Updated dependencies [0c67e33]
|
|
78
|
-
- Updated dependencies [15c4968]
|
|
79
|
-
- Updated dependencies [d75a23d]
|
|
80
|
-
- Updated dependencies [9b12c8a]
|
|
81
|
-
- @pikku/core@0.12.138
|
|
82
|
-
|
|
83
|
-
## 0.13.34
|
|
84
|
-
|
|
85
|
-
### Patch Changes
|
|
86
|
-
|
|
87
|
-
- 80c94f9: MySQL is a third dialect for the `pikku db` commands, beside sqlite and postgres.
|
|
88
|
-
|
|
89
|
-
Set `mysqlUrl` in `createConfig` and `db migrate`, `generate`, `check`, `baseline`, `reset`, `codegen` and the dev seed behave as they do elsewhere, with migrations in `db/mysql/` and the seed in `db/mysql-dev-seed.sql`. MySQL has no embedded engine, so a command that needs a throwaway database creates and drops a `pikku_scratch_<hex>` one on your server — the account needs `CREATE` and `DROP`. DDL is not transactional there, so a migration that fails halfway is replayed from the top. `db.schema` is refused, because a MySQL schema is a database.
|
|
90
|
-
|
|
91
|
-
`@pikku/migrator-sql` gains `@pikku/migrator-sql/mysql`. The runtime schemas in `@pikku/kysely` now compile for MySQL without changing what sqlite and postgres get: keys are `varchar(255)`, free text is `longtext`, literal text defaults are expressions, and foreign keys are table-level constraints, because MySQL parses an inline `REFERENCES` and silently drops it. A foreign key onto a column another source owns takes that column's full type (`varchar(36)`), not the bare `varchar` the introspector reports.
|
|
92
|
-
|
|
93
|
-
An addon that ships `db/mysql` migrations needs `db.mysqlUrl` in its `pikku.config.json` for `pikku all` to publish them. The standalone bundle does not support MySQL yet and refuses a MySQL project by name.
|
|
94
|
-
|
|
95
|
-
- Updated dependencies [149faae]
|
|
96
|
-
- @pikku/core@0.12.136
|
|
97
|
-
|
|
98
|
-
## 0.13.33
|
|
99
|
-
|
|
100
|
-
### Patch Changes
|
|
101
|
-
|
|
102
|
-
- a16b0ba: The workflow run lease takes the app's `leaseService` (`holdLease(leaseService, 'workflow-run:<id>', …)`) in place of `pg_advisory_lock` / `GET_LOCK`, for DSL and graph runs alike. A message for a run already being orchestrated elsewhere wakes the run again a second later instead of failing, so a long pass never spends the retry budget the queue keeps for real failures. An inline run whose lease was lost after its body finished keeps the outcome it wrote. `PgWorkflowQueueOptions` and `RunLockHoldTimeoutError` are removed. `WorkflowService.withRunLock` is renamed `withRunLease`, since what it holds runs out unless renewed; a custom workflow service overriding it renames the method.
|
|
103
|
-
|
|
104
|
-
Pass the lease service to the workflow service — `new PgKyselyWorkflowService(db, { leaseService })` — register the same instance as the app's `leaseService`, and migrate `pikku_lease`.
|
|
105
|
-
|
|
106
|
-
A step lease is renewed by the same loop as the run lease. A graph node whose worker died is dispatched again once its lease lapses, instead of leaving the run waiting on it. A replayed step on Kysely now sees its lease, as `getStepState` does. The in-memory store refuses a superseded worker's outcome, as the database stores do. The MySQL workflow service can now record a workflow version; it used `ON CONFLICT`, which MySQL does not have.
|
|
107
|
-
|
|
108
|
-
`pikku db generate` now writes the `pikku_lease` table for any project that runs workflows, not only one that reaches `leaseService`, since every persistent workflow service holds its runs and steps there.
|
|
109
|
-
|
|
110
|
-
- a16b0ba: Give a running workflow step a lease, so a step whose worker dies can be claimed again
|
|
111
|
-
|
|
112
|
-
A step moving from `pending` to `running` only proves it was dispatched; it says
|
|
113
|
-
nothing about whether the worker holding it is still alive. A worker that died
|
|
114
|
-
mid-step therefore left the step wedged in `running` forever: unclaimable by the
|
|
115
|
-
next dispatch, and invisible to the stalled-run sweep.
|
|
116
|
-
|
|
117
|
-
The dispatch that claims a step now stamps a lease on it, refreshes that lease on
|
|
118
|
-
an interval for as long as it is working, and releases it when the step parks on
|
|
119
|
-
a child run. A step whose lease has lapsed is claimable again, and counts as
|
|
120
|
-
in-flight no longer, so the stalled sweep can pick its run back up. A step that
|
|
121
|
-
keeps losing its worker fails with `WorkflowStepLeaseExpiredError` once its
|
|
122
|
-
attempts run out, rather than looping.
|
|
123
|
-
|
|
124
|
-
The lease duration is taken from the queue the step is dispatched through, so the
|
|
125
|
-
lease and the queue lock never disagree about who owns the job.
|
|
126
|
-
|
|
127
|
-
The refresh runs at half the lease and never later, even when that is under the
|
|
128
|
-
one-second floor the interval otherwise respects: applying that floor as a
|
|
129
|
-
maximum would renew a shorter lease for the first time after it had already
|
|
130
|
-
lapsed, which is the double-claim the lease exists to prevent. A lease that
|
|
131
|
-
short is logged once, pointing at the queue's `lockDuration`.
|
|
132
|
-
|
|
133
|
-
The lease is written and judged on the database's clock, never the worker's,
|
|
134
|
-
so a worker whose clock runs fast cannot claim a step another worker still
|
|
135
|
-
holds. A dispatch whose step has since been claimed by another stops renewing,
|
|
136
|
-
and says so: `refreshStepLease(stepId, leaseMs, attempt)` resolves `false` once
|
|
137
|
-
the step is no longer that attempt's.
|
|
138
|
-
|
|
139
|
-
The lease lives in a new `workflow_step.lease_expires_at` column, in epoch
|
|
140
|
-
milliseconds (`bigint`). Run `pikku db generate` and `pikku db migrate` after
|
|
141
|
-
upgrading: the runtime does not add columns, and every step read selects this
|
|
142
|
-
one.
|
|
143
|
-
|
|
144
|
-
- a16b0ba: Persistent workflow services take a required `leaseService` (`WorkflowServiceOptions`) and lock runs and steps on it. The Postgres advisory and MySQL `GET_LOCK` step locks, and Redis's own `SET NX` run and step locks, are removed; `RedisWorkflowService` now takes `(connection, { leaseService, keyPrefix? })`.
|
|
145
|
-
- Updated dependencies [a16b0ba]
|
|
146
|
-
- Updated dependencies [21e9c3a]
|
|
147
|
-
- Updated dependencies [a16b0ba]
|
|
148
|
-
- Updated dependencies [a16b0ba]
|
|
149
|
-
- @pikku/core@0.12.133
|
|
150
|
-
|
|
151
|
-
## 0.13.32
|
|
152
|
-
|
|
153
|
-
### Patch Changes
|
|
154
|
-
|
|
155
|
-
- 942ebdd: Add `LeaseService`: named leases shared by every process on the same store. A lease is not a mutex: a holder that stalls past its expiry loses the key without knowing, so whatever the body writes to should check the lease's `token` and refuse an older one. `acquire` never blocks and answers `null` while someone else holds the key; a lease lapses on its own if its holder dies; and each lease carries a `token` that rises every time the key changes hands, so a stale holder cannot refresh or release its successor's lease. `holdLease` refreshes the lease while its body runs, hands the body an `AbortSignal` that fires the moment the lease is lost, and throws `LeaseLostError` once the body finishes if the lease lapsed or changed hands meanwhile, so a caller never takes that result as produced under the lease.
|
|
156
|
-
|
|
157
|
-
Ships as `InMemoryLeaseService`, `PgKyselyLeaseService` (`@pikku/kysely-postgres`), `MySQLKyselyLeaseService` (`@pikku/kysely-mysql`) and `KyselyLeaseService` (SQLite), all on `pikku_lease`. The Postgres and MySQL services judge every lease by the database's clock, so a worker whose clock runs fast cannot take a live lease or stretch its own; `KyselyLeaseService` reads the process clock and is for a single-host SQLite app. `pikku db generate` writes the table for any project that reaches `leaseService`.
|
|
158
|
-
|
|
159
|
-
`RedisLeaseService` (`@pikku/redis`) keeps each lease in a hash Redis expires itself, with every check-and-set in one Lua script that reads Redis's `TIME`, so it too judges leases by the server's clock; its token counter outlives release, so the next holder always gets a higher token.
|
|
160
|
-
|
|
161
|
-
- Updated dependencies [d327fa5]
|
|
162
|
-
- Updated dependencies [942ebdd]
|
|
163
|
-
- Updated dependencies [8ac25a8]
|
|
164
|
-
- Updated dependencies [6606777]
|
|
165
|
-
- @pikku/core@0.12.132
|
|
166
|
-
|
|
167
|
-
## 0.13.31
|
|
168
|
-
|
|
169
|
-
### Patch Changes
|
|
170
|
-
|
|
171
|
-
- 01c0209: `@pikku/kysely` re-exports `Kysely`, `PostgresDialect` and `CamelCasePlugin` from its own copy of kysely. The local-services codegen writes these imports into a project, so it now opens and types the database with the same kysely copy the generated services were built against, instead of a second copy the project may resolve on its own.
|
|
172
|
-
- 5bce779: Webhook trigger sources are off until someone turns them on, and addons declare their own.
|
|
173
|
-
|
|
174
|
-
An addon calls `wireTriggerWebhookSource` in its own package, and an app that wires the addon gets the source (its route included) without declaring it: named and routed after the addon's namespace, so two instances get one each. A source the app declares under the same name wins.
|
|
175
|
-
|
|
176
|
-
Every source now has an `enabled` switch in the `triggerSourceStore`, off by default. `reconcileTriggerSources` registers only enabled sources and records each one's `baseUrl` and `labelPrefix`; a disabled source's route answers 404 without running `receive`. New in core: `enableTriggerSource` registers a source with its provider and `disableTriggerSource` stops it receiving, then tears it down, both at the recorded address unless one is given. The admin addon exposes them as `triggerSourceEnable` and `triggerSourceDisable`. The `pikkuTriggerSource` table gains `enabled`, `baseUrl` and `labelPrefix`: run `pikku db generate` for the migration.
|
|
177
|
-
|
|
178
|
-
- Updated dependencies [dfcd351]
|
|
179
|
-
- Updated dependencies [cf40182]
|
|
180
|
-
- Updated dependencies [5bce779]
|
|
181
|
-
- Updated dependencies [5bce779]
|
|
182
|
-
- @pikku/core@0.12.130
|
|
183
|
-
|
|
184
|
-
## 0.13.30
|
|
185
|
-
|
|
186
|
-
### Patch Changes
|
|
187
|
-
|
|
188
|
-
- 658f047: A declared webhook source is a registered one. `reconcileTriggerSources` sets up every declared source with its provider (check, then setup where missing or drifted) and `teardownTriggerSources` removes named ones, recording what was registered in a `TriggerSourceStore` (in-memory, or `KyselyTriggerSourceStore` on `pikku_trigger_source`). The admin addon exposes list, reconcile, teardown and forget under the new `admin:triggers` scopes.
|
|
189
|
-
- Updated dependencies [658f047]
|
|
190
|
-
- Updated dependencies [de63ab2]
|
|
191
|
-
- Updated dependencies [658f047]
|
|
192
|
-
- Updated dependencies [658f047]
|
|
193
|
-
- Updated dependencies [658f047]
|
|
194
|
-
- Updated dependencies [658f047]
|
|
195
|
-
- @pikku/core@0.12.128
|
|
196
|
-
|
|
197
|
-
## 0.13.29
|
|
198
|
-
|
|
199
|
-
### Patch Changes
|
|
200
|
-
|
|
201
|
-
- 5e93f30: Add `wireTriggerWebhookSource({ name, method?, route?, secret?, events, receive?, check?, setup?, teardown? })` in `#pikku/trigger`. Each source becomes a `POST /webhooks/<name>` route whose events are validated against their schemas and queued on `pikku-incoming-webhooks` through `IncomingWebhookService`; a generated worker runs the matching `wireTrigger({ name: '<source>:<event>' })` and the queue retries it on failure. `pikku webhooks status | setup | teardown --url --labelPrefix [--previous]` registers the routes with the provider and prints one JSON line per source.
|
|
202
|
-
|
|
203
|
-
`KyselyIncomingWebhookService` (with the `incoming-webhook` schema) records a receipt per event, drops a provider's redelivery of an event it already accepted, and keeps each dispatch's attempts and last error. `pikku dev` and `pikku serve` use it when a Kysely database is configured.
|
|
204
|
-
|
|
205
|
-
- Updated dependencies [5e93f30]
|
|
206
|
-
- Updated dependencies [5e93f30]
|
|
207
|
-
- @pikku/core@0.12.125
|
|
208
|
-
|
|
209
|
-
## 0.13.28
|
|
210
|
-
|
|
211
|
-
### Patch Changes
|
|
212
|
-
|
|
213
|
-
- 4a9dcd2: `admin:listUsers` now pages, counts and can carry roles.
|
|
214
|
-
|
|
215
|
-
`ListUsersInput` gains `offset` and `includeRoles`; `ListUsersOutput` gains `total`, and each `User` gains `roles` and `fields`. `total` is how many users match `search`, which is what a pager counts against — `users.length` never was, because it is capped by `limit`.
|
|
216
|
-
|
|
217
|
-
```typescript
|
|
218
|
-
const { users, total } = await rpc.invoke('admin:listUsers', {
|
|
219
|
-
search: 'example.com',
|
|
220
|
-
limit: 50,
|
|
221
|
-
offset: 50,
|
|
222
|
-
includeRoles: true,
|
|
223
|
-
})
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
Paging only means something over a stable order, so the query now sorts newest first rather than however the database felt like returning rows.
|
|
227
|
-
|
|
228
|
-
Synthetic principals — the platform credential owner, Fabric service users, scenario actors — are excluded by the query instead of dropped from the page afterwards. Filtering after the fact broke both halves of paging: `limit` had already counted the rows it then discarded, so a page came back short, and `offset` skipped synthetic rows as though they were people, so the same person could appear on two pages or on none.
|
|
229
|
-
|
|
230
|
-
`includeRoles` is refused without `admin:scopes:read`. `admin:users:list` says who may see the directory; it does not say who may see what each of those users can do.
|
|
231
|
-
|
|
232
|
-
`ScopeService` gains `listRolesForUsers(userIds)`, implemented in `@pikku/kysely`. It answers for every id asked for — an empty array for a user holding no roles, so a caller cannot read a missing key as "holds nothing" — and chunks its `in` list to stay inside the bound-parameter cap. A page of users used to cost one query per row, which on a database reached over the network is a round trip per row.
|
|
233
|
-
|
|
234
|
-
```typescript
|
|
235
|
-
listRolesForUsers(userIds: string[]): Promise<Record<string, string[]>>
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
Anything implementing `ScopeService` outside this repository has to add it.
|
|
239
|
-
|
|
240
|
-
- Updated dependencies [4a9dcd2]
|
|
241
|
-
- Updated dependencies [5ab24ad]
|
|
242
|
-
- Updated dependencies [42b7ac3]
|
|
243
|
-
- @pikku/core@0.12.120
|
|
244
|
-
|
|
245
|
-
## 0.13.27
|
|
246
|
-
|
|
247
|
-
### Patch Changes
|
|
248
|
-
|
|
249
|
-
- 78237ac: The console shows feature flags as a launch board, and analytics events as a
|
|
250
|
-
declared catalog.
|
|
251
|
-
|
|
252
|
-
A flag's state is four fields — `enabled`, `rolloutPercent`, `declared`,
|
|
253
|
-
`backed` — and none of them is the question an operator actually asks, which is
|
|
254
|
-
how far this has got. The board answers that directly: every declared flag sits
|
|
255
|
-
in the lane its rollout has reached, `dark` → `rolling` → `live`, with
|
|
256
|
-
`attention` for the flags that are not resolving in a way anybody chose.
|
|
257
|
-
|
|
258
|
-
Attention is evaluated before every other reading, and that ordering is the
|
|
259
|
-
whole point rather than an implementation detail. A flag declared in code with
|
|
260
|
-
no row in the store fails open, and it reports `enabled: true` with no rollout
|
|
261
|
-
limit — byte-identical to a deliberate full launch. Read the fields in the
|
|
262
|
-
obvious order and the one production-severity state on the board renders as the
|
|
263
|
-
healthiest one. `groupFlagsByLane` also returns all four lanes whether or not
|
|
264
|
-
they hold anything, because a board read by shape must not rearrange itself the
|
|
265
|
-
moment a lane empties.
|
|
266
|
-
|
|
267
|
-
Selecting a flag opens its controls beside the board rather than over it: the
|
|
268
|
-
switch, the rollout bucket, and the subjects pinned on or off past that bucket.
|
|
269
|
-
They share one surface because they are read together — "off for everyone except
|
|
270
|
-
these three" is a switch and an override row, and an operator who has to leave
|
|
271
|
-
one screen to see the other is the operator who turns a flag on for everybody by
|
|
272
|
-
mistake. The panel tracks the open flag by name and re-reads it from the list, so
|
|
273
|
-
committing a rollout moves the card and the panel together instead of leaving the
|
|
274
|
-
panel describing the flag as it was before the operator changed it.
|
|
275
|
-
|
|
276
|
-
A board whose flags come from a `FeatureFlagSource` — a provider Pikku reads but
|
|
277
|
-
does not own — says so and offers no controls, rather than offering controls that
|
|
278
|
-
would fail.
|
|
279
|
-
|
|
280
|
-
The analytics screen is a catalog of what the code declares, read from build-time
|
|
281
|
-
meta: the events a client may emit and the props each carries, with every prop
|
|
282
|
-
rendered as the schema source text the declaration wrote. It is deliberately not
|
|
283
|
-
a volume report — nothing here counts what was emitted — and saying which of the
|
|
284
|
-
two it is turned out to be the only design question the screen had.
|
|
285
|
-
|
|
286
|
-
Turning a flag on while it carries no rollout limit now asks first. That press
|
|
287
|
-
is the one irreversible thing the board can do — with no bucket left to hold
|
|
288
|
-
anybody back it admits everyone the flag's capabilities allow — and it used to
|
|
289
|
-
be a single click on a switch. The panel also reports what a mutation is doing
|
|
290
|
-
and what it refused to do: the controls it is waiting on go into a pending
|
|
291
|
-
state, and a failed write raises an inline `<Alert>` rather than reverting in
|
|
292
|
-
silence. The console mounts no notification provider, so the feedback is inline
|
|
293
|
-
where the action is, which is the idiom the rest of the console already uses.
|
|
294
|
-
|
|
295
|
-
`@pikku/mantine`'s theme gains four aliases, and they close a contrast defect
|
|
296
|
-
that predates this board:
|
|
297
|
-
|
|
298
|
-
```ts
|
|
299
|
-
'--mantine-color-orange-light': 'var(--app-surface-warning)',
|
|
300
|
-
'--mantine-color-orange-light-color': 'var(--app-amber)',
|
|
301
|
-
'--mantine-color-teal-light': 'var(--app-surface-success)',
|
|
302
|
-
'--mantine-color-teal-light-color': 'var(--app-green)',
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
The theme already documents two colour tiers — TEXT must clear AA, GRAPHIC only
|
|
306
|
-
3:1 — and already pulls Mantine's own variables into that contract rather than
|
|
307
|
-
linting call sites. What it had not covered was Mantine's _light variants_:
|
|
308
|
-
`<Alert color="orange">` renders #d9480f on #ffe8cc at 3.62:1, and
|
|
309
|
-
`<Badge variant="light" color="teal">` at 4.33:1, neither reachable from an
|
|
310
|
-
`--app-*` token because the component never asks for one. The ramp itself is
|
|
311
|
-
deliberately untouched: Mantine conflates `--mantine-color-orange-filled`
|
|
312
|
-
between `c="orange"` text and a `variant="filled"` background, so darkening it
|
|
313
|
-
for light-mode text would make an existing filled badge unreadable in dark mode.
|
|
314
|
-
Eight pre-existing `c="orange"` call sites moved onto the amber TEXT tier in the
|
|
315
|
-
same pass.
|
|
316
|
-
|
|
317
|
-
The analytics catalog is grouped by the file that declares each event, and its
|
|
318
|
-
rows are real buttons rather than table cells carrying a tabindex.
|
|
319
|
-
|
|
320
|
-
`ShellHeaderAction` gains `loading` and `testId`, and `ActionCluster` gains a
|
|
321
|
-
`measurement` flag. `ShellHeader` sizes its actions by rendering them a second
|
|
322
|
-
time off-screen, and that measuring copy was carrying the same `data-testid` and
|
|
323
|
-
`data-help` as the real one — so every action on a page with a collapsing header
|
|
324
|
-
resolved to two elements. The flags board also moved its two header actions from
|
|
325
|
-
`actionsNode` (documented as the non-collapsing escape hatch) onto the structured
|
|
326
|
-
`actions` array, which is what stopped them clipping off the right edge at 400px.
|
|
327
|
-
|
|
328
|
-
- Updated dependencies [78237ac]
|
|
329
|
-
- Updated dependencies [add56d2]
|
|
330
|
-
- @pikku/core@0.12.111
|
|
331
|
-
|
|
332
|
-
## 0.13.26
|
|
333
|
-
|
|
334
|
-
### Patch Changes
|
|
335
|
-
|
|
336
|
-
- 1c9a55a: Review fixes across the feature-flag and analytics primitives:
|
|
337
|
-
|
|
338
|
-
- An addon function's `featureFlag:` gate now reads the consuming application's
|
|
339
|
-
flag source rather than the package's own services, which never carry one.
|
|
340
|
-
- A flag named `__proto__`, `constructor` or `prototype` is rejected instead of
|
|
341
|
-
being silently dropped from the generated metadata.
|
|
342
|
-
- Two declarations of one flag with different descriptions are a hard error,
|
|
343
|
-
rather than the inspector's traversal order deciding what operators read.
|
|
344
|
-
- `subjectIdOf` falls through an empty organization id to the user, instead of
|
|
345
|
-
resolving to no subject and skipping every override and rollout bucket.
|
|
346
|
-
- `CachedFlagSource.invalidate()` retires the in-flight read, so a webhook that
|
|
347
|
-
lands mid-fetch is not answered by the pre-webhook snapshot for another TTL.
|
|
348
|
-
- The generated `/feature-flags` wire resolves against the compiled fallback
|
|
349
|
-
when no source is wired, so a scope-gated flag is not reported to a caller
|
|
350
|
-
who cannot hold it.
|
|
351
|
-
- `pruneFlags()` rechecks `declared = false` in the delete and reports only
|
|
352
|
-
what it removed, so a redeclaration between the two keeps its overrides.
|
|
353
|
-
- A destination's `accepts` throwing no longer costs every later sink its batch.
|
|
354
|
-
- The React analytics client drops events at collection time when analytics is
|
|
355
|
-
disabled, so a later consent grant cannot send what was gathered before it.
|
|
356
|
-
- The React flag client keeps its map when the wire answers a non-object.
|
|
357
|
-
- `KyselyAnalyticsService` mints event ids from `crypto` rather than a
|
|
358
|
-
timestamp with a short random tail.
|
|
359
|
-
|
|
360
|
-
- 1c9a55a: Add `KyselyAnalyticsService`, so declared events have somewhere to land.
|
|
361
|
-
|
|
362
|
-
Every other pikku primitive backed by a table had a Kysely implementation and
|
|
363
|
-
analytics did not, which meant a project that declared events either wired a
|
|
364
|
-
vendor sink or watched them go to the logger — and the logger is not somewhere
|
|
365
|
-
you can answer a question from. The new service appends to `pikkuAnalyticsEvents`,
|
|
366
|
-
gated by `ownedBy: ['analyticsService']` so only a project that declares events
|
|
367
|
-
carries the table.
|
|
368
|
-
|
|
369
|
-
- 1c9a55a: Export `flagSchema` beside the other schemas.
|
|
370
|
-
|
|
371
|
-
`KyselyFeatureFlagStore.init()` expects its tables to exist, and the only way
|
|
372
|
-
an app creates them is `applyPikkuSchemas(db, [flagSchema])`. Every other store
|
|
373
|
-
in this package exports the schema that backs it; this one did not, so the
|
|
374
|
-
store was unusable outside the package that defined it.
|
|
375
|
-
|
|
376
|
-
- 1c9a55a: Feature flags, declared in source and resolved from two independent booleans.
|
|
377
|
-
|
|
378
|
-
`defineFeatureFlags` declares a flag the way `defineScopes` declares a scope —
|
|
379
|
-
the inspector collects it, the CLI emits a `FeatureFlagName` union, and a
|
|
380
|
-
misspelled `featureFlag:` is a type error rather than a gate that silently fails
|
|
381
|
-
open.
|
|
382
|
-
|
|
383
|
-
A flag answers two questions that are not the same question. `capable` comes
|
|
384
|
-
from the session's scopes and is per-user, advisory, and protects nothing — it
|
|
385
|
-
hides UI. `available` comes from one global config snapshot, is caller-blind,
|
|
386
|
-
and is the only half the runner enforces: `override(subject) ?? (enabled AND
|
|
387
|
-
bucket)`, so "off for everyone except these three organizations" is one row, and
|
|
388
|
-
a kill is one write rather than a fan-out. Authorization stays where it was, in
|
|
389
|
-
the function's own `scopes:` — enforcing capability would make a flag a second
|
|
390
|
-
authorization path OR-ing against them. An unavailable feature throws 503, not
|
|
391
|
-
403, because the caller was allowed; the feature was not on.
|
|
392
|
-
|
|
393
|
-
`featureFlag:` is deliberately available on sessionless functions too. It reads
|
|
394
|
-
the config, not the session, so the kill switch reaches a cron task, a queue
|
|
395
|
-
worker and a webhook — which is where it matters most, since nobody is watching
|
|
396
|
-
a UI to notice the feature is off.
|
|
397
|
-
|
|
398
|
-
Refresh is pull-on-demand, so the TTL is the kill-switch latency. Where that is
|
|
399
|
-
too long, `invalidate()` is public: a provider's change webhook lands on an HTTP
|
|
400
|
-
wiring, drops the cache, and the next request does the read. It deliberately
|
|
401
|
-
does not fetch — a burst of webhooks would be N round trips, and on a serverless
|
|
402
|
-
runtime the isolate that took the signal may be gone before anything reads the
|
|
403
|
-
result.
|
|
404
|
-
|
|
405
|
-
Availability fails open through three layers: a fresh read, then the last good
|
|
406
|
-
cached read, then the compiled declaration. The middle layer is load-bearing —
|
|
407
|
-
dropping straight to the compiled fallback on a blip would switch on every flag
|
|
408
|
-
that was deliberately dark.
|
|
409
|
-
|
|
410
|
-
Backing stores split along what they can honestly do. `FeatureFlagSource` is
|
|
411
|
-
read-only (`snapshot()`) and is what a third-party provider implements;
|
|
412
|
-
`FeatureFlagStore` adds the write half and is for stores Pikku owns.
|
|
413
|
-
`@pikku/kysely` ships the store, with declarations synced additively — a removed
|
|
414
|
-
declaration is marked undeclared, never revoked, and a sync never re-enables a
|
|
415
|
-
killed flag. Third-party providers implement the read-only half in the addons
|
|
416
|
-
repository, over plain `fetch` rather than a vendor SDK — those poll on a timer
|
|
417
|
-
belonging to a long-lived process, which a serverless isolate cannot hold
|
|
418
|
-
between requests.
|
|
419
|
-
|
|
420
|
-
A client asks for its flags once per session rather than per flag:
|
|
421
|
-
`scaffold.featureFlags` generates a `GET /feature-flags` returning every
|
|
422
|
-
declared flag resolved for the caller, keyed by this app's `FeatureFlagName`.
|
|
423
|
-
Generated into the app rather than shipped in an addon precisely for that union
|
|
424
|
-
— an addon never sees the host's, and could only answer
|
|
425
|
-
`Record<string, boolean>`. It returns `show` alone: sending `available` apart
|
|
426
|
-
from `capable` would tell every visitor which features exist but are dark.
|
|
427
|
-
|
|
428
|
-
The write half is the operator's, and lives in `@pikku/addon-admin` beside the
|
|
429
|
-
scope RPCs, under a new `admin:flags` scope. `flagList` reports `writable:
|
|
430
|
-
false` rather than failing when flags come from a provider, because a provider's
|
|
431
|
-
own UI is its operator surface and a console full of buttons that 500 is worse
|
|
432
|
-
than a read-only tab. It still lists the flags: a source may report its declared
|
|
433
|
-
set through `declaredFlags()`, and each row carries `backed`, false where the
|
|
434
|
-
provider has never heard of a declared flag. That row is the one worth seeing —
|
|
435
|
-
an absent row fails open, so a dark launch nobody created in PostHog is already
|
|
436
|
-
live for everyone, and a store pikku owns can reconcile that on deploy where a
|
|
437
|
-
provider cannot.
|
|
438
|
-
|
|
439
|
-
On the client, `createFeatureFlags` fetches that map once and `useFeatureFlag`
|
|
440
|
-
reads it synchronously after, through the same provider the analytics client
|
|
441
|
-
hangs off. It takes a `bootstrap` map so a server-rendered page hydrates onto
|
|
442
|
-
the answer it already computed: without one there is a gap in which neither
|
|
443
|
-
default is right, since false hides a feature the user has and true flashes one
|
|
444
|
-
they do not. A failed refresh keeps the map already on screen rather than
|
|
445
|
-
relabelling every flag on a blip.
|
|
446
|
-
|
|
447
|
-
- Updated dependencies [1c9a55a]
|
|
448
|
-
- Updated dependencies [1c9a55a]
|
|
449
|
-
- Updated dependencies [1c9a55a]
|
|
450
|
-
- @pikku/core@0.12.110
|
|
451
|
-
|
|
452
|
-
## 0.13.25
|
|
453
|
-
|
|
454
|
-
### Patch Changes
|
|
455
|
-
|
|
456
|
-
- 4c7a1b5: Run the monorepo's own scripts through bun instead of yarn. What moves is the
|
|
457
|
-
package manager each package's `prepublishOnly` and build scripts invoke, plus
|
|
458
|
-
the two manifest fixes bun needs to resolve the tree: `uWebSockets.js` is
|
|
459
|
-
declared with an explicit `github:` specifier, and `@pikku/uws-handler` marks
|
|
460
|
-
its `uWebSockets.js` peer optional so a bun install of a consumer that brings
|
|
461
|
-
its own uWS app does not try to fetch it from the registry.
|
|
462
|
-
|
|
463
|
-
Three published behaviours change, all of them cases where an isolated
|
|
464
|
-
`node_modules` or bun as the runtime had been papered over by yarn's hoisting:
|
|
465
|
-
|
|
466
|
-
- `@pikku/migrator-sql` turns foreign keys on when it opens a sqlite database
|
|
467
|
-
through bun. `node:sqlite` enforces them by default and `bun:sqlite` does not,
|
|
468
|
-
which silently turned every `ON DELETE CASCADE` into a no-op under
|
|
469
|
-
`bunx --bun pikku`.
|
|
470
|
-
- `@pikku/cli` resolves a deploy provider against the project being deployed
|
|
471
|
-
rather than against wherever the CLI itself is installed, which is what its
|
|
472
|
-
own "is not installed" error asks the user to arrange.
|
|
473
|
-
- `@pikku/cli` treats a specifier a runtime hands straight back — bun does this
|
|
474
|
-
for the modules it implements itself — as not resolved from the project, so
|
|
475
|
-
it falls back rather than loading the runtime's own copy.
|
|
476
|
-
|
|
477
|
-
- Updated dependencies [4c7a1b5]
|
|
478
|
-
- @pikku/core@0.12.108
|
|
479
|
-
|
|
480
|
-
## 0.13.24
|
|
481
|
-
|
|
482
|
-
### Patch Changes
|
|
483
|
-
|
|
484
|
-
- f10162a: `send()` now reports the delivery id it wrote, not only the broker's job id.
|
|
485
|
-
|
|
486
|
-
`KyselyWebhookService.send()` returned `{ jobId }` straight from `queueService.add()`, and callers handed that to `getDelivery()`. That only worked because every queue in the test suite echoed the requested `jobId` back. A broker is free to assign its own identity — the JetStream queue returns a stream sequence — so on those the read-back looked up an id that was never written and 404'd.
|
|
487
|
-
|
|
488
|
-
`SendWebhookResult` gains an optional `deliveryId`, which store-backed implementations always populate.
|
|
489
|
-
|
|
490
|
-
- Updated dependencies [f10162a]
|
|
491
|
-
- @pikku/core@0.12.104
|
|
492
|
-
|
|
493
|
-
## 0.13.23
|
|
494
|
-
|
|
495
|
-
### Patch Changes
|
|
496
|
-
|
|
497
|
-
- 80eb5c0: Encrypt classified columns from the generated manifest.
|
|
498
|
-
|
|
499
|
-
`ClassificationPlugin` reads the per-column classification manifest and decrypts `wrapped` and `sealed` columns transparently on the way out. Writes are not transparent — Kysely's `transformQuery` is synchronous and WebCrypto is not — so plaintext heading for a classified column **throws** instead, and values are produced by `ClassificationCrypto.encryptColumn()`. A forgotten call site is a loud error rather than a silent plaintext row. The stored envelope is self-describing (`pikku1.<keyId>.<version>.<wrappedDek>.<ciphertext>`), so a row records which key opens it without a schema change to every table.
|
|
500
|
-
|
|
501
|
-
`keyId` now flows from the hand-authored `db/annotations.ts` through `pikku db migrate` into `classification.gen.ts`. It is emitted only for `wrapped` and `sealed` columns: naming a key on a plain column would claim a protection it does not have, and a hashed column has no key at all — the hash is the lookup key.
|
|
502
|
-
|
|
503
|
-
- Updated dependencies [80eb5c0]
|
|
504
|
-
- Updated dependencies [2252016]
|
|
505
|
-
- @pikku/core@0.12.98
|
|
506
|
-
|
|
507
|
-
## 0.13.22
|
|
508
|
-
|
|
509
|
-
### Patch Changes
|
|
510
|
-
|
|
511
|
-
- 4450b2a: Name the missing key when a secret is not found.
|
|
512
|
-
|
|
513
|
-
Every `SecretService` threw a bare `Requested secret not found`. In a deployed
|
|
514
|
-
runtime the stack is minified, so the message was the only evidence there was —
|
|
515
|
-
and it identified neither the key nor the service. Each implementation now names
|
|
516
|
-
the key it looked for; the better-auth middlewares that skip on an absent secret
|
|
517
|
-
match the prefix through one shared predicate instead of the whole string.
|
|
518
|
-
|
|
519
|
-
- Updated dependencies [4058c3a]
|
|
520
|
-
- Updated dependencies [4058c3a]
|
|
521
|
-
- Updated dependencies [4058c3a]
|
|
522
|
-
- Updated dependencies [4058c3a]
|
|
523
|
-
- Updated dependencies [4058c3a]
|
|
524
|
-
- Updated dependencies [4058c3a]
|
|
525
|
-
- Updated dependencies [114c079]
|
|
526
|
-
- Updated dependencies [4450b2a]
|
|
527
|
-
- Updated dependencies [4058c3a]
|
|
528
|
-
- Updated dependencies [4058c3a]
|
|
529
|
-
- @pikku/core@0.12.93
|
|
530
|
-
|
|
531
|
-
## 0.13.21
|
|
532
|
-
|
|
533
|
-
### Patch Changes
|
|
534
|
-
|
|
535
|
-
- cfd364a: Remove the last `@pikku/core/ecosystem` references and guard against new ones
|
|
536
|
-
|
|
537
|
-
`@pikku/kysely`'s workflow-service test still imported `StepState` from
|
|
538
|
-
`@pikku/core/ecosystem/workflow`, a subpath that no longer exists in
|
|
539
|
-
`@pikku/core`'s `exports`. Nothing caught it: the import is type-only, so tsx
|
|
540
|
-
erases it before it can fail at runtime, and the package tsconfig excludes
|
|
541
|
-
`**/*.test.ts`, so `yarn tsc` never saw it either. It now imports from
|
|
542
|
-
`@pikku/core/workflow`.
|
|
543
|
-
|
|
544
|
-
A new guard test in `@pikku/core` scans the repository for the dead specifier
|
|
545
|
-
and fails if one comes back, so the next stale import is a red test rather than
|
|
546
|
-
a silent `any`.
|
|
547
|
-
|
|
548
|
-
- 05e47cf: feat(virtual-user): keep the transcript a run already produced
|
|
549
|
-
|
|
550
|
-
The engine returns `intents` and `steps` on every run — what the user set out
|
|
551
|
-
to do, and every turn it took getting there — and `VirtualUserRunOutcome` kept
|
|
552
|
-
neither. The record held counts and findings, so the one question anybody
|
|
553
|
-
actually asks of a completed run ("what did it _do_?") had no answer anywhere,
|
|
554
|
-
even though the answer had been computed and thrown away a moment earlier.
|
|
555
|
-
|
|
556
|
-
`VirtualUserRunOutcome` now carries both, and `VirtualUserRunStore` gains a
|
|
557
|
-
`steps(runId, options?)` read. Intents ride on the run record: there are a
|
|
558
|
-
handful of them and every read of the run wants them. Steps get their own
|
|
559
|
-
`virtualUserRunStep` table, because a run at a 500-step budget carries more
|
|
560
|
-
transcript than every other column together and `list()` would pay for it on
|
|
561
|
-
every row.
|
|
562
|
-
|
|
563
|
-
Three things the kysely store had to get right, all of them driver differences
|
|
564
|
-
rather than design:
|
|
565
|
-
|
|
566
|
-
- steps are inserted in chunks of 50, because a bare sqlite driver binds at
|
|
567
|
-
most 999 variables per statement and ten columns times a 500-step budget is
|
|
568
|
-
five thousand — an un-chunked insert fails on long runs, which are the
|
|
569
|
-
interesting ones;
|
|
570
|
-
- `ok` is stored as 0 or 1, since a bare driver cannot bind a boolean at all
|
|
571
|
-
and `SerializePlugin` is not installed everywhere;
|
|
572
|
-
- `response` is stored JSON-encoded, because a truncated API response usually
|
|
573
|
-
starts with a brace and `SerializePlugin` would otherwise read it back as an
|
|
574
|
-
object rather than the string the engine saw.
|
|
575
|
-
|
|
576
|
-
Completing a run that does not exist no longer writes steps: there is no
|
|
577
|
-
foreign key to refuse them and nothing would ever read or reap them.
|
|
578
|
-
|
|
579
|
-
**This adds a table to the `virtualUser` schema**, and the runtime creates
|
|
580
|
-
nothing: a database that already has `virtualUserRun` gets the store's own
|
|
581
|
-
refusal at startup until `pikku db generate` writes the migration and
|
|
582
|
-
`pikku db migrate` applies it. Landing it now costs nothing, because
|
|
583
|
-
`scaffold.virtualUser` is not yet switched on anywhere.
|
|
584
|
-
|
|
585
|
-
- 05e47cf: feat(virtual-user): put each persona on its own clock
|
|
586
|
-
|
|
587
|
-
A budget says where one run stops. Nothing said how often a persona should use
|
|
588
|
-
the application, so in practice each one ran whenever somebody remembered — and
|
|
589
|
-
what actually tells you about a product is the same user coming back over a
|
|
590
|
-
fortnight.
|
|
591
|
-
|
|
592
|
-
Each persona now gets a row rather than a bigger budget. `virtualUserSchedule`
|
|
593
|
-
holds `enabled`, the disposition and goals to run with, an interval **range**,
|
|
594
|
-
and `nextRunAt`. `tickVirtualUserSchedules` acts on whichever rows are due:
|
|
595
|
-
|
|
596
|
-
```ts
|
|
597
|
-
wireScheduler({
|
|
598
|
-
name: 'virtualUsers',
|
|
599
|
-
schedule: '0 * * * *',
|
|
600
|
-
func: tickVirtualUserSchedules,
|
|
601
|
-
})
|
|
602
|
-
```
|
|
603
|
-
|
|
604
|
-
The tick is generated and wired by nobody, deliberately. A scaffolded
|
|
605
|
-
`wireScheduler` would start spending an application's model budget the moment
|
|
606
|
-
somebody ran `pikku all`, on a host that may not run schedulers at all. Tick
|
|
607
|
-
resolution bounds how late a due persona is, never how often it runs.
|
|
608
|
-
|
|
609
|
-
Three things it does that are easy to leave out:
|
|
610
|
-
|
|
611
|
-
- The next due time is written **before** the run is dispatched, so a tick that
|
|
612
|
-
dies halfway cannot hand the same persona to the next one. A dispatch that
|
|
613
|
-
throws waits a full interval instead of retrying every minute for a week.
|
|
614
|
-
That write is a compare-and-set against the `nextRunAt` the tick read, so it
|
|
615
|
-
is also how a tick _wins_ the persona: two processes on the same cron see the
|
|
616
|
-
same due row, and only the one whose claim lands dispatches.
|
|
617
|
-
- A persona whose previous run is still `running` is skipped, not queued. Two
|
|
618
|
-
copies of the same user acting at once is a different test, and its findings
|
|
619
|
-
do not reproduce.
|
|
620
|
-
- A run still `running` after two hours is failed. Without that, one restart
|
|
621
|
-
mid-run blocks that persona's schedule permanently — which is where the
|
|
622
|
-
stranded-record cost of not using a queue finally gets paid.
|
|
623
|
-
|
|
624
|
-
Reschedule-on-completion was the other candidate and is worse in exactly one
|
|
625
|
-
way, fatally: a crash between finishing and scheduling ends the persona forever,
|
|
626
|
-
and the evidence is an absence.
|
|
627
|
-
|
|
628
|
-
New: `VirtualUserScheduleStore` in core (with the tick, `isDue` and `nextRunAt`
|
|
629
|
-
as pure functions), `KyselyVirtualUserScheduleStore` and its own schema —
|
|
630
|
-
its own rather than a third table in `virtualUserSchema`, and owned by its own
|
|
631
|
-
store, so a project that records runs and never wants them unattended carries no
|
|
632
|
-
cadence table. `scaffold.virtualUser` gains `setVirtualUserSchedule`,
|
|
633
|
-
`listVirtualUserSchedules` and the tick, behind a new `virtualUser:schedule`
|
|
634
|
-
scope: starting a run spends money once with a caller watching, while writing a
|
|
635
|
-
schedule spends it repeatedly with nobody there.
|
|
636
|
-
|
|
637
|
-
The console's Virtual Users screen gains a **Run now** button beside a persona's
|
|
638
|
-
run history, gated on `pikku:console:virtualUsers:run`. It dispatches the
|
|
639
|
-
project's own `runVirtualUser` rather than starting a run itself, so a run the
|
|
640
|
-
application would refuse — an acted-upon persona, a non-accountable disposition
|
|
641
|
-
in production — is still refused.
|
|
642
|
-
|
|
643
|
-
- Updated dependencies [3c0012c]
|
|
644
|
-
- Updated dependencies [05e47cf]
|
|
645
|
-
- Updated dependencies [cfd364a]
|
|
646
|
-
- Updated dependencies [05e47cf]
|
|
647
|
-
- Updated dependencies [05e47cf]
|
|
648
|
-
- Updated dependencies [05e47cf]
|
|
649
|
-
- @pikku/core@0.12.90
|
|
650
|
-
|
|
651
|
-
## 0.13.20
|
|
652
|
-
|
|
653
|
-
### Patch Changes
|
|
654
|
-
|
|
655
|
-
- 274cab3: The singleton intersection moves to the leaves that name it, the runtime stops
|
|
656
|
-
creating schema, and `db generate` writes only the runtime tables a project's
|
|
657
|
-
services own
|
|
658
|
-
|
|
659
|
-
`WiredSingletonServices` was exported from the generated function leaf so the
|
|
660
|
-
auth leaf could import it. Nothing outside a generated leaf ever names it —
|
|
661
|
-
emit declarations for a project of any size and it appears in none of them —
|
|
662
|
-
so the auth and middleware leaves derive the intersection themselves and the
|
|
663
|
-
function leaf keeps it private. `WiredServices` stays exported: 147 `.d.ts`
|
|
664
|
-
files name it, and unexporting it asks every wired module to name each member
|
|
665
|
-
service through a specifier it does not have.
|
|
666
|
-
|
|
667
|
-
`ensurePikkuSchema` is gone. `requirePikkuSchema` replaces it: a service calls
|
|
668
|
-
it at boot, it looks, and it issues no DDL at all. `pikku db generate` writes
|
|
669
|
-
the declaration down as a migration and `pikku db migrate` applies it, and
|
|
670
|
-
those two are now the only way pikku's runtime tables come into existence. A
|
|
671
|
-
service that finds them missing says so and stops, naming both commands.
|
|
672
|
-
Half-present is no longer a distinct case — the remedy is the same migration
|
|
673
|
-
either way. `audit` and `virtual-user` join `pikkuSchemas` as a consequence:
|
|
674
|
-
boot was the only thing that had ever created them.
|
|
675
|
-
|
|
676
|
-
`pikku db generate` applied all of `pikkuSchemas`, so a project with no agents,
|
|
677
|
-
no channels and no workflows still had `agent_threads`, `channels` and
|
|
678
|
-
`workflow_runs` written into its migrations, and then carried them forever. A
|
|
679
|
-
schema now names the services that own it, and generation gates on
|
|
680
|
-
`requiredServices` — the set the inspector already builds for service
|
|
681
|
-
tree-shaking. The gate is one-sided: a schema that names no owner is always
|
|
682
|
-
written, because the session and secret stores and the deployment record are
|
|
683
|
-
reached by the runtime itself and nothing in a project's source implies them.
|
|
684
|
-
Declared scopes now imply `scopeService`, which nothing destructures because
|
|
685
|
-
the generated auth layer is what reaches it.
|
|
686
|
-
|
|
687
|
-
Drift keeps asking the unscoped question. A table already in a database has to
|
|
688
|
-
stay recognisable as a runtime table after the service that needed it is
|
|
689
|
-
dropped — scoping it there would report those tables as unexplained.
|
|
690
|
-
|
|
691
|
-
Every project in this repo that had been relying on boot-time creation now says
|
|
692
|
-
where its tables come from. `createConfig` moves into its own `config.ts` in the
|
|
693
|
-
templates — `pikku db` looks for it there — and the three postgres templates plus
|
|
694
|
-
the workflow verifier declare `postgresUrl` and run `pikku db generate && pikku
|
|
695
|
-
db migrate` before the server starts, from the single connection string their
|
|
696
|
-
runtime opens. The e2e harness cannot: its databases are in-memory sqlite built
|
|
697
|
-
inside the services factory, so nothing outside the process can migrate them. It
|
|
698
|
-
applies the schemas it owns with `applyPikkuSchemas` instead — the same DDL, run
|
|
699
|
-
by the one process that has the database.
|
|
700
|
-
|
|
701
|
-
- Updated dependencies [32616af]
|
|
702
|
-
- Updated dependencies [6848cd9]
|
|
703
|
-
- @pikku/core@0.12.89
|
|
704
|
-
|
|
705
|
-
## 0.13.19
|
|
706
|
-
|
|
707
|
-
### Patch Changes
|
|
708
|
-
|
|
709
|
-
- 2d21628: fix(kysely): claim a workflow step atomically in every SQL dialect
|
|
710
|
-
|
|
711
|
-
The workflow engine's "atomic claim" was a read-then-write guarded by
|
|
712
|
-
`withStepLock`, and `@pikku/kysely` inherited a silent pass-through for that
|
|
713
|
-
lock — so on every dialect but Postgres and MySQL a redelivered queue job could
|
|
714
|
-
claim a step another dispatch was already running, executing a side-effecting
|
|
715
|
-
step twice.
|
|
716
|
-
|
|
717
|
-
`@pikku/kysely` now claims the step with a status-guarded `UPDATE` and reads the
|
|
718
|
-
affected-row count, which is atomic in every SQL dialect without an
|
|
719
|
-
advisory-lock primitive. Relay redispatch is enabled for all Kysely dialects as
|
|
720
|
-
a result, not just Postgres and MySQL.
|
|
721
|
-
|
|
722
|
-
- Updated dependencies [9687ad1]
|
|
723
|
-
- Updated dependencies [2d21628]
|
|
724
|
-
- Updated dependencies [985b87b]
|
|
725
|
-
- Updated dependencies [3a83f85]
|
|
726
|
-
- @pikku/core@0.12.87
|
|
727
|
-
|
|
728
|
-
## 0.13.18
|
|
729
|
-
|
|
730
|
-
### Patch Changes
|
|
731
|
-
|
|
732
|
-
- 746ed6a: fix: one coercion plugin, not three
|
|
733
|
-
|
|
734
|
-
The Kysely coercion plugin existed in three copies — the CLI's local database,
|
|
735
|
-
`@pikku/kysely-node-sqlite` and `@pikku/kysely-bun-sqlite` — and all three had
|
|
736
|
-
drifted apart. Only the CLI's resolved a column against the tables the query
|
|
737
|
-
actually named, so two tables that disagree on the kind of a same-named column
|
|
738
|
-
coerced correctly in local development and silently did not at runtime; only
|
|
739
|
-
bun's dropped a genuinely ambiguous column instead of letting the last table
|
|
740
|
-
processed win.
|
|
741
|
-
|
|
742
|
-
The single implementation now lives in `@pikku/kysely`, which all three already
|
|
743
|
-
depended on, and keeps both behaviours: table-qualified resolution first, an
|
|
744
|
-
ambiguity-safe bare-name fallback second.
|
|
745
|
-
|
|
746
|
-
`ColumnKind` — the value type of the generated `coercion.gen.ts` — is
|
|
747
|
-
`'date' | 'bool' | 'json'`. The CLI's fourth member, `uuid`, was never a
|
|
748
|
-
coercion kind: the codegen excludes it from the map by construction, because a
|
|
749
|
-
UUID is a string in both Postgres and SQLite. It is now `AnnotationKind` in the
|
|
750
|
-
CLI, the union a column may declare in `db/annotations.ts`, of which
|
|
751
|
-
`ColumnKind` is the coercible subset.
|
|
752
|
-
|
|
753
|
-
`@pikku/cli` also drops its unused dependency on the Node-only
|
|
754
|
-
`@pikku/kysely-node-sqlite`.
|
|
755
|
-
|
|
756
|
-
- Updated dependencies [5a1a962]
|
|
757
|
-
- @pikku/core@0.12.86
|
|
758
|
-
|
|
759
|
-
## 0.13.17
|
|
760
|
-
|
|
761
|
-
### Patch Changes
|
|
762
|
-
|
|
763
|
-
- 266e3bc: One door per name: `@pikku/core/ecosystem/*` and the package root are gone
|
|
764
|
-
|
|
765
|
-
`@pikku/core` published every module twice. `ecosystem/http` re-exported
|
|
766
|
-
`./http`, `ecosystem/services` re-exported `./services`, and a name was
|
|
767
|
-
reachable through either — so every addition had to be made in two places, and a
|
|
768
|
-
consumer's import said nothing about what it actually used. The package root was
|
|
769
|
-
the same problem at a larger scale: a single barrel of 206 names that no bundler
|
|
770
|
-
could take apart, and the one specifier that revealed nothing at all.
|
|
771
|
-
|
|
772
|
-
Both are deleted. Every name now lives on the subpath that owns it, and every
|
|
773
|
-
import carries that subpath — `@pikku/core/http`, `@pikku/core/services`,
|
|
774
|
-
`@pikku/core/errors`, `@pikku/core/types`.
|
|
775
|
-
|
|
776
|
-
Deleting the facades meant the raw subpaths had to become a superset of them,
|
|
777
|
-
which they were not: the facade tree had accumulated 25 names with no raw home
|
|
778
|
-
and about 26 more filed under a different area than the module they came from.
|
|
779
|
-
Those names moved to the area that owns them, and three areas were published as
|
|
780
|
-
new entry points rather than left on a root that is going away — `./types` (the
|
|
781
|
-
shared type surface, the largest single destination), `./state` and
|
|
782
|
-
`./classification`.
|
|
783
|
-
|
|
784
|
-
`./classification` is one door onto one subject: what a value is and how it must
|
|
785
|
-
be handled. Its three halves would each have been an entry point — the brands
|
|
786
|
-
and manifest types, the stored-form helpers (`hashToken`, `unsafeAsSealed` and
|
|
787
|
-
friends), and `SecretValue` — split by whether a name happens to be a type or a
|
|
788
|
-
value, which is the same defect as the facades. The duration and versioned-id
|
|
789
|
-
helpers went to `./utils`, which already published, and `PikkuRequest` went to
|
|
790
|
-
`./function`: it is the transport-agnostic request base, not an HTTP one — HTTP
|
|
791
|
-
has `PikkuHTTPAbstractRequest`, and the only thing outside core that extends
|
|
792
|
-
`PikkuRequest` is Azure's timer request.
|
|
793
|
-
|
|
794
|
-
`./types` inherited the root barrel's habit before it inherited its contents, so
|
|
795
|
-
the names with an owner elsewhere were moved off it. The middleware types and the
|
|
796
|
-
five middleware factories — `pikkuMiddleware`, `pikkuMiddlewareFactory`,
|
|
797
|
-
`pikkuChannelMiddleware`, `pikkuChannelMiddlewareFactory` and
|
|
798
|
-
`pikkuAgentMiddleware`, runtime values on a types entry point — are now
|
|
799
|
-
`@pikku/core/middleware`; the function meta types are `@pikku/core/function`;
|
|
800
|
-
`SerializedError` is `@pikku/core/errors`; and the generic TypeScript helpers
|
|
801
|
-
(`MakeRequired`, `PickRequired`, `PickOptional`, `RequireAtLeastOne`,
|
|
802
|
-
`JSONPrimitive`, `JSONValue`) are `@pikku/core/utils`. What is left on `./types`
|
|
803
|
-
is the vocabulary the wirings share, which no single module owns.
|
|
804
|
-
|
|
805
|
-
`pikku` was itself a root barrel — `export * from '@pikku/core'` — and
|
|
806
|
-
now exports only the services it bundles.
|
|
807
|
-
|
|
808
|
-
One module survives at the old specifier, and only for the bootstrap:
|
|
809
|
-
`packages/cli` is generated by the _published_ CLI pinned in its `build.sh`, and
|
|
810
|
-
that CLI still writes a bare `@pikku/core` into the files it generates for the
|
|
811
|
-
CLI itself. `bootstrap-compat/root.ts` carries the eight types it names, a test
|
|
812
|
-
in core fails if that list grows, and it goes when the pin moves to a CLI
|
|
813
|
-
released from this branch. The adapter names the pinned CLI reaches for —
|
|
814
|
-
`pikkuState` and `CreateWireServices` — are rewritten to `@pikku/core/state` and
|
|
815
|
-
`@pikku/core/types` by the same `build.sh` patch pass, so no second shim is
|
|
816
|
-
needed for them.
|
|
817
|
-
|
|
818
|
-
A guard test keeps the root shut: it parses imports and rejects a bare
|
|
819
|
-
`@pikku/core` rather than grepping for it, because several tests hold a user's
|
|
820
|
-
file as a template literal, where `import … from '@pikku/core'` is fixture text
|
|
821
|
-
rather than an import this repo makes.
|
|
822
|
-
|
|
823
|
-
An agent scaffold a project generated under an older CLI is refreshed rather
|
|
824
|
-
than left to fail: `pikku all` already deleted one importing an entry point
|
|
825
|
-
`@pikku/core` no longer publishes, and the `#pikku` hub joins that list.
|
|
826
|
-
Without it a project that scaffolds the agent endpoint but
|
|
827
|
-
declares no agents keeps the old file forever — the generator that would rewrite
|
|
828
|
-
it only runs when agents exist, and the file being present is what stops it
|
|
829
|
-
being regenerated as missing.
|
|
830
|
-
|
|
831
|
-
`pikku new addon` also wrote a tsconfig `paths` map naming only the deleted hub.
|
|
832
|
-
An addon's `imports` map points into `dist`, so `paths` is what resolves
|
|
833
|
-
`#pikku/<leaf>` for the addon's own source build — it now names the two leaf
|
|
834
|
-
patterns, in both the addon and its test harness.
|
|
835
|
-
|
|
836
|
-
- 786dae5: Bump every dependency whose latest release is a major across the monorepo, and
|
|
837
|
-
port the code the majors broke: `cookie` 2's `parseCookie`/`stringifySetCookie`
|
|
838
|
-
API in `@pikku/core` and the three runtime HTTP adapters, and assistant-ui 0.15's
|
|
839
|
-
store client in `@pikku/assistant-ui`.
|
|
840
|
-
- 6eef0a0: Bump every dependency to its latest compatible minor/patch across the monorepo.
|
|
841
|
-
- Updated dependencies [7722ceb]
|
|
842
|
-
- Updated dependencies [375c1ff]
|
|
843
|
-
- Updated dependencies [02a70cd]
|
|
844
|
-
- Updated dependencies [aeef159]
|
|
845
|
-
- Updated dependencies [a281de6]
|
|
846
|
-
- Updated dependencies [266e3bc]
|
|
847
|
-
- Updated dependencies [02a70cd]
|
|
848
|
-
- Updated dependencies [786dae5]
|
|
849
|
-
- Updated dependencies [6eef0a0]
|
|
850
|
-
- Updated dependencies [3561d67]
|
|
851
|
-
- Updated dependencies [a91c433]
|
|
852
|
-
- Updated dependencies [02a70cd]
|
|
853
|
-
- Updated dependencies [9537f74]
|
|
854
|
-
- Updated dependencies [2b57ca8]
|
|
855
|
-
- Updated dependencies [266e3bc]
|
|
856
|
-
- Updated dependencies [9fce0f1]
|
|
857
|
-
- Updated dependencies [83683a0]
|
|
858
|
-
- Updated dependencies [456c88b]
|
|
859
|
-
- Updated dependencies [456c88b]
|
|
860
|
-
- Updated dependencies [c127273]
|
|
861
|
-
- @pikku/core@0.12.85
|
|
862
|
-
|
|
863
|
-
## 0.13.16
|
|
864
|
-
|
|
865
|
-
### Patch Changes
|
|
866
|
-
|
|
867
|
-
- 7406bfe: Rename the agent runtime from `AI*` to `Agent*` (#596)
|
|
868
|
-
|
|
869
|
-
`AI` described the model provider, not the thing being named. Every symbol that
|
|
870
|
-
belongs to the agent runtime now says `Agent`; the symbols that genuinely wrap a
|
|
871
|
-
model provider — `AIEmbeddingService`, `AIProviderOptions`, `AIEmbedParams`,
|
|
872
|
-
`AITranscriptionParams`, `AIGenerateImageParams` and their siblings, and the
|
|
873
|
-
`@pikku/ai-vercel` / `@pikku/ai-deepinfra` / `@pikku/ai-voice` packages — keep
|
|
874
|
-
their names.
|
|
875
|
-
|
|
876
|
-
**Wiring**
|
|
877
|
-
- `pikkuAIAgent` → `pikkuAgent`, `pikkuAIScorer` → `pikkuAgentScorer`,
|
|
878
|
-
`pikkuAIJudge` → `pikkuAgentJudge`
|
|
879
|
-
- `CoreAIAgent` → `CoreAgent`, `AIAgentInput` → `AgentInput`, `AIAgentStep` →
|
|
880
|
-
`AgentStep`, `AIMessage` → `AgentMessage`, and the rest of the agent types
|
|
881
|
-
- `AIAgentRunnerService` → `AgentRunnerService`, `AIStorageService` →
|
|
882
|
-
`AgentStorageService`, `AIRunStateService` → `AgentRunStateService`
|
|
883
|
-
|
|
884
|
-
**Entry points**
|
|
885
|
-
|
|
886
|
-
`@pikku/core/agent` → `@pikku/core/agent`, `@pikku/core/agent-scorer` →
|
|
887
|
-
`@pikku/core/agent-scorer`.
|
|
888
|
-
|
|
889
|
-
**Queues**
|
|
890
|
-
|
|
891
|
-
The scorer queues are now `agent-score-fast` and `agent-score-slow`. Drain the
|
|
892
|
-
old `ai-score-fast` / `ai-score-slow` queues before deploying — jobs still
|
|
893
|
-
sitting on them when the new workers start will never be picked up.
|
|
894
|
-
|
|
895
|
-
**Scaffolds**
|
|
896
|
-
|
|
897
|
-
The agent scaffold pikku wrote for your project — `<scaffold>/agent/agent.gen.ts`
|
|
898
|
-
and its schemas file — imports `@pikku/core/ai-agent`, which no longer exists. A
|
|
899
|
-
scaffold is normally written once and then left alone, so `pikku all` would find
|
|
900
|
-
it present and leave the broken import in place. It now deletes an agent scaffold
|
|
901
|
-
importing either removed entry point and regenerates it in the same run. Anything
|
|
902
|
-
you added to that file goes with it, so move local edits out first.
|
|
903
|
-
|
|
904
|
-
**Database**
|
|
905
|
-
|
|
906
|
-
The agent tables are renamed: `ai_threads`, `ai_message`, `ai_tool_call`,
|
|
907
|
-
`ai_working_memory`, `ai_run` and `ai_run_score` become `agent_threads`,
|
|
908
|
-
`agent_message`, `agent_tool_call`, `agent_working_memory`, `agent_run` and
|
|
909
|
-
`agent_run_score`, along with their indexes and the `ai_working_memory_pk`
|
|
910
|
-
constraint. The same rename applies to the MongoDB collections.
|
|
911
|
-
|
|
912
|
-
`ensurePikkuSchema` creates tables it cannot find, so an existing database will
|
|
913
|
-
get empty `agent_*` tables and leave the old data stranded in `ai_*`. Rename
|
|
914
|
-
them before the first boot on the new version:
|
|
915
|
-
|
|
916
|
-
```sql
|
|
917
|
-
ALTER TABLE ai_threads RENAME TO agent_threads;
|
|
918
|
-
ALTER TABLE ai_message RENAME TO agent_message;
|
|
919
|
-
ALTER TABLE ai_tool_call RENAME TO agent_tool_call;
|
|
920
|
-
ALTER TABLE ai_working_memory RENAME TO agent_working_memory;
|
|
921
|
-
ALTER TABLE ai_run RENAME TO agent_run;
|
|
922
|
-
ALTER TABLE ai_run_score RENAME TO agent_run_score;
|
|
923
|
-
```
|
|
924
|
-
|
|
925
|
-
- 6794681: Publish the ecosystem surface as per-area sub-barrels under `@pikku/core/ecosystem/*`, and point generated code, the CLI, the inspector and the runtime adapters at them.
|
|
926
|
-
|
|
927
|
-
348 names that only generated code, the toolchain or a runtime adapter ever imports now have a second home on `@pikku/core/ecosystem/<area>` — one sub-barrel per area, matching how core already publishes its entrypoints, so no single barrel grows without bound and a consumer only pulls in the area it uses.
|
|
928
|
-
|
|
929
|
-
This step is additive: every name is still exported from the entrypoint it was published from before, so nothing downstream breaks. Removing them from the app-facing barrels is a later change, and needs a release carrying `./ecosystem/*` first.
|
|
930
|
-
|
|
931
|
-
- a7fcd2e: Declare dependencies that were imported but missing from `package.json`
|
|
932
|
-
|
|
933
|
-
`@pikku/openapi-parser` and `@pikku/better-auth` imported `zod`, `@pikku/next`
|
|
934
|
-
imported `path-to-regexp`, `@pikku/cli` imported `kysely`, and
|
|
935
|
-
`@pikku/assistant-ui` imported `rxjs`, none of which were declared. Each
|
|
936
|
-
resolved through Yarn hoisting inside the monorepo and would fail for anyone
|
|
937
|
-
installing the package on its own.
|
|
938
|
-
|
|
939
|
-
`rxjs`, `kysely` and `path-to-regexp` reach consumers through public
|
|
940
|
-
signatures — `Observable<BaseEvent>` is the return type of a published method,
|
|
941
|
-
and `createCoercionPlugin` returns a `KyselyPlugin` — so they are runtime
|
|
942
|
-
dependencies rather than build-only ones.
|
|
943
|
-
|
|
944
|
-
`@pikku/assistant-ui` pins `rxjs` to the exact `7.8.1` that `@ag-ui/client`
|
|
945
|
-
pins, rather than a caret range. The two packages exchange `Observable`s, so a
|
|
946
|
-
range that floats to a second copy gives them two incompatible `Observable`
|
|
947
|
-
types.
|
|
948
|
-
|
|
949
|
-
`@pikku/kysely` also drops `SqliteSerializePlugin`, an alias of
|
|
950
|
-
`SerializePlugin` that has been marked `@deprecated` in favour of it. Use
|
|
951
|
-
`SerializePlugin`.
|
|
952
|
-
|
|
953
|
-
- Updated dependencies [7406bfe]
|
|
954
|
-
- Updated dependencies [6794681]
|
|
955
|
-
- @pikku/core@0.12.84
|
|
956
|
-
|
|
957
|
-
## 0.13.15
|
|
958
|
-
|
|
959
|
-
### Patch Changes
|
|
960
|
-
|
|
961
|
-
- fd9d834: Stop publishing internals that only their own package or file used. The declarations stay; only the entrypoint re-export is removed, so nothing that imported a name from where it is declared is affected.
|
|
962
|
-
- Updated dependencies [063f43a]
|
|
963
|
-
- Updated dependencies [ce66bf8]
|
|
964
|
-
- Updated dependencies [d0307a8]
|
|
965
|
-
- Updated dependencies [ce66bf8]
|
|
966
|
-
- Updated dependencies [3ad2131]
|
|
967
|
-
- Updated dependencies [b930dca]
|
|
968
|
-
- Updated dependencies [b95e77d]
|
|
969
|
-
- Updated dependencies [fd9d834]
|
|
970
|
-
- Updated dependencies [8978fbd]
|
|
971
|
-
- @pikku/core@0.12.82
|
|
972
|
-
|
|
973
|
-
## 0.13.14
|
|
974
|
-
|
|
975
|
-
### Patch Changes
|
|
976
|
-
|
|
977
|
-
- e110c55: Add runtime scoring for AI agents: `pikkuAIScorer` for heuristic grades and
|
|
978
|
-
`pikkuAIJudge` for LLM-judged ones, graded off the request path on two queue
|
|
979
|
-
lanes so a slow judge cannot starve the cheap checks. Grades are sampled
|
|
980
|
-
deterministically per `(run, scorer)` and persisted to `ai_run_score`.
|
|
981
|
-
- Updated dependencies [e110c55]
|
|
982
|
-
- Updated dependencies [e110c55]
|
|
983
|
-
- Updated dependencies [e110c55]
|
|
984
|
-
- Updated dependencies [acc8077]
|
|
985
|
-
- Updated dependencies [905f737]
|
|
986
|
-
- Updated dependencies [3cc6428]
|
|
987
|
-
- Updated dependencies [c524adf]
|
|
988
|
-
- Updated dependencies [e110c55]
|
|
989
|
-
- @pikku/core@0.12.81
|
|
990
|
-
|
|
991
|
-
## 0.13.13
|
|
992
|
-
|
|
993
|
-
### Patch Changes
|
|
994
|
-
|
|
995
|
-
- 6dada45: fix(workflow,ai-agent): make a run's owner, entry node and step function authoritative
|
|
996
|
-
|
|
997
|
-
A graph run may only start at a node the graph declared in `meta.entryNodeIds`, and
|
|
998
|
-
the generated `POST /workflow/:workflowName/graph/:nodeId` route that let an HTTP
|
|
999
|
-
caller pick the entry node is gone. `startNode` stays for `PikkuTriggerService`,
|
|
1000
|
-
which names a declared entry node anyway.
|
|
1001
|
-
|
|
1002
|
-
`StepState` now records the `rpcName` the workflow dispatched a step with, and the
|
|
1003
|
-
step claim rejects a queue message naming a different function with
|
|
1004
|
-
`WorkflowStepFunctionMismatchError` before mutating any status — a step runs under
|
|
1005
|
-
the run owner's identity and without the `expose` gate, so the message must not
|
|
1006
|
-
choose what runs.
|
|
1007
|
-
|
|
1008
|
-
`approveStep` takes the caller's session, and the generated status routes and
|
|
1009
|
-
streams assert the same `assertWorkflowRunOwner` check: a run started through a
|
|
1010
|
-
session may only be read and approved by that session's user. A run with no
|
|
1011
|
-
recorded owner (trigger, scheduler, unauthenticated route) has nobody to compare
|
|
1012
|
-
against and is still gated by the entrypoint's own `auth`/`permissions`.
|
|
1013
|
-
|
|
1014
|
-
`AIRunStateService.resolveApproval` is now a compare-and-swap returning whether
|
|
1015
|
-
_this_ caller made the claim, and both agent resume paths run a tool only for the
|
|
1016
|
-
approvals they claimed — concurrent approvals of one tool call no longer all
|
|
1017
|
-
execute it.
|
|
1018
|
-
|
|
1019
|
-
- Updated dependencies [41c1a95]
|
|
1020
|
-
- Updated dependencies [ce96383]
|
|
1021
|
-
- Updated dependencies [7e60867]
|
|
1022
|
-
- Updated dependencies [f8f1244]
|
|
1023
|
-
- Updated dependencies [dcf20cb]
|
|
1024
|
-
- Updated dependencies [6512384]
|
|
1025
|
-
- Updated dependencies [e3b4c14]
|
|
1026
|
-
- Updated dependencies [efd0ed1]
|
|
1027
|
-
- Updated dependencies [cba98fb]
|
|
1028
|
-
- Updated dependencies [ce96383]
|
|
1029
|
-
- Updated dependencies [f8f1244]
|
|
1030
|
-
- Updated dependencies [f8f1244]
|
|
1031
|
-
- Updated dependencies [6e93a35]
|
|
1032
|
-
- Updated dependencies [6dada45]
|
|
1033
|
-
- @pikku/core@0.12.80
|
|
1034
|
-
|
|
1035
|
-
## 0.13.12
|
|
1036
|
-
|
|
1037
|
-
### Patch Changes
|
|
1038
|
-
|
|
1039
|
-
- e848eb2: Add `relayUndispatchedSteps()`, which re-drives steps whose queue or scheduler
|
|
1040
|
-
dispatch was lost.
|
|
1041
|
-
|
|
1042
|
-
Arming a step is two writes to two systems — the step row lands `pending`, then
|
|
1043
|
-
a job is published — and nothing spans both, so a crash in between leaves a
|
|
1044
|
-
durable row nothing will ever pick up. The run then neither finishes nor fails.
|
|
1045
|
-
|
|
1046
|
-
The step row is the outbox record and this is the relay. It is safe to
|
|
1047
|
-
re-dispatch a step that already has a live job because `executeWorkflowStepInner`
|
|
1048
|
-
claims the step under `withStepLock` before invoking anything: the loser reads
|
|
1049
|
-
`running` and returns. Stores opt in by overriding `findUndispatchedSteps`; the
|
|
1050
|
-
default returns nothing, so a store without an atomic step lock gains no
|
|
1051
|
-
re-dispatches. Opted in: `kysely-postgres` and `kysely-mysql` (real locks) and
|
|
1052
|
-
in-memory (inline, single-process, no queues). Not opted in: `mongodb` and
|
|
1053
|
-
`kysely-sqlite`, whose `withStepLock` is a pass-through.
|
|
1054
|
-
|
|
1055
|
-
Not self-starting — call it from a scheduled task.
|
|
1056
|
-
|
|
1057
|
-
- Updated dependencies [e848eb2]
|
|
1058
|
-
- Updated dependencies [b170489]
|
|
1059
|
-
- Updated dependencies [ae4e898]
|
|
1060
|
-
- @pikku/core@0.12.79
|
|
1061
|
-
|
|
1062
|
-
## 0.13.11
|
|
1063
|
-
|
|
1064
|
-
### Patch Changes
|
|
1065
|
-
|
|
1066
|
-
- f5ce870: Recover workflow runs stalled by a crash mid-dispatch.
|
|
1067
|
-
|
|
1068
|
-
Arming a step is two writes to two systems — the step row, then the queue or
|
|
1069
|
-
scheduler job — so a process that died between them left a run `running` with
|
|
1070
|
-
nothing in flight. It parked on a step that would never complete and never
|
|
1071
|
-
error, so the run neither finished nor failed, and nothing swept it up.
|
|
1072
|
-
|
|
1073
|
-
`workflowService.recoverStalledRuns()` re-drives those runs through
|
|
1074
|
-
`resumeWorkflow`. Replay is memoized per step, so resuming a run that was not
|
|
1075
|
-
actually stuck changes nothing; runs mid-sleep or with a step in flight are
|
|
1076
|
-
excluded outright. It is not self-starting — call it from a scheduled task.
|
|
1077
|
-
|
|
1078
|
-
Stores opt in by overriding `findStalledRunIds`; implemented here for the
|
|
1079
|
-
Kysely and in-memory services, and a no-op elsewhere.
|
|
1080
|
-
|
|
1081
|
-
- Updated dependencies [f5ce870]
|
|
1082
|
-
- @pikku/core@0.12.78
|
|
1083
|
-
|
|
1084
|
-
## 0.13.10
|
|
1085
|
-
|
|
1086
|
-
### Patch Changes
|
|
1087
|
-
|
|
1088
|
-
- 3df4f95: Scaffold virtual user runs as RPCs, backed by a run store.
|
|
1089
|
-
|
|
1090
|
-
`pikku persona run` could already turn a declared persona loose on a running
|
|
1091
|
-
stage, but only from a terminal, and the result only existed in that terminal's
|
|
1092
|
-
output. There was no way for CI, a console, or a scheduled job to start a run —
|
|
1093
|
-
and nothing kept what a run found, so this week's findings could not be compared
|
|
1094
|
-
against last week's.
|
|
1095
|
-
|
|
1096
|
-
`scaffold.virtualUser` now generates two RPCs and the function behind them:
|
|
1097
|
-
- `runVirtualUser({ persona, goals?, memory?, disposition?, budget?, seed? })
|
|
1098
|
-
-> { runId }`
|
|
1099
|
-
- `getVirtualUserRun({ runId }) -> { status, findings, tally, memory, … }`
|
|
1100
|
-
|
|
1101
|
-
They are gated on separate scopes — `virtualUser:run` and `virtualUser:read` —
|
|
1102
|
-
because an adversarial run's findings are working exploits carrying live ids,
|
|
1103
|
-
which makes reading them the more sensitive of the two. Production refuses every
|
|
1104
|
-
disposition but `accountable`, checked against the effective one so the
|
|
1105
|
-
per-run override cannot smuggle another in.
|
|
1106
|
-
|
|
1107
|
-
**A run is not a workflow and not a queued job.** It explores, so no two
|
|
1108
|
-
attempts take the same steps and there is nothing to replay; and the record
|
|
1109
|
-
already carries the progress a queue would only be holding on the way to the
|
|
1110
|
-
same place. `runVirtualUser` writes the record, dispatches without awaiting, and
|
|
1111
|
-
returns the id. The cost is stated on the type: a restart mid-run strands a
|
|
1112
|
-
record at `running`, so a run older than its budget window and still `running`
|
|
1113
|
-
is dead rather than working.
|
|
1114
|
-
|
|
1115
|
-
`@pikku/core` gains `VirtualUserRunStore` (with `virtualUserRunStore` on
|
|
1116
|
-
`CoreSingletonServices`), and `@pikku/kysely` ships
|
|
1117
|
-
`KyselyVirtualUserRunStore`, which creates its own table on first use like the
|
|
1118
|
-
audit sink — the runtime never needs it, so it arrives with the feature that
|
|
1119
|
-
fills it rather than in every database.
|
|
1120
|
-
|
|
1121
|
-
Also in core: `prepareVirtualUserRun`, which derives the catalogue, intents,
|
|
1122
|
-
scopes and reachable agents in one place. `pikku persona run` reads the
|
|
1123
|
-
inspector state and the generated RPC reads `metaService`, and the two have to
|
|
1124
|
-
agree — otherwise the same persona and seed explore a different API depending on
|
|
1125
|
-
how the run was started. `personaScopes` moved here from the CLI for the same
|
|
1126
|
-
reason and is still re-exported from its old home. `PRODUCTION_DISPOSITION` is
|
|
1127
|
-
now exported from `@pikku/core/virtual-user`, which it should always have been.
|
|
1128
|
-
|
|
1129
|
-
- Updated dependencies [3df4f95]
|
|
1130
|
-
- @pikku/core@0.12.77
|
|
1131
|
-
|
|
1132
|
-
## 0.13.9
|
|
1133
|
-
|
|
1134
|
-
### Patch Changes
|
|
1135
|
-
|
|
1136
|
-
- 62ea4cc: The audit trail is now readable — in the generated meta, through an RPC, and as
|
|
1137
|
-
a page in the console.
|
|
1138
|
-
|
|
1139
|
-
`audit: true` reaches `FunctionRuntimeMeta.audit` as its resolved form
|
|
1140
|
-
(`{ durability }`), so which functions record anything is answerable without
|
|
1141
|
-
running them. It is informational: the runner still resolves audit from the live
|
|
1142
|
-
function config, so meta and runtime cannot disagree.
|
|
1143
|
-
|
|
1144
|
-
`AuditService` grows an optional read side — `query(AuditQuery)` and `facets()`.
|
|
1145
|
-
Optional because a sink can legitimately be write-only: a queue producer that
|
|
1146
|
-
hands events to another system has nothing to read back, and a reader that finds
|
|
1147
|
-
these absent should say the trail is not readable here rather than that it is
|
|
1148
|
-
empty. The two are very different answers to give someone auditing a system.
|
|
1149
|
-
|
|
1150
|
-
`KyselyAuditService` implements both, newest first with offset paging, filtered
|
|
1151
|
-
by user, action and time window. Two things it now gets right that are easy to
|
|
1152
|
-
get wrong: an empty filter array means "match nothing" rather than "no filter",
|
|
1153
|
-
and results are read by physical _and_ camelCase key, because `CamelCasePlugin`
|
|
1154
|
-
is on most pikku Kysely instances and renames result keys on the way out — the
|
|
1155
|
-
mismatch does not throw, it returns a page of `undefined`. `init()` creates the
|
|
1156
|
-
`audit` table for projects that do not migrate it themselves, from a new
|
|
1157
|
-
exported `auditSchema` that stays out of `pikkuSchemas` because the runtime does
|
|
1158
|
-
not need it.
|
|
1159
|
-
|
|
1160
|
-
The console addon exposes `console:getAudits` and `console:getAuditFilters`
|
|
1161
|
-
behind a new `pikku:audit:read` scope, and forwards the application's `audit`
|
|
1162
|
-
service into the addon's own services — without that last part every install
|
|
1163
|
-
reported the trail as unreadable, whatever sink it had configured.
|
|
1164
|
-
|
|
1165
|
-
The console gets an Audit trail page: an infinite list filtered server-side by
|
|
1166
|
-
user and action, and a row that opens the whole event, metadata rendered as a
|
|
1167
|
-
JSON tree. Refused, unreadable and empty are three different screens, because
|
|
1168
|
-
"you may not read this", "nobody can read this" and "nothing happened" are three
|
|
1169
|
-
different facts.
|
|
1170
|
-
|
|
1171
|
-
Events name the person who caused them. The trail records a user id — the only
|
|
1172
|
-
thing stable enough to record, since a name can change after the event — so
|
|
1173
|
-
`getAudits` resolves those ids against better-auth's user directory at read
|
|
1174
|
-
time, and the page shows the name while keeping the recorded id on the event.
|
|
1175
|
-
The filter follows: pick a colleague by name, filter by the id. A scenario
|
|
1176
|
-
actor is labelled as one, so synthetic traffic is not mistaken for real, and a
|
|
1177
|
-
caller who was signed out shows the wire identity pikku resolved for them
|
|
1178
|
-
rather than being credited to the system.
|
|
1179
|
-
|
|
1180
|
-
**Breaking, for anyone already reading `AuditEvent`:** `actor` is now
|
|
1181
|
-
`userIdentity`, and its type `AuditActor` is `AuditUserIdentity`; `AuditQuery`
|
|
1182
|
-
takes `userIds`/`orgId` in place of `actorUserIds`/`actorOrgId`, and
|
|
1183
|
-
`AuditFacets` returns `userIds`. In pikku an _actor_ is a synthetic person a
|
|
1184
|
-
scenario drives, flagged on the user row — so naming the causer of an event
|
|
1185
|
-
`actor` made the synthetic case unsayable (`actor.actor === true`) and implied
|
|
1186
|
-
every recorded action was a test. The overwhelming majority are ordinary
|
|
1187
|
-
customers. The `audit` table follows: `actor_user_id` / `actor_org_id`
|
|
1188
|
-
are now `user_id` / `org_id`, and a `pikku_user_id` column joins them so the
|
|
1189
|
-
wire identity of a caller who never signed in survives the round trip — the
|
|
1190
|
-
sink was dropping it, which left the console's Session field permanently
|
|
1191
|
-
blank. A project that already migrated the table needs to rename the two
|
|
1192
|
-
columns and add the third; `KyselyAuditService.init()` creates the new shape
|
|
1193
|
-
for anyone who did not.
|
|
1194
|
-
|
|
1195
|
-
- 78b29f0: `SecretService` now returns a `SecretValue<T>` rather than the bare value, so a
|
|
1196
|
-
vault secret cannot reach a sink by accident.
|
|
1197
|
-
|
|
1198
|
-
`SecretValue` is nominally typed, which means it is not assignable to `string`
|
|
1199
|
-
(or to any other concretely-typed field). Every sink with a real type — a
|
|
1200
|
-
database column, an email body, a session payload — rejects it with no lint
|
|
1201
|
-
rule involved. The sinks typed `any`, `unknown`, or a free generic — the logger,
|
|
1202
|
-
queue payloads, webhook and email inputs, and a function's own output — are
|
|
1203
|
-
guarded with `Safe<T>`, which collapses a `SecretValue` found anywhere inside
|
|
1204
|
-
`T`, however deeply nested, to `never`.
|
|
1205
|
-
|
|
1206
|
-
Unwrap deliberately at the point the secret reaches the wire:
|
|
1207
|
-
|
|
1208
|
-
```ts
|
|
1209
|
-
const secret = await secrets.getSecret('BETTER_AUTH_SECRET')
|
|
1210
|
-
betterAuth({ secret: secret.reveal() })
|
|
1211
|
-
```
|
|
1212
|
-
|
|
1213
|
-
Two behaviours cover what types cannot see. Structured serialization redacts —
|
|
1214
|
-
`JSON.stringify` and node's inspect both yield `[secret]`, so an audit or log
|
|
1215
|
-
write stays honest without crashing the request. String coercion throws
|
|
1216
|
-
`SecretCoercionError`, because a template literal is always a leak.
|
|
1217
|
-
|
|
1218
|
-
`AuditLog.write` is guarded the same way as the logger, since an audit event
|
|
1219
|
-
carries `input` and `metadata` as `unknown` and nominality alone cannot stop a
|
|
1220
|
-
secret landing in one.
|
|
1221
|
-
|
|
1222
|
-
`.reveal()` is the deliberate escape hatch, and what it hands back is an
|
|
1223
|
-
ordinary string as far as every sink signature is concerned. **PKU953** closes
|
|
1224
|
-
that gap: under `pikku all --security` the inspector reports a revealed secret
|
|
1225
|
-
that flows into a logger, an audit, a queue, an email or a webhook — `console` included.
|
|
1226
|
-
|
|
1227
|
-
This also fixed a real one: `remote-addon-auth.ts` called `String(token)` on an
|
|
1228
|
-
`unknown` and wrote the result straight into an `Authorization` header.
|
|
1229
|
-
|
|
1230
|
-
- Updated dependencies [62ea4cc]
|
|
1231
|
-
- Updated dependencies [9dddff8]
|
|
1232
|
-
- Updated dependencies [78b29f0]
|
|
1233
|
-
- @pikku/core@0.12.76
|
|
1234
|
-
|
|
1235
|
-
## 0.13.8
|
|
1236
|
-
|
|
1237
|
-
### Patch Changes
|
|
1238
|
-
|
|
1239
|
-
- cabd9dc: Add a `db.schema` CLI config option, so `pikku db generate` can write the runtime tables into a named postgres schema.
|
|
1240
|
-
|
|
1241
|
-
Without it the generator emits unqualified `create table` against the default `search_path` of `"$user", public`. A project that keeps everything in one namespace — `app`, say — gets a second copy of every runtime table in `public` alongside the ones it already has, which is how stray `public.ai_*` tables appear next to the real `app.ai_*` ones.
|
|
1242
|
-
|
|
1243
|
-
`compilePikkuSchemas` takes the schema and binds only the rendered SQL, never the caller's connection: that connection is the throwaway database the declaration was just applied to, and qualifying it would create tables in a schema the scratch database has never heard of.
|
|
1244
|
-
|
|
1245
|
-
Raw SQL is not rewritten by `withSchema`, so `rawStatement` now also accepts a builder taking a `SchemaContext` — the expression index on `credentials` uses it to qualify its own table. Statements otherwise pick the context up from whatever connection they are handed, so a schema-bound connection needs nothing said twice.
|
|
1246
|
-
|
|
1247
|
-
Two fixes fall out of it:
|
|
1248
|
-
- The `ALTER TABLE` delta for a partially covered source is written from bare introspected names, so it is qualified explicitly. Unqualified it altered a table in whichever schema `search_path` found.
|
|
1249
|
-
- A source was only counted as partially covered on an exact name match, so a project whose migrations already create `app.workflow_step` read as "nothing covered" and had its whole schema re-emitted over tables that were already there. It now matches the schema qualifier the same way the drift diff does.
|
|
1250
|
-
|
|
1251
|
-
`db.schema` is postgres only, and is rejected with an explanation on sqlite, whose `REFERENCES` clause takes a bare table name.
|
|
1252
|
-
|
|
1253
|
-
- Updated dependencies [32277d5]
|
|
1254
|
-
- Updated dependencies [ea8aabf]
|
|
1255
|
-
- Updated dependencies [33e96ab]
|
|
1256
|
-
- Updated dependencies [fd72e58]
|
|
1257
|
-
- Updated dependencies [fd72e58]
|
|
1258
|
-
- Updated dependencies [fd72e58]
|
|
1259
|
-
- Updated dependencies [894b2f8]
|
|
1260
|
-
- Updated dependencies [dd19aa7]
|
|
1261
|
-
- Updated dependencies [50ec500]
|
|
1262
|
-
- @pikku/core@0.12.75
|
|
1263
|
-
|
|
1264
|
-
## 0.13.7
|
|
1265
|
-
|
|
1266
|
-
### Patch Changes
|
|
1267
|
-
|
|
1268
|
-
- 6a307f0: Fix four latent correctness bugs in the function, RPC and error runtimes, and
|
|
1269
|
-
remove dead code from the workflow service surface.
|
|
1270
|
-
|
|
1271
|
-
`WorkflowService.getNodesWithoutSteps` is gone. It was declared on the abstract
|
|
1272
|
-
service and implemented by all five storage backends, and nothing ever called
|
|
1273
|
-
it — hence the non-core packages in this changeset, which only lose that method.
|
|
1274
|
-
|
|
1275
|
-
**An RPC could execute twice.** `RPCService.invoke`, its addon path, and
|
|
1276
|
-
`rpcWithWire` each wrapped the _execution_ of a resolved function in a `try`
|
|
1277
|
-
whose `catch` treated `RPCNotFoundError` as "not found locally" and re-dispatched
|
|
1278
|
-
the call through `deploymentService`. A nested `rpc.invoke` to a missing name,
|
|
1279
|
-
raised from inside an already-running function, therefore re-ran that function on
|
|
1280
|
-
a remote instance after its local side effects had already committed. Resolution
|
|
1281
|
-
is now separated from execution on all three paths, so only a genuinely
|
|
1282
|
-
unresolvable name reaches the fallback. What escapes to callers is unchanged.
|
|
1283
|
-
|
|
1284
|
-
**`addonNamespace` leaked between sibling calls.** The function runner's
|
|
1285
|
-
middleware path restored `rpc`, `functionId`, `audit` and `addonNamespace` after
|
|
1286
|
-
an invocation; the non-middleware path restored the first three but not the
|
|
1287
|
-
fourth. A call into an addon function with no middleware left the addon's
|
|
1288
|
-
namespace on the wire, so subsequent sibling calls resolved the wrong
|
|
1289
|
-
per-instance singletons and `credentialOverrides`.
|
|
1290
|
-
|
|
1291
|
-
**Errors registered on a subclass never resolved.** `misc.errors` was typed
|
|
1292
|
-
`Map<PikkuError, ErrorDetails>` — instances — while `addError` stores
|
|
1293
|
-
constructors, a mismatch hidden by its `error: any` parameter. The instance
|
|
1294
|
-
lookup in `getErrorResponse` was consequently dead, and lookup fell through to a
|
|
1295
|
-
scan comparing `constructor.name`, so a subclass of a registered error got no
|
|
1296
|
-
status mapping at all. The map is now typed `Map<PikkuErrorConstructor, …>` and
|
|
1297
|
-
lookup walks the prototype chain first. Name matching is retained, deliberately,
|
|
1298
|
-
as the fallback that keeps error mapping working when two copies of
|
|
1299
|
-
`@pikku/core` are installed.
|
|
1300
|
-
|
|
1301
|
-
**`createWeakUID` collided across instances.** The prefix was
|
|
1302
|
-
`Date.now().toString(36)` evaluated at module load, so any two instances loading
|
|
1303
|
-
the module in the same millisecond emitted identical `channelId` and `requestId`
|
|
1304
|
-
sequences — reproducibly, not just in principle. It is now seeded lazily from
|
|
1305
|
-
`crypto.randomUUID()`.
|
|
1306
|
-
|
|
1307
|
-
Also: `pikkuState` keys its global map with `Symbol.for` rather than `Symbol`, so
|
|
1308
|
-
two copies of the package share registrations instead of silently getting
|
|
1309
|
-
disjoint state; and the local channel upgrade path no longer keys its middleware
|
|
1310
|
-
cache on the raw request path, which grew the cache without bound while the
|
|
1311
|
-
cached value never varied by path.
|
|
1312
|
-
|
|
1313
|
-
- afef587: Close eleven security weaknesses found in a review of `@pikku/core`. Most are
|
|
1314
|
-
breaking, and two invalidate data or credentials already in the wild — read the
|
|
1315
|
-
migration notes before upgrading.
|
|
1316
|
-
|
|
1317
|
-
**Breaking: AI agent thread ownership now fails closed.** Reading, listing,
|
|
1318
|
-
resuming or approving an existing thread or run requires a resolved session
|
|
1319
|
-
principal (`userId`, or `orgId` for `sessionScope: 'org'`), regardless of the
|
|
1320
|
-
agent's `auth` setting. Previously a request without a session had no ownership
|
|
1321
|
-
model at all: the caller-supplied `resourceId` was accepted as the ownership
|
|
1322
|
-
key, so any caller could read or resume another party's thread by naming its
|
|
1323
|
-
`resourceId`. Worse, `threadOwnerConstraint` returned `undefined` for a
|
|
1324
|
-
sessionless caller, and `undefined` means _no filter_ rather than _no rows_ —
|
|
1325
|
-
so `getAgentThreads` returned every thread in the deployment. It now returns
|
|
1326
|
-
`string[]`, empty for a sessionless caller, which every storage backend already
|
|
1327
|
-
treats as matching nothing. Sessionless agents still run one-shot conversations,
|
|
1328
|
-
each with a fresh unguessable owner; what they lose is cross-request continuity.
|
|
1329
|
-
Wire a session to restore it.
|
|
1330
|
-
|
|
1331
|
-
**Breaking: stored secrets and credentials must be re-entered.** `deriveKey` ran
|
|
1332
|
-
a single unsalted round of SHA-256 over the passphrase and used the digest
|
|
1333
|
-
directly as the AES-GCM key — roughly one hash per brute-force guess, with one
|
|
1334
|
-
rainbow table working against every deployment. It is now PBKDF2-HMAC-SHA256 at
|
|
1335
|
-
600,000 iterations over a random salt. There is no compatibility path: every
|
|
1336
|
-
value held by the kysely, mongodb and redis secret services and the kysely
|
|
1337
|
-
credential service becomes undecryptable. They fail loud, naming the key and
|
|
1338
|
-
`key_version`, so the app hard-fails on first secret read until each is re-set.
|
|
1339
|
-
|
|
1340
|
-
The KEK salt is scoped to the key version and stored alongside it, rather than
|
|
1341
|
-
per secret, so a bulk read costs one derivation instead of N — `getSecrets` over
|
|
1342
|
-
50 secrets went from ~2.3s to ~48ms, and rotation from ~4.6s to ~94ms. This adds
|
|
1343
|
-
a salt table (kysely), hash field (redis) or collection (mongodb), created
|
|
1344
|
-
automatically on first use.
|
|
1345
|
-
|
|
1346
|
-
**Breaking: `PIKKU_REMOTE_SECRET` must be at least 32 characters.** The
|
|
1347
|
-
remote-RPC session envelope moved from PBKDF2 to HKDF, which expands
|
|
1348
|
-
high-entropy key material rather than stretching a low-entropy passphrase. That
|
|
1349
|
-
took a remote hop from ~269ms to ~0.4ms — PBKDF2 was running twice per request —
|
|
1350
|
-
but HKDF supplies no brute-force resistance, so the secret must carry the
|
|
1351
|
-
entropy itself. A shorter secret now throws `WeakKeyMaterialError` at both ends.
|
|
1352
|
-
Generate one with `openssl rand -base64 32` and roll it out to every service in
|
|
1353
|
-
the mesh together: existing bearer tokens are format-incompatible, so a partial
|
|
1354
|
-
rollout produces 401s until every instance is updated. The Cloudflare, Lambda
|
|
1355
|
-
and Azure deployment services each hand-rolled a copy of `buildRemoteHeaders`
|
|
1356
|
-
and now call the shared one, which is what keeps the two sides in step.
|
|
1357
|
-
|
|
1358
|
-
**Breaking: previously signed content URLs stop verifying.** `LocalContent`
|
|
1359
|
-
signed only `{signedAt, expiresAt, notBefore}`, so a signature proved when a URL
|
|
1360
|
-
was issued but never what it was issued for — any valid token was a skeleton
|
|
1361
|
-
key, and swapping the pathname from a public thumbnail to a private document
|
|
1362
|
-
still verified. The signature now binds the request path. Separately, the
|
|
1363
|
-
verifier returned "valid" when no JWT service was wired, which is how
|
|
1364
|
-
`pikku serve` ran: a forged `?signedAt=0&expiresAt=99999999999999` was accepted.
|
|
1365
|
-
It now rejects with 403, `LocalContent` requires a `JWTService`, and
|
|
1366
|
-
`pikku serve`/`pikku dev` mint an ephemeral per-process signing key so local
|
|
1367
|
-
development works without shipping a fail-open path. In-flight signed URLs must
|
|
1368
|
-
be re-issued.
|
|
1369
|
-
|
|
1370
|
-
**Request body size limits now apply to every adapter.** The `maxBodySize` cap
|
|
1371
|
-
existed only in `PikkuFetchHTTPRequest`. The real hole was uWebSockets, which
|
|
1372
|
-
drove `res.onData` itself and concatenated every chunk with no bound and nothing
|
|
1373
|
-
downstream able to intervene; it now drops chunks past the limit and replies 413
|
|
1374
|
-
before routing. Fastify delegates to its native `bodyLimit` (set only when
|
|
1375
|
-
`maxBodySize` is configured, so fastify's stricter 1 MB default is never
|
|
1376
|
-
loosened), and `PikkuExpressServer` feeds the limit into its body parsers. Two
|
|
1377
|
-
paths can only reject rather than prevent, and are documented as such:
|
|
1378
|
-
`express-middleware` mounted on your own app receives an already-parsed body, so
|
|
1379
|
-
that deployment must bound its own parser; Next server actions bottom out at
|
|
1380
|
-
`experimental.serverActions.bodySizeLimit`.
|
|
1381
|
-
|
|
1382
|
-
**Breaking: the console addon's privileged functions are gated by default.**
|
|
1383
|
-
`wireAddon` gains a `scopes` option that applies to every function in the
|
|
1384
|
-
addon's namespace, and the console scaffold now generates
|
|
1385
|
-
`wireAddon({ name: 'console', package: '@pikku/addon-console', scopes: ['admin'] })`.
|
|
1386
|
-
Previously the console's entire privileged surface — around 54 functions
|
|
1387
|
-
including `credentialGet`, which returns a resolved OAuth token for an arbitrary
|
|
1388
|
-
`userId`, `updateFunctionBody`, and `installAddon`, which shells out to a
|
|
1389
|
-
package install — was protected only by an optional host-registered
|
|
1390
|
-
`addGlobalPermission`. `resolveGlobalPermissions` returns `[]` when none is
|
|
1391
|
-
registered and permission checking then no-ops, so an app that never registered
|
|
1392
|
-
one served those functions to anyone, and with the template's default
|
|
1393
|
-
`scaffold.rpc: "no-auth"` that meant unauthenticated. All of them now return 403
|
|
1394
|
-
`MissingScopeError` without an `admin`, `admin:*` or `*` scope. **Regenerating
|
|
1395
|
-
is required** — an app holding an old `console.gen.ts` stays open.
|
|
1396
|
-
`installAddon` and `installOpenapiAddon` additionally declare their own
|
|
1397
|
-
`auth: true, scopes: ['admin']`, and `getAgentThreads` now scopes its listing to
|
|
1398
|
-
the session's own threads unless the caller holds admin.
|
|
1399
|
-
|
|
1400
|
-
Addon scopes are enforced in `runPikkuFunc` rather than at the RPC boundary,
|
|
1401
|
-
because a wiring can reference an addon function directly — the inspector
|
|
1402
|
-
records the addon's `packageName` on HTTP, channel, schedule, queue, CLI,
|
|
1403
|
-
trigger, gateway and MCP wirings — and those paths never call `resolveNamespace`.
|
|
1404
|
-
Enforcing at the RPC seam would have covered only the `namespace:function` form
|
|
1405
|
-
while reading as complete.
|
|
1406
|
-
|
|
1407
|
-
**Breaking: `wireAddon`'s `auth` and `tags` now apply on direct wirings too.**
|
|
1408
|
-
Both were read only by `resolveAddonFunction`, so they had exactly the hole
|
|
1409
|
-
scopes had: `wireAddon({ name: 'console', package: '@pikku/addon-console', auth:
|
|
1410
|
-
true, tags: ['admin'] })` gated `rpc('console:credentialGet')` and gated nothing
|
|
1411
|
-
at all on an HTTP route wired straight to `credentialGet`. A consumer who
|
|
1412
|
-
reached for the documented way to lock an addon down got a control that was
|
|
1413
|
-
silently inert on every wiring except one. Both now resolve in `runPikkuFunc`.
|
|
1414
|
-
`auth` merges as an OR — `auth: false` from an addon is ignored on a direct
|
|
1415
|
-
wiring, because an addon may require a session the wiring did not but must never
|
|
1416
|
-
waive one it did. Addon tags resolve to concrete middleware against the **root**
|
|
1417
|
-
tag groups before the call rather than being folded into the function's
|
|
1418
|
-
inherited middleware: `addTagMiddleware('admin', …)` is written by the consuming
|
|
1419
|
-
app and registers under the root package, whereas `combineMiddleware` would look
|
|
1420
|
-
the tag up under the addon's own `packageName`, where it does not exist.
|
|
1421
|
-
|
|
1422
|
-
One consequence worth naming: an addon that wires `auth: true` and also runs its
|
|
1423
|
-
own sessionless internal work — a scheduled task or queue worker inside the
|
|
1424
|
-
addon calling a sibling function — is now gated where it previously was not,
|
|
1425
|
-
because a bare `rpc('fn')` from inside the addon reaches `runPikkuFunc` with the
|
|
1426
|
-
addon's `packageName` like any other call. This reverses a decision that
|
|
1427
|
-
deliberately scoped the gate to the namespaced boundary; that reasoning held
|
|
1428
|
-
only while the boundary was real, and a direct wiring can enter an addon without
|
|
1429
|
-
crossing it, so "already inside" is not something the runtime can infer. Such an
|
|
1430
|
-
addon should carry authorization on the function via
|
|
1431
|
-
`pikkuFunc({ permissions })`, which has always been enforced on every path. A
|
|
1432
|
-
follow-up will add execution provenance so an intra-addon call can be
|
|
1433
|
-
distinguished from an external one and skip the addon-level check; that needs a
|
|
1434
|
-
marker no caller outside the process can set, which is its own design problem
|
|
1435
|
-
and does not belong in a security fix.
|
|
1436
|
-
|
|
1437
|
-
**Codegen now warns when an exposed function has no gate (PKU574).** The
|
|
1438
|
-
generated `POST /rpc/:rpcName` dispatcher forwards to `rpc.exposed`, which
|
|
1439
|
-
refuses anything without `expose: true` — but nothing checked whether the
|
|
1440
|
-
target was gated, because a dispatcher cannot know what it dispatches to. The
|
|
1441
|
-
console shipped ~54 privileged functions through that gap and the toolchain was
|
|
1442
|
-
silent. The inspector now reports every function that is exposed, sessionless,
|
|
1443
|
-
and carries no `auth`, `scopes` or `permissions` of its own and none from a
|
|
1444
|
-
governing `wireAddon`. It is a `warn`, not a critical: `expose: true` on an
|
|
1445
|
-
ungated sessionless function is correct for a genuinely public endpoint, so it
|
|
1446
|
-
blocks a build only under `--fail-on-warn`.
|
|
1447
|
-
|
|
1448
|
-
Two pieces of metadata were missing for this to be answerable statically, and
|
|
1449
|
-
both are now recorded. A `pikkuSessionlessFunc`'s own `auth: true` was read at
|
|
1450
|
-
runtime but never written to function meta, so a self-gated function was
|
|
1451
|
-
indistinguishable from an ungated one — `sessionless` carries the baseline, and
|
|
1452
|
-
`auth` now carries the tightening. And `wireAddon`'s `scopes`, `auth` and `tags`
|
|
1453
|
-
were not parsed at all: the inspector recorded the addon's `rpcEndpoint` and its
|
|
1454
|
-
secret, variable and credential overrides, and dropped every one of its gates.
|
|
1455
|
-
An addon whose gates are not statically knowable is treated as gated, because a
|
|
1456
|
-
false positive on a correctly-secured addon costs more than the one case it
|
|
1457
|
-
would catch.
|
|
1458
|
-
|
|
1459
|
-
**Breaking: an application's global permissions now apply inside addons.**
|
|
1460
|
-
`resolveGlobalPermissions` read only the bucket matching the function's own
|
|
1461
|
-
package, but the generated `addGlobalPermission` wrapper takes no package
|
|
1462
|
-
argument and always registers under the root. An app-wide rule like "every
|
|
1463
|
-
request needs a signed-in user" therefore stopped at the addon boundary, and the
|
|
1464
|
-
bucket an addon's functions did read was one no host could write to — which is
|
|
1465
|
-
why the console addon's recommended `addGlobalPermission([isAdmin],
|
|
1466
|
-
'@pikku/addon-console')` was never a gate anybody could actually install. A
|
|
1467
|
-
function now resolves the root bucket and its own package's, root first.
|
|
1468
|
-
Unioning is safe in a way nothing else here would be: globals AND, so adding the
|
|
1469
|
-
root ones can only tighten. Package buckets stay one-way — a package's globals
|
|
1470
|
-
never reach root functions, or an installed addon could gate the whole
|
|
1471
|
-
application. Apps with both a root global and addon-provided functions will see
|
|
1472
|
-
those functions gated where they previously were not.
|
|
1473
|
-
|
|
1474
|
-
**Codegen now records whether each HTTP route requires a session, and warns
|
|
1475
|
-
about inert addon tags (PKU575).** Four separate things can demand a session —
|
|
1476
|
-
the function's `sessionless`, its own `auth`, the route's (or its group's)
|
|
1477
|
-
`auth`, and the addon it belongs to — and answering "which routes are open?"
|
|
1478
|
-
meant joining all four by hand and knowing which wins. Each route's meta now
|
|
1479
|
-
carries the resolved `requiresSession` alongside the route's own `auth`. Scopes
|
|
1480
|
-
count as requiring one, since they are matched against the session's and fail
|
|
1481
|
-
closed. Anything not statically knowable resolves to `true`, matching PKU574:
|
|
1482
|
-
a route that looks stricter than it is costs less than one that looks open and
|
|
1483
|
-
isn't. Separately, `wireAddon({ tags: ['admin'] })` reads like a gate and is
|
|
1484
|
-
applied like one right up until no `addTagMiddleware('admin', …)` exists, at
|
|
1485
|
-
which point it resolves to an empty list and gates nothing; that now warns.
|
|
1486
|
-
Only addon tags are reported — a tag on a function is as likely to be
|
|
1487
|
-
organizational, and warning about those would bury the case that matters.
|
|
1488
|
-
|
|
1489
|
-
**Object-shorthand permissions were missing from meta.** The inspector visited
|
|
1490
|
-
`ts.PropertyAssignment` but not `ts.ShorthandPropertyAssignment`, so
|
|
1491
|
-
`permissions: { canAdminOrg }` — enforced identically to the longhand form at
|
|
1492
|
-
runtime, since `verifyPermissions` has a non-array branch — was recorded as _no
|
|
1493
|
-
permissions at all_. That is the most dangerous direction for meta to be wrong
|
|
1494
|
-
in: an audit reading it sees an open door where one is shut. It cost this review
|
|
1495
|
-
a false IDOR report across ~35 billing and org functions before the source
|
|
1496
|
-
contradicted the metadata.
|
|
1497
|
-
|
|
1498
|
-
**Functions that authorize in their own body can say so.** A webhook receiver
|
|
1499
|
-
verifying a signature, or a handler redeeming a signed invite, is genuinely
|
|
1500
|
-
closed while carrying no session, scope or permission — indistinguishable in
|
|
1501
|
-
meta from one nobody remembered to gate, and so warned about forever by PKU574.
|
|
1502
|
-
`selfAuthenticated: true` on the function config records the claim and silences
|
|
1503
|
-
the warning for that function. It is declarative only: nothing at runtime reads
|
|
1504
|
-
it and it grants nothing. Detection was rejected deliberately — inferring it
|
|
1505
|
-
from the body means a function that _looks_ like it checks something silences
|
|
1506
|
-
the warning while checking nothing, and a warning that is usually wrong stops
|
|
1507
|
-
being read.
|
|
1508
|
-
|
|
1509
|
-
**Breaking: `scaffold.<feature>` is now `boolean | { auth?, path? }`, and `true`
|
|
1510
|
-
means authenticated.** The old `'auth' | 'no-auth' | false` read like a
|
|
1511
|
-
starter-file preference while being a live authorization decision, set three
|
|
1512
|
-
directories from the functions it governed — the shape the console incident
|
|
1513
|
-
took. A surface now becomes public only by writing `{ auth: false }`, so
|
|
1514
|
-
omitting a field can never open anything: the failure mode of a forgotten flag
|
|
1515
|
-
is a locked door. `{ path }` additionally overrides where the file is
|
|
1516
|
-
generated, which previously could only be set for all features at once via
|
|
1517
|
-
`pikkuDir`.
|
|
1518
|
-
|
|
1519
|
-
The legacy strings are **refused, not coerced**. `resolveScaffoldFeature` throws
|
|
1520
|
-
naming the key and its replacement (`"rpc": "no-auth"` → `"rpc": { "auth":
|
|
1521
|
-
false }`), and it does so at config load, not downstream. An earlier design used
|
|
1522
|
-
a bare `string` for the output path, under which `"no-auth"` would have parsed
|
|
1523
|
-
as a file named `no-auth` and every unmigrated config would have silently
|
|
1524
|
-
produced nonsense; the object form makes any string invalid, so the failure is
|
|
1525
|
-
loud.
|
|
1526
|
-
|
|
1527
|
-
The collapse is deliberately not uniform in effect. For `rpc` the flag was a
|
|
1528
|
-
blanket "no anonymous RPC in this app" set on a dispatcher that cannot know what
|
|
1529
|
-
it dispatches to; for `userAdmin` it was redundant, since the generated
|
|
1530
|
-
functions are already `pikkuFunc` with `scopes: ['admin:users:list']`. But for
|
|
1531
|
-
`agent`, `workflow`, `events` and `scenarios` it is the only gate — those
|
|
1532
|
-
generate real endpoints the app never authors — so `true` keeps them
|
|
1533
|
-
authenticated rather than opening them as a side effect of a config cleanup.
|
|
1534
|
-
`webhook` and `remoteRpc` have no auth dimension at all (`serialize-remote-rpc.ts`
|
|
1535
|
-
hardcodes `auth: false`), so an `{ auth }` on them is ignored. The three
|
|
1536
|
-
configs in this repo are migrated preserving their current behaviour exactly.
|
|
1537
|
-
|
|
1538
|
-
**Queue job identities are signed.** A job carried the producer's `pikkuUserId`
|
|
1539
|
-
as a plain string and the worker resolved a session from it with no
|
|
1540
|
-
verification, so write access to the queue backend was act-as-any-user. The
|
|
1541
|
-
identity is now `pq1.<claim>.<hmac>`, HMAC-SHA256 over the claim and the
|
|
1542
|
-
canonicalized job payload, keyed by HKDF expansion of a new
|
|
1543
|
-
`PIKKU_QUEUE_IDENTITY_SECRET`. Producers opt in by wrapping their queue service
|
|
1544
|
-
with `SignedQueueService`. This fails safe rather than closed: with no secret
|
|
1545
|
-
configured the identity is dropped and jobs still process, warning once per
|
|
1546
|
-
process, so no existing deployment breaks on upgrade — it simply loses queue
|
|
1547
|
-
identity until the secret is set. The payload rather than the job id is bound
|
|
1548
|
-
because SQS, Cloudflare Queues, Azure and the in-memory service all mint ids
|
|
1549
|
-
after `add` returns.
|
|
1550
|
-
|
|
1551
|
-
**Workflow inline state is read from the run record.** `isInline` consulted a
|
|
1552
|
-
process-local `Map`, while `WorkflowRun.inline` is durable. Any instance that
|
|
1553
|
-
did not start a run disagreed with the record, so one instance could dispatch a
|
|
1554
|
-
queued job for a workflow another was already executing in-process. It is now
|
|
1555
|
-
async and resolves through the durable identity, cached only when a context
|
|
1556
|
-
already exists so a passive reader allocates nothing. The same `Map` also leaked:
|
|
1557
|
-
`nextStepKey` fabricated replay state on every step, and `releaseContext`
|
|
1558
|
-
refused to free anything carrying it, so runs whose steps executed outside a
|
|
1559
|
-
`beginReplay` bracket — the step-worker queue path — stranded their context and
|
|
1560
|
-
step state for the process lifetime. Contexts are now released by an explicit
|
|
1561
|
-
execution counter. Step ordinals reset per execution rather than accumulating
|
|
1562
|
-
across step-worker invocations in one process, which makes step naming
|
|
1563
|
-
independent of how work was distributed.
|
|
1564
|
-
|
|
1565
|
-
**Secret reads fail loud in every store.** `MongoDBSecretService.getSecrets`
|
|
1566
|
-
skipped rows that failed to decrypt, and the redis equivalent dropped every
|
|
1567
|
-
rejection via `Promise.allSettled`, including the "No KEK available for
|
|
1568
|
-
key_version N" configuration error. Both now throw, naming the key and its key
|
|
1569
|
-
version, matching the kysely behaviour. This matters most alongside the KEK
|
|
1570
|
-
change above: without it, an upgrade surfaces as a partial secrets map and an
|
|
1571
|
-
opaque downstream failure instead of an error naming the secret to re-enter.
|
|
1572
|
-
|
|
1573
|
-
**A second middleware registration for a pattern no longer erases the first.**
|
|
1574
|
-
`addHTTPMiddleware`, `addTagMiddleware` and `addChannelMiddleware` groups are
|
|
1575
|
-
keyed by pattern or tag and held one source file each, so a second file's call
|
|
1576
|
-
overwrote the first's. Codegen emits its imports from what is stored, so the
|
|
1577
|
-
losing file was never imported and its middleware never registered — the
|
|
1578
|
-
runtime composes repeated registrations for a pattern happily, and only codegen
|
|
1579
|
-
dropped one. Adding an unrelated `addHTTPMiddleware('*', …)` to an app was
|
|
1580
|
-
enough to silently unregister the generated better-auth session bridge, which
|
|
1581
|
-
fails open and gives no sign until a request arrives without a session. A group
|
|
1582
|
-
now carries every registration made for it, and all of them are imported.
|
|
1583
|
-
|
|
1584
|
-
- Updated dependencies [6a307f0]
|
|
1585
|
-
- Updated dependencies [afef587]
|
|
1586
|
-
- Updated dependencies [8075f6a]
|
|
1587
|
-
- @pikku/core@0.12.74
|
|
1588
|
-
|
|
1589
|
-
## 0.13.6
|
|
1590
|
-
|
|
1591
|
-
### Patch Changes
|
|
1592
|
-
|
|
1593
|
-
- 8a2c993: Make the workflow service cheaper to run, and fix two ways it lost state.
|
|
1594
|
-
|
|
1595
|
-
The SQL workflow tables had no indexes at all, so every step read, every
|
|
1596
|
-
history walk and every orchestrator tick was a sequential scan; five indexes
|
|
1597
|
-
now cover the columns the engine actually queries by. A replay used to ask for
|
|
1598
|
-
each step's row individually — O(N) reads per replay, O(N^2) over a run — and
|
|
1599
|
-
now takes one read of the run's steps and serves the walk from it. A step
|
|
1600
|
-
transition wrote the step row and its history row as two separate statements,
|
|
1601
|
-
so a crash between them left a step saying `succeeded` whose history still said
|
|
1602
|
-
`running`; both halves are now one transaction, and the history row is found by
|
|
1603
|
-
attempt number rather than by sorting on `created_at`, which two attempts can
|
|
1604
|
-
share. Resolving a dynamic workflow read and parsed every AI-generated workflow
|
|
1605
|
-
in the deployment to `.find()` one by name; it is a point lookup now.
|
|
1606
|
-
|
|
1607
|
-
Waiting on a run no longer polls at a fixed interval. `pollIntervalMs` became a
|
|
1608
|
-
ceiling rather than a cadence: polling starts at 10ms and widens towards it, so
|
|
1609
|
-
a workflow that finishes in milliseconds is no longer held for a full second,
|
|
1610
|
-
and a long-running one is not read at full rate for its whole life.
|
|
1611
|
-
|
|
1612
|
-
Two backend-specific defects: Redis kept a run's state as one JSON blob and
|
|
1613
|
-
read-modified-wrote it, so parallel branches setting different variables
|
|
1614
|
-
overwrote each other — state is a field per variable now, with the old blob
|
|
1615
|
-
still read underneath so runs in flight keep what they had. Mongo's
|
|
1616
|
-
`setStepScheduled` never wrote history, leaving a queued step reading as never
|
|
1617
|
-
dispatched.
|
|
1618
|
-
|
|
1619
|
-
Also: dispatch no longer JSON round-trips every step payload before handing it
|
|
1620
|
-
to a queue that serialises it anyway — the in-process dev queue, which is the
|
|
1621
|
-
only one that was relying on it, does it itself now.
|
|
1622
|
-
|
|
1623
|
-
Two more defects. A transition whose step had no live attempt wrote its status
|
|
1624
|
-
to the step row and silently nothing to history — the exact divergence the
|
|
1625
|
-
transaction exists to prevent — and now repairs the step and writes the
|
|
1626
|
-
missing row. And resolving a dynamic workflow was non-deterministic on all
|
|
1627
|
-
three backends: a name can hold several active versions, and none of them
|
|
1628
|
-
ordered the candidates, so which one ran could change between two calls
|
|
1629
|
-
reading identical data. The newest version wins, with the graph hash breaking
|
|
1630
|
-
a tie.
|
|
1631
|
-
|
|
1632
|
-
The two attempt columns and the five indexes are declared in the workflow
|
|
1633
|
-
schema, so a fresh database gets them at boot. An existing one gets them from
|
|
1634
|
-
a migration — `pikku db generate` writes the declaration down — rather than
|
|
1635
|
-
from DDL issued at boot.
|
|
1636
|
-
|
|
1637
|
-
- a261006: **Breaking:** removed dynamic workflows — runtime-defined workflow graphs stored in the database and resolved by name instead of by codegen.
|
|
1638
|
-
|
|
1639
|
-
The feature was already half-gone. Its authoring surface (`createAgentWorkflow`, `saveAgentWorkflow`, `listAgentWorkflows`, `executeAgentWorkflow`, and the AI-agent instruction builder) was deleted in April 2026 along with its entire e2e suite, and nothing has written a dynamic workflow since. What remained could not execute one either: `executeAgentWorkflow` gated on `pikkuState('workflows', 'meta')`, which only codegen ever populates, so a graph that existed solely in the database was never findable. The two backend families had also drifted onto different `source` sentinels (`'ai-agent'` vs `'dynamic-workflow'`), and the two Redis implementations disagreed on key escaping — so at least one of them matched nothing. Rather than keep shipping plumbing for a path no caller could complete, it is removed until it can be reintroduced deliberately.
|
|
1640
|
-
|
|
1641
|
-
Removed:
|
|
1642
|
-
- `getAIGeneratedWorkflows` from `WorkflowService` and `WorkflowRunService`, and from every backend (in-memory, Redis, MongoDB, Kysely, and the Cloudflare Durable Object service and client — the last two were already a `return []` stub and a rejection).
|
|
1643
|
-
- The database-lookup fallbacks in `startWorkflow` and `runWorkflowJob` that resolved a workflow name against stored graphs when static meta had no match.
|
|
1644
|
-
- `'dynamic-workflow'` from the `WorkflowRuntimeMeta['source']` union.
|
|
1645
|
-
- `validateWorkflowWiring` and `computeEntryNodeIds` from `@pikku/core/workflow`. These validated AI-authored graphs and had no callers in core; the inspector keeps its own private entry-node computation for static graph wiring, which is unaffected.
|
|
1646
|
-
- The `workflow-created` AI stream event and its AG-UI `pikku:workflow-created` custom event. Its only emitter went with the April deletion, so it could never fire.
|
|
1647
|
-
- The console's `console:getAIWorkflows` RPC, the `useAIWorkflows` hook, the "Dynamic" workflow filter and badge, and the trigger-schema scraper that derived an input form from a stored graph's `$ref` bindings.
|
|
1648
|
-
|
|
1649
|
-
Kept, because static graph workflows depend on them and this is not a change to versioning:
|
|
1650
|
-
- `upsertWorkflowVersion`, `getWorkflowVersion`, `updateWorkflowVersionStatus`, and the `workflowVersions` storage in every backend. These back version-mismatch replay: when a deployed graph's hash changes, in-flight runs continue against the exact graph they started on. No schema migration is needed — the table, its columns, and its `(workflowName, graphHash)` upsert key are unchanged.
|
|
1651
|
-
- `generateMermaidDiagram`, which renders any workflow graph and is not specific to dynamic ones.
|
|
1652
|
-
|
|
1653
|
-
Static `pikkuWorkflowGraph` and DSL workflows are entirely unaffected: they resolve from codegen'd meta, which was always the only path that worked.
|
|
1654
|
-
|
|
1655
|
-
To revive this post-MVP, the deleted authoring code is recoverable in full — its prompt engineering (a compact tool table upfront, full schemas with flattened dotted output paths returned only after a validation failure) is worth reading before rewriting:
|
|
1656
|
-
|
|
1657
|
-
```
|
|
1658
|
-
git show f52f3308b^:packages/core/src/wirings/ai-agent/agent-dynamic-workflow.ts
|
|
1659
|
-
git show f52f3308b^:packages/core/src/wirings/workflow/graph/graph-validation.ts
|
|
1660
|
-
git show f52f3308b --stat # the April removal, incl. the three e2e feature files
|
|
1661
|
-
```
|
|
1662
|
-
|
|
1663
|
-
Note that reviving it needs more than restoring those files: the queued-step path (`executeWorkflowStep`), `onError` compensation, and sub-workflow resolution all read static meta only and would need a fallback for a graph that exists solely in the database.
|
|
1664
|
-
|
|
1665
|
-
- Updated dependencies [8a2c993]
|
|
1666
|
-
- Updated dependencies [a261006]
|
|
1667
|
-
- Updated dependencies [09973b9]
|
|
1668
|
-
- @pikku/core@0.12.71
|
|
1669
|
-
|
|
1670
|
-
## 0.13.5
|
|
1671
|
-
|
|
1672
|
-
### Patch Changes
|
|
1673
|
-
|
|
1674
|
-
- 220a8c4: fix: `ensurePikkuSchema` now sees tables on a `withSchema(...)`-bound connection
|
|
1675
|
-
|
|
1676
|
-
It read the table name out of its own compiled DDL with a regex that matched the
|
|
1677
|
-
first quoted identifier. On a connection bound to a schema that DDL is
|
|
1678
|
-
`create table "app"."workflow_runs"`, so it captured `app` — never a real table
|
|
1679
|
-
name — concluded every table was missing, and issued a bare `create table` that
|
|
1680
|
-
the database rejected with `relation "workflow_runs" already exists`, on every
|
|
1681
|
-
boot.
|
|
1682
|
-
|
|
1683
|
-
The schema half of the name is now parsed, and the lookup matches on the pair
|
|
1684
|
-
when the DDL is qualified (falling back to the bare name when it is not, since
|
|
1685
|
-
an unqualified statement resolves against a `search_path` that is not knowable
|
|
1686
|
-
from here). Error messages name the schema too.
|
|
1687
|
-
|
|
1688
|
-
Also: applying a schema over a `withSchema(...)`-bound **sqlite** connection now
|
|
1689
|
-
explains itself. `withSchema` qualifies foreign key targets along with everything
|
|
1690
|
-
else — which postgres requires and sqlite refuses, since a `REFERENCES` clause
|
|
1691
|
-
there takes a bare table name — and all the engine says about it is
|
|
1692
|
-
`near ".": syntax error`. The failure is now reported with the schema that
|
|
1693
|
-
produced it and what to do instead, with the engine error kept as the `cause`.
|
|
1694
|
-
|
|
1695
|
-
## 0.13.4
|
|
1696
|
-
|
|
1697
|
-
### Patch Changes
|
|
1698
|
-
|
|
1699
|
-
- 91077ff: Declare the pikku runtime tables instead of creating them at boot.
|
|
1700
|
-
|
|
1701
|
-
The tables the runtime needs — workflow, AI, scopes, secrets, credentials, webhooks, channels, deployments, sessions — were created by `createTable(...).ifNotExists()` inside each service's `init()`. A table therefore existed if and only if some service happened to be constructed, in whatever order, with whatever schema qualifier that call site passed. In one deployment that produced a duplicate set of AI tables in `public` shadowing the intended ones in `app`.
|
|
1702
|
-
|
|
1703
|
-
`pikkuSchemas` is now the single declaration, exported from `@pikku/kysely`: the same kysely schema-builder chains, moved out of `init()` and never executed at boot. `applyPikkuSchemas` materializes them onto a database, `compilePikkuSchemas` renders them as SQL for a dialect, and both bind `CamelCasePlugin` themselves so a declaration always compiles to the physical names the rest of the package queries.
|
|
1704
|
-
|
|
1705
|
-
`applyPikkuSchemas` runs its statements in one transaction, so the promise it makes about a half-applied database holds for the failures the prerequisite check cannot foresee too — a statement colliding with a table something else already created rolls back the ones that ran before it.
|
|
1706
|
-
|
|
1707
|
-
Auth is a declared prerequisite. `pikkuUserRole` and `pikkuUserScope` reference `user.id`, which Better Auth owns, so `scopeSchema` says so via `requires` and `applyPikkuSchemas` checks every prerequisite before creating anything — a project without auth gets a sentence naming what is missing and who owns it, not a foreign key error and not a half-applied database. `resolveRequirements` returns the same answer as data for callers that need to describe the gap rather than die on it.
|
|
1708
|
-
|
|
1709
|
-
That prerequisite also fixes a fourth disagreement: `user_id` was declared `text`, but `user.id` has no fixed type — Better Auth decides it from config, giving `uuid` under `generateId: 'uuid'` and an identity `integer` under `'serial'`, and postgres refuses a `text` column referencing either. The whole statement was rejected, so `KyselyScopeService.init()` had never actually created these tables on such a project — one had a migration written by hand with a comment explaining why. The column now takes its type from the column it references, whatever that turns out to be.
|
|
1710
|
-
|
|
1711
|
-
Three further disagreements the single declaration settled:
|
|
1712
|
-
- `aiRun` was created by two services with different columns. `KyselyAIStorageService` omitted `pendingApprovals`; `KyselyAIRunStateService` declared it and read it back through `as any` casts. Whichever ran first decided the shape, and where the storage service won, resolving an approval failed. The column is declared.
|
|
1713
|
-
- `workflowRuns`, `workflowStep` and `workflowStepHistory` defaulted their primary keys to `sql.raw("'" + crypto.randomUUID() + "'")`, evaluated once when the statement was built — one shared default for every row, not a generator. Dropped; the services supply the id.
|
|
1714
|
-
- `workflowStep.fromStepName` was backfilled by an `alterTable(...).execute().catch(() => {})` bolted on after the fact. It is part of the declaration.
|
|
1715
|
-
|
|
1716
|
-
Every service's `init()` now goes through `ensurePikkuSchema`, which looks before it creates: all the tables present is a no-op, none present creates them from the declaration, and some present throws rather than filling in the rest. That last case is the point. `.ifNotExists()` turned every failure into a silent success — it is why nobody noticed the `user_id` type had been rejected since the day it was written — and a schema half-owned by a migration and half by a boot-time create is the condition all of this exists to end. Around 615 lines of duplicated DDL went with it.
|
|
1717
|
-
|
|
1718
|
-
Creating at boot is now the fallback rather than the intent: run `pikku db generate` and `init()` takes the `present` path and issues no DDL at all.
|
|
1719
|
-
|
|
1720
|
-
`KyselyPikkuDB` stays hand-written, because it carries what introspection cannot recover — `WorkflowStatus` rather than `string`, `Generated<Date>` rather than `Date`. A test materializes the declaration and asserts the two agree on every table and column, which is the drift protection generating it would have bought. It found one on its first run: `ai_run.pending_approvals` was in the DDL and in `KyselyAIRunStateService`, but not in `AIRunTable` — the reason that service read it back through `as any`. Declared, and the casts are gone.
|
|
1721
|
-
|
|
1722
|
-
## 0.13.3
|
|
1723
|
-
|
|
1724
|
-
### Patch Changes
|
|
1725
|
-
|
|
1726
|
-
- e3d4454: Add job groups, so one shared queue can stay fair without splitting into one
|
|
1727
|
-
queue per producer.
|
|
1728
|
-
|
|
1729
|
-
A job may now carry `group: { id, tier }`, and a worker may cap how many jobs
|
|
1730
|
-
of any one group run at once via `groupConcurrency`. On pg-boss this maps to
|
|
1731
|
-
`localGroupConcurrency`, which excludes at-capacity groups from the fetch query
|
|
1732
|
-
itself, so a capped group costs nothing rather than being fetched and restored.
|
|
1733
|
-
BullMQ declares it unsupported (groups are a BullMQ Pro feature) — being
|
|
1734
|
-
push-based, it can simply use a queue per group at no polling cost.
|
|
1735
|
-
|
|
1736
|
-
Workflow services accept a `queueStrategy`. The default `'per-workflow'` is
|
|
1737
|
-
unchanged: every workflow gets its own `wf-orchestrator-*` / `wf-step-*` queue,
|
|
1738
|
-
which is also what lets serverless providers deploy one unit per workflow. The
|
|
1739
|
-
new `'shared-groups'` routes every workflow through the shared
|
|
1740
|
-
orchestrator/step-worker queues and isolates them by group instead, so a
|
|
1741
|
-
monolith runs one set of pollers rather than one per workflow — on a
|
|
1742
|
-
pull-based backend with dozens of workflows that is the difference between
|
|
1743
|
-
hundreds of poll loops and twenty. It is for single-process runtimes only; a
|
|
1744
|
-
per-unit serverless deploy still needs the per-workflow queues to route to its
|
|
1745
|
-
units.
|
|
1746
|
-
|
|
1747
|
-
- Updated dependencies [24252b8]
|
|
1748
|
-
- Updated dependencies [e3d4454]
|
|
1749
|
-
- @pikku/core@0.12.69
|
|
1750
|
-
|
|
1751
|
-
## 0.13.2
|
|
1752
|
-
|
|
1753
|
-
### Patch Changes
|
|
1754
|
-
|
|
1755
|
-
- 4324652: Scope AI agent thread reads to the calling session.
|
|
1756
|
-
|
|
1757
|
-
The generated thread-management functions (`getAgentThreads`,
|
|
1758
|
-
`getAgentThreadMessages`, `getAgentThreadRuns`, `deleteAgentThread`) keyed purely
|
|
1759
|
-
off a caller-supplied `threadId` and treated `resourceId` as an optional filter,
|
|
1760
|
-
so omitting it enumerated every tenant's threads.
|
|
1761
|
-
- `listThreads` gains an `owners` **authorization constraint** (distinct from the
|
|
1762
|
-
`resourceId` filter): an empty array matches nothing, and it is always derived
|
|
1763
|
-
from the session, never from input. Implemented across the Kysely, Redis and
|
|
1764
|
-
MongoDB agent run services, with LIKE/regex metacharacter escaping so an owner
|
|
1765
|
-
id containing `_` or `%` cannot match a foreign owner.
|
|
1766
|
-
- The three `threadId`-keyed functions are now guarded by an `isThreadOwner`
|
|
1767
|
-
`pikkuPermission` rather than an in-body check. A thread that does not exist is
|
|
1768
|
-
denied rather than 404'd, so it is indistinguishable from one owned by someone
|
|
1769
|
-
else.
|
|
1770
|
-
- New `@pikku/core/ai-agent` helpers: `canAccessThread`, `threadOwnerConstraint`,
|
|
1771
|
-
`sessionPrincipals`, `isOwnedByPrincipal`.
|
|
1772
|
-
|
|
1773
|
-
Services destructured by a wired function are now non-optional inside it.
|
|
1774
|
-
|
|
1775
|
-
The inspector already aggregated the services used by every wired `func`,
|
|
1776
|
-
`permissions` and `middleware` into `RequiredSingletonServices`, but the
|
|
1777
|
-
generated function types defaulted their service parameter to the raw `Services`
|
|
1778
|
-
— so a service declared `foo?: Foo` still arrived as possibly-undefined, forcing
|
|
1779
|
-
`if (!foo) throw new MissingServiceError(...)` guards that could never fire.
|
|
1780
|
-
Generated types now expose `WiredSingletonServices` / `WiredServices`
|
|
1781
|
-
(`RequiredSingletonServices & Services`) and default the `RequiredServices`
|
|
1782
|
-
generic of functions, permissions, middleware, auth and approval-description
|
|
1783
|
-
helpers to them. Optionality now means only what it should: "this service may
|
|
1784
|
-
not be created, because nothing uses it".
|
|
1785
|
-
|
|
1786
|
-
- Updated dependencies [5f19016]
|
|
1787
|
-
- Updated dependencies [78e4778]
|
|
1788
|
-
- Updated dependencies [4324652]
|
|
1789
|
-
- Updated dependencies [de044f8]
|
|
1790
|
-
- Updated dependencies [cd1a811]
|
|
1791
|
-
- Updated dependencies [19fa6f0]
|
|
1792
|
-
- Updated dependencies [b501612]
|
|
1793
|
-
- Updated dependencies [eb37b1e]
|
|
1794
|
-
- @pikku/core@0.12.66
|
|
1795
|
-
|
|
1796
|
-
## 0.13.1
|
|
1797
|
-
|
|
1798
|
-
### Patch Changes
|
|
1799
|
-
|
|
1800
|
-
- 13474a6: feat(scopes): grant scopes directly to a user, not only through roles
|
|
1801
|
-
|
|
1802
|
-
A scope can now be granted to a user directly, outside of any role.
|
|
1803
|
-
`resolveScopes` returns the union of a user's role-derived scopes and their
|
|
1804
|
-
direct grants, so a one-off capability no longer requires inventing a role.
|
|
1805
|
-
- `@pikku/core`: `ScopeService` gains `addScopeToUser` / `removeScopeFromUser` /
|
|
1806
|
-
`listUserScopes`.
|
|
1807
|
-
- `@pikku/kysely`: a new `pikku_user_scope` table (FK into `pikku_scopes`, so the
|
|
1808
|
-
database still refuses an undeclared grant; `ON DELETE CASCADE` from `user`,
|
|
1809
|
-
so deleting a user takes their direct grants with it). `resolveScopes` unions
|
|
1810
|
-
it with the role join.
|
|
1811
|
-
- `@pikku/addon-console`: `scopeAddScopeToUser` / `scopeRemoveScopeFromUser`
|
|
1812
|
-
(gated by `pikku:scopes:manage`), and `scopeListUserRoles` now also returns
|
|
1813
|
-
`directScopes`.
|
|
1814
|
-
- `@pikku/console`: a **Direct scopes** section in the user roles drawer to grant
|
|
1815
|
-
and revoke scopes directly, showing them distinctly from the resolved union.
|
|
1816
|
-
|
|
1817
|
-
Also: the Scopes page now distinguishes a permission error (a console admin
|
|
1818
|
-
without `pikku:scopes:read`) from an actual scope-service outage, instead of
|
|
1819
|
-
showing "the scope service may be unavailable" for both.
|
|
1820
|
-
|
|
1821
|
-
- 13474a6: feat: KyselyScopeService — resolve and administer user scopes
|
|
1822
|
-
|
|
1823
|
-
Adds `KyselyScopeService`, backing the core `ScopeService` interface with four
|
|
1824
|
-
self-created tables: `pikku_scopes`, `pikku_roles`, `pikku_role_scopes` and
|
|
1825
|
-
`pikku_user_role`.
|
|
1826
|
-
|
|
1827
|
-
Scopes are declared in code and synced additively — a scope that is no longer
|
|
1828
|
-
declared is marked, never deleted, so a rename or a rolling deploy cannot
|
|
1829
|
-
silently revoke a grant. `pikku scopes prune` is the deliberate removal path.
|
|
1830
|
-
Roles are data, composed by admins at runtime, and `pikku_role_scopes` has a
|
|
1831
|
-
foreign key into `pikku_scopes`, so the database itself refuses to grant a
|
|
1832
|
-
scope that was never declared.
|
|
1833
|
-
|
|
1834
|
-
- 13474a6: feat: ScopeService.listScopes
|
|
1835
|
-
|
|
1836
|
-
Exposes the scope vocabulary held in the store — everything a role can be
|
|
1837
|
-
composed from — flagging any scope that is still present but no longer declared
|
|
1838
|
-
in code (inert, and awaiting `pikku scopes prune`).
|
|
1839
|
-
|
|
1840
|
-
- 70fa400: Add outgoing webhooks — `webhookService.send()` enqueues signed deliveries onto a retrying queue, `@pikku/kysely`'s `KyselyWebhookService` persists per-attempt delivery history, and `@pikku/console` gains a read-only `/webhooks` page; also caches resolved secrets in `TypedSecretService` and registers inline-`func` metadata for queue/scheduler/trigger/gateway wirings.
|
|
1841
|
-
- Updated dependencies [7ab5287]
|
|
1842
|
-
- Updated dependencies [e86bc17]
|
|
1843
|
-
- Updated dependencies [a9b96a0]
|
|
1844
|
-
- Updated dependencies [3f7fc54]
|
|
1845
|
-
- Updated dependencies [c478794]
|
|
1846
|
-
- Updated dependencies [3f04ae4]
|
|
1847
|
-
- Updated dependencies [90d9f04]
|
|
1848
|
-
- Updated dependencies [cb079cc]
|
|
1849
|
-
- Updated dependencies [cb079cc]
|
|
1850
|
-
- Updated dependencies [0a7db82]
|
|
1851
|
-
- Updated dependencies [981c4db]
|
|
1852
|
-
- Updated dependencies [13474a6]
|
|
1853
|
-
- Updated dependencies [5a2b0d5]
|
|
1854
|
-
- Updated dependencies [13474a6]
|
|
1855
|
-
- Updated dependencies [ee040dc]
|
|
1856
|
-
- Updated dependencies [cb079cc]
|
|
1857
|
-
- Updated dependencies [13474a6]
|
|
1858
|
-
- Updated dependencies [9f0d0eb]
|
|
1859
|
-
- Updated dependencies [13474a6]
|
|
1860
|
-
- Updated dependencies [70fa400]
|
|
1861
|
-
- Updated dependencies [7b2ea23]
|
|
1862
|
-
- Updated dependencies [1dc77d5]
|
|
1863
|
-
- Updated dependencies [416606c]
|
|
1864
|
-
- Updated dependencies [d2a6eea]
|
|
1865
|
-
- Updated dependencies [30e62ee]
|
|
1866
|
-
- @pikku/core@0.12.64
|
|
1867
|
-
|
|
1868
|
-
## 0.13.0
|
|
1869
|
-
|
|
1870
|
-
### Minor Changes
|
|
1871
|
-
|
|
1872
|
-
- 241e6cf: Add `KyselyAuditService` — a durable `AuditService` that persists AuditEvents to an `audit` table via Kysely (the companion sink to `createAuditedKysely`). Its column mapping matches Fabric's platform audit-queue consumer, so a locally-run project and a deployed stage produce identical rows. Use it as the local/dev audit sink so audit events persist and are queryable without the platform queue.
|
|
1873
|
-
|
|
1874
|
-
### Patch Changes
|
|
1875
|
-
|
|
1876
|
-
- 41ce2cb: Upgrade to TypeScript 6 and raise the minimum Node.js version to 22.
|
|
1877
|
-
|
|
1878
|
-
All packages now build against `typescript@^6.0.3` and declare `engines.node >= 22`. Internal tooling (`ts-json-schema-generator`, `zod-to-ts`) was bumped to TypeScript 6-compatible releases.
|
|
1879
|
-
|
|
1880
|
-
- Updated dependencies [41ce2cb]
|
|
1881
|
-
- @pikku/core@0.12.44
|
|
1882
|
-
|
|
1883
|
-
## 0.12.18
|
|
1884
|
-
|
|
1885
|
-
### Patch Changes
|
|
1886
|
-
|
|
1887
|
-
- 5c0ff0f: Fix `getRunHistory` dropping step provenance (`fromStepName`). The value was persisted on the step row and used by the graph planner, but `getRunHistory` built its rows from the per-attempt history and never carried `fromStepName` through — so run history (and any timeline reconstructed from it) reported no predecessors. Redis and Kysely `getRunHistory` now return `fromStepName`. Also adds the missing `from_step_name` column (+ backfill) to the Kysely workflow mirror's `workflow_step` schema and persists it on mirror inserts, so a mirror-side history has identical provenance.
|
|
1888
|
-
- 72694f6: feat(workflow): expose per-step attempt count + record running/succeeded/failed timestamps
|
|
1889
|
-
|
|
1890
|
-
`getRunStatus` now returns `attempts` (the latest attempt count) per step, so
|
|
1891
|
-
consumers can show retry counts without a second history query. It already
|
|
1892
|
-
computed `duration` from `runningAt`/`succeededAt`, but the kysely and mongodb
|
|
1893
|
-
workflow stores only stamped those timestamps on the _insert_ path — the
|
|
1894
|
-
`running` / `succeeded` / `failed` status transitions updated the history row's
|
|
1895
|
-
status without setting `runningAt` / `succeededAt` / `failedAt`, so `duration`
|
|
1896
|
-
was always undefined. The transitions now stamp the matching timestamp, so step
|
|
1897
|
-
duration is populated for kysely- and mongodb-backed runs. (Redis already
|
|
1898
|
-
stamped on transition.) A shared service-suite test guards both behaviours.
|
|
1899
|
-
|
|
1900
|
-
- Updated dependencies [4be205f]
|
|
1901
|
-
- Updated dependencies [061c717]
|
|
1902
|
-
- Updated dependencies [2c55e13]
|
|
1903
|
-
- Updated dependencies [c745c26]
|
|
1904
|
-
- Updated dependencies [57900b5]
|
|
1905
|
-
- Updated dependencies [72694f6]
|
|
1906
|
-
- @pikku/core@0.12.39
|
|
1907
|
-
|
|
1908
|
-
## 0.12.17
|
|
1909
|
-
|
|
1910
|
-
### Patch Changes
|
|
1911
|
-
|
|
1912
|
-
- 92cd5b1: feat(workflow): workflow-owned step retries + stable invocationId
|
|
1913
|
-
|
|
1914
|
-
The workflow — not the queue — now owns step retry policy, and each step
|
|
1915
|
-
invocation gets a stable idempotency key.
|
|
1916
|
-
- **Default `retries: 5` with exponential backoff.** A step with no `retries`
|
|
1917
|
-
previously inherited the queue's bare default (e.g. pg-boss `retry_limit 2`,
|
|
1918
|
-
no backoff) so retries fired instantly and couldn't outlast a transient
|
|
1919
|
-
outage. Retries now default to 5 with backoff, resolved at the workflow layer.
|
|
1920
|
-
- **`retries: 0` is honored.** Dispatch previously passed `undefined` options
|
|
1921
|
-
for `retries: 0`, letting the queue re-run a non-idempotent step up to its own
|
|
1922
|
-
default. The resolved policy now always sets `attempts` (`retries: 0` →
|
|
1923
|
-
`attempts: 1`), so the queue never second-guesses the workflow. The persisted
|
|
1924
|
-
step retries and the dispatched `attempts` are resolved together so
|
|
1925
|
-
"retries exhausted" and "no more redeliveries" are the same event.
|
|
1926
|
-
- **`workflowStep.invocationId`** — a deterministic, dependency-free
|
|
1927
|
-
`uuidv5(runId:stepName)` handed to every step. Unlike `stepId` (minted per
|
|
1928
|
-
attempt), it is identical across retries, so a step can dedupe on it
|
|
1929
|
-
(`ON CONFLICT (invocationId)`, Stripe idempotency keys, etc.).
|
|
1930
|
-
- **queue-bullmq**: `mapPikkuJobToBull` now maps `backoff` (previously dropped,
|
|
1931
|
-
so a step's backoff silently never applied on Redis), and `registerQueues`
|
|
1932
|
-
throws a clear error when no logger is available (matching queue-pg-boss).
|
|
1933
|
-
- **Dispatch failures are recoverable, not fatal.** A step is now marked
|
|
1934
|
-
`scheduled` only _after_ it is successfully handed to its transport (queue or
|
|
1935
|
-
scheduler) — a failed hand-off leaves it `pending` so a replay re-dispatches
|
|
1936
|
-
it, instead of stranding it in `scheduled` (replay would pause forever on a
|
|
1937
|
-
job that was never enqueued). A transport outage (e.g. pg-boss momentarily
|
|
1938
|
-
down) is surfaced as a new `WorkflowDispatchException`, which the orchestrator
|
|
1939
|
-
treats as transient: the run is left running and the orchestrator job is
|
|
1940
|
-
rethrown for redelivery (it replays idempotently from the snapshot) rather
|
|
1941
|
-
than the whole run being marked `failed`. The orchestrator job now also
|
|
1942
|
-
carries its own retry policy, so this holds even when the orchestrator queue
|
|
1943
|
-
is configured `retry_limit 0`. A genuine step error still fails the run.
|
|
1944
|
-
- **Same step name can be invoked multiple times in one run.** Step rows are now
|
|
1945
|
-
keyed per _invocation_: the Nth reach of a step name in a replay resolves to a
|
|
1946
|
-
physical key (`name` for the first, `name#N` for repeats), so a literal
|
|
1947
|
-
duplicate name no longer clobbers the earlier step's state. The first reach
|
|
1948
|
-
keeps the bare name, so existing rows, graph-node matching and `invocationId`s
|
|
1949
|
-
are unchanged. Ordinals are derived deterministically from DSL execution order
|
|
1950
|
-
and reset each replay.
|
|
1951
|
-
- **Step provenance (`fromStepName`) + graph cycles.** Every step now records
|
|
1952
|
-
the predecessor it was scheduled from (`fromStepName`; entry steps have none),
|
|
1953
|
-
persisted on the step row across all stores (in-memory, kysely, redis,
|
|
1954
|
-
mongodb, cloudflare DO) and carried in the queued payload. The DSL wire
|
|
1955
|
-
exposes the derived `fromInvocationId` (`uuidv5(runId:fromStepName)`) so
|
|
1956
|
-
consumers get the stable predecessor key without a second persisted id —
|
|
1957
|
-
`fromStepName` is the source of truth (it is replay-deterministic; `stepId`,
|
|
1958
|
-
minted per row, is not). This makes the walked path reconstructable even when
|
|
1959
|
-
a node is reached more than once: in `a → b → a → c` the second `a` is a
|
|
1960
|
-
distinct ordinal instance (`a#1`) whose `fromStepName` is `b`.
|
|
1961
|
-
The graph runner now supports **cycles**: a forward edge into an
|
|
1962
|
-
already-started node still collapses to a single run (joins/diamonds are
|
|
1963
|
-
unchanged), but a _back-edge_ — one whose target can reach its source — fires
|
|
1964
|
-
a fresh ordinal instance, so a node can loop back to itself. Termination is
|
|
1965
|
-
the graph's responsibility (branch routing must converge); the engine enforces
|
|
1966
|
-
no visit cap.
|
|
1967
|
-
|
|
1968
|
-
- Updated dependencies [92cd5b1]
|
|
1969
|
-
- @pikku/core@0.12.38
|
|
1970
|
-
|
|
1971
|
-
## 0.12.16
|
|
1972
|
-
|
|
1973
|
-
### Patch Changes
|
|
1974
|
-
|
|
1975
|
-
- 6565b97: Fix `KyselyWorkflowRunService.getRunSteps`: build the `runningAt` /
|
|
1976
|
-
`succeededAt` / `failedAt` correlated subqueries through the query builder
|
|
1977
|
-
instead of raw `sql` fragments, so the active schema (`withSchema(...)`)
|
|
1978
|
-
qualifies `workflow_step_history`. The raw fragments hardcoded an unqualified
|
|
1979
|
-
table name and failed with `relation "workflow_step_history" does not exist`
|
|
1980
|
-
against a connection whose `search_path` did not include the schema.
|
|
1981
|
-
- 34f254e: Bump the `kysely` dependency range to `^0.29.0` so it dedupes onto a single
|
|
1982
|
-
copy alongside Better Auth (which bundles kysely 0.29.x), avoiding two
|
|
1983
|
-
incompatible `Kysely` classes (the `#private` brand mismatch) when both pikku's
|
|
1984
|
-
adapters and Better Auth share a database connection.
|
|
1985
|
-
|
|
1986
|
-
kysely 0.29 is ESM-only, which the unmaintained `kysely-plugin-serialize`
|
|
1987
|
-
(no `exports` map, CommonJS build) cannot import. Its `SerializePlugin` is now
|
|
1988
|
-
maintained directly in `@pikku/kysely` and re-exported, and the external
|
|
1989
|
-
dependency is dropped from `@pikku/kysely`, `@pikku/kysely-sqlite`, and
|
|
1990
|
-
`@pikku/cloudflare`.
|
|
1991
|
-
|
|
1992
|
-
## 0.12.15
|
|
1993
|
-
|
|
1994
|
-
### Patch Changes
|
|
1995
|
-
|
|
1996
|
-
- ea48df2: Include runningAt, succeededAt, and failedAt timestamps in getRunSteps results
|
|
1997
|
-
- Updated dependencies [2cf67be]
|
|
1998
|
-
- @pikku/core@0.12.28
|
|
1999
|
-
|
|
2000
|
-
## 0.12.14
|
|
2001
|
-
|
|
2002
|
-
### Patch Changes
|
|
2003
|
-
|
|
2004
|
-
- 4b5c75b: feat(auth-js): wire OIDC config (issuer/tenantId) as variables, expand provider registry
|
|
2005
|
-
- Move `issuer` and `tenantId` out of the secret blob for OIDC providers (auth0, okta, azure-ad, keycloak, cognito, microsoft-entra-id) — they are public config URLs, not secrets. Now registered via `wireVariable` and loaded at runtime via `services.variables.get()`.
|
|
2006
|
-
- Expand provider registry from 13 to 31 providers: reddit, notion, instagram, zoom, figma, tiktok, threads, patreon, dropbox, bitbucket, hubspot, salesforce, atlassian, strava, keycloak, cognito, microsoft-entra-id added.
|
|
2007
|
-
- `serialize-auth-gen` emits `wireVariable({...})` declarations and `services.variables.get()` calls in the generated factory for OIDC providers.
|
|
2008
|
-
- Integration verifier exercises real `/auth/providers` endpoint with `LocalSecretService` + `LocalVariablesService`, including a spy test proving `services.variables.get('AUTH0_ISSUER')` is called at request time.
|
|
2009
|
-
|
|
2010
|
-
- Updated dependencies [4b5c75b]
|
|
2011
|
-
- Updated dependencies [4b5c75b]
|
|
2012
|
-
- @pikku/core@0.12.27
|
|
2013
|
-
|
|
2014
|
-
## 0.12.13
|
|
2015
|
-
|
|
2016
|
-
### Patch Changes
|
|
2017
|
-
|
|
2018
|
-
- 909eb25: Add audit logging support for function invocations and database queries.
|
|
2019
|
-
|
|
2020
|
-
Introduces `AuditService` and `createAuditedKysely` — configurable audit capture with best-effort and transactional durability modes. Audit logs capture session metadata (user, org), RPC call details, and Kysely query operations (type, tables, changes). Audit context is scoped per-invocation so nested RPC calls are correctly attributed.
|
|
2021
|
-
|
|
2022
|
-
- Updated dependencies [909eb25]
|
|
2023
|
-
- @pikku/core@0.12.26
|
|
2024
|
-
|
|
2025
|
-
## 0.12.12
|
|
2026
|
-
|
|
2027
|
-
### Patch Changes
|
|
2028
|
-
|
|
2029
|
-
- 55ba75a: Update the OSS runtime dependency set for newer Node support by bumping `uWebSockets.js` to `v20.68.0` and `better-sqlite3` to `v12.10.0`.
|
|
2030
|
-
- Updated dependencies [c02275f]
|
|
2031
|
-
- Updated dependencies [0bd0433]
|
|
2032
|
-
- @pikku/core@0.12.24
|
|
2033
|
-
|
|
2034
|
-
## 0.12.11
|
|
2035
|
-
|
|
2036
|
-
### Patch Changes
|
|
2037
|
-
|
|
2038
|
-
- b9ed73e: Add deterministic workflow planned-step metadata support and SSE init stream payload generation.
|
|
2039
|
-
- Persist `deterministic` and `plannedSteps` on workflow runs in core and service adapters.
|
|
2040
|
-
- Expose planned-step metadata on workflow run status responses.
|
|
2041
|
-
- Emit an initial `type: 'init'` SSE event for deterministic workflow streams before incremental updates.
|
|
2042
|
-
- Add CLI tests covering serialized stream route output for init/update/done event behavior.
|
|
2043
|
-
|
|
2044
|
-
- Updated dependencies [b9ed73e]
|
|
2045
|
-
- @pikku/core@0.12.19
|
|
2046
|
-
|
|
2047
|
-
## 0.12.0
|
|
2048
|
-
|
|
2049
|
-
## 0.12.10
|
|
2050
|
-
|
|
2051
|
-
### Patch Changes
|
|
2052
|
-
|
|
2053
|
-
- 311c0c4: Unify session persistence through SessionStore, remove session blob from ChannelStore
|
|
2054
|
-
- PikkuSessionService now persists sessions via SessionStore on set()/clear() instead of every function call
|
|
2055
|
-
- ChannelStore no longer stores session data — maps channelId to pikkuUserId only
|
|
2056
|
-
- ChannelStore API: setUserSession/getChannelAndSession replaced with setPikkuUserId/getChannel
|
|
2057
|
-
- Serverless channel runner resolves sessions from SessionStore using pikkuUserId from ChannelStore
|
|
2058
|
-
|
|
2059
|
-
- Updated dependencies [311c0c4]
|
|
2060
|
-
- @pikku/core@0.12.18
|
|
2061
|
-
|
|
2062
|
-
## 0.12.9
|
|
2063
|
-
|
|
2064
|
-
### Patch Changes
|
|
2065
|
-
|
|
2066
|
-
- 624097e: Add deploy pipeline with provider-agnostic architecture
|
|
2067
|
-
- Add MetaService with explicit typed API, absorb WiringService reads
|
|
2068
|
-
- Add deployment service, traceId propagation, scoped logger
|
|
2069
|
-
- Rewrite analyzer: one function = one worker, gateways dispatch via RPC
|
|
2070
|
-
- Add Cloudflare deploy provider with plan/apply commands
|
|
2071
|
-
- Add per-unit filtered codegen for deploy pipeline
|
|
2072
|
-
- Skip missing metadata in wiring registration for deploy units
|
|
2073
|
-
- Fix schema coercion crash when schema has no properties
|
|
2074
|
-
- Fix E2E codegen: double-pass resolves cross-package Zod type imports
|
|
2075
|
-
|
|
2076
|
-
- Updated dependencies [9e8605f]
|
|
2077
|
-
- Updated dependencies [624097e]
|
|
2078
|
-
- Updated dependencies [7ab3243]
|
|
2079
|
-
- @pikku/core@0.12.15
|
|
2080
|
-
|
|
2081
|
-
## 0.12.8
|
|
2082
|
-
|
|
2083
|
-
### Patch Changes
|
|
2084
|
-
|
|
2085
|
-
- f85c234: Add unified credential system with per-user OAuth and AI agent pre-flight checks
|
|
2086
|
-
- Unified CredentialService with lazy loading per user via pikkuUserId
|
|
2087
|
-
- wire.getCredential() for typed single credential lookup
|
|
2088
|
-
- MissingCredentialError with structured payload for client-side connect flows
|
|
2089
|
-
- Console UI: Global/Users credential tabs, per-user OAuth connect/revoke
|
|
2090
|
-
- AI agent pre-flight check: detects missing OAuth credentials from addon metadata, shows "Connect your accounts" prompt before chat
|
|
2091
|
-
- CLI codegen: generates credentialsMeta per addon package for runtime lookup
|
|
2092
|
-
- Vercel AI runner: catches MissingCredentialError as runtime fallback
|
|
2093
|
-
|
|
2094
|
-
- Updated dependencies [f85c234]
|
|
2095
|
-
- Updated dependencies [88d3100]
|
|
2096
|
-
- @pikku/core@0.12.14
|
|
2097
|
-
|
|
2098
|
-
## 0.12.7
|
|
2099
|
-
|
|
2100
|
-
### Patch Changes
|
|
2101
|
-
|
|
2102
|
-
- c485aab: Fix CamelCasePlugin mismatch: convert all table types, query references, and result property accesses from snake_case to camelCase to match Kysely CamelCasePlugin runtime behavior
|
|
2103
|
-
|
|
2104
|
-
## 0.12.6
|
|
2105
|
-
|
|
2106
|
-
### Patch Changes
|
|
2107
|
-
|
|
2108
|
-
- 0f59432: Add per-user credential system with CredentialService, OAuth2 route handlers, and KyselyCredentialService with envelope encryption
|
|
2109
|
-
- Updated dependencies [0f59432]
|
|
2110
|
-
- Updated dependencies [52b64d1]
|
|
2111
|
-
- @pikku/core@0.12.10
|
|
2112
|
-
|
|
2113
|
-
## 0.12.5
|
|
2114
|
-
|
|
2115
|
-
### Patch Changes
|
|
2116
|
-
|
|
2117
|
-
- 87433f0: Remove secret key names from error messages to prevent information disclosure.
|
|
2118
|
-
- Updated dependencies [e412b4d]
|
|
2119
|
-
- Updated dependencies [53dc8c8]
|
|
2120
|
-
- Updated dependencies [0a1cc51]
|
|
2121
|
-
- Updated dependencies [0a1cc51]
|
|
2122
|
-
- Updated dependencies [0a1cc51]
|
|
2123
|
-
- Updated dependencies [0a1cc51]
|
|
2124
|
-
- Updated dependencies [0a1cc51]
|
|
2125
|
-
- Updated dependencies [0a1cc51]
|
|
2126
|
-
- Updated dependencies [0a1cc51]
|
|
2127
|
-
- Updated dependencies [0a1cc51]
|
|
2128
|
-
- Updated dependencies [0a1cc51]
|
|
2129
|
-
- Updated dependencies [8b9b2e9]
|
|
2130
|
-
- Updated dependencies [8b9b2e9]
|
|
2131
|
-
- Updated dependencies [b973d44]
|
|
2132
|
-
- Updated dependencies [8b9b2e9]
|
|
2133
|
-
- Updated dependencies [8b9b2e9]
|
|
2134
|
-
- @pikku/core@0.12.9
|
|
2135
|
-
|
|
2136
|
-
## 0.12.4
|
|
2137
|
-
|
|
2138
|
-
### Patch Changes
|
|
2139
|
-
|
|
2140
|
-
- 3e79248: Add setStepChildRunId to workflow service implementations and auto-bootstrap in pikku all
|
|
2141
|
-
- Updated dependencies [bb27710]
|
|
2142
|
-
- Updated dependencies [a31bc63]
|
|
2143
|
-
- Updated dependencies [3e79248]
|
|
2144
|
-
- Updated dependencies [b0a81cc]
|
|
2145
|
-
- Updated dependencies [6413df7]
|
|
2146
|
-
- @pikku/core@0.12.6
|
|
2147
|
-
|
|
2148
|
-
## 0.12.3
|
|
2149
|
-
|
|
2150
|
-
### Patch Changes
|
|
2151
|
-
|
|
2152
|
-
- 32ed003: Add envelope encryption utilities and database-backed secret services with KEK rotation support
|
|
2153
|
-
- 387b2ee: Add error_message column to agent run storage and queries
|
|
2154
|
-
- b2b0af9: Migrate all consumers from @pikku/pg to @pikku/kysely and remove the @pikku/pg package
|
|
2155
|
-
- c7ff141: Add WorkflowVersionStatus type with draft→active lifecycle for AI-generated workflows, type all DB status fields with proper unions instead of plain strings
|
|
2156
|
-
- Updated dependencies [387b2ee]
|
|
2157
|
-
- Updated dependencies [32ed003]
|
|
2158
|
-
- Updated dependencies [7d369f3]
|
|
2159
|
-
- Updated dependencies [508a796]
|
|
2160
|
-
- Updated dependencies [ffe83af]
|
|
2161
|
-
- Updated dependencies [c7ff141]
|
|
2162
|
-
- @pikku/core@0.12.3
|
|
2163
|
-
|
|
2164
|
-
## 0.12.2
|
|
2165
|
-
|
|
2166
|
-
### Patch Changes
|
|
2167
|
-
|
|
2168
|
-
- ce961b5: fix: improve MySQL compatibility in AI storage service by using varchar columns with explicit lengths instead of text for primary keys, foreign keys, and indexed columns, and handle duplicate index errors gracefully
|
|
2169
|
-
- 3e04565: chore: update dependencies to latest minor/patch versions
|
|
2170
|
-
- Updated dependencies [cc4c9e9]
|
|
2171
|
-
- Updated dependencies [3e04565]
|
|
2172
|
-
- @pikku/core@0.12.2
|
|
2173
|
-
|
|
2174
|
-
## 0.12.1
|
|
2175
|
-
|
|
2176
|
-
### Patch Changes
|
|
2177
|
-
|
|
2178
|
-
- e04531f: Code quality improvements: resolve oxlint warnings and apply autofixes across the codebase (unused bindings, unnecessary constructors, prefer `const` over `let`, etc.). No behaviour changes.
|
|
2179
|
-
- Updated dependencies [62a8725]
|
|
2180
|
-
- Updated dependencies [a3bdb0d]
|
|
2181
|
-
- Updated dependencies [e0349ff]
|
|
2182
|
-
- Updated dependencies [62a8725]
|
|
2183
|
-
- Updated dependencies [e04531f]
|
|
2184
|
-
- Updated dependencies [62a8725]
|
|
2185
|
-
- Updated dependencies [a83efb8]
|
|
2186
|
-
- Updated dependencies [8eed717]
|
|
2187
|
-
- Updated dependencies [62a8725]
|
|
2188
|
-
- Updated dependencies [62a8725]
|
|
2189
|
-
- Updated dependencies [62a8725]
|
|
2190
|
-
- @pikku/core@0.12.1
|
|
2191
|
-
|
|
2192
|
-
- Updated dependencies
|
|
2193
|
-
|
|
2194
|
-
## 0.11.0
|
|
2195
|
-
|
|
2196
|
-
### Minor Changes
|
|
2197
|
-
|
|
2198
|
-
- Remove Kysely-based channel and eventhub stores (use @pikku/pg instead)
|
|
2199
|
-
- Update to support shared connection instances
|
|
2200
|
-
|
|
2201
|
-
# @pikku/kysely
|
|
2202
|
-
|
|
2203
|
-
## 0.10.0
|
|
2204
|
-
|
|
2205
|
-
This release includes significant improvements across the framework including tree-shaking support, middleware/permission factories, enhanced CLI functionality, improved TypeScript type safety, and comprehensive test strategies.
|
|
2206
|
-
|
|
2207
|
-
For complete details, see https://pikku.dev/changelogs/0_10_0.md
|
|
2208
|
-
|
|
2209
|
-
## 0.9.5-next.0
|
|
2210
|
-
|
|
2211
|
-
### Patch Changes
|
|
2212
|
-
|
|
2213
|
-
- Updated dependencies
|
|
2214
|
-
- @pikku/core@0.9.12-next.0
|
|
2215
|
-
|
|
2216
|
-
## 0.9.4
|
|
2217
|
-
|
|
2218
|
-
### Patch Changes
|
|
2219
|
-
|
|
2220
|
-
- 58fe540: fix: kysely pure script should also clean arrays
|
|
2221
|
-
- Updated dependencies [85a1c76]
|
|
2222
|
-
- @pikku/core@0.9.7
|
|
2223
|
-
|
|
2224
|
-
## 0.9.3
|
|
2225
|
-
|
|
2226
|
-
### Patch Changes
|
|
2227
|
-
|
|
2228
|
-
- 917bd6b: feat: fixing number issue with pure generation
|
|
2229
|
-
- af95a59: fix: adding a number type (string or number) to db for now. Going forward should probably parse to a number but js and floats..
|
|
2230
|
-
- Updated dependencies [9691aba]
|
|
2231
|
-
- Updated dependencies [2ab0278]
|
|
2232
|
-
- Updated dependencies [81005ba]
|
|
2233
|
-
- @pikku/core@0.9.3
|
|
2234
|
-
|
|
2235
|
-
## 0.9.2
|
|
2236
|
-
|
|
2237
|
-
### Patch Changes
|
|
2238
|
-
|
|
2239
|
-
- a5905a9: chore: updating all dependencies
|
|
2240
|
-
- Updated dependencies [1256238]
|
|
2241
|
-
- Updated dependencies [6cf8efd]
|
|
2242
|
-
- Updated dependencies [d3a9a09]
|
|
2243
|
-
- Updated dependencies [840e078]
|
|
2244
|
-
- Updated dependencies [667d23c]
|
|
2245
|
-
- Updated dependencies [a5905a9]
|
|
2246
|
-
- @pikku/core@0.9.2
|
|
2247
|
-
|
|
2248
|
-
## 0.9.1
|
|
2249
|
-
|
|
2250
|
-
### Patch Changes
|
|
2251
|
-
|
|
2252
|
-
- fdb1593: core: bumping everything with a patch to sync up the major release inconsistencies in dependencies
|
|
2253
|
-
- Updated dependencies [fdb1593]
|
|
2254
|
-
- @pikku/core@0.9.1
|
|
2255
|
-
|
|
2256
|
-
## 0.9.0
|
|
2257
|
-
|
|
2258
|
-
### Breaking Changes
|
|
2259
|
-
|
|
2260
|
-
- Normalized all transports to use "wirings" instead of events/routes/transports for consistency across the framework
|
|
2261
|
-
|
|
2262
|
-
## 0.8.0
|
|
2263
|
-
|
|
2264
|
-
- Updated to match the 0.8 version
|
|
2265
|
-
|
|
2266
|
-
## 0.7.0
|
|
2267
|
-
|
|
2268
|
-
- Updating to match remaining packages
|
|
2269
|
-
|
|
2270
|
-
## 0.6.5
|
|
2271
|
-
|
|
2272
|
-
### Patch Changes
|
|
2273
|
-
|
|
2274
|
-
- 9541f42: fix: deleting ssl invalidation
|
|
2275
|
-
|
|
2276
|
-
## 0.6.4
|
|
2277
|
-
|
|
2278
|
-
### Patch Changes
|
|
2279
|
-
|
|
2280
|
-
- 8a14f3a: refactor: removing user session from channel object
|
|
2281
|
-
- Updated dependencies [ebc04eb]
|
|
2282
|
-
- Updated dependencies [8a14f3a]
|
|
2283
|
-
- Updated dependencies [2c47386]
|
|
2284
|
-
- @pikku/core@0.6.17
|
|
2285
|
-
|
|
2286
|
-
## 0.6.3
|
|
2287
|
-
|
|
2288
|
-
### Patch Changes
|
|
2289
|
-
|
|
2290
|
-
- 2c9a6b0: fix: correct reference to pikku-kysely-pure
|
|
2291
|
-
|
|
2292
|
-
## 0.6.2
|
|
2293
|
-
|
|
2294
|
-
### Patch Changes
|
|
2295
|
-
|
|
2296
|
-
- 990c2c2: fix: not requiring kysely as a peerDependency
|
|
2297
|
-
|
|
2298
|
-
## 0.6.1
|
|
2299
|
-
|
|
2300
|
-
### Patch Changes
|
|
2301
|
-
|
|
2302
|
-
- 8fcaa7e: feat: adding kysely wrapper
|
|
2303
|
-
- Updated dependencies [eb8a8b4]
|
|
2304
|
-
- @pikku/core@0.6.13
|
|
2305
|
-
|
|
2306
|
-
## 0.6.1
|
|
2307
|
-
|
|
2308
|
-
### Patch Changes
|
|
2309
|
-
|
|
2310
|
-
- 0a92fa7: refactor: pulling schema into seperate package since ajv doesnt work on cloudflare (also keeps bundle size small!)
|
|
2311
|
-
- Updated dependencies [0a92fa7]
|
|
2312
|
-
- @pikku/core@0.6.7
|
|
2313
|
-
|
|
2314
|
-
## 0.6
|
|
2315
|
-
|
|
2316
|
-
Marking a major release to include channels and scheduled tasks
|
|
2317
|
-
|
|
2318
|
-
## 0.5.3
|
|
2319
|
-
|
|
2320
|
-
### Patch Changes
|
|
2321
|
-
|
|
2322
|
-
- 886a2fb: refactor: moving singletons (like routes and channels) to global to avoid nodemodule overrides
|
|
2323
|
-
- Updated dependencies [a768bad]
|
|
2324
|
-
- Updated dependencies [886a2fb]
|
|
2325
|
-
- Updated dependencies [886a2fb]
|
|
2326
|
-
- @pikku/core@0.5.28
|
|
2327
|
-
|
|
2328
|
-
## 0.5.2
|
|
2329
|
-
|
|
2330
|
-
### Patch Changes
|
|
2331
|
-
|
|
2332
|
-
- 0f96787: refactor: dropping cjs support
|
|
2333
|
-
- c23524a: refactor: bump to versions to ensure correct package usage
|
|
2334
|
-
- Updated dependencies [0f96787]
|
|
2335
|
-
- Updated dependencies [64e4a1e]
|
|
2336
|
-
- Updated dependencies [c23524a]
|
|
2337
|
-
- @pikku/core@0.5.25
|
|
2338
|
-
|
|
2339
|
-
## 0.5.1
|
|
2340
|
-
|
|
2341
|
-
### Patch Changes
|
|
2342
|
-
|
|
2343
|
-
- bba25cc: chore: updating all packages to reflect major changes
|
|
2344
|
-
- Updated dependencies [bba25cc]
|
|
2345
|
-
- Updated dependencies [9deb482]
|
|
2346
|
-
- Updated dependencies [ee0c6ea]
|
|
2347
|
-
- @pikku/core@0.5.24
|