@naladelponce/hf-web-client
Version:
Un cliente TypeScript moderno y robusto para interactuar con Hyperledger Fabric desde entornos web y Node.js.
800 lines (787 loc) • 46.2 kB
JavaScript
import { startRegistration, startAuthentication } from '@simplewebauthn/browser';
import { set, get } from 'idb-keyval';
import { serviceDesc, messageDesc, fileDesc } from '@bufbuild/protobuf/codegenv2';
import { TimestampSchema, file_google_protobuf_timestamp } from '@bufbuild/protobuf/wkt';
import { createClient, ConnectError } from '@connectrpc/connect';
import { createGrpcWebTransport } from '@connectrpc/connect-web';
import { toBinary, fromBinary, create, protoInt64 } from '@bufbuild/protobuf';
import BN from 'bn.js';
import { sha256 } from '@noble/hashes/sha2';
import { createRequire } from 'module';
// src/identity/identity-service.ts
function uint8ArrayToBase64Url(array) {
return btoa(String.fromCharCode.apply(null, Array.from(array))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
var IdentityService = class {
worker;
constructor() {
this.worker = new Worker(new URL("./crypto-worker.js", import.meta.url), {
type: "module"
});
}
request(action, payload, engineType) {
return new Promise((resolve) => {
const handleResponse = (event) => {
this.worker.removeEventListener("message", handleResponse);
resolve(event.data);
};
this.worker.addEventListener("message", handleResponse);
this.worker.postMessage({ action, payload, engineType });
});
}
/**
* Constructs the active AppIdentity object.
* @param cert The user's certificate PEM.
* @returns An AppIdentity object with a live `sign` method.
*/
buildActiveIdentity(cert) {
const serviceInstance = this;
return {
cert,
// We create the sign method using an arrow function to capture `serviceInstance`.
// This is the core of the magic. When the user calls `identity.sign()`,
// it's actually calling back into this service instance.
sign: async (dataToSign) => {
const signResult = await serviceInstance.request(
"SIGN_PAYLOAD" /* SignPayload */,
dataToSign,
// The engineType here doesn't matter for signing, as the key is already
// unlocked. But we'll just pick one to satisfy the contract.
"password-base"
);
if (!signResult.success) {
throw signResult.error;
}
return signResult.data;
}
};
}
doesHardwareIdentityExist() {
return this.request("DOES_IDENTITY_EXIST" /* DoesIdentityExist */, null, "hardware-base");
}
doesPasswordIdentityExist() {
return this.request("DOES_IDENTITY_EXIST" /* DoesIdentityExist */, null, "password-base");
}
async createPasswordIdentity(options) {
const result = await this.request(
"CREATE_IDENTITY" /* CreateIdentity */,
options,
"password-base"
);
if (!result.success) {
return result;
}
const activeIdentity = this.buildActiveIdentity(result.data.cert);
return {
success: true,
data: {
...activeIdentity,
phrase: result.data.phrase,
recoveryShares: result.data.recoveryShares
},
error: null
};
}
async createHardwareIdentity(options) {
const cryptoResult = await this.request(
"CREATE_IDENTITY_HW_CRYPTO" /* CreateHardwareIdentityCrypto */,
options,
"hardware-base"
);
if (!cryptoResult.success) {
return cryptoResult;
}
try {
const rpName = "Fabric Client App";
const rpID = window.location.hostname;
const registrationOptions = {
rp: { name: rpName, id: rpID },
user: {
id: uint8ArrayToBase64Url(
new TextEncoder().encode(`user-${Date.now()}`)
),
name: `user@${rpID}`,
displayName: "Fabric User"
},
challenge: uint8ArrayToBase64Url(
window.crypto.getRandomValues(new Uint8Array(32))
),
pubKeyCredParams: [{ alg: -7, type: "public-key" }],
// ES256
authenticatorSelection: {
residentKey: "required",
userVerification: "required",
authenticatorAttachment: "platform"
},
attestation: "none"
};
const attestation = await startRegistration({
optionsJSON: registrationOptions
});
await set("hw-fabric-credential-id", attestation.id);
return cryptoResult;
} catch (error) {
return {
success: false,
data: null,
error: new Error(`WebAuthn registration failed: ${error.message}`)
};
}
}
async unlockIdentity(options, mode) {
if (mode === "hardware-base") {
const bioResult = await this.verifyBiometrics();
if (!bioResult.success) {
return { success: false, data: null, error: bioResult.error };
}
}
const result = await this.request(
"UNLOCK_IDENTITY" /* UnlockIdentity */,
options,
mode
);
if (!result.success) {
return result;
}
const activeIdentity = this.buildActiveIdentity(result.data.cert);
return { success: true, data: activeIdentity, error: null };
}
async verifyBiometrics() {
try {
const rpID = window.location.hostname;
const credentialId = await get("hw-fabric-credential-id");
if (!credentialId)
throw new Error("No hardware credential ID found in storage.");
const authOptions = {
challenge: uint8ArrayToBase64Url(
window.crypto.getRandomValues(new Uint8Array(16))
),
allowCredentials: [{ id: credentialId, type: "public-key" }],
userVerification: "required",
rpId: rpID
};
await startAuthentication({ optionsJSON: authOptions });
return { success: true, data: true, error: null };
} catch (error) {
return {
success: false,
data: null,
error: new Error(`Biometric verification failed: ${error.message}`)
};
}
}
deleteIdentity(mode) {
return this.request("DELETE_IDENTITY" /* DeleteIdentity */, null, mode);
}
};
var file_peer_chaincode_event = /* @__PURE__ */ fileDesc("ChpwZWVyL2NoYWluY29kZV9ldmVudC5wcm90bxIGcHJvdG9zIloKDkNoYWluY29kZUV2ZW50EhQKDGNoYWluY29kZV9pZBgBIAEoCRINCgV0eF9pZBgCIAEoCRISCgpldmVudF9uYW1lGAMgASgJEg8KB3BheWxvYWQYBCABKAxCaQoib3JnLmh5cGVybGVkZ2VyLmZhYnJpYy5wcm90b3MucGVlckIVQ2hhaW5jb2RlRXZlbnRQYWNrYWdlWixnaXRodWIuY29tL2h5cGVybGVkZ2VyL2ZhYnJpYy1wcm90b3MtZ28vcGVlcmIGcHJvdG8z");
var file_msp_msp_principal = /* @__PURE__ */ fileDesc("Chdtc3AvbXNwX3ByaW5jaXBhbC5wcm90bxIGY29tbW9uIsYBCgxNU1BQcmluY2lwYWwSRQoYcHJpbmNpcGFsX2NsYXNzaWZpY2F0aW9uGAEgASgOMiMuY29tbW9uLk1TUFByaW5jaXBhbC5DbGFzc2lmaWNhdGlvbhIRCglwcmluY2lwYWwYAiABKAwiXAoOQ2xhc3NpZmljYXRpb24SCAoEUk9MRRAAEhUKEU9SR0FOSVpBVElPTl9VTklUEAESDAoISURFTlRJVFkQAhINCglBTk9OWU1JVFkQAxIMCghDT01CSU5FRBAEInEKEE9yZ2FuaXphdGlvblVuaXQSFgoObXNwX2lkZW50aWZpZXIYASABKAkSJgoeb3JnYW5pemF0aW9uYWxfdW5pdF9pZGVudGlmaWVyGAIgASgJEh0KFWNlcnRpZmllcnNfaWRlbnRpZmllchgDIAEoDCKVAQoHTVNQUm9sZRIWCg5tc3BfaWRlbnRpZmllchgBIAEoCRIpCgRyb2xlGAIgASgOMhsuY29tbW9uLk1TUFJvbGUuTVNQUm9sZVR5cGUiRwoLTVNQUm9sZVR5cGUSCgoGTUVNQkVSEAASCQoFQURNSU4QARIKCgZDTElFTlQQAhIICgRQRUVSEAMSCwoHT1JERVJFUhAEIp0BChRNU1BJZGVudGl0eUFub255bWl0eRJNCg5hbm9ueW1pdHlfdHlwZRgBIAEoDjI1LmNvbW1vbi5NU1BJZGVudGl0eUFub255bWl0eS5NU1BJZGVudGl0eUFub255bWl0eVR5cGUiNgoYTVNQSWRlbnRpdHlBbm9ueW1pdHlUeXBlEgsKB05PTUlOQUwQABINCglBTk9OWU1PVVMQASI9ChFDb21iaW5lZFByaW5jaXBhbBIoCgpwcmluY2lwYWxzGAEgAygLMhQuY29tbW9uLk1TUFByaW5jaXBhbEJTCiRvcmcuaHlwZXJsZWRnZXIuZmFicmljLnByb3Rvcy5jb21tb25aK2dpdGh1Yi5jb20vaHlwZXJsZWRnZXIvZmFicmljLXByb3Rvcy1nby9tc3BiBnByb3RvMw");
// src/generated_protos/common/policies_pb.ts
var file_common_policies = /* @__PURE__ */ fileDesc("ChVjb21tb24vcG9saWNpZXMucHJvdG8SBmNvbW1vbiJrCgZQb2xpY3kSDAoEdHlwZRgBIAEoBRINCgV2YWx1ZRgCIAEoDCJECgpQb2xpY3lUeXBlEgsKB1VOS05PV04QABINCglTSUdOQVRVUkUQARIHCgNNU1AQAhIRCg1JTVBMSUNJVF9NRVRBEAMiewoXU2lnbmF0dXJlUG9saWN5RW52ZWxvcGUSDwoHdmVyc2lvbhgBIAEoBRIlCgRydWxlGAIgASgLMhcuY29tbW9uLlNpZ25hdHVyZVBvbGljeRIoCgppZGVudGl0aWVzGAMgAygLMhQuY29tbW9uLk1TUFByaW5jaXBhbCKfAQoPU2lnbmF0dXJlUG9saWN5EhMKCXNpZ25lZF9ieRgBIAEoBUgAEjIKCG5fb3V0X29mGAIgASgLMh4uY29tbW9uLlNpZ25hdHVyZVBvbGljeS5OT3V0T2ZIABo7CgZOT3V0T2YSCQoBbhgBIAEoBRImCgVydWxlcxgCIAMoCzIXLmNvbW1vbi5TaWduYXR1cmVQb2xpY3lCBgoEVHlwZSJ/ChJJbXBsaWNpdE1ldGFQb2xpY3kSEgoKc3ViX3BvbGljeRgBIAEoCRItCgRydWxlGAIgASgOMh8uY29tbW9uLkltcGxpY2l0TWV0YVBvbGljeS5SdWxlIiYKBFJ1bGUSBwoDQU5ZEAASBwoDQUxMEAESDAoITUFKT1JJVFkQAiKHAQoRQXBwbGljYXRpb25Qb2xpY3kSOwoQc2lnbmF0dXJlX3BvbGljeRgBIAEoCzIfLmNvbW1vbi5TaWduYXR1cmVQb2xpY3lFbnZlbG9wZUgAEikKH2NoYW5uZWxfY29uZmlnX3BvbGljeV9yZWZlcmVuY2UYAiABKAlIADoCGAFCBgoEVHlwZUJWCiRvcmcuaHlwZXJsZWRnZXIuZmFicmljLnByb3Rvcy5jb21tb25aLmdpdGh1Yi5jb20vaHlwZXJsZWRnZXIvZmFicmljLXByb3Rvcy1nby9jb21tb25iBnByb3RvMw", [file_msp_msp_principal]);
// src/generated_protos/peer/chaincode_pb.ts
var file_peer_chaincode = /* @__PURE__ */ fileDesc("ChRwZWVyL2NoYWluY29kZS5wcm90bxIGcHJvdG9zIjoKC0NoYWluY29kZUlEEgwKBHBhdGgYASABKAkSDAoEbmFtZRgCIAEoCRIPCgd2ZXJzaW9uGAMgASgJIqEBCg5DaGFpbmNvZGVJbnB1dBIMCgRhcmdzGAEgAygMEjwKC2RlY29yYXRpb25zGAIgAygLMicucHJvdG9zLkNoYWluY29kZUlucHV0LkRlY29yYXRpb25zRW50cnkSDwoHaXNfaW5pdBgDIAEoCBoyChBEZWNvcmF0aW9uc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoDDoCOAEi3AEKDUNoYWluY29kZVNwZWMSKAoEdHlwZRgBIAEoDjIaLnByb3Rvcy5DaGFpbmNvZGVTcGVjLlR5cGUSKQoMY2hhaW5jb2RlX2lkGAIgASgLMhMucHJvdG9zLkNoYWluY29kZUlEEiUKBWlucHV0GAMgASgLMhYucHJvdG9zLkNoYWluY29kZUlucHV0Eg8KB3RpbWVvdXQYBCABKAUiPgoEVHlwZRINCglVTkRFRklORUQQABIKCgZHT0xBTkcQARIICgROT0RFEAISBwoDQ0FSEAMSCAoESkFWQRAEIoQBChdDaGFpbmNvZGVEZXBsb3ltZW50U3BlYxItCg5jaGFpbmNvZGVfc3BlYxgBIAEoCzIVLnByb3Rvcy5DaGFpbmNvZGVTcGVjEhQKDGNvZGVfcGFja2FnZRgDIAEoDEoECAIQA0oECAQQBVIOZWZmZWN0aXZlX2RhdGVSCGV4ZWNfZW52ImEKF0NoYWluY29kZUludm9jYXRpb25TcGVjEi0KDmNoYWluY29kZV9zcGVjGAEgASgLMhUucHJvdG9zLkNoYWluY29kZVNwZWNKBAgCEANSEWlkX2dlbmVyYXRpb25fYWxnIigKDkxpZmVjeWNsZUV2ZW50EhYKDmNoYWluY29kZV9uYW1lGAEgASgJIi0KB0NEU0RhdGESDAoEaGFzaBgBIAEoDBIUCgxtZXRhZGF0YWhhc2gYAiABKAwi1AEKDUNoYWluY29kZURhdGESDAoEbmFtZRgBIAEoCRIPCgd2ZXJzaW9uGAIgASgJEgwKBGVzY2MYAyABKAkSDAoEdnNjYxgEIAEoCRIvCgZwb2xpY3kYBSABKAsyHy5jb21tb24uU2lnbmF0dXJlUG9saWN5RW52ZWxvcGUSDAoEZGF0YRgGIAEoDBIKCgJpZBgHIAEoDBI9ChRpbnN0YW50aWF0aW9uX3BvbGljeRgIIAEoCzIfLmNvbW1vbi5TaWduYXR1cmVQb2xpY3lFbnZlbG9wZSKVAQoZQ2hhaW5jb2RlQWRkaXRpb25hbFBhcmFtcxIXCg91c2Vfd3JpdGVfYmF0Y2gYASABKAgSHAoUbWF4X3NpemVfd3JpdGVfYmF0Y2gYAiABKA0SHQoVdXNlX2dldF9tdWx0aXBsZV9rZXlzGAMgASgIEiIKGm1heF9zaXplX2dldF9tdWx0aXBsZV9rZXlzGAQgASgNQlIKIm9yZy5oeXBlcmxlZGdlci5mYWJyaWMucHJvdG9zLnBlZXJaLGdpdGh1Yi5jb20vaHlwZXJsZWRnZXIvZmFicmljLXByb3Rvcy1nby9wZWVyYgZwcm90bzM", [file_common_policies]);
var ChaincodeIDSchema = /* @__PURE__ */ messageDesc(file_peer_chaincode, 0);
var ChaincodeInputSchema = /* @__PURE__ */ messageDesc(file_peer_chaincode, 1);
var ChaincodeSpecSchema = /* @__PURE__ */ messageDesc(file_peer_chaincode, 2);
var ChaincodeInvocationSpecSchema = /* @__PURE__ */ messageDesc(file_peer_chaincode, 4);
var file_peer_proposal_response = /* @__PURE__ */ fileDesc("ChxwZWVyL3Byb3Bvc2FsX3Jlc3BvbnNlLnByb3RvEgZwcm90b3Mi3gEKEFByb3Bvc2FsUmVzcG9uc2USDwoHdmVyc2lvbhgBIAEoBRItCgl0aW1lc3RhbXAYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEiIKCHJlc3BvbnNlGAQgASgLMhAucHJvdG9zLlJlc3BvbnNlEg8KB3BheWxvYWQYBSABKAwSKAoLZW5kb3JzZW1lbnQYBiABKAsyEy5wcm90b3MuRW5kb3JzZW1lbnQSKwoIaW50ZXJlc3QYByABKAsyGS5wcm90b3MuQ2hhaW5jb2RlSW50ZXJlc3QiPAoIUmVzcG9uc2USDgoGc3RhdHVzGAEgASgFEg8KB21lc3NhZ2UYAiABKAkSDwoHcGF5bG9hZBgDIAEoDCJDChdQcm9wb3NhbFJlc3BvbnNlUGF5bG9hZBIVCg1wcm9wb3NhbF9oYXNoGAEgASgMEhEKCWV4dGVuc2lvbhgCIAEoDCIyCgtFbmRvcnNlbWVudBIQCghlbmRvcnNlchgBIAEoDBIRCglzaWduYXR1cmUYAiABKAwiPgoRQ2hhaW5jb2RlSW50ZXJlc3QSKQoKY2hhaW5jb2RlcxgBIAMoCzIVLnByb3Rvcy5DaGFpbmNvZGVDYWxsIsYBCg1DaGFpbmNvZGVDYWxsEgwKBG5hbWUYASABKAkSGAoQY29sbGVjdGlvbl9uYW1lcxgCIAMoCRIYChBub19wcml2YXRlX3JlYWRzGAMgASgIEhgKEG5vX3B1YmxpY193cml0ZXMYBCABKAgSNQoMa2V5X3BvbGljaWVzGAUgAygLMh8uY29tbW9uLlNpZ25hdHVyZVBvbGljeUVudmVsb3BlEiIKGmRpc3JlZ2FyZF9uYW1lc3BhY2VfcG9saWN5GAYgASgIQmsKIm9yZy5oeXBlcmxlZGdlci5mYWJyaWMucHJvdG9zLnBlZXJCF1Byb3Bvc2FsUmVzcG9uc2VQYWNrYWdlWixnaXRodWIuY29tL2h5cGVybGVkZ2VyL2ZhYnJpYy1wcm90b3MtZ28vcGVlcmIGcHJvdG8z", [file_google_protobuf_timestamp, file_common_policies]);
// src/generated_protos/peer/proposal_pb.ts
var file_peer_proposal = /* @__PURE__ */ fileDesc("ChNwZWVyL3Byb3Bvc2FsLnByb3RvEgZwcm90b3MiOwoOU2lnbmVkUHJvcG9zYWwSFgoOcHJvcG9zYWxfYnl0ZXMYASABKAwSEQoJc2lnbmF0dXJlGAIgASgMIj4KCFByb3Bvc2FsEg4KBmhlYWRlchgBIAEoDBIPCgdwYXlsb2FkGAIgASgMEhEKCWV4dGVuc2lvbhgDIAEoDCJeChhDaGFpbmNvZGVIZWFkZXJFeHRlbnNpb24SKQoMY2hhaW5jb2RlX2lkGAIgASgLMhMucHJvdG9zLkNoYWluY29kZUlESgQIARACUhFwYXlsb2FkX3Zpc2JpbGl0eSKoAQoYQ2hhaW5jb2RlUHJvcG9zYWxQYXlsb2FkEg0KBWlucHV0GAEgASgMEkgKDFRyYW5zaWVudE1hcBgCIAMoCzIyLnByb3Rvcy5DaGFpbmNvZGVQcm9wb3NhbFBheWxvYWQuVHJhbnNpZW50TWFwRW50cnkaMwoRVHJhbnNpZW50TWFwRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgMOgI4ASKZAQoPQ2hhaW5jb2RlQWN0aW9uEg8KB3Jlc3VsdHMYASABKAwSDgoGZXZlbnRzGAIgASgMEiIKCHJlc3BvbnNlGAMgASgLMhAucHJvdG9zLlJlc3BvbnNlEikKDGNoYWluY29kZV9pZBgEIAEoCzITLnByb3Rvcy5DaGFpbmNvZGVJREoECAUQBlIQdG9rZW5fb3BlcmF0aW9uc0JjCiJvcmcuaHlwZXJsZWRnZXIuZmFicmljLnByb3Rvcy5wZWVyQg9Qcm9wb3NhbFBhY2thZ2VaLGdpdGh1Yi5jb20vaHlwZXJsZWRnZXIvZmFicmljLXByb3Rvcy1nby9wZWVyYgZwcm90bzM", [file_peer_chaincode, file_peer_proposal_response]);
var SignedProposalSchema = /* @__PURE__ */ messageDesc(file_peer_proposal, 0);
var ProposalSchema = /* @__PURE__ */ messageDesc(file_peer_proposal, 1);
var ChaincodeHeaderExtensionSchema = /* @__PURE__ */ messageDesc(file_peer_proposal, 2);
var ChaincodeProposalPayloadSchema = /* @__PURE__ */ messageDesc(file_peer_proposal, 3);
var file_common_common = /* @__PURE__ */ fileDesc("ChNjb21tb24vY29tbW9uLnByb3RvEgZjb21tb24iGwoKTGFzdENvbmZpZxINCgVpbmRleBgBIAEoBCJICghNZXRhZGF0YRINCgV2YWx1ZRgBIAEoDBItCgpzaWduYXR1cmVzGAIgAygLMhkuY29tbW9uLk1ldGFkYXRhU2lnbmF0dXJlIlsKEU1ldGFkYXRhU2lnbmF0dXJlEhgKEHNpZ25hdHVyZV9oZWFkZXIYASABKAwSEQoJc2lnbmF0dXJlGAIgASgMEhkKEWlkZW50aWZpZXJfaGVhZGVyGAMgASgMIjUKEElkZW50aWZpZXJIZWFkZXISEgoKaWRlbnRpZmllchgBIAEoDRINCgVub25jZRgCIAEoDCI6CgZIZWFkZXISFgoOY2hhbm5lbF9oZWFkZXIYASABKAwSGAoQc2lnbmF0dXJlX2hlYWRlchgCIAEoDCK5AQoNQ2hhbm5lbEhlYWRlchIMCgR0eXBlGAEgASgFEg8KB3ZlcnNpb24YAiABKAUSLQoJdGltZXN0YW1wGAMgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBISCgpjaGFubmVsX2lkGAQgASgJEg0KBXR4X2lkGAUgASgJEg0KBWVwb2NoGAYgASgEEhEKCWV4dGVuc2lvbhgHIAEoDBIVCg10bHNfY2VydF9oYXNoGAggASgMIjEKD1NpZ25hdHVyZUhlYWRlchIPCgdjcmVhdG9yGAEgASgMEg0KBW5vbmNlGAIgASgMIjcKB1BheWxvYWQSHgoGaGVhZGVyGAEgASgLMg4uY29tbW9uLkhlYWRlchIMCgRkYXRhGAIgASgMIi4KCEVudmVsb3BlEg8KB3BheWxvYWQYASABKAwSEQoJc2lnbmF0dXJlGAIgASgMInYKBUJsb2NrEiMKBmhlYWRlchgBIAEoCzITLmNvbW1vbi5CbG9ja0hlYWRlchIfCgRkYXRhGAIgASgLMhEuY29tbW9uLkJsb2NrRGF0YRInCghtZXRhZGF0YRgDIAEoCzIVLmNvbW1vbi5CbG9ja01ldGFkYXRhIkcKC0Jsb2NrSGVhZGVyEg4KBm51bWJlchgBIAEoBBIVCg1wcmV2aW91c19oYXNoGAIgASgMEhEKCWRhdGFfaGFzaBgDIAEoDCIZCglCbG9ja0RhdGESDAoEZGF0YRgBIAMoDCIhCg1CbG9ja01ldGFkYXRhEhAKCG1ldGFkYXRhGAEgAygMIlsKFE9yZGVyZXJCbG9ja01ldGFkYXRhEicKC2xhc3RfY29uZmlnGAEgASgLMhIuY29tbW9uLkxhc3RDb25maWcSGgoSY29uc2VudGVyX21ldGFkYXRhGAIgASgMKsABCgZTdGF0dXMSCwoHVU5LTk9XThAAEgwKB1NVQ0NFU1MQyAESEAoLQkFEX1JFUVVFU1QQkAMSDgoJRk9SQklEREVOEJMDEg4KCU5PVF9GT1VORBCUAxIdChhSRVFVRVNUX0VOVElUWV9UT09fTEFSR0UQnQMSGgoVSU5URVJOQUxfU0VSVkVSX0VSUk9SEPQDEhQKD05PVF9JTVBMRU1FTlRFRBD1AxIYChNTRVJWSUNFX1VOQVZBSUxBQkxFEPcDKu4BCgpIZWFkZXJUeXBlEgsKB01FU1NBR0UQABIKCgZDT05GSUcQARIRCg1DT05GSUdfVVBEQVRFEAISGAoURU5ET1JTRVJfVFJBTlNBQ1RJT04QAxIbChNPUkRFUkVSX1RSQU5TQUNUSU9OEAQaAggBEhUKEURFTElWRVJfU0VFS19JTkZPEAUSFQoRQ0hBSU5DT0RFX1BBQ0tBR0UQBiIECAcQByIECAgQCCIECAkQCSoUUEVFUl9SRVNPVVJDRV9VUERBVEUqFFBFRVJfQURNSU5fT1BFUkFUSU9OKhFUT0tFTl9UUkFOU0FDVElPTip0ChJCbG9ja01ldGFkYXRhSW5kZXgSDgoKU0lHTkFUVVJFUxAAEhMKC0xBU1RfQ09ORklHEAEaAggBEhcKE1RSQU5TQUNUSU9OU19GSUxURVIQAhIPCgdPUkRFUkVSEAMaAggBEg8KC0NPTU1JVF9IQVNIEARCVgokb3JnLmh5cGVybGVkZ2VyLmZhYnJpYy5wcm90b3MuY29tbW9uWi5naXRodWIuY29tL2h5cGVybGVkZ2VyL2ZhYnJpYy1wcm90b3MtZ28vY29tbW9uYgZwcm90bzM", [file_google_protobuf_timestamp]);
var HeaderSchema = /* @__PURE__ */ messageDesc(file_common_common, 4);
var ChannelHeaderSchema = /* @__PURE__ */ messageDesc(file_common_common, 5);
var SignatureHeaderSchema = /* @__PURE__ */ messageDesc(file_common_common, 6);
var PayloadSchema = /* @__PURE__ */ messageDesc(file_common_common, 7);
var EnvelopeSchema = /* @__PURE__ */ messageDesc(file_common_common, 8);
// src/generated_protos/peer/transaction_pb.ts
var file_peer_transaction = /* @__PURE__ */ fileDesc("ChZwZWVyL3RyYW5zYWN0aW9uLnByb3RvEgZwcm90b3MiXQoUUHJvY2Vzc2VkVHJhbnNhY3Rpb24SLQoTdHJhbnNhY3Rpb25FbnZlbG9wZRgBIAEoCzIQLmNvbW1vbi5FbnZlbG9wZRIWCg52YWxpZGF0aW9uQ29kZRgCIAEoBSI5CgtUcmFuc2FjdGlvbhIqCgdhY3Rpb25zGAEgAygLMhkucHJvdG9zLlRyYW5zYWN0aW9uQWN0aW9uIjQKEVRyYW5zYWN0aW9uQWN0aW9uEg4KBmhlYWRlchgBIAEoDBIPCgdwYXlsb2FkGAIgASgMIm0KFkNoYWluY29kZUFjdGlvblBheWxvYWQSIgoaY2hhaW5jb2RlX3Byb3Bvc2FsX3BheWxvYWQYASABKAwSLwoGYWN0aW9uGAIgASgLMh8ucHJvdG9zLkNoYWluY29kZUVuZG9yc2VkQWN0aW9uImcKF0NoYWluY29kZUVuZG9yc2VkQWN0aW9uEiEKGXByb3Bvc2FsX3Jlc3BvbnNlX3BheWxvYWQYASABKAwSKQoMZW5kb3JzZW1lbnRzGAIgAygLMhMucHJvdG9zLkVuZG9yc2VtZW50KqsFChBUeFZhbGlkYXRpb25Db2RlEgkKBVZBTElEEAASEAoMTklMX0VOVkVMT1BFEAESDwoLQkFEX1BBWUxPQUQQAhIVChFCQURfQ09NTU9OX0hFQURFUhADEhkKFUJBRF9DUkVBVE9SX1NJR05BVFVSRRAEEiAKHElOVkFMSURfRU5ET1JTRVJfVFJBTlNBQ1RJT04QBRIeChpJTlZBTElEX0NPTkZJR19UUkFOU0FDVElPThAGEhoKFlVOU1VQUE9SVEVEX1RYX1BBWUxPQUQQBxIVChFCQURfUFJPUE9TQUxfVFhJRBAIEhIKDkRVUExJQ0FURV9UWElEEAkSHgoaRU5ET1JTRU1FTlRfUE9MSUNZX0ZBSUxVUkUQChIWChJNVkNDX1JFQURfQ09ORkxJQ1QQCxIZChVQSEFOVE9NX1JFQURfQ09ORkxJQ1QQDBITCg9VTktOT1dOX1RYX1RZUEUQDRIaChZUQVJHRVRfQ0hBSU5fTk9UX0ZPVU5EEA4SFAoQTUFSU0hBTF9UWF9FUlJPUhAPEhAKDE5JTF9UWEFDVElPThAQEhUKEUVYUElSRURfQ0hBSU5DT0RFEBESHgoaQ0hBSU5DT0RFX1ZFUlNJT05fQ09ORkxJQ1QQEhIYChRCQURfSEVBREVSX0VYVEVOU0lPThATEhYKEkJBRF9DSEFOTkVMX0hFQURFUhAUEhgKFEJBRF9SRVNQT05TRV9QQVlMT0FEEBUSDQoJQkFEX1JXU0VUEBYSFAoQSUxMRUdBTF9XUklURVNFVBAXEhQKEElOVkFMSURfV1JJVEVTRVQQGBIVChFJTlZBTElEX0NIQUlOQ09ERRAZEhIKDU5PVF9WQUxJREFURUQQ/gESGQoUSU5WQUxJRF9PVEhFUl9SRUFTT04Q/wEqRQoMTWV0YURhdGFLZXlzEhgKFFZBTElEQVRJT05fUEFSQU1FVEVSEAASGwoXVkFMSURBVElPTl9QQVJBTUVURVJfVjIQAUJmCiJvcmcuaHlwZXJsZWRnZXIuZmFicmljLnByb3Rvcy5wZWVyQhJUcmFuc2FjdGlvblBhY2thZ2VaLGdpdGh1Yi5jb20vaHlwZXJsZWRnZXIvZmFicmljLXByb3Rvcy1nby9wZWVyYgZwcm90bzM", [file_peer_proposal_response, file_common_common]);
var file_orderer_ab = /* @__PURE__ */ fileDesc("ChBvcmRlcmVyL2FiLnByb3RvEgdvcmRlcmVyIkEKEUJyb2FkY2FzdFJlc3BvbnNlEh4KBnN0YXR1cxgBIAEoDjIOLmNvbW1vbi5TdGF0dXMSDAoEaW5mbxgCIAEoCSIMCgpTZWVrTmV3ZXN0IgwKClNlZWtPbGRlc3QiHwoNU2Vla1NwZWNpZmllZBIOCgZudW1iZXIYASABKAQiEAoOU2Vla05leHRDb21taXQiwQEKDFNlZWtQb3NpdGlvbhIlCgZuZXdlc3QYASABKAsyEy5vcmRlcmVyLlNlZWtOZXdlc3RIABIlCgZvbGRlc3QYAiABKAsyEy5vcmRlcmVyLlNlZWtPbGRlc3RIABIrCglzcGVjaWZpZWQYAyABKAsyFi5vcmRlcmVyLlNlZWtTcGVjaWZpZWRIABIuCgtuZXh0X2NvbW1pdBgEIAEoCzIXLm9yZGVyZXIuU2Vla05leHRDb21taXRIAEIGCgRUeXBlIqADCghTZWVrSW5mbxIkCgVzdGFydBgBIAEoCzIVLm9yZGVyZXIuU2Vla1Bvc2l0aW9uEiMKBHN0b3AYAiABKAsyFS5vcmRlcmVyLlNlZWtQb3NpdGlvbhIwCghiZWhhdmlvchgDIAEoDjIeLm9yZGVyZXIuU2Vla0luZm8uU2Vla0JlaGF2aW9yEjsKDmVycm9yX3Jlc3BvbnNlGAQgASgOMiMub3JkZXJlci5TZWVrSW5mby5TZWVrRXJyb3JSZXNwb25zZRI3Cgxjb250ZW50X3R5cGUYBSABKA4yIS5vcmRlcmVyLlNlZWtJbmZvLlNlZWtDb250ZW50VHlwZSI8CgxTZWVrQmVoYXZpb3ISFQoRQkxPQ0tfVU5USUxfUkVBRFkQABIVChFGQUlMX0lGX05PVF9SRUFEWRABIjAKEVNlZWtFcnJvclJlc3BvbnNlEgoKBlNUUklDVBAAEg8KC0JFU1RfRUZGT1JUEAEiMQoPU2Vla0NvbnRlbnRUeXBlEgkKBUJMT0NLEAASEwoPSEVBREVSX1dJVEhfU0lHEAEiWwoPRGVsaXZlclJlc3BvbnNlEiAKBnN0YXR1cxgBIAEoDjIOLmNvbW1vbi5TdGF0dXNIABIeCgVibG9jaxgCIAEoCzINLmNvbW1vbi5CbG9ja0gAQgYKBFR5cGUyiwEKD0F0b21pY0Jyb2FkY2FzdBI9CglCcm9hZGNhc3QSEC5jb21tb24uRW52ZWxvcGUaGi5vcmRlcmVyLkJyb2FkY2FzdFJlc3BvbnNlKAEwARI5CgdEZWxpdmVyEhAuY29tbW9uLkVudmVsb3BlGhgub3JkZXJlci5EZWxpdmVyUmVzcG9uc2UoATABQlgKJW9yZy5oeXBlcmxlZGdlci5mYWJyaWMucHJvdG9zLm9yZGVyZXJaL2dpdGh1Yi5jb20vaHlwZXJsZWRnZXIvZmFicmljLXByb3Rvcy1nby9vcmRlcmVyYgZwcm90bzM", [file_common_common]);
var SeekNewestSchema = /* @__PURE__ */ messageDesc(file_orderer_ab, 1);
var SeekSpecifiedSchema = /* @__PURE__ */ messageDesc(file_orderer_ab, 3);
var SeekPositionSchema = /* @__PURE__ */ messageDesc(file_orderer_ab, 5);
var SeekInfoSchema = /* @__PURE__ */ messageDesc(file_orderer_ab, 6);
// src/generated_protos/gateway/gateway_pb.ts
var file_gateway_gateway = /* @__PURE__ */ fileDesc("ChVnYXRld2F5L2dhdGV3YXkucHJvdG8SB2dhdGV3YXkikwEKDkVuZG9yc2VSZXF1ZXN0EhYKDnRyYW5zYWN0aW9uX2lkGAEgASgJEhIKCmNoYW5uZWxfaWQYAiABKAkSNAoUcHJvcG9zZWRfdHJhbnNhY3Rpb24YAyABKAsyFi5wcm90b3MuU2lnbmVkUHJvcG9zYWwSHwoXZW5kb3JzaW5nX29yZ2FuaXphdGlvbnMYBCADKAkiQQoPRW5kb3JzZVJlc3BvbnNlEi4KFHByZXBhcmVkX3RyYW5zYWN0aW9uGAEgASgLMhAuY29tbW9uLkVudmVsb3BlImsKDVN1Ym1pdFJlcXVlc3QSFgoOdHJhbnNhY3Rpb25faWQYASABKAkSEgoKY2hhbm5lbF9pZBgCIAEoCRIuChRwcmVwYXJlZF90cmFuc2FjdGlvbhgDIAEoCzIQLmNvbW1vbi5FbnZlbG9wZSIQCg5TdWJtaXRSZXNwb25zZSI/ChlTaWduZWRDb21taXRTdGF0dXNSZXF1ZXN0Eg8KB3JlcXVlc3QYASABKAwSEQoJc2lnbmF0dXJlGAIgASgMIlMKE0NvbW1pdFN0YXR1c1JlcXVlc3QSFgoOdHJhbnNhY3Rpb25faWQYASABKAkSEgoKY2hhbm5lbF9pZBgCIAEoCRIQCghpZGVudGl0eRgDIAEoDCJWChRDb21taXRTdGF0dXNSZXNwb25zZRIoCgZyZXN1bHQYASABKA4yGC5wcm90b3MuVHhWYWxpZGF0aW9uQ29kZRIUCgxibG9ja19udW1iZXIYAiABKAQikQEKD0V2YWx1YXRlUmVxdWVzdBIWCg50cmFuc2FjdGlvbl9pZBgBIAEoCRISCgpjaGFubmVsX2lkGAIgASgJEjQKFHByb3Bvc2VkX3RyYW5zYWN0aW9uGAMgASgLMhYucHJvdG9zLlNpZ25lZFByb3Bvc2FsEhwKFHRhcmdldF9vcmdhbml6YXRpb25zGAQgAygJIjQKEEV2YWx1YXRlUmVzcG9uc2USIAoGcmVzdWx0GAEgASgLMhAucHJvdG9zLlJlc3BvbnNlIkIKHFNpZ25lZENoYWluY29kZUV2ZW50c1JlcXVlc3QSDwoHcmVxdWVzdBgBIAEoDBIRCglzaWduYXR1cmUYAiABKAwioQEKFkNoYWluY29kZUV2ZW50c1JlcXVlc3QSEgoKY2hhbm5lbF9pZBgBIAEoCRIUCgxjaGFpbmNvZGVfaWQYAiABKAkSEAoIaWRlbnRpdHkYAyABKAwSLQoOc3RhcnRfcG9zaXRpb24YBCABKAsyFS5vcmRlcmVyLlNlZWtQb3NpdGlvbhIcChRhZnRlcl90cmFuc2FjdGlvbl9pZBgFIAEoCSJXChdDaGFpbmNvZGVFdmVudHNSZXNwb25zZRImCgZldmVudHMYASADKAsyFi5wcm90b3MuQ2hhaW5jb2RlRXZlbnQSFAoMYmxvY2tfbnVtYmVyGAIgASgEIj8KC0Vycm9yRGV0YWlsEg8KB2FkZHJlc3MYASABKAkSDgoGbXNwX2lkGAIgASgJEg8KB21lc3NhZ2UYAyABKAkieAoTUHJvcG9zZWRUcmFuc2FjdGlvbhIWCg50cmFuc2FjdGlvbl9pZBgBIAEoCRIoCghwcm9wb3NhbBgCIAEoCzIWLnByb3Rvcy5TaWduZWRQcm9wb3NhbBIfChdlbmRvcnNpbmdfb3JnYW5pemF0aW9ucxgDIAMoCSJRChNQcmVwYXJlZFRyYW5zYWN0aW9uEhYKDnRyYW5zYWN0aW9uX2lkGAEgASgJEiIKCGVudmVsb3BlGAIgASgLMhAuY29tbW9uLkVudmVsb3BlMvQCCgdHYXRld2F5EjwKB0VuZG9yc2USFy5nYXRld2F5LkVuZG9yc2VSZXF1ZXN0GhguZ2F0ZXdheS5FbmRvcnNlUmVzcG9uc2USOQoGU3VibWl0EhYuZ2F0ZXdheS5TdWJtaXRSZXF1ZXN0GhcuZ2F0ZXdheS5TdWJtaXRSZXNwb25zZRJRCgxDb21taXRTdGF0dXMSIi5nYXRld2F5LlNpZ25lZENvbW1pdFN0YXR1c1JlcXVlc3QaHS5nYXRld2F5LkNvbW1pdFN0YXR1c1Jlc3BvbnNlEj8KCEV2YWx1YXRlEhguZ2F0ZXdheS5FdmFsdWF0ZVJlcXVlc3QaGS5nYXRld2F5LkV2YWx1YXRlUmVzcG9uc2USXAoPQ2hhaW5jb2RlRXZlbnRzEiUuZ2F0ZXdheS5TaWduZWRDaGFpbmNvZGVFdmVudHNSZXF1ZXN0GiAuZ2F0ZXdheS5DaGFpbmNvZGVFdmVudHNSZXNwb25zZTABQmgKJW9yZy5oeXBlcmxlZGdlci5mYWJyaWMucHJvdG9zLmdhdGV3YXlCDEdhdGV3YXlQcm90b1ABWi9naXRodWIuY29tL2h5cGVybGVkZ2VyL2ZhYnJpYy1wcm90b3MtZ28vZ2F0ZXdheWIGcHJvdG8z", [file_peer_chaincode_event, file_peer_proposal, file_peer_proposal_response, file_peer_transaction, file_common_common, file_orderer_ab]);
var EndorseRequestSchema = /* @__PURE__ */ messageDesc(file_gateway_gateway, 0);
var SubmitRequestSchema = /* @__PURE__ */ messageDesc(file_gateway_gateway, 2);
var EvaluateRequestSchema = /* @__PURE__ */ messageDesc(file_gateway_gateway, 7);
var SignedChaincodeEventsRequestSchema = /* @__PURE__ */ messageDesc(file_gateway_gateway, 9);
var ChaincodeEventsRequestSchema = /* @__PURE__ */ messageDesc(file_gateway_gateway, 10);
var Gateway = /* @__PURE__ */ serviceDesc(file_gateway_gateway, 0);
function getGroundedError(error) {
if (error instanceof ConnectError) {
if (error.details && error.details.length > 0) {
const decodedDetails = error.details.map((detail) => {
if (detail && "value" in detail && detail.value instanceof Uint8Array) {
try {
return new TextDecoder().decode(detail.value);
} catch (e) {
return null;
}
}
return null;
}).filter((msg) => msg !== null);
if (decodedDetails.length > 0) {
return decodedDetails.join("; \n");
}
}
return error.message;
}
if (error instanceof Error) {
return error.message;
}
return String(error);
}
// src/utils/try-catch.ts
async function tryCatch(promiseFn, errorFn = getGroundedError) {
try {
const data = await promiseFn();
return { success: true, data, error: null };
} catch (caughtError) {
return {
success: false,
data: null,
error: new Error(errorFn(caughtError))
};
}
}
function tryCatchSync(fn) {
try {
const data = fn();
return { success: true, data, error: null };
} catch (caughtError) {
if (caughtError instanceof Error) {
return { success: false, data: null, error: caughtError };
}
return {
success: false,
data: null,
error: new Error(String(caughtError))
};
}
}
// src/protobuf/parser.ts
function decodeChaincodePayload(payloadBytes) {
if (!payloadBytes || payloadBytes.length === 0) {
return null;
}
try {
const decodedString = new TextDecoder("utf-8", { fatal: true }).decode(
payloadBytes
);
try {
return JSON.parse(decodedString);
} catch {
return decodedString;
}
} catch {
const hex = Array.from(payloadBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
return `(binary) 0x${hex}`;
}
}
function parseEvaluateResponse(response) {
return tryCatchSync(() => {
if (!response || !response.result) {
throw new Error(
"La respuesta de evaluate o su campo 'result' est\xE1n ausentes."
);
}
const finalResponse = response.result;
const parsedData = decodeChaincodePayload(finalResponse.payload);
return {
status: finalResponse.status,
message: finalResponse.message,
parsedData
};
});
}
var N = new BN(
"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
16
);
var HALF_N = N.shrn(1);
function rsToDer(rs) {
const n = rs.length / 2;
let r = rs.slice(0, n);
let s = rs.slice(n);
while (r.length > 1 && r[0] === 0 && r[1] < 128) r = r.slice(1);
while (s.length > 1 && s[0] === 0 && s[1] < 128) s = s.slice(1);
if (r[0] >= 128) r = new Uint8Array([0, ...r]);
if (s[0] >= 128) s = new Uint8Array([0, ...s]);
const encoded = new Uint8Array([2, r.length, ...r, 2, s.length, ...s]);
return new Uint8Array([48, encoded.length, ...encoded]);
}
function preventMalleability(signature) {
const r = signature.slice(0, signature.length / 2);
let s = signature.slice(signature.length / 2);
const sBN = new BN(s);
if (sBN.cmp(HALF_N) > 0) {
const newS = N.sub(sBN);
s = new Uint8Array(newS.toArray("be", 32));
}
return new Uint8Array([...r, ...s]);
}
async function signAndFormat(dataToSign, identity) {
const rawSignature = await identity.sign(dataToSign);
const lowSSignature = preventMalleability(rawSignature);
return rsToDer(lowSSignature);
}
async function signProposal(proposalBytes, identity) {
return signAndFormat(proposalBytes, identity);
}
async function signEnvelope(envelopePayload, identity) {
return signAndFormat(envelopePayload, identity);
}
var file_msp_identities = /* @__PURE__ */ fileDesc("ChRtc3AvaWRlbnRpdGllcy5wcm90bxIDbXNwIjUKElNlcmlhbGl6ZWRJZGVudGl0eRINCgVtc3BpZBgBIAEoCRIQCghpZF9ieXRlcxgCIAEoDCJhChhTZXJpYWxpemVkSWRlbWl4SWRlbnRpdHkSDQoFbnltX3gYASABKAwSDQoFbnltX3kYAiABKAwSCgoCb3UYAyABKAwSDAoEcm9sZRgEIAEoDBINCgVwcm9vZhgFIAEoDEJQCiFvcmcuaHlwZXJsZWRnZXIuZmFicmljLnByb3Rvcy5tc3BaK2dpdGh1Yi5jb20vaHlwZXJsZWRnZXIvZmFicmljLXByb3Rvcy1nby9tc3BiBnByb3RvMw");
var SerializedIdentitySchema = /* @__PURE__ */ messageDesc(file_msp_identities, 0);
var require2 = createRequire(import.meta.url);
var nodeCrypto;
if (typeof window === "undefined") {
const { webcrypto } = require2("crypto");
nodeCrypto = webcrypto;
}
function getRandomValues(array) {
if (typeof window !== "undefined" && window.crypto) {
return window.crypto.getRandomValues(array);
}
if (nodeCrypto) {
return nodeCrypto.getRandomValues(array);
}
throw new Error(
"Unsupported environment: A Web Crypto API implementation is required."
);
}
// src/protobuf/builder.ts
function stringToUint8Array(str) {
return new TextEncoder().encode(str);
}
function bytesToHexString(bytes) {
return (bytes ?? new Uint8Array()).reduce(
(s, byte) => s + byte.toString(16).padStart(2, "0"),
""
);
}
function generateNonce() {
return getRandomValues(new Uint8Array(24));
}
function createSerializedIdentityBytes(mspId, certPem) {
const si = create(SerializedIdentitySchema, {
mspid: mspId,
idBytes: stringToUint8Array(certPem)
});
return toBinary(SerializedIdentitySchema, si);
}
async function generateTransactionId(identity, mspId) {
const nonce = generateNonce();
const creatorBytes = createSerializedIdentityBytes(mspId, identity.cert);
const combined = new Uint8Array(nonce.length + creatorBytes.length);
combined.set(nonce);
combined.set(creatorBytes, nonce.length);
const hashBytes = sha256(combined);
const txId = bytesToHexString(hashBytes);
return { txId, nonce, creatorBytes };
}
function buildProposalPayload(params, txId, creatorBytes, nonce) {
const ccId = create(ChaincodeIDSchema, { name: params.chaincodeName });
const argsAsBytes = [stringToUint8Array(params.functionName)];
(params.args || []).forEach((arg) => {
argsAsBytes.push(typeof arg === "string" ? stringToUint8Array(arg) : arg);
});
const ccInput = create(ChaincodeInputSchema, { args: argsAsBytes });
const ccSpec = create(ChaincodeSpecSchema, {
type: 1 /* GOLANG */,
chaincodeId: ccId,
input: ccInput
});
const ccInvocationSpec = create(ChaincodeInvocationSpecSchema, {
chaincodeSpec: ccSpec
});
const ccProposalPayload = create(ChaincodeProposalPayloadSchema, {
input: toBinary(ChaincodeInvocationSpecSchema, ccInvocationSpec)
});
const ccHeaderExtension = create(ChaincodeHeaderExtensionSchema, {
chaincodeId: ccId
});
const channelHeader = create(ChannelHeaderSchema, {
type: 3 /* ENDORSER_TRANSACTION */,
version: 1,
channelId: params.channelName,
txId,
epoch: protoInt64.parse(0),
extension: toBinary(ChaincodeHeaderExtensionSchema, ccHeaderExtension)
});
const signatureHeader = create(SignatureHeaderSchema, {
creator: creatorBytes,
nonce
});
const header = create(HeaderSchema, {
channelHeader: toBinary(ChannelHeaderSchema, channelHeader),
signatureHeader: toBinary(SignatureHeaderSchema, signatureHeader)
});
const proposal = create(ProposalSchema, {
header: toBinary(HeaderSchema, header),
payload: toBinary(ChaincodeProposalPayloadSchema, ccProposalPayload)
});
return toBinary(ProposalSchema, proposal);
}
// src/client/fabric-client.ts
var FabricClient = class {
gatewayClient;
constructor(config) {
const transport = createGrpcWebTransport({ baseUrl: config.gatewayUrl });
this.gatewayClient = createClient(Gateway, transport);
}
/**
* Evalúa una transacción de solo lectura. La propuesta se envía a un peer,
* pero no se envía al servicio de ordenamiento.
*
* @param params Los detalles de la propuesta de transacción.
* @param identity La identidad del cliente para firmar la propuesta.
* @returns Un Result con los datos de la transacción evaluada o un error.
*/
async evaluateTransaction(params, identity) {
return tryCatch(async () => {
const { txId, nonce, creatorBytes } = await generateTransactionId(
identity,
params.mspId
);
const proposalPayloadBytes = buildProposalPayload(
params,
txId,
creatorBytes,
nonce
);
const signature = await signProposal(proposalPayloadBytes, identity);
const signedProposal = create(SignedProposalSchema, {
proposalBytes: proposalPayloadBytes,
signature
});
const evaluateRequest = create(EvaluateRequestSchema, {
channelId: params.channelName,
transactionId: txId,
proposedTransaction: signedProposal
});
const evaluateResponse = await this.gatewayClient.evaluate(evaluateRequest);
const parsedResult = parseEvaluateResponse(evaluateResponse);
if (!parsedResult.success) {
throw parsedResult.error;
}
return { txId, ...parsedResult.data };
}, getGroundedError);
}
/**
* Prepara (endorsa) una transacción para su posterior envío al orderer.
* La propuesta se envía a los peers para su endoso según la política.
*
* @param params Los detalles de la propuesta de transacción.
* @param identity La identidad del cliente para firmar la propuesta.
* @returns Un Result con la transacción preparada (el envelope de la transacción) o un error.
*/
async prepareTransaction(params, identity) {
return tryCatch(async () => {
const { txId, nonce, creatorBytes } = await generateTransactionId(
identity,
params.mspId
);
const proposalPayloadBytes = buildProposalPayload(
params,
txId,
creatorBytes,
nonce
);
const signature = await signProposal(proposalPayloadBytes, identity);
const signedProposal = create(SignedProposalSchema, {
proposalBytes: proposalPayloadBytes,
signature
});
const endorseRequest = create(EndorseRequestSchema, {
channelId: params.channelName,
transactionId: txId,
proposedTransaction: signedProposal
});
const endorseResponse = await this.gatewayClient.endorse(endorseRequest);
if (!endorseResponse.preparedTransaction?.payload) {
throw new Error(
"La respuesta del Endorse no conten\xEDa una transacci\xF3n preparada v\xE1lida."
);
}
return {
txId,
transactionEnvelope: endorseResponse.preparedTransaction.payload
};
}, getGroundedError);
}
/**
* Envía una transacción previamente preparada y firmada al orderer para su commit en el ledger.
*
* @param params Los detalles de la transacción a enviar, incluyendo el envelope de `prepareTransaction`.
* @param identity La identidad del cliente para firmar el envelope final.
* @returns Un Result confirmando el envío exitoso o un error.
*/
async submitSignedTransaction(params, identity) {
return tryCatch(async () => {
const envelopeSignature = await signEnvelope(
params.preparedTransaction,
identity
);
const clientSignedEnvelope = create(EnvelopeSchema, {
payload: params.preparedTransaction,
signature: envelopeSignature
});
const submitRequest = create(SubmitRequestSchema, {
channelId: params.channelName,
transactionId: params.txId,
preparedTransaction: clientSignedEnvelope
});
await this.gatewayClient.submit(submitRequest);
return {
txId: params.txId,
status: "Transacci\xF3n enviada con \xE9xito al gateway."
};
}, getGroundedError);
}
};
var file_ledger_rwset_rwset = /* @__PURE__ */ fileDesc("ChhsZWRnZXIvcndzZXQvcndzZXQucHJvdG8SBXJ3c2V0IoMBCg5UeFJlYWRXcml0ZVNldBIzCgpkYXRhX21vZGVsGAEgASgOMh8ucndzZXQuVHhSZWFkV3JpdGVTZXQuRGF0YU1vZGVsEicKCG5zX3J3c2V0GAIgAygLMhUucndzZXQuTnNSZWFkV3JpdGVTZXQiEwoJRGF0YU1vZGVsEgYKAktWEAAieAoOTnNSZWFkV3JpdGVTZXQSEQoJbmFtZXNwYWNlGAEgASgJEg0KBXJ3c2V0GAIgASgMEkQKF2NvbGxlY3Rpb25faGFzaGVkX3J3c2V0GAMgAygLMiMucndzZXQuQ29sbGVjdGlvbkhhc2hlZFJlYWRXcml0ZVNldCJlChxDb2xsZWN0aW9uSGFzaGVkUmVhZFdyaXRlU2V0EhcKD2NvbGxlY3Rpb25fbmFtZRgBIAEoCRIUCgxoYXNoZWRfcndzZXQYAiABKAwSFgoOcHZ0X3J3c2V0X2hhc2gYAyABKAwieAoRVHhQdnRSZWFkV3JpdGVTZXQSMwoKZGF0YV9tb2RlbBgBIAEoDjIfLnJ3c2V0LlR4UmVhZFdyaXRlU2V0LkRhdGFNb2RlbBIuCgxuc19wdnRfcndzZXQYAiADKAsyGC5yd3NldC5Oc1B2dFJlYWRXcml0ZVNldCJmChFOc1B2dFJlYWRXcml0ZVNldBIRCgluYW1lc3BhY2UYASABKAkSPgoUY29sbGVjdGlvbl9wdnRfcndzZXQYAiADKAsyIC5yd3NldC5Db2xsZWN0aW9uUHZ0UmVhZFdyaXRlU2V0IkMKGUNvbGxlY3Rpb25QdnRSZWFkV3JpdGVTZXQSFwoPY29sbGVjdGlvbl9uYW1lGAEgASgJEg0KBXJ3c2V0GAIgASgMQmIKKm9yZy5oeXBlcmxlZGdlci5mYWJyaWMucHJvdG9zLmxlZGdlci5yd3NldFo0Z2l0aHViLmNvbS9oeXBlcmxlZGdlci9mYWJyaWMtcHJvdG9zLWdvL2xlZGdlci9yd3NldGIGcHJvdG8z");
// src/generated_protos/peer/events_pb.ts
var file_peer_events = /* @__PURE__ */ fileDesc("ChFwZWVyL2V2ZW50cy5wcm90bxIGcHJvdG9zIm8KDUZpbHRlcmVkQmxvY2sSEgoKY2hhbm5lbF9pZBgBIAEoCRIOCgZudW1iZXIYAiABKAQSOgoVZmlsdGVyZWRfdHJhbnNhY3Rpb25zGAQgAygLMhsucHJvdG9zLkZpbHRlcmVkVHJhbnNhY3Rpb24ixgEKE0ZpbHRlcmVkVHJhbnNhY3Rpb24SDAoEdHhpZBgBIAEoCRIgCgR0eXBlGAIgASgOMhIuY29tbW9uLkhlYWRlclR5cGUSNAoSdHhfdmFsaWRhdGlvbl9jb2RlGAMgASgOMhgucHJvdG9zLlR4VmFsaWRhdGlvbkNvZGUSQQoTdHJhbnNhY3Rpb25fYWN0aW9ucxgEIAEoCzIiLnByb3Rvcy5GaWx0ZXJlZFRyYW5zYWN0aW9uQWN0aW9uc0gAQgYKBERhdGEiWAoaRmlsdGVyZWRUcmFuc2FjdGlvbkFjdGlvbnMSOgoRY2hhaW5jb2RlX2FjdGlvbnMYASADKAsyHy5wcm90b3MuRmlsdGVyZWRDaGFpbmNvZGVBY3Rpb24iSgoXRmlsdGVyZWRDaGFpbmNvZGVBY3Rpb24SLwoPY2hhaW5jb2RlX2V2ZW50GAEgASgLMhYucHJvdG9zLkNoYWluY29kZUV2ZW50Is8BChNCbG9ja0FuZFByaXZhdGVEYXRhEhwKBWJsb2NrGAEgASgLMg0uY29tbW9uLkJsb2NrEkkKEHByaXZhdGVfZGF0YV9tYXAYAiADKAsyLy5wcm90b3MuQmxvY2tBbmRQcml2YXRlRGF0YS5Qcml2YXRlRGF0YU1hcEVudHJ5Gk8KE1ByaXZhdGVEYXRhTWFwRW50cnkSCwoDa2V5GAEgASgEEicKBXZhbHVlGAIgASgLMhgucndzZXQuVHhQdnRSZWFkV3JpdGVTZXQ6AjgBIssBCg9EZWxpdmVyUmVzcG9uc2USIAoGc3RhdHVzGAEgASgOMg4uY29tbW9uLlN0YXR1c0gAEh4KBWJsb2NrGAIgASgLMg0uY29tbW9uLkJsb2NrSAASLwoOZmlsdGVyZWRfYmxvY2sYAyABKAsyFS5wcm90b3MuRmlsdGVyZWRCbG9ja0gAEj0KFmJsb2NrX2FuZF9wcml2YXRlX2RhdGEYBCABKAsyGy5wcm90b3MuQmxvY2tBbmRQcml2YXRlRGF0YUgAQgYKBFR5cGUy1AEKB0RlbGl2ZXISOgoHRGVsaXZlchIQLmNvbW1vbi5FbnZlbG9wZRoXLnByb3Rvcy5EZWxpdmVyUmVzcG9uc2UiACgBMAESQgoPRGVsaXZlckZpbHRlcmVkEhAuY29tbW9uLkVudmVsb3BlGhcucHJvdG9zLkRlbGl2ZXJSZXNwb25zZSIAKAEwARJJChZEZWxpdmVyV2l0aFByaXZhdGVEYXRhEhAuY29tbW9uLkVudmVsb3BlGhcucHJvdG9zLkRlbGl2ZXJSZXNwb25zZSIAKAEwAUJhCiJvcmcuaHlwZXJsZWRnZXIuZmFicmljLnByb3Rvcy5wZWVyQg1FdmVudHNQYWNrYWdlWixnaXRodWIuY29tL2h5cGVybGVkZ2VyL2ZhYnJpYy1wcm90b3MtZ28vcGVlcmIGcHJvdG8z", [file_common_common, file_ledger_rwset_rwset, file_peer_chaincode_event, file_peer_transaction]);
var DeliverResponseSchema = /* @__PURE__ */ messageDesc(file_peer_events, 5);
async function createSignedDeliverRequest(params) {
const { txId, nonce, creatorBytes } = await generateTransactionId(
params.identity,
params.mspId
);
let startPosition;
if (typeof params.startBlock === "bigint") {
startPosition = create(SeekPositionSchema, {
Type: {
case: "specified",
value: create(SeekSpecifiedSchema, { number: params.startBlock })
}
});
} else {
startPosition = create(SeekPositionSchema, {
Type: { case: "newest", value: create(SeekNewestSchema, {}) }
});
}
const stopPosition = create(SeekPositionSchema, {
Type: {
case: "specified",
value: create(SeekSpecifiedSchema, {
number: protoInt64.parse(Number.MAX_SAFE_INTEGER.toString())
})
}
});
const seekInfo = create(SeekInfoSchema, {
start: startPosition,
stop: stopPosition,
behavior: 0
});
const channelHeader = create(ChannelHeaderSchema, {
type: 5 /* DELIVER_SEEK_INFO */,
version: 0,
channelId: params.channelName,
txId,
epoch: protoInt64.parse(0),
timestamp: create(TimestampSchema, {
seconds: BigInt(Math.floor(Date.now() / 1e3)),
// Segundos como BigInt
nanos: Date.now() % 1e3 * 1e6
// Nanosegundos
})
});
const signatureHeader = create(SignatureHeaderSchema, {
creator: creatorBytes,
nonce
});
const payload = create(PayloadSchema, {
header: create(HeaderSchema, {
channelHeader: toBinary(ChannelHeaderSchema, channelHeader),
signatureHeader: toBinary(SignatureHeaderSchema, signatureHeader)
}),
data: toBinary(SeekInfoSchema, seekInfo)
});
const payloadBytes = toBinary(PayloadSchema, payload);
const signature = await signEnvelope(payloadBytes, params.identity);
return create(EnvelopeSchema, { payload: payloadBytes, signature });
}
// src/events/event-service.ts
var EventService = class {
gatewayClient;
wsBaseUrl;
constructor(config) {
const transport = createGrpcWebTransport({ baseUrl: config.gatewayUrl });
this.gatewayClient = createClient(Gateway, transport);
this.wsBaseUrl = config.wsUrl;
}
/**
* Establece una conexión para escuchar eventos emitidos por un chaincode específico.
* Devuelve un Generador Asíncrono que produce respuestas a medida que llegan.
*
* @param params Los detalles del canal y chaincode a escuchar.
* @param identity La identidad del cliente para firmar la petición de eventos.
* @param signal Un AbortSignal para cancelar la suscripción y cerrar el stream.
* @yields {ChaincodeEventsResponse} Un objeto de respuesta por cada bloque que contenga eventos.
*/
async *listenToChaincodeEvents(params, identity, signal) {
try {
const signedRequest = await this.createSignedChaincodeEventsRequest(
params,
identity
);
const stream = this.gatewayClient.chaincodeEvents(signedRequest, {
signal
});
console.log(
`[EventService] Escuchando eventos para ${params.chaincodeName} en ${params.channelName}...`
);
for await (const response of stream) {
if (signal.aborted) break;
yield response;
}
} catch (error) {
if (signal.aborted || error instanceof Error && error.name === "AbortError") {
console.log(
"[EventService] Stream de eventos de chaincode cancelado por el cliente."
);
} else {
console.error(
"[EventService] Error en el stream de eventos de chaincode:",
error
);
throw error;
}
} finally {
console.log(
`[EventService] Stream para ${params.chaincodeName} finalizado.`
);
}
}
/**
* Establece una conexión WebSocket para escuchar eventos de bloque filtrados de un canal.
* Devuelve un Generador Asíncrono que produce bloques a medida que son commiteados.
*
* @param params Los detalles del canal y peer a escuchar.
* @param identity La identidad del cliente para firmar la petición de deliver.
* @param signal Un AbortSignal para cancelar la suscripción y cerrar el WebSocket.
* @yields {FilteredBlock} Un bloque filtrado cada vez que se commitea uno nuevo.
*/
async *listenToBlockEvents(params, identity, signal) {
const wsUrl = new URL(this.wsBaseUrl);
wsUrl.searchParams.append("target", params.targetPeer);
wsUrl.searchParams.append("hostname", params.targetHostname);
const signedRequestEnvelope = await createSignedDeliverRequest({
...params,
identity
});
const requestBytes = toBinary(EnvelopeSchema, signedRequestEnvelope);
const socket = new WebSocket(wsUrl.toString());
socket.binaryType = "arraybuffer";
try {
await this.waitForSocketOpen(socket, signal);
socket.send(requestBytes);
console.log(
`[EventService] Escuchando eventos de bloque en el canal ${params.channelName}...`
);
while (!signal.aborted) {
const message = await this.waitForSocketMessage(socket, signal);
const deliverResponse = fromBinary(
DeliverResponseSchema,
new Uint8Array(message.data)
);
if (deliverResponse.Type.case === "filteredBlock") {
yield deliverResponse.Type.value;
} else if (deliverResponse.Type.case === "status") {
console.warn(
"[EventService] Mensaje de estado recibido del peer:",
deliverResponse.Type.value
);
}
}
} catch (error) {
if (signal.aborted || error instanceof Error && error.name === "AbortError") {
console.log(
"[EventService] Stream de eventos de bloque cancelado por el cliente."
);
} else {
console.error(
"[EventService] Error en el stream de eventos de bloque:",
error
);
throw error;
}
} finally {
if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
socket.close(1e3, "Stream finished by client");
}
console.log(
`[EventService] Stream de bloques para ${params.channelName} finalizado.`
);
}
}
// --- Métodos Privados de Soporte ---
async createSignedChaincodeEventsRequest(params, identity) {
const identityBytes = createSerializedIdentityBytes(
params.mspId,
identity.cert
);
const eventsRequest = create(ChaincodeEventsRequestSchema, {
channelId: params.channelName,
chaincodeId: params.chaincodeName,
identity: identityBytes
});
const requestBytes = toBinary(ChaincodeEventsRequestSchema, eventsRequest);
const signature = await signProposal(requestBytes, identity);
return create(SignedChaincodeEventsRequestSchema, {
request: requestBytes,
signature
});
}
waitForSocketOpen(socket, signal) {
return new Promise((resolve, reject) => {
if (signal.aborted) return reject(new Error("AbortError"));
const abortHandler = () => {
socket.close();
reject(new Error("AbortError"));
};
signal.addEventListener("abort", abortHandler, { once: true });
socket.onopen = () => {
signal.removeEventListener("abort", abortHandler);
resolve();
};
socket.onerror = () => {
signal.removeEventListener("abort", abortHandler);
reject(new Error("Fallo al establecer la conexi\xF3n WebSocket."));
};
});
}
waitForSocketMessage(socket, signal) {
return new Promise((resolve, reject) => {
if (signal.aborted) return reject(new Error("AbortError"));
const abortHandler = () => reject(new Error("AbortError"));
signal.addEventListener("abort", abortHandler, { once: true });
socket.onmessage = (event) => {
signal.removeEventListener("abort", abortHandler);
resolve(event);
};
socket.onclose = (event) => {
signal.removeEventListener("abort", abortHandler);
reject(
new Error(
`WebSocket cerrado inesperadamente: ${event.code} ${event.reason}`
)
);
};
socket.onerror = () => {
signal.removeEventListener("abort", abortHandler);
reject(new Error("Error en la conexi\xF3n WebSocket."));
};
});
}
};
export { EventService, FabricClient, IdentityService };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map