@ledgerhq/device-contacts-kit 0.0.0-develop-20261008001410 → 0.0.0-develop-20261010001520

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 (83) hide show
  1. package/README.md +14 -2
  2. package/lib/cjs/api/index.js +1 -1
  3. package/lib/cjs/api/index.js.map +2 -2
  4. package/lib/cjs/api/model/ContactsVersionRequirements.js +1 -1
  5. package/lib/cjs/api/model/ContactsVersionRequirements.js.map +3 -3
  6. package/lib/cjs/api/model/ContactsVersionRequirements.test.js +1 -1
  7. package/lib/cjs/api/model/ContactsVersionRequirements.test.js.map +2 -2
  8. package/lib/cjs/api/model/EditExternalAddressIdentifier.js.map +1 -1
  9. package/lib/cjs/api/model/EditExternalAddressScope.js.map +1 -1
  10. package/lib/cjs/api/model/ProvideContact.js.map +1 -1
  11. package/lib/cjs/api/model/RegisterExternalAddress.js.map +1 -1
  12. package/lib/cjs/internal/app-binder/contactsVersionGuards.test.js +1 -1
  13. package/lib/cjs/internal/app-binder/contactsVersionGuards.test.js.map +3 -3
  14. package/lib/cjs/internal/app-binder/device-action/EditExternalAddressIdentifier/validateEditExternalAddressIdentifierInput.js +1 -1
  15. package/lib/cjs/internal/app-binder/device-action/EditExternalAddressIdentifier/validateEditExternalAddressIdentifierInput.js.map +3 -3
  16. package/lib/cjs/internal/app-binder/device-action/EditExternalAddressIdentifier/validateEditExternalAddressIdentifierInput.test.js +1 -1
  17. package/lib/cjs/internal/app-binder/device-action/EditExternalAddressIdentifier/validateEditExternalAddressIdentifierInput.test.js.map +3 -3
  18. package/lib/cjs/internal/app-binder/device-action/EditExternalAddressScope/validateEditExternalAddressScopeInput.js +1 -1
  19. package/lib/cjs/internal/app-binder/device-action/EditExternalAddressScope/validateEditExternalAddressScopeInput.js.map +3 -3
  20. package/lib/cjs/internal/app-binder/device-action/EditExternalAddressScope/validateEditExternalAddressScopeInput.test.js +1 -1
  21. package/lib/cjs/internal/app-binder/device-action/EditExternalAddressScope/validateEditExternalAddressScopeInput.test.js.map +3 -3
  22. package/lib/cjs/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.js +1 -1
  23. package/lib/cjs/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.js.map +3 -3
  24. package/lib/cjs/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.test.js +1 -1
  25. package/lib/cjs/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.test.js.map +3 -3
  26. package/lib/cjs/internal/app-binder/model/contactsValidation.js +1 -1
  27. package/lib/cjs/internal/app-binder/model/contactsValidation.js.map +3 -3
  28. package/lib/cjs/internal/app-binder/model/contactsValidation.test.js +1 -1
  29. package/lib/cjs/internal/app-binder/model/contactsValidation.test.js.map +3 -3
  30. package/lib/cjs/internal/app-binder/services/provideContact.js +1 -1
  31. package/lib/cjs/internal/app-binder/services/provideContact.js.map +3 -3
  32. package/lib/cjs/internal/app-binder/services/provideContact.test.js +1 -1
  33. package/lib/cjs/internal/app-binder/services/provideContact.test.js.map +2 -2
  34. package/lib/cjs/package.json +1 -1
  35. package/lib/esm/api/index.js +1 -1
  36. package/lib/esm/api/index.js.map +3 -3
  37. package/lib/esm/api/model/ContactsVersionRequirements.js +1 -1
  38. package/lib/esm/api/model/ContactsVersionRequirements.js.map +3 -3
  39. package/lib/esm/api/model/ContactsVersionRequirements.test.js +1 -1
  40. package/lib/esm/api/model/ContactsVersionRequirements.test.js.map +3 -3
  41. package/lib/esm/internal/app-binder/contactsVersionGuards.test.js +1 -1
  42. package/lib/esm/internal/app-binder/contactsVersionGuards.test.js.map +3 -3
  43. package/lib/esm/internal/app-binder/device-action/EditExternalAddressIdentifier/validateEditExternalAddressIdentifierInput.js +1 -1
  44. package/lib/esm/internal/app-binder/device-action/EditExternalAddressIdentifier/validateEditExternalAddressIdentifierInput.js.map +3 -3
  45. package/lib/esm/internal/app-binder/device-action/EditExternalAddressIdentifier/validateEditExternalAddressIdentifierInput.test.js +1 -1
  46. package/lib/esm/internal/app-binder/device-action/EditExternalAddressIdentifier/validateEditExternalAddressIdentifierInput.test.js.map +3 -3
  47. package/lib/esm/internal/app-binder/device-action/EditExternalAddressScope/validateEditExternalAddressScopeInput.js +1 -1
  48. package/lib/esm/internal/app-binder/device-action/EditExternalAddressScope/validateEditExternalAddressScopeInput.js.map +3 -3
  49. package/lib/esm/internal/app-binder/device-action/EditExternalAddressScope/validateEditExternalAddressScopeInput.test.js +1 -1
  50. package/lib/esm/internal/app-binder/device-action/EditExternalAddressScope/validateEditExternalAddressScopeInput.test.js.map +3 -3
  51. package/lib/esm/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.js +1 -1
  52. package/lib/esm/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.js.map +3 -3
  53. package/lib/esm/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.test.js +1 -1
  54. package/lib/esm/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.test.js.map +3 -3
  55. package/lib/esm/internal/app-binder/model/contactsValidation.js +1 -1
  56. package/lib/esm/internal/app-binder/model/contactsValidation.js.map +3 -3
  57. package/lib/esm/internal/app-binder/model/contactsValidation.test.js +1 -1
  58. package/lib/esm/internal/app-binder/model/contactsValidation.test.js.map +3 -3
  59. package/lib/esm/internal/app-binder/services/provideContact.js +1 -1
  60. package/lib/esm/internal/app-binder/services/provideContact.js.map +3 -3
  61. package/lib/esm/internal/app-binder/services/provideContact.test.js +1 -1
  62. package/lib/esm/internal/app-binder/services/provideContact.test.js.map +2 -2
  63. package/lib/esm/package.json +1 -1
  64. package/lib/types/api/index.d.ts +1 -1
  65. package/lib/types/api/index.d.ts.map +1 -1
  66. package/lib/types/api/model/ContactsVersionRequirements.d.ts +1 -0
  67. package/lib/types/api/model/ContactsVersionRequirements.d.ts.map +1 -1
  68. package/lib/types/api/model/EditExternalAddressIdentifier.d.ts +2 -2
  69. package/lib/types/api/model/EditExternalAddressIdentifier.d.ts.map +1 -1
  70. package/lib/types/api/model/EditExternalAddressScope.d.ts +2 -2
  71. package/lib/types/api/model/EditExternalAddressScope.d.ts.map +1 -1
  72. package/lib/types/api/model/ProvideContact.d.ts +1 -1
  73. package/lib/types/api/model/ProvideContact.d.ts.map +1 -1
  74. package/lib/types/api/model/RegisterExternalAddress.d.ts +2 -2
  75. package/lib/types/api/model/RegisterExternalAddress.d.ts.map +1 -1
  76. package/lib/types/internal/app-binder/device-action/EditExternalAddressIdentifier/validateEditExternalAddressIdentifierInput.d.ts.map +1 -1
  77. package/lib/types/internal/app-binder/device-action/EditExternalAddressScope/validateEditExternalAddressScopeInput.d.ts.map +1 -1
  78. package/lib/types/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.d.ts.map +1 -1
  79. package/lib/types/internal/app-binder/model/contactsValidation.d.ts +23 -0
  80. package/lib/types/internal/app-binder/model/contactsValidation.d.ts.map +1 -1
  81. package/lib/types/internal/app-binder/services/provideContact.d.ts.map +1 -1
  82. package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
  83. package/package.json +7 -7
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/internal/app-binder/device-action/EditExternalAddressScope/validateEditExternalAddressScopeInput.test.ts"],
4
- "sourcesContent": ["import { type EditExternalAddressScopeInput } from \"@api/model/EditExternalAddressScope\";\nimport { ContactsValidationError } from \"@internal/app-binder/model/contactsValidation\";\n\nimport { validateEditExternalAddressScopeInput } from \"./validateEditExternalAddressScopeInput\";\n\nconst VALID_INPUT: EditExternalAddressScopeInput = {\n contactName: \"Alice\",\n previousScope: \"Eth main\",\n newScope: \"Eth cold\",\n identifier: new Uint8Array(20).fill(0x11),\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n groupHandle: new Uint8Array(64).fill(0xcc),\n hmacProof: new Uint8Array(32).fill(0xdd),\n hmacRest: new Uint8Array(32).fill(0xaa),\n};\n\ndescribe(\"validateEditExternalAddressScopeInput\", () => {\n it(\"returns null for a valid input\", () => {\n expect(validateEditExternalAddressScopeInput(VALID_INPUT)).toBeNull();\n });\n\n it(\"rejects an empty contactName\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n contactName: \"\",\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects a non-printable previousScope\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n previousScope: \"caf\u00E9\", // 0xC3 0xA9 is non-ASCII\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects a non-printable newScope\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n newScope: \"caf\u00E9\",\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects an unsupported blockchain family\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n blockchainFamily: \"dogecoin\",\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects an identifier of the wrong length for Ethereum\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n identifier: new Uint8Array(19).fill(0x11),\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"requires chainId for the Ethereum family\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n chainId: undefined,\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects a groupHandle of the wrong length\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n groupHandle: new Uint8Array(63).fill(0xcc),\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects an hmacProof of the wrong length\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n hmacProof: new Uint8Array(31).fill(0xdd),\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects an hmacRest of the wrong length\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n hmacRest: new Uint8Array(33).fill(0xaa),\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n});\n"],
5
- "mappings": "aACA,IAAAA,EAAwC,yDAExCC,EAAsD,mDAEtD,MAAMC,EAA6C,CACjD,YAAa,QACb,cAAe,WACf,SAAU,WACV,WAAY,IAAI,WAAW,EAAE,EAAE,KAAK,EAAI,EACxC,iBAAkB,WAClB,QAAS,GACT,YAAa,IAAI,WAAW,EAAE,EAAE,KAAK,GAAI,EACzC,UAAW,IAAI,WAAW,EAAE,EAAE,KAAK,GAAI,EACvC,SAAU,IAAI,WAAW,EAAE,EAAE,KAAK,GAAI,CACxC,EAEA,SAAS,wCAAyC,IAAM,CACtD,GAAG,iCAAkC,IAAM,CACzC,UAAO,yCAAsCA,CAAW,CAAC,EAAE,SAAS,CACtE,CAAC,EAED,GAAG,+BAAgC,IAAM,CACvC,MAAMC,KAAQ,yCAAsC,CAClD,GAAGD,EACH,YAAa,EACf,CAAC,EACD,OAAOC,CAAK,EAAE,eAAe,yBAAuB,CACtD,CAAC,EAED,GAAG,wCAAyC,IAAM,CAChD,MAAMA,KAAQ,yCAAsC,CAClD,GAAGD,EACH,cAAe,SACjB,CAAC,EACD,OAAOC,CAAK,EAAE,eAAe,yBAAuB,CACtD,CAAC,EAED,GAAG,mCAAoC,IAAM,CAC3C,MAAMA,KAAQ,yCAAsC,CAClD,GAAGD,EACH,SAAU,SACZ,CAAC,EACD,OAAOC,CAAK,EAAE,eAAe,yBAAuB,CACtD,CAAC,EAED,GAAG,2CAA4C,IAAM,CACnD,MAAMA,KAAQ,yCAAsC,CAClD,GAAGD,EACH,iBAAkB,UACpB,CAAC,EACD,OAAOC,CAAK,EAAE,eAAe,yBAAuB,CACtD,CAAC,EAED,GAAG,yDAA0D,IAAM,CACjE,MAAMA,KAAQ,yCAAsC,CAClD,GAAGD,EACH,WAAY,IAAI,WAAW,EAAE,EAAE,KAAK,EAAI,CAC1C,CAAC,EACD,OAAOC,CAAK,EAAE,eAAe,yBAAuB,CACtD,CAAC,EAED,GAAG,2CAA4C,IAAM,CACnD,MAAMA,KAAQ,yCAAsC,CAClD,GAAGD,EACH,QAAS,MACX,CAAC,EACD,OAAOC,CAAK,EAAE,eAAe,yBAAuB,CACtD,CAAC,EAED,GAAG,4CAA6C,IAAM,CACpD,MAAMA,KAAQ,yCAAsC,CAClD,GAAGD,EACH,YAAa,IAAI,WAAW,EAAE,EAAE,KAAK,GAAI,CAC3C,CAAC,EACD,OAAOC,CAAK,EAAE,eAAe,yBAAuB,CACtD,CAAC,EAED,GAAG,2CAA4C,IAAM,CACnD,MAAMA,KAAQ,yCAAsC,CAClD,GAAGD,EACH,UAAW,IAAI,WAAW,EAAE,EAAE,KAAK,GAAI,CACzC,CAAC,EACD,OAAOC,CAAK,EAAE,eAAe,yBAAuB,CACtD,CAAC,EAED,GAAG,0CAA2C,IAAM,CAClD,MAAMA,KAAQ,yCAAsC,CAClD,GAAGD,EACH,SAAU,IAAI,WAAW,EAAE,EAAE,KAAK,GAAI,CACxC,CAAC,EACD,OAAOC,CAAK,EAAE,eAAe,yBAAuB,CACtD,CAAC,CACH,CAAC",
6
- "names": ["import_contactsValidation", "import_validateEditExternalAddressScopeInput", "VALID_INPUT", "error"]
4
+ "sourcesContent": ["import { type EditExternalAddressScopeInput } from \"@api/model/EditExternalAddressScope\";\nimport { ContactsValidationError } from \"@internal/app-binder/model/contactsValidation\";\n\nimport { validateEditExternalAddressScopeInput } from \"./validateEditExternalAddressScopeInput\";\n\nconst VALID_INPUT: EditExternalAddressScopeInput = {\n contactName: \"Alice\",\n previousScope: \"Eth main\",\n newScope: \"Eth cold\",\n identifier: new Uint8Array(20).fill(0x11),\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n groupHandle: new Uint8Array(64).fill(0xcc),\n hmacProof: new Uint8Array(32).fill(0xdd),\n hmacRest: new Uint8Array(32).fill(0xaa),\n};\n\ndescribe(\"validateEditExternalAddressScopeInput\", () => {\n it(\"returns null for a valid input\", () => {\n expect(validateEditExternalAddressScopeInput(VALID_INPUT)).toBeNull();\n });\n\n it(\"rejects an empty contactName\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n contactName: \"\",\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects a non-printable previousScope\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n previousScope: \"caf\u00E9\", // 0xC3 0xA9 is non-ASCII\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects a non-printable newScope\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n newScope: \"caf\u00E9\",\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects an unsupported blockchain family\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n blockchainFamily: \"dogecoin\",\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects an identifier of the wrong length for Ethereum\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n identifier: new Uint8Array(19).fill(0x11),\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"requires chainId for the Ethereum family\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n chainId: undefined,\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n describe(\"Solana\", () => {\n const SOLANA_INPUT: EditExternalAddressScopeInput = {\n ...VALID_INPUT,\n identifier: new Uint8Array(32).fill(0x11),\n blockchainFamily: \"solana\",\n chainId: undefined,\n };\n\n it(\"accepts a 32-byte public key without chainId\", () => {\n expect(validateEditExternalAddressScopeInput(SOLANA_INPUT)).toBeNull();\n });\n\n it(\"rejects an identifier that is not 32 bytes\", () => {\n expect(\n validateEditExternalAddressScopeInput({\n ...SOLANA_INPUT,\n identifier: new Uint8Array(20),\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects a chainId\", () => {\n expect(\n validateEditExternalAddressScopeInput({ ...SOLANA_INPUT, chainId: 1n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n });\n\n it(\"rejects a groupHandle of the wrong length\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n groupHandle: new Uint8Array(63).fill(0xcc),\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects an hmacProof of the wrong length\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n hmacProof: new Uint8Array(31).fill(0xdd),\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"rejects an hmacRest of the wrong length\", () => {\n const error = validateEditExternalAddressScopeInput({\n ...VALID_INPUT,\n hmacRest: new Uint8Array(33).fill(0xaa),\n });\n expect(error).toBeInstanceOf(ContactsValidationError);\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": ["import_contactsValidation", "import_validateEditExternalAddressScopeInput", "VALID_INPUT", "error", "SOLANA_INPUT"]
7
7
  }
@@ -1,2 +1,2 @@
1
- "use strict";var o=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var s=(t,i)=>{for(var n in i)o(t,n,{get:i[n],enumerable:!0})},h=(t,i,n,a)=>{if(i&&typeof i=="object"||typeof i=="function")for(let r of f(i))!l.call(t,r)&&r!==n&&o(t,r,{get:()=>i[r],enumerable:!(a=c(i,r))||a.enumerable});return t};var m=t=>h(o({},"__esModule",{value:!0}),t);var C={};s(C,{validateRegisterExternalAddressInput:()=>E});module.exports=m(C);var d=require("../../../app-binder/model/contactsConstants"),e=require("../../../app-binder/model/contactsValidation");function E(t){try{(0,e.validatePrintableLabel)(t.contactName,{field:"contactName",bufferLength:e.CONTACT_NAME_BUFFER_LENGTH}),(0,e.validatePrintableLabel)(t.scope,{field:"scope",bufferLength:e.SCOPE_BUFFER_LENGTH});const i=t.blockchainFamily.toLowerCase();if(!(i in d.BLOCKCHAIN_FAMILY_BY_NAME))throw new e.ContactsValidationError(`Unsupported blockchain family: ${t.blockchainFamily}`);if(i==="ethereum"){if((0,e.validateByteLength)(t.identifier,{field:"identifier",expectedBytes:e.ETH_ADDRESS_BYTES}),t.chainId===void 0)throw new e.ContactsValidationError("chainId is required for the Ethereum blockchain family.")}else if(t.identifier.length===0)throw new e.ContactsValidationError("identifier must not be empty.");return t.chainId!==void 0&&(0,e.validateChainId)(t.chainId),t.existingContactGroup&&((0,e.validateByteLength)(t.existingContactGroup.groupHandle,{field:"existingContactGroup.groupHandle",expectedBytes:e.GROUP_HANDLE_SIZE}),(0,e.validateByteLength)(t.existingContactGroup.hmacProof,{field:"existingContactGroup.hmacProof",expectedBytes:e.HMAC_PROOF_LENGTH})),null}catch(i){if(i instanceof e.ContactsValidationError)return i;throw i}}0&&(module.exports={validateRegisterExternalAddressInput});
1
+ "use strict";var n=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var d=Object.prototype.hasOwnProperty;var s=(t,r)=>{for(var a in r)n(t,a,{get:r[a],enumerable:!0})},f=(t,r,a,o)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of c(r))!d.call(t,i)&&i!==a&&n(t,i,{get:()=>r[i],enumerable:!(o=l(r,i))||o.enumerable});return t};var E=t=>f(n({},"__esModule",{value:!0}),t);var h={};s(h,{validateRegisterExternalAddressInput:()=>g});module.exports=E(h);var e=require("../../../app-binder/model/contactsValidation");function g(t){try{return(0,e.validatePrintableLabel)(t.contactName,{field:"contactName",bufferLength:e.CONTACT_NAME_BUFFER_LENGTH}),(0,e.validatePrintableLabel)(t.scope,{field:"scope",bufferLength:e.SCOPE_BUFFER_LENGTH}),(0,e.validateFamilyIdentifiers)({blockchainFamily:t.blockchainFamily,identifiers:[{field:"identifier",value:t.identifier}],chainId:t.chainId}),t.existingContactGroup&&((0,e.validateByteLength)(t.existingContactGroup.groupHandle,{field:"existingContactGroup.groupHandle",expectedBytes:e.GROUP_HANDLE_SIZE}),(0,e.validateByteLength)(t.existingContactGroup.hmacProof,{field:"existingContactGroup.hmacProof",expectedBytes:e.HMAC_PROOF_LENGTH})),null}catch(r){if(r instanceof e.ContactsValidationError)return r;throw r}}0&&(module.exports={validateRegisterExternalAddressInput});
2
2
  //# sourceMappingURL=validateRegisterExternalAddressInput.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.ts"],
