@fgv/ts-extras 5.1.0-16 → 5.1.0-18

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 (81) hide show
  1. package/dist/index.browser.js +2 -1
  2. package/dist/packlets/ai-assist/apiClient.js +570 -58
  3. package/dist/packlets/ai-assist/chatRequestBuilders.js +180 -0
  4. package/dist/packlets/ai-assist/index.js +4 -3
  5. package/dist/packlets/ai-assist/model.js +20 -3
  6. package/dist/packlets/ai-assist/registry.js +66 -10
  7. package/dist/packlets/ai-assist/sseParser.js +122 -0
  8. package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +192 -0
  9. package/dist/packlets/ai-assist/streamingAdapters/common.js +77 -0
  10. package/dist/packlets/ai-assist/streamingAdapters/gemini.js +160 -0
  11. package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js +149 -0
  12. package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +163 -0
  13. package/dist/packlets/ai-assist/streamingAdapters/proxy.js +157 -0
  14. package/dist/packlets/ai-assist/streamingClient.js +88 -0
  15. package/dist/packlets/conversion/converters.js +1 -1
  16. package/dist/packlets/crypto-utils/index.browser.js +2 -0
  17. package/dist/packlets/crypto-utils/index.js +2 -0
  18. package/dist/packlets/crypto-utils/keyPairAlgorithmParams.js +47 -0
  19. package/dist/packlets/crypto-utils/keystore/converters.js +101 -9
  20. package/dist/packlets/crypto-utils/keystore/index.js +1 -0
  21. package/dist/packlets/crypto-utils/keystore/keyStore.js +271 -46
  22. package/dist/packlets/crypto-utils/keystore/model.js +22 -1
  23. package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js +21 -0
  24. package/dist/packlets/crypto-utils/model.js +5 -0
  25. package/dist/packlets/crypto-utils/nodeCryptoProvider.js +44 -1
  26. package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js +2 -2
  27. package/dist/test/unit/crypto/keystore/inMemoryPrivateKeyStorage.js +78 -0
  28. package/dist/ts-extras.d.ts +1089 -37
  29. package/lib/index.browser.d.ts +2 -1
  30. package/lib/index.browser.js +3 -1
  31. package/lib/packlets/ai-assist/apiClient.d.ts +103 -1
  32. package/lib/packlets/ai-assist/apiClient.js +574 -58
  33. package/lib/packlets/ai-assist/chatRequestBuilders.d.ts +89 -0
  34. package/lib/packlets/ai-assist/chatRequestBuilders.js +189 -0
  35. package/lib/packlets/ai-assist/index.d.ts +4 -3
  36. package/lib/packlets/ai-assist/index.js +10 -1
  37. package/lib/packlets/ai-assist/model.d.ts +271 -2
  38. package/lib/packlets/ai-assist/model.js +21 -3
  39. package/lib/packlets/ai-assist/registry.d.ts +10 -1
  40. package/lib/packlets/ai-assist/registry.js +67 -11
  41. package/lib/packlets/ai-assist/sseParser.d.ts +45 -0
  42. package/lib/packlets/ai-assist/sseParser.js +127 -0
  43. package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +18 -0
  44. package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +195 -0
  45. package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +71 -0
  46. package/lib/packlets/ai-assist/streamingAdapters/common.js +81 -0
  47. package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts +19 -0
  48. package/lib/packlets/ai-assist/streamingAdapters/gemini.js +163 -0
  49. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts +18 -0
  50. package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js +152 -0
  51. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +19 -0
  52. package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +166 -0
  53. package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts +34 -0
  54. package/lib/packlets/ai-assist/streamingAdapters/proxy.js +160 -0
  55. package/lib/packlets/ai-assist/streamingClient.d.ts +33 -0
  56. package/lib/packlets/ai-assist/streamingClient.js +93 -0
  57. package/lib/packlets/conversion/converters.d.ts +1 -1
  58. package/lib/packlets/conversion/converters.js +1 -1
  59. package/lib/packlets/crypto-utils/index.browser.d.ts +1 -0
  60. package/lib/packlets/crypto-utils/index.browser.js +4 -1
  61. package/lib/packlets/crypto-utils/index.d.ts +1 -0
  62. package/lib/packlets/crypto-utils/index.js +4 -1
  63. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.d.ts +39 -0
  64. package/lib/packlets/crypto-utils/keyPairAlgorithmParams.js +50 -0
  65. package/lib/packlets/crypto-utils/keystore/converters.d.ts +68 -6
  66. package/lib/packlets/crypto-utils/keystore/converters.js +100 -8
  67. package/lib/packlets/crypto-utils/keystore/index.d.ts +1 -0
  68. package/lib/packlets/crypto-utils/keystore/index.js +1 -0
  69. package/lib/packlets/crypto-utils/keystore/keyStore.d.ts +77 -9
  70. package/lib/packlets/crypto-utils/keystore/keyStore.js +271 -46
  71. package/lib/packlets/crypto-utils/keystore/model.d.ts +238 -19
  72. package/lib/packlets/crypto-utils/keystore/model.js +24 -2
  73. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts +50 -0
  74. package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js +22 -0
  75. package/lib/packlets/crypto-utils/model.d.ts +38 -0
  76. package/lib/packlets/crypto-utils/model.js +6 -1
  77. package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts +26 -1
  78. package/lib/packlets/crypto-utils/nodeCryptoProvider.js +43 -0
  79. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts +2 -2
  80. package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js +2 -2
  81. package/package.json +7 -7
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ // Copyright (c) 2026 Erik Fortune
3
+ //
4
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ // of this software and associated documentation files (the "Software"), to deal
6
+ // in the Software without restriction, including without limitation the rights
7
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ // copies of the Software, and to permit persons to whom the Software is
9
+ // furnished to do so, subject to the following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included in all
12
+ // copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ // SOFTWARE.
21
+ var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
22
+ var __asyncValues = (this && this.__asyncValues) || function (o) {
23
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
24
+ var m = o[Symbol.asyncIterator], i;
25
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
26
+ function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
27
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
28
+ };
29
+ var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
30
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
31
+ var g = generator.apply(thisArg, _arguments || []), i, q = [];
32
+ return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
33
+ function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
34
+ function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
35
+ function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
36
+ function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
37
+ function fulfill(value) { resume("next", value); }
38
+ function reject(value) { resume("throw", value); }
39
+ function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.callProxiedCompletionStream = callProxiedCompletionStream;
43
+ /**
44
+ * Streaming adapter for a caller-provided proxy server. Unlike the
45
+ * provider-specific adapters, the proxy speaks our own unified vocabulary
46
+ * directly: each `data:` line is a JSON-serialized {@link AiAssist.IAiStreamEvent},
47
+ * so this adapter only validates the event-type discriminator and forwards.
48
+ *
49
+ * @packageDocumentation
50
+ */
51
+ const ts_utils_1 = require("@fgv/ts-utils");
52
+ const sseParser_1 = require("../sseParser");
53
+ const common_1 = require("./common");
54
+ const proxyEventTypes = ['text-delta', 'tool-event', 'done', 'error'];
55
+ const proxyEventEnvelope = ts_utils_1.Validators.object({
56
+ type: ts_utils_1.Validators.enumeratedValue(proxyEventTypes)
57
+ });
58
+ // ============================================================================
59
+ // Stream translator
60
+ // ============================================================================
61
+ /**
62
+ * Translates a proxied SSE stream back into {@link AiAssist.IAiStreamEvent} objects.
63
+ * Validation is limited to the type discriminator; the proxy is contractually
64
+ * required to emit shape-correct unified events.
65
+ *
66
+ * @internal
67
+ */
68
+ function translateProxyStream(response) {
69
+ return __asyncGenerator(this, arguments, function* translateProxyStream_1() {
70
+ var _a, e_1, _b, _c;
71
+ try {
72
+ /* c8 ignore next - body is non-null at this point per openSseConnection */
73
+ if (!response.body)
74
+ return yield __await(void 0);
75
+ try {
76
+ for (var _d = true, _e = __asyncValues((0, sseParser_1.readSseEvents)(response.body)), _f; _f = yield __await(_e.next()), _a = _f.done, !_a; _d = true) {
77
+ _c = _f.value;
78
+ _d = false;
79
+ const message = _c;
80
+ const json = (0, sseParser_1.parseSseEventJson)(message.data);
81
+ if (json === undefined) {
82
+ continue;
83
+ }
84
+ const envelope = (0, common_1.validateEventPayload)(json, proxyEventEnvelope);
85
+ if (!envelope) {
86
+ continue;
87
+ }
88
+ const event = json;
89
+ yield yield __await(event);
90
+ if (envelope.type === 'done' || envelope.type === 'error') {
91
+ return yield __await(void 0);
92
+ }
93
+ }
94
+ }
95
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
96
+ finally {
97
+ try {
98
+ if (!_d && !_a && (_b = _e.return)) yield __await(_b.call(_e));
99
+ }
100
+ finally { if (e_1) throw e_1.error; }
101
+ }
102
+ }
103
+ catch (err) {
104
+ yield yield __await({ type: 'error', message: err instanceof Error ? err.message : String(err) });
105
+ }
106
+ });
107
+ }
108
+ // ============================================================================
109
+ // Public entry point
110
+ // ============================================================================
111
+ /**
112
+ * Calls the streaming chat endpoint on a proxy server instead of calling
113
+ * the provider directly from the browser.
114
+ *
115
+ * @remarks
116
+ * Proxy contract:
117
+ * - Endpoint: `POST ${proxyUrl}/api/ai/completion-stream`
118
+ * - Request body: same JSON as `/api/ai/completion` plus `"stream": true`
119
+ * - Response: `Content-Type: text/event-stream`; body is the unified
120
+ * {@link AiAssist.IAiStreamEvent} JSON-serialized one event per SSE `data:` line
121
+ * (no `event:` line needed since the type discriminator is in the JSON).
122
+ * - Error response (when the proxy can't even start): JSON `{error: string}`
123
+ * with a non-2xx status, surfaced as `proxy: ${error}`.
124
+ *
125
+ * The proxy server is responsible for opening the upstream SSE connection,
126
+ * translating provider-native events to the unified vocabulary, and
127
+ * forwarding events as they arrive (no buffering). The library does not
128
+ * ship a proxy implementation.
129
+ *
130
+ * @public
131
+ */
132
+ async function callProxiedCompletionStream(proxyUrl, params) {
133
+ const { descriptor, apiKey, prompt, messagesBefore, temperature, modelOverride, logger, tools, signal } = params;
134
+ const promptBody = { system: prompt.system, user: prompt.user };
135
+ if (prompt.attachments.length > 0) {
136
+ promptBody.attachments = prompt.attachments;
137
+ }
138
+ const body = {
139
+ providerId: descriptor.id,
140
+ apiKey,
141
+ prompt: promptBody,
142
+ temperature: temperature !== null && temperature !== void 0 ? temperature : 0.7,
143
+ stream: true
144
+ };
145
+ if (messagesBefore && messagesBefore.length > 0) {
146
+ body.messagesBefore = messagesBefore;
147
+ }
148
+ if (modelOverride !== undefined) {
149
+ body.modelOverride = modelOverride;
150
+ }
151
+ if (tools && tools.length > 0) {
152
+ body.tools = tools;
153
+ }
154
+ /* c8 ignore next 1 - optional logger */
155
+ logger === null || logger === void 0 ? void 0 : logger.info(`AI streaming proxy request: provider=${descriptor.id}, proxy=${proxyUrl}`);
156
+ const url = `${proxyUrl}/api/ai/completion-stream`;
157
+ const conn = await (0, common_1.openSseConnection)(url, {}, body, logger, signal);
158
+ return conn.onSuccess((response) => (0, ts_utils_1.succeed)(translateProxyStream(response)));
159
+ }
160
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Streaming chat completion client. Public façade over the per-format
3
+ * adapters under `streamingAdapters/`: provider dispatch and pre-flight
4
+ * validation live here; format-specific request/translation logic and the
5
+ * typed event-payload validators live with each adapter.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ import { Result } from '@fgv/ts-utils';
10
+ import { type IAiStreamEvent } from './model';
11
+ import { type IProviderCompletionStreamParams } from './streamingAdapters/common';
12
+ export { callProxiedCompletionStream } from './streamingAdapters/proxy';
13
+ export type { IProviderCompletionStreamParams } from './streamingAdapters/common';
14
+ /**
15
+ * Calls the appropriate streaming chat completion API for a given provider.
16
+ *
17
+ * @remarks
18
+ * Pre-flight rejection: when `descriptor.streamingCorsRestricted === true`
19
+ * and the call isn't being routed through a proxy, this returns
20
+ * `Result.fail` before fetch is invoked. Callers should route through
21
+ * {@link AiAssist.callProxiedCompletionStream} or surface the failure to the user.
22
+ *
23
+ * Connection-time failures (auth, network, non-2xx) surface as the outer
24
+ * `Result.fail`. Once iteration begins, errors mid-stream surface as a
25
+ * terminal error event ({@link AiAssist.IAiStreamError}) followed by the iterable
26
+ * ending. The final successful event is {@link AiAssist.IAiStreamDone}.
27
+ *
28
+ * @param params - Request parameters including descriptor, API key, prompt, and optional tools
29
+ * @returns A streaming iterable of unified events, or a Result.fail
30
+ * @public
31
+ */
32
+ export declare function callProviderCompletionStream(params: IProviderCompletionStreamParams): Promise<Result<AsyncIterable<IAiStreamEvent>>>;
33
+ //# sourceMappingURL=streamingClient.d.ts.map
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ // Copyright (c) 2026 Erik Fortune
3
+ //
4
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ // of this software and associated documentation files (the "Software"), to deal
6
+ // in the Software without restriction, including without limitation the rights
7
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ // copies of the Software, and to permit persons to whom the Software is
9
+ // furnished to do so, subject to the following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included in all
12
+ // copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ // SOFTWARE.
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.callProxiedCompletionStream = void 0;
23
+ exports.callProviderCompletionStream = callProviderCompletionStream;
24
+ /**
25
+ * Streaming chat completion client. Public façade over the per-format
26
+ * adapters under `streamingAdapters/`: provider dispatch and pre-flight
27
+ * validation live here; format-specific request/translation logic and the
28
+ * typed event-payload validators live with each adapter.
29
+ *
30
+ * @packageDocumentation
31
+ */
32
+ const ts_utils_1 = require("@fgv/ts-utils");
33
+ const model_1 = require("./model");
34
+ const anthropic_1 = require("./streamingAdapters/anthropic");
35
+ const gemini_1 = require("./streamingAdapters/gemini");
36
+ const openaiChat_1 = require("./streamingAdapters/openaiChat");
37
+ const openaiResponses_1 = require("./streamingAdapters/openaiResponses");
38
+ var proxy_1 = require("./streamingAdapters/proxy");
39
+ Object.defineProperty(exports, "callProxiedCompletionStream", { enumerable: true, get: function () { return proxy_1.callProxiedCompletionStream; } });
40
+ /**
41
+ * Calls the appropriate streaming chat completion API for a given provider.
42
+ *
43
+ * @remarks
44
+ * Pre-flight rejection: when `descriptor.streamingCorsRestricted === true`
45
+ * and the call isn't being routed through a proxy, this returns
46
+ * `Result.fail` before fetch is invoked. Callers should route through
47
+ * {@link AiAssist.callProxiedCompletionStream} or surface the failure to the user.
48
+ *
49
+ * Connection-time failures (auth, network, non-2xx) surface as the outer
50
+ * `Result.fail`. Once iteration begins, errors mid-stream surface as a
51
+ * terminal error event ({@link AiAssist.IAiStreamError}) followed by the iterable
52
+ * ending. The final successful event is {@link AiAssist.IAiStreamDone}.
53
+ *
54
+ * @param params - Request parameters including descriptor, API key, prompt, and optional tools
55
+ * @returns A streaming iterable of unified events, or a Result.fail
56
+ * @public
57
+ */
58
+ async function callProviderCompletionStream(params) {
59
+ const { descriptor, apiKey, prompt, messagesBefore, temperature = 0.7, modelOverride, logger, tools, signal } = params;
60
+ if (!descriptor.baseUrl) {
61
+ return (0, ts_utils_1.fail)(`provider "${descriptor.id}" has no API endpoint configured`);
62
+ }
63
+ if (descriptor.streamingCorsRestricted) {
64
+ return (0, ts_utils_1.fail)(`provider "${descriptor.id}" requires a proxy for streaming; none is configured`);
65
+ }
66
+ if (prompt.attachments.length > 0 && !descriptor.acceptsImageInput) {
67
+ return (0, ts_utils_1.fail)(`provider "${descriptor.id}" does not accept image input`);
68
+ }
69
+ const hasTools = tools !== undefined && tools.length > 0;
70
+ const modelContext = hasTools ? 'tools' : undefined;
71
+ const config = {
72
+ baseUrl: descriptor.baseUrl,
73
+ apiKey,
74
+ model: (0, model_1.resolveModel)(modelOverride !== null && modelOverride !== void 0 ? modelOverride : descriptor.defaultModel, modelContext)
75
+ };
76
+ switch (descriptor.apiFormat) {
77
+ case 'openai':
78
+ if (hasTools) {
79
+ return (0, openaiResponses_1.callOpenAiResponsesStream)(config, prompt, tools, messagesBefore, temperature, logger, signal);
80
+ }
81
+ return (0, openaiChat_1.callOpenAiChatStream)(config, prompt, messagesBefore, temperature, logger, signal);
82
+ case 'anthropic':
83
+ return (0, anthropic_1.callAnthropicStream)(config, prompt, messagesBefore, temperature, tools, logger, signal);
84
+ case 'gemini':
85
+ return (0, gemini_1.callGeminiStream)(config, prompt, messagesBefore, temperature, tools, logger, signal);
86
+ /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */
87
+ default: {
88
+ const _exhaustive = descriptor.apiFormat;
89
+ return (0, ts_utils_1.fail)(`unsupported API format: ${String(_exhaustive)}`);
90
+ }
91
+ }
92
+ }
93
+ //# sourceMappingURL=streamingClient.js.map
@@ -30,7 +30,7 @@ export declare const isoDateTime: Converter<DateTime, unknown>;
30
30
  * If `onError` is `'failOnError'` (default), then the entire conversion fails if any element cannot
