Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions src/meilisearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import type {
ResultsWrapper,
WebhookCreatePayload,
WebhookUpdatePayload,
UpdatableNetwork,
} from "./types/index.js";
import { ErrorStatusCode } from "./types/index.js";
import { HttpRequests } from "./http-requests.js";
Expand Down Expand Up @@ -383,11 +384,8 @@ export class MeiliSearch {
*
* @experimental
*/
async updateNetwork(network: Partial<Network>): Promise<Network> {
return await this.httpRequest.patch({
path: "network",
body: network,
});
async updateNetwork(options: UpdatableNetwork): Promise<Network> {
return await this.httpRequest.patch({ path: "network", body: options });
}

///
Expand Down
3 changes: 2 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from "./experimental-features.js";
export * from "./task_and_batch.js";
export * from "./network.js";
export * from "./task-and-batch.js";
export * from "./token.js";
export * from "./types.js";
export * from "./webhooks.js";
17 changes: 17 additions & 0 deletions src/types/network.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { DeepPartial } from "./shared.js";

/** {@link https://www.meilisearch.com/docs/reference/api/network#the-remote-object} */
export type Remote = {
url: string;
searchApiKey?: string | null;
writeApiKey?: string | null;
};

/** {@link https://www.meilisearch.com/docs/reference/api/network#the-network-object} */
export type Network = {
self?: string | null;
remotes?: Record<string, Remote>;
sharding?: boolean;
};

export type UpdatableNetwork = DeepPartial<Network>;
14 changes: 4 additions & 10 deletions src/types/shared.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { RecordAny } from "./types.js";

export type CursorResults<T> = {
results: T[];
limit: number;
Expand All @@ -8,14 +6,10 @@ export type CursorResults<T> = {
total: number;
};

export type NonNullableDeepRecordValues<T> = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[P in keyof T]: T[P] extends any[]
? Array<NonNullableDeepRecordValues<T[P][number]>>
: T[P] extends RecordAny
? NonNullableDeepRecordValues<T[P]>
: NonNullable<T[P]>;
};
/** Deeply map every property of a record to itself making it partial. */
export type DeepPartial<T> = T extends object
? { [TKey in keyof T]?: DeepPartial<T[TKey]> }
: T;

// taken from https://stackoverflow.com/a/65642944
export type PascalToCamelCase<S extends string> = Uncapitalize<S>;
Expand Down
14 changes: 14 additions & 0 deletions src/types/task_and_batch.ts → src/types/task-and-batch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,18 @@ export type TaskDetails = Settings &
upgradeTo: string;
}>;

/** {@link https://www.meilisearch.com/docs/reference/api/tasks#network} */
type Origin = { remoteName: string; taskUid: number };

/** {@link https://www.meilisearch.com/docs/reference/api/tasks#network} */
type NetworkOrigin = { origin: Origin };

/** {@link https://www.meilisearch.com/docs/reference/api/tasks#network} */
type RemoteTask = { taskUid?: number; error: MeiliSearchErrorResponse | null };

/** {@link https://www.meilisearch.com/docs/reference/api/tasks#network} */
type NetworkRemoteTasks = { remoteTasks: Record<string, RemoteTask> };

/**
* {@link https://www.meilisearch.com/docs/reference/api/tasks#task-object}
*
Expand All @@ -150,6 +162,8 @@ export type Task = SafeOmit<EnqueuedTask, "taskUid"> & {
duration: string | null;
startedAt: string | null;
finishedAt: string | null;
/** {@link https://www.meilisearch.com/docs/reference/api/tasks#network} */
network?: NetworkOrigin | NetworkRemoteTasks;
};

/**
Expand Down
28 changes: 1 addition & 27 deletions src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// Definitions: https://github.com/meilisearch/meilisearch-js
// TypeScript Version: ^5.8.2

import type { WaitOptions } from "./task_and_batch.js";
import type { WaitOptions } from "./task-and-batch.js";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type RecordAny = Record<string, any>;
Expand Down Expand Up @@ -310,26 +310,6 @@ export type FederatedMultiSearchParams = {
queries: MultiSearchQueryWithFederation[];
};

/**
* {@link https://www.meilisearch.com/docs/reference/api/network#the-remote-object}
*
* @see `meilisearch_types::features::Remote` at {@link https://github.com/meilisearch/meilisearch}
*/
export type Remote = {
url: string;
searchApiKey: string | null;
};

/**
* {@link https://www.meilisearch.com/docs/reference/api/network#the-network-object}
*
* @see `meilisearch_types::features::Network` at {@link https://github.com/meilisearch/meilisearch}
*/
export type Network = {
self: string | null;
remotes: Record<string, Remote>;
};