4
- "sourcesContent": ["import { type RegisterExternalAddressInput } from \"@api/model/RegisterExternalAddress\";\nimport { BLOCKCHAIN_FAMILY_BY_NAME } from \"@internal/app-binder/model/contactsConstants\";\nimport {\n CONTACT_NAME_BUFFER_LENGTH,\n ContactsValidationError,\n ETH_ADDRESS_BYTES,\n GROUP_HANDLE_SIZE,\n HMAC_PROOF_LENGTH,\n SCOPE_BUFFER_LENGTH,\n validateByteLength,\n validateChainId,\n validatePrintableLabel,\n} from \"@internal/app-binder/model/contactsValidation\";\n\n/**\n * Validate the caller input for Register External Address. Returns the first\n * `ContactsValidationError` found, or `null` when the input is valid.\n *\n * Non-throwing by design: the device action calls this so an invalid input is\n * surfaced as a typed terminal error state on the observable, keeping the\n * public `ContactsManager.registerExternalAddress` free of synchronous throws.\n */\nexport function validateRegisterExternalAddressInput(\n input: RegisterExternalAddressInput,\n): ContactsValidationError | null {\n try {\n validatePrintableLabel(input.contactName, {\n field: \"contactName\",\n bufferLength: CONTACT_NAME_BUFFER_LENGTH,\n });\n validatePrintableLabel(input.scope, {\n field: \"scope\",\n bufferLength: SCOPE_BUFFER_LENGTH,\n });\n\n const family = input.blockchainFamily.toLowerCase();\n if (!(family in BLOCKCHAIN_FAMILY_BY_NAME)) {\n throw new ContactsValidationError(\n `Unsupported blockchain family: ${input.blockchainFamily}`,\n );\n }\n if (family === \"ethereum\") {\n validateByteLength(input.identifier, {\n field: \"identifier\",\n expectedBytes: ETH_ADDRESS_BYTES,\n });\n // CHAIN_ID is mandatory for the Ethereum family (multiple networks share\n // the same address format).\n if (input.chainId === undefined) {\n throw new ContactsValidationError(\n \"chainId is required for the Ethereum blockchain family.\",\n );\n }\n } else if (input.identifier.length === 0) {\n throw new ContactsValidationError(\"identifier must not be empty.\");\n }\n\n if (input.chainId !== undefined) {\n validateChainId(input.chainId);\n }\n\n if (input.existingContactGroup) {\n validateByteLength(input.existingContactGroup.groupHandle, {\n field: \"existingContactGroup.groupHandle\",\n expectedBytes: GROUP_HANDLE_SIZE,\n });\n validateByteLength(input.existingContactGroup.hmacProof, {\n field: \"existingContactGroup.hmacProof\",\n expectedBytes: HMAC_PROOF_LENGTH,\n });\n }\n\n return null;\n } catch (error) {\n if (error instanceof ContactsValidationError) {\n return error;\n }\n throw error;\n }\n}\n"],
5
- "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,0CAAAE,IAAA,eAAAC,EAAAH,GACA,IAAAI,EAA0C,wDAC1CC,EAUO,yDAUA,SAASH,EACdI,EACgC,CAChC,GAAI,IACF,0BAAuBA,EAAM,YAAa,CACxC,MAAO,cACP,aAAc,4BAChB,CAAC,KACD,0BAAuBA,EAAM,MAAO,CAClC,MAAO,QACP,aAAc,qBAChB,CAAC,EAED,MAAMC,EAASD,EAAM,iBAAiB,YAAY,EAClD,GAAI,EAAEC,KAAU,6BACd,MAAM,IAAI,0BACR,kCAAkCD,EAAM,gBAAgB,EAC1D,EAEF,GAAIC,IAAW,YAOb,MANA,sBAAmBD,EAAM,WAAY,CACnC,MAAO,aACP,cAAe,mBACjB,CAAC,EAGGA,EAAM,UAAY,OACpB,MAAM,IAAI,0BACR,yDACF,UAEOA,EAAM,WAAW,SAAW,EACrC,MAAM,IAAI,0BAAwB,+BAA+B,EAGnE,OAAIA,EAAM,UAAY,WACpB,mBAAgBA,EAAM,OAAO,EAG3BA,EAAM,0BACR,sBAAmBA,EAAM,qBAAqB,YAAa,CACzD,MAAO,mCACP,cAAe,mBACjB,CAAC,KACD,sBAAmBA,EAAM,qBAAqB,UAAW,CACvD,MAAO,iCACP,cAAe,mBACjB,CAAC,GAGI,IACT,OAASE,EAAO,CACd,GAAIA,aAAiB,0BACnB,OAAOA,EAET,MAAMA,CACR,CACF",
6
- "names": ["validateRegisterExternalAddressInput_exports", "__export", "validateRegisterExternalAddressInput", "__toCommonJS", "import_contactsConstants", "import_contactsValidation", "input", "family", "error"]
4
+ "sourcesContent": ["import { type RegisterExternalAddressInput } from \"@api/model/RegisterExternalAddress\";\nimport {\n CONTACT_NAME_BUFFER_LENGTH,\n ContactsValidationError,\n GROUP_HANDLE_SIZE,\n HMAC_PROOF_LENGTH,\n SCOPE_BUFFER_LENGTH,\n validateByteLength,\n validateFamilyIdentifiers,\n validatePrintableLabel,\n} from \"@internal/app-binder/model/contactsValidation\";\n\n/**\n * Validate the caller input for Register External Address. Returns the first\n * `ContactsValidationError` found, or `null` when the input is valid.\n *\n * Non-throwing by design: the device action calls this so an invalid input is\n * surfaced as a typed terminal error state on the observable, keeping the\n * public `ContactsManager.registerExternalAddress` free of synchronous throws.\n */\nexport function validateRegisterExternalAddressInput(\n input: RegisterExternalAddressInput,\n): ContactsValidationError | null {\n try {\n validatePrintableLabel(input.contactName, {\n field: \"contactName\",\n bufferLength: CONTACT_NAME_BUFFER_LENGTH,\n });\n validatePrintableLabel(input.scope, {\n field: \"scope\",\n bufferLength: SCOPE_BUFFER_LENGTH,\n });\n\n validateFamilyIdentifiers({\n blockchainFamily: input.blockchainFamily,\n identifiers: [{ field: \"identifier\", value: input.identifier }],\n chainId: input.chainId,\n });\n\n if (input.existingContactGroup) {\n validateByteLength(input.existingContactGroup.groupHandle, {\n field: \"existingContactGroup.groupHandle\",\n expectedBytes: GROUP_HANDLE_SIZE,\n });\n validateByteLength(input.existingContactGroup.hmacProof, {\n field: \"existingContactGroup.hmacProof\",\n expectedBytes: HMAC_PROOF_LENGTH,\n });\n }\n\n return null;\n } catch (error) {\n if (error instanceof ContactsValidationError) {\n return error;\n }\n throw error;\n }\n}\n"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,0CAAAE,IAAA,eAAAC,EAAAH,GACA,IAAAI,EASO,yDAUA,SAASF,EACdG,EACgC,CAChC,GAAI,CACF,mCAAuBA,EAAM,YAAa,CACxC,MAAO,cACP,aAAc,4BAChB,CAAC,KACD,0BAAuBA,EAAM,MAAO,CAClC,MAAO,QACP,aAAc,qBAChB,CAAC,KAED,6BAA0B,CACxB,iBAAkBA,EAAM,iBACxB,YAAa,CAAC,CAAE,MAAO,aAAc,MAAOA,EAAM,UAAW,CAAC,EAC9D,QAASA,EAAM,OACjB,CAAC,EAEGA,EAAM,0BACR,sBAAmBA,EAAM,qBAAqB,YAAa,CACzD,MAAO,mCACP,cAAe,mBACjB,CAAC,KACD,sBAAmBA,EAAM,qBAAqB,UAAW,CACvD,MAAO,iCACP,cAAe,mBACjB,CAAC,GAGI,IACT,OAASC,EAAO,CACd,GAAIA,aAAiB,0BACnB,OAAOA,EAET,MAAMA,CACR,CACF",
6
+ "names": ["validateRegisterExternalAddressInput_exports", "__export", "validateRegisterExternalAddressInput", "__toCommonJS", "import_contactsValidation", "input", "error"]
7
7
  }
@@ -1,2 +1,2 @@
1
- "use strict";var n=require("../../../app-binder/model/contactsValidation"),e=require("./validateRegisterExternalAddressInput");const t={contactName:"Alice",scope:"Eth main",identifier:new Uint8Array(20).fill(17),blockchainFamily:"ethereum",chainId:1n};describe("validateRegisterExternalAddressInput",()=>{it("returns null for valid input",()=>{expect((0,e.validateRegisterExternalAddressInput)(t)).toBeNull()}),it("returns null for a valid existing-contact-group input",()=>{expect((0,e.validateRegisterExternalAddressInput)({...t,existingContactGroup:{groupHandle:new Uint8Array(64),hmacProof:new Uint8Array(32)}})).toBeNull()}),it("returns a ContactsValidationError for a non-printable contact name",()=>{expect((0,e.validateRegisterExternalAddressInput)({...t,contactName:"Am\xE9lie"})).toBeInstanceOf(n.ContactsValidationError)}),it("returns an error for an Ethereum identifier of the wrong length",()=>{expect((0,e.validateRegisterExternalAddressInput)({...t,identifier:new Uint8Array(19)})).toBeInstanceOf(n.ContactsValidationError)}),it("returns an error for an unsupported blockchain family",()=>{expect((0,e.validateRegisterExternalAddressInput)({...t,blockchainFamily:"dogecoin"})).toBeInstanceOf(n.ContactsValidationError)}),it("returns an error when chainId is missing for the Ethereum family",()=>{expect((0,e.validateRegisterExternalAddressInput)({...t,chainId:void 0})).toBeInstanceOf(n.ContactsValidationError)}),it("returns an error for a wrong-sized existing group handle",()=>{expect((0,e.validateRegisterExternalAddressInput)({...t,existingContactGroup:{groupHandle:new Uint8Array(32),hmacProof:new Uint8Array(32)}})).toBeInstanceOf(n.ContactsValidationError)})});
1
+ "use strict";var t=require("../../../app-binder/model/contactsValidation"),e=require("./validateRegisterExternalAddressInput");const n={contactName:"Alice",scope:"Eth main",identifier:new Uint8Array(20).fill(17),blockchainFamily:"ethereum",chainId:1n};describe("validateRegisterExternalAddressInput",()=>{it("returns null for valid input",()=>{expect((0,e.validateRegisterExternalAddressInput)(n)).toBeNull()}),it("returns null for a valid existing-contact-group input",()=>{expect((0,e.validateRegisterExternalAddressInput)({...n,existingContactGroup:{groupHandle:new Uint8Array(64),hmacProof:new Uint8Array(32)}})).toBeNull()}),it("returns a ContactsValidationError for a non-printable contact name",()=>{expect((0,e.validateRegisterExternalAddressInput)({...n,contactName:"Am\xE9lie"})).toBeInstanceOf(t.ContactsValidationError)}),it("returns an error for an Ethereum identifier of the wrong length",()=>{expect((0,e.validateRegisterExternalAddressInput)({...n,identifier:new Uint8Array(19)})).toBeInstanceOf(t.ContactsValidationError)}),it("returns an error for an unsupported blockchain family",()=>{expect((0,e.validateRegisterExternalAddressInput)({...n,blockchainFamily:"dogecoin"})).toBeInstanceOf(t.ContactsValidationError)}),it("returns an error when chainId is missing for the Ethereum family",()=>{expect((0,e.validateRegisterExternalAddressInput)({...n,chainId:void 0})).toBeInstanceOf(t.ContactsValidationError)}),describe("Solana",()=>{const r={...n,identifier:new Uint8Array(32).fill(17),blockchainFamily:"solana",chainId:void 0};it("returns null for a 32-byte public key without chainId",()=>{expect((0,e.validateRegisterExternalAddressInput)(r)).toBeNull()}),it.each([31,33])("returns an error for a %i-byte identifier",i=>{expect((0,e.validateRegisterExternalAddressInput)({...r,identifier:new Uint8Array(i)})).toBeInstanceOf(t.ContactsValidationError)}),it("returns an error when a chainId is given",()=>{expect((0,e.validateRegisterExternalAddressInput)({...r,chainId:1n})).toBeInstanceOf(t.ContactsValidationError)})}),it("returns an error for a wrong-sized existing group handle",()=>{expect((0,e.validateRegisterExternalAddressInput)({...n,existingContactGroup:{groupHandle:new Uint8Array(32),hmacProof:new Uint8Array(32)}})).toBeInstanceOf(t.ContactsValidationError)})});
2
2
  //# sourceMappingURL=validateRegisterExternalAddressInput.test.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/internal/app-binder/device-action/RegisterExternalAddress/validateRegisterExternalAddressInput.test.ts"],
4
- "sourcesContent": ["import { type RegisterExternalAddressInput } from \"@api/model/RegisterExternalAddress\";\nimport { ContactsValidationError } from \"@internal/app-binder/model/contactsValidation\";\n\nimport { validateRegisterExternalAddressInput } from \"./validateRegisterExternalAddressInput\";\n\nconst VALID_INPUT: RegisterExternalAddressInput = {\n contactName: \"Alice\",\n scope: \"Eth main\",\n identifier: new Uint8Array(20).fill(0x11),\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n};\n\ndescribe(\"validateRegisterExternalAddressInput\", () => {\n it(\"returns null for valid input\", () => {\n expect(validateRegisterExternalAddressInput(VALID_INPUT)).toBeNull();\n });\n\n it(\"returns null for a valid existing-contact-group input\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n existingContactGroup: {\n groupHandle: new Uint8Array(64),\n hmacProof: new Uint8Array(32),\n },\n }),\n ).toBeNull();\n });\n\n it(\"returns a ContactsValidationError for a non-printable contact name\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n contactName: \"Am\u00E9lie\",\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"returns an error for an Ethereum identifier of the wrong length\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n identifier: new Uint8Array(19),\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"returns an error for an unsupported blockchain family\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n blockchainFamily: \"dogecoin\",\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"returns an error when chainId is missing for the Ethereum family\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n chainId: undefined,\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"returns an error for a wrong-sized existing group handle\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n existingContactGroup: {\n groupHandle: new Uint8Array(32),\n hmacProof: new Uint8Array(32),\n },\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n});\n"],
5
- "mappings": "aACA,IAAAA,EAAwC,yDAExCC,EAAqD,kDAErD,MAAMC,EAA4C,CAChD,YAAa,QACb,MAAO,WACP,WAAY,IAAI,WAAW,EAAE,EAAE,KAAK,EAAI,EACxC,iBAAkB,WAClB,QAAS,EACX,EAEA,SAAS,uCAAwC,IAAM,CACrD,GAAG,+BAAgC,IAAM,CACvC,UAAO,wCAAqCA,CAAW,CAAC,EAAE,SAAS,CACrE,CAAC,EAED,GAAG,wDAAyD,IAAM,CAChE,UACE,wCAAqC,CACnC,GAAGA,EACH,qBAAsB,CACpB,YAAa,IAAI,WAAW,EAAE,EAC9B,UAAW,IAAI,WAAW,EAAE,CAC9B,CACF,CAAC,CACH,EAAE,SAAS,CACb,CAAC,EAED,GAAG,qEAAsE,IAAM,CAC7E,UACE,wCAAqC,CACnC,GAAGA,EACH,YAAa,WACf,CAAC,CACH,EAAE,eAAe,yBAAuB,CAC1C,CAAC,EAED,GAAG,kEAAmE,IAAM,CAC1E,UACE,wCAAqC,CACnC,GAAGA,EACH,WAAY,IAAI,WAAW,EAAE,CAC/B,CAAC,CACH,EAAE,eAAe,yBAAuB,CAC1C,CAAC,EAED,GAAG,wDAAyD,IAAM,CAChE,UACE,wCAAqC,CACnC,GAAGA,EACH,iBAAkB,UACpB,CAAC,CACH,EAAE,eAAe,yBAAuB,CAC1C,CAAC,EAED,GAAG,mEAAoE,IAAM,CAC3E,UACE,wCAAqC,CACnC,GAAGA,EACH,QAAS,MACX,CAAC,CACH,EAAE,eAAe,yBAAuB,CAC1C,CAAC,EAED,GAAG,2DAA4D,IAAM,CACnE,UACE,wCAAqC,CACnC,GAAGA,EACH,qBAAsB,CACpB,YAAa,IAAI,WAAW,EAAE,EAC9B,UAAW,IAAI,WAAW,EAAE,CAC9B,CACF,CAAC,CACH,EAAE,eAAe,yBAAuB,CAC1C,CAAC,CACH,CAAC",
6
- "names": ["import_contactsValidation", "import_validateRegisterExternalAddressInput", "VALID_INPUT"]
4
+ "sourcesContent": ["import { type RegisterExternalAddressInput } from \"@api/model/RegisterExternalAddress\";\nimport { ContactsValidationError } from \"@internal/app-binder/model/contactsValidation\";\n\nimport { validateRegisterExternalAddressInput } from \"./validateRegisterExternalAddressInput\";\n\nconst VALID_INPUT: RegisterExternalAddressInput = {\n contactName: \"Alice\",\n scope: \"Eth main\",\n identifier: new Uint8Array(20).fill(0x11),\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n};\n\ndescribe(\"validateRegisterExternalAddressInput\", () => {\n it(\"returns null for valid input\", () => {\n expect(validateRegisterExternalAddressInput(VALID_INPUT)).toBeNull();\n });\n\n it(\"returns null for a valid existing-contact-group input\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n existingContactGroup: {\n groupHandle: new Uint8Array(64),\n hmacProof: new Uint8Array(32),\n },\n }),\n ).toBeNull();\n });\n\n it(\"returns a ContactsValidationError for a non-printable contact name\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n contactName: \"Am\u00E9lie\",\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"returns an error for an Ethereum identifier of the wrong length\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n identifier: new Uint8Array(19),\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"returns an error for an unsupported blockchain family\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n blockchainFamily: \"dogecoin\",\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"returns an error when chainId is missing for the Ethereum family\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n chainId: undefined,\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n describe(\"Solana\", () => {\n const SOLANA_INPUT: RegisterExternalAddressInput = {\n ...VALID_INPUT,\n identifier: new Uint8Array(32).fill(0x11),\n blockchainFamily: \"solana\",\n chainId: undefined,\n };\n\n it(\"returns null for a 32-byte public key without chainId\", () => {\n expect(validateRegisterExternalAddressInput(SOLANA_INPUT)).toBeNull();\n });\n\n it.each([31, 33])(\"returns an error for a %i-byte identifier\", (length) => {\n expect(\n validateRegisterExternalAddressInput({\n ...SOLANA_INPUT,\n identifier: new Uint8Array(length),\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n\n it(\"returns an error when a chainId is given\", () => {\n expect(\n validateRegisterExternalAddressInput({ ...SOLANA_INPUT, chainId: 1n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n });\n\n it(\"returns an error for a wrong-sized existing group handle\", () => {\n expect(\n validateRegisterExternalAddressInput({\n ...VALID_INPUT,\n existingContactGroup: {\n groupHandle: new Uint8Array(32),\n hmacProof: new Uint8Array(32),\n },\n }),\n ).toBeInstanceOf(ContactsValidationError);\n });\n});\n"],
5
+ "mappings": "aACA,IAAAA,EAAwC,yDAExCC,EAAqD,kDAErD,MAAMC,EAA4C,CAChD,YAAa,QACb,MAAO,WACP,WAAY,IAAI,WAAW,EAAE,EAAE,KAAK,EAAI,EACxC,iBAAkB,WAClB,QAAS,EACX,EAEA,SAAS,uCAAwC,IAAM,CACrD,GAAG,+BAAgC,IAAM,CACvC,UAAO,wCAAqCA,CAAW,CAAC,EAAE,SAAS,CACrE,CAAC,EAED,GAAG,wDAAyD,IAAM,CAChE,UACE,wCAAqC,CACnC,GAAGA,EACH,qBAAsB,CACpB,YAAa,IAAI,WAAW,EAAE,EAC9B,UAAW,IAAI,WAAW,EAAE,CAC9B,CACF,CAAC,CACH,EAAE,SAAS,CACb,CAAC,EAED,GAAG,qEAAsE,IAAM,CAC7E,UACE,wCAAqC,CACnC,GAAGA,EACH,YAAa,WACf,CAAC,CACH,EAAE,eAAe,yBAAuB,CAC1C,CAAC,EAED,GAAG,kEAAmE,IAAM,CAC1E,UACE,wCAAqC,CACnC,GAAGA,EACH,WAAY,IAAI,WAAW,EAAE,CAC/B,CAAC,CACH,EAAE,eAAe,yBAAuB,CAC1C,CAAC,EAED,GAAG,wDAAyD,IAAM,CAChE,UACE,wCAAqC,CACnC,GAAGA,EACH,iBAAkB,UACpB,CAAC,CACH,EAAE,eAAe,yBAAuB,CAC1C,CAAC,EAED,GAAG,mEAAoE,IAAM,CAC3E,UACE,wCAAqC,CACnC,GAAGA,EACH,QAAS,MACX,CAAC,CACH,EAAE,eAAe,yBAAuB,CAC1C,CAAC,EAED,SAAS,SAAU,IAAM,CACvB,MAAMC,EAA6C,CACjD,GAAGD,EACH,WAAY,IAAI,WAAW,EAAE,EAAE,KAAK,EAAI,EACxC,iBAAkB,SAClB,QAAS,MACX,EAEA,GAAG,wDAAyD,IAAM,CAChE,UAAO,wCAAqCC,CAAY,CAAC,EAAE,SAAS,CACtE,CAAC,EAED,GAAG,KAAK,CAAC,GAAI,EAAE,CAAC,EAAE,4CAA8CC,GAAW,CACzE,UACE,wCAAqC,CACnC,GAAGD,EACH,WAAY,IAAI,WAAWC,CAAM,CACnC,CAAC,CACH,EAAE,eAAe,yBAAuB,CAC1C,CAAC,EAED,GAAG,2CAA4C,IAAM,CACnD,UACE,wCAAqC,CAAE,GAAGD,EAAc,QAAS,EAAG,CAAC,CACvE,EAAE,eAAe,yBAAuB,CAC1C,CAAC,CACH,CAAC,EAED,GAAG,2DAA4D,IAAM,CACnE,UACE,wCAAqC,CACnC,GAAGD,EACH,qBAAsB,CACpB,YAAa,IAAI,WAAW,EAAE,EAC9B,UAAW,IAAI,WAAW,EAAE,CAC9B,CACF,CAAC,CACH,EAAE,eAAe,yBAAuB,CAC1C,CAAC,CACH,CAAC",
6
+ "names": ["import_contactsValidation", "import_validateRegisterExternalAddressInput", "VALID_INPUT", "SOLANA_INPUT", "length"]
7
7
  }
