@fgv/ts-extras 5.1.0-5 → 5.1.0-50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +90 -0
- package/dist/index.browser.js +6 -2
- package/dist/index.browser.js.map +1 -0
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -0
- package/dist/packlets/ai-assist/chatRequestBuilders.js +282 -0
- package/dist/packlets/ai-assist/chatRequestBuilders.js.map +1 -0
- package/dist/packlets/ai-assist/{apiClient.js → completionClient.js} +165 -214
- package/dist/packlets/ai-assist/completionClient.js.map +1 -0
- package/dist/packlets/ai-assist/converters.js +47 -3
- package/dist/packlets/ai-assist/converters.js.map +1 -0
- package/dist/packlets/ai-assist/embeddingClient.js +345 -0
- package/dist/packlets/ai-assist/embeddingClient.js.map +1 -0
- package/dist/packlets/ai-assist/endpoint.js +107 -0
- package/dist/packlets/ai-assist/endpoint.js.map +1 -0
- package/dist/packlets/ai-assist/http.js +104 -0
- package/dist/packlets/ai-assist/http.js.map +1 -0
- package/dist/packlets/ai-assist/imageGenerationClient.js +454 -0
- package/dist/packlets/ai-assist/imageGenerationClient.js.map +1 -0
- package/dist/packlets/ai-assist/imageOptionsResolver.js +193 -0
- package/dist/packlets/ai-assist/imageOptionsResolver.js.map +1 -0
- package/dist/packlets/ai-assist/index.js +12 -4
- package/dist/packlets/ai-assist/index.js.map +1 -0
- package/dist/packlets/ai-assist/jsonCompletion.js +93 -0
- package/dist/packlets/ai-assist/jsonCompletion.js.map +1 -0
- package/dist/packlets/ai-assist/jsonResponse.js +423 -0
- package/dist/packlets/ai-assist/jsonResponse.js.map +1 -0
- package/dist/packlets/ai-assist/listModelsClient.js +294 -0
- package/dist/packlets/ai-assist/listModelsClient.js.map +1 -0
- package/dist/packlets/ai-assist/model.js +301 -9
- package/dist/packlets/ai-assist/model.js.map +1 -0
- package/dist/packlets/ai-assist/registry.js +376 -12
- package/dist/packlets/ai-assist/registry.js.map +1 -0
- package/dist/packlets/ai-assist/sseParser.js +123 -0
- package/dist/packlets/ai-assist/sseParser.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +376 -0
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +687 -0
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/common.js +187 -0
- package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js +208 -0
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js +175 -0
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +390 -0
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js +178 -0
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -0
- package/dist/packlets/ai-assist/streamingClient.js +140 -0
- package/dist/packlets/ai-assist/streamingClient.js.map +1 -0
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js +288 -0
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -0
- package/dist/packlets/ai-assist/toolFormats.js +106 -10
- package/dist/packlets/ai-assist/toolFormats.js.map +1 -0
- package/dist/packlets/conversion/converters.js +35 -1
- package/dist/packlets/conversion/converters.js.map +1 -0
- package/dist/packlets/conversion/index.js.map +1 -0
- package/dist/packlets/crypto-utils/constants.js.map +1 -0
- package/dist/packlets/crypto-utils/converters.js +42 -4
- package/dist/packlets/crypto-utils/converters.js.map +1 -0
- package/dist/packlets/crypto-utils/directEncryptionProvider.js.map +1 -0
- package/dist/packlets/crypto-utils/encryptedFile.js +37 -0
- package/dist/packlets/crypto-utils/encryptedFile.js.map +1 -0
- package/dist/packlets/crypto-utils/hpkeProvider.js +355 -0
- package/dist/packlets/crypto-utils/hpkeProvider.js.map +1 -0
- package/dist/packlets/crypto-utils/index.browser.js +13 -2
- package/dist/packlets/crypto-utils/index.browser.js.map +1 -0
- package/dist/packlets/crypto-utils/index.js +9 -1
- package/dist/packlets/crypto-utils/index.js.map +1 -0
- package/dist/packlets/crypto-utils/keyPairAlgorithmParams.js +71 -0
- package/dist/packlets/crypto-utils/keyPairAlgorithmParams.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/converters.js +111 -16
- package/dist/packlets/crypto-utils/keystore/converters.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js +287 -0
- package/dist/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/index.browser.js +36 -0
- package/dist/packlets/crypto-utils/keystore/index.browser.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/index.js +3 -0
- package/dist/packlets/crypto-utils/keystore/index.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/keyStore.js +872 -119
- package/dist/packlets/crypto-utils/keystore/keyStore.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/model.js +35 -4
- package/dist/packlets/crypto-utils/keystore/model.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js +21 -0
- package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -0
- package/dist/packlets/crypto-utils/model.js +32 -0
- package/dist/packlets/crypto-utils/model.js.map +1 -0
- package/dist/packlets/crypto-utils/nodeCryptoProvider.js +347 -1
- package/dist/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -0
- package/dist/packlets/crypto-utils/seedDerivedKeyPair.js +120 -0
- package/dist/packlets/crypto-utils/seedDerivedKeyPair.js.map +1 -0
- package/dist/packlets/crypto-utils/spkiHelpers.js +284 -0
- package/dist/packlets/crypto-utils/spkiHelpers.js.map +1 -0
- package/dist/packlets/csv/csvFileHelpers.js +0 -14
- package/dist/packlets/csv/csvFileHelpers.js.map +1 -0
- package/dist/packlets/csv/csvHelpers.js +14 -0
- package/dist/packlets/csv/csvHelpers.js.map +1 -0
- package/dist/packlets/csv/index.browser.js +1 -3
- package/dist/packlets/csv/index.browser.js.map +1 -0
- package/dist/packlets/csv/index.js.map +1 -0
- package/dist/packlets/experimental/extendedArray.js.map +1 -0
- package/dist/packlets/experimental/formatter.js.map +1 -0
- package/dist/packlets/experimental/index.js.map +1 -0
- package/dist/packlets/experimental/rangeOf.js.map +1 -0
- package/dist/packlets/hash/index.browser.js.map +1 -0
- package/dist/packlets/hash/index.js.map +1 -0
- package/dist/packlets/hash/index.node.js.map +1 -0
- package/dist/packlets/hash/md5Normalizer.browser.js.map +1 -0
- package/dist/packlets/hash/md5Normalizer.js.map +1 -0
- package/dist/packlets/mustache/index.js.map +1 -0
- package/dist/packlets/mustache/interfaces.js.map +1 -0
- package/dist/packlets/mustache/mustacheTemplate.js +42 -4
- package/dist/packlets/mustache/mustacheTemplate.js.map +1 -0
- package/dist/packlets/record-jar/index.browser.js +1 -3
- package/dist/packlets/record-jar/index.browser.js.map +1 -0
- package/dist/packlets/record-jar/index.js.map +1 -0
- package/dist/packlets/record-jar/recordJarFileHelpers.js +0 -18
- package/dist/packlets/record-jar/recordJarFileHelpers.js.map +1 -0
- package/dist/packlets/record-jar/recordJarHelpers.js +18 -0
- package/dist/packlets/record-jar/recordJarHelpers.js.map +1 -0
- package/dist/packlets/safer-fetch/addressClassification.js +438 -0
- package/dist/packlets/safer-fetch/addressClassification.js.map +1 -0
- package/dist/packlets/safer-fetch/addressPolicy.js +119 -0
- package/dist/packlets/safer-fetch/addressPolicy.js.map +1 -0
- package/dist/packlets/safer-fetch/contentType.js +120 -0
- package/dist/packlets/safer-fetch/contentType.js.map +1 -0
- package/dist/packlets/safer-fetch/deadline.js +254 -0
- package/dist/packlets/safer-fetch/deadline.js.map +1 -0
- package/dist/packlets/safer-fetch/defaults.js +131 -0
- package/dist/packlets/safer-fetch/defaults.js.map +1 -0
- package/dist/packlets/safer-fetch/failureReason.js +21 -0
- package/dist/packlets/safer-fetch/failureReason.js.map +1 -0
- package/dist/packlets/safer-fetch/guards.js +148 -0
- package/dist/packlets/safer-fetch/guards.js.map +1 -0
- package/dist/packlets/safer-fetch/index.browser.js +58 -0
- package/dist/packlets/safer-fetch/index.browser.js.map +1 -0
- package/dist/packlets/safer-fetch/index.js +52 -0
- package/dist/packlets/safer-fetch/index.js.map +1 -0
- package/dist/packlets/safer-fetch/model.js +21 -0
- package/dist/packlets/safer-fetch/model.js.map +1 -0
- package/dist/packlets/safer-fetch/nodeAddressGuard.js +191 -0
- package/dist/packlets/safer-fetch/nodeAddressGuard.js.map +1 -0
- package/dist/packlets/safer-fetch/redirect.js +93 -0
- package/dist/packlets/safer-fetch/redirect.js.map +1 -0
- package/dist/packlets/safer-fetch/retry.js +188 -0
- package/dist/packlets/safer-fetch/retry.js.map +1 -0
- package/dist/packlets/safer-fetch/saferFetch.js +755 -0
- package/dist/packlets/safer-fetch/saferFetch.js.map +1 -0
- package/dist/packlets/safer-fetch/transport.js +50 -0
- package/dist/packlets/safer-fetch/transport.js.map +1 -0
- package/dist/packlets/yaml/converters.js.map +1 -0
- package/dist/packlets/yaml/index.js +1 -0
- package/dist/packlets/yaml/index.js.map +1 -0
- package/dist/packlets/yaml/serializers.js +48 -0
- package/dist/packlets/yaml/serializers.js.map +1 -0
- package/dist/packlets/zip-file-tree/index.js.map +1 -0
- package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js +99 -9
- package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -0
- package/dist/packlets/zip-file-tree/zipFileTreeWriter.js +16 -1
- package/dist/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -0
- package/dist/ts-extras.d.ts +6648 -553
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/index.browser.d.ts +5 -2
- package/lib/index.browser.d.ts.map +1 -0
- package/lib/index.browser.js +11 -3
- package/lib/index.browser.js.map +1 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -0
- package/lib/packlets/ai-assist/chatRequestBuilders.d.ts +149 -0
- package/lib/packlets/ai-assist/chatRequestBuilders.d.ts.map +1 -0
- package/lib/packlets/ai-assist/chatRequestBuilders.js +293 -0
- package/lib/packlets/ai-assist/chatRequestBuilders.js.map +1 -0
- package/lib/packlets/ai-assist/completionClient.d.ts +74 -0
- package/lib/packlets/ai-assist/completionClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/{apiClient.js → completionClient.js} +164 -213
- package/lib/packlets/ai-assist/completionClient.js.map +1 -0
- package/lib/packlets/ai-assist/converters.d.ts +15 -1
- package/lib/packlets/ai-assist/converters.d.ts.map +1 -0
- package/lib/packlets/ai-assist/converters.js +47 -3
- package/lib/packlets/ai-assist/converters.js.map +1 -0
- package/lib/packlets/ai-assist/embeddingClient.d.ts +69 -0
- package/lib/packlets/ai-assist/embeddingClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/embeddingClient.js +349 -0
- package/lib/packlets/ai-assist/embeddingClient.js.map +1 -0
- package/lib/packlets/ai-assist/endpoint.d.ts +49 -0
- package/lib/packlets/ai-assist/endpoint.d.ts.map +1 -0
- package/lib/packlets/ai-assist/endpoint.js +113 -0
- package/lib/packlets/ai-assist/endpoint.js.map +1 -0
- package/lib/packlets/ai-assist/http.d.ts +34 -0
- package/lib/packlets/ai-assist/http.d.ts.map +1 -0
- package/lib/packlets/ai-assist/http.js +109 -0
- package/lib/packlets/ai-assist/http.js.map +1 -0
- package/lib/packlets/ai-assist/imageGenerationClient.d.ts +46 -0
- package/lib/packlets/ai-assist/imageGenerationClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/imageGenerationClient.js +458 -0
- package/lib/packlets/ai-assist/imageGenerationClient.js.map +1 -0
- package/lib/packlets/ai-assist/imageOptionsResolver.d.ts +66 -0
- package/lib/packlets/ai-assist/imageOptionsResolver.d.ts.map +1 -0
- package/lib/packlets/ai-assist/imageOptionsResolver.js +197 -0
- package/lib/packlets/ai-assist/imageOptionsResolver.js.map +1 -0
- package/lib/packlets/ai-assist/index.d.ts +12 -4
- package/lib/packlets/ai-assist/index.d.ts.map +1 -0
- package/lib/packlets/ai-assist/index.js +47 -4
- package/lib/packlets/ai-assist/index.js.map +1 -0
- package/lib/packlets/ai-assist/jsonCompletion.d.ts +93 -0
- package/lib/packlets/ai-assist/jsonCompletion.d.ts.map +1 -0
- package/lib/packlets/ai-assist/jsonCompletion.js +97 -0
- package/lib/packlets/ai-assist/jsonCompletion.js.map +1 -0
- package/lib/packlets/ai-assist/jsonResponse.d.ts +194 -0
- package/lib/packlets/ai-assist/jsonResponse.d.ts.map +1 -0
- package/lib/packlets/ai-assist/jsonResponse.js +429 -0
- package/lib/packlets/ai-assist/jsonResponse.js.map +1 -0
- package/lib/packlets/ai-assist/listModelsClient.d.ts +46 -0
- package/lib/packlets/ai-assist/listModelsClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/listModelsClient.js +298 -0
- package/lib/packlets/ai-assist/listModelsClient.js.map +1 -0
- package/lib/packlets/ai-assist/model.d.ts +1346 -12
- package/lib/packlets/ai-assist/model.d.ts.map +1 -0
- package/lib/packlets/ai-assist/model.js +309 -10
- package/lib/packlets/ai-assist/model.js.map +1 -0
- package/lib/packlets/ai-assist/registry.d.ts +76 -1
- package/lib/packlets/ai-assist/registry.d.ts.map +1 -0
- package/lib/packlets/ai-assist/registry.js +381 -13
- package/lib/packlets/ai-assist/registry.js.map +1 -0
- package/lib/packlets/ai-assist/sseParser.d.ts +45 -0
- package/lib/packlets/ai-assist/sseParser.d.ts.map +1 -0
- package/lib/packlets/ai-assist/sseParser.js +128 -0
- package/lib/packlets/ai-assist/sseParser.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +72 -0
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +379 -0
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts +269 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +694 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +163 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.js +193 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts +43 -0
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js +211 -0
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts +19 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js +178 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +33 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +393 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts +34 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js +181 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -0
- package/lib/packlets/ai-assist/streamingClient.d.ts +50 -0
- package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingClient.js +146 -0
- package/lib/packlets/ai-assist/streamingClient.js.map +1 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts +87 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts.map +1 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js +294 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -0
- package/lib/packlets/ai-assist/toolFormats.d.ts +40 -9
- package/lib/packlets/ai-assist/toolFormats.d.ts.map +1 -0
- package/lib/packlets/ai-assist/toolFormats.js +107 -10
- package/lib/packlets/ai-assist/toolFormats.js.map +1 -0
- package/lib/packlets/conversion/converters.d.ts +8 -1
- package/lib/packlets/conversion/converters.d.ts.map +1 -0
- package/lib/packlets/conversion/converters.js +36 -2
- package/lib/packlets/conversion/converters.js.map +1 -0
- package/lib/packlets/conversion/index.d.ts.map +1 -0
- package/lib/packlets/conversion/index.js.map +1 -0
- package/lib/packlets/crypto-utils/constants.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/constants.js.map +1 -0
- package/lib/packlets/crypto-utils/converters.d.ts +20 -1
- package/lib/packlets/crypto-utils/converters.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/converters.js +43 -5
- package/lib/packlets/crypto-utils/converters.js.map +1 -0
- package/lib/packlets/crypto-utils/directEncryptionProvider.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/directEncryptionProvider.js.map +1 -0
- package/lib/packlets/crypto-utils/encryptedFile.d.ts +25 -0
- package/lib/packlets/crypto-utils/encryptedFile.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/encryptedFile.js +38 -0
- package/lib/packlets/crypto-utils/encryptedFile.js.map +1 -0
- package/lib/packlets/crypto-utils/hpkeProvider.d.ts +150 -0
- package/lib/packlets/crypto-utils/hpkeProvider.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/hpkeProvider.js +359 -0
- package/lib/packlets/crypto-utils/hpkeProvider.js.map +1 -0
- package/lib/packlets/crypto-utils/index.browser.d.ts +5 -1
- package/lib/packlets/crypto-utils/index.browser.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/index.browser.js +28 -3
- package/lib/packlets/crypto-utils/index.browser.js.map +1 -0
- package/lib/packlets/crypto-utils/index.d.ts +5 -1
- package/lib/packlets/crypto-utils/index.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/index.js +24 -1
- package/lib/packlets/crypto-utils/index.js.map +1 -0
- package/lib/packlets/crypto-utils/keyPairAlgorithmParams.d.ts +54 -0
- package/lib/packlets/crypto-utils/keyPairAlgorithmParams.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keyPairAlgorithmParams.js +74 -0
- package/lib/packlets/crypto-utils/keyPairAlgorithmParams.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/converters.d.ts +68 -6
- package/lib/packlets/crypto-utils/keystore/converters.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/converters.js +109 -14
- package/lib/packlets/crypto-utils/keystore/converters.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.d.ts +148 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js +324 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.d.ts +10 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.js +76 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.d.ts +2 -0
- package/lib/packlets/crypto-utils/keystore/index.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.js +5 -1
- package/lib/packlets/crypto-utils/keystore/index.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/keyStore.d.ts +314 -13
- package/lib/packlets/crypto-utils/keystore/keyStore.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/keyStore.js +877 -124
- package/lib/packlets/crypto-utils/keystore/keyStore.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/model.d.ts +404 -21
- package/lib/packlets/crypto-utils/keystore/model.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/model.js +37 -5
- package/lib/packlets/crypto-utils/keystore/model.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts +53 -0
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js +22 -0
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -0
- package/lib/packlets/crypto-utils/model.d.ts +518 -10
- package/lib/packlets/crypto-utils/model.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/model.js +33 -1
- package/lib/packlets/crypto-utils/model.js.map +1 -0
- package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts +142 -2
- package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/nodeCryptoProvider.js +346 -0
- package/lib/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -0
- package/lib/packlets/crypto-utils/seedDerivedKeyPair.d.ts +42 -0
- package/lib/packlets/crypto-utils/seedDerivedKeyPair.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/seedDerivedKeyPair.js +123 -0
- package/lib/packlets/crypto-utils/seedDerivedKeyPair.js.map +1 -0
- package/lib/packlets/crypto-utils/spkiHelpers.d.ts +151 -0
- package/lib/packlets/crypto-utils/spkiHelpers.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/spkiHelpers.js +297 -0
- package/lib/packlets/crypto-utils/spkiHelpers.js.map +1 -0
- package/lib/packlets/csv/csvFileHelpers.d.ts +0 -10
- package/lib/packlets/csv/csvFileHelpers.d.ts.map +1 -0
- package/lib/packlets/csv/csvFileHelpers.js +0 -15
- package/lib/packlets/csv/csvFileHelpers.js.map +1 -0
- package/lib/packlets/csv/csvHelpers.d.ts +10 -0
- package/lib/packlets/csv/csvHelpers.d.ts.map +1 -0
- package/lib/packlets/csv/csvHelpers.js +15 -0
- package/lib/packlets/csv/csvHelpers.js.map +1 -0
- package/lib/packlets/csv/index.browser.d.ts +0 -1
- package/lib/packlets/csv/index.browser.d.ts.map +1 -0
- package/lib/packlets/csv/index.browser.js +1 -5
- package/lib/packlets/csv/index.browser.js.map +1 -0
- package/lib/packlets/csv/index.d.ts.map +1 -0
- package/lib/packlets/csv/index.js.map +1 -0
- package/lib/packlets/experimental/extendedArray.d.ts.map +1 -0
- package/lib/packlets/experimental/extendedArray.js.map +1 -0
- package/lib/packlets/experimental/formatter.d.ts.map +1 -0
- package/lib/packlets/experimental/formatter.js.map +1 -0
- package/lib/packlets/experimental/index.d.ts.map +1 -0
- package/lib/packlets/experimental/index.js.map +1 -0
- package/lib/packlets/experimental/rangeOf.d.ts.map +1 -0
- package/lib/packlets/experimental/rangeOf.js.map +1 -0
- package/lib/packlets/hash/index.browser.d.ts.map +1 -0
- package/lib/packlets/hash/index.browser.js.map +1 -0
- package/lib/packlets/hash/index.d.ts.map +1 -0
- package/lib/packlets/hash/index.js.map +1 -0
- package/lib/packlets/hash/index.node.d.ts.map +1 -0
- package/lib/packlets/hash/index.node.js.map +1 -0
- package/lib/packlets/hash/md5Normalizer.browser.d.ts.map +1 -0
- package/lib/packlets/hash/md5Normalizer.browser.js.map +1 -0
- package/lib/packlets/hash/md5Normalizer.d.ts.map +1 -0
- package/lib/packlets/hash/md5Normalizer.js.map +1 -0
- package/lib/packlets/mustache/index.d.ts +1 -1
- package/lib/packlets/mustache/index.d.ts.map +1 -0
- package/lib/packlets/mustache/index.js.map +1 -0
- package/lib/packlets/mustache/interfaces.d.ts +34 -0
- package/lib/packlets/mustache/interfaces.d.ts.map +1 -0
- package/lib/packlets/mustache/interfaces.js.map +1 -0
- package/lib/packlets/mustache/mustacheTemplate.d.ts +2 -0
- package/lib/packlets/mustache/mustacheTemplate.d.ts.map +1 -0
- package/lib/packlets/mustache/mustacheTemplate.js +42 -4
- package/lib/packlets/mustache/mustacheTemplate.js.map +1 -0
- package/lib/packlets/record-jar/index.browser.d.ts +0 -1
- package/lib/packlets/record-jar/index.browser.d.ts.map +1 -0
- package/lib/packlets/record-jar/index.browser.js +1 -5
- package/lib/packlets/record-jar/index.browser.js.map +1 -0
- package/lib/packlets/record-jar/index.d.ts.map +1 -0
- package/lib/packlets/record-jar/index.js.map +1 -0
- package/lib/packlets/record-jar/recordJarFileHelpers.d.ts +0 -11
- package/lib/packlets/record-jar/recordJarFileHelpers.d.ts.map +1 -0
- package/lib/packlets/record-jar/recordJarFileHelpers.js +0 -19
- package/lib/packlets/record-jar/recordJarFileHelpers.js.map +1 -0
- package/lib/packlets/record-jar/recordJarHelpers.d.ts +11 -0
- package/lib/packlets/record-jar/recordJarHelpers.d.ts.map +1 -0
- package/lib/packlets/record-jar/recordJarHelpers.js +19 -0
- package/lib/packlets/record-jar/recordJarHelpers.js.map +1 -0
- package/lib/packlets/safer-fetch/addressClassification.d.ts +144 -0
- package/lib/packlets/safer-fetch/addressClassification.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/addressClassification.js +441 -0
- package/lib/packlets/safer-fetch/addressClassification.js.map +1 -0
- package/lib/packlets/safer-fetch/addressPolicy.d.ts +113 -0
- package/lib/packlets/safer-fetch/addressPolicy.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/addressPolicy.js +123 -0
- package/lib/packlets/safer-fetch/addressPolicy.js.map +1 -0
- package/lib/packlets/safer-fetch/contentType.d.ts +51 -0
- package/lib/packlets/safer-fetch/contentType.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/contentType.js +127 -0
- package/lib/packlets/safer-fetch/contentType.js.map +1 -0
- package/lib/packlets/safer-fetch/deadline.d.ts +138 -0
- package/lib/packlets/safer-fetch/deadline.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/deadline.js +258 -0
- package/lib/packlets/safer-fetch/deadline.js.map +1 -0
- package/lib/packlets/safer-fetch/defaults.d.ts +108 -0
- package/lib/packlets/safer-fetch/defaults.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/defaults.js +134 -0
- package/lib/packlets/safer-fetch/defaults.js.map +1 -0
- package/lib/packlets/safer-fetch/failureReason.d.ts +148 -0
- package/lib/packlets/safer-fetch/failureReason.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/failureReason.js +22 -0
- package/lib/packlets/safer-fetch/failureReason.js.map +1 -0
- package/lib/packlets/safer-fetch/guards.d.ts +62 -0
- package/lib/packlets/safer-fetch/guards.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/guards.js +153 -0
- package/lib/packlets/safer-fetch/guards.js.map +1 -0
- package/lib/packlets/safer-fetch/index.browser.d.ts +33 -0
- package/lib/packlets/safer-fetch/index.browser.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/index.browser.js +82 -0
- package/lib/packlets/safer-fetch/index.browser.js.map +1 -0
- package/lib/packlets/safer-fetch/index.d.ts +27 -0
- package/lib/packlets/safer-fetch/index.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/index.js +78 -0
- package/lib/packlets/safer-fetch/index.js.map +1 -0
- package/lib/packlets/safer-fetch/model.d.ts +373 -0
- package/lib/packlets/safer-fetch/model.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/model.js +22 -0
- package/lib/packlets/safer-fetch/model.js.map +1 -0
- package/lib/packlets/safer-fetch/nodeAddressGuard.d.ts +129 -0
- package/lib/packlets/safer-fetch/nodeAddressGuard.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/nodeAddressGuard.js +196 -0
- package/lib/packlets/safer-fetch/nodeAddressGuard.js.map +1 -0
- package/lib/packlets/safer-fetch/redirect.d.ts +62 -0
- package/lib/packlets/safer-fetch/redirect.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/redirect.js +98 -0
- package/lib/packlets/safer-fetch/redirect.js.map +1 -0
- package/lib/packlets/safer-fetch/retry.d.ts +162 -0
- package/lib/packlets/safer-fetch/retry.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/retry.js +197 -0
- package/lib/packlets/safer-fetch/retry.js.map +1 -0
- package/lib/packlets/safer-fetch/saferFetch.d.ts +108 -0
- package/lib/packlets/safer-fetch/saferFetch.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/saferFetch.js +760 -0
- package/lib/packlets/safer-fetch/saferFetch.js.map +1 -0
- package/lib/packlets/safer-fetch/transport.d.ts +18 -0
- package/lib/packlets/safer-fetch/transport.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/transport.js +53 -0
- package/lib/packlets/safer-fetch/transport.js.map +1 -0
- package/lib/packlets/yaml/converters.d.ts.map +1 -0
- package/lib/packlets/yaml/converters.js.map +1 -0
- package/lib/packlets/yaml/index.d.ts +1 -0
- package/lib/packlets/yaml/index.d.ts.map +1 -0
- package/lib/packlets/yaml/index.js +1 -0
- package/lib/packlets/yaml/index.js.map +1 -0
- package/lib/packlets/yaml/serializers.d.ts +45 -0
- package/lib/packlets/yaml/serializers.d.ts.map +1 -0
- package/lib/packlets/yaml/serializers.js +84 -0
- package/lib/packlets/yaml/serializers.js.map +1 -0
- package/lib/packlets/zip-file-tree/index.d.ts.map +1 -0
- package/lib/packlets/zip-file-tree/index.js.map +1 -0
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts +84 -8
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts.map +1 -0
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js +99 -9
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -0
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.d.ts +26 -1
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.d.ts.map +1 -0
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.js +17 -1
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -0
- package/package.json +30 -15
- package/lib/packlets/ai-assist/apiClient.d.ts +0 -60
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seedDerivedKeyPair.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/seedDerivedKeyPair.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport { captureAsyncResult, fail, Result } from '@fgv/ts-utils';\nimport { SeedDerivableAlgorithm } from './model';\n\n/**\n * Per-algorithm parameters for the shared seed→keypair derivation. The two\n * supported algorithms differ only in the OID embedded in the PKCS#8 envelope,\n * the WebCrypto algorithm name, the JWK curve name, and the key usages — the\n * envelope structure and 32-byte seed handling are identical.\n */\ninterface ISeedAlgorithmParams {\n /**\n * The RFC 8410 §7 DER prefix for a PKCS#8 `OneAsymmetricKey` wrapping a bare\n * 32-byte seed. Decodes as:\n *\n * ```text\n * 30 2e SEQUENCE (46 bytes)\n * 02 01 00 INTEGER version 0 (v1)\n * 30 05 SEQUENCE AlgorithmIdentifier (5 bytes)\n * 06 03 2b65XX OID 1.3.101.XXX\n * 04 22 OCTET STRING privateKey (34 bytes)\n * 04 20 OCTET STRING CurvePrivateKey (32 bytes)\n * ```\n *\n * The 32-byte seed follows immediately (total 48 bytes). Ed25519 uses OID\n * 1.3.101.112 (`...2b 65 70`); X25519 uses 1.3.101.110 (`...2b 65 6e`) — the\n * two prefixes differ only in that final OID byte.\n */\n readonly pkcs8Prefix: ReadonlyArray<number>;\n /** WebCrypto algorithm name (`importKey`'s `algorithm.name`). */\n readonly webCryptoName: 'Ed25519' | 'X25519';\n /** JWK curve name for the reconstructed public key. */\n readonly jwkCrv: 'Ed25519' | 'X25519';\n /** Usages for the imported private key. */\n readonly privateUsages: ReadonlyArray<KeyUsage>;\n /** Usages for the reconstructed public key (empty for X25519). */\n readonly publicUsages: ReadonlyArray<KeyUsage>;\n}\n\n/**\n * An Ed25519 or X25519 private key *is* its 32-byte seed (RFC 8032 §5.1.5 /\n * RFC 7748 §5), and the public key is a deterministic function of that seed, so\n * wrapping the seed in the PKCS#8 envelope and importing it via WebCrypto\n * recovers the exact keypair on every runtime.\n */\nconst _SEED_ALGORITHMS: Readonly<Record<SeedDerivableAlgorithm, ISeedAlgorithmParams>> = {\n ed25519: {\n pkcs8Prefix: [\n 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20\n ],\n webCryptoName: 'Ed25519',\n jwkCrv: 'Ed25519',\n privateUsages: ['sign'],\n publicUsages: ['verify']\n },\n x25519: {\n pkcs8Prefix: [\n 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04, 0x20\n ],\n webCryptoName: 'X25519',\n jwkCrv: 'X25519',\n privateUsages: ['deriveBits'],\n publicUsages: []\n }\n};\n\n/**\n * Required length, in bytes, of an Ed25519 / X25519 seed (RFC 8032 §5.1.5 /\n * RFC 7748 §5).\n */\nconst _SEED_LENGTH: number = 32;\n\n/**\n * Derives an asymmetric keypair *deterministically* from a fixed secret seed\n * using `globalThis.crypto.subtle`, shared by the Node and browser\n * {@link CryptoUtils.ICryptoProvider} implementations (both speak the same\n * WebCrypto API). See\n * {@link CryptoUtils.ICryptoProvider.importKeyPairFromSeed | importKeyPairFromSeed}\n * for the public contract.\n *\n * For each supported algorithm: wraps the 32-byte seed in the RFC 8410 PKCS#8\n * envelope, then runs a transient-extractable-then-derive dance so the public\n * key is recoverable even when the caller requests a non-extractable private key:\n *\n * 1. Import the PKCS#8 as a *transient* extractable private key.\n * 2. Export it to JWK to read the deterministic public coordinate `x`.\n * 3. Import `{ kty: 'OKP', crv, x }` as the returned public key.\n * 4. For the returned private key: reuse the transient key when `extractable`\n * is `true`; otherwise re-import the same PKCS#8 as a non-extractable key.\n * The transient extractable key is never returned when `extractable` is\n * `false`, so seed material cannot escape through it.\n *\n * The two algorithms differ only in the OID/name/curve/usages (see\n * {@link ISeedAlgorithmParams}); `'x25519'` yields the DH key-agreement keypair\n * (private `'deriveBits'`, public no-usage) that {@link CryptoUtils.HpkeProvider}\n * consumes as its recipient key.\n *\n * The seed bytes are copied into a freshly allocated PKCS#8 buffer, so the\n * `BufferSource` handed to WebCrypto is always backed by a plain `ArrayBuffer`\n * (side-stepping the Node-20 `SharedArrayBuffer`-view rejection) and the\n * caller's `seed` is never mutated.\n *\n * @param algorithm - The seed-derivable algorithm (`'ed25519'` or `'x25519'`).\n * Any other value fails loudly rather than being mis-handled.\n * @param seed - The 32-byte secret seed. Any other length fails loudly, before\n * any WebCrypto call.\n * @param extractable - Whether the returned private key may be exported.\n * @returns `Success` with the derived `CryptoKeyPair`, or `Failure` with error context.\n * @public\n */\nexport async function deriveKeyPairFromSeed(\n algorithm: SeedDerivableAlgorithm,\n seed: Uint8Array,\n extractable: boolean\n): Promise<Result<CryptoKeyPair>> {\n const params = _SEED_ALGORITHMS[algorithm];\n if (params === undefined) {\n return fail(\n `importKeyPairFromSeed: unsupported seed-derivable algorithm '${algorithm}' (supported: 'ed25519', 'x25519')`\n );\n }\n if (seed.length !== _SEED_LENGTH) {\n return fail(\n `importKeyPairFromSeed: ${algorithm} seed must be exactly ${_SEED_LENGTH} bytes, got ${seed.length}`\n );\n }\n\n // Back the PKCS#8 by a fresh, non-shared ArrayBuffer so the BufferSource handed\n // to WebCrypto is a `Uint8Array<ArrayBuffer>` — Node 20+ rejects a shared-buffer\n // view, and TypeScript's `BufferSource` excludes the `SharedArrayBuffer` branch.\n const pkcs8: Uint8Array<ArrayBuffer> = new Uint8Array(\n new ArrayBuffer(params.pkcs8Prefix.length + _SEED_LENGTH)\n );\n pkcs8.set(params.pkcs8Prefix, 0);\n pkcs8.set(seed, params.pkcs8Prefix.length);\n\n const algo = { name: params.webCryptoName };\n const privateUsages = [...params.privateUsages];\n\n return (\n await captureAsyncResult<CryptoKeyPair>(async () => {\n const subtle = globalThis.crypto.subtle;\n // Transient extractable private key — only used to read the deterministic\n // public coordinate; dropped (never returned/logged) when the caller\n // asked for a non-extractable private key.\n const transientPrivateKey = await subtle.importKey('pkcs8', pkcs8, algo, true, privateUsages);\n const jwk = await subtle.exportKey('jwk', transientPrivateKey);\n const publicKey = await subtle.importKey(\n 'jwk',\n { kty: 'OKP', crv: params.jwkCrv, x: jwk.x },\n algo,\n true,\n [...params.publicUsages]\n );\n const privateKey = extractable\n ? transientPrivateKey\n : await subtle.importKey('pkcs8', pkcs8, algo, false, privateUsages);\n return { publicKey, privateKey };\n })\n ).withErrorFormat((e) => `importKeyPairFromSeed: failed to derive ${algorithm} keypair from seed: ${e}`);\n}\n"]}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { Result } from '@fgv/ts-utils';
|
|
2
|
+
import { ICryptoProvider, KeyPairAlgorithm, MultibaseSpkiPublicKey } from './model';
|
|
3
|
+
/**
|
|
4
|
+
* Encodes a `Uint8Array` as a base64url (no-padding) string (RFC 4648 §5).
|
|
5
|
+
*
|
|
6
|
+
* The body uses the base64url alphabet (`+` → `-`, `/` → `_`) and trailing `=`
|
|
7
|
+
* padding is stripped. This is the bare primitive with no multibase prefix; use
|
|
8
|
+
* {@link CryptoUtils.multibaseBase64UrlEncode} when a multibase-`'m'`-prefixed value is required.
|
|
9
|
+
*
|
|
10
|
+
* @param data - The binary data to encode.
|
|
11
|
+
* @returns The base64url-no-pad string.
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
export declare function base64UrlNoPadEncode(data: Uint8Array): string;
|
|
15
|
+
/**
|
|
16
|
+
* Decodes a base64url (no-padding) string (RFC 4648 §5) back to a `Uint8Array`.
|
|
17
|
+
*
|
|
18
|
+
* This is the bare primitive with no multibase prefix; use
|
|
19
|
+
* {@link CryptoUtils.multibaseBase64UrlDecode} to decode a multibase-`'m'`-prefixed value.
|
|
20
|
+
*
|
|
21
|
+
* @param encoded - The base64url-no-pad body to decode.
|
|
22
|
+
* @returns `Success` with the decoded bytes, or `Failure` with error context.
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
export declare function base64UrlNoPadDecode(encoded: string): Result<Uint8Array>;
|
|
26
|
+
/**
|
|
27
|
+
* Encodes a `Uint8Array` as a lowercase hexadecimal string with no `0x` prefix.
|
|
28
|
+
*
|
|
29
|
+
* Each byte becomes exactly two lowercase hex characters (zero-padded), so an
|
|
30
|
+
* `n`-byte input yields a `2n`-character string. An empty input yields the empty
|
|
31
|
+
* string. This is the inverse of {@link CryptoUtils.hexDecode}.
|
|
32
|
+
*
|
|
33
|
+
* @param data - The binary data to encode.
|
|
34
|
+
* @returns The lowercase, unprefixed hex string.
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
export declare function hexEncode(data: Uint8Array): string;
|
|
38
|
+
/**
|
|
39
|
+
* Decodes a hexadecimal string (no `0x` prefix) back to a `Uint8Array`.
|
|
40
|
+
*
|
|
41
|
+
* Liberal in what it accepts: both lowercase and uppercase hex digits are
|
|
42
|
+
* allowed (whereas {@link CryptoUtils.hexEncode} always emits lowercase). The
|
|
43
|
+
* input must have even length and contain only hex digits (`0-9`, `a-f`, `A-F`);
|
|
44
|
+
* an empty string decodes to an empty `Uint8Array`. Odd length or any non-hex
|
|
45
|
+
* character fails with error context.
|
|
46
|
+
*
|
|
47
|
+
* @param encoded - The hex string to decode.
|
|
48
|
+
* @returns `Success` with the decoded bytes, or `Failure` with error context.
|
|
49
|
+
* @public
|
|
50
|
+
*/
|
|
51
|
+
export declare function hexDecode(encoded: string): Result<Uint8Array>;
|
|
52
|
+
/**
|
|
53
|
+
* The structural *shape* of a {@link CryptoUtils.MultibaseSpkiPublicKey}: the
|
|
54
|
+
* multibase `'m'` prefix followed by a non-empty base64url-no-pad body
|
|
55
|
+
* (`A-Z`, `a-z`, `0-9`, `-`, `_`).
|
|
56
|
+
*
|
|
57
|
+
* This is a shape prefilter, not full validation: it does not decode the DER
|
|
58
|
+
* SPKI or verify the key material or algorithm (that happens in
|
|
59
|
+
* {@link CryptoUtils.importPublicKeyFromMultibaseSpki}). The authoritative guard
|
|
60
|
+
* is {@link CryptoUtils.isValidMultibaseSpkiPublicKey}, which enforces this
|
|
61
|
+
* pattern **and** additionally rejects a body whose length is an impossible
|
|
62
|
+
* base64 remainder. Exposed for callers that need the pattern directly (e.g. a
|
|
63
|
+
* JSON-schema `pattern` field); prefer the guard/converter for validation.
|
|
64
|
+
*
|
|
65
|
+
* @public
|
|
66
|
+
*/
|
|
67
|
+
export declare const MultibaseSpkiPublicKeyRegExp: RegExp;
|
|
68
|
+
/**
|
|
69
|
+
* Type guard for {@link CryptoUtils.MultibaseSpkiPublicKey}: a string matching
|
|
70
|
+
* {@link CryptoUtils.MultibaseSpkiPublicKeyRegExp} (multibase `'m'` prefix + a
|
|
71
|
+
* non-empty base64url-no-pad body) whose body also satisfies the base64url-no-pad
|
|
72
|
+
* length rule shared with {@link CryptoUtils.base64UrlNoPadDecode}. This is a
|
|
73
|
+
* structural *shape* check, not full validation — it does not decode the DER SPKI
|
|
74
|
+
* or verify the key material/algorithm (a malformed-but-well-shaped string fails
|
|
75
|
+
* later, with clear context, in {@link CryptoUtils.importPublicKeyFromMultibaseSpki}).
|
|
76
|
+
*
|
|
77
|
+
* @param value - The value to test.
|
|
78
|
+
* @returns `true` if `value` is a well-formed multibase SPKI public key string.
|
|
79
|
+
* @public
|
|
80
|
+
*/
|
|
81
|
+
export declare function isValidMultibaseSpkiPublicKey(value: unknown): value is MultibaseSpkiPublicKey;
|
|
82
|
+
/**
|
|
83
|
+
* Encodes a `Uint8Array` as a multibase base64url (no-padding) string.
|
|
84
|
+
*
|
|
85
|
+
* The multibase prefix `'m'` identifies the encoding as RFC 4648 base64url
|
|
86
|
+
* without padding. The body uses base64url alphabet: `+` → `-`, `/` → `_`,
|
|
87
|
+
* and trailing `=` padding is stripped.
|
|
88
|
+
*
|
|
89
|
+
* @param data - The binary data to encode.
|
|
90
|
+
* @returns A multibase-prefixed base64url string (`'m' + base64url-no-pad`).
|
|
91
|
+
* @public
|
|
92
|
+
*/
|
|
93
|
+
export declare function multibaseBase64UrlEncode(data: Uint8Array): string;
|
|
94
|
+
/**
|
|
95
|
+
* Decodes a multibase base64url (no-padding) string back to a `Uint8Array`.
|
|
96
|
+
*
|
|
97
|
+
* Validates that the first character is `'m'` (the multibase prefix for
|
|
98
|
+
* RFC 4648 base64url without padding), then decodes the remaining body.
|
|
99
|
+
*
|
|
100
|
+
* @param encoded - A multibase-prefixed base64url string.
|
|
101
|
+
* @returns `Success` with the decoded bytes, or `Failure` with error context.
|
|
102
|
+
* @public
|
|
103
|
+
*/
|
|
104
|
+
export declare function multibaseBase64UrlDecode(encoded: string): Result<Uint8Array>;
|
|
105
|
+
/**
|
|
106
|
+
* Exports a public `CryptoKey` as a multibase base64url-encoded SPKI blob.
|
|
107
|
+
*
|
|
108
|
+
* The SPKI (SubjectPublicKeyInfo) format is the standard DER-encoded structure
|
|
109
|
+
* for public keys defined in RFC 5280, RFC 5480, and RFC 8410. It is
|
|
110
|
+
* algorithm-agnostic and suitable for storage and transmission.
|
|
111
|
+
*
|
|
112
|
+
* @param key - The `CryptoKey` to export. Must have `key.type === 'public'`.
|
|
113
|
+
* @param provider - The {@link CryptoUtils.ICryptoProvider} to use for the export operation.
|
|
114
|
+
* @returns `Success` with the multibase SPKI string, or `Failure` with error context.
|
|
115
|
+
* @public
|
|
116
|
+
*/
|
|
117
|
+
export declare function exportPublicKeyAsMultibaseSpki(key: CryptoKey, provider: ICryptoProvider): Promise<Result<MultibaseSpkiPublicKey>>;
|
|
118
|
+
/**
|
|
119
|
+
* Imports a public key from a multibase base64url-encoded SPKI blob.
|
|
120
|
+
*
|
|
121
|
+
* Decodes the multibase prefix, decodes the base64url body, then uses
|
|
122
|
+
* the provider to import the key with the algorithm parameters from
|
|
123
|
+
* {@link CryptoUtils.keyPairAlgorithmParams}.
|
|
124
|
+
*
|
|
125
|
+
* Accepts a plain `string` (not only a branded {@link CryptoUtils.MultibaseSpkiPublicKey}),
|
|
126
|
+
* so callers holding an unbranded value read from storage or the wire can import
|
|
127
|
+
* it directly; a malformed value fails with error context rather than throwing.
|
|
128
|
+
*
|
|
129
|
+
* @param encoded - A multibase SPKI string produced by {@link CryptoUtils.exportPublicKeyAsMultibaseSpki}.
|
|
130
|
+
* @param algorithm - The {@link CryptoUtils.KeyPairAlgorithm} the key was generated for.
|
|
131
|
+
* @param provider - The {@link CryptoUtils.ICryptoProvider} to use for the import operation.
|
|
132
|
+
* @returns `Success` with the imported public `CryptoKey`, or `Failure` with error context.
|
|
133
|
+
* @public
|
|
134
|
+
*/
|
|
135
|
+
export declare function importPublicKeyFromMultibaseSpki(encoded: string, algorithm: KeyPairAlgorithm, provider: ICryptoProvider): Promise<Result<CryptoKey>>;
|
|
136
|
+
/**
|
|
137
|
+
* Strips the fixed DER prefix from an X25519 SubjectPublicKeyInfo blob, returning the raw
|
|
138
|
+
* 32-byte public key.
|
|
139
|
+
*
|
|
140
|
+
* An X25519 SPKI is always exactly 44 bytes: a fixed 12-byte prefix (SEQUENCE / AlgorithmIdentifier
|
|
141
|
+
* with OID 1.3.101.110 / BIT STRING) followed by the 32-byte raw key. Use this to convert a
|
|
142
|
+
* SPKI-held recipient public key into the raw form accepted by {@link HpkeProvider.openBase}'s
|
|
143
|
+
* `recipientPublicKey` parameter.
|
|
144
|
+
*
|
|
145
|
+
* @param spki - The DER-encoded X25519 SubjectPublicKeyInfo bytes.
|
|
146
|
+
* @returns `Success` with the raw 32-byte public key, or `Failure` if `spki` is not a
|
|
147
|
+
* well-formed 44-byte X25519 SPKI blob.
|
|
148
|
+
* @public
|
|
149
|
+
*/
|
|
150
|
+
export declare function spkiToRawX25519(spki: Uint8Array): Result<Uint8Array>;
|
|
151
|
+
//# sourceMappingURL=spkiHelpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spkiHelpers.d.ts","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/spkiHelpers.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,MAAM,EAAiB,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAYpF;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAe7D;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,CAyBxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAMlD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,CAY7D;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,4BAA4B,EAAE,MAA4B,CAAC;AAExE;;;;;;;;;;;;GAYG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,sBAAsB,CAM7F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAEjE;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,CAe5E;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,8BAA8B,CAClD,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAQzC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAQ5B;AASD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,CAUpE"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) 2026 Erik Fortune
|
|
3
|
+
//
|
|
4
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
// in the Software without restriction, including without limitation the rights
|
|
7
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
// furnished to do so, subject to the following conditions:
|
|
10
|
+
//
|
|
11
|
+
// The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
// copies or substantial portions of the Software.
|
|
13
|
+
//
|
|
14
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
// SOFTWARE.
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.MultibaseSpkiPublicKeyRegExp = void 0;
|
|
23
|
+
exports.base64UrlNoPadEncode = base64UrlNoPadEncode;
|
|
24
|
+
exports.base64UrlNoPadDecode = base64UrlNoPadDecode;
|
|
25
|
+
exports.hexEncode = hexEncode;
|
|
26
|
+
exports.hexDecode = hexDecode;
|
|
27
|
+
exports.isValidMultibaseSpkiPublicKey = isValidMultibaseSpkiPublicKey;
|
|
28
|
+
exports.multibaseBase64UrlEncode = multibaseBase64UrlEncode;
|
|
29
|
+
exports.multibaseBase64UrlDecode = multibaseBase64UrlDecode;
|
|
30
|
+
exports.exportPublicKeyAsMultibaseSpki = exportPublicKeyAsMultibaseSpki;
|
|
31
|
+
exports.importPublicKeyFromMultibaseSpki = importPublicKeyFromMultibaseSpki;
|
|
32
|
+
exports.spkiToRawX25519 = spkiToRawX25519;
|
|
33
|
+
const ts_utils_1 = require("@fgv/ts-utils");
|
|
34
|
+
/**
|
|
35
|
+
* Shared shape check for a base64url (no-padding) body: only base64url alphabet
|
|
36
|
+
* characters (`A-Z`, `a-z`, `0-9`, `-`, `_`) and a length that is never `% 4 === 1`
|
|
37
|
+
* (an impossible base64 remainder). Factored so the decoder and the
|
|
38
|
+
* {@link isValidMultibaseSpkiPublicKey} guard agree on exactly one rule.
|
|
39
|
+
*/
|
|
40
|
+
function isBase64UrlNoPadBody(body) {
|
|
41
|
+
return /^[A-Za-z0-9_-]*$/.test(body) && body.length % 4 !== 1;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Encodes a `Uint8Array` as a base64url (no-padding) string (RFC 4648 §5).
|
|
45
|
+
*
|
|
46
|
+
* The body uses the base64url alphabet (`+` → `-`, `/` → `_`) and trailing `=`
|
|
47
|
+
* padding is stripped. This is the bare primitive with no multibase prefix; use
|
|
48
|
+
* {@link CryptoUtils.multibaseBase64UrlEncode} when a multibase-`'m'`-prefixed value is required.
|
|
49
|
+
*
|
|
50
|
+
* @param data - The binary data to encode.
|
|
51
|
+
* @returns The base64url-no-pad string.
|
|
52
|
+
* @public
|
|
53
|
+
*/
|
|
54
|
+
function base64UrlNoPadEncode(data) {
|
|
55
|
+
let base64;
|
|
56
|
+
if (typeof Buffer !== 'undefined') {
|
|
57
|
+
base64 = Buffer.from(data).toString('base64');
|
|
58
|
+
/* c8 ignore start - browser-only: btoa path not available in Node tests */
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
let binary = '';
|
|
62
|
+
for (let i = 0; i < data.length; i++) {
|
|
63
|
+
binary += String.fromCharCode(data[i]);
|
|
64
|
+
}
|
|
65
|
+
base64 = btoa(binary);
|
|
66
|
+
}
|
|
67
|
+
/* c8 ignore stop */
|
|
68
|
+
// Convert to base64url: + → -, / → _, strip = padding
|
|
69
|
+
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Decodes a base64url (no-padding) string (RFC 4648 §5) back to a `Uint8Array`.
|
|
73
|
+
*
|
|
74
|
+
* This is the bare primitive with no multibase prefix; use
|
|
75
|
+
* {@link CryptoUtils.multibaseBase64UrlDecode} to decode a multibase-`'m'`-prefixed value.
|
|
76
|
+
*
|
|
77
|
+
* @param encoded - The base64url-no-pad body to decode.
|
|
78
|
+
* @returns `Success` with the decoded bytes, or `Failure` with error context.
|
|
79
|
+
* @public
|
|
80
|
+
*/
|
|
81
|
+
function base64UrlNoPadDecode(encoded) {
|
|
82
|
+
if (!isBase64UrlNoPadBody(encoded)) {
|
|
83
|
+
return (0, ts_utils_1.fail)(`base64UrlNoPadDecode: malformed base64url body`);
|
|
84
|
+
}
|
|
85
|
+
// Convert base64url back to standard base64 and restore padding
|
|
86
|
+
const base64 = encoded.replace(/-/g, '+').replace(/_/g, '/');
|
|
87
|
+
const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);
|
|
88
|
+
try {
|
|
89
|
+
let bytes;
|
|
90
|
+
if (typeof Buffer !== 'undefined') {
|
|
91
|
+
bytes = new Uint8Array(Buffer.from(padded, 'base64'));
|
|
92
|
+
/* c8 ignore start - browser-only: atob path not available in Node tests */
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const binary = atob(padded);
|
|
96
|
+
bytes = new Uint8Array(binary.length);
|
|
97
|
+
for (let i = 0; i < binary.length; i++) {
|
|
98
|
+
bytes[i] = binary.charCodeAt(i);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/* c8 ignore stop */
|
|
102
|
+
return (0, ts_utils_1.succeed)(bytes);
|
|
103
|
+
/* c8 ignore next 3 - defensive: shape check above prevents invalid chars from reaching here */
|
|
104
|
+
}
|
|
105
|
+
catch (_a) {
|
|
106
|
+
return (0, ts_utils_1.fail)(`base64UrlNoPadDecode: malformed base64url body`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Encodes a `Uint8Array` as a lowercase hexadecimal string with no `0x` prefix.
|
|
111
|
+
*
|
|
112
|
+
* Each byte becomes exactly two lowercase hex characters (zero-padded), so an
|
|
113
|
+
* `n`-byte input yields a `2n`-character string. An empty input yields the empty
|
|
114
|
+
* string. This is the inverse of {@link CryptoUtils.hexDecode}.
|
|
115
|
+
*
|
|
116
|
+
* @param data - The binary data to encode.
|
|
117
|
+
* @returns The lowercase, unprefixed hex string.
|
|
118
|
+
* @public
|
|
119
|
+
*/
|
|
120
|
+
function hexEncode(data) {
|
|
121
|
+
let hex = '';
|
|
122
|
+
for (let i = 0; i < data.length; i++) {
|
|
123
|
+
hex += data[i].toString(16).padStart(2, '0');
|
|
124
|
+
}
|
|
125
|
+
return hex;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Decodes a hexadecimal string (no `0x` prefix) back to a `Uint8Array`.
|
|
129
|
+
*
|
|
130
|
+
* Liberal in what it accepts: both lowercase and uppercase hex digits are
|
|
131
|
+
* allowed (whereas {@link CryptoUtils.hexEncode} always emits lowercase). The
|
|
132
|
+
* input must have even length and contain only hex digits (`0-9`, `a-f`, `A-F`);
|
|
133
|
+
* an empty string decodes to an empty `Uint8Array`. Odd length or any non-hex
|
|
134
|
+
* character fails with error context.
|
|
135
|
+
*
|
|
136
|
+
* @param encoded - The hex string to decode.
|
|
137
|
+
* @returns `Success` with the decoded bytes, or `Failure` with error context.
|
|
138
|
+
* @public
|
|
139
|
+
*/
|
|
140
|
+
function hexDecode(encoded) {
|
|
141
|
+
if (encoded.length % 2 !== 0) {
|
|
142
|
+
return (0, ts_utils_1.fail)(`hexDecode: odd-length hex string (length ${encoded.length})`);
|
|
143
|
+
}
|
|
144
|
+
if (!/^[0-9a-fA-F]*$/.test(encoded)) {
|
|
145
|
+
return (0, ts_utils_1.fail)(`hexDecode: string contains non-hex characters`);
|
|
146
|
+
}
|
|
147
|
+
const bytes = new Uint8Array(encoded.length / 2);
|
|
148
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
149
|
+
bytes[i] = parseInt(encoded.slice(i * 2, i * 2 + 2), 16);
|
|
150
|
+
}
|
|
151
|
+
return (0, ts_utils_1.succeed)(bytes);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The structural *shape* of a {@link CryptoUtils.MultibaseSpkiPublicKey}: the
|
|
155
|
+
* multibase `'m'` prefix followed by a non-empty base64url-no-pad body
|
|
156
|
+
* (`A-Z`, `a-z`, `0-9`, `-`, `_`).
|
|
157
|
+
*
|
|
158
|
+
* This is a shape prefilter, not full validation: it does not decode the DER
|
|
159
|
+
* SPKI or verify the key material or algorithm (that happens in
|
|
160
|
+
* {@link CryptoUtils.importPublicKeyFromMultibaseSpki}). The authoritative guard
|
|
161
|
+
* is {@link CryptoUtils.isValidMultibaseSpkiPublicKey}, which enforces this
|
|
162
|
+
* pattern **and** additionally rejects a body whose length is an impossible
|
|
163
|
+
* base64 remainder. Exposed for callers that need the pattern directly (e.g. a
|
|
164
|
+
* JSON-schema `pattern` field); prefer the guard/converter for validation.
|
|
165
|
+
*
|
|
166
|
+
* @public
|
|
167
|
+
*/
|
|
168
|
+
exports.MultibaseSpkiPublicKeyRegExp = /^m[A-Za-z0-9_-]+$/;
|
|
169
|
+
/**
|
|
170
|
+
* Type guard for {@link CryptoUtils.MultibaseSpkiPublicKey}: a string matching
|
|
171
|
+
* {@link CryptoUtils.MultibaseSpkiPublicKeyRegExp} (multibase `'m'` prefix + a
|
|
172
|
+
* non-empty base64url-no-pad body) whose body also satisfies the base64url-no-pad
|
|
173
|
+
* length rule shared with {@link CryptoUtils.base64UrlNoPadDecode}. This is a
|
|
174
|
+
* structural *shape* check, not full validation — it does not decode the DER SPKI
|
|
175
|
+
* or verify the key material/algorithm (a malformed-but-well-shaped string fails
|
|
176
|
+
* later, with clear context, in {@link CryptoUtils.importPublicKeyFromMultibaseSpki}).
|
|
177
|
+
*
|
|
178
|
+
* @param value - The value to test.
|
|
179
|
+
* @returns `true` if `value` is a well-formed multibase SPKI public key string.
|
|
180
|
+
* @public
|
|
181
|
+
*/
|
|
182
|
+
function isValidMultibaseSpkiPublicKey(value) {
|
|
183
|
+
return (typeof value === 'string' &&
|
|
184
|
+
exports.MultibaseSpkiPublicKeyRegExp.test(value) &&
|
|
185
|
+
isBase64UrlNoPadBody(value.slice(1)));
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Encodes a `Uint8Array` as a multibase base64url (no-padding) string.
|
|
189
|
+
*
|
|
190
|
+
* The multibase prefix `'m'` identifies the encoding as RFC 4648 base64url
|
|
191
|
+
* without padding. The body uses base64url alphabet: `+` → `-`, `/` → `_`,
|
|
192
|
+
* and trailing `=` padding is stripped.
|
|
193
|
+
*
|
|
194
|
+
* @param data - The binary data to encode.
|
|
195
|
+
* @returns A multibase-prefixed base64url string (`'m' + base64url-no-pad`).
|
|
196
|
+
* @public
|
|
197
|
+
*/
|
|
198
|
+
function multibaseBase64UrlEncode(data) {
|
|
199
|
+
return 'm' + base64UrlNoPadEncode(data);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Decodes a multibase base64url (no-padding) string back to a `Uint8Array`.
|
|
203
|
+
*
|
|
204
|
+
* Validates that the first character is `'m'` (the multibase prefix for
|
|
205
|
+
* RFC 4648 base64url without padding), then decodes the remaining body.
|
|
206
|
+
*
|
|
207
|
+
* @param encoded - A multibase-prefixed base64url string.
|
|
208
|
+
* @returns `Success` with the decoded bytes, or `Failure` with error context.
|
|
209
|
+
* @public
|
|
210
|
+
*/
|
|
211
|
+
function multibaseBase64UrlDecode(encoded) {
|
|
212
|
+
var _a;
|
|
213
|
+
if (!encoded.startsWith('m')) {
|
|
214
|
+
return (0, ts_utils_1.fail)(`multibaseBase64UrlDecode: invalid multibase prefix '${(_a = encoded[0]) !== null && _a !== void 0 ? _a : '(empty)'}' — expected 'm' (base64url)`);
|
|
215
|
+
}
|
|
216
|
+
// Intentionally pin the exact original message (the delegate has a single failure
|
|
217
|
+
// mode) to keep this established public function byte-for-byte behavior-preserving
|
|
218
|
+
// after the extract-and-delegate refactor — do not "fix" this into composing the
|
|
219
|
+
// delegate's message without updating the delegation-equivalence tests.
|
|
220
|
+
return base64UrlNoPadDecode(encoded.slice(1)).withErrorFormat(() => `multibaseBase64UrlDecode: malformed base64url body`);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Exports a public `CryptoKey` as a multibase base64url-encoded SPKI blob.
|
|
224
|
+
*
|
|
225
|
+
* The SPKI (SubjectPublicKeyInfo) format is the standard DER-encoded structure
|
|
226
|
+
* for public keys defined in RFC 5280, RFC 5480, and RFC 8410. It is
|
|
227
|
+
* algorithm-agnostic and suitable for storage and transmission.
|
|
228
|
+
*
|
|
229
|
+
* @param key - The `CryptoKey` to export. Must have `key.type === 'public'`.
|
|
230
|
+
* @param provider - The {@link CryptoUtils.ICryptoProvider} to use for the export operation.
|
|
231
|
+
* @returns `Success` with the multibase SPKI string, or `Failure` with error context.
|
|
232
|
+
* @public
|
|
233
|
+
*/
|
|
234
|
+
async function exportPublicKeyAsMultibaseSpki(key, provider) {
|
|
235
|
+
return (await provider.exportPublicKeySpki(key))
|
|
236
|
+
.withErrorFormat((e) => `exportPublicKeyAsMultibaseSpki: ${e}`)
|
|
237
|
+
.onSuccess((buf) =>
|
|
238
|
+
// The output is a freshly-built valid multibase SPKI string (`'m'` prefix +
|
|
239
|
+
// base64url-no-pad body), so brand it at the construction site — no re-validation needed.
|
|
240
|
+
(0, ts_utils_1.succeed)(multibaseBase64UrlEncode(buf)));
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Imports a public key from a multibase base64url-encoded SPKI blob.
|
|
244
|
+
*
|
|
245
|
+
* Decodes the multibase prefix, decodes the base64url body, then uses
|
|
246
|
+
* the provider to import the key with the algorithm parameters from
|
|
247
|
+
* {@link CryptoUtils.keyPairAlgorithmParams}.
|
|
248
|
+
*
|
|
249
|
+
* Accepts a plain `string` (not only a branded {@link CryptoUtils.MultibaseSpkiPublicKey}),
|
|
250
|
+
* so callers holding an unbranded value read from storage or the wire can import
|
|
251
|
+
* it directly; a malformed value fails with error context rather than throwing.
|
|
252
|
+
*
|
|
253
|
+
* @param encoded - A multibase SPKI string produced by {@link CryptoUtils.exportPublicKeyAsMultibaseSpki}.
|
|
254
|
+
* @param algorithm - The {@link CryptoUtils.KeyPairAlgorithm} the key was generated for.
|
|
255
|
+
* @param provider - The {@link CryptoUtils.ICryptoProvider} to use for the import operation.
|
|
256
|
+
* @returns `Success` with the imported public `CryptoKey`, or `Failure` with error context.
|
|
257
|
+
* @public
|
|
258
|
+
*/
|
|
259
|
+
async function importPublicKeyFromMultibaseSpki(encoded, algorithm, provider) {
|
|
260
|
+
const decodeResult = multibaseBase64UrlDecode(encoded);
|
|
261
|
+
if (decodeResult.isFailure()) {
|
|
262
|
+
return (0, ts_utils_1.fail)(`importPublicKeyFromMultibaseSpki: ${decodeResult.message}`);
|
|
263
|
+
}
|
|
264
|
+
return (await provider.importPublicKeySpki(decodeResult.value, algorithm)).withErrorFormat((e) => `importPublicKeyFromMultibaseSpki: ${e}`);
|
|
265
|
+
}
|
|
266
|
+
// DER prefix for an X25519 SubjectPublicKeyInfo: SEQUENCE { SEQUENCE { OID id-X25519 }, BIT STRING }.
|
|
267
|
+
// SEQUENCE(42) / SEQUENCE(5) / OID 1.3.101.110 (id-X25519) / BIT STRING(33, 0 unused bits).
|
|
268
|
+
const _X25519_SPKI_PREFIX = [
|
|
269
|
+
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00
|
|
270
|
+
];
|
|
271
|
+
const _X25519_SPKI_LENGTH = _X25519_SPKI_PREFIX.length + 32;
|
|
272
|
+
/**
|
|
273
|
+
* Strips the fixed DER prefix from an X25519 SubjectPublicKeyInfo blob, returning the raw
|
|
274
|
+
* 32-byte public key.
|
|
275
|
+
*
|
|
276
|
+
* An X25519 SPKI is always exactly 44 bytes: a fixed 12-byte prefix (SEQUENCE / AlgorithmIdentifier
|
|
277
|
+
* with OID 1.3.101.110 / BIT STRING) followed by the 32-byte raw key. Use this to convert a
|
|
278
|
+
* SPKI-held recipient public key into the raw form accepted by {@link HpkeProvider.openBase}'s
|
|
279
|
+
* `recipientPublicKey` parameter.
|
|
280
|
+
*
|
|
281
|
+
* @param spki - The DER-encoded X25519 SubjectPublicKeyInfo bytes.
|
|
282
|
+
* @returns `Success` with the raw 32-byte public key, or `Failure` if `spki` is not a
|
|
283
|
+
* well-formed 44-byte X25519 SPKI blob.
|
|
284
|
+
* @public
|
|
285
|
+
*/
|
|
286
|
+
function spkiToRawX25519(spki) {
|
|
287
|
+
if (spki.length !== _X25519_SPKI_LENGTH) {
|
|
288
|
+
return (0, ts_utils_1.fail)(`spkiToRawX25519: expected ${_X25519_SPKI_LENGTH} bytes, got ${spki.length}`);
|
|
289
|
+
}
|
|
290
|
+
for (let i = 0; i < _X25519_SPKI_PREFIX.length; i++) {
|
|
291
|
+
if (spki[i] !== _X25519_SPKI_PREFIX[i]) {
|
|
292
|
+
return (0, ts_utils_1.fail)(`spkiToRawX25519: byte ${i} does not match the expected X25519 SPKI prefix`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return (0, ts_utils_1.succeed)(spki.slice(_X25519_SPKI_PREFIX.length));
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=spkiHelpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spkiHelpers.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/spkiHelpers.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\nimport { Result, fail, succeed } from '@fgv/ts-utils';\nimport { ICryptoProvider, KeyPairAlgorithm, MultibaseSpkiPublicKey } from './model';\n\n/**\n * Shared shape check for a base64url (no-padding) body: only base64url alphabet\n * characters (`A-Z`, `a-z`, `0-9`, `-`, `_`) and a length that is never `% 4 === 1`\n * (an impossible base64 remainder). Factored so the decoder and the\n * {@link isValidMultibaseSpkiPublicKey} guard agree on exactly one rule.\n */\nfunction isBase64UrlNoPadBody(body: string): boolean {\n return /^[A-Za-z0-9_-]*$/.test(body) && body.length % 4 !== 1;\n}\n\n/**\n * Encodes a `Uint8Array` as a base64url (no-padding) string (RFC 4648 §5).\n *\n * The body uses the base64url alphabet (`+` → `-`, `/` → `_`) and trailing `=`\n * padding is stripped. This is the bare primitive with no multibase prefix; use\n * {@link CryptoUtils.multibaseBase64UrlEncode} when a multibase-`'m'`-prefixed value is required.\n *\n * @param data - The binary data to encode.\n * @returns The base64url-no-pad string.\n * @public\n */\nexport function base64UrlNoPadEncode(data: Uint8Array): string {\n let base64: string;\n if (typeof Buffer !== 'undefined') {\n base64 = Buffer.from(data).toString('base64');\n /* c8 ignore start - browser-only: btoa path not available in Node tests */\n } else {\n let binary = '';\n for (let i = 0; i < data.length; i++) {\n binary += String.fromCharCode(data[i]);\n }\n base64 = btoa(binary);\n }\n /* c8 ignore stop */\n // Convert to base64url: + → -, / → _, strip = padding\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * Decodes a base64url (no-padding) string (RFC 4648 §5) back to a `Uint8Array`.\n *\n * This is the bare primitive with no multibase prefix; use\n * {@link CryptoUtils.multibaseBase64UrlDecode} to decode a multibase-`'m'`-prefixed value.\n *\n * @param encoded - The base64url-no-pad body to decode.\n * @returns `Success` with the decoded bytes, or `Failure` with error context.\n * @public\n */\nexport function base64UrlNoPadDecode(encoded: string): Result<Uint8Array> {\n if (!isBase64UrlNoPadBody(encoded)) {\n return fail(`base64UrlNoPadDecode: malformed base64url body`);\n }\n // Convert base64url back to standard base64 and restore padding\n const base64 = encoded.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);\n try {\n let bytes: Uint8Array;\n if (typeof Buffer !== 'undefined') {\n bytes = new Uint8Array(Buffer.from(padded, 'base64'));\n /* c8 ignore start - browser-only: atob path not available in Node tests */\n } else {\n const binary = atob(padded);\n bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n }\n /* c8 ignore stop */\n return succeed(bytes);\n /* c8 ignore next 3 - defensive: shape check above prevents invalid chars from reaching here */\n } catch {\n return fail(`base64UrlNoPadDecode: malformed base64url body`);\n }\n}\n\n/**\n * Encodes a `Uint8Array` as a lowercase hexadecimal string with no `0x` prefix.\n *\n * Each byte becomes exactly two lowercase hex characters (zero-padded), so an\n * `n`-byte input yields a `2n`-character string. An empty input yields the empty\n * string. This is the inverse of {@link CryptoUtils.hexDecode}.\n *\n * @param data - The binary data to encode.\n * @returns The lowercase, unprefixed hex string.\n * @public\n */\nexport function hexEncode(data: Uint8Array): string {\n let hex = '';\n for (let i = 0; i < data.length; i++) {\n hex += data[i].toString(16).padStart(2, '0');\n }\n return hex;\n}\n\n/**\n * Decodes a hexadecimal string (no `0x` prefix) back to a `Uint8Array`.\n *\n * Liberal in what it accepts: both lowercase and uppercase hex digits are\n * allowed (whereas {@link CryptoUtils.hexEncode} always emits lowercase). The\n * input must have even length and contain only hex digits (`0-9`, `a-f`, `A-F`);\n * an empty string decodes to an empty `Uint8Array`. Odd length or any non-hex\n * character fails with error context.\n *\n * @param encoded - The hex string to decode.\n * @returns `Success` with the decoded bytes, or `Failure` with error context.\n * @public\n */\nexport function hexDecode(encoded: string): Result<Uint8Array> {\n if (encoded.length % 2 !== 0) {\n return fail(`hexDecode: odd-length hex string (length ${encoded.length})`);\n }\n if (!/^[0-9a-fA-F]*$/.test(encoded)) {\n return fail(`hexDecode: string contains non-hex characters`);\n }\n const bytes = new Uint8Array(encoded.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(encoded.slice(i * 2, i * 2 + 2), 16);\n }\n return succeed(bytes);\n}\n\n/**\n * The structural *shape* of a {@link CryptoUtils.MultibaseSpkiPublicKey}: the\n * multibase `'m'` prefix followed by a non-empty base64url-no-pad body\n * (`A-Z`, `a-z`, `0-9`, `-`, `_`).\n *\n * This is a shape prefilter, not full validation: it does not decode the DER\n * SPKI or verify the key material or algorithm (that happens in\n * {@link CryptoUtils.importPublicKeyFromMultibaseSpki}). The authoritative guard\n * is {@link CryptoUtils.isValidMultibaseSpkiPublicKey}, which enforces this\n * pattern **and** additionally rejects a body whose length is an impossible\n * base64 remainder. Exposed for callers that need the pattern directly (e.g. a\n * JSON-schema `pattern` field); prefer the guard/converter for validation.\n *\n * @public\n */\nexport const MultibaseSpkiPublicKeyRegExp: RegExp = /^m[A-Za-z0-9_-]+$/;\n\n/**\n * Type guard for {@link CryptoUtils.MultibaseSpkiPublicKey}: a string matching\n * {@link CryptoUtils.MultibaseSpkiPublicKeyRegExp} (multibase `'m'` prefix + a\n * non-empty base64url-no-pad body) whose body also satisfies the base64url-no-pad\n * length rule shared with {@link CryptoUtils.base64UrlNoPadDecode}. This is a\n * structural *shape* check, not full validation — it does not decode the DER SPKI\n * or verify the key material/algorithm (a malformed-but-well-shaped string fails\n * later, with clear context, in {@link CryptoUtils.importPublicKeyFromMultibaseSpki}).\n *\n * @param value - The value to test.\n * @returns `true` if `value` is a well-formed multibase SPKI public key string.\n * @public\n */\nexport function isValidMultibaseSpkiPublicKey(value: unknown): value is MultibaseSpkiPublicKey {\n return (\n typeof value === 'string' &&\n MultibaseSpkiPublicKeyRegExp.test(value) &&\n isBase64UrlNoPadBody(value.slice(1))\n );\n}\n\n/**\n * Encodes a `Uint8Array` as a multibase base64url (no-padding) string.\n *\n * The multibase prefix `'m'` identifies the encoding as RFC 4648 base64url\n * without padding. The body uses base64url alphabet: `+` → `-`, `/` → `_`,\n * and trailing `=` padding is stripped.\n *\n * @param data - The binary data to encode.\n * @returns A multibase-prefixed base64url string (`'m' + base64url-no-pad`).\n * @public\n */\nexport function multibaseBase64UrlEncode(data: Uint8Array): string {\n return 'm' + base64UrlNoPadEncode(data);\n}\n\n/**\n * Decodes a multibase base64url (no-padding) string back to a `Uint8Array`.\n *\n * Validates that the first character is `'m'` (the multibase prefix for\n * RFC 4648 base64url without padding), then decodes the remaining body.\n *\n * @param encoded - A multibase-prefixed base64url string.\n * @returns `Success` with the decoded bytes, or `Failure` with error context.\n * @public\n */\nexport function multibaseBase64UrlDecode(encoded: string): Result<Uint8Array> {\n if (!encoded.startsWith('m')) {\n return fail(\n `multibaseBase64UrlDecode: invalid multibase prefix '${\n encoded[0] ?? '(empty)'\n }' — expected 'm' (base64url)`\n );\n }\n // Intentionally pin the exact original message (the delegate has a single failure\n // mode) to keep this established public function byte-for-byte behavior-preserving\n // after the extract-and-delegate refactor — do not \"fix\" this into composing the\n // delegate's message without updating the delegation-equivalence tests.\n return base64UrlNoPadDecode(encoded.slice(1)).withErrorFormat(\n () => `multibaseBase64UrlDecode: malformed base64url body`\n );\n}\n\n/**\n * Exports a public `CryptoKey` as a multibase base64url-encoded SPKI blob.\n *\n * The SPKI (SubjectPublicKeyInfo) format is the standard DER-encoded structure\n * for public keys defined in RFC 5280, RFC 5480, and RFC 8410. It is\n * algorithm-agnostic and suitable for storage and transmission.\n *\n * @param key - The `CryptoKey` to export. Must have `key.type === 'public'`.\n * @param provider - The {@link CryptoUtils.ICryptoProvider} to use for the export operation.\n * @returns `Success` with the multibase SPKI string, or `Failure` with error context.\n * @public\n */\nexport async function exportPublicKeyAsMultibaseSpki(\n key: CryptoKey,\n provider: ICryptoProvider\n): Promise<Result<MultibaseSpkiPublicKey>> {\n return (await provider.exportPublicKeySpki(key))\n .withErrorFormat((e) => `exportPublicKeyAsMultibaseSpki: ${e}`)\n .onSuccess((buf) =>\n // The output is a freshly-built valid multibase SPKI string (`'m'` prefix +\n // base64url-no-pad body), so brand it at the construction site — no re-validation needed.\n succeed(multibaseBase64UrlEncode(buf) as MultibaseSpkiPublicKey)\n );\n}\n\n/**\n * Imports a public key from a multibase base64url-encoded SPKI blob.\n *\n * Decodes the multibase prefix, decodes the base64url body, then uses\n * the provider to import the key with the algorithm parameters from\n * {@link CryptoUtils.keyPairAlgorithmParams}.\n *\n * Accepts a plain `string` (not only a branded {@link CryptoUtils.MultibaseSpkiPublicKey}),\n * so callers holding an unbranded value read from storage or the wire can import\n * it directly; a malformed value fails with error context rather than throwing.\n *\n * @param encoded - A multibase SPKI string produced by {@link CryptoUtils.exportPublicKeyAsMultibaseSpki}.\n * @param algorithm - The {@link CryptoUtils.KeyPairAlgorithm} the key was generated for.\n * @param provider - The {@link CryptoUtils.ICryptoProvider} to use for the import operation.\n * @returns `Success` with the imported public `CryptoKey`, or `Failure` with error context.\n * @public\n */\nexport async function importPublicKeyFromMultibaseSpki(\n encoded: string,\n algorithm: KeyPairAlgorithm,\n provider: ICryptoProvider\n): Promise<Result<CryptoKey>> {\n const decodeResult = multibaseBase64UrlDecode(encoded);\n if (decodeResult.isFailure()) {\n return fail(`importPublicKeyFromMultibaseSpki: ${decodeResult.message}`);\n }\n return (await provider.importPublicKeySpki(decodeResult.value, algorithm)).withErrorFormat(\n (e) => `importPublicKeyFromMultibaseSpki: ${e}`\n );\n}\n\n// DER prefix for an X25519 SubjectPublicKeyInfo: SEQUENCE { SEQUENCE { OID id-X25519 }, BIT STRING }.\n// SEQUENCE(42) / SEQUENCE(5) / OID 1.3.101.110 (id-X25519) / BIT STRING(33, 0 unused bits).\nconst _X25519_SPKI_PREFIX: ReadonlyArray<number> = [\n 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00\n];\nconst _X25519_SPKI_LENGTH: number = _X25519_SPKI_PREFIX.length + 32;\n\n/**\n * Strips the fixed DER prefix from an X25519 SubjectPublicKeyInfo blob, returning the raw\n * 32-byte public key.\n *\n * An X25519 SPKI is always exactly 44 bytes: a fixed 12-byte prefix (SEQUENCE / AlgorithmIdentifier\n * with OID 1.3.101.110 / BIT STRING) followed by the 32-byte raw key. Use this to convert a\n * SPKI-held recipient public key into the raw form accepted by {@link HpkeProvider.openBase}'s\n * `recipientPublicKey` parameter.\n *\n * @param spki - The DER-encoded X25519 SubjectPublicKeyInfo bytes.\n * @returns `Success` with the raw 32-byte public key, or `Failure` if `spki` is not a\n * well-formed 44-byte X25519 SPKI blob.\n * @public\n */\nexport function spkiToRawX25519(spki: Uint8Array): Result<Uint8Array> {\n if (spki.length !== _X25519_SPKI_LENGTH) {\n return fail(`spkiToRawX25519: expected ${_X25519_SPKI_LENGTH} bytes, got ${spki.length}`);\n }\n for (let i = 0; i < _X25519_SPKI_PREFIX.length; i++) {\n if (spki[i] !== _X25519_SPKI_PREFIX[i]) {\n return fail(`spkiToRawX25519: byte ${i} does not match the expected X25519 SPKI prefix`);\n }\n }\n return succeed(spki.slice(_X25519_SPKI_PREFIX.length));\n}\n"]}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Result } from '@fgv/ts-utils';
|
|
2
|
-
import { FileTree } from '@fgv/ts-json-base';
|
|
3
2
|
import { CsvOptions } from './csvHelpers';
|
|
4
3
|
/**
|
|
5
4
|
* Reads a CSV file from a supplied path.
|
|
@@ -9,13 +8,4 @@ import { CsvOptions } from './csvHelpers';
|
|
|
9
8
|
* @beta
|
|
10
9
|
*/
|
|
11
10
|
export declare function readCsvFileSync(srcPath: string, options?: CsvOptions): Result<unknown>;
|
|
12
|
-
/**
|
|
13
|
-
* Reads a CSV file from a FileTree.
|
|
14
|
-
* @param fileTree - The FileTree to read from.
|
|
15
|
-
* @param filePath - Path of the file within the tree.
|
|
16
|
-
* @param options - optional parameters to control the processing
|
|
17
|
-
* @returns The parsed CSV data.
|
|
18
|
-
* @beta
|
|
19
|
-
*/
|
|
20
|
-
export declare function readCsvFromTree(fileTree: FileTree.FileTree, filePath: string, options?: CsvOptions): Result<unknown>;
|
|
21
11
|
//# sourceMappingURL=csvFileHelpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csvFileHelpers.d.ts","sourceRoot":"","sources":["../../../src/packlets/csv/csvFileHelpers.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,MAAM,EAAiB,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAkB,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAOtF"}
|
|
@@ -55,7 +55,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
55
55
|
})();
|
|
56
56
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
57
57
|
exports.readCsvFileSync = readCsvFileSync;
|
|
58
|
-
exports.readCsvFromTree = readCsvFromTree;
|
|
59
58
|
const ts_utils_1 = require("@fgv/ts-utils");
|
|
60
59
|
const fs = __importStar(require("fs"));
|
|
61
60
|
const path = __importStar(require("path"));
|
|
@@ -75,18 +74,4 @@ function readCsvFileSync(srcPath, options) {
|
|
|
75
74
|
return (0, csvHelpers_1.parseCsvString)(body, options);
|
|
76
75
|
});
|
|
77
76
|
}
|
|
78
|
-
/**
|
|
79
|
-
* Reads a CSV file from a FileTree.
|
|
80
|
-
* @param fileTree - The FileTree to read from.
|
|
81
|
-
* @param filePath - Path of the file within the tree.
|
|
82
|
-
* @param options - optional parameters to control the processing
|
|
83
|
-
* @returns The parsed CSV data.
|
|
84
|
-
* @beta
|
|
85
|
-
*/
|
|
86
|
-
function readCsvFromTree(fileTree, filePath, options) {
|
|
87
|
-
return fileTree
|
|
88
|
-
.getFile(filePath)
|
|
89
|
-
.onSuccess((file) => file.getRawContents())
|
|
90
|
-
.onSuccess((contents) => (0, csvHelpers_1.parseCsvString)(contents, options));
|
|
91
|
-
}
|
|
92
77
|
//# sourceMappingURL=csvFileHelpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csvFileHelpers.js","sourceRoot":"","sources":["../../../src/packlets/csv/csvFileHelpers.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcH,0CAOC;AAnBD,4CAAsD;AACtD,uCAAyB;AACzB,2CAA6B;AAC7B,6CAA0D;AAE1D;;;;;;GAMG;AACH,SAAgB,eAAe,CAAC,OAAe,EAAE,OAAoB;IACnE,OAAO,IAAA,wBAAa,EAAC,GAAG,EAAE;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvC,OAAO,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IACtD,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;QACpB,OAAO,IAAA,2BAAc,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC","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 } from '@fgv/ts-utils';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { parseCsvString, CsvOptions } from './csvHelpers';\n\n/**\n * Reads a CSV file from a supplied path.\n * @param srcPath - Source path from which the file is read.\n * @param options - optional parameters to control the processing\n * @returns The contents of the file.\n * @beta\n */\nexport function readCsvFileSync(srcPath: string, options?: CsvOptions): Result<unknown> {\n return captureResult(() => {\n const fullPath = path.resolve(srcPath);\n return fs.readFileSync(fullPath, 'utf8').toString();\n }).onSuccess((body) => {\n return parseCsvString(body, options);\n });\n}\n\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Result } from '@fgv/ts-utils';
|
|
2
|
+
import { FileTree } from '@fgv/ts-json-base';
|
|
2
3
|
/**
|
|
3
4
|
* Options for {@link Csv.readCsvFileSync | readCsvFileSync}
|
|
4
5
|
* @beta
|
|
@@ -14,4 +15,13 @@ export interface CsvOptions {
|
|
|
14
15
|
* @beta
|
|
15
16
|
*/
|
|
16
17
|
export declare function parseCsvString(body: string, options?: CsvOptions): Result<unknown>;
|
|
18
|
+
/**
|
|
19
|
+
* Reads a CSV file from a FileTree.
|
|
20
|
+
* @param fileTree - The FileTree to read from.
|
|
21
|
+
* @param filePath - Path of the file within the tree.
|
|
22
|
+
* @param options - optional parameters to control the processing
|
|
23
|
+
* @returns The parsed CSV data.
|
|
24
|
+
* @beta
|
|
25
|
+
*/
|
|
26
|
+
export declare function readCsvFromTree(fileTree: FileTree.FileTree, filePath: string, options?: CsvOptions): Result<unknown>;
|
|
17
27
|
//# sourceMappingURL=csvHelpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csvHelpers.d.ts","sourceRoot":"","sources":["../../../src/packlets/csv/csvHelpers.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,MAAM,EAAiB,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7C;;;GAGG;AAEH,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAYlF;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAC3B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,UAAU,GACnB,MAAM,CAAC,OAAO,CAAC,CAKjB"}
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
24
|
exports.parseCsvString = parseCsvString;
|
|
25
|
+
exports.readCsvFromTree = readCsvFromTree;
|
|
25
26
|
const ts_utils_1 = require("@fgv/ts-utils");
|
|
26
27
|
const papaparse_1 = require("papaparse");
|
|
27
28
|
/**
|
|
@@ -37,4 +38,18 @@ function parseCsvString(body, options) {
|
|
|
37
38
|
return (0, papaparse_1.parse)(body, Object.assign({ transform: (s) => s.trim(), header: false, dynamicTyping: false, skipEmptyLines: 'greedy' }, options)).data.slice(1);
|
|
38
39
|
});
|
|
39
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Reads a CSV file from a FileTree.
|
|
43
|
+
* @param fileTree - The FileTree to read from.
|
|
44
|
+
* @param filePath - Path of the file within the tree.
|
|
45
|
+
* @param options - optional parameters to control the processing
|
|
46
|
+
* @returns The parsed CSV data.
|
|
47
|
+
* @beta
|
|
48
|
+
*/
|
|
49
|
+
function readCsvFromTree(fileTree, filePath, options) {
|
|
50
|
+
return fileTree
|
|
51
|
+
.getFile(filePath)
|
|
52
|
+
.onSuccess((file) => file.getRawContents())
|
|
53
|
+
.onSuccess((contents) => parseCsvString(contents, options));
|
|
54
|
+
}
|
|
40
55
|
//# sourceMappingURL=csvHelpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csvHelpers.js","sourceRoot":"","sources":["../../../src/packlets/csv/csvHelpers.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;AAsBH,wCAYC;AAUD,0CASC;AAnDD,4CAAsD;AAEtD,yCAAkC;AAWlC;;;;;;GAMG;AACH,SAAgB,cAAc,CAAC,IAAY,EAAE,OAAoB;IAC/D,OAAO,IAAA,wBAAa,EAAC,GAAG,EAAE;QACxB,OAAO,GAAG,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,EAAE,CAAC;QAExB,OAAO,IAAA,iBAAK,EAAC,IAAI,kBACf,SAAS,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAClC,MAAM,EAAE,KAAK,EACb,aAAa,EAAE,KAAK,EACpB,cAAc,EAAE,QAAQ,IACrB,OAAO,EACV,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,eAAe,CAC7B,QAA2B,EAC3B,QAAgB,EAChB,OAAoB;IAEpB,OAAO,QAAQ;SACZ,OAAO,CAAC,QAAQ,CAAC;SACjB,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;SAC1C,SAAS,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;AAChE,CAAC","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 } from '@fgv/ts-utils';\nimport { FileTree } from '@fgv/ts-json-base';\nimport { parse } from 'papaparse';\n\n/**\n * Options for {@link Csv.readCsvFileSync | readCsvFileSync}\n * @beta\n */\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport interface CsvOptions {\n delimiter?: string;\n}\n\n/**\n * Parses CSV data from a string.\n * @param body - The CSV string to parse.\n * @param options - optional parameters to control the processing\n * @returns The parsed CSV data.\n * @beta\n */\nexport function parseCsvString(body: string, options?: CsvOptions): Result<unknown> {\n return captureResult(() => {\n options = options ?? {};\n\n return parse(body, {\n transform: (s: string) => s.trim(),\n header: false,\n dynamicTyping: false,\n skipEmptyLines: 'greedy',\n ...options\n }).data.slice(1);\n });\n}\n\n/**\n * Reads a CSV file from a FileTree.\n * @param fileTree - The FileTree to read from.\n * @param filePath - Path of the file within the tree.\n * @param options - optional parameters to control the processing\n * @returns The parsed CSV data.\n * @beta\n */\nexport function readCsvFromTree(\n fileTree: FileTree.FileTree,\n filePath: string,\n options?: CsvOptions\n): Result<unknown> {\n return fileTree\n .getFile(filePath)\n .onSuccess((file) => file.getRawContents())\n .onSuccess((contents) => parseCsvString(contents, options));\n}\n"]}
|