@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,42 @@
1
+ /**
2
+ * SQLite DDL schema and migration helpers for @npm-safe/core.
3
+ *
4
+ * This module is a pure SQL-string + types module. It MUST NOT import or
5
+ * execute better-sqlite3; consumers (e.g. the store layer) are responsible
6
+ * for running the SQL through `Database#prepare().run()`.
7
+ */
8
+ /**
9
+ * Full DDL for the core database. Contains 6 application tables plus the
10
+ * `_migrations` bookkeeping table used by the migration runner.
11
+ *
12
+ * Tables:
13
+ * 1. packages - cached npm package metadata
14
+ * 2. package_versions - per-version info
15
+ * 3. security_reports - scan results (static + llm)
16
+ * 4. watchlist - user-tracked packages
17
+ * 5. settings - key-value configuration
18
+ * 6. translations - cached translation results
19
+ * 7. _migrations - migration tracking (internal)
20
+ */
21
+ export declare const SCHEMA_SQL = "\n-- 1. packages table - cached npm package metadata\nCREATE TABLE IF NOT EXISTS packages (\n name TEXT PRIMARY KEY,\n latest_version TEXT NOT NULL,\n description TEXT DEFAULT '',\n homepage TEXT DEFAULT '',\n repository TEXT DEFAULT '',\n registry_data TEXT DEFAULT '{}', -- JSON blob of raw registry response\n cached_at TEXT NOT NULL DEFAULT (datetime('now')),\n ttl_until TEXT NOT NULL -- cache expiry timestamp\n);\n\n-- 2. package_versions table - version info\nCREATE TABLE IF NOT EXISTS package_versions (\n package_name TEXT NOT NULL REFERENCES packages(name) ON DELETE CASCADE,\n version TEXT NOT NULL,\n publish_time TEXT,\n has_readme INTEGER NOT NULL DEFAULT 0,\n integrity TEXT,\n PRIMARY KEY (package_name, version)\n);\n\n-- 3. security_reports table - scan results\nCREATE TABLE IF NOT EXISTS security_reports (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n package_name TEXT NOT NULL REFERENCES packages(name) ON DELETE CASCADE,\n version TEXT NOT NULL,\n scan_type TEXT NOT NULL CHECK(scan_type IN ('static', 'llm')),\n overall_score INTEGER NOT NULL CHECK(overall_score >= 0 AND overall_score <= 100),\n findings_json TEXT DEFAULT '[]', -- JSON array of ScanFinding objects\n summary TEXT DEFAULT '',\n scanned_at TEXT NOT NULL DEFAULT (datetime('now')),\n UNIQUE(package_name, version, scan_type)\n);\n\n-- 4. watchlist table - user-tracked packages\nCREATE TABLE IF NOT EXISTS watchlist (\n package_name TEXT PRIMARY KEY REFERENCES packages(name) ON DELETE CASCADE,\n added_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\n-- 5. settings table - key-value configuration\nCREATE TABLE IF NOT EXISTS settings (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n\n-- 6. translations table - cached translations\nCREATE TABLE IF NOT EXISTS translations (\n source_hash TEXT PRIMARY KEY,\n source_text TEXT NOT NULL,\n target_lang TEXT NOT NULL,\n translated_text TEXT NOT NULL,\n provider TEXT NOT NULL,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\nCREATE INDEX IF NOT EXISTS idx_translations_lang ON translations(target_lang);\n\n-- 7. _migrations table - migration tracking\nCREATE TABLE IF NOT EXISTS _migrations (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT NOT NULL UNIQUE,\n applied_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n";
22
+ /**
23
+ * Returns ordered list of migration file names to apply.
24
+ *
25
+ * Migrations are applied in order; each name must be unique. The initial
26
+ * migration (`001_initial.sql`) is expected to create every table in
27
+ * {@link SCHEMA_SQL} via {@link getInitialMigration}.
28
+ */
29
+ export declare function getMigrationList(): string[];
30
+ /**
31
+ * Returns the SQL for the `check_history` migration: a table recording every
32
+ * check performed by the CLI or the desktop extension so the GUI can load
33
+ * history straight from the shared database.
34
+ */
35
+ export declare function getCheckHistoryMigration(): string;
36
+ /**
37
+ * Returns the SQL for the initial migration. This is the same DDL as
38
+ * {@link SCHEMA_SQL}, wrapped for the migration system so the runner can
39
+ * record it under the `001_initial.sql` name.
40
+ */
41
+ export declare function getInitialMigration(): string;
42
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/store/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,67EAiEtB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAK3C;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAYjD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * SQLite DDL schema and migration helpers for @npm-safe/core.
3
+ *
4
+ * This module is a pure SQL-string + types module. It MUST NOT import or
5
+ * execute better-sqlite3; consumers (e.g. the store layer) are responsible
6
+ * for running the SQL through `Database#prepare().run()`.
7
+ */
8
+ /**
9
+ * Full DDL for the core database. Contains 6 application tables plus the
10
+ * `_migrations` bookkeeping table used by the migration runner.
11
+ *
12
+ * Tables:
13
+ * 1. packages - cached npm package metadata
14
+ * 2. package_versions - per-version info
15
+ * 3. security_reports - scan results (static + llm)
16
+ * 4. watchlist - user-tracked packages
17
+ * 5. settings - key-value configuration
18
+ * 6. translations - cached translation results
19
+ * 7. _migrations - migration tracking (internal)
20
+ */
21
+ export const SCHEMA_SQL = `
22
+ -- 1. packages table - cached npm package metadata
23
+ CREATE TABLE IF NOT EXISTS packages (
24
+ name TEXT PRIMARY KEY,
25
+ latest_version TEXT NOT NULL,
26
+ description TEXT DEFAULT '',
27
+ homepage TEXT DEFAULT '',
28
+ repository TEXT DEFAULT '',
29
+ registry_data TEXT DEFAULT '{}', -- JSON blob of raw registry response
30
+ cached_at TEXT NOT NULL DEFAULT (datetime('now')),
31
+ ttl_until TEXT NOT NULL -- cache expiry timestamp
32
+ );
33
+
34
+ -- 2. package_versions table - version info
35
+ CREATE TABLE IF NOT EXISTS package_versions (
36
+ package_name TEXT NOT NULL REFERENCES packages(name) ON DELETE CASCADE,
37
+ version TEXT NOT NULL,
38
+ publish_time TEXT,
39
+ has_readme INTEGER NOT NULL DEFAULT 0,
40
+ integrity TEXT,
41
+ PRIMARY KEY (package_name, version)
42
+ );
43
+
44
+ -- 3. security_reports table - scan results
45
+ CREATE TABLE IF NOT EXISTS security_reports (
46
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
47
+ package_name TEXT NOT NULL REFERENCES packages(name) ON DELETE CASCADE,
48
+ version TEXT NOT NULL,
49
+ scan_type TEXT NOT NULL CHECK(scan_type IN ('static', 'llm')),
50
+ overall_score INTEGER NOT NULL CHECK(overall_score >= 0 AND overall_score <= 100),
51
+ findings_json TEXT DEFAULT '[]', -- JSON array of ScanFinding objects
52
+ summary TEXT DEFAULT '',
53
+ scanned_at TEXT NOT NULL DEFAULT (datetime('now')),
54
+ UNIQUE(package_name, version, scan_type)
55
+ );
56
+
57
+ -- 4. watchlist table - user-tracked packages
58
+ CREATE TABLE IF NOT EXISTS watchlist (
59
+ package_name TEXT PRIMARY KEY REFERENCES packages(name) ON DELETE CASCADE,
60
+ added_at TEXT NOT NULL DEFAULT (datetime('now'))
61
+ );
62
+
63
+ -- 5. settings table - key-value configuration
64
+ CREATE TABLE IF NOT EXISTS settings (
65
+ key TEXT PRIMARY KEY,
66
+ value TEXT NOT NULL
67
+ );
68
+
69
+ -- 6. translations table - cached translations
70
+ CREATE TABLE IF NOT EXISTS translations (
71
+ source_hash TEXT PRIMARY KEY,
72
+ source_text TEXT NOT NULL,
73
+ target_lang TEXT NOT NULL,
74
+ translated_text TEXT NOT NULL,
75
+ provider TEXT NOT NULL,
76
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
77
+ );
78
+ CREATE INDEX IF NOT EXISTS idx_translations_lang ON translations(target_lang);
79
+
80
+ -- 7. _migrations table - migration tracking
81
+ CREATE TABLE IF NOT EXISTS _migrations (
82
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
83
+ name TEXT NOT NULL UNIQUE,
84
+ applied_at TEXT NOT NULL DEFAULT (datetime('now'))
85
+ );
86
+ `;
87
+ /**
88
+ * Returns ordered list of migration file names to apply.
89
+ *
90
+ * Migrations are applied in order; each name must be unique. The initial
91
+ * migration (`001_initial.sql`) is expected to create every table in
92
+ * {@link SCHEMA_SQL} via {@link getInitialMigration}.
93
+ */
94
+ export function getMigrationList() {
95
+ return [
96
+ '001_initial.sql',
97
+ '002_check_history.sql',
98
+ ];
99
+ }
100
+ /**
101
+ * Returns the SQL for the `check_history` migration: a table recording every
102
+ * check performed by the CLI or the desktop extension so the GUI can load
103
+ * history straight from the shared database.
104
+ */
105
+ export function getCheckHistoryMigration() {
106
+ return `
107
+ -- 8. check_history table - persistent check history
108
+ CREATE TABLE IF NOT EXISTS check_history (
109
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
110
+ package_name TEXT NOT NULL,
111
+ level TEXT NOT NULL,
112
+ score INTEGER NOT NULL CHECK(score >= 0 AND score <= 100),
113
+ timestamp TEXT NOT NULL
114
+ );
115
+ CREATE INDEX IF NOT EXISTS idx_check_history_timestamp ON check_history(timestamp DESC);
116
+ `;
117
+ }
118
+ /**
119
+ * Returns the SQL for the initial migration. This is the same DDL as
120
+ * {@link SCHEMA_SQL}, wrapped for the migration system so the runner can
121
+ * record it under the `001_initial.sql` name.
122
+ */
123
+ export function getInitialMigration() {
124
+ return SCHEMA_SQL;
125
+ }
126
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/store/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiEzB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL,iBAAiB;QACjB,uBAAuB;KACxB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO;;;;;;;;;;CAUR,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Translator provider interface and adapter skeletons for @npm-safe/core.
3
+ *
4
+ * This module defines the {@link TranslatorProvider} interface that all
5
+ * translation backends must implement, together with skeleton adapters for
6
+ * DeepL and OpenAI-compatible APIs. The skeletons are ready for Phase 5
7
+ * integration — they validate credentials but throw
8
+ * {@link ProviderNotConfigured} or {@link TranslationError} with a "not yet
9
+ * implemented" message instead of making actual API calls.
10
+ *
11
+ * @module translator/provider
12
+ */
13
+ import { TranslationResult, TranslatorConfig } from './types.js';
14
+ /**
15
+ * Interface that every translation provider adapter must implement.
16
+ *
17
+ * Adapters are stateless beyond their configuration (API key, base URL,
18
+ * model) and may be shared across requests.
19
+ */
20
+ export interface TranslatorProvider {
21
+ /** Human-readable name of the provider (e.g. `'DeepL'`, `'OpenAI'`). */
22
+ readonly name: string;
23
+ /**
24
+ * Translate text from a source language to a target language.
25
+ *
26
+ * @param text - The text to translate.
27
+ * @param targetLang - Target language code (e.g. `'zh-CN'`, `'fr'`).
28
+ * @param sourceLang - Optional source language code. When omitted the
29
+ * provider may auto-detect the source language.
30
+ * @returns A promise resolving to the translation result.
31
+ * @throws {ProviderNotConfigured} When the provider has no API key.
32
+ * @throws {TranslationError} When the request fails at the network or
33
+ * provider level.
34
+ */
35
+ translate(text: string, targetLang: string, sourceLang?: string): Promise<TranslationResult>;
36
+ /**
37
+ * Verify that the provider is reachable and the configured credentials
38
+ * are valid.
39
+ *
40
+ * @returns A promise resolving to `true` when the connection succeeds,
41
+ * `false` when the provider is not configured.
42
+ * @throws {TranslationError} When the connection test fails at the
43
+ * network or provider level.
44
+ */
45
+ testConnection(): Promise<boolean>;
46
+ }
47
+ /**
48
+ * Adapter for the DeepL translation API.
49
+ *
50
+ * This is a skeleton implementation for Phase 5. Construction requires an
51
+ * optional `apiKey`; without one, both {@link DeepLAdapter.translate} and
52
+ * {@link DeepLAdapter.testConnection} throw {@link ProviderNotConfigured}.
53
+ * With a key they throw {@link TranslationError} with a "not yet implemented"
54
+ * message.
55
+ */
56
+ export declare class DeepLAdapter implements TranslatorProvider {
57
+ readonly name = "DeepL";
58
+ private readonly apiKey?;
59
+ private readonly baseUrl;
60
+ /**
61
+ * @param config.apiKey - DeepL API key (optional; required at call time).
62
+ * @param config.baseUrl - DeepL API base URL. Defaults to the free-tier
63
+ * endpoint `https://api-free.deepl.com`.
64
+ */
65
+ constructor(config: {
66
+ apiKey?: string;
67
+ baseUrl?: string;
68
+ });
69
+ /**
70
+ * Translate text via DeepL.
71
+ *
72
+ * Phase 5: This method will POST to `${this.baseUrl}/v2/translate` with
73
+ * an `Authorization: DeepL-Auth-Key ${this.apiKey}` header.
74
+ *
75
+ * @param text - Text to translate.
76
+ * @param targetLang - Target language code.
77
+ * @param sourceLang - Optional source language code.
78
+ * @throws {ProviderNotConfigured} When no API key has been provided.
79
+ * @throws {TranslationError} Always — implementation is deferred to Phase 5.
80
+ */
81
+ translate(text: string, targetLang: string, sourceLang?: string): Promise<TranslationResult>;
82
+ /**
83
+ * Test the connection to the DeepL API.
84
+ *
85
+ * @returns `false` when no API key is configured (no test attempted).
86
+ * @throws {TranslationError} Always when an API key is present —
87
+ * implementation is deferred to Phase 5.
88
+ */
89
+ testConnection(): Promise<boolean>;
90
+ }
91
+ /**
92
+ * Adapter for OpenAI-compatible chat completion APIs used for translation.
93
+ *
94
+ * This is a skeleton implementation for Phase 5. Construction requires an
95
+ * optional `apiKey`; without one, both {@link OpenAIAdapter.translate} and
96
+ * {@link OpenAIAdapter.testConnection} throw {@link ProviderNotConfigured}.
97
+ * With a key they throw {@link TranslationError} with a "not yet implemented"
98
+ * message.
99
+ */
100
+ export declare class OpenAIAdapter implements TranslatorProvider {
101
+ readonly name = "OpenAI";
102
+ private readonly apiKey?;
103
+ private readonly baseUrl;
104
+ private readonly model;
105
+ /**
106
+ * @param config.apiKey - OpenAI API key (optional; required at call time).
107
+ * @param config.baseUrl - OpenAI API base URL. Defaults to
108
+ * `https://api.openai.com/v1`.
109
+ * @param config.model - Model identifier for chat completions. Defaults to
110
+ * `gpt-4o-mini`.
111
+ */
112
+ constructor(config: {
113
+ apiKey?: string;
114
+ baseUrl?: string;
115
+ model?: string;
116
+ });
117
+ /**
118
+ * Translate text via an OpenAI-compatible chat completion API.
119
+ *
120
+ * Phase 5: This method will POST to `${this.baseUrl}/chat/completions`
121
+ * with a system prompt instructing the model to translate, sending the
122
+ * given text as the user message.
123
+ *
124
+ * @param text - Text to translate.
125
+ * @param targetLang - Target language code.
126
+ * @param sourceLang - Optional source language code (passed as context
127
+ * to the model; not used for auto-detection since LLMs do not return
128
+ * a detected language).
129
+ * @throws {ProviderNotConfigured} When no API key has been provided.
130
+ * @throws {TranslationError} Always — implementation is deferred to Phase 5.
131
+ */
132
+ translate(text: string, targetLang: string, sourceLang?: string): Promise<TranslationResult>;
133
+ /**
134
+ * Test the connection to the OpenAI API.
135
+ *
136
+ * @returns `false` when no API key is configured (no test attempted).
137
+ * @throws {TranslationError} Always when an API key is present —
138
+ * implementation is deferred to Phase 5.
139
+ */
140
+ testConnection(): Promise<boolean>;
141
+ }
142
+ /**
143
+ * Create a translator provider instance from a configuration object.
144
+ *
145
+ * @param config - Complete translator configuration including the target
146
+ * provider type and any required credentials.
147
+ * @returns A provider adapter instance matching the configured type.
148
+ * @throws {TranslationError} When the requested provider type is
149
+ * `LibreTranslate` (not yet implemented).
150
+ */
151
+ export declare function createTranslator(config: TranslatorConfig): TranslatorProvider;
152
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/translator/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAIjB,MAAM,YAAY,CAAC;AAEpB;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;;;;;;;;;OAWG;IACH,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAE9B;;;;;;;;OAQG;IACH,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CACpC;AAED;;;;;;;;GAQG;AACH,qBAAa,YAAa,YAAW,kBAAkB;IACrD,QAAQ,CAAC,IAAI,WAAW;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC;;;;OAIG;gBACS,MAAM,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;IAKzD;;;;;;;;;;;OAWG;IACG,SAAS,CACb,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;;;;OAMG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAQzC;AAED;;;;;;;;GAQG;AACH,qBAAa,aAAc,YAAW,kBAAkB;IACtD,QAAQ,CAAC,IAAI,YAAY;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B;;;;;;OAMG;gBACS,MAAM,EAAE;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB;IAMD;;;;;;;;;;;;;;OAcG;IACG,SAAS,CACb,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC;IAe7B;;;;;;OAMG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAQzC;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,kBAAkB,CAmB7E"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Translator provider interface and adapter skeletons for @npm-safe/core.
3
+ *
4
+ * This module defines the {@link TranslatorProvider} interface that all
5
+ * translation backends must implement, together with skeleton adapters for
6
+ * DeepL and OpenAI-compatible APIs. The skeletons are ready for Phase 5
7
+ * integration — they validate credentials but throw
8
+ * {@link ProviderNotConfigured} or {@link TranslationError} with a "not yet
9
+ * implemented" message instead of making actual API calls.
10
+ *
11
+ * @module translator/provider
12
+ */
13
+ import { TranslatorProviderType, ProviderNotConfigured, TranslationError, } from './types.js';
14
+ /**
15
+ * Adapter for the DeepL translation API.
16
+ *
17
+ * This is a skeleton implementation for Phase 5. Construction requires an
18
+ * optional `apiKey`; without one, both {@link DeepLAdapter.translate} and
19
+ * {@link DeepLAdapter.testConnection} throw {@link ProviderNotConfigured}.
20
+ * With a key they throw {@link TranslationError} with a "not yet implemented"
21
+ * message.
22
+ */
23
+ export class DeepLAdapter {
24
+ name = 'DeepL';
25
+ apiKey;
26
+ baseUrl;
27
+ /**
28
+ * @param config.apiKey - DeepL API key (optional; required at call time).
29
+ * @param config.baseUrl - DeepL API base URL. Defaults to the free-tier
30
+ * endpoint `https://api-free.deepl.com`.
31
+ */
32
+ constructor(config) {
33
+ this.apiKey = config.apiKey;
34
+ this.baseUrl = config.baseUrl ?? 'https://api-free.deepl.com';
35
+ }
36
+ /**
37
+ * Translate text via DeepL.
38
+ *
39
+ * Phase 5: This method will POST to `${this.baseUrl}/v2/translate` with
40
+ * an `Authorization: DeepL-Auth-Key ${this.apiKey}` header.
41
+ *
42
+ * @param text - Text to translate.
43
+ * @param targetLang - Target language code.
44
+ * @param sourceLang - Optional source language code.
45
+ * @throws {ProviderNotConfigured} When no API key has been provided.
46
+ * @throws {TranslationError} Always — implementation is deferred to Phase 5.
47
+ */
48
+ async translate(text, targetLang, sourceLang) {
49
+ if (!this.apiKey) {
50
+ throw new ProviderNotConfigured('DeepL', 'No API key provided. Configure it in Settings.');
51
+ }
52
+ // Phase 5: Implement actual API call
53
+ // POST ${this.baseUrl}/v2/translate with Authorization: DeepL-Auth-Key ${this.apiKey}
54
+ throw new TranslationError('DeepL translation not yet implemented', 'DeepL');
55
+ }
56
+ /**
57
+ * Test the connection to the DeepL API.
58
+ *
59
+ * @returns `false` when no API key is configured (no test attempted).
60
+ * @throws {TranslationError} Always when an API key is present —
61
+ * implementation is deferred to Phase 5.
62
+ */
63
+ async testConnection() {
64
+ if (!this.apiKey)
65
+ return false;
66
+ // Phase 5: Implement actual connection test
67
+ throw new TranslationError('DeepL testConnection not yet implemented', 'DeepL');
68
+ }
69
+ }
70
+ /**
71
+ * Adapter for OpenAI-compatible chat completion APIs used for translation.
72
+ *
73
+ * This is a skeleton implementation for Phase 5. Construction requires an
74
+ * optional `apiKey`; without one, both {@link OpenAIAdapter.translate} and
75
+ * {@link OpenAIAdapter.testConnection} throw {@link ProviderNotConfigured}.
76
+ * With a key they throw {@link TranslationError} with a "not yet implemented"
77
+ * message.
78
+ */
79
+ export class OpenAIAdapter {
80
+ name = 'OpenAI';
81
+ apiKey;
82
+ baseUrl;
83
+ model;
84
+ /**
85
+ * @param config.apiKey - OpenAI API key (optional; required at call time).
86
+ * @param config.baseUrl - OpenAI API base URL. Defaults to
87
+ * `https://api.openai.com/v1`.
88
+ * @param config.model - Model identifier for chat completions. Defaults to
89
+ * `gpt-4o-mini`.
90
+ */
91
+ constructor(config) {
92
+ this.apiKey = config.apiKey;
93
+ this.baseUrl = config.baseUrl ?? 'https://api.openai.com/v1';
94
+ this.model = config.model ?? 'gpt-4o-mini';
95
+ }
96
+ /**
97
+ * Translate text via an OpenAI-compatible chat completion API.
98
+ *
99
+ * Phase 5: This method will POST to `${this.baseUrl}/chat/completions`
100
+ * with a system prompt instructing the model to translate, sending the
101
+ * given text as the user message.
102
+ *
103
+ * @param text - Text to translate.
104
+ * @param targetLang - Target language code.
105
+ * @param sourceLang - Optional source language code (passed as context
106
+ * to the model; not used for auto-detection since LLMs do not return
107
+ * a detected language).
108
+ * @throws {ProviderNotConfigured} When no API key has been provided.
109
+ * @throws {TranslationError} Always — implementation is deferred to Phase 5.
110
+ */
111
+ async translate(text, targetLang, sourceLang) {
112
+ if (!this.apiKey) {
113
+ throw new ProviderNotConfigured('OpenAI', 'No API key provided. Configure it in Settings.');
114
+ }
115
+ // Phase 5: Implement actual API call
116
+ // POST ${this.baseUrl}/chat/completions with system prompt for translation
117
+ throw new TranslationError('OpenAI translation not yet implemented', 'OpenAI');
118
+ }
119
+ /**
120
+ * Test the connection to the OpenAI API.
121
+ *
122
+ * @returns `false` when no API key is configured (no test attempted).
123
+ * @throws {TranslationError} Always when an API key is present —
124
+ * implementation is deferred to Phase 5.
125
+ */
126
+ async testConnection() {
127
+ if (!this.apiKey)
128
+ return false;
129
+ // Phase 5: Implement actual connection test
130
+ throw new TranslationError('OpenAI testConnection not yet implemented', 'OpenAI');
131
+ }
132
+ }
133
+ /**
134
+ * Create a translator provider instance from a configuration object.
135
+ *
136
+ * @param config - Complete translator configuration including the target
137
+ * provider type and any required credentials.
138
+ * @returns A provider adapter instance matching the configured type.
139
+ * @throws {TranslationError} When the requested provider type is
140
+ * `LibreTranslate` (not yet implemented).
141
+ */
142
+ export function createTranslator(config) {
143
+ switch (config.provider) {
144
+ case TranslatorProviderType.DeepL:
145
+ return new DeepLAdapter({
146
+ apiKey: config.apiKey,
147
+ baseUrl: config.baseUrl,
148
+ });
149
+ case TranslatorProviderType.OpenAI:
150
+ return new OpenAIAdapter({
151
+ apiKey: config.apiKey,
152
+ baseUrl: config.baseUrl,
153
+ model: config.model,
154
+ });
155
+ case TranslatorProviderType.LibreTranslate:
156
+ throw new TranslationError('LibreTranslate support not yet implemented', 'LibreTranslate');
157
+ }
158
+ }
159
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/translator/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAGL,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AA0CpB;;;;;;;;GAQG;AACH,MAAM,OAAO,YAAY;IACd,IAAI,GAAG,OAAO,CAAC;IACP,MAAM,CAAU;IAChB,OAAO,CAAS;IAEjC;;;;OAIG;IACH,YAAY,MAA6C;QACvD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAC5B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,4BAA4B,CAAC;IAChE,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,SAAS,CACb,IAAY,EACZ,UAAkB,EAClB,UAAmB;QAEnB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,qBAAqB,CAC7B,OAAO,EACP,gDAAgD,CACjD,CAAC;QACJ,CAAC;QACD,qCAAqC;QACrC,sFAAsF;QACtF,MAAM,IAAI,gBAAgB,CAAC,uCAAuC,EAAE,OAAO,CAAC,CAAC;IAC/E,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,cAAc;QAClB,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC/B,4CAA4C;QAC5C,MAAM,IAAI,gBAAgB,CACxB,0CAA0C,EAC1C,OAAO,CACR,CAAC;IACJ,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,aAAa;IACf,IAAI,GAAG,QAAQ,CAAC;IACR,MAAM,CAAU;IAChB,OAAO,CAAS;IAChB,KAAK,CAAS;IAE/B;;;;;;OAMG;IACH,YAAY,MAIX;QACC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAC5B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,2BAA2B,CAAC;QAC7D,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,aAAa,CAAC;IAC7C,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,SAAS,CACb,IAAY,EACZ,UAAkB,EAClB,UAAmB;QAEnB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,qBAAqB,CAC7B,QAAQ,EACR,gDAAgD,CACjD,CAAC;QACJ,CAAC;QACD,qCAAqC;QACrC,2EAA2E;QAC3E,MAAM,IAAI,gBAAgB,CACxB,wCAAwC,EACxC,QAAQ,CACT,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,cAAc;QAClB,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC/B,4CAA4C;QAC5C,MAAM,IAAI,gBAAgB,CACxB,2CAA2C,EAC3C,QAAQ,CACT,CAAC;IACJ,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAwB;IACvD,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,sBAAsB,CAAC,KAAK;YAC/B,OAAO,IAAI,YAAY,CAAC;gBACtB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC,CAAC;QACL,KAAK,sBAAsB,CAAC,MAAM;YAChC,OAAO,IAAI,aAAa,CAAC;gBACvB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,KAAK,EAAE,MAAM,CAAC,KAAK;aACpB,CAAC,CAAC;QACL,KAAK,sBAAsB,CAAC,cAAc;YACxC,MAAM,IAAI,gBAAgB,CACxB,4CAA4C,EAC5C,gBAAgB,CACjB,CAAC;IACN,CAAC;AACH,CAAC"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Type definitions for the translator provider system.
3
+ *
4
+ * This module defines the provider enumeration, configuration schemas,
5
+ * result types, and typed error classes used by the translator adapters
6
+ * defined in {@link ./provider.ts}.
7
+ *
8
+ * @module translator/types
9
+ */
10
+ /**
11
+ * Supported translation provider backends.
12
+ *
13
+ * Each enum member corresponds to a concrete adapter implementation in
14
+ * {@link ../translator/provider.ts}.
15
+ */
16
+ export declare enum TranslatorProviderType {
17
+ /** DeepL translation API (api-free.deepl.com or api.deepl.com). */
18
+ DeepL = "deepL",
19
+ /** OpenAI-compatible chat completion API for translation. */
20
+ OpenAI = "openAI",
21
+ /** Self-hosted LibreTranslate instance. */
22
+ LibreTranslate = "libreTranslate"
23
+ }
24
+ /**
25
+ * Result of a translation request.
26
+ */
27
+ export interface TranslationResult {
28
+ /** The translated text in the target language. */
29
+ readonly translatedText: string;
30
+ /**
31
+ * Language code of the source text as detected by the provider, if the
32
+ * provider supports automatic source-language detection.
33
+ */
34
+ readonly detectedSourceLang?: string;
35
+ /** Usage metering information, if reported by the provider. */
36
+ readonly usage?: {
37
+ /** Number of characters billed for the request. */
38
+ readonly characters: number;
39
+ };
40
+ }
41
+ /**
42
+ * Configuration for initialising a translator provider adapter.
43
+ */
44
+ export interface TranslatorConfig {
45
+ /** Which backend provider to use. */
46
+ readonly provider: TranslatorProviderType;
47
+ /** API key for the provider. May be omitted if the provider is configured
48
+ * elsewhere (e.g. environment variables) or does not require one. */
49
+ readonly apiKey?: string;
50
+ /** Base URL of the provider's API endpoint. Defaults are specific to each
51
+ * adapter. */
52
+ readonly baseUrl?: string;
53
+ /** Model identifier, used only by OpenAI-compatible providers. */
54
+ readonly model?: string;
55
+ /** Default target language code (e.g. `'zh-CN'`, `'fr'`). */
56
+ readonly targetLang: string;
57
+ }
58
+ /**
59
+ * Error thrown when a translator provider was selected but not configured
60
+ * with the required credentials.
61
+ */
62
+ export declare class ProviderNotConfigured extends Error {
63
+ /**
64
+ * @param provider - Human-readable provider name (e.g. `'DeepL'`).
65
+ * @param reason - Explanation of what configuration is missing.
66
+ */
67
+ constructor(provider: string, reason: string);
68
+ }
69
+ /**
70
+ * Error thrown when a translation request fails at the network or provider
71
+ * level (timeout, non-2xx response, malformed reply, etc.).
72
+ */
73
+ export declare class TranslationError extends Error {
74
+ readonly provider: string;
75
+ readonly statusCode?: number | undefined;
76
+ /**
77
+ * @param message - Human-readable error description.
78
+ * @param provider - Name of the provider that produced the error.
79
+ * @param statusCode - HTTP status code from the provider, if applicable.
80
+ */
81
+ constructor(message: string, provider: string, statusCode?: number | undefined);
82
+ }
83
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/translator/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;GAKG;AACH,oBAAY,sBAAsB;IAChC,mEAAmE;IACnE,KAAK,UAAU;IACf,6DAA6D;IAC7D,MAAM,WAAW;IACjB,2CAA2C;IAC3C,cAAc,mBAAmB;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,+DAA+D;IAC/D,QAAQ,CAAC,KAAK,CAAC,EAAE;QACf,mDAAmD;QACnD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;KAC7B,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C;0EACsE;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;mBACe;IACf,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C;;;OAGG;gBACS,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAI7C;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;aAQvB,QAAQ,EAAE,MAAM;aAChB,UAAU,CAAC,EAAE,MAAM;IARrC;;;;OAIG;gBAED,OAAO,EAAE,MAAM,EACC,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,YAAA;CAKtC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Type definitions for the translator provider system.
3
+ *
4
+ * This module defines the provider enumeration, configuration schemas,
5
+ * result types, and typed error classes used by the translator adapters
6
+ * defined in {@link ./provider.ts}.
7
+ *
8
+ * @module translator/types
9
+ */
10
+ /**
11
+ * Supported translation provider backends.
12
+ *
13
+ * Each enum member corresponds to a concrete adapter implementation in
14
+ * {@link ../translator/provider.ts}.
15
+ */
16
+ export var TranslatorProviderType;
17
+ (function (TranslatorProviderType) {
18
+ /** DeepL translation API (api-free.deepl.com or api.deepl.com). */
19
+ TranslatorProviderType["DeepL"] = "deepL";
20
+ /** OpenAI-compatible chat completion API for translation. */
21
+ TranslatorProviderType["OpenAI"] = "openAI";
22
+ /** Self-hosted LibreTranslate instance. */
23
+ TranslatorProviderType["LibreTranslate"] = "libreTranslate";
24
+ })(TranslatorProviderType || (TranslatorProviderType = {}));
25
+ /**
26
+ * Error thrown when a translator provider was selected but not configured
27
+ * with the required credentials.
28
+ */
29
+ export class ProviderNotConfigured extends Error {
30
+ /**
31
+ * @param provider - Human-readable provider name (e.g. `'DeepL'`).
32
+ * @param reason - Explanation of what configuration is missing.
33
+ */
34
+ constructor(provider, reason) {
35
+ super(`Translator provider "${provider}" is not configured: ${reason}`);
36
+ this.name = 'ProviderNotConfigured';
37
+ }
38
+ }
39
+ /**
40
+ * Error thrown when a translation request fails at the network or provider
41
+ * level (timeout, non-2xx response, malformed reply, etc.).
42
+ */
43
+ export class TranslationError extends Error {
44
+ provider;
45
+ statusCode;
46
+ /**
47
+ * @param message - Human-readable error description.
48
+ * @param provider - Name of the provider that produced the error.
49
+ * @param statusCode - HTTP status code from the provider, if applicable.
50
+ */
51
+ constructor(message, provider, statusCode) {
52
+ super(message);
53
+ this.provider = provider;
54
+ this.statusCode = statusCode;
55
+ this.name = 'TranslationError';
56
+ }
57
+ }
58
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/translator/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;GAKG;AACH,MAAM,CAAN,IAAY,sBAOX;AAPD,WAAY,sBAAsB;IAChC,mEAAmE;IACnE,yCAAe,CAAA;IACf,6DAA6D;IAC7D,2CAAiB,CAAA;IACjB,2CAA2C;IAC3C,2DAAiC,CAAA;AACnC,CAAC,EAPW,sBAAsB,KAAtB,sBAAsB,QAOjC;AAsCD;;;GAGG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9C;;;OAGG;IACH,YAAY,QAAgB,EAAE,MAAc;QAC1C,KAAK,CAAC,wBAAwB,QAAQ,wBAAwB,MAAM,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAQvB;IACA;IARlB;;;;OAIG;IACH,YACE,OAAe,EACC,QAAgB,EAChB,UAAmB;QAEnC,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,aAAQ,GAAR,QAAQ,CAAQ;QAChB,eAAU,GAAV,UAAU,CAAS;QAGnC,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF"}