feat(db): add read replicas
This commit is contained in:
+1
-1
@@ -68,4 +68,4 @@ COPY --from=builder /home/container/.next/static ./.next/static
|
||||
COPY --from=builder /home/container/.version ./.version
|
||||
|
||||
ENV HOSTNAME=0.0.0.0
|
||||
CMD ["bun", "server.js"]
|
||||
CMD ["bun", "server.js"]
|
||||
|
||||
@@ -26,6 +26,6 @@ export async function retrieveMobileUpload(accessKey: TAccessKey) {
|
||||
type: object.type!,
|
||||
}),
|
||||
);
|
||||
fd.set("name", object.name!)
|
||||
fd.set("name", object.name!);
|
||||
return fd;
|
||||
}
|
||||
|
||||
+7
-1
@@ -1,4 +1,10 @@
|
||||
import { drizzle } from "drizzle-orm/bun-sql";
|
||||
import * as schema from "./schema";
|
||||
import { withReplicas } from "drizzle-orm/pg-core";
|
||||
|
||||
export const db = drizzle(process.env.DATABASE_URL!, { schema });
|
||||
export const db = process.env.REPLICA_DATABASE_URL
|
||||
? withReplicas(drizzle(process.env.DATABASE_URL!, { schema }), [
|
||||
drizzle(process.env.REPLICA_DATABASE_URL!, { schema }),
|
||||
drizzle(process.env.REPLICA_DATABASE_URL!, { schema }),
|
||||
])
|
||||
: drizzle(process.env.DATABASE_URL!, { schema });
|
||||
|
||||
@@ -56,7 +56,7 @@ export const sse = sseEndpointMap({
|
||||
},
|
||||
slip_sync: {
|
||||
complete: z.custom<TTrackingKey>(),
|
||||
connected: z.custom<TTrackingKey>()
|
||||
connected: z.custom<TTrackingKey>(),
|
||||
},
|
||||
});
|
||||
export const adminSseList: (keyof typeof sse)[] = ["log"];
|
||||
|
||||
+54
-61
@@ -155,35 +155,32 @@ describe("parseTLV", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test.each([
|
||||
"0",
|
||||
"000",
|
||||
"0001x00",
|
||||
])("rejects an incomplete header in %p", (payload) => {
|
||||
expect(() => parseTLV(payload)).toThrow(
|
||||
/Malformed TLV payload: incomplete headers at index/,
|
||||
);
|
||||
});
|
||||
test.each(["0", "000", "0001x00"])(
|
||||
"rejects an incomplete header in %p",
|
||||
(payload) => {
|
||||
expect(() => parseTLV(payload)).toThrow(
|
||||
/Malformed TLV payload: incomplete headers at index/,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test.each([
|
||||
"AA00",
|
||||
"0A00",
|
||||
" 100",
|
||||
])("rejects invalid tags in %p", (payload) => {
|
||||
expect(() => parseTLV(payload)).toThrow(
|
||||
/Malformed TLV payload: invalid tag/,
|
||||
);
|
||||
});
|
||||
test.each(["AA00", "0A00", " 100"])(
|
||||
"rejects invalid tags in %p",
|
||||
(payload) => {
|
||||
expect(() => parseTLV(payload)).toThrow(
|
||||
/Malformed TLV payload: invalid tag/,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test.each([
|
||||
"00AA",
|
||||
"000A",
|
||||
"00 1",
|
||||
])("rejects invalid lengths in %p", (payload) => {
|
||||
expect(() => parseTLV(payload)).toThrow(
|
||||
/Malformed TLV payload: invalid length/,
|
||||
);
|
||||
});
|
||||
test.each(["00AA", "000A", "00 1"])(
|
||||
"rejects invalid lengths in %p",
|
||||
(payload) => {
|
||||
expect(() => parseTLV(payload)).toThrow(
|
||||
/Malformed TLV payload: invalid length/,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test("rejects a value shorter than its declared length", () => {
|
||||
expect(() => parseTLV("0005abc")).toThrow(
|
||||
@@ -351,11 +348,12 @@ describe("decodeEMVCo", () => {
|
||||
{ type: "primitive", tag: 58, value: "THA" },
|
||||
],
|
||||
},
|
||||
] satisfies { name: string; objects: DataObject[] }[])("rejects $name", ({
|
||||
objects,
|
||||
}) => {
|
||||
expect(() => decodeEMVCo(objects)).toThrow();
|
||||
});
|
||||
] satisfies { name: string; objects: DataObject[] }[])(
|
||||
"rejects $name",
|
||||
({ objects }) => {
|
||||
expect(() => decodeEMVCo(objects)).toThrow();
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("encodeEMVCo", () => {
|
||||
@@ -703,20 +701,19 @@ describe("encodePromptPay", () => {
|
||||
{ type: "mobile", tag: 1, value: "0066812345678" },
|
||||
{ type: "nationalId", tag: 2, value: "1234567890123" },
|
||||
{ type: "ewallet", tag: 3, value: "123456789012345" },
|
||||
] as const)("encodes a canonical $type identifier", ({
|
||||
type,
|
||||
tag,
|
||||
value,
|
||||
}) => {
|
||||
expect(encodePromptPay({ type, value })).toEqual([
|
||||
{
|
||||
type: "primitive",
|
||||
tag: 0,
|
||||
value: "A000000677010111",
|
||||
},
|
||||
{ type: "primitive", tag, value },
|
||||
]);
|
||||
});
|
||||
] as const)(
|
||||
"encodes a canonical $type identifier",
|
||||
({ type, tag, value }) => {
|
||||
expect(encodePromptPay({ type, value })).toEqual([
|
||||
{
|
||||
type: "primitive",
|
||||
tag: 0,
|
||||
value: "A000000677010111",
|
||||
},
|
||||
{ type: "primitive", tag, value },
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
test("rejects noncanonical identifier values", () => {
|
||||
expect(() =>
|
||||
@@ -885,21 +882,17 @@ describe("generatePromptPayPayload", () => {
|
||||
expect(parsed.emvco.merchantCategoryCode).toBe("0000");
|
||||
});
|
||||
|
||||
test.each([
|
||||
0,
|
||||
-1,
|
||||
Number.NaN,
|
||||
Number.POSITIVE_INFINITY,
|
||||
"",
|
||||
"1.234",
|
||||
])("rejects invalid amount %p", (amount) => {
|
||||
expect(() =>
|
||||
generatePromptPayPayload({
|
||||
identifier: { type: "mobile", value: "0801234567" },
|
||||
amount,
|
||||
}),
|
||||
).toThrow();
|
||||
});
|
||||
test.each([0, -1, Number.NaN, Number.POSITIVE_INFINITY, "", "1.234"])(
|
||||
"rejects invalid amount %p",
|
||||
(amount) => {
|
||||
expect(() =>
|
||||
generatePromptPayPayload({
|
||||
identifier: { type: "mobile", value: "0801234567" },
|
||||
amount,
|
||||
}),
|
||||
).toThrow();
|
||||
},
|
||||
);
|
||||
|
||||
test("rejects invalid merchant category codes", () => {
|
||||
expect(() =>
|
||||
|
||||
Reference in New Issue
Block a user