@@ -1,2 +1,2 @@
1
- "use strict";var d=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var w=Object.prototype.hasOwnProperty;var b=(t,e)=>{for(var o in e)d(t,o,{get:e[o],enumerable:!0})},x=(t,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of y(e))!w.call(t,n)&&n!==o&&d(t,n,{get:()=>e[n],enumerable:!(i=p(e,n))||i.enumerable});return t};var l=t=>x(d({},"__esModule",{value:!0}),t);var L={};b(L,{CONTACT_NAME_BUFFER_LENGTH:()=>$,ContactsValidationError:()=>r,ETH_ADDRESS_BYTES:()=>I,GROUP_HANDLE_SIZE:()=>N,HMAC_PROOF_LENGTH:()=>u,MAX_BIP32_DEPTH:()=>h,SCOPE_BUFFER_LENGTH:()=>E,validateByteLength:()=>T,validateChainId:()=>O,validateDerivationPath:()=>A,validatePrintableLabel:()=>P});module.exports=l(L);const $=33,E=33,N=64,u=32,h=10,I=20;class r extends Error{_tag="ContactsValidationError";originalError;constructor(e){super(e),this.name="ContactsValidationError"}}const S=32,_=126,B=new TextEncoder;function P(t,e){const{field:o,bufferLength:i}=e;if(!t)throw new r(`${o} must not be empty (firmware rejects empty strings).`);const n=B.encode(t),s=i-1;if(n.length>s)throw new r(`${o} ${JSON.stringify(t)} is too long: ${n.length} bytes encoded (max ${s}). The device buffer is ${i} bytes including the trailing NUL.`);const f=[];for(let c=0;c<n.length;c++){const a=n[c];(a<S||a>_)&&f.push(c)}if(f.length>0){const a=Array.from(new Set(f.map(g=>n[g]))).sort((g,m)=>g-m).map(g=>`0x${g.toString(16).padStart(2,"0")}`).join(", ");throw new r(`${o} ${JSON.stringify(t)} contains ${f.length} non-ASCII byte(s) at position(s) [${f.join(", ")}]: ${a}. The device buffer is byte-level isprint() \u2014 only 0x20-0x7E are accepted, no UTF-8 / accents / emoji.`)}}function T(t,e){const{field:o,expectedBytes:i}=e;if(t.length!==i)throw new r(`${o} is ${t.length} bytes, expected ${i}.`)}function A(t){if(!t)throw new r(`derivationPath must not be empty (e.g. "m/44'/60'/0'/0/0").`);const e=t.split("/"),o=e[0]==="m"||e[0]==="M"?e.slice(1):e;if(o.length===0)throw new r(`derivationPath ${JSON.stringify(t)} has no segments past 'm'.`);if(o.length>h)throw new r(`derivationPath ${JSON.stringify(t)} has ${o.length} segments (max ${h}). Firmware rejects deeper paths.`);for(const i of o){const n=i.endsWith("'")?i.slice(0,-1):i;if(!n||!/^\d+$/.test(n))throw new r(`derivationPath ${JSON.stringify(t)} segment ${JSON.stringify(i)} is not numeric. Use plain integers, optionally suffixed with ' for hardened.`);const s=Number(n);if(!Number.isSafeInteger(s)||s>=2147483648)throw new r(`derivationPath ${JSON.stringify(t)} segment ${JSON.stringify(i)} >= 2^31. Use the ' suffix for hardening rather than overflowing.`)}}function O(t){const e=typeof t=="number";if(!e&&!(typeof t=="bigint"))throw new r(`chainId must be number or bigint, got ${typeof t}.`);if(e&&!Number.isInteger(t))throw new r(`chainId must be an integer, got ${t}.`);const i=typeof t=="bigint"?t:BigInt(t);if(i<=0n)throw new r(`chainId must be positive, got ${t}.`);const n=(1n<<64n)-1n;if(i>n)throw new r(`chainId ${t} exceeds uint64 range (max ${n}).`)}0&&(module.exports={CONTACT_NAME_BUFFER_LENGTH,ContactsValidationError,ETH_ADDRESS_BYTES,GROUP_HANDLE_SIZE,HMAC_PROOF_LENGTH,MAX_BIP32_DEPTH,SCOPE_BUFFER_LENGTH,validateByteLength,validateChainId,validateDerivationPath,validatePrintableLabel});
1
+ "use strict";var h=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var $=Object.prototype.hasOwnProperty;var E=(e,t)=>{for(var o in t)h(e,o,{get:t[o],enumerable:!0})},I=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of x(t))!$.call(e,i)&&i!==o&&h(e,i,{get:()=>t[i],enumerable:!(n=u(t,i))||n.enumerable});return e};var N=e=>I(h({},"__esModule",{value:!0}),e);var C={};E(C,{CONTACT_NAME_BUFFER_LENGTH:()=>S,ContactsValidationError:()=>r,ETH_ADDRESS_BYTES:()=>y,GROUP_HANDLE_SIZE:()=>B,HMAC_PROOF_LENGTH:()=>A,MAX_BIP32_DEPTH:()=>g,SCOPE_BUFFER_LENGTH:()=>_,SOLANA_ADDRESS_BYTES:()=>p,validateByteLength:()=>l,validateChainId:()=>w,validateDerivationPath:()=>F,validateFamilyIdentifiers:()=>v,validatePrintableLabel:()=>P});module.exports=N(C);var m=require("../../app-binder/model/contactsConstants");const S=33,_=33,B=64,A=32,g=10,y=20,p=32;class r extends Error{_tag="ContactsValidationError";originalError;constructor(t){super(t),this.name="ContactsValidationError"}}const T=32,L=126,O=new TextEncoder;function P(e,t){const{field:o,bufferLength:n}=t;if(!e)throw new r(`${o} must not be empty (firmware rejects empty strings).`);const i=O.encode(e),a=n-1;if(i.length>a)throw new r(`${o} ${JSON.stringify(e)} is too long: ${i.length} bytes encoded (max ${a}). The device buffer is ${n} bytes including the trailing NUL.`);const s=[];for(let f=0;f<i.length;f++){const c=i[f];(c<T||c>L)&&s.push(f)}if(s.length>0){const c=Array.from(new Set(s.map(d=>i[d]))).sort((d,b)=>d-b).map(d=>`0x${d.toString(16).padStart(2,"0")}`).join(", ");throw new r(`${o} ${JSON.stringify(e)} contains ${s.length} non-ASCII byte(s) at position(s) [${s.join(", ")}]: ${c}. The device buffer is byte-level isprint() \u2014 only 0x20-0x7E are accepted, no UTF-8 / accents / emoji.`)}}function l(e,t){const{field:o,expectedBytes:n}=t;if(e.length!==n)throw new r(`${o} is ${e.length} bytes, expected ${n}.`)}function F(e){if(!e)throw new r(`derivationPath must not be empty (e.g. "m/44'/60'/0'/0/0").`);const t=e.split("/"),o=t[0]==="m"||t[0]==="M"?t.slice(1):t;if(o.length===0)throw new r(`derivationPath ${JSON.stringify(e)} has no segments past 'm'.`);if(o.length>g)throw new r(`derivationPath ${JSON.stringify(e)} has ${o.length} segments (max ${g}). Firmware rejects deeper paths.`);for(const n of o){const i=n.endsWith("'")?n.slice(0,-1):n;if(!i||!/^\d+$/.test(i))throw new r(`derivationPath ${JSON.stringify(e)} segment ${JSON.stringify(n)} is not numeric. Use plain integers, optionally suffixed with ' for hardened.`);const a=Number(i);if(!Number.isSafeInteger(a)||a>=2147483648)throw new r(`derivationPath ${JSON.stringify(e)} segment ${JSON.stringify(n)} >= 2^31. Use the ' suffix for hardening rather than overflowing.`)}}function w(e){const t=typeof e=="number";if(!t&&!(typeof e=="bigint"))throw new r(`chainId must be number or bigint, got ${typeof e}.`);if(t&&!Number.isInteger(e))throw new r(`chainId must be an integer, got ${e}.`);const n=typeof e=="bigint"?e:BigInt(e);if(n<=0n)throw new r(`chainId must be positive, got ${e}.`);const i=(1n<<64n)-1n;if(n>i)throw new r(`chainId ${e} exceeds uint64 range (max ${i}).`)}function v(e){const{blockchainFamily:t,identifiers:o,chainId:n}=e,i=t.toLowerCase(),a=m.BLOCKCHAIN_FAMILY_BY_NAME[i];if(a===void 0)throw new r(`Unsupported blockchain family: ${t}`);if(i==="ethereum"){for(const{field:s,value:f}of o)l(f,{field:s,expectedBytes:y});if(n===void 0)throw new r("chainId is required for the Ethereum blockchain family.")}else if(i==="solana"){for(const{field:s,value:f}of o)l(f,{field:s,expectedBytes:p});if(n!==void 0)throw new r("chainId is not allowed for the Solana blockchain family.")}else for(const{field:s,value:f}of o)if(f.length===0)throw new r(`${s} must not be empty.`);return n!==void 0&&w(n),a}0&&(module.exports={CONTACT_NAME_BUFFER_LENGTH,ContactsValidationError,ETH_ADDRESS_BYTES,GROUP_HANDLE_SIZE,HMAC_PROOF_LENGTH,MAX_BIP32_DEPTH,SCOPE_BUFFER_LENGTH,SOLANA_ADDRESS_BYTES,validateByteLength,validateChainId,validateDerivationPath,validateFamilyIdentifiers,validatePrintableLabel});
2
2
  //# sourceMappingURL=contactsValidation.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/model/contactsValidation.ts"],
