@ledgerhq/device-contacts-kit 0.4.0 → 0.5.0

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 (101) hide show
  1. package/lib/cjs/api/app-binder/RenameContactDeviceActionTypes.js.map +1 -1
  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 +3 -3
  8. package/lib/cjs/api/model/RenameContact.js.map +1 -1
  9. package/lib/cjs/internal/app-binder/command/EditExternalAddressIdentifierCommand.js +1 -1
  10. package/lib/cjs/internal/app-binder/command/EditExternalAddressIdentifierCommand.js.map +3 -3
  11. package/lib/cjs/internal/app-binder/command/EditExternalAddressScopeCommand.js +1 -1
  12. package/lib/cjs/internal/app-binder/command/EditExternalAddressScopeCommand.js.map +3 -3
  13. package/lib/cjs/internal/app-binder/command/ProvideContactCommand.js +1 -1
  14. package/lib/cjs/internal/app-binder/command/ProvideContactCommand.js.map +3 -3
  15. package/lib/cjs/internal/app-binder/command/RegisterIdentityCommand.js +1 -1
  16. package/lib/cjs/internal/app-binder/command/RegisterIdentityCommand.js.map +3 -3
  17. package/lib/cjs/internal/app-binder/command/RenameContactCommand.js +1 -1
  18. package/lib/cjs/internal/app-binder/command/RenameContactCommand.js.map +3 -3
  19. package/lib/cjs/internal/app-binder/command/RenameContactCommand.test.js +1 -1
  20. package/lib/cjs/internal/app-binder/command/RenameContactCommand.test.js.map +2 -2
  21. package/lib/cjs/internal/app-binder/contactsVersionGuards.js +1 -1
  22. package/lib/cjs/internal/app-binder/contactsVersionGuards.js.map +3 -3
  23. package/lib/cjs/internal/app-binder/contactsVersionGuards.test.js +1 -1
  24. package/lib/cjs/internal/app-binder/contactsVersionGuards.test.js.map +2 -2
  25. package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js +1 -1
  26. package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js.map +3 -3
  27. package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js +1 -1
  28. package/lib/cjs/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js.map +3 -3
  29. package/lib/cjs/internal/app-binder/model/contactsConstants.js +1 -1
  30. package/lib/cjs/internal/app-binder/model/contactsConstants.js.map +2 -2
  31. package/lib/cjs/internal/app-binder/model/contactsErrors.js +1 -1
  32. package/lib/cjs/internal/app-binder/model/contactsErrors.js.map +3 -3
  33. package/lib/cjs/internal/app-binder/services/provideContact.test.js +1 -1
  34. package/lib/cjs/internal/app-binder/services/provideContact.test.js.map +2 -2
  35. package/lib/cjs/internal/app-binder/task/SendRenameContactTask.js +1 -1
  36. package/lib/cjs/internal/app-binder/task/SendRenameContactTask.js.map +2 -2
  37. package/lib/cjs/internal/app-binder/task/SendRenameContactTask.test.js +1 -1
  38. package/lib/cjs/internal/app-binder/task/SendRenameContactTask.test.js.map +3 -3
  39. package/lib/cjs/package.json +1 -1
  40. package/lib/esm/api/index.js +1 -1
  41. package/lib/esm/api/index.js.map +3 -3
  42. package/lib/esm/api/model/ContactsVersionRequirements.js +1 -1
  43. package/lib/esm/api/model/ContactsVersionRequirements.js.map +3 -3
  44. package/lib/esm/api/model/ContactsVersionRequirements.test.js +1 -1
  45. package/lib/esm/api/model/ContactsVersionRequirements.test.js.map +3 -3
  46. package/lib/esm/internal/app-binder/command/EditExternalAddressIdentifierCommand.js +1 -1
  47. package/lib/esm/internal/app-binder/command/EditExternalAddressIdentifierCommand.js.map +3 -3
  48. package/lib/esm/internal/app-binder/command/EditExternalAddressScopeCommand.js +1 -1
  49. package/lib/esm/internal/app-binder/command/EditExternalAddressScopeCommand.js.map +3 -3
  50. package/lib/esm/internal/app-binder/command/ProvideContactCommand.js +1 -1
  51. package/lib/esm/internal/app-binder/command/ProvideContactCommand.js.map +3 -3
  52. package/lib/esm/internal/app-binder/command/RegisterIdentityCommand.js +1 -1
  53. package/lib/esm/internal/app-binder/command/RegisterIdentityCommand.js.map +3 -3
  54. package/lib/esm/internal/app-binder/command/RenameContactCommand.js +1 -1
  55. package/lib/esm/internal/app-binder/command/RenameContactCommand.js.map +3 -3
  56. package/lib/esm/internal/app-binder/command/RenameContactCommand.test.js +1 -1
  57. package/lib/esm/internal/app-binder/command/RenameContactCommand.test.js.map +3 -3
  58. package/lib/esm/internal/app-binder/contactsVersionGuards.js +1 -1
  59. package/lib/esm/internal/app-binder/contactsVersionGuards.js.map +3 -3
  60. package/lib/esm/internal/app-binder/contactsVersionGuards.test.js +1 -1
  61. package/lib/esm/internal/app-binder/contactsVersionGuards.test.js.map +3 -3
  62. package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js +1 -1
  63. package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.js.map +3 -3
  64. package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js +1 -1
  65. package/lib/esm/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.test.js.map +3 -3
  66. package/lib/esm/internal/app-binder/model/contactsConstants.js +1 -1
  67. package/lib/esm/internal/app-binder/model/contactsConstants.js.map +2 -2
  68. package/lib/esm/internal/app-binder/model/contactsErrors.js +1 -1
  69. package/lib/esm/internal/app-binder/model/contactsErrors.js.map +3 -3
  70. package/lib/esm/internal/app-binder/services/provideContact.test.js +1 -1
  71. package/lib/esm/internal/app-binder/services/provideContact.test.js.map +2 -2
  72. package/lib/esm/internal/app-binder/task/SendRenameContactTask.js +1 -1
  73. package/lib/esm/internal/app-binder/task/SendRenameContactTask.js.map +3 -3
  74. package/lib/esm/internal/app-binder/task/SendRenameContactTask.test.js +1 -1
  75. package/lib/esm/internal/app-binder/task/SendRenameContactTask.test.js.map +3 -3
  76. package/lib/esm/package.json +1 -1
  77. package/lib/types/api/app-binder/RenameContactDeviceActionTypes.d.ts +2 -1
  78. package/lib/types/api/app-binder/RenameContactDeviceActionTypes.d.ts.map +1 -1
  79. package/lib/types/api/index.d.ts +1 -1
  80. package/lib/types/api/index.d.ts.map +1 -1
  81. package/lib/types/api/model/ContactsVersionRequirements.d.ts +36 -3
  82. package/lib/types/api/model/ContactsVersionRequirements.d.ts.map +1 -1
  83. package/lib/types/api/model/RenameContact.d.ts +5 -3
  84. package/lib/types/api/model/RenameContact.d.ts.map +1 -1
  85. package/lib/types/internal/app-binder/command/EditExternalAddressIdentifierCommand.d.ts.map +1 -1
  86. package/lib/types/internal/app-binder/command/EditExternalAddressScopeCommand.d.ts.map +1 -1
  87. package/lib/types/internal/app-binder/command/ProvideContactCommand.d.ts.map +1 -1
  88. package/lib/types/internal/app-binder/command/RegisterIdentityCommand.d.ts.map +1 -1
  89. package/lib/types/internal/app-binder/command/RenameContactCommand.d.ts.map +1 -1
  90. package/lib/types/internal/app-binder/contactsVersionGuards.d.ts +9 -1
  91. package/lib/types/internal/app-binder/contactsVersionGuards.d.ts.map +1 -1
  92. package/lib/types/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.d.ts +4 -3
  93. package/lib/types/internal/app-binder/device-action/RenameContact/RenameContactDeviceAction.d.ts.map +1 -1
  94. package/lib/types/internal/app-binder/model/contactsConstants.d.ts +2 -2
  95. package/lib/types/internal/app-binder/model/contactsConstants.d.ts.map +1 -1
  96. package/lib/types/internal/app-binder/model/contactsErrors.d.ts +21 -2
  97. package/lib/types/internal/app-binder/model/contactsErrors.d.ts.map +1 -1
  98. package/lib/types/internal/app-binder/task/SendRenameContactTask.d.ts +8 -0
  99. package/lib/types/internal/app-binder/task/SendRenameContactTask.d.ts.map +1 -1
  100. package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
  101. package/package.json +6 -6
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/task/SendRenameContactTask.ts"],
4
- "sourcesContent": ["// Builds the TLV payload for the Rename Contact (EDIT CONTACT NAME) op and\n// dispatches it via the chunked-framing scheme shared with the other\n// address-book ops (2-byte BE total length + <=255B chunks). Rename is an\n// OS/dashboard command (CLA 0xE0 / INS 0x2E) \u2014 the caller runs this task after\n// navigating to the dashboard (GoToDashboardDeviceAction), never inside an app.\n//\n// The device rotates the contact-level hmac_name and returns the fresh proof on\n// the final chunk; per-entry hmac_rest values are untouched (they bind\n// gid|scope|id|family|chain_id, never the name), so a single APDU regardless of\n// the contact's entry count.\n//\n// Reference: Address Book Final Specifications \u2014 Edit Contact Name. Tag order:\n// STRUCT_TYPE, STRUCT_VERSION, CONTACT_NAME (new), PREVIOUS_CONTACT_NAME\n// (old), GROUP_HANDLE, HMAC_PROOF.\n//\n// No DERIVATION_PATH. The tag's status changed three times in the BOLOS SDK,\n// and the address-book TLV parser is compiled into the app (app_features/), so\n// the SDK revision the app was *built* against decides \u2014 not the app version,\n// which reads 1.23.0-dev either way:\n// - before 2026-08-07: tag 0x69 present and MANDATORY, omitting it -> 0x6a80\n// - 8e7e7a4f (2026-08-07): made optional, both forms accepted\n// - a0bb21f5 (2026-08-10): removed, sending it -> 0x6a80 (unknown tag)\n// Omitting it is therefore correct for any app built from 2026-08-07 onward,\n// and wrong for one built before. Both ends verified on hardware: a Flex\n// running a pre-08-07 build of app-ethereum a79f9f8f rejects the payload\n// without the tag in 9ms and no review screen; Speculos running a post-08-10\n// build of the same commit rejects it *with* the tag, the same way.\nimport {\n ByteArrayBuilder,\n type CommandResult,\n DmkResultFactory,\n type InternalApi,\n InvalidStatusWordError,\n isSuccessCommandResult,\n type LoggerPublisherService,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { RenameContactCommand } from \"@internal/app-binder/command/RenameContactCommand\";\nimport { RENAME_CONTACT_P1 } 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 encodeTlvUInt8,\n STRUCT_TYPE_EDIT_CONTACT_NAME,\n STRUCT_VERSION_VALUE,\n} from \"@internal/app-binder/services/contactsTlvSerializer\";\nimport { sendFramedContactsPayload } from \"@internal/app-binder/services/sendFramedContactsPayload\";\n\nexport type RenameContactProof = {\n readonly hmacProof: Uint8Array;\n};\n\nexport type SendRenameContactTaskArgs = {\n readonly previousContactName: string;\n readonly newContactName: string;\n readonly groupHandle: Uint8Array;\n readonly hmacProof: Uint8Array;\n readonly logger?: LoggerPublisherService;\n};\n\nexport class SendRenameContactTask {\n constructor(\n private readonly api: InternalApi,\n private readonly args: SendRenameContactTaskArgs,\n ) {}\n\n async run(): Promise<CommandResult<RenameContactProof, ContactsErrorCodes>> {\n const payload = this.buildPayload(this.args);\n\n const result = (await sendFramedContactsPayload(this.api, {\n payload,\n p1: RENAME_CONTACT_P1,\n makeCommand: (chunk, p2) => new RenameContactCommand({ data: chunk, p2 }),\n logger: this.args.logger,\n commandTag: \"SendRenameContactTask\",\n })) as CommandResult<\n { readonly hmacProof?: Uint8Array },\n ContactsErrorCodes\n >;\n\n if (!isSuccessCommandResult(result)) {\n return result;\n }\n\n const { hmacProof } = result.data;\n if (!hmacProof) {\n return DmkResultFactory({\n error: new InvalidStatusWordError(\n \"RenameContact final-chunk response did not carry hmac_name\",\n ),\n });\n }\n return DmkResultFactory({ data: { hmacProof } });\n }\n\n private buildPayload(args: SendRenameContactTaskArgs): Uint8Array {\n const builder = new ByteArrayBuilder();\n encodeTlvUInt8(\n builder,\n CONTACTS_TLV_TAG.STRUCT_TYPE,\n STRUCT_TYPE_EDIT_CONTACT_NAME,\n );\n encodeTlvUInt8(\n builder,\n CONTACTS_TLV_TAG.STRUCT_VERSION,\n STRUCT_VERSION_VALUE,\n );\n encodeTlvAscii(builder, CONTACTS_TLV_TAG.CONTACT_NAME, args.newContactName);\n encodeTlvAscii(\n builder,\n CONTACTS_TLV_TAG.PREVIOUS_CONTACT_NAME,\n args.previousContactName,\n );\n encodeTlvBuffer(builder, CONTACTS_TLV_TAG.GROUP_HANDLE, args.groupHandle);\n encodeTlvBuffer(builder, CONTACTS_TLV_TAG.HMAC_PROOF, args.hmacProof);\n\n return builder.build();\n }\n}\n"],
5
- "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,2BAAAE,IAAA,eAAAC,EAAAH,GA2BA,IAAAI,EAQO,2CAEPC,EAAqC,6DACrCC,EAAkC,wDAElCC,EAOO,+DACPC,EAA0C,mEAcnC,MAAMN,CAAsB,CACjC,YACmBO,EACAC,EACjB,CAFiB,SAAAD,EACA,UAAAC,CAChB,CAEH,MAAM,KAAsE,CAC1E,MAAMC,EAAU,KAAK,aAAa,KAAK,IAAI,EAErCC,EAAU,QAAM,6BAA0B,KAAK,IAAK,CACxD,QAAAD,EACA,GAAI,oBACJ,YAAa,CAACE,EAAOC,IAAO,IAAI,uBAAqB,CAAE,KAAMD,EAAO,GAAAC,CAAG,CAAC,EACxE,OAAQ,KAAK,KAAK,OAClB,WAAY,uBACd,CAAC,EAKD,GAAI,IAAC,0BAAuBF,CAAM,EAChC,OAAOA,EAGT,KAAM,CAAE,UAAAG,CAAU,EAAIH,EAAO,KAC7B,OAAKG,KAOE,oBAAiB,CAAE,KAAM,CAAE,UAAAA,CAAU,CAAE,CAAC,KANtC,oBAAiB,CACtB,MAAO,IAAI,yBACT,4DACF,CACF,CAAC,CAGL,CAEQ,aAAaL,EAA6C,CAChE,MAAMM,EAAU,IAAI,mBACpB,2BACEA,EACA,mBAAiB,YACjB,+BACF,KACA,kBACEA,EACA,mBAAiB,eACjB,sBACF,KACA,kBAAeA,EAAS,mBAAiB,aAAcN,EAAK,cAAc,KAC1E,kBACEM,EACA,mBAAiB,sBACjBN,EAAK,mBACP,KACA,mBAAgBM,EAAS,mBAAiB,aAAcN,EAAK,WAAW,KACxE,mBAAgBM,EAAS,mBAAiB,WAAYN,EAAK,SAAS,EAE7DM,EAAQ,MAAM,CACvB,CACF",
4
+ "sourcesContent": ["// Builds the TLV payload for the Rename Contact (EDIT CONTACT NAME) op and\n// dispatches it via the chunked-framing scheme shared with the other\n// address-book ops (2-byte BE total length + <=255B chunks). Rename is an\n// OS/dashboard command (CLA 0xE0 / INS 0x2E) \u2014 the caller runs this task after\n// navigating to the dashboard (GoToDashboardDeviceAction), never inside an app.\n//\n// The device rotates the contact-level hmac_name and returns the fresh proof on\n// the final chunk; per-entry hmac_rest values are untouched (they bind\n// gid|scope|id|family|chain_id, never the name), so a single APDU regardless of\n// the contact's entry count.\n//\n// Reference: Address Book Final Specifications \u2014 Edit Contact Name. Tag order:\n// STRUCT_TYPE, STRUCT_VERSION, CONTACT_NAME (new), PREVIOUS_CONTACT_NAME\n// (old), GROUP_HANDLE, [DERIVATION_PATH], HMAC_PROOF.\n//\n// DERIVATION_PATH (tag 0x69) is CONDITIONAL (DSDK-1481). The final product\n// serves rename from the OS, which needs no path \u2014 but the OS build decides the\n// payload shape, and the two shapes are mutually exclusive across builds:\n// - OS below the model's cutoff (e.g. Flex 1.7.0-rc2 and earlier): the path\n// is still MANDATORY, omitting it -> 0x686A (before any review screen).\n// - OS at/after the cutoff (Flex 1.7.0-rc3, final, later): the path is\n// rejected, sending it -> 0x6A80 (unknown tag).\n// So the caller passes includeDerivationPath, computed from the device OS\n// version read *freshly* from the device (renameRequiresDerivationPath), and we\n// emit the tag only for the older builds. This shim \u2014 the flag, the cutoff\n// table entries, and renameRequiresDerivationPath \u2014 is removed in one commit\n// once no in-the-field OS predates the cutoff. The rc2 requirement was verified\n// on hardware: a Flex on OS 1.7.0-rc2 rejects the path-free payload with 0x686A.\nimport {\n ByteArrayBuilder,\n type CommandResult,\n DmkResultFactory,\n type InternalApi,\n InvalidStatusWordError,\n isSuccessCommandResult,\n type LoggerPublisherService,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { RenameContactCommand } from \"@internal/app-binder/command/RenameContactCommand\";\nimport { RENAME_CONTACT_P1 } 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 encodeTlvUInt8,\n packDerivationPath,\n STRUCT_TYPE_EDIT_CONTACT_NAME,\n STRUCT_VERSION_VALUE,\n} from \"@internal/app-binder/services/contactsTlvSerializer\";\nimport { sendFramedContactsPayload } from \"@internal/app-binder/services/sendFramedContactsPayload\";\n\nexport type RenameContactProof = {\n readonly hmacProof: Uint8Array;\n};\n\nexport type SendRenameContactTaskArgs = {\n readonly previousContactName: string;\n readonly newContactName: string;\n readonly groupHandle: Uint8Array;\n readonly hmacProof: Uint8Array;\n /**\n * TEMPORARY (DSDK-1481) \u2014 emit the `DERIVATION_PATH` (tag 0x69) TLV. Defaults\n * to `false` (the GA payload, path-free). The caller sets it `true` only for\n * OS builds below the model's cutoff, which still mandate the path; see\n * {@link renameRequiresDerivationPath}. Not exposed on the public\n * `RenameContactInput` \u2014 the host never chooses this.\n */\n readonly includeDerivationPath?: boolean;\n readonly logger?: LoggerPublisherService;\n};\n\nexport class SendRenameContactTask {\n constructor(\n private readonly api: InternalApi,\n private readonly args: SendRenameContactTaskArgs,\n ) {}\n\n async run(): Promise<CommandResult<RenameContactProof, ContactsErrorCodes>> {\n const payload = this.buildPayload(this.args);\n\n const result = (await sendFramedContactsPayload(this.api, {\n payload,\n p1: RENAME_CONTACT_P1,\n makeCommand: (chunk, p2) => new RenameContactCommand({ data: chunk, p2 }),\n logger: this.args.logger,\n commandTag: \"SendRenameContactTask\",\n })) as CommandResult<\n { readonly hmacProof?: Uint8Array },\n ContactsErrorCodes\n >;\n\n if (!isSuccessCommandResult(result)) {\n return result;\n }\n\n const { hmacProof } = result.data;\n if (!hmacProof) {\n return DmkResultFactory({\n error: new InvalidStatusWordError(\n \"RenameContact final-chunk response did not carry hmac_name\",\n ),\n });\n }\n return DmkResultFactory({ data: { hmacProof } });\n }\n\n private buildPayload(args: SendRenameContactTaskArgs): Uint8Array {\n const builder = new ByteArrayBuilder();\n encodeTlvUInt8(\n builder,\n CONTACTS_TLV_TAG.STRUCT_TYPE,\n STRUCT_TYPE_EDIT_CONTACT_NAME,\n );\n encodeTlvUInt8(\n builder,\n CONTACTS_TLV_TAG.STRUCT_VERSION,\n STRUCT_VERSION_VALUE,\n );\n encodeTlvAscii(builder, CONTACTS_TLV_TAG.CONTACT_NAME, args.newContactName);\n encodeTlvAscii(\n builder,\n CONTACTS_TLV_TAG.PREVIOUS_CONTACT_NAME,\n args.previousContactName,\n );\n encodeTlvBuffer(builder, CONTACTS_TLV_TAG.GROUP_HANDLE, args.groupHandle);\n // TEMPORARY (DSDK-1481): OS builds below the model's cutoff still mandate\n // DERIVATION_PATH for EDIT CONTACT NAME (0x686A without it); newer builds\n // reject it (0x6A80). The caller sets includeDerivationPath from the fresh\n // device OS version. Fixed m/44'/60'/0'/0/0 \u2014 rename is name-only, the path\n // is a payload-shape formality the old OS parser requires.\n if (args.includeDerivationPath) {\n encodeTlvBuffer(\n builder,\n CONTACTS_TLV_TAG.DERIVATION_PATH,\n packDerivationPath([0x8000002c, 0x8000003c, 0x80000000, 0, 0]),\n );\n }\n encodeTlvBuffer(builder, CONTACTS_TLV_TAG.HMAC_PROOF, args.hmacProof);\n\n return builder.build();\n }\n}\n"],
5
+ "mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,2BAAAE,IAAA,eAAAC,EAAAH,GA4BA,IAAAI,EAQO,2CAEPC,EAAqC,6DACrCC,EAAkC,wDAElCC,EAQO,+DACPC,EAA0C,mEAsBnC,MAAMN,CAAsB,CACjC,YACmBO,EACAC,EACjB,CAFiB,SAAAD,EACA,UAAAC,CAChB,CAEH,MAAM,KAAsE,CAC1E,MAAMC,EAAU,KAAK,aAAa,KAAK,IAAI,EAErCC,EAAU,QAAM,6BAA0B,KAAK,IAAK,CACxD,QAAAD,EACA,GAAI,oBACJ,YAAa,CAACE,EAAOC,IAAO,IAAI,uBAAqB,CAAE,KAAMD,EAAO,GAAAC,CAAG,CAAC,EACxE,OAAQ,KAAK,KAAK,OAClB,WAAY,uBACd,CAAC,EAKD,GAAI,IAAC,0BAAuBF,CAAM,EAChC,OAAOA,EAGT,KAAM,CAAE,UAAAG,CAAU,EAAIH,EAAO,KAC7B,OAAKG,KAOE,oBAAiB,CAAE,KAAM,CAAE,UAAAA,CAAU,CAAE,CAAC,KANtC,oBAAiB,CACtB,MAAO,IAAI,yBACT,4DACF,CACF,CAAC,CAGL,CAEQ,aAAaL,EAA6C,CAChE,MAAMM,EAAU,IAAI,mBACpB,2BACEA,EACA,mBAAiB,YACjB,+BACF,KACA,kBACEA,EACA,mBAAiB,eACjB,sBACF,KACA,kBAAeA,EAAS,mBAAiB,aAAcN,EAAK,cAAc,KAC1E,kBACEM,EACA,mBAAiB,sBACjBN,EAAK,mBACP,KACA,mBAAgBM,EAAS,mBAAiB,aAAcN,EAAK,WAAW,EAMpEA,EAAK,0BACP,mBACEM,EACA,mBAAiB,mBACjB,sBAAmB,CAAC,WAAY,WAAY,WAAY,EAAG,CAAC,CAAC,CAC/D,KAEF,mBAAgBA,EAAS,mBAAiB,WAAYN,EAAK,SAAS,EAE7DM,EAAQ,MAAM,CACvB,CACF",
6
6
  "names": ["SendRenameContactTask_exports", "__export", "SendRenameContactTask", "__toCommonJS", "import_device_management_kit", "import_RenameContactCommand", "import_contactsConstants", "import_contactsTlvSerializer", "import_sendFramedContactsPayload", "api", "args", "payload", "result", "chunk", "p2", "hmacProof", "builder"]
7
7
  }
@@ -1,2 +1,2 @@
1
- "use strict";var a=require("@ledgerhq/device-management-kit"),i=require("../../app-binder/command/RenameContactCommand"),o=require("./SendRenameContactTask");function s(e){const n=new Uint8Array(e.length/2);for(let t=0;t<e.length;t+=2)n[t/2]=parseInt(e.slice(t,t+2),16);return n}const r=s("cc".repeat(64)),c=s("dd".repeat(32)),d=s("ee".repeat(32)),l=s("007901012e02010181f003426f6281f305416c69636581f640"+"cc".repeat(64)+"2920"+"dd".repeat(32));function m(){return{sendCommand:vi.fn()}}describe("SendRenameContactTask",()=>{it("assembles the rename framed chunk and dispatches RenameContactCommand",async()=>{const e=m();e.sendCommand.mockResolvedValueOnce((0,a.CommandResultFactory)({data:{hmacProof:d}}));const n=await new o.SendRenameContactTask(e,{previousContactName:"Alice",newContactName:"Bob",groupHandle:r,hmacProof:c}).run();expect(e.sendCommand.mock.calls).toHaveLength(1),expect(e.sendCommand.mock.calls[0][0]).toStrictEqual(new i.RenameContactCommand({data:l,p2:0})),expect(n).toStrictEqual((0,a.CommandResultFactory)({data:{hmacProof:d}}))}),it("does not emit a DERIVATION_PATH tag",async()=>{const e=m();e.sendCommand.mockResolvedValueOnce((0,a.CommandResultFactory)({data:{hmacProof:d}})),await new o.SendRenameContactTask(e,{previousContactName:"Alice",newContactName:"Bob",groupHandle:r,hmacProof:c}).run();const n=e.sendCommand.mock.calls[0][0],t=Buffer.from(n.args.data).toString("hex");expect(t).not.toContain("691505"),expect(t.endsWith("81f640"+"cc".repeat(64)+"2920"+"dd".repeat(32))).toBe(!0)}),it("propagates command-level errors",async()=>{const e=m();e.sendCommand.mockResolvedValueOnce((0,a.CommandResultFactory)({error:new a.InvalidStatusWordError("user cancelled")}));const n=await new o.SendRenameContactTask(e,{previousContactName:"Alice",newContactName:"Bob",groupHandle:r,hmacProof:c}).run();expect(n).toStrictEqual((0,a.CommandResultFactory)({error:new a.InvalidStatusWordError("user cancelled")}))}),it("returns InvalidStatusWordError when the final response carries no hmac_name",async()=>{const e=m();e.sendCommand.mockResolvedValueOnce((0,a.CommandResultFactory)({data:{}}));const n=await new o.SendRenameContactTask(e,{previousContactName:"Alice",newContactName:"Bob",groupHandle:r,hmacProof:c}).run();expect(n.status).not.toBe(void 0),"error"in n&&expect(n.error).toBeInstanceOf(a.InvalidStatusWordError)})});
1
+ "use strict";var t=require("@ledgerhq/device-management-kit"),i=require("../../app-binder/command/RenameContactCommand"),o=require("./SendRenameContactTask");function s(e){const a=new Uint8Array(e.length/2);for(let n=0;n<e.length;n+=2)a[n/2]=parseInt(e.slice(n,n+2),16);return a}const c=s("cc".repeat(64)),r=s("dd".repeat(32)),d=s("ee".repeat(32)),p=s("007901012e02010181f003426f6281f305416c69636581f640"+"cc".repeat(64)+"2920"+"dd".repeat(32));function m(){return{sendCommand:vi.fn()}}describe("SendRenameContactTask",()=>{it("assembles the rename framed chunk and dispatches RenameContactCommand",async()=>{const e=m();e.sendCommand.mockResolvedValueOnce((0,t.CommandResultFactory)({data:{hmacProof:d}}));const a=await new o.SendRenameContactTask(e,{previousContactName:"Alice",newContactName:"Bob",groupHandle:c,hmacProof:r}).run();expect(e.sendCommand.mock.calls).toHaveLength(1),expect(e.sendCommand.mock.calls[0][0]).toStrictEqual(new i.RenameContactCommand({data:p,p2:0})),expect(a).toStrictEqual((0,t.CommandResultFactory)({data:{hmacProof:d}}))}),it("does not emit a DERIVATION_PATH tag by default",async()=>{const e=m();e.sendCommand.mockResolvedValueOnce((0,t.CommandResultFactory)({data:{hmacProof:d}})),await new o.SendRenameContactTask(e,{previousContactName:"Alice",newContactName:"Bob",groupHandle:c,hmacProof:r}).run();const a=e.sendCommand.mock.calls[0][0],n=Buffer.from(a.args.data).toString("hex");expect(n).not.toContain("6915"),expect(n.endsWith("81f640"+"cc".repeat(64)+"2920"+"dd".repeat(32))).toBe(!0)}),it("emits the DERIVATION_PATH tag when includeDerivationPath is set",async()=>{const e=m();e.sendCommand.mockResolvedValueOnce((0,t.CommandResultFactory)({data:{hmacProof:d}})),await new o.SendRenameContactTask(e,{previousContactName:"Alice",newContactName:"Bob",groupHandle:c,hmacProof:r,includeDerivationPath:!0}).run();const n=s("009001012e02010181f003426f6281f305416c69636581f640"+"cc".repeat(64)+"6915058000002c8000003c800000000000000000000000"+"2920"+"dd".repeat(32)),l=e.sendCommand.mock.calls[0][0];expect(l).toStrictEqual(new i.RenameContactCommand({data:n,p2:0}))}),it("propagates command-level errors",async()=>{const e=m();e.sendCommand.mockResolvedValueOnce((0,t.CommandResultFactory)({error:new t.InvalidStatusWordError("user cancelled")}));const a=await new o.SendRenameContactTask(e,{previousContactName:"Alice",newContactName:"Bob",groupHandle:c,hmacProof:r}).run();expect(a).toStrictEqual((0,t.CommandResultFactory)({error:new t.InvalidStatusWordError("user cancelled")}))}),it("returns InvalidStatusWordError when the final response carries no hmac_name",async()=>{const e=m();e.sendCommand.mockResolvedValueOnce((0,t.CommandResultFactory)({data:{}}));const a=await new o.SendRenameContactTask(e,{previousContactName:"Alice",newContactName:"Bob",groupHandle:c,hmacProof:r}).run();expect(a.status).not.toBe(void 0),"error"in a&&expect(a.error).toBeInstanceOf(t.InvalidStatusWordError)})});
2
2
  //# sourceMappingURL=SendRenameContactTask.test.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/task/SendRenameContactTask.test.ts"],
4
- "sourcesContent": ["// Validates that the TLV serializer + tag ordering + chunk framing produce the\n// expected wire bytes for the Rename Contact (EDIT CONTACT NAME) op. The framed\n// chunk = 2-byte BE total length + TLV. Tag order: STRUCT_TYPE, STRUCT_VERSION,\n// CONTACT_NAME (new), PREVIOUS_CONTACT_NAME (old), GROUP_HANDLE, HMAC_PROOF \u2014\n// with tags >= 0x80 (0xf0/0xf3/0xf6) encoded as the 2-byte DER form [0x81, tag].\n// No DERIVATION_PATH: the SDK removed tag 0x69 from EDIT_CONTACT_NAME_TAGS on\n// 2026-08-10 and rejects payloads carrying it.\nimport {\n CommandResultFactory,\n type InternalApi,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { RenameContactCommand } from \"@internal/app-binder/command/RenameContactCommand\";\n\nimport { SendRenameContactTask } from \"./SendRenameContactTask\";\n\nfunction hexToBytes(hex: string): Uint8Array {\n const out = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n out[i / 2] = parseInt(hex.slice(i, i + 2), 16);\n }\n return out;\n}\n\nconst GROUP_HANDLE = hexToBytes(\"cc\".repeat(64));\nconst HMAC_PROOF_IN = hexToBytes(\"dd\".repeat(32));\nconst HMAC_PROOF_OUT = hexToBytes(\"ee\".repeat(32));\n\n// Framed chunk = \"00 79\" (2-byte BE total TLV length = 121) + TLV:\n// 01 01 2e STRUCT_TYPE = EDIT_CONTACT_NAME (0x2e)\n// 02 01 01 STRUCT_VERSION = 1\n// 81 f0 03 \"Bob\" CONTACT_NAME (new), tag 0xf0 -> [81 f0]\n// 81 f3 05 \"Alice\" PREVIOUS_CONTACT_NAME (old), tag 0xf3 -> [81 f3]\n// 81 f6 40 <64x cc> GROUP_HANDLE, tag 0xf6 -> [81 f6]\n// 29 20 <32x dd> HMAC_PROOF\nconst FRAMED_CHUNK = hexToBytes(\n \"0079\" +\n \"01012e\" +\n \"020101\" +\n \"81f003426f62\" +\n \"81f305416c696365\" +\n \"81f640\" +\n \"cc\".repeat(64) +\n \"2920\" +\n \"dd\".repeat(32),\n);\n\nfunction makeApiMock(): InternalApi & {\n sendCommand: ReturnType<typeof vi.fn>;\n} {\n return { sendCommand: vi.fn() } as unknown as InternalApi & {\n sendCommand: ReturnType<typeof vi.fn>;\n };\n}\n\ndescribe(\"SendRenameContactTask\", () => {\n it(\"assembles the rename framed chunk and dispatches RenameContactCommand\", async () => {\n const api = makeApiMock();\n api.sendCommand.mockResolvedValueOnce(\n CommandResultFactory({ data: { hmacProof: HMAC_PROOF_OUT } }),\n );\n\n const result = await new SendRenameContactTask(api, {\n previousContactName: \"Alice\",\n newContactName: \"Bob\",\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF_IN,\n }).run();\n\n expect(api.sendCommand.mock.calls).toHaveLength(1);\n expect(api.sendCommand.mock.calls[0]![0]).toStrictEqual(\n new RenameContactCommand({ data: FRAMED_CHUNK, p2: 0x00 }),\n );\n expect(result).toStrictEqual(\n CommandResultFactory({ data: { hmacProof: HMAC_PROOF_OUT } }),\n );\n });\n\n it(\"does not emit a DERIVATION_PATH tag\", async () => {\n const api = makeApiMock();\n api.sendCommand.mockResolvedValueOnce(\n CommandResultFactory({ data: { hmacProof: HMAC_PROOF_OUT } }),\n );\n\n await new SendRenameContactTask(api, {\n previousContactName: \"Alice\",\n newContactName: \"Bob\",\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF_IN,\n }).run();\n\n // api-level 27 dropped tag 0x69 from EDIT_CONTACT_NAME_TAGS: a payload\n // carrying it fails to parse and the device answers 0x6a80. HMAC_PROOF\n // (0x29) therefore follows GROUP_HANDLE directly.\n const command = api.sendCommand.mock.calls[0]![0] as RenameContactCommand;\n const framedHex = Buffer.from(command.args.data).toString(\"hex\");\n expect(framedHex).not.toContain(\"691505\");\n expect(\n framedHex.endsWith(\"81f640\" + \"cc\".repeat(64) + \"2920\" + \"dd\".repeat(32)),\n ).toBe(true);\n });\n\n it(\"propagates command-level errors\", async () => {\n const api = makeApiMock();\n api.sendCommand.mockResolvedValueOnce(\n CommandResultFactory({\n error: new InvalidStatusWordError(\"user cancelled\"),\n }),\n );\n\n const result = await new SendRenameContactTask(api, {\n previousContactName: \"Alice\",\n newContactName: \"Bob\",\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF_IN,\n }).run();\n\n expect(result).toStrictEqual(\n CommandResultFactory({\n error: new InvalidStatusWordError(\"user cancelled\"),\n }),\n );\n });\n\n it(\"returns InvalidStatusWordError when the final response carries no hmac_name\", async () => {\n const api = makeApiMock();\n api.sendCommand.mockResolvedValueOnce(CommandResultFactory({ data: {} }));\n\n const result = await new SendRenameContactTask(api, {\n previousContactName: \"Alice\",\n newContactName: \"Bob\",\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF_IN,\n }).run();\n\n expect(result.status).not.toBe(undefined);\n if (\"error\" in result) {\n expect(result.error).toBeInstanceOf(InvalidStatusWordError);\n }\n });\n});\n"],
5
- "mappings": "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",
6
- "names": ["import_device_management_kit", "import_RenameContactCommand", "import_SendRenameContactTask", "hexToBytes", "hex", "out", "i", "GROUP_HANDLE", "HMAC_PROOF_IN", "HMAC_PROOF_OUT", "FRAMED_CHUNK", "makeApiMock", "api", "result", "command", "framedHex"]
4
+ "sourcesContent": ["// Validates that the TLV serializer + tag ordering + chunk framing produce the\n// expected wire bytes for the Rename Contact (EDIT CONTACT NAME) op. The framed\n// chunk = 2-byte BE total length + TLV. Tag order: STRUCT_TYPE, STRUCT_VERSION,\n// CONTACT_NAME (new), PREVIOUS_CONTACT_NAME (old), GROUP_HANDLE, HMAC_PROOF \u2014\n// with tags >= 0x80 (0xf0/0xf3/0xf6) encoded as the 2-byte DER form [0x81, tag].\n// DERIVATION_PATH (tag 0x69) is CONDITIONAL (DSDK-1481): omitted by default (the\n// GA payload), and inserted between GROUP_HANDLE and HMAC_PROOF only when the\n// caller passes includeDerivationPath \u2014 the shape older OS builds still require.\nimport {\n CommandResultFactory,\n type InternalApi,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\n\nimport { RenameContactCommand } from \"@internal/app-binder/command/RenameContactCommand\";\n\nimport { SendRenameContactTask } from \"./SendRenameContactTask\";\n\nfunction hexToBytes(hex: string): Uint8Array {\n const out = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n out[i / 2] = parseInt(hex.slice(i, i + 2), 16);\n }\n return out;\n}\n\nconst GROUP_HANDLE = hexToBytes(\"cc\".repeat(64));\nconst HMAC_PROOF_IN = hexToBytes(\"dd\".repeat(32));\nconst HMAC_PROOF_OUT = hexToBytes(\"ee\".repeat(32));\n\n// Framed chunk = \"00 79\" (2-byte BE total TLV length = 121) + TLV:\n// 01 01 2e STRUCT_TYPE = EDIT_CONTACT_NAME (0x2e)\n// 02 01 01 STRUCT_VERSION = 1\n// 81 f0 03 \"Bob\" CONTACT_NAME (new), tag 0xf0 -> [81 f0]\n// 81 f3 05 \"Alice\" PREVIOUS_CONTACT_NAME (old), tag 0xf3 -> [81 f3]\n// 81 f6 40 <64x cc> GROUP_HANDLE, tag 0xf6 -> [81 f6]\n// 29 20 <32x dd> HMAC_PROOF\nconst FRAMED_CHUNK = hexToBytes(\n \"0079\" +\n \"01012e\" +\n \"020101\" +\n \"81f003426f62\" +\n \"81f305416c696365\" +\n \"81f640\" +\n \"cc\".repeat(64) +\n \"2920\" +\n \"dd\".repeat(32),\n);\n\nfunction makeApiMock(): InternalApi & {\n sendCommand: ReturnType<typeof vi.fn>;\n} {\n return { sendCommand: vi.fn() } as unknown as InternalApi & {\n sendCommand: ReturnType<typeof vi.fn>;\n };\n}\n\ndescribe(\"SendRenameContactTask\", () => {\n it(\"assembles the rename framed chunk and dispatches RenameContactCommand\", async () => {\n const api = makeApiMock();\n api.sendCommand.mockResolvedValueOnce(\n CommandResultFactory({ data: { hmacProof: HMAC_PROOF_OUT } }),\n );\n\n const result = await new SendRenameContactTask(api, {\n previousContactName: \"Alice\",\n newContactName: \"Bob\",\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF_IN,\n }).run();\n\n expect(api.sendCommand.mock.calls).toHaveLength(1);\n expect(api.sendCommand.mock.calls[0]![0]).toStrictEqual(\n new RenameContactCommand({ data: FRAMED_CHUNK, p2: 0x00 }),\n );\n expect(result).toStrictEqual(\n CommandResultFactory({ data: { hmacProof: HMAC_PROOF_OUT } }),\n );\n });\n\n it(\"does not emit a DERIVATION_PATH tag by default\", async () => {\n const api = makeApiMock();\n api.sendCommand.mockResolvedValueOnce(\n CommandResultFactory({ data: { hmacProof: HMAC_PROOF_OUT } }),\n );\n\n await new SendRenameContactTask(api, {\n previousContactName: \"Alice\",\n newContactName: \"Bob\",\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF_IN,\n }).run();\n\n // GA payload (includeDerivationPath omitted): newer OS builds reject tag\n // 0x69, so HMAC_PROOF (0x29) follows GROUP_HANDLE directly.\n const command = api.sendCommand.mock.calls[0]![0] as RenameContactCommand;\n const framedHex = Buffer.from(command.args.data).toString(\"hex\");\n expect(framedHex).not.toContain(\"6915\");\n expect(\n framedHex.endsWith(\"81f640\" + \"cc\".repeat(64) + \"2920\" + \"dd\".repeat(32)),\n ).toBe(true);\n });\n\n it(\"emits the DERIVATION_PATH tag when includeDerivationPath is set\", async () => {\n const api = makeApiMock();\n api.sendCommand.mockResolvedValueOnce(\n CommandResultFactory({ data: { hmacProof: HMAC_PROOF_OUT } }),\n );\n\n await new SendRenameContactTask(api, {\n previousContactName: \"Alice\",\n newContactName: \"Bob\",\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF_IN,\n includeDerivationPath: true,\n }).run();\n\n // Older OS builds (below the model cutoff) mandate tag 0x69. The path TLV\n // (fixed m/44'/60'/0'/0/0) sits between GROUP_HANDLE and HMAC_PROOF, and the\n // framed total length grows by its 23 bytes: 0x0079 -> 0x0090.\n // 69 15 05 8000002c 8000003c 80000000 00000000 00000000\n const pathTlv =\n \"6915\" +\n \"05\" +\n \"8000002c\" +\n \"8000003c\" +\n \"80000000\" +\n \"00000000\" +\n \"00000000\";\n const expectedFramed = hexToBytes(\n \"0090\" +\n \"01012e\" +\n \"020101\" +\n \"81f003426f62\" +\n \"81f305416c696365\" +\n \"81f640\" +\n \"cc\".repeat(64) +\n pathTlv +\n \"2920\" +\n \"dd\".repeat(32),\n );\n const command = api.sendCommand.mock.calls[0]![0] as RenameContactCommand;\n expect(command).toStrictEqual(\n new RenameContactCommand({ data: expectedFramed, p2: 0x00 }),\n );\n });\n\n it(\"propagates command-level errors\", async () => {\n const api = makeApiMock();\n api.sendCommand.mockResolvedValueOnce(\n CommandResultFactory({\n error: new InvalidStatusWordError(\"user cancelled\"),\n }),\n );\n\n const result = await new SendRenameContactTask(api, {\n previousContactName: \"Alice\",\n newContactName: \"Bob\",\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF_IN,\n }).run();\n\n expect(result).toStrictEqual(\n CommandResultFactory({\n error: new InvalidStatusWordError(\"user cancelled\"),\n }),\n );\n });\n\n it(\"returns InvalidStatusWordError when the final response carries no hmac_name\", async () => {\n const api = makeApiMock();\n api.sendCommand.mockResolvedValueOnce(CommandResultFactory({ data: {} }));\n\n const result = await new SendRenameContactTask(api, {\n previousContactName: \"Alice\",\n newContactName: \"Bob\",\n groupHandle: GROUP_HANDLE,\n hmacProof: HMAC_PROOF_IN,\n }).run();\n\n expect(result.status).not.toBe(undefined);\n if (\"error\" in result) {\n expect(result.error).toBeInstanceOf(InvalidStatusWordError);\n }\n });\n});\n"],
5
+ "mappings": "aAQA,IAAAA,EAIO,2CAEPC,EAAqC,6DAErCC,EAAsC,mCAEtC,SAASC,EAAWC,EAAyB,CAC3C,MAAMC,EAAM,IAAI,WAAWD,EAAI,OAAS,CAAC,EACzC,QAASE,EAAI,EAAGA,EAAIF,EAAI,OAAQE,GAAK,EACnCD,EAAIC,EAAI,CAAC,EAAI,SAASF,EAAI,MAAME,EAAGA,EAAI,CAAC,EAAG,EAAE,EAE/C,OAAOD,CACT,CAEA,MAAME,EAAeJ,EAAW,KAAK,OAAO,EAAE,CAAC,EACzCK,EAAgBL,EAAW,KAAK,OAAO,EAAE,CAAC,EAC1CM,EAAiBN,EAAW,KAAK,OAAO,EAAE,CAAC,EAS3CO,EAAeP,EACnB,qDAME,KAAK,OAAO,EAAE,EACd,OACA,KAAK,OAAO,EAAE,CAClB,EAEA,SAASQ,GAEP,CACA,MAAO,CAAE,YAAa,GAAG,GAAG,CAAE,CAGhC,CAEA,SAAS,wBAAyB,IAAM,CACtC,GAAG,wEAAyE,SAAY,CACtF,MAAMC,EAAMD,EAAY,EACxBC,EAAI,YAAY,yBACd,wBAAqB,CAAE,KAAM,CAAE,UAAWH,CAAe,CAAE,CAAC,CAC9D,EAEA,MAAMI,EAAS,MAAM,IAAI,wBAAsBD,EAAK,CAClD,oBAAqB,QACrB,eAAgB,MAChB,YAAaL,EACb,UAAWC,CACb,CAAC,EAAE,IAAI,EAEP,OAAOI,EAAI,YAAY,KAAK,KAAK,EAAE,aAAa,CAAC,EACjD,OAAOA,EAAI,YAAY,KAAK,MAAM,CAAC,EAAG,CAAC,CAAC,EAAE,cACxC,IAAI,uBAAqB,CAAE,KAAMF,EAAc,GAAI,CAAK,CAAC,CAC3D,EACA,OAAOG,CAAM,EAAE,iBACb,wBAAqB,CAAE,KAAM,CAAE,UAAWJ,CAAe,CAAE,CAAC,CAC9D,CACF,CAAC,EAED,GAAG,iDAAkD,SAAY,CAC/D,MAAMG,EAAMD,EAAY,EACxBC,EAAI,YAAY,yBACd,wBAAqB,CAAE,KAAM,CAAE,UAAWH,CAAe,CAAE,CAAC,CAC9D,EAEA,MAAM,IAAI,wBAAsBG,EAAK,CACnC,oBAAqB,QACrB,eAAgB,MAChB,YAAaL,EACb,UAAWC,CACb,CAAC,EAAE,IAAI,EAIP,MAAMM,EAAUF,EAAI,YAAY,KAAK,MAAM,CAAC,EAAG,CAAC,EAC1CG,EAAY,OAAO,KAAKD,EAAQ,KAAK,IAAI,EAAE,SAAS,KAAK,EAC/D,OAAOC,CAAS,EAAE,IAAI,UAAU,MAAM,EACtC,OACEA,EAAU,SAAS,SAAW,KAAK,OAAO,EAAE,EAAI,OAAS,KAAK,OAAO,EAAE,CAAC,CAC1E,EAAE,KAAK,EAAI,CACb,CAAC,EAED,GAAG,kEAAmE,SAAY,CAChF,MAAMH,EAAMD,EAAY,EACxBC,EAAI,YAAY,yBACd,wBAAqB,CAAE,KAAM,CAAE,UAAWH,CAAe,CAAE,CAAC,CAC9D,EAEA,MAAM,IAAI,wBAAsBG,EAAK,CACnC,oBAAqB,QACrB,eAAgB,MAChB,YAAaL,EACb,UAAWC,EACX,sBAAuB,EACzB,CAAC,EAAE,IAAI,EAcP,MAAMQ,EAAiBb,EACrB,qDAME,KAAK,OAAO,EAAE,EAdhB,iDAgBE,OACA,KAAK,OAAO,EAAE,CAClB,EACMW,EAAUF,EAAI,YAAY,KAAK,MAAM,CAAC,EAAG,CAAC,EAChD,OAAOE,CAAO,EAAE,cACd,IAAI,uBAAqB,CAAE,KAAME,EAAgB,GAAI,CAAK,CAAC,CAC7D,CACF,CAAC,EAED,GAAG,kCAAmC,SAAY,CAChD,MAAMJ,EAAMD,EAAY,EACxBC,EAAI,YAAY,yBACd,wBAAqB,CACnB,MAAO,IAAI,yBAAuB,gBAAgB,CACpD,CAAC,CACH,EAEA,MAAMC,EAAS,MAAM,IAAI,wBAAsBD,EAAK,CAClD,oBAAqB,QACrB,eAAgB,MAChB,YAAaL,EACb,UAAWC,CACb,CAAC,EAAE,IAAI,EAEP,OAAOK,CAAM,EAAE,iBACb,wBAAqB,CACnB,MAAO,IAAI,yBAAuB,gBAAgB,CACpD,CAAC,CACH,CACF,CAAC,EAED,GAAG,8EAA+E,SAAY,CAC5F,MAAMD,EAAMD,EAAY,EACxBC,EAAI,YAAY,yBAAsB,wBAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,CAAC,EAExE,MAAMC,EAAS,MAAM,IAAI,wBAAsBD,EAAK,CAClD,oBAAqB,QACrB,eAAgB,MAChB,YAAaL,EACb,UAAWC,CACb,CAAC,EAAE,IAAI,EAEP,OAAOK,EAAO,MAAM,EAAE,IAAI,KAAK,MAAS,EACpC,UAAWA,GACb,OAAOA,EAAO,KAAK,EAAE,eAAe,wBAAsB,CAE9D,CAAC,CACH,CAAC",
6
+ "names": ["import_device_management_kit", "import_RenameContactCommand", "import_SendRenameContactTask", "hexToBytes", "hex", "out", "i", "GROUP_HANDLE", "HMAC_PROOF_IN", "HMAC_PROOF_OUT", "FRAMED_CHUNK", "makeApiMock", "api", "result", "command", "framedHex", "expectedFramed"]
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.4.0"
61
+ "version": "0.5.0"
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}from"./model/ContactsVersionRequirements";import{buildProvideContactPayload as i,sendProvideContactPayload as A}from"../internal/app-binder/services/provideContact";export{n as CONTACTS_VERSION_REQUIREMENTS,r as ContactsManagerBuilder,p as ETHEREUM_APP_NAME,i as buildProvideContactPayload,o as isVersionAtLeast,s as resolveContactsVersionRequirements,A 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,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};
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} 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,MACK,yCAqBP,OACE,8BAAAC,EACA,6BAAAC,MAEK",
6
- "names": ["ContactsManagerBuilder", "CONTACTS_VERSION_REQUIREMENTS", "ETHEREUM_APP_NAME", "isVersionAtLeast", "resolveContactsVersionRequirements", "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 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"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{DeviceModelId as e}from"@ledgerhq/device-management-kit";import{coerce as p,gte as u,valid as i}from"semver";const o="Ethereum",c={supported:!1},l="1.11.0",N="1.7.0",_="1.2.0",O="2.8.0",a="1.7.0",t="1.23.0",m={[e.NANO_S]:c,[e.NANO_SP]:{supported:!0,minOsVersion:a,minAppVersion:{[o]:t}},[e.NANO_X]:{supported:!0,minOsVersion:O,minAppVersion:{[o]:t}},[e.STAX]:{supported:!0,minOsVersion:l,minAppVersion:{[o]:t}},[e.FLEX]:{supported:!0,minOsVersion:N,minAppVersion:{[o]:t}},[e.APEX]:{supported:!0,minOsVersion:_,minAppVersion:{[o]:t}}};function R(n){return m[n]}function S(n,d){const r=i(p(n)),s=i(p(d));return r===null||s===null?!1:u(r,s)}export{m as CONTACTS_VERSION_REQUIREMENTS,o as ETHEREUM_APP_NAME,S as isVersionAtLeast,R as resolveContactsVersionRequirements};
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};
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, 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; v1 ships\n * Ethereum only.\n */\nexport type ContactsModelSupport = {\n readonly supported: true;\n readonly minOsVersion: string;\n readonly minAppVersion: Readonly<Record<string, 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/** The name of the Ethereum embedded app (the only app supported in v1). */\nexport const ETHEREUM_APP_NAME = \"Ethereum\";\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\";\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: { [ETHEREUM_APP_NAME]: MIN_ETHEREUM_APP_VERSION },\n },\n [DeviceModelId.NANO_X]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_NANO_X,\n minAppVersion: { [ETHEREUM_APP_NAME]: MIN_ETHEREUM_APP_VERSION },\n },\n [DeviceModelId.STAX]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_STAX,\n minAppVersion: { [ETHEREUM_APP_NAME]: MIN_ETHEREUM_APP_VERSION },\n },\n [DeviceModelId.FLEX]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_FLEX,\n minAppVersion: { [ETHEREUM_APP_NAME]: MIN_ETHEREUM_APP_VERSION },\n },\n [DeviceModelId.APEX]: {\n supported: true,\n minOsVersion: MIN_OS_VERSION_APEX,\n minAppVersion: { [ETHEREUM_APP_NAME]: MIN_ETHEREUM_APP_VERSION },\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"],
5
- "mappings": "AAAA,OAAS,iBAAAA,MAAqB,kCAC9B,OAAS,UAAAC,EAAQ,OAAAC,EAAK,SAAAC,MAAa,SAwC5B,MAAMC,EAAoB,WAE3BC,EAAwC,CAAE,UAAW,EAAM,EAE3DC,EAAsB,SACtBC,EAAsB,QACtBC,EAAsB,QACtBC,EAAwB,QACxBC,EAAyB,QAEzBC,EAA2B,SAMpBC,EAA6D,CACxE,CAACZ,EAAc,MAAM,EAAGK,EACxB,CAACL,EAAc,OAAO,EAAG,CACvB,UAAW,GACX,aAAcU,EACd,cAAe,CAAE,CAACN,CAAiB,EAAGO,CAAyB,CACjE,EACA,CAACX,EAAc,MAAM,EAAG,CACtB,UAAW,GACX,aAAcS,EACd,cAAe,CAAE,CAACL,CAAiB,EAAGO,CAAyB,CACjE,EACA,CAACX,EAAc,IAAI,EAAG,CACpB,UAAW,GACX,aAAcM,EACd,cAAe,CAAE,CAACF,CAAiB,EAAGO,CAAyB,CACjE,EACA,CAACX,EAAc,IAAI,EAAG,CACpB,UAAW,GACX,aAAcO,EACd,cAAe,CAAE,CAACH,CAAiB,EAAGO,CAAyB,CACjE,EACA,CAACX,EAAc,IAAI,EAAG,CACpB,UAAW,GACX,aAAcQ,EACd,cAAe,CAAE,CAACJ,CAAiB,EAAGO,CAAyB,CACjE,CACF,EAMO,SAASE,EACdC,EAC0B,CAC1B,OAAOF,EAA8BE,CAAa,CACpD,CAUO,SAASC,EAAiBC,EAAgBC,EAA0B,CACzE,MAAMC,EAAIf,EAAMF,EAAOe,CAAM,CAAC,EACxBG,EAAIhB,EAAMF,EAAOgB,CAAO,CAAC,EAC/B,OAAIC,IAAM,MAAQC,IAAM,KAAa,GAC9BjB,EAAIgB,EAAGC,CAAC,CACjB",
6
- "names": ["DeviceModelId", "coerce", "gte", "valid", "ETHEREUM_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", "CONTACTS_VERSION_REQUIREMENTS", "resolveContactsVersionRequirements", "deviceModelId", "isVersionAtLeast", "actual", "minimum", "a", "b"]
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"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{DeviceModelId as t}from"@ledgerhq/device-management-kit";import{CONTACTS_VERSION_REQUIREMENTS as o,ETHEREUM_APP_NAME as r,isVersionAtLeast as e,resolveContactsVersionRequirements as i}from"./ContactsVersionRequirements";describe("ContactsVersionRequirements",()=>{describe("resolveContactsVersionRequirements",()=>{it("marks every device model, supported or not",()=>{for(const s of Object.values(t))expect(o[s]).toBeDefined()}),it("reports Nano S as unsupported",()=>{expect(i(t.NANO_S)).toEqual({supported:!1})}),it("pins the minimum OS and app versions of every supported model",()=>{const s={[r]:"1.23.0"};expect(o).toEqual({[t.NANO_S]:{supported:!1},[t.NANO_SP]:{supported:!0,minOsVersion:"1.7.0",minAppVersion:s},[t.NANO_X]:{supported:!0,minOsVersion:"2.8.0",minAppVersion:s},[t.STAX]:{supported:!0,minOsVersion:"1.11.0",minAppVersion:s},[t.FLEX]:{supported:!0,minOsVersion:"1.7.0",minAppVersion:s},[t.APEX]:{supported:!0,minOsVersion:"1.2.0",minAppVersion:s}})})}),describe("isVersionAtLeast",()=>{it("compares versions as semver, inclusive of equality",()=>{expect(e("1.2.0","1.2.0")).toBe(!0),expect(e("1.3.0","1.2.0")).toBe(!0),expect(e("1.1.9","1.2.0")).toBe(!1)}),it("coerces non-strict version strings",()=>{expect(e("1.2","1.2.0")).toBe(!0)}),it("returns false when a version cannot be parsed",()=>{expect(e("not-a-version","1.2.0")).toBe(!1),expect(e("1.2.0","not-a-version")).toBe(!1)}),it("ignores prerelease and build tags when comparing to the minimum",()=>{expect(e("1.7.0-rc2","1.7.0")).toBe(!0),expect(e("1.23.0-dev","1.23.0")).toBe(!0)}),it("still fails a minimum strictly above the tagged version's core",()=>{expect(e("1.6.9-rc5","1.7.0")).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,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)})})});
2
2
  //# sourceMappingURL=ContactsVersionRequirements.test.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/api/model/ContactsVersionRequirements.test.ts"],
4
- "sourcesContent": ["import { DeviceModelId } from \"@ledgerhq/device-management-kit\";\n\nimport {\n CONTACTS_VERSION_REQUIREMENTS,\n ETHEREUM_APP_NAME,\n isVersionAtLeast,\n resolveContactsVersionRequirements,\n} from \"./ContactsVersionRequirements\";\n\ndescribe(\"ContactsVersionRequirements\", () => {\n describe(\"resolveContactsVersionRequirements\", () => {\n it(\"marks every device model, supported or not\", () => {\n for (const modelId of Object.values(DeviceModelId)) {\n expect(CONTACTS_VERSION_REQUIREMENTS[modelId]).toBeDefined();\n }\n });\n\n it(\"reports Nano S as unsupported\", () => {\n expect(resolveContactsVersionRequirements(DeviceModelId.NANO_S)).toEqual({\n supported: false,\n });\n });\n\n // Pins the minimums themselves, not just their shape: each OS version is\n // the release whose changelog introduces the Address Book feature, so a\n // change here has to be a deliberate one, reviewed against that release.\n it(\"pins the minimum OS and app versions of every supported model\", () => {\n const ethereum = { [ETHEREUM_APP_NAME]: \"1.23.0\" };\n\n expect(CONTACTS_VERSION_REQUIREMENTS).toEqual({\n [DeviceModelId.NANO_S]: { supported: false },\n [DeviceModelId.NANO_SP]: {\n supported: true,\n minOsVersion: \"1.7.0\",\n minAppVersion: ethereum,\n },\n [DeviceModelId.NANO_X]: {\n supported: true,\n minOsVersion: \"2.8.0\",\n minAppVersion: ethereum,\n },\n [DeviceModelId.STAX]: {\n supported: true,\n minOsVersion: \"1.11.0\",\n minAppVersion: ethereum,\n },\n [DeviceModelId.FLEX]: {\n supported: true,\n minOsVersion: \"1.7.0\",\n minAppVersion: ethereum,\n },\n [DeviceModelId.APEX]: {\n supported: true,\n minOsVersion: \"1.2.0\",\n minAppVersion: ethereum,\n },\n });\n });\n });\n\n describe(\"isVersionAtLeast\", () => {\n it(\"compares versions as semver, inclusive of equality\", () => {\n expect(isVersionAtLeast(\"1.2.0\", \"1.2.0\")).toBe(true);\n expect(isVersionAtLeast(\"1.3.0\", \"1.2.0\")).toBe(true);\n expect(isVersionAtLeast(\"1.1.9\", \"1.2.0\")).toBe(false);\n });\n\n it(\"coerces non-strict version strings\", () => {\n expect(isVersionAtLeast(\"1.2\", \"1.2.0\")).toBe(true);\n });\n\n it(\"returns false when a version cannot be parsed\", () => {\n expect(isVersionAtLeast(\"not-a-version\", \"1.2.0\")).toBe(false);\n expect(isVersionAtLeast(\"1.2.0\", \"not-a-version\")).toBe(false);\n });\n\n it(\"ignores prerelease and build tags when comparing to the minimum\", () => {\n expect(isVersionAtLeast(\"1.7.0-rc2\", \"1.7.0\")).toBe(true);\n expect(isVersionAtLeast(\"1.23.0-dev\", \"1.23.0\")).toBe(true);\n });\n\n it(\"still fails a minimum strictly above the tagged version's core\", () => {\n expect(isVersionAtLeast(\"1.6.9-rc5\", \"1.7.0\")).toBe(false);\n });\n });\n});\n"],
5
- "mappings": "AAAA,OAAS,iBAAAA,MAAqB,kCAE9B,OACE,iCAAAC,EACA,qBAAAC,EACA,oBAAAC,EACA,sCAAAC,MACK,gCAEP,SAAS,8BAA+B,IAAM,CAC5C,SAAS,qCAAsC,IAAM,CACnD,GAAG,6CAA8C,IAAM,CACrD,UAAWC,KAAW,OAAO,OAAOL,CAAa,EAC/C,OAAOC,EAA8BI,CAAO,CAAC,EAAE,YAAY,CAE/D,CAAC,EAED,GAAG,gCAAiC,IAAM,CACxC,OAAOD,EAAmCJ,EAAc,MAAM,CAAC,EAAE,QAAQ,CACvE,UAAW,EACb,CAAC,CACH,CAAC,EAKD,GAAG,gEAAiE,IAAM,CACxE,MAAMM,EAAW,CAAE,CAACJ,CAAiB,EAAG,QAAS,EAEjD,OAAOD,CAA6B,EAAE,QAAQ,CAC5C,CAACD,EAAc,MAAM,EAAG,CAAE,UAAW,EAAM,EAC3C,CAACA,EAAc,OAAO,EAAG,CACvB,UAAW,GACX,aAAc,QACd,cAAeM,CACjB,EACA,CAACN,EAAc,MAAM,EAAG,CACtB,UAAW,GACX,aAAc,QACd,cAAeM,CACjB,EACA,CAACN,EAAc,IAAI,EAAG,CACpB,UAAW,GACX,aAAc,SACd,cAAeM,CACjB,EACA,CAACN,EAAc,IAAI,EAAG,CACpB,UAAW,GACX,aAAc,QACd,cAAeM,CACjB,EACA,CAACN,EAAc,IAAI,EAAG,CACpB,UAAW,GACX,aAAc,QACd,cAAeM,CACjB,CACF,CAAC,CACH,CAAC,CACH,CAAC,EAED,SAAS,mBAAoB,IAAM,CACjC,GAAG,qDAAsD,IAAM,CAC7D,OAAOH,EAAiB,QAAS,OAAO,CAAC,EAAE,KAAK,EAAI,EACpD,OAAOA,EAAiB,QAAS,OAAO,CAAC,EAAE,KAAK,EAAI,EACpD,OAAOA,EAAiB,QAAS,OAAO,CAAC,EAAE,KAAK,EAAK,CACvD,CAAC,EAED,GAAG,qCAAsC,IAAM,CAC7C,OAAOA,EAAiB,MAAO,OAAO,CAAC,EAAE,KAAK,EAAI,CACpD,CAAC,EAED,GAAG,gDAAiD,IAAM,CACxD,OAAOA,EAAiB,gBAAiB,OAAO,CAAC,EAAE,KAAK,EAAK,EAC7D,OAAOA,EAAiB,QAAS,eAAe,CAAC,EAAE,KAAK,EAAK,CAC/D,CAAC,EAED,GAAG,kEAAmE,IAAM,CAC1E,OAAOA,EAAiB,YAAa,OAAO,CAAC,EAAE,KAAK,EAAI,EACxD,OAAOA,EAAiB,aAAc,QAAQ,CAAC,EAAE,KAAK,EAAI,CAC5D,CAAC,EAED,GAAG,iEAAkE,IAAM,CACzE,OAAOA,EAAiB,YAAa,OAAO,CAAC,EAAE,KAAK,EAAK,CAC3D,CAAC,CACH,CAAC,CACH,CAAC",
6
- "names": ["DeviceModelId", "CONTACTS_VERSION_REQUIREMENTS", "ETHEREUM_APP_NAME", "isVersionAtLeast", "resolveContactsVersionRequirements", "modelId", "ethereum"]
4
+ "sourcesContent": ["import { DeviceModelId } from \"@ledgerhq/device-management-kit\";\n\nimport {\n CONTACTS_VERSION_REQUIREMENTS,\n ETHEREUM_APP_NAME,\n isVersionAtLeast,\n isVersionBelow,\n renameRequiresDerivationPath,\n resolveContactsVersionRequirements,\n TRON_APP_NAME,\n} from \"./ContactsVersionRequirements\";\n\ndescribe(\"ContactsVersionRequirements\", () => {\n describe(\"resolveContactsVersionRequirements\", () => {\n it(\"marks every device model, supported or not\", () => {\n for (const modelId of Object.values(DeviceModelId)) {\n expect(CONTACTS_VERSION_REQUIREMENTS[modelId]).toBeDefined();\n }\n });\n\n it(\"reports Nano S as unsupported\", () => {\n expect(resolveContactsVersionRequirements(DeviceModelId.NANO_S)).toEqual({\n supported: false,\n });\n });\n\n // Pins the minimums themselves, not just their shape: each OS version is\n // the release whose changelog introduces the Address Book feature, so a\n // change here has to be a deliberate one, reviewed against that release.\n it(\"pins the minimum OS and app versions of every supported model\", () => {\n const appVersions = {\n [ETHEREUM_APP_NAME]: \"1.23.0\",\n [TRON_APP_NAME]: \"0.8.0\",\n };\n\n expect(CONTACTS_VERSION_REQUIREMENTS).toEqual({\n [DeviceModelId.NANO_S]: { supported: false },\n [DeviceModelId.NANO_SP]: {\n supported: true,\n minOsVersion: \"1.7.0\",\n minAppVersion: appVersions,\n renameDerivationPathRequiredBelowOsVersion: \"1.7.0-rc3\",\n },\n [DeviceModelId.NANO_X]: {\n supported: true,\n minOsVersion: \"2.8.0\",\n minAppVersion: appVersions,\n renameDerivationPathRequiredBelowOsVersion: \"2.8.0-rc3\",\n },\n [DeviceModelId.STAX]: {\n supported: true,\n minOsVersion: \"1.11.0\",\n minAppVersion: appVersions,\n renameDerivationPathRequiredBelowOsVersion: \"1.11.0-rc3\",\n },\n [DeviceModelId.FLEX]: {\n supported: true,\n minOsVersion: \"1.7.0\",\n minAppVersion: appVersions,\n renameDerivationPathRequiredBelowOsVersion: \"1.7.0-rc3\",\n },\n [DeviceModelId.APEX]: {\n supported: true,\n minOsVersion: \"1.2.0\",\n minAppVersion: appVersions,\n renameDerivationPathRequiredBelowOsVersion: \"1.2.0-rc3\",\n },\n });\n });\n });\n\n describe(\"isVersionAtLeast\", () => {\n it(\"compares versions as semver, inclusive of equality\", () => {\n expect(isVersionAtLeast(\"1.2.0\", \"1.2.0\")).toBe(true);\n expect(isVersionAtLeast(\"1.3.0\", \"1.2.0\")).toBe(true);\n expect(isVersionAtLeast(\"1.1.9\", \"1.2.0\")).toBe(false);\n });\n\n it(\"coerces non-strict version strings\", () => {\n expect(isVersionAtLeast(\"1.2\", \"1.2.0\")).toBe(true);\n });\n\n it(\"returns false when a version cannot be parsed\", () => {\n expect(isVersionAtLeast(\"not-a-version\", \"1.2.0\")).toBe(false);\n expect(isVersionAtLeast(\"1.2.0\", \"not-a-version\")).toBe(false);\n });\n\n it(\"ignores prerelease and build tags when comparing to the minimum\", () => {\n expect(isVersionAtLeast(\"1.7.0-rc2\", \"1.7.0\")).toBe(true);\n expect(isVersionAtLeast(\"1.23.0-dev\", \"1.23.0\")).toBe(true);\n });\n\n it(\"still fails a minimum strictly above the tagged version's core\", () => {\n expect(isVersionAtLeast(\"1.6.9-rc5\", \"1.7.0\")).toBe(false);\n });\n });\n\n describe(\"isVersionBelow\", () => {\n it(\"orders release candidates of the same core (unlike isVersionAtLeast)\", () => {\n // The whole reason this helper exists: rc2 must sort below rc3.\n expect(isVersionBelow(\"1.7.0-rc2\", \"1.7.0-rc3\")).toBe(true);\n expect(isVersionBelow(\"1.7.0-rc3\", \"1.7.0-rc3\")).toBe(false);\n expect(isVersionBelow(\"1.7.0-rc4\", \"1.7.0-rc3\")).toBe(false);\n });\n\n it(\"treats the final release as newer than any of its prereleases\", () => {\n expect(isVersionBelow(\"1.7.0\", \"1.7.0-rc3\")).toBe(false);\n });\n\n it(\"compares the release core when it differs\", () => {\n expect(isVersionBelow(\"1.6.9\", \"1.7.0-rc3\")).toBe(true);\n expect(isVersionBelow(\"1.8.0\", \"1.7.0-rc3\")).toBe(false);\n });\n\n it(\"does not coerce, so a non-strict version is unparseable and returns false\", () => {\n expect(isVersionBelow(\"1.7\", \"1.7.0-rc3\")).toBe(false);\n expect(isVersionBelow(\"not-a-version\", \"1.7.0-rc3\")).toBe(false);\n expect(isVersionBelow(\"1.7.0-rc2\", \"not-a-version\")).toBe(false);\n });\n });\n\n describe(\"renameRequiresDerivationPath\", () => {\n it(\"requires the path below the model's cutoff (rc2) and not at/after it\", () => {\n expect(\n renameRequiresDerivationPath(DeviceModelId.FLEX, \"1.7.0-rc2\"),\n ).toBe(true);\n expect(\n renameRequiresDerivationPath(DeviceModelId.FLEX, \"1.7.0-rc3\"),\n ).toBe(false);\n // GA and later never want the path.\n expect(renameRequiresDerivationPath(DeviceModelId.FLEX, \"1.7.0\")).toBe(\n false,\n );\n expect(renameRequiresDerivationPath(DeviceModelId.FLEX, \"1.8.0\")).toBe(\n false,\n );\n });\n\n it(\"applies the same rc2/rc3 split to the other supported models\", () => {\n expect(\n renameRequiresDerivationPath(DeviceModelId.STAX, \"1.11.0-rc2\"),\n ).toBe(true);\n expect(\n renameRequiresDerivationPath(DeviceModelId.STAX, \"1.11.0-rc3\"),\n ).toBe(false);\n expect(\n renameRequiresDerivationPath(DeviceModelId.NANO_SP, \"1.7.0-rc2\"),\n ).toBe(true);\n });\n\n it(\"returns false for an unsupported model\", () => {\n expect(\n renameRequiresDerivationPath(DeviceModelId.NANO_S, \"1.7.0-rc2\"),\n ).toBe(false);\n });\n\n it(\"returns false (no path) when the OS version is unparseable\", () => {\n expect(renameRequiresDerivationPath(DeviceModelId.FLEX, \"\")).toBe(false);\n });\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": ["DeviceModelId", "CONTACTS_VERSION_REQUIREMENTS", "ETHEREUM_APP_NAME", "isVersionAtLeast", "isVersionBelow", "renameRequiresDerivationPath", "resolveContactsVersionRequirements", "TRON_APP_NAME", "modelId", "appVersions"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{ApduBuilder as i,ApduParser as m,CommandResultFactory as t,InvalidStatusWordError as a}from"@ledgerhq/device-management-kit";import{CommandErrorHelper as p}from"@ledgerhq/signer-utils";import{Maybe as E}from"purify-ts";import{CONTACTS_APDU_CLA as l,CONTACTS_APDU_INS as u,HMAC_REST_BYTES as C,SUB_CMD_EDIT_IDENTIFIER as A}from"../../app-binder/model/contactsConstants";import{CONTACTS_APP_ERRORS as f,contactsCommandErrorFactory as c}from"../../app-binder/model/contactsErrors";import{STRUCT_TYPE_EDIT_IDENTIFIER as y}from"../../app-binder/services/contactsTlvSerializer";const s=y;function I(n,r){const e=n.extractFieldByLength(r);if(!(!e||e.length!==r))return Uint8Array.from(e)}class U{name="editExternalAddressIdentifier";args;errorHelper=new p(f,c);constructor(r){this.args=r}getApdu(){return new i({cla:l,ins:u,p1:A,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(r){return E.fromNullable(this.errorHelper.getError(r)).orDefaultLazy(()=>{if(r.data.length===0)return t({data:{}});const e=new m(r),d=e.extract8BitUInt();if(d!==s)return t({error:new a(`Expected struct_type 0x${s.toString(16)}, got ${d===void 0?"undefined":`0x${d.toString(16)}`}`)});const o=I(e,C);return o?t({data:{hmacRest:o}}):t({error:new a("hmac_rest missing or truncated")})})}}export{U as EditExternalAddressIdentifierCommand};
1
+ import{ApduBuilder as i,ApduParser as m,CommandResultFactory as t,InvalidStatusWordError as o}from"@ledgerhq/device-management-kit";import{Maybe as p}from"purify-ts";import{CONTACTS_APDU_CLA as E,CONTACTS_APDU_INS as l,HMAC_REST_BYTES as u,SUB_CMD_EDIT_IDENTIFIER as A}from"../../app-binder/model/contactsConstants";import{ContactsCommandErrorHelper as C}from"../../app-binder/model/contactsErrors";import{STRUCT_TYPE_EDIT_IDENTIFIER as f}from"../../app-binder/services/contactsTlvSerializer";const s=f;function c(n,r){const e=n.extractFieldByLength(r);if(!(!e||e.length!==r))return Uint8Array.from(e)}class g{name="editExternalAddressIdentifier";args;errorHelper=new C;constructor(r){this.args=r}getApdu(){return new i({cla:E,ins:l,p1:A,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(r){return p.fromNullable(this.errorHelper.getError(r)).orDefaultLazy(()=>{if(r.data.length===0)return t({data:{}});const e=new m(r),d=e.extract8BitUInt();if(d!==s)return t({error:new o(`Expected struct_type 0x${s.toString(16)}, got ${d===void 0?"undefined":`0x${d.toString(16)}`}`)});const a=c(e,u);return a?t({data:{hmacRest:a}}):t({error:new o("hmac_rest missing or truncated")})})}}export{g as EditExternalAddressIdentifierCommand};
2
2
  //# sourceMappingURL=EditExternalAddressIdentifierCommand.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/command/EditExternalAddressIdentifierCommand.ts"],
4
- "sourcesContent": ["// Edit Identifier \u2014 sub-command P1=0x03 of the address-book APDU (CLA 0xB0 /\n// INS 0x10). Frames one chunk; on the final chunk parses the 33-byte response\n// struct_type(0x31) + hmac_rest(32) (the rotated address-level proof).\n// Intermediate chunks ack SW=0x9000 with no data. SW 0x6982 = seed/handle\n// mismatch, surfaced via the shared error helper before any device UI.\n// Protocol: Address Book Final Specifications \u2014 Edit Identifier.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { CommandErrorHelper } from \"@ledgerhq/signer-utils\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n CONTACTS_APDU_CLA,\n CONTACTS_APDU_INS,\n HMAC_REST_BYTES,\n SUB_CMD_EDIT_IDENTIFIER,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n CONTACTS_APP_ERRORS,\n contactsCommandErrorFactory,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\nimport { STRUCT_TYPE_EDIT_IDENTIFIER } from \"@internal/app-binder/services/contactsTlvSerializer\";\n\nexport type EditExternalAddressIdentifierCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type EditExternalAddressIdentifierCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x31) +\n * hmac_rest(32) there. Intermediate chunks return SW=0x9000 with no data.\n * This is the replacement address-level proof (rotated `hmac_rest`).\n */\n readonly hmacRest?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = STRUCT_TYPE_EDIT_IDENTIFIER;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class EditExternalAddressIdentifierCommand\n implements\n Command<\n EditExternalAddressIdentifierCommandResponse,\n EditExternalAddressIdentifierCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"editExternalAddressIdentifier\";\n readonly args: EditExternalAddressIdentifierCommandArgs;\n private readonly errorHelper = new CommandErrorHelper<\n EditExternalAddressIdentifierCommandResponse,\n ContactsErrorCodes\n >(CONTACTS_APP_ERRORS, contactsCommandErrorFactory);\n\n constructor(args: EditExternalAddressIdentifierCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: CONTACTS_APDU_CLA,\n ins: CONTACTS_APDU_INS,\n p1: SUB_CMD_EDIT_IDENTIFIER,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<\n EditExternalAddressIdentifierCommandResponse,\n ContactsErrorCodes\n > {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const hmacRest = extractField(parser, HMAC_REST_BYTES);\n if (!hmacRest) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_rest missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { hmacRest },\n });\n });\n }\n}\n"],
5
- "mappings": "AAMA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,sBAAAC,MAA0B,yBACnC,OAAS,SAAAC,MAAa,YAEtB,OACE,qBAAAC,EACA,qBAAAC,EACA,mBAAAC,EACA,2BAAAC,MACK,+CACP,OACE,uBAAAC,EACA,+BAAAC,MAEK,4CACP,OAAS,+BAAAC,MAAmC,sDAkB5C,MAAMC,EAAuBD,EAO7B,SAASE,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,gCACP,KACQ,YAAc,IAAId,EAGjCM,EAAqBC,CAA2B,EAElD,YAAYQ,EAAgD,CAC1D,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAInB,EAAY,CACrB,IAAKM,EACL,IAAKC,EACL,GAAIE,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEW,EAIA,CACA,OAAOf,EAAM,aACX,KAAK,YAAY,SAASe,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOlB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMa,EAAS,IAAId,EAAWmB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOX,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BU,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAWR,EAAaC,EAAQP,CAAe,EACrD,OAAKc,EAMEpB,EAAqB,CAC1B,KAAM,CAAE,SAAAoB,CAAS,CACnB,CAAC,EAPQpB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
6
- "names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "CommandErrorHelper", "Maybe", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "HMAC_REST_BYTES", "SUB_CMD_EDIT_IDENTIFIER", "CONTACTS_APP_ERRORS", "contactsCommandErrorFactory", "STRUCT_TYPE_EDIT_IDENTIFIER", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "EditExternalAddressIdentifierCommand", "args", "response", "structType", "hmacRest"]
4
+ "sourcesContent": ["// Edit Identifier \u2014 sub-command P1=0x03 of the address-book APDU (CLA 0xB0 /\n// INS 0x10). Frames one chunk; on the final chunk parses the 33-byte response\n// struct_type(0x31) + hmac_rest(32) (the rotated address-level proof).\n// Intermediate chunks ack SW=0x9000 with no data. SW 0x6982 = seed/handle\n// mismatch, surfaced via the shared error helper before any device UI.\n// Protocol: Address Book Final Specifications \u2014 Edit Identifier.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n CONTACTS_APDU_CLA,\n CONTACTS_APDU_INS,\n HMAC_REST_BYTES,\n SUB_CMD_EDIT_IDENTIFIER,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n ContactsCommandErrorHelper,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\nimport { STRUCT_TYPE_EDIT_IDENTIFIER } from \"@internal/app-binder/services/contactsTlvSerializer\";\n\nexport type EditExternalAddressIdentifierCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type EditExternalAddressIdentifierCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x31) +\n * hmac_rest(32) there. Intermediate chunks return SW=0x9000 with no data.\n * This is the replacement address-level proof (rotated `hmac_rest`).\n */\n readonly hmacRest?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = STRUCT_TYPE_EDIT_IDENTIFIER;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class EditExternalAddressIdentifierCommand\n implements\n Command<\n EditExternalAddressIdentifierCommandResponse,\n EditExternalAddressIdentifierCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"editExternalAddressIdentifier\";\n readonly args: EditExternalAddressIdentifierCommandArgs;\n private readonly errorHelper =\n new ContactsCommandErrorHelper<EditExternalAddressIdentifierCommandResponse>();\n\n constructor(args: EditExternalAddressIdentifierCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: CONTACTS_APDU_CLA,\n ins: CONTACTS_APDU_INS,\n p1: SUB_CMD_EDIT_IDENTIFIER,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<\n EditExternalAddressIdentifierCommandResponse,\n ContactsErrorCodes\n > {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const hmacRest = extractField(parser, HMAC_REST_BYTES);\n if (!hmacRest) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_rest missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { hmacRest },\n });\n });\n }\n}\n"],
5
+ "mappings": "AAMA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,SAAAC,MAAa,YAEtB,OACE,qBAAAC,EACA,qBAAAC,EACA,mBAAAC,EACA,2BAAAC,MACK,+CACP,OACE,8BAAAC,MAEK,4CACP,OAAS,+BAAAC,MAAmC,sDAkB5C,MAAMC,EAAuBD,EAO7B,SAASE,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,gCACP,KACQ,YACf,IAAIP,EAEN,YAAYQ,EAAgD,CAC1D,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAIjB,EAAY,CACrB,IAAKK,EACL,IAAKC,EACL,GAAIE,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEU,EAIA,CACA,OAAOd,EAAM,aACX,KAAK,YAAY,SAASc,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOhB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMW,EAAS,IAAIZ,EAAWiB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOT,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BQ,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAWR,EAAaC,EAAQN,CAAe,EACrD,OAAKa,EAMElB,EAAqB,CAC1B,KAAM,CAAE,SAAAkB,CAAS,CACnB,CAAC,EAPQlB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
6
+ "names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "Maybe", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "HMAC_REST_BYTES", "SUB_CMD_EDIT_IDENTIFIER", "ContactsCommandErrorHelper", "STRUCT_TYPE_EDIT_IDENTIFIER", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "EditExternalAddressIdentifierCommand", "args", "response", "structType", "hmacRest"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{ApduBuilder as m,ApduParser as p,CommandResultFactory as t,InvalidStatusWordError as a}from"@ledgerhq/device-management-kit";import{CommandErrorHelper as i}from"@ledgerhq/signer-utils";import{Maybe as E}from"purify-ts";import{CONTACTS_APDU_CLA as c,CONTACTS_APDU_INS as C,HMAC_REST_BYTES as l,SUB_CMD_EDIT_SCOPE as u}from"../../app-binder/model/contactsConstants";import{CONTACTS_APP_ERRORS as A,contactsCommandErrorFactory as S}from"../../app-binder/model/contactsErrors";import{STRUCT_TYPE_EDIT_SCOPE as y}from"../../app-binder/services/contactsTlvSerializer";const s=y;function f(d,r){const e=d.extractFieldByLength(r);if(!(!e||e.length!==r))return Uint8Array.from(e)}class U{name="editExternalAddressScope";args;errorHelper=new i(A,S);constructor(r){this.args=r}getApdu(){return new m({cla:c,ins:C,p1:u,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(r){return E.fromNullable(this.errorHelper.getError(r)).orDefaultLazy(()=>{if(r.data.length===0)return t({data:{}});const e=new p(r),o=e.extract8BitUInt();if(o!==s)return t({error:new a(`Expected struct_type 0x${s.toString(16)}, got ${o===void 0?"undefined":`0x${o.toString(16)}`}`)});const n=f(e,l);return n?t({data:{hmacRest:n}}):t({error:new a("hmac_rest missing or truncated")})})}}export{U as EditExternalAddressScopeCommand};
1
+ import{ApduBuilder as p,ApduParser as m,CommandResultFactory as t,InvalidStatusWordError as a}from"@ledgerhq/device-management-kit";import{Maybe as i}from"purify-ts";import{CONTACTS_APDU_CLA as l,CONTACTS_APDU_INS as u,HMAC_REST_BYTES as E,SUB_CMD_EDIT_SCOPE as c}from"../../app-binder/model/contactsConstants";import{ContactsCommandErrorHelper as C}from"../../app-binder/model/contactsErrors";import{STRUCT_TYPE_EDIT_SCOPE as A}from"../../app-binder/services/contactsTlvSerializer";const s=A;function S(n,r){const e=n.extractFieldByLength(r);if(!(!e||e.length!==r))return Uint8Array.from(e)}class T{name="editExternalAddressScope";args;errorHelper=new C;constructor(r){this.args=r}getApdu(){return new p({cla:l,ins:u,p1:c,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(r){return i.fromNullable(this.errorHelper.getError(r)).orDefaultLazy(()=>{if(r.data.length===0)return t({data:{}});const e=new m(r),d=e.extract8BitUInt();if(d!==s)return t({error:new a(`Expected struct_type 0x${s.toString(16)}, got ${d===void 0?"undefined":`0x${d.toString(16)}`}`)});const o=S(e,E);return o?t({data:{hmacRest:o}}):t({error:new a("hmac_rest missing or truncated")})})}}export{T as EditExternalAddressScopeCommand};
2
2
  //# sourceMappingURL=EditExternalAddressScopeCommand.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/command/EditExternalAddressScopeCommand.ts"],
4
- "sourcesContent": ["// Edit Scope \u2014 sub-command P1=0x04 of the address-book APDU (CLA 0xB0 /\n// INS 0x10). Frames one chunk; on the final chunk parses the 33-byte response\n// struct_type(0x32) + hmac_rest(32) (the rotated address-level proof).\n// Intermediate chunks ack SW=0x9000 with no data. SW 0x6982 = seed/handle\n// mismatch, surfaced via the shared error helper before any device UI.\n// Protocol: Address Book Final Specifications \u2014 Edit Scope.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { CommandErrorHelper } from \"@ledgerhq/signer-utils\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n CONTACTS_APDU_CLA,\n CONTACTS_APDU_INS,\n HMAC_REST_BYTES,\n SUB_CMD_EDIT_SCOPE,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n CONTACTS_APP_ERRORS,\n contactsCommandErrorFactory,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\nimport { STRUCT_TYPE_EDIT_SCOPE } from \"@internal/app-binder/services/contactsTlvSerializer\";\n\nexport type EditExternalAddressScopeCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type EditExternalAddressScopeCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x32) +\n * hmac_rest(32) there. Intermediate chunks return SW=0x9000 with no data.\n * This is the replacement address-level proof (rotated `hmac_rest`).\n */\n readonly hmacRest?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = STRUCT_TYPE_EDIT_SCOPE;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class EditExternalAddressScopeCommand\n implements\n Command<\n EditExternalAddressScopeCommandResponse,\n EditExternalAddressScopeCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"editExternalAddressScope\";\n readonly args: EditExternalAddressScopeCommandArgs;\n private readonly errorHelper = new CommandErrorHelper<\n EditExternalAddressScopeCommandResponse,\n ContactsErrorCodes\n >(CONTACTS_APP_ERRORS, contactsCommandErrorFactory);\n\n constructor(args: EditExternalAddressScopeCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: CONTACTS_APDU_CLA,\n ins: CONTACTS_APDU_INS,\n p1: SUB_CMD_EDIT_SCOPE,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<\n EditExternalAddressScopeCommandResponse,\n ContactsErrorCodes\n > {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const hmacRest = extractField(parser, HMAC_REST_BYTES);\n if (!hmacRest) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_rest missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { hmacRest },\n });\n });\n }\n}\n"],
5
- "mappings": "AAMA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,sBAAAC,MAA0B,yBACnC,OAAS,SAAAC,MAAa,YAEtB,OACE,qBAAAC,EACA,qBAAAC,EACA,mBAAAC,EACA,sBAAAC,MACK,+CACP,OACE,uBAAAC,EACA,+BAAAC,MAEK,4CACP,OAAS,0BAAAC,MAA8B,sDAkBvC,MAAMC,EAAuBD,EAO7B,SAASE,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,2BACP,KACQ,YAAc,IAAId,EAGjCM,EAAqBC,CAA2B,EAElD,YAAYQ,EAA2C,CACrD,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAInB,EAAY,CACrB,IAAKM,EACL,IAAKC,EACL,GAAIE,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEW,EAIA,CACA,OAAOf,EAAM,aACX,KAAK,YAAY,SAASe,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOlB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMa,EAAS,IAAId,EAAWmB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOX,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BU,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAWR,EAAaC,EAAQP,CAAe,EACrD,OAAKc,EAMEpB,EAAqB,CAC1B,KAAM,CAAE,SAAAoB,CAAS,CACnB,CAAC,EAPQpB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
6
- "names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "CommandErrorHelper", "Maybe", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "HMAC_REST_BYTES", "SUB_CMD_EDIT_SCOPE", "CONTACTS_APP_ERRORS", "contactsCommandErrorFactory", "STRUCT_TYPE_EDIT_SCOPE", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "EditExternalAddressScopeCommand", "args", "response", "structType", "hmacRest"]
4
+ "sourcesContent": ["// Edit Scope \u2014 sub-command P1=0x04 of the address-book APDU (CLA 0xB0 /\n// INS 0x10). Frames one chunk; on the final chunk parses the 33-byte response\n// struct_type(0x32) + hmac_rest(32) (the rotated address-level proof).\n// Intermediate chunks ack SW=0x9000 with no data. SW 0x6982 = seed/handle\n// mismatch, surfaced via the shared error helper before any device UI.\n// Protocol: Address Book Final Specifications \u2014 Edit Scope.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n CONTACTS_APDU_CLA,\n CONTACTS_APDU_INS,\n HMAC_REST_BYTES,\n SUB_CMD_EDIT_SCOPE,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n ContactsCommandErrorHelper,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\nimport { STRUCT_TYPE_EDIT_SCOPE } from \"@internal/app-binder/services/contactsTlvSerializer\";\n\nexport type EditExternalAddressScopeCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type EditExternalAddressScopeCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x32) +\n * hmac_rest(32) there. Intermediate chunks return SW=0x9000 with no data.\n * This is the replacement address-level proof (rotated `hmac_rest`).\n */\n readonly hmacRest?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = STRUCT_TYPE_EDIT_SCOPE;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class EditExternalAddressScopeCommand\n implements\n Command<\n EditExternalAddressScopeCommandResponse,\n EditExternalAddressScopeCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"editExternalAddressScope\";\n readonly args: EditExternalAddressScopeCommandArgs;\n private readonly errorHelper =\n new ContactsCommandErrorHelper<EditExternalAddressScopeCommandResponse>();\n\n constructor(args: EditExternalAddressScopeCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: CONTACTS_APDU_CLA,\n ins: CONTACTS_APDU_INS,\n p1: SUB_CMD_EDIT_SCOPE,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<\n EditExternalAddressScopeCommandResponse,\n ContactsErrorCodes\n > {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const hmacRest = extractField(parser, HMAC_REST_BYTES);\n if (!hmacRest) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_rest missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { hmacRest },\n });\n });\n }\n}\n"],
5
+ "mappings": "AAMA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,SAAAC,MAAa,YAEtB,OACE,qBAAAC,EACA,qBAAAC,EACA,mBAAAC,EACA,sBAAAC,MACK,+CACP,OACE,8BAAAC,MAEK,4CACP,OAAS,0BAAAC,MAA8B,sDAkBvC,MAAMC,EAAuBD,EAO7B,SAASE,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,2BACP,KACQ,YACf,IAAIP,EAEN,YAAYQ,EAA2C,CACrD,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAIjB,EAAY,CACrB,IAAKK,EACL,IAAKC,EACL,GAAIE,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEU,EAIA,CACA,OAAOd,EAAM,aACX,KAAK,YAAY,SAASc,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOhB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMW,EAAS,IAAIZ,EAAWiB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOT,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BQ,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAWR,EAAaC,EAAQN,CAAe,EACrD,OAAKa,EAMElB,EAAqB,CAC1B,KAAM,CAAE,SAAAkB,CAAS,CACnB,CAAC,EAPQlB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
6
+ "names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "Maybe", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "HMAC_REST_BYTES", "SUB_CMD_EDIT_SCOPE", "ContactsCommandErrorHelper", "STRUCT_TYPE_EDIT_SCOPE", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "EditExternalAddressScopeCommand", "args", "response", "structType", "hmacRest"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{ApduBuilder as r,CommandResultFactory as e}from"@ledgerhq/device-management-kit";import{CommandErrorHelper as t}from"@ledgerhq/signer-utils";import{Maybe as a}from"purify-ts";import{CONTACTS_APDU_CLA as n,CONTACTS_APDU_INS as d,SUB_CMD_PROVIDE_CONTACT as m}from"../../app-binder/model/contactsConstants";import{CONTACTS_APP_ERRORS as s,contactsCommandErrorFactory as C}from"../../app-binder/model/contactsErrors";class y{name="provideContact";args;errorHelper=new t(s,C);constructor(o){this.args=o}getApdu(){return new r({cla:n,ins:d,p1:m,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(o){return a.fromNullable(this.errorHelper.getError(o)).orDefaultLazy(()=>e({data:void 0}))}}export{y as ProvideContactCommand};
1
+ import{ApduBuilder as r,CommandResultFactory as e}from"@ledgerhq/device-management-kit";import{Maybe as t}from"purify-ts";import{CONTACTS_APDU_CLA as a,CONTACTS_APDU_INS as n,SUB_CMD_PROVIDE_CONTACT as d}from"../../app-binder/model/contactsConstants";import{ContactsCommandErrorHelper as s}from"../../app-binder/model/contactsErrors";class l{name="provideContact";args;errorHelper=new s;constructor(o){this.args=o}getApdu(){return new r({cla:a,ins:n,p1:d,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(o){return t.fromNullable(this.errorHelper.getError(o)).orDefaultLazy(()=>e({data:void 0}))}}export{l as ProvideContactCommand};
2
2
  //# sourceMappingURL=ProvideContactCommand.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/command/ProvideContactCommand.ts"],
4
- "sourcesContent": ["// Provide Contact \u2014 sub-command P1=0x20 of the address-book APDU (CLA 0xB0 /\n// INS 0x10). Sent before a signing APDU so the device renders a registered\n// contact name in place of the raw recipient address. Caller\n// (sendProvideContactPayload) assembles the TLV, prepends the 2-byte BE total\n// length and slices into <=255B chunks; this command frames one chunk. Every\n// chunk answers with SW=0x9000 and no data \u2014 the outcome is a device-side\n// effect, not a returned value.\n// Protocol: Address Book Final Specifications \u2014 Provide Contact.\nimport {\n type Apdu,\n ApduBuilder,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n} from \"@ledgerhq/device-management-kit\";\nimport { CommandErrorHelper } from \"@ledgerhq/signer-utils\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n CONTACTS_APDU_CLA,\n CONTACTS_APDU_INS,\n SUB_CMD_PROVIDE_CONTACT,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n CONTACTS_APP_ERRORS,\n contactsCommandErrorFactory,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nexport type ProvideContactCommandArgs = {\n /** One framed chunk built by sendProvideContactPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type ProvideContactCommandResponse = void;\n\nexport class ProvideContactCommand\n implements\n Command<\n ProvideContactCommandResponse,\n ProvideContactCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"provideContact\";\n readonly args: ProvideContactCommandArgs;\n private readonly errorHelper = new CommandErrorHelper<\n ProvideContactCommandResponse,\n ContactsErrorCodes\n >(CONTACTS_APP_ERRORS, contactsCommandErrorFactory);\n\n constructor(args: ProvideContactCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: CONTACTS_APDU_CLA,\n ins: CONTACTS_APDU_INS,\n p1: SUB_CMD_PROVIDE_CONTACT,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<ProvideContactCommandResponse, ContactsErrorCodes> {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() =>\n CommandResultFactory<ProvideContactCommandResponse, ContactsErrorCodes>({\n data: undefined,\n }),\n );\n }\n}\n"],
5
- "mappings": "AAQA,OAEE,eAAAA,EAIA,wBAAAC,MACK,kCACP,OAAS,sBAAAC,MAA0B,yBACnC,OAAS,SAAAC,MAAa,YAEtB,OACE,qBAAAC,EACA,qBAAAC,EACA,2BAAAC,MACK,+CACP,OACE,uBAAAC,EACA,+BAAAC,MAEK,4CAWA,MAAMC,CAOb,CACW,KAAO,iBACP,KACQ,YAAc,IAAIP,EAGjCK,EAAqBC,CAA2B,EAElD,YAAYE,EAAiC,CAC3C,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAIV,EAAY,CACrB,IAAKI,EACL,IAAKC,EACL,GAAIC,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEK,EACkE,CAClE,OAAOR,EAAM,aACX,KAAK,YAAY,SAASQ,CAAQ,CACpC,EAAE,cAAc,IACdV,EAAwE,CACtE,KAAM,MACR,CAAC,CACH,CACF,CACF",
6
- "names": ["ApduBuilder", "CommandResultFactory", "CommandErrorHelper", "Maybe", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "SUB_CMD_PROVIDE_CONTACT", "CONTACTS_APP_ERRORS", "contactsCommandErrorFactory", "ProvideContactCommand", "args", "response"]
4
+ "sourcesContent": ["// Provide Contact \u2014 sub-command P1=0x20 of the address-book APDU (CLA 0xB0 /\n// INS 0x10). Sent before a signing APDU so the device renders a registered\n// contact name in place of the raw recipient address. Caller\n// (sendProvideContactPayload) assembles the TLV, prepends the 2-byte BE total\n// length and slices into <=255B chunks; this command frames one chunk. Every\n// chunk answers with SW=0x9000 and no data \u2014 the outcome is a device-side\n// effect, not a returned value.\n// Protocol: Address Book Final Specifications \u2014 Provide Contact.\nimport {\n type Apdu,\n ApduBuilder,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n} from \"@ledgerhq/device-management-kit\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n CONTACTS_APDU_CLA,\n CONTACTS_APDU_INS,\n SUB_CMD_PROVIDE_CONTACT,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n ContactsCommandErrorHelper,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nexport type ProvideContactCommandArgs = {\n /** One framed chunk built by sendProvideContactPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type ProvideContactCommandResponse = void;\n\nexport class ProvideContactCommand\n implements\n Command<\n ProvideContactCommandResponse,\n ProvideContactCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"provideContact\";\n readonly args: ProvideContactCommandArgs;\n private readonly errorHelper =\n new ContactsCommandErrorHelper<ProvideContactCommandResponse>();\n\n constructor(args: ProvideContactCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: CONTACTS_APDU_CLA,\n ins: CONTACTS_APDU_INS,\n p1: SUB_CMD_PROVIDE_CONTACT,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<ProvideContactCommandResponse, ContactsErrorCodes> {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() =>\n CommandResultFactory<ProvideContactCommandResponse, ContactsErrorCodes>({\n data: undefined,\n }),\n );\n }\n}\n"],
5
+ "mappings": "AAQA,OAEE,eAAAA,EAIA,wBAAAC,MACK,kCACP,OAAS,SAAAC,MAAa,YAEtB,OACE,qBAAAC,EACA,qBAAAC,EACA,2BAAAC,MACK,+CACP,OACE,8BAAAC,MAEK,4CAWA,MAAMC,CAOb,CACW,KAAO,iBACP,KACQ,YACf,IAAID,EAEN,YAAYE,EAAiC,CAC3C,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAIR,EAAY,CACrB,IAAKG,EACL,IAAKC,EACL,GAAIC,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEI,EACkE,CAClE,OAAOP,EAAM,aACX,KAAK,YAAY,SAASO,CAAQ,CACpC,EAAE,cAAc,IACdR,EAAwE,CACtE,KAAM,MACR,CAAC,CACH,CACF,CACF",
6
+ "names": ["ApduBuilder", "CommandResultFactory", "Maybe", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "SUB_CMD_PROVIDE_CONTACT", "ContactsCommandErrorHelper", "ProvideContactCommand", "args", "response"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{ApduBuilder as u,ApduParser as y,CommandResultFactory as t,InvalidStatusWordError as n}from"@ledgerhq/device-management-kit";import{CommandErrorHelper as c}from"@ledgerhq/signer-utils";import{Maybe as C}from"purify-ts";import{CONTACTS_APDU_CLA as g,CONTACTS_APDU_INS as l,GROUP_HANDLE_BYTES as R,HMAC_PROOF_BYTES as A,HMAC_REST_BYTES as f,SUB_CMD_REGISTER_IDENTITY as E}from"../../app-binder/model/contactsConstants";import{CONTACTS_APP_ERRORS as _,contactsCommandErrorFactory as T}from"../../app-binder/model/contactsErrors";const p=45;function a(d,r){const e=d.extractFieldByLength(r);if(!(!e||e.length!==r))return Uint8Array.from(e)}class x{name="registerIdentity";args;errorHelper=new c(_,T);constructor(r){this.args=r}getApdu(){return new u({cla:g,ins:l,p1:E,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(r){return C.fromNullable(this.errorHelper.getError(r)).orDefaultLazy(()=>{if(r.data.length===0)return t({data:{}});const e=new y(r),o=e.extract8BitUInt();if(o!==p)return t({error:new n(`Expected struct_type 0x${p.toString(16)}, got ${o===void 0?"undefined":`0x${o.toString(16)}`}`)});const s=a(e,R);if(!s)return t({error:new n("group_handle missing or truncated")});const i=a(e,A);if(!i)return t({error:new n("hmac_name missing or truncated")});const m=a(e,f);return m?t({data:{groupHandle:s,hmacProof:i,hmacRest:m}}):t({error:new n("hmac_rest missing or truncated")})})}}export{x as RegisterIdentityCommand};
1
+ import{ApduBuilder as u,ApduParser as y,CommandResultFactory as t,InvalidStatusWordError as n}from"@ledgerhq/device-management-kit";import{Maybe as c}from"purify-ts";import{CONTACTS_APDU_CLA as g,CONTACTS_APDU_INS as l,GROUP_HANDLE_BYTES as C,HMAC_PROOF_BYTES as R,HMAC_REST_BYTES as A,SUB_CMD_REGISTER_IDENTITY as f}from"../../app-binder/model/contactsConstants";import{ContactsCommandErrorHelper as _}from"../../app-binder/model/contactsErrors";const p=45;function a(d,r){const e=d.extractFieldByLength(r);if(!(!e||e.length!==r))return Uint8Array.from(e)}class h{name="registerIdentity";args;errorHelper=new _;constructor(r){this.args=r}getApdu(){return new u({cla:g,ins:l,p1:f,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(r){return c.fromNullable(this.errorHelper.getError(r)).orDefaultLazy(()=>{if(r.data.length===0)return t({data:{}});const e=new y(r),o=e.extract8BitUInt();if(o!==p)return t({error:new n(`Expected struct_type 0x${p.toString(16)}, got ${o===void 0?"undefined":`0x${o.toString(16)}`}`)});const s=a(e,C);if(!s)return t({error:new n("group_handle missing or truncated")});const i=a(e,R);if(!i)return t({error:new n("hmac_name missing or truncated")});const m=a(e,A);return m?t({data:{groupHandle:s,hmacProof:i,hmacRest:m}}):t({error:new n("hmac_rest missing or truncated")})})}}export{h as RegisterIdentityCommand};
2
2
  //# sourceMappingURL=RegisterIdentityCommand.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/command/RegisterIdentityCommand.ts"],
4
- "sourcesContent": ["// Register Identity (register external address) \u2014 sub-command P1=0x01 of the\n// address-book APDU (CLA 0xB0 / INS 0x10). Caller (SendRegisterIdentityTask +\n// sendFramedContactsPayload) assembles the TLV, prepends the 2-byte BE total\n// length and slices into <=255B chunks; this command frames one chunk and, on\n// the final chunk, parses the 129-byte response: struct_type(0x2d) +\n// group_handle(64) + hmac_proof(32) + hmac_rest(32). Intermediate chunks ack\n// with SW=0x9000 and no data.\n// Protocol: Address Book Final Specifications \u2014 Register Identity.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { CommandErrorHelper } from \"@ledgerhq/signer-utils\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n CONTACTS_APDU_CLA,\n CONTACTS_APDU_INS,\n GROUP_HANDLE_BYTES,\n HMAC_PROOF_BYTES,\n HMAC_REST_BYTES,\n SUB_CMD_REGISTER_IDENTITY,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n CONTACTS_APP_ERRORS,\n contactsCommandErrorFactory,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nexport type RegisterIdentityCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type RegisterIdentityCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x2d) +\n * group_handle(64) + hmac_proof(32) + hmac_rest(32) there. Intermediate\n * chunks return SW=0x9000 with no data.\n *\n * `hmacProof` is the device's HMAC_PROOF (binds the contact name);\n * `hmacRest` is the HMAC_REST (binds scope + identifier + family).\n */\n readonly groupHandle?: Uint8Array;\n readonly hmacProof?: Uint8Array;\n readonly hmacRest?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = 0x2d;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class RegisterIdentityCommand\n implements\n Command<\n RegisterIdentityCommandResponse,\n RegisterIdentityCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"registerIdentity\";\n readonly args: RegisterIdentityCommandArgs;\n private readonly errorHelper = new CommandErrorHelper<\n RegisterIdentityCommandResponse,\n ContactsErrorCodes\n >(CONTACTS_APP_ERRORS, contactsCommandErrorFactory);\n\n constructor(args: RegisterIdentityCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: CONTACTS_APDU_CLA,\n ins: CONTACTS_APDU_INS,\n p1: SUB_CMD_REGISTER_IDENTITY,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<RegisterIdentityCommandResponse, ContactsErrorCodes> {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const groupHandle = extractField(parser, GROUP_HANDLE_BYTES);\n if (!groupHandle) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n \"group_handle missing or truncated\",\n ),\n });\n }\n\n const hmacProof = extractField(parser, HMAC_PROOF_BYTES);\n if (!hmacProof) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_name missing or truncated\"),\n });\n }\n\n const hmacRest = extractField(parser, HMAC_REST_BYTES);\n if (!hmacRest) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_rest missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { groupHandle, hmacProof, hmacRest },\n });\n });\n }\n}\n"],
5
- "mappings": "AAQA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,sBAAAC,MAA0B,yBACnC,OAAS,SAAAC,MAAa,YAEtB,OACE,qBAAAC,EACA,qBAAAC,EACA,sBAAAC,EACA,oBAAAC,EACA,mBAAAC,EACA,6BAAAC,MACK,+CACP,OACE,uBAAAC,EACA,+BAAAC,MAEK,4CAuBP,MAAMC,EAAuB,GAO7B,SAASC,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,mBACP,KACQ,YAAc,IAAIf,EAGjCQ,EAAqBC,CAA2B,EAElD,YAAYO,EAAmC,CAC7C,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAIpB,EAAY,CACrB,IAAKM,EACL,IAAKC,EACL,GAAII,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEU,EACoE,CACpE,OAAOhB,EAAM,aACX,KAAK,YAAY,SAASgB,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOnB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMc,EAAS,IAAIf,EAAWoB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOZ,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BW,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAcR,EAAaC,EAAQR,CAAkB,EAC3D,GAAI,CAACe,EACH,OAAOrB,EAAqB,CAC1B,MAAO,IAAIC,EACT,mCACF,CACF,CAAC,EAGH,MAAMqB,EAAYT,EAAaC,EAAQP,CAAgB,EACvD,GAAI,CAACe,EACH,OAAOtB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,EAGH,MAAMsB,EAAWV,EAAaC,EAAQN,CAAe,EACrD,OAAKe,EAMEvB,EAAqB,CAC1B,KAAM,CAAE,YAAAqB,EAAa,UAAAC,EAAW,SAAAC,CAAS,CAC3C,CAAC,EAPQvB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
6
- "names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "CommandErrorHelper", "Maybe", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "GROUP_HANDLE_BYTES", "HMAC_PROOF_BYTES", "HMAC_REST_BYTES", "SUB_CMD_REGISTER_IDENTITY", "CONTACTS_APP_ERRORS", "contactsCommandErrorFactory", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "RegisterIdentityCommand", "args", "response", "structType", "groupHandle", "hmacProof", "hmacRest"]
4
+ "sourcesContent": ["// Register Identity (register external address) \u2014 sub-command P1=0x01 of the\n// address-book APDU (CLA 0xB0 / INS 0x10). Caller (SendRegisterIdentityTask +\n// sendFramedContactsPayload) assembles the TLV, prepends the 2-byte BE total\n// length and slices into <=255B chunks; this command frames one chunk and, on\n// the final chunk, parses the 129-byte response: struct_type(0x2d) +\n// group_handle(64) + hmac_proof(32) + hmac_rest(32). Intermediate chunks ack\n// with SW=0x9000 and no data.\n// Protocol: Address Book Final Specifications \u2014 Register Identity.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n CONTACTS_APDU_CLA,\n CONTACTS_APDU_INS,\n GROUP_HANDLE_BYTES,\n HMAC_PROOF_BYTES,\n HMAC_REST_BYTES,\n SUB_CMD_REGISTER_IDENTITY,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n ContactsCommandErrorHelper,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\n\nexport type RegisterIdentityCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type RegisterIdentityCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x2d) +\n * group_handle(64) + hmac_proof(32) + hmac_rest(32) there. Intermediate\n * chunks return SW=0x9000 with no data.\n *\n * `hmacProof` is the device's HMAC_PROOF (binds the contact name);\n * `hmacRest` is the HMAC_REST (binds scope + identifier + family).\n */\n readonly groupHandle?: Uint8Array;\n readonly hmacProof?: Uint8Array;\n readonly hmacRest?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = 0x2d;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class RegisterIdentityCommand\n implements\n Command<\n RegisterIdentityCommandResponse,\n RegisterIdentityCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"registerIdentity\";\n readonly args: RegisterIdentityCommandArgs;\n private readonly errorHelper =\n new ContactsCommandErrorHelper<RegisterIdentityCommandResponse>();\n\n constructor(args: RegisterIdentityCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: CONTACTS_APDU_CLA,\n ins: CONTACTS_APDU_INS,\n p1: SUB_CMD_REGISTER_IDENTITY,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<RegisterIdentityCommandResponse, ContactsErrorCodes> {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const groupHandle = extractField(parser, GROUP_HANDLE_BYTES);\n if (!groupHandle) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n \"group_handle missing or truncated\",\n ),\n });\n }\n\n const hmacProof = extractField(parser, HMAC_PROOF_BYTES);\n if (!hmacProof) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_name missing or truncated\"),\n });\n }\n\n const hmacRest = extractField(parser, HMAC_REST_BYTES);\n if (!hmacRest) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_rest missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { groupHandle, hmacProof, hmacRest },\n });\n });\n }\n}\n"],
5
+ "mappings": "AAQA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,SAAAC,MAAa,YAEtB,OACE,qBAAAC,EACA,qBAAAC,EACA,sBAAAC,EACA,oBAAAC,EACA,mBAAAC,EACA,6BAAAC,MACK,+CACP,OACE,8BAAAC,MAEK,4CAuBP,MAAMC,EAAuB,GAO7B,SAASC,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,mBACP,KACQ,YACf,IAAIN,EAEN,YAAYO,EAAmC,CAC7C,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAIlB,EAAY,CACrB,IAAKK,EACL,IAAKC,EACL,GAAII,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACES,EACoE,CACpE,OAAOf,EAAM,aACX,KAAK,YAAY,SAASe,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOjB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMY,EAAS,IAAIb,EAAWkB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOV,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BS,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAcR,EAAaC,EAAQP,CAAkB,EAC3D,GAAI,CAACc,EACH,OAAOnB,EAAqB,CAC1B,MAAO,IAAIC,EACT,mCACF,CACF,CAAC,EAGH,MAAMmB,EAAYT,EAAaC,EAAQN,CAAgB,EACvD,GAAI,CAACc,EACH,OAAOpB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,EAGH,MAAMoB,EAAWV,EAAaC,EAAQL,CAAe,EACrD,OAAKc,EAMErB,EAAqB,CAC1B,KAAM,CAAE,YAAAmB,EAAa,UAAAC,EAAW,SAAAC,CAAS,CAC3C,CAAC,EAPQrB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
6
+ "names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "Maybe", "CONTACTS_APDU_CLA", "CONTACTS_APDU_INS", "GROUP_HANDLE_BYTES", "HMAC_PROOF_BYTES", "HMAC_REST_BYTES", "SUB_CMD_REGISTER_IDENTITY", "ContactsCommandErrorHelper", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "RegisterIdentityCommand", "args", "response", "structType", "groupHandle", "hmacProof", "hmacRest"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{ApduBuilder as s,ApduParser as C,CommandResultFactory as t,InvalidStatusWordError as m}from"@ledgerhq/device-management-kit";import{CommandErrorHelper as p}from"@ledgerhq/signer-utils";import{Maybe as c}from"purify-ts";import{HMAC_NAME_BYTES as i,RENAME_CONTACT_APDU_CLA as u,RENAME_CONTACT_APDU_INS as A,RENAME_CONTACT_P1 as R}from"../../app-binder/model/contactsConstants";import{CONTACTS_APP_ERRORS as l,contactsCommandErrorFactory as y}from"../../app-binder/model/contactsErrors";import{STRUCT_TYPE_EDIT_CONTACT_NAME as E}from"../../app-binder/services/contactsTlvSerializer";const d=E;function f(o,r){const e=o.extractFieldByLength(r);if(!(!e||e.length!==r))return Uint8Array.from(e)}class h{name="renameContact";args;errorHelper=new p(l,y);constructor(r){this.args=r}getApdu(){return new s({cla:u,ins:A,p1:R,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(r){return c.fromNullable(this.errorHelper.getError(r)).orDefaultLazy(()=>{if(r.data.length===0)return t({data:{}});const e=new C(r),n=e.extract8BitUInt();if(n!==d)return t({error:new m(`Expected struct_type 0x${d.toString(16)}, got ${n===void 0?"undefined":`0x${n.toString(16)}`}`)});const a=f(e,i);return a?t({data:{hmacProof:a}}):t({error:new m("hmac_name missing or truncated")})})}}export{h as RenameContactCommand};
1
+ import{ApduBuilder as s,ApduParser as C,CommandResultFactory as t,InvalidStatusWordError as m}from"@ledgerhq/device-management-kit";import{Maybe as p}from"purify-ts";import{HMAC_NAME_BYTES as i,RENAME_CONTACT_APDU_CLA as u,RENAME_CONTACT_APDU_INS as c,RENAME_CONTACT_P1 as A}from"../../app-binder/model/contactsConstants";import{ContactsCommandErrorHelper as l}from"../../app-binder/model/contactsErrors";import{STRUCT_TYPE_EDIT_CONTACT_NAME as R}from"../../app-binder/services/contactsTlvSerializer";const d=R;function y(a,e){const r=a.extractFieldByLength(e);if(!(!r||r.length!==e))return Uint8Array.from(r)}class N{name="renameContact";args;errorHelper=new l;constructor(e){this.args=e}getApdu(){return new s({cla:u,ins:c,p1:A,p2:this.args.p2}).addBufferToData(this.args.data).build()}parseResponse(e){return p.fromNullable(this.errorHelper.getError(e)).orDefaultLazy(()=>{if(e.data.length===0)return t({data:{}});const r=new C(e),n=r.extract8BitUInt();if(n!==d)return t({error:new m(`Expected struct_type 0x${d.toString(16)}, got ${n===void 0?"undefined":`0x${n.toString(16)}`}`)});const o=y(r,i);return o?t({data:{hmacProof:o}}):t({error:new m("hmac_name missing or truncated")})})}}export{N as RenameContactCommand};
2
2
  //# sourceMappingURL=RenameContactCommand.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/internal/app-binder/command/RenameContactCommand.ts"],
4
- "sourcesContent": ["// Rename Contact (EDIT CONTACT NAME) \u2014 the blockchain-agnostic address-book\n// rename. It is dispatched as an OS/dashboard command (CLA 0xE0 / INS 0x2E /\n// P1 0x00), NOT through the embedded app: the caller navigates to the dashboard\n// first (GoToDashboardDeviceAction) so the OS handles it directly.\n// SendRenameContactTask + sendFramedContactsPayload assemble the TLV, prepend\n// the 2-byte BE total length and slice into <=255B chunks; this command frames\n// one chunk and, on the final chunk, parses the 33-byte response:\n// struct_type(0x2e) + rotated hmac_name(32). Intermediate chunks ack with\n// SW=0x9000 and no data.\n//\n// The device is stateless: it verifies the supplied group handle + old-name\n// proof against the seed-derived key (SW 0x6982 on a seed mismatch, before any\n// UI) and, on approval, returns a fresh proof for the new name.\n// Protocol: Address Book Final Specifications \u2014 Edit Contact Name.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { CommandErrorHelper } from \"@ledgerhq/signer-utils\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n HMAC_NAME_BYTES,\n RENAME_CONTACT_APDU_CLA,\n RENAME_CONTACT_APDU_INS,\n RENAME_CONTACT_P1,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n CONTACTS_APP_ERRORS,\n contactsCommandErrorFactory,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\nimport { STRUCT_TYPE_EDIT_CONTACT_NAME } from \"@internal/app-binder/services/contactsTlvSerializer\";\n\nexport type RenameContactCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type RenameContactCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x2e) +\n * rotated hmac_name(32) there. Intermediate chunks return SW=0x9000 with no\n * data. This is the replacement group-level name proof.\n */\n readonly hmacProof?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = STRUCT_TYPE_EDIT_CONTACT_NAME;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class RenameContactCommand\n implements\n Command<\n RenameContactCommandResponse,\n RenameContactCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"renameContact\";\n readonly args: RenameContactCommandArgs;\n private readonly errorHelper = new CommandErrorHelper<\n RenameContactCommandResponse,\n ContactsErrorCodes\n >(CONTACTS_APP_ERRORS, contactsCommandErrorFactory);\n\n constructor(args: RenameContactCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: RENAME_CONTACT_APDU_CLA,\n ins: RENAME_CONTACT_APDU_INS,\n p1: RENAME_CONTACT_P1,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<RenameContactCommandResponse, ContactsErrorCodes> {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const hmacProof = extractField(parser, HMAC_NAME_BYTES);\n if (!hmacProof) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_name missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { hmacProof },\n });\n });\n }\n}\n"],
5
- "mappings": "AAcA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,sBAAAC,MAA0B,yBACnC,OAAS,SAAAC,MAAa,YAEtB,OACE,mBAAAC,EACA,2BAAAC,EACA,2BAAAC,EACA,qBAAAC,MACK,+CACP,OACE,uBAAAC,EACA,+BAAAC,MAEK,4CACP,OAAS,iCAAAC,MAAqC,sDAkB9C,MAAMC,EAAuBD,EAO7B,SAASE,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,gBACP,KACQ,YAAc,IAAId,EAGjCM,EAAqBC,CAA2B,EAElD,YAAYQ,EAAgC,CAC1C,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAInB,EAAY,CACrB,IAAKO,EACL,IAAKC,EACL,GAAIC,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEW,EACiE,CACjE,OAAOf,EAAM,aACX,KAAK,YAAY,SAASe,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOlB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMa,EAAS,IAAId,EAAWmB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOX,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BU,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAYR,EAAaC,EAAQT,CAAe,EACtD,OAAKgB,EAMEpB,EAAqB,CAC1B,KAAM,CAAE,UAAAoB,CAAU,CACpB,CAAC,EAPQpB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
6
- "names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "CommandErrorHelper", "Maybe", "HMAC_NAME_BYTES", "RENAME_CONTACT_APDU_CLA", "RENAME_CONTACT_APDU_INS", "RENAME_CONTACT_P1", "CONTACTS_APP_ERRORS", "contactsCommandErrorFactory", "STRUCT_TYPE_EDIT_CONTACT_NAME", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "RenameContactCommand", "args", "response", "structType", "hmacProof"]
4
+ "sourcesContent": ["// Rename Contact (EDIT CONTACT NAME) \u2014 the blockchain-agnostic address-book\n// rename. It is dispatched as an OS/dashboard command (CLA 0xE0 / INS 0x2E /\n// P1 0x00), NOT through the embedded app: the caller navigates to the dashboard\n// first (GoToDashboardDeviceAction) so the OS handles it directly.\n// SendRenameContactTask + sendFramedContactsPayload assemble the TLV, prepend\n// the 2-byte BE total length and slice into <=255B chunks; this command frames\n// one chunk and, on the final chunk, parses the 33-byte response:\n// struct_type(0x2e) + rotated hmac_name(32). Intermediate chunks ack with\n// SW=0x9000 and no data.\n//\n// The device is stateless: it verifies the supplied group handle + old-name\n// proof against the seed-derived key (SW 0x6982 on a seed mismatch, before any\n// UI) and, on approval, returns a fresh proof for the new name.\n// Protocol: Address Book Final Specifications \u2014 Edit Contact Name.\nimport {\n type Apdu,\n ApduBuilder,\n ApduParser,\n type ApduResponse,\n type Command,\n type CommandResult,\n CommandResultFactory,\n InvalidStatusWordError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Maybe } from \"purify-ts\";\n\nimport {\n HMAC_NAME_BYTES,\n RENAME_CONTACT_APDU_CLA,\n RENAME_CONTACT_APDU_INS,\n RENAME_CONTACT_P1,\n} from \"@internal/app-binder/model/contactsConstants\";\nimport {\n ContactsCommandErrorHelper,\n type ContactsErrorCodes,\n} from \"@internal/app-binder/model/contactsErrors\";\nimport { STRUCT_TYPE_EDIT_CONTACT_NAME } from \"@internal/app-binder/services/contactsTlvSerializer\";\n\nexport type RenameContactCommandArgs = {\n /** One framed chunk built by sendFramedContactsPayload. */\n readonly data: Uint8Array;\n /** 0x00 for the first/only chunk, 0x80 for continuation chunks. */\n readonly p2: number;\n};\n\nexport type RenameContactCommandResponse = {\n /**\n * Present only on the final chunk \u2014 the device returns struct_type(0x2e) +\n * rotated hmac_name(32) there. Intermediate chunks return SW=0x9000 with no\n * data. This is the replacement group-level name proof.\n */\n readonly hmacProof?: Uint8Array;\n};\n\nconst RESPONSE_STRUCT_TYPE = STRUCT_TYPE_EDIT_CONTACT_NAME;\n\n/**\n * Extract `length` bytes as a freshly-owned plain `Uint8Array` (the parser may\n * hand back a `Buffer` view backed by the response), or `undefined` if the\n * response is too short.\n */\nfunction extractField(\n parser: ApduParser,\n length: number,\n): Uint8Array | undefined {\n const field = parser.extractFieldByLength(length);\n if (!field || field.length !== length) return undefined;\n return Uint8Array.from(field);\n}\n\nexport class RenameContactCommand\n implements\n Command<\n RenameContactCommandResponse,\n RenameContactCommandArgs,\n ContactsErrorCodes\n >\n{\n readonly name = \"renameContact\";\n readonly args: RenameContactCommandArgs;\n private readonly errorHelper =\n new ContactsCommandErrorHelper<RenameContactCommandResponse>();\n\n constructor(args: RenameContactCommandArgs) {\n this.args = args;\n }\n\n getApdu(): Apdu {\n return new ApduBuilder({\n cla: RENAME_CONTACT_APDU_CLA,\n ins: RENAME_CONTACT_APDU_INS,\n p1: RENAME_CONTACT_P1,\n p2: this.args.p2,\n })\n .addBufferToData(this.args.data)\n .build();\n }\n\n parseResponse(\n response: ApduResponse,\n ): CommandResult<RenameContactCommandResponse, ContactsErrorCodes> {\n return Maybe.fromNullable(\n this.errorHelper.getError(response),\n ).orDefaultLazy(() => {\n if (response.data.length === 0) {\n // Intermediate chunk \u2014 device acks with SW=0x9000 and no payload.\n return CommandResultFactory({ data: {} });\n }\n\n const parser = new ApduParser(response);\n\n const structType = parser.extract8BitUInt();\n if (structType !== RESPONSE_STRUCT_TYPE) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\n `Expected struct_type 0x${RESPONSE_STRUCT_TYPE.toString(16)}, got ${\n structType === undefined\n ? \"undefined\"\n : `0x${structType.toString(16)}`\n }`,\n ),\n });\n }\n\n const hmacProof = extractField(parser, HMAC_NAME_BYTES);\n if (!hmacProof) {\n return CommandResultFactory({\n error: new InvalidStatusWordError(\"hmac_name missing or truncated\"),\n });\n }\n\n return CommandResultFactory({\n data: { hmacProof },\n });\n });\n }\n}\n"],
5
+ "mappings": "AAcA,OAEE,eAAAA,EACA,cAAAC,EAIA,wBAAAC,EACA,0BAAAC,MACK,kCACP,OAAS,SAAAC,MAAa,YAEtB,OACE,mBAAAC,EACA,2BAAAC,EACA,2BAAAC,EACA,qBAAAC,MACK,+CACP,OACE,8BAAAC,MAEK,4CACP,OAAS,iCAAAC,MAAqC,sDAkB9C,MAAMC,EAAuBD,EAO7B,SAASE,EACPC,EACAC,EACwB,CACxB,MAAMC,EAAQF,EAAO,qBAAqBC,CAAM,EAChD,GAAI,GAACC,GAASA,EAAM,SAAWD,GAC/B,OAAO,WAAW,KAAKC,CAAK,CAC9B,CAEO,MAAMC,CAOb,CACW,KAAO,gBACP,KACQ,YACf,IAAIP,EAEN,YAAYQ,EAAgC,CAC1C,KAAK,KAAOA,CACd,CAEA,SAAgB,CACd,OAAO,IAAIjB,EAAY,CACrB,IAAKM,EACL,IAAKC,EACL,GAAIC,EACJ,GAAI,KAAK,KAAK,EAChB,CAAC,EACE,gBAAgB,KAAK,KAAK,IAAI,EAC9B,MAAM,CACX,CAEA,cACEU,EACiE,CACjE,OAAOd,EAAM,aACX,KAAK,YAAY,SAASc,CAAQ,CACpC,EAAE,cAAc,IAAM,CACpB,GAAIA,EAAS,KAAK,SAAW,EAE3B,OAAOhB,EAAqB,CAAE,KAAM,CAAC,CAAE,CAAC,EAG1C,MAAMW,EAAS,IAAIZ,EAAWiB,CAAQ,EAEhCC,EAAaN,EAAO,gBAAgB,EAC1C,GAAIM,IAAeR,EACjB,OAAOT,EAAqB,CAC1B,MAAO,IAAIC,EACT,0BAA0BQ,EAAqB,SAAS,EAAE,CAAC,SACzDQ,IAAe,OACX,YACA,KAAKA,EAAW,SAAS,EAAE,CAAC,EAClC,EACF,CACF,CAAC,EAGH,MAAMC,EAAYR,EAAaC,EAAQR,CAAe,EACtD,OAAKe,EAMElB,EAAqB,CAC1B,KAAM,CAAE,UAAAkB,CAAU,CACpB,CAAC,EAPQlB,EAAqB,CAC1B,MAAO,IAAIC,EAAuB,gCAAgC,CACpE,CAAC,CAML,CAAC,CACH,CACF",
6
+ "names": ["ApduBuilder", "ApduParser", "CommandResultFactory", "InvalidStatusWordError", "Maybe", "HMAC_NAME_BYTES", "RENAME_CONTACT_APDU_CLA", "RENAME_CONTACT_APDU_INS", "RENAME_CONTACT_P1", "ContactsCommandErrorHelper", "STRUCT_TYPE_EDIT_CONTACT_NAME", "RESPONSE_STRUCT_TYPE", "extractField", "parser", "length", "field", "RenameContactCommand", "args", "response", "structType", "hmacProof"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import{CommandResultStatus as a}from"@ledgerhq/device-management-kit";import{CONTACT_SEED_MISMATCH_ERROR_CODE as d,ContactsCommandError as s}from"../../app-binder/model/contactsErrors";import{RenameContactCommand as o}from"./RenameContactCommand";function m(e){const t=new Uint8Array(e.length/2);for(let r=0;r<e.length;r+=2)t[r/2]=parseInt(e.slice(r,r+2),16);return t}const u=m("dd".repeat(32)),c="2e"+"dd".repeat(32);function n(e){return{data:Buffer.from(m(e)),statusCode:Buffer.from([144,0])}}describe("RenameContactCommand",()=>{describe("getApdu",()=>{it("wraps the framed chunk under E0 2E 00 with P2=0x00 for the first/only chunk",()=>{const e=Uint8Array.from([0,3,170,187,204]),t=new o({data:e,p2:0}).getApdu();expect(t.getRawApdu()).toStrictEqual(Uint8Array.from([224,46,0,0,5,0,3,170,187,204]))}),it("uses P2=0x80 for continuation chunks",()=>{const e=Uint8Array.from([170,187]),t=new o({data:e,p2:128}).getApdu();expect(t.getRawApdu()).toStrictEqual(Uint8Array.from([224,46,0,128,2,170,187]))})}),describe("parseResponse",()=>{it("returns an empty payload for an intermediate chunk (SW=0x9000, no data)",()=>{const e=new o({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([144,0])});expect(e).toStrictEqual({status:a.Success,data:{}})}),it("extracts the rotated hmac_name from an edit-contact-name response",()=>{const t=new o({data:new Uint8Array,p2:0}).parseResponse(n(c));expect(t).toStrictEqual({status:a.Success,data:{hmacProof:u}})}),it("returns InvalidStatusWordError when struct_type is wrong",()=>{const e="ee"+c.slice(2),r=new o({data:new Uint8Array,p2:0}).parseResponse(n(e));expect(r.status).toBe(a.Error)}),it("returns InvalidStatusWordError when hmac_name is truncated",()=>{const e="2e"+"dd".repeat(16),r=new o({data:new Uint8Array,p2:0}).parseResponse(n(e));expect(r.status).toBe(a.Error)}),it("maps a known SW (0x6985) to a ContactsCommandError",()=>{const t=new o({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([105,133])});expect(t.status).toBe(a.Error),t.status===a.Error&&(expect(t.error).toBeInstanceOf(s),expect(t.error.errorCode).toBe("6985"))}),it("maps SW=0x6982 to a seed-mismatch ContactsCommandError",()=>{const t=new o({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([105,130])});expect(t.status).toBe(a.Error),t.status===a.Error&&(expect(t.error).toBeInstanceOf(s),expect(t.error.errorCode).toBe(d))})})});
1
+ import{CommandResultStatus as r,InvalidStatusWordError as m}from"@ledgerhq/device-management-kit";import{CONTACT_SEED_MISMATCH_ERROR_CODE as u,ContactsCommandError as n}from"../../app-binder/model/contactsErrors";import{RenameContactCommand as a}from"./RenameContactCommand";function d(e){const t=new Uint8Array(e.length/2);for(let o=0;o<e.length;o+=2)t[o/2]=parseInt(e.slice(o,o+2),16);return t}const p=d("dd".repeat(32)),c="2e"+"dd".repeat(32);function s(e){return{data:Buffer.from(d(e)),statusCode:Buffer.from([144,0])}}describe("RenameContactCommand",()=>{describe("getApdu",()=>{it("wraps the framed chunk under E0 2E 00 with P2=0x00 for the first/only chunk",()=>{const e=Uint8Array.from([0,3,170,187,204]),t=new a({data:e,p2:0}).getApdu();expect(t.getRawApdu()).toStrictEqual(Uint8Array.from([224,46,0,0,5,0,3,170,187,204]))}),it("uses P2=0x80 for continuation chunks",()=>{const e=Uint8Array.from([170,187]),t=new a({data:e,p2:128}).getApdu();expect(t.getRawApdu()).toStrictEqual(Uint8Array.from([224,46,0,128,2,170,187]))})}),describe("parseResponse",()=>{it("returns an empty payload for an intermediate chunk (SW=0x9000, no data)",()=>{const e=new a({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([144,0])});expect(e).toStrictEqual({status:r.Success,data:{}})}),it("extracts the rotated hmac_name from an edit-contact-name response",()=>{const t=new a({data:new Uint8Array,p2:0}).parseResponse(s(c));expect(t).toStrictEqual({status:r.Success,data:{hmacProof:p}})}),it("returns InvalidStatusWordError when struct_type is wrong",()=>{const e="ee"+c.slice(2),o=new a({data:new Uint8Array,p2:0}).parseResponse(s(e));expect(o.status).toBe(r.Error)}),it("returns InvalidStatusWordError when hmac_name is truncated",()=>{const e="2e"+"dd".repeat(16),o=new a({data:new Uint8Array,p2:0}).parseResponse(s(e));expect(o.status).toBe(r.Error)}),it("maps a known SW (0x6985) to a ContactsCommandError",()=>{const t=new a({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([105,133])});expect(t.status).toBe(r.Error),t.status===r.Error&&(expect(t.error).toBeInstanceOf(n),expect(t.error.errorCode).toBe("6985"))}),it("maps SW=0x686A (OS still mandates the derivation path) to a ContactsCommandError",()=>{const t=new a({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([104,106])});expect(t.status).toBe(r.Error),t.status===r.Error&&(expect(t.error).toBeInstanceOf(n),expect(t.error.errorCode).toBe("686a"))}),it("gives an unmapped status word an actionable message instead of UnknownDeviceExchangeError",()=>{const t=new a({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([109,1])});expect(t.status).toBe(r.Error),t.status===r.Error&&(expect(t.error).toBeInstanceOf(m),expect(t.error.originalError?.message).toContain("0x6d01"))}),it("maps SW=0x6982 to a seed-mismatch ContactsCommandError",()=>{const t=new a({data:new Uint8Array,p2:0}).parseResponse({data:Buffer.from([]),statusCode:Buffer.from([105,130])});expect(t.status).toBe(r.Error),t.status===r.Error&&(expect(t.error).toBeInstanceOf(n),expect(t.error.errorCode).toBe(u))})})});
2
2
  //# sourceMappingURL=RenameContactCommand.test.js.map