@fgv/ts-extras 5.1.0-27 → 5.1.0-29

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 (73) hide show
  1. package/dist/index.browser.js +2 -1
  2. package/dist/index.browser.js.map +1 -1
  3. package/dist/packlets/crypto-utils/converters.js +24 -4
  4. package/dist/packlets/crypto-utils/converters.js.map +1 -1
  5. package/dist/packlets/crypto-utils/hpkeProvider.js +333 -0
  6. package/dist/packlets/crypto-utils/hpkeProvider.js.map +1 -0
  7. package/dist/packlets/crypto-utils/index.browser.js +3 -0
  8. package/dist/packlets/crypto-utils/index.browser.js.map +1 -1
  9. package/dist/packlets/crypto-utils/index.js +2 -0
  10. package/dist/packlets/crypto-utils/index.js.map +1 -1
  11. package/dist/packlets/crypto-utils/keystore/converters.js +2 -2
  12. package/dist/packlets/crypto-utils/keystore/converters.js.map +1 -1
  13. package/dist/packlets/crypto-utils/keystore/keyStore.js +108 -3
  14. package/dist/packlets/crypto-utils/keystore/keyStore.js.map +1 -1
  15. package/dist/packlets/crypto-utils/keystore/model.js.map +1 -1
  16. package/dist/packlets/crypto-utils/model.js +21 -0
  17. package/dist/packlets/crypto-utils/model.js.map +1 -1
  18. package/dist/packlets/crypto-utils/nodeCryptoProvider.js +74 -0
  19. package/dist/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -1
  20. package/dist/packlets/mustache/index.js.map +1 -1
  21. package/dist/packlets/mustache/interfaces.js.map +1 -1
  22. package/dist/packlets/mustache/mustacheTemplate.js +42 -4
  23. package/dist/packlets/mustache/mustacheTemplate.js.map +1 -1
  24. package/dist/ts-extras.d.ts +472 -18
  25. package/dist/tsdoc-metadata.json +1 -1
  26. package/lib/index.browser.d.ts +2 -1
  27. package/lib/index.browser.d.ts.map +1 -1
  28. package/lib/index.browser.js +3 -1
  29. package/lib/index.browser.js.map +1 -1
  30. package/lib/packlets/crypto-utils/converters.d.ts +12 -1
  31. package/lib/packlets/crypto-utils/converters.d.ts.map +1 -1
  32. package/lib/packlets/crypto-utils/converters.js +25 -5
  33. package/lib/packlets/crypto-utils/converters.js.map +1 -1
  34. package/lib/packlets/crypto-utils/hpkeProvider.d.ts +142 -0
  35. package/lib/packlets/crypto-utils/hpkeProvider.d.ts.map +1 -0
  36. package/lib/packlets/crypto-utils/hpkeProvider.js +337 -0
  37. package/lib/packlets/crypto-utils/hpkeProvider.js.map +1 -0
  38. package/lib/packlets/crypto-utils/index.browser.d.ts +1 -0
  39. package/lib/packlets/crypto-utils/index.browser.d.ts.map +1 -1
  40. package/lib/packlets/crypto-utils/index.browser.js +5 -1
  41. package/lib/packlets/crypto-utils/index.browser.js.map +1 -1
  42. package/lib/packlets/crypto-utils/index.d.ts +1 -0
  43. package/lib/packlets/crypto-utils/index.d.ts.map +1 -1
  44. package/lib/packlets/crypto-utils/index.js +4 -1
  45. package/lib/packlets/crypto-utils/index.js.map +1 -1
  46. package/lib/packlets/crypto-utils/keystore/converters.js +1 -1
  47. package/lib/packlets/crypto-utils/keystore/converters.js.map +1 -1
  48. package/lib/packlets/crypto-utils/keystore/keyStore.d.ts +32 -2
  49. package/lib/packlets/crypto-utils/keystore/keyStore.d.ts.map +1 -1
  50. package/lib/packlets/crypto-utils/keystore/keyStore.js +116 -11
  51. package/lib/packlets/crypto-utils/keystore/keyStore.js.map +1 -1
  52. package/lib/packlets/crypto-utils/keystore/model.d.ts +21 -3
  53. package/lib/packlets/crypto-utils/keystore/model.d.ts.map +1 -1
  54. package/lib/packlets/crypto-utils/keystore/model.js.map +1 -1
  55. package/lib/packlets/crypto-utils/model.d.ts +165 -9
  56. package/lib/packlets/crypto-utils/model.d.ts.map +1 -1
  57. package/lib/packlets/crypto-utils/model.js +22 -1
  58. package/lib/packlets/crypto-utils/model.js.map +1 -1
  59. package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts +39 -0
  60. package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts.map +1 -1
  61. package/lib/packlets/crypto-utils/nodeCryptoProvider.js +74 -0
  62. package/lib/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -1
  63. package/lib/packlets/mustache/index.d.ts +1 -1
  64. package/lib/packlets/mustache/index.d.ts.map +1 -1
  65. package/lib/packlets/mustache/index.js.map +1 -1
  66. package/lib/packlets/mustache/interfaces.d.ts +34 -0
  67. package/lib/packlets/mustache/interfaces.d.ts.map +1 -1
  68. package/lib/packlets/mustache/interfaces.js.map +1 -1
  69. package/lib/packlets/mustache/mustacheTemplate.d.ts +2 -0
  70. package/lib/packlets/mustache/mustacheTemplate.d.ts.map +1 -1
  71. package/lib/packlets/mustache/mustacheTemplate.js +42 -4
  72. package/lib/packlets/mustache/mustacheTemplate.js.map +1 -1
  73. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"nodeCryptoProvider.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/nodeCryptoProvider.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2024 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 * as crypto from 'crypto';\nimport {\n captureAsyncResult,\n captureResult,\n fail,\n Failure,\n generateUuid,\n Result,\n succeed,\n Success,\n Uuid\n} from '@fgv/ts-utils';\nimport * as Constants from './constants';\nimport { keyPairAlgorithmParams } from './keyPairAlgorithmParams';\nimport {\n ICryptoProvider,\n IEncryptionResult,\n IWrapBytesOptions,\n IWrappedBytes,\n KeyPairAlgorithm\n} from './model';\n\n/**\n * Node.js implementation of {@link CryptoUtils.ICryptoProvider} using the built-in crypto module.\n * Uses AES-256-GCM for authenticated encryption.\n * @public\n */\nexport class NodeCryptoProvider implements ICryptoProvider {\n /**\n * Encrypts plaintext using AES-256-GCM.\n * @param plaintext - UTF-8 string to encrypt\n * @param key - 32-byte encryption key\n * @returns `Success` with encryption result, or `Failure` with an error.\n */\n public async encrypt(plaintext: string, key: Uint8Array): Promise<Result<IEncryptionResult>> {\n return captureResult(() => {\n if (key.length !== Constants.AES_256_KEY_SIZE) {\n throw new Error(`Key must be ${Constants.AES_256_KEY_SIZE} bytes, got ${key.length}`);\n }\n\n // Generate random IV\n const iv = crypto.randomBytes(Constants.GCM_IV_SIZE);\n\n // Create cipher\n const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);\n\n // Encrypt\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n\n // Get auth tag\n const authTag = cipher.getAuthTag();\n\n return {\n iv: new Uint8Array(iv),\n authTag: new Uint8Array(authTag),\n encryptedData: new Uint8Array(encrypted)\n };\n });\n }\n\n /**\n * Decrypts ciphertext using AES-256-GCM.\n * @param encryptedData - Encrypted bytes\n * @param key - 32-byte decryption key\n * @param iv - Initialization vector (12 bytes)\n * @param authTag - GCM authentication tag (16 bytes)\n * @returns `Success` with decrypted UTF-8 string, or `Failure` with an error.\n */\n public async decrypt(\n encryptedData: Uint8Array,\n key: Uint8Array,\n iv: Uint8Array,\n authTag: Uint8Array\n ): Promise<Result<string>> {\n if (key.length !== Constants.AES_256_KEY_SIZE) {\n return fail(`Key must be ${Constants.AES_256_KEY_SIZE} bytes, got ${key.length}`);\n }\n if (iv.length !== Constants.GCM_IV_SIZE) {\n return fail(`IV must be ${Constants.GCM_IV_SIZE} bytes, got ${iv.length}`);\n }\n if (authTag.length !== Constants.GCM_AUTH_TAG_SIZE) {\n return fail(`Auth tag must be ${Constants.GCM_AUTH_TAG_SIZE} bytes, got ${authTag.length}`);\n }\n\n return captureResult(() => {\n // Create decipher\n const decipher = crypto.createDecipheriv('aes-256-gcm', Buffer.from(key), Buffer.from(iv));\n\n // Set auth tag\n decipher.setAuthTag(Buffer.from(authTag));\n\n // Decrypt\n const decrypted = Buffer.concat([decipher.update(Buffer.from(encryptedData)), decipher.final()]);\n\n return decrypted.toString('utf8');\n }).withErrorFormat((e) => `Decryption failed: ${e}`);\n }\n\n /**\n * Generates a random 32-byte key suitable for AES-256.\n * @returns `Success` with generated key, or `Failure` with an error.\n */\n public async generateKey(): Promise<Result<Uint8Array>> {\n return captureResult(() => {\n const key = crypto.randomBytes(Constants.AES_256_KEY_SIZE);\n return new Uint8Array(key);\n });\n }\n\n /**\n * Derives a key from a password using PBKDF2.\n * @param password - Password string\n * @param salt - Salt bytes (should be at least 16 bytes)\n * @param iterations - Number of iterations (recommend 100000+)\n * @returns `Success` with derived 32-byte key, or `Failure` with an error.\n */\n public async deriveKey(\n password: string,\n salt: Uint8Array,\n iterations: number\n ): Promise<Result<Uint8Array>> {\n if (iterations < 1) {\n return fail('Iterations must be at least 1');\n }\n if (salt.length < 8) {\n return fail('Salt should be at least 8 bytes');\n }\n\n return new Promise((resolve) => {\n crypto.pbkdf2(\n password,\n Buffer.from(salt),\n iterations,\n Constants.AES_256_KEY_SIZE,\n 'sha256',\n (err, derivedKey) => {\n /* c8 ignore next 3 - PBKDF2 internal errors are hard to trigger with valid parameters */\n if (err) {\n resolve(fail(`Key derivation failed: ${err.message}`));\n } else {\n resolve(succeed(new Uint8Array(derivedKey)));\n }\n }\n );\n });\n }\n\n /**\n * Computes a SHA-256 hash of the given data.\n * @param data - UTF-8 string to hash\n * @returns `Success` with hex-encoded hash string, or `Failure` with an error.\n */\n public async sha256(data: string): Promise<Result<string>> {\n return captureResult(() => {\n const hash = crypto.createHash('sha256');\n hash.update(data, 'utf8');\n return hash.digest('hex');\n });\n }\n\n // ============================================================================\n // Platform Utility Methods\n // ============================================================================\n\n /**\n * Generates cryptographically secure random bytes.\n * @param length - Number of bytes to generate\n * @returns Success with random bytes, or Failure with error\n */\n public generateRandomBytes(length: number): Result<Uint8Array> {\n if (length < 1) {\n return Failure.with('Length must be at least 1');\n }\n return captureResult(() => new Uint8Array(crypto.randomBytes(length)));\n }\n\n /**\n * Generates a cryptographically random UUIDv4 via the platform Web Crypto API.\n * @returns `Success` with the generated UUID, or `Failure` if the runtime\n * does not expose `globalThis.crypto.randomUUID`.\n */\n public generateUuid(): Result<Uuid> {\n return captureResult(() => generateUuid());\n }\n\n /**\n * Encodes binary data to base64 string.\n * @param data - Binary data to encode\n * @returns Base64-encoded string\n */\n public toBase64(data: Uint8Array): string {\n return Buffer.from(data).toString('base64');\n }\n\n /**\n * Decodes base64 string to binary data.\n * @param base64 - Base64-encoded string\n * @returns Success with decoded bytes, or Failure if invalid base64\n */\n public fromBase64(base64: string): Result<Uint8Array> {\n // Check for obviously invalid characters\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(base64)) {\n return Failure.with('Invalid base64 string');\n }\n return Success.with(new Uint8Array(Buffer.from(base64, 'base64')));\n }\n\n // ============================================================================\n // Asymmetric Key Operations\n // ============================================================================\n\n /**\n * Generates a new asymmetric keypair using Node's WebCrypto.\n * @param algorithm - The {@link CryptoUtils.KeyPairAlgorithm | algorithm} to use.\n * @param extractable - Whether the resulting keys may be exported.\n * @returns `Success` with the generated `CryptoKeyPair`, or `Failure` with an error.\n */\n public async generateKeyPair(\n algorithm: KeyPairAlgorithm,\n extractable: boolean\n ): Promise<Result<CryptoKeyPair>> {\n const params = keyPairAlgorithmParams[algorithm];\n // Widening upcast to `AlgorithmIdentifier` steers TS to subtle.generateKey's\n // broad overload, which accepts the Ed25519 `{ name: 'Ed25519' }` shape and\n // returns `CryptoKey | CryptoKeyPair`. The narrowing back to `CryptoKeyPair`\n // is a runtime check via the `in` operator, not a type assertion.\n const result = await captureAsyncResult(async () => {\n const generated = await crypto.webcrypto.subtle.generateKey(\n params.generateKey as AlgorithmIdentifier,\n extractable,\n [...params.keyPairUsages]\n );\n if ('privateKey' in generated && 'publicKey' in generated) {\n return generated;\n }\n /* c8 ignore next - unreachable: every entry in keyPairAlgorithmParams produces a keypair */\n throw new Error(`${algorithm} unexpectedly produced a single CryptoKey`);\n });\n return result.withErrorFormat((e) => `Failed to generate ${algorithm} keypair: ${e}`);\n }\n\n /**\n * Exports a public `CryptoKey` as a JSON Web Key.\n * @remarks\n * Rejects non-public keys at runtime. WebCrypto's `exportKey('jwk', ...)`\n * does not enforce public-vs-private; without this guard a caller that\n * passed an extractable private key would receive its private fields\n * (`d`, `p`, `q`, ...) as JWK, defeating the method's name.\n * @param publicKey - Extractable public key to export.\n * @returns `Success` with the JWK, or `Failure` if not a public key or if export fails.\n */\n public async exportPublicKeyJwk(publicKey: CryptoKey): Promise<Result<JsonWebKey>> {\n if (publicKey.type !== 'public') {\n return fail(`exportPublicKeyJwk requires a public CryptoKey, got '${publicKey.type}'`);\n }\n const result = await captureAsyncResult(() => crypto.webcrypto.subtle.exportKey('jwk', publicKey));\n return result.withErrorFormat((e) => `Failed to export public key as JWK: ${e}`);\n }\n\n /**\n * Imports a public-key JWK as a `CryptoKey` for the requested algorithm.\n * @param jwk - The JSON Web Key produced by a prior export.\n * @param algorithm - The algorithm the key was generated for.\n * @returns `Success` with the imported public `CryptoKey`, or `Failure` with an error.\n */\n public async importPublicKeyJwk(jwk: JsonWebKey, algorithm: KeyPairAlgorithm): Promise<Result<CryptoKey>> {\n const params = keyPairAlgorithmParams[algorithm];\n const result = await captureAsyncResult(() =>\n crypto.webcrypto.subtle.importKey('jwk', jwk, params.importPublicKey, true, params.publicKeyUsages)\n );\n return result.withErrorFormat((e) => `Failed to import ${algorithm} public key from JWK: ${e}`);\n }\n\n /**\n * Exports a public `CryptoKey` as a DER-encoded SPKI blob.\n * @param publicKey - The public `CryptoKey` to export.\n * @returns `Success` with the raw SPKI bytes, or `Failure` with error context.\n */\n public async exportPublicKeySpki(publicKey: CryptoKey): Promise<Result<Uint8Array>> {\n if (publicKey.type !== 'public') {\n return fail(`exportPublicKeySpki requires a public CryptoKey, got '${publicKey.type}'`);\n }\n const result = await captureAsyncResult(() => crypto.webcrypto.subtle.exportKey('spki', publicKey));\n return result\n .withErrorFormat((e) => `exportPublicKeySpki: failed to export key: ${e}`)\n .onSuccess((buf) => succeed(new Uint8Array(buf)));\n }\n\n /**\n * Imports a public key from a DER-encoded SPKI blob.\n * @param spkiBytes - The raw SPKI bytes.\n * @param algorithm - The algorithm the key was generated for.\n * @returns `Success` with the imported public `CryptoKey`, or `Failure` with error context.\n */\n public async importPublicKeySpki(\n spkiBytes: Uint8Array,\n algorithm: KeyPairAlgorithm\n ): Promise<Result<CryptoKey>> {\n const params = keyPairAlgorithmParams[algorithm];\n const result = await captureAsyncResult(() =>\n crypto.webcrypto.subtle.importKey(\n 'spki',\n spkiBytes,\n params.importPublicKey as AlgorithmIdentifier,\n true,\n [...params.publicKeyUsages]\n )\n );\n return result.withErrorFormat(\n (e) => `importPublicKeySpki: failed to import ${algorithm} public key from SPKI: ${e}`\n );\n }\n\n /**\n * Wraps `plaintext` for the holder of `recipientPublicKey` using\n * ECIES (ECDH P-256 + HKDF-SHA256 + AES-GCM-256). See\n * {@link CryptoUtils.ICryptoProvider.wrapBytes | ICryptoProvider.wrapBytes}.\n * @param plaintext - The bytes to wrap.\n * @param recipientPublicKey - The recipient's ECDH P-256 public `CryptoKey`.\n * @param options - HKDF salt and info; see {@link CryptoUtils.IWrapBytesOptions | IWrapBytesOptions}.\n * @returns `Success` with the wrapped payload, or `Failure` with an error.\n */\n public async wrapBytes(\n plaintext: Uint8Array,\n recipientPublicKey: CryptoKey,\n options: IWrapBytesOptions\n ): Promise<Result<IWrappedBytes>> {\n const recipientCheck = checkEcdhP256(recipientPublicKey, 'public', 'recipient public key');\n if (recipientCheck.isFailure()) {\n return fail(`wrapBytes failed: ${recipientCheck.message}`);\n }\n const subtle = crypto.webcrypto.subtle;\n const result = await captureAsyncResult(async () => {\n const ephemeral = (await subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, true, [\n 'deriveKey'\n ])) as CryptoKeyPair;\n const hkdfBase = await subtle.deriveKey(\n { name: 'ECDH', public: recipientPublicKey },\n ephemeral.privateKey,\n { name: 'HKDF' },\n false,\n ['deriveKey']\n );\n const wrapKey = await subtle.deriveKey(\n { name: 'HKDF', salt: options.salt, info: options.info, hash: 'SHA-256' },\n hkdfBase,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt']\n );\n const nonce = crypto.randomBytes(Constants.GCM_IV_SIZE);\n const ctBuf = await subtle.encrypt({ name: 'AES-GCM', iv: nonce }, wrapKey, plaintext);\n const ephemeralPublicKey = await subtle.exportKey('jwk', ephemeral.publicKey);\n return {\n ephemeralPublicKey,\n nonce: this.toBase64(nonce),\n ciphertext: this.toBase64(new Uint8Array(ctBuf))\n };\n });\n return result.withErrorFormat((e) => `wrapBytes failed: ${e}`);\n }\n\n /**\n * Unwraps a payload produced by `wrapBytes` using the recipient's private\n * key. See {@link CryptoUtils.ICryptoProvider.unwrapBytes | ICryptoProvider.unwrapBytes}.\n * @param wrapped - The wrapped payload.\n * @param recipientPrivateKey - The recipient's ECDH P-256 private `CryptoKey`.\n * @param options - HKDF salt and info matching the wrap call.\n * @returns `Success` with the original `plaintext`, or `Failure` with an error.\n */\n public async unwrapBytes(\n wrapped: IWrappedBytes,\n recipientPrivateKey: CryptoKey,\n options: IWrapBytesOptions\n ): Promise<Result<Uint8Array>> {\n const recipientCheck = checkEcdhP256(recipientPrivateKey, 'private', 'recipient private key');\n if (recipientCheck.isFailure()) {\n return fail(`unwrapBytes failed: ${recipientCheck.message}`);\n }\n const nonceResult = this.fromBase64(wrapped.nonce);\n if (nonceResult.isFailure()) {\n return fail(`unwrapBytes failed: nonce: ${nonceResult.message}`);\n }\n if (nonceResult.value.length !== Constants.GCM_IV_SIZE) {\n return fail(\n `unwrapBytes failed: nonce must be ${Constants.GCM_IV_SIZE} bytes (got ${nonceResult.value.length})`\n );\n }\n const ciphertextResult = this.fromBase64(wrapped.ciphertext);\n if (ciphertextResult.isFailure()) {\n return fail(`unwrapBytes failed: ciphertext: ${ciphertextResult.message}`);\n }\n if (ciphertextResult.value.length < Constants.GCM_AUTH_TAG_SIZE) {\n return fail(\n `unwrapBytes failed: ciphertext must be at least ${Constants.GCM_AUTH_TAG_SIZE} bytes (got ${ciphertextResult.value.length})`\n );\n }\n const subtle = crypto.webcrypto.subtle;\n const result = await captureAsyncResult(async () => {\n const ephemeralPub = await subtle.importKey(\n 'jwk',\n wrapped.ephemeralPublicKey,\n { name: 'ECDH', namedCurve: 'P-256' },\n false,\n []\n );\n const hkdfBase = await subtle.deriveKey(\n { name: 'ECDH', public: ephemeralPub },\n recipientPrivateKey,\n { name: 'HKDF' },\n false,\n ['deriveKey']\n );\n const wrapKey = await subtle.deriveKey(\n { name: 'HKDF', salt: options.salt, info: options.info, hash: 'SHA-256' },\n hkdfBase,\n { name: 'AES-GCM', length: 256 },\n false,\n ['decrypt']\n );\n const ptBuf = await subtle.decrypt(\n { name: 'AES-GCM', iv: nonceResult.value },\n wrapKey,\n ciphertextResult.value\n );\n return new Uint8Array(ptBuf);\n });\n return result.withErrorFormat((e) => `unwrapBytes failed: ${e}`);\n }\n}\n\n/**\n * Verifies that `key` is an ECDH P-256 `CryptoKey` of the expected `keyType`\n * (public or private). Used by the wrap/unwrap methods to surface a clean\n * `Failure` instead of letting the WebCrypto deriveKey call throw a less\n * informative error later in the pipeline. Key usages are intentionally not\n * checked here: WebCrypto already produces a specific error if `deriveKey` is\n * not in `usages`, and `deriveBits` is an equally valid alternative usage that\n * an explicit check would have to track.\n * @param key - The CryptoKey to validate.\n * @param keyType - The required `key.type` ('public' for wrap, 'private' for unwrap).\n * @param label - Human-readable role label included in the failure message.\n * @returns `Success` with the key (unchanged) when the algorithm, curve, and\n * type all match; otherwise `Failure` with `<label> must be ECDH P-256 (...)`.\n */\nfunction checkEcdhP256(key: CryptoKey, keyType: 'public' | 'private', label: string): Result<CryptoKey> {\n if (key.algorithm.name !== 'ECDH') {\n return fail(`${label} must be ECDH P-256 (got algorithm '${key.algorithm.name}')`);\n }\n const namedCurve = (key.algorithm as EcKeyAlgorithm).namedCurve;\n if (namedCurve !== 'P-256') {\n return fail(`${label} must be ECDH P-256 (got curve '${namedCurve}')`);\n }\n if (key.type !== keyType) {\n return fail(`${label} must be a ${keyType} CryptoKey (got '${key.type}')`);\n }\n return succeed(key);\n}\n\n/**\n * Singleton instance of {@link CryptoUtils.NodeCryptoProvider}.\n * @public\n */\nexport const nodeCryptoProvider: NodeCryptoProvider = new NodeCryptoProvider();\n"]}
