@fgv/ts-extras 5.1.0-42 → 5.1.0-44
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.
- package/dist/packlets/ai-assist/model.js.map +1 -1
- package/dist/packlets/ai-assist/registry.js +22 -18
- package/dist/packlets/ai-assist/registry.js.map +1 -1
- package/dist/packlets/crypto-utils/index.browser.js +1 -1
- package/dist/packlets/crypto-utils/index.browser.js.map +1 -1
- package/dist/packlets/crypto-utils/index.js +1 -1
- package/dist/packlets/crypto-utils/index.js.map +1 -1
- package/dist/packlets/crypto-utils/keystore/converters.js +8 -4
- package/dist/packlets/crypto-utils/keystore/converters.js.map +1 -1
- package/dist/packlets/crypto-utils/keystore/keyStore.js +101 -2
- package/dist/packlets/crypto-utils/keystore/keyStore.js.map +1 -1
- package/dist/packlets/crypto-utils/keystore/model.js +9 -4
- package/dist/packlets/crypto-utils/keystore/model.js.map +1 -1
- package/dist/packlets/crypto-utils/model.js.map +1 -1
- package/dist/packlets/crypto-utils/seedDerivedKeyPair.js +51 -38
- package/dist/packlets/crypto-utils/seedDerivedKeyPair.js.map +1 -1
- package/dist/packlets/crypto-utils/spkiHelpers.js +44 -0
- package/dist/packlets/crypto-utils/spkiHelpers.js.map +1 -1
- package/dist/ts-extras.d.ts +220 -38
- package/lib/packlets/ai-assist/model.d.ts +9 -8
- package/lib/packlets/ai-assist/model.d.ts.map +1 -1
- package/lib/packlets/ai-assist/model.js.map +1 -1
- package/lib/packlets/ai-assist/registry.d.ts.map +1 -1
- package/lib/packlets/ai-assist/registry.js +22 -18
- package/lib/packlets/ai-assist/registry.js.map +1 -1
- package/lib/packlets/crypto-utils/index.browser.d.ts +1 -1
- package/lib/packlets/crypto-utils/index.browser.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/index.browser.js +3 -1
- package/lib/packlets/crypto-utils/index.browser.js.map +1 -1
- package/lib/packlets/crypto-utils/index.d.ts +1 -1
- package/lib/packlets/crypto-utils/index.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/index.js +3 -1
- package/lib/packlets/crypto-utils/index.js.map +1 -1
- package/lib/packlets/crypto-utils/keystore/converters.d.ts +1 -1
- package/lib/packlets/crypto-utils/keystore/converters.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/keystore/converters.js +8 -4
- package/lib/packlets/crypto-utils/keystore/converters.js.map +1 -1
- package/lib/packlets/crypto-utils/keystore/keyStore.d.ts +45 -1
- package/lib/packlets/crypto-utils/keystore/keyStore.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/keystore/keyStore.js +101 -2
- package/lib/packlets/crypto-utils/keystore/keyStore.js.map +1 -1
- package/lib/packlets/crypto-utils/keystore/model.d.ts +57 -3
- package/lib/packlets/crypto-utils/keystore/model.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/keystore/model.js +9 -4
- package/lib/packlets/crypto-utils/keystore/model.js.map +1 -1
- package/lib/packlets/crypto-utils/model.d.ts +65 -20
- package/lib/packlets/crypto-utils/model.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/model.js.map +1 -1
- package/lib/packlets/crypto-utils/seedDerivedKeyPair.d.ts +11 -6
- package/lib/packlets/crypto-utils/seedDerivedKeyPair.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/seedDerivedKeyPair.js +51 -38
- package/lib/packlets/crypto-utils/seedDerivedKeyPair.js.map +1 -1
- package/lib/packlets/crypto-utils/spkiHelpers.d.ts +26 -0
- package/lib/packlets/crypto-utils/spkiHelpers.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/spkiHelpers.js +46 -0
- package/lib/packlets/crypto-utils/spkiHelpers.js.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spkiHelpers.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/spkiHelpers.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport { Result, fail, succeed } from '@fgv/ts-utils';\nimport { ICryptoProvider, KeyPairAlgorithm, MultibaseSpkiPublicKey } from './model';\n\n/**\n * Shared shape check for a base64url (no-padding) body: only base64url alphabet\n * characters (`A-Z`, `a-z`, `0-9`, `-`, `_`) and a length that is never `% 4 === 1`\n * (an impossible base64 remainder). Factored so the decoder and the\n * {@link isValidMultibaseSpkiPublicKey} guard agree on exactly one rule.\n */\nfunction isBase64UrlNoPadBody(body: string): boolean {\n return /^[A-Za-z0-9_-]*$/.test(body) && body.length % 4 !== 1;\n}\n\n/**\n * Encodes a `Uint8Array` as a base64url (no-padding) string (RFC 4648 §5).\n *\n * The body uses the base64url alphabet (`+` → `-`, `/` → `_`) and trailing `=`\n * padding is stripped. This is the bare primitive with no multibase prefix; use\n * {@link CryptoUtils.multibaseBase64UrlEncode} when a multibase-`'m'`-prefixed value is required.\n *\n * @param data - The binary data to encode.\n * @returns The base64url-no-pad string.\n * @public\n */\nexport function base64UrlNoPadEncode(data: Uint8Array): string {\n let base64: string;\n if (typeof Buffer !== 'undefined') {\n base64 = Buffer.from(data).toString('base64');\n /* c8 ignore start - browser-only: btoa path not available in Node tests */\n } else {\n let binary = '';\n for (let i = 0; i < data.length; i++) {\n binary += String.fromCharCode(data[i]);\n }\n base64 = btoa(binary);\n }\n /* c8 ignore stop */\n // Convert to base64url: + → -, / → _, strip = padding\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * Decodes a base64url (no-padding) string (RFC 4648 §5) back to a `Uint8Array`.\n *\n * This is the bare primitive with no multibase prefix; use\n * {@link CryptoUtils.multibaseBase64UrlDecode} to decode a multibase-`'m'`-prefixed value.\n *\n * @param encoded - The base64url-no-pad body to decode.\n * @returns `Success` with the decoded bytes, or `Failure` with error context.\n * @public\n */\nexport function base64UrlNoPadDecode(encoded: string): Result<Uint8Array> {\n if (!isBase64UrlNoPadBody(encoded)) {\n return fail(`base64UrlNoPadDecode: malformed base64url body`);\n }\n // Convert base64url back to standard base64 and restore padding\n const base64 = encoded.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);\n try {\n let bytes: Uint8Array;\n if (typeof Buffer !== 'undefined') {\n bytes = new Uint8Array(Buffer.from(padded, 'base64'));\n /* c8 ignore start - browser-only: atob path not available in Node tests */\n } else {\n const binary = atob(padded);\n bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n }\n /* c8 ignore stop */\n return succeed(bytes);\n /* c8 ignore next 3 - defensive: shape check above prevents invalid chars from reaching here */\n } catch {\n return fail(`base64UrlNoPadDecode: malformed base64url body`);\n }\n}\n\n/**\n * The structural *shape* of a {@link CryptoUtils.MultibaseSpkiPublicKey}: the\n * multibase `'m'` prefix followed by a non-empty base64url-no-pad body\n * (`A-Z`, `a-z`, `0-9`, `-`, `_`).\n *\n * This is a shape prefilter, not full validation: it does not decode the DER\n * SPKI or verify the key material or algorithm (that happens in\n * {@link CryptoUtils.importPublicKeyFromMultibaseSpki}). The authoritative guard\n * is {@link CryptoUtils.isValidMultibaseSpkiPublicKey}, which enforces this\n * pattern **and** additionally rejects a body whose length is an impossible\n * base64 remainder. Exposed for callers that need the pattern directly (e.g. a\n * JSON-schema `pattern` field); prefer the guard/converter for validation.\n *\n * @public\n */\nexport const MultibaseSpkiPublicKeyRegExp: RegExp = /^m[A-Za-z0-9_-]+$/;\n\n/**\n * Type guard for {@link CryptoUtils.MultibaseSpkiPublicKey}: a string matching\n * {@link CryptoUtils.MultibaseSpkiPublicKeyRegExp} (multibase `'m'` prefix + a\n * non-empty base64url-no-pad body) whose body also satisfies the base64url-no-pad\n * length rule shared with {@link CryptoUtils.base64UrlNoPadDecode}. This is a\n * structural *shape* check, not full validation — it does not decode the DER SPKI\n * or verify the key material/algorithm (a malformed-but-well-shaped string fails\n * later, with clear context, in {@link CryptoUtils.importPublicKeyFromMultibaseSpki}).\n *\n * @param value - The value to test.\n * @returns `true` if `value` is a well-formed multibase SPKI public key string.\n * @public\n */\nexport function isValidMultibaseSpkiPublicKey(value: unknown): value is MultibaseSpkiPublicKey {\n return (\n typeof value === 'string' &&\n MultibaseSpkiPublicKeyRegExp.test(value) &&\n isBase64UrlNoPadBody(value.slice(1))\n );\n}\n\n/**\n * Encodes a `Uint8Array` as a multibase base64url (no-padding) string.\n *\n * The multibase prefix `'m'` identifies the encoding as RFC 4648 base64url\n * without padding. The body uses base64url alphabet: `+` → `-`, `/` → `_`,\n * and trailing `=` padding is stripped.\n *\n * @param data - The binary data to encode.\n * @returns A multibase-prefixed base64url string (`'m' + base64url-no-pad`).\n * @public\n */\nexport function multibaseBase64UrlEncode(data: Uint8Array): string {\n return 'm' + base64UrlNoPadEncode(data);\n}\n\n/**\n * Decodes a multibase base64url (no-padding) string back to a `Uint8Array`.\n *\n * Validates that the first character is `'m'` (the multibase prefix for\n * RFC 4648 base64url without padding), then decodes the remaining body.\n *\n * @param encoded - A multibase-prefixed base64url string.\n * @returns `Success` with the decoded bytes, or `Failure` with error context.\n * @public\n */\nexport function multibaseBase64UrlDecode(encoded: string): Result<Uint8Array> {\n if (!encoded.startsWith('m')) {\n return fail(\n `multibaseBase64UrlDecode: invalid multibase prefix '${\n encoded[0] ?? '(empty)'\n }' — expected 'm' (base64url)`\n );\n }\n // Intentionally pin the exact original message (the delegate has a single failure\n // mode) to keep this established public function byte-for-byte behavior-preserving\n // after the extract-and-delegate refactor — do not \"fix\" this into composing the\n // delegate's message without updating the delegation-equivalence tests.\n return base64UrlNoPadDecode(encoded.slice(1)).withErrorFormat(\n () => `multibaseBase64UrlDecode: malformed base64url body`\n );\n}\n\n/**\n * Exports a public `CryptoKey` as a multibase base64url-encoded SPKI blob.\n *\n * The SPKI (SubjectPublicKeyInfo) format is the standard DER-encoded structure\n * for public keys defined in RFC 5280, RFC 5480, and RFC 8410. It is\n * algorithm-agnostic and suitable for storage and transmission.\n *\n * @param key - The `CryptoKey` to export. Must have `key.type === 'public'`.\n * @param provider - The {@link CryptoUtils.ICryptoProvider} to use for the export operation.\n * @returns `Success` with the multibase SPKI string, or `Failure` with error context.\n * @public\n */\nexport async function exportPublicKeyAsMultibaseSpki(\n key: CryptoKey,\n provider: ICryptoProvider\n): Promise<Result<MultibaseSpkiPublicKey>> {\n return (await provider.exportPublicKeySpki(key))\n .withErrorFormat((e) => `exportPublicKeyAsMultibaseSpki: ${e}`)\n .onSuccess((buf) =>\n // The output is a freshly-built valid multibase SPKI string (`'m'` prefix +\n // base64url-no-pad body), so brand it at the construction site — no re-validation needed.\n succeed(multibaseBase64UrlEncode(buf) as MultibaseSpkiPublicKey)\n );\n}\n\n/**\n * Imports a public key from a multibase base64url-encoded SPKI blob.\n *\n * Decodes the multibase prefix, decodes the base64url body, then uses\n * the provider to import the key with the algorithm parameters from\n * {@link CryptoUtils.keyPairAlgorithmParams}.\n *\n * Accepts a plain `string` (not only a branded {@link CryptoUtils.MultibaseSpkiPublicKey}),\n * so callers holding an unbranded value read from storage or the wire can import\n * it directly; a malformed value fails with error context rather than throwing.\n *\n * @param encoded - A multibase SPKI string produced by {@link CryptoUtils.exportPublicKeyAsMultibaseSpki}.\n * @param algorithm - The {@link CryptoUtils.KeyPairAlgorithm} the key was generated for.\n * @param provider - The {@link CryptoUtils.ICryptoProvider} to use for the import operation.\n * @returns `Success` with the imported public `CryptoKey`, or `Failure` with error context.\n * @public\n */\nexport async function importPublicKeyFromMultibaseSpki(\n encoded: string,\n algorithm: KeyPairAlgorithm,\n provider: ICryptoProvider\n): Promise<Result<CryptoKey>> {\n const decodeResult = multibaseBase64UrlDecode(encoded);\n if (decodeResult.isFailure()) {\n return fail(`importPublicKeyFromMultibaseSpki: ${decodeResult.message}`);\n }\n return (await provider.importPublicKeySpki(decodeResult.value, algorithm)).withErrorFormat(\n (e) => `importPublicKeyFromMultibaseSpki: ${e}`\n );\n}\n\n// DER prefix for an X25519 SubjectPublicKeyInfo: SEQUENCE { SEQUENCE { OID id-X25519 }, BIT STRING }.\n// SEQUENCE(42) / SEQUENCE(5) / OID 1.3.101.110 (id-X25519) / BIT STRING(33, 0 unused bits).\nconst _X25519_SPKI_PREFIX: ReadonlyArray<number> = [\n 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00\n];\nconst _X25519_SPKI_LENGTH: number = _X25519_SPKI_PREFIX.length + 32;\n\n/**\n * Strips the fixed DER prefix from an X25519 SubjectPublicKeyInfo blob, returning the raw\n * 32-byte public key.\n *\n * An X25519 SPKI is always exactly 44 bytes: a fixed 12-byte prefix (SEQUENCE / AlgorithmIdentifier\n * with OID 1.3.101.110 / BIT STRING) followed by the 32-byte raw key. Use this to convert a\n * SPKI-held recipient public key into the raw form accepted by {@link HpkeProvider.openBase}'s\n * `recipientPublicKey` parameter.\n *\n * @param spki - The DER-encoded X25519 SubjectPublicKeyInfo bytes.\n * @returns `Success` with the raw 32-byte public key, or `Failure` if `spki` is not a\n * well-formed 44-byte X25519 SPKI blob.\n * @public\n */\nexport function spkiToRawX25519(spki: Uint8Array): Result<Uint8Array> {\n if (spki.length !== _X25519_SPKI_LENGTH) {\n return fail(`spkiToRawX25519: expected ${_X25519_SPKI_LENGTH} bytes, got ${spki.length}`);\n }\n for (let i = 0; i < _X25519_SPKI_PREFIX.length; i++) {\n if (spki[i] !== _X25519_SPKI_PREFIX[i]) {\n return fail(`spkiToRawX25519: byte ${i} does not match the expected X25519 SPKI prefix`);\n }\n }\n return succeed(spki.slice(_X25519_SPKI_PREFIX.length));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"spkiHelpers.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/spkiHelpers.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport { Result, fail, succeed } from '@fgv/ts-utils';\nimport { ICryptoProvider, KeyPairAlgorithm, MultibaseSpkiPublicKey } from './model';\n\n/**\n * Shared shape check for a base64url (no-padding) body: only base64url alphabet\n * characters (`A-Z`, `a-z`, `0-9`, `-`, `_`) and a length that is never `% 4 === 1`\n * (an impossible base64 remainder). Factored so the decoder and the\n * {@link isValidMultibaseSpkiPublicKey} guard agree on exactly one rule.\n */\nfunction isBase64UrlNoPadBody(body: string): boolean {\n return /^[A-Za-z0-9_-]*$/.test(body) && body.length % 4 !== 1;\n}\n\n/**\n * Encodes a `Uint8Array` as a base64url (no-padding) string (RFC 4648 §5).\n *\n * The body uses the base64url alphabet (`+` → `-`, `/` → `_`) and trailing `=`\n * padding is stripped. This is the bare primitive with no multibase prefix; use\n * {@link CryptoUtils.multibaseBase64UrlEncode} when a multibase-`'m'`-prefixed value is required.\n *\n * @param data - The binary data to encode.\n * @returns The base64url-no-pad string.\n * @public\n */\nexport function base64UrlNoPadEncode(data: Uint8Array): string {\n let base64: string;\n if (typeof Buffer !== 'undefined') {\n base64 = Buffer.from(data).toString('base64');\n /* c8 ignore start - browser-only: btoa path not available in Node tests */\n } else {\n let binary = '';\n for (let i = 0; i < data.length; i++) {\n binary += String.fromCharCode(data[i]);\n }\n base64 = btoa(binary);\n }\n /* c8 ignore stop */\n // Convert to base64url: + → -, / → _, strip = padding\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * Decodes a base64url (no-padding) string (RFC 4648 §5) back to a `Uint8Array`.\n *\n * This is the bare primitive with no multibase prefix; use\n * {@link CryptoUtils.multibaseBase64UrlDecode} to decode a multibase-`'m'`-prefixed value.\n *\n * @param encoded - The base64url-no-pad body to decode.\n * @returns `Success` with the decoded bytes, or `Failure` with error context.\n * @public\n */\nexport function base64UrlNoPadDecode(encoded: string): Result<Uint8Array> {\n if (!isBase64UrlNoPadBody(encoded)) {\n return fail(`base64UrlNoPadDecode: malformed base64url body`);\n }\n // Convert base64url back to standard base64 and restore padding\n const base64 = encoded.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);\n try {\n let bytes: Uint8Array;\n if (typeof Buffer !== 'undefined') {\n bytes = new Uint8Array(Buffer.from(padded, 'base64'));\n /* c8 ignore start - browser-only: atob path not available in Node tests */\n } else {\n const binary = atob(padded);\n bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n }\n /* c8 ignore stop */\n return succeed(bytes);\n /* c8 ignore next 3 - defensive: shape check above prevents invalid chars from reaching here */\n } catch {\n return fail(`base64UrlNoPadDecode: malformed base64url body`);\n }\n}\n\n/**\n * Encodes a `Uint8Array` as a lowercase hexadecimal string with no `0x` prefix.\n *\n * Each byte becomes exactly two lowercase hex characters (zero-padded), so an\n * `n`-byte input yields a `2n`-character string. An empty input yields the empty\n * string. This is the inverse of {@link CryptoUtils.hexDecode}.\n *\n * @param data - The binary data to encode.\n * @returns The lowercase, unprefixed hex string.\n * @public\n */\nexport function hexEncode(data: Uint8Array): string {\n let hex = '';\n for (let i = 0; i < data.length; i++) {\n hex += data[i].toString(16).padStart(2, '0');\n }\n return hex;\n}\n\n/**\n * Decodes a hexadecimal string (no `0x` prefix) back to a `Uint8Array`.\n *\n * Liberal in what it accepts: both lowercase and uppercase hex digits are\n * allowed (whereas {@link CryptoUtils.hexEncode} always emits lowercase). The\n * input must have even length and contain only hex digits (`0-9`, `a-f`, `A-F`);\n * an empty string decodes to an empty `Uint8Array`. Odd length or any non-hex\n * character fails with error context.\n *\n * @param encoded - The hex string to decode.\n * @returns `Success` with the decoded bytes, or `Failure` with error context.\n * @public\n */\nexport function hexDecode(encoded: string): Result<Uint8Array> {\n if (encoded.length % 2 !== 0) {\n return fail(`hexDecode: odd-length hex string (length ${encoded.length})`);\n }\n if (!/^[0-9a-fA-F]*$/.test(encoded)) {\n return fail(`hexDecode: string contains non-hex characters`);\n }\n const bytes = new Uint8Array(encoded.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(encoded.slice(i * 2, i * 2 + 2), 16);\n }\n return succeed(bytes);\n}\n\n/**\n * The structural *shape* of a {@link CryptoUtils.MultibaseSpkiPublicKey}: the\n * multibase `'m'` prefix followed by a non-empty base64url-no-pad body\n * (`A-Z`, `a-z`, `0-9`, `-`, `_`).\n *\n * This is a shape prefilter, not full validation: it does not decode the DER\n * SPKI or verify the key material or algorithm (that happens in\n * {@link CryptoUtils.importPublicKeyFromMultibaseSpki}). The authoritative guard\n * is {@link CryptoUtils.isValidMultibaseSpkiPublicKey}, which enforces this\n * pattern **and** additionally rejects a body whose length is an impossible\n * base64 remainder. Exposed for callers that need the pattern directly (e.g. a\n * JSON-schema `pattern` field); prefer the guard/converter for validation.\n *\n * @public\n */\nexport const MultibaseSpkiPublicKeyRegExp: RegExp = /^m[A-Za-z0-9_-]+$/;\n\n/**\n * Type guard for {@link CryptoUtils.MultibaseSpkiPublicKey}: a string matching\n * {@link CryptoUtils.MultibaseSpkiPublicKeyRegExp} (multibase `'m'` prefix + a\n * non-empty base64url-no-pad body) whose body also satisfies the base64url-no-pad\n * length rule shared with {@link CryptoUtils.base64UrlNoPadDecode}. This is a\n * structural *shape* check, not full validation — it does not decode the DER SPKI\n * or verify the key material/algorithm (a malformed-but-well-shaped string fails\n * later, with clear context, in {@link CryptoUtils.importPublicKeyFromMultibaseSpki}).\n *\n * @param value - The value to test.\n * @returns `true` if `value` is a well-formed multibase SPKI public key string.\n * @public\n */\nexport function isValidMultibaseSpkiPublicKey(value: unknown): value is MultibaseSpkiPublicKey {\n return (\n typeof value === 'string' &&\n MultibaseSpkiPublicKeyRegExp.test(value) &&\n isBase64UrlNoPadBody(value.slice(1))\n );\n}\n\n/**\n * Encodes a `Uint8Array` as a multibase base64url (no-padding) string.\n *\n * The multibase prefix `'m'` identifies the encoding as RFC 4648 base64url\n * without padding. The body uses base64url alphabet: `+` → `-`, `/` → `_`,\n * and trailing `=` padding is stripped.\n *\n * @param data - The binary data to encode.\n * @returns A multibase-prefixed base64url string (`'m' + base64url-no-pad`).\n * @public\n */\nexport function multibaseBase64UrlEncode(data: Uint8Array): string {\n return 'm' + base64UrlNoPadEncode(data);\n}\n\n/**\n * Decodes a multibase base64url (no-padding) string back to a `Uint8Array`.\n *\n * Validates that the first character is `'m'` (the multibase prefix for\n * RFC 4648 base64url without padding), then decodes the remaining body.\n *\n * @param encoded - A multibase-prefixed base64url string.\n * @returns `Success` with the decoded bytes, or `Failure` with error context.\n * @public\n */\nexport function multibaseBase64UrlDecode(encoded: string): Result<Uint8Array> {\n if (!encoded.startsWith('m')) {\n return fail(\n `multibaseBase64UrlDecode: invalid multibase prefix '${\n encoded[0] ?? '(empty)'\n }' — expected 'm' (base64url)`\n );\n }\n // Intentionally pin the exact original message (the delegate has a single failure\n // mode) to keep this established public function byte-for-byte behavior-preserving\n // after the extract-and-delegate refactor — do not \"fix\" this into composing the\n // delegate's message without updating the delegation-equivalence tests.\n return base64UrlNoPadDecode(encoded.slice(1)).withErrorFormat(\n () => `multibaseBase64UrlDecode: malformed base64url body`\n );\n}\n\n/**\n * Exports a public `CryptoKey` as a multibase base64url-encoded SPKI blob.\n *\n * The SPKI (SubjectPublicKeyInfo) format is the standard DER-encoded structure\n * for public keys defined in RFC 5280, RFC 5480, and RFC 8410. It is\n * algorithm-agnostic and suitable for storage and transmission.\n *\n * @param key - The `CryptoKey` to export. Must have `key.type === 'public'`.\n * @param provider - The {@link CryptoUtils.ICryptoProvider} to use for the export operation.\n * @returns `Success` with the multibase SPKI string, or `Failure` with error context.\n * @public\n */\nexport async function exportPublicKeyAsMultibaseSpki(\n key: CryptoKey,\n provider: ICryptoProvider\n): Promise<Result<MultibaseSpkiPublicKey>> {\n return (await provider.exportPublicKeySpki(key))\n .withErrorFormat((e) => `exportPublicKeyAsMultibaseSpki: ${e}`)\n .onSuccess((buf) =>\n // The output is a freshly-built valid multibase SPKI string (`'m'` prefix +\n // base64url-no-pad body), so brand it at the construction site — no re-validation needed.\n succeed(multibaseBase64UrlEncode(buf) as MultibaseSpkiPublicKey)\n );\n}\n\n/**\n * Imports a public key from a multibase base64url-encoded SPKI blob.\n *\n * Decodes the multibase prefix, decodes the base64url body, then uses\n * the provider to import the key with the algorithm parameters from\n * {@link CryptoUtils.keyPairAlgorithmParams}.\n *\n * Accepts a plain `string` (not only a branded {@link CryptoUtils.MultibaseSpkiPublicKey}),\n * so callers holding an unbranded value read from storage or the wire can import\n * it directly; a malformed value fails with error context rather than throwing.\n *\n * @param encoded - A multibase SPKI string produced by {@link CryptoUtils.exportPublicKeyAsMultibaseSpki}.\n * @param algorithm - The {@link CryptoUtils.KeyPairAlgorithm} the key was generated for.\n * @param provider - The {@link CryptoUtils.ICryptoProvider} to use for the import operation.\n * @returns `Success` with the imported public `CryptoKey`, or `Failure` with error context.\n * @public\n */\nexport async function importPublicKeyFromMultibaseSpki(\n encoded: string,\n algorithm: KeyPairAlgorithm,\n provider: ICryptoProvider\n): Promise<Result<CryptoKey>> {\n const decodeResult = multibaseBase64UrlDecode(encoded);\n if (decodeResult.isFailure()) {\n return fail(`importPublicKeyFromMultibaseSpki: ${decodeResult.message}`);\n }\n return (await provider.importPublicKeySpki(decodeResult.value, algorithm)).withErrorFormat(\n (e) => `importPublicKeyFromMultibaseSpki: ${e}`\n );\n}\n\n// DER prefix for an X25519 SubjectPublicKeyInfo: SEQUENCE { SEQUENCE { OID id-X25519 }, BIT STRING }.\n// SEQUENCE(42) / SEQUENCE(5) / OID 1.3.101.110 (id-X25519) / BIT STRING(33, 0 unused bits).\nconst _X25519_SPKI_PREFIX: ReadonlyArray<number> = [\n 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00\n];\nconst _X25519_SPKI_LENGTH: number = _X25519_SPKI_PREFIX.length + 32;\n\n/**\n * Strips the fixed DER prefix from an X25519 SubjectPublicKeyInfo blob, returning the raw\n * 32-byte public key.\n *\n * An X25519 SPKI is always exactly 44 bytes: a fixed 12-byte prefix (SEQUENCE / AlgorithmIdentifier\n * with OID 1.3.101.110 / BIT STRING) followed by the 32-byte raw key. Use this to convert a\n * SPKI-held recipient public key into the raw form accepted by {@link HpkeProvider.openBase}'s\n * `recipientPublicKey` parameter.\n *\n * @param spki - The DER-encoded X25519 SubjectPublicKeyInfo bytes.\n * @returns `Success` with the raw 32-byte public key, or `Failure` if `spki` is not a\n * well-formed 44-byte X25519 SPKI blob.\n * @public\n */\nexport function spkiToRawX25519(spki: Uint8Array): Result<Uint8Array> {\n if (spki.length !== _X25519_SPKI_LENGTH) {\n return fail(`spkiToRawX25519: expected ${_X25519_SPKI_LENGTH} bytes, got ${spki.length}`);\n }\n for (let i = 0; i < _X25519_SPKI_PREFIX.length; i++) {\n if (spki[i] !== _X25519_SPKI_PREFIX[i]) {\n return fail(`spkiToRawX25519: byte ${i} does not match the expected X25519 SPKI prefix`);\n }\n }\n return succeed(spki.slice(_X25519_SPKI_PREFIX.length));\n}\n"]}
|
package/dist/ts-extras.d.ts
CHANGED
|
@@ -435,12 +435,13 @@ declare function anthropicEffortToBudgetTokens(effort: NonNullable<IAnthropicThi
|
|
|
435
435
|
* Model IDs for Anthropic thinking-capable models.
|
|
436
436
|
*
|
|
437
437
|
* @remarks
|
|
438
|
-
* Only thinking-capable lines are listed. The non-tier `@anthropic:haiku`
|
|
439
|
-
*
|
|
440
|
-
*
|
|
438
|
+
* Only thinking-capable lines are listed. The non-tier `@anthropic:haiku` alias (reachable via
|
|
439
|
+
* `modelOverride` only) is deliberately omitted — it is not documented as thinking-capable, so
|
|
440
|
+
* naming it in a thinking-model filter would be misleading. `claude-fable-5` (the `@anthropic:fable`
|
|
441
|
+
* non-tier alias) is thinking-capable and reachable via `modelOverride`, so it is listed.
|
|
441
442
|
* @public
|
|
442
443
|
*/
|
|
443
|
-
declare type AnthropicThinkingModelNames = 'claude-sonnet-4-5' | 'claude-sonnet-4-6' | 'claude-sonnet-5' | 'claude-opus-4-6' | 'claude-opus-4-7' | 'claude-opus-4-8';
|
|
444
|
+
declare type AnthropicThinkingModelNames = 'claude-sonnet-4-5' | 'claude-sonnet-4-6' | 'claude-sonnet-5' | 'claude-opus-4-6' | 'claude-opus-4-7' | 'claude-opus-4-8' | 'claude-opus-5' | 'claude-fable-5';
|
|
444
445
|
|
|
445
446
|
/**
|
|
446
447
|
* Recommended OWASP 2023 minimum Argon2id parameters.
|
|
@@ -732,6 +733,8 @@ declare namespace CryptoUtils {
|
|
|
732
733
|
base64UrlNoPadDecode,
|
|
733
734
|
base64UrlNoPadEncode,
|
|
734
735
|
exportPublicKeyAsMultibaseSpki,
|
|
736
|
+
hexDecode,
|
|
737
|
+
hexEncode,
|
|
735
738
|
importPublicKeyFromMultibaseSpki,
|
|
736
739
|
isValidMultibaseSpkiPublicKey,
|
|
737
740
|
MultibaseSpkiPublicKeyRegExp,
|
|
@@ -759,6 +762,7 @@ declare namespace CryptoUtils {
|
|
|
759
762
|
IArgon2idParams,
|
|
760
763
|
ARGON2ID_OWASP_MIN,
|
|
761
764
|
ARGON2ID_PASSPHRASE,
|
|
765
|
+
IArgon2idKeyingOptions,
|
|
762
766
|
IArgon2idProvider,
|
|
763
767
|
IEncryptedFile,
|
|
764
768
|
ICryptoProvider,
|
|
@@ -851,25 +855,30 @@ declare const DEFAULT_SECRET_ITERATIONS: number;
|
|
|
851
855
|
* {@link CryptoUtils.ICryptoProvider.importKeyPairFromSeed | importKeyPairFromSeed}
|
|
852
856
|
* for the public contract.
|
|
853
857
|
*
|
|
854
|
-
* For
|
|
855
|
-
* runs a transient-extractable-then-derive dance so the public
|
|
856
|
-
* recoverable even when the caller requests a non-extractable private key:
|
|
858
|
+
* For each supported algorithm: wraps the 32-byte seed in the RFC 8410 PKCS#8
|
|
859
|
+
* envelope, then runs a transient-extractable-then-derive dance so the public
|
|
860
|
+
* key is recoverable even when the caller requests a non-extractable private key:
|
|
857
861
|
*
|
|
858
862
|
* 1. Import the PKCS#8 as a *transient* extractable private key.
|
|
859
863
|
* 2. Export it to JWK to read the deterministic public coordinate `x`.
|
|
860
|
-
* 3. Import `{ kty: 'OKP', crv
|
|
864
|
+
* 3. Import `{ kty: 'OKP', crv, x }` as the returned public key.
|
|
861
865
|
* 4. For the returned private key: reuse the transient key when `extractable`
|
|
862
866
|
* is `true`; otherwise re-import the same PKCS#8 as a non-extractable key.
|
|
863
867
|
* The transient extractable key is never returned when `extractable` is
|
|
864
868
|
* `false`, so seed material cannot escape through it.
|
|
865
869
|
*
|
|
870
|
+
* The two algorithms differ only in the OID/name/curve/usages (see
|
|
871
|
+
* {@link ISeedAlgorithmParams}); `'x25519'` yields the DH key-agreement keypair
|
|
872
|
+
* (private `'deriveBits'`, public no-usage) that {@link CryptoUtils.HpkeProvider}
|
|
873
|
+
* consumes as its recipient key.
|
|
874
|
+
*
|
|
866
875
|
* The seed bytes are copied into a freshly allocated PKCS#8 buffer, so the
|
|
867
876
|
* `BufferSource` handed to WebCrypto is always backed by a plain `ArrayBuffer`
|
|
868
877
|
* (side-stepping the Node-20 `SharedArrayBuffer`-view rejection) and the
|
|
869
878
|
* caller's `seed` is never mutated.
|
|
870
879
|
*
|
|
871
|
-
* @param algorithm - The seed-derivable algorithm
|
|
872
|
-
*
|
|
880
|
+
* @param algorithm - The seed-derivable algorithm (`'ed25519'` or `'x25519'`).
|
|
881
|
+
* Any other value fails loudly rather than being mis-handled.
|
|
873
882
|
* @param seed - The 32-byte secret seed. Any other length fails loudly, before
|
|
874
883
|
* any WebCrypto call.
|
|
875
884
|
* @param extractable - Whether the returned private key may be exported.
|
|
@@ -1342,7 +1351,7 @@ declare const GCM_AUTH_TAG_SIZE: number;
|
|
|
1342
1351
|
declare const GCM_IV_SIZE: number;
|
|
1343
1352
|
|
|
1344
1353
|
/** Model names in the Gemini Flash Image family. @public */
|
|
1345
|
-
declare type GeminiFlashImageModelNames = 'gemini-3.1-flash-image
|
|
1354
|
+
declare type GeminiFlashImageModelNames = 'gemini-3.1-flash-image';
|
|
1346
1355
|
|
|
1347
1356
|
/**
|
|
1348
1357
|
* Model IDs for Google Gemini thinking-capable models.
|
|
@@ -1387,7 +1396,7 @@ declare function getProviderDescriptor(id: string): Result<IAiProviderDescriptor
|
|
|
1387
1396
|
declare function getProviderDescriptors(): ReadonlyArray<IAiProviderDescriptor>;
|
|
1388
1397
|
|
|
1389
1398
|
/** Model names in the GPT Image family. @public */
|
|
1390
|
-
declare type GptImageModelNames = 'gpt-image-1' | 'gpt-image-1.5';
|
|
1399
|
+
declare type GptImageModelNames = 'gpt-image-1' | 'gpt-image-1.5' | 'gpt-image-2';
|
|
1391
1400
|
|
|
1392
1401
|
/** Quality values for gpt-image-1. @public */
|
|
1393
1402
|
declare type GptImageQuality = 'low' | 'medium' | 'high' | 'auto';
|
|
@@ -1405,6 +1414,34 @@ declare namespace Hash {
|
|
|
1405
1414
|
}
|
|
1406
1415
|
export { Hash }
|
|
1407
1416
|
|
|
1417
|
+
/**
|
|
1418
|
+
* Decodes a hexadecimal string (no `0x` prefix) back to a `Uint8Array`.
|
|
1419
|
+
*
|
|
1420
|
+
* Liberal in what it accepts: both lowercase and uppercase hex digits are
|
|
1421
|
+
* allowed (whereas {@link CryptoUtils.hexEncode} always emits lowercase). The
|
|
1422
|
+
* input must have even length and contain only hex digits (`0-9`, `a-f`, `A-F`);
|
|
1423
|
+
* an empty string decodes to an empty `Uint8Array`. Odd length or any non-hex
|
|
1424
|
+
* character fails with error context.
|
|
1425
|
+
*
|
|
1426
|
+
* @param encoded - The hex string to decode.
|
|
1427
|
+
* @returns `Success` with the decoded bytes, or `Failure` with error context.
|
|
1428
|
+
* @public
|
|
1429
|
+
*/
|
|
1430
|
+
declare function hexDecode(encoded: string): Result<Uint8Array>;
|
|
1431
|
+
|
|
1432
|
+
/**
|
|
1433
|
+
* Encodes a `Uint8Array` as a lowercase hexadecimal string with no `0x` prefix.
|
|
1434
|
+
*
|
|
1435
|
+
* Each byte becomes exactly two lowercase hex characters (zero-padded), so an
|
|
1436
|
+
* `n`-byte input yields a `2n`-character string. An empty input yields the empty
|
|
1437
|
+
* string. This is the inverse of {@link CryptoUtils.hexDecode}.
|
|
1438
|
+
*
|
|
1439
|
+
* @param data - The binary data to encode.
|
|
1440
|
+
* @returns The lowercase, unprefixed hex string.
|
|
1441
|
+
* @public
|
|
1442
|
+
*/
|
|
1443
|
+
declare function hexEncode(data: Uint8Array): string;
|
|
1444
|
+
|
|
1408
1445
|
/**
|
|
1409
1446
|
* HPKE base mode (RFC 9180) — `DHKEM(X25519, HKDF-SHA256) + HKDF-SHA256 + AES-256-GCM`.
|
|
1410
1447
|
*
|
|
@@ -2560,6 +2597,33 @@ declare interface IArgon2idKeyDerivationParams {
|
|
|
2560
2597
|
readonly parallelism: number;
|
|
2561
2598
|
}
|
|
2562
2599
|
|
|
2600
|
+
/**
|
|
2601
|
+
* Optional keyed-hashing inputs for {@link CryptoUtils.IArgon2idProvider.argon2id | argon2id}
|
|
2602
|
+
* (RFC 9106 §3.1). These are distinct from the cost parameters in
|
|
2603
|
+
* {@link CryptoUtils.IArgon2idParams} — they change the derived output but are
|
|
2604
|
+
* not tuning knobs. Both fields are optional; omitting a field (or passing an
|
|
2605
|
+
* empty `Uint8Array`) is a no-op that leaves the output byte-identical to a call
|
|
2606
|
+
* with no options at all.
|
|
2607
|
+
* @public
|
|
2608
|
+
*/
|
|
2609
|
+
declare interface IArgon2idKeyingOptions {
|
|
2610
|
+
/**
|
|
2611
|
+
* Optional secret key K (RFC 9106 keyed hashing, sometimes called a "pepper").
|
|
2612
|
+
* When present and non-empty it is mixed into the hash so that the derived
|
|
2613
|
+
* output cannot be reproduced without also knowing K. Empty or omitted means
|
|
2614
|
+
* no secret. Honored by both the Node and browser backends.
|
|
2615
|
+
*/
|
|
2616
|
+
readonly secret?: Uint8Array;
|
|
2617
|
+
/**
|
|
2618
|
+
* Optional associated data X (RFC 9106 §3.1). When present and non-empty it is
|
|
2619
|
+
* mixed into the hash. **Node-only:** the WASM (`hash-wasm`) browser backend
|
|
2620
|
+
* has no associated-data input, so `BrowserArgon2Provider` fails loudly rather
|
|
2621
|
+
* than silently dropping it (which would produce wrong bytes). Empty or omitted
|
|
2622
|
+
* means no associated data and is accepted by both backends.
|
|
2623
|
+
*/
|
|
2624
|
+
readonly associatedData?: Uint8Array;
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2563
2627
|
/**
|
|
2564
2628
|
* Parameters for Argon2id key derivation (RFC 9106).
|
|
2565
2629
|
* All fields are required; fgv does not pick defaults silently.
|
|
@@ -2607,15 +2671,24 @@ declare interface IArgon2idProvider {
|
|
|
2607
2671
|
/**
|
|
2608
2672
|
* Derives key material from a password using Argon2id (RFC 9106 §3.1).
|
|
2609
2673
|
*
|
|
2610
|
-
* Returns the raw derived bytes as a `Uint8Array`.
|
|
2611
|
-
*
|
|
2674
|
+
* Returns the raw derived bytes as a `Uint8Array`. For the same inputs that
|
|
2675
|
+
* both backends support, the Node and browser implementations produce
|
|
2676
|
+
* byte-identical output. The optional `associatedData` in
|
|
2677
|
+
* {@link CryptoUtils.IArgon2idKeyingOptions} is the one exception: it is
|
|
2678
|
+
* Node-only (the browser WASM backend has no associated-data input), so a call
|
|
2679
|
+
* that supplies non-empty `associatedData` is not portable to the browser
|
|
2680
|
+
* backend. Every input the browser backend *does* support (including the
|
|
2681
|
+
* optional `secret`) is byte-identical across the two.
|
|
2612
2682
|
*
|
|
2613
2683
|
* @param password - Password or passphrase. Accepts string (UTF-8) or raw bytes.
|
|
2614
2684
|
* @param salt - Salt bytes. Must be random and unique per credential (\>= 16 bytes recommended).
|
|
2615
2685
|
* @param params - Argon2id parameters. Use `ARGON2ID_OWASP_MIN` as a starting point.
|
|
2686
|
+
* @param options - Optional {@link CryptoUtils.IArgon2idKeyingOptions | keyed-hashing inputs}
|
|
2687
|
+
* (secret K and/or associated data X). Omitting them (the default) leaves the
|
|
2688
|
+
* output byte-identical to prior behavior.
|
|
2616
2689
|
* @returns Success with derived bytes, Failure with error context.
|
|
2617
2690
|
*/
|
|
2618
|
-
argon2id(password: Uint8Array | string, salt: Uint8Array, params: IArgon2idParams): Promise<Result<Uint8Array>>;
|
|
2691
|
+
argon2id(password: Uint8Array | string, salt: Uint8Array, params: IArgon2idParams, options?: IArgon2idKeyingOptions): Promise<Result<Uint8Array>>;
|
|
2619
2692
|
}
|
|
2620
2693
|
|
|
2621
2694
|
/**
|
|
@@ -2881,16 +2954,19 @@ declare interface ICryptoProvider {
|
|
|
2881
2954
|
* material (key escrow, HD-style derivation, deterministic test vectors) rather
|
|
2882
2955
|
* than freshly sampled by {@link CryptoUtils.ICryptoProvider.generateKeyPair | generateKeyPair}.
|
|
2883
2956
|
*
|
|
2884
|
-
* For `'ed25519'` the private key *is* its 32-byte seed and
|
|
2885
|
-
* deterministic function of that seed (RFC 8032
|
|
2886
|
-
* recovered even when the caller requests a
|
|
2887
|
-
* transient extractable key used internally to
|
|
2888
|
-
* returned or logged when `extractable` is
|
|
2889
|
-
*
|
|
2890
|
-
*
|
|
2891
|
-
*
|
|
2892
|
-
*
|
|
2893
|
-
*
|
|
2957
|
+
* For both `'ed25519'` and `'x25519'` the private key *is* its 32-byte seed and
|
|
2958
|
+
* the public key is a deterministic function of that seed (RFC 8032 / RFC 7748),
|
|
2959
|
+
* so the returned public key is recovered even when the caller requests a
|
|
2960
|
+
* non-extractable private key. The transient extractable key used internally to
|
|
2961
|
+
* recover the public half is never returned or logged when `extractable` is
|
|
2962
|
+
* `false`. The returned keys carry the algorithm's usages: `'ed25519'` →
|
|
2963
|
+
* private `'sign'` / public `'verify'`; `'x25519'` → private `'deriveBits'` /
|
|
2964
|
+
* public no-usage (ready to hand to {@link CryptoUtils.HpkeProvider}).
|
|
2965
|
+
* @param algorithm - The {@link CryptoUtils.SeedDerivableAlgorithm | seed-derivable algorithm}
|
|
2966
|
+
* (`'ed25519'` or `'x25519'`); any other value fails loudly with context.
|
|
2967
|
+
* @param seed - The secret seed. It must be exactly 32 bytes for both supported
|
|
2968
|
+
* algorithms; any other length fails loudly, before any WebCrypto call. The
|
|
2969
|
+
* bytes are copied, not retained or mutated.
|
|
2894
2970
|
* @param extractable - Whether the returned private key may be exported. The
|
|
2895
2971
|
* returned public key is identical for a given seed regardless of this flag.
|
|
2896
2972
|
* @returns Success with the derived `CryptoKeyPair`, or Failure with error context.
|
|
@@ -3570,6 +3646,19 @@ declare interface IImportKeyOptions extends IImportSecretOptions {
|
|
|
3570
3646
|
readonly type?: KeyStoreSymmetricSecretType;
|
|
3571
3647
|
}
|
|
3572
3648
|
|
|
3649
|
+
/**
|
|
3650
|
+
* Options for importing raw opaque bytes via {@link KeyStore.importSecretBytes}.
|
|
3651
|
+
* Extends {@link IImportSecretOptions} with optional initial metadata.
|
|
3652
|
+
* @public
|
|
3653
|
+
*/
|
|
3654
|
+
declare interface IImportSecretBytesOptions extends IImportSecretOptions {
|
|
3655
|
+
/**
|
|
3656
|
+
* Optional initial mutable metadata to store with the entry. Can also be set
|
|
3657
|
+
* or replaced later via {@link KeyStore.setSecretMetadata}.
|
|
3658
|
+
*/
|
|
3659
|
+
readonly metadata?: JsonValue;
|
|
3660
|
+
}
|
|
3661
|
+
|
|
3573
3662
|
/**
|
|
3574
3663
|
* Options for importing a secret.
|
|
3575
3664
|
* @public
|
|
@@ -3850,16 +3939,36 @@ declare interface IKeyStoreSymmetricEntry {
|
|
|
3850
3939
|
* The secret data.
|
|
3851
3940
|
* - For `'encryption-key'`: 32-byte AES-256 key.
|
|
3852
3941
|
* - For `'api-key'`: UTF-8 encoded API key string (arbitrary length).
|
|
3942
|
+
* - For `'opaque'`: arbitrary raw bytes, stored and returned verbatim.
|
|
3853
3943
|
*/
|
|
3854
3944
|
readonly key: Uint8Array;
|
|
3855
3945
|
/**
|
|
3856
3946
|
* Optional description for this secret.
|
|
3857
3947
|
*/
|
|
3858
3948
|
readonly description?: string;
|
|
3949
|
+
/**
|
|
3950
|
+
* Optional mutable, non-secret-by-contract metadata for this entry. Set via
|
|
3951
|
+
* {@link CryptoUtils.KeyStore.KeyStore.setSecretMetadata} without touching the
|
|
3952
|
+
* secret `key` bytes.
|
|
3953
|
+
*
|
|
3954
|
+
* "Non-secret by contract" means the field is intended for lifecycle metadata
|
|
3955
|
+
* (rotation timestamps, labels, provenance) rather than secret material.
|
|
3956
|
+
* PHYSICALLY it lives inside the vault's AES-GCM ciphertext alongside the key
|
|
3957
|
+
* bytes — the vault has no plaintext index — so it is protected at rest by the
|
|
3958
|
+
* master password; the "non-secret" designation is a usage contract, not a
|
|
3959
|
+
* weaker custody class.
|
|
3960
|
+
*/
|
|
3961
|
+
readonly metadata?: JsonValue;
|
|
3859
3962
|
/**
|
|
3860
3963
|
* When this secret was added (ISO 8601).
|
|
3861
3964
|
*/
|
|
3862
3965
|
readonly createdAt: string;
|
|
3966
|
+
/**
|
|
3967
|
+
* When this entry was last mutated (ISO 8601). Stamped on any metadata
|
|
3968
|
+
* mutation (see {@link CryptoUtils.KeyStore.KeyStore.setSecretMetadata}).
|
|
3969
|
+
* Absent on entries that have never been mutated since creation.
|
|
3970
|
+
*/
|
|
3971
|
+
readonly updatedAt?: string;
|
|
3863
3972
|
}
|
|
3864
3973
|
|
|
3865
3974
|
/**
|
|
@@ -3899,10 +4008,22 @@ declare interface IKeyStoreSymmetricEntryJson {
|
|
|
3899
4008
|
* Optional description.
|
|
3900
4009
|
*/
|
|
3901
4010
|
readonly description?: string;
|
|
4011
|
+
/**
|
|
4012
|
+
* Optional mutable, non-secret-by-contract metadata for this entry. Present
|
|
4013
|
+
* only on `'keystore-v3'` vaults whose entry carried metadata; a v1/v2 vault
|
|
4014
|
+
* omits the field. Physically carried inside the vault ciphertext (the vault
|
|
4015
|
+
* has no plaintext index).
|
|
4016
|
+
*/
|
|
4017
|
+
readonly metadata?: JsonValue;
|
|
3902
4018
|
/**
|
|
3903
4019
|
* When this secret was added (ISO 8601).
|
|
3904
4020
|
*/
|
|
3905
4021
|
readonly createdAt: string;
|
|
4022
|
+
/**
|
|
4023
|
+
* When this entry was last mutated (ISO 8601). Present only on `'keystore-v3'`
|
|
4024
|
+
* vaults whose entry has been mutated since creation.
|
|
4025
|
+
*/
|
|
4026
|
+
readonly updatedAt?: string;
|
|
3906
4027
|
}
|
|
3907
4028
|
|
|
3908
4029
|
/**
|
|
@@ -3977,7 +4098,7 @@ declare type IModelFamilyConfig = IGptImageModelOptions | IGrokImagineModelOptio
|
|
|
3977
4098
|
* const simple: ModelSpec = 'grok-4.3';
|
|
3978
4099
|
*
|
|
3979
4100
|
* // Context-aware — different model per quality tier:
|
|
3980
|
-
* const split: ModelSpec = { base: 'gpt-5.
|
|
4101
|
+
* const split: ModelSpec = { base: 'gpt-5.6-luna', advanced: 'gpt-5.6-terra', frontier: 'gpt-5.6-sol' };
|
|
3981
4102
|
*
|
|
3982
4103
|
* // Nested — a tier branch is itself a spec:
|
|
3983
4104
|
* const nested: ModelSpec = { base: 'grok-fast', advanced: { base: 'grok-r', image: 'grok-v' } };
|
|
@@ -4859,6 +4980,7 @@ declare namespace KeyStore {
|
|
|
4859
4980
|
IAddSecretOptions,
|
|
4860
4981
|
IImportSecretOptions,
|
|
4861
4982
|
IImportKeyOptions,
|
|
4983
|
+
IImportSecretBytesOptions,
|
|
4862
4984
|
IAddSecretFromPasswordOptions,
|
|
4863
4985
|
DEFAULT_SECRET_ITERATIONS,
|
|
4864
4986
|
IAddSecretFromPasswordResult,
|
|
@@ -5179,6 +5301,50 @@ declare class KeyStore_2 implements IEncryptionProvider {
|
|
|
5179
5301
|
* @public
|
|
5180
5302
|
*/
|
|
5181
5303
|
getApiKey(name: string): Result<string>;
|
|
5304
|
+
/**
|
|
5305
|
+
* Imports arbitrary raw bytes into the vault with type `'opaque'`.
|
|
5306
|
+
*
|
|
5307
|
+
* Unlike {@link KeyStore.importSecret} (which enforces a 32-byte AES-256 key)
|
|
5308
|
+
* and {@link KeyStore.importApiKey} (which UTF-8 encodes a string), this
|
|
5309
|
+
* accepts a byte buffer of any length and stores it verbatim — including
|
|
5310
|
+
* embedded NUL bytes. Use it for byte blobs that are neither a fixed-size key
|
|
5311
|
+
* nor a UTF-8 string (e.g. a serialized credential bundle), so they are not
|
|
5312
|
+
* mistyped as `'api-key'`.
|
|
5313
|
+
*
|
|
5314
|
+
* @param name - Unique name for the secret
|
|
5315
|
+
* @param bytes - The raw bytes to store
|
|
5316
|
+
* @param options - Optional description, initial metadata, whether to replace existing
|
|
5317
|
+
* @returns Success with entry, Failure if locked, empty, or exists and !replace
|
|
5318
|
+
* @public
|
|
5319
|
+
*/
|
|
5320
|
+
importSecretBytes(name: string, bytes: Uint8Array, options?: IImportSecretBytesOptions): Promise<Result<IAddSecretResult>>;
|
|
5321
|
+
/**
|
|
5322
|
+
* Retrieves the raw stored bytes for a symmetric entry, returned verbatim
|
|
5323
|
+
* (never UTF-8 decoded). Intended for `'opaque'` entries but works for any
|
|
5324
|
+
* symmetric type; asymmetric-keypair entries carry no raw key material and
|
|
5325
|
+
* are rejected.
|
|
5326
|
+
*
|
|
5327
|
+
* @param name - Name of the secret
|
|
5328
|
+
* @returns Success with a copy of the stored bytes, Failure if not found,
|
|
5329
|
+
* locked, or the entry is asymmetric
|
|
5330
|
+
* @public
|
|
5331
|
+
*/
|
|
5332
|
+
getSecretBytes(name: string): Result<Uint8Array>;
|
|
5333
|
+
/**
|
|
5334
|
+
* Replaces the mutable metadata on a symmetric entry and stamps `updatedAt`
|
|
5335
|
+
* with the current timestamp. Does NOT touch the secret `key` bytes — the
|
|
5336
|
+
* material reads back identically afterward.
|
|
5337
|
+
*
|
|
5338
|
+
* Metadata is non-secret by contract but physically lives inside the vault
|
|
5339
|
+
* ciphertext (see {@link CryptoUtils.KeyStore.IKeyStoreSymmetricEntry.metadata}).
|
|
5340
|
+
*
|
|
5341
|
+
* @param name - Name of the secret to update
|
|
5342
|
+
* @param value - New metadata value (replaces any prior metadata)
|
|
5343
|
+
* @returns Success with the updated entry, Failure if not found, locked, or
|
|
5344
|
+
* the entry is asymmetric
|
|
5345
|
+
* @public
|
|
5346
|
+
*/
|
|
5347
|
+
setSecretMetadata(name: string, value: JsonValue): Result<IKeyStoreSymmetricEntry>;
|
|
5182
5348
|
/**
|
|
5183
5349
|
* Adds a new asymmetric keypair to the vault. Storage-first: the private key
|
|
5184
5350
|
* is stored under a freshly-minted `id` before the public-key vault entry is
|
|
@@ -5364,7 +5530,7 @@ declare class KeyStore_2 implements IEncryptionProvider {
|
|
|
5364
5530
|
}
|
|
5365
5531
|
|
|
5366
5532
|
/**
|
|
5367
|
-
* Current format version constant. New vaults are written as `'keystore-
|
|
5533
|
+
* Current format version constant. New vaults are written as `'keystore-v3'`.
|
|
5368
5534
|
* @public
|
|
5369
5535
|
*/
|
|
5370
5536
|
declare const KEYSTORE_FORMAT: KeyStoreFormat;
|
|
@@ -5408,9 +5574,14 @@ declare const keystoreFile: Converter<IKeyStoreFile>;
|
|
|
5408
5574
|
* asymmetric-keypair entries. A strict superset of v1 — the field is
|
|
5409
5575
|
* optional, so a v2 reader opens a v1 vault with no special-casing, and a
|
|
5410
5576
|
* v1 vault opened and re-saved is silently upgraded to v2.
|
|
5577
|
+
* - `'keystore-v3'`: adds the `'opaque'` symmetric secret type and the optional
|
|
5578
|
+
* `metadata` / `updatedAt` fields on symmetric entries. A strict superset of
|
|
5579
|
+
* v1/v2 — the additions are optional (and `'opaque'` is simply a new enum
|
|
5580
|
+
* value), so a v3 reader opens a v1/v2 vault with no special-casing, and a
|
|
5581
|
+
* v1/v2 vault opened and re-saved is silently upgraded to v3.
|
|
5411
5582
|
* @public
|
|
5412
5583
|
*/
|
|
5413
|
-
declare type KeyStoreFormat = 'keystore-v1' | 'keystore-v2';
|
|
5584
|
+
declare type KeyStoreFormat = 'keystore-v1' | 'keystore-v2' | 'keystore-v3';
|
|
5414
5585
|
|
|
5415
5586
|
/**
|
|
5416
5587
|
* Converter for {@link CryptoUtils.KeyStore.KeyStoreFormat | key store format} version.
|
|
@@ -5468,13 +5639,17 @@ declare const keystoreSymmetricEntryJson: Converter<IKeyStoreSymmetricEntryJson>
|
|
|
5468
5639
|
* Discriminator for symmetric secret types stored in the vault.
|
|
5469
5640
|
* - `'encryption-key'`: A 32-byte AES-256 encryption key.
|
|
5470
5641
|
* - `'api-key'`: An arbitrary-length API key string (UTF-8 encoded).
|
|
5642
|
+
* - `'opaque'`: Arbitrary raw bytes with no encoding contract — stored and
|
|
5643
|
+
* returned verbatim (never UTF-8 decoded). Use for byte blobs that are
|
|
5644
|
+
* neither a fixed-size AES key nor a UTF-8 string (e.g. a serialized
|
|
5645
|
+
* credential bundle), so they are not mistyped as `'api-key'`.
|
|
5471
5646
|
* @public
|
|
5472
5647
|
*/
|
|
5473
|
-
declare type KeyStoreSymmetricSecretType = 'encryption-key' | 'api-key';
|
|
5648
|
+
declare type KeyStoreSymmetricSecretType = 'encryption-key' | 'api-key' | 'opaque';
|
|
5474
5649
|
|
|
5475
5650
|
/**
|
|
5476
5651
|
* Converter for {@link CryptoUtils.KeyStore.KeyStoreSymmetricSecretType | symmetric secret type} discriminator.
|
|
5477
|
-
* Accepts
|
|
5652
|
+
* Accepts `'encryption-key'`, `'api-key'`, and `'opaque'`.
|
|
5478
5653
|
* @public
|
|
5479
5654
|
*/
|
|
5480
5655
|
declare const keystoreSymmetricSecretType: Converter<KeyStoreSymmetricSecretType>;
|
|
@@ -5931,7 +6106,7 @@ declare const nodeCryptoProvider: NodeCryptoProvider;
|
|
|
5931
6106
|
* Model IDs for OpenAI thinking-capable models.
|
|
5932
6107
|
* @public
|
|
5933
6108
|
*/
|
|
5934
|
-
declare type OpenAiThinkingModelNames = 'o3' | 'o4-mini' | 'o3-deep-research' | 'o4-mini-deep-research' | 'gpt-5' | 'gpt-5.1' | 'gpt-5.2' | 'gpt-5.4-mini' | 'gpt-5.5' | 'gpt-5.5-pro' | 'gpt-5-pro';
|
|
6109
|
+
declare type OpenAiThinkingModelNames = 'o3' | 'o4-mini' | 'o3-deep-research' | 'o4-mini-deep-research' | 'gpt-5' | 'gpt-5.1' | 'gpt-5.2' | 'gpt-5.4-mini' | 'gpt-5.5' | 'gpt-5.5-pro' | 'gpt-5.6-sol' | 'gpt-5.6-terra' | 'gpt-5.6-luna' | 'gpt-5-pro';
|
|
5935
6110
|
|
|
5936
6111
|
/**
|
|
5937
6112
|
* Parses CSV data from a string.
|
|
@@ -6286,15 +6461,22 @@ declare type SecretProvider = (secretName: string) => Promise<Result<Uint8Array>
|
|
|
6286
6461
|
* derived *deterministically* from a fixed secret seed, for use with
|
|
6287
6462
|
* {@link CryptoUtils.ICryptoProvider.importKeyPairFromSeed | importKeyPairFromSeed}.
|
|
6288
6463
|
*
|
|
6289
|
-
*
|
|
6290
|
-
* seed and
|
|
6291
|
-
*
|
|
6292
|
-
*
|
|
6293
|
-
*
|
|
6294
|
-
* `'x25519'`
|
|
6464
|
+
* Two algorithms are supported, both of whose 32-byte private scalar *is* the
|
|
6465
|
+
* seed and whose public key is a deterministic function of it, so the same seed
|
|
6466
|
+
* always yields the same keypair on every runtime:
|
|
6467
|
+
* - `'ed25519'` — signing keypair (RFC 8032). Private usage `'sign'`, public
|
|
6468
|
+
* usage `'verify'`.
|
|
6469
|
+
* - `'x25519'` — Diffie-Hellman key-agreement keypair (RFC 7748), the recipient
|
|
6470
|
+
* keypair consumed by {@link CryptoUtils.HpkeProvider}. Private usage
|
|
6471
|
+
* `'deriveBits'`, public key imported with no usages. Deriving a fixed X25519
|
|
6472
|
+
* recipient keypair from a checked-in seed is what makes a deterministic HPKE
|
|
6473
|
+
* seal/open round-trip vector possible.
|
|
6474
|
+
*
|
|
6475
|
+
* The type is a proper subset of {@link CryptoUtils.KeyPairAlgorithm} because
|
|
6476
|
+
* algorithms like RSA or the NIST curves are not recoverable from a bare seed.
|
|
6295
6477
|
* @public
|
|
6296
6478
|
*/
|
|
6297
|
-
declare type SeedDerivableAlgorithm = 'ed25519';
|
|
6479
|
+
declare type SeedDerivableAlgorithm = 'ed25519' | 'x25519';
|
|
6298
6480
|
|
|
6299
6481
|
/**
|
|
6300
6482
|
* Default system-prompt suffix appended when {@link AiAssist.IGenerateJsonCompletionParams.promptHint}
|
|
@@ -415,7 +415,7 @@ export declare const MODEL_SPEC_BASE_KEY: ModelSpecKey;
|
|
|
415
415
|
* const simple: ModelSpec = 'grok-4.3';
|
|
416
416
|
*
|
|
417
417
|
* // Context-aware — different model per quality tier:
|
|
418
|
-
* const split: ModelSpec = { base: 'gpt-5.
|
|
418
|
+
* const split: ModelSpec = { base: 'gpt-5.6-luna', advanced: 'gpt-5.6-terra', frontier: 'gpt-5.6-sol' };
|
|
419
419
|
*
|
|
420
420
|
* // Nested — a tier branch is itself a spec:
|
|
421
421
|
* const nested: ModelSpec = { base: 'grok-fast', advanced: { base: 'grok-r', image: 'grok-v' } };
|
|
@@ -938,11 +938,11 @@ export type GptImageQuality = 'low' | 'medium' | 'high' | 'auto';
|
|
|
938
938
|
/** All accepted quality strings across all providers. @public */
|
|
939
939
|
export type AiImageQuality = GptImageQuality;
|
|
940
940
|
/** Model names in the GPT Image family. @public */
|
|
941
|
-
export type GptImageModelNames = 'gpt-image-1' | 'gpt-image-1.5';
|
|
941
|
+
export type GptImageModelNames = 'gpt-image-1' | 'gpt-image-1.5' | 'gpt-image-2';
|
|
942
942
|
/** Model names in the xAI Grok Imagine family. @public */
|
|
943
943
|
export type GrokImagineModelNames = 'grok-imagine-image' | 'grok-imagine-image-quality';
|
|
944
944
|
/** Model names in the Gemini Flash Image family. @public */
|
|
945
|
-
export type GeminiFlashImageModelNames = 'gemini-3.1-flash-image
|
|
945
|
+
export type GeminiFlashImageModelNames = 'gemini-3.1-flash-image';
|
|
946
946
|
/**
|
|
947
947
|
* Provider-specific config for gpt-image-1.
|
|
948
948
|
* @public
|
|
@@ -1186,17 +1186,18 @@ export interface IAiImageGenerationResponse {
|
|
|
1186
1186
|
* Model IDs for Anthropic thinking-capable models.
|
|
1187
1187
|
*
|
|
1188
1188
|
* @remarks
|
|
1189
|
-
* Only thinking-capable lines are listed. The non-tier `@anthropic:haiku`
|
|
1190
|
-
*
|
|
1191
|
-
*
|
|
1189
|
+
* Only thinking-capable lines are listed. The non-tier `@anthropic:haiku` alias (reachable via
|
|
1190
|
+
* `modelOverride` only) is deliberately omitted — it is not documented as thinking-capable, so
|
|
1191
|
+
* naming it in a thinking-model filter would be misleading. `claude-fable-5` (the `@anthropic:fable`
|
|
1192
|
+
* non-tier alias) is thinking-capable and reachable via `modelOverride`, so it is listed.
|
|
1192
1193
|
* @public
|
|
1193
1194
|
*/
|
|
1194
|
-
export type AnthropicThinkingModelNames = 'claude-sonnet-4-5' | 'claude-sonnet-4-6' | 'claude-sonnet-5' | 'claude-opus-4-6' | 'claude-opus-4-7' | 'claude-opus-4-8';
|
|
1195
|
+
export type AnthropicThinkingModelNames = 'claude-sonnet-4-5' | 'claude-sonnet-4-6' | 'claude-sonnet-5' | 'claude-opus-4-6' | 'claude-opus-4-7' | 'claude-opus-4-8' | 'claude-opus-5' | 'claude-fable-5';
|
|
1195
1196
|
/**
|
|
1196
1197
|
* Model IDs for OpenAI thinking-capable models.
|
|
1197
1198
|
* @public
|
|
1198
1199
|
*/
|
|
1199
|
-
export type OpenAiThinkingModelNames = 'o3' | 'o4-mini' | 'o3-deep-research' | 'o4-mini-deep-research' | 'gpt-5' | 'gpt-5.1' | 'gpt-5.2' | 'gpt-5.4-mini' | 'gpt-5.5' | 'gpt-5.5-pro' | 'gpt-5-pro';
|
|
1200
|
+
export type OpenAiThinkingModelNames = 'o3' | 'o4-mini' | 'o3-deep-research' | 'o4-mini-deep-research' | 'gpt-5' | 'gpt-5.1' | 'gpt-5.2' | 'gpt-5.4-mini' | 'gpt-5.5' | 'gpt-5.5-pro' | 'gpt-5.6-sol' | 'gpt-5.6-terra' | 'gpt-5.6-luna' | 'gpt-5-pro';
|
|
1200
1201
|
/**
|
|
1201
1202
|
* Model IDs for Google Gemini thinking-capable models.
|
|
1202
1203
|
* @public
|