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
4 changes: 2 additions & 2 deletions src/commands/db/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ const roleSub = async (
}
const auth = await reg.getAuth();
try {
if (op === "assign") auth.assignRole(targetUser, role);
else if (op === "remove") auth.removeRole(targetUser, role);
if (op === "assign") await auth.assignRole(targetUser, role);
else if (op === "remove") await auth.removeRole(targetUser, role);
Comment on lines +161 to +162
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Adding await here is correct as these operations are asynchronous and must complete before the handler returns to ensure the response is accurate and errors are caught.

Note that the same issue appears to exist in logoutSub (lines 136 and 138 in the full file), where auth.logoutAll() and auth.logout() are called without await. You should consider applying the same fix there to ensure consistent behavior and proper error handling during logout.

else throw new CommandError(EXIT.USAGE, `unknown role op: ${op}`);
} catch (err) {
if (err instanceof CommandError) throw err;
Expand Down
6 changes: 4 additions & 2 deletions src/commands/db/crud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,11 @@ export const aggregateHandler = async (
case "$project":
pipe = pipe.project(arg as Record<string, unknown>);
break;
case "$unwind":
pipe = pipe.unwind(arg as string);
case "$unwind": {
const unwindField = typeof arg === "string" && arg.startsWith("$") ? arg.slice(1) : arg;
pipe = pipe.unwind(unwindField as string);
break;
}
Comment on lines +253 to +257
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The fix for $unwind correctly handles the string shorthand by stripping the leading $. However, if the underlying library supports the object form of $unwind (e.g., {$unwind: { path: '$field', preserveNullAndEmptyArrays: true }}), this implementation will pass the object directly to pipe.unwind() with a string cast, and the leading $ inside the path property will remain.

If the object form is supported, you should also strip the $ from the path property within the object, similar to how it's handled in the $group stage (lines 214 and 233).

default:
throw new CommandError(EXIT.USAGE, `unknown aggregation operator: ${op}`);
}
Expand Down
2 changes: 1 addition & 1 deletion src/commands/db/meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
const sorted = flagBool(parsed.flags, "sorted");
const unique = flagBool(parsed.flags, "unique");
try {
c.createIndex(field, { sorted, unique });
c.createIndex(field, { type: sorted ? "sorted" : "hash", unique });

Check failure on line 29 in src/commands/db/meta.ts

View workflow job for this annotation

GitHub Actions / test

Object literal may only specify known properties, and 'type' does not exist in type '{ unique?: boolean; sorted?: boolean; }'.
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
if (msg.includes("Unique constraint")) {
Expand Down
8 changes: 6 additions & 2 deletions src/commands/vec/ops.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@
throw new CommandError(EXIT.VALIDATION, `validation: id collision: ${check.id}`);
}
const rec = parsedRec as Record<string, unknown>;
const recMeta = rec["meta"];
const recMeta = rec["metadata"] ?? rec["meta"];
const meta = recMeta && typeof recMeta === "object" && !Array.isArray(recMeta)
? (recMeta as Record<string, unknown>)
: {};
Expand Down Expand Up @@ -473,13 +473,17 @@
throw new CommandError(EXIT.VALIDATION, "validation: invalid JSON for import");
}
if (!Array.isArray(parsedInput)) {
throw new CommandError(EXIT.VALIDATION, "validation: import expects an array of records");
if (parsedInput && typeof parsedInput === "object" && Array.isArray((parsedInput as Record<string, unknown>)["records"])) {
parsedInput = (parsedInput as Record<string, unknown>)["records"];
} else {
throw new CommandError(EXIT.VALIDATION, "validation: import expects an array of records");
}
}
// Validate every record before handing off to upstream — surface clear
// errors with the offending index instead of letting upstream throw an
// opaque "Cannot read property" mid-import.
for (let i = 0; i < parsedInput.length; i++) {

Check failure on line 485 in src/commands/vec/ops.ts

View workflow job for this annotation

GitHub Actions / test

'parsedInput' is of type 'unknown'.
const check = checkVectorRecord(parsedInput[i], entry.dim);

Check failure on line 486 in src/commands/vec/ops.ts

View workflow job for this annotation

GitHub Actions / test

'parsedInput' is of type 'unknown'.
if (!check.ok) {
throw new CommandError(
EXIT.VALIDATION,
Expand All @@ -491,5 +495,5 @@
coll,
parsedInput as Array<{ id: string; vector: number[]; metadata?: Record<string, unknown> }>,
);
return { stdout: JSON.stringify({ imported: parsedInput.length }) };

Check failure on line 498 in src/commands/vec/ops.ts

View workflow job for this annotation

GitHub Actions / test

'parsedInput' is of type 'unknown'.
};
Loading