@taskcast/server 0.3.0 → 1.0.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/dist/index.d.ts CHANGED
@@ -1,21 +1,52 @@
1
1
  export { createAuthMiddleware, checkScope } from './auth.js';
2
2
  export type { AuthConfig, AuthContext, JWTConfig } from './auth.js';
3
3
  export { createTasksRouter } from './routes/tasks.js';
4
- export { createSSERouter } from './routes/sse.js';
5
- export { createWorkersRouter, WorkerWSHandler } from './routes/workers.js';
4
+ export { createSSERouter, createSubscriberCounts, getSubscriberCount } from './routes/sse.js';
5
+ export type { SubscriberCounts } from './routes/sse.js';
6
+ export { createWorkersRouter, WorkerWSHandler, WorkerWSRegistry } from './routes/workers.js';
6
7
  export type { WSLike, TaskSummary } from './routes/workers.js';
8
+ export { createAdminRouter } from './routes/admin.js';
9
+ export type { AdminRouteOptions } from './routes/admin.js';
7
10
  export { WebhookDelivery } from './webhook.js';
8
- import { Hono } from 'hono';
11
+ export { TaskSchema, TaskEventSchema, WorkerSchema, ErrorSchema, CreateTaskSchema, TransitionSchema, PublishEventSchema, } from './schemas.js';
12
+ import type { Hono } from 'hono';
13
+ import { WorkerWSRegistry } from './routes/worker-ws.js';
9
14
  import type { AuthConfig } from './auth.js';
10
- import type { TaskEngine, WorkerManager } from '@taskcast/core';
15
+ import type { TaskEngine, WorkerManager, ShortTermStore, DisconnectPolicy, TaskcastConfig } from '@taskcast/core';
11
16
  export interface TaskcastServerOptions {
12
17
  engine: TaskEngine;
13
18
  workerManager?: WorkerManager;
19
+ shortTermStore?: ShortTermStore;
14
20
  auth?: AuthConfig;
21
+ config?: TaskcastConfig;
22
+ cors?: boolean | {
23
+ origin: string | string[];
24
+ };
25
+ scheduler?: {
26
+ enabled?: boolean;
27
+ checkIntervalMs?: number;
28
+ pausedColdAfterMs?: number;
29
+ blockedColdAfterMs?: number;
30
+ };
31
+ heartbeat?: {
32
+ enabled?: boolean;
33
+ checkIntervalMs?: number;
34
+ heartbeatTimeoutMs?: number;
35
+ defaultDisconnectPolicy?: DisconnectPolicy;
36
+ disconnectGraceMs?: number;
37
+ };
38
+ }
39
+ export interface TaskcastApp {
40
+ app: Hono;
41
+ wsRegistry?: WorkerWSRegistry;
42
+ stop(): void;
15
43
  }
16
44
  /**
17
- * Creates a Hono app with all taskcast routes mounted.
45
+ * Creates an OpenAPIHono app with all taskcast routes mounted.
18
46
  * Can be used standalone or mounted into an existing Hono app.
47
+ *
48
+ * Returns a TaskcastApp with `app` (the Hono instance) and `stop()` to
49
+ * clean up scheduler/heartbeat timers.
19
50
  */
20
- export declare function createTaskcastApp(opts: TaskcastServerOptions): Hono;
51
+ export declare function createTaskcastApp(opts: TaskcastServerOptions): TaskcastApp;
21
52
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC5D,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAC1E,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAE9C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAK3B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE/D,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,UAAU,CAAA;IAClB,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,IAAI,CAAC,EAAE,UAAU,CAAA;CAClB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,IAAI,CAUnE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC5D,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAC7F,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACvD,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC5F,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EACL,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EACtD,gBAAgB,EAAE,gBAAgB,EAAE,kBAAkB,GACvD,MAAM,cAAc,CAAA;AAErB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAQhC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE3C,OAAO,KAAK,EAEV,UAAU,EACV,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,cAAc,EACf,MAAM,gBAAgB,CAAA;AAIvB,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,UAAU,CAAA;IAClB,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,MAAM,CAAC,EAAE,cAAc,CAAA;IACvB,IAAI,CAAC,EAAE,OAAO,GAAG;QAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;KAAE,CAAA;IAC9C,SAAS,CAAC,EAAE;QACV,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAA;KAC5B,CAAA;IACD,SAAS,CAAC,EAAE;QACV,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,kBAAkB,CAAC,EAAE,MAAM,CAAA;QAC3B,uBAAuB,CAAC,EAAE,gBAAgB,CAAA;QAC1C,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAC3B,CAAA;CACF;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,IAAI,CAAA;IACT,UAAU,CAAC,EAAE,gBAAgB,CAAA;IAC7B,IAAI,IAAI,IAAI,CAAA;CACb;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,WAAW,CA0I1E"}
package/dist/index.js CHANGED
@@ -1,26 +1,165 @@
1
1
  export { createAuthMiddleware, checkScope } from './auth.js';