export type CategoriesDistribution = {
[category: string]: number;
};
Expand Down Expand Up @@ -842,12 +822,6 @@ export type Version = {
** ERROR HANDLER
*/

export interface FetchError extends Error {
type: string;
errno: string;
code: string;
}

export type MeiliSearchErrorResponse = {
message: string;
// https://www.meilisearch.com/docs/reference/errors/error_codes
Expand Down
36 changes: 19 additions & 17 deletions tests/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ import {
type MockInstance,
beforeAll,
} from "vitest";
import type { Health, Version, Stats, IndexSwap } from "../src/index.js";
import type {
Health,
Version,
Stats,
IndexSwap,
UpdatableNetwork,
} from "../src/index.js";
import { ErrorStatusCode, MeiliSearchRequestError } from "../src/index.js";
import pkg from "../package.json" with { type: "json" };
import {
Expand Down Expand Up @@ -887,26 +893,22 @@ describe.each([{ permission: "Master" }])(
test(`${permission} key: Update and get network settings`, async () => {
const client = await getClient(permission);

const instances = {
[instanceName]: {
url: "http://instance-1:7700",
searchApiKey: "search-key-1",
const options: UpdatableNetwork = {
self: instanceName,
remotes: {
[instanceName]: {
url: "http://instance-1:7700",
searchApiKey: "search-key-1",
writeApiKey: "write-key-1",
},
},
sharding: true,
};

await client.updateNetwork({ self: instanceName, remotes: instances });
await client.updateNetwork(options);
const response = await client.getNetwork();
expect(response).toHaveProperty("self", instanceName);
expect(response).toHaveProperty("remotes");
expect(response.remotes).toHaveProperty("instance_1");
expect(response.remotes["instance_1"]).toHaveProperty(
"url",
instances[instanceName].url,
);
expect(response.remotes["instance_1"]).toHaveProperty(
"searchApiKey",
instances[instanceName].searchApiKey,
);

assert.deepEqual(response, options);
});
},
);
21 changes: 12 additions & 9 deletions tests/tasks-and-batches.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { randomUUID } from "node:crypto";
import { beforeAll, describe, test, vi } from "vitest";
import type { TasksOrBatchesQuery } from "../src/types/index.js";
import { getClient, objectEntries } from "./utils/meilisearch-test-utils.js";
import {
getClient,
objectEntries,
assert,
possibleTaskTypes,
} from "./utils/meilisearch-test-utils.js";
import {
possibleTaskStatuses,
} from "./utils/tasks-and-batches.js";
possibleTaskTypes,
} from "./utils/assertions/tasks-and-batches.js";

const INDEX_UID = randomUUID();
const ms = await getClient("Master");
Expand Down Expand Up @@ -188,11 +191,11 @@ describe.for(objectEntries(testValuesRecord))("%s", ([key, testValues]) => {
test.for(testValues)(
`${ms.tasks.getTasks.name} method%s`,
async ([, value]) => {
const { results, ...r } = await ms.tasks.getTasks({ [key]: value });
const tasksResults = await ms.tasks.getTasks({ [key]: value });

assert.isResult(r);
assert.isTasksOrBatchesResults(tasksResults);

for (const task of results) {
for (const task of tasksResults.results) {
assert.isTask(task);
}
},
Expand All @@ -201,11 +204,11 @@ describe.for(objectEntries(testValuesRecord))("%s", ([key, testValues]) => {
test.for(testValues)(
`${ms.batches.getBatches.name} method%s`,
async ([, value]) => {
const { results, ...r } = await ms.batches.getBatches({ [key]: value });
const batchesResults = await ms.batches.getBatches({ [key]: value });

assert.isResult(r);
assert.isTasksOrBatchesResults(batchesResults);

for (const batch of results) {
for (const batch of batchesResults.results) {
assert.isBatch(batch);
}
},
Expand Down
18 changes: 18 additions & 0 deletions tests/utils/assert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { assert } from "vitest";
import { errorAssertions } from "./assertions/error.js";
import { promiseAssertions } from "./assertions/promise.js";
import { tasksAndBatchesAssertions } from "./assertions/tasks-and-batches.js";

const source = {
...errorAssertions,
...promiseAssertions,
...tasksAndBatchesAssertions,
};

const customAssert: typeof assert & typeof source = Object.assign(
assert,
source,
);

// needs to be named assert to satisfy Vitest ESLint plugin in tests
export { customAssert as assert };
12 changes: 12 additions & 0 deletions tests/utils/assertions/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { assert } from "vitest";
import type { MeiliSearchErrorResponse } from "../../../src/index.js";

export const errorAssertions = {
isErrorResponse(error: MeiliSearchErrorResponse) {
assert.lengthOf(Object.keys(error), 4);
const { message, code, type, link } = error;
for (const val of Object.values({ message, code, type, link })) {
assert.typeOf(val, "string");
}
},
};
43 changes: 43 additions & 0 deletions tests/utils/assertions/promise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { assert } from "vitest";

const NOT_RESOLVED = Symbol("<not resolved>");
const RESOLVED = Symbol("<resolved>");

export const promiseAssertions = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async rejects<T extends { new (...args: any[]): any }>(
promise: Promise<unknown>,
errorConstructor: T,
errMsgMatcher?: RegExp | string,
): Promise<InstanceType<T>> {
let resolvedValue;

try {
resolvedValue = await promise;
} catch (error) {
assert.instanceOf(error, errorConstructor);

if (errMsgMatcher !== undefined) {
const { message } = error as Error;
if (typeof errMsgMatcher === "string") {
assert.strictEqual(message, errMsgMatcher);
} else {
assert.match(message, errMsgMatcher);
}
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return error as InstanceType<T>;
}

assert.fail(resolvedValue, NOT_RESOLVED, "expected value to not resolve");
},

async resolves(promise: Promise<unknown>): Promise<void> {
try {
await promise;
} catch (error) {
assert.fail(error, RESOLVED, "expected value to not reject");
}
},
};
Loading