@pikku/skills 0.12.12 → 0.12.14

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/dist/skills.gen.js +1 -1
  3. package/package.json +1 -1
  4. package/skills/pikku-addon/references/addon-package-manifest.md +61 -11
  5. package/skills/pikku-ai-vercel/SKILL.md +0 -1
  6. package/skills/pikku-ai-voice/SKILL.md +1 -0
  7. package/skills/pikku-audit/SKILL.md +0 -1
  8. package/skills/pikku-better-auth/SKILL.md +0 -1
  9. package/skills/pikku-build-app/SKILL.md +0 -1
  10. package/skills/pikku-build-platform/SKILL.md +3 -4
  11. package/skills/pikku-build-quick/SKILL.md +0 -1
  12. package/skills/pikku-concepts/SKILL.md +58 -16
  13. package/skills/pikku-concepts/references/concept-mapping.md +1 -1
  14. package/skills/pikku-deploy-cloudflare/SKILL.md +0 -1
  15. package/skills/pikku-deps/SKILL.md +0 -1
  16. package/skills/pikku-emails/SKILL.md +0 -1
  17. package/skills/pikku-fabric/SKILL.md +55 -4
  18. package/skills/pikku-feature/SKILL.md +0 -1
  19. package/skills/pikku-gateway-slack/SKILL.md +1 -0
  20. package/skills/pikku-i18n/SKILL.md +1 -1
  21. package/skills/pikku-info/SKILL.md +0 -1
  22. package/skills/pikku-knowledge/SKILL.md +0 -1
  23. package/skills/pikku-kysely/SKILL.md +0 -1
  24. package/skills/pikku-paraglide/SKILL.md +1 -1
  25. package/skills/pikku-product-second-opinion/SKILL.md +0 -1
  26. package/skills/pikku-queue/SKILL.md +1 -1
  27. package/skills/pikku-react/SKILL.md +1 -1
  28. package/skills/pikku-react-query/SKILL.md +1 -1
  29. package/skills/pikku-realtime/SKILL.md +0 -1
  30. package/skills/pikku-rpc/SKILL.md +0 -1
  31. package/skills/pikku-rtl/SKILL.md +1 -1
  32. package/skills/pikku-scenario/SKILL.md +29 -2
  33. package/skills/pikku-schedule/SKILL.md +178 -50
  34. package/skills/pikku-schema-ajv/SKILL.md +0 -1
  35. package/skills/pikku-schema-cfworker/SKILL.md +0 -1
  36. package/skills/pikku-security/SKILL.md +2 -2
  37. package/skills/pikku-software-archaeology/SKILL.md +0 -1
  38. package/skills/pikku-template-clone/SKILL.md +0 -1
  39. package/skills/pikku-trigger/SKILL.md +1 -1
  40. package/skills/pikku-versioning/SKILL.md +0 -1
  41. package/skills/pikku-workflow/SKILL.md +1 -1
  42. package/skills/pikku-workflows-client/SKILL.md +1 -1
  43. package/skills/pikku-cron/SKILL.md +0 -221
  44. package/skills/pikku-tag-middleware/SKILL.md +0 -14
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  name: pikku-schedule
3
3
  description: >-
4
- Use when setting up in-memory cron scheduling in a Pikku app. Covers InMemorySchedulerService
5
- for running scheduled tasks. TRIGGER when: code uses InMemorySchedulerService,
6
- PikkuTaskScheduler, or user asks about in-memory scheduling, cron jobs without external
7
- dependencies, or @pikku/schedule. DO NOT TRIGGER when: user asks about cron wiring (use
8
- pikku-cron) or queue-based scheduling with BullMQ/PgBoss (use pikku-queue).
4
+ Use when adding scheduled tasks, recurring jobs, or cron-based automation to a Pikku app. Covers
5
+ wireScheduler, cron expressions, the scheduled task wire object, and scheduler middleware.
6
+ TRIGGER when: code uses wireScheduler, user asks about cron, scheduled tasks, recurring jobs, or
7
+ "run every X minutes/hours". DO NOT TRIGGER when: user asks about background jobs with retries
8
+ (use pikku-queue) or event-driven triggers (use pikku-trigger).
9
9
  installGroups: [core]
10
10
  ---
11
11
 