31
31
  * be converted. If `onError` is `'ignoreErrors'`, then failing elements are silently ignored.
32
32
  * @param converter - `Converter` used to convert each item in the array
33
- * @param ignoreErrors - Specifies treatment of unconvertible elements
33
+ * @param onError - Specifies treatment of unconvertible elements
34
34
  * @beta
35
35
  */
36
36
  export declare function extendedArrayOf<T, TC = undefined>(label: string, converter: Converter<T, TC>, onError?: Conversion.OnError): Converter<ExtendedArray<T>, TC>;
@@ -111,7 +111,7 @@ exports.isoDateTime = new ts_utils_1.Conversion.BaseConverter((from) => {
111
111
  * If `onError` is `'failOnError'` (default), then the entire conversion fails if any element cannot
112
112
  * be converted. If `onError` is `'ignoreErrors'`, then failing elements are silently ignored.
113
113
  * @param converter - `Converter` used to convert each item in the array
114
- * @param ignoreErrors - Specifies treatment of unconvertible elements
114
+ * @param onError - Specifies treatment of unconvertible elements
115
115
  * @beta
116
116
  */
117
117
  function extendedArrayOf(label, converter, onError = 'failOnError') {
@@ -10,5 +10,6 @@ export { KeyStore };
10
10
  import * as Converters from './converters';
11
11
  export { Converters };
12
12
  export { DirectEncryptionProvider, IDirectEncryptionProviderParams } from './directEncryptionProvider';
13
+ export { IKeyPairAlgorithmParams, keyPairAlgorithmParams } from './keyPairAlgorithmParams';
13
14
  export { createEncryptedFile, decryptFile, fromBase64, ICreateEncryptedFileParams, toBase64, tryDecryptFile } from './encryptedFile';
14
15
  //# sourceMappingURL=index.browser.d.ts.map
@@ -55,7 +55,7 @@ var __importStar = (this && this.__importStar) || (function () {
55
55
  };
56
56
  })();
57
57
  Object.defineProperty(exports, "__esModule", { value: true });
58
- exports.tryDecryptFile = exports.toBase64 = exports.fromBase64 = exports.decryptFile = exports.createEncryptedFile = exports.DirectEncryptionProvider = exports.Converters = exports.KeyStore = exports.GCM_IV_SIZE = exports.GCM_AUTH_TAG_SIZE = exports.ENCRYPTED_FILE_FORMAT = exports.DEFAULT_ALGORITHM = exports.AES_256_KEY_SIZE = void 0;
58
+ exports.tryDecryptFile = exports.toBase64 = exports.fromBase64 = exports.decryptFile = exports.createEncryptedFile = exports.keyPairAlgorithmParams = exports.DirectEncryptionProvider = exports.Converters = exports.KeyStore = exports.GCM_IV_SIZE = exports.GCM_AUTH_TAG_SIZE = exports.ENCRYPTED_FILE_FORMAT = exports.DEFAULT_ALGORITHM = exports.AES_256_KEY_SIZE = void 0;
59
59
  /**
60
60
  * Crypto utilities for encrypted file handling and key management (browser version).
61
61
  * Note: For browser crypto provider, use \@fgv/ts-web-extras.
@@ -79,6 +79,9 @@ exports.Converters = Converters;
79
79
  // Direct encryption provider
80
80
  var directEncryptionProvider_1 = require("./directEncryptionProvider");
81
81
  Object.defineProperty(exports, "DirectEncryptionProvider", { enumerable: true, get: function () { return directEncryptionProvider_1.DirectEncryptionProvider; } });
82
+ // WebCrypto parameter table for asymmetric keypair algorithms
83
+ var keyPairAlgorithmParams_1 = require("./keyPairAlgorithmParams");
84
+ Object.defineProperty(exports, "keyPairAlgorithmParams", { enumerable: true, get: function () { return keyPairAlgorithmParams_1.keyPairAlgorithmParams; } });
82
85
  // Note: NodeCryptoProvider is NOT exported in browser version
83
86
  // Use BrowserCryptoProvider from @fgv/ts-web-extras instead
84
87
  // Encrypted file helpers
@@ -10,6 +10,7 @@ export { KeyStore };
10
10
  import * as Converters from './converters';
11
11
  export { Converters };
12
12
  export { DirectEncryptionProvider, IDirectEncryptionProviderParams } from './directEncryptionProvider';
13
+ export { IKeyPairAlgorithmParams, keyPairAlgorithmParams } from './keyPairAlgorithmParams';
13
14
  export { NodeCryptoProvider, nodeCryptoProvider } from './nodeCryptoProvider';
14
15
  export { createEncryptedFile, decryptFile, fromBase64, ICreateEncryptedFileParams, toBase64, tryDecryptFile } from './encryptedFile';
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -55,7 +55,7 @@ var __importStar = (this && this.__importStar) || (function () {
55
55
  };
56
56
  })();
57
57
  Object.defineProperty(exports, "__esModule", { value: true });
58
- exports.tryDecryptFile = exports.toBase64 = exports.fromBase64 = exports.decryptFile = exports.createEncryptedFile = exports.nodeCryptoProvider = exports.NodeCryptoProvider = exports.DirectEncryptionProvider = exports.Converters = exports.KeyStore = exports.Constants = void 0;
58
+ exports.tryDecryptFile = exports.toBase64 = exports.fromBase64 = exports.decryptFile = exports.createEncryptedFile = exports.nodeCryptoProvider = exports.NodeCryptoProvider = exports.keyPairAlgorithmParams = exports.DirectEncryptionProvider = exports.Converters = exports.KeyStore = exports.Constants = void 0;
59
59
  /**
60
60
  * Crypto utilities for encrypted file handling and key management.
61
61
  * @packageDocumentation
@@ -74,6 +74,9 @@ exports.Converters = Converters;
74
74
  // Direct encryption provider
75
75
  var directEncryptionProvider_1 = require("./directEncryptionProvider");
76
76
  Object.defineProperty(exports, "DirectEncryptionProvider", { enumerable: true, get: function () { return directEncryptionProvider_1.DirectEncryptionProvider; } });
77
+ // WebCrypto parameter table for asymmetric keypair algorithms
78
+ var keyPairAlgorithmParams_1 = require("./keyPairAlgorithmParams");
79
+ Object.defineProperty(exports, "keyPairAlgorithmParams", { enumerable: true, get: function () { return keyPairAlgorithmParams_1.keyPairAlgorithmParams; } });
77
80
  // Node.js crypto provider (Node.js environment only)
78
81
  var nodeCryptoProvider_1 = require("./nodeCryptoProvider");
79
82
  Object.defineProperty(exports, "NodeCryptoProvider", { enumerable: true, get: function () { return nodeCryptoProvider_1.NodeCryptoProvider; } });
@@ -0,0 +1,39 @@
1
+ import { KeyPairAlgorithm } from './model';
2
+ /**
3
+ * WebCrypto parameters for a single {@link CryptoUtils.KeyPairAlgorithm}.
4
+ * Implementations of {@link CryptoUtils.ICryptoProvider} use this table to
5
+ * translate the small public algorithm enum into the WebCrypto algorithm
6
+ * objects and key-usage arrays expected by `crypto.subtle`.
7
+ * @public
8
+ */
9
+ export interface IKeyPairAlgorithmParams {
10
+ /**
11
+ * Algorithm parameters for `crypto.subtle.generateKey`. Always an asymmetric
12
+ * variant — these algorithms produce a `CryptoKeyPair`, not a single key.
13
+ */
14
+ readonly generateKey: RsaHashedKeyGenParams | EcKeyGenParams;
15
+ /**
16
+ * Algorithm parameters for `crypto.subtle.importKey('jwk', ...)` when
17
+ * importing the public half of a keypair.
18
+ */
19
+ readonly importPublicKey: RsaHashedImportParams | EcKeyImportParams;
20
+ /**
21
+ * Default key usages for the generated `CryptoKeyPair`. Both halves receive
22
+ * the usages WebCrypto considers valid for their role; the platform filters.
23
+ */
24
+ readonly keyPairUsages: ReadonlyArray<KeyUsage>;
25
+ /**
26
+ * Key usages applied when re-importing only the public key.
27
+ */
28
+ readonly publicKeyUsages: ReadonlyArray<KeyUsage>;
29
+ }
30
+ /**
31
+ * Lookup table from {@link CryptoUtils.KeyPairAlgorithm} to the WebCrypto
32
+ * parameters needed to drive `crypto.subtle`. Shared between every
33
+ * {@link CryptoUtils.ICryptoProvider} implementation since both Node and
34
+ * browser providers speak the same WebCrypto API. Exposed for downstream
35
+ * provider implementations (e.g. browser-side providers in `@fgv/ts-web-extras`).
36
+ * @public
37
+ */
38
+ export declare const keyPairAlgorithmParams: Readonly<Record<KeyPairAlgorithm, IKeyPairAlgorithmParams>>;
39
+ //# sourceMappingURL=keyPairAlgorithmParams.d.ts.map
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ // Copyright (c) 2026 Erik Fortune
3
+ //
4
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ // of this software and associated documentation files (the "Software"), to deal
6
+ // in the Software without restriction, including without limitation the rights
7
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ // copies of the Software, and to permit persons to whom the Software is
9
+ // furnished to do so, subject to the following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included in all
12
+ // copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ // SOFTWARE.
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.keyPairAlgorithmParams = void 0;
23
+ /**
24
+ * Lookup table from {@link CryptoUtils.KeyPairAlgorithm} to the WebCrypto
25
+ * parameters needed to drive `crypto.subtle`. Shared between every
26
+ * {@link CryptoUtils.ICryptoProvider} implementation since both Node and
27
+ * browser providers speak the same WebCrypto API. Exposed for downstream
28
+ * provider implementations (e.g. browser-side providers in `@fgv/ts-web-extras`).
29
+ * @public
30
+ */
31
+ exports.keyPairAlgorithmParams = {
32
+ 'ecdsa-p256': {
33
+ generateKey: { name: 'ECDSA', namedCurve: 'P-256' },
34
+ importPublicKey: { name: 'ECDSA', namedCurve: 'P-256' },
35
+ keyPairUsages: ['sign', 'verify'],
36
+ publicKeyUsages: ['verify']
37
+ },
38
+ 'rsa-oaep-2048': {
39
+ generateKey: {
40
+ name: 'RSA-OAEP',
41
+ modulusLength: 2048,
42
+ publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
43
+ hash: 'SHA-256'
44
+ },
45
+ importPublicKey: { name: 'RSA-OAEP', hash: 'SHA-256' },
46
+ keyPairUsages: ['encrypt', 'decrypt'],
47
+ publicKeyUsages: ['encrypt']
48
+ }
49
+ };
50
+ //# sourceMappingURL=keyPairAlgorithmParams.js.map
@@ -1,21 +1,83 @@
1
- import { Converter } from '@fgv/ts-utils';
2
- import { IKeyStoreFile, IKeyStoreSecretEntryJson, IKeyStoreVaultContents, KeyStoreFormat, KeyStoreSecretType } from './model';
1
+ import { Converter, Validator } from '@fgv/ts-utils';
2
+ import { IKeyStoreAsymmetricEntryJson, IKeyStoreEntryJson, IKeyStoreFile, IKeyStoreSymmetricEntryJson, IKeyStoreVaultContents, KeyPairAlgorithm, KeyStoreAsymmetricSecretType, KeyStoreFormat, KeyStoreSecretType, KeyStoreSymmetricSecretType } from './model';
3
3
  /**
4
4
  * Converter for {@link CryptoUtils.KeyStore.KeyStoreFormat | key store format} version.
5
5
  * @public
6
6
  */
7
7
  export declare const keystoreFormat: Converter<KeyStoreFormat>;
8
8
  /**
9
- * Converter for {@link CryptoUtils.KeyStore.KeyStoreSecretType | key store secret type} discriminator.
9
+ * Converter for {@link CryptoUtils.KeyStore.KeyStoreSecretType | any key store secret type} discriminator.
10
+ * Accepts both symmetric and asymmetric type values.
10
11
  * @public
11
12
  */
12
13
  export declare const keystoreSecretType: Converter<KeyStoreSecretType>;
13
14
  /**
14
- * Converter for {@link CryptoUtils.KeyStore.IKeyStoreSecretEntryJson | key store secret entry} in JSON format.
15
- * The `type` field is optional for backwards compatibility — missing means `'encryption-key'`.
15
+ * Converter for {@link CryptoUtils.KeyStore.KeyStoreSymmetricSecretType | symmetric secret type} discriminator.
16
+ * Accepts only `'encryption-key'` and `'api-key'`.
16
17
  * @public
17
18
  */
18
- export declare const keystoreSecretEntryJson: Converter<IKeyStoreSecretEntryJson>;
19
+ export declare const keystoreSymmetricSecretType: Converter<KeyStoreSymmetricSecretType>;
20
+ /**
21
+ * Converter for {@link CryptoUtils.KeyStore.KeyStoreAsymmetricSecretType | asymmetric secret type} discriminator.
22
+ * Accepts only `'asymmetric-keypair'`.
23
+ * @public
24
+ */
25
+ export declare const keystoreAsymmetricSecretType: Converter<KeyStoreAsymmetricSecretType>;
26
+ /**
27
+ * Converter for {@link CryptoUtils.KeyStore.KeyPairAlgorithm | key pair algorithm}.
28
+ * @public
29
+ */
30
+ export declare const keyPairAlgorithm: Converter<KeyPairAlgorithm>;
31
+ /**
32
+ * In-place shape check for a JSON Web Key. Asserts only that the input is a
33
+ * non-array object whose `kty` discriminator is a string; every other JWK
34
+ * field passes through untouched. This is intentionally **not** a true JWK
35
+ * validator — per-algorithm correctness (RSA `n`/`e`, EC `crv`/`x`/`y`,
36
+ * key-size constraints, etc.) is delegated to `crypto.subtle.importKey` at
37
+ * first use, which is the authoritative checker. The "shape" suffix in the
38
+ * name is the warning sign for readers expecting full validation.
39
+ * @remarks
40
+ * Built with `Validators.object` (in-place, non-strict) so unknown JWK fields
41
+ * survive the round-trip; the cast to `FieldValidators<JsonWebKey>` is required
42
+ * only because TypeScript's mapped type demands an entry for every key in
43
+ * `JsonWebKey`. At runtime the `ObjectValidator` only inspects keys present in
44
+ * the field-validators map.
45
+ * @public
46
+ */
47
+ export declare const jsonWebKeyShape: Validator<JsonWebKey>;
48
+ /**
49
+ * Converter for {@link CryptoUtils.KeyStore.IKeyStoreSymmetricEntryJson | symmetric secret entry} in JSON form.
50
+ *
51
+ * @remarks
52
+ * Backwards compatibility with vaults written before asymmetric-keypair
53
+ * support: those entries may lack the `type` discriminator on the wire. To
54
+ * keep the model type honest (`type` is required on
55
+ * {@link CryptoUtils.KeyStore.IKeyStoreSymmetricEntryJson}, see its docs),
56
+ * we declare `type` in `optionalFields` so the inner `Converters.object` will
57
+ * accept input without it, then `.map()` injects the default
58
+ * `'encryption-key'` when missing. The output therefore always carries the
59
+ * discriminator and downstream code never sees the legacy missing-type form.
60
+ *
61
+ * @public
62
+ */
63
+ export declare const keystoreSymmetricEntryJson: Converter<IKeyStoreSymmetricEntryJson>;
64
+ /**
65
+ * Converter for {@link CryptoUtils.KeyStore.IKeyStoreAsymmetricEntryJson | asymmetric keypair entry} in JSON form.
66
+ * The `publicKeyJwk` field passes through {@link CryptoUtils.KeyStore.Converters.jsonWebKeyShape | jsonWebKeyShape}
67
+ * (shape check only — see its docs); cryptographic correctness is enforced by
68
+ * `crypto.subtle.importKey` at use.
69
+ * @public
70
+ */
71
+ export declare const keystoreAsymmetricEntryJson: Converter<IKeyStoreAsymmetricEntryJson>;
72
+ /**
73
+ * Discriminated-union converter for any {@link CryptoUtils.KeyStore.IKeyStoreEntryJson | key store entry} in JSON form.
74
+ * Routes by the `type` field: `'asymmetric-keypair'` is parsed by
75
+ * {@link CryptoUtils.KeyStore.Converters.keystoreAsymmetricEntryJson | keystoreAsymmetricEntryJson},
76
+ * anything else (including a missing `type` field for backwards compatibility) by
77
+ * {@link CryptoUtils.KeyStore.Converters.keystoreSymmetricEntryJson | keystoreSymmetricEntryJson}.
78
+ * @public
79
+ */
80
+ export declare const keystoreSecretEntryJson: Converter<IKeyStoreEntryJson>;
19
81
  /**
20
82
  * Converter for {@link CryptoUtils.KeyStore.IKeyStoreVaultContents | key store vault contents} (decrypted state).
21
83
  * @public