1
+ {"version":3,"file":"nodeCryptoProvider.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/nodeCryptoProvider.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2024 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 * as crypto from 'crypto';\nimport {\n captureAsyncResult,\n captureResult,\n fail,\n Failure,\n generateUuid,\n Result,\n succeed,\n Success,\n Uuid\n} from '@fgv/ts-utils';\nimport * as Constants from './constants';\nimport { keyPairAlgorithmParams } from './keyPairAlgorithmParams';\nimport {\n ICryptoProvider,\n IEncryptionResult,\n IWrapBytesOptions,\n IWrappedBytes,\n KeyPairAlgorithm\n} from './model';\n\n/**\n * Node.js implementation of {@link CryptoUtils.ICryptoProvider} using the built-in crypto module.\n * Uses AES-256-GCM for authenticated encryption.\n * @public\n */\nexport class NodeCryptoProvider implements ICryptoProvider {\n /**\n * Encrypts plaintext using AES-256-GCM.\n * @param plaintext - UTF-8 string to encrypt\n * @param key - 32-byte encryption key\n * @returns `Success` with encryption result, or `Failure` with an error.\n */\n public async encrypt(plaintext: string, key: Uint8Array): Promise<Result<IEncryptionResult>> {\n return captureResult(() => {\n if (key.length !== Constants.AES_256_KEY_SIZE) {\n throw new Error(`Key must be ${Constants.AES_256_KEY_SIZE} bytes, got ${key.length}`);\n }\n\n // Generate random IV\n const iv = crypto.randomBytes(Constants.GCM_IV_SIZE);\n\n // Create cipher\n const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);\n\n // Encrypt\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n\n // Get auth tag\n const authTag = cipher.getAuthTag();\n\n return {\n iv: new Uint8Array(iv),\n authTag: new Uint8Array(authTag),\n encryptedData: new Uint8Array(encrypted)\n };\n });\n }\n\n /**\n * Decrypts ciphertext using AES-256-GCM.\n * @param encryptedData - Encrypted bytes\n * @param key - 32-byte decryption key\n * @param iv - Initialization vector (12 bytes)\n * @param authTag - GCM authentication tag (16 bytes)\n * @returns `Success` with decrypted UTF-8 string, or `Failure` with an error.\n */\n public async decrypt(\n encryptedData: Uint8Array,\n key: Uint8Array,\n iv: Uint8Array,\n authTag: Uint8Array\n ): Promise<Result<string>> {\n if (key.length !== Constants.AES_256_KEY_SIZE) {\n return fail(`Key must be ${Constants.AES_256_KEY_SIZE} bytes, got ${key.length}`);\n }\n if (iv.length !== Constants.GCM_IV_SIZE) {\n return fail(`IV must be ${Constants.GCM_IV_SIZE} bytes, got ${iv.length}`);\n }\n if (authTag.length !== Constants.GCM_AUTH_TAG_SIZE) {\n return fail(`Auth tag must be ${Constants.GCM_AUTH_TAG_SIZE} bytes, got ${authTag.length}`);\n }\n\n return captureResult(() => {\n // Create decipher\n const decipher = crypto.createDecipheriv('aes-256-gcm', Buffer.from(key), Buffer.from(iv));\n\n // Set auth tag\n decipher.setAuthTag(Buffer.from(authTag));\n\n // Decrypt\n const decrypted = Buffer.concat([decipher.update(Buffer.from(encryptedData)), decipher.final()]);\n\n return decrypted.toString('utf8');\n }).withErrorFormat((e) => `Decryption failed: ${e}`);\n }\n\n /**\n * Generates a random 32-byte key suitable for AES-256.\n * @returns `Success` with generated key, or `Failure` with an error.\n */\n public async generateKey(): Promise<Result<Uint8Array>> {\n return captureResult(() => {\n const key = crypto.randomBytes(Constants.AES_256_KEY_SIZE);\n return new Uint8Array(key);\n });\n }\n\n /**\n * Derives a key from a password using PBKDF2.\n * @param password - Password string\n * @param salt - Salt bytes (should be at least 16 bytes)\n * @param iterations - Number of iterations (recommend 100000+)\n * @returns `Success` with derived 32-byte key, or `Failure` with an error.\n */\n public async deriveKey(\n password: string,\n salt: Uint8Array,\n iterations: number\n ): Promise<Result<Uint8Array>> {\n if (iterations < 1) {\n return fail('Iterations must be at least 1');\n }\n if (salt.length < 8) {\n return fail('Salt should be at least 8 bytes');\n }\n\n return new Promise((resolve) => {\n crypto.pbkdf2(\n password,\n Buffer.from(salt),\n iterations,\n Constants.AES_256_KEY_SIZE,\n 'sha256',\n (err, derivedKey) => {\n /* c8 ignore next 3 - PBKDF2 internal errors are hard to trigger with valid parameters */\n if (err) {\n resolve(fail(`Key derivation failed: ${err.message}`));\n } else {\n resolve(succeed(new Uint8Array(derivedKey)));\n }\n }\n );\n });\n }\n\n /**\n * Computes a SHA-256 hash of the given data.\n * @param data - UTF-8 string to hash\n * @returns `Success` with hex-encoded hash string, or `Failure` with an error.\n */\n public async sha256(data: string): Promise<Result<string>> {\n return captureResult(() => {\n const hash = crypto.createHash('sha256');\n hash.update(data, 'utf8');\n return hash.digest('hex');\n });\n }\n\n // ============================================================================\n // Platform Utility Methods\n // ============================================================================\n\n /**\n * Generates cryptographically secure random bytes.\n * @param length - Number of bytes to generate\n * @returns Success with random bytes, or Failure with error\n */\n public generateRandomBytes(length: number): Result<Uint8Array> {\n if (length < 1) {\n return Failure.with('Length must be at least 1');\n }\n return captureResult(() => new Uint8Array(crypto.randomBytes(length)));\n }\n\n /**\n * Generates a cryptographically random UUIDv4 via the platform Web Crypto API.\n * @returns `Success` with the generated UUID, or `Failure` if the runtime\n * does not expose `globalThis.crypto.randomUUID`.\n */\n public generateUuid(): Result<Uuid> {\n return captureResult(() => generateUuid());\n }\n\n /**\n * Encodes binary data to base64 string.\n * @param data - Binary data to encode\n * @returns Base64-encoded string\n */\n public toBase64(data: Uint8Array): string {\n return Buffer.from(data).toString('base64');\n }\n\n /**\n * Decodes base64 string to binary data.\n * @param base64 - Base64-encoded string\n * @returns Success with decoded bytes, or Failure if invalid base64\n */\n public fromBase64(base64: string): Result<Uint8Array> {\n // Check for obviously invalid characters\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(base64)) {\n return Failure.with('Invalid base64 string');\n }\n return Success.with(new Uint8Array(Buffer.from(base64, 'base64')));\n }\n\n // ============================================================================\n // Asymmetric Key Operations\n // ============================================================================\n\n /**\n * Generates a new asymmetric keypair using Node's WebCrypto.\n * @param algorithm - The {@link CryptoUtils.KeyPairAlgorithm | algorithm} to use.\n * @param extractable - Whether the resulting keys may be exported.\n * @returns `Success` with the generated `CryptoKeyPair`, or `Failure` with an error.\n */\n public async generateKeyPair(\n algorithm: KeyPairAlgorithm,\n extractable: boolean\n ): Promise<Result<CryptoKeyPair>> {\n const params = keyPairAlgorithmParams[algorithm];\n // Widening upcast to `AlgorithmIdentifier` steers TS to subtle.generateKey's\n // broad overload, which accepts the Ed25519 `{ name: 'Ed25519' }` shape and\n // returns `CryptoKey | CryptoKeyPair`. The narrowing back to `CryptoKeyPair`\n // is a runtime check via the `in` operator, not a type assertion.\n const result = await captureAsyncResult(async () => {\n const generated = await crypto.webcrypto.subtle.generateKey(\n params.generateKey as AlgorithmIdentifier,\n extractable,\n [...params.keyPairUsages]\n );\n if ('privateKey' in generated && 'publicKey' in generated) {\n return generated;\n }\n /* c8 ignore next - unreachable: every entry in keyPairAlgorithmParams produces a keypair */\n throw new Error(`${algorithm} unexpectedly produced a single CryptoKey`);\n });\n return result.withErrorFormat((e) => `Failed to generate ${algorithm} keypair: ${e}`);\n }\n\n /**\n * Exports a public `CryptoKey` as a JSON Web Key.\n * @remarks\n * Rejects non-public keys at runtime. WebCrypto's `exportKey('jwk', ...)`\n * does not enforce public-vs-private; without this guard a caller that\n * passed an extractable private key would receive its private fields\n * (`d`, `p`, `q`, ...) as JWK, defeating the method's name.\n * @param publicKey - Extractable public key to export.\n * @returns `Success` with the JWK, or `Failure` if not a public key or if export fails.\n */\n public async exportPublicKeyJwk(publicKey: CryptoKey): Promise<Result<JsonWebKey>> {\n if (publicKey.type !== 'public') {\n return fail(`exportPublicKeyJwk requires a public CryptoKey, got '${publicKey.type}'`);\n }\n const result = await captureAsyncResult(() => crypto.webcrypto.subtle.exportKey('jwk', publicKey));\n return result.withErrorFormat((e) => `Failed to export public key as JWK: ${e}`);\n }\n\n /**\n * Imports a public-key JWK as a `CryptoKey` for the requested algorithm.\n * @param jwk - The JSON Web Key produced by a prior export.\n * @param algorithm - The algorithm the key was generated for.\n * @returns `Success` with the imported public `CryptoKey`, or `Failure` with an error.\n */\n public async importPublicKeyJwk(jwk: JsonWebKey, algorithm: KeyPairAlgorithm): Promise<Result<CryptoKey>> {\n const params = keyPairAlgorithmParams[algorithm];\n const result = await captureAsyncResult(() =>\n crypto.webcrypto.subtle.importKey('jwk', jwk, params.importPublicKey, true, params.publicKeyUsages)\n );\n return result.withErrorFormat((e) => `Failed to import ${algorithm} public key from JWK: ${e}`);\n }\n\n /**\n * Exports a public `CryptoKey` as a DER-encoded SPKI blob.\n * @param publicKey - The public `CryptoKey` to export.\n * @returns `Success` with the raw SPKI bytes, or `Failure` with error context.\n */\n public async exportPublicKeySpki(publicKey: CryptoKey): Promise<Result<Uint8Array>> {\n if (publicKey.type !== 'public') {\n return fail(`exportPublicKeySpki requires a public CryptoKey, got '${publicKey.type}'`);\n }\n const result = await captureAsyncResult(() => crypto.webcrypto.subtle.exportKey('spki', publicKey));\n return result\n .withErrorFormat((e) => `exportPublicKeySpki: failed to export key: ${e}`)\n .onSuccess((buf) => succeed(new Uint8Array(buf)));\n }\n\n /**\n * Imports a public key from a DER-encoded SPKI blob.\n * @param spkiBytes - The raw SPKI bytes.\n * @param algorithm - The algorithm the key was generated for.\n * @returns `Success` with the imported public `CryptoKey`, or `Failure` with error context.\n */\n public async importPublicKeySpki(\n spkiBytes: Uint8Array,\n algorithm: KeyPairAlgorithm\n ): Promise<Result<CryptoKey>> {\n const params = keyPairAlgorithmParams[algorithm];\n const result = await captureAsyncResult(() =>\n crypto.webcrypto.subtle.importKey(\n 'spki',\n spkiBytes,\n params.importPublicKey as AlgorithmIdentifier,\n true,\n [...params.publicKeyUsages]\n )\n );\n return result.withErrorFormat(\n (e) => `importPublicKeySpki: failed to import ${algorithm} public key from SPKI: ${e}`\n );\n }\n\n /**\n * Signs `data` with `privateKey` using the algorithm inferred from the key.\n * @param privateKey - A signing `CryptoKey` (`'ecdsa-p256'` or `'ed25519'`).\n * @param data - The bytes to sign.\n * @returns `Success` with the raw signature bytes, or `Failure` with error context.\n */\n public async sign(privateKey: CryptoKey, data: Uint8Array): Promise<Result<Uint8Array>> {\n const algorithm = signAlgorithmFromKey(privateKey);\n const result = await captureAsyncResult(() => crypto.webcrypto.subtle.sign(algorithm, privateKey, data));\n return result\n .withErrorFormat((e) => `sign failed: ${e}`)\n .onSuccess((buf) => succeed(new Uint8Array(buf)));\n }\n\n /**\n * Verifies a signature produced by {@link NodeCryptoProvider.sign}.\n * @param publicKey - A verify `CryptoKey` (`'ecdsa-p256'` or `'ed25519'`).\n * @param signature - The raw signature bytes.\n * @param data - The original data that was signed.\n * @returns `Success` with `true` if valid, `false` if not, or `Failure` with error context.\n */\n public async verify(\n publicKey: CryptoKey,\n signature: Uint8Array,\n data: Uint8Array\n ): Promise<Result<boolean>> {\n const algorithm = signAlgorithmFromKey(publicKey);\n const result = await captureAsyncResult(() =>\n crypto.webcrypto.subtle.verify(algorithm, publicKey, signature, data)\n );\n return result.withErrorFormat((e) => `verify failed: ${e}`);\n }\n\n /**\n * Compares two byte arrays in constant time using Node's native\n * `crypto.timingSafeEqual`. Returns `false` for mismatched lengths\n * rather than throwing (Node's native throws on length mismatch).\n * @param a - First byte array.\n * @param b - Second byte array.\n * @returns `true` if lengths match and all bytes are equal, `false` otherwise.\n */\n public timingSafeEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n return crypto.timingSafeEqual(a, b);\n }\n\n /**\n * Computes an HMAC-SHA256 MAC for `data` using `key`.\n * @param key - An HMAC `CryptoKey` with `'sign'` usage.\n * @param data - The bytes to authenticate.\n * @returns `Success` with the 32-byte MAC, or `Failure` with error context.\n */\n public async hmacSha256(key: CryptoKey, data: Uint8Array): Promise<Result<Uint8Array>> {\n const result = await captureAsyncResult(() => crypto.webcrypto.subtle.sign({ name: 'HMAC' }, key, data));\n return result\n .withErrorFormat((e) => `hmacSha256 failed: ${e}`)\n .onSuccess((buf) => succeed(new Uint8Array(buf)));\n }\n\n /**\n * Verifies an HMAC-SHA256 MAC in constant time.\n * @param key - An HMAC `CryptoKey` with `'sign'` usage.\n * @param signature - The MAC bytes to verify.\n * @param data - The original data that was authenticated.\n * @returns `Success` with `true` if valid, `false` if not, or `Failure` with error context.\n */\n public async verifyHmacSha256(\n key: CryptoKey,\n signature: Uint8Array,\n data: Uint8Array\n ): Promise<Result<boolean>> {\n return (await this.hmacSha256(key, data))\n .withErrorFormat((e) => `verifyHmacSha256 failed: ${e}`)\n .onSuccess((mac) => succeed(this.timingSafeEqual(mac, signature)));\n }\n\n /**\n * Wraps `plaintext` for the holder of `recipientPublicKey` using\n * ECIES (ECDH P-256 + HKDF-SHA256 + AES-GCM-256). See\n * {@link CryptoUtils.ICryptoProvider.wrapBytes | ICryptoProvider.wrapBytes}.\n * @param plaintext - The bytes to wrap.\n * @param recipientPublicKey - The recipient's ECDH P-256 public `CryptoKey`.\n * @param options - HKDF salt and info; see {@link CryptoUtils.IWrapBytesOptions | IWrapBytesOptions}.\n * @returns `Success` with the wrapped payload, or `Failure` with an error.\n */\n public async wrapBytes(\n plaintext: Uint8Array,\n recipientPublicKey: CryptoKey,\n options: IWrapBytesOptions\n ): Promise<Result<IWrappedBytes>> {\n const recipientCheck = checkEcdhP256(recipientPublicKey, 'public', 'recipient public key');\n if (recipientCheck.isFailure()) {\n return fail(`wrapBytes failed: ${recipientCheck.message}`);\n }\n const subtle = crypto.webcrypto.subtle;\n const result = await captureAsyncResult(async () => {\n const ephemeral = (await subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, true, [\n 'deriveKey'\n ])) as CryptoKeyPair;\n const hkdfBase = await subtle.deriveKey(\n { name: 'ECDH', public: recipientPublicKey },\n ephemeral.privateKey,\n { name: 'HKDF' },\n false,\n ['deriveKey']\n );\n const wrapKey = await subtle.deriveKey(\n { name: 'HKDF', salt: options.salt, info: options.info, hash: 'SHA-256' },\n hkdfBase,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt']\n );\n const nonce = crypto.randomBytes(Constants.GCM_IV_SIZE);\n const ctBuf = await subtle.encrypt({ name: 'AES-GCM', iv: nonce }, wrapKey, plaintext);\n const ephemeralPublicKey = await subtle.exportKey('jwk', ephemeral.publicKey);\n return {\n ephemeralPublicKey,\n nonce: this.toBase64(nonce),\n ciphertext: this.toBase64(new Uint8Array(ctBuf))\n };\n });\n return result.withErrorFormat((e) => `wrapBytes failed: ${e}`);\n }\n\n /**\n * Unwraps a payload produced by `wrapBytes` using the recipient's private\n * key. See {@link CryptoUtils.ICryptoProvider.unwrapBytes | ICryptoProvider.unwrapBytes}.\n * @param wrapped - The wrapped payload.\n * @param recipientPrivateKey - The recipient's ECDH P-256 private `CryptoKey`.\n * @param options - HKDF salt and info matching the wrap call.\n * @returns `Success` with the original `plaintext`, or `Failure` with an error.\n */\n public async unwrapBytes(\n wrapped: IWrappedBytes,\n recipientPrivateKey: CryptoKey,\n options: IWrapBytesOptions\n ): Promise<Result<Uint8Array>> {\n const recipientCheck = checkEcdhP256(recipientPrivateKey, 'private', 'recipient private key');\n if (recipientCheck.isFailure()) {\n return fail(`unwrapBytes failed: ${recipientCheck.message}`);\n }\n const nonceResult = this.fromBase64(wrapped.nonce);\n if (nonceResult.isFailure()) {\n return fail(`unwrapBytes failed: nonce: ${nonceResult.message}`);\n }\n if (nonceResult.value.length !== Constants.GCM_IV_SIZE) {\n return fail(\n `unwrapBytes failed: nonce must be ${Constants.GCM_IV_SIZE} bytes (got ${nonceResult.value.length})`\n );\n }\n const ciphertextResult = this.fromBase64(wrapped.ciphertext);\n if (ciphertextResult.isFailure()) {\n return fail(`unwrapBytes failed: ciphertext: ${ciphertextResult.message}`);\n }\n if (ciphertextResult.value.length < Constants.GCM_AUTH_TAG_SIZE) {\n return fail(\n `unwrapBytes failed: ciphertext must be at least ${Constants.GCM_AUTH_TAG_SIZE} bytes (got ${ciphertextResult.value.length})`\n );\n }\n const subtle = crypto.webcrypto.subtle;\n const result = await captureAsyncResult(async () => {\n const ephemeralPub = await subtle.importKey(\n 'jwk',\n wrapped.ephemeralPublicKey,\n { name: 'ECDH', namedCurve: 'P-256' },\n false,\n []\n );\n const hkdfBase = await subtle.deriveKey(\n { name: 'ECDH', public: ephemeralPub },\n recipientPrivateKey,\n { name: 'HKDF' },\n false,\n ['deriveKey']\n );\n const wrapKey = await subtle.deriveKey(\n { name: 'HKDF', salt: options.salt, info: options.info, hash: 'SHA-256' },\n hkdfBase,\n { name: 'AES-GCM', length: 256 },\n false,\n ['decrypt']\n );\n const ptBuf = await subtle.decrypt(\n { name: 'AES-GCM', iv: nonceResult.value },\n wrapKey,\n ciphertextResult.value\n );\n return new Uint8Array(ptBuf);\n });\n return result.withErrorFormat((e) => `unwrapBytes failed: ${e}`);\n }\n}\n\n/**\n * Derives the algorithm identifier needed by `crypto.subtle.sign/verify`\n * from the key's embedded `algorithm` property. ECDSA requires an explicit\n * `hash` parameter that is not stored on the key object itself; all other\n * supported signing algorithms (`Ed25519`) use the key algorithm as-is.\n */\nfunction signAlgorithmFromKey(key: CryptoKey): AlgorithmIdentifier | EcdsaParams {\n if (key.algorithm.name === 'ECDSA') {\n return { name: 'ECDSA', hash: 'SHA-256' };\n }\n return key.algorithm as AlgorithmIdentifier;\n}\n\n/**\n * Verifies that `key` is an ECDH P-256 `CryptoKey` of the expected `keyType`\n * (public or private). Used by the wrap/unwrap methods to surface a clean\n * `Failure` instead of letting the WebCrypto deriveKey call throw a less\n * informative error later in the pipeline. Key usages are intentionally not\n * checked here: WebCrypto already produces a specific error if `deriveKey` is\n * not in `usages`, and `deriveBits` is an equally valid alternative usage that\n * an explicit check would have to track.\n * @param key - The CryptoKey to validate.\n * @param keyType - The required `key.type` ('public' for wrap, 'private' for unwrap).\n * @param label - Human-readable role label included in the failure message.\n * @returns `Success` with the key (unchanged) when the algorithm, curve, and\n * type all match; otherwise `Failure` with `<label> must be ECDH P-256 (...)`.\n */\nfunction checkEcdhP256(key: CryptoKey, keyType: 'public' | 'private', label: string): Result<CryptoKey> {\n if (key.algorithm.name !== 'ECDH') {\n return fail(`${label} must be ECDH P-256 (got algorithm '${key.algorithm.name}')`);\n }\n const namedCurve = (key.algorithm as EcKeyAlgorithm).namedCurve;\n if (namedCurve !== 'P-256') {\n return fail(`${label} must be ECDH P-256 (got curve '${namedCurve}')`);\n }\n if (key.type !== keyType) {\n return fail(`${label} must be a ${keyType} CryptoKey (got '${key.type}')`);\n }\n return succeed(key);\n}\n\n/**\n * Singleton instance of {@link CryptoUtils.NodeCryptoProvider}.\n * @public\n */\nexport const nodeCryptoProvider: NodeCryptoProvider = new NodeCryptoProvider();\n"]}
@@ -1,3 +1,3 @@
1
- export { IContextValidationResult, IMissingVariableDetail, IMustacheTemplateOptions, IVariableRef, MustacheTokenType } from './interfaces';
1
+ export { IContextValidationResult, IMissingVariableDetail, IMustacheTemplateOptions, IVariableRef, MustacheEscapeStrategy, MustacheTokenType } from './interfaces';
2
2
  export { MustacheTemplate } from './mustacheTemplate';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/mustache/index.ts"],"names":[],"mappings":"AAsBA,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,YAAY,EACZ,iBAAiB,EAClB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/packlets/mustache/index.ts"],"names":[],"mappings":"AAsBA,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,YAAY,EACZ,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/mustache/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AAUH,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA","sourcesContent":["/*\n * Copyright (c) 2020 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 */\n\nexport {\n IContextValidationResult,\n IMissingVariableDetail,\n IMustacheTemplateOptions,\n IVariableRef,\n MustacheTokenType\n} from './interfaces';\n\nexport { MustacheTemplate } from './mustacheTemplate';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/packlets/mustache/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AAWH,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA","sourcesContent":["/*\n * Copyright (c) 2020 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 */\n\nexport {\n IContextValidationResult,\n IMissingVariableDetail,\n IMustacheTemplateOptions,\n IVariableRef,\n MustacheEscapeStrategy,\n MustacheTokenType\n} from './interfaces';\n\nexport { MustacheTemplate } from './mustacheTemplate';\n"]}
