@npm-safe/core-dsh 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/LICENSE +204 -0
  2. package/dist/index.d.ts +513 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +711 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/llm/anthropic.d.ts +47 -0
  7. package/dist/llm/anthropic.d.ts.map +1 -0
  8. package/dist/llm/anthropic.js +161 -0
  9. package/dist/llm/anthropic.js.map +1 -0
  10. package/dist/llm/gemini.d.ts +47 -0
  11. package/dist/llm/gemini.d.ts.map +1 -0
  12. package/dist/llm/gemini.js +165 -0
  13. package/dist/llm/gemini.js.map +1 -0
  14. package/dist/llm/llm-config.d.ts +97 -0
  15. package/dist/llm/llm-config.d.ts.map +1 -0
  16. package/dist/llm/llm-config.js +188 -0
  17. package/dist/llm/llm-config.js.map +1 -0
  18. package/dist/llm/parse.d.ts +95 -0
  19. package/dist/llm/parse.d.ts.map +1 -0
  20. package/dist/llm/parse.js +158 -0
  21. package/dist/llm/parse.js.map +1 -0
  22. package/dist/llm/provider.d.ts +122 -0
  23. package/dist/llm/provider.d.ts.map +1 -0
  24. package/dist/llm/provider.js +206 -0
  25. package/dist/llm/provider.js.map +1 -0
  26. package/dist/registry/client.d.ts +164 -0
  27. package/dist/registry/client.d.ts.map +1 -0
  28. package/dist/registry/client.js +378 -0
  29. package/dist/registry/client.js.map +1 -0
  30. package/dist/registry/types.d.ts +226 -0
  31. package/dist/registry/types.d.ts.map +1 -0
  32. package/dist/registry/types.js +32 -0
  33. package/dist/registry/types.js.map +1 -0
  34. package/dist/registry/validator.d.ts +87 -0
  35. package/dist/registry/validator.d.ts.map +1 -0
  36. package/dist/registry/validator.js +214 -0
  37. package/dist/registry/validator.js.map +1 -0
  38. package/dist/scanner/ci-scan.d.ts +82 -0
  39. package/dist/scanner/ci-scan.d.ts.map +1 -0
  40. package/dist/scanner/ci-scan.js +130 -0
  41. package/dist/scanner/ci-scan.js.map +1 -0
  42. package/dist/scanner/rule-config.d.ts +61 -0
  43. package/dist/scanner/rule-config.d.ts.map +1 -0
  44. package/dist/scanner/rule-config.js +103 -0
  45. package/dist/scanner/rule-config.js.map +1 -0
  46. package/dist/scanner/rule-loader.d.ts +28 -0
  47. package/dist/scanner/rule-loader.d.ts.map +1 -0
  48. package/dist/scanner/rule-loader.js +67 -0
  49. package/dist/scanner/rule-loader.js.map +1 -0
  50. package/dist/scanner/static-rules.d.ts +88 -0
  51. package/dist/scanner/static-rules.d.ts.map +1 -0
  52. package/dist/scanner/static-rules.js +723 -0
  53. package/dist/scanner/static-rules.js.map +1 -0
  54. package/dist/scanner/types.d.ts +177 -0
  55. package/dist/scanner/types.d.ts.map +1 -0
  56. package/dist/scanner/types.js +53 -0
  57. package/dist/scanner/types.js.map +1 -0
  58. package/dist/scheduler/rate-limiter.d.ts +74 -0
  59. package/dist/scheduler/rate-limiter.d.ts.map +1 -0
  60. package/dist/scheduler/rate-limiter.js +182 -0
  61. package/dist/scheduler/rate-limiter.js.map +1 -0
  62. package/dist/scheduler/refresh-scheduler.d.ts +201 -0
  63. package/dist/scheduler/refresh-scheduler.d.ts.map +1 -0
  64. package/dist/scheduler/refresh-scheduler.js +295 -0
  65. package/dist/scheduler/refresh-scheduler.js.map +1 -0
  66. package/dist/store/cache-manager.d.ts +166 -0
  67. package/dist/store/cache-manager.d.ts.map +1 -0
  68. package/dist/store/cache-manager.js +356 -0
  69. package/dist/store/cache-manager.js.map +1 -0
  70. package/dist/store/database.d.ts +81 -0
  71. package/dist/store/database.d.ts.map +1 -0
  72. package/dist/store/database.js +182 -0
  73. package/dist/store/database.js.map +1 -0
  74. package/dist/store/schema.d.ts +42 -0
  75. package/dist/store/schema.d.ts.map +1 -0
  76. package/dist/store/schema.js +126 -0
  77. package/dist/store/schema.js.map +1 -0
  78. package/dist/translator/provider.d.ts +152 -0
  79. package/dist/translator/provider.d.ts.map +1 -0
  80. package/dist/translator/provider.js +159 -0
  81. package/dist/translator/provider.js.map +1 -0
  82. package/dist/translator/types.d.ts +83 -0
  83. package/dist/translator/types.d.ts.map +1 -0
  84. package/dist/translator/types.js +58 -0
  85. package/dist/translator/types.js.map +1 -0
  86. package/package.json +42 -0
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Multi-provider LLM scan core.
3
+ *
4
+ * This module hosts the unified {@link LlmProviderOptions} interface, the
5
+ * {@link LlmProviderType} enum, and the {@link createLlmProvider} factory
6
+ * that dispatches to a concrete provider implementation. The OpenAI-
7
+ * compatible provider ({@link OpenAICompatibleLlmProvider}) lives here as
8
+ * the reference implementation; Gemini and Anthropic providers live in
9
+ * sibling modules and are wired up through the factory.
10
+ *
11
+ * Shared parsing/validation helpers and the {@link LlmProviderError} class
12
+ * are imported from {@link ./parse.js} so every provider reuses the same
13
+ * logic instead of duplicating it.
14
+ */
15
+ import { LlmProviderError, SYSTEM_PROMPT, buildReport, parseJsonObject, } from "./parse.js";
16
+ import { GeminiLlmProvider } from "./gemini.js";
17
+ import { AnthropicLlmProvider } from "./anthropic.js";
18
+ // Re-export LlmProviderError for backward compatibility: index.ts and the
19
+ // existing test suite import it from this module.
20
+ export { LlmProviderError } from "./parse.js";
21
+ // Re-export the concrete provider classes so tests and consumers can import
22
+ // them from this barrel module alongside the factory and shared types.
23
+ export { GeminiLlmProvider } from "./gemini.js";
24
+ export { AnthropicLlmProvider } from "./anthropic.js";
25
+ /**
26
+ * Supported LLM provider backends.
27
+ */
28
+ export var LlmProviderType;
29
+ (function (LlmProviderType) {
30
+ LlmProviderType["OpenAi"] = "openai";
31
+ LlmProviderType["Gemini"] = "gemini";
32
+ LlmProviderType["Anthropic"] = "anthropic";
33
+ })(LlmProviderType || (LlmProviderType = {}));
34
+ const DEFAULT_BASE_URL = "https://api.openai.com/v1";
35
+ const DEFAULT_MODEL = "gpt-4o-mini";
36
+ const DEFAULT_TIMEOUT_MS = 30_000;
37
+ const DEFAULT_MAX_INPUT_CHARS = 12_000;
38
+ const DEFAULT_MAX_TOKENS = 4096;
39
+ /**
40
+ * Construct an {@link LlmScanProvider} for the backend selected via
41
+ * {@link LlmProviderOptions.provider}. Defaults to the OpenAI-compatible
42
+ * provider.
43
+ *
44
+ * @param options - Provider configuration. When omitted, an OpenAI-
45
+ * compatible provider is constructed with environment-derived defaults.
46
+ * @returns A concrete {@link LlmScanProvider} instance.
47
+ */
48
+ export function createLlmProvider(options) {
49
+ switch (options?.provider ?? LlmProviderType.OpenAi) {
50
+ case LlmProviderType.Gemini:
51
+ return new GeminiLlmProvider(options);
52
+ case LlmProviderType.Anthropic:
53
+ return new AnthropicLlmProvider(options);
54
+ default:
55
+ return new OpenAICompatibleLlmProvider(options);
56
+ }
57
+ }
58
+ /**
59
+ * OpenAI-compatible chat completions LLM scan provider.
60
+ *
61
+ * Talks to any endpoint that implements the `/chat/completions` surface
62
+ * (OpenAI, Azure OpenAI, local LM Studio / Ollama OpenAI shims, etc.).
63
+ */
64
+ export class OpenAICompatibleLlmProvider {
65
+ apiKey;
66
+ baseUrl;
67
+ model;
68
+ timeoutMs;
69
+ maxInputChars;
70
+ maxTokens;
71
+ /**
72
+ * @param options - Provider configuration. Env-var fallbacks:
73
+ * `apiKey` defaults to `process.env.OPENAI_API_KEY`.
74
+ */
75
+ constructor(options = {}) {
76
+ this.apiKey = options.apiKey ?? process.env.OPENAI_API_KEY;
77
+ this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
78
+ this.model = options.model ?? DEFAULT_MODEL;
79
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
80
+ this.maxInputChars = options.maxInputChars ?? DEFAULT_MAX_INPUT_CHARS;
81
+ this.maxTokens = options.maxTokens ?? DEFAULT_MAX_TOKENS;
82
+ }
83
+ /** @inheritdoc */
84
+ async scan(input) {
85
+ if (!this.apiKey) {
86
+ return {
87
+ enabled: false,
88
+ reason: "LLM provider is not configured.",
89
+ };
90
+ }
91
+ const packageJsonBudget = Math.floor(this.maxInputChars / 3);
92
+ const packageJsonStr = input.packageJson
93
+ ? JSON.stringify(input.packageJson).slice(0, packageJsonBudget)
94
+ : undefined;
95
+ const content = JSON.stringify({
96
+ packageName: input.packageName,
97
+ version: input.version,
98
+ description: input.description,
99
+ readme: input.readme.slice(0, this.maxInputChars),
100
+ packageJson: packageJsonStr,
101
+ });
102
+ const payload = await this.request({
103
+ model: this.model,
104
+ temperature: 0,
105
+ max_tokens: this.maxTokens,
106
+ response_format: { type: "json_object" },
107
+ messages: [
108
+ { role: "system", content: SYSTEM_PROMPT },
109
+ { role: "user", content },
110
+ ],
111
+ }, input.signal);
112
+ const parsed = parseJsonObject(payload);
113
+ return buildReport(parsed, new Date().toISOString());
114
+ }
115
+ /** @inheritdoc */
116
+ async testConnection() {
117
+ if (!this.apiKey)
118
+ return false;
119
+ await this.request({
120
+ model: this.model,
121
+ messages: [{ role: "user", content: "Reply with OK." }],
122
+ max_tokens: this.maxTokens,
123
+ });
124
+ return true;
125
+ }
126
+ /**
127
+ * Issue a POST to `/chat/completions` with timeout and error normalization.
128
+ *
129
+ * @param body - The JSON request body.
130
+ * @param signal - Optional external abort signal combined with the owned
131
+ * timeout controller via `AbortSignal.any`. An external abort propagates
132
+ * as `DOMException('The operation was aborted.', 'AbortError')`.
133
+ * @returns The `choices[0].message.content` string from the response.
134
+ * @throws {LlmProviderError} On network, timeout, HTTP, or shape errors.
135
+ * @throws {DOMException} With name `AbortError` when `signal` is aborted.
136
+ */
137
+ async request(body, signal) {
138
+ if (!this.apiKey) {
139
+ throw new LlmProviderError("LLM provider is not configured.");
140
+ }
141
+ const controller = new AbortController();
142
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
143
+ // Combine the owned timeout controller with the external abort signal
144
+ // so either one aborts the fetch. When no external signal is supplied
145
+ // the owned controller is used directly.
146
+ const combinedSignal = signal
147
+ ? AbortSignal.any([controller.signal, signal])
148
+ : controller.signal;
149
+ try {
150
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
151
+ method: "POST",
152
+ headers: {
153
+ "content-type": "application/json",
154
+ authorization: `Bearer ${this.apiKey}`,
155
+ },
156
+ body: JSON.stringify(body),
157
+ signal: combinedSignal,
158
+ });
159
+ if (!response.ok) {
160
+ throw new LlmProviderError(`LLM request failed with HTTP ${response.status}.`, response.status);
161
+ }
162
+ const json = (await response.json());
163
+ const content = readResponseContent(json);
164
+ if (!content)
165
+ throw new LlmProviderError("LLM response contained no content.");
166
+ return content;
167
+ }
168
+ catch (error) {
169
+ if (error instanceof LlmProviderError)
170
+ throw error;
171
+ if (error instanceof DOMException && error.name === "AbortError") {
172
+ // An external abort must propagate as AbortError (cooperative
173
+ // cancellation); the owned timeout is wrapped as LlmProviderError.
174
+ if (signal?.aborted) {
175
+ throw new DOMException("The operation was aborted.", "AbortError");
176
+ }
177
+ throw new LlmProviderError("LLM request timed out.");
178
+ }
179
+ throw new LlmProviderError(`LLM request failed: ${error instanceof Error ? error.message : String(error)}`);
180
+ }
181
+ finally {
182
+ clearTimeout(timer);
183
+ }
184
+ }
185
+ }
186
+ /**
187
+ * Extract the `choices[0].message.content` string from an OpenAI-shaped
188
+ * chat completion response. Returns `undefined` when the shape does not
189
+ * match.
190
+ *
191
+ * @param value - The parsed JSON response body.
192
+ * @returns The content string, or `undefined`.
193
+ */
194
+ function readResponseContent(value) {
195
+ if (!value || typeof value !== "object")
196
+ return undefined;
197
+ const choices = value.choices;
198
+ if (!Array.isArray(choices) || choices.length === 0)
199
+ return undefined;
200
+ const message = choices[0];
201
+ if (!message || typeof message !== "object")
202
+ return undefined;
203
+ const content = message.message?.content;
204
+ return typeof content === "string" ? content : undefined;
205
+ }
206
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/llm/provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,164 @@
1
+ /**
2
+ * HTTP client for the npm registry API v2.
3
+ *
4
+ * This module provides {@link NpmRegistryClient}, a thin wrapper around the
5
+ * global `fetch` (available in Node 18+) that adds:
6
+ *
7
+ * - **Timeout**: each request is aborted after 10 seconds via an
8
+ * `AbortController`.
9
+ * - **Retry with exponential backoff**: failed requests (network errors or
10
+ * non-2xx responses) are retried up to 3 times with delays of 1s, 2s, and
11
+ * 4s between attempts.
12
+ * - **Compression**: the `Accept-Encoding` header advertises gzip and
13
+ * deflate support.
14
+ * - **User-Agent**: a customisable UA header is sent on every request.
15
+ * - **Typed errors**: non-success responses and unrecoverable failures are
16
+ * surfaced as {@link NpmRegistryError} carrying the HTTP status code and
17
+ * status text.
18
+ *
19
+ * The client intentionally contains **no caching** and **no rate limiting**
20
+ * — those concerns are delegated to dedicated modules layered on top.
21
+ *
22
+ * @module registry/client
23
+ */
24
+ import type { AbbreviatedVersion, PackageMetadata, SearchResult } from './types.js';
25
+ /**
26
+ * HTTP client for the npm registry.
27
+ *
28
+ * Construct an instance once and reuse it across calls — the client holds no
29
+ * per-request mutable state beyond the configured base URL and User-Agent.
30
+ * All public methods are async and return parsed, typed JSON payloads.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * const client = new NpmRegistryClient();
35
+ * const meta = await client.getPackageMetadata('lodash');
36
+ * const manifest = await client.getVersionManifest('lodash', '4.17.21');
37
+ * const hits = await client.searchPackages('security', 10);
38
+ * ```
39
+ */
40
+ export declare class NpmRegistryClient {
41
+ /** Base URL (no trailing slash) prepended to every request path. */
42
+ private readonly baseUrl;
43
+ /** User-Agent header value sent on every request. */
44
+ private readonly userAgent;
45
+ /** Explicit proxy URL from constructor options (highest priority). */
46
+ private readonly proxyUrl?;
47
+ /** Proxy dispatchers keyed by proxy URL, lazily created. */
48
+ private readonly proxyAgents;
49
+ /** Hosts that must bypass the proxy. */
50
+ private readonly noProxyHosts;
51
+ /**
52
+ * @param options - Optional configuration overriding the defaults.
53
+ * @param options.baseUrl - Registry base URL. Defaults to
54
+ * `https://registry.npmjs.org`. A trailing slash is stripped.
55
+ * @param options.userAgent - User-Agent header value. Defaults to a
56
+ * string identifying `@npm-safe/core`.
57
+ * @param options.proxy - Proxy URL (e.g. `http://127.0.0.1:7897`). When
58
+ * omitted, the conventional environment variables are consulted.
59
+ */
60
+ constructor(options?: {
61
+ readonly baseUrl?: string;
62
+ readonly userAgent?: string;
63
+ readonly proxy?: string;
64
+ });
65
+ /**
66
+ * Resolve the fetch `dispatcher` to use for a request URL.
67
+ *
68
+ * Returns `undefined` when no proxy is configured or the hostname is in
69
+ * the `NO_PROXY` list; otherwise returns a lazily created
70
+ * {@link Dispatcher} for the active proxy.
71
+ *
72
+ * @param url - Fully-qualified request URL.
73
+ * @returns A proxy dispatcher, or `undefined` to use the default fetch.
74
+ */
75
+ private getDispatcher;
76
+ /**
77
+ * Fetch the full packument (metadata) for a package.
78
+ *
79
+ * Issues `GET {baseUrl}/{name}` and returns the parsed
80
+ * {@link PackageMetadata} document, which includes all published versions,
81
+ * dist-tags, and the readme.
82
+ *
83
+ * @param name - Package name (scoped names include the leading `@`).
84
+ * @param options - Optional request options. `options.signal` is forwarded
85
+ * to the underlying fetch as part of a combined abort signal; an external
86
+ * abort settles the promise promptly with an `AbortError` `DOMException`
87
+ * (no retry).
88
+ * @returns The full package metadata document.
89
+ * @throws {NpmRegistryError} When the request fails after all retries or
90
+ * the registry returns a non-2xx status.
91
+ * @throws {DOMException} With name `AbortError` when `options.signal` is
92
+ * aborted.
93
+ */
94
+ getPackageMetadata(name: string, options?: {
95
+ readonly signal?: AbortSignal;
96
+ }): Promise<PackageMetadata>;
97
+ /**
98
+ * Fetch the abbreviated packument for a single published version.
99
+ *
100
+ * Issues `GET {baseUrl}/{name}/{version}` and returns the parsed
101
+ * {@link AbbreviatedVersion} manifest.
102
+ *
103
+ * @param name - Package name (scoped names include the leading `@`).
104
+ * @param version - Semver version string (e.g. `4.17.21`).
105
+ * @returns The abbreviated version manifest.
106
+ * @throws {NpmRegistryError} When the request fails after all retries or
107
+ * the registry returns a non-2xx status.
108
+ */
109
+ getVersionManifest(name: string, version: string): Promise<AbbreviatedVersion>;
110
+ /**
111
+ * Search the registry for packages matching a text query.
112
+ *
113
+ * Issues `GET {baseUrl}/-/v1/search?text={query}&size={size}` and returns
114
+ * the array of {@link SearchResult} hits. The `size` parameter caps the
115
+ * number of results (the registry imposes its own upper bound).
116
+ *
117
+ * @param query - Free-text search query.
118
+ * @param options - Optional search options. `options.size` caps the number
119
+ * of results (defaults to 20); `options.signal` is forwarded to the
120
+ * underlying fetch as part of a combined abort signal.
121
+ * @returns An array of search-result hits, ordered by relevance.
122
+ * @throws {NpmRegistryError} When the request fails after all retries or
123
+ * the registry returns a non-2xx status.
124
+ * @throws {DOMException} With name `AbortError` when `options.signal` is
125
+ * aborted.
126
+ */
127
+ searchPackages(query: string, options?: {
128
+ readonly size?: number;
129
+ readonly signal?: AbortSignal;
130
+ }): Promise<SearchResult[]>;
131
+ /**
132
+ * Perform a single HTTP GET against `url` with timeout and retry.
133
+ *
134
+ * The request is retried up to {@link MAX_ATTEMPTS} times with exponential
135
+ * backoff (1s, 2s, 4s). A retry is attempted when:
136
+ *
137
+ * - The fetch rejects (network error, DNS failure, abort due to the owned
138
+ * timeout controller).
139
+ * - The response status is not in the 2xx range.
140
+ *
141
+ * On the final attempt the underlying error (or a new
142
+ * {@link NpmRegistryError} for non-2xx responses) is rethrown.
143
+ *
144
+ * **Cooperative cancellation**: when `options.signal` is supplied it is
145
+ * combined with the per-request timeout controller via `AbortSignal.any`.
146
+ * An external abort (`options.signal` aborted) breaks the retry loop
147
+ * immediately and rethrows `DOMException('The operation was aborted.',
148
+ * 'AbortError')` with NO retry — the abort is never swallowed as a
149
+ * retryable timeout. Only the owned timeout controller keeps the existing
150
+ * wrap-as-`NpmRegistryError` + retry behaviour.
151
+ *
152
+ * @typeParam T - Expected shape of the parsed JSON response.
153
+ * @param url - Fully-qualified URL to fetch.
154
+ * @param options - Optional request options. `options.signal` is an
155
+ * external abort signal forwarded by callers.
156
+ * @returns The parsed JSON response body typed as `T`.
157
+ * @throws {NpmRegistryError} When all attempts are exhausted or the
158
+ * registry returns a non-2xx status on the final attempt.
159
+ * @throws {DOMException} With name `AbortError` when `options.signal` is
160
+ * aborted.
161
+ */
162
+ private request;
163
+ }
164
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/registry/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,YAAY,EACb,MAAM,YAAY,CAAC;AA+GpB;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAiB;IAC5B,oEAAoE;IACpE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,qDAAqD;IACrD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,sEAAsE;IACtE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAS;IACnC,4DAA4D;IAC5D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiC;IAC7D,wCAAwC;IACxC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IAEnD;;;;;;;;OAQG;gBACS,OAAO,CAAC,EAAE;QACpB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;KACzB;IAUD;;;;;;;;;OASG;IACH,OAAO,CAAC,aAAa;IAmBrB;;;;;;;;;;;;;;;;;OAiBG;IACG,kBAAkB,CACtB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAC1C,OAAO,CAAC,eAAe,CAAC;IAO3B;;;;;;;;;;;OAWG;IACG,kBAAkB,CACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,kBAAkB,CAAC;IAM9B;;;;;;;;;;;;;;;;OAgBG;IACG,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAClE,OAAO,CAAC,YAAY,EAAE,CAAC;IAgB1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;YACW,OAAO;CAyGtB"}