2
2
  export { createTasksRouter } from './routes/tasks.js';
3
- export { createSSERouter } from './routes/sse.js';
4
- export { createWorkersRouter, WorkerWSHandler } from './routes/workers.js';
3
+ export { createSSERouter, createSubscriberCounts, getSubscriberCount } from './routes/sse.js';
4
+ export { createWorkersRouter, WorkerWSHandler, WorkerWSRegistry } from './routes/workers.js';
5
+ export { createAdminRouter } from './routes/admin.js';
5
6
  export { WebhookDelivery } from './webhook.js';
6
- import { Hono } from 'hono';
7
+ export { TaskSchema, TaskEventSchema, WorkerSchema, ErrorSchema, CreateTaskSchema, TransitionSchema, PublishEventSchema, } from './schemas.js';
8
+ import { OpenAPIHono } from '@hono/zod-openapi';
9
+ import { cors } from 'hono/cors';
10
+ import { apiReference } from '@scalar/hono-api-reference';
7
11
  import { createAuthMiddleware } from './auth.js';
8
12
  import { createTasksRouter } from './routes/tasks.js';
9
- import { createSSERouter } from './routes/sse.js';
13
+ import { createSSERouter, createSubscriberCounts } from './routes/sse.js';
10
14
  import { createWorkersRouter } from './routes/workers.js';
15
+ import { WorkerWSRegistry } from './routes/worker-ws.js';
16
+ import { createAdminRouter } from './routes/admin.js';
17
+ import { isTerminal, matchesWorkerRule } from '@taskcast/core';
18
+ import { TaskScheduler } from '@taskcast/core';
19
+ import { HeartbeatMonitor } from '@taskcast/core';
11
20
  /**
12
- * Creates a Hono app with all taskcast routes mounted.
21
+ * Creates an OpenAPIHono app with all taskcast routes mounted.
13
22
  * Can be used standalone or mounted into an existing Hono app.
23
+ *
24
+ * Returns a TaskcastApp with `app` (the Hono instance) and `stop()` to
25
+ * clean up scheduler/heartbeat timers.
14
26
  */
