@remit/backend 0.0.49 → 0.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.test
CHANGED
package/dev-server/server.ts
CHANGED
|
@@ -327,8 +327,7 @@ app.listen(Number(port), "0.0.0.0", () => {
|
|
|
327
327
|
{
|
|
328
328
|
port: Number(port),
|
|
329
329
|
url: `http://localhost:${port}`,
|
|
330
|
-
|
|
331
|
-
dynamodbTable: env.DYNAMODB_TABLE_NAME,
|
|
330
|
+
dataBackend: process.env.DATA_BACKEND,
|
|
332
331
|
nodeEnv: env.NODE_ENV,
|
|
333
332
|
...(isSelfHostBackend
|
|
334
333
|
? {}
|
package/package.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { describe, it } from "node:test";
|
|
3
3
|
import type { OrganizeInput } from "@remit/api-openapi-types";
|
|
4
|
+
import { BadRequestError } from "@remit/data-ports/errors";
|
|
4
5
|
import { FilterMatchOperator } from "@remit/domain-enums";
|
|
6
|
+
import { handleError } from "../error.js";
|
|
5
7
|
import { predicateFromInput } from "./organize.js";
|
|
6
8
|
|
|
7
9
|
const input = (over: Partial<OrganizeInput> = {}): OrganizeInput => ({
|
|
@@ -41,3 +43,21 @@ describe("predicateFromInput (move back-apply accepted)", () => {
|
|
|
41
43
|
assert.equal(predicate.actionLabelId, "None");
|
|
42
44
|
});
|
|
43
45
|
});
|
|
46
|
+
|
|
47
|
+
// previewOrganize rejects a body-content (HasWords) clause by throwing
|
|
48
|
+
// BadRequestError (see service/organize.test.ts for the throw site). Proving
|
|
49
|
+
// the 4xx actually reaches the wire — not just that the right class is
|
|
50
|
+
// thrown — means proving the shared error handler maps it, since a plain
|
|
51
|
+
// Error would otherwise fall through to a 500 (reader #457).
|
|
52
|
+
describe("previewOrganize rejected-rule response (reader #457)", () => {
|
|
53
|
+
it("maps a rejected HasWords clause to a 400 naming the reason, not a 500", async () => {
|
|
54
|
+
const error = new BadRequestError(
|
|
55
|
+
"Organize literal matching cannot evaluate a body-content (HasWords) clause without the vector pipeline — it requires the semantic widen path",
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const response = await handleError(error);
|
|
59
|
+
|
|
60
|
+
assert.equal(response.statusCode, 400);
|
|
61
|
+
assert.match(JSON.parse(response.body).message, /HasWords/);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
3
3
|
import type { FilterAnchorItem, FilterItem } from "@remit/data-ports";
|
|
4
|
-
import { NotFoundError } from "@remit/data-ports/errors";
|
|
4
|
+
import { BadRequestError, NotFoundError } from "@remit/data-ports/errors";
|
|
5
5
|
import { FilterMatchOperator, FilterState } from "@remit/domain-enums";
|
|
6
6
|
import type {
|
|
7
7
|
AnchorPayload,
|
|
@@ -487,7 +487,7 @@ describe("matchOrganize on a deployment without the vector pipeline", () => {
|
|
|
487
487
|
);
|
|
488
488
|
});
|
|
489
489
|
|
|
490
|
-
it("
|
|
490
|
+
it("rejects a body-content (HasWords) clause as a 400 rather than matching it against a preview", async () => {
|
|
491
491
|
const deps = vectorlessDeps([
|
|
492
492
|
candidate("msg-1", { subject: "Dinner reservation" }),
|
|
493
493
|
]);
|
|
@@ -499,7 +499,12 @@ describe("matchOrganize on a deployment without the vector pipeline", () => {
|
|
|
499
499
|
anchorMessageId: "None",
|
|
500
500
|
literalClauses: [{ field: "HasWords", value: "invoice" }],
|
|
501
501
|
}),
|
|
502
|
-
|
|
502
|
+
(error: unknown) => {
|
|
503
|
+
assert.ok(error instanceof BadRequestError);
|
|
504
|
+
assert.equal(error.statusCode, 400);
|
|
505
|
+
assert.match(error.message, /HasWords/);
|
|
506
|
+
return true;
|
|
507
|
+
},
|
|
503
508
|
"the vector-free literal path must not silently narrow a body match to a preview",
|
|
504
509
|
);
|
|
505
510
|
assert.equal(deps.semanticUsed(), false);
|
package/src/service/organize.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
IFilterAnchorRepository,
|
|
4
4
|
OrganizeJobRequestItem,
|
|
5
5
|
} from "@remit/data-ports";
|
|
6
|
-
import { NotFoundError } from "@remit/data-ports/errors";
|
|
6
|
+
import { BadRequestError, NotFoundError } from "@remit/data-ports/errors";
|
|
7
7
|
import { FilterClauseField, FilterState } from "@remit/domain-enums";
|
|
8
8
|
import {
|
|
9
9
|
buildMatchText,
|
|
@@ -280,16 +280,14 @@ const matchSemantic = async (
|
|
|
280
280
|
* happened to be indexed. Body-content matching therefore requires the widen
|
|
281
281
|
* (vector) path — {@link matchSemantic} reconstructs body text from chunk
|
|
282
282
|
* previews there. This guard keeps the two matchers from diverging silently: a
|
|
283
|
-
* body-content clause reaching the vector-free path
|
|
284
|
-
* returning a wrong set.
|
|
285
|
-
* `HasWords` clause (the organize UI sends empty `literalClauses`, the filter
|
|
286
|
-
* builder emits none) — and stays a fail-fast for any future surface that does.
|
|
283
|
+
* body-content clause reaching the vector-free path is rejected instead of
|
|
284
|
+
* returning a wrong set.
|
|
287
285
|
*/
|
|
288
286
|
const assertNoBodyContentClause = (
|
|
289
287
|
clauses: OrganizePredicate["literalClauses"],
|
|
290
288
|
): void => {
|
|
291
289
|
if (clauses.some((clause) => clause.field === FilterClauseField.HasWords)) {
|
|
292
|
-
throw new
|
|
290
|
+
throw new BadRequestError(
|
|
293
291
|
"Organize literal matching cannot evaluate a body-content (HasWords) clause without the vector pipeline — it requires the semantic widen path",
|
|
294
292
|
);
|
|
295
293
|
}
|