4
- "sourcesContent": ["/**\n * Pre-APDU input validators for the Contacts operations.\n *\n * Buffer-length constants mirror the Ledger secure SDK `#define` values\n * *including* the trailing NUL terminator (so a 32-printable-char name lives in\n * a 33-byte buffer). Validators subtract 1 internally so the constants remain\n * pure equality checks against the upstream `#define`s. The byte-level\n * `0x20..0x7E` printable check exactly matches firmware `is_printable_string`.\n */\nimport { type DmkError } from \"@ledgerhq/device-management-kit\";\n\n// ---- SDK-mirrored constants -------------------------------------------------\n// Source of truth: ledger-secure-sdk/app_features/address_book/include/\n\nexport const CONTACT_NAME_BUFFER_LENGTH = 33; // identity.h:49 (incl. NUL)\nexport const SCOPE_BUFFER_LENGTH = 33; // identity.h:50 (incl. NUL)\nexport const GROUP_HANDLE_SIZE = 64; // identity.h:47\nexport const HMAC_PROOF_LENGTH = 32; // CX_SHA256_SIZE\nexport const MAX_BIP32_DEPTH = 10; // bip32.h:15 (MAX_BIP32_PATH)\nexport const ETH_ADDRESS_BYTES = 20; // protocol convention, no header\n\n// ---- error type -------------------------------------------------------------\n\n/**\n * Raised when caller input fails a pre-APDU check. Implements `DmkError` (and\n * stays an `Error` subclass) so a Contacts device action can surface it as a\n * typed terminal error state on the observable rather than throwing out of the\n * public, device-action-returning API.\n */\nexport class ContactsValidationError extends Error implements DmkError {\n readonly _tag = \"ContactsValidationError\";\n readonly originalError?: unknown;\n constructor(message: string) {\n super(message);\n this.name = \"ContactsValidationError\";\n }\n}\n\n// ---- printable-string validation -------------------------------------------\n\nconst PRINTABLE_MIN = 0x20;\nconst PRINTABLE_MAX = 0x7e;\n\nconst utf8Encoder = new TextEncoder();\n\n/**\n * Mirror of firmware `is_printable_string` + length cap. `bufferLength` is the\n * firmware's fixed buffer size *including* the trailing NUL, so the maximum\n * payload byte length is `bufferLength - 1`.\n */\nexport function validatePrintableLabel(\n value: string,\n options: { field: string; bufferLength: number },\n): void {\n const { field, bufferLength } = options;\n if (!value) {\n throw new ContactsValidationError(\n `${field} must not be empty (firmware rejects empty strings).`,\n );\n }\n const encoded = utf8Encoder.encode(value);\n const maxBytes = bufferLength - 1;\n if (encoded.length > maxBytes) {\n throw new ContactsValidationError(\n `${field} ${JSON.stringify(value)} is too long: ${encoded.length} bytes ` +\n `encoded (max ${maxBytes}). The device buffer is ${bufferLength} bytes ` +\n `including the trailing NUL.`,\n );\n }\n const badPositions: number[] = [];\n for (let i = 0; i < encoded.length; i++) {\n const byte = encoded[i]!;\n if (byte < PRINTABLE_MIN || byte > PRINTABLE_MAX) {\n badPositions.push(i);\n }\n }\n if (badPositions.length > 0) {\n const offendingBytes = Array.from(\n new Set(badPositions.map((i) => encoded[i]!)),\n ).sort((a, b) => a - b);\n const offendingHex = offendingBytes\n .map((b) => `0x${b.toString(16).padStart(2, \"0\")}`)\n .join(\", \");\n throw new ContactsValidationError(\n `${field} ${JSON.stringify(value)} contains ${badPositions.length} ` +\n `non-ASCII byte(s) at position(s) [${badPositions.join(\", \")}]: ` +\n `${offendingHex}. The device buffer is byte-level isprint() \u2014 only ` +\n `0x20-0x7E are accepted, no UTF-8 / accents / emoji.`,\n );\n }\n}\n\n// ---- byte-buffer validation ------------------------------------------------\n\n/** Assert a byte buffer is exactly `expectedBytes` long and non-empty. */\nexport function validateByteLength(\n value: Uint8Array,\n options: { field: string; expectedBytes: number },\n): void {\n const { field, expectedBytes } = options;\n if (value.length !== expectedBytes) {\n throw new ContactsValidationError(\n `${field} is ${value.length} bytes, expected ${expectedBytes}.`,\n );\n }\n}\n\n// ---- BIP32 path validation -------------------------------------------------\n\n/**\n * Sanity-check a BIP32 path before serialization. Firmware enforces depth <=\n * MAX_BIP32_DEPTH and rejects malformed segments. Accepts `m/44'/60'/0'/0/0`\n * style; segments may end in `'` (hardened).\n */\nexport function validateDerivationPath(path: string): void {\n if (!path) {\n throw new ContactsValidationError(\n `derivationPath must not be empty (e.g. \"m/44'/60'/0'/0/0\").`,\n );\n }\n const parts = path.split(\"/\");\n const segments =\n parts[0] === \"m\" || parts[0] === \"M\" ? parts.slice(1) : parts;\n if (segments.length === 0) {\n throw new ContactsValidationError(\n `derivationPath ${JSON.stringify(path)} has no segments past 'm'.`,\n );\n }\n if (segments.length > MAX_BIP32_DEPTH) {\n throw new ContactsValidationError(\n `derivationPath ${JSON.stringify(path)} has ${segments.length} segments ` +\n `(max ${MAX_BIP32_DEPTH}). Firmware rejects deeper paths.`,\n );\n }\n for (const segment of segments) {\n const token = segment.endsWith(\"'\") ? segment.slice(0, -1) : segment;\n if (!token || !/^\\d+$/.test(token)) {\n throw new ContactsValidationError(\n `derivationPath ${JSON.stringify(path)} segment ${JSON.stringify(segment)} ` +\n `is not numeric. Use plain integers, optionally suffixed with ' for hardened.`,\n );\n }\n const n = Number(token);\n if (!Number.isSafeInteger(n) || n >= 0x80000000) {\n throw new ContactsValidationError(\n `derivationPath ${JSON.stringify(path)} segment ${JSON.stringify(segment)} ` +\n `>= 2^31. Use the ' suffix for hardening rather than overflowing.`,\n );\n }\n }\n}\n\n// ---- chain id validation ---------------------------------------------------\n\n/**\n * Firmware encodes chain_id as uint64. JS `number` is fine up to 2^53; accept\n * `bigint` for the high range so callers don't silently truncate.\n */\nexport function validateChainId(value: number | bigint): void {\n const isNumber = typeof value === \"number\";\n const isBigInt = typeof value === \"bigint\";\n if (!isNumber && !isBigInt) {\n throw new ContactsValidationError(\n `chainId must be number or bigint, got ${typeof value}.`,\n );\n }\n if (isNumber && !Number.isInteger(value)) {\n throw new ContactsValidationError(\n `chainId must be an integer, got ${value}.`,\n );\n }\n const v = typeof value === \"bigint\" ? value : BigInt(value);\n if (v <= 0n) {\n throw new ContactsValidationError(\n `chainId must be positive, got ${value}.`,\n );\n }\n const UINT64_MAX = (1n << 64n) - 1n;\n if (v > UINT64_MAX) {\n throw new ContactsValidationError(\n `chainId ${value} exceeds uint64 range (max ${UINT64_MAX}).`,\n );\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["contactsValidation_exports", "__export", "CONTACT_NAME_BUFFER_LENGTH", "ContactsValidationError", "ETH_ADDRESS_BYTES", "GROUP_HANDLE_SIZE", "HMAC_PROOF_LENGTH", "MAX_BIP32_DEPTH", "SCOPE_BUFFER_LENGTH", "validateByteLength", "validateChainId", "validateDerivationPath", "validatePrintableLabel", "__toCommonJS", "message", "PRINTABLE_MIN", "PRINTABLE_MAX", "utf8Encoder", "value", "options", "field", "bufferLength", "encoded", "maxBytes", "badPositions", "i", "byte", "offendingHex", "a", "b", "expectedBytes", "path", "parts", "segments", "segment", "token", "n", "isNumber", "v", "UINT64_MAX"]
4
+ "sourcesContent": ["/**\n * Pre-APDU input validators for the Contacts operations.\n *\n * Buffer-length constants mirror the Ledger secure SDK `#define` values\n * *including* the trailing NUL terminator (so a 32-printable-char name lives in\n * a 33-byte buffer). Validators subtract 1 internally so the constants remain\n * pure equality checks against the upstream `#define`s. The byte-level\n * `0x20..0x7E` printable check exactly matches firmware `is_printable_string`.\n */\nimport { type DmkError } from \"@ledgerhq/device-management-kit\";\n\nimport { BLOCKCHAIN_FAMILY_BY_NAME } from \"@internal/app-binder/model/contactsConstants\";\n\n// ---- SDK-mirrored constants -------------------------------------------------\n// Source of truth: ledger-secure-sdk/app_features/address_book/include/\n\nexport const CONTACT_NAME_BUFFER_LENGTH = 33; // identity.h:49 (incl. NUL)\nexport const SCOPE_BUFFER_LENGTH = 33; // identity.h:50 (incl. NUL)\nexport const GROUP_HANDLE_SIZE = 64; // identity.h:47\nexport const HMAC_PROOF_LENGTH = 32; // CX_SHA256_SIZE\nexport const MAX_BIP32_DEPTH = 10; // bip32.h:15 (MAX_BIP32_PATH)\nexport const ETH_ADDRESS_BYTES = 20; // protocol convention, no header\nexport const SOLANA_ADDRESS_BYTES = 32; // ed25519 public key, no header\n\n// ---- error type -------------------------------------------------------------\n\n/**\n * Raised when caller input fails a pre-APDU check. Implements `DmkError` (and\n * stays an `Error` subclass) so a Contacts device action can surface it as a\n * typed terminal error state on the observable rather than throwing out of the\n * public, device-action-returning API.\n */\nexport class ContactsValidationError extends Error implements DmkError {\n readonly _tag = \"ContactsValidationError\";\n readonly originalError?: unknown;\n constructor(message: string) {\n super(message);\n this.name = \"ContactsValidationError\";\n }\n}\n\n// ---- printable-string validation -------------------------------------------\n\nconst PRINTABLE_MIN = 0x20;\nconst PRINTABLE_MAX = 0x7e;\n\nconst utf8Encoder = new TextEncoder();\n\n/**\n * Mirror of firmware `is_printable_string` + length cap. `bufferLength` is the\n * firmware's fixed buffer size *including* the trailing NUL, so the maximum\n * payload byte length is `bufferLength - 1`.\n */\nexport function validatePrintableLabel(\n value: string,\n options: { field: string; bufferLength: number },\n): void {\n const { field, bufferLength } = options;\n if (!value) {\n throw new ContactsValidationError(\n `${field} must not be empty (firmware rejects empty strings).`,\n );\n }\n const encoded = utf8Encoder.encode(value);\n const maxBytes = bufferLength - 1;\n if (encoded.length > maxBytes) {\n throw new ContactsValidationError(\n `${field} ${JSON.stringify(value)} is too long: ${encoded.length} bytes ` +\n `encoded (max ${maxBytes}). The device buffer is ${bufferLength} bytes ` +\n `including the trailing NUL.`,\n );\n }\n const badPositions: number[] = [];\n for (let i = 0; i < encoded.length; i++) {\n const byte = encoded[i]!;\n if (byte < PRINTABLE_MIN || byte > PRINTABLE_MAX) {\n badPositions.push(i);\n }\n }\n if (badPositions.length > 0) {\n const offendingBytes = Array.from(\n new Set(badPositions.map((i) => encoded[i]!)),\n ).sort((a, b) => a - b);\n const offendingHex = offendingBytes\n .map((b) => `0x${b.toString(16).padStart(2, \"0\")}`)\n .join(\", \");\n throw new ContactsValidationError(\n `${field} ${JSON.stringify(value)} contains ${badPositions.length} ` +\n `non-ASCII byte(s) at position(s) [${badPositions.join(\", \")}]: ` +\n `${offendingHex}. The device buffer is byte-level isprint() \u2014 only ` +\n `0x20-0x7E are accepted, no UTF-8 / accents / emoji.`,\n );\n }\n}\n\n// ---- byte-buffer validation ------------------------------------------------\n\n/** Assert a byte buffer is exactly `expectedBytes` long and non-empty. */\nexport function validateByteLength(\n value: Uint8Array,\n options: { field: string; expectedBytes: number },\n): void {\n const { field, expectedBytes } = options;\n if (value.length !== expectedBytes) {\n throw new ContactsValidationError(\n `${field} is ${value.length} bytes, expected ${expectedBytes}.`,\n );\n }\n}\n\n// ---- BIP32 path validation -------------------------------------------------\n\n/**\n * Sanity-check a BIP32 path before serialization. Firmware enforces depth <=\n * MAX_BIP32_DEPTH and rejects malformed segments. Accepts `m/44'/60'/0'/0/0`\n * style; segments may end in `'` (hardened).\n */\nexport function validateDerivationPath(path: string): void {\n if (!path) {\n throw new ContactsValidationError(\n `derivationPath must not be empty (e.g. \"m/44'/60'/0'/0/0\").`,\n );\n }\n const parts = path.split(\"/\");\n const segments =\n parts[0] === \"m\" || parts[0] === \"M\" ? parts.slice(1) : parts;\n if (segments.length === 0) {\n throw new ContactsValidationError(\n `derivationPath ${JSON.stringify(path)} has no segments past 'm'.`,\n );\n }\n if (segments.length > MAX_BIP32_DEPTH) {\n throw new ContactsValidationError(\n `derivationPath ${JSON.stringify(path)} has ${segments.length} segments ` +\n `(max ${MAX_BIP32_DEPTH}). Firmware rejects deeper paths.`,\n );\n }\n for (const segment of segments) {\n const token = segment.endsWith(\"'\") ? segment.slice(0, -1) : segment;\n if (!token || !/^\\d+$/.test(token)) {\n throw new ContactsValidationError(\n `derivationPath ${JSON.stringify(path)} segment ${JSON.stringify(segment)} ` +\n `is not numeric. Use plain integers, optionally suffixed with ' for hardened.`,\n );\n }\n const n = Number(token);\n if (!Number.isSafeInteger(n) || n >= 0x80000000) {\n throw new ContactsValidationError(\n `derivationPath ${JSON.stringify(path)} segment ${JSON.stringify(segment)} ` +\n `>= 2^31. Use the ' suffix for hardening rather than overflowing.`,\n );\n }\n }\n}\n\n// ---- chain id validation ---------------------------------------------------\n\n/**\n * Firmware encodes chain_id as uint64. JS `number` is fine up to 2^53; accept\n * `bigint` for the high range so callers don't silently truncate.\n */\nexport function validateChainId(value: number | bigint): void {\n const isNumber = typeof value === \"number\";\n const isBigInt = typeof value === \"bigint\";\n if (!isNumber && !isBigInt) {\n throw new ContactsValidationError(\n `chainId must be number or bigint, got ${typeof value}.`,\n );\n }\n if (isNumber && !Number.isInteger(value)) {\n throw new ContactsValidationError(\n `chainId must be an integer, got ${value}.`,\n );\n }\n const v = typeof value === \"bigint\" ? value : BigInt(value);\n if (v <= 0n) {\n throw new ContactsValidationError(\n `chainId must be positive, got ${value}.`,\n );\n }\n const UINT64_MAX = (1n << 64n) - 1n;\n if (v > UINT64_MAX) {\n throw new ContactsValidationError(\n `chainId ${value} exceeds uint64 range (max ${UINT64_MAX}).`,\n );\n }\n}\n\n// ---- blockchain family validation ------------------------------------------\n\n/** An address identifier to check, named after its input field. */\ntype IdentifierField = {\n readonly field: string;\n readonly value: Uint8Array;\n};\n\n/**\n * Check a blockchain family, its address identifiers and its chain id:\n * - Ethereum: 20-byte addresses, and CHAIN_ID is mandatory (multiple networks\n * share the same address format).\n * - Solana: 32-byte public keys, and no CHAIN_ID (the firmware specification\n * only defines one for Ethereum).\n * - Any other known family: non-empty identifiers.\n *\n * A chain id, when present, is range-checked. Returns the family byte encoded\n * in the `BLOCKCHAIN_FAMILY` TLV.\n */\nexport function validateFamilyIdentifiers(options: {\n blockchainFamily: string;\n identifiers: readonly IdentifierField[];\n chainId?: bigint;\n}): number {\n const { blockchainFamily, identifiers, chainId } = options;\n const family = blockchainFamily.toLowerCase();\n const familyByte = BLOCKCHAIN_FAMILY_BY_NAME[family];\n if (familyByte === undefined) {\n throw new ContactsValidationError(\n `Unsupported blockchain family: ${blockchainFamily}`,\n );\n }\n\n if (family === \"ethereum\") {\n for (const { field, value } of identifiers) {\n validateByteLength(value, { field, expectedBytes: ETH_ADDRESS_BYTES });\n }\n if (chainId === undefined) {\n throw new ContactsValidationError(\n \"chainId is required for the Ethereum blockchain family.\",\n );\n }\n } else if (family === \"solana\") {\n for (const { field, value } of identifiers) {\n validateByteLength(value, { field, expectedBytes: SOLANA_ADDRESS_BYTES });\n }\n if (chainId !== undefined) {\n throw new ContactsValidationError(\n \"chainId is not allowed for the Solana blockchain family.\",\n );\n }\n } else {\n for (const { field, value } of identifiers) {\n if (value.length === 0) {\n throw new ContactsValidationError(`${field} must not be empty.`);\n }\n }\n }\n\n if (chainId !== undefined) {\n validateChainId(chainId);\n }\n\n return familyByte;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["contactsValidation_exports", "__export", "CONTACT_NAME_BUFFER_LENGTH", "ContactsValidationError", "ETH_ADDRESS_BYTES", "GROUP_HANDLE_SIZE", "HMAC_PROOF_LENGTH", "MAX_BIP32_DEPTH", "SCOPE_BUFFER_LENGTH", "SOLANA_ADDRESS_BYTES", "validateByteLength", "validateChainId", "validateDerivationPath", "validateFamilyIdentifiers", "validatePrintableLabel", "__toCommonJS", "import_contactsConstants", "message", "PRINTABLE_MIN", "PRINTABLE_MAX", "utf8Encoder", "value", "options", "field", "bufferLength", "encoded", "maxBytes", "badPositions", "i", "byte", "offendingHex", "a", "b", "expectedBytes", "path", "parts", "segments", "segment", "token", "n", "isNumber", "v", "UINT64_MAX", "blockchainFamily", "identifiers", "chainId", "family", "familyByte"]
7
7
  }
@@ -1,2 +1,2 @@
1
- "use strict";var e=require("./contactsValidation");const i="44'/60'/0'/0/0";describe("contactsValidation",()=>{describe("validatePrintableLabel",()=>{const t={field:"name",bufferLength:e.CONTACT_NAME_BUFFER_LENGTH};it("accepts a printable ASCII label within the buffer",()=>{expect(()=>(0,e.validatePrintableLabel)("Alice",t)).not.toThrow()}),it("rejects an empty label",()=>{expect(()=>(0,e.validatePrintableLabel)("",t)).toThrow(e.ContactsValidationError)}),it("rejects a label exceeding bufferLength - 1 bytes",()=>{expect(()=>(0,e.validatePrintableLabel)("x".repeat(e.CONTACT_NAME_BUFFER_LENGTH),t)).toThrow(e.ContactsValidationError)}),it("rejects non-ASCII / accented characters (byte-level isprint)",()=>{expect(()=>(0,e.validatePrintableLabel)("Am\xE9lie",t)).toThrow(e.ContactsValidationError)})}),describe("validateByteLength",()=>{it("accepts an exact-length buffer",()=>{expect(()=>(0,e.validateByteLength)(new Uint8Array(20),{field:"identifier",expectedBytes:20})).not.toThrow()}),it("rejects a wrong-length buffer",()=>{expect(()=>(0,e.validateByteLength)(new Uint8Array(19),{field:"identifier",expectedBytes:20})).toThrow(e.ContactsValidationError)})}),describe("validateChainId",()=>{it("accepts a positive integer and bigint",()=>{expect(()=>(0,e.validateChainId)(1)).not.toThrow(),expect(()=>(0,e.validateChainId)(56n)).not.toThrow()}),it("rejects zero, negative, and non-integer",()=>{expect(()=>(0,e.validateChainId)(0)).toThrow(e.ContactsValidationError),expect(()=>(0,e.validateChainId)(-1)).toThrow(e.ContactsValidationError),expect(()=>(0,e.validateChainId)(1.5)).toThrow(e.ContactsValidationError)})}),describe("validateDerivationPath",()=>{it("accepts a representative BIP32 path",()=>{expect(()=>(0,e.validateDerivationPath)(i)).not.toThrow()}),it("accepts m-prefixed and hardened paths",()=>{expect(()=>(0,e.validateDerivationPath)("m/44'/60'/0'/0/0")).not.toThrow()}),it("rejects a non-numeric segment",()=>{expect(()=>(0,e.validateDerivationPath)("44'/x/0")).toThrow(e.ContactsValidationError)})})});
1
+ "use strict";var e=require("./contactsValidation");const n="44'/60'/0'/0/0";describe("contactsValidation",()=>{describe("validatePrintableLabel",()=>{const t={field:"name",bufferLength:e.CONTACT_NAME_BUFFER_LENGTH};it("accepts a printable ASCII label within the buffer",()=>{expect(()=>(0,e.validatePrintableLabel)("Alice",t)).not.toThrow()}),it("rejects an empty label",()=>{expect(()=>(0,e.validatePrintableLabel)("",t)).toThrow(e.ContactsValidationError)}),it("rejects a label exceeding bufferLength - 1 bytes",()=>{expect(()=>(0,e.validatePrintableLabel)("x".repeat(e.CONTACT_NAME_BUFFER_LENGTH),t)).toThrow(e.ContactsValidationError)}),it("rejects non-ASCII / accented characters (byte-level isprint)",()=>{expect(()=>(0,e.validatePrintableLabel)("Am\xE9lie",t)).toThrow(e.ContactsValidationError)})}),describe("validateByteLength",()=>{it("accepts an exact-length buffer",()=>{expect(()=>(0,e.validateByteLength)(new Uint8Array(20),{field:"identifier",expectedBytes:20})).not.toThrow()}),it("rejects a wrong-length buffer",()=>{expect(()=>(0,e.validateByteLength)(new Uint8Array(19),{field:"identifier",expectedBytes:20})).toThrow(e.ContactsValidationError)})}),describe("validateChainId",()=>{it("accepts a positive integer and bigint",()=>{expect(()=>(0,e.validateChainId)(1)).not.toThrow(),expect(()=>(0,e.validateChainId)(56n)).not.toThrow()}),it("rejects zero, negative, and non-integer",()=>{expect(()=>(0,e.validateChainId)(0)).toThrow(e.ContactsValidationError),expect(()=>(0,e.validateChainId)(-1)).toThrow(e.ContactsValidationError),expect(()=>(0,e.validateChainId)(1.5)).toThrow(e.ContactsValidationError)})}),describe("validateDerivationPath",()=>{it("accepts a representative BIP32 path",()=>{expect(()=>(0,e.validateDerivationPath)(n)).not.toThrow()}),it("accepts m-prefixed and hardened paths",()=>{expect(()=>(0,e.validateDerivationPath)("m/44'/60'/0'/0/0")).not.toThrow()}),it("rejects a non-numeric segment",()=>{expect(()=>(0,e.validateDerivationPath)("44'/x/0")).toThrow(e.ContactsValidationError)})}),describe("validateFamilyIdentifiers",()=>{const t=i=>[{field:"identifier",value:new Uint8Array(i).fill(17)}];it("returns the BLOCKCHAIN_FAMILY byte, case-insensitively",()=>{expect((0,e.validateFamilyIdentifiers)({blockchainFamily:"Ethereum",identifiers:t(20),chainId:1n})).toBe(1),expect((0,e.validateFamilyIdentifiers)({blockchainFamily:"solana",identifiers:t(32)})).toBe(2),expect((0,e.validateFamilyIdentifiers)({blockchainFamily:"tron",identifiers:t(21)})).toBe(6)}),it("rejects an unknown family",()=>{expect(()=>(0,e.validateFamilyIdentifiers)({blockchainFamily:"dogecoin",identifiers:t(20)})).toThrow("Unsupported blockchain family: dogecoin")}),it("requires 20-byte identifiers and a chainId for Ethereum",()=>{expect(()=>(0,e.validateFamilyIdentifiers)({blockchainFamily:"ethereum",identifiers:t(32),chainId:1n})).toThrow("identifier is 32 bytes, expected 20."),expect(()=>(0,e.validateFamilyIdentifiers)({blockchainFamily:"ethereum",identifiers:t(20)})).toThrow("chainId is required for the Ethereum blockchain family.")}),it("requires 32-byte identifiers and no chainId for Solana",()=>{expect(()=>(0,e.validateFamilyIdentifiers)({blockchainFamily:"solana",identifiers:t(20)})).toThrow("identifier is 20 bytes, expected 32."),expect(()=>(0,e.validateFamilyIdentifiers)({blockchainFamily:"solana",identifiers:t(32),chainId:101n})).toThrow("chainId is not allowed for the Solana blockchain family.")}),it("only requires non-empty identifiers for other families",()=>{expect(()=>(0,e.validateFamilyIdentifiers)({blockchainFamily:"tron",identifiers:t(0)})).toThrow("identifier must not be empty.")}),it("range-checks a chainId",()=>{expect(()=>(0,e.validateFamilyIdentifiers)({blockchainFamily:"ethereum",identifiers:t(20),chainId:0n})).toThrow(e.ContactsValidationError)})})});
2
2
  //# sourceMappingURL=contactsValidation.test.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/model/contactsValidation.test.ts"],
4
- "sourcesContent": ["import {\n CONTACT_NAME_BUFFER_LENGTH,\n ContactsValidationError,\n validateByteLength,\n validateChainId,\n validateDerivationPath,\n validatePrintableLabel,\n} from \"./contactsValidation\";\n\n// A representative BIP32 path (used by Ledger-Account ops, not external\n// addresses). Kept here to exercise the shared validator.\nconst SAMPLE_DERIVATION_PATH = \"44'/60'/0'/0/0\";\n\ndescribe(\"contactsValidation\", () => {\n describe(\"validatePrintableLabel\", () => {\n const opts = { field: \"name\", bufferLength: CONTACT_NAME_BUFFER_LENGTH };\n\n it(\"accepts a printable ASCII label within the buffer\", () => {\n expect(() => validatePrintableLabel(\"Alice\", opts)).not.toThrow();\n });\n\n it(\"rejects an empty label\", () => {\n expect(() => validatePrintableLabel(\"\", opts)).toThrow(\n ContactsValidationError,\n );\n });\n\n it(\"rejects a label exceeding bufferLength - 1 bytes\", () => {\n expect(() =>\n validatePrintableLabel(\"x\".repeat(CONTACT_NAME_BUFFER_LENGTH), opts),\n ).toThrow(ContactsValidationError);\n });\n\n it(\"rejects non-ASCII / accented characters (byte-level isprint)\", () => {\n expect(() => validatePrintableLabel(\"Am\u00E9lie\", opts)).toThrow(\n ContactsValidationError,\n );\n });\n });\n\n describe(\"validateByteLength\", () => {\n it(\"accepts an exact-length buffer\", () => {\n expect(() =>\n validateByteLength(new Uint8Array(20), {\n field: \"identifier\",\n expectedBytes: 20,\n }),\n ).not.toThrow();\n });\n\n it(\"rejects a wrong-length buffer\", () => {\n expect(() =>\n validateByteLength(new Uint8Array(19), {\n field: \"identifier\",\n expectedBytes: 20,\n }),\n ).toThrow(ContactsValidationError);\n });\n });\n\n describe(\"validateChainId\", () => {\n it(\"accepts a positive integer and bigint\", () => {\n expect(() => validateChainId(1)).not.toThrow();\n expect(() => validateChainId(56n)).not.toThrow();\n });\n\n it(\"rejects zero, negative, and non-integer\", () => {\n expect(() => validateChainId(0)).toThrow(ContactsValidationError);\n expect(() => validateChainId(-1)).toThrow(ContactsValidationError);\n expect(() => validateChainId(1.5)).toThrow(ContactsValidationError);\n });\n });\n\n describe(\"validateDerivationPath\", () => {\n it(\"accepts a representative BIP32 path\", () => {\n expect(() =>\n validateDerivationPath(SAMPLE_DERIVATION_PATH),\n ).not.toThrow();\n });\n\n it(\"accepts m-prefixed and hardened paths\", () => {\n expect(() => validateDerivationPath(\"m/44'/60'/0'/0/0\")).not.toThrow();\n });\n\n it(\"rejects a non-numeric segment\", () => {\n expect(() => validateDerivationPath(\"44'/x/0\")).toThrow(\n ContactsValidationError,\n );\n });\n });\n});\n"],
5
- "mappings": "aAAA,IAAAA,EAOO,gCAIP,MAAMC,EAAyB,iBAE/B,SAAS,qBAAsB,IAAM,CACnC,SAAS,yBAA0B,IAAM,CACvC,MAAMC,EAAO,CAAE,MAAO,OAAQ,aAAc,4BAA2B,EAEvE,GAAG,oDAAqD,IAAM,CAC5D,OAAO,OAAM,0BAAuB,QAASA,CAAI,CAAC,EAAE,IAAI,QAAQ,CAClE,CAAC,EAED,GAAG,yBAA0B,IAAM,CACjC,OAAO,OAAM,0BAAuB,GAAIA,CAAI,CAAC,EAAE,QAC7C,yBACF,CACF,CAAC,EAED,GAAG,mDAAoD,IAAM,CAC3D,OAAO,OACL,0BAAuB,IAAI,OAAO,4BAA0B,EAAGA,CAAI,CACrE,EAAE,QAAQ,yBAAuB,CACnC,CAAC,EAED,GAAG,+DAAgE,IAAM,CACvE,OAAO,OAAM,0BAAuB,YAAUA,CAAI,CAAC,EAAE,QACnD,yBACF,CACF,CAAC,CACH,CAAC,EAED,SAAS,qBAAsB,IAAM,CACnC,GAAG,iCAAkC,IAAM,CACzC,OAAO,OACL,sBAAmB,IAAI,WAAW,EAAE,EAAG,CACrC,MAAO,aACP,cAAe,EACjB,CAAC,CACH,EAAE,IAAI,QAAQ,CAChB,CAAC,EAED,GAAG,gCAAiC,IAAM,CACxC,OAAO,OACL,sBAAmB,IAAI,WAAW,EAAE,EAAG,CACrC,MAAO,aACP,cAAe,EACjB,CAAC,CACH,EAAE,QAAQ,yBAAuB,CACnC,CAAC,CACH,CAAC,EAED,SAAS,kBAAmB,IAAM,CAChC,GAAG,wCAAyC,IAAM,CAChD,OAAO,OAAM,mBAAgB,CAAC,CAAC,EAAE,IAAI,QAAQ,EAC7C,OAAO,OAAM,mBAAgB,GAAG,CAAC,EAAE,IAAI,QAAQ,CACjD,CAAC,EAED,GAAG,0CAA2C,IAAM,CAClD,OAAO,OAAM,mBAAgB,CAAC,CAAC,EAAE,QAAQ,yBAAuB,EAChE,OAAO,OAAM,mBAAgB,EAAE,CAAC,EAAE,QAAQ,yBAAuB,EACjE,OAAO,OAAM,mBAAgB,GAAG,CAAC,EAAE,QAAQ,yBAAuB,CACpE,CAAC,CACH,CAAC,EAED,SAAS,yBAA0B,IAAM,CACvC,GAAG,sCAAuC,IAAM,CAC9C,OAAO,OACL,0BAAuBD,CAAsB,CAC/C,EAAE,IAAI,QAAQ,CAChB,CAAC,EAED,GAAG,wCAAyC,IAAM,CAChD,OAAO,OAAM,0BAAuB,kBAAkB,CAAC,EAAE,IAAI,QAAQ,CACvE,CAAC,EAED,GAAG,gCAAiC,IAAM,CACxC,OAAO,OAAM,0BAAuB,SAAS,CAAC,EAAE,QAC9C,yBACF,CACF,CAAC,CACH,CAAC,CACH,CAAC",
6
- "names": ["import_contactsValidation", "SAMPLE_DERIVATION_PATH", "opts"]
4
+ "sourcesContent": ["import {\n CONTACT_NAME_BUFFER_LENGTH,\n ContactsValidationError,\n validateByteLength,\n validateChainId,\n validateDerivationPath,\n validateFamilyIdentifiers,\n validatePrintableLabel,\n} from \"./contactsValidation\";\n\n// A representative BIP32 path (used by Ledger-Account ops, not external\n// addresses). Kept here to exercise the shared validator.\nconst SAMPLE_DERIVATION_PATH = \"44'/60'/0'/0/0\";\n\ndescribe(\"contactsValidation\", () => {\n describe(\"validatePrintableLabel\", () => {\n const opts = { field: \"name\", bufferLength: CONTACT_NAME_BUFFER_LENGTH };\n\n it(\"accepts a printable ASCII label within the buffer\", () => {\n expect(() => validatePrintableLabel(\"Alice\", opts)).not.toThrow();\n });\n\n it(\"rejects an empty label\", () => {\n expect(() => validatePrintableLabel(\"\", opts)).toThrow(\n ContactsValidationError,\n );\n });\n\n it(\"rejects a label exceeding bufferLength - 1 bytes\", () => {\n expect(() =>\n validatePrintableLabel(\"x\".repeat(CONTACT_NAME_BUFFER_LENGTH), opts),\n ).toThrow(ContactsValidationError);\n });\n\n it(\"rejects non-ASCII / accented characters (byte-level isprint)\", () => {\n expect(() => validatePrintableLabel(\"Am\u00E9lie\", opts)).toThrow(\n ContactsValidationError,\n );\n });\n });\n\n describe(\"validateByteLength\", () => {\n it(\"accepts an exact-length buffer\", () => {\n expect(() =>\n validateByteLength(new Uint8Array(20), {\n field: \"identifier\",\n expectedBytes: 20,\n }),\n ).not.toThrow();\n });\n\n it(\"rejects a wrong-length buffer\", () => {\n expect(() =>\n validateByteLength(new Uint8Array(19), {\n field: \"identifier\",\n expectedBytes: 20,\n }),\n ).toThrow(ContactsValidationError);\n });\n });\n\n describe(\"validateChainId\", () => {\n it(\"accepts a positive integer and bigint\", () => {\n expect(() => validateChainId(1)).not.toThrow();\n expect(() => validateChainId(56n)).not.toThrow();\n });\n\n it(\"rejects zero, negative, and non-integer\", () => {\n expect(() => validateChainId(0)).toThrow(ContactsValidationError);\n expect(() => validateChainId(-1)).toThrow(ContactsValidationError);\n expect(() => validateChainId(1.5)).toThrow(ContactsValidationError);\n });\n });\n\n describe(\"validateDerivationPath\", () => {\n it(\"accepts a representative BIP32 path\", () => {\n expect(() =>\n validateDerivationPath(SAMPLE_DERIVATION_PATH),\n ).not.toThrow();\n });\n\n it(\"accepts m-prefixed and hardened paths\", () => {\n expect(() => validateDerivationPath(\"m/44'/60'/0'/0/0\")).not.toThrow();\n });\n\n it(\"rejects a non-numeric segment\", () => {\n expect(() => validateDerivationPath(\"44'/x/0\")).toThrow(\n ContactsValidationError,\n );\n });\n });\n describe(\"validateFamilyIdentifiers\", () => {\n const identifier = (length: number) => [\n { field: \"identifier\", value: new Uint8Array(length).fill(0x11) },\n ];\n\n it(\"returns the BLOCKCHAIN_FAMILY byte, case-insensitively\", () => {\n expect(\n validateFamilyIdentifiers({\n blockchainFamily: \"Ethereum\",\n identifiers: identifier(20),\n chainId: 1n,\n }),\n ).toBe(0x01);\n expect(\n validateFamilyIdentifiers({\n blockchainFamily: \"solana\",\n identifiers: identifier(32),\n }),\n ).toBe(0x02);\n expect(\n validateFamilyIdentifiers({\n blockchainFamily: \"tron\",\n identifiers: identifier(21),\n }),\n ).toBe(0x06);\n });\n\n it(\"rejects an unknown family\", () => {\n expect(() =>\n validateFamilyIdentifiers({\n blockchainFamily: \"dogecoin\",\n identifiers: identifier(20),\n }),\n ).toThrow(\"Unsupported blockchain family: dogecoin\");\n });\n\n it(\"requires 20-byte identifiers and a chainId for Ethereum\", () => {\n expect(() =>\n validateFamilyIdentifiers({\n blockchainFamily: \"ethereum\",\n identifiers: identifier(32),\n chainId: 1n,\n }),\n ).toThrow(\"identifier is 32 bytes, expected 20.\");\n expect(() =>\n validateFamilyIdentifiers({\n blockchainFamily: \"ethereum\",\n identifiers: identifier(20),\n }),\n ).toThrow(\"chainId is required for the Ethereum blockchain family.\");\n });\n\n it(\"requires 32-byte identifiers and no chainId for Solana\", () => {\n expect(() =>\n validateFamilyIdentifiers({\n blockchainFamily: \"solana\",\n identifiers: identifier(20),\n }),\n ).toThrow(\"identifier is 20 bytes, expected 32.\");\n expect(() =>\n validateFamilyIdentifiers({\n blockchainFamily: \"solana\",\n identifiers: identifier(32),\n chainId: 101n,\n }),\n ).toThrow(\"chainId is not allowed for the Solana blockchain family.\");\n });\n\n it(\"only requires non-empty identifiers for other families\", () => {\n expect(() =>\n validateFamilyIdentifiers({\n blockchainFamily: \"tron\",\n identifiers: identifier(0),\n }),\n ).toThrow(\"identifier must not be empty.\");\n });\n\n it(\"range-checks a chainId\", () => {\n expect(() =>\n validateFamilyIdentifiers({\n blockchainFamily: \"ethereum\",\n identifiers: identifier(20),\n chainId: 0n,\n }),\n ).toThrow(ContactsValidationError);\n });\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": ["import_contactsValidation", "SAMPLE_DERIVATION_PATH", "opts", "identifier", "length"]
7
7
  }
@@ -1,2 +1,2 @@
1
- "use strict";var C=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var s=Object.prototype.hasOwnProperty;var A=(e,a)=>{for(var r in a)C(e,r,{get:a[r],enumerable:!0})},P=(e,a,r,n)=>{if(a&&typeof a=="object"||typeof a=="function")for(let t of T(a))!s.call(e,t)&&t!==r&&C(e,t,{get:()=>a[t],enumerable:!(n=l(a,t))||n.enumerable});return e};var y=e=>P(C({},"__esModule",{value:!0}),e);var f={};A(f,{buildProvideContactPayload:()=>_,sendProvideContactPayload:()=>I});module.exports=y(f);var i=require("@ledgerhq/device-management-kit"),c=require("../../app-binder/command/ProvideContactCommand"),d=require("../../app-binder/model/contactsConstants"),o=require("../../app-binder/services/contactsTlvSerializer"),m=require("../../app-binder/services/sendFramedContactsPayload");function _(e){const a=d.BLOCKCHAIN_FAMILY_BY_NAME[e.blockchainFamily.toLowerCase()];if(a===void 0)throw new Error(`Unsupported blockchain family: ${e.blockchainFamily}`);const r=new i.ByteArrayBuilder;return(0,o.encodeTlvUInt8)(r,o.CONTACTS_TLV_TAG.STRUCT_TYPE,o.STRUCT_TYPE_PROVIDE_CONTACT),(0,o.encodeTlvUInt8)(r,o.CONTACTS_TLV_TAG.STRUCT_VERSION,o.STRUCT_VERSION_VALUE),(0,o.encodeTlvAscii)(r,o.CONTACTS_TLV_TAG.CONTACT_NAME,e.contactName),(0,o.encodeTlvAscii)(r,o.CONTACTS_TLV_TAG.SCOPE,e.scope),(0,o.encodeTlvBuffer)(r,o.CONTACTS_TLV_TAG.ACCOUNT_IDENTIFIER,e.identifier),(0,o.encodeTlvBuffer)(r,o.CONTACTS_TLV_TAG.GROUP_HANDLE,e.groupHandle),e.chainId!==void 0&&(0,o.encodeTlvChainId)(r,o.CONTACTS_TLV_TAG.CHAIN_ID,e.chainId),(0,o.encodeTlvUInt8)(r,o.CONTACTS_TLV_TAG.BLOCKCHAIN_FAMILY,a),(0,o.encodeTlvBuffer)(r,o.CONTACTS_TLV_TAG.HMAC_PROOF,e.hmacProof),(0,o.encodeTlvBuffer)(r,o.CONTACTS_TLV_TAG.HMAC_REST,e.hmacRest),r.build()}function I(e,{payload:a,logger:r}){return(0,m.sendFramedContactsPayload)(e,{payload:a,p1:d.SUB_CMD_PROVIDE_CONTACT,makeCommand:(n,t)=>new c.ProvideContactCommand({data:n,p2:t}),logger:r,commandTag:"provideContact"})}0&&(module.exports={buildProvideContactPayload,sendProvideContactPayload});
1
+ "use strict";var i=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var s=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var f=(e,a)=>{for(var r in a)i(e,r,{get:a[r],enumerable:!0})},y=(e,a,r,d)=>{if(a&&typeof a=="object"||typeof a=="function")for(let t of s(a))!P.call(e,t)&&t!==r&&i(e,t,{get:()=>a[t],enumerable:!(d=T(a,t))||d.enumerable});return e};var A=e=>y(i({},"__esModule",{value:!0}),e);var v={};f(v,{buildProvideContactPayload:()=>I,sendProvideContactPayload:()=>_});module.exports=A(v);var n=require("@ledgerhq/device-management-kit"),C=require("../../app-binder/command/ProvideContactCommand"),m=require("../../app-binder/model/contactsConstants"),c=require("../../app-binder/model/contactsValidation"),o=require("../../app-binder/services/contactsTlvSerializer"),l=require("../../app-binder/services/sendFramedContactsPayload");function I(e){const a=(0,c.validateFamilyIdentifiers)({blockchainFamily:e.blockchainFamily,identifiers:[{field:"identifier",value:e.identifier}],chainId:e.chainId}),r=new n.ByteArrayBuilder;return(0,o.encodeTlvUInt8)(r,o.CONTACTS_TLV_TAG.STRUCT_TYPE,o.STRUCT_TYPE_PROVIDE_CONTACT),(0,o.encodeTlvUInt8)(r,o.CONTACTS_TLV_TAG.STRUCT_VERSION,o.STRUCT_VERSION_VALUE),(0,o.encodeTlvAscii)(r,o.CONTACTS_TLV_TAG.CONTACT_NAME,e.contactName),(0,o.encodeTlvAscii)(r,o.CONTACTS_TLV_TAG.SCOPE,e.scope),(0,o.encodeTlvBuffer)(r,o.CONTACTS_TLV_TAG.ACCOUNT_IDENTIFIER,e.identifier),(0,o.encodeTlvBuffer)(r,o.CONTACTS_TLV_TAG.GROUP_HANDLE,e.groupHandle),e.chainId!==void 0&&(0,o.encodeTlvChainId)(r,o.CONTACTS_TLV_TAG.CHAIN_ID,e.chainId),(0,o.encodeTlvUInt8)(r,o.CONTACTS_TLV_TAG.BLOCKCHAIN_FAMILY,a),(0,o.encodeTlvBuffer)(r,o.CONTACTS_TLV_TAG.HMAC_PROOF,e.hmacProof),(0,o.encodeTlvBuffer)(r,o.CONTACTS_TLV_TAG.HMAC_REST,e.hmacRest),r.build()}function _(e,{payload:a,logger:r}){return(0,l.sendFramedContactsPayload)(e,{payload:a,p1:m.SUB_CMD_PROVIDE_CONTACT,makeCommand:(d,t)=>new C.ProvideContactCommand({data:d,p2:t}),logger:r,commandTag:"provideContact"})}0&&(module.exports={buildProvideContactPayload,sendProvideContactPayload});
2
2
  //# sourceMappingURL=provideContact.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/services/provideContact.ts"],
4
- "sourcesContent": ["// TLV assembly and transport for op 0x20 (Provide Contact), dispatched via the\n// chunked-framing scheme shared with the other address-book ops.\n//\n// Reference: Address Book Final Specifications \u2014 Provide Contact. Tag order:\n// STRUCT_TYPE, STRUCT_VERSION, CONTACT_NAME, SCOPE, ACCOUNT_IDENTIFIER,\n// GROUP_HANDLE, CHAIN_ID (Ethereum only), BLOCKCHAIN_FAMILY, HMAC_PROOF,\n// HMAC_REST. No DERIVATION_PATH \u2014 that tag is Ledger-Account only.\n//\n// Device replies SW=0x9000 with empty data on success \u2014 no fields to extract.\nimport {\n ByteArrayBuilder,\n type CommandResult,\n type InternalApi,\n type LoggerPublisherService,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { type ProvideContactInput } from \"@api/model/ProvideContact\";\nimport { ProvideContactCommand } from \"@internal/app-binder/command/ProvideContactCommand\";\nimport {\n BLOCKCHAIN_FAMILY_BY_NAME,\n SUB_CMD_PROVIDE_CONTACT,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport { type ContactsErrorCodes } from \"@internal/app-binder/model/contactsErrors\";\nimport {\n CONTACTS_TLV_TAG,\n encodeTlvAscii,\n encodeTlvBuffer,\n encodeTlvChainId,\n encodeTlvUInt8,\n STRUCT_TYPE_PROVIDE_CONTACT,\n STRUCT_VERSION_VALUE,\n} from \"@internal/app-binder/services/contactsTlvSerializer\";\nimport { sendFramedContactsPayload } from \"@internal/app-binder/services/sendFramedContactsPayload\";\n\n/**\n * Encode a matched contact as the PROVIDE CONTACT TLV payload, without the\n * chunk framing. Pure, so callers can build it while matching a recipient\n * against the address book, with no device involved.\n */\nexport function buildProvideContactPayload(\n input: ProvideContactInput,\n): Uint8Array {\n const family =\n BLOCKCHAIN_FAMILY_BY_NAME[input.blockchainFamily.toLowerCase()];\n if (family === undefined) {\n throw new Error(`Unsupported blockchain family: ${input.blockchainFamily}`);\n }\n\n const builder = new ByteArrayBuilder();\n encodeTlvUInt8(\n builder,\n CONTACTS_TLV_TAG.STRUCT_TYPE,\n STRUCT_TYPE_PROVIDE_CONTACT,\n );\n encodeTlvUInt8(\n builder,\n CONTACTS_TLV_TAG.STRUCT_VERSION,\n STRUCT_VERSION_VALUE,\n );\n encodeTlvAscii(builder, CONTACTS_TLV_TAG.CONTACT_NAME, input.contactName);\n encodeTlvAscii(builder, CONTACTS_TLV_TAG.SCOPE, input.scope);\n encodeTlvBuffer(\n builder,\n CONTACTS_TLV_TAG.ACCOUNT_IDENTIFIER,\n input.identifier,\n );\n encodeTlvBuffer(builder, CONTACTS_TLV_TAG.GROUP_HANDLE, input.groupHandle);\n if (input.chainId !== undefined) {\n encodeTlvChainId(builder, CONTACTS_TLV_TAG.CHAIN_ID, input.chainId);\n }\n encodeTlvUInt8(builder, CONTACTS_TLV_TAG.BLOCKCHAIN_FAMILY, family);\n encodeTlvBuffer(builder, CONTACTS_TLV_TAG.HMAC_PROOF, input.hmacProof);\n encodeTlvBuffer(builder, CONTACTS_TLV_TAG.HMAC_REST, input.hmacRest);\n\n return builder.build();\n}\n\nexport type SendProvideContactPayloadArgs = {\n readonly payload: Uint8Array;\n readonly logger?: LoggerPublisherService;\n};\n\nexport function sendProvideContactPayload(\n api: InternalApi,\n { payload, logger }: SendProvideContactPayloadArgs,\n): Promise<CommandResult<void, ContactsErrorCodes>> {\n return sendFramedContactsPayload(api, {\n payload,\n p1: SUB_CMD_PROVIDE_CONTACT,\n makeCommand: (chunk, p2) => new ProvideContactCommand({ data: chunk, p2 }),\n logger,\n commandTag: \"provideContact\",\n }) as Promise<CommandResult<void, ContactsErrorCodes>>;\n}\n"],
5
- "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,gCAAAE,EAAA,8BAAAC,IAAA,eAAAC,EAAAJ,GASA,IAAAK,EAKO,2CAGPC,EAAsC,8DACtCC,EAGO,wDAEPC,EAQO,+DACPC,EAA0C,mEAOnC,SAASP,EACdQ,EACY,CACZ,MAAMC,EACJ,4BAA0BD,EAAM,iBAAiB,YAAY,CAAC,EAChE,GAAIC,IAAW,OACb,MAAM,IAAI,MAAM,kCAAkCD,EAAM,gBAAgB,EAAE,EAG5E,MAAME,EAAU,IAAI,mBACpB,2BACEA,EACA,mBAAiB,YACjB,6BACF,KACA,kBACEA,EACA,mBAAiB,eACjB,sBACF,KACA,kBAAeA,EAAS,mBAAiB,aAAcF,EAAM,WAAW,KACxE,kBAAeE,EAAS,mBAAiB,MAAOF,EAAM,KAAK,KAC3D,mBACEE,EACA,mBAAiB,mBACjBF,EAAM,UACR,KACA,mBAAgBE,EAAS,mBAAiB,aAAcF,EAAM,WAAW,EACrEA,EAAM,UAAY,WACpB,oBAAiBE,EAAS,mBAAiB,SAAUF,EAAM,OAAO,KAEpE,kBAAeE,EAAS,mBAAiB,kBAAmBD,CAAM,KAClE,mBAAgBC,EAAS,mBAAiB,WAAYF,EAAM,SAAS,KACrE,mBAAgBE,EAAS,mBAAiB,UAAWF,EAAM,QAAQ,EAE5DE,EAAQ,MAAM,CACvB,CAOO,SAAST,EACdU,EACA,CAAE,QAAAC,EAAS,OAAAC,CAAO,EACgC,CAClD,SAAO,6BAA0BF,EAAK,CACpC,QAAAC,EACA,GAAI,0BACJ,YAAa,CAACE,EAAOC,IAAO,IAAI,wBAAsB,CAAE,KAAMD,EAAO,GAAAC,CAAG,CAAC,EACzE,OAAAF,EACA,WAAY,gBACd,CAAC,CACH",
6
- "names": ["provideContact_exports", "__export", "buildProvideContactPayload", "sendProvideContactPayload", "__toCommonJS", "import_device_management_kit", "import_ProvideContactCommand", "import_contactsConstants", "import_contactsTlvSerializer", "import_sendFramedContactsPayload", "input", "family", "builder", "api", "payload", "logger", "chunk", "p2"]
4
+ "sourcesContent": ["// TLV assembly and transport for op 0x20 (Provide Contact), dispatched via the\n// chunked-framing scheme shared with the other address-book ops.\n//\n// Reference: Address Book Final Specifications \u2014 Provide Contact. Tag order:\n// STRUCT_TYPE, STRUCT_VERSION, CONTACT_NAME, SCOPE, ACCOUNT_IDENTIFIER,\n// GROUP_HANDLE, CHAIN_ID (Ethereum only), BLOCKCHAIN_FAMILY, HMAC_PROOF,\n// HMAC_REST. No DERIVATION_PATH \u2014 that tag is Ledger-Account only.\n//\n// Device replies SW=0x9000 with empty data on success \u2014 no fields to extract.\nimport {\n ByteArrayBuilder,\n type CommandResult,\n type InternalApi,\n type LoggerPublisherService,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { type ProvideContactInput } from \"@api/model/ProvideContact\";\nimport { ProvideContactCommand } from \"@internal/app-binder/command/ProvideContactCommand\";\nimport { SUB_CMD_PROVIDE_CONTACT } from \"@internal/app-binder/model/contactsConstants\";\nimport { type ContactsErrorCodes } from \"@internal/app-binder/model/contactsErrors\";\nimport { validateFamilyIdentifiers } from \"@internal/app-binder/model/contactsValidation\";\nimport {\n CONTACTS_TLV_TAG,\n encodeTlvAscii,\n encodeTlvBuffer,\n encodeTlvChainId,\n encodeTlvUInt8,\n STRUCT_TYPE_PROVIDE_CONTACT,\n STRUCT_VERSION_VALUE,\n} from \"@internal/app-binder/services/contactsTlvSerializer\";\nimport { sendFramedContactsPayload } from \"@internal/app-binder/services/sendFramedContactsPayload\";\n\n/**\n * Encode a matched contact as the PROVIDE CONTACT TLV payload, without the\n * chunk framing. Pure, so callers can build it while matching a recipient\n * against the address book, with no device involved.\n */\nexport function buildProvideContactPayload(\n input: ProvideContactInput,\n): Uint8Array {\n const family = validateFamilyIdentifiers({\n blockchainFamily: input.blockchainFamily,\n identifiers: [{ field: \"identifier\", value: input.identifier }],\n chainId: input.chainId,\n });\n\n const builder = new ByteArrayBuilder();\n encodeTlvUInt8(\n builder,\n CONTACTS_TLV_TAG.STRUCT_TYPE,\n STRUCT_TYPE_PROVIDE_CONTACT,\n );\n encodeTlvUInt8(\n builder,\n CONTACTS_TLV_TAG.STRUCT_VERSION,\n STRUCT_VERSION_VALUE,\n );\n encodeTlvAscii(builder, CONTACTS_TLV_TAG.CONTACT_NAME, input.contactName);\n encodeTlvAscii(builder, CONTACTS_TLV_TAG.SCOPE, input.scope);\n encodeTlvBuffer(\n builder,\n CONTACTS_TLV_TAG.ACCOUNT_IDENTIFIER,\n input.identifier,\n );\n encodeTlvBuffer(builder, CONTACTS_TLV_TAG.GROUP_HANDLE, input.groupHandle);\n if (input.chainId !== undefined) {\n encodeTlvChainId(builder, CONTACTS_TLV_TAG.CHAIN_ID, input.chainId);\n }\n encodeTlvUInt8(builder, CONTACTS_TLV_TAG.BLOCKCHAIN_FAMILY, family);\n encodeTlvBuffer(builder, CONTACTS_TLV_TAG.HMAC_PROOF, input.hmacProof);\n encodeTlvBuffer(builder, CONTACTS_TLV_TAG.HMAC_REST, input.hmacRest);\n\n return builder.build();\n}\n\nexport type SendProvideContactPayloadArgs = {\n readonly payload: Uint8Array;\n readonly logger?: LoggerPublisherService;\n};\n\nexport function sendProvideContactPayload(\n api: InternalApi,\n { payload, logger }: SendProvideContactPayloadArgs,\n): Promise<CommandResult<void, ContactsErrorCodes>> {\n return sendFramedContactsPayload(api, {\n payload,\n p1: SUB_CMD_PROVIDE_CONTACT,\n makeCommand: (chunk, p2) => new ProvideContactCommand({ data: chunk, p2 }),\n logger,\n commandTag: \"provideContact\",\n }) as Promise<CommandResult<void, ContactsErrorCodes>>;\n}\n"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,gCAAAE,EAAA,8BAAAC,IAAA,eAAAC,EAAAJ,GASA,IAAAK,EAKO,2CAGPC,EAAsC,8DACtCC,EAAwC,wDAExCC,EAA0C,yDAC1CC,EAQO,+DACPC,EAA0C,mEAOnC,SAASR,EACdS,EACY,CACZ,MAAMC,KAAS,6BAA0B,CACvC,iBAAkBD,EAAM,iBACxB,YAAa,CAAC,CAAE,MAAO,aAAc,MAAOA,EAAM,UAAW,CAAC,EAC9D,QAASA,EAAM,OACjB,CAAC,EAEKE,EAAU,IAAI,mBACpB,2BACEA,EACA,mBAAiB,YACjB,6BACF,KACA,kBACEA,EACA,mBAAiB,eACjB,sBACF,KACA,kBAAeA,EAAS,mBAAiB,aAAcF,EAAM,WAAW,KACxE,kBAAeE,EAAS,mBAAiB,MAAOF,EAAM,KAAK,KAC3D,mBACEE,EACA,mBAAiB,mBACjBF,EAAM,UACR,KACA,mBAAgBE,EAAS,mBAAiB,aAAcF,EAAM,WAAW,EACrEA,EAAM,UAAY,WACpB,oBAAiBE,EAAS,mBAAiB,SAAUF,EAAM,OAAO,KAEpE,kBAAeE,EAAS,mBAAiB,kBAAmBD,CAAM,KAClE,mBAAgBC,EAAS,mBAAiB,WAAYF,EAAM,SAAS,KACrE,mBAAgBE,EAAS,mBAAiB,UAAWF,EAAM,QAAQ,EAE5DE,EAAQ,MAAM,CACvB,CAOO,SAASV,EACdW,EACA,CAAE,QAAAC,EAAS,OAAAC,CAAO,EACgC,CAClD,SAAO,6BAA0BF,EAAK,CACpC,QAAAC,EACA,GAAI,0BACJ,YAAa,CAACE,EAAOC,IAAO,IAAI,wBAAsB,CAAE,KAAMD,EAAO,GAAAC,CAAG,CAAC,EACzE,OAAAF,EACA,WAAY,gBACd,CAAC,CACH",
6
+ "names": ["provideContact_exports", "__export", "buildProvideContactPayload", "sendProvideContactPayload", "__toCommonJS", "import_device_management_kit", "import_ProvideContactCommand", "import_contactsConstants", "import_contactsValidation", "import_contactsTlvSerializer", "import_sendFramedContactsPayload", "input", "family", "builder", "api", "payload", "logger", "chunk", "p2"]
7
7
  }
@@ -1,2 +1,2 @@
1
- "use strict";var o=require("@ledgerhq/device-management-kit"),r=require("../../app-binder/command/ProvideContactCommand"),i=require("../../app-binder/device-action/__test-utils__/makeInternalApi"),d=require("../../app-binder/model/contactsErrors"),t=require("./provideContact");const m=new Uint8Array(20).fill(17),p=new Uint8Array(64).fill(34),f=new Uint8Array(32).fill(51),h=new Uint8Array(32).fill(68),n={contactName:"Alice",scope:"Ethereum",identifier:m,groupHandle:p,hmacProof:f,hmacRest:h,blockchainFamily:"ethereum",chainId:1n},C="010133",u="020101",y="81f005416c696365",T="81f108457468657265756d",x="81f214"+"11".repeat(20),s="81f640"+"22".repeat(64),E="230101",P="510101",_="2920"+"33".repeat(32),I="81f720"+"44".repeat(32);describe("buildProvideContactPayload",()=>{it("encodes every tag in the order the spec lists",()=>{const e=(0,t.buildProvideContactPayload)(n);expect((0,o.bufferToHexaString)(e,!1)).toBe(C+u+y+T+x+s+E+P+_+I)}),it("fits an Ethereum contact in a single 255-byte chunk",()=>{expect((0,t.buildProvideContactPayload)(n).length).toBeLessThanOrEqual(253)}),it("omits CHAIN_ID for a family that does not carry one",()=>{const e=(0,t.buildProvideContactPayload)({...n,blockchainFamily:"tron",chainId:void 0});expect((0,o.bufferToHexaString)(e,!1)).toContain(s+"510106")}),it("encodes a multi-byte chain id big-endian with no leading zeroes",()=>{const e=(0,t.buildProvideContactPayload)({...n,chainId:8453n});expect((0,o.bufferToHexaString)(e,!1)).toContain("23022105")}),it("accepts the family name case-insensitively",()=>{expect((0,t.buildProvideContactPayload)({...n,blockchainFamily:"Ethereum"})).toStrictEqual((0,t.buildProvideContactPayload)(n))}),it("throws on an unknown blockchain family",()=>{expect(()=>(0,t.buildProvideContactPayload)({...n,blockchainFamily:"dogecoin"})).toThrow("Unsupported blockchain family: dogecoin")})});describe("sendProvideContactPayload",()=>{it("sends one chunk under P2=0x00, prefixed with the 2-byte BE total length",async()=>{const e=(0,i.makeDeviceActionInternalApiMock)();e.sendCommand.mockResolvedValue((0,o.CommandResultFactory)({data:void 0}));const a=(0,t.buildProvideContactPayload)(n),l=await(0,t.sendProvideContactPayload)(e,{payload:a});expect(e.sendCommand).toHaveBeenCalledTimes(1);const c=e.sendCommand.mock.calls[0][0];expect(c).toBeInstanceOf(r.ProvideContactCommand),expect(c.args.p2).toBe(0),expect(c.args.data.slice(0,2)).toStrictEqual(Uint8Array.from([a.length>>8&255,a.length&255])),expect(c.args.data.slice(2)).toStrictEqual(a),expect(l.status).toBe(o.CommandResultStatus.Success)}),it("propagates a device rejection instead of throwing",async()=>{const e=(0,i.makeDeviceActionInternalApiMock)();e.sendCommand.mockResolvedValue((0,o.CommandResultFactory)({error:new d.ContactsCommandError({errorCode:"6982",message:"wrong seed"})}));const a=await(0,t.sendProvideContactPayload)(e,{payload:(0,t.buildProvideContactPayload)(n)});expect(a.status).toBe(o.CommandResultStatus.Error)})});
1
+ "use strict";var n=require("@ledgerhq/device-management-kit"),r=require("../../app-binder/command/ProvideContactCommand"),s=require("../../app-binder/device-action/__test-utils__/makeInternalApi"),d=require("../../app-binder/model/contactsErrors"),t=require("./provideContact");const m=new Uint8Array(20).fill(17),p=new Uint8Array(64).fill(34),f=new Uint8Array(32).fill(51),h=new Uint8Array(32).fill(68),o={contactName:"Alice",scope:"Ethereum",identifier:m,groupHandle:p,hmacProof:f,hmacRest:h,blockchainFamily:"ethereum",chainId:1n},y="010133",C="020101",u="81f005416c696365",x="81f108457468657265756d",T="81f214"+"11".repeat(20),c="81f640"+"22".repeat(64),I="230101",E="510101",_="2920"+"33".repeat(32),A="81f720"+"44".repeat(32);describe("buildProvideContactPayload",()=>{it("encodes every tag in the order the spec lists",()=>{const e=(0,t.buildProvideContactPayload)(o);expect((0,n.bufferToHexaString)(e,!1)).toBe(y+C+u+x+T+c+I+E+_+A)}),it("fits an Ethereum contact in a single 255-byte chunk",()=>{expect((0,t.buildProvideContactPayload)(o).length).toBeLessThanOrEqual(253)}),it("omits CHAIN_ID for a family that does not carry one",()=>{const e=(0,t.buildProvideContactPayload)({...o,blockchainFamily:"tron",chainId:void 0});expect((0,n.bufferToHexaString)(e,!1)).toContain(c+"510106")}),it("encodes a multi-byte chain id big-endian with no leading zeroes",()=>{const e=(0,t.buildProvideContactPayload)({...o,chainId:8453n});expect((0,n.bufferToHexaString)(e,!1)).toContain("23022105")}),it("accepts the family name case-insensitively",()=>{expect((0,t.buildProvideContactPayload)({...o,blockchainFamily:"Ethereum"})).toStrictEqual((0,t.buildProvideContactPayload)(o))}),it("encodes a Solana contact with its family byte and no CHAIN_ID",()=>{const e=(0,t.buildProvideContactPayload)({...o,identifier:new Uint8Array(32).fill(17),blockchainFamily:"solana",chainId:void 0});expect((0,n.bufferToHexaString)(e,!1)).toContain("81f220"+"11".repeat(32)+c+"510102")}),it("throws on a Solana identifier that is not 32 bytes",()=>{expect(()=>(0,t.buildProvideContactPayload)({...o,blockchainFamily:"solana",chainId:void 0})).toThrow("identifier is 20 bytes, expected 32.")}),it("throws on an unknown blockchain family",()=>{expect(()=>(0,t.buildProvideContactPayload)({...o,blockchainFamily:"dogecoin"})).toThrow("Unsupported blockchain family: dogecoin")})});describe("sendProvideContactPayload",()=>{it("sends one chunk under P2=0x00, prefixed with the 2-byte BE total length",async()=>{const e=(0,s.makeDeviceActionInternalApiMock)();e.sendCommand.mockResolvedValue((0,n.CommandResultFactory)({data:void 0}));const a=(0,t.buildProvideContactPayload)(o),l=await(0,t.sendProvideContactPayload)(e,{payload:a});expect(e.sendCommand).toHaveBeenCalledTimes(1);const i=e.sendCommand.mock.calls[0][0];expect(i).toBeInstanceOf(r.ProvideContactCommand),expect(i.args.p2).toBe(0),expect(i.args.data.slice(0,2)).toStrictEqual(Uint8Array.from([a.length>>8&255,a.length&255])),expect(i.args.data.slice(2)).toStrictEqual(a),expect(l.status).toBe(n.CommandResultStatus.Success)}),it("propagates a device rejection instead of throwing",async()=>{const e=(0,s.makeDeviceActionInternalApiMock)();e.sendCommand.mockResolvedValue((0,n.CommandResultFactory)({error:new d.ContactsCommandError({errorCode:"6982",message:"wrong seed"})}));const a=await(0,t.sendProvideContactPayload)(e,{payload:(0,t.buildProvideContactPayload)(o)});expect(a.status).toBe(n.CommandResultStatus.Error)})});
2
2
  //# sourceMappingURL=provideContact.test.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/services/provideContact.test.ts"],
4
- "sourcesContent": ["import {\n bufferToHexaString,\n CommandResultFactory,\n CommandResultStatus,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { type ProvideContactInput } from \"@api/model/ProvideContact\";\nimport { ProvideContactCommand } from \"@internal/app-binder/command/ProvideContactCommand\";\nimport { makeDeviceActionInternalApiMock } from \"@internal/app-binder/device-action/__test-utils__/makeInternalApi\";\nimport { ContactsCommandError } from \"@internal/app-binder/model/contactsErrors\";\n\nimport {\n buildProvideContactPayload,\n sendProvideContactPayload,\n} from \"./provideContact\";\n\nconst IDENTIFIER = new Uint8Array(20).fill(0x11);\nconst GROUP_HANDLE = new Uint8Array(64).fill(0x22);\nconst HMAC_PROOF = new Uint8Array(32).fill(0x33);\nconst HMAC_REST = new Uint8Array(32).fill(0x44);\n\nconst INPUT: ProvideContactInput = {\n contactName: \"Alice\",\n scope: \"Ethereum\",\n identifier: IDENTIFIER,\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF,\n hmacRest: HMAC_REST,\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n};\n\n// Tags >= 0x80 use the DER long form (0x81 then the tag), hence the \"81\" prefix\n// on CONTACT_NAME (0xf0), SCOPE (0xf1), ACCOUNT_IDENTIFIER (0xf2),\n// GROUP_HANDLE (0xf6) and HMAC_REST (0xf7).\nconst STRUCT_TYPE_TLV = \"010133\";\nconst STRUCT_VERSION_TLV = \"020101\";\nconst CONTACT_NAME_TLV = \"81f005\" + \"416c696365\"; // \"Alice\"\nconst SCOPE_TLV = \"81f108\" + \"457468657265756d\"; // \"Ethereum\"\nconst IDENTIFIER_TLV = \"81f214\" + \"11\".repeat(20);\nconst GROUP_HANDLE_TLV = \"81f640\" + \"22\".repeat(64);\nconst CHAIN_ID_TLV = \"230101\";\nconst FAMILY_TLV = \"510101\";\nconst HMAC_PROOF_TLV = \"2920\" + \"33\".repeat(32);\nconst HMAC_REST_TLV = \"81f720\" + \"44\".repeat(32);\n\ndescribe(\"buildProvideContactPayload\", () => {\n it(\"encodes every tag in the order the spec lists\", () => {\n const payload = buildProvideContactPayload(INPUT);\n\n expect(bufferToHexaString(payload, false)).toBe(\n STRUCT_TYPE_TLV +\n STRUCT_VERSION_TLV +\n CONTACT_NAME_TLV +\n SCOPE_TLV +\n IDENTIFIER_TLV +\n GROUP_HANDLE_TLV +\n CHAIN_ID_TLV +\n FAMILY_TLV +\n HMAC_PROOF_TLV +\n HMAC_REST_TLV,\n );\n });\n\n it(\"fits an Ethereum contact in a single 255-byte chunk\", () => {\n expect(buildProvideContactPayload(INPUT).length).toBeLessThanOrEqual(253);\n });\n\n it(\"omits CHAIN_ID for a family that does not carry one\", () => {\n const payload = buildProvideContactPayload({\n ...INPUT,\n blockchainFamily: \"tron\",\n chainId: undefined,\n });\n\n expect(bufferToHexaString(payload, false)).toContain(\n GROUP_HANDLE_TLV + \"510106\",\n );\n });\n\n it(\"encodes a multi-byte chain id big-endian with no leading zeroes\", () => {\n const payload = buildProvideContactPayload({ ...INPUT, chainId: 8453n });\n\n expect(bufferToHexaString(payload, false)).toContain(\"2302\" + \"2105\");\n });\n\n it(\"accepts the family name case-insensitively\", () => {\n expect(\n buildProvideContactPayload({ ...INPUT, blockchainFamily: \"Ethereum\" }),\n ).toStrictEqual(buildProvideContactPayload(INPUT));\n });\n\n it(\"throws on an unknown blockchain family\", () => {\n expect(() =>\n buildProvideContactPayload({ ...INPUT, blockchainFamily: \"dogecoin\" }),\n ).toThrow(\"Unsupported blockchain family: dogecoin\");\n });\n});\n\ndescribe(\"sendProvideContactPayload\", () => {\n it(\"sends one chunk under P2=0x00, prefixed with the 2-byte BE total length\", async () => {\n const api = makeDeviceActionInternalApiMock();\n api.sendCommand.mockResolvedValue(\n CommandResultFactory({ data: undefined }),\n );\n const payload = buildProvideContactPayload(INPUT);\n\n const result = await sendProvideContactPayload(api, { payload });\n\n expect(api.sendCommand).toHaveBeenCalledTimes(1);\n const command = api.sendCommand.mock.calls[0]![0] as ProvideContactCommand;\n expect(command).toBeInstanceOf(ProvideContactCommand);\n expect(command.args.p2).toBe(0x00);\n expect(command.args.data.slice(0, 2)).toStrictEqual(\n Uint8Array.from([(payload.length >> 8) & 0xff, payload.length & 0xff]),\n );\n expect(command.args.data.slice(2)).toStrictEqual(payload);\n expect(result.status).toBe(CommandResultStatus.Success);\n });\n\n it(\"propagates a device rejection instead of throwing\", async () => {\n const api = makeDeviceActionInternalApiMock();\n api.sendCommand.mockResolvedValue(\n CommandResultFactory({\n error: new ContactsCommandError({\n errorCode: \"6982\",\n message: \"wrong seed\",\n }),\n }),\n );\n\n const result = await sendProvideContactPayload(api, {\n payload: buildProvideContactPayload(INPUT),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n });\n});\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n bufferToHexaString,\n CommandResultFactory,\n CommandResultStatus,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { type ProvideContactInput } from \"@api/model/ProvideContact\";\nimport { ProvideContactCommand } from \"@internal/app-binder/command/ProvideContactCommand\";\nimport { makeDeviceActionInternalApiMock } from \"@internal/app-binder/device-action/__test-utils__/makeInternalApi\";\nimport { ContactsCommandError } from \"@internal/app-binder/model/contactsErrors\";\n\nimport {\n buildProvideContactPayload,\n sendProvideContactPayload,\n} from \"./provideContact\";\n\nconst IDENTIFIER = new Uint8Array(20).fill(0x11);\nconst GROUP_HANDLE = new Uint8Array(64).fill(0x22);\nconst HMAC_PROOF = new Uint8Array(32).fill(0x33);\nconst HMAC_REST = new Uint8Array(32).fill(0x44);\n\nconst INPUT: ProvideContactInput = {\n contactName: \"Alice\",\n scope: \"Ethereum\",\n identifier: IDENTIFIER,\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF,\n hmacRest: HMAC_REST,\n blockchainFamily: \"ethereum\",\n chainId: 1n,\n};\n\n// Tags >= 0x80 use the DER long form (0x81 then the tag), hence the \"81\" prefix\n// on CONTACT_NAME (0xf0), SCOPE (0xf1), ACCOUNT_IDENTIFIER (0xf2),\n// GROUP_HANDLE (0xf6) and HMAC_REST (0xf7).\nconst STRUCT_TYPE_TLV = \"010133\";\nconst STRUCT_VERSION_TLV = \"020101\";\nconst CONTACT_NAME_TLV = \"81f005\" + \"416c696365\"; // \"Alice\"\nconst SCOPE_TLV = \"81f108\" + \"457468657265756d\"; // \"Ethereum\"\nconst IDENTIFIER_TLV = \"81f214\" + \"11\".repeat(20);\nconst GROUP_HANDLE_TLV = \"81f640\" + \"22\".repeat(64);\nconst CHAIN_ID_TLV = \"230101\";\nconst FAMILY_TLV = \"510101\";\nconst HMAC_PROOF_TLV = \"2920\" + \"33\".repeat(32);\nconst HMAC_REST_TLV = \"81f720\" + \"44\".repeat(32);\n\ndescribe(\"buildProvideContactPayload\", () => {\n it(\"encodes every tag in the order the spec lists\", () => {\n const payload = buildProvideContactPayload(INPUT);\n\n expect(bufferToHexaString(payload, false)).toBe(\n STRUCT_TYPE_TLV +\n STRUCT_VERSION_TLV +\n CONTACT_NAME_TLV +\n SCOPE_TLV +\n IDENTIFIER_TLV +\n GROUP_HANDLE_TLV +\n CHAIN_ID_TLV +\n FAMILY_TLV +\n HMAC_PROOF_TLV +\n HMAC_REST_TLV,\n );\n });\n\n it(\"fits an Ethereum contact in a single 255-byte chunk\", () => {\n expect(buildProvideContactPayload(INPUT).length).toBeLessThanOrEqual(253);\n });\n\n it(\"omits CHAIN_ID for a family that does not carry one\", () => {\n const payload = buildProvideContactPayload({\n ...INPUT,\n blockchainFamily: \"tron\",\n chainId: undefined,\n });\n\n expect(bufferToHexaString(payload, false)).toContain(\n GROUP_HANDLE_TLV + \"510106\",\n );\n });\n\n it(\"encodes a multi-byte chain id big-endian with no leading zeroes\", () => {\n const payload = buildProvideContactPayload({ ...INPUT, chainId: 8453n });\n\n expect(bufferToHexaString(payload, false)).toContain(\"2302\" + \"2105\");\n });\n\n it(\"accepts the family name case-insensitively\", () => {\n expect(\n buildProvideContactPayload({ ...INPUT, blockchainFamily: \"Ethereum\" }),\n ).toStrictEqual(buildProvideContactPayload(INPUT));\n });\n\n it(\"encodes a Solana contact with its family byte and no CHAIN_ID\", () => {\n const payload = buildProvideContactPayload({\n ...INPUT,\n identifier: new Uint8Array(32).fill(0x11),\n blockchainFamily: \"solana\",\n chainId: undefined,\n });\n\n expect(bufferToHexaString(payload, false)).toContain(\n \"81f220\" + \"11\".repeat(32) + GROUP_HANDLE_TLV + \"510102\",\n );\n });\n\n it(\"throws on a Solana identifier that is not 32 bytes\", () => {\n expect(() =>\n buildProvideContactPayload({\n ...INPUT,\n blockchainFamily: \"solana\",\n chainId: undefined,\n }),\n ).toThrow(\"identifier is 20 bytes, expected 32.\");\n });\n\n it(\"throws on an unknown blockchain family\", () => {\n expect(() =>\n buildProvideContactPayload({ ...INPUT, blockchainFamily: \"dogecoin\" }),\n ).toThrow(\"Unsupported blockchain family: dogecoin\");\n });\n});\n\ndescribe(\"sendProvideContactPayload\", () => {\n it(\"sends one chunk under P2=0x00, prefixed with the 2-byte BE total length\", async () => {\n const api = makeDeviceActionInternalApiMock();\n api.sendCommand.mockResolvedValue(\n CommandResultFactory({ data: undefined }),\n );\n const payload = buildProvideContactPayload(INPUT);\n\n const result = await sendProvideContactPayload(api, { payload });\n\n expect(api.sendCommand).toHaveBeenCalledTimes(1);\n const command = api.sendCommand.mock.calls[0]![0] as ProvideContactCommand;\n expect(command).toBeInstanceOf(ProvideContactCommand);\n expect(command.args.p2).toBe(0x00);\n expect(command.args.data.slice(0, 2)).toStrictEqual(\n Uint8Array.from([(payload.length >> 8) & 0xff, payload.length & 0xff]),\n );\n expect(command.args.data.slice(2)).toStrictEqual(payload);\n expect(result.status).toBe(CommandResultStatus.Success);\n });\n\n it(\"propagates a device rejection instead of throwing\", async () => {\n const api = makeDeviceActionInternalApiMock();\n api.sendCommand.mockResolvedValue(\n CommandResultFactory({\n error: new ContactsCommandError({\n errorCode: \"6982\",\n message: \"wrong seed\",\n }),\n }),\n );\n\n const result = await sendProvideContactPayload(api, {\n payload: buildProvideContactPayload(INPUT),\n });\n\n expect(result.status).toBe(CommandResultStatus.Error);\n });\n});\n"],
5
+ "mappings": "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",
6
6
  "names": ["import_device_management_kit", "import_ProvideContactCommand", "import_makeInternalApi", "import_contactsErrors", "import_provideContact", "IDENTIFIER", "GROUP_HANDLE", "HMAC_PROOF", "HMAC_REST", "INPUT", "STRUCT_TYPE_TLV", "STRUCT_VERSION_TLV", "CONTACT_NAME_TLV", "SCOPE_TLV", "IDENTIFIER_TLV", "GROUP_HANDLE_TLV", "CHAIN_ID_TLV", "FAMILY_TLV", "HMAC_PROOF_TLV", "HMAC_REST_TLV", "payload", "api", "result", "command"]
7
7
  }