@@ -67,6 +67,22 @@ export interface IContextValidationResult {
67
67
  */
68
68
  readonly missingDetails: readonly IMissingVariableDetail[];
69
69
  }
70
+ /**
71
+ * Strategy applied to double-brace `{{name}}` tokens at render time.
72
+ *
73
+ * - `'html'`: the standard mustache.js HTML escape (back-compat default).
74
+ * - `'none'`: verbatim passthrough — values are interpolated as-is
75
+ * (coerced to `String`). Suitable for LLM-prompt rendering and other
76
+ * non-HTML targets where `& → &amp;` corrupts the output.
77
+ * - `(value) => string`: caller-supplied escape function.
78
+ *
79
+ * Note: triple-brace `{{{name}}}` (and `{{&name}}`) tokens are always
80
+ * rendered unescaped regardless of this strategy — that is the standard
81
+ * mustache.js semantics and is not affected by this option.
82
+ *
83
+ * @public
84
+ */
85
+ export type MustacheEscapeStrategy = 'html' | 'none' | ((value: string) => string);
70
86
  /**
71
87
  * Options for template parsing and validation.
72
88
  * @public
@@ -84,6 +100,23 @@ export interface IMustacheTemplateOptions {
84
100
  * Whether to include partial references in variable extraction (default: false)
85
101
  */