12
- # Pikku Schedule (In-Memory Scheduler)
12
+ # Pikku Scheduled Tasks
13
13
 
14
14
  ## Agent Operating Procedure
15
15
 
@@ -21,75 +21,203 @@ Use this skill as an execution checklist, not reference material.
21
21
  4. Validate with the narrowest relevant command first, then run `pikku-verify` or `pikku all` when functions, wirings, schemas, or generated clients may have changed.
22
22
  5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
23
23
 
24
- `@pikku/schedule` provides an in-memory cron scheduler for running Pikku scheduled functions without external dependencies like Redis or PostgreSQL.
24
+ Wire Pikku functions to run on a schedule using cron expressions. Uses `pikkuVoidFunc` (no input/output).
25
25
 
26
- ## Installation
26
+ `pikku dev`, `pikku serve` and the standalone deploy adapter each register a scheduler service for you, so a wired task runs without any setup. Only register one yourself when deploying somewhere those do not reach, and then take it off the queue factory (`bullFactory.getSchedulerService()`, `pgBossFactory.getSchedulerService()` — see `pikku-queue`) so it survives a restart and is shared between instances.
27
+
28
+ ## Before You Start
27
29
 
28
30
  ```bash
29
- yarn add @pikku/schedule
31
+ pikku info functions --verbose # See existing functions and their types
32
+ pikku info tags --verbose # Understand project organization
30
33
  ```
31
34
 
35
+ See `pikku-concepts` for the core mental model.
36
+
32
37
  ## API Reference
33
38
 
34
- ### `InMemorySchedulerService`
39
+ ### `wireScheduler(config)`
35
40
 
36
41
  ```typescript
37
- import { InMemorySchedulerService } from '@pikku/schedule'
38
-
39
- const schedulerService = new InMemorySchedulerService()
40
- await schedulerService.start() // registers a CronJob per wired scheduled task
42
+ import { wireScheduler } from '@pikku/core/scheduler'
43
+
44
+ wireScheduler({
45
+ name: string, // Unique scheduler name
46
+ schedule: string, // Cron expression
47
+ func: PikkuVoidFunc, // Must be pikkuVoidFunc (no input/output)
48
+ tags?: string[], // Targets tag middleware — see pikku-middleware
49
+ middleware?: PikkuMiddleware[],
50
+ })
41
51
  ```
42
52
 
43
- It implements core's `SchedulerService` on two mechanisms: `cron` for the
44
- recurring tasks you declared with `wireScheduler` (see `pikku-cron`), and
45
- `setTimeout` for one-off delayed RPCs. Both live in process memory, so nothing
46
- survives a restart and nothing is shared between instances — fine for
47
- development and a single-instance deployment, wrong for anything else.
48
-
49
- `PikkuTaskScheduler` is a deprecated alias for the same class.
53
+ ### Wire Object (`wire.scheduledTask`)
50
54
 
51
- ### Scheduling a one-off RPC
55
+ Inside scheduled functions:
52
56
 
53
57
  ```typescript
54
- const taskId = await schedulerService.scheduleRPC(
55
- '5m',
56
- 'sendReminder',
57
- data,
58
- session
59
- )
60
- await schedulerService.getTask(taskId) // { rpcName, scheduledFor, status, … } | null
61
- await schedulerService.getAllTasks() // pending one-offs only
62
- await schedulerService.unschedule(taskId) // true when it was still pending
58
+ wire.scheduledTask.name // Scheduler name
59
+ wire.scheduledTask.schedule // Cron expression string
60
+ wire.scheduledTask.executionTime // Date this execution was triggered
61
+ wire.scheduledTask.skip(reason?) // Abort this execution — THROWS, never returns
62
+ ```
63
+
64
+ **`skip()` aborts by throwing.** It reads like an early return but it is not:
65
+ nothing after the call runs, so there is no need to `return` afterwards. The
66
+ consequence that bites is in middleware — a `try/catch` around `await next()`
67
+ will catch a skip and report it as a failure. If your middleware distinguishes
68
+ success from failure, let the skip pass through rather than logging it as an
69
+ error.
70
+
71
+ ### Cron Expression Reference
72
+
73
+ ```
74
+ ┌───────────── minute (0-59)
75
+ │ ┌───────────── hour (0-23)
76
+ │ │ ┌───────────── day of month (1-31)
77
+ │ │ │ ┌───────────── month (1-12)
78
+ │ │ │ │ ┌───────────── day of week (0-7, 0 and 7 = Sunday)
79
+ │ │ │ │ │
80
+ * * * * *
63
81
  ```
