From 84f45e9bf735a76a8bab6cbfef5a689aefda5ddc Mon Sep 17 00:00:00 2001 From: huketo Date: Sat, 13 Sep 2025 18:56:21 +0900 Subject: [PATCH] refactor(ffi): replace node-ffi-napi with koffi - Switched to koffi due to node-ffi-napi's incompatibility with Node.js v16+ on Windows. Signed-off-by: huketo --- biome.json | 3 + packages/anoncreds-nodejs/package.json | 9 +- .../anoncreds-nodejs/src/NodeJSAnoncreds.ts | 692 +++++++++++------- packages/anoncreds-nodejs/src/ffi/alloc.ts | 22 +- .../anoncreds-nodejs/src/ffi/conversion.ts | 9 +- packages/anoncreds-nodejs/src/ffi/helpers.ts | 95 +++ packages/anoncreds-nodejs/src/ffi/index.ts | 1 + .../anoncreds-nodejs/src/ffi/primitives.ts | 30 +- .../anoncreds-nodejs/src/ffi/serialize.ts | 71 +- .../anoncreds-nodejs/src/ffi/structures.ts | 106 ++- .../src/library/NativeBindingInterface.ts | 262 ++++++- .../anoncreds-nodejs/src/library/bindings.ts | 376 ++++------ .../anoncreds-nodejs/src/library/register.ts | 22 +- pnpm-lock.yaml | 201 +---- 14 files changed, 1027 insertions(+), 872 deletions(-) create mode 100644 packages/anoncreds-nodejs/src/ffi/helpers.ts diff --git a/biome.json b/biome.json index c489061..9eae3e6 100644 --- a/biome.json +++ b/biome.json @@ -32,6 +32,9 @@ }, "complexity": { "noStaticOnlyClass": "off" + }, + "suspicious": { + "noExplicitAny": "off" } } }, diff --git a/packages/anoncreds-nodejs/package.json b/packages/anoncreds-nodejs/package.json index 43776b3..d2ebe6c 100644 --- a/packages/anoncreds-nodejs/package.json +++ b/packages/anoncreds-nodejs/package.json @@ -24,16 +24,11 @@ "install": "node scripts/install.js" }, "dependencies": { - "@2060.io/ffi-napi": "^4.0.9", - "@2060.io/ref-napi": "^3.0.6", - "@hyperledger/anoncreds-shared": "workspace:*", - "ref-array-di": "1.2.2", - "ref-struct-di": "1.1.1" + "koffi": "^2.14.0", + "@hyperledger/anoncreds-shared": "workspace:*" }, "devDependencies": { "@types/node": "catalog:", - "@types/ref-array-di": "^1.2.3", - "@types/ref-struct-di": "^1.1.6", "typescript": "catalog:" }, "binary": { diff --git a/packages/anoncreds-nodejs/src/NodeJSAnoncreds.ts b/packages/anoncreds-nodejs/src/NodeJSAnoncreds.ts index 5a48a71..fb7ad7c 100644 --- a/packages/anoncreds-nodejs/src/NodeJSAnoncreds.ts +++ b/packages/anoncreds-nodejs/src/NodeJSAnoncreds.ts @@ -6,48 +6,58 @@ import type { NativeCredentialRevocationConfig, NativeNonRevokedIntervalOverride, } from '@hyperledger/anoncreds-shared' -import type { TypedArray } from 'ref-array-di' -import type { StructObject } from 'ref-struct-di' +import koffi, { type IKoffiCType, alloc } from 'koffi' import { TextDecoder, TextEncoder } from 'util' import { AnoncredsError, ByteBuffer, ObjectHandle } from '@hyperledger/anoncreds-shared' import { + ByteBufferStruct, CredRevInfoStruct, CredentialEntryListStruct, CredentialEntryStruct, CredentialProveListStruct, CredentialProveStruct, + FFI_INT8, + FFI_OBJECT_HANDLE, + FFI_STRING, + FFI_STRING_PTR, NonRevokedIntervalOverrideListStruct, NonRevokedIntervalOverrideStruct, ObjectHandleArray, ObjectHandleListStruct, StringListStruct, - allocateByteBuffer, - allocateInt8Buffer, allocatePointer, - allocateStringBuffer, - byteBufferToBuffer, + createCredRevInfoStruct, + createCredentialEntryListStruct, + createCredentialEntryStruct, + createCredentialProveListStruct, + createCredentialProveStruct, + createI32ListStruct, + createNonRevokedIntervalOverrideListStruct, + createNonRevokedIntervalOverrideStruct, + createObjectHandleListStruct, + createStringListStruct, serializeArguments, } from './ffi' import { getNativeAnoncreds } from './library' -function handleReturnPointer(returnValue: Buffer, cleanupCallback?: (buffer: Buffer) => void): Return { - if (returnValue.address() === 0) { - throw AnoncredsError.customError({ message: 'Unexpected null pointer' }) - } - - const ret = returnValue.deref() as Return - if (cleanupCallback) cleanupCallback(returnValue) - - return ret +function handleReturnPointer(ptr: [null]): Return { + const value = ptr[0] + return value as Return } export class NodeJSAnoncreds implements Anoncreds { private handleError() { - const nativeError = allocateStringBuffer() - getNativeAnoncreds().anoncreds_get_current_error(nativeError) - const anoncredsErrorObject = JSON.parse(nativeError.deref() as string) as AnoncredsErrorObject + const nativeError: [null] = [null] + const result = getNativeAnoncreds().anoncreds_get_current_error(nativeError) + if (result !== 0) { + throw AnoncredsError.customError({ message: 'Failed to get current error' }) + } + + const errorJsonString = handleReturnPointer(nativeError) + + const anoncredsErrorObject: AnoncredsErrorObject = JSON.parse(errorJsonString) as AnoncredsErrorObject if (anoncredsErrorObject.code === 0) return @@ -59,11 +69,13 @@ export class NodeJSAnoncreds implements Anoncreds { } public generateNonce(): string { - const ret = allocateStringBuffer() - this.nativeAnoncreds.anoncreds_generate_nonce(ret) - this.handleError() + const outNonceString: [null] = [null] + const result = this.nativeAnoncreds.anoncreds_generate_nonce(outNonceString) + if (result !== 0) { + this.handleError() + } - return handleReturnPointer(ret) + return handleReturnPointer(outNonceString) } public createSchema(options: { @@ -74,32 +86,52 @@ export class NodeJSAnoncreds implements Anoncreds { }): ObjectHandle { const { name, version, issuerId, attributeNames } = serializeArguments(options) - const ret = allocatePointer() + const outSchemaHandle: [null] = [null] - this.nativeAnoncreds.anoncreds_create_schema(name, version, issuerId, attributeNames, ret) - this.handleError() + const result = this.nativeAnoncreds.anoncreds_create_schema( + name, + version, + issuerId, + attributeNames, + outSchemaHandle + ) + if (result !== 0) { + this.handleError() + } + + const schemaHandle = handleReturnPointer(outSchemaHandle) - return new ObjectHandle(handleReturnPointer(ret)) + return new ObjectHandle(schemaHandle) } public revocationRegistryDefinitionGetAttribute(options: { objectHandle: ObjectHandle; name: string }) { const { objectHandle, name } = serializeArguments(options) - const ret = allocateStringBuffer() - this.nativeAnoncreds.anoncreds_revocation_registry_definition_get_attribute(objectHandle, name, ret) - this.handleError() + const outString: [null] = [null] + + const result = this.nativeAnoncreds.anoncreds_revocation_registry_definition_get_attribute( + objectHandle, + name, + outString + ) + if (result !== 0) { + this.handleError() + } - return handleReturnPointer(ret) + return handleReturnPointer(outString) } public credentialGetAttribute(options: { objectHandle: ObjectHandle; name: string }) { const { objectHandle, name } = serializeArguments(options) - const ret = allocateStringBuffer() - this.nativeAnoncreds.anoncreds_credential_get_attribute(objectHandle, name, ret) - this.handleError() + const outString: [null] = [null] + + const result = this.nativeAnoncreds.anoncreds_credential_get_attribute(objectHandle, name, outString) + if (result !== 0) { + this.handleError() + } - return handleReturnPointer(ret) + return handleReturnPointer(outString) } public createCredentialDefinition(options: { @@ -116,11 +148,11 @@ export class NodeJSAnoncreds implements Anoncreds { } { const { schemaId, issuerId, schema, tag, signatureType, supportRevocation } = serializeArguments(options) - const credentialDefinitionPtr = allocatePointer() - const credentialDefinitionPrivatePtr = allocatePointer() - const keyCorrectnessProofPtr = allocatePointer() + const credentialDefinitionPtr: [null] = [null] + const credentialDefinitionPrivatePtr: [null] = [null] + const keyCorrectnessProofPtr: [null] = [null] - this.nativeAnoncreds.anoncreds_create_credential_definition( + const result = this.nativeAnoncreds.anoncreds_create_credential_definition( schemaId, schema, tag, @@ -131,7 +163,9 @@ export class NodeJSAnoncreds implements Anoncreds { credentialDefinitionPrivatePtr, keyCorrectnessProofPtr ) - this.handleError() + if (result !== 0) { + this.handleError() + } return { credentialDefinition: new ObjectHandle(handleReturnPointer(credentialDefinitionPtr)), @@ -157,19 +191,22 @@ export class NodeJSAnoncreds implements Anoncreds { const attributeEncodedValues = this.convertAttributeEncodedValues(options.attributeEncodedValues) const revocationConfiguration = this.convertRevocationConfiguration(options.revocationConfiguration) - const credentialPtr = allocatePointer() - this.nativeAnoncreds.anoncreds_create_credential( + const credentialPtr: [null] = [null] + const result = this.nativeAnoncreds.anoncreds_create_credential( credentialDefinition, credentialDefinitionPrivate, credentialOffer, credentialRequest, attributeNames, attributeRawValues, - attributeEncodedValues as unknown as Buffer, - revocationConfiguration?.ref().address() ?? 0, + attributeEncodedValues, + revocationConfiguration ?? null, credentialPtr ) - this.handleError() + + if (result !== 0) { + this.handleError() + } return new ObjectHandle(handleReturnPointer(credentialPtr)) } @@ -177,14 +214,16 @@ export class NodeJSAnoncreds implements Anoncreds { public encodeCredentialAttributes(options: { attributeRawValues: string[] }): string[] { const { attributeRawValues } = serializeArguments(options) - const ret = allocateStringBuffer() + const outStringPtr: [null] = [null] - this.nativeAnoncreds.anoncreds_encode_credential_attributes(attributeRawValues, ret) - this.handleError() + const result = this.nativeAnoncreds.anoncreds_encode_credential_attributes(attributeRawValues, outStringPtr) + if (result !== 0) { + this.handleError() + } - const result = handleReturnPointer(ret) + const encodedValues = handleReturnPointer(outStringPtr) - return result.split(',') + return encodedValues.split(',') } public processCredential(options: { @@ -196,19 +235,22 @@ export class NodeJSAnoncreds implements Anoncreds { }): ObjectHandle { const { credential, credentialRequestMetadata, linkSecret, credentialDefinition } = serializeArguments(options) - const ret = allocatePointer() + const outObjectHandle: [null] = [null] - this.nativeAnoncreds.anoncreds_process_credential( + const result = this.nativeAnoncreds.anoncreds_process_credential( credential, credentialRequestMetadata, linkSecret, credentialDefinition, options.revocationRegistryDefinition?.handle ?? 0, - ret + outObjectHandle ) - this.handleError() - return new ObjectHandle(handleReturnPointer(ret)) + if (result !== 0) { + this.handleError() + } + + return new ObjectHandle(handleReturnPointer(outObjectHandle)) } public createCredentialOffer(options: { @@ -218,11 +260,19 @@ export class NodeJSAnoncreds implements Anoncreds { }): ObjectHandle { const { schemaId, credentialDefinitionId, keyCorrectnessProof } = serializeArguments(options) - const ret = allocatePointer() - this.nativeAnoncreds.anoncreds_create_credential_offer(schemaId, credentialDefinitionId, keyCorrectnessProof, ret) - this.handleError() + const outObjectHandle: [null] = [null] + const result = this.nativeAnoncreds.anoncreds_create_credential_offer( + schemaId, + credentialDefinitionId, + keyCorrectnessProof, + outObjectHandle + ) + + if (result !== 0) { + this.handleError() + } - return new ObjectHandle(handleReturnPointer(ret)) + return new ObjectHandle(handleReturnPointer(outObjectHandle)) } public createCredentialRequest(options: { @@ -236,10 +286,10 @@ export class NodeJSAnoncreds implements Anoncreds { const { entropy, proverDid, credentialDefinition, linkSecret, linkSecretId, credentialOffer } = serializeArguments(options) - const credentialRequestPtr = allocatePointer() - const credentialRequestMetadataPtr = allocatePointer() + const credentialRequestPtr: [null] = [null] + const credentialRequestMetadataPtr: [null] = [null] - this.nativeAnoncreds.anoncreds_create_credential_request( + const result = this.nativeAnoncreds.anoncreds_create_credential_request( entropy, proverDid, credentialDefinition, @@ -249,7 +299,10 @@ export class NodeJSAnoncreds implements Anoncreds { credentialRequestPtr, credentialRequestMetadataPtr ) - this.handleError() + + if (result !== 0) { + this.handleError() + } return { credentialRequest: new ObjectHandle(handleReturnPointer(credentialRequestPtr)), @@ -258,12 +311,14 @@ export class NodeJSAnoncreds implements Anoncreds { } public createLinkSecret(): string { - const ret = allocateStringBuffer() + const outStringPtr: [null] = [null] - this.nativeAnoncreds.anoncreds_create_link_secret(ret) - this.handleError() + const result = this.nativeAnoncreds.anoncreds_create_link_secret(outStringPtr) + if (result !== 0) { + this.handleError() + } - return handleReturnPointer(ret) + return handleReturnPointer(outStringPtr) } public createPresentation(options: { @@ -277,14 +332,14 @@ export class NodeJSAnoncreds implements Anoncreds { }): ObjectHandle { const { presentationRequest, linkSecret } = serializeArguments(options) - const selfAttestNames = StringListStruct({ + const selfAttestNames = createStringListStruct({ count: Object.keys(options.selfAttest).length, - data: Object.keys(options.selfAttest) as unknown as TypedArray, + data: Object.keys(options.selfAttest), }) - const selfAttestValues = StringListStruct({ + const selfAttestValues = createStringListStruct({ count: Object.values(options.selfAttest).length, - data: Object.values(options.selfAttest) as unknown as TypedArray, + data: Object.values(options.selfAttest), }) const credentialEntryList = this.convertCredentialList(options.credentials) @@ -292,24 +347,27 @@ export class NodeJSAnoncreds implements Anoncreds { const { schemaIds, schemas } = this.convertSchemas(options.schemas) const { credentialDefinitionIds, credentialDefinitions } = this.convertCredDefs(options.credentialDefinitions) - const ret = allocatePointer() + const outObjectHandle: [null] = [null] - this.nativeAnoncreds.anoncreds_create_presentation( + const result = this.nativeAnoncreds.anoncreds_create_presentation( presentationRequest, credentialEntryList, credentialProveList, - selfAttestNames as unknown as Buffer, - selfAttestValues as unknown as Buffer, + selfAttestNames, + selfAttestValues, linkSecret, schemas, schemaIds, credentialDefinitions, credentialDefinitionIds, - ret + outObjectHandle ) - this.handleError() - return new ObjectHandle(handleReturnPointer(ret)) + if (result !== 0) { + this.handleError() + } + + return new ObjectHandle(handleReturnPointer(outObjectHandle)) } public verifyPresentation(options: { @@ -324,38 +382,68 @@ export class NodeJSAnoncreds implements Anoncreds { revocationStatusLists?: ObjectHandle[] nonRevokedIntervalOverrides?: NativeNonRevokedIntervalOverride[] }): boolean { - const { - presentation, - presentationRequest, - schemas, - credentialDefinitions, - revocationRegistryDefinitions, - revocationStatusLists, - revocationRegistryDefinitionIds, - schemaIds, - credentialDefinitionIds, - } = serializeArguments(options) + // Mandatory handles + const { presentation, presentationRequest } = serializeArguments({ + presentation: options.presentation, + presentationRequest: options.presentationRequest, + }) + + // Build required list structs explicitly (do NOT rely on serializeArguments for Koffi struct expectations) + const schemasList = createObjectHandleListStruct({ + count: options.schemas.length, + data: options.schemas.map((s) => s.handle), + }) as unknown as Buffer + const schemaIdsList = createStringListStruct({ + count: options.schemaIds.length, + data: options.schemaIds, + }) + + const credDefsList = createObjectHandleListStruct({ + count: options.credentialDefinitions.length, + data: options.credentialDefinitions.map((c) => c.handle), + }) as unknown as Buffer + const credDefIdsList = createStringListStruct({ + count: options.credentialDefinitionIds.length, + data: options.credentialDefinitionIds, + }) + + // Optional revocation related collections -> supply empty lists when undefined per native API contract + const revRegDefsList = createObjectHandleListStruct({ + count: options.revocationRegistryDefinitions?.length ?? 0, + data: (options.revocationRegistryDefinitions ?? []).map((r) => r.handle), + }) as unknown as Buffer + const revRegDefIdsList = createStringListStruct({ + count: options.revocationRegistryDefinitionIds?.length ?? 0, + data: options.revocationRegistryDefinitionIds ?? [], + }) + const revStatusLists = createObjectHandleListStruct({ + count: options.revocationStatusLists?.length ?? 0, + data: (options.revocationStatusLists ?? []).map((r) => r.handle), + }) as unknown as Buffer const nonRevokedIntervalOverrideList = this.convertNonRevokedIntervalOverrides(options.nonRevokedIntervalOverrides) - const ret = allocateInt8Buffer() + const outInt8: [null] = [null] - this.nativeAnoncreds.anoncreds_verify_presentation( + const result = this.nativeAnoncreds.anoncreds_verify_presentation( presentation, presentationRequest, - schemas, - schemaIds, - credentialDefinitions, - credentialDefinitionIds, - revocationRegistryDefinitions, - revocationRegistryDefinitionIds, - revocationStatusLists, + schemasList, + schemaIdsList, + credDefsList, + credDefIdsList, + revRegDefsList, + revRegDefIdsList, + revStatusLists, nonRevokedIntervalOverrideList, - ret + outInt8 ) - this.handleError() - return Boolean(handleReturnPointer(ret)) + if (result !== 0) { + this.handleError() + } + + return Boolean(handleReturnPointer(outInt8)) } public createRevocationStatusList(options: { @@ -377,9 +465,9 @@ export class NodeJSAnoncreds implements Anoncreds { timestamp, } = serializeArguments(options) - const ret = allocatePointer() + const outObjectHandle: [null] = [null] - this.nativeAnoncreds.anoncreds_create_revocation_status_list( + const result = this.nativeAnoncreds.anoncreds_create_revocation_status_list( credentialDefinition, revocationRegistryDefinitionId, revocationRegistryDefinition, @@ -387,11 +475,14 @@ export class NodeJSAnoncreds implements Anoncreds { issuerId, issuanceByDefault, timestamp ?? -1, - ret + outObjectHandle ) - this.handleError() - return new ObjectHandle(handleReturnPointer(ret)) + if (result !== 0) { + this.handleError() + } + + return new ObjectHandle(handleReturnPointer(outObjectHandle)) } public updateRevocationStatusListTimestampOnly(options: { @@ -399,16 +490,19 @@ export class NodeJSAnoncreds implements Anoncreds { currentRevocationStatusList: ObjectHandle }): ObjectHandle { const { currentRevocationStatusList, timestamp } = serializeArguments(options) - const ret = allocatePointer() + const outObjectHandle: [null] = [null] - this.nativeAnoncreds.anoncreds_update_revocation_status_list_timestamp_only( + const result = this.nativeAnoncreds.anoncreds_update_revocation_status_list_timestamp_only( timestamp, currentRevocationStatusList, - ret + outObjectHandle ) - this.handleError() - return new ObjectHandle(handleReturnPointer(ret)) + if (result !== 0) { + this.handleError() + } + + return new ObjectHandle(handleReturnPointer(outObjectHandle)) } public updateRevocationStatusList(options: { @@ -425,25 +519,42 @@ export class NodeJSAnoncreds implements Anoncreds { revocationRegistryDefinition, revocationRegistryDefinitionPrivate, currentRevocationStatusList, - issued, - revoked, timestamp, - } = serializeArguments(options) - const ret = allocatePointer() + } = serializeArguments({ + credentialDefinition: options.credentialDefinition, + revocationRegistryDefinition: options.revocationRegistryDefinition, + revocationRegistryDefinitionPrivate: options.revocationRegistryDefinitionPrivate, + currentRevocationStatusList: options.currentRevocationStatusList, + timestamp: options.timestamp ?? -1, + }) - this.nativeAnoncreds.anoncreds_update_revocation_status_list( - credentialDefinition, - revocationRegistryDefinition, - revocationRegistryDefinitionPrivate, - currentRevocationStatusList, - issued, - revoked, + // issued/revoked must be I32List structs, not undefined/null + const issuedList = createI32ListStruct({ + count: options.issued?.length ?? 0, + data: options.issued ?? [], + }) + const revokedList = createI32ListStruct({ + count: options.revoked?.length ?? 0, + data: options.revoked ?? [], + }) + + const newRevStatusListPtr: [null] = [null] + + const result = this.nativeAnoncreds.anoncreds_update_revocation_status_list( + credentialDefinition, // cred_def + revocationRegistryDefinition, // rev_reg_def + revocationRegistryDefinitionPrivate, // rev_reg_priv + currentRevocationStatusList, // rev_current_list + issuedList, + revokedList, timestamp ?? -1, - ret + newRevStatusListPtr ) - this.handleError() + if (result !== 0) { + this.handleError() + } - return new ObjectHandle(handleReturnPointer(ret)) + return new ObjectHandle(handleReturnPointer(newRevStatusListPtr)) } public createRevocationRegistryDefinition(options: { @@ -468,7 +579,7 @@ export class NodeJSAnoncreds implements Anoncreds { const revocationRegistryDefinitionPtr = allocatePointer() const revocationRegistryDefinitionPrivate = allocatePointer() - this.nativeAnoncreds.anoncreds_create_revocation_registry_def( + const result = this.nativeAnoncreds.anoncreds_create_revocation_registry_def( credentialDefinition, credentialDefinitionId, issuerId, @@ -479,12 +590,15 @@ export class NodeJSAnoncreds implements Anoncreds { revocationRegistryDefinitionPtr, revocationRegistryDefinitionPrivate ) - this.handleError() + + if (result !== 0) { + this.handleError() + } return { - revocationRegistryDefinition: new ObjectHandle(handleReturnPointer(revocationRegistryDefinitionPtr)), + revocationRegistryDefinition: new ObjectHandle(koffi.decode(revocationRegistryDefinitionPtr, FFI_OBJECT_HANDLE)), revocationRegistryDefinitionPrivate: new ObjectHandle( - handleReturnPointer(revocationRegistryDefinitionPrivate) + koffi.decode(revocationRegistryDefinitionPrivate, FFI_OBJECT_HANDLE) ), } } @@ -502,20 +616,22 @@ export class NodeJSAnoncreds implements Anoncreds { const oldRevocationState = options.oldRevocationState ?? new ObjectHandle(0) const oldRevocationStatusList = options.oldRevocationStatusList ?? new ObjectHandle(0) - const ret = allocatePointer() + const outObjectHandle: [null] = [null] - this.nativeAnoncreds.anoncreds_create_or_update_revocation_state( + const result = this.nativeAnoncreds.anoncreds_create_or_update_revocation_state( revocationRegistryDefinition, revocationStatusList, revocationRegistryIndex, tailsPath, oldRevocationState.handle, oldRevocationStatusList.handle, - ret + outObjectHandle ) - this.handleError() + if (result !== 0) { + this.handleError() + } - return new ObjectHandle(handleReturnPointer(ret)) + return new ObjectHandle(handleReturnPointer(outObjectHandle)) } public createW3cCredential(options: { @@ -534,19 +650,21 @@ export class NodeJSAnoncreds implements Anoncreds { const attributeRawValues = this.convertAttributeRawValues(options.attributeRawValues) const revocationConfiguration = this.convertRevocationConfiguration(options.revocationConfiguration) - const credentialPtr = allocatePointer() - this.nativeAnoncreds.anoncreds_create_w3c_credential( + const credentialPtr: [null] = [null] + const result = this.nativeAnoncreds.anoncreds_create_w3c_credential( credentialDefinition, credentialDefinitionPrivate, credentialOffer, credentialRequest, attributeNames, attributeRawValues, - revocationConfiguration?.ref().address() ?? 0, + revocationConfiguration ?? null, w3cVersion, credentialPtr ) - this.handleError() + if (result !== 0) { + this.handleError() + } return new ObjectHandle(handleReturnPointer(credentialPtr)) } @@ -560,19 +678,21 @@ export class NodeJSAnoncreds implements Anoncreds { }): ObjectHandle { const { credential, credentialRequestMetadata, linkSecret, credentialDefinition } = serializeArguments(options) - const ret = allocatePointer() + const credentialPtr: [null] = [null] - this.nativeAnoncreds.anoncreds_process_w3c_credential( + const result = this.nativeAnoncreds.anoncreds_process_w3c_credential( credential, credentialRequestMetadata, linkSecret, credentialDefinition, options.revocationRegistryDefinition?.handle ?? 0, - ret + credentialPtr ) - this.handleError() + if (result !== 0) { + this.handleError() + } - return new ObjectHandle(handleReturnPointer(ret)) + return new ObjectHandle(handleReturnPointer(credentialPtr)) } public createW3cPresentation(options: { @@ -591,9 +711,9 @@ export class NodeJSAnoncreds implements Anoncreds { const { schemaIds, schemas } = this.convertSchemas(options.schemas) const { credentialDefinitionIds, credentialDefinitions } = this.convertCredDefs(options.credentialDefinitions) - const ret = allocatePointer() + const presentationPtr: [null] = [null] - this.nativeAnoncreds.anoncreds_create_w3c_presentation( + const result = this.nativeAnoncreds.anoncreds_create_w3c_presentation( presentationRequest, credentialEntryList, credentialProveList, @@ -603,11 +723,13 @@ export class NodeJSAnoncreds implements Anoncreds { credentialDefinitions, credentialDefinitionIds, w3cVersion, - ret + presentationPtr ) - this.handleError() + if (result !== 0) { + this.handleError() + } - return new ObjectHandle(handleReturnPointer(ret)) + return new ObjectHandle(handleReturnPointer(presentationPtr)) } public verifyW3cPresentation(options: { @@ -622,80 +744,117 @@ export class NodeJSAnoncreds implements Anoncreds { revocationStatusLists?: ObjectHandle[] nonRevokedIntervalOverrides?: NativeNonRevokedIntervalOverride[] }): boolean { - const { - presentation, - presentationRequest, - schemas, - credentialDefinitions, - revocationRegistryDefinitions, - revocationStatusLists, - revocationRegistryDefinitionIds, - schemaIds, - credentialDefinitionIds, - } = serializeArguments(options) + const { presentation, presentationRequest } = serializeArguments({ + presentation: options.presentation, + presentationRequest: options.presentationRequest, + }) + + const schemasList = createObjectHandleListStruct({ + count: options.schemas.length, + data: options.schemas.map((s) => s.handle), + }) as unknown as Buffer + const schemaIdsList = createStringListStruct({ + count: options.schemaIds.length, + data: options.schemaIds, + }) + + const credDefsList = createObjectHandleListStruct({ + count: options.credentialDefinitions.length, + data: options.credentialDefinitions.map((c) => c.handle), + }) as unknown as Buffer + const credDefIdsList = createStringListStruct({ + count: options.credentialDefinitionIds.length, + data: options.credentialDefinitionIds, + }) + + const revRegDefsList = createObjectHandleListStruct({ + count: options.revocationRegistryDefinitions?.length ?? 0, + data: (options.revocationRegistryDefinitions ?? []).map((r) => r.handle), + }) as unknown as Buffer + const revRegDefIdsList = createStringListStruct({ + count: options.revocationRegistryDefinitionIds?.length ?? 0, + data: options.revocationRegistryDefinitionIds ?? [], + }) + const revStatusLists = createObjectHandleListStruct({ + count: options.revocationStatusLists?.length ?? 0, + data: (options.revocationStatusLists ?? []).map((r) => r.handle), + }) as unknown as Buffer const nonRevokedIntervalOverrideList = this.convertNonRevokedIntervalOverrides(options.nonRevokedIntervalOverrides) - const ret = allocateInt8Buffer() + const outInt8: [null] = [null] - this.nativeAnoncreds.anoncreds_verify_w3c_presentation( + const result = this.nativeAnoncreds.anoncreds_verify_w3c_presentation( presentation, presentationRequest, - schemas, - schemaIds, - credentialDefinitions, - credentialDefinitionIds, - revocationRegistryDefinitions, - revocationRegistryDefinitionIds, - revocationStatusLists, + schemasList, + schemaIdsList, + credDefsList, + credDefIdsList, + revRegDefsList, + revRegDefIdsList, + revStatusLists, nonRevokedIntervalOverrideList, - ret + outInt8 ) - this.handleError() + if (result !== 0) { + this.handleError() + } - return Boolean(handleReturnPointer(ret)) + return Boolean(handleReturnPointer(outInt8)) } public credentialToW3c(options: { objectHandle: ObjectHandle; issuerId: string; w3cVersion?: string }): ObjectHandle { const { objectHandle, issuerId, w3cVersion } = serializeArguments(options) - const ret = allocatePointer() + const credPtrBuf: [null] = [null] + const result = this.nativeAnoncreds.anoncreds_credential_to_w3c(objectHandle, issuerId, w3cVersion, credPtrBuf) - this.nativeAnoncreds.anoncreds_credential_to_w3c(objectHandle, issuerId, w3cVersion, ret) - this.handleError() + if (result !== 0) { + this.handleError() + } - return new ObjectHandle(handleReturnPointer(ret)) + return new ObjectHandle(handleReturnPointer(credPtrBuf)) } public credentialFromW3c(options: { objectHandle: ObjectHandle }): ObjectHandle { const { objectHandle } = serializeArguments(options) - const ret = allocatePointer() + const outObjectHandle: [null] = [null] - this.nativeAnoncreds.anoncreds_credential_from_w3c(objectHandle, ret) - this.handleError() + const result = this.nativeAnoncreds.anoncreds_credential_from_w3c(objectHandle, outObjectHandle) + if (result !== 0) { + this.handleError() + } - return new ObjectHandle(handleReturnPointer(ret)) + return new ObjectHandle(handleReturnPointer(outObjectHandle)) } public w3cCredentialGetIntegrityProofDetails(options: { objectHandle: ObjectHandle }) { const { objectHandle } = serializeArguments(options) - const ret = allocatePointer() - this.nativeAnoncreds.anoncreds_w3c_credential_get_integrity_proof_details(objectHandle, ret) - this.handleError() + const credProofInfoPtr: [null] = [null] + const result = this.nativeAnoncreds.anoncreds_w3c_credential_get_integrity_proof_details( + objectHandle, + credProofInfoPtr + ) + if (result !== 0) { + this.handleError() + } - return new ObjectHandle(handleReturnPointer(ret)) + return new ObjectHandle(handleReturnPointer(credProofInfoPtr)) } public w3cCredentialProofGetAttribute(options: { objectHandle: ObjectHandle; name: string }) { const { objectHandle, name } = serializeArguments(options) - const ret = allocateStringBuffer() - this.nativeAnoncreds.anoncreds_w3c_credential_proof_get_attribute(objectHandle, name, ret) - this.handleError() + const outStringPtr: [null] = [null] + const result = this.nativeAnoncreds.anoncreds_w3c_credential_proof_get_attribute(objectHandle, name, outStringPtr) + if (result !== 0) { + this.handleError() + } - return handleReturnPointer(ret) + return handleReturnPointer(outStringPtr) } public w3cCredentialFromJson(options: { json: string }): ObjectHandle { @@ -707,7 +866,13 @@ export class NodeJSAnoncreds implements Anoncreds { } public version(): string { - return this.nativeAnoncreds.anoncreds_version() + try { + const result = this.nativeAnoncreds.anoncreds_version() + return result as string + } catch (error) { + this.handleError() + return 'unknown' + } } public setDefaultLogger(): void { @@ -715,24 +880,26 @@ export class NodeJSAnoncreds implements Anoncreds { this.handleError() } - // This should be called when a function returns a non-zero code public getCurrentError(): string { - const ret = allocateStringBuffer() - this.nativeAnoncreds.anoncreds_get_current_error(ret) - this.handleError() + const outStringPtr: [null] = [null] + const result = this.nativeAnoncreds.anoncreds_get_current_error(outStringPtr) + if (result !== 0) { + this.handleError() + } - return handleReturnPointer(ret) + return handleReturnPointer(outStringPtr) } - private objectFromJson(method: (byteBuffer: Buffer, ret: Buffer) => unknown, options: { json: string }) { - const ret = allocatePointer() + private objectFromJson(method: (byteBuffer: Buffer, ret: [null]) => unknown, options: { json: string }) { + const outHandle: [null] = [null] const byteBuffer = ByteBuffer.fromUint8Array(new TextEncoder().encode(options.json)) - this.handleError() - - method(byteBuffer as unknown as Buffer, ret) + const result = method(byteBuffer as unknown as Buffer, outHandle) + if (result !== 0) { + this.handleError() + } - return new ObjectHandle(handleReturnPointer(ret)) + return new ObjectHandle(handleReturnPointer(outHandle)) } public presentationRequestFromJson(options: { json: string }) { @@ -795,32 +962,36 @@ export class NodeJSAnoncreds implements Anoncreds { return this.objectFromJson(this.nativeAnoncreds.anoncreds_key_correctness_proof_from_json, options) } - public getJson(options: { objectHandle: ObjectHandle }) { - const ret = allocateByteBuffer() - + public getJson(options: { objectHandle: ObjectHandle }): string { const { objectHandle } = serializeArguments(options) - this.nativeAnoncreds.anoncreds_object_get_json(objectHandle, ret) - this.handleError() - const returnValue = handleReturnPointer<{ data: Buffer; len: number }>(ret) - const jsonAsArray = new Uint8Array(byteBufferToBuffer(returnValue)) + const outByteBuffer: any = {} - const output = new TextDecoder().decode(jsonAsArray) + const result = this.nativeAnoncreds.anoncreds_object_get_json(objectHandle, outByteBuffer) + if (result !== 0) { + this.handleError() + } + + const output = koffi.decode(outByteBuffer.data, 'char', outByteBuffer.len) - this.nativeAnoncreds.anoncreds_buffer_free(returnValue.data) + this.nativeAnoncreds.anoncreds_buffer_free(outByteBuffer) return output } - public getTypeName(options: { objectHandle: ObjectHandle }) { + public getTypeName(options: { objectHandle: ObjectHandle }): string { const { objectHandle } = serializeArguments(options) - const ret = allocateStringBuffer() + const outStringPtr: [null] = [null] - this.nativeAnoncreds.anoncreds_object_get_type_name(objectHandle, ret) - this.handleError() + const result = this.nativeAnoncreds.anoncreds_object_get_type_name(objectHandle, outStringPtr) + + if (result !== 0) { + this.handleError() + throw new Error('Failed to get type name from object') + } - return handleReturnPointer(ret) + return handleReturnPointer(outStringPtr) } public objectFree(options: { objectHandle: ObjectHandle }) { @@ -830,55 +1001,42 @@ export class NodeJSAnoncreds implements Anoncreds { private convertCredentialList(credentials: NativeCredentialEntry[]) { const credentialEntries = credentials.map((value) => - CredentialEntryStruct({ + createCredentialEntryStruct({ credential: value.credential.handle, timestamp: value.timestamp ?? -1, rev_state: value.revocationState?.handle ?? 0, }) ) - return CredentialEntryListStruct({ + return createCredentialEntryListStruct({ count: credentialEntries.length, - data: credentialEntries as unknown as TypedArray< - StructObject<{ - credential: number - timestamp: number - rev_state: number - }> - >, + data: credentialEntries, }) as unknown as Buffer } private convertCredentialProves(credentialsProve: NativeCredentialProve[]) { const credentialProves = credentialsProve.map((value) => { const { entryIndex: entry_idx, isPredicate: is_predicate, reveal, referent } = serializeArguments(value) - return CredentialProveStruct({ entry_idx, referent, is_predicate, reveal }) + return createCredentialProveStruct({ entry_idx, referent, is_predicate, reveal }) }) - return CredentialProveListStruct({ + return createCredentialProveListStruct({ count: credentialProves.length, - data: credentialProves as unknown as TypedArray< - StructObject<{ - entry_idx: string | number - referent: string - is_predicate: number - reveal: number - }> - >, + data: credentialProves, }) as unknown as Buffer } private convertSchemas(schemas: Record) { const schemaKeys = Object.keys(schemas) - const schemaIds = StringListStruct({ + const schemaIds = createStringListStruct({ count: schemaKeys.length, - data: schemaKeys as unknown as TypedArray, - }) as unknown as Buffer + data: schemaKeys, + }) const schemaValues = Object.values(schemas) - const schemasList = ObjectHandleListStruct({ + const schemasList = createObjectHandleListStruct({ count: schemaValues.length, - data: ObjectHandleArray(schemaValues.map((o) => o.handle)), + data: schemaValues.map((o) => o.handle), }) as unknown as Buffer return { schemaIds, @@ -888,16 +1046,16 @@ export class NodeJSAnoncreds implements Anoncreds { private convertCredDefs(credentialDefinitions: Record) { const credentialDefinitionKeys = Object.keys(credentialDefinitions) - const credentialDefinitionIds = StringListStruct({ + const credentialDefinitionIds = createStringListStruct({ count: credentialDefinitionKeys.length, - data: credentialDefinitionKeys as unknown as TypedArray, - }) as unknown as Buffer + data: credentialDefinitionKeys, + }) const credentialDefinitionValues = Object.values(credentialDefinitions) - const credentialDefinitionsList = ObjectHandleListStruct({ + const credentialDefinitionsList = createObjectHandleListStruct({ count: credentialDefinitionValues.length, - data: ObjectHandleArray(credentialDefinitionValues.map((o) => o.handle)), - }) as unknown as Buffer + data: credentialDefinitionValues.map((o) => o.handle), + }) return { credentialDefinitionIds, credentialDefinitions: credentialDefinitionsList, @@ -905,49 +1063,55 @@ export class NodeJSAnoncreds implements Anoncreds { } private convertNonRevokedIntervalOverrides(nonRevokedIntervalOverrides?: NativeNonRevokedIntervalOverride[]) { - const nativeNonRevokedIntervalOverrides = nonRevokedIntervalOverrides?.map((value) => { + if (!nonRevokedIntervalOverrides) { + return createNonRevokedIntervalOverrideListStruct({ + count: 0, + data: [], + }) + } + + const nativeNonRevokedIntervalOverrides = nonRevokedIntervalOverrides.map((value) => { const { requestedFromTimestamp, revocationRegistryDefinitionId, overrideRevocationStatusListTimestamp } = serializeArguments(value) - return NonRevokedIntervalOverrideStruct({ + return createNonRevokedIntervalOverrideStruct({ rev_reg_def_id: revocationRegistryDefinitionId, requested_from_ts: requestedFromTimestamp, override_rev_status_list_ts: overrideRevocationStatusListTimestamp, }) }) - return NonRevokedIntervalOverrideListStruct({ + return createNonRevokedIntervalOverrideListStruct({ count: nonRevokedIntervalOverrides?.length ?? 0, - data: nativeNonRevokedIntervalOverrides as unknown as TypedArray< - StructObject<{ - rev_reg_def_id: string - requested_from_ts: number - override_rev_status_list_ts: number - }> - >, - }) as unknown as Buffer + data: nativeNonRevokedIntervalOverrides ?? [], + }) } private convertAttributeNames(attributeRawValues: Record) { - return StringListStruct({ + return createStringListStruct({ count: Object.keys(attributeRawValues).length, - data: Object.keys(attributeRawValues) as unknown as TypedArray, + data: Object.keys(attributeRawValues), }) as unknown as Buffer } private convertAttributeRawValues(attributeRawValues: Record) { - return StringListStruct({ + return createStringListStruct({ count: Object.keys(attributeRawValues).length, - data: Object.values(attributeRawValues) as unknown as TypedArray, + data: Object.values(attributeRawValues), }) as unknown as Buffer } private convertAttributeEncodedValues(attributeEncodedValues?: Record) { - return attributeEncodedValues - ? StringListStruct({ - count: Object.keys(attributeEncodedValues).length, - data: Object.values(attributeEncodedValues) as unknown as TypedArray, - }) - : undefined + if (!attributeEncodedValues) { + return createStringListStruct({ + count: 0, + data: [], + }) + } + + return createStringListStruct({ + count: Object.keys(attributeEncodedValues).length, + data: Object.values(attributeEncodedValues), + }) } private convertRevocationConfiguration(revocationConfiguration?: NativeCredentialRevocationConfig) { @@ -955,7 +1119,7 @@ export class NodeJSAnoncreds implements Anoncreds { const { revocationRegistryDefinition, revocationRegistryDefinitionPrivate, revocationStatusList, registryIndex } = serializeArguments(revocationConfiguration) - return CredRevInfoStruct({ + return createCredRevInfoStruct({ reg_def: revocationRegistryDefinition, reg_def_private: revocationRegistryDefinitionPrivate, status_list: revocationStatusList, diff --git a/packages/anoncreds-nodejs/src/ffi/alloc.ts b/packages/anoncreds-nodejs/src/ffi/alloc.ts index 04a7c7f..1d346bb 100644 --- a/packages/anoncreds-nodejs/src/ffi/alloc.ts +++ b/packages/anoncreds-nodejs/src/ffi/alloc.ts @@ -1,17 +1,7 @@ -import { alloc } from '@2060.io/ref-napi' +import koffi from 'koffi' +import { FFI_OBJECT_HANDLE } from './primitives' +import { ByteBufferStruct } from './structures' -import { FFI_INT8, FFI_OBJECT_HANDLE, FFI_STRING } from '../ffi/primitives' - -import { ByteBufferStruct, CredRevInfoStruct } from './structures' - -// TODO: more allocations here - -export const allocateStringBuffer = (): Buffer => alloc(FFI_STRING) - -export const allocatePointer = (): Buffer => alloc(FFI_OBJECT_HANDLE) - -export const allocateInt8Buffer = (): Buffer => alloc(FFI_INT8) - -export const allocateCredRevInfoStructPointer = (): Buffer => alloc(CredRevInfoStruct) - -export const allocateByteBuffer = (): Buffer => alloc(ByteBufferStruct) +export const allocatePointer = (): Buffer => { + return koffi.alloc(FFI_OBJECT_HANDLE, 1) +} diff --git a/packages/anoncreds-nodejs/src/ffi/conversion.ts b/packages/anoncreds-nodejs/src/ffi/conversion.ts index 57bcc7d..47dfc83 100644 --- a/packages/anoncreds-nodejs/src/ffi/conversion.ts +++ b/packages/anoncreds-nodejs/src/ffi/conversion.ts @@ -1,5 +1,10 @@ -import { reinterpret } from '@2060.io/ref-napi' +import koffi from 'koffi' -export const byteBufferToBuffer = (buffer: { data: Buffer; len: number }) => reinterpret(buffer.data, buffer.len) +// Conversion utilities for koffi +export const byteBufferToBuffer = (buffer: { data: Buffer; len: number }): Buffer => { + const dataAsArray = koffi.decode(buffer.data, 'uint8', buffer.len) + + return Buffer.from(dataAsArray) +} export const secretBufferToBuffer = byteBufferToBuffer diff --git a/packages/anoncreds-nodejs/src/ffi/helpers.ts b/packages/anoncreds-nodejs/src/ffi/helpers.ts new file mode 100644 index 0000000..e80bb02 --- /dev/null +++ b/packages/anoncreds-nodejs/src/ffi/helpers.ts @@ -0,0 +1,95 @@ +import koffi from 'koffi' + +// Helper functions to create struct instances for koffi +// Since koffi structs are not callable, we need to create plain objects + +export const createStringListStruct = (data: { count: number; data: string[] }) => { + return { + count: data.count, + data: data.data, + } as unknown as Buffer +} + +export const createObjectHandleListStruct = (data: { count: number; data: number[] }) => { + return { + count: data.count, + data: data.data, + } +} + +// I32List helper (issued / revoked lists) +export const createI32ListStruct = (data: { count: number; data: number[] }) => { + return { + count: data.count, + data: data.data, + } +} + +export const createCredentialEntryStruct = (data: { credential: number; timestamp: number; rev_state: number }) => { + return { + credential: data.credential, + timestamp: data.timestamp, + rev_state: data.rev_state, + } +} + +export const createCredentialEntryListStruct = (data: { count: number; data: any[] }) => { + return { + count: data.count, + data: data.data, + } +} + +export const createCredentialProveStruct = (data: { + entry_idx: number + referent: string + is_predicate: number + reveal: number +}) => { + return { + entry_idx: data.entry_idx, + referent: data.referent, + is_predicate: data.is_predicate, + reveal: data.reveal, + } +} + +export const createCredentialProveListStruct = (data: { count: number; data: any[] }) => { + return { + count: data.count, + data: data.data, + } +} + +export const createNonRevokedIntervalOverrideStruct = (data: { + rev_reg_def_id: string + requested_from_ts: number + override_rev_status_list_ts: number +}) => { + return { + rev_reg_def_id: data.rev_reg_def_id, + requested_from_ts: data.requested_from_ts, + override_rev_status_list_ts: data.override_rev_status_list_ts, + } +} + +export const createNonRevokedIntervalOverrideListStruct = (data: { count: number; data: any[] }) => { + return { + count: data.count, + data: data.data, + } +} + +export const createCredRevInfoStruct = (data: { + reg_def: number + reg_def_private: number + status_list: number + reg_idx: number +}) => { + return { + reg_def: data.reg_def, + reg_def_private: data.reg_def_private, + status_list: data.status_list, + reg_idx: data.reg_idx, + } +} diff --git a/packages/anoncreds-nodejs/src/ffi/index.ts b/packages/anoncreds-nodejs/src/ffi/index.ts index 9852fd8..7cf7579 100644 --- a/packages/anoncreds-nodejs/src/ffi/index.ts +++ b/packages/anoncreds-nodejs/src/ffi/index.ts @@ -3,3 +3,4 @@ export * from './conversion' export * from './structures' export * from './primitives' export * from './serialize' +export * from './helpers' diff --git a/packages/anoncreds-nodejs/src/ffi/primitives.ts b/packages/anoncreds-nodejs/src/ffi/primitives.ts index 5f6fea6..7f8cdbd 100644 --- a/packages/anoncreds-nodejs/src/ffi/primitives.ts +++ b/packages/anoncreds-nodejs/src/ffi/primitives.ts @@ -1,21 +1,21 @@ -import { refType, types } from '@2060.io/ref-napi' +import koffi from 'koffi' -// Primitives +// Primitives (Koffi type names) -export const FFI_ISIZE = 'size_t' -export const FFI_INT8 = 'int8' -export const FFI_INT32 = 'int32' -export const FFI_INT64 = 'int64' -export const FFI_UINT = 'uint' -export const FFI_UINT8 = 'uint8' +export const FFI_ISIZE = koffi.types.size_t +export const FFI_INT8 = koffi.types.int8 +export const FFI_INT32 = koffi.types.int32 +export const FFI_INT64 = koffi.types.int64 +export const FFI_UINT = koffi.types.uint +export const FFI_UINT8 = koffi.types.uint8 export const FFI_ERRORCODE = FFI_UINT export const FFI_OBJECT_HANDLE = FFI_ISIZE -export const FFI_VOID = types.void -export const FFI_STRING = 'string' +export const FFI_VOID = koffi.types.void +export const FFI_STRING = koffi.types.string -// Pointers +// Pointers (using Koffi pointer types) -export const FFI_ISIZE_PTR = refType(FFI_ISIZE) -export const FFI_INT8_PTR = refType(FFI_INT8) -export const FFI_OBJECT_HANDLE_PTR = refType(FFI_OBJECT_HANDLE) -export const FFI_STRING_PTR = refType(FFI_STRING) +export const FFI_ISIZE_PTR = koffi.pointer(FFI_ISIZE) +export const FFI_INT8_PTR = koffi.pointer(FFI_INT8) +export const FFI_OBJECT_HANDLE_PTR = koffi.pointer(FFI_OBJECT_HANDLE) +export const FFI_STRING_PTR = koffi.pointer(FFI_STRING) diff --git a/packages/anoncreds-nodejs/src/ffi/serialize.ts b/packages/anoncreds-nodejs/src/ffi/serialize.ts index 2e7b0c3..f092c8e 100644 --- a/packages/anoncreds-nodejs/src/ffi/serialize.ts +++ b/packages/anoncreds-nodejs/src/ffi/serialize.ts @@ -1,22 +1,9 @@ -import type { Pointer } from '@2060.io/ref-napi' -import type { TypedArray } from 'ref-array-di' -import type { StructObject } from 'ref-struct-di' -import type { ByteBufferStruct } from './structures' - -import { NULL } from '@2060.io/ref-napi' import { ObjectHandle } from '@hyperledger/anoncreds-shared' - -import { I32ListStruct, Int32List, ObjectHandleListStruct, StringListStruct } from './structures' +import { I32ListStruct, ObjectHandleListStruct, StringListStruct } from './structures' type Argument = Record | unknown[] | Date | Uint8Array | SerializedArgument | boolean | ObjectHandle -type SerializedArgument = - | string - | number - | ArrayBuffer - | Buffer - | StructObject<{ count: number | string; data: TypedArray }> - | StructObject<{ count: number | string; data: Pointer> }> +type SerializedArgument = string | number | ArrayBuffer | Buffer | object | null type SerializedArguments = Record @@ -32,13 +19,13 @@ export type SerializedOptions = Required<{ : Type[Property] extends Record ? string : Type[Property] extends string[] - ? Buffer + ? object : Type[Property] extends string[] | undefined - ? Buffer + ? object : Type[Property] extends number[] - ? Buffer + ? object : Type[Property] extends number[] | undefined - ? Buffer + ? object : Type[Property] extends Date ? number : Type[Property] extends Date | undefined @@ -52,15 +39,15 @@ export type SerializedOptions = Required<{ : Type[Property] extends ObjectHandle ? number : Type[Property] extends ObjectHandle[] - ? Buffer + ? object : Type[Property] extends ObjectHandle[] | undefined - ? Buffer + ? object : Type[Property] extends ObjectHandle | undefined ? number : Type[Property] extends Uint8Array - ? typeof ByteBufferStruct + ? object : Type[Property] extends Uint8Array | undefined - ? typeof ByteBufferStruct + ? object : Type[Property] extends unknown[] | undefined ? string : Type[Property] extends Record | undefined @@ -68,13 +55,11 @@ export type SerializedOptions = Required<{ : unknown }> -// TODO: this method needs to be reworked. -// It is very messy -// cannot handle complex data structures well +// Serialize arguments for koffi const serialize = (arg: Argument): SerializedArgument => { switch (typeof arg) { case 'undefined': - return NULL + return null case 'boolean': return Number(arg) case 'string': @@ -84,27 +69,43 @@ const serialize = (arg: Argument): SerializedArgument => { case 'function': return arg case 'object': + if (arg === null) { + return null + } if (arg instanceof ObjectHandle) { return arg.handle } if (Array.isArray(arg)) { if (arg.every((it) => typeof it === 'string')) { - return StringListStruct({ count: arg.length, data: arg as unknown as TypedArray }) + // For koffi, create a simple object structure + return { + count: arg.length, + data: arg, + } } if (arg.every((it) => it instanceof ObjectHandle)) { - return ObjectHandleListStruct({ + return { count: arg.length, - data: (arg as ObjectHandle[]).map((i: ObjectHandle) => i.handle) as unknown as TypedArray, - }) + data: (arg as ObjectHandle[]).map((i: ObjectHandle) => i.handle), + } } if (arg.every((it) => typeof it === 'number')) { - return I32ListStruct({ + return { count: arg.length, - data: Int32List(arg as number[]) as unknown as TypedArray, - }) + data: arg, + } + } + } + if (arg instanceof Date) { + return arg.getTime() + } + if (arg instanceof Uint8Array) { + return { + len: arg.length, + data: Buffer.from(arg), } } - // TODO: add more serialization here for classes and uint8arrays + // For objects, JSON stringify return JSON.stringify(arg) default: throw new Error('could not serialize value') diff --git a/packages/anoncreds-nodejs/src/ffi/structures.ts b/packages/anoncreds-nodejs/src/ffi/structures.ts index 3db0933..3d5d57f 100644 --- a/packages/anoncreds-nodejs/src/ffi/structures.ts +++ b/packages/anoncreds-nodejs/src/ffi/structures.ts @@ -1,113 +1,105 @@ -import * as ref from '@2060.io/ref-napi' -import RefArray from 'ref-array-di' -import RefStruct from 'ref-struct-di' +import koffi from 'koffi' -import { FFI_INT8, FFI_INT32, FFI_INT64, FFI_ISIZE, FFI_OBJECT_HANDLE, FFI_STRING } from './primitives' +import { FFI_INT8, FFI_INT32, FFI_INT64, FFI_ISIZE, FFI_OBJECT_HANDLE, FFI_STRING, FFI_STRING_PTR } from './primitives' -const CStruct = RefStruct(ref) -const CArray = RefArray(ref) - -export const StringArray = CArray('string') - -const FFI_INT32_ARRAY = CArray('int32') - -const FFI_INT64_ARRAY = CArray('int64') - -export const ByteBufferArray = CArray('uint8') -export const ByteBufferArrayPtr = ref.refType(FFI_STRING) - -export const Int64List = FFI_INT64_ARRAY -export const Int32List = FFI_INT32_ARRAY - -export const StringArrayPtr = ref.refType(StringArray) - -export const ByteBufferStruct = CStruct({ +// ByteBuffer struct +export const ByteBufferStruct = koffi.struct('ByteBuffer', { len: FFI_INT64, - data: ByteBufferArrayPtr, + data: koffi.pointer('uint8'), }) -export const ByteBufferStructPtr = ref.refType(ByteBufferStruct) +export const ByteBufferStructPtr = koffi.pointer(ByteBufferStruct) -export const StringListStruct = CStruct({ - count: ref.types.size_t, - data: StringArray, +// StringList struct +export const StringListStruct = koffi.struct('StringList', { + count: FFI_ISIZE, + data: FFI_STRING_PTR, }) -export const StringListStructPtr = ref.refType(StringListStruct) +export const StringListStructPtr = koffi.pointer(StringListStruct) -export const I64ListStruct = CStruct({ +// I64List struct +export const I64ListStruct = koffi.struct('I64List', { count: FFI_ISIZE, - data: FFI_INT64_ARRAY, + data: koffi.pointer(FFI_INT64), }) -export const I32ListStruct = CStruct({ +// I32List struct +export const I32ListStruct = koffi.struct('I32List', { count: FFI_ISIZE, - data: FFI_INT32_ARRAY, + data: koffi.pointer(FFI_INT32), }) -export const CredRevInfoStruct = CStruct({ +// CredRevInfo struct +export const CredRevInfoStruct = koffi.struct('CredRevInfo', { reg_def: FFI_OBJECT_HANDLE, reg_def_private: FFI_OBJECT_HANDLE, status_list: FFI_OBJECT_HANDLE, reg_idx: FFI_INT64, }) -export const CredentialEntryStruct = CStruct({ +// CredentialEntry struct +export const CredentialEntryStruct = koffi.struct('CredentialEntry', { credential: FFI_ISIZE, timestamp: FFI_INT64, rev_state: FFI_ISIZE, }) -export const CredentialEntryArray = CArray(CredentialEntryStruct) - -export const CredentialEntryListStruct = CStruct({ +export const CredentialEntryListStruct = koffi.struct('CredentialEntryList', { count: FFI_ISIZE, - data: CredentialEntryArray, + data: koffi.pointer(CredentialEntryStruct), }) -export const CredentialProveStruct = CStruct({ +// CredentialProve struct +export const CredentialProveStruct = koffi.struct('CredentialProve', { entry_idx: FFI_INT64, referent: FFI_STRING, is_predicate: FFI_INT8, reveal: FFI_INT8, }) -export const CredentialProveArray = CArray(CredentialProveStruct) - -export const CredentialProveListStruct = CStruct({ +export const CredentialProveListStruct = koffi.struct('CredentialProveList', { count: FFI_ISIZE, - data: CredentialProveArray, + data: koffi.pointer(CredentialProveStruct), }) -export const ObjectHandleArray = CArray('size_t') - -export const ObjectHandleListStruct = CStruct({ +// ObjectHandle list +export const ObjectHandleListStruct = koffi.struct('ObjectHandleList', { count: FFI_ISIZE, - data: ObjectHandleArray, + data: koffi.pointer(FFI_ISIZE), }) -export const RevocationEntryStruct = CStruct({ +// RevocationEntry struct +export const RevocationEntryStruct = koffi.struct('RevocationEntry', { def_entry_idx: FFI_INT64, entry: FFI_ISIZE, timestamp: FFI_INT64, }) -export const RevocationEntryArray = CArray(RevocationEntryStruct) - -export const RevocationEntryListStruct = CStruct({ +export const RevocationEntryListStruct = koffi.struct('RevocationEntryList', { count: FFI_ISIZE, - data: RevocationEntryArray, + data: koffi.pointer(RevocationEntryStruct), }) -export const NonRevokedIntervalOverrideStruct = CStruct({ +// NonRevokedIntervalOverride struct +export const NonRevokedIntervalOverrideStruct = koffi.struct('NonRevokedIntervalOverride', { rev_reg_def_id: FFI_STRING, requested_from_ts: FFI_INT32, override_rev_status_list_ts: FFI_INT32, }) -export const NonRevokedIntervalOverrideArray = CArray(NonRevokedIntervalOverrideStruct) - -export const NonRevokedIntervalOverrideListStruct = CStruct({ +export const NonRevokedIntervalOverrideListStruct = koffi.struct('NonRevokedIntervalOverrideList', { count: FFI_ISIZE, - data: NonRevokedIntervalOverrideArray, + data: koffi.pointer(NonRevokedIntervalOverrideStruct), }) + +// For compatibility - we'll keep these exports +export const StringArray = koffi.pointer(FFI_STRING) +// biome-ignore lint/suspicious/noShadowRestrictedNames: FFI struct helpers need flexible any types for dynamic data +export const Int32Array = koffi.pointer(FFI_INT32) +export const Int64Array = koffi.pointer(FFI_INT64) +export const UInt8Array = koffi.pointer('uint8') +export const ObjectHandleArray = koffi.pointer(FFI_ISIZE) + +export const Int64List = Int64Array +export const Int32List = Int32Array diff --git a/packages/anoncreds-nodejs/src/library/NativeBindingInterface.ts b/packages/anoncreds-nodejs/src/library/NativeBindingInterface.ts index bb0a9fa..74caef3 100644 --- a/packages/anoncreds-nodejs/src/library/NativeBindingInterface.ts +++ b/packages/anoncreds-nodejs/src/library/NativeBindingInterface.ts @@ -1,34 +1,238 @@ +import type { IKoffiCType } from 'koffi' import type { nativeBindings } from './bindings' -// We need a mapping from string type value => type (property 'string' maps to type string) -interface StringTypeMapping { - pointer: Buffer - 'char*': Buffer - string: string - int64: number - int32: number - int8: number - int: number - size_t: number -} +export type NativeMethods = { + // Buffer management + anoncreds_buffer_free(buffer: Buffer): void -// Needed so TS stops complaining about index signatures -type ShapeOf = { - [Property in keyof T]: T[Property] -} -type StringTypeArrayToTypes = { - [Item in keyof List]: List[Item] extends keyof StringTypeMapping ? StringTypeMapping[List[Item]] : Buffer -} + // String management + anoncreds_string_free(str: IKoffiCType): void -// biome-ignore lint/suspicious/noExplicitAny: -type TypedMethods> = { - [Property in keyof Base]: ( - // biome-ignore lint/suspicious/noExplicitAny: - ...args: StringTypeArrayToTypes extends any[] ? StringTypeArrayToTypes : [] - ) => StringTypeMapping[Base[Property][0]] -} -type Mutable = { - -readonly [K in keyof T]: Mutable -} + // Object management + anoncreds_object_free(handle: number): void + anoncreds_object_get_json(handle: number, out: object): number + anoncreds_object_get_type_name(handle: number, out: [null]): number + + // Error functions + anoncreds_get_current_error(out: [null]): number + anoncreds_set_default_logger(): number + + // Version + anoncreds_version(): string + + // Utility functions + anoncreds_generate_nonce(out: [null]): number + anoncreds_encode_credential_attributes(attr_names: object, out: [null]): number + + // Schema functions + anoncreds_create_schema(name: string, version: string, issuer_id: string, attr_names: object, out: [null]): number + anoncreds_schema_from_json(buffer: Buffer, out: [null]): number + + // Credential definition functions + anoncreds_create_credential_definition( + schema_id: string, + schema: number, + tag: string, + issuer_id: string, + signature_type: string, + support_revocation: number, + cred_def_out: [null], + cred_def_priv_out: [null], + key_correctness_proof_out: [null] + ): number + anoncreds_credential_definition_from_json(buffer: Buffer, out: [null]): number + anoncreds_credential_definition_private_from_json(buffer: Buffer, out: [null]): number + anoncreds_key_correctness_proof_from_json(buffer: Buffer, out: [null]): number + + // Link secret + anoncreds_create_link_secret(out: [null]): number -export type NativeMethods = TypedMethods>> + // Credential offer functions + anoncreds_create_credential_offer( + schema_id: string, + cred_def_id: string, + key_correctness_proof: number, + out: [null] + ): number + anoncreds_credential_offer_from_json(buffer: Buffer, out: [null]): number + + // Credential request functions + anoncreds_create_credential_request( + entropy: string, + prover_did: string, + cred_def: number, + link_secret: string, + link_secret_id: string, + cred_offer: number, + cred_req_out: [null], + cred_req_metadata_out: [null] + ): number + anoncreds_credential_request_from_json(buffer: Buffer, out: [null]): number + anoncreds_credential_request_metadata_from_json(buffer: Buffer, out: [null]): number + + // Credential functions + anoncreds_create_credential( + cred_def: number, + cred_def_private: number, + cred_offer: number, + cred_request: number, + attr_names: object, + attr_raw_values: object, + attr_enc_values: object, + revocation: any, + out: [null] + ): number + anoncreds_process_credential( + cred: number, + cred_req_metadata: number, + link_secret: string, + cred_def: number, + rev_reg_def: number, + out: [null] + ): number + anoncreds_credential_get_attribute(handle: number, name: string, out: [null]): number + anoncreds_credential_from_json(buffer: Buffer, out: [null]): number + + // Revocation registry definition functions + anoncreds_create_revocation_registry_def( + cred_def: number, + cred_def_id: string, + issuer_id: string, + tag: string, + rev_reg_type: string, + max_cred_num: number, + tails_dir_path: string, + rev_reg_def_out: Buffer, + rev_reg_def_private_out: Buffer + ): number + anoncreds_revocation_registry_definition_get_attribute(handle: number, name: string, out: [null]): number + anoncreds_revocation_registry_definition_from_json(buffer: Buffer, out: [null]): number + anoncreds_revocation_registry_definition_private_from_json(buffer: Buffer, out: [null]): number + + // Revocation registry functions + anoncreds_revocation_registry_from_json(buffer: Buffer, out: [null]): number + + // Revocation status list functions + anoncreds_create_revocation_status_list( + rev_reg_def: number, + rev_reg_def_id: string, + rev_reg: number, + rev_reg_def_private: number, + issuance_by_default: string, + issuance_by_default_bool: number, + timestamp: number, + out: [null] + ): number + anoncreds_update_revocation_status_list( + cred_def: number, + rev_reg_def: number, + rev_reg_private: number, + rev_current_list: number, + issued: object, + revoked: object, + timestamp: number, + out: [null] + ): number + anoncreds_update_revocation_status_list_timestamp_only( + timestamp: number, + rev_status_list: number, + out: [null] + ): number + anoncreds_revocation_status_list_from_json(buffer: Buffer, out: [null]): number + + // Revocation state functions + anoncreds_create_or_update_revocation_state( + rev_reg_def: number, + rev_status_list: number, + rev_reg_idx: number, + tails_path: string, + old_rev_state: number, + old_rev_status_list: number, + out: [null] + ): number + anoncreds_revocation_state_from_json(buffer: Buffer, out: [null]): number + + // Presentation request functions + anoncreds_presentation_request_from_json(buffer: Buffer, out: [null]): number + + // Presentation functions + anoncreds_create_presentation( + pres_req: number, + credentials: object, + credentials_prove: object, + self_attested_names: object, + self_attested_values: object, + link_secret: string, + schemas: object, + schema_ids: object, + cred_defs: object, + cred_def_ids: object, + out: [null] + ): number + anoncreds_verify_presentation( + presentation: number, + pres_req: number, + schemas: object, + schema_ids: object, + cred_defs: object, + cred_def_ids: object, + rev_reg_defs: object, + rev_reg_def_ids: object, + rev_status_list: object, + nonrevoked_interval_override: object, + out: [null] + ): number + anoncreds_presentation_from_json(buffer: Buffer, out: [null]): number + + // W3C Credential functions (if supported) + anoncreds_create_w3c_credential( + cred_def: number, + cred_def_private: number, + cred_offer: number, + cred_req: number, + attr_names: object, + attr_values: object, + revocation: any, + w3c_version: string, + out: [null] + ): number + anoncreds_process_w3c_credential( + w3c_credential: number, + cred_req_metadata: number, + link_secret: string, + cred_def: number, + rev_reg_def: number, + out: [null] + ): number + anoncreds_create_w3c_presentation( + pres_req: number, + credentials: object, + credentials_prove: object, + link_secret: string, + schemas: object, + schema_ids: object, + cred_defs: object, + cred_def_ids: object, + w3c_version: string, + out: [null] + ): number + anoncreds_verify_w3c_presentation( + presentation: number, + pres_req: number, + schemas: object, + schema_ids: object, + cred_defs: object, + cred_def_ids: object, + rev_reg_defs: object, + rev_reg_def_ids: object, + rev_status_lists: object, + nonrevoked_interval_override: object, + out: [null] + ): number + anoncreds_credential_to_w3c(credential: number, issuer_id: string, w3c_version: string, out: [null]): number + anoncreds_credential_from_w3c(w3c_credential: number, out: [null]): number + anoncreds_w3c_credential_get_integrity_proof_details(w3c_credential: number, out: [null]): number + anoncreds_w3c_credential_proof_get_attribute(w3c_credential: number, name: string, out: [null]): number + anoncreds_w3c_credential_from_json(buffer: Buffer, out: [null]): number + anoncreds_w3c_presentation_from_json(buffer: Buffer, out: [null]): number +} diff --git a/packages/anoncreds-nodejs/src/library/bindings.ts b/packages/anoncreds-nodejs/src/library/bindings.ts index 5105d3b..be1a8ce 100644 --- a/packages/anoncreds-nodejs/src/library/bindings.ts +++ b/packages/anoncreds-nodejs/src/library/bindings.ts @@ -1,250 +1,128 @@ -import { - ByteBufferStruct, - ByteBufferStructPtr, - CredentialEntryListStruct, - CredentialProveListStruct, - FFI_ERRORCODE, - FFI_INT8, - FFI_INT8_PTR, - FFI_INT64, - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE_PTR, - FFI_STRING, - FFI_STRING_PTR, - FFI_VOID, - I32ListStruct, - NonRevokedIntervalOverrideListStruct, - ObjectHandleListStruct, - StringListStruct, -} from '../ffi' - +// Koffi function signatures using C-like prototypes +// Based on anoncreds-rs FFI functions export const nativeBindings = { - // first element is method return type, second element is list of method argument types - anoncreds_buffer_free: [FFI_VOID, [ByteBufferStruct]], - anoncreds_create_credential: [ - FFI_ERRORCODE, - [ - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - StringListStruct, - StringListStruct, - StringListStruct, - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE_PTR, - ], - ], - anoncreds_create_credential_definition: [ - FFI_ERRORCODE, - [ - FFI_STRING, - FFI_OBJECT_HANDLE, - FFI_STRING, - FFI_STRING, - FFI_STRING, - FFI_INT8, - FFI_OBJECT_HANDLE_PTR, - FFI_OBJECT_HANDLE_PTR, - FFI_OBJECT_HANDLE_PTR, - ], - ], - anoncreds_create_credential_offer: [ - FFI_ERRORCODE, - [FFI_STRING, FFI_STRING, FFI_OBJECT_HANDLE, FFI_OBJECT_HANDLE_PTR], - ], - anoncreds_create_credential_request: [ - FFI_ERRORCODE, - [ - FFI_STRING, - FFI_STRING, - FFI_OBJECT_HANDLE, - FFI_STRING, - FFI_STRING, - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE_PTR, - FFI_OBJECT_HANDLE_PTR, - ], - ], - anoncreds_create_link_secret: [FFI_ERRORCODE, [FFI_OBJECT_HANDLE_PTR]], - anoncreds_create_or_update_revocation_state: [ - FFI_ERRORCODE, - [ - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - FFI_INT64, - FFI_STRING, - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE_PTR, - ], - ], - anoncreds_create_presentation: [ - FFI_ERRORCODE, - [ - FFI_OBJECT_HANDLE, - CredentialEntryListStruct, - CredentialProveListStruct, - StringListStruct, - StringListStruct, - FFI_STRING, - ObjectHandleListStruct, - StringListStruct, - ObjectHandleListStruct, - StringListStruct, - FFI_OBJECT_HANDLE_PTR, - ], - ], - anoncreds_create_revocation_registry_def: [ - FFI_ERRORCODE, - [ - FFI_OBJECT_HANDLE, - FFI_STRING, - FFI_STRING, - FFI_STRING, - FFI_STRING, - FFI_INT64, - FFI_STRING, - FFI_OBJECT_HANDLE_PTR, - FFI_OBJECT_HANDLE_PTR, - ], - ], - anoncreds_create_schema: [ - FFI_ERRORCODE, - [FFI_STRING, FFI_STRING, FFI_STRING, StringListStruct, FFI_OBJECT_HANDLE_PTR], - ], - anoncreds_credential_get_attribute: [FFI_ERRORCODE, [FFI_OBJECT_HANDLE, FFI_STRING, FFI_STRING_PTR]], - anoncreds_encode_credential_attributes: [FFI_ERRORCODE, [StringListStruct, FFI_STRING_PTR]], - anoncreds_generate_nonce: [FFI_ERRORCODE, [FFI_STRING_PTR]], - anoncreds_get_current_error: [FFI_ERRORCODE, [FFI_STRING_PTR]], - anoncreds_object_free: [FFI_VOID, [FFI_OBJECT_HANDLE]], - anoncreds_string_free: [FFI_VOID, [FFI_STRING_PTR]], - anoncreds_object_get_json: [FFI_ERRORCODE, [FFI_OBJECT_HANDLE, ByteBufferStructPtr]], - anoncreds_object_get_type_name: [FFI_ERRORCODE, [FFI_OBJECT_HANDLE, FFI_STRING_PTR]], - anoncreds_presentation_request_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_process_credential: [ - FFI_ERRORCODE, - [FFI_OBJECT_HANDLE, FFI_OBJECT_HANDLE, FFI_STRING, FFI_OBJECT_HANDLE, FFI_OBJECT_HANDLE, FFI_OBJECT_HANDLE_PTR], - ], - anoncreds_revocation_registry_definition_get_attribute: [ - FFI_ERRORCODE, - [FFI_OBJECT_HANDLE, FFI_STRING, FFI_STRING_PTR], - ], - anoncreds_set_default_logger: [FFI_ERRORCODE, []], - anoncreds_verify_presentation: [ - FFI_ERRORCODE, - [ - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - ObjectHandleListStruct, - StringListStruct, - ObjectHandleListStruct, - StringListStruct, - ObjectHandleListStruct, - StringListStruct, - ObjectHandleListStruct, - NonRevokedIntervalOverrideListStruct, - FFI_INT8_PTR, - ], - ], - anoncreds_create_revocation_status_list: [ - FFI_ERRORCODE, - [ - FFI_OBJECT_HANDLE, - FFI_STRING, - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - FFI_STRING, - FFI_INT8, - FFI_INT64, - FFI_OBJECT_HANDLE_PTR, - ], - ], - anoncreds_update_revocation_status_list_timestamp_only: [ - FFI_ERRORCODE, - [FFI_INT64, FFI_OBJECT_HANDLE, FFI_OBJECT_HANDLE_PTR], - ], - anoncreds_update_revocation_status_list: [ - FFI_ERRORCODE, - [ - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - I32ListStruct, - I32ListStruct, - FFI_INT64, - FFI_OBJECT_HANDLE_PTR, - ], - ], - anoncreds_version: [FFI_STRING, []], - anoncreds_credential_request_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_credential_request_metadata_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_presentation_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_credential_offer_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_revocation_registry_definition_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_revocation_registry_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_revocation_status_list_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_revocation_state_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_credential_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_credential_definition_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_credential_definition_private_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_revocation_registry_definition_private_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_key_correctness_proof_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_schema_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_create_w3c_credential: [ - FFI_ERRORCODE, - [ - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - StringListStruct, - StringListStruct, - FFI_OBJECT_HANDLE, - FFI_STRING, - FFI_OBJECT_HANDLE_PTR, - ], - ], - anoncreds_process_w3c_credential: [ - FFI_ERRORCODE, - [FFI_OBJECT_HANDLE, FFI_OBJECT_HANDLE, FFI_STRING, FFI_OBJECT_HANDLE, FFI_OBJECT_HANDLE, FFI_OBJECT_HANDLE_PTR], - ], - anoncreds_create_w3c_presentation: [ - FFI_ERRORCODE, - [ - FFI_OBJECT_HANDLE, - CredentialEntryListStruct, - CredentialProveListStruct, - FFI_STRING, - ObjectHandleListStruct, - StringListStruct, - ObjectHandleListStruct, - StringListStruct, - FFI_STRING, - FFI_OBJECT_HANDLE_PTR, - ], - ], - anoncreds_verify_w3c_presentation: [ - FFI_ERRORCODE, - [ - FFI_OBJECT_HANDLE, - FFI_OBJECT_HANDLE, - ObjectHandleListStruct, - StringListStruct, - ObjectHandleListStruct, - StringListStruct, - ObjectHandleListStruct, - StringListStruct, - ObjectHandleListStruct, - NonRevokedIntervalOverrideListStruct, - FFI_INT8_PTR, - ], - ], - anoncreds_credential_to_w3c: [FFI_ERRORCODE, [FFI_OBJECT_HANDLE, FFI_STRING, FFI_STRING, FFI_OBJECT_HANDLE_PTR]], - anoncreds_credential_from_w3c: [FFI_ERRORCODE, [FFI_OBJECT_HANDLE, FFI_OBJECT_HANDLE_PTR]], - anoncreds_w3c_credential_get_integrity_proof_details: [FFI_ERRORCODE, [FFI_OBJECT_HANDLE, FFI_OBJECT_HANDLE_PTR]], - anoncreds_w3c_credential_proof_get_attribute: [FFI_ERRORCODE, [FFI_OBJECT_HANDLE, FFI_STRING, FFI_STRING_PTR]], - anoncreds_w3c_presentation_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], - anoncreds_w3c_credential_from_json: [FFI_ERRORCODE, [ByteBufferStruct, FFI_STRING_PTR]], -} as const + // Buffer management + anoncreds_buffer_free: 'void anoncreds_buffer_free(ByteBuffer buffer)', + + // String management + anoncreds_string_free: 'void anoncreds_string_free(const char *str)', + + // Object management + anoncreds_object_free: 'void anoncreds_object_free(size_t handle)', + anoncreds_object_get_json: 'uint anoncreds_object_get_json(size_t handle, _Out_ ByteBuffer *out)', + anoncreds_object_get_type_name: 'uint anoncreds_object_get_type_name(size_t handle, _Out_ const char **out)', + + // Error handling + anoncreds_get_current_error: 'uint anoncreds_get_current_error(_Out_ const char **error_json_p)', + anoncreds_set_default_logger: 'uint anoncreds_set_default_logger()', + + // Version + anoncreds_version: 'const char *anoncreds_version()', + + // Utility functions + anoncreds_generate_nonce: 'uint anoncreds_generate_nonce(_Out_ const char **out)', + anoncreds_encode_credential_attributes: + 'uint anoncreds_encode_credential_attributes(StringList attr_names, _Out_ const char **out)', + + // Schema functions + anoncreds_create_schema: + 'uint anoncreds_create_schema(const char *name, const char *version, const char *issuer_id, StringList attr_names, _Out_ size_t *out)', + anoncreds_schema_from_json: 'uint anoncreds_schema_from_json(ByteBuffer buffer, _Out_ size_t *out)', + + // Credential definition functions + anoncreds_create_credential_definition: + 'uint anoncreds_create_credential_definition(const char *schema_id, size_t schema, const char *tag, const char *issuer_id, const char *signature_type, int8 support_revocation, _Out_ size_t *cred_def_out, _Out_ size_t *cred_def_priv_out, _Out_ size_t *key_correctness_proof_out)', + anoncreds_credential_definition_from_json: + 'uint anoncreds_credential_definition_from_json(ByteBuffer buffer, _Out_ size_t *out)', + anoncreds_credential_definition_private_from_json: + 'uint anoncreds_credential_definition_private_from_json(ByteBuffer buffer, _Out_ size_t *out)', + anoncreds_key_correctness_proof_from_json: + 'uint anoncreds_key_correctness_proof_from_json(ByteBuffer buffer, _Out_ size_t *out)', + + // Link secret + anoncreds_create_link_secret: 'uint anoncreds_create_link_secret(_Out_ const char **out)', + + // Credential offer functions + anoncreds_create_credential_offer: + 'uint anoncreds_create_credential_offer(const char *schema_id, const char *cred_def_id, size_t key_correctness_proof, _Out_ size_t *out)', + anoncreds_credential_offer_from_json: + 'uint anoncreds_credential_offer_from_json(ByteBuffer buffer, _Out_ size_t *out)', + + // Credential request functions + anoncreds_create_credential_request: + 'uint anoncreds_create_credential_request(const char *entropy, const char *prover_did, size_t cred_def, const char *link_secret, const char *link_secret_id, size_t cred_offer, _Out_ size_t *cred_req_out, _Out_ size_t *cred_req_metadata_out)', + anoncreds_credential_request_from_json: + 'uint anoncreds_credential_request_from_json(ByteBuffer buffer, _Out_ size_t *out)', + anoncreds_credential_request_metadata_from_json: + 'uint anoncreds_credential_request_metadata_from_json(ByteBuffer buffer, _Out_ size_t *out)', + + // Credential functions + anoncreds_create_credential: + 'uint anoncreds_create_credential(size_t cred_def, size_t cred_def_private, size_t cred_offer, size_t cred_request, StringList attr_names, StringList attr_raw_values, StringList attr_enc_values, const CredRevInfo *revocation, _Out_ size_t *out)', + anoncreds_process_credential: + 'uint anoncreds_process_credential(size_t cred, size_t cred_req_metadata, const char *link_secret, size_t cred_def, size_t rev_reg_def, _Out_ size_t *out)', + anoncreds_credential_get_attribute: + 'uint anoncreds_credential_get_attribute(size_t handle, const char *name, _Out_ const char **out)', + anoncreds_credential_from_json: 'uint anoncreds_credential_from_json(ByteBuffer buffer, _Out_ size_t *out)', + + // Revocation registry definition functions + anoncreds_create_revocation_registry_def: + 'uint anoncreds_create_revocation_registry_def(size_t cred_def, const char *cred_def_id, const char *issuer_id, const char *tag, const char *rev_reg_type, int32 max_cred_num, const char *tails_dir_path, size_t *rev_reg_def_out, size_t *rev_reg_def_private_out)', + anoncreds_revocation_registry_definition_get_attribute: + 'uint anoncreds_revocation_registry_definition_get_attribute(size_t handle, const char *name, _Out_ const char **out)', + anoncreds_revocation_registry_definition_from_json: + 'uint anoncreds_revocation_registry_definition_from_json(ByteBuffer buffer, _Out_ size_t *out)', + anoncreds_revocation_registry_definition_private_from_json: + 'uint anoncreds_revocation_registry_definition_private_from_json(ByteBuffer buffer, _Out_ size_t *out)', + + // Revocation registry functions + anoncreds_revocation_registry_from_json: + 'uint anoncreds_revocation_registry_from_json(ByteBuffer buffer, _Out_ size_t *out)', + + // Revocation status list functions + anoncreds_create_revocation_status_list: + 'uint anoncreds_create_revocation_status_list(size_t cred_def, const char *rev_reg_def_id, size_t rev_reg_def, size_t rev_reg_priv, const char *_issuer_id, int8 issuance_by_default, int64 timestamp, _Out_ size_t *out)', + anoncreds_update_revocation_status_list: + 'uint anoncreds_update_revocation_status_list(size_t cred_def, size_t rev_reg_def, size_t rev_reg_priv, size_t rev_current_list, I32List issued, I32List revoked, int64 timestamp, _Out_ size_t *out)', + anoncreds_update_revocation_status_list_timestamp_only: + 'uint anoncreds_update_revocation_status_list_timestamp_only(int64 timestamp, size_t rev_status_list, _Out_ size_t *out)', + anoncreds_revocation_status_list_from_json: + 'uint anoncreds_revocation_status_list_from_json(ByteBuffer buffer, _Out_ size_t *out)', + + // Revocation state functions + anoncreds_create_or_update_revocation_state: + 'uint anoncreds_create_or_update_revocation_state(size_t rev_reg_def, size_t rev_status_list, int64 rev_reg_idx, const char *tails_path, size_t old_rev_state, size_t old_rev_status_list, _Out_ size_t *out)', + anoncreds_revocation_state_from_json: + 'uint anoncreds_revocation_state_from_json(ByteBuffer buffer, _Out_ size_t *out)', + + // Presentation request functions + anoncreds_presentation_request_from_json: + 'uint anoncreds_presentation_request_from_json(ByteBuffer buffer, _Out_ size_t *out)', + + // Presentation functions + anoncreds_create_presentation: + 'uint anoncreds_create_presentation(size_t pres_req, CredentialEntryList credentials, CredentialProveList credentials_prove, StringList self_attested_names, StringList self_attested_values, const char *link_secret, ObjectHandleList schemas, StringList schema_ids, ObjectHandleList cred_defs, StringList cred_def_ids, _Out_ size_t *out)', + anoncreds_verify_presentation: + 'uint anoncreds_verify_presentation(size_t presentation, size_t pres_req, ObjectHandleList schemas, StringList schema_ids, ObjectHandleList cred_defs, StringList cred_def_ids, ObjectHandleList rev_reg_defs, StringList rev_reg_def_ids, ObjectHandleList rev_status_list, NonRevokedIntervalOverrideList nonrevoked_interval_override, _Out_ int8 *out)', + anoncreds_presentation_from_json: 'uint anoncreds_presentation_from_json(ByteBuffer buffer, _Out_ size_t *out)', + + // W3C Credential functions + anoncreds_create_w3c_credential: + 'uint anoncreds_create_w3c_credential(size_t cred_def, size_t cred_def_private, size_t cred_offer, size_t cred_request, StringList attr_names, StringList attr_raw_values, const CredRevInfo *revocation, const char *w3c_version, _Out_ size_t *out)', + anoncreds_process_w3c_credential: + 'uint anoncreds_process_w3c_credential(size_t cred, size_t cred_req_metadata, const char *link_secret, size_t cred_def, size_t rev_reg_def, _Out_ size_t *out)', + anoncreds_create_w3c_presentation: + 'uint anoncreds_create_w3c_presentation(size_t pres_req, CredentialEntryList credentials, CredentialProveList credentials_prove, const char *link_secret, ObjectHandleList schemas, StringList schema_ids, ObjectHandleList cred_defs, StringList cred_def_ids, const char *w3c_version, _Out_ size_t *out)', + anoncreds_verify_w3c_presentation: + 'uint anoncreds_verify_w3c_presentation(size_t presentation, size_t pres_req, ObjectHandleList schemas, StringList schema_ids, ObjectHandleList cred_defs, StringList cred_def_ids, ObjectHandleList rev_reg_defs, StringList rev_reg_def_ids, ObjectHandleList rev_status_lists, NonRevokedIntervalOverrideList nonrevoked_interval_override, _Out_ int8 *out)', + anoncreds_credential_to_w3c: + 'uint anoncreds_credential_to_w3c(size_t cred, const char *issuer_id, const char *w3c_version, _Out_ size_t *out)', + anoncreds_credential_from_w3c: 'uint anoncreds_credential_from_w3c(size_t w3c_credential, _Out_ size_t *out)', + anoncreds_w3c_credential_get_integrity_proof_details: + 'uint anoncreds_w3c_credential_get_integrity_proof_details(size_t w3c_credential, _Out_ size_t *out)', + anoncreds_w3c_credential_proof_get_attribute: + 'uint anoncreds_w3c_credential_proof_get_attribute(size_t w3c_credential, const char *name, _Out_ const char **out)', + anoncreds_w3c_credential_from_json: 'uint anoncreds_w3c_credential_from_json(ByteBuffer buffer, _Out_ size_t *out)', + anoncreds_w3c_presentation_from_json: + 'uint anoncreds_w3c_presentation_from_json(ByteBuffer buffer, _Out_ size_t *out)', +} diff --git a/packages/anoncreds-nodejs/src/library/register.ts b/packages/anoncreds-nodejs/src/library/register.ts index 27eb967..4903a7d 100644 --- a/packages/anoncreds-nodejs/src/library/register.ts +++ b/packages/anoncreds-nodejs/src/library/register.ts @@ -3,7 +3,7 @@ import type { NativeMethods } from './NativeBindingInterface' import fs from 'fs' import os from 'os' import path from 'path' -import { Library } from '@2060.io/ffi-napi' +import koffi from 'koffi' import { nativeBindings } from './bindings' @@ -63,10 +63,22 @@ const getLibrary = () => { // Casting here as a string because there is a guard of none of the paths const validLibraryPath = libaries.find((l) => doesPathExist(l)) as string - // TODO - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - return Library(validLibraryPath, nativeBindings) + // Load library with Koffi + const lib = koffi.load(validLibraryPath) + + // Bind functions using koffi + const boundMethods: { [key: string]: any } = {} + + for (const [funcName, signature] of Object.entries(nativeBindings)) { + try { + boundMethods[funcName] = lib.func(signature as string) + } catch (error) { + console.warn(`Warning: Failed to bind function ${funcName}: ${error}`) + // Continue binding other functions + } + } + + return boundMethods } let nativeAnoncreds: NativeMethods | undefined diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 458373f..5b7ebfe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,31 +81,16 @@ importers: packages/anoncreds-nodejs: dependencies: - '@2060.io/ffi-napi': - specifier: ^4.0.9 - version: 4.0.9 - '@2060.io/ref-napi': - specifier: ^3.0.6 - version: 3.0.6 '@hyperledger/anoncreds-shared': specifier: workspace:* version: link:../anoncreds-shared - ref-array-di: - specifier: 1.2.2 - version: 1.2.2 - ref-struct-di: - specifier: 1.1.1 - version: 1.1.1 + koffi: + specifier: ^2.14.0 + version: 2.14.0 devDependencies: '@types/node': specifier: 'catalog:' version: 20.17.23 - '@types/ref-array-di': - specifier: ^1.2.3 - version: 1.2.8 - '@types/ref-struct-di': - specifier: ^1.1.6 - version: 1.1.12 typescript: specifier: 'catalog:' version: 5.4.5 @@ -146,14 +131,6 @@ packages: graphql: optional: true - '@2060.io/ffi-napi@4.0.9': - resolution: {integrity: sha512-JfVREbtkJhMXSUpya3JCzDumdjeZDCKv4PemiWK+pts5CYgdoMidxeySVlFeF5pHqbBpox4I0Be7sDwAq4N0VQ==} - engines: {node: '>=18'} - - '@2060.io/ref-napi@3.0.6': - resolution: {integrity: sha512-8VAIXLdKL85E85jRYpPcZqATBL6fGnC/XjBGNeSgRSMJtrAMSmfRksqIq5AmuZkA2eeJXMWCiN6UQOUdozcymg==} - engines: {node: '>= 18.0'} - '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -1410,15 +1387,6 @@ packages: '@types/react@18.3.18': resolution: {integrity: sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==} - '@types/ref-array-di@1.2.8': - resolution: {integrity: sha512-+re5xrhRXDUR3sicMvN9N3C+6mklq5kd7FkN3ciRWio3BAvUDh2OEUTTG+619r10dqc6de25LIDtgpHtXCKGbA==} - - '@types/ref-napi@3.0.12': - resolution: {integrity: sha512-UZPKghRaLlWx2lPAphpdtYe62TbGBaPeqUM6gF1vI6FPRIu/Tff/WMAzpJRFU3jJIiD8HiXpVt2RjcFHtA6YRg==} - - '@types/ref-struct-di@1.1.12': - resolution: {integrity: sha512-R2RNkGIROGoJTbXYTXrsXybnsQD4iAy26ih/G6HCeCB9luWFQKkr537XGz0uGJ1kH8y8RMkdbQmD/wBulrOPHw==} - '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -1520,9 +1488,6 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - array-index@1.0.0: - resolution: {integrity: sha512-jesyNbBkLQgGZMSwA1FanaFjalb1mZUGxGeUEkSDidzgrbjBGhvizJkaItdhkt8eIHFOJC7nDsrXk+BaehTdRw==} - array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -1865,10 +1830,6 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - d@1.0.2: - resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} - engines: {node: '>=0.12'} - debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -2013,17 +1974,6 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - es5-ext@0.10.64: - resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} - engines: {node: '>=0.10'} - - es6-iterator@2.0.3: - resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} - - es6-symbol@3.1.4: - resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} - engines: {node: '>=0.12'} - esbuild@0.25.0: resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} engines: {node: '>=18'} @@ -2048,10 +1998,6 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - esniff@2.0.1: - resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} - engines: {node: '>=0.10'} - esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -2065,9 +2011,6 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - event-emitter@0.3.5: - resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} - event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -2147,9 +2090,6 @@ packages: exponential-backoff@3.1.2: resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} - ext@1.7.0: - resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} - extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -2299,15 +2239,9 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - get-symbol-from-current-process-h@1.0.2: - resolution: {integrity: sha512-syloC6fsCt62ELLrr1VKBM1ggOpMdetX9hTrdW77UQdcApPHLmf7CI7OKcN1c9kYuNxKcDe4iJ4FY9sX3aw2xw==} - get-tsconfig@4.10.0: resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} - get-uv-event-loop-napi-h@1.0.6: - resolution: {integrity: sha512-t5c9VNR84nRoF+eLiz6wFrEp1SE2Acg0wS+Ysa2zF0eROes+LzOfuTaVHxGy8AbS8rq7FHEJzjnCZo1BupwdJg==} - getenv@1.0.0: resolution: {integrity: sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==} engines: {node: '>=6'} @@ -2622,6 +2556,9 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + koffi@2.14.0: + resolution: {integrity: sha512-/ihgdvoeSSaX9S6nVNaZ/uPdYrpN0rIx15kgqzVdu6JPxo9jhc6Lh+dmxpURrEi8MAZcJqRLP1FFsmIF4uTZbg==} + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -2941,15 +2878,9 @@ packages: nested-error-stacks@2.0.1: resolution: {integrity: sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==} - next-tick@1.1.0: - resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} - nice-try@1.0.5: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} - node-addon-api@3.2.1: - resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} - node-dir@0.1.17: resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} engines: {node: '>= 0.10.5'} @@ -2967,10 +2898,6 @@ packages: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} - node-gyp-build@4.8.4: - resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} - hasBin: true - node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -3278,12 +3205,6 @@ packages: resolution: {integrity: sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==} engines: {node: '>= 4'} - ref-array-di@1.2.2: - resolution: {integrity: sha512-jhCmhqWa7kvCVrWhR/d7RemkppqPUdxEil1CtTtm7FkZV8LcHHCK3Or9GinUiFP5WY3k0djUkMvhBhx49Jb2iA==} - - ref-struct-di@1.1.1: - resolution: {integrity: sha512-2Xyn/0Qgz89VT+++WP0sTosdm9oeowLP23wRJYhG4BFdMUrLj3jhwHZNEytYNYgtPKLNTP3KJX4HEgBvM1/Y2g==} - regenerate-unicode-properties@10.2.0: resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==} engines: {node: '>=4'} @@ -3691,9 +3612,6 @@ packages: resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} engines: {node: '>=8'} - type@2.7.3: - resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} - typescript@5.4.5: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} @@ -3928,26 +3846,6 @@ snapshots: '@0no-co/graphql.web@1.1.2': {} - '@2060.io/ffi-napi@4.0.9': - dependencies: - '@2060.io/ref-napi': 3.0.6 - debug: 4.4.0 - get-uv-event-loop-napi-h: 1.0.6 - node-addon-api: 3.2.1 - node-gyp-build: 4.8.4 - ref-struct-di: 1.1.1 - transitivePeerDependencies: - - supports-color - - '@2060.io/ref-napi@3.0.6': - dependencies: - debug: 4.4.0 - get-symbol-from-current-process-h: 1.0.2 - node-addon-api: 3.2.1 - node-gyp-build: 4.8.4 - transitivePeerDependencies: - - supports-color - '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.8 @@ -5741,18 +5639,6 @@ snapshots: '@types/prop-types': 15.7.14 csstype: 3.1.3 - '@types/ref-array-di@1.2.8': - dependencies: - '@types/ref-napi': 3.0.12 - - '@types/ref-napi@3.0.12': - dependencies: - '@types/node': 20.17.23 - - '@types/ref-struct-di@1.1.12': - dependencies: - '@types/ref-napi': 3.0.12 - '@types/stack-utils@2.0.3': {} '@types/yargs-parser@21.0.3': {} @@ -5836,13 +5722,6 @@ snapshots: argparse@2.0.1: {} - array-index@1.0.0: - dependencies: - debug: 2.6.9 - es6-symbol: 3.1.4 - transitivePeerDependencies: - - supports-color - array-union@2.1.0: {} asap@2.0.6: {} @@ -6249,11 +6128,6 @@ snapshots: csstype@3.1.3: {} - d@1.0.2: - dependencies: - es5-ext: 0.10.64 - type: 2.7.3 - debug@2.6.9: dependencies: ms: 2.0.0 @@ -6368,24 +6242,6 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 - es5-ext@0.10.64: - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esniff: 2.0.1 - next-tick: 1.1.0 - - es6-iterator@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-symbol: 3.1.4 - - es6-symbol@3.1.4: - dependencies: - d: 1.0.2 - ext: 1.7.0 - esbuild@0.25.0: optionalDependencies: '@esbuild/aix-ppc64': 0.25.0 @@ -6424,24 +6280,12 @@ snapshots: escape-string-regexp@4.0.0: {} - esniff@2.0.1: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - event-emitter: 0.3.5 - type: 2.7.3 - esprima@4.0.1: {} esutils@2.0.3: {} etag@1.8.1: {} - event-emitter@0.3.5: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - event-target-shim@5.0.1: {} exec-async@2.2.0: {} @@ -6561,10 +6405,6 @@ snapshots: exponential-backoff@3.1.2: {} - ext@1.7.0: - dependencies: - type: 2.7.3 - extendable-error@0.1.7: {} external-editor@3.1.0: @@ -6744,16 +6584,10 @@ snapshots: get-stream@6.0.1: {} - get-symbol-from-current-process-h@1.0.2: {} - get-tsconfig@4.10.0: dependencies: resolve-pkg-maps: 1.0.0 - get-uv-event-loop-napi-h@1.0.6: - dependencies: - get-symbol-from-current-process-h: 1.0.2 - getenv@1.0.0: {} glob-parent@5.1.2: @@ -7082,6 +6916,8 @@ snapshots: kleur@3.0.3: {} + koffi@2.14.0: {} + leven@3.1.0: {} lighthouse-logger@1.4.2: @@ -7463,12 +7299,8 @@ snapshots: nested-error-stacks@2.0.1: {} - next-tick@1.1.0: {} - nice-try@1.0.5: {} - node-addon-api@3.2.1: {} - node-dir@0.1.17: dependencies: minimatch: 3.1.2 @@ -7479,8 +7311,6 @@ snapshots: node-forge@1.3.1: {} - node-gyp-build@4.8.4: {} - node-int64@0.4.0: {} node-releases@2.0.19: {} @@ -7860,19 +7690,6 @@ snapshots: source-map: 0.6.1 tslib: 2.8.1 - ref-array-di@1.2.2: - dependencies: - array-index: 1.0.0 - debug: 3.2.7 - transitivePeerDependencies: - - supports-color - - ref-struct-di@1.1.1: - dependencies: - debug: 3.2.7 - transitivePeerDependencies: - - supports-color - regenerate-unicode-properties@10.2.0: dependencies: regenerate: 1.4.2 @@ -8269,8 +8086,6 @@ snapshots: type-fest@0.7.1: {} - type@2.7.3: {} - typescript@5.4.5: {} ua-parser-js@1.0.40: {}