@critical-path/server 0.15.0 → 0.17.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.
@@ -0,0 +1,139 @@
1
+ import { zodToJsonSchema } from 'zod-to-json-schema';
2
+ import * as schemas from '@critical-path/core/schemas';
3
+ /** Every route served by `CriticalPathRouter`. Kept in sync by the route drift test. */
4
+ export const ROUTES = [
5
+ { method: 'get', path: '/workflows', summary: 'List workflows', tag: 'Workflows', responseKey: 'workflows' },
6
+ { method: 'post', path: '/workflows', summary: 'Create a workflow', tag: 'Workflows', body: schemas.CreateWorkflowSchema, responseKey: 'workflow', status: 201 },
7
+ { method: 'get', path: '/workflows/{workflowId}', summary: 'Get a workflow', tag: 'Workflows', responseKey: 'workflow' },
8
+ { method: 'patch', path: '/workflows/{workflowId}', summary: 'Update a workflow', tag: 'Workflows', body: schemas.UpdateWorkflowSchema, responseKey: 'workflow' },
9
+ { method: 'delete', path: '/workflows/{workflowId}', summary: 'Delete a workflow', tag: 'Workflows' },
10
+ { method: 'get', path: '/projects', summary: 'List projects', tag: 'Projects', responseKey: 'projects' },
11
+ { method: 'post', path: '/projects', summary: 'Create a project', tag: 'Projects', body: schemas.CreateProjectSchema, responseKey: 'project', status: 201 },
12
+ { method: 'get', path: '/projects/{projectId}', summary: 'Get a project', tag: 'Projects', responseKey: 'project' },
13
+ { method: 'patch', path: '/projects/{projectId}', summary: 'Update a project', tag: 'Projects', body: schemas.UpdateProjectSchema, responseKey: 'project' },
14
+ { method: 'delete', path: '/projects/{projectId}', summary: 'Delete a project and its tasks', tag: 'Projects' },
15
+ { method: 'get', path: '/projects/{projectId}/critical-path', summary: 'Critical path (CPM) analysis', tag: 'Analysis', responseKey: 'analysis' },
16
+ { method: 'get', path: '/projects/{projectId}/ladder', summary: 'Timeline ladder of abstraction', tag: 'Analysis', query: ['level', 'containerId', 'iterationId'], responseKey: 'ladder' },
17
+ { method: 'get', path: '/projects/{projectId}/workload', summary: 'Project workload distribution', tag: 'Analysis', query: ['startDate', 'endDate', 'interval', 'groupBy', 'metric', 'defaultWeeklyCapacityHours'], responseKey: 'workload' },
18
+ { method: 'get', path: '/tasks', summary: 'List tasks', tag: 'Tasks', query: ['projectId'], responseKey: 'tasks' },
19
+ { method: 'post', path: '/tasks', summary: 'Create a task', tag: 'Tasks', body: schemas.CreateTaskSchema, responseKey: 'task', status: 201 },
20
+ { method: 'get', path: '/tasks/{taskId}', summary: 'Get a task', tag: 'Tasks', responseKey: 'task' },
21
+ { method: 'patch', path: '/tasks/{taskId}', summary: 'Update a task (enforces workflow transitions)', tag: 'Tasks', body: schemas.UpdateTaskSchema, responseKey: 'task' },
22
+ { method: 'delete', path: '/tasks/{taskId}', summary: 'Delete a task', tag: 'Tasks' },
23
+ { method: 'get', path: '/tasks/{taskId}/comments', summary: 'List task comments', tag: 'Comments', responseKey: 'comments' },
24
+ { method: 'post', path: '/tasks/{taskId}/comments', summary: 'Comment on a task', tag: 'Comments', body: schemas.CreateCommentSchema.omit({ taskId: true }), responseKey: 'comment', status: 201 },
25
+ { method: 'get', path: '/tasks/{taskId}/attachments', summary: 'List task attachments', tag: 'Attachments', responseKey: 'attachments' },
26
+ { method: 'post', path: '/tasks/{taskId}/attachments', summary: 'Attach a file link to a task', tag: 'Attachments', body: schemas.CreateAttachmentSchema.omit({ taskId: true }), responseKey: 'attachment', status: 201 },
27
+ { method: 'get', path: '/tasks/{taskId}/dependencies', summary: 'Task dependency graph', tag: 'Dependencies', responseKey: 'graph' },
28
+ { method: 'post', path: '/tasks/{taskId}/dependencies', summary: 'Add a dependency (409 on cycles)', tag: 'Dependencies', body: schemas.CreateDependencySchema, responseKey: 'dependency', status: 201 },
29
+ { method: 'get', path: '/tasks/{taskId}/lifecycle', summary: 'Derived lifecycle state', tag: 'Tasks', responseKey: 'state' },
30
+ { method: 'get', path: '/tasks/{taskId}/transitions', summary: 'Allowed status transitions', tag: 'Tasks' },
31
+ { method: 'get', path: '/tasks/{taskId}/ladder', summary: 'Single-task ladder view', tag: 'Analysis', responseKey: 'taskLadder' },
32
+ { method: 'get', path: '/tasks/{taskId}/metrics', summary: 'Task metrics and EVM', tag: 'Analysis', responseKey: 'metrics' },
33
+ { method: 'get', path: '/tasks/{taskId}/progress-history', summary: 'Reconstructed progress history', tag: 'Analysis', responseKey: 'progressHistory' },
34
+ { method: 'get', path: '/teams', summary: 'List teams', tag: 'Teams', responseKey: 'teams' },
35
+ { method: 'post', path: '/teams', summary: 'Create a team', tag: 'Teams', body: schemas.CreateTeamSchema, responseKey: 'team', status: 201 },
36
+ { method: 'get', path: '/teams/{teamId}', summary: 'Get a team', tag: 'Teams', responseKey: 'team' },
37
+ { method: 'patch', path: '/teams/{teamId}', summary: 'Update a team', tag: 'Teams', body: schemas.UpdateTeamSchema, responseKey: 'team' },
38
+ { method: 'delete', path: '/teams/{teamId}', summary: 'Delete a team', tag: 'Teams' },
39
+ { method: 'get', path: '/containers', summary: 'List containers', tag: 'Containers', query: ['projectId!'], responseKey: 'containers' },
40
+ { method: 'post', path: '/containers', summary: 'Create a container', tag: 'Containers', body: schemas.CreateContainerSchema, responseKey: 'container', status: 201 },
41
+ { method: 'get', path: '/containers/{containerId}', summary: 'Get a container', tag: 'Containers', responseKey: 'container' },
42
+ { method: 'patch', path: '/containers/{containerId}', summary: 'Update a container', tag: 'Containers', body: schemas.UpdateContainerSchema, responseKey: 'container' },
43
+ { method: 'delete', path: '/containers/{containerId}', summary: 'Delete a container', tag: 'Containers' },
44
+ { method: 'get', path: '/deliverables', summary: 'List deliverables', tag: 'Deliverables', query: ['projectId!'], responseKey: 'deliverables' },
45
+ { method: 'post', path: '/deliverables', summary: 'Create a deliverable', tag: 'Deliverables', body: schemas.CreateDeliverableSchema, responseKey: 'deliverable', status: 201 },
46
+ { method: 'get', path: '/deliverables/{deliverableId}', summary: 'Get a deliverable', tag: 'Deliverables', responseKey: 'deliverable' },
47
+ { method: 'get', path: '/deliverables/{deliverableId}/summary', summary: 'Deliverable rollup summary', tag: 'Deliverables', responseKey: 'summary' },
48
+ { method: 'patch', path: '/deliverables/{deliverableId}', summary: 'Update a deliverable', tag: 'Deliverables', body: schemas.UpdateDeliverableSchema, responseKey: 'deliverable' },
49
+ { method: 'delete', path: '/deliverables/{deliverableId}', summary: 'Delete a deliverable', tag: 'Deliverables' },
50
+ { method: 'get', path: '/iterations', summary: 'List iterations', tag: 'Iterations', query: ['projectId!'], responseKey: 'iterations' },
51
+ { method: 'post', path: '/iterations', summary: 'Create an iteration', tag: 'Iterations', body: schemas.CreateIterationSchema, responseKey: 'iteration', status: 201 },
52
+ { method: 'get', path: '/iterations/{iterationId}', summary: 'Get an iteration', tag: 'Iterations', responseKey: 'iteration' },
53
+ { method: 'patch', path: '/iterations/{iterationId}', summary: 'Update an iteration', tag: 'Iterations', body: schemas.UpdateIterationSchema, responseKey: 'iteration' },
54
+ { method: 'delete', path: '/iterations/{iterationId}', summary: 'Delete an iteration', tag: 'Iterations' },
55
+ { method: 'get', path: '/activities', summary: 'Activity (audit) stream', tag: 'Activity', query: ['projectId', 'taskId'], responseKey: 'activities' },
56
+ { method: 'get', path: '/comments', summary: 'List comments for a task', tag: 'Comments', query: ['taskId!'], responseKey: 'comments' },
57
+ { method: 'post', path: '/comments', summary: 'Create a comment', tag: 'Comments', body: schemas.CreateCommentSchema, responseKey: 'comment', status: 201 },
58
+ { method: 'get', path: '/comments/{commentId}', summary: 'Get a comment', tag: 'Comments', responseKey: 'comment' },
59
+ { method: 'patch', path: '/comments/{commentId}', summary: 'Update a comment', tag: 'Comments', body: schemas.UpdateCommentSchema, responseKey: 'comment' },
60
+ { method: 'delete', path: '/comments/{commentId}', summary: 'Delete a comment', tag: 'Comments' },
61
+ { method: 'post', path: '/comments/{commentId}/reactions', summary: 'Add a reaction', tag: 'Comments', body: schemas.CommentReactionSchema, responseKey: 'comment' },
62
+ { method: 'delete', path: '/comments/{commentId}/reactions', summary: 'Remove a reaction', tag: 'Comments', query: ['emoji!'], responseKey: 'comment' },
63
+ { method: 'get', path: '/attachments', summary: 'List attachments', tag: 'Attachments', query: ['taskId', 'projectId', 'commentId'], responseKey: 'attachments' },
64
+ { method: 'post', path: '/attachments', summary: 'Register an attachment', tag: 'Attachments', body: schemas.CreateAttachmentSchema, responseKey: 'attachment', status: 201 },
65
+ { method: 'post', path: '/attachments/upload', summary: 'Upload a file through the configured FileStorageAdapter', tag: 'Attachments', body: schemas.UploadAttachmentSchema, responseKey: 'attachment', status: 201 },
66
+ { method: 'post', path: '/attachments/presign', summary: 'Request a presigned upload URL', tag: 'Attachments', body: schemas.PresignAttachmentSchema, responseKey: 'presigned' },
67
+ { method: 'get', path: '/attachments/{attachmentId}', summary: 'Get an attachment', tag: 'Attachments', responseKey: 'attachment' },
68
+ { method: 'delete', path: '/attachments/{attachmentId}', summary: 'Delete an attachment', tag: 'Attachments' },
69
+ { method: 'get', path: '/time-entries', summary: 'List time entries for a task', tag: 'Time Tracking', query: ['taskId!'], responseKey: 'timeEntries' },
70
+ { method: 'post', path: '/time-entries', summary: 'Log time against a task', tag: 'Time Tracking', body: schemas.LogTimeSchema, responseKey: 'timeEntry', status: 201 },
71
+ { method: 'get', path: '/workload', summary: 'Workload distribution across projects', tag: 'Analysis', query: ['projectId', 'startDate', 'endDate', 'interval', 'groupBy', 'metric', 'defaultWeeklyCapacityHours'], responseKey: 'workload' },
72
+ { method: 'post', path: '/status', summary: 'Publish an agent status update', tag: 'Agents' }
73
+ ];
74
+ const errorResponse = {
75
+ description: 'Error',
76
+ content: {
77
+ 'application/json': {
78
+ schema: {
79
+ type: 'object',
80
+ properties: {
81
+ error: { type: 'string' },
82
+ issues: { type: 'array', items: { type: 'object', properties: { path: { type: 'string' }, message: { type: 'string' } } } }
83
+ },
84
+ required: ['error']
85
+ }
86
+ }
87
+ }
88
+ };
89
+ function toJsonSchema(schema) {
90
+ const { $schema: _ignored, ...json } = zodToJsonSchema(schema, { $refStrategy: 'none' });
91
+ return json;
92
+ }
93
+ /**
94
+ * Builds an OpenAPI 3.1 document for the router. Request bodies are generated from the same zod
95
+ * schemas the router validates with, so the contract cannot drift from enforcement.
96
+ */
97
+ export function buildOpenApiDocument(options = {}) {
98
+ const paths = {};
99
+ for (const route of ROUTES) {
100
+ const pathParams = [...route.path.matchAll(/\{(\w+)\}/g)].map((m) => m[1]);
101
+ const parameters = [
102
+ ...pathParams.map((name) => ({ name, in: 'path', required: true, schema: { type: 'string' } })),
103
+ ...(route.query ?? []).map((q) => ({
104
+ name: q.replace(/!$/, ''),
105
+ in: 'query',
106
+ required: q.endsWith('!'),
107
+ schema: { type: 'string' }
108
+ }))
109
+ ];
110
+ const status = String(route.status ?? 200);
111
+ const successSchema = route.responseKey
112
+ ? { type: 'object', properties: { [route.responseKey]: {} }, required: [route.responseKey] }
113
+ : { type: 'object' };
114
+ paths[route.path] ??= {};
115
+ paths[route.path][route.method] = {
116
+ summary: route.summary,
117
+ tags: [route.tag],
118
+ ...(parameters.length ? { parameters } : {}),
119
+ ...(route.body
120
+ ? { requestBody: { required: true, content: { 'application/json': { schema: toJsonSchema(route.body) } } } }
121
+ : {}),
122
+ responses: {
123
+ [status]: { description: 'Success', content: { 'application/json': { schema: successSchema } } },
124
+ '400': errorResponse,
125
+ '401': errorResponse,
126
+ '404': errorResponse,
127
+ ...(route.path.endsWith('/dependencies') && route.method === 'post' ? { '409': errorResponse } : {}),
128
+ '500': errorResponse
129
+ }
130
+ };
131
+ }
132
+ return {
133
+ openapi: '3.1.0',
134
+ info: { title: options.title ?? 'Critical Path API', version: options.version ?? '1.0.0' },
135
+ ...(options.serverUrl ? { servers: [{ url: options.serverUrl }] } : {}),
136
+ paths
137
+ };
138
+ }
139
+ //# sourceMappingURL=openapi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.js","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=openapi.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.test.d.ts","sourceRoot":"","sources":["../src/openapi.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,86 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { CriticalPathRouter } from './router.js';
3
+ import { ROUTES, buildOpenApiDocument } from './openapi.js';
4
+ const base = 'http://localhost:3000/api/critical-path';
5
+ describe('OpenAPI document', () => {
6
+ it('documents every route the router serves, with matching response envelopes', async () => {
7
+ const router = new CriticalPathRouter();
8
+ const engine = router.engine;
9
+ const project = await engine.createProject({ key: 'OAS', name: 'OpenAPI' });
10
+ const task = await engine.createTask({ projectId: project.id, title: 'Task' });
11
+ const workflow = await engine.createWorkflow({ name: 'WF', statuses: [], transitions: [] });
12
+ const team = await engine.createTeam({ name: 'Team', memberIds: [] });
13
+ const container = await engine.createContainer({ projectId: project.id, name: 'Epic' });
14
+ const deliverable = await engine.createDeliverable({ projectId: project.id, title: 'Cut' });
15
+ const iteration = await engine.createIteration({ projectId: project.id, name: 'S1', status: 'planning' });
16
+ const comment = await engine.addComment({ taskId: task.id, content: 'hi', authorId: 'u1' });
17
+ const attachment = await engine.createAttachment({
18
+ taskId: task.id,
19
+ uploaderId: 'u1',
20
+ filename: 'a.md',
21
+ mimeType: 'text/markdown',
22
+ sizeBytes: 1,
23
+ url: 'https://example.com/a.md'
24
+ });
25
+ const ids = {
26
+ projectId: project.id,
27
+ taskId: task.id,
28
+ workflowId: workflow.id,
29
+ teamId: team.id,
30
+ containerId: container.id,
31
+ deliverableId: deliverable.id,
32
+ iterationId: iteration.id,
33
+ commentId: comment.id,
34
+ attachmentId: attachment.id
35
+ };
36
+ const query = { projectId: project.id, taskId: task.id, emoji: '👍', userId: 'u1' };
37
+ // Deletes run last so earlier routes still have data; the project goes last of all.
38
+ const ordered = [...ROUTES].sort((a, b) => {
39
+ const rank = (r) => (r.method === 'delete' ? (r.path === '/projects/{projectId}' ? 2 : 1) : 0);
40
+ return rank(a) - rank(b);
41
+ });
42
+ for (const route of ordered) {
43
+ const path = route.path.replace(/\{(\w+)\}/g, (_, name) => ids[name]);
44
+ const params = new URLSearchParams();
45
+ for (const q of route.query ?? []) {
46
+ const name = q.replace(/!$/, '');
47
+ if (query[name])
48
+ params.set(name, query[name]);
49
+ }
50
+ const res = await router.handleRequest(new Request(`${base}${path}${params.size ? `?${params}` : ''}`, {
51
+ method: route.method.toUpperCase(),
52
+ headers: { 'Content-Type': 'application/json' },
53
+ ...(route.method === 'post' || route.method === 'patch' ? { body: '{}' } : {})
54
+ }));
55
+ const body = await res.json();
56
+ const label = `${route.method.toUpperCase()} ${route.path}`;
57
+ expect(String(body.error ?? ''), label).not.toMatch(/^Route not found/);
58
+ if (res.status < 300 && route.responseKey) {
59
+ expect(body, label).toHaveProperty(route.responseKey);
60
+ }
61
+ }
62
+ });
63
+ it('serves the document at /openapi.json with request bodies from the validation schemas', async () => {
64
+ const router = new CriticalPathRouter();
65
+ const res = await router.handleRequest(new Request(`${base}/openapi.json`));
66
+ expect(res.status).toBe(200);
67
+ const doc = await res.json();
68
+ expect(doc.openapi).toBe('3.1.0');
69
+ expect(doc.servers[0].url).toBe('http://localhost:3000/api/critical-path');
70
+ const createTask = doc.paths['/tasks'].post.requestBody.content['application/json'].schema;
71
+ expect(createTask.required).toEqual(expect.arrayContaining(['projectId', 'title']));
72
+ expect(createTask.properties).not.toHaveProperty('id');
73
+ expect(doc.paths['/tasks/{taskId}/dependencies'].post.responses).toHaveProperty('409');
74
+ });
75
+ it('respects requireAuth', async () => {
76
+ const router = new CriticalPathRouter(undefined, { requireAuth: true });
77
+ const res = await router.handleRequest(new Request(`${base}/openapi.json`));
78
+ expect(res.status).toBe(401);
79
+ });
80
+ it('can be built without a router for static publishing', () => {
81
+ const doc = buildOpenApiDocument({ serverUrl: 'https://api.example.com/pm', version: '2.0.0' });
82
+ expect(doc.info.version).toBe('2.0.0');
83
+ expect(Object.keys(doc.paths).length).toBeGreaterThan(30);
84
+ });
85
+ });
86
+ //# sourceMappingURL=openapi.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.test.js","sourceRoot":"","sources":["../src/openapi.test.ts"],"names":[],"mappings":"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"}
package/dist/router.d.ts CHANGED
@@ -1,4 +1,10 @@
1
1
  import { CriticalPathEngine, type AuthorType, type CriticalPathConfig } from '@critical-path/core';
