@devpad/api 2.0.0 → 2.0.2

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.
@@ -1,530 +0,0 @@
1
- import { ApiClient as HttpClient } from "./request";
2
- import { wrap } from "./result";
3
- /**
4
- * API client with Result-wrapped operations for clean error handling
5
- * All methods return ApiResult<T> types using @f0rbit/corpus Result
6
- */
7
- export class ApiClient {
8
- constructor(options) {
9
- /**
10
- * Auth namespace with Result-wrapped operations
11
- */
12
- this.auth = {
13
- session: () => wrap(() => this.clients.auth_root.get("/auth/session")),
14
- keys: {
15
- list: () => wrap(() => this.clients.auth.get("/keys")),
16
- create: (name) => wrap(() => this.clients.auth.post("/keys", { body: name ? { name } : {} })),
17
- revoke: (key_id) => wrap(() => this.clients.auth.delete(`/keys/${key_id}`)),
18
- remove: (key_id) => wrap(() => this.clients.auth.delete(`/keys/${key_id}`)),
19
- },
20
- };
21
- /**
22
- * Projects namespace with Result-wrapped operations
23
- */
24
- this.projects = {
25
- /**
26
- * List projects with optional filtering
27
- */
28
- list: (filters) => wrap(() => this.clients.projects.get(filters?.private === false ? "/projects/public" : "/projects")),
29
- /**
30
- * Get project map
31
- */
32
- map: async (filters) => wrap(async () => {
33
- const result = await this.projects.list(filters);
34
- if (!result.ok)
35
- throw new Error(result.error.message);
36
- return result.value.reduce((acc, project) => {
37
- acc[project.id] = project;
38
- return acc;
39
- }, {});
40
- }),
41
- /**
42
- * Get project by ID
43
- */
44
- find: (id) => wrap(() => this.clients.projects.get("/projects", { query: { id } })),
45
- /**
46
- * Get project by name
47
- */
48
- getByName: (name) => wrap(() => this.clients.projects.get("/projects", { query: { name } })),
49
- /**
50
- * Get project by ID (throws if not found)
51
- */
52
- getById: (id) => wrap(() => this.clients.projects.get("/projects", { query: { id } })),
53
- /**
54
- * Create a new project
55
- */
56
- create: (data) => wrap(() => this.clients.projects.patch("/projects", { body: data })),
57
- /**
58
- * Update an existing project
59
- */
60
- update: async (idOrData, changes) => wrap(async () => {
61
- // Handle backward compatibility: update(data)
62
- if (typeof idOrData === "object" && idOrData.id) {
63
- return this.clients.projects.patch("/projects", { body: idOrData });
64
- }
65
- // Handle new clean interface: update(id, changes)
66
- const id = idOrData;
67
- if (!changes) {
68
- throw new Error("Changes parameter required for update");
69
- }
70
- // Fetch the existing project to get current values
71
- const result = await this.projects.find(id);
72
- if (!result.ok)
73
- throw new Error(result.error.message);
74
- if (!result.value)
75
- throw new Error(`Project with id ${id} not found`);
76
- const project = result.value;
77
- // Merge changes with existing project data
78
- const updateData = {
79
- id: project.id,
80
- project_id: project.project_id,
81
- owner_id: project.owner_id,
82
- name: project.name,
83
- description: project.description,
84
- specification: project.specification,
85
- repo_url: project.repo_url,
86
- repo_id: project.repo_id,
87
- icon_url: project.icon_url,
88
- status: project.status,
89
- deleted: project.deleted,
90
- link_url: project.link_url,
91
- link_text: project.link_text,
92
- visibility: project.visibility,
93
- current_version: project.current_version,
94
- ...changes,
95
- };
96
- return this.clients.projects.patch("/projects", { body: updateData });
97
- }),
98
- /**
99
- * Project configuration operations
100
- */
101
- config: {
102
- /**
103
- * Get project configuration
104
- */
105
- load: (project_id) => wrap(() => this.clients.projects.get("/projects/config", { query: { project_id } })),
106
- /**
107
- * Save project configuration
108
- */
109
- save: (request) => wrap(() => this.clients.projects.patch("/projects/save_config", { body: request })),
110
- },
111
- /**
112
- * Scanning operations
113
- */
114
- scan: {
115
- /**
116
- * Initiate a repository scan (returns stream)
117
- */
118
- initiate: async (project_id) => {
119
- const response = await fetch(`${this.clients.projects.url()}/projects/scan?project_id=${project_id}`, {
120
- method: "POST",
121
- headers: this.clients.projects.headers(),
122
- });
123
- if (!response.body) {
124
- throw new Error("No response body");
125
- }
126
- const stream = response.body.pipeThrough(new TextDecoderStream());
127
- return stream;
128
- },
129
- /**
130
- * Get pending scan updates for a project
131
- */
132
- updates: (project_id) => wrap(() => this.clients.projects.get("/projects/updates", { query: { project_id } }).then(response => response.updates)),
133
- /**
134
- * Process scan results
135
- */
136
- update: (project_id, data) => wrap(() => this.clients.projects.post("/projects/scan_status", { query: { project_id }, body: data })),
137
- },
138
- /**
139
- * Get project history
140
- */
141
- history: (project_id) => wrap(() => this.clients.projects.get(`/projects/${project_id}/history`)),
142
- /**
143
- * Legacy methods (keeping for compatibility)
144
- */
145
- upsert: (data) => wrap(() => this.clients.projects.patch("/projects", { body: data })),
146
- /**
147
- * Fetch project specification from GitHub
148
- */
149
- specification: (project_id) => wrap(() => this.clients.projects.get("/projects/fetch_spec", { query: { project_id } })),
150
- /**
151
- * Delete project (soft delete)
152
- */
153
- deleteProject: (project) => wrap(() => this.clients.projects.patch("/projects", { body: { ...project, deleted: true } })),
154
- };
155
- /**
156
- * Milestones namespace with Result-wrapped operations
157
- */
158
- this.milestones = {
159
- /**
160
- * List milestones for authenticated user
161
- */
162
- list: () => wrap(() => this.clients.milestones.get("/milestones")),
163
- /**
164
- * Get milestones by project ID
165
- */
166
- getByProject: (project_id) => wrap(() => this.clients.milestones.get(`/projects/${project_id}/milestones`)),
167
- /**
168
- * Get milestone by ID
169
- */
170
- find: (id) => wrap(async () => {
171
- try {
172
- return await this.clients.milestones.get(`/milestones/${id}`);
173
- }
174
- catch (error) {
175
- return null;
176
- }
177
- }),
178
- /**
179
- * Create new milestone
180
- */
181
- create: (data) => wrap(() => this.clients.milestones.post("/milestones", { body: data })),
182
- /**
183
- * Update milestone
184
- */
185
- update: async (id, data) => wrap(async () => {
186
- // Fetch the existing milestone to get required fields
187
- const result = await this.milestones.find(id);
188
- if (!result.ok)
189
- throw new Error(result.error.message);
190
- if (!result.value)
191
- throw new Error(`Milestone with id ${id} not found`);
192
- const milestone = result.value;
193
- // Merge changes with existing milestone data
194
- const updateData = {
195
- id: milestone.id,
196
- project_id: milestone.project_id,
197
- name: data.name ?? milestone.name,
198
- description: data.description ?? milestone.description,
199
- target_time: data.target_time ?? milestone.target_time,
200
- target_version: data.target_version ?? milestone.target_version,
201
- };
202
- return this.clients.milestones.patch(`/milestones/${id}`, { body: updateData });
203
- }),
204
- /**
205
- * Delete milestone (soft delete)
206
- */
207
- delete: (id) => wrap(() => this.clients.milestones.delete(`/milestones/${id}`)),
208
- /**
209
- * Get goals for a milestone
210
- */
211
- goals: (id) => wrap(() => this.clients.milestones.get(`/milestones/${id}/goals`)),
212
- };
213
- /**
214
- * Goals namespace with Result-wrapped operations
215
- */
216
- this.goals = {
217
- /**
218
- * List goals for authenticated user
219
- */
220
- list: () => wrap(() => this.clients.goals.get("/goals")),
221
- /**
222
- * Get goal by ID
223
- */
224
- find: (id) => wrap(() => this.clients.goals.get(`/goals/${id}`)),
225
- /**
226
- * Create new goal
227
- */
228
- create: (data) => wrap(() => this.clients.goals.post("/goals", { body: data })),
229
- /**
230
- * Update goal
231
- */
232
- update: async (id, data) => wrap(async () => {
233
- // Fetch the existing goal to get required fields
234
- const result = await this.goals.find(id);
235
- if (!result.ok)
236
- throw new Error(result.error.message);
237
- if (!result.value)
238
- throw new Error(`Goal with id ${id} not found`);
239
- const goal = result.value;
240
- // Merge changes with existing goal data
241
- const updateData = {
242
- id: goal.id,
243
- milestone_id: goal.milestone_id,
244
- name: data.name ?? goal.name,
245
- description: data.description ?? goal.description,
246
- target_time: data.target_time ?? goal.target_time,
247
- };
248
- return this.clients.goals.patch(`/goals/${id}`, { body: updateData });
249
- }),
250
- /**
251
- * Delete goal (soft delete)
252
- */
253
- delete: (id) => wrap(() => this.clients.goals.delete(`/goals/${id}`)),
254
- };
255
- /**
256
- * Tasks namespace with Result-wrapped operations
257
- */
258
- this.tasks = {
259
- /**
260
- * List tasks with optional filtering
261
- */
262
- list: (filters) => wrap(() => {
263
- const query = {};
264
- if (filters?.project_id)
265
- query.project = filters.project_id;
266
- if (filters?.tag_id)
267
- query.tag = filters.tag_id;
268
- return this.clients.tasks.get("/tasks", Object.keys(query).length > 0 ? { query } : {});
269
- }),
270
- /**
271
- * Get task by ID
272
- */
273
- find: (id) => wrap(() => this.clients.tasks.get("/tasks", { query: { id } })),
274
- /**
275
- * Get tasks by project ID
276
- */
277
- getByProject: (project_id) => wrap(() => this.clients.tasks.get(`/tasks`, { query: { project: project_id } })),
278
- /**
279
- * Create a new task
280
- */
281
- create: (data) => wrap(() => this.clients.tasks.patch("/tasks", { body: data })),
282
- /**
283
- * Update an existing task
284
- */
285
- update: async (id, changes) => wrap(async () => {
286
- // Fetch existing task to merge changes
287
- const result = await this.tasks.find(id);
288
- if (!result.ok)
289
- throw new Error(result.error.message);
290
- if (!result.value)
291
- throw new Error(`Task with id ${id} not found`);
292
- const task = result.value;
293
- const updateData = {
294
- id,
295
- title: task.task.title,
296
- summary: task.task.summary,
297
- description: task.task.description,
298
- progress: task.task.progress,
299
- visibility: task.task.visibility,
300
- start_time: task.task.start_time,
301
- end_time: task.task.end_time,
302
- priority: task.task.priority,
303
- owner_id: task.task.owner_id,
304
- project_id: task.task.project_id,
305
- ...changes,
306
- };
307
- return this.clients.tasks.patch("/tasks", { body: updateData });
308
- }),
309
- /**
310
- * Upsert task (create or update)
311
- */
312
- upsert: (data) => wrap(() => this.clients.tasks.patch("/tasks", { body: data })),
313
- /**
314
- * Save tags for tasks
315
- */
316
- saveTags: (data) => wrap(() => this.clients.tasks.patch("/tasks/save_tags", { body: data })),
317
- /**
318
- * Delete task (soft delete)
319
- */
320
- deleteTask: (task) => wrap(() => this.clients.tasks.patch("/tasks", { body: { ...task.task, deleted: true } })),
321
- /**
322
- * Task history operations
323
- */
324
- history: {
325
- /**
326
- * Get task history by task ID
327
- */
328
- get: (task_id) => wrap(() => this.clients.tasks.get(`/tasks/history/${task_id}`)),
329
- },
330
- };
331
- /**
332
- * Tags namespace with Result-wrapped operations
333
- */
334
- this.tags = {
335
- /**
336
- * List tags for authenticated user
337
- */
338
- list: () => wrap(() => this.clients.tags.get("/tags")),
339
- };
340
- /**
341
- * GitHub namespace with Result-wrapped operations
342
- */
343
- this.github = {
344
- /**
345
- * List repositories for authenticated user
346
- */
347
- repos: () => wrap(() => this.clients.github.get("/repos")),
348
- /**
349
- * List branches for a GitHub repository
350
- */
351
- branches: (owner, repo) => wrap(() => this.clients.github.get(`/repos/${owner}/${repo}/branches`)),
352
- };
353
- this.blog = {
354
- posts: {
355
- list: (params) => wrap(() => {
356
- const query = {};
357
- if (params?.category)
358
- query.category = params.category;
359
- if (params?.tag)
360
- query.tag = params.tag;
361
- if (params?.project)
362
- query.project = params.project;
363
- if (params?.status)
364
- query.status = params.status;
365
- if (params?.archived !== undefined)
366
- query.archived = String(params.archived);
367
- if (params?.limit)
368
- query.limit = String(params.limit);
369
- if (params?.offset !== undefined)
370
- query.offset = String(params.offset);
371
- if (params?.sort)
372
- query.sort = params.sort;
373
- return this.clients.blog.get("/blog/posts", Object.keys(query).length ? { query } : {});
374
- }),
375
- getBySlug: (slug) => wrap(() => this.clients.blog.get(`/blog/posts/${slug}`)),
376
- create: (data) => wrap(() => this.clients.blog.post("/blog/posts", { body: data })),
377
- update: (uuid, data) => wrap(() => this.clients.blog.put(`/blog/posts/${uuid}`, { body: data })),
378
- delete: (uuid) => wrap(() => this.clients.blog.delete(`/blog/posts/${uuid}`)),
379
- versions: (uuid) => wrap(() => this.clients.blog.get(`/blog/posts/${uuid}/versions`)),
380
- version: (uuid, hash) => wrap(() => this.clients.blog.get(`/blog/posts/${uuid}/version/${hash}`)),
381
- restore: (uuid, hash) => wrap(() => this.clients.blog.post(`/blog/posts/${uuid}/restore/${hash}`)),
382
- },
383
- tags: {
384
- list: () => wrap(() => this.clients.blog.get("/blog/tags")),
385
- getForPost: (uuid) => wrap(() => this.clients.blog.get(`/blog/tags/posts/${uuid}/tags`)),
386
- setForPost: (uuid, tags) => wrap(() => this.clients.blog.put(`/blog/tags/posts/${uuid}/tags`, { body: { tags } })),
387
- addToPost: (uuid, tags) => wrap(() => this.clients.blog.post(`/blog/tags/posts/${uuid}/tags`, { body: { tags } })),
388
- removeFromPost: (uuid, tag) => wrap(() => this.clients.blog.delete(`/blog/tags/posts/${uuid}/tags/${tag}`)),
389
- },
390
- categories: {
391
- tree: () => wrap(() => this.clients.blog.get("/blog/categories")),
392
- create: (data) => wrap(() => this.clients.blog.post("/blog/categories", { body: data })),
393
- update: (name, data) => wrap(() => this.clients.blog.put(`/blog/categories/${name}`, { body: data })),
394
- delete: (name) => wrap(() => this.clients.blog.delete(`/blog/categories/${name}`)),
395
- },
396
- tokens: {
397
- list: () => wrap(() => this.clients.blog.get("/blog/tokens")),
398
- create: (data) => wrap(() => this.clients.blog.post("/blog/tokens", { body: data })),
399
- update: (id, data) => wrap(() => this.clients.blog.put(`/blog/tokens/${id}`, { body: data })),
400
- delete: (id) => wrap(() => this.clients.blog.delete(`/blog/tokens/${id}`)),
401
- },
402
- };
403
- this.media = {
404
- profiles: {
405
- list: () => wrap(async () => {
406
- const res = await this.clients.media.get("/profiles");
407
- return res.profiles;
408
- }),
409
- create: (data) => wrap(() => this.clients.media.post("/profiles", { body: data })),
410
- get: (id) => wrap(() => this.clients.media.get(`/profiles/${id}`)),
411
- update: (id, data) => wrap(() => this.clients.media.patch(`/profiles/${id}`, { body: data })),
412
- delete: (id) => wrap(() => this.clients.media.delete(`/profiles/${id}`)),
413
- filters: {
414
- list: (profile_id) => wrap(async () => {
415
- const res = await this.clients.media.get(`/profiles/${profile_id}/filters`);
416
- return res.filters;
417
- }),
418
- add: (profile_id, data) => wrap(() => this.clients.media.post(`/profiles/${profile_id}/filters`, { body: data })),
419
- remove: (profile_id, filter_id) => wrap(() => this.clients.media.delete(`/profiles/${profile_id}/filters/${filter_id}`)),
420
- },
421
- timeline: (slug, params) => wrap(() => {
422
- const query = {};
423
- if (params?.limit)
424
- query.limit = String(params.limit);
425
- if (params?.before)
426
- query.before = params.before;
427
- return this.clients.media.get(`/profiles/${slug}/timeline`, Object.keys(query).length ? { query } : {});
428
- }),
429
- },
430
- connections: {
431
- list: (profile_id, options) => wrap(async () => {
432
- const query = { profile_id };
433
- if (options?.include_settings)
434
- query.include_settings = "true";
435
- const res = await this.clients.media.get("/connections", { query });
436
- return res.accounts;
437
- }),
438
- create: (data) => wrap(() => this.clients.media.post("/connections", { body: data })),
439
- delete: (account_id) => wrap(() => this.clients.media.delete(`/connections/${account_id}`)),
440
- refresh: (account_id) => wrap(() => this.clients.media.post(`/connections/${account_id}/refresh`)),
441
- refreshAll: () => wrap(() => this.clients.media.post("/connections/refresh-all")),
442
- updateStatus: (account_id, is_active) => wrap(() => this.clients.media.patch(`/connections/${account_id}`, { body: { is_active } })),
443
- settings: {
444
- get: (account_id) => wrap(() => this.clients.media.get(`/connections/${account_id}/settings`)),
445
- update: (account_id, settings) => wrap(() => this.clients.media.put(`/connections/${account_id}/settings`, { body: { settings } })),
446
- },
447
- repos: (account_id) => wrap(async () => {
448
- const res = await this.clients.media.get(`/connections/${account_id}/repos`);
449
- return res.repos;
450
- }),
451
- subreddits: (account_id) => wrap(async () => {
452
- const res = await this.clients.media.get(`/connections/${account_id}/subreddits`);
453
- return res.subreddits;
454
- }),
455
- },
456
- credentials: {
457
- check: (platform, profile_id) => wrap(() => this.clients.media.get(`/credentials/${platform}`, { query: { profile_id } })),
458
- save: (platform, data) => wrap(() => this.clients.media.post(`/credentials/${platform}`, { body: data })),
459
- delete: (platform, profile_id) => wrap(() => this.clients.media.delete(`/credentials/${platform}`, { query: { profile_id } })),
460
- },
461
- timeline: {
462
- get: (user_id, params) => wrap(() => {
463
- const query = {};
464
- if (params?.from)
465
- query.from = params.from;
466
- if (params?.to)
467
- query.to = params.to;
468
- return this.clients.media.get(`/timeline/${user_id}`, Object.keys(query).length ? { query } : {});
469
- }),
470
- getRaw: (user_id, platform, account_id) => wrap(() => this.clients.media.get(`/timeline/${user_id}/raw/${platform}`, { query: { account_id } })),
471
- },
472
- };
473
- /**
474
- * User namespace with Result-wrapped operations
475
- */
476
- this.user = {
477
- /**
478
- * Get user activity history
479
- */
480
- history: () => wrap(() => this.clients.auth.get("/user/history")),
481
- /**
482
- * Update user preferences
483
- */
484
- preferences: (data) => wrap(() => this.clients.auth.patch("/user/preferences", { body: data })),
485
- };
486
- const base_url = options.base_url || "http://localhost:4321/api/v1";
487
- this._api_key = options.api_key ?? "";
488
- this._auth_mode = options.auth_mode ?? (options.api_key?.startsWith("jwt:") ? "session" : options.api_key ? "key" : "cookie");
489
- const clientOptions = {
490
- base_url,
491
- api_key: options.api_key,
492
- max_history_size: options.max_history_size,
493
- auth_mode: this._auth_mode,
494
- credentials: options.credentials,
495
- default_headers: options.default_headers,
496
- custom_fetch: options.custom_fetch,
497
- };
498
- const auth_base_url = base_url.replace(/\/v1\/?$/, "");
499
- this.clients = {
500
- auth: new HttpClient({ ...clientOptions, category: "auth" }),
501
- auth_root: new HttpClient({ ...clientOptions, base_url: auth_base_url, category: "auth" }),
502
- projects: new HttpClient({ ...clientOptions, category: "projects" }),
503
- tasks: new HttpClient({ ...clientOptions, category: "tasks" }),
504
- milestones: new HttpClient({ ...clientOptions, category: "milestones" }),
505
- goals: new HttpClient({ ...clientOptions, category: "goals" }),
506
- github: new HttpClient({ ...clientOptions, category: "github" }),
507
- tags: new HttpClient({ ...clientOptions, category: "tags" }),
508
- blog: new HttpClient({ ...clientOptions, category: "blog" }),
509
- media: new HttpClient({ ...clientOptions, category: "media" }),
510
- };
511
- }
512
- /**
513
- * Get request history for debugging
514
- */
515
- history() {
516
- return this.clients.projects.history();
517
- }
518
- /**
519
- * Get the API key
520
- */
521
- getApiKey() {
522
- return this._api_key;
523
- }
524
- /**
525
- * Get the authentication mode
526
- */
527
- getAuthMode() {
528
- return this._auth_mode;
529
- }
530
- }
@@ -1,55 +0,0 @@
1
- import { ApiError, AuthenticationError, NetworkError } from "./errors";
2
- /**
3
- * Centralized error handling utilities to reduce duplication
4
- * across API client methods and improve consistency
5
- */
6
- /**
7
- * Standard HTTP status codes
8
- */
9
- export declare const HTTP_STATUS: {
10
- readonly OK: 200;
11
- readonly CREATED: 201;
12
- readonly NO_CONTENT: 204;
13
- readonly BAD_REQUEST: 400;
14
- readonly UNAUTHORIZED: 401;
15
- readonly FORBIDDEN: 403;
16
- readonly NOT_FOUND: 404;
17
- readonly INTERNAL_SERVER_ERROR: 500;
18
- };
19
- /**
20
- * Handle response based on status code with consistent error types
21
- */
22
- export declare function handleHttpResponse(response: Response): void;
23
- /**
24
- * Parse and throw appropriate error from response text
25
- */
26
- export declare function handleResponseError(response: Response): Promise<never>;
27
- /**
28
- * Handle network errors consistently
29
- */
30
- export declare function handleNetworkError(error: unknown): never;
31
- /**
32
- * Type guard to check if error is an API error
33
- */
34
- export declare function isApiError(error: unknown): error is ApiError;
35
- /**
36
- * Type guard to check if error is an authentication error
37
- */
38
- export declare function isAuthenticationError(error: unknown): error is AuthenticationError;
39
- /**
40
- * Type guard to check if error is a network error
41
- */
42
- export declare function isNetworkError(error: unknown): error is NetworkError;
43
- /**
44
- * Parse Zod validation errors into user-friendly messages
45
- */
46
- export declare function parseZodErrors(errorMessage: string): string;
47
- /**
48
- * Get user-friendly error message from any error
49
- */
50
- export declare function getUserFriendlyErrorMessage(error: unknown): string;
51
- /**
52
- * Retry wrapper for API calls with exponential backoff
53
- */
54
- export declare function withRetry<T>(operation: () => Promise<T>, maxRetries?: number, baseDelay?: number): Promise<T>;
55
- //# sourceMappingURL=error-handlers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"error-handlers.d.ts","sourceRoot":"","sources":["../src/error-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,YAAY,EAAmB,MAAM,UAAU,CAAC;AAExF;;;GAGG;AAEH;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;CASd,CAAC;AAEX;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAc3D;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,CAmB5E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAGxD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CAElF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAEpE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAgF3D;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA0BlE;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,GAAE,MAAU,EAAE,SAAS,GAAE,MAAa,GAAG,OAAO,CAAC,CAAC,CAAC,CA0B5H"}