15
27
  export function createTaskcastApp(opts) {
16
- const app = new Hono();
28
+ const app = new OpenAPIHono();
29
+ // CORS middleware
30
+ if (opts.cors) {
31
+ const origin = opts.cors === true ? '*' : opts.cors.origin;
32
+ app.use('*', cors({ origin }));
33
+ }
17
34
  app.get('/health', (c) => c.json({ ok: true }));
35
+ // Admin route is mounted BEFORE auth middleware so it bypasses JWT/custom auth.
36
+ // It authenticates via admin token independently.
37
+ if (opts.config) {
38
+ app.route('/admin', createAdminRouter({ config: opts.config, auth: opts.auth }));
39
+ }
40
+ const subscriberCounts = createSubscriberCounts();
18
41
  app.use('*', createAuthMiddleware(opts.auth ?? { mode: 'none' }));
19
- app.route('/tasks', createTasksRouter(opts.engine));
20
- app.route('/tasks', createSSERouter(opts.engine));
42
+ app.route('/tasks', createTasksRouter(opts.engine, subscriberCounts));
43
+ app.route('/tasks', createSSERouter(opts.engine, subscriberCounts));
44
+ const cleanups = [];
45
+ // Wire scheduler
46
+ let scheduler;
47
+ if (opts.scheduler?.enabled !== false && opts.shortTermStore) {
48
+ const schedulerOpts = {
49
+ engine: opts.engine,
50
+ shortTermStore: opts.shortTermStore,
51
+ };
52
+ if (opts.scheduler?.checkIntervalMs !== undefined)
53
+ schedulerOpts.checkIntervalMs = opts.scheduler.checkIntervalMs;
54
+ if (opts.scheduler?.pausedColdAfterMs !== undefined)
55
+ schedulerOpts.pausedColdAfterMs = opts.scheduler.pausedColdAfterMs;
56
+ if (opts.scheduler?.blockedColdAfterMs !== undefined)
57
+ schedulerOpts.blockedColdAfterMs = opts.scheduler.blockedColdAfterMs;
58
+ scheduler = new TaskScheduler(schedulerOpts);
59
+ scheduler.start();
60
+ cleanups.push(() => scheduler.stop());
61
+ }
62
+ // Wire worker manager
63
+ let wsRegistry;
21
64
  if (opts.workerManager) {
65
+ const wm = opts.workerManager;
66
+ wsRegistry = new WorkerWSRegistry();
67
+ // Auto-release capacity on terminal transitions
68
+ opts.engine.addTransitionListener((_task, _from, to) => {
69
+ if (isTerminal(to)) {
70
+ wm.releaseTask(_task.id).catch(() => { });
71
+ }
72
+ });
73
+ // Wire ws-offer/ws-race dispatch on pending transitions
74
+ async function dispatchToWS(task) {
75
+ if (task.assignMode === 'ws-offer') {
76
+ const result = await wm.dispatchTask(task.id);
77
+ if (result.matched && result.workerId) {
78
+ const handler = wsRegistry.get(result.workerId);
79
+ if (handler)
80
+ handler.offerTask(task);
81
+ }
82
+ }
83
+ else if (task.assignMode === 'ws-race') {
84
+ const workers = await wm.listWorkers({ status: ['idle', 'busy'] });
85
+ for (const worker of workers) {
86
+ if (worker.connectionMode !== 'websocket')
87
+ continue;
88
+ if (!matchesWorkerRule(task, worker.matchRule))
89
+ continue;
90
+ const cost = task.cost ?? 1;
91
+ if (worker.usedSlots + cost > worker.capacity)
92
+ continue;
93
+ const handler = wsRegistry.get(worker.id);
94
+ if (handler)
95
+ handler.broadcastAvailable(task);
96
+ }
97
+ }
98
+ }
99
+ // Dispatch on initial task creation
100
+ opts.engine.addCreationListener((task) => {
101
+ if (!task.assignMode || (task.assignMode !== 'ws-offer' && task.assignMode !== 'ws-race'))
102
+ return;
103
+ dispatchToWS(task).catch(() => { });
104
+ });
105
+ // Re-dispatch when task transitions back to pending (e.g. after decline)
106
+ opts.engine.addTransitionListener((task, _from, to) => {
107
+ if (to !== 'pending')
108
+ return;
109
+ if (!task.assignMode || (task.assignMode !== 'ws-offer' && task.assignMode !== 'ws-race'))
110
+ return;
111
+ // Fire-and-forget async dispatch
112
+ dispatchToWS(task).catch(() => { });
113
+ });
22
114
  app.route('/workers', createWorkersRouter(opts.workerManager, opts.engine));
115
+ // Wire heartbeat monitor
116
+ if (opts.heartbeat?.enabled !== false && opts.shortTermStore) {
117
+ const monitorOpts = {
118
+ workerManager: wm,
119
+ engine: opts.engine,
120
+ shortTermStore: opts.shortTermStore,
121
+ };
122
+ if (opts.heartbeat?.checkIntervalMs !== undefined)
123
+ monitorOpts.checkIntervalMs = opts.heartbeat.checkIntervalMs;
124
+ if (opts.heartbeat?.heartbeatTimeoutMs !== undefined)
125
+ monitorOpts.heartbeatTimeoutMs = opts.heartbeat.heartbeatTimeoutMs;
126
+ if (opts.heartbeat?.defaultDisconnectPolicy !== undefined)
127
+ monitorOpts.defaultDisconnectPolicy = opts.heartbeat.defaultDisconnectPolicy;
128
+ if (opts.heartbeat?.disconnectGraceMs !== undefined)
129
+ monitorOpts.disconnectGraceMs = opts.heartbeat.disconnectGraceMs;
130
+ const monitor = new HeartbeatMonitor(monitorOpts);
131
+ monitor.start();
132
+ cleanups.push(() => monitor.stop());
133
+ }
23
134
  }
24
- return app;
135
+ // Register security scheme
136
+ app.openAPIRegistry.registerComponent('securitySchemes', 'Bearer', {
137
+ type: 'http',
138
+ scheme: 'bearer',
139
+ bearerFormat: 'JWT',
140
+ description: 'JWT Bearer token. Required scopes vary per endpoint.',
141
+ });
142
+ // OpenAPI spec endpoint
143
+ app.doc('/openapi.json', {
144
+ openapi: '3.1.0',
145
+ info: {
146
+ title: 'Taskcast API',
147
+ version: '0.3.0',
148
+ description: 'Unified long-lifecycle task tracking service for LLM streaming, agents, and async workloads.',
149
+ },
150
+ security: [{ Bearer: [] }],
151
+ });
152
+ // API documentation UI
153
+ app.get('/docs', apiReference({
154
+ url: '/openapi.json',
155
+ }));
156
+ return {
157
+ app: app,
158
+ ...(wsRegistry !== undefined && { wsRegistry }),
159
+ stop() {
160
+ for (const fn of cleanups)
161
+ fn();
162
+ },
163
+ };
25
164
  }