86
102
  readonly includePartials?: boolean;
103
+ /**
104
+ * Escape strategy applied to double-brace `{{name}}` tokens at render
105
+ * time. Default `'html'` preserves the existing mustache.js behavior
106
+ * (back-compat).
107
+ *
108
+ * Pass `'none'` for LLM-prompt or other non-HTML targets where the
109
+ * default `& → &amp;` escape would corrupt the output. Pass a custom
110
+ * function for any other escape policy.
111
+ *
112
+ * The strategy is applied per-template via a private `Mustache.Writer`
113
+ * instance; no global state on the `mustache` module is mutated, so
114
+ * concurrent templates with different strategies are safe.
115
+ *
116
+ * Note: triple-brace `{{{name}}}` tokens are always rendered unescaped
117
+ * regardless of strategy (standard mustache.js semantics).
118
+ */
119
+ readonly escape?: MustacheEscapeStrategy;
87
120
  }
88
121
  /**
89
122
  * Required version of options with all fields populated.
@@ -93,5 +126,6 @@ export interface IRequiredMustacheTemplateOptions {
93
126
  readonly tags: [string, string];
94
127
  readonly includeComments: boolean;
95
128
  readonly includePartials: boolean;
129
+ readonly escape: MustacheEscapeStrategy;
96
130
  }
97
131
  //# sourceMappingURL=interfaces.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../../src/packlets/mustache/interfaces.ts"],"names":[],"mappings":"AAuBA;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,MAAM,GACN,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,CAAC;AAER;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IAEjC;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IAEtC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAEhC;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAElC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAE7C;;OAEG;IACH,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAE7C;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,SAAS,sBAAsB,EAAE,CAAC;CAC5D;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE1C;;OAEG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAEnC;;OAEG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACpC;AAED;;;GAGG;AACH,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;CACnC"}
1
+ {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../../src/packlets/mustache/interfaces.ts"],"names":[],"mappings":"AAuBA;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,MAAM,GACN,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,CAAC;AAER;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IAEjC;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IAEtC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAEhC;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAElC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAE7C;;OAEG;IACH,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAE7C;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,SAAS,sBAAsB,EAAE,CAAC;CAC5D;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;AAEnF;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE1C;;OAEG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAEnC;;OAEG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAEnC;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,sBAAsB,CAAC;CAC1C;AAED;;;GAGG;AACH,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAC;CACzC"}
@@ -1 +1 @@
1
- {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../../../src/packlets/mustache/interfaces.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D;;;;;;;;;;;;;;;;;;;;GAoBG;;AA0HH,oBAAoB","sourcesContent":["/* c8 ignore start - Type definitions only, no runtime code */\n/*\n * Copyright (c) 2020 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 */\n\n/**\n * Type of a Mustache token as returned by Mustache.parse()\n * @public\n */\nexport type MustacheTokenType =\n | 'text' // Raw text\n | 'name' // {{ variable }} - escaped value\n | '&' // {{{ variable }}} or {{& variable }} - unescaped value\n | '#' // {{# section }} - section start\n | '^' // {{^ section }} - inverted section\n | '!' // {{! comment }} - comment\n | '>' // {{> partial }} - partial\n | '='; // {{= =}} - set delimiter\n\n/**\n * Represents a variable reference extracted from a Mustache template.\n * @public\n */\nexport interface IVariableRef {\n /**\n * The raw variable name as it appears in the template (e.g., 'user.name')\n */\n readonly name: string;\n\n /**\n * The path segments parsed from the variable name (e.g., ['user', 'name'])\n */\n readonly path: readonly string[];\n\n /**\n * The type of token this variable was extracted from\n */\n readonly tokenType: MustacheTokenType;\n\n /**\n * Whether this variable is used in a section context (# or ^)\n * Section variables may reference arrays/objects for iteration\n */\n readonly isSection: boolean;\n}\n\n/**\n * Details about a missing variable in context validation.\n * @public\n */\nexport interface IMissingVariableDetail {\n /**\n * The variable reference that is missing\n */\n readonly variable: IVariableRef;\n\n /**\n * The path segment where the lookup failed\n * (e.g., for 'user.profile.name' if 'profile' is missing, this would be 'profile')\n */\n readonly failedAtSegment?: string;\n\n /**\n * The parent path that exists (e.g., ['user'] if 'user' exists but 'user.profile' does not)\n */\n readonly existingPath: readonly string[];\n}\n\n/**\n * Result of context validation, containing details about missing variables.\n * @public\n */\nexport interface IContextValidationResult {\n /**\n * Whether the context is valid (has all required variables)\n */\n readonly isValid: boolean;\n\n /**\n * Variables that are present in the context\n */\n readonly presentVariables: readonly string[];\n\n /**\n * Variables that are missing from the context\n */\n readonly missingVariables: readonly string[];\n\n /**\n * Detailed information about each missing variable\n */\n readonly missingDetails: readonly IMissingVariableDetail[];\n}\n\n/**\n * Options for template parsing and validation.\n * @public\n */\nexport interface IMustacheTemplateOptions {\n /**\n * Custom opening and closing tags (default: `['{{', '}}']`)\n */\n readonly tags?: readonly [string, string];\n\n /**\n * Whether to include comment tokens in variable extraction (default: false)\n */\n readonly includeComments?: boolean;\n\n /**\n * Whether to include partial references in variable extraction (default: false)\n */\n readonly includePartials?: boolean;\n}\n\n/**\n * Required version of options with all fields populated.\n * @internal\n */\nexport interface IRequiredMustacheTemplateOptions {\n readonly tags: [string, string];\n readonly includeComments: boolean;\n readonly includePartials: boolean;\n}\n\n/* c8 ignore stop */\n"]}
1
+ {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../../../src/packlets/mustache/interfaces.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D;;;;;;;;;;;;;;;;;;;;GAoBG;;AA8JH,oBAAoB","sourcesContent":["/* c8 ignore start - Type definitions only, no runtime code */\n/*\n * Copyright (c) 2020 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 */\n\n/**\n * Type of a Mustache token as returned by Mustache.parse()\n * @public\n */\nexport type MustacheTokenType =\n | 'text' // Raw text\n | 'name' // {{ variable }} - escaped value\n | '&' // {{{ variable }}} or {{& variable }} - unescaped value\n | '#' // {{# section }} - section start\n | '^' // {{^ section }} - inverted section\n | '!' // {{! comment }} - comment\n | '>' // {{> partial }} - partial\n | '='; // {{= =}} - set delimiter\n\n/**\n * Represents a variable reference extracted from a Mustache template.\n * @public\n */\nexport interface IVariableRef {\n /**\n * The raw variable name as it appears in the template (e.g., 'user.name')\n */\n readonly name: string;\n\n /**\n * The path segments parsed from the variable name (e.g., ['user', 'name'])\n */\n readonly path: readonly string[];\n\n /**\n * The type of token this variable was extracted from\n */\n readonly tokenType: MustacheTokenType;\n\n /**\n * Whether this variable is used in a section context (# or ^)\n * Section variables may reference arrays/objects for iteration\n */\n readonly isSection: boolean;\n}\n\n/**\n * Details about a missing variable in context validation.\n * @public\n */\nexport interface IMissingVariableDetail {\n /**\n * The variable reference that is missing\n */\n readonly variable: IVariableRef;\n\n /**\n * The path segment where the lookup failed\n * (e.g., for 'user.profile.name' if 'profile' is missing, this would be 'profile')\n */\n readonly failedAtSegment?: string;\n\n /**\n * The parent path that exists (e.g., ['user'] if 'user' exists but 'user.profile' does not)\n */\n readonly existingPath: readonly string[];\n}\n\n/**\n * Result of context validation, containing details about missing variables.\n * @public\n */\nexport interface IContextValidationResult {\n /**\n * Whether the context is valid (has all required variables)\n */\n readonly isValid: boolean;\n\n /**\n * Variables that are present in the context\n */\n readonly presentVariables: readonly string[];\n\n /**\n * Variables that are missing from the context\n */\n readonly missingVariables: readonly string[];\n\n /**\n * Detailed information about each missing variable\n */\n readonly missingDetails: readonly IMissingVariableDetail[];\n}\n\n/**\n * Strategy applied to double-brace `{{name}}` tokens at render time.\n *\n * - `'html'`: the standard mustache.js HTML escape (back-compat default).\n * - `'none'`: verbatim passthrough — values are interpolated as-is\n * (coerced to `String`). Suitable for LLM-prompt rendering and other\n * non-HTML targets where `& → &amp;` corrupts the output.\n * - `(value) => string`: caller-supplied escape function.\n *\n * Note: triple-brace `{{{name}}}` (and `{{&name}}`) tokens are always\n * rendered unescaped regardless of this strategy — that is the standard\n * mustache.js semantics and is not affected by this option.\n *\n * @public\n */\nexport type MustacheEscapeStrategy = 'html' | 'none' | ((value: string) => string);\n\n/**\n * Options for template parsing and validation.\n * @public\n */\nexport interface IMustacheTemplateOptions {\n /**\n * Custom opening and closing tags (default: `['{{', '}}']`)\n */\n readonly tags?: readonly [string, string];\n\n /**\n * Whether to include comment tokens in variable extraction (default: false)\n */\n readonly includeComments?: boolean;\n\n /**\n * Whether to include partial references in variable extraction (default: false)\n */\n readonly includePartials?: boolean;\n\n /**\n * Escape strategy applied to double-brace `{{name}}` tokens at render\n * time. Default `'html'` preserves the existing mustache.js behavior\n * (back-compat).\n *\n * Pass `'none'` for LLM-prompt or other non-HTML targets where the\n * default `& → &amp;` escape would corrupt the output. Pass a custom\n * function for any other escape policy.\n *\n * The strategy is applied per-template via a private `Mustache.Writer`\n * instance; no global state on the `mustache` module is mutated, so\n * concurrent templates with different strategies are safe.\n *\n * Note: triple-brace `{{{name}}}` tokens are always rendered unescaped\n * regardless of strategy (standard mustache.js semantics).\n */\n readonly escape?: MustacheEscapeStrategy;\n}\n\n/**\n * Required version of options with all fields populated.\n * @internal\n */\nexport interface IRequiredMustacheTemplateOptions {\n readonly tags: [string, string];\n readonly includeComments: boolean;\n readonly includePartials: boolean;\n readonly escape: MustacheEscapeStrategy;\n}\n\n/* c8 ignore stop */\n"]}
@@ -15,6 +15,8 @@ export declare class MustacheTemplate {
15
15
  */
16
16
  readonly options: Readonly<IRequiredMustacheTemplateOptions>;
17
17
  private readonly _tokens;
18
+ private readonly _writer;
19
+ private readonly _escapeFn;
18
20
  private _variables?;
19
21
  private constructor();
20
22
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"mustacheTemplate.d.ts","sourceRoot":"","sources":["../../../src/packlets/mustache/mustacheTemplate.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,MAAM,EAAgC,MAAM,eAAe,CAAC;AAGrE,OAAO,EACL,wBAAwB,EAExB,wBAAwB,EACxB,gCAAgC,EAChC,YAAY,EAEb,MAAM,cAAc,CAAC;AAWtB;;;;GAIG;AACH,qBAAa,gBAAgB;IAC3B;;OAEG;IACH,SAAgB,QAAQ,EAAE,MAAM,CAAC;IAEjC;;OAEG;IACH,SAAgB,OAAO,EAAE,QAAQ,CAAC,gCAAgC,CAAC,CAAC;IAEpE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,UAAU,CAAC,CAA0B;IAE7C,OAAO;IAMP;;;;;OAKG;WACW,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,wBAAwB,GAAG,MAAM,CAAC,gBAAgB,CAAC;IAOpG;;;;;OAKG;WACW,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,wBAAwB,GAAG,MAAM,CAAC,IAAI,CAAC;IAK1F;;;;OAIG;IACI,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC;IAI/B;;;OAGG;IACI,gBAAgB,IAAI,SAAS,YAAY,EAAE;IAOlD;;;OAGG;IACI,oBAAoB,IAAI,SAAS,MAAM,EAAE;IAehD;;;;OAIG;IACI,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,wBAAwB,CAAC;IAmC1E;;;;;;OAMG;IACI,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;IAI/C;;;;OAIG;IACI,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;IAU1D,OAAO,CAAC,MAAM,CAAC,eAAe;IAY9B,OAAO,CAAC,MAAM,CAAC,YAAY;IAO3B,OAAO,CAAC,2BAA2B;IA6CnC,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,WAAW;CAgCpB"}
1
+ {"version":3,"file":"mustacheTemplate.d.ts","sourceRoot":"","sources":["../../../src/packlets/mustache/mustacheTemplate.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,MAAM,EAAgC,MAAM,eAAe,CAAC;AAGrE,OAAO,EACL,wBAAwB,EAExB,wBAAwB,EACxB,gCAAgC,EAChC,YAAY,EAGb,MAAM,cAAc,CAAC;AAmDtB;;;;GAIG;AACH,qBAAa,gBAAgB;IAC3B;;OAEG;IACH,SAAgB,QAAQ,EAAE,MAAM,CAAC;IAEjC;;OAEG;IACH,SAAgB,OAAO,EAAE,QAAQ,CAAC,gCAAgC,CAAC,CAAC;IAEpE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,OAAO,CAAC,UAAU,CAAC,CAA0B;IAE7C,OAAO;IAQP;;;;;OAKG;WACW,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,wBAAwB,GAAG,MAAM,CAAC,gBAAgB,CAAC;IAOpG;;;;;OAKG;WACW,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,wBAAwB,GAAG,MAAM,CAAC,IAAI,CAAC;IAK1F;;;;OAIG;IACI,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC;IAI/B;;;OAGG;IACI,gBAAgB,IAAI,SAAS,YAAY,EAAE;IAOlD;;;OAGG;IACI,oBAAoB,IAAI,SAAS,MAAM,EAAE;IAehD;;;;OAIG;IACI,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,wBAAwB,CAAC;IAmC1E;;;;;;OAMG;IACI,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;IAM/C;;;;OAIG;IACI,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;IAU1D,OAAO,CAAC,MAAM,CAAC,eAAe;IAa9B,OAAO,CAAC,MAAM,CAAC,YAAY;IAO3B,OAAO,CAAC,2BAA2B;IA6CnC,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,WAAW;CAgCpB"}
@@ -33,8 +33,43 @@ const mustache_1 = __importDefault(require("mustache"));
33
33
  const DEFAULT_OPTIONS = {
34
34
  tags: ['{{', '}}'],
35
35
  includeComments: false,
36
- includePartials: false
36
+ includePartials: false,
37
+ escape: 'html'
37
38
  };
39
+ /**
40
+ * HTML entity map matching mustache.js's internal `escapeHtml`. Held
41
+ * locally so the `'html'` escape strategy does not depend on the global
42
+ * `Mustache.escape` (which other packlets — notably `experimental` —
43
+ * mutate at module load and which mustache.js itself defines as
44
+ * mutable). Per-instance escape avoids that shared-state coupling.
45
+ */
46
+ const HTML_ENTITY_MAP = {
47
+ '&': '&amp;',
48
+ '<': '&lt;',
49
+ '>': '&gt;',
50
+ '"': '&quot;',
51
+ "'": '&#39;',
52
+ '/': '&#x2F;',
53
+ '`': '&#x60;',
54
+ '=': '&#x3D;'
55
+ };
56
+ const HTML_ESCAPE = (value) => String(value).replace(/[&<>"'`=/]/g, (ch) => HTML_ENTITY_MAP[ch]);
57
+ const PASSTHROUGH_ESCAPE = (value) => String(value);
58
+ /**
59
+ * Resolves a {@link MustacheEscapeStrategy} into the per-render
60
+ * `escape` function understood by `Mustache.Writer.render`. The
61
+ * resolved function is always non-`undefined` so the writer never
62
+ * consults the (mutable, process-global) `Mustache.escape`.
63
+ */
64
+ function _resolveEscapeFunction(strategy) {
65
+ if (strategy === 'html') {
66
+ return HTML_ESCAPE;
67
+ }
68
+ if (strategy === 'none') {
69
+ return PASSTHROUGH_ESCAPE;
70
+ }
71
+ return (value) => strategy(String(value));
72
+ }
38
73
  /**
39
74
  * A helper class for working with Mustache templates that provides
40
75
  * validation, variable extraction, and context validation utilities.
@@ -45,6 +80,8 @@ class MustacheTemplate {
45
80
  this.template = template;
46
81
  this._tokens = tokens;
47
82
  this.options = options;
83
+ this._writer = new mustache_1.default.Writer();
84
+ this._escapeFn = _resolveEscapeFunction(options.escape);
48
85
  }
49
86
  /**
50
87
  * Creates a new MustacheTemplate instance.
@@ -146,7 +183,7 @@ class MustacheTemplate {
146
183
  * @returns Success with the rendered string, or Failure if rendering fails
147
184
  */
148
185
  render(context) {
149
- return (0, ts_utils_1.captureResult)(() => mustache_1.default.render(this.template, context));
186
+ return (0, ts_utils_1.captureResult)(() => this._writer.render(this.template, context, undefined, { escape: this._escapeFn }));
150
187
  }
151
188
  /**
152
189
  * Validates the context and renders the template if validation passes.
@@ -163,14 +200,15 @@ class MustacheTemplate {
163
200
  });
164
201
  }
165
202
  static _resolveOptions(options) {
166
- var _a, _b;
203
+ var _a, _b, _c;
167
204
  if (options === undefined) {
168
205
  return DEFAULT_OPTIONS;
169
206
  }
170
207
  return {
171
208
  tags: options.tags ? [options.tags[0], options.tags[1]] : DEFAULT_OPTIONS.tags,
172
209
  includeComments: (_a = options.includeComments) !== null && _a !== void 0 ? _a : DEFAULT_OPTIONS.includeComments,
173
- includePartials: (_b = options.includePartials) !== null && _b !== void 0 ? _b : DEFAULT_OPTIONS.includePartials
210
+ includePartials: (_b = options.includePartials) !== null && _b !== void 0 ? _b : DEFAULT_OPTIONS.includePartials,
211
+ escape: (_c = options.escape) !== null && _c !== void 0 ? _c : DEFAULT_OPTIONS.escape
174
212
  };
175
213
  }
176
214
  static _parseTokens(template, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"mustacheTemplate.js","sourceRoot":"","sources":["../../../src/packlets/mustache/mustacheTemplate.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2020 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 */\n\nimport { Result, captureResult, fail, succeed } from '@fgv/ts-utils';\nimport Mustache, { TemplateSpans } from 'mustache';\n\nimport {\n IContextValidationResult,\n IMissingVariableDetail,\n IMustacheTemplateOptions,\n IRequiredMustacheTemplateOptions,\n IVariableRef,\n MustacheTokenType\n} from './interfaces';\n\n/**\n * Default options for MustacheTemplate\n */\nconst DEFAULT_OPTIONS: IRequiredMustacheTemplateOptions = {\n tags: ['{{', '}}'],\n includeComments: false,\n includePartials: false\n};\n\n/**\n * A helper class for working with Mustache templates that provides\n * validation, variable extraction, and context validation utilities.\n * @public\n */\nexport class MustacheTemplate {\n /**\n * The original template string\n */\n public readonly template: string;\n\n /**\n * The options used for parsing this template\n */\n public readonly options: Readonly<IRequiredMustacheTemplateOptions>;\n\n private readonly _tokens: TemplateSpans;\n private _variables?: readonly IVariableRef[];\n\n private constructor(template: string, tokens: TemplateSpans, options: IRequiredMustacheTemplateOptions) {\n this.template = template;\n this._tokens = tokens;\n this.options = options;\n }\n\n /**\n * Creates a new MustacheTemplate instance.\n * @param template - The Mustache template string to parse\n * @param options - Optional parsing options\n * @returns Success with the template instance, or Failure if parsing fails\n */\n public static create(template: string, options?: IMustacheTemplateOptions): Result<MustacheTemplate> {\n const resolvedOptions = MustacheTemplate._resolveOptions(options);\n return MustacheTemplate._parseTokens(template, resolvedOptions).onSuccess((tokens) => {\n return succeed(new MustacheTemplate(template, tokens, resolvedOptions));\n });\n }\n\n /**\n * Validates that a template string has valid Mustache syntax.\n * @param template - The template string to validate\n * @param options - Optional parsing options\n * @returns Success with true if valid, or Failure with a descriptive error message\n */\n public static validate(template: string, options?: IMustacheTemplateOptions): Result<true> {\n const resolvedOptions = MustacheTemplate._resolveOptions(options);\n return MustacheTemplate._parseTokens(template, resolvedOptions).onSuccess(() => succeed(true as const));\n }\n\n /**\n * Checks if this template instance has valid syntax.\n * Always returns Success(true) since parsing succeeded in create().\n * @returns Success with true\n */\n public validate(): Result<true> {\n return succeed(true as const);\n }\n\n /**\n * Extracts all variable references from the template.\n * @returns An array of variable references found in the template\n */\n public extractVariables(): readonly IVariableRef[] {\n if (this._variables === undefined) {\n this._variables = this._extractVariablesFromTokens(this._tokens);\n }\n return this._variables;\n }\n\n /**\n * Extracts unique variable names from the template.\n * @returns An array of unique variable name strings (e.g., ['user.name', 'items'])\n */\n public extractVariableNames(): readonly string[] {\n const variables = this.extractVariables();\n const seen = new Set<string>();\n const names: string[] = [];\n\n for (const variable of variables) {\n if (!seen.has(variable.name)) {\n seen.add(variable.name);\n names.push(variable.name);\n }\n }\n\n return names;\n }\n\n /**\n * Validates that a context object has all required variables.\n * @param context - The context object to validate\n * @returns Success with validation result containing details about present/missing variables\n */\n public validateContext(context: unknown): Result<IContextValidationResult> {\n const variables = this.extractVariables();\n const presentVariables: string[] = [];\n const missingVariables: string[] = [];\n const missingDetails: IMissingVariableDetail[] = [];\n const checked = new Set<string>();\n\n for (const variable of variables) {\n if (checked.has(variable.name)) {\n continue;\n }\n checked.add(variable.name);\n\n const lookup = this._lookupPath(context, variable.path);\n\n if (lookup.found) {\n presentVariables.push(variable.name);\n } else {\n missingVariables.push(variable.name);\n missingDetails.push({\n variable,\n failedAtSegment: lookup.failedAt,\n existingPath: lookup.existingPath\n });\n }\n }\n\n return succeed({\n isValid: missingVariables.length === 0,\n presentVariables,\n missingVariables,\n missingDetails\n });\n }\n\n /**\n * Renders the template with the given context.\n * Use this for pre-validated contexts where you've already checked\n * that all required variables are present.\n * @param context - The context object for template rendering\n * @returns Success with the rendered string, or Failure if rendering fails\n */\n public render(context: unknown): Result<string> {\n return captureResult(() => Mustache.render(this.template, context));\n }\n\n /**\n * Validates the context and renders the template if validation passes.\n * @param context - The context object to validate and render with\n * @returns Success with the rendered string, or Failure with validation or render errors\n */\n public validateAndRender(context: unknown): Result<string> {\n return this.validateContext(context).onSuccess((validation) => {\n if (!validation.isValid) {\n const missing = validation.missingVariables.join(', ');\n return fail(`Missing required variables: ${missing}`);\n }\n return this.render(context);\n });\n }\n\n private static _resolveOptions(options?: IMustacheTemplateOptions): IRequiredMustacheTemplateOptions {\n if (options === undefined) {\n return DEFAULT_OPTIONS;\n }\n\n return {\n tags: options.tags ? [options.tags[0], options.tags[1]] : DEFAULT_OPTIONS.tags,\n includeComments: options.includeComments ?? DEFAULT_OPTIONS.includeComments,\n includePartials: options.includePartials ?? DEFAULT_OPTIONS.includePartials\n };\n }\n\n private static _parseTokens(\n template: string,\n options: IRequiredMustacheTemplateOptions\n ): Result<TemplateSpans> {\n return captureResult(() => Mustache.parse(template, options.tags));\n }\n\n private _extractVariablesFromTokens(tokens: TemplateSpans): IVariableRef[] {\n const variables: IVariableRef[] = [];\n\n for (const token of tokens) {\n const type = token[0] as MustacheTokenType;\n const value = token[1] as string;\n\n // Skip text tokens\n if (type === 'text') {\n continue;\n }\n\n // Handle comments based on options\n if (type === '!' && !this.options.includeComments) {\n continue;\n }\n\n // Handle partials based on options\n if (type === '>' && !this.options.includePartials) {\n continue;\n }\n\n // Handle variable tokens: 'name', '&', '#', '^', and optionally '!', '>'\n if (type === 'name' || type === '&' || type === '#' || type === '^' || type === '!' || type === '>') {\n const isSection = type === '#' || type === '^';\n variables.push({\n name: value,\n path: this._parsePath(value),\n tokenType: type,\n isSection\n });\n }\n\n // Recursively extract from nested tokens in sections\n if ((type === '#' || type === '^') && token.length > 4) {\n const nestedTokens = token[4] as TemplateSpans;\n if (nestedTokens) {\n variables.push(...this._extractVariablesFromTokens(nestedTokens));\n }\n }\n }\n\n return variables;\n }\n\n private _parsePath(name: string): readonly string[] {\n // Handle special case of '.' which means current context\n if (name === '.') {\n return ['.'];\n }\n\n // Split on dots to get path segments\n return name.split('.').filter((segment) => segment.length > 0);\n }\n\n private _lookupPath(\n context: unknown,\n path: readonly string[]\n ): { found: boolean; existingPath: string[]; failedAt?: string } {\n // Handle '.' which always exists if context is not null/undefined\n if (path.length === 1 && path[0] === '.') {\n return { found: context !== undefined && context !== null, existingPath: [] };\n }\n\n let current: unknown = context;\n const existingPath: string[] = [];\n\n for (const segment of path) {\n if (current === undefined || current === null) {\n return { found: false, existingPath, failedAt: segment };\n }\n\n if (typeof current !== 'object') {\n return { found: false, existingPath, failedAt: segment };\n }\n\n const obj = current as Record<string, unknown>;\n if (!(segment in obj)) {\n return { found: false, existingPath, failedAt: segment };\n }\n\n current = obj[segment];\n existingPath.push(segment);\n }\n\n return { found: true, existingPath };\n }\n}\n"]}
1
+ {"version":3,"file":"mustacheTemplate.js","sourceRoot":"","sources":["../../../src/packlets/mustache/mustacheTemplate.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2020 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 */\n\nimport { Result, captureResult, fail, succeed } from '@fgv/ts-utils';\nimport Mustache, { EscapeFunction, TemplateSpans, Writer } from 'mustache';\n\nimport {\n IContextValidationResult,\n IMissingVariableDetail,\n IMustacheTemplateOptions,\n IRequiredMustacheTemplateOptions,\n IVariableRef,\n MustacheEscapeStrategy,\n MustacheTokenType\n} from './interfaces';\n\n/**\n * Default options for MustacheTemplate\n */\nconst DEFAULT_OPTIONS: IRequiredMustacheTemplateOptions = {\n tags: ['{{', '}}'],\n includeComments: false,\n includePartials: false,\n escape: 'html'\n};\n\n/**\n * HTML entity map matching mustache.js's internal `escapeHtml`. Held\n * locally so the `'html'` escape strategy does not depend on the global\n * `Mustache.escape` (which other packlets — notably `experimental` —\n * mutate at module load and which mustache.js itself defines as\n * mutable). Per-instance escape avoids that shared-state coupling.\n */\nconst HTML_ENTITY_MAP: Readonly<Record<string, string>> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;',\n '/': '&#x2F;',\n '`': '&#x60;',\n '=': '&#x3D;'\n};\n\nconst HTML_ESCAPE: EscapeFunction = (value) =>\n String(value).replace(/[&<>\"'`=/]/g, (ch) => HTML_ENTITY_MAP[ch]);\n\nconst PASSTHROUGH_ESCAPE: EscapeFunction = (value) => String(value);\n\n/**\n * Resolves a {@link MustacheEscapeStrategy} into the per-render\n * `escape` function understood by `Mustache.Writer.render`. The\n * resolved function is always non-`undefined` so the writer never\n * consults the (mutable, process-global) `Mustache.escape`.\n */\nfunction _resolveEscapeFunction(strategy: MustacheEscapeStrategy): EscapeFunction {\n if (strategy === 'html') {\n return HTML_ESCAPE;\n }\n if (strategy === 'none') {\n return PASSTHROUGH_ESCAPE;\n }\n return (value) => strategy(String(value));\n}\n\n/**\n * A helper class for working with Mustache templates that provides\n * validation, variable extraction, and context validation utilities.\n * @public\n */\nexport class MustacheTemplate {\n /**\n * The original template string\n */\n public readonly template: string;\n\n /**\n * The options used for parsing this template\n */\n public readonly options: Readonly<IRequiredMustacheTemplateOptions>;\n\n private readonly _tokens: TemplateSpans;\n private readonly _writer: Writer;\n private readonly _escapeFn: EscapeFunction;\n private _variables?: readonly IVariableRef[];\n\n private constructor(template: string, tokens: TemplateSpans, options: IRequiredMustacheTemplateOptions) {\n this.template = template;\n this._tokens = tokens;\n this.options = options;\n this._writer = new Mustache.Writer();\n this._escapeFn = _resolveEscapeFunction(options.escape);\n }\n\n /**\n * Creates a new MustacheTemplate instance.\n * @param template - The Mustache template string to parse\n * @param options - Optional parsing options\n * @returns Success with the template instance, or Failure if parsing fails\n */\n public static create(template: string, options?: IMustacheTemplateOptions): Result<MustacheTemplate> {\n const resolvedOptions = MustacheTemplate._resolveOptions(options);\n return MustacheTemplate._parseTokens(template, resolvedOptions).onSuccess((tokens) => {\n return succeed(new MustacheTemplate(template, tokens, resolvedOptions));\n });\n }\n\n /**\n * Validates that a template string has valid Mustache syntax.\n * @param template - The template string to validate\n * @param options - Optional parsing options\n * @returns Success with true if valid, or Failure with a descriptive error message\n */\n public static validate(template: string, options?: IMustacheTemplateOptions): Result<true> {\n const resolvedOptions = MustacheTemplate._resolveOptions(options);\n return MustacheTemplate._parseTokens(template, resolvedOptions).onSuccess(() => succeed(true as const));\n }\n\n /**\n * Checks if this template instance has valid syntax.\n * Always returns Success(true) since parsing succeeded in create().\n * @returns Success with true\n */\n public validate(): Result<true> {\n return succeed(true as const);\n }\n\n /**\n * Extracts all variable references from the template.\n * @returns An array of variable references found in the template\n */\n public extractVariables(): readonly IVariableRef[] {\n if (this._variables === undefined) {\n this._variables = this._extractVariablesFromTokens(this._tokens);\n }\n return this._variables;\n }\n\n /**\n * Extracts unique variable names from the template.\n * @returns An array of unique variable name strings (e.g., ['user.name', 'items'])\n */\n public extractVariableNames(): readonly string[] {\n const variables = this.extractVariables();\n const seen = new Set<string>();\n const names: string[] = [];\n\n for (const variable of variables) {\n if (!seen.has(variable.name)) {\n seen.add(variable.name);\n names.push(variable.name);\n }\n }\n\n return names;\n }\n\n /**\n * Validates that a context object has all required variables.\n * @param context - The context object to validate\n * @returns Success with validation result containing details about present/missing variables\n */\n public validateContext(context: unknown): Result<IContextValidationResult> {\n const variables = this.extractVariables();\n const presentVariables: string[] = [];\n const missingVariables: string[] = [];\n const missingDetails: IMissingVariableDetail[] = [];\n const checked = new Set<string>();\n\n for (const variable of variables) {\n if (checked.has(variable.name)) {\n continue;\n }\n checked.add(variable.name);\n\n const lookup = this._lookupPath(context, variable.path);\n\n if (lookup.found) {\n presentVariables.push(variable.name);\n } else {\n missingVariables.push(variable.name);\n missingDetails.push({\n variable,\n failedAtSegment: lookup.failedAt,\n existingPath: lookup.existingPath\n });\n }\n }\n\n return succeed({\n isValid: missingVariables.length === 0,\n presentVariables,\n missingVariables,\n missingDetails\n });\n }\n\n /**\n * Renders the template with the given context.\n * Use this for pre-validated contexts where you've already checked\n * that all required variables are present.\n * @param context - The context object for template rendering\n * @returns Success with the rendered string, or Failure if rendering fails\n */\n public render(context: unknown): Result<string> {\n return captureResult(() =>\n this._writer.render(this.template, context, undefined, { escape: this._escapeFn })\n );\n }\n\n /**\n * Validates the context and renders the template if validation passes.\n * @param context - The context object to validate and render with\n * @returns Success with the rendered string, or Failure with validation or render errors\n */\n public validateAndRender(context: unknown): Result<string> {\n return this.validateContext(context).onSuccess((validation) => {\n if (!validation.isValid) {\n const missing = validation.missingVariables.join(', ');\n return fail(`Missing required variables: ${missing}`);\n }\n return this.render(context);\n });\n }\n\n private static _resolveOptions(options?: IMustacheTemplateOptions): IRequiredMustacheTemplateOptions {\n if (options === undefined) {\n return DEFAULT_OPTIONS;\n }\n\n return {\n tags: options.tags ? [options.tags[0], options.tags[1]] : DEFAULT_OPTIONS.tags,\n includeComments: options.includeComments ?? DEFAULT_OPTIONS.includeComments,\n includePartials: options.includePartials ?? DEFAULT_OPTIONS.includePartials,\n escape: options.escape ?? DEFAULT_OPTIONS.escape\n };\n }\n\n private static _parseTokens(\n template: string,\n options: IRequiredMustacheTemplateOptions\n ): Result<TemplateSpans> {\n return captureResult(() => Mustache.parse(template, options.tags));\n }\n\n private _extractVariablesFromTokens(tokens: TemplateSpans): IVariableRef[] {\n const variables: IVariableRef[] = [];\n\n for (const token of tokens) {\n const type = token[0] as MustacheTokenType;\n const value = token[1] as string;\n\n // Skip text tokens\n if (type === 'text') {\n continue;\n }\n\n // Handle comments based on options\n if (type === '!' && !this.options.includeComments) {\n continue;\n }\n\n // Handle partials based on options\n if (type === '>' && !this.options.includePartials) {\n continue;\n }\n\n // Handle variable tokens: 'name', '&', '#', '^', and optionally '!', '>'\n if (type === 'name' || type === '&' || type === '#' || type === '^' || type === '!' || type === '>') {\n const isSection = type === '#' || type === '^';\n variables.push({\n name: value,\n path: this._parsePath(value),\n tokenType: type,\n isSection\n });\n }\n\n // Recursively extract from nested tokens in sections\n if ((type === '#' || type === '^') && token.length > 4) {\n const nestedTokens = token[4] as TemplateSpans;\n if (nestedTokens) {\n variables.push(...this._extractVariablesFromTokens(nestedTokens));\n }\n }\n }\n\n return variables;\n }\n\n private _parsePath(name: string): readonly string[] {\n // Handle special case of '.' which means current context\n if (name === '.') {\n return ['.'];\n }\n\n // Split on dots to get path segments\n return name.split('.').filter((segment) => segment.length > 0);\n }\n\n private _lookupPath(\n context: unknown,\n path: readonly string[]\n ): { found: boolean; existingPath: string[]; failedAt?: string } {\n // Handle '.' which always exists if context is not null/undefined\n if (path.length === 1 && path[0] === '.') {\n return { found: context !== undefined && context !== null, existingPath: [] };\n }\n\n let current: unknown = context;\n const existingPath: string[] = [];\n\n for (const segment of path) {\n if (current === undefined || current === null) {\n return { found: false, existingPath, failedAt: segment };\n }\n\n if (typeof current !== 'object') {\n return { found: false, existingPath, failedAt: segment };\n }\n\n const obj = current as Record<string, unknown>;\n if (!(segment in obj)) {\n return { found: false, existingPath, failedAt: segment };\n }\n\n current = obj[segment];\n existingPath.push(segment);\n }\n\n return { found: true, existingPath };\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fgv/ts-extras",
3
- "version": "5.1.0-27",
3
+ "version": "5.1.0-29",
4
4
  "description": "Assorted Typescript Utilities",
5
5
  "main": "lib/index.js",
6
6
  "types": "dist/ts-extras.d.ts",
@@ -86,10 +86,10 @@
86
86
  "@types/js-yaml": "~4.0.9",
87
87
  "typedoc": "~0.28.16",
88
88
  "typedoc-plugin-markdown": "~4.9.0",
89
- "@fgv/heft-dual-rig": "5.1.0-27",
90
- "@fgv/typedoc-compact-theme": "5.1.0-27",
91
- "@fgv/ts-utils": "5.1.0-27",
92
- "@fgv/ts-utils-jest": "5.1.0-27"
89
+ "@fgv/ts-utils-jest": "5.1.0-29",
90
+ "@fgv/ts-utils": "5.1.0-29",
91
+ "@fgv/typedoc-compact-theme": "5.1.0-29",
92
+ "@fgv/heft-dual-rig": "5.1.0-29"
93
93
  },
94
94
  "dependencies": {
95
95
  "luxon": "^3.7.2",
@@ -97,10 +97,10 @@
97
97
  "papaparse": "^5.4.1",
98
98
  "fflate": "~0.8.2",
99
99
  "js-yaml": "~4.1.1",
100
- "@fgv/ts-json-base": "5.1.0-27"
100
+ "@fgv/ts-json-base": "5.1.0-29"
101
101
  },
102
102
  "peerDependencies": {
103
- "@fgv/ts-utils": "5.1.0-27"
103
+ "@fgv/ts-utils": "5.1.0-29"
104
104
  },
105
105
  "repository": {
106
106
  "type": "git",