@keetanetwork/anchor 0.0.47 → 0.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/certificates.d.ts +6 -4
- package/lib/certificates.d.ts.map +1 -1
- package/lib/certificates.js +13 -6
- package/lib/certificates.js.map +1 -1
- package/lib/resolver.js +33 -33
- package/lib/utils/pii.js +1 -1
- package/lib/utils/pii.js.map +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/services/asset-movement/common.d.ts +3 -3
- package/services/asset-movement/common.d.ts.map +1 -1
- package/services/asset-movement/common.js +5092 -2014
- package/services/asset-movement/common.js.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/fps.d.ts +4 -0
- package/services/asset-movement/lib/data/addresses/bank-account/fps.d.ts.map +1 -0
- package/services/asset-movement/lib/data/addresses/bank-account/fps.js +34 -0
- package/services/asset-movement/lib/data/addresses/bank-account/fps.js.map +1 -0
- package/services/asset-movement/lib/data/addresses/bank-account/iban-swift.d.ts.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/iban-swift.js +22 -1
- package/services/asset-movement/lib/data/addresses/bank-account/iban-swift.js.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/index.generated.d.ts +2 -0
- package/services/asset-movement/lib/data/addresses/bank-account/index.generated.d.ts.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/index.generated.js +2 -0
- package/services/asset-movement/lib/data/addresses/bank-account/index.generated.js.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/interac.d.ts +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/interac.d.ts.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/interac.js +12 -2
- package/services/asset-movement/lib/data/addresses/bank-account/interac.js.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/pix.d.ts +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/pix.d.ts.map +1 -1
- package/services/asset-movement/lib/data/addresses/bank-account/pix.js +11 -1
- package/services/asset-movement/lib/data/addresses/bank-account/pix.js.map +1 -1
- package/services/asset-movement/lib/data/addresses/types.generated.d.ts +176 -4
- package/services/asset-movement/lib/data/addresses/types.generated.d.ts.map +1 -1
- package/services/asset-movement/lib/data/addresses/types.generated.js +164 -2
- package/services/asset-movement/lib/data/addresses/types.generated.js.map +1 -1
- package/services/asset-movement/lib/location.generated.js +3 -3
- package/services/storage/client.d.ts +8 -0
- package/services/storage/client.d.ts.map +1 -1
- package/services/storage/client.js +11 -0
- package/services/storage/client.js.map +1 -1
- package/services/storage/clients/contacts.d.ts +14 -5
- package/services/storage/clients/contacts.d.ts.map +1 -1
- package/services/storage/clients/contacts.generated.js +497 -200
- package/services/storage/clients/contacts.generated.js.map +1 -1
- package/services/storage/clients/contacts.js +23 -8
- package/services/storage/clients/contacts.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contacts.generated.js","sourceRoot":"","sources":["../../../../src/services/storage/clients/contacts.generated.ts"],"names":[],"mappings":";;AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAGrC,MAAM,CAAC,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"contacts.generated.js","sourceRoot":"","sources":["../../../../src/services/storage/clients/contacts.generated.ts"],"names":[],"mappings":";;AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAGrC,MAAM,CAAC,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAAuD,CAAC","sourcesContent":["import { createAssert } from 'typia';\nimport type { Contact } from './contacts.ts';\n\nexport const assertContact: (input: unknown) => Contact = createAssert<Contact>();\n"]}
|
|
@@ -3,6 +3,7 @@ import { convertAssetLocationToString } from '../../asset-movement/lib/location.
|
|
|
3
3
|
import { Errors } from '../common.js';
|
|
4
4
|
import { Buffer } from '../../../lib/utils/buffer.js';
|
|
5
5
|
import { assertContact } from './contacts.generated.js';
|
|
6
|
+
;
|
|
6
7
|
// #endregion
|
|
7
8
|
// #region Storage Implementation
|
|
8
9
|
/**
|
|
@@ -71,15 +72,25 @@ export class StorageContactsClient {
|
|
|
71
72
|
#serialize(contact) {
|
|
72
73
|
return (Buffer.from(JSON.stringify(contact)));
|
|
73
74
|
}
|
|
74
|
-
#deserialize(data) {
|
|
75
|
-
|
|
75
|
+
#deserialize(data, metadata) {
|
|
76
|
+
const contact = assertContact(JSON.parse(data.toString()));
|
|
77
|
+
if (metadata) {
|
|
78
|
+
return ({
|
|
79
|
+
...contact,
|
|
80
|
+
...metadata
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
return (contact);
|
|
85
|
+
}
|
|
76
86
|
}
|
|
77
87
|
async create(options) {
|
|
78
88
|
const id = this.deriveId(options.address);
|
|
79
89
|
const contact = {
|
|
80
90
|
id,
|
|
81
91
|
label: options.label,
|
|
82
|
-
address: options.address
|
|
92
|
+
address: options.address,
|
|
93
|
+
...(options.rail !== undefined ? { rail: options.rail } : {})
|
|
83
94
|
};
|
|
84
95
|
await this.#session.put(id, this.#serialize(contact), {
|
|
85
96
|
mimeType: MIME_TYPE,
|
|
@@ -87,12 +98,15 @@ export class StorageContactsClient {
|
|
|
87
98
|
});
|
|
88
99
|
return (contact);
|
|
89
100
|
}
|
|
90
|
-
async get(id) {
|
|
91
|
-
const result = await
|
|
101
|
+
async get(id, includeMetadata) {
|
|
102
|
+
const [result, metadata] = await Promise.all([
|
|
103
|
+
this.#session.get(id),
|
|
104
|
+
includeMetadata ? this.#session.getMetadata(id) : Promise.resolve(null)
|
|
105
|
+
]);
|
|
92
106
|
if (!result) {
|
|
93
107
|
return (null);
|
|
94
108
|
}
|
|
95
|
-
return (this.#deserialize(result.data));
|
|
109
|
+
return (this.#deserialize(result.data, metadata));
|
|
96
110
|
}
|
|
97
111
|
async update(id, options) {
|
|
98
112
|
const existing = await this.get(id);
|
|
@@ -104,7 +118,8 @@ export class StorageContactsClient {
|
|
|
104
118
|
const updated = {
|
|
105
119
|
id: newId,
|
|
106
120
|
label: options.label ?? existing.label,
|
|
107
|
-
address: newAddress
|
|
121
|
+
address: newAddress,
|
|
122
|
+
...(existing.rail !== undefined ? { rail: existing.rail } : {})
|
|
108
123
|
};
|
|
109
124
|
await this.#session.put(newId, this.#serialize(updated), {
|
|
110
125
|
mimeType: MIME_TYPE,
|
|
@@ -136,7 +151,7 @@ export class StorageContactsClient {
|
|
|
136
151
|
for (const metadata of searchResult.results) {
|
|
137
152
|
const result = await this.#session.get(metadata.path);
|
|
138
153
|
if (result) {
|
|
139
|
-
contacts.push(this.#deserialize(result.data));
|
|
154
|
+
contacts.push(this.#deserialize(result.data, metadata));
|
|
140
155
|
}
|
|
141
156
|
}
|
|
142
157
|
return (contacts);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contacts.js","sourceRoot":"","sources":["../../../../src/services/storage/clients/contacts.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssetTransferInstructions, RecipientResolved, KeetaNetAccount } from '../../asset-movement/common.js';\nimport type { AssetLocationLike, PickChainLocation } from '../../asset-movement/lib/location.js';\nimport type { KeetaStorageAnchorSession } from '../client.js';\nimport { lib as KeetaNetLib } from '@keetanetwork/keetanet-client';\nimport { convertAssetLocationToString } from '../../asset-movement/lib/location.js';\nimport { Errors } from '../common.js';\nimport { Buffer } from '../../../lib/utils/buffer.js';\nimport { assertContact } from './contacts.generated.js';\n\n// #region Types\n\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\n/**\n * The structural shape of a transfer instruction, excluding transaction-specific fields.\n */\nexport type TransferInstructionShape = DistributiveOmit<\n\tAssetTransferInstructions,\n\t'value' | 'assetFee' | 'totalReceiveAmount' | 'persistentAddressId'\n>;\n\n/**\n * The type of provider information allowed for a contact address.\n */\nexport type ProviderInformationType = 'username' | 'template';\n\n/**\n * The type of recipient for a persistent address template.\n */\nexport type PersistentAddressTemplateRecipient = Extract<RecipientResolved, { type: 'persistent-address' }>;\n\n/**\n * Base interface for contact addresses with narrowed generic parameters.\n */\nexport interface ContactAddressBase<\n\tRecipientType extends RecipientResolved,\n\tLocation extends AssetLocationLike,\n\tProviderInformationAllowedTypes extends ProviderInformationType\n> {\n\trecipient: RecipientType;\n\tlocation?: Location;\n\tproviderInformation?: { [providerId: string]: ProviderInformationAllowedTypes[] };\n\tpastInstructions?: TransferInstructionShape[];\n}\n\nexport type KeetaAssetLocation = PickChainLocation<'keeta'> | `chain:keeta:${bigint}`;\n\n/**\n * A contact address for a Keeta account.\n */\nexport type KeetaContactAddress = ContactAddressBase<string, KeetaAssetLocation, 'username'>;\n\n/**\n * A contact address for a persistent address template.\n */\nexport type TemplateContactAddress = ContactAddressBase<PersistentAddressTemplateRecipient, AssetLocationLike, 'template'>;\n\n/**\n * A contact address for a non-Keeta, non-persistent-address recipient.\n */\nexport type OtherContactAddress = ContactAddressBase<\n\tExclude<RecipientResolved, KeetaNetAccount | PersistentAddressTemplateRecipient>,\n\tExclude<AssetLocationLike, KeetaAssetLocation>,\n\t'template'\n>;\n\nexport type ContactAddress = KeetaContactAddress | TemplateContactAddress | OtherContactAddress;\n\n/**\n * A stored contact with metadata and an address.\n */\nexport type Contact = {\n\tid: string;\n\tlabel: string;\n\taddress: ContactAddress;\n};\n\n// #endregion\n\n// #region Interface\n\n/**\n * Generic contacts client interface\n */\nexport interface ContactsClient {\n\tderiveId(address: ContactAddress): string;\n\n\tcreate(options: {\n\t\tlabel: string;\n\t\taddress: ContactAddress;\n\t}): Promise<Contact>;\n\n\tget(id: string): Promise<Contact | null>;\n\n\tupdate(id: string, options: {\n\t\tlabel?: string;\n\t\taddress?: ContactAddress;\n\t}): Promise<Contact>;\n\n\tdelete(id: string): Promise<boolean>;\n\n\tlist(options?: {\n\t\tlocation?: AssetLocationLike;\n\t}): Promise<Contact[]>;\n}\n\n// #endregion\n\n// #region Storage Implementation\n\n/**\n * MIME type for contact data.\n */\nconst MIME_TYPE = 'application/json';\n\n/**\n * Canonicalize a contact address for use in ID derivation.\n * Excludes metadata fields (`providerInformation`, `pastInstructions`) that are not part of contact identity.\n *\n * @param address - The contact address to canonicalize.\n *\n * @returns The canonicalized string representation of the contact address identity fields.\n */\nfunction canonicalizeContactAddress(address: ContactAddress): string {\n\tconst { providerInformation: _, pastInstructions: __, ...identity } = address; // eslint-disable-line @typescript-eslint/no-unused-vars\n\treturn(JSON.stringify(identity, function(_key: string, value: unknown): unknown {\n\t\tif (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\tconst obj = value as { [k: string]: unknown };\n\t\t\treturn(Object.fromEntries(\n\t\t\t\tObject.entries(obj).sort(([a], [b]) => a.localeCompare(b))\n\t\t\t));\n\t\t}\n\n\t\treturn(value);\n\t}));\n}\n\n/**\n * Convert an asset location to a tag for use in storage.\n *\n * @param location - The asset location to convert to a tag.\n *\n * @returns The tag string.\n */\nfunction locationToTag(location: AssetLocationLike): string {\n\tconst str = convertAssetLocationToString(location);\n\n\tconst parts = str.split(':');\n\treturn(parts.join('-'));\n}\n\n/**\n * Convert a contact address to a list of tags for use in storage.\n *\n * @param address - The contact address to convert to tags.\n *\n * @returns The list of tags.\n */\nfunction contactTags(address: ContactAddress): string[] {\n\tif (address.location) {\n\t\treturn([locationToTag(address.location)]);\n\t}\n\n\treturn([]);\n}\n\n/**\n * Storage Anchor-backed implementation of `ContactsClient`.\n * Stores contacts as encrypted JSON objects via a `KeetaStorageAnchorSession`.\n */\nexport class StorageContactsClient implements ContactsClient {\n\treadonly #session: KeetaStorageAnchorSession;\n\n\tconstructor(session: KeetaStorageAnchorSession) {\n\t\tthis.#session = session;\n\t}\n\n\tderiveId(address: ContactAddress): string {\n\t\tconst data = Buffer.from(canonicalizeContactAddress(address));\n\t\tconst hash = KeetaNetLib.Utils.Hash.Hash(data);\n\n\t\tconst result = Buffer.from(hash).toString('hex');\n\t\treturn(result);\n\t}\n\n\t#serialize(contact: Contact): Buffer {\n\t\treturn(Buffer.from(JSON.stringify(contact)));\n\t}\n\n\t#deserialize(data: Buffer): Contact {\n\t\treturn(assertContact(JSON.parse(data.toString())));\n\t}\n\n\tasync create(options: {\n\t\tlabel: string;\n\t\taddress: ContactAddress;\n\t}): Promise<Contact> {\n\t\tconst id = this.deriveId(options.address);\n\t\tconst contact: Contact = {\n\t\t\tid,\n\t\t\tlabel: options.label,\n\t\t\taddress: options.address\n\t\t};\n\n\t\tawait this.#session.put(id, this.#serialize(contact), {\n\t\t\tmimeType: MIME_TYPE,\n\t\t\ttags: contactTags(options.address)\n\t\t});\n\n\t\treturn(contact);\n\t}\n\n\tasync get(id: string): Promise<Contact | null> {\n\t\tconst result = await this.#session.get(id);\n\t\tif (!result) {\n\t\t\treturn(null);\n\t\t}\n\n\t\treturn(this.#deserialize(result.data));\n\t}\n\n\tasync update(id: string, options: {\n\t\tlabel?: string;\n\t\taddress?: ContactAddress;\n\t}): Promise<Contact> {\n\t\tconst existing = await this.get(id);\n\t\tif (!existing) {\n\t\t\tthrow(new Errors.DocumentNotFound(`Contact not found: ${id}`));\n\t\t}\n\n\t\tconst newAddress = options.address ?? existing.address;\n\t\tconst newId = this.deriveId(newAddress);\n\n\t\tconst updated: Contact = {\n\t\t\tid: newId,\n\t\t\tlabel: options.label ?? existing.label,\n\t\t\taddress: newAddress\n\t\t};\n\n\t\tawait this.#session.put(newId, this.#serialize(updated), {\n\t\t\tmimeType: MIME_TYPE,\n\t\t\ttags: contactTags(updated.address)\n\t\t});\n\n\t\tif (newId !== id) {\n\t\t\ttry {\n\t\t\t\tawait this.#session.delete(id);\n\t\t\t} catch {\n\t\t\t\t// Put succeeded; old contact is now orphaned\n\t\t\t}\n\t\t}\n\n\t\treturn(updated);\n\t}\n\n\tasync delete(id: string): Promise<boolean> {\n\t\tconst result = await this.#session.delete(id);\n\t\treturn(result);\n\t}\n\n\tasync list(options?: {\n\t\tlocation?: AssetLocationLike;\n\t}): Promise<Contact[]> {\n\t\tconst criteria: { pathPrefix: string; tags?: string[] } = {\n\t\t\tpathPrefix: this.#session.workingDirectory\n\t\t};\n\n\t\tif (options?.location) {\n\t\t\tcriteria.tags = [locationToTag(options.location)];\n\t\t}\n\n\t\tconst searchResult = await this.#session.search(criteria);\n\n\t\tconst contacts: Contact[] = [];\n\t\tfor (const metadata of searchResult.results) {\n\t\t\tconst result = await this.#session.get(metadata.path);\n\t\t\tif (result) {\n\t\t\t\tcontacts.push(this.#deserialize(result.data));\n\t\t\t}\n\t\t}\n\n\t\treturn(contacts);\n\t}\n}\n\n// #endregion\n"]}
|
|
1
|
+
{"version":3,"file":"contacts.js","sourceRoot":"","sources":["../../../../src/services/storage/clients/contacts.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssetTransferInstructions, RecipientResolved, KeetaNetAccount, Rail } from '../../asset-movement/common.js';\nimport type { AssetLocationLike, PickChainLocation } from '../../asset-movement/lib/location.js';\nimport type { KeetaStorageAnchorSession } from '../client.js';\nimport { lib as KeetaNetLib } from '@keetanetwork/keetanet-client';\nimport { convertAssetLocationToString } from '../../asset-movement/lib/location.js';\nimport { Errors } from '../common.js';\nimport type { StorageObjectMetadata } from '../common.js';\nimport { Buffer } from '../../../lib/utils/buffer.js';\nimport { assertContact } from './contacts.generated.js';\n\n// #region Types\n\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\n/**\n * The structural shape of a transfer instruction, excluding transaction-specific fields.\n */\nexport type TransferInstructionShape = DistributiveOmit<\n\tAssetTransferInstructions,\n\t'value' | 'assetFee' | 'totalReceiveAmount' | 'persistentAddressId'\n>;\n\n/**\n * The type of provider information allowed for a contact address.\n */\nexport type ProviderInformationType = 'username' | 'template';\n\n/**\n * The type of recipient for a persistent address template.\n */\nexport type PersistentAddressTemplateRecipient = Extract<RecipientResolved, { type: 'persistent-address' }>;\n\n/**\n * Base interface for contact addresses with narrowed generic parameters.\n */\nexport interface ContactAddressBase<\n\tRecipientType extends RecipientResolved,\n\tLocation extends AssetLocationLike,\n\tProviderInformationAllowedTypes extends ProviderInformationType\n> {\n\trecipient: RecipientType;\n\tlocation?: Location;\n\tproviderInformation?: { [providerId: string]: ProviderInformationAllowedTypes[] };\n\tpastInstructions?: TransferInstructionShape[];\n}\n\nexport type KeetaAssetLocation = PickChainLocation<'keeta'> | `chain:keeta:${bigint}`;\n\n/**\n * A contact address for a Keeta account.\n */\nexport type KeetaContactAddress = ContactAddressBase<string, KeetaAssetLocation, 'username'>;\n\n/**\n * A contact address for a persistent address template.\n */\nexport type TemplateContactAddress = ContactAddressBase<PersistentAddressTemplateRecipient, AssetLocationLike, 'template'>;\n\n/**\n * A contact address for a non-Keeta, non-persistent-address recipient.\n */\nexport type OtherContactAddress = ContactAddressBase<\n\tExclude<RecipientResolved, KeetaNetAccount | PersistentAddressTemplateRecipient>,\n\tExclude<AssetLocationLike, KeetaAssetLocation>,\n\t'template'\n>;\n\nexport type ContactAddress = KeetaContactAddress | TemplateContactAddress | OtherContactAddress;\n\n/**\n * A stored contact with metadata and an address.\n */\nexport interface Contact {\n\tid: string;\n\tlabel: string;\n\taddress: ContactAddress;\n\trail?: Rail;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\ninterface SharedStorageObjectMetadata extends Pick<StorageObjectMetadata, 'createdAt' | 'updatedAt'> {};\n\nexport interface ContactWithMetadata extends Contact, SharedStorageObjectMetadata {}\n\n// #endregion\n\n// #region Interface\n\n/**\n * Generic contacts client interface\n */\nexport interface ContactsClient {\n\tderiveId(address: ContactAddress): string;\n\n\tcreate(options: {\n\t\tlabel: string;\n\t\taddress: ContactAddress;\n\t\trail?: Rail;\n\t}): Promise<Contact>;\n\n\tget(id: string): Promise<Contact | null>;\n\n\tupdate(id: string, options: {\n\t\tlabel?: string;\n\t\taddress?: ContactAddress;\n\t}): Promise<Contact>;\n\n\tdelete(id: string): Promise<boolean>;\n\n\tlist(options?: {\n\t\tlocation?: AssetLocationLike;\n\t}): Promise<Contact[]>;\n}\n\n// #endregion\n\n// #region Storage Implementation\n\n/**\n * MIME type for contact data.\n */\nconst MIME_TYPE = 'application/json';\n\n/**\n * Canonicalize a contact address for use in ID derivation.\n * Excludes metadata fields (`providerInformation`, `pastInstructions`) that are not part of contact identity.\n *\n * @param address - The contact address to canonicalize.\n *\n * @returns The canonicalized string representation of the contact address identity fields.\n */\nfunction canonicalizeContactAddress(address: ContactAddress): string {\n\tconst { providerInformation: _, pastInstructions: __, ...identity } = address; // eslint-disable-line @typescript-eslint/no-unused-vars\n\treturn(JSON.stringify(identity, function(_key: string, value: unknown): unknown {\n\t\tif (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\tconst obj = value as { [k: string]: unknown };\n\t\t\treturn(Object.fromEntries(\n\t\t\t\tObject.entries(obj).sort(([a], [b]) => a.localeCompare(b))\n\t\t\t));\n\t\t}\n\n\t\treturn(value);\n\t}));\n}\n\n/**\n * Convert an asset location to a tag for use in storage.\n *\n * @param location - The asset location to convert to a tag.\n *\n * @returns The tag string.\n */\nfunction locationToTag(location: AssetLocationLike): string {\n\tconst str = convertAssetLocationToString(location);\n\n\tconst parts = str.split(':');\n\treturn(parts.join('-'));\n}\n\n/**\n * Convert a contact address to a list of tags for use in storage.\n *\n * @param address - The contact address to convert to tags.\n *\n * @returns The list of tags.\n */\nfunction contactTags(address: ContactAddress): string[] {\n\tif (address.location) {\n\t\treturn([locationToTag(address.location)]);\n\t}\n\n\treturn([]);\n}\n\n/**\n * Storage Anchor-backed implementation of `ContactsClient`.\n * Stores contacts as encrypted JSON objects via a `KeetaStorageAnchorSession`.\n */\nexport class StorageContactsClient implements ContactsClient {\n\treadonly #session: KeetaStorageAnchorSession;\n\n\tconstructor(session: KeetaStorageAnchorSession) {\n\t\tthis.#session = session;\n\t}\n\n\tderiveId(address: ContactAddress): string {\n\t\tconst data = Buffer.from(canonicalizeContactAddress(address));\n\t\tconst hash = KeetaNetLib.Utils.Hash.Hash(data);\n\n\t\tconst result = Buffer.from(hash).toString('hex');\n\t\treturn(result);\n\t}\n\n\t#serialize(contact: Contact): Buffer {\n\t\treturn(Buffer.from(JSON.stringify(contact)));\n\t}\n\n\t#deserialize(data: Buffer, metadata: SharedStorageObjectMetadata): ContactWithMetadata;\n\t#deserialize(data: Buffer, metadata: null): Contact;\n\t#deserialize(data: Buffer, metadata: SharedStorageObjectMetadata | null): ContactWithMetadata | Contact;\n\t#deserialize(data: Buffer, metadata: SharedStorageObjectMetadata | null): ContactWithMetadata | Contact {\n\t\tconst contact = assertContact(JSON.parse(data.toString()));\n\n\t\tif (metadata) {\n\t\t\treturn({\n\t\t\t\t...contact,\n\t\t\t\t...metadata\n\t\t\t});\n\t\t} else {\n\t\t\treturn(contact);\n\t\t}\n\t}\n\n\tasync create(options: {\n\t\tlabel: string;\n\t\taddress: ContactAddress;\n\t\trail?: Rail | undefined;\n\t}): Promise<Contact> {\n\t\tconst id = this.deriveId(options.address);\n\t\tconst contact: Contact = {\n\t\t\tid,\n\t\t\tlabel: options.label,\n\t\t\taddress: options.address,\n\t\t\t...(options.rail !== undefined ? { rail: options.rail } : {})\n\t\t};\n\n\t\tawait this.#session.put(id, this.#serialize(contact), {\n\t\t\tmimeType: MIME_TYPE,\n\t\t\ttags: contactTags(options.address)\n\t\t});\n\n\t\treturn(contact);\n\t}\n\n\tasync get(id: string, includeMetadata: true): Promise<ContactWithMetadata | null>;\n\tasync get(id: string, includeMetadata?: false): Promise<Contact | null>;\n\tasync get(id: string, includeMetadata?: boolean) {\n\t\tconst [ result, metadata ] = await Promise.all([\n\t\t\tthis.#session.get(id),\n\t\t\tincludeMetadata ? this.#session.getMetadata(id) : Promise.resolve(null)\n\t\t]);\n\n\t\tif (!result) {\n\t\t\treturn(null);\n\t\t}\n\n\t\treturn(this.#deserialize(result.data, metadata));\n\t}\n\n\tasync update(id: string, options: {\n\t\tlabel?: string;\n\t\taddress?: ContactAddress;\n\t}): Promise<Contact> {\n\t\tconst existing = await this.get(id);\n\t\tif (!existing) {\n\t\t\tthrow(new Errors.DocumentNotFound(`Contact not found: ${id}`));\n\t\t}\n\n\t\tconst newAddress = options.address ?? existing.address;\n\t\tconst newId = this.deriveId(newAddress);\n\n\t\tconst updated: Contact = {\n\t\t\tid: newId,\n\t\t\tlabel: options.label ?? existing.label,\n\t\t\taddress: newAddress,\n\t\t\t...(existing.rail !== undefined ? { rail: existing.rail } : {})\n\t\t};\n\n\t\tawait this.#session.put(newId, this.#serialize(updated), {\n\t\t\tmimeType: MIME_TYPE,\n\t\t\ttags: contactTags(updated.address)\n\t\t});\n\n\t\tif (newId !== id) {\n\t\t\ttry {\n\t\t\t\tawait this.#session.delete(id);\n\t\t\t} catch {\n\t\t\t\t// Put succeeded; old contact is now orphaned\n\t\t\t}\n\t\t}\n\n\t\treturn(updated);\n\t}\n\n\tasync delete(id: string): Promise<boolean> {\n\t\tconst result = await this.#session.delete(id);\n\t\treturn(result);\n\t}\n\n\tasync list(options?: {\n\t\tlocation?: AssetLocationLike;\n\t}): Promise<ContactWithMetadata[]> {\n\t\tconst criteria: { pathPrefix: string; tags?: string[] } = {\n\t\t\tpathPrefix: this.#session.workingDirectory\n\t\t};\n\n\t\tif (options?.location) {\n\t\t\tcriteria.tags = [locationToTag(options.location)];\n\t\t}\n\n\t\tconst searchResult = await this.#session.search(criteria);\n\n\t\tconst contacts: ContactWithMetadata[] = [];\n\t\tfor (const metadata of searchResult.results) {\n\t\t\tconst result = await this.#session.get(metadata.path);\n\t\t\tif (result) {\n\t\t\t\tcontacts.push(this.#deserialize(result.data, metadata));\n\t\t\t}\n\t\t}\n\n\t\treturn(contacts);\n\t}\n}\n\n// #endregion\n"]}
|