@ternent/core 0.0.1

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 (313) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +17 -0
  3. package/.github/workflows/deploy-armour.yml +42 -0
  4. package/.github/workflows/deploy-identity.yml +42 -0
  5. package/.github/workflows/deploy-seal.yml +42 -0
  6. package/.github/workflows/deploy-ui.yml +42 -0
  7. package/.github/workflows/deploy-utils.yml +42 -0
  8. package/.github/workflows/release-create.yml +59 -0
  9. package/.github/workflows/release-publish.yml +54 -0
  10. package/.nvmrc +1 -0
  11. package/.ops/publish.mjs +31 -0
  12. package/package.json +16 -0
  13. package/packages/README.md +0 -0
  14. package/packages/armour/CHANGELOG.md +66 -0
  15. package/packages/armour/CLAUDE.md +8 -0
  16. package/packages/armour/README.md +103 -0
  17. package/packages/armour/SPEC.md +92 -0
  18. package/packages/armour/package.json +45 -0
  19. package/packages/armour/src/constants.ts +5 -0
  20. package/packages/armour/src/deps.d.ts +56 -0
  21. package/packages/armour/src/errors.ts +172 -0
  22. package/packages/armour/src/files.ts +73 -0
  23. package/packages/armour/src/identity.ts +72 -0
  24. package/packages/armour/src/index.ts +56 -0
  25. package/packages/armour/src/init.ts +10 -0
  26. package/packages/armour/src/passphrase.ts +33 -0
  27. package/packages/armour/src/recipients.ts +73 -0
  28. package/packages/armour/src/text.ts +68 -0
  29. package/packages/armour/src/types.ts +93 -0
  30. package/packages/armour/test/armour.test.ts +270 -0
  31. package/packages/armour/tsconfig.build.json +12 -0
  32. package/packages/armour/tsconfig.json +12 -0
  33. package/packages/armour/vite.config.ts +29 -0
  34. package/packages/concord/CHANGELOG.md +83 -0
  35. package/packages/concord/CLAUDE.md +9 -0
  36. package/packages/concord/README.md +146 -0
  37. package/packages/concord/SPEC.md +287 -0
  38. package/packages/concord/package.json +51 -0
  39. package/packages/concord/src/app.ts +717 -0
  40. package/packages/concord/src/errors.ts +9 -0
  41. package/packages/concord/src/index.ts +20 -0
  42. package/packages/concord/src/types.ts +127 -0
  43. package/packages/concord/test/concord.test.ts +978 -0
  44. package/packages/concord/tsconfig.json +12 -0
  45. package/packages/concord/vite.browser.config.ts +27 -0
  46. package/packages/concord/vite.config.ts +35 -0
  47. package/packages/concord/vite.config.ts.timestamp-1774262297922-ffd76e35ea668.mjs +83 -0
  48. package/packages/identity/CHANGELOG.md +47 -0
  49. package/packages/identity/README.md +236 -0
  50. package/packages/identity/package.json +41 -0
  51. package/packages/identity/src/index.ts +538 -0
  52. package/packages/identity/test/identity.test.ts +172 -0
  53. package/packages/identity/tsconfig.build.json +12 -0
  54. package/packages/identity/vite.config.ts +17 -0
  55. package/packages/ledger/CHANGELOG.md +69 -0
  56. package/packages/ledger/CLAUDE.md +9 -0
  57. package/packages/ledger/SPEC.md +304 -0
  58. package/packages/ledger/package.json +48 -0
  59. package/packages/ledger/src/index.ts +2 -0
  60. package/packages/ledger/src/ledger.ts +1286 -0
  61. package/packages/ledger/src/seal-cli.d.ts +25 -0
  62. package/packages/ledger/src/types.ts +294 -0
  63. package/packages/ledger/test/ledger.test.ts +838 -0
  64. package/packages/ledger/tsconfig.json +12 -0
  65. package/packages/ledger/vite.browser.config.ts +27 -0
  66. package/packages/ledger/vite.config.ts +39 -0
  67. package/packages/seal/CHANGELOG.md +137 -0
  68. package/packages/seal/CLAUDE.md +8 -0
  69. package/packages/seal/README.md +258 -0
  70. package/packages/seal/bin/seal +6 -0
  71. package/packages/seal/package.json +59 -0
  72. package/packages/seal/src/artifact.ts +380 -0
  73. package/packages/seal/src/cli.ts +372 -0
  74. package/packages/seal/src/commands/identity.ts +52 -0
  75. package/packages/seal/src/commands/manifest.ts +71 -0
  76. package/packages/seal/src/commands/publicKey.ts +7 -0
  77. package/packages/seal/src/commands/sign.ts +56 -0
  78. package/packages/seal/src/commands/verify.ts +54 -0
  79. package/packages/seal/src/crypto.ts +85 -0
  80. package/packages/seal/src/errors.ts +88 -0
  81. package/packages/seal/src/index.ts +5 -0
  82. package/packages/seal/src/manifest.ts +114 -0
  83. package/packages/seal/src/node.ts +18 -0
  84. package/packages/seal/src/proof.ts +344 -0
  85. package/packages/seal/test/artifact.test.ts +86 -0
  86. package/packages/seal/test/cli.test.ts +208 -0
  87. package/packages/seal/test/crypto.test.ts +21 -0
  88. package/packages/seal/test/manifest.test.ts +32 -0
  89. package/packages/seal/test/proof.test.ts +60 -0
  90. package/packages/seal/tsconfig.json +12 -0
  91. package/packages/seal/vite.config.ts +54 -0
  92. package/packages/ui/CHANGELOG.md +393 -0
  93. package/packages/ui/README.md +57 -0
  94. package/packages/ui/jsconfig.json +19 -0
  95. package/packages/ui/package.json +64 -0
  96. package/packages/ui/scripts/check-tokens.js +56 -0
  97. package/packages/ui/scripts/generate-theme-css.mjs +85 -0
  98. package/packages/ui/src/design-system/base.css +8 -0
  99. package/packages/ui/src/design-system/docs/ACCESSIBILITY_RULES.md +186 -0
  100. package/packages/ui/src/design-system/docs/AI_SYSTEM.md +281 -0
  101. package/packages/ui/src/design-system/docs/PATTERN_RULES.md +83 -0
  102. package/packages/ui/src/design-system/docs/PRIMITIVE_RULES.md +258 -0
  103. package/packages/ui/src/design-system/docs/TOKEN_RULES.md +235 -0
  104. package/packages/ui/src/design-system/docs/VISUAL_DIRECTION.md +68 -0
  105. package/packages/ui/src/design-system/foundation.js +420 -0
  106. package/packages/ui/src/design-system/tokens.css +140 -0
  107. package/packages/ui/src/design-system/tokens.js +327 -0
  108. package/packages/ui/src/design-system/utils.js +246 -0
  109. package/packages/ui/src/main.js +4 -0
  110. package/packages/ui/src/patterns/FeatureCard/FeatureCard.spec.md +24 -0
  111. package/packages/ui/src/patterns/FeatureCard/FeatureCard.types.ts +8 -0
  112. package/packages/ui/src/patterns/FeatureCard/FeatureCard.vue +175 -0
  113. package/packages/ui/src/patterns/FormField/FormField.spec.md +65 -0
  114. package/packages/ui/src/patterns/FormField/FormField.types.ts +11 -0
  115. package/packages/ui/src/patterns/FormField/FormField.vue +87 -0
  116. package/packages/ui/src/patterns/IdentityGlyph/IdentityGlyph.vue +61 -0
  117. package/packages/ui/src/patterns/IdentityGlyph/IdentityHandle.vue +58 -0
  118. package/packages/ui/src/patterns/IdentityGlyph/identityGlyph.types.ts +36 -0
  119. package/packages/ui/src/patterns/IdentityGlyph/identityGlyph.utils.ts +585 -0
  120. package/packages/ui/src/patterns/IdentityGlyph/index.ts +5 -0
  121. package/packages/ui/src/patterns/KeyValueList/KeyValueList.spec.md +28 -0
  122. package/packages/ui/src/patterns/KeyValueList/KeyValueList.types.ts +16 -0
  123. package/packages/ui/src/patterns/KeyValueList/KeyValueList.vue +50 -0
  124. package/packages/ui/src/patterns/LandingPage/LandingIcon.vue +90 -0
  125. package/packages/ui/src/patterns/LandingPage/LandingPage.spec.md +24 -0
  126. package/packages/ui/src/patterns/LandingPage/LandingPage.types.ts +212 -0
  127. package/packages/ui/src/patterns/LandingPage/LandingPage.vue +599 -0
  128. package/packages/ui/src/patterns/ListWorkspaceLayout/ListWorkspaceLayout.test.ts +33 -0
  129. package/packages/ui/src/patterns/ListWorkspaceLayout/ListWorkspaceLayout.vue +44 -0
  130. package/packages/ui/src/patterns/Logo/Logo.spec.md +22 -0
  131. package/packages/ui/src/patterns/Logo/Logo.vue +160 -0
  132. package/packages/ui/src/patterns/PageSurface/PageSurface.spec.md +15 -0
  133. package/packages/ui/src/patterns/PageSurface/PageSurface.vue +85 -0
  134. package/packages/ui/src/patterns/PanelChrome/PanelChrome.spec.md +39 -0
  135. package/packages/ui/src/patterns/PanelChrome/PanelChrome.types.ts +1 -0
  136. package/packages/ui/src/patterns/PanelChrome/PanelChrome.vue +187 -0
  137. package/packages/ui/src/patterns/PreviewPanel/PreviewPanel.spec.md +31 -0
  138. package/packages/ui/src/patterns/PreviewPanel/PreviewPanel.types.ts +23 -0
  139. package/packages/ui/src/patterns/PreviewPanel/PreviewPanel.vue +354 -0
  140. package/packages/ui/src/patterns/RecordList/RecordList.spec.md +35 -0
  141. package/packages/ui/src/patterns/RecordList/RecordList.test.ts +42 -0
  142. package/packages/ui/src/patterns/RecordList/RecordList.types.ts +9 -0
  143. package/packages/ui/src/patterns/RecordList/RecordList.utils.ts +5 -0
  144. package/packages/ui/src/patterns/RecordList/RecordList.vue +134 -0
  145. package/packages/ui/src/patterns/SectionClarifier/SectionClarifier.vue +85 -0
  146. package/packages/ui/src/patterns/SectionIntro/SectionIntro.spec.md +25 -0
  147. package/packages/ui/src/patterns/SectionIntro/SectionIntro.types.ts +7 -0
  148. package/packages/ui/src/patterns/SectionIntro/SectionIntro.vue +141 -0
  149. package/packages/ui/src/patterns/SidebarNav/SidebarNav.spec.md +34 -0
  150. package/packages/ui/src/patterns/SidebarNav/SidebarNav.types.ts +17 -0
  151. package/packages/ui/src/patterns/SidebarNav/SidebarNav.vue +110 -0
  152. package/packages/ui/src/patterns/SplitView/SplitView.spec.md +28 -0
  153. package/packages/ui/src/patterns/SplitView/SplitView.test.ts +22 -0
  154. package/packages/ui/src/patterns/SplitView/SplitView.types.ts +3 -0
  155. package/packages/ui/src/patterns/SplitView/SplitView.utils.ts +13 -0
  156. package/packages/ui/src/patterns/SplitView/SplitView.vue +39 -0
  157. package/packages/ui/src/patterns/StepList/StepList.spec.md +15 -0
  158. package/packages/ui/src/patterns/StepList/StepList.types.ts +4 -0
  159. package/packages/ui/src/patterns/StepList/StepList.vue +91 -0
  160. package/packages/ui/src/patterns/Verification/VerificationBadge.vue +97 -0
  161. package/packages/ui/src/patterns/Verification/VerificationComponents.test.ts +153 -0
  162. package/packages/ui/src/patterns/Verification/VerificationDetailsPanel.vue +270 -0
  163. package/packages/ui/src/patterns/Verification/VerificationSummary.vue +171 -0
  164. package/packages/ui/src/patterns/Verification/index.ts +6 -0
  165. package/packages/ui/src/patterns/Verification/verification.types.ts +8 -0
  166. package/packages/ui/src/patterns/Verification/verification.utils.test.ts +37 -0
  167. package/packages/ui/src/patterns/Verification/verification.utils.ts +75 -0
  168. package/packages/ui/src/patterns/index.ts +25 -0
  169. package/packages/ui/src/primitives/Accordian/Accordian.vue +11 -0
  170. package/packages/ui/src/primitives/Accordian/AccordianItem.vue +14 -0
  171. package/packages/ui/src/primitives/Accordion/Accordion.props.ts +21 -0
  172. package/packages/ui/src/primitives/Accordion/Accordion.spec.md +50 -0
  173. package/packages/ui/src/primitives/Accordion/Accordion.types.ts +4 -0
  174. package/packages/ui/src/primitives/Accordion/Accordion.variants.ts +12 -0
  175. package/packages/ui/src/primitives/Accordion/Accordion.vue +71 -0
  176. package/packages/ui/src/primitives/Accordion/AccordionItem.props.ts +14 -0
  177. package/packages/ui/src/primitives/Accordion/AccordionItem.vue +40 -0
  178. package/packages/ui/src/primitives/Badge/Badge.props.ts +17 -0
  179. package/packages/ui/src/primitives/Badge/Badge.spec.md +17 -0
  180. package/packages/ui/src/primitives/Badge/Badge.types.ts +15 -0
  181. package/packages/ui/src/primitives/Badge/Badge.variants.ts +48 -0
  182. package/packages/ui/src/primitives/Badge/Badge.vue +31 -0
  183. package/packages/ui/src/primitives/Button/Button.props.ts +29 -0
  184. package/packages/ui/src/primitives/Button/Button.spec.md +139 -0
  185. package/packages/ui/src/primitives/Button/Button.types.ts +19 -0
  186. package/packages/ui/src/primitives/Button/Button.variants.ts +72 -0
  187. package/packages/ui/src/primitives/Button/Button.vue +90 -0
  188. package/packages/ui/src/primitives/Card/Card.props.ts +17 -0
  189. package/packages/ui/src/primitives/Card/Card.spec.md +29 -0
  190. package/packages/ui/src/primitives/Card/Card.types.ts +12 -0
  191. package/packages/ui/src/primitives/Card/Card.variants.ts +27 -0
  192. package/packages/ui/src/primitives/Card/Card.vue +37 -0
  193. package/packages/ui/src/primitives/Checkbox/Checkbox.props.ts +21 -0
  194. package/packages/ui/src/primitives/Checkbox/Checkbox.spec.md +51 -0
  195. package/packages/ui/src/primitives/Checkbox/Checkbox.types.ts +4 -0
  196. package/packages/ui/src/primitives/Checkbox/Checkbox.variants.ts +34 -0
  197. package/packages/ui/src/primitives/Checkbox/Checkbox.vue +92 -0
  198. package/packages/ui/src/primitives/Dialog/Dialog.props.ts +29 -0
  199. package/packages/ui/src/primitives/Dialog/Dialog.spec.md +52 -0
  200. package/packages/ui/src/primitives/Dialog/Dialog.types.ts +3 -0
  201. package/packages/ui/src/primitives/Dialog/Dialog.variants.ts +27 -0
  202. package/packages/ui/src/primitives/Dialog/Dialog.vue +78 -0
  203. package/packages/ui/src/primitives/Drawer/Drawer.props.ts +33 -0
  204. package/packages/ui/src/primitives/Drawer/Drawer.spec.md +50 -0
  205. package/packages/ui/src/primitives/Drawer/Drawer.types.ts +5 -0
  206. package/packages/ui/src/primitives/Drawer/Drawer.variants.ts +35 -0
  207. package/packages/ui/src/primitives/Drawer/Drawer.vue +88 -0
  208. package/packages/ui/src/primitives/FieldMessage/FieldMessage.props.ts +17 -0
  209. package/packages/ui/src/primitives/FieldMessage/FieldMessage.spec.md +35 -0
  210. package/packages/ui/src/primitives/FieldMessage/FieldMessage.types.ts +5 -0
  211. package/packages/ui/src/primitives/FieldMessage/FieldMessage.variants.ts +14 -0
  212. package/packages/ui/src/primitives/FieldMessage/FieldMessage.vue +40 -0
  213. package/packages/ui/src/primitives/FileInput/FileInput.props.ts +41 -0
  214. package/packages/ui/src/primitives/FileInput/FileInput.types.ts +6 -0
  215. package/packages/ui/src/primitives/FileInput/FileInput.variants.ts +46 -0
  216. package/packages/ui/src/primitives/FileInput/FileInput.vue +163 -0
  217. package/packages/ui/src/primitives/Input/Input.props.ts +29 -0
  218. package/packages/ui/src/primitives/Input/Input.spec.md +79 -0
  219. package/packages/ui/src/primitives/Input/Input.types.ts +13 -0
  220. package/packages/ui/src/primitives/Input/Input.variants.ts +54 -0
  221. package/packages/ui/src/primitives/Input/Input.vue +99 -0
  222. package/packages/ui/src/primitives/Label/Label.props.ts +25 -0
  223. package/packages/ui/src/primitives/Label/Label.spec.md +31 -0
  224. package/packages/ui/src/primitives/Label/Label.types.ts +3 -0
  225. package/packages/ui/src/primitives/Label/Label.variants.ts +17 -0
  226. package/packages/ui/src/primitives/Label/Label.vue +38 -0
  227. package/packages/ui/src/primitives/Menu/Menu.props.ts +17 -0
  228. package/packages/ui/src/primitives/Menu/Menu.spec.md +38 -0
  229. package/packages/ui/src/primitives/Menu/Menu.types.ts +10 -0
  230. package/packages/ui/src/primitives/Menu/Menu.variants.ts +10 -0
  231. package/packages/ui/src/primitives/Menu/Menu.vue +57 -0
  232. package/packages/ui/src/primitives/Popover/Popover.props.ts +25 -0
  233. package/packages/ui/src/primitives/Popover/Popover.spec.md +49 -0
  234. package/packages/ui/src/primitives/Popover/Popover.types.ts +3 -0
  235. package/packages/ui/src/primitives/Popover/Popover.variants.ts +18 -0
  236. package/packages/ui/src/primitives/Popover/Popover.vue +74 -0
  237. package/packages/ui/src/primitives/RadioGroup/RadioGroup.props.ts +29 -0
  238. package/packages/ui/src/primitives/RadioGroup/RadioGroup.spec.md +50 -0
  239. package/packages/ui/src/primitives/RadioGroup/RadioGroup.types.ts +12 -0
  240. package/packages/ui/src/primitives/RadioGroup/RadioGroup.variants.ts +48 -0
  241. package/packages/ui/src/primitives/RadioGroup/RadioGroup.vue +87 -0
  242. package/packages/ui/src/primitives/Separator/Separator.props.ts +9 -0
  243. package/packages/ui/src/primitives/Separator/Separator.spec.md +15 -0
  244. package/packages/ui/src/primitives/Separator/Separator.types.ts +3 -0
  245. package/packages/ui/src/primitives/Separator/Separator.variants.ts +8 -0
  246. package/packages/ui/src/primitives/Separator/Separator.vue +23 -0
  247. package/packages/ui/src/primitives/Skeleton/Skeleton.props.ts +21 -0
  248. package/packages/ui/src/primitives/Skeleton/Skeleton.spec.md +18 -0
  249. package/packages/ui/src/primitives/Skeleton/Skeleton.types.ts +5 -0
  250. package/packages/ui/src/primitives/Skeleton/Skeleton.variants.ts +18 -0
  251. package/packages/ui/src/primitives/Skeleton/Skeleton.vue +37 -0
  252. package/packages/ui/src/primitives/Spinner/Spinner.props.ts +13 -0
  253. package/packages/ui/src/primitives/Spinner/Spinner.spec.md +16 -0
  254. package/packages/ui/src/primitives/Spinner/Spinner.types.ts +5 -0
  255. package/packages/ui/src/primitives/Spinner/Spinner.variants.ts +15 -0
  256. package/packages/ui/src/primitives/Spinner/Spinner.vue +33 -0
  257. package/packages/ui/src/primitives/SplitButton/SplitButton.vue +108 -0
  258. package/packages/ui/src/primitives/Switch/Switch.props.ts +21 -0
  259. package/packages/ui/src/primitives/Switch/Switch.spec.md +49 -0
  260. package/packages/ui/src/primitives/Switch/Switch.types.ts +3 -0
  261. package/packages/ui/src/primitives/Switch/Switch.variants.ts +34 -0
  262. package/packages/ui/src/primitives/Switch/Switch.vue +71 -0
  263. package/packages/ui/src/primitives/Tabs/Tabs.props.ts +25 -0
  264. package/packages/ui/src/primitives/Tabs/Tabs.spec.md +48 -0
  265. package/packages/ui/src/primitives/Tabs/Tabs.types.ts +11 -0
  266. package/packages/ui/src/primitives/Tabs/Tabs.variants.ts +28 -0
  267. package/packages/ui/src/primitives/Tabs/Tabs.vue +59 -0
  268. package/packages/ui/src/primitives/Textarea/Textarea.props.ts +33 -0
  269. package/packages/ui/src/primitives/Textarea/Textarea.spec.md +59 -0
  270. package/packages/ui/src/primitives/Textarea/Textarea.types.ts +5 -0
  271. package/packages/ui/src/primitives/Textarea/Textarea.variants.ts +27 -0
  272. package/packages/ui/src/primitives/Textarea/Textarea.vue +74 -0
  273. package/packages/ui/src/primitives/Tooltip/Tooltip.props.ts +21 -0
  274. package/packages/ui/src/primitives/Tooltip/Tooltip.spec.md +45 -0
  275. package/packages/ui/src/primitives/Tooltip/Tooltip.types.ts +3 -0
  276. package/packages/ui/src/primitives/Tooltip/Tooltip.variants.ts +4 -0
  277. package/packages/ui/src/primitives/Tooltip/Tooltip.vue +31 -0
  278. package/packages/ui/src/primitives/TreeView/TreeView.types.ts +10 -0
  279. package/packages/ui/src/primitives/TreeView/TreeView.vue +113 -0
  280. package/packages/ui/src/primitives/TreeView/TreeViewNode.vue +190 -0
  281. package/packages/ui/src/primitives/index.ts +29 -0
  282. package/packages/ui/src/style.css +7 -0
  283. package/packages/ui/src/style.js +1 -0
  284. package/packages/ui/src/themes/armour.css +147 -0
  285. package/packages/ui/src/themes/aurora.css +147 -0
  286. package/packages/ui/src/themes/citrine-ash.css +147 -0
  287. package/packages/ui/src/themes/concord.css +147 -0
  288. package/packages/ui/src/themes/garnet-honey.css +147 -0
  289. package/packages/ui/src/themes/harbor-rose.css +147 -0
  290. package/packages/ui/src/themes/ledger.css +147 -0
  291. package/packages/ui/src/themes/neon-noir.css +74 -0
  292. package/packages/ui/src/themes/obsidian-iris.css +147 -0
  293. package/packages/ui/src/themes/pixpax.css +147 -0
  294. package/packages/ui/src/themes/print.css +147 -0
  295. package/packages/ui/src/themes/prism.css +147 -0
  296. package/packages/ui/src/themes/proof.css +145 -0
  297. package/packages/ui/src/themes/semanticThemeContract.js +2256 -0
  298. package/packages/ui/src/themes/spruce-ink.css +147 -0
  299. package/packages/ui/src/themes/sunset.css +147 -0
  300. package/packages/ui/tailwind.config.js +64 -0
  301. package/packages/ui/vite.config.js +35 -0
  302. package/packages/ui/vite.config.js.timestamp-1780697224943-89fbc929987bc.mjs +38 -0
  303. package/packages/utils/CHANGELOG.md +111 -0
  304. package/packages/utils/README.md +3 -0
  305. package/packages/utils/package.json +46 -0
  306. package/packages/utils/src/index.test.js +39 -0
  307. package/packages/utils/src/index.ts +289 -0
  308. package/packages/utils/tsconfig.build.json +12 -0
  309. package/packages/utils/vite.config.js +28 -0
  310. package/pnpm-workspace.yaml +8 -0
  311. package/scripts/vite/package-lib-config.ts +59 -0
  312. package/tsconfig.json +24 -0
  313. package/tsconfig.node.json +9 -0