@@ -58,5 +58,5 @@
58
58
  "watch:builds": "pnpm ldmk-tool watch --entryPoints src/index.ts,src/**/*.ts --tsconfig tsconfig.prod.json",
59
59
  "watch:types": "concurrently \"tsc --watch -p tsconfig.prod.json\" \"tsc-alias --watch -p tsconfig.prod.json\""
60
60
  },
61
- "version": "0.0.0-develop-20261008001410"
61
+ "version": "0.0.0-develop-20261010001520"
62
62
  }
@@ -1,2 +1,2 @@
1
- import{ContactsManagerBuilder as r}from"./ContactsManagerBuilder";import{CONTACTS_VERSION_REQUIREMENTS as n,ETHEREUM_APP_NAME as p,isVersionAtLeast as o,resolveContactsVersionRequirements as s,TRON_APP_NAME as a}from"./model/ContactsVersionRequirements";import{buildProvideContactPayload as A,sendProvideContactPayload as E}from"../internal/app-binder/services/provideContact";export{n as CONTACTS_VERSION_REQUIREMENTS,r as ContactsManagerBuilder,p as ETHEREUM_APP_NAME,a as TRON_APP_NAME,A as buildProvideContactPayload,o as isVersionAtLeast,s as resolveContactsVersionRequirements,E as sendProvideContactPayload};
1
+ import{ContactsManagerBuilder as r}from"./ContactsManagerBuilder";import{CONTACTS_VERSION_REQUIREMENTS as n,ETHEREUM_APP_NAME as p,isVersionAtLeast as o,resolveContactsVersionRequirements as s,SOLANA_APP_NAME as a,TRON_APP_NAME as i}from"./model/ContactsVersionRequirements";import{buildProvideContactPayload as E,sendProvideContactPayload as y}from"../internal/app-binder/services/provideContact";export{n as CONTACTS_VERSION_REQUIREMENTS,r as ContactsManagerBuilder,p as ETHEREUM_APP_NAME,a as SOLANA_APP_NAME,i as TRON_APP_NAME,E as buildProvideContactPayload,o as isVersionAtLeast,s as resolveContactsVersionRequirements,y as sendProvideContactPayload};
2
2
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/api/index.ts"],
4
- "sourcesContent": ["export {\n type EditExternalAddressIdentifierDAError,\n type EditExternalAddressIdentifierDAInput,\n type EditExternalAddressIdentifierDAIntermediateValue,\n type EditExternalAddressIdentifierDAOutput,\n type EditExternalAddressIdentifierDARequiredInteraction,\n type EditExternalAddressIdentifierDAReturnType,\n type EditExternalAddressIdentifierDAState,\n} from \"@api/app-binder/EditExternalAddressIdentifierDeviceActionTypes\";\nexport {\n type EditExternalAddressScopeDAError,\n type EditExternalAddressScopeDAInput,\n type EditExternalAddressScopeDAIntermediateValue,\n type EditExternalAddressScopeDAOutput,\n type EditExternalAddressScopeDARequiredInteraction,\n type EditExternalAddressScopeDAReturnType,\n type EditExternalAddressScopeDAState,\n} from \"@api/app-binder/EditExternalAddressScopeDeviceActionTypes\";\nexport {\n type RegisterExternalAddressDAError,\n type RegisterExternalAddressDAInput,\n type RegisterExternalAddressDAIntermediateValue,\n type RegisterExternalAddressDAOutput,\n type RegisterExternalAddressDARequiredInteraction,\n type RegisterExternalAddressDAReturnType,\n type RegisterExternalAddressDAState,\n} from \"@api/app-binder/RegisterExternalAddressDeviceActionTypes\";\nexport {\n type RenameContactDAError,\n type RenameContactDAInput,\n type RenameContactDAIntermediateValue,\n type RenameContactDAOutput,\n type RenameContactDARequiredInteraction,\n type RenameContactDAReturnType,\n type RenameContactDAState,\n} from \"@api/app-binder/RenameContactDeviceActionTypes\";\nexport { type ContactsManager } from \"@api/ContactsManager\";\nexport { ContactsManagerBuilder } from \"@api/ContactsManagerBuilder\";\nexport {\n CONTACTS_VERSION_REQUIREMENTS,\n type ContactsModelRequirement,\n type ContactsModelSupport,\n type ContactsModelUnsupported,\n type ContactsVersionRequirements,\n ETHEREUM_APP_NAME,\n isVersionAtLeast,\n resolveContactsVersionRequirements,\n TRON_APP_NAME,\n} from \"@api/model/ContactsVersionRequirements\";\nexport {\n type EditExternalAddressIdentifierInput,\n type EditExternalAddressIdentifierOutput,\n} from \"@api/model/EditExternalAddressIdentifier\";\nexport {\n type EditExternalAddressScopeInput,\n type EditExternalAddressScopeOutput,\n} from \"@api/model/EditExternalAddressScope\";\nexport { type ProvideContactInput } from \"@api/model/ProvideContact\";\nexport {\n type ExistingContactGroup,\n type RegisterExternalAddressInput,\n type RegisterExternalAddressMode,\n type RegisterExternalAddressOutput,\n} from \"@api/model/RegisterExternalAddress\";\nexport {\n type RenameContactInput,\n type RenameContactOutput,\n} from \"@api/model/RenameContact\";\nexport { type ContactsErrorCodes } from \"@internal/app-binder/model/contactsErrors\";\nexport {\n buildProvideContactPayload,\n sendProvideContactPayload,\n type SendProvideContactPayloadArgs,\n} from \"@internal/app-binder/services/provideContact\";\n"],
5
- "mappings": "AAqCA,OAAS,0BAAAA,MAA8B,8BACvC,OACE,iCAAAC,EAKA,qBAAAC,EACA,oBAAAC,EACA,sCAAAC,EACA,iBAAAC,MACK,yCAqBP,OACE,8BAAAC,EACA,6BAAAC,MAEK",
6
- "names": ["ContactsManagerBuilder", "CONTACTS_VERSION_REQUIREMENTS", "ETHEREUM_APP_NAME", "isVersionAtLeast", "resolveContactsVersionRequirements", "TRON_APP_NAME", "buildProvideContactPayload", "sendProvideContactPayload"]
4
+ "sourcesContent": ["export {\n type EditExternalAddressIdentifierDAError,\n type EditExternalAddressIdentifierDAInput,\n type EditExternalAddressIdentifierDAIntermediateValue,\n type EditExternalAddressIdentifierDAOutput,\n type EditExternalAddressIdentifierDARequiredInteraction,\n type EditExternalAddressIdentifierDAReturnType,\n type EditExternalAddressIdentifierDAState,\n} from \"@api/app-binder/EditExternalAddressIdentifierDeviceActionTypes\";\nexport {\n type EditExternalAddressScopeDAError,\n type EditExternalAddressScopeDAInput,\n type EditExternalAddressScopeDAIntermediateValue,\n type EditExternalAddressScopeDAOutput,\n type EditExternalAddressScopeDARequiredInteraction,\n type EditExternalAddressScopeDAReturnType,\n type EditExternalAddressScopeDAState,\n} from \"@api/app-binder/EditExternalAddressScopeDeviceActionTypes\";\nexport {\n type RegisterExternalAddressDAError,\n type RegisterExternalAddressDAInput,\n type RegisterExternalAddressDAIntermediateValue,\n type RegisterExternalAddressDAOutput,\n type RegisterExternalAddressDARequiredInteraction,\n type RegisterExternalAddressDAReturnType,\n type RegisterExternalAddressDAState,\n} from \"@api/app-binder/RegisterExternalAddressDeviceActionTypes\";\nexport {\n type RenameContactDAError,\n type RenameContactDAInput,\n type RenameContactDAIntermediateValue,\n type RenameContactDAOutput,\n type RenameContactDARequiredInteraction,\n type RenameContactDAReturnType,\n type RenameContactDAState,\n} from \"@api/app-binder/RenameContactDeviceActionTypes\";\nexport { type ContactsManager } from \"@api/ContactsManager\";\nexport { ContactsManagerBuilder } from \"@api/ContactsManagerBuilder\";\nexport {\n CONTACTS_VERSION_REQUIREMENTS,\n type ContactsModelRequirement,\n type ContactsModelSupport,\n type ContactsModelUnsupported,\n type ContactsVersionRequirements,\n ETHEREUM_APP_NAME,\n isVersionAtLeast,\n resolveContactsVersionRequirements,\n SOLANA_APP_NAME,\n TRON_APP_NAME,\n} from \"@api/model/ContactsVersionRequirements\";\nexport {\n type EditExternalAddressIdentifierInput,\n type EditExternalAddressIdentifierOutput,\n} from \"@api/model/EditExternalAddressIdentifier\";\nexport {\n type EditExternalAddressScopeInput,\n type EditExternalAddressScopeOutput,\n} from \"@api/model/EditExternalAddressScope\";\nexport { type ProvideContactInput } from \"@api/model/ProvideContact\";\nexport {\n type ExistingContactGroup,\n type RegisterExternalAddressInput,\n type RegisterExternalAddressMode,\n type RegisterExternalAddressOutput,\n} from \"@api/model/RegisterExternalAddress\";\nexport {\n type RenameContactInput,\n type RenameContactOutput,\n} from \"@api/model/RenameContact\";\nexport { type ContactsErrorCodes } from \"@internal/app-binder/model/contactsErrors\";\nexport {\n buildProvideContactPayload,\n sendProvideContactPayload,\n type SendProvideContactPayloadArgs,\n} from \"@internal/app-binder/services/provideContact\";\n"],
5
+ "mappings": "AAqCA,OAAS,0BAAAA,MAA8B,8BACvC,OACE,iCAAAC,EAKA,qBAAAC,EACA,oBAAAC,EACA,sCAAAC,EACA,mBAAAC,EACA,iBAAAC,MACK,yCAqBP,OACE,8BAAAC,EACA,6BAAAC,MAEK",
6
+ "names": ["ContactsManagerBuilder", "CONTACTS_VERSION_REQUIREMENTS", "ETHEREUM_APP_NAME", "isVersionAtLeast", "resolveContactsVersionRequirements", "SOLANA_APP_NAME", "TRON_APP_NAME", "buildProvideContactPayload", "sendProvideContactPayload"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{DeviceModelId as r}from"@ledgerhq/device-management-kit";import{coerce as p,gte as N,lt as O,valid as i}from"semver";const R="Ethereum",A="Tron",E={supported:!1},a="1.11.0",u="1.7.0",c="1.2.0",_="2.8.0",d="1.7.0",V="1.23.0",m="0.8.0",s={[R]:V,[A]:m},P=`${a}-rc3`,M=`${u}-rc3`,S=`${c}-rc3`,I=`${_}-rc3`,T=`${d}-rc3`,l={[r.NANO_S]:E,[r.NANO_SP]:{supported:!0,minOsVersion:d,minAppVersion:s,renameDerivationPathRequiredBelowOsVersion:T},[r.NANO_X]:{supported:!0,minOsVersion:_,minAppVersion:s,renameDerivationPathRequiredBelowOsVersion:I},[r.STAX]:{supported:!0,minOsVersion:a,minAppVersion:s,renameDerivationPathRequiredBelowOsVersion:P},[r.FLEX]:{supported:!0,minOsVersion:u,minAppVersion:s,renameDerivationPathRequiredBelowOsVersion:M},[r.APEX]:{supported:!0,minOsVersion:c,minAppVersion:s,renameDerivationPathRequiredBelowOsVersion:S}};function v(o){return l[o]}function D(o,t){const e=i(p(o)),n=i(p(t));return e===null||n===null?!1:N(e,n)}function f(o,t){const e=i(o),n=i(t);return e===null||n===null?!1:O(e,n)}function F(o,t){const e=l[o];if(!e.supported)return!1;const n=e.renameDerivationPathRequiredBelowOsVersion;return n===void 0?!1:f(t,n)}export{l as CONTACTS_VERSION_REQUIREMENTS,R as ETHEREUM_APP_NAME,A as TRON_APP_NAME,D as isVersionAtLeast,f as isVersionBelow,F as renameRequiresDerivationPath,v as resolveContactsVersionRequirements};
1
+ import{DeviceModelId as t}from"@ledgerhq/device-management-kit";import{coerce as p,gte as d,lt as O,valid as i}from"semver";const A="Ethereum",E="Tron",R="Solana",P={supported:!1},a="1.11.0",_="1.7.0",c="1.2.0",u="2.8.0",l="1.7.0",V="1.23.0",m="0.8.0",M="10.0.0",s={[A]:V,[E]:m,[R]:M},S=`${a}-rc3`,I=`${_}-rc3`,T=`${c}-rc3`,f=`${u}-rc3`,C=`${l}-rc3`,N={[t.NANO_S]:P,[t.NANO_SP]:{supported:!0,minOsVersion:l,minAppVersion:s,renameDerivationPathRequiredBelowOsVersion:C},[t.NANO_X]:{supported:!0,minOsVersion:u,minAppVersion:s,renameDerivationPathRequiredBelowOsVersion:f},[t.STAX]:{supported:!0,minOsVersion:a,minAppVersion:s,renameDerivationPathRequiredBelowOsVersion:S},[t.FLEX]:{supported:!0,minOsVersion:_,minAppVersion:s,renameDerivationPathRequiredBelowOsVersion:I},[t.APEX]:{supported:!0,minOsVersion:c,minAppVersion:s,renameDerivationPathRequiredBelowOsVersion:T}};function F(n){return N[n]}function U(n,r){const e=i(p(n)),o=i(p(r));return e===null||o===null?!1:d(e,o)}function q(n,r){const e=i(n),o=i(r);return e===null||o===null?!1:O(e,o)}function x(n,r){const e=N[n];if(!e.supported)return!1;const o=e.renameDerivationPathRequiredBelowOsVersion;return o===void 0?!1:q(r,o)}export{N as CONTACTS_VERSION_REQUIREMENTS,A as ETHEREUM_APP_NAME,R as SOLANA_APP_NAME,E as TRON_APP_NAME,U as isVersionAtLeast,q as isVersionBelow,x as renameRequiresDerivationPath,F as resolveContactsVersionRequirements};
2
2
  //# sourceMappingURL=ContactsVersionRequirements.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/api/model/ContactsVersionRequirements.ts"],
4
- "sourcesContent": ["import { DeviceModelId } from \"@ledgerhq/device-management-kit\";\nimport { coerce, gte, lt, valid } from \"semver\";\n\n/**\n * Version requirements for a device model on which Contacts (Address Book)\n * operations are supported.\n *\n * Contacts has two independent version axes:\n * - `minOsVersion` gates OS-owned operations (e.g. renaming a contact from the\n * device dashboard), which are served by the device OS.\n * - `minAppVersion` gates app-owned operations (registering / editing external\n * addresses and Ledger accounts), which are served by the embedded app. It is\n * keyed by app name because the required version differs per app.\n */\nexport type ContactsModelSupport = {\n readonly supported: true;\n readonly minOsVersion: string;\n readonly minAppVersion: Readonly<Record<string, string>>;\n /**\n * TEMPORARY (DSDK-1481) \u2014 the first OS build for this model that no longer\n * wants the `DERIVATION_PATH` (tag 0x69) on EDIT CONTACT NAME. Rename is\n * served by the OS, and OS builds *below* this version still require the path\n * (omitting it yields 0x686A), while this build and later reject it\n * (0x6A80). So the path is sent only when the device OS is below this\n * cutoff. Absent means the model never wanted the path (send nothing \u2014 the\n * GA end-state). Delete this field, its constants, and\n * {@link renameRequiresDerivationPath} once no in-the-field OS predates the\n * cutoff.\n */\n readonly renameDerivationPathRequiredBelowOsVersion?: string;\n};\n\n/** Marks a device model on which Contacts is not supported at all. */\nexport type ContactsModelUnsupported = {\n readonly supported: false;\n};\n\nexport type ContactsModelRequirement =\n | ContactsModelSupport\n | ContactsModelUnsupported;\n\n/**\n * The full, static Contacts version-requirement table, keyed by device model.\n * Serializable plain data with no runtime dependencies, so hosts (e.g. Ledger\n * Wallet) can import and consume it directly when composing their own\n * app-readiness checks, without duplicating the values.\n */\nexport type ContactsVersionRequirements = Readonly<\n Record<DeviceModelId, ContactsModelRequirement>\n>;\n\n/** Names of embedded apps supporting Contacts. */\nexport const ETHEREUM_APP_NAME = \"Ethereum\";\nexport const TRON_APP_NAME = \"Tron\";\n\nconst UNSUPPORTED: ContactsModelUnsupported = { supported: false };\n\nconst MIN_OS_VERSION_STAX = \"1.11.0\";\nconst MIN_OS_VERSION_FLEX = \"1.7.0\";\nconst MIN_OS_VERSION_APEX = \"1.2.0\";\nconst MIN_OS_VERSION_NANO_X = \"2.8.0\";\nconst MIN_OS_VERSION_NANO_SP = \"1.7.0\";\n\nconst MIN_ETHEREUM_APP_VERSION = \"1.23.0\";\nconst MIN_TRON_APP_VERSION = \"0.8.0\";\n\nconst MIN_APP_VERSION = {\n [ETHEREUM_APP_NAME]: MIN_ETHEREUM_APP_VERSION,\n [TRON_APP_NAME]: MIN_TRON_APP_VERSION,\n};\n\n// TEMPORARY (DSDK-1481) \u2014 per-model cutoff below which the OS still requires the\n// EDIT CONTACT NAME derivation path. Each model's Address-Book-introducing OS\n// release shipped an rc2 that mandates the path (0x686A without it) and an rc3\n// that drops it (0x6A80 with it), so the cutoff is that release's `-rc3`. Only\n// Flex is hardware-confirmed (rc2 on a real device); the others follow the same\n// rc2/rc3 split per firmware \u2014 revise here if firmware says a model differs.\nconst RENAME_PATH_CUTOFF_STAX = `${MIN_OS_VERSION_STAX}-rc3`;\nconst RENAME_PATH_CUTOFF_FLEX = `${MIN_OS_VERSION_FLEX}-rc3`;\nconst RENAME_PATH_CUTOFF_APEX = `${MIN_OS_VERSION_APEX}-rc3`;\nconst RENAME_PATH_CUTOFF_NANO_X = `${MIN_OS_VERSION_NANO_X}-rc3`;\nconst RENAME_PATH_CUTOFF_NANO_SP = `${MIN_OS_VERSION_NANO_SP}-rc3`;\n\n/**\n * Contacts APDUs are supported on the touchscreen device models (Stax, Flex,\n * Apex) and on Nano X / Nano SP. Nano S does not support Contacts at all.\n */\nexport const CONTACTS_VERSION_REQUIREMENTS: ContactsVersionRequirements = {\n [DeviceModelId.NANO_S]: UNSUPPORTED,\n [DeviceModelId.NANO_SP]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_NANO_SP,\n minAppVersion: MIN_APP_VERSION,\n renameDerivationPathRequiredBelowOsVersion: RENAME_PATH_CUTOFF_NANO_SP,\n },\n [DeviceModelId.NANO_X]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_NANO_X,\n minAppVersion: MIN_APP_VERSION,\n renameDerivationPathRequiredBelowOsVersion: RENAME_PATH_CUTOFF_NANO_X,\n },\n [DeviceModelId.STAX]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_STAX,\n minAppVersion: MIN_APP_VERSION,\n renameDerivationPathRequiredBelowOsVersion: RENAME_PATH_CUTOFF_STAX,\n },\n [DeviceModelId.FLEX]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_FLEX,\n minAppVersion: MIN_APP_VERSION,\n renameDerivationPathRequiredBelowOsVersion: RENAME_PATH_CUTOFF_FLEX,\n },\n [DeviceModelId.APEX]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_APEX,\n minAppVersion: MIN_APP_VERSION,\n renameDerivationPathRequiredBelowOsVersion: RENAME_PATH_CUTOFF_APEX,\n },\n};\n\n/**\n * Resolve the Contacts version requirements for a device model \u2014 i.e. the\n * minimum supported OS and app versions, or that the model is unsupported.\n */\nexport function resolveContactsVersionRequirements(\n deviceModelId: DeviceModelId,\n): ContactsModelRequirement {\n return CONTACTS_VERSION_REQUIREMENTS[deviceModelId];\n}\n\n/**\n * Whether `actual` is greater than or equal to `minimum`, comparing as semver.\n * Tolerant of non-strict version strings and prerelease/build tags (coerces\n * both sides, which drops them) so a release candidate such as `1.7.0-rc2`\n * counts as meeting a `1.7.0` minimum. Returns `false` (i.e. requirement not\n * met) when either version cannot be parsed, so an unknown version never\n * passes a check.\n */\nexport function isVersionAtLeast(actual: string, minimum: string): boolean {\n const a = valid(coerce(actual));\n const b = valid(coerce(minimum));\n if (a === null || b === null) return false;\n return gte(a, b);\n}\n\n/**\n * Whether `actual` is strictly less than `boundary`, comparing as semver with\n * prerelease precedence preserved \u2014 unlike {@link isVersionAtLeast}, neither\n * side is coerced, so `1.7.0-rc2` sorts *below* `1.7.0-rc3` (and both below the\n * `1.7.0` release). Used to tell release candidates apart for the DSDK-1481\n * derivation-path cutoff, which `isVersionAtLeast` cannot do (it drops the\n * `-rcN` tag). Requires strict semver on both sides; returns `false` when\n * either cannot be parsed, so an unknown version is treated as *not* below the\n * boundary (i.e. the newer/GA payload shape).\n */\nexport function isVersionBelow(actual: string, boundary: string): boolean {\n const a = valid(actual);\n const b = valid(boundary);\n if (a === null || b === null) return false;\n return lt(a, b);\n}\n\n/**\n * TEMPORARY (DSDK-1481) \u2014 whether the EDIT CONTACT NAME (rename) payload must\n * carry the `DERIVATION_PATH` (tag 0x69) for a device on `osVersion`. True only\n * when the model is supported, declares a\n * {@link ContactsModelSupport.renameDerivationPathRequiredBelowOsVersion}\n * cutoff, and the fresh device OS version is strictly below that cutoff\n * (prerelease-aware). Callers pass the OS version read freshly from the device\n * (not the session state, which may be stale/absent on the dashboard path).\n */\nexport function renameRequiresDerivationPath(\n deviceModelId: DeviceModelId,\n osVersion: string,\n): boolean {\n const requirement = CONTACTS_VERSION_REQUIREMENTS[deviceModelId];\n if (!requirement.supported) return false;\n const cutoff = requirement.renameDerivationPathRequiredBelowOsVersion;\n if (cutoff === undefined) return false;\n return isVersionBelow(osVersion, cutoff);\n}\n"],
5
- "mappings": "AAAA,OAAS,iBAAAA,MAAqB,kCAC9B,OAAS,UAAAC,EAAQ,OAAAC,EAAK,MAAAC,EAAI,SAAAC,MAAa,SAmDhC,MAAMC,EAAoB,WACpBC,EAAgB,OAEvBC,EAAwC,CAAE,UAAW,EAAM,EAE3DC,EAAsB,SACtBC,EAAsB,QACtBC,EAAsB,QACtBC,EAAwB,QACxBC,EAAyB,QAEzBC,EAA2B,SAC3BC,EAAuB,QAEvBC,EAAkB,CACtB,CAACV,CAAiB,EAAGQ,EACrB,CAACP,CAAa,EAAGQ,CACnB,EAQME,EAA0B,GAAGR,CAAmB,OAChDS,EAA0B,GAAGR,CAAmB,OAChDS,EAA0B,GAAGR,CAAmB,OAChDS,EAA4B,GAAGR,CAAqB,OACpDS,EAA6B,GAAGR,CAAsB,OAM/CS,EAA6D,CACxE,CAACrB,EAAc,MAAM,EAAGO,EACxB,CAACP,EAAc,OAAO,EAAG,CACvB,UAAW,GACX,aAAcY,EACd,cAAeG,EACf,2CAA4CK,CAC9C,EACA,CAACpB,EAAc,MAAM,EAAG,CACtB,UAAW,GACX,aAAcW,EACd,cAAeI,EACf,2CAA4CI,CAC9C,EACA,CAACnB,EAAc,IAAI,EAAG,CACpB,UAAW,GACX,aAAcQ,EACd,cAAeO,EACf,2CAA4CC,CAC9C,EACA,CAAChB,EAAc,IAAI,EAAG,CACpB,UAAW,GACX,aAAcS,EACd,cAAeM,EACf,2CAA4CE,CAC9C,EACA,CAACjB,EAAc,IAAI,EAAG,CACpB,UAAW,GACX,aAAcU,EACd,cAAeK,EACf,2CAA4CG,CAC9C,CACF,EAMO,SAASI,EACdC,EAC0B,CAC1B,OAAOF,EAA8BE,CAAa,CACpD,CAUO,SAASC,EAAiBC,EAAgBC,EAA0B,CACzE,MAAMC,EAAIvB,EAAMH,EAAOwB,CAAM,CAAC,EACxBG,EAAIxB,EAAMH,EAAOyB,CAAO,CAAC,EAC/B,OAAIC,IAAM,MAAQC,IAAM,KAAa,GAC9B1B,EAAIyB,EAAGC,CAAC,CACjB,CAYO,SAASC,EAAeJ,EAAgBK,EAA2B,CACxE,MAAMH,EAAIvB,EAAMqB,CAAM,EAChBG,EAAIxB,EAAM0B,CAAQ,EACxB,OAAIH,IAAM,MAAQC,IAAM,KAAa,GAC9BzB,EAAGwB,EAAGC,CAAC,CAChB,CAWO,SAASG,EACdR,EACAS,EACS,CACT,MAAMC,EAAcZ,EAA8BE,CAAa,EAC/D,GAAI,CAACU,EAAY,UAAW,MAAO,GACnC,MAAMC,EAASD,EAAY,2CAC3B,OAAIC,IAAW,OAAkB,GAC1BL,EAAeG,EAAWE,CAAM,CACzC",
6
- "names": ["DeviceModelId", "coerce", "gte", "lt", "valid", "ETHEREUM_APP_NAME", "TRON_APP_NAME", "UNSUPPORTED", "MIN_OS_VERSION_STAX", "MIN_OS_VERSION_FLEX", "MIN_OS_VERSION_APEX", "MIN_OS_VERSION_NANO_X", "MIN_OS_VERSION_NANO_SP", "MIN_ETHEREUM_APP_VERSION", "MIN_TRON_APP_VERSION", "MIN_APP_VERSION", "RENAME_PATH_CUTOFF_STAX", "RENAME_PATH_CUTOFF_FLEX", "RENAME_PATH_CUTOFF_APEX", "RENAME_PATH_CUTOFF_NANO_X", "RENAME_PATH_CUTOFF_NANO_SP", "CONTACTS_VERSION_REQUIREMENTS", "resolveContactsVersionRequirements", "deviceModelId", "isVersionAtLeast", "actual", "minimum", "a", "b", "isVersionBelow", "boundary", "renameRequiresDerivationPath", "osVersion", "requirement", "cutoff"]
4
+ "sourcesContent": ["import { DeviceModelId } from \"@ledgerhq/device-management-kit\";\nimport { coerce, gte, lt, valid } from \"semver\";\n\n/**\n * Version requirements for a device model on which Contacts (Address Book)\n * operations are supported.\n *\n * Contacts has two independent version axes:\n * - `minOsVersion` gates OS-owned operations (e.g. renaming a contact from the\n * device dashboard), which are served by the device OS.\n * - `minAppVersion` gates app-owned operations (registering / editing external\n * addresses and Ledger accounts), which are served by the embedded app. It is\n * keyed by app name because the required version differs per app.\n */\nexport type ContactsModelSupport = {\n readonly supported: true;\n readonly minOsVersion: string;\n readonly minAppVersion: Readonly<Record<string, string>>;\n /**\n * TEMPORARY (DSDK-1481) \u2014 the first OS build for this model that no longer\n * wants the `DERIVATION_PATH` (tag 0x69) on EDIT CONTACT NAME. Rename is\n * served by the OS, and OS builds *below* this version still require the path\n * (omitting it yields 0x686A), while this build and later reject it\n * (0x6A80). So the path is sent only when the device OS is below this\n * cutoff. Absent means the model never wanted the path (send nothing \u2014 the\n * GA end-state). Delete this field, its constants, and\n * {@link renameRequiresDerivationPath} once no in-the-field OS predates the\n * cutoff.\n */\n readonly renameDerivationPathRequiredBelowOsVersion?: string;\n};\n\n/** Marks a device model on which Contacts is not supported at all. */\nexport type ContactsModelUnsupported = {\n readonly supported: false;\n};\n\nexport type ContactsModelRequirement =\n | ContactsModelSupport\n | ContactsModelUnsupported;\n\n/**\n * The full, static Contacts version-requirement table, keyed by device model.\n * Serializable plain data with no runtime dependencies, so hosts (e.g. Ledger\n * Wallet) can import and consume it directly when composing their own\n * app-readiness checks, without duplicating the values.\n */\nexport type ContactsVersionRequirements = Readonly<\n Record<DeviceModelId, ContactsModelRequirement>\n>;\n\n/** Names of embedded apps supporting Contacts. */\nexport const ETHEREUM_APP_NAME = \"Ethereum\";\nexport const TRON_APP_NAME = \"Tron\";\nexport const SOLANA_APP_NAME = \"Solana\";\n\nconst UNSUPPORTED: ContactsModelUnsupported = { supported: false };\n\nconst MIN_OS_VERSION_STAX = \"1.11.0\";\nconst MIN_OS_VERSION_FLEX = \"1.7.0\";\nconst MIN_OS_VERSION_APEX = \"1.2.0\";\nconst MIN_OS_VERSION_NANO_X = \"2.8.0\";\nconst MIN_OS_VERSION_NANO_SP = \"1.7.0\";\n\nconst MIN_ETHEREUM_APP_VERSION = \"1.23.0\";\nconst MIN_TRON_APP_VERSION = \"0.8.0\";\n// TEMPORARY (DSDK-1571) \u2014 the Solana app does not support Contacts yet and its\n// implementation is not scheduled, so this unreleased version keeps every\n// existing build out. Pin it to the first Contacts-enabled release once the\n// Solana app team names it.\nconst MIN_SOLANA_APP_VERSION = \"10.0.0\";\n\nconst MIN_APP_VERSION = {\n [ETHEREUM_APP_NAME]: MIN_ETHEREUM_APP_VERSION,\n [TRON_APP_NAME]: MIN_TRON_APP_VERSION,\n [SOLANA_APP_NAME]: MIN_SOLANA_APP_VERSION,\n};\n\n// TEMPORARY (DSDK-1481) \u2014 per-model cutoff below which the OS still requires the\n// EDIT CONTACT NAME derivation path. Each model's Address-Book-introducing OS\n// release shipped an rc2 that mandates the path (0x686A without it) and an rc3\n// that drops it (0x6A80 with it), so the cutoff is that release's `-rc3`. Only\n// Flex is hardware-confirmed (rc2 on a real device); the others follow the same\n// rc2/rc3 split per firmware \u2014 revise here if firmware says a model differs.\nconst RENAME_PATH_CUTOFF_STAX = `${MIN_OS_VERSION_STAX}-rc3`;\nconst RENAME_PATH_CUTOFF_FLEX = `${MIN_OS_VERSION_FLEX}-rc3`;\nconst RENAME_PATH_CUTOFF_APEX = `${MIN_OS_VERSION_APEX}-rc3`;\nconst RENAME_PATH_CUTOFF_NANO_X = `${MIN_OS_VERSION_NANO_X}-rc3`;\nconst RENAME_PATH_CUTOFF_NANO_SP = `${MIN_OS_VERSION_NANO_SP}-rc3`;\n\n/**\n * Contacts APDUs are supported on the touchscreen device models (Stax, Flex,\n * Apex) and on Nano X / Nano SP. Nano S does not support Contacts at all.\n */\nexport const CONTACTS_VERSION_REQUIREMENTS: ContactsVersionRequirements = {\n [DeviceModelId.NANO_S]: UNSUPPORTED,\n [DeviceModelId.NANO_SP]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_NANO_SP,\n minAppVersion: MIN_APP_VERSION,\n renameDerivationPathRequiredBelowOsVersion: RENAME_PATH_CUTOFF_NANO_SP,\n },\n [DeviceModelId.NANO_X]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_NANO_X,\n minAppVersion: MIN_APP_VERSION,\n renameDerivationPathRequiredBelowOsVersion: RENAME_PATH_CUTOFF_NANO_X,\n },\n [DeviceModelId.STAX]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_STAX,\n minAppVersion: MIN_APP_VERSION,\n renameDerivationPathRequiredBelowOsVersion: RENAME_PATH_CUTOFF_STAX,\n },\n [DeviceModelId.FLEX]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_FLEX,\n minAppVersion: MIN_APP_VERSION,\n renameDerivationPathRequiredBelowOsVersion: RENAME_PATH_CUTOFF_FLEX,\n },\n [DeviceModelId.APEX]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_APEX,\n minAppVersion: MIN_APP_VERSION,\n renameDerivationPathRequiredBelowOsVersion: RENAME_PATH_CUTOFF_APEX,\n },\n};\n\n/**\n * Resolve the Contacts version requirements for a device model \u2014 i.e. the\n * minimum supported OS and app versions, or that the model is unsupported.\n */\nexport function resolveContactsVersionRequirements(\n deviceModelId: DeviceModelId,\n): ContactsModelRequirement {\n return CONTACTS_VERSION_REQUIREMENTS[deviceModelId];\n}\n\n/**\n * Whether `actual` is greater than or equal to `minimum`, comparing as semver.\n * Tolerant of non-strict version strings and prerelease/build tags (coerces\n * both sides, which drops them) so a release candidate such as `1.7.0-rc2`\n * counts as meeting a `1.7.0` minimum. Returns `false` (i.e. requirement not\n * met) when either version cannot be parsed, so an unknown version never\n * passes a check.\n */\nexport function isVersionAtLeast(actual: string, minimum: string): boolean {\n const a = valid(coerce(actual));\n const b = valid(coerce(minimum));\n if (a === null || b === null) return false;\n return gte(a, b);\n}\n\n/**\n * Whether `actual` is strictly less than `boundary`, comparing as semver with\n * prerelease precedence preserved \u2014 unlike {@link isVersionAtLeast}, neither\n * side is coerced, so `1.7.0-rc2` sorts *below* `1.7.0-rc3` (and both below the\n * `1.7.0` release). Used to tell release candidates apart for the DSDK-1481\n * derivation-path cutoff, which `isVersionAtLeast` cannot do (it drops the\n * `-rcN` tag). Requires strict semver on both sides; returns `false` when\n * either cannot be parsed, so an unknown version is treated as *not* below the\n * boundary (i.e. the newer/GA payload shape).\n */\nexport function isVersionBelow(actual: string, boundary: string): boolean {\n const a = valid(actual);\n const b = valid(boundary);\n if (a === null || b === null) return false;\n return lt(a, b);\n}\n\n/**\n * TEMPORARY (DSDK-1481) \u2014 whether the EDIT CONTACT NAME (rename) payload must\n * carry the `DERIVATION_PATH` (tag 0x69) for a device on `osVersion`. True only\n * when the model is supported, declares a\n * {@link ContactsModelSupport.renameDerivationPathRequiredBelowOsVersion}\n * cutoff, and the fresh device OS version is strictly below that cutoff\n * (prerelease-aware). Callers pass the OS version read freshly from the device\n * (not the session state, which may be stale/absent on the dashboard path).\n */\nexport function renameRequiresDerivationPath(\n deviceModelId: DeviceModelId,\n osVersion: string,\n): boolean {\n const requirement = CONTACTS_VERSION_REQUIREMENTS[deviceModelId];\n if (!requirement.supported) return false;\n const cutoff = requirement.renameDerivationPathRequiredBelowOsVersion;\n if (cutoff === undefined) return false;\n return isVersionBelow(osVersion, cutoff);\n}\n"],
5
+ "mappings": "AAAA,OAAS,iBAAAA,MAAqB,kCAC9B,OAAS,UAAAC,EAAQ,OAAAC,EAAK,MAAAC,EAAI,SAAAC,MAAa,SAmDhC,MAAMC,EAAoB,WACpBC,EAAgB,OAChBC,EAAkB,SAEzBC,EAAwC,CAAE,UAAW,EAAM,EAE3DC,EAAsB,SACtBC,EAAsB,QACtBC,EAAsB,QACtBC,EAAwB,QACxBC,EAAyB,QAEzBC,EAA2B,SAC3BC,EAAuB,QAKvBC,EAAyB,SAEzBC,EAAkB,CACtB,CAACZ,CAAiB,EAAGS,EACrB,CAACR,CAAa,EAAGS,EACjB,CAACR,CAAe,EAAGS,CACrB,EAQME,EAA0B,GAAGT,CAAmB,OAChDU,EAA0B,GAAGT,CAAmB,OAChDU,EAA0B,GAAGT,CAAmB,OAChDU,EAA4B,GAAGT,CAAqB,OACpDU,EAA6B,GAAGT,CAAsB,OAM/CU,EAA6D,CACxE,CAACvB,EAAc,MAAM,EAAGQ,EACxB,CAACR,EAAc,OAAO,EAAG,CACvB,UAAW,GACX,aAAca,EACd,cAAeI,EACf,2CAA4CK,CAC9C,EACA,CAACtB,EAAc,MAAM,EAAG,CACtB,UAAW,GACX,aAAcY,EACd,cAAeK,EACf,2CAA4CI,CAC9C,EACA,CAACrB,EAAc,IAAI,EAAG,CACpB,UAAW,GACX,aAAcS,EACd,cAAeQ,EACf,2CAA4CC,CAC9C,EACA,CAAClB,EAAc,IAAI,EAAG,CACpB,UAAW,GACX,aAAcU,EACd,cAAeO,EACf,2CAA4CE,CAC9C,EACA,CAACnB,EAAc,IAAI,EAAG,CACpB,UAAW,GACX,aAAcW,EACd,cAAeM,EACf,2CAA4CG,CAC9C,CACF,EAMO,SAASI,EACdC,EAC0B,CAC1B,OAAOF,EAA8BE,CAAa,CACpD,CAUO,SAASC,EAAiBC,EAAgBC,EAA0B,CACzE,MAAMC,EAAIzB,EAAMH,EAAO0B,CAAM,CAAC,EACxBG,EAAI1B,EAAMH,EAAO2B,CAAO,CAAC,EAC/B,OAAIC,IAAM,MAAQC,IAAM,KAAa,GAC9B5B,EAAI2B,EAAGC,CAAC,CACjB,CAYO,SAASC,EAAeJ,EAAgBK,EAA2B,CACxE,MAAMH,EAAIzB,EAAMuB,CAAM,EAChBG,EAAI1B,EAAM4B,CAAQ,EACxB,OAAIH,IAAM,MAAQC,IAAM,KAAa,GAC9B3B,EAAG0B,EAAGC,CAAC,CAChB,CAWO,SAASG,EACdR,EACAS,EACS,CACT,MAAMC,EAAcZ,EAA8BE,CAAa,EAC/D,GAAI,CAACU,EAAY,UAAW,MAAO,GACnC,MAAMC,EAASD,EAAY,2CAC3B,OAAIC,IAAW,OAAkB,GAC1BL,EAAeG,EAAWE,CAAM,CACzC",
6
+ "names": ["DeviceModelId", "coerce", "gte", "lt", "valid", "ETHEREUM_APP_NAME", "TRON_APP_NAME", "SOLANA_APP_NAME", "UNSUPPORTED", "MIN_OS_VERSION_STAX", "MIN_OS_VERSION_FLEX", "MIN_OS_VERSION_APEX", "MIN_OS_VERSION_NANO_X", "MIN_OS_VERSION_NANO_SP", "MIN_ETHEREUM_APP_VERSION", "MIN_TRON_APP_VERSION", "MIN_SOLANA_APP_VERSION", "MIN_APP_VERSION", "RENAME_PATH_CUTOFF_STAX", "RENAME_PATH_CUTOFF_FLEX", "RENAME_PATH_CUTOFF_APEX", "RENAME_PATH_CUTOFF_NANO_X", "RENAME_PATH_CUTOFF_NANO_SP", "CONTACTS_VERSION_REQUIREMENTS", "resolveContactsVersionRequirements", "deviceModelId", "isVersionAtLeast", "actual", "minimum", "a", "b", "isVersionBelow", "boundary", "renameRequiresDerivationPath", "osVersion", "requirement", "cutoff"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{DeviceModelId as e}from"@ledgerhq/device-management-kit";import{CONTACTS_VERSION_REQUIREMENTS as i,ETHEREUM_APP_NAME as n,isVersionAtLeast as t,isVersionBelow as r,renameRequiresDerivationPath as s,resolveContactsVersionRequirements as a,TRON_APP_NAME as c}from"./ContactsVersionRequirements";describe("ContactsVersionRequirements",()=>{describe("resolveContactsVersionRequirements",()=>{it("marks every device model, supported or not",()=>{for(const o of Object.values(e))expect(i[o]).toBeDefined()}),it("reports Nano S as unsupported",()=>{expect(a(e.NANO_S)).toEqual({supported:!1})}),it("pins the minimum OS and app versions of every supported model",()=>{const o={[n]:"1.23.0",[c]:"0.8.0"};expect(i).toEqual({[e.NANO_S]:{supported:!1},[e.NANO_SP]:{supported:!0,minOsVersion:"1.7.0",minAppVersion:o,renameDerivationPathRequiredBelowOsVersion:"1.7.0-rc3"},[e.NANO_X]:{supported:!0,minOsVersion:"2.8.0",minAppVersion:o,renameDerivationPathRequiredBelowOsVersion:"2.8.0-rc3"},[e.STAX]:{supported:!0,minOsVersion:"1.11.0",minAppVersion:o,renameDerivationPathRequiredBelowOsVersion:"1.11.0-rc3"},[e.FLEX]:{supported:!0,minOsVersion:"1.7.0",minAppVersion:o,renameDerivationPathRequiredBelowOsVersion:"1.7.0-rc3"},[e.APEX]:{supported:!0,minOsVersion:"1.2.0",minAppVersion:o,renameDerivationPathRequiredBelowOsVersion:"1.2.0-rc3"}})})}),describe("isVersionAtLeast",()=>{it("compares versions as semver, inclusive of equality",()=>{expect(t("1.2.0","1.2.0")).toBe(!0),expect(t("1.3.0","1.2.0")).toBe(!0),expect(t("1.1.9","1.2.0")).toBe(!1)}),it("coerces non-strict version strings",()=>{expect(t("1.2","1.2.0")).toBe(!0)}),it("returns false when a version cannot be parsed",()=>{expect(t("not-a-version","1.2.0")).toBe(!1),expect(t("1.2.0","not-a-version")).toBe(!1)}),it("ignores prerelease and build tags when comparing to the minimum",()=>{expect(t("1.7.0-rc2","1.7.0")).toBe(!0),expect(t("1.23.0-dev","1.23.0")).toBe(!0)}),it("still fails a minimum strictly above the tagged version's core",()=>{expect(t("1.6.9-rc5","1.7.0")).toBe(!1)})}),describe("isVersionBelow",()=>{it("orders release candidates of the same core (unlike isVersionAtLeast)",()=>{expect(r("1.7.0-rc2","1.7.0-rc3")).toBe(!0),expect(r("1.7.0-rc3","1.7.0-rc3")).toBe(!1),expect(r("1.7.0-rc4","1.7.0-rc3")).toBe(!1)}),it("treats the final release as newer than any of its prereleases",()=>{expect(r("1.7.0","1.7.0-rc3")).toBe(!1)}),it("compares the release core when it differs",()=>{expect(r("1.6.9","1.7.0-rc3")).toBe(!0),expect(r("1.8.0","1.7.0-rc3")).toBe(!1)}),it("does not coerce, so a non-strict version is unparseable and returns false",()=>{expect(r("1.7","1.7.0-rc3")).toBe(!1),expect(r("not-a-version","1.7.0-rc3")).toBe(!1),expect(r("1.7.0-rc2","not-a-version")).toBe(!1)})}),describe("renameRequiresDerivationPath",()=>{it("requires the path below the model's cutoff (rc2) and not at/after it",()=>{expect(s(e.FLEX,"1.7.0-rc2")).toBe(!0),expect(s(e.FLEX,"1.7.0-rc3")).toBe(!1),expect(s(e.FLEX,"1.7.0")).toBe(!1),expect(s(e.FLEX,"1.8.0")).toBe(!1)}),it("applies the same rc2/rc3 split to the other supported models",()=>{expect(s(e.STAX,"1.11.0-rc2")).toBe(!0),expect(s(e.STAX,"1.11.0-rc3")).toBe(!1),expect(s(e.NANO_SP,"1.7.0-rc2")).toBe(!0)}),it("returns false for an unsupported model",()=>{expect(s(e.NANO_S,"1.7.0-rc2")).toBe(!1)}),it("returns false (no path) when the OS version is unparseable",()=>{expect(s(e.FLEX,"")).toBe(!1)})})});
1
+ import{DeviceModelId as e}from"@ledgerhq/device-management-kit";import{CONTACTS_VERSION_REQUIREMENTS as i,ETHEREUM_APP_NAME as n,isVersionAtLeast as t,isVersionBelow as r,renameRequiresDerivationPath as s,resolveContactsVersionRequirements as a,SOLANA_APP_NAME as c,TRON_APP_NAME as p}from"./ContactsVersionRequirements";describe("ContactsVersionRequirements",()=>{describe("resolveContactsVersionRequirements",()=>{it("marks every device model, supported or not",()=>{for(const o of Object.values(e))expect(i[o]).toBeDefined()}),it("reports Nano S as unsupported",()=>{expect(a(e.NANO_S)).toEqual({supported:!1})}),it("pins the minimum OS and app versions of every supported model",()=>{const o={[n]:"1.23.0",[p]:"0.8.0",[c]:"10.0.0"};expect(i).toEqual({[e.NANO_S]:{supported:!1},[e.NANO_SP]:{supported:!0,minOsVersion:"1.7.0",minAppVersion:o,renameDerivationPathRequiredBelowOsVersion:"1.7.0-rc3"},[e.NANO_X]:{supported:!0,minOsVersion:"2.8.0",minAppVersion:o,renameDerivationPathRequiredBelowOsVersion:"2.8.0-rc3"},[e.STAX]:{supported:!0,minOsVersion:"1.11.0",minAppVersion:o,renameDerivationPathRequiredBelowOsVersion:"1.11.0-rc3"},[e.FLEX]:{supported:!0,minOsVersion:"1.7.0",minAppVersion:o,renameDerivationPathRequiredBelowOsVersion:"1.7.0-rc3"},[e.APEX]:{supported:!0,minOsVersion:"1.2.0",minAppVersion:o,renameDerivationPathRequiredBelowOsVersion:"1.2.0-rc3"}})})}),describe("isVersionAtLeast",()=>{it("compares versions as semver, inclusive of equality",()=>{expect(t("1.2.0","1.2.0")).toBe(!0),expect(t("1.3.0","1.2.0")).toBe(!0),expect(t("1.1.9","1.2.0")).toBe(!1)}),it("coerces non-strict version strings",()=>{expect(t("1.2","1.2.0")).toBe(!0)}),it("returns false when a version cannot be parsed",()=>{expect(t("not-a-version","1.2.0")).toBe(!1),expect(t("1.2.0","not-a-version")).toBe(!1)}),it("ignores prerelease and build tags when comparing to the minimum",()=>{expect(t("1.7.0-rc2","1.7.0")).toBe(!0),expect(t("1.23.0-dev","1.23.0")).toBe(!0)}),it("still fails a minimum strictly above the tagged version's core",()=>{expect(t("1.6.9-rc5","1.7.0")).toBe(!1)})}),describe("isVersionBelow",()=>{it("orders release candidates of the same core (unlike isVersionAtLeast)",()=>{expect(r("1.7.0-rc2","1.7.0-rc3")).toBe(!0),expect(r("1.7.0-rc3","1.7.0-rc3")).toBe(!1),expect(r("1.7.0-rc4","1.7.0-rc3")).toBe(!1)}),it("treats the final release as newer than any of its prereleases",()=>{expect(r("1.7.0","1.7.0-rc3")).toBe(!1)}),it("compares the release core when it differs",()=>{expect(r("1.6.9","1.7.0-rc3")).toBe(!0),expect(r("1.8.0","1.7.0-rc3")).toBe(!1)}),it("does not coerce, so a non-strict version is unparseable and returns false",()=>{expect(r("1.7","1.7.0-rc3")).toBe(!1),expect(r("not-a-version","1.7.0-rc3")).toBe(!1),expect(r("1.7.0-rc2","not-a-version")).toBe(!1)})}),describe("renameRequiresDerivationPath",()=>{it("requires the path below the model's cutoff (rc2) and not at/after it",()=>{expect(s(e.FLEX,"1.7.0-rc2")).toBe(!0),expect(s(e.FLEX,"1.7.0-rc3")).toBe(!1),expect(s(e.FLEX,"1.7.0")).toBe(!1),expect(s(e.FLEX,"1.8.0")).toBe(!1)}),it("applies the same rc2/rc3 split to the other supported models",()=>{expect(s(e.STAX,"1.11.0-rc2")).toBe(!0),expect(s(e.STAX,"1.11.0-rc3")).toBe(!1),expect(s(e.NANO_SP,"1.7.0-rc2")).toBe(!0)}),it("returns false for an unsupported model",()=>{expect(s(e.NANO_S,"1.7.0-rc2")).toBe(!1)}),it("returns false (no path) when the OS version is unparseable",()=>{expect(s(e.FLEX,"")).toBe(!1)})})});
2
2
  //# sourceMappingURL=ContactsVersionRequirements.test.js.map