@moneypot/hub 1.20.6 → 1.22.0
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/dist/cli/add-casino.js +1 -1
- package/dist/cli/db-migrate.js +0 -0
- package/dist/dashboard/assets/{index-0G7cFk_0.js → index-n_xD3-qc.js} +48 -48
- package/dist/dashboard/index.html +1 -1
- package/dist/src/audit-log.d.ts +1 -1
- package/dist/src/config.js +2 -3
- package/dist/src/log-serializers.d.ts +4 -0
- package/dist/src/log-serializers.js +118 -0
- package/dist/src/logger.js +4 -0
- package/dist/src/pg-versions/018-scope-chat-owner-reads.sql +49 -0
- package/dist/src/plugins/chat/hub-chat-create-system-message.js +5 -1
- package/dist/src/plugins/chat/hub-chat-mod-management.js +4 -4
- package/dist/src/plugins/graphql-error-log.d.ts +28 -0
- package/dist/src/plugins/graphql-error-log.js +103 -0
- package/dist/src/plugins/hub-add-casino.js +1 -1
- package/dist/src/plugins/hub-adjust-bankroll.d.ts +1 -0
- package/dist/src/plugins/hub-adjust-bankroll.js +106 -0
- package/dist/src/plugins/validate-fields.js +0 -8
- package/dist/src/process-transfers/index.js +0 -44
- package/dist/src/process-transfers/polling-processor.js +45 -21
- package/dist/src/process-transfers/process-transfer.js +0 -4
- package/dist/src/process-transfers/websocket-processor.js +1 -1
- package/dist/src/server/graphile.config.js +4 -0
- package/dist/src/smart-tags.js +7 -7
- package/dist/src/take-request/process-take-request.js +87 -44
- package/package.json +20 -23
|
@@ -123,35 +123,59 @@ export function startPollingProcessor({ casinoId, signal, pool, }) {
|
|
|
123
123
|
logger.info(`[startTransferProcessor] Aborted by graceful shutdown. (3)`);
|
|
124
124
|
break;
|
|
125
125
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
126
|
+
let anyTaskFailed = false;
|
|
127
|
+
try {
|
|
128
|
+
cursor = await processTransfersUntilEmpty({
|
|
129
|
+
afterCursor: cursor,
|
|
130
|
+
graphqlClient,
|
|
131
|
+
casinoInfo: { ...casino, ...casinoSecret },
|
|
132
|
+
signal,
|
|
133
|
+
pool,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
catch (e) {
|
|
137
|
+
anyTaskFailed = true;
|
|
138
|
+
logger.error(e, `transfer polling failed for casino ${casinoId}`);
|
|
139
|
+
}
|
|
133
140
|
if (signal.aborted) {
|
|
134
141
|
logger.info(`[startTransferProcessor] Aborted by graceful shutdown. (4)`);
|
|
135
142
|
break;
|
|
136
143
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
144
|
+
try {
|
|
145
|
+
await processWithdrawals({
|
|
146
|
+
abortSignal: signal,
|
|
147
|
+
casinoId: casino.id,
|
|
148
|
+
graphqlClient,
|
|
149
|
+
pool,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
catch (e) {
|
|
153
|
+
anyTaskFailed = true;
|
|
154
|
+
logger.error(e, `withdrawal processing failed for casino ${casinoId}`);
|
|
155
|
+
}
|
|
143
156
|
if (signal.aborted) {
|
|
144
157
|
logger.info(`[startTransferProcessor] Aborted by graceful shutdown. (5)`);
|
|
145
158
|
break;
|
|
146
159
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
160
|
+
try {
|
|
161
|
+
await processTakeRequests({
|
|
162
|
+
abortSignal: signal,
|
|
163
|
+
controllerId: casinoSecret.controller_id,
|
|
164
|
+
casinoId: casino.id,
|
|
165
|
+
graphqlClient,
|
|
166
|
+
pool,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
anyTaskFailed = true;
|
|
171
|
+
logger.error(e, `take request processing failed for casino ${casinoId}`);
|
|
172
|
+
}
|
|
173
|
+
if (anyTaskFailed) {
|
|
174
|
+
processorState.backoffTime = Math.min(processorState.backoffTime * 2, MAX_BACKOFF_TIME);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
processorState.backoffTime = MIN_BACKOFF_TIME;
|
|
178
|
+
}
|
|
155
179
|
}
|
|
156
180
|
catch (e) {
|
|
157
181
|
processorState.backoffTime = Math.min(processorState.backoffTime * 2, MAX_BACKOFF_TIME);
|
|
@@ -143,10 +143,6 @@ export async function processTransfer({ casinoId, controllerId, transfer, graphq
|
|
|
143
143
|
logger.debug(`I sent ${user.uname} ${transfer.amount} base units of ${currency.id}`);
|
|
144
144
|
switch (transfer.status) {
|
|
145
145
|
case TransferStatusKind.Canceled:
|
|
146
|
-
await db.settleWithdrawal(pool, {
|
|
147
|
-
withdrawalId: transfer.id,
|
|
148
|
-
newStatus: "CANCELED",
|
|
149
|
-
});
|
|
150
146
|
return;
|
|
151
147
|
case TransferStatusKind.Unclaimed:
|
|
152
148
|
throw new Error(`Unexpected UNCLAIMED withdrawal.`);
|
|
@@ -90,7 +90,7 @@ export function startWebsocketProcessor({ casinoId, graphqlUrl, signal, controll
|
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
92
|
assert(mpTransfer.__typename === "ExperienceTransfer", `Expected experience transfer but got ${mpTransfer.__typename}`);
|
|
93
|
-
processTransfer({
|
|
93
|
+
await processTransfer({
|
|
94
94
|
casinoId,
|
|
95
95
|
controllerId,
|
|
96
96
|
transfer: mpTransfer,
|
|
@@ -15,6 +15,8 @@ import { HubUserBalanceByCurrencyPlugin } from "../plugins/hub-user-balance-by-c
|
|
|
15
15
|
import { logger } from "../logger.js";
|
|
16
16
|
import { ValidateCasinoFieldsPlugin } from "../plugins/validate-fields.js";
|
|
17
17
|
import { HubAddCasinoPlugin } from "../plugins/hub-add-casino.js";
|
|
18
|
+
import { HubAdjustBankrollPlugin } from "../plugins/hub-adjust-bankroll.js";
|
|
19
|
+
import { GraphQLErrorLogPlugin } from "../plugins/graphql-error-log.js";
|
|
18
20
|
import { HubBalanceAlertPlugin } from "../plugins/hub-balance-alert.js";
|
|
19
21
|
import { custom as customPgOmitArchivedPlugin } from "@graphile-contrib/pg-omit-archived";
|
|
20
22
|
import { HubCurrentXPlugin } from "../plugins/hub-current-x.js";
|
|
@@ -44,6 +46,8 @@ export const requiredPlugins = [
|
|
|
44
46
|
HubUserBalanceByCurrencyPlugin,
|
|
45
47
|
HubAddCasinoPlugin,
|
|
46
48
|
ValidateCasinoFieldsPlugin,
|
|
49
|
+
HubAdjustBankrollPlugin,
|
|
50
|
+
GraphQLErrorLogPlugin,
|
|
47
51
|
HubOutcomeInputNonNullFieldsPlugin,
|
|
48
52
|
HubBadHashChainErrorPlugin,
|
|
49
53
|
HubCreateHashChainPlugin,
|
package/dist/src/smart-tags.js
CHANGED
|
@@ -23,9 +23,14 @@ export const SmartTagsPlugin = makeJSONPgSmartTagsPlugin({
|
|
|
23
23
|
behavior: ["-orderBy"],
|
|
24
24
|
},
|
|
25
25
|
},
|
|
26
|
-
"hub.
|
|
26
|
+
"hub.user.client_id": {
|
|
27
27
|
tags: {
|
|
28
|
-
behavior: ["
|
|
28
|
+
behavior: ["-select", "-filterBy", "-orderBy"],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
"hub.experience.client_id": {
|
|
32
|
+
tags: {
|
|
33
|
+
behavior: ["-select", "-filterBy", "-orderBy"],
|
|
29
34
|
},
|
|
30
35
|
},
|
|
31
36
|
},
|
|
@@ -35,11 +40,6 @@ export const SmartTagsPlugin = makeJSONPgSmartTagsPlugin({
|
|
|
35
40
|
behavior: ["-resource:select"],
|
|
36
41
|
},
|
|
37
42
|
},
|
|
38
|
-
"hub.bankroll": {
|
|
39
|
-
tags: {
|
|
40
|
-
behavior: ["+resource:update"],
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
43
|
"hub.casino": {
|
|
44
44
|
tags: {
|
|
45
45
|
behavior: [
|
|
@@ -215,8 +215,8 @@ export async function processSingleTakeRequest({ mpTakeRequestId, mpTakeRequest,
|
|
|
215
215
|
const existingRequest = await pgClient
|
|
216
216
|
.query({
|
|
217
217
|
text: `
|
|
218
|
-
SELECT id, mp_take_request_id, status, reserved_amount, user_id, experience_id, currency_key
|
|
219
|
-
FROM hub.take_request
|
|
218
|
+
SELECT id, mp_take_request_id, status, reserved_amount, user_id, experience_id, currency_key, mp_transfer_id
|
|
219
|
+
FROM hub.take_request
|
|
220
220
|
WHERE mp_take_request_id = $1 AND casino_id = $2
|
|
221
221
|
FOR UPDATE
|
|
222
222
|
`,
|
|
@@ -332,6 +332,10 @@ async function processExistingTakeRequest({ pgClient, takeRequest, casinoId, gra
|
|
|
332
332
|
logger.info(`[processExistingTakeRequest] Take request ${takeRequest.id} in PENDING state`);
|
|
333
333
|
break;
|
|
334
334
|
case LocalTakeRequestStatus.PROCESSING: {
|
|
335
|
+
if (takeRequest.mp_transfer_id) {
|
|
336
|
+
logger.info(`[processExistingTakeRequest] Take request ${takeRequest.id} already has transfer ${takeRequest.mp_transfer_id}`);
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
335
339
|
const { dbUser, dbExperience, dbCurrency } = await loadRequiredEntities(pgClient, {
|
|
336
340
|
type: "localId",
|
|
337
341
|
userId: takeRequest.user_id,
|
|
@@ -439,7 +443,6 @@ async function attemptTransfer({ pgClient, takeRequestId, mpTakeRequestId, mpExp
|
|
|
439
443
|
catch (error) {
|
|
440
444
|
logger.error(error, `[attemptTransfer] Error creating transfer`);
|
|
441
445
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
442
|
-
const shouldRetry = error instanceof Error && isNetworkError(error);
|
|
443
446
|
await pgClient.query({
|
|
444
447
|
text: `
|
|
445
448
|
UPDATE hub.take_request
|
|
@@ -450,41 +453,12 @@ async function attemptTransfer({ pgClient, takeRequestId, mpTakeRequestId, mpExp
|
|
|
450
453
|
`,
|
|
451
454
|
values: [takeRequestId, errorMessage.slice(0, 200)],
|
|
452
455
|
});
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
debug = COALESCE(debug, '') || ' | Non-retryable error, refunding'
|
|
460
|
-
WHERE id = $2
|
|
461
|
-
`,
|
|
462
|
-
values: [LocalTakeRequestStatus.FAILED, takeRequestId],
|
|
463
|
-
});
|
|
464
|
-
await refundTakeRequest(pgClient, takeRequestId);
|
|
465
|
-
return null;
|
|
466
|
-
}
|
|
467
|
-
const TRANSFER_RETRY_TIMEOUT_SECONDS = 30;
|
|
468
|
-
const takeRequestAfterAttempt = await pgClient
|
|
469
|
-
.query({
|
|
470
|
-
text: `SELECT transfer_first_failure_at FROM hub.take_request WHERE id = $1`,
|
|
471
|
-
values: [takeRequestId],
|
|
472
|
-
})
|
|
473
|
-
.then(exactlyOneRow);
|
|
474
|
-
const elapsedMs = Date.now() - takeRequestAfterAttempt.transfer_first_failure_at.getTime();
|
|
475
|
-
if (elapsedMs >= TRANSFER_RETRY_TIMEOUT_SECONDS * 1000) {
|
|
476
|
-
logger.error({ takeRequestId, elapsedMs }, `[attemptTransfer] Retry timeout (${TRANSFER_RETRY_TIMEOUT_SECONDS}s) reached, marking as FAILED and refunding`);
|
|
477
|
-
await pgClient.query({
|
|
478
|
-
text: `
|
|
479
|
-
UPDATE hub.take_request
|
|
480
|
-
SET status = $1,
|
|
481
|
-
debug = COALESCE(debug, '') || ' | Transfer retry timeout reached, refunding'
|
|
482
|
-
WHERE id = $2
|
|
483
|
-
`,
|
|
484
|
-
values: [LocalTakeRequestStatus.FAILED, takeRequestId],
|
|
485
|
-
});
|
|
486
|
-
await refundTakeRequest(pgClient, takeRequestId);
|
|
487
|
-
}
|
|
456
|
+
await settleTakeRequestAfterFailedTransfer({
|
|
457
|
+
pgClient,
|
|
458
|
+
graphqlClient,
|
|
459
|
+
takeRequestId,
|
|
460
|
+
mpTakeRequestId,
|
|
461
|
+
});
|
|
488
462
|
return null;
|
|
489
463
|
}
|
|
490
464
|
}
|
|
@@ -633,6 +607,10 @@ export async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTrans
|
|
|
633
607
|
.then(exactlyOneRow);
|
|
634
608
|
if (takeRequestData.refunded_at) {
|
|
635
609
|
logger.warn({ mpTransferId, takeRequestId }, `[completeTransfer] Transfer was already refunded. This should never happen.`);
|
|
610
|
+
await pgClient.query({
|
|
611
|
+
text: `UPDATE hub.take_request SET transfer_needs_completion = FALSE WHERE id = $1`,
|
|
612
|
+
values: [takeRequestId],
|
|
613
|
+
});
|
|
636
614
|
break;
|
|
637
615
|
}
|
|
638
616
|
const dbLockedBalance = await pgClient
|
|
@@ -1094,11 +1072,76 @@ async function refundTakeRequest(pgClient, takeRequestId) {
|
|
|
1094
1072
|
logger.info({ takeRequestId, amount: takeRequestData.reserved_amount }, `[refundTakeRequest] Successfully refunded`);
|
|
1095
1073
|
return true;
|
|
1096
1074
|
}
|
|
1075
|
+
const NETWORK_ERROR_MARKERS = [
|
|
1076
|
+
"ECONNREFUSED",
|
|
1077
|
+
"ECONNRESET",
|
|
1078
|
+
"ETIMEDOUT",
|
|
1079
|
+
"EHOSTUNREACH",
|
|
1080
|
+
"ENETUNREACH",
|
|
1081
|
+
"socket hang up",
|
|
1082
|
+
];
|
|
1097
1083
|
function isNetworkError(e) {
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1084
|
+
for (let cur = e, depth = 0; cur && depth < 5; depth++) {
|
|
1085
|
+
const err = cur;
|
|
1086
|
+
const text = `${String(err.code ?? "")} ${String(err.message ?? "")}`;
|
|
1087
|
+
if (NETWORK_ERROR_MARKERS.some((marker) => text.includes(marker))) {
|
|
1088
|
+
return true;
|
|
1089
|
+
}
|
|
1090
|
+
cur = err.cause;
|
|
1091
|
+
}
|
|
1092
|
+
return false;
|
|
1093
|
+
}
|
|
1094
|
+
async function settleTakeRequestAfterFailedTransfer({ pgClient, graphqlClient, takeRequestId, mpTakeRequestId, }) {
|
|
1095
|
+
let mpTakeRequest = null;
|
|
1096
|
+
try {
|
|
1097
|
+
const rejectResult = await graphqlClient.request(MP_REJECT_TAKE_REQUEST, {
|
|
1098
|
+
mpTakeRequestId,
|
|
1099
|
+
});
|
|
1100
|
+
if (rejectResult.rejectTakeRequest.result.__typename !==
|
|
1101
|
+
"RejectTakeRequestSuccess") {
|
|
1102
|
+
mpTakeRequest = await mpGetTakeRequest(graphqlClient, mpTakeRequestId);
|
|
1103
|
+
if (!mpTakeRequest) {
|
|
1104
|
+
throw new Error(`Take request ${mpTakeRequestId} not found on casino`);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
catch (e) {
|
|
1109
|
+
logger.error({ err: e, takeRequestId, networkError: isNetworkError(e) }, `[settleTakeRequestAfterFailedTransfer] Transfer outcome unknown, keeping the reservation and retrying`);
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
if (mpTakeRequest?.experienceTransfer) {
|
|
1113
|
+
logger.info({ takeRequestId, mpTransferId: mpTakeRequest.experienceTransfer.id }, `[settleTakeRequestAfterFailedTransfer] Casino already made the transfer`);
|
|
1114
|
+
await pgClient.query({
|
|
1115
|
+
text: `
|
|
1116
|
+
UPDATE hub.take_request
|
|
1117
|
+
SET mp_transfer_id = $1,
|
|
1118
|
+
mp_transfer_status = $2,
|
|
1119
|
+
transfer_needs_completion = TRUE,
|
|
1120
|
+
mp_status = $3
|
|
1121
|
+
WHERE id = $4
|
|
1122
|
+
`,
|
|
1123
|
+
values: [
|
|
1124
|
+
mpTakeRequest.experienceTransfer.id,
|
|
1125
|
+
MpTransferStatus.Pending,
|
|
1126
|
+
mpTakeRequest.status,
|
|
1127
|
+
takeRequestId,
|
|
1128
|
+
],
|
|
1129
|
+
});
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
const [status, mpStatus] = mpTakeRequest
|
|
1133
|
+
? [LocalTakeRequestStatus.FAILED, mpTakeRequest.status]
|
|
1134
|
+
: [LocalTakeRequestStatus.REJECTED, MpTakeRequestStatus.ControllerRejected];
|
|
1135
|
+
logger.info({ takeRequestId, mpStatus }, `[settleTakeRequestAfterFailedTransfer] Casino confirmed no transfer, refunding`);
|
|
1136
|
+
await pgClient.query({
|
|
1137
|
+
text: `
|
|
1138
|
+
UPDATE hub.take_request
|
|
1139
|
+
SET status = $1,
|
|
1140
|
+
mp_status = $2,
|
|
1141
|
+
debug = COALESCE(debug, '') || ' | Casino confirmed no transfer, refunding'
|
|
1142
|
+
WHERE id = $3
|
|
1143
|
+
`,
|
|
1144
|
+
values: [status, mpStatus, takeRequestId],
|
|
1145
|
+
});
|
|
1146
|
+
await refundTakeRequest(pgClient, takeRequestId);
|
|
1104
1147
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moneypot/hub",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.0",
|
|
4
4
|
"author": "moneypot.com",
|
|
5
5
|
"homepage": "https://moneypot.com/hub",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"moneypot"
|
|
8
8
|
],
|
|
9
9
|
"description": "Official MoneyPot hub server",
|
|
10
|
-
"packageManager": "pnpm@10.25.0",
|
|
11
10
|
"type": "module",
|
|
12
11
|
"main": "dist/src/index.js",
|
|
13
12
|
"types": "dist/src/index.d.ts",
|
|
@@ -35,25 +34,6 @@
|
|
|
35
34
|
"add-casino": "./dist/cli/add-casino.js",
|
|
36
35
|
"db-migrate": "./dist/cli/db-migrate.js"
|
|
37
36
|
},
|
|
38
|
-
"scripts": {
|
|
39
|
-
"build:hub": "rm -rf dist/src && tsc && cp -R src/pg-versions dist/src/ && ./scripts/strip-sql.sh",
|
|
40
|
-
"build": "pnpm run build:hub && rm -rf dist/dashboard && pnpm run build-dashboard",
|
|
41
|
-
"check": "tsc --noEmit && pnpm run check-dashboard",
|
|
42
|
-
"check-tests": "tsc -p tests/tsconfig.json --noEmit",
|
|
43
|
-
"check-dashboard": "cd ./dashboard && pnpm run check",
|
|
44
|
-
"format": "prettier --write \"**/*.ts\"",
|
|
45
|
-
"lint": "eslint --fix . && pnpm run lint-dashboard",
|
|
46
|
-
"lint-dashboard": "cd ./dashboard && pnpm run lint",
|
|
47
|
-
"prepublishOnly": "pnpm run build",
|
|
48
|
-
"codegen": "npx graphql-codegen",
|
|
49
|
-
"codegen-watch": "graphql-codegen --watch",
|
|
50
|
-
"build-dashboard": "cd ./dashboard && pnpm run build && rm -rf ../dist/dashboard && cp -Rv dist ../dist/dashboard",
|
|
51
|
-
"test:startup": "dropdb --if-exists hub-test && createdb hub-test && SUPERUSER_DATABASE_URL=postgres://localhost:5432/hub-test DATABASE_URL=postgres://localhost:5432/hub-test tsx src/test-startup.ts",
|
|
52
|
-
"test": "vitest run",
|
|
53
|
-
"test:watch": "vitest",
|
|
54
|
-
"test:bail": "pnpm test -- --bail --silent --reporter=basic 2>&1 | head -25",
|
|
55
|
-
"prepare": "husky"
|
|
56
|
-
},
|
|
57
37
|
"dependencies": {
|
|
58
38
|
"@graphile-contrib/pg-omit-archived": "4.0.0-rc.1",
|
|
59
39
|
"@moneypot/hash-herald": "^1.0.0",
|
|
@@ -94,5 +74,22 @@
|
|
|
94
74
|
"peerDependencies": {
|
|
95
75
|
"graphile-config": "^1.0.0-rc.2"
|
|
96
76
|
},
|
|
97
|
-
"license": "UNLICENSED"
|
|
98
|
-
|
|
77
|
+
"license": "UNLICENSED",
|
|
78
|
+
"scripts": {
|
|
79
|
+
"build:hub": "rm -rf dist/src && tsc && cp -R src/pg-versions dist/src/ && ./scripts/strip-sql.sh",
|
|
80
|
+
"build": "pnpm run build:hub && rm -rf dist/dashboard && pnpm run build-dashboard",
|
|
81
|
+
"check": "tsc --noEmit && pnpm run check-dashboard",
|
|
82
|
+
"check-tests": "tsc -p tests/tsconfig.json --noEmit",
|
|
83
|
+
"check-dashboard": "cd ./dashboard && pnpm run check",
|
|
84
|
+
"format": "prettier --write \"**/*.ts\"",
|
|
85
|
+
"lint": "eslint --fix . && pnpm run lint-dashboard",
|
|
86
|
+
"lint-dashboard": "cd ./dashboard && pnpm run lint",
|
|
87
|
+
"codegen": "npx graphql-codegen",
|
|
88
|
+
"codegen-watch": "graphql-codegen --watch",
|
|
89
|
+
"build-dashboard": "cd ./dashboard && pnpm run build && rm -rf ../dist/dashboard && cp -Rv dist ../dist/dashboard",
|
|
90
|
+
"test:startup": "dropdb --if-exists hub-test && createdb hub-test && NODE_ENV=development SUPERUSER_DATABASE_URL=postgres://localhost:5432/hub-test DATABASE_URL=postgres://localhost:5432/hub-test tsx src/test-startup.ts",
|
|
91
|
+
"test": "vitest run",
|
|
92
|
+
"test:watch": "vitest",
|
|
93
|
+
"test:bail": "pnpm test -- --bail --silent --reporter=basic 2>&1 | head -25"
|
|
94
|
+
}
|
|
95
|
+
}
|