@@ -0,0 +1,88 @@
1
+ import { ArmourError, ArmourValidationError } from "@ternent/armour";
2
+
3
+ export const EXIT_SUCCESS = 0;
4
+ export const EXIT_FAILURE = 1;
5
+ export const EXIT_HASH_MISMATCH = 2;
6
+ export const EXIT_SIGNATURE_INVALID = 3;
7
+ export const EXIT_INVALID_PROOF = 4;
8
+ export const EXIT_KEY_CONFIG = 5;
9
+
10
+ export type SealErrorCode =
11
+ | "SEAL_INVALID_RECIPIENT"
12
+ | "SEAL_ENCRYPTION_FAILED"
13
+ | "SEAL_DECRYPTION_FAILED"
14
+ | "SEAL_UNSUPPORTED_ENCRYPTION_MODE";
15
+
16
+ export class SealError extends Error {
17
+ readonly code: SealErrorCode;
18
+ readonly cause?: unknown;
19
+
20
+ constructor(code: SealErrorCode, message: string, cause?: unknown) {
21
+ super(message);
22
+ this.name = new.target.name;
23
+ this.code = code;
24
+ if (cause !== undefined) {
25
+ this.cause = cause;
26
+ }
27
+ }
28
+ }
29
+
30
+ export class SealArtifactError extends SealError {}
31
+
32
+ export class SealCliError extends Error {
33
+ exitCode: number;
34
+
35
+ constructor(message: string, exitCode = EXIT_FAILURE) {
36
+ super(message);
37
+ this.name = "SealCliError";
38
+ this.exitCode = exitCode;
39
+ }
40
+ }
41
+
42
+ export function getExitCode(error: unknown): number {
43
+ if (error instanceof SealCliError) {
44
+ return error.exitCode;
45
+ }
46
+ return EXIT_FAILURE;
47
+ }
48
+
49
+ export function unsupportedEncryptionModeError(
50
+ message = "Seal does not support this encryption mode.",
51
+ ): SealArtifactError {
52
+ return new SealArtifactError("SEAL_UNSUPPORTED_ENCRYPTION_MODE", message);
53
+ }
54
+
55
+ export function toSealEncryptionError(error: unknown): SealArtifactError {
56
+ if (error instanceof SealArtifactError) {
57
+ return error;
58
+ }
59
+
60
+ if (
61
+ error instanceof ArmourValidationError &&
62
+ (error.code === "ARMOUR_EMPTY_RECIPIENTS" || error.code === "ARMOUR_INVALID_RECIPIENT")
63
+ ) {
64
+ return new SealArtifactError(
65
+ "SEAL_INVALID_RECIPIENT",
66
+ "Recipient must be a valid age recipient string.",
67
+ error,
68
+ );
69
+ }
70
+
71
+ if (error instanceof ArmourError) {
72
+ return new SealArtifactError("SEAL_ENCRYPTION_FAILED", "Failed to encrypt payload.", error);
73
+ }
74
+
75
+ return new SealArtifactError("SEAL_ENCRYPTION_FAILED", "Failed to encrypt payload.", error);
76
+ }
77
+
78
+ export function toSealDecryptionError(error: unknown): SealArtifactError {
79
+ if (error instanceof SealArtifactError) {
80
+ return error;
81
+ }
82
+
83
+ if (error instanceof ArmourError) {
84
+ return new SealArtifactError("SEAL_DECRYPTION_FAILED", "Failed to decrypt payload.", error);
85
+ }
86
+
87
+ return new SealArtifactError("SEAL_DECRYPTION_FAILED", "Failed to decrypt payload.", error);
88
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./proof";
2
+ export * from "./artifact";
3
+ export * from "./manifest";
4
+ export * from "./crypto";
5
+ export * from "./errors";
@@ -0,0 +1,114 @@
1
+ import { canonicalStringify } from "ternent-utils";
2
+
3
+ export const SEAL_MANIFEST_VERSION = "1" as const;
4
+ export const SEAL_MANIFEST_TYPE = "seal-manifest" as const;
5
+
6
+ export type SealHash = `sha256:${string}`;
7
+
8
+ export type SealManifestV1 = {
9
+ version: typeof SEAL_MANIFEST_VERSION;
10
+ type: typeof SEAL_MANIFEST_TYPE;
11
+ root: string;
12
+ files: Record<string, SealHash>;
13
+ };
14
+
15
+ function isRecord(value: unknown): value is Record<string, unknown> {
16
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
17
+ }
18
+
19
+ function hasOnlyKeys(value: Record<string, unknown>, allowed: string[]): boolean {
20
+ return Object.keys(value).every((key) => allowed.includes(key));
21
+ }
22
+
23
+ function isSealHash(value: unknown): value is SealHash {
24
+ return typeof value === "string" && /^sha256:[0-9a-f]{64}$/.test(value);
25
+ }
26
+
27
+ export function validateSealManifestShape(value: unknown): {
28
+ ok: boolean;
29
+ errors: string[];
30
+ manifest: SealManifestV1 | null;
31
+ } {
32
+ if (!isRecord(value)) {
33
+ return {
34
+ ok: false,
35
+ errors: ["Manifest must be a JSON object."],
36
+ manifest: null,
37
+ };
38
+ }
39
+
40
+ const errors: string[] = [];
41
+
42
+ if (!hasOnlyKeys(value, ["version", "type", "root", "files"])) {
43
+ errors.push("Manifest contains unsupported fields.");
44
+ }
45
+
46
+ if (value.version !== SEAL_MANIFEST_VERSION) {
47
+ errors.push(`Manifest version must be ${SEAL_MANIFEST_VERSION}.`);
48
+ }
49
+
50
+ if (value.type !== SEAL_MANIFEST_TYPE) {
51
+ errors.push(`Manifest type must be ${SEAL_MANIFEST_TYPE}.`);
52
+ }
53
+
54
+ if (typeof value.root !== "string" || value.root.length === 0) {
55
+ errors.push("Manifest root must be a non-empty string.");
56
+ }
57
+
58
+ if (!isRecord(value.files)) {
59
+ errors.push("Manifest files must be an object.");
60
+ }
61
+
62
+ if (errors.length > 0 || !isRecord(value.files)) {
63
+ return { ok: false, errors, manifest: null };
64
+ }
65
+
66
+ const filesEntries = Object.entries(value.files);
67
+ const files: Record<string, SealHash> = {};
68
+ for (const [path, hash] of filesEntries) {
69
+ if (!path || path.includes("\\")) {
70
+ errors.push(`Manifest file path is invalid: ${path || "<empty>"}.`);
71
+ continue;
72
+ }
73
+ if (!isSealHash(hash)) {
74
+ errors.push(`Manifest file hash is invalid for ${path}.`);
75
+ continue;
76
+ }
77
+ files[path] = hash;
78
+ }
79
+
80
+ if (errors.length > 0) {
81
+ return { ok: false, errors, manifest: null };
82
+ }
83
+
84
+ return {
85
+ ok: true,
86
+ errors: [],
87
+ manifest: {
88
+ version: SEAL_MANIFEST_VERSION,
89
+ type: SEAL_MANIFEST_TYPE,
90
+ root: value.root as string,
91
+ files,
92
+ },
93
+ };
94
+ }
95
+
96
+ export function parseSealManifestJson(raw: string): {
97
+ ok: boolean;
98
+ errors: string[];
99
+ manifest: SealManifestV1 | null;
100
+ } {
101
+ try {
102
+ return validateSealManifestShape(JSON.parse(raw));
103
+ } catch {
104
+ return {
105
+ ok: false,
106
+ errors: ["Manifest JSON is not valid JSON."],
107
+ manifest: null,
108
+ };
109
+ }
110
+ }
111
+
112
+ export function stringifySealManifest(manifest: SealManifestV1): string {
113
+ return canonicalStringify(manifest);
114
+ }
@@ -0,0 +1,18 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { parseIdentity, type SerializedIdentity } from "@ternent/identity";
3
+
4
+ export async function resolveSealIdentityFromEnv(
5
+ env: Record<string, string | undefined>,
6
+ ): Promise<SerializedIdentity> {
7
+ const identityJson = String(env.SEAL_IDENTITY || "").trim();
8
+ if (identityJson) {
9
+ return parseIdentity(identityJson);
10
+ }
11
+
12
+ const identityFile = String(env.SEAL_IDENTITY_FILE || "").trim();
13
+ if (identityFile) {
14
+ return parseIdentity(await readFile(identityFile, "utf8"));
15
+ }
16
+
17
+ throw new Error("Missing SEAL_IDENTITY or SEAL_IDENTITY_FILE environment variable.");
18
+ }
@@ -0,0 +1,344 @@
1
+ import { canonicalStringify, hashBytes } from "ternent-utils";
2
+ import {
3
+ resolveSealSigner,
4
+ signSealUtf8,
5
+ verifyPublicKeyKeyId,
6
+ verifySealUtf8,
7
+ type SealSignerInput,
8
+ } from "./crypto";
9
+
10
+ export const SEAL_PROOF_VERSION = "2" as const;
11
+ export const SEAL_PROOF_TYPE = "seal-proof" as const;
12
+ export const SEAL_PUBLIC_KEY_TYPE = "seal-public-key" as const;
13
+ export const SEAL_SIGNATURE_ALGORITHM = "Ed25519" as const;
14
+
15
+ export type SealSubjectKind = "file" | "manifest" | "artifact";
16
+
17
+ export type SealProofV1 = {
18
+ version: typeof SEAL_PROOF_VERSION;
19
+ type: typeof SEAL_PROOF_TYPE;
20
+ algorithm: typeof SEAL_SIGNATURE_ALGORITHM;
21
+ createdAt: string;
22
+ subject: {
23
+ kind: SealSubjectKind;
24
+ path: string;
25
+ hash: `sha256:${string}`;
26
+ };
27
+ signer: {
28
+ publicKey: string;
29
+ keyId: string;
30
+ };
31
+ signature: string;
32
+ };
33
+
34
+ export type SealPublicKeyArtifact = {
35
+ version: typeof SEAL_PROOF_VERSION;
36
+ type: typeof SEAL_PUBLIC_KEY_TYPE;
37
+ algorithm: typeof SEAL_SIGNATURE_ALGORITHM;
38
+ publicKey: string;
39
+ keyId: string;
40
+ };
41
+
42
+ type SealProofSignableFields = Omit<SealProofV1, "signature">;
43
+
44
+ function isRecord(value: unknown): value is Record<string, unknown> {
45
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
46
+ }
47
+
48
+ function hasOnlyKeys(value: Record<string, unknown>, allowed: string[]): boolean {
49
+ return Object.keys(value).every((key) => allowed.includes(key));
50
+ }
51
+
52
+ function isSealHash(value: unknown): value is `sha256:${string}` {
53
+ return typeof value === "string" && /^sha256:[0-9a-f]{64}$/.test(value);
54
+ }
55
+
56
+ function isIsoDate(value: string): boolean {
57
+ return !Number.isNaN(Date.parse(value));
58
+ }
59
+
60
+ export function getSealProofSignableFields(
61
+ proof: SealProofV1 | SealProofSignableFields,
62
+ ): SealProofSignableFields {
63
+ return {
64
+ version: proof.version,
65
+ type: proof.type,
66
+ algorithm: proof.algorithm,
67
+ createdAt: proof.createdAt,
68
+ subject: proof.subject,
69
+ signer: proof.signer,
70
+ };
71
+ }
72
+
73
+ export function getSealProofSigningPayload(proof: SealProofV1 | SealProofSignableFields): string {
74
+ return canonicalStringify(getSealProofSignableFields(proof));
75
+ }
76
+
77
+ export async function createSealHash(bytes: Uint8Array | ArrayBuffer): Promise<`sha256:${string}`> {
78
+ const hash = await hashBytes(bytes);
79
+ return `sha256:${hash}`;
80
+ }
81
+
82
+ export async function createSealProof(input: {
83
+ createdAt?: string;
84
+ signer: SealSignerInput;
85
+ subject: SealProofV1["subject"];
86
+ }): Promise<SealProofV1> {
87
+ const signer = await resolveSealSigner(input.signer);
88
+ const fields: SealProofSignableFields = {
89
+ version: SEAL_PROOF_VERSION,
90
+ type: SEAL_PROOF_TYPE,
91
+ algorithm: SEAL_SIGNATURE_ALGORITHM,
92
+ createdAt: input.createdAt ?? new Date().toISOString(),
93
+ subject: input.subject,
94
+ signer: {
95
+ publicKey: signer.publicKey,
96
+ keyId: signer.keyId,
97
+ },
98
+ };
99
+
100
+ const signature = await signSealUtf8(signer.identity, getSealProofSigningPayload(fields));
101
+
102
+ return {
103
+ ...fields,
104
+ signature,
105
+ };
106
+ }
107
+
108
+ export async function createSealPublicKeyArtifact(
109
+ signer: SealSignerInput,
110
+ ): Promise<SealPublicKeyArtifact> {
111
+ const resolved = await resolveSealSigner(signer);
112
+ return {
113
+ version: SEAL_PROOF_VERSION,
114
+ type: SEAL_PUBLIC_KEY_TYPE,
115
+ algorithm: SEAL_SIGNATURE_ALGORITHM,
116
+ publicKey: resolved.publicKey,
117
+ keyId: resolved.keyId,
118
+ };
119
+ }
120
+
121
+ export function validateSealProofShape(value: unknown): {
122
+ ok: boolean;
123
+ errors: string[];
124
+ proof: SealProofV1 | null;
125
+ } {
126
+ if (!isRecord(value)) {
127
+ return { ok: false, errors: ["Proof must be a JSON object."], proof: null };
128
+ }
129
+
130
+ const errors: string[] = [];
131
+
132
+ if (
133
+ !hasOnlyKeys(value, [
134
+ "version",
135
+ "type",
136
+ "algorithm",
137
+ "createdAt",
138
+ "subject",
139
+ "signer",
140
+ "signature",
141
+ ])
142
+ ) {
143
+ errors.push("Proof contains unsupported fields.");
144
+ }
145
+
146
+ if (value.version !== SEAL_PROOF_VERSION) {
147
+ errors.push(`Proof version must be ${SEAL_PROOF_VERSION}.`);
148
+ }
149
+ if (value.type !== SEAL_PROOF_TYPE) {
150
+ errors.push(`Proof type must be ${SEAL_PROOF_TYPE}.`);
151
+ }
152
+ if (value.algorithm !== SEAL_SIGNATURE_ALGORITHM) {
153
+ errors.push(`Proof algorithm must be ${SEAL_SIGNATURE_ALGORITHM}.`);
154
+ }
155
+ if (typeof value.createdAt !== "string" || !isIsoDate(value.createdAt)) {
156
+ errors.push("Proof createdAt must be an ISO timestamp.");
157
+ }
158
+ if (typeof value.signature !== "string" || value.signature.length === 0) {
159
+ errors.push("Proof signature must be a non-empty base64url string.");
160
+ }
161
+ if (!isRecord(value.subject)) {
162
+ errors.push("Proof subject must be an object.");
163
+ }
164
+ if (!isRecord(value.signer)) {
165
+ errors.push("Proof signer must be an object.");
166
+ }
167
+
168
+ if (errors.length > 0 || !isRecord(value.subject) || !isRecord(value.signer)) {
169
+ return { ok: false, errors, proof: null };
170
+ }
171
+
172
+ if (!hasOnlyKeys(value.subject, ["kind", "path", "hash"])) {
173
+ errors.push("Proof subject contains unsupported fields.");
174
+ }
175
+ if (!hasOnlyKeys(value.signer, ["publicKey", "keyId"])) {
176
+ errors.push("Proof signer contains unsupported fields.");
177
+ }
178
+ if (
179
+ value.subject.kind !== "file" &&
180
+ value.subject.kind !== "manifest" &&
181
+ value.subject.kind !== "artifact"
182
+ ) {
183
+ errors.push("Proof subject kind must be file, manifest, or artifact.");
184
+ }
185
+ if (typeof value.subject.path !== "string" || value.subject.path.length === 0) {
186
+ errors.push("Proof subject path must be a non-empty string.");
187
+ }
188
+ if (!isSealHash(value.subject.hash)) {
189
+ errors.push("Proof subject hash must be a sha256 hash.");
190
+ }
191
+ if (typeof value.signer.publicKey !== "string" || value.signer.publicKey.length === 0) {
192
+ errors.push("Proof signer publicKey must be a non-empty base64url string.");
193
+ }
194
+ if (typeof value.signer.keyId !== "string" || value.signer.keyId.length === 0) {
195
+ errors.push("Proof signer keyId must be a non-empty string.");
196
+ }
197
+
198
+ if (errors.length > 0) {
199
+ return { ok: false, errors, proof: null };
200
+ }
201
+
202
+ return {
203
+ ok: true,
204
+ errors: [],
205
+ proof: value as SealProofV1,
206
+ };
207
+ }
208
+
209
+ export function parseSealProofJson(raw: string): {
210
+ ok: boolean;
211
+ errors: string[];
212
+ proof: SealProofV1 | null;
213
+ } {
214
+ try {
215
+ return validateSealProofShape(JSON.parse(raw));
216
+ } catch {
217
+ return {
218
+ ok: false,
219
+ errors: ["Proof JSON is not valid JSON."],
220
+ proof: null,
221
+ };
222
+ }
223
+ }
224
+
225
+ export function validateSealPublicKeyShape(value: unknown): {
226
+ ok: boolean;
227
+ errors: string[];
228
+ artifact: SealPublicKeyArtifact | null;
229
+ } {
230
+ if (!isRecord(value)) {
231
+ return {
232
+ ok: false,
233
+ errors: ["Public key artifact must be a JSON object."],
234
+ artifact: null,
235
+ };
236
+ }
237
+
238
+ const errors: string[] = [];
239
+
240
+ if (!hasOnlyKeys(value, ["version", "type", "algorithm", "publicKey", "keyId"])) {
241
+ errors.push("Public key artifact contains unsupported fields.");
242
+ }
243
+ if (value.version !== SEAL_PROOF_VERSION) {
244
+ errors.push(`Public key artifact version must be ${SEAL_PROOF_VERSION}.`);
245
+ }
246
+ if (value.type !== SEAL_PUBLIC_KEY_TYPE) {
247
+ errors.push(`Public key artifact type must be ${SEAL_PUBLIC_KEY_TYPE}.`);
248
+ }
249
+ if (value.algorithm !== SEAL_SIGNATURE_ALGORITHM) {
250
+ errors.push(`Public key artifact algorithm must be ${SEAL_SIGNATURE_ALGORITHM}.`);
251
+ }
252
+ if (typeof value.publicKey !== "string" || value.publicKey.length === 0) {
253
+ errors.push("Public key artifact publicKey must be a non-empty base64url string.");
254
+ }
255
+ if (typeof value.keyId !== "string" || value.keyId.length === 0) {
256
+ errors.push("Public key artifact keyId must be a non-empty string.");
257
+ }
258
+
259
+ if (errors.length > 0) {
260
+ return { ok: false, errors, artifact: null };
261
+ }
262
+
263
+ return {
264
+ ok: true,
265
+ errors: [],
266
+ artifact: value as SealPublicKeyArtifact,
267
+ };
268
+ }
269
+
270
+ export function parseSealPublicKeyJson(raw: string): {
271
+ ok: boolean;
272
+ errors: string[];
273
+ artifact: SealPublicKeyArtifact | null;
274
+ } {
275
+ try {
276
+ return validateSealPublicKeyShape(JSON.parse(raw));
277
+ } catch {
278
+ return {
279
+ ok: false,
280
+ errors: ["Public key JSON is not valid JSON."],
281
+ artifact: null,
282
+ };
283
+ }
284
+ }
285
+
286
+ export async function verifySealProofSignature(proof: SealProofV1): Promise<{
287
+ ok: boolean;
288
+ errors: string[];
289
+ }> {
290
+ const validation = validateSealProofShape(proof);
291
+ if (!validation.ok || !validation.proof) {
292
+ return { ok: false, errors: validation.errors };
293
+ }
294
+
295
+ if (!(await verifyPublicKeyKeyId(proof.signer.publicKey, proof.signer.keyId))) {
296
+ return {
297
+ ok: false,
298
+ errors: ["Proof signer keyId does not match signer public key."],
299
+ };
300
+ }
301
+
302
+ try {
303
+ const valid = await verifySealUtf8(
304
+ proof.signature,
305
+ getSealProofSigningPayload(proof),
306
+ proof.signer.publicKey,
307
+ );
308
+ if (!valid) {
309
+ return { ok: false, errors: ["Invalid signature."] };
310
+ }
311
+ return { ok: true, errors: [] };
312
+ } catch (caught) {
313
+ return {
314
+ ok: false,
315
+ errors: ["Invalid signature."],
316
+ };
317
+ }
318
+ }
319
+
320
+ export async function verifySealProofAgainstBytes(
321
+ proof: SealProofV1,
322
+ bytes: Uint8Array | ArrayBuffer,
323
+ ): Promise<{
324
+ valid: boolean;
325
+ hashMatch: boolean;
326
+ signatureValid: boolean;
327
+ keyId: string;
328
+ algorithm: typeof SEAL_SIGNATURE_ALGORITHM;
329
+ subjectHash: `sha256:${string}`;
330
+ }> {
331
+ const subjectHash = await createSealHash(bytes);
332
+ const signatureCheck = await verifySealProofSignature(proof);
333
+ const hashMatch = subjectHash === proof.subject.hash;
334
+ const signatureValid = signatureCheck.ok;
335
+
336
+ return {
337
+ valid: hashMatch && signatureValid,
338
+ hashMatch,
339
+ signatureValid,
340
+ keyId: proof.signer.keyId,
341
+ algorithm: proof.algorithm,
342
+ subjectHash,
343
+ };
344
+ }
@@ -0,0 +1,86 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createIdentity } from "@ternent/identity";
3
+ import { recipientFromIdentity } from "@ternent/armour";
4
+ import {
5
+ createSealArtifact,
6
+ decryptSealArtifactPayload,
7
+ verifySealArtifact,
8
+ } from "../src/artifact";
9
+ import { SealArtifactError } from "../src/errors";
10
+
11
+ async function createSigner() {
12
+ return createIdentity();
13
+ }
14
+
15
+ describe("seal artifact", () => {
16
+ it("creates, verifies, and decrypts an encrypted artifact", async () => {
17
+ const signer = await createSigner();
18
+ const alice = await createIdentity();
19
+ const bob = await createIdentity();
20
+ const aliceRecipient = await recipientFromIdentity(alice);
21
+ const bobRecipient = await recipientFromIdentity(bob);
22
+ const plaintext = new TextEncoder().encode("recipient targeted payload");
23
+ const artifact = await createSealArtifact({
24
+ signer: { identity: signer },
25
+ subjectPath: "dist-manifest.json",
26
+ payload: plaintext,
27
+ recipients: [aliceRecipient, bobRecipient],
28
+ });
29
+
30
+ expect(artifact.type).toBe("seal-artifact");
31
+ expect(artifact.version).toBe("1");
32
+ expect(artifact.proof.subject.kind).toBe("artifact");
33
+ const serialized = JSON.stringify(artifact);
34
+ expect(serialized).not.toContain(aliceRecipient);
35
+ expect(serialized).not.toContain(bobRecipient);
36
+
37
+ const verification = await verifySealArtifact(artifact);
38
+ expect(verification.valid).toBe(true);
39
+ expect(verification.subjectHash).toBe(artifact.proof.subject.hash);
40
+ expect(artifact.manifest.payloadHash).not.toBe(artifact.proof.subject.hash);
41
+
42
+ const decrypted = await decryptSealArtifactPayload({
43
+ artifact,
44
+ identity: bob,
45
+ });
46
+ expect(new TextDecoder().decode(decrypted)).toBe("recipient targeted payload");
47
+ });
48
+
49
+ it("maps invalid recipients to seal errors", async () => {
50
+ const signer = await createSigner();
51
+
52
+ await expect(
53
+ createSealArtifact({
54
+ signer: { identity: signer },
55
+ subjectPath: "artifact.tar.gz",
56
+ payload: new TextEncoder().encode("secret"),
57
+ recipients: ["bad-recipient"],
58
+ }),
59
+ ).rejects.toMatchObject({
60
+ code: "SEAL_INVALID_RECIPIENT",
61
+ message: "Recipient must be a valid age recipient string.",
62
+ });
63
+ });
64
+
65
+ it("fails decryption for unauthorized identities", async () => {
66
+ const signer = await createSigner();
67
+ const recipient = await createIdentity();
68
+ const outsider = await createIdentity();
69
+ const artifact = await createSealArtifact({
70
+ signer: { identity: signer },
71
+ subjectPath: "artifact.tar.gz",
72
+ payload: new TextEncoder().encode("secret"),
73
+ recipients: [await recipientFromIdentity(recipient)],
74
+ });
75
+
76
+ await expect(
77
+ decryptSealArtifactPayload({
78
+ artifact,
79
+ identity: outsider,
80
+ }),
81
+ ).rejects.toMatchObject({
82
+ code: "SEAL_DECRYPTION_FAILED",
83
+ message: "Failed to decrypt payload.",
84
+ });
85
+ });
86
+ });