Skip to content

Commit 8ae04bf

Browse files
committed
fix(build): build errors after rebase
- Removed metadata image service, this has been split in the resolver - Updated Order invalidation cron job to use injected marketplace order service - Refactored order invalidation cron job to be singleton usin tsyringe - Updated tests
1 parent 5d25f5c commit 8ae04bf

File tree

6 files changed

+89
-170
lines changed

6 files changed

+89
-170
lines changed

src/cron/OrderInvalidation.ts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import cron from "node-cron";
21
import { OrderValidatorCode } from "@hypercerts-org/marketplace-sdk";
3-
import { SupabaseDataService } from "../services/SupabaseDataService.js";
2+
import { sql } from "kysely";
43
import _ from "lodash";
4+
import cron from "node-cron";
5+
import { inject, singleton } from "tsyringe";
56
import { kyselyData } from "../client/kysely.js";
6-
import { sql } from "kysely";
7+
import { MarketplaceOrdersService } from "../services/database/entities/MarketplaceOrdersEntityService.js";
78

89
/**
910
* These error codes are considered temporary and should be
@@ -14,18 +15,23 @@ export const TEMPORARILY_INVALID_ERROR_CODES = [
1415
OrderValidatorCode.TOO_EARLY_TO_EXECUTE_ORDER,
1516
];
1617

18+
@singleton()
1719
export default class OrderInvalidationCronjob {
18-
private static instance: OrderInvalidationCronjob;
19-
private dataService: SupabaseDataService;
20+
private cronJob: cron.ScheduledTask | null = null;
2021

21-
private constructor() {
22-
this.dataService = new SupabaseDataService();
23-
this.setupCronJob();
24-
}
22+
constructor(
23+
@inject(MarketplaceOrdersService)
24+
private marketplaceOrdersService: MarketplaceOrdersService,
25+
) {}
26+
27+
public start(): void {
28+
if (this.cronJob) {
29+
// Already started
30+
return;
31+
}
2532

26-
private setupCronJob() {
27-
// Run every 30 seconds
28-
cron.schedule("*/30 * * * * *", async () => {
33+
// Schedule the cron job
34+
this.cronJob = cron.schedule("*/30 * * * * *", async () => {
2935
try {
3036
await this.invalidateOrders();
3137
} catch (error) {
@@ -34,9 +40,11 @@ export default class OrderInvalidationCronjob {
3440
});
3541
}
3642

37-
public static start(): void {
38-
if (!OrderInvalidationCronjob.instance) {
39-
OrderInvalidationCronjob.instance = new OrderInvalidationCronjob();
43+
// Stop method is useful for testing or graceful shutdown
44+
public stop(): void {
45+
if (this.cronJob) {
46+
this.cronJob.stop();
47+
this.cronJob = null;
4048
}
4149
}
4250

@@ -64,10 +72,10 @@ export default class OrderInvalidationCronjob {
6472
for (const chainId in ordersByChain) {
6573
const ordersForChain = ordersByChain[chainId];
6674
const tokenIds = _.uniq(ordersForChain.map((order) => order.itemIds[0]));
67-
await this.dataService.validateOrdersByTokenIds({
75+
await this.marketplaceOrdersService.validateOrdersByTokenIds(
6876
tokenIds,
69-
chainId: parseInt(chainId, 10),
70-
});
77+
parseInt(chainId, 10),
78+
);
7179
}
7280
}
7381
}

src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { RegisterRoutes } from "./__generated__/routes/routes.js";
1010
import * as Sentry from "@sentry/node";
1111
import SignatureRequestProcessorCron from "./cron/SignatureRequestProcessing.js";
1212
import OrderInvalidationCronjob from "./cron/OrderInvalidation.js";
13+
import { container } from "tsyringe";
1314

1415
// @ts-expect-error BigInt is not supported by JSON
1516
BigInt.prototype.toJSON = function () {
@@ -47,7 +48,8 @@ Sentry.setupExpressErrorHandler(app);
4748

4849
// Start Safe signature request processing cron job
4950
SignatureRequestProcessorCron.start();
50-
OrderInvalidationCronjob.start();
51+
const cronJob = container.resolve(OrderInvalidationCronjob);
52+
cronJob.start();
5153

5254
app.listen(PORT, () => {
5355
console.log(

src/services/MetadataImageService.ts

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/services/database/entities/MarketplaceOrdersEntityService.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -294,15 +294,22 @@ export class MarketplaceOrdersService {
294294
);
295295
const validationResults = await hec.checkOrdersValidity(matchingOrders);
296296

297-
ordersToUpdate.push(
298-
...validationResults
299-
.filter((x) => !x.valid)
300-
.map(({ validatorCodes, id }) => ({
301-
id,
302-
invalidated: true,
303-
validator_codes: validatorCodes,
304-
})),
305-
);
297+
// filter all orders that have changed validity or validator codes
298+
const _changedOrders = validationResults
299+
.filter((x) => {
300+
const order = matchingOrders.find((y) => y.id === x.id);
301+
return (
302+
order?.invalidated !== x.valid ||
303+
order?.validator_codes !== x.validatorCodes
304+
);
305+
})
306+
.map((x) => ({
307+
id: x.id,
308+
invalidated: x.valid,
309+
validator_codes: x.validatorCodes,
310+
}));
311+
312+
ordersToUpdate.push(..._changedOrders);
306313
}
307314

308315
return await this.updateOrders(ordersToUpdate);

src/services/graphql/resolvers/hyperboardResolver.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import { Args, FieldResolver, Query, Resolver, Root } from "type-graphql";
55
import { DataKyselyService } from "../../../client/kysely.js";
66
import { GetHyperboardsArgs } from "../../../graphql/schemas/args/hyperboardArgs.js";
77
import {
8+
GetHyperboardOwnersResponse,
89
GetHyperboardsResponse,
9-
Hyperboard,
10-
HyperboardOwner,
1110
GetSectionsResponse,
11+
Hyperboard,
1212
} from "../../../graphql/schemas/typeDefs/hyperboardTypeDefs.js";
1313
import GetUsersResponse from "../../../graphql/schemas/typeDefs/userTypeDefs.js";
1414
import { CachingDatabase } from "../../../types/kyselySupabaseCaching.js";
@@ -271,7 +271,7 @@ class HyperboardResolver {
271271
* - Array of owners if found
272272
* - null if an error occurs
273273
*/
274-
@FieldResolver(() => [HyperboardOwner])
274+
@FieldResolver(() => GetHyperboardOwnersResponse)
275275
async owners(@Root() hyperboard: Hyperboard) {
276276
try {
277277
const sections = await this.sections(hyperboard);

test/utils/testUtils.ts

Lines changed: 41 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -628,144 +628,76 @@ export function generateMockOrder(
628628
} as unknown as MarketplaceOrderSelect;
629629
}
630630

631-
export function generateMockHyperboard(
632-
overrides?: Partial<{
633-
id: string;
634-
name: string;
635-
chain_ids: (bigint | number | string)[];
636-
background_image: string;
637-
grayscale_images: boolean;
638-
tile_border_color: string;
639-
admins: { data: ReturnType<typeof generateMockUser>[]; count: number };
640-
sections: {
641-
data: Array<{
642-
label: string;
643-
collection: ReturnType<typeof generateMockCollection>;
644-
entries: {
645-
id: string;
646-
is_blueprint: boolean;
647-
percentage_of_section: number;
648-
display_size: number;
649-
name?: string;
650-
total_units?: bigint | number | string;
651-
owners: {
652-
data: Array<
653-
ReturnType<typeof generateMockUser> & {
654-
percentage: number;
655-
units?: bigint | number | string;
656-
}
657-
>;
658-
count: number;
659-
};
660-
}[];
661-
owners: Array<{
662-
data: Array<
663-
ReturnType<typeof generateMockUser> & { percentage_owned: number }
664-
>;
665-
count: number;
666-
}>;
667-
}>;
668-
count: number;
669-
};
670-
owners: {
671-
data: Array<
672-
ReturnType<typeof generateMockUser> & { percentage_owned: number }
673-
>;
674-
count: number;
675-
};
676-
}>,
677-
) {
631+
export function generateMockHyperboard() {
678632
const mockUser = generateMockUser();
679633
const mockCollection = generateMockCollection();
680634

681-
const defaultHyperboard = {
635+
return {
682636
id: faker.string.uuid(),
683-
name: faker.company.name(),
684-
chain_ids: [generateChainId()],
637+
name: faker.commerce.productName(),
638+
chain_ids: [faker.number.bigInt()],
685639
background_image: faker.image.url(),
686640
grayscale_images: faker.datatype.boolean(),
687641
tile_border_color: faker.color.rgb(),
688642
admins: {
689643
data: [mockUser],
690644
count: 1,
691645
},
692-
sections: [
693-
{
694-
data: [
695-
{
696-
label: faker.commerce.department(),
697-
collection: mockCollection,
698-
entries: [
699-
{
700-
id: faker.string.uuid(),
701-
is_blueprint: faker.datatype.boolean(),
702-
percentage_of_section: faker.number.float({
703-
min: 0,
704-
max: 100,
705-
fractionDigits: 2,
706-
}),
707-
display_size: faker.number.float({
708-
min: 1,
709-
max: 10,
710-
fractionDigits: 2,
711-
}),
712-
name: faker.commerce.productName(),
713-
total_units: faker.number.bigInt({ min: 1000n, max: 1000000n }),
714-
owners: {
715-
data: [
716-
{
717-
...mockUser,
718-
percentage: faker.number.float({
719-
min: 0,
720-
max: 100,
721-
fractionDigits: 2,
722-
}),
723-
units: faker.number.bigInt({ min: 1n, max: 1000n }),
724-
},
725-
],
726-
count: 1,
727-
},
728-
},
729-
],
730-
owners: [
731-
{
646+
sections: {
647+
data: [
648+
{
649+
label: faker.commerce.department(),
650+
collections: [mockCollection],
651+
entries: [
652+
{
653+
id: faker.string.uuid(),
654+
is_blueprint: faker.datatype.boolean(),
655+
percentage_of_section: faker.number.float({
656+
min: 0,
657+
max: 100,
658+
fractionDigits: 2,
659+
}),
660+
display_size: faker.number.float({
661+
min: 1,
662+
max: 10,
663+
fractionDigits: 2,
664+
}),
665+
name: faker.commerce.productName(),
666+
total_units: faker.number.bigInt({ min: 1000n, max: 1000000n }),
667+
owners: {
732668
data: [
733669
{
734670
...mockUser,
735-
percentage_owned: faker.number.float({
671+
percentage: faker.number.float({
736672
min: 0,
737673
max: 100,
738674
fractionDigits: 2,
739675
}),
676+
units: faker.number.bigInt({ min: 1n, max: 1000n }),
740677
},
741678
],
742679
count: 1,
743680
},
681+
},
682+
],
683+
owners: {
684+
data: [
685+
{
686+
...mockUser,
687+
percentage_owned: faker.number.float({
688+
min: 0,
689+
max: 100,
690+
fractionDigits: 2,
691+
}),
692+
},
744693
],
694+
count: 1,
745695
},
746-
],
747-
count: 1,
748-
},
749-
],
750-
owners: {
751-
data: [
752-
{
753-
...mockUser,
754-
percentage_owned: faker.number.float({
755-
min: 0,
756-
max: 100,
757-
fractionDigits: 2,
758-
}),
759696
},
760697
],
761698
count: 1,
762699
},
763700
};
764-
765-
return {
766-
...defaultHyperboard,
767-
...overrides,
768-
};
769701
}
770702

771703
// Check similarity of mock and returned object. The createdAt field is a timestamp and will be different. Its value in seconds should be the same.

0 commit comments

Comments
 (0)