64
82
 
65
- The delay is milliseconds or a duration string (`'30s'`, `'5m'`, `'2h'`). This is
66
- also the mechanism a workflow's delayed steps use, which is why a workflow that
67
- sleeps needs a `schedulerService` registered.
83
+ Common patterns:
84
+
85
+ | Expression | Meaning |
86
+ | ------------- | -------------------------- |
87
+ | `*/5 * * * *` | Every 5 minutes |
88
+ | `0 9 * * *` | Daily at 9:00 AM |
89
+ | `0 9 * * 1` | Every Monday at 9:00 AM |
90
+ | `0 0 1 * *` | First of month at midnight |
91
+ | `0 */6 * * *` | Every 6 hours |
92
+ | `30 2 * * 0` | Sundays at 2:30 AM |
68
93
 
69
94
  ## Usage Patterns
70
95
 
71
- ### Basic Setup
96
+ ### Basic Scheduled Task
97
+
98
+ ```typescript
99
+ const dailySummary = pikkuVoidFunc({
100
+ title: 'Daily Summary',
101
+ func: async ({ db, emailService, logger }) => {
102
+ logger.info('Generating daily summary')
103
+ const stats = await db.getDailyStats()
104
+ await emailService.sendSummary(stats)
105
+ },
106
+ })
107
+
108
+ wireScheduler({
109
+ name: 'dailySummary',
110
+ schedule: '0 9 * * *',
111
+ func: dailySummary,
112
+ })
113
+ ```
72
114
 
73
- The scheduler is a singleton service under the name **`schedulerService`**, and
74
- it is started in your server bootstrap — declaring it without calling `start()`
75
- registers no cron jobs, so nothing ever fires:
115
+ ### Using the Wire Object
76
116
 
77
117
  ```typescript
78
- // start.ts
79
- import { InMemorySchedulerService } from '@pikku/schedule'
118
+ const weeklyCleanup = pikkuVoidFunc({
119
+ title: 'Weekly Cleanup',
120
+ func: async ({ db, logger }, _input, wire) => {
121
+ logger.info(`Running: ${wire.scheduledTask.name}`)
122
+ logger.info(`Schedule: ${wire.scheduledTask.schedule}`)
123
+ logger.info(`Execution time: ${wire.scheduledTask.executionTime}`)
124
+
125
+ const staleCount = await db.countStaleTodos()
126
+ if (staleCount === 0) {
127
+ wire.scheduledTask.skip('No stale todos found') // throws — nothing below runs
128
+ }
129
+
130
+ await db.deleteCompletedTodos({ olderThan: '30d' })
131
+ logger.info(`Cleaned ${staleCount} stale todos`)
132
+ },
133
+ })
80
134
 
81
- const schedulerService = new InMemorySchedulerService()
82
- const singletonServices = await createSingletonServices(config, {
83
- schedulerService,
135
+ wireScheduler({
136
+ name: 'weeklyCleanup',
137
+ schedule: '0 0 * * 0',
138
+ func: weeklyCleanup,
84
139
  })
140
+ ```
141
+
142
+ ### Scheduler Middleware
85
143
 
86
- await appServer.start()
87
- await schedulerService.start()
144
+ ```typescript
145
+ const schedulerMetrics = pikkuMiddleware(
146
+ async ({ logger }, { scheduledTask }, next) => {
147
+ const start = Date.now()
148
+ logger.info(`Task started: ${scheduledTask.name}`)
149
+
150
+ try {
151
+ await next()
152
+ logger.info(`Task completed: ${scheduledTask.name}`, {
153
+ duration: Date.now() - start,
154
+ })
155
+ } catch (error) {
156
+ logger.error(`Task failed: ${scheduledTask.name}`, {
157
+ error: error.message,
158
+ duration: Date.now() - start,
159
+ })
160
+ throw error
161
+ }
162
+ }
163
+ )
164
+
165
+ wireScheduler({
166
+ name: 'dailySummary',
167
+ schedule: '0 9 * * *',
168
+ func: dailySummary,
169
+ middleware: [schedulerMetrics],
170
+ })
88
171
  ```
89
172
 
90
- Call `close()` on shutdown — it stops every cron job and clears pending timers.
173
+ ## Complete Example
174
+
175
+ ```typescript
176
+ // functions/scheduled.functions.ts
177
+ export const dailySummary = pikkuVoidFunc({
178
+ title: 'Daily Summary',
179
+ func: async ({ db, emailService, logger }) => {
180
+ const stats = await db.getDailyStats()
181
+ await emailService.sendSummary(stats)
182
+ logger.info('Daily summary sent', { stats })
183
+ },
184
+ })
185
+
186
+ export const cleanupExpired = pikkuVoidFunc({
187
+ title: 'Cleanup Expired',
188
+ func: async ({ db, logger }, _input, wire) => {
189
+ const count = await db.countExpiredSessions()
190
+ if (count === 0) {
191
+ wire.scheduledTask.skip('No expired sessions') // throws — nothing below runs
192
+ }
193
+ await db.deleteExpiredSessions()
194
+ logger.info(`Cleaned ${count} expired sessions`)
195
+ },
196
+ })
197
+
198
+ export const syncInventory = pikkuVoidFunc({
199
+ title: 'Sync Inventory',
200
+ func: async ({ inventoryApi, db, logger }) => {
201
+ const updates = await inventoryApi.getChanges()
202
+ await db.applyInventoryUpdates(updates)
203
+ logger.info(`Synced ${updates.length} inventory changes`)
204
+ },
205
+ })
91
206
 
92
- For distributed or persistent scheduling, take the scheduler service off the
93
- queue factory instead (`bullFactory.getSchedulerService()`,
94
- `pgBossFactory.getSchedulerService()`) and register it under the same name. See
95
- `pikku-queue`.
207
+ // wirings/scheduler.wiring.ts
208
+ wireScheduler({
209
+ name: 'dailySummary',
210
+ schedule: '0 9 * * *',
211
+ func: dailySummary,
212
+ })
213
+ wireScheduler({
214
+ name: 'cleanupExpired',
215
+ schedule: '0 */6 * * *',
216
+ func: cleanupExpired,
217
+ })
218
+ wireScheduler({
219
+ name: 'syncInventory',
220
+ schedule: '*/15 * * * *',
221
+ func: syncInventory,
222
+ })
223
+ ```
@@ -5,7 +5,6 @@ description: >-
5
5
  request/response validation. TRIGGER when: code uses AjvSchemaService, user asks about AJV, JSON
6
6
  schema validation, or @pikku/schema-ajv. DO NOT TRIGGER when: user asks about Cloudflare Workers
7
7
  schema validation (use pikku-schema-cfworker).
8
- installGroups: [core]
9
8
  ---
10
9
 
11
10
  # Pikku Schema AJV (JSON Schema Validation)
@@ -6,7 +6,6 @@ description: >-
6
6
  CFWorkerSchemaService, user asks about schema validation on Cloudflare Workers, or
7
7
  @pikku/schema-cfworker. DO NOT TRIGGER when: user asks about AJV schema validation (use
8
8
  pikku-schema-ajv).
9
- installGroups: [core, fabric]
10
9
  ---
11
10
 
12
11
  # Pikku Schema CFWorker (Cloudflare Workers Validation)
@@ -61,7 +61,7 @@ with the default `auth` would be rejected before its body ever ran.
61
61
  Apply these via `addHTTPMiddleware` in a wirings file:
62
62
 
63
63
  ```typescript
64
- import { authBearer, authCookie, authAPIKey } from '@pikku/core/middleware'
64
+ import { authBearer, authCookie, authAPIKey } from '#pikku/middleware'
65
65
  import { addHTTPMiddleware } from '#pikku/http'
66
66
 
67
67
  // JWT bearer token — reads Authorization header
@@ -128,7 +128,7 @@ export const isVerified = pikkuAuth(
128
128
  )
129
129
 
130
130
  // wirings/auth.wiring.ts
131
- import { authCookie } from '@pikku/core/middleware'
131
+ import { authCookie } from '#pikku/middleware'
132
132
  import { addHTTPMiddleware } from '#pikku/http'
133
133
 
134
134
  addHTTPMiddleware('*', [
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: pikku-software-archaeology
3
3
  description: 'Use when reverse-engineering an existing repository into a Product Blueprint — recovering what product an undocumented or organically-grown codebase implements so it can be rebuilt cleanly (e.g. as a Pikku app). TRIGGER when: user says "extract a blueprint", "reverse engineer this app", "what does this codebase actually do as a product", "prepare this repo for a rewrite/migration", or points at a legacy repo (any language — JS, TS, Ruby, Python, PHP, Go) and asks for its domains, workflows, business rules, or a rebuild plan. DO NOT TRIGGER for: documenting code structure, generating API docs from an already-clean codebase, or code review.'
4
- installGroups: [fabric]
5
4
  ---
6
5
 
7
6
  # Software Archaeology
@@ -2,7 +2,6 @@
2
2
  name: pikku-template-clone
3
3
  description: 'Standard cleanup to run right after a Pikku template is cloned or scaffolded into a new project. TRIGGER when: a Pikku template was just cloned/scaffolded (via `npm create pikku`, `git clone <template>`, or the user says "I cloned the kanban template / starter / template"), or the working tree still looks like an untouched template (template README, placeholder `@project/*` name in package.json). DO NOT TRIGGER when: working in an established project mid-feature, or editing the template repo itself.'
4
4
  allowed-tools: Bash(git status *), Bash(git add *), Bash(git commit *), Bash(git rm *), Bash(git mv *), Bash(git log *)
5
- installGroups: [core]
6
5
  ---
7
6
 
8
7
  # Pikku Template Post-Clone Cleanup
@@ -5,7 +5,7 @@ description: >-
5
5
  PostgreSQL LISTEN/NOTIFY, or custom event sources. Covers wireTrigger, wireTriggerSource, and
6
6
  pikkuTriggerFunc. TRIGGER when: code uses wireTrigger/wireTriggerSource/pikkuTriggerFunc, user
7
7
  asks about event-driven functions, Redis pub/sub, PostgreSQL LISTEN/NOTIFY, or reacting to
8
- external events. DO NOT TRIGGER when: user asks about scheduled tasks (use pikku-cron) or
8
+ external events. DO NOT TRIGGER when: user asks about scheduled tasks (use pikku-schedule) or
9
9
  background job queues (use pikku-queue).
10
10
  installGroups: [core]
11
11
  ---
@@ -11,7 +11,6 @@ description: >-
11
11
  CLI commands. DO NOT TRIGGER when: user asks about secrets/variables/OAuth2 (use pikku-config)
12
12
  or general function definitions (use pikku-concepts), or about updating dependency versions
13
13
  (use pikku-deps).
14
- installGroups: [core]
15
14
  ---
16
15
 
17
16
  # Pikku Function Versioning
@@ -6,7 +6,7 @@ description: >-
6
6
  TRIGGER when: code uses pikkuWorkflowFunc/pikkuWorkflowGraph, user asks about workflows,
7
7
  multi-step processes, durable execution, suspend/resume, or DAG orchestration. DO NOT TRIGGER
8
8
  when: user asks about simple background jobs (use pikku-queue) or scheduled tasks (use
9
- pikku-cron).
9
+ pikku-schedule).
10
10
  installGroups: [core]
11
11
  ---
12
12
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pikku-workflows-client
3
3
  description: 'Run Pikku workflows from a React frontend and track their progress. Covers `useRunWorkflow` (run-and-wait), `useStartWorkflow` (fire-and-poll), and `useWorkflowStatus` (live status). TRIGGER when: a React component needs to invoke or display the status of a Pikku workflow, the user mentions long-running tasks / background jobs / progress UI tied to a workflow, or asks how to start/track a workflow from the client. DO NOT TRIGGER when: the user is wiring the workflow itself (use pikku-workflow) or only making regular RPC calls (use pikku-react-query).'
4
- installGroups: [core]
4
+ installGroups: [client]
5
5
  ---
6
6
 
7
7
  # Pikku Workflows — Client Hooks
@@ -1,221 +0,0 @@
1
- ---
2
- name: pikku-cron
3
- description: >-
4
- Use when adding scheduled tasks, recurring jobs, or cron-based automation to a Pikku app. Covers
5
- wireScheduler, cron expressions, scheduled task wire object, and scheduler middleware. TRIGGER
6
- when: code uses wireScheduler, user asks about cron, scheduled tasks, recurring jobs, or "run
7
- every X minutes/hours". DO NOT TRIGGER when: user asks about background jobs with retries (use
8
- pikku-queue) or event-driven triggers (use pikku-trigger).
9
- installGroups: [core]
10
- ---
11
-
12
- # Pikku Cron/Scheduler Wiring
13
-
14
- ## Agent Operating Procedure
15
-
16
- Use this skill as an execution checklist, not reference material.
17
-
18
- 1. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
19
- 2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, vendored packages, or broad build artifacts.
20
- 3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
21
- 4. Validate with the narrowest relevant command first, then run `pikku-verify` or `pikku all` when functions, wirings, schemas, or generated clients may have changed.
22
- 5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
23
-
24
- Wire Pikku functions to run on a schedule using cron expressions. Uses `pikkuVoidFunc` (no input/output).
25
-
26
- ## Before You Start
27
-
28
- ```bash
29
- pikku info functions --verbose # See existing functions and their types
30
- pikku info tags --verbose # Understand project organization
31
- ```
32
-
33
- See `pikku-concepts` for the core mental model.
34
-
35
- ## API Reference
36
-
37
- ### `wireScheduler(config)`
38
-
39
- ```typescript
40
- import { wireScheduler } from '@pikku/core/scheduler'
41
-
42
- wireScheduler({
43
- name: string, // Unique scheduler name
44
- schedule: string, // Cron expression
45
- func: PikkuVoidFunc, // Must be pikkuVoidFunc (no input/output)
46
- tags?: string[], // Targets tag middleware — see pikku-middleware
47
- middleware?: PikkuMiddleware[],
48
- })
49
- ```
50
-
51
- ### Wire Object (`wire.scheduledTask`)
52
-
53
- Inside scheduled functions:
54
-
55
- ```typescript
56
- wire.scheduledTask.name // Scheduler name
57
- wire.scheduledTask.schedule // Cron expression string
58
- wire.scheduledTask.executionTime // Date this execution was triggered
59
- wire.scheduledTask.skip(reason?) // Abort this execution — THROWS, never returns
60
- ```
61
-
62
- **`skip()` aborts by throwing.** It reads like an early return but it is not:
63
- nothing after the call runs, so there is no need to `return` afterwards. The
64
- consequence that bites is in middleware — a `try/catch` around `await next()`
65
- will catch a skip and report it as a failure. If your middleware distinguishes
66
- success from failure, let the skip pass through rather than logging it as an
67
- error.
68
-
69
- ### Cron Expression Reference
70
-
71
- ```
72
- ┌───────────── minute (0-59)
73
- │ ┌───────────── hour (0-23)
74
- │ │ ┌───────────── day of month (1-31)
75
- │ │ │ ┌───────────── month (1-12)
76
- │ │ │ │ ┌───────────── day of week (0-7, 0 and 7 = Sunday)
77
- │ │ │ │ │
78
- * * * * *
79
- ```
80
-
81
- Common patterns:
82
-
83
- | Expression | Meaning |
84
- | ------------- | -------------------------- |
85
- | `*/5 * * * *` | Every 5 minutes |
86
- | `0 9 * * *` | Daily at 9:00 AM |
87
- | `0 9 * * 1` | Every Monday at 9:00 AM |
88
- | `0 0 1 * *` | First of month at midnight |
89
- | `0 */6 * * *` | Every 6 hours |
90
- | `30 2 * * 0` | Sundays at 2:30 AM |
91
-
92
- ## Usage Patterns
93
-
94
- ### Basic Scheduled Task
95
-
96
- ```typescript
97
- const dailySummary = pikkuVoidFunc({
98
- title: 'Daily Summary',
99
- func: async ({ db, emailService, logger }) => {
100
- logger.info('Generating daily summary')
101
- const stats = await db.getDailyStats()
102
- await emailService.sendSummary(stats)
103
- },
104
- })
105
-
106
- wireScheduler({
107
- name: 'dailySummary',
108
- schedule: '0 9 * * *',
109
- func: dailySummary,
110
- })
111
- ```
112
-
113
- ### Using the Wire Object
114
-
115
- ```typescript
116
- const weeklyCleanup = pikkuVoidFunc({
117
- title: 'Weekly Cleanup',
118
- func: async ({ db, logger }, _input, wire) => {
119
- logger.info(`Running: ${wire.scheduledTask.name}`)
120
- logger.info(`Schedule: ${wire.scheduledTask.schedule}`)
121
- logger.info(`Execution time: ${wire.scheduledTask.executionTime}`)
122
-
123
- const staleCount = await db.countStaleTodos()
124
- if (staleCount === 0) {
125
- wire.scheduledTask.skip('No stale todos found') // throws — nothing below runs
126
- }
127
-
128
- await db.deleteCompletedTodos({ olderThan: '30d' })
129
- logger.info(`Cleaned ${staleCount} stale todos`)
130
- },
131
- })
132
-
133
- wireScheduler({
134
- name: 'weeklyCleanup',
135
- schedule: '0 0 * * 0',
136
- func: weeklyCleanup,
137
- })
138
- ```
139
-
140
- ### Scheduler Middleware
141
-
142
- ```typescript
143
- const schedulerMetrics = pikkuMiddleware(
144
- async ({ logger }, { scheduledTask }, next) => {
145
- const start = Date.now()
146
- logger.info(`Task started: ${scheduledTask.name}`)
147
-
148
- try {
149
- await next()
150
- logger.info(`Task completed: ${scheduledTask.name}`, {
151
- duration: Date.now() - start,
152
- })
153
- } catch (error) {
154
- logger.error(`Task failed: ${scheduledTask.name}`, {
155
- error: error.message,
156
- duration: Date.now() - start,
157
- })
158
- throw error
159
- }
160
- }
161
- )
162
-
163
- wireScheduler({
164
- name: 'dailySummary',
165
- schedule: '0 9 * * *',
166
- func: dailySummary,
167
- middleware: [schedulerMetrics],
168
- })
169
- ```
170
-
171
- ## Complete Example
172
-
173
- ```typescript
174
- // functions/scheduled.functions.ts
175
- export const dailySummary = pikkuVoidFunc({
176
- title: 'Daily Summary',
177
- func: async ({ db, emailService, logger }) => {
178
- const stats = await db.getDailyStats()
179
- await emailService.sendSummary(stats)
180
- logger.info('Daily summary sent', { stats })
181
- },
182
- })
183
-
184
- export const cleanupExpired = pikkuVoidFunc({
185
- title: 'Cleanup Expired',
186
- func: async ({ db, logger }, _input, wire) => {
187
- const count = await db.countExpiredSessions()
188
- if (count === 0) {
189
- wire.scheduledTask.skip('No expired sessions') // throws — nothing below runs
190
- }
191
- await db.deleteExpiredSessions()
192
- logger.info(`Cleaned ${count} expired sessions`)
193
- },
194
- })
195
-
196
- export const syncInventory = pikkuVoidFunc({
197
- title: 'Sync Inventory',
198
- func: async ({ inventoryApi, db, logger }) => {
199
- const updates = await inventoryApi.getChanges()
200
- await db.applyInventoryUpdates(updates)
201
- logger.info(`Synced ${updates.length} inventory changes`)
202
- },
203
- })
204
-
205
- // wirings/scheduler.wiring.ts
206
- wireScheduler({
207
- name: 'dailySummary',
208
- schedule: '0 9 * * *',
209
- func: dailySummary,
210
- })
211
- wireScheduler({
212
- name: 'cleanupExpired',
213
- schedule: '0 */6 * * *',
214
- func: cleanupExpired,
215
- })
216
- wireScheduler({
217
- name: 'syncInventory',
218
- schedule: '*/15 * * * *',
219
- func: syncInventory,
220
- })
221
- ```
@@ -1,14 +0,0 @@
1
- ---
2
- name: pikku-tag-middleware
3
- description: 'Deprecated — use pikku-middleware instead. Tag middleware (addTagMiddleware) is now documented as a section within the pikku-middleware skill, alongside global HTTP middleware, execution order, and the service-to-service bearer auth pattern.'
4
- ---
5
-
6
- # Deprecated: use `pikku-middleware`
7
-
8
- Tag middleware is covered in the **`pikku-middleware`** skill, which also covers:
9
-
10
- - `addHTTPMiddleware` (global / prefix-based)
11
- - `addTagMiddleware` (tag-scoped)
12
- - Middleware execution order and priority
13
- - Service-to-service bearer auth pattern
14
- - Session-setting middleware pattern