26
165
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAE9C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAUzD;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAA2B;IAC3D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;IACtB,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IAC/C,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,oBAAoB,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;IACjE,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;IACnD,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;IACjD,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,mBAAmB,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;IAC7E,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { Hono } from 'hono';
2
+ import type { TaskcastConfig } from '@taskcast/core';
3
+ import type { AuthConfig } from '../auth.js';
4
+ export interface AdminRouteOptions {
5
+ config: TaskcastConfig;
6
+ auth?: AuthConfig | undefined;
7
+ }
8
+ /**
9
+ * Creates the admin router with POST /token endpoint.
10
+ *
11
+ * This route is intentionally NOT behind the normal auth middleware.
12
+ * It authenticates via admin token and issues JWTs (when auth mode is jwt).
13
+ */
14
+ export declare function createAdminRouter(opts: AdminRouteOptions): Hono;
15
+ //# sourceMappingURL=admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/routes/admin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,gBAAgB,CAAA;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,cAAc,CAAA;IACtB,IAAI,CAAC,EAAE,UAAU,GAAG,SAAS,CAAA;CAC9B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CA2D/D"}
@@ -0,0 +1,59 @@
1
+ import { Hono } from 'hono';
2
+ import { SignJWT } from 'jose';
3
+ /**
4
+ * Creates the admin router with POST /token endpoint.
5
+ *
6
+ * This route is intentionally NOT behind the normal auth middleware.
7
+ * It authenticates via admin token and issues JWTs (when auth mode is jwt).
8
+ */
9
+ export function createAdminRouter(opts) {
10
+ const router = new Hono();
11
+ router.post('/token', async (c) => {
12
+ // 1. If adminApi is not enabled, this endpoint does not exist
13
+ if (!opts.config.adminApi) {
14
+ return c.json({ error: 'Not found' }, 404);
15
+ }
16
+ // 2. Parse and validate request body
17
+ let body;
18
+ try {
19
+ body = await c.req.json();
20
+ }
21
+ catch {
22
+ return c.json({ error: 'Invalid request body' }, 400);
23
+ }
24
+ const adminToken = body.adminToken;
25
+ if (typeof adminToken !== 'string' || adminToken === '') {
26
+ return c.json({ error: 'Invalid admin token' }, 401);
27
+ }
28
+ // 3. Validate admin token — ALWAYS, regardless of server auth mode
29
+ if (adminToken !== opts.config.adminToken) {
30
+ return c.json({ error: 'Invalid admin token' }, 401);
31
+ }
32
+ // 4. Parse optional fields
33
+ const scopes = Array.isArray(body.scopes) ? body.scopes : ['*'];
34
+ const expiresIn = typeof body.expiresIn === 'number' && body.expiresIn > 0
35
+ ? body.expiresIn
36
+ : 86400; // default: 24h
37
+ const expiresAt = Math.floor(Date.now() / 1000) + expiresIn;
38
+ // 5. If auth mode is JWT, sign a real token
39
+ if (opts.auth?.mode === 'jwt' && opts.auth.jwt?.secret) {
40
+ const secret = new TextEncoder().encode(opts.auth.jwt.secret);
41
+ const algorithm = opts.auth.jwt.algorithm ?? 'HS256';
42
+ const jwt = await new SignJWT({
43
+ sub: 'admin',
44
+ scope: scopes,
45
+ taskIds: '*',
46
+ })
47
+ .setProtectedHeader({ alg: algorithm })
48
+ .setExpirationTime(expiresAt)
49
+ .setIssuedAt()
50
+ .sign(secret);
51
+ return c.json({ token: jwt, expiresAt });
52
+ }
53
+ // 6. Non-JWT mode (e.g., "none"): still validated admin token above (double insurance!)
54
+ // Return placeholder since no JWT system is configured
55
+ return c.json({ token: '', expiresAt });
56
+ });
57
+ return router;
58
+ }
59
+ //# sourceMappingURL=admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/routes/admin.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,7 @@
1
- import { Hono } from 'hono';
1
+ import type { Hono } from 'hono';
2
2
  import type { TaskEngine } from '@taskcast/core';
3
- export declare function createSSERouter(engine: TaskEngine): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export type SubscriberCounts = Map<string, number>;
4
+ export declare function createSubscriberCounts(): SubscriberCounts;
5
+ export declare function getSubscriberCount(counts: SubscriberCounts, taskId: string): number;
6
+ export declare function createSSERouter(engine: TaskEngine, subscriberCounts: SubscriberCounts): Hono;
4
7
  //# sourceMappingURL=sse.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/routes/sse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAI3B,OAAO,KAAK,EAAE,UAAU,EAAkD,MAAM,gBAAgB,CAAA;AAkDhG,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,8EAyEjD"}
1
+ {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/routes/sse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAOhC,OAAO,KAAK,EAAE,UAAU,EAAkD,MAAM,gBAAgB,CAAA;AAIhG,MAAM,MAAM,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAElD,wBAAgB,sBAAsB,IAAI,gBAAgB,CAEzD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnF;AAmGD,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAyF5F"}
@@ -1,7 +1,53 @@
1
- import { Hono } from 'hono';
1
+ import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi';
2
2
  import { streamSSE } from 'hono/streaming';
3
3
  import { applyFilteredIndex, matchesFilter, TERMINAL_STATUSES } from '@taskcast/core';
4
4
  import { checkScope } from '../auth.js';
5
+ import { ErrorSchema } from '../schemas.js';
6
+ export function createSubscriberCounts() {
7
+ return new Map();
8
+ }
9
+ export function getSubscriberCount(counts, taskId) {
10
+ return counts.get(taskId) ?? 0;
11
+ }
12
+ function incrementSubscriberCount(counts, taskId) {
13
+ counts.set(taskId, (counts.get(taskId) ?? 0) + 1);
14
+ }
15
+ function decrementSubscriberCount(counts, taskId) {
16
+ const count = (counts.get(taskId) ?? 1) - 1;
17
+ if (count <= 0) {
18
+ counts.delete(taskId);
19
+ }
20
+ else {
21
+ counts.set(taskId, count);
22
+ }
23
+ }
24
+ // ─── Route Definition ──────────────────────────────────────────────────────
25
+ const sseRoute = createRoute({
26
+ method: 'get',
27
+ path: '/{taskId}/events',
28
+ tags: ['Events'],
29
+ summary: 'Subscribe to task events via SSE',
30
+ description: 'Server-Sent Events stream. Replays history then streams live. Closes on terminal status.',
31
+ security: [{ Bearer: [] }],
32
+ request: {
33
+ params: z.object({ taskId: z.string() }),
34
+ query: z.object({
35
+ types: z.string().optional().openapi({ description: 'Comma-separated type filter with wildcard support' }),
36
+ levels: z.string().optional().openapi({ description: 'Comma-separated level filter' }),
37
+ includeStatus: z.string().optional().openapi({ description: 'Include taskcast:status events (default: true)' }),
38
+ wrap: z.string().optional().openapi({ description: 'Wrap in SSEEnvelope (default: true)' }),
39
+ 'since.id': z.string().optional(),
40
+ 'since.index': z.string().optional(),
41
+ 'since.timestamp': z.string().optional(),
42
+ }),
43
+ },
44
+ responses: {
45
+ 200: { description: 'SSE event stream (text/event-stream)' },
46
+ 403: { description: 'Forbidden', content: { 'application/json': { schema: ErrorSchema } } },
47
+ 404: { description: 'Task not found', content: { 'application/json': { schema: ErrorSchema } } },
48
+ },
49
+ });
50
+ // ─── Helpers ───────────────────────────────────────────────────────────────
5
51
  function parseFilter(query) {
6
52
  const get = (k) => query[k];
7
53
  const filter = {};
@@ -47,13 +93,16 @@ function toEnvelope(event, filteredIndex) {
47
93
  env.seriesId = event.seriesId;
48
94
  if (event.seriesMode !== undefined)
49
95
  env.seriesMode = event.seriesMode;
96
+ if (event.seriesAccField !== undefined)
97
+ env.seriesAccField = event.seriesAccField;
50
98
  return env;
51
99
  }
52
100
  const TERMINAL = new Set(TERMINAL_STATUSES);
53
- export function createSSERouter(engine) {
54
- const router = new Hono();
55
- router.get('/:taskId/events', async (c) => {
56
- const { taskId } = c.req.param();
101
+ export function createSSERouter(engine, subscriberCounts) {
102
+ const router = new OpenAPIHono();
103
+ const register = router.openapi.bind(router);
104
+ register(sseRoute, async (c) => {
105
+ const taskId = c.req.param('taskId');
57
106
  const auth = c.get('auth');
58
107
  if (!checkScope(auth, 'event:subscribe', taskId))
59
108
  return c.json({ error: 'Forbidden' }, 403);
@@ -63,6 +112,14 @@ export function createSSERouter(engine) {
63
112
  const filter = parseFilter(c.req.query());
64
113
  const wrap = filter.wrap !== false; // default true
65
114
  return streamSSE(c, async (stream) => {
115
+ incrementSubscriberCount(subscriberCounts, taskId);
116
+ let decremented = false;
117
+ const cleanup = () => {
118
+ if (!decremented) {
119
+ decremented = true;
120
+ decrementSubscriberCount(subscriberCounts, taskId);
121
+ }
122
+ };
66
123
  const sendEvent = async (event, filteredIndex) => {
67
124
  const payload = wrap ? toEnvelope(event, filteredIndex) : event;
68
125
  await stream.writeSSE({
@@ -78,7 +135,14 @@ export function createSSERouter(engine) {
78
135
  });
79
136
  };
80
137
  // Replay history
81
- const history = await engine.getEvents(taskId);
138
+ let history;
139
+ try {
140
+ history = await engine.getEvents(taskId);
141
+ }
142
+ catch {
143
+ cleanup();
144
+ return;
145
+ }
82
146
  const filtered = applyFilteredIndex(history, filter);
83
147
  for (const { event, filteredIndex } of filtered) {
84
148
  await sendEvent(event, filteredIndex);
@@ -86,6 +150,7 @@ export function createSSERouter(engine) {
86
150
  // If task is already terminal, send done and close
87
151
  if (TERMINAL.has(task.status)) {
88
152
  await sendDone(task.status);
153
+ cleanup();
89
154
  return;
90
155
  }
91
156
  // Subscribe to live events
@@ -101,12 +166,14 @@ export function createSSERouter(engine) {
101
166
  const status = event.data.status;
102
167
  if (TERMINAL.has(status)) {
103
168
  await sendDone(status);
169
+ cleanup();
104
170
  unsub();
105
171
  resolve();
106
172
  }
107
173
  }
108
174
  });
109
175
  stream.onAbort(() => {
176
+ cleanup();
110
177
  unsub();
111
178
  resolve();
112
179
  });
@@ -1 +1 @@
1
- {"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/routes/sse.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/routes/sse.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,EAAE,MAAM,mBAAmB,CAAA;AAE/D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACrF,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAO3C,MAAM,UAAU,sBAAsB;IACpC,OAAO,IAAI,GAAG,EAAkB,CAAA;AAClC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAwB,EAAE,MAAc;IACzE,OAAO,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AAChC,CAAC;AAED,SAAS,wBAAwB,CAAC,MAAwB,EAAE,MAAc;IACxE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;AACnD,CAAC;AAED,SAAS,wBAAwB,CAAC,MAAwB,EAAE,MAAc;IACxE,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;IAC3C,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACf,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACvB,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAC3B,CAAC;AACH,CAAC;AAED,8EAA8E;AAE9E,MAAM,QAAQ,GAAG,WAAW,CAAC;IAC3B,MAAM,EAAE,KAAK;IACb,IAAI,EAAE,kBAAkB;IACxB,IAAI,EAAE,CAAC,QAAQ,CAAC;IAChB,OAAO,EAAE,kCAAkC;IAC3C,WAAW,EAAE,0FAA0F;IACvG,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC1B,OAAO,EAAE;QACP,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;QACxC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;YACd,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,mDAAmD,EAAE,CAAC;YAC1G,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,8BAA8B,EAAE,CAAC;YACtF,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,gDAAgD,EAAE,CAAC;YAC/G,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,qCAAqC,EAAE,CAAC;YAC3F,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YACjC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YACpC,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SACzC,CAAC;KACH;IACD,SAAS,EAAE;QACT,GAAG,EAAE,EAAE,WAAW,EAAE,sCAAsC,EAAE;QAC5D,GAAG,EAAE,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,kBAAkB,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE;QAC3F,GAAG,EAAE,EAAE,WAAW,EAAE,gBAAgB,EAAE,OAAO,EAAE,EAAE,kBAAkB,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE;KACjG;CACF,CAAC,CAAA;AAEF,8EAA8E;AAE9E,SAAS,WAAW,CAAC,KAAyC;IAC5D,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACnC,MAAM,MAAM,GAAoB,EAAE,CAAA;IAElC,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,CAAA;IAC1B,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAExE,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC5B,IAAI,MAAM,KAAK,SAAS;QAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAY,CAAA;IAEtF,MAAM,aAAa,GAAG,GAAG,CAAC,eAAe,CAAC,CAAA;IAC1C,IAAI,aAAa,KAAK,SAAS;QAAE,MAAM,CAAC,aAAa,GAAG,aAAa,KAAK,OAAO,CAAA;IAEjF,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAA;IACxB,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,CAAC,IAAI,GAAG,IAAI,KAAK,OAAO,CAAA;IAEtD,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,CAAC,CAAA;IAC/B,MAAM,UAAU,GAAG,GAAG,CAAC,aAAa,CAAC,CAAA;IACrC,MAAM,cAAc,GAAG,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAC7C,IAAI,OAAO,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QACtF,MAAM,KAAK,GAA6B,EAAE,CAAA;QAC1C,IAAI,OAAO,KAAK,SAAS;YAAE,KAAK,CAAC,EAAE,GAAG,OAAO,CAAA;QAC7C,IAAI,UAAU,KAAK,SAAS;YAAE,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,CAAA;QAC9D,IAAI,cAAc,KAAK,SAAS;YAAE,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,CAAA;QAC1E,MAAM,CAAC,KAAK,GAAG,KAAK,CAAA;IACtB,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,SAAS,UAAU,CAAC,KAAgB,EAAE,aAAqB;IACzD,MAAM,GAAG,GAAgB;QACvB,aAAa;QACb,QAAQ,EAAE,KAAK,CAAC,KAAK;QACrB,OAAO,EAAE,KAAK,CAAC,EAAE;QACjB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAE,KAAK,CAAC,IAAI;KACjB,CAAA;IACD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;QAAE,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAA;IAC/D,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;QAAE,GAAG,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAA;IACrE,IAAI,KAAK,CAAC,cAAc,KAAK,SAAS;QAAE,GAAG,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,CAAA;IACjF,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,QAAQ,GAAgB,IAAI,GAAG,CAAC,iBAAiB,CAAC,CAAA;AAOxD,MAAM,UAAU,eAAe,CAAC,MAAkB,EAAE,gBAAkC;IACpF,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAA;IAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAoB,CAAA;IAE/D,QAAQ,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAW,CAAA;QAC9C,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAC1B,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,CAAC;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC,CAAA;QAE5F,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QACzC,IAAI,CAAC,IAAI;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,GAAG,CAAC,CAAA;QAE1D,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAwC,CAAC,CAAA;QAC/E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,KAAK,KAAK,CAAA,CAAC,eAAe;QAElD,OAAO,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YACnC,wBAAwB,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAA;YAClD,IAAI,WAAW,GAAG,KAAK,CAAA;YACvB,MAAM,OAAO,GAAG,GAAG,EAAE;gBACnB,IAAI,CAAC,WAAW,EAAE,CAAC;oBAAC,WAAW,GAAG,IAAI,CAAC;oBAAC,wBAAwB,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAA;gBAAC,CAAC;YAC9F,CAAC,CAAA;YAED,MAAM,SAAS,GAAG,KAAK,EAAE,KAAgB,EAAE,aAAqB,EAAE,EAAE;gBAClE,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;gBAC/D,MAAM,MAAM,CAAC,QAAQ,CAAC;oBACpB,KAAK,EAAE,gBAAgB;oBACvB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;oBAC7B,EAAE,EAAE,KAAK,CAAC,EAAE;iBACb,CAAC,CAAA;YACJ,CAAC,CAAA;YAED,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;gBACxC,MAAM,MAAM,CAAC,QAAQ,CAAC;oBACpB,KAAK,EAAE,eAAe;oBACtB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;iBACjC,CAAC,CAAA;YACJ,CAAC,CAAA;YAED,iBAAiB;YACjB,IAAI,OAAoB,CAAA;YACxB,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,CAAA;gBACT,OAAM;YACR,CAAC;YACD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YACpD,KAAK,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,QAAQ,EAAE,CAAC;gBAChD,MAAM,SAAS,CAAC,KAAK,EAAE,aAAa,CAAC,CAAA;YACvC,CAAC;YAED,mDAAmD;YACnD,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC9B,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBAC3B,OAAO,EAAE,CAAA;gBACT,OAAM;YACR,CAAC;YAED,2BAA2B;YAC3B,IAAI,iBAAiB,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC;gBACzC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,aAAa,GAAG,CAAC,CAAC;gBACpD,CAAC,CAAC,CAAC,CAAA;YAEL,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBAClC,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;oBACrD,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC;wBAAE,OAAM;oBACzC,MAAM,SAAS,CAAC,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAA;oBAE3C,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;wBACrC,MAAM,MAAM,GAAI,KAAK,CAAC,IAA2B,CAAC,MAAM,CAAA;wBACxD,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;4BACzB,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAA;4BACtB,OAAO,EAAE,CAAA;4BACT,KAAK,EAAE,CAAA;4BACP,OAAO,EAAE,CAAA;wBACX,CAAC;oBACH,CAAC;gBACH,CAAC,CAAC,CAAA;gBAEF,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;oBAClB,OAAO,EAAE,CAAA;oBACT,KAAK,EAAE,CAAA;oBACP,OAAO,EAAE,CAAA;gBACX,CAAC,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,OAAO,MAAyB,CAAA;AAClC,CAAC"}
@@ -1,4 +1,5 @@
1
- import { Hono } from 'hono';
1
+ import type { Hono } from 'hono';
2
+ import type { SubscriberCounts } from './sse.js';
2
3
  import type { TaskEngine } from '@taskcast/core';
3
- export declare function createTasksRouter(engine: TaskEngine): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
4
+ export declare function createTasksRouter(engine: TaskEngine, subscriberCounts: SubscriberCounts): Hono;
4
5
  //# sourceMappingURL=tasks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/routes/tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAG3B,OAAO,KAAK,EAAE,UAAU,EAA8D,MAAM,gBAAgB,CAAA;AAwB5G,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,8EA6InD"}
1
+ {"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/routes/tasks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAKhC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAUhD,OAAO,KAAK,EAAE,UAAU,EAAsG,MAAM,gBAAgB,CAAA;AA+HpJ,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAsN9F"}