2
+ /** Actor for requests when no `getContext` is configured or it resolves no user. */
3
+ export declare const ANONYMOUS_ACTOR: Readonly<{
4
+ userId: "anonymous";
5
+ username: "Anonymous";
6
+ actorType: "user";
7
+ }>;
2
8
  /**
3
9
  * Per-request identity resolved by `getContext`. `userId` becomes the actor every mutation in
4
10
  * the request is attributed to. Extra fields (e.g. `tenantId`, `roles`) are carried for
@@ -37,8 +43,8 @@ export interface CriticalPathRouterOptions {
37
43
  exposeErrors?: boolean;
38
44
  /**
39
45
  * Resolves the caller's identity from the request (session cookie, bearer token, etc.).
40
- * When it returns a `userId`, all mutations in the request are attributed to that user and
41
- * identity fields in request bodies (`actorId`, `authorId`, `userId`, ...) are ignored.
46
+ * When it returns a `userId`, all mutations in the request are attributed to that user;
47
+ * otherwise they are attributed to `ANONYMOUS_ACTOR`. Request bodies never carry identity.
42
48
  */
43
49
  getContext?: (request: Request) => RequestContext | null | undefined | Promise<RequestContext | null | undefined>;
44
50
  /** Reject requests with `401` unless `getContext` returns a `userId`. Defaults to `false`. */
@@ -48,7 +54,10 @@ export interface CriticalPathRouterOptions {
48
54
  * When omitted, everything up to the first `/critical-path` segment is stripped.
49
55
  */
50
56
  basePath?: string;
51
- /** CORS policy. Defaults to `{ origins: '*' }`; pass `false` to send no CORS headers. */
57
+ /**
58
+ * CORS policy. Defaults to `false` (no CORS headers, so only same-origin browsers can call the
59
+ * API). Set `{ origins: [...] }` to allow specific sites, or `{ origins: '*' }` for any site.
60
+ */
52
61
  cors?: CorsOptions | false;
53
62
  }
54
63
  export declare class CriticalPathRouter {
@@ -70,6 +79,13 @@ export declare class CriticalPathRouter {
70
79
  private resolveSubpath;
71
80
  private applyCors;
72
81
  private dispatch;
82
+ /**
83
+ * Reads and validates a JSON body. `overrides` (e.g. a `taskId` from the URL) are applied before
84
+ * validation so path parameters always win over body fields.
85
+ */
86
+ private readBody;
87
+ /** The API root as seen by this request, e.g. `https://host/api/critical-path`. */
88
+ private openApiServerUrl;
73
89
  private readJson;
74
90
  private errorResponse;
75
91
  private jsonResponse;
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,KAAK,UAAU,EAAE,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAKnG;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,yBAAyB,CAAC,YAAY,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,WAAW;IAC1B,4FAA4F;IAC5F,OAAO,EAAE,GAAG,GAAG,MAAM,EAAE,CAAC;IACxB,yEAAyE;IACzE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yFAAyF;IACzF,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AASD,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,QAAQ,GAAG,OAAO,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC;IAC3F;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAClH,8FAA8F;IAC9F,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yFAAyF;IACzF,IAAI,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;CAC5B;AAMD,qBAAa,kBAAkB;IACtB,MAAM,EAAE,kBAAkB,CAAC;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAuC;IAChE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAA0C;IACtE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;gBAE/B,cAAc,CAAC,EAAE,kBAAkB,GAAG,kBAAkB,EAAE,OAAO,GAAE,yBAA8B;IAiB7G;;;;OAIG;IACG,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAKvF,gGAAgG;IAChG,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,SAAS;YA0BH,QAAQ;YAujBR,QAAQ;YAQR,aAAa;IAoC3B,OAAO,CAAC,YAAY;CAQrB"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,KAAK,UAAU,EAAE,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAInG,oFAAoF;AACpF,eAAO,MAAM,eAAe;;;;EAA4F,CAAC;AAKzH;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,yBAAyB,CAAC,YAAY,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,WAAW;IAC1B,4FAA4F;IAC5F,OAAO,EAAE,GAAG,GAAG,MAAM,EAAE,CAAC;IACxB,yEAAyE;IACzE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yFAAyF;IACzF,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AASD,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,QAAQ,GAAG,OAAO,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC;IAC3F;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAClH,8FAA8F;IAC9F,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,IAAI,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;CAC5B;AAMD,qBAAa,kBAAkB;IACtB,MAAM,EAAE,kBAAkB,CAAC;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAuC;IAChE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAA0C;IACtE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;gBAE/B,cAAc,CAAC,EAAE,kBAAkB,GAAG,kBAAkB,EAAE,OAAO,GAAE,yBAA8B;IAiB7G;;;;OAIG;IACG,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAKvF,gGAAgG;IAChG,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,SAAS;YA0BH,QAAQ;IAijBtB;;;OAGG;YACW,QAAQ;IAUtB,mFAAmF;IACnF,OAAO,CAAC,gBAAgB;YAKV,QAAQ;YAQR,aAAa;IAqC3B,OAAO,CAAC,YAAY;CAQrB"}