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