delaykit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +264 -0
- package/dist/delaykit.d.ts +77 -0
- package/dist/delaykit.d.ts.map +1 -0
- package/dist/delaykit.js +525 -0
- package/dist/delaykit.js.map +1 -0
- package/dist/duration.d.ts +7 -0
- package/dist/duration.d.ts.map +1 -0
- package/dist/duration.js +38 -0
- package/dist/duration.js.map +1 -0
- package/dist/emitter.d.ts +9 -0
- package/dist/emitter.d.ts.map +1 -0
- package/dist/emitter.js +41 -0
- package/dist/emitter.js.map +1 -0
- package/dist/executor.d.ts +41 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +98 -0
- package/dist/executor.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/result-handler.d.ts +23 -0
- package/dist/result-handler.d.ts.map +1 -0
- package/dist/result-handler.js +155 -0
- package/dist/result-handler.js.map +1 -0
- package/dist/schedulers/polling.d.ts +46 -0
- package/dist/schedulers/polling.d.ts.map +1 -0
- package/dist/schedulers/polling.js +148 -0
- package/dist/schedulers/polling.js.map +1 -0
- package/dist/schedulers/posthook.d.ts +29 -0
- package/dist/schedulers/posthook.d.ts.map +1 -0
- package/dist/schedulers/posthook.js +49 -0
- package/dist/schedulers/posthook.js.map +1 -0
- package/dist/stores/memory.d.ts +28 -0
- package/dist/stores/memory.d.ts.map +1 -0
- package/dist/stores/memory.js +282 -0
- package/dist/stores/memory.js.map +1 -0
- package/dist/stores/postgres-migrations.d.ts +6 -0
- package/dist/stores/postgres-migrations.d.ts.map +1 -0
- package/dist/stores/postgres-migrations.js +65 -0
- package/dist/stores/postgres-migrations.js.map +1 -0
- package/dist/stores/postgres.d.ts +32 -0
- package/dist/stores/postgres.d.ts.map +1 -0
- package/dist/stores/postgres.js +382 -0
- package/dist/stores/postgres.js.map +1 -0
- package/dist/types.d.ts +192 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/package.json +80 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Posthook, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# DelayKit
|
|
2
|
+
|
|
3
|
+
Run code later in Next.js. Reminders, expirations, follow-ups — backed by Postgres.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install delaykit
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Try it locally with MemoryStore — no database needed:
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { DelayKit } from "delaykit";
|
|
15
|
+
import { MemoryStore } from "delaykit/memory";
|
|
16
|
+
import { PollingScheduler } from "delaykit/polling";
|
|
17
|
+
|
|
18
|
+
const dk = new DelayKit({
|
|
19
|
+
store: new MemoryStore(), // swap to PostgresStore for production
|
|
20
|
+
scheduler: new PollingScheduler(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
dk.handle("send-reminder", async ({ key }) => {
|
|
24
|
+
const user = await db.users.find(key);
|
|
25
|
+
if (user.onboarded) return; // already acted, skip
|
|
26
|
+
await sendEmail(user.email, "Complete your profile");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
await dk.start(); // for serverless (Vercel), use poll() instead — see Deploy to Vercel
|
|
30
|
+
|
|
31
|
+
// Send a reminder if the user hasn't onboarded after 24 hours
|
|
32
|
+
await dk.schedule("send-reminder", {
|
|
33
|
+
key: "user_123",
|
|
34
|
+
delay: "24h",
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// User completed onboarding — cancel the reminder
|
|
38
|
+
await dk.unschedule("send-reminder", "user_123");
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
MemoryStore is for local development. For jobs that survive restarts, use PostgresStore — see [Deploy to Vercel](#deploy-to-vercel).
|
|
42
|
+
|
|
43
|
+
## What you can build with it
|
|
44
|
+
|
|
45
|
+
### Expire a trial or reservation
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
await dk.schedule("expire-trial", { key: "acct_456", delay: "14d" });
|
|
49
|
+
|
|
50
|
+
// Or use an absolute time
|
|
51
|
+
await dk.schedule("expire-trial", { key: "acct_456", at: trialEndsAt });
|
|
52
|
+
|
|
53
|
+
// User upgraded — cancel the expiration
|
|
54
|
+
await dk.unschedule("expire-trial", "acct_456");
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Reindex after a burst of edits
|
|
58
|
+
|
|
59
|
+
User updates several fields — reindex once after they stop, not on every change.
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
await dk.debounce("reindex", { key: "project_789", wait: "5s" });
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Send a follow-up after inactivity
|
|
66
|
+
|
|
67
|
+
If the user comes back, the timer resets.
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
await dk.schedule("follow-up", {
|
|
71
|
+
key: "user_123",
|
|
72
|
+
delay: "3d",
|
|
73
|
+
onDuplicate: "replace", // resets the timer on each visit
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Safe to call from repeated requests
|
|
78
|
+
|
|
79
|
+
Same handler + same key won't create duplicate jobs. Call schedule from every request — only one pending job exists at a time.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
await dk.schedule("welcome-email", { key: "user_123", delay: "10m" });
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## What DelayKit handles for you
|
|
86
|
+
|
|
87
|
+
- **Jobs survive restarts and deploys** — they're in Postgres, not memory
|
|
88
|
+
- **No duplicate jobs** — same handler + key won't create a second pending job
|
|
89
|
+
- **Fresh state at execution time** — handlers receive the key and fetch current data, no stale payloads
|
|
90
|
+
- **Automatic retries** — failed handlers retry with configurable backoff
|
|
91
|
+
- **Stalled job recovery** — crashed processes don't leave stuck jobs
|
|
92
|
+
- **Handlers should be idempotent** — DelayKit prevents duplicate scheduling, but handlers may re-execute after a crash recovery
|
|
93
|
+
|
|
94
|
+
## Deploy to Vercel
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npm install delaykit postgres
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 1. Set up DelayKit
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
// lib/delaykit.ts
|
|
104
|
+
import { DelayKit } from "delaykit";
|
|
105
|
+
import { PostgresStore } from "delaykit/postgres";
|
|
106
|
+
import { PollingScheduler } from "delaykit/polling";
|
|
107
|
+
|
|
108
|
+
export async function dk() {
|
|
109
|
+
const store = await PostgresStore.connect(process.env.DATABASE_URL!);
|
|
110
|
+
const dk = new DelayKit({ store, scheduler: new PollingScheduler() });
|
|
111
|
+
|
|
112
|
+
dk.handle("send-reminder", async ({ key }) => {
|
|
113
|
+
// your handler logic
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return dk;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 2. Add a poll route
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
// app/api/delaykit/poll/route.ts
|
|
124
|
+
import { dk } from "@/lib/delaykit";
|
|
125
|
+
|
|
126
|
+
export async function GET(req: Request) {
|
|
127
|
+
// Verify the request is from Vercel Cron or an authorized caller
|
|
128
|
+
const auth = req.headers.get("authorization");
|
|
129
|
+
if (auth !== `Bearer ${process.env.CRON_SECRET}`) {
|
|
130
|
+
return new Response("Unauthorized", { status: 401 });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const d = await dk();
|
|
134
|
+
await d.poll({
|
|
135
|
+
batchSize: 10, // jobs per batch, run concurrently (default: 10)
|
|
136
|
+
timeout: "8s", // hard deadline — leave headroom under Vercel's 10s function limit
|
|
137
|
+
});
|
|
138
|
+
return Response.json({ ok: true });
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Set `CRON_SECRET` in your Vercel environment variables. Vercel automatically sends it with cron requests. For external cron services, include it as `Authorization: Bearer <secret>`.
|
|
143
|
+
|
|
144
|
+
`poll()` processes due jobs in batches of `batchSize`, running each batch concurrently. It keeps processing batches until there are no more due jobs or `timeout` is reached. If a handler is still running when the deadline hits, it stays in `running` state and is automatically recovered on the next poll cycle.
|
|
145
|
+
|
|
146
|
+
### 3. Schedule the cron
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
// vercel.json (Pro plan — runs every minute)
|
|
150
|
+
{ "crons": [{ "path": "/api/delaykit/poll", "schedule": "* * * * *" }] }
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Auto-migrates on first connect. Works with Neon, Supabase, Railway — any Postgres.
|
|
154
|
+
|
|
155
|
+
### Calling your poll route
|
|
156
|
+
|
|
157
|
+
`poll()` needs something to call it on a schedule. Vercel Hobby only allows daily cron — use an external service for more frequent polling:
|
|
158
|
+
|
|
159
|
+
- **Vercel Cron (Pro)** — every minute, built-in
|
|
160
|
+
- **[cron-job.org](https://cron-job.org)** — free, calls any URL on a schedule
|
|
161
|
+
- **[Posthook Sequences](https://posthook.io)** — hourly on the free tier
|
|
162
|
+
- **Any server with cron** — `curl https://your-app.vercel.app/api/delaykit/poll`
|
|
163
|
+
|
|
164
|
+
## How it works
|
|
165
|
+
|
|
166
|
+
Jobs live in Postgres. A cron route calls `dk.poll()` on a schedule to find due jobs and run your handlers. If the process crashes mid-execution, the job is still in Postgres — it recovers on the next poll cycle.
|
|
167
|
+
|
|
168
|
+
DelayKit stores keys, not payloads. Handlers receive the key (`user_123`) and fetch current state when they run. This means handlers always act on fresh data, not stale snapshots from scheduling time. If you need an immutable snapshot (e.g., the price at the time of an order), store that in your app's tables and schedule the job with a reference to it.
|
|
169
|
+
|
|
170
|
+
## Not cron, not a queue, not a workflow engine
|
|
171
|
+
|
|
172
|
+
- **Cron** is for recurring tasks on a fixed schedule. DelayKit is for one-time actions tied to a specific user or entity.
|
|
173
|
+
- **Queues** (BullMQ, QStash) process background jobs as soon as possible. DelayKit schedules actions for a specific time in the future.
|
|
174
|
+
- **Workflow engines** (Inngest, Temporal) orchestrate multi-step pipelines. DelayKit does one thing: run your handler at the right time.
|
|
175
|
+
|
|
176
|
+
## Lifecycle events
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
dk.on("job:completed", ({ job, durationMs }) => {
|
|
180
|
+
console.log(`${job.key} completed in ${durationMs}ms`);
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
| Event | Fires when |
|
|
185
|
+
|-------|-----------|
|
|
186
|
+
| `job:scheduled` | Job created (schedule, debounce, throttle) |
|
|
187
|
+
| `job:started` | Handler begins executing |
|
|
188
|
+
| `job:completed` | Handler succeeded |
|
|
189
|
+
| `job:failed` | Retries exhausted |
|
|
190
|
+
| `job:retrying` | Handler failed, will retry |
|
|
191
|
+
| `job:cancelled` | Job cancelled |
|
|
192
|
+
| `job:stalled` | Stalled job detected and recovered |
|
|
193
|
+
|
|
194
|
+
Listeners run inline during job execution — keep them fast (logging, metrics). Listener errors are caught and won't break your handlers.
|
|
195
|
+
|
|
196
|
+
## External schedulers
|
|
197
|
+
|
|
198
|
+
DelayKit's `Scheduler` interface is pluggable. Instead of polling, an external scheduler can call your app directly when each job is due. [Posthook](https://posthook.io) is the first supported external scheduler:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
npm install @posthook/node
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { PosthookScheduler } from "delaykit/posthook";
|
|
206
|
+
|
|
207
|
+
const dk = new DelayKit({
|
|
208
|
+
store,
|
|
209
|
+
scheduler: new PosthookScheduler({
|
|
210
|
+
apiKey: process.env.POSTHOOK_API_KEY!,
|
|
211
|
+
signingKey: process.env.POSTHOOK_SIGNING_KEY!,
|
|
212
|
+
basePath: "/api/delaykit",
|
|
213
|
+
}),
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Mount a catch-all route to receive deliveries:
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
// app/api/delaykit/[handler]/route.ts
|
|
221
|
+
import { dk } from "@/lib/delaykit";
|
|
222
|
+
|
|
223
|
+
export async function POST(req: Request) {
|
|
224
|
+
const d = await dk();
|
|
225
|
+
const handler = d.createHandler();
|
|
226
|
+
return handler(req);
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
With an external scheduler, you don't need a cron route or poll cycle.
|
|
231
|
+
|
|
232
|
+
## API reference
|
|
233
|
+
|
|
234
|
+
| Method | Description |
|
|
235
|
+
|--------|-------------|
|
|
236
|
+
| `dk.handle(name, handler)` | Register a handler (before start/poll/createHandler) |
|
|
237
|
+
| `dk.schedule(handler, opts)` | Schedule a one-time job |
|
|
238
|
+
| `dk.debounce(handler, opts)` | Debounce rapid events into one handler call |
|
|
239
|
+
| `dk.throttle(handler, opts)` | Throttle to one handler call per time window |
|
|
240
|
+
| `dk.cancel(id)` | Cancel a pending job by ID |
|
|
241
|
+
| `dk.unschedule(handler, key)` | Cancel by handler and key |
|
|
242
|
+
| `dk.getJob(id)` | Look up a job by ID |
|
|
243
|
+
| `dk.getJobByKey(handler, key)` | Look up the active job for a handler + key |
|
|
244
|
+
| `dk.poll(opts?)` | Run one poll cycle (for cron routes) |
|
|
245
|
+
| `dk.createHandler()` | Create a webhook route handler (for external schedulers) |
|
|
246
|
+
| `dk.on(event, listener)` | Subscribe to lifecycle events |
|
|
247
|
+
|
|
248
|
+
### Duration format
|
|
249
|
+
|
|
250
|
+
Delays and timeouts use human-readable strings: `"5s"`, `"30m"`, `"24h"`, `"14d"`, `"500ms"`. Compound durations work too: `"1h30m"`.
|
|
251
|
+
|
|
252
|
+
| Unit | Example |
|
|
253
|
+
|------|---------|
|
|
254
|
+
| `ms` | `"500ms"` |
|
|
255
|
+
| `s` | `"30s"` |
|
|
256
|
+
| `m` | `"5m"` |
|
|
257
|
+
| `h` | `"24h"` |
|
|
258
|
+
| `d` | `"14d"` |
|
|
259
|
+
|
|
260
|
+
## License
|
|
261
|
+
|
|
262
|
+
MIT
|
|
263
|
+
|
|
264
|
+
Built by the team behind [Posthook](https://posthook.io).
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { HandlerEntry } from "./executor.js";
|
|
2
|
+
import type { DebounceOptions, ThrottleOptions, HandlerFn, HandlerConfig, Job, Scheduler, ScheduleOptions, Store, JobEventType, JobEventListener } from "./types.js";
|
|
3
|
+
export interface DelayKitOptions {
|
|
4
|
+
store: Store;
|
|
5
|
+
scheduler: Scheduler;
|
|
6
|
+
}
|
|
7
|
+
export declare class DelayKit {
|
|
8
|
+
private store;
|
|
9
|
+
private scheduler;
|
|
10
|
+
private handlerConfigs;
|
|
11
|
+
private retryConfigCache;
|
|
12
|
+
private started;
|
|
13
|
+
private emitter;
|
|
14
|
+
constructor(options: DelayKitOptions);
|
|
15
|
+
on<E extends JobEventType>(event: E, listener: JobEventListener<E>): () => void;
|
|
16
|
+
handle(name: string, handlerOrConfig: HandlerFn | HandlerConfig): void;
|
|
17
|
+
schedule(handler: string, options: ScheduleOptions): Promise<{
|
|
18
|
+
job: Job;
|
|
19
|
+
created: boolean;
|
|
20
|
+
}>;
|
|
21
|
+
debounce(handler: string, options: DebounceOptions): Promise<void>;
|
|
22
|
+
throttle(handler: string, options: ThrottleOptions): Promise<void>;
|
|
23
|
+
cancel(id: string): Promise<boolean>;
|
|
24
|
+
getJob(id: string): Promise<Job | null>;
|
|
25
|
+
getJobByKey(handler: string, key: string): Promise<Job | null>;
|
|
26
|
+
unschedule(handler: string, key: string): Promise<boolean>;
|
|
27
|
+
start(): Promise<void>;
|
|
28
|
+
stop(): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Run one poll cycle: find due jobs and execute them concurrently.
|
|
31
|
+
* Use this from a Vercel cron route instead of start():
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* // app/api/delaykit/poll/route.ts
|
|
35
|
+
* export async function GET() {
|
|
36
|
+
* await dk().poll({ batchSize: 10, timeout: "8s" });
|
|
37
|
+
* return Response.json({ ok: true });
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* ```json
|
|
42
|
+
* // vercel.json
|
|
43
|
+
* { "crons": [{ "path": "/api/delaykit/poll", "schedule": "* * * * *" }] }
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @param options.batchSize - Jobs per batch, run concurrently. Keeps
|
|
47
|
+
* processing batches until no more due jobs or timeout. Default: 10.
|
|
48
|
+
* @param options.timeout - Hard deadline for the poll cycle. If the timeout
|
|
49
|
+
* elapses, poll() returns. Jobs still running are left in 'running' state
|
|
50
|
+
* and recovered by stalled job recovery on the next cycle.
|
|
51
|
+
* Example: "8s" on Vercel Hobby (10s function limit).
|
|
52
|
+
*/
|
|
53
|
+
poll(options?: {
|
|
54
|
+
batchSize?: number;
|
|
55
|
+
timeout?: string;
|
|
56
|
+
}): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Creates a webhook route handler for PosthookScheduler delivery.
|
|
59
|
+
* Mount this as a POST handler in your Next.js app:
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* // app/api/delaykit/route.ts
|
|
63
|
+
* export const runtime = 'nodejs';
|
|
64
|
+
* export const POST = dk().createHandler();
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
createHandler(): (req: Request) => Promise<Response>;
|
|
68
|
+
private emitScheduled;
|
|
69
|
+
private materializeWakeup;
|
|
70
|
+
buildHandlers(): Map<string, HandlerEntry>;
|
|
71
|
+
private buildPollingHandlers;
|
|
72
|
+
private getMaxAttempts;
|
|
73
|
+
private getRetryConfig;
|
|
74
|
+
private validateHandler;
|
|
75
|
+
private validateScheduleOptions;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=delaykit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delaykit.d.ts","sourceRoot":"","sources":["../src/delaykit.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,SAAS,EACT,aAAa,EACb,GAAG,EACH,SAAS,EACT,eAAe,EACf,KAAK,EACL,YAAY,EACZ,gBAAgB,EAEjB,MAAM,YAAY,CAAC;AASpB,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,qBAAa,QAAQ;IACnB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,cAAc,CAAgD;IACtE,OAAO,CAAC,gBAAgB,CAA2C;IACnE,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAyB;gBAE5B,OAAO,EAAE,eAAe;IAKpC,EAAE,CAAC,CAAC,SAAS,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAI/E,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,GAAG,aAAa,GAAG,IAAI;IA6BhE,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,GAAG,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAkG5F,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAuDlE,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDlE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA2BpC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAIvC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAI9D,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAatB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkE7E;;;;;;;;;OASG;IACH,aAAa,IAAI,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC;IAoGpD,OAAO,CAAC,aAAa;YAQP,iBAAiB;IAS/B,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC;IAe1C,OAAO,CAAC,oBAAoB;IAkC5B,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,uBAAuB;CAahC"}
|