From deef86e6de4963265d48c17627d5bc749922fa74 Mon Sep 17 00:00:00 2001 From: Aryan Jassal Date: Tue, 8 Oct 2024 18:02:18 +1100 Subject: [PATCH] chore: added error type for mkdir --- src/client/handlers/VaultsSecretsMkdir.ts | 26 ++++++++++++----------- src/client/types.ts | 17 ++++++++++----- src/vaults/VaultOps.ts | 12 +++++++---- tests/client/handlers/vaults.test.ts | 19 ++++++++++------- 4 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/client/handlers/VaultsSecretsMkdir.ts b/src/client/handlers/VaultsSecretsMkdir.ts index 896b1ab7b..d9a13e7d2 100644 --- a/src/client/handlers/VaultsSecretsMkdir.ts +++ b/src/client/handlers/VaultsSecretsMkdir.ts @@ -4,7 +4,7 @@ import type { ClientRPCRequestParams, ClientRPCResponseResult, SecretDirMessage, - SuccessWithErrorMessage, + SuccessOrErrorMessage, } from '../types'; import type VaultManager from '../../vaults/VaultManager'; import { DuplexHandler } from '@matrixai/rpc'; @@ -18,16 +18,16 @@ class VaultsSecretsMkdir extends DuplexHandler< db: DB; }, ClientRPCRequestParams, - ClientRPCResponseResult + ClientRPCResponseResult > { public handle = async function* ( input: AsyncIterable>, - ): AsyncGenerator> { + ): AsyncGenerator> { const { vaultManager, db }: { vaultManager: VaultManager; db: DB } = this.container; let metadata: JSONObject; yield* db.withTransactionG( - async function* (tran): AsyncGenerator { + async function* (tran): AsyncGenerator { for await (const secretDirMessage of input) { // Unpack input if (metadata == null) metadata = secretDirMessage.metadata ?? {}; @@ -41,20 +41,22 @@ class VaultsSecretsMkdir extends DuplexHandler< throw new vaultsErrors.ErrorVaultsVaultUndefined(); } // Write directories. This doesn't need to be grouped by vault names, - // as no commit is created for empty directories anyways. - let response: SuccessWithErrorMessage; - await vaultManager.withVaults( + // as no commit is created for empty directories anyways. The + // vaultOps.mkdir() method also returns an object of type + // SuccessOrErrorMessage. As such, we can return the result without + // doing any type conversion or extra processing. + yield await vaultManager.withVaults( [vaultId], async (vault) => { - const options = metadata?.options as { recursive?: boolean }; - response = await vaultOps.mkdir(vault, dirName, { - recursive: options.recursive, + const options = metadata?.options as + | { recursive?: boolean } + | undefined; + return await vaultOps.mkdir(vault, dirName, { + recursive: options?.recursive, }); }, tran, ); - if (response!.success) yield { success: true }; - else yield { success: false, error: response!.error }; } }, ); diff --git a/src/client/types.ts b/src/client/types.ts index ae40011b7..564848d59 100644 --- a/src/client/types.ts +++ b/src/client/types.ts @@ -204,6 +204,16 @@ type SuccessMessage = { success: boolean; }; +type ErrorMessage = { + type: 'error'; + success: false; + code: string; + reason?: string; + data?: JSONObject; +}; + +type SuccessOrErrorMessage = SuccessMessage | ErrorMessage; + // Notifications messages type NotificationReadMessage = { @@ -321,10 +331,6 @@ type SecretDirMessage = VaultIdentifierMessage & { dirName: string; }; -type SuccessWithErrorMessage = SuccessMessage & { - error?: string; -}; - type SecretRenameMessage = SecretIdentifierMessage & { newSecretName: string; }; @@ -397,6 +403,8 @@ export type { NodesGetMessage, NodesAddMessage, SuccessMessage, + ErrorMessage, + SuccessOrErrorMessage, NotificationInboxMessage, NotificationOutboxMessage, NotificationReadMessage, @@ -423,7 +431,6 @@ export type { ContentWithErrorMessage, SecretContentMessage, SecretDirMessage, - SuccessWithErrorMessage, SecretRenameMessage, SecretFilesMessage, SecretStatMessage, diff --git a/src/vaults/VaultOps.ts b/src/vaults/VaultOps.ts index 51dbf8512..a9eb93a8a 100644 --- a/src/vaults/VaultOps.ts +++ b/src/vaults/VaultOps.ts @@ -4,7 +4,7 @@ import type Logger from '@matrixai/logger'; import type { Vault } from './Vault'; import type { Stat } from 'encryptedfs'; -import type { SuccessWithErrorMessage } from '../client/types'; +import type { SuccessOrErrorMessage } from '../client/types'; import path from 'path'; import * as vaultsErrors from './errors'; import * as vaultsUtils from './utils'; @@ -174,7 +174,7 @@ async function mkdir( dirPath: string, fileOptions?: FileOptions, logger?: Logger, -): Promise { +): Promise { const recursive = fileOptions?.recursive ?? false; // Technically, writing an empty directory won't make a commit, and doesn't // need a write resource as git doesn't track empty directories. It is @@ -189,13 +189,17 @@ async function mkdir( logger?.error(`Failed to create directory '${dirPath}'. Reason: ${e.code}`); if (e.code === 'ENOENT' && !recursive) { return { + type: 'error', success: false, - error: `${e.code}: cannot create directory ${dirPath}: No such secret or directory`, + code: e.code, + reason: dirPath, }; } else if (e.code === 'EEXIST') { return { + type: 'error', success: false, - error: `${e.code}: cannot create directory ${dirPath}: Secret or directory exists`, + code: e.code, + reason: dirPath, }; } else { throw e; diff --git a/tests/client/handlers/vaults.test.ts b/tests/client/handlers/vaults.test.ts index 43a5b9566..8c86e5c63 100644 --- a/tests/client/handlers/vaults.test.ts +++ b/tests/client/handlers/vaults.test.ts @@ -3,6 +3,7 @@ import type { FileSystem } from '@/types'; import type { VaultId } from '@/ids'; import type NodeManager from '@/nodes/NodeManager'; import type { + ErrorMessage, LogEntryMessage, SecretContentMessage, VaultListMessage, @@ -1352,7 +1353,6 @@ describe('vaultsSecretsMkdir', () => { for await (const data of response.readable) { expect(data.success).toBeTruthy(); - expect(data.error).toBeUndefined(); } await vaultManager.withVaults([vaultId], async (vault) => { await vault.readF(async (efs) => { @@ -1371,7 +1371,9 @@ describe('vaultsSecretsMkdir', () => { await writer.close(); for await (const data of response.readable) { expect(data.success).toBeFalsy(); - expect(data.error?.substring(0, 6)).toStrictEqual('ENOENT'); + const error = data as ErrorMessage; + expect(error.code).toEqual('ENOENT'); + expect(error.reason).toEqual(dirPath); } await vaultManager.withVaults([vaultId], async (vault) => { await vault.readF(async (efs) => { @@ -1403,7 +1405,6 @@ describe('vaultsSecretsMkdir', () => { // Check if the operation concluded as expected for await (const data of response.readable) { expect(data.success).toBeTruthy(); - expect(data.error).toBeUndefined(); } await vaultManager.withVaults( [vaultId1, vaultId2], @@ -1437,10 +1438,10 @@ describe('vaultsSecretsMkdir', () => { await writer.close(); // Check if the operation concluded as expected for await (const data of response.readable) { - if (data.success) { - expect(data.error).toBeUndefined(); - } else { - expect(data.error?.substring(0, 6)).toStrictEqual('ENOENT'); + if (!data.success) { + const error = data as ErrorMessage; + expect(error.code).toEqual('ENOENT'); + expect(error.reason).toEqual(dirPath3); } } await vaultManager.withVaults( @@ -1474,7 +1475,9 @@ describe('vaultsSecretsMkdir', () => { // Check if the operation concluded as expected for await (const data of response.readable) { expect(data.success).toBeFalsy(); - expect(data.error?.substring(0, 6)).toStrictEqual('EEXIST'); + const error = data as ErrorMessage; + expect(error.code).toEqual('EEXIST'); + expect(error.reason).toEqual(dirPath); } await vaultManager.withVaults([vaultId], async (vault) => { await vault.readF(async (efs) => {