@moneypot/hub 1.9.0-dev.9 → 1.9.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.
@@ -19,7 +19,7 @@ type Documents = {
19
19
  "\n query MpPaginatedPendingTakeRequests($controllerId: UUID!, $after: Cursor) {\n allTakeRequests(\n condition: { controllerId: $controllerId, status: PENDING }\n after: $after\n orderBy: ID_ASC\n ) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n ...MpTakeRequestFields\n }\n }\n }\n }\n": typeof types.MpPaginatedPendingTakeRequestsDocument;
20
20
  "\n mutation MpRejectTakeRequest($mpTakeRequestId: UUID!) {\n rejectTakeRequest(input: { id: $mpTakeRequestId }) {\n result {\n ... on RejectTakeRequestSuccess {\n __typename\n takeRequest {\n id\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n": typeof types.MpRejectTakeRequestDocument;
21
21
  "\n mutation MpTransferTakeRequest(\n $mpTakeRequestId: UUID!\n $mpExperienceId: UUID!\n $mpUserId: UUID!\n $amount: Int!\n $currencyKey: String!\n ) {\n transferCurrencyExperienceToUser(\n input: {\n takeRequestId: $mpTakeRequestId\n experienceId: $mpExperienceId\n userId: $mpUserId\n amount: $amount\n currency: $currencyKey\n }\n ) {\n result {\n ... on TransferSuccess {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TransferMetadataIdExists {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n experienceTransfer {\n id\n status\n }\n }\n }\n }\n }\n }\n": typeof types.MpTransferTakeRequestDocument;
22
- "\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n __typename\n id\n status\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n ... on InvalidTransferStatus {\n __typename\n currentStatus\n message\n transfer {\n __typename\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n }\n }\n": typeof types.CompleteTransfer2Document;
22
+ "\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n __typename\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n id\n status\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n ... on InsufficientBalance {\n message\n }\n ... on InvalidTransferStatus {\n currentStatus\n message\n transfer {\n __typename\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n }\n }\n": typeof types.CompleteTransfer2Document;
23
23
  };
24
24
  declare const documents: Documents;
25
25
  export declare function gql(source: string): unknown;
@@ -41,6 +41,6 @@ export declare function gql(source: "\n query MpGetTakeRequest($id: UUID!) {\n
41
41
  export declare function gql(source: "\n query MpPaginatedPendingTakeRequests($controllerId: UUID!, $after: Cursor) {\n allTakeRequests(\n condition: { controllerId: $controllerId, status: PENDING }\n after: $after\n orderBy: ID_ASC\n ) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n ...MpTakeRequestFields\n }\n }\n }\n }\n"): (typeof documents)["\n query MpPaginatedPendingTakeRequests($controllerId: UUID!, $after: Cursor) {\n allTakeRequests(\n condition: { controllerId: $controllerId, status: PENDING }\n after: $after\n orderBy: ID_ASC\n ) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n ...MpTakeRequestFields\n }\n }\n }\n }\n"];
42
42
  export declare function gql(source: "\n mutation MpRejectTakeRequest($mpTakeRequestId: UUID!) {\n rejectTakeRequest(input: { id: $mpTakeRequestId }) {\n result {\n ... on RejectTakeRequestSuccess {\n __typename\n takeRequest {\n id\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n"): (typeof documents)["\n mutation MpRejectTakeRequest($mpTakeRequestId: UUID!) {\n rejectTakeRequest(input: { id: $mpTakeRequestId }) {\n result {\n ... on RejectTakeRequestSuccess {\n __typename\n takeRequest {\n id\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n"];
43
43
  export declare function gql(source: "\n mutation MpTransferTakeRequest(\n $mpTakeRequestId: UUID!\n $mpExperienceId: UUID!\n $mpUserId: UUID!\n $amount: Int!\n $currencyKey: String!\n ) {\n transferCurrencyExperienceToUser(\n input: {\n takeRequestId: $mpTakeRequestId\n experienceId: $mpExperienceId\n userId: $mpUserId\n amount: $amount\n currency: $currencyKey\n }\n ) {\n result {\n ... on TransferSuccess {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TransferMetadataIdExists {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n experienceTransfer {\n id\n status\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n mutation MpTransferTakeRequest(\n $mpTakeRequestId: UUID!\n $mpExperienceId: UUID!\n $mpUserId: UUID!\n $amount: Int!\n $currencyKey: String!\n ) {\n transferCurrencyExperienceToUser(\n input: {\n takeRequestId: $mpTakeRequestId\n experienceId: $mpExperienceId\n userId: $mpUserId\n amount: $amount\n currency: $currencyKey\n }\n ) {\n result {\n ... on TransferSuccess {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TransferMetadataIdExists {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n experienceTransfer {\n id\n status\n }\n }\n }\n }\n }\n }\n"];
44
- export declare function gql(source: "\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n __typename\n id\n status\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n ... on InvalidTransferStatus {\n __typename\n currentStatus\n message\n transfer {\n __typename\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n __typename\n id\n status\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n ... on InvalidTransferStatus {\n __typename\n currentStatus\n message\n transfer {\n __typename\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n }\n }\n"];
44
+ export declare function gql(source: "\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n __typename\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n id\n status\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n ... on InsufficientBalance {\n message\n }\n ... on InvalidTransferStatus {\n currentStatus\n message\n transfer {\n __typename\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n __typename\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n id\n status\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n ... on InsufficientBalance {\n message\n }\n ... on InvalidTransferStatus {\n currentStatus\n message\n transfer {\n __typename\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n }\n }\n"];
45
45
  export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode<infer TType, any> ? TType : never;
46
46
  export {};
@@ -18,7 +18,7 @@ const documents = {
18
18
  "\n query MpPaginatedPendingTakeRequests($controllerId: UUID!, $after: Cursor) {\n allTakeRequests(\n condition: { controllerId: $controllerId, status: PENDING }\n after: $after\n orderBy: ID_ASC\n ) {\n pageInfo {\n endCursor\n hasNextPage\n }\n edges {\n cursor\n node {\n ...MpTakeRequestFields\n }\n }\n }\n }\n": types.MpPaginatedPendingTakeRequestsDocument,
19
19
  "\n mutation MpRejectTakeRequest($mpTakeRequestId: UUID!) {\n rejectTakeRequest(input: { id: $mpTakeRequestId }) {\n result {\n ... on RejectTakeRequestSuccess {\n __typename\n takeRequest {\n id\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n": types.MpRejectTakeRequestDocument,
20
20
  "\n mutation MpTransferTakeRequest(\n $mpTakeRequestId: UUID!\n $mpExperienceId: UUID!\n $mpUserId: UUID!\n $amount: Int!\n $currencyKey: String!\n ) {\n transferCurrencyExperienceToUser(\n input: {\n takeRequestId: $mpTakeRequestId\n experienceId: $mpExperienceId\n userId: $mpUserId\n amount: $amount\n currency: $currencyKey\n }\n ) {\n result {\n ... on TransferSuccess {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TransferMetadataIdExists {\n __typename\n transfer {\n id\n status\n }\n }\n ... on TakeRequestAlreadyTerminal {\n __typename\n takeRequest {\n id\n status\n experienceTransfer {\n id\n status\n }\n }\n }\n }\n }\n }\n": types.MpTransferTakeRequestDocument,
21
- "\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n __typename\n id\n status\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n ... on InvalidTransferStatus {\n __typename\n currentStatus\n message\n transfer {\n __typename\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n }\n }\n": types.CompleteTransfer2Document,
21
+ "\n mutation CompleteTransfer2($mpTransferId: UUID!) {\n completeTransfer(input: { id: $mpTransferId }) {\n result {\n __typename\n ... on CompleteTransferSuccess {\n __typename\n transfer {\n id\n status\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n ... on InsufficientBalance {\n message\n }\n ... on InvalidTransferStatus {\n currentStatus\n message\n transfer {\n __typename\n ... on ExperienceTransfer {\n id\n takeRequest {\n id\n status\n }\n }\n }\n }\n }\n }\n }\n": types.CompleteTransfer2Document,
22
22
  };
23
23
  export function gql(source) {
24
24
  return documents[source] ?? {};
@@ -336,6 +336,17 @@ export type ChallengeFailed = {
336
336
  __typename?: 'ChallengeFailed';
337
337
  message: Scalars['String']['output'];
338
338
  };
339
+ export type ChangeUserRoleInput = {
340
+ clientMutationId?: InputMaybe<Scalars['String']['input']>;
341
+ role: UserRole;
342
+ userId: Scalars['UUID']['input'];
343
+ };
344
+ export type ChangeUserRolePayload = {
345
+ __typename?: 'ChangeUserRolePayload';
346
+ clientMutationId?: Maybe<Scalars['String']['output']>;
347
+ query?: Maybe<Query>;
348
+ user: User;
349
+ };
339
350
  export type ClaimFaucetInput = {
340
351
  clientMutationId?: InputMaybe<Scalars['String']['input']>;
341
352
  currencyKey: Scalars['String']['input'];
@@ -1281,6 +1292,7 @@ export type Mutation = {
1281
1292
  cancelPendingPayout: CancelPendingPayoutPayload;
1282
1293
  cancelTakeRequest: CancelTakeRequestPayload;
1283
1294
  cancelTransfer?: Maybe<CancelTransferPayload>;
1295
+ changeUserRole?: Maybe<ChangeUserRolePayload>;
1284
1296
  claimFaucet?: Maybe<ClaimFaucetPayload>;
1285
1297
  claimTransfer?: Maybe<ClaimTransferPayload>;
1286
1298
  completeTransfer?: Maybe<CompleteTransferPayload>;
@@ -1337,6 +1349,9 @@ export type MutationCancelTakeRequestArgs = {
1337
1349
  export type MutationCancelTransferArgs = {
1338
1350
  input: CancelTransferInput;
1339
1351
  };
1352
+ export type MutationChangeUserRoleArgs = {
1353
+ input: ChangeUserRoleInput;
1354
+ };
1340
1355
  export type MutationClaimFaucetArgs = {
1341
1356
  input: ClaimFaucetInput;
1342
1357
  };
@@ -1550,6 +1565,7 @@ export declare enum PayoutStatus {
1550
1565
  New = "new",
1551
1566
  Pending = "pending",
1552
1567
  Rejected = "rejected",
1568
+ Scheduled = "scheduled",
1553
1569
  Unconfirmed = "unconfirmed"
1554
1570
  }
1555
1571
  export type PayoutStatusChange = {
@@ -3237,7 +3253,8 @@ export declare enum UserOrderBy {
3237
3253
  export declare enum UserRole {
3238
3254
  Admin = "ADMIN",
3239
3255
  Demo = "DEMO",
3240
- Member = "MEMBER"
3256
+ Member = "MEMBER",
3257
+ Restricted = "RESTRICTED"
3241
3258
  }
3242
3259
  export type UserTransfer = Transfer & {
3243
3260
  __typename?: 'UserTransfer';
@@ -3861,11 +3878,11 @@ export type CompleteTransfer2Mutation = {
3861
3878
  result: {
3862
3879
  __typename: 'CompleteTransferSuccess';
3863
3880
  transfer: {
3864
- __typename: 'ControllerTransfer';
3881
+ __typename?: 'ControllerTransfer';
3865
3882
  id: string;
3866
3883
  status: TransferStatusKind;
3867
3884
  } | {
3868
- __typename: 'ExperienceTransfer';
3885
+ __typename?: 'ExperienceTransfer';
3869
3886
  id: string;
3870
3887
  status: TransferStatusKind;
3871
3888
  takeRequest?: {
@@ -3874,12 +3891,13 @@ export type CompleteTransfer2Mutation = {
3874
3891
  status: TakeRequestStatus;
3875
3892
  } | null;
3876
3893
  } | {
3877
- __typename: 'UserTransfer';
3894
+ __typename?: 'UserTransfer';
3878
3895
  id: string;
3879
3896
  status: TransferStatusKind;
3880
3897
  };
3881
3898
  } | {
3882
- __typename?: 'InsufficientBalance';
3899
+ __typename: 'InsufficientBalance';
3900
+ message: string;
3883
3901
  } | {
3884
3902
  __typename: 'InvalidTransferStatus';
3885
3903
  currentStatus: TransferStatusKind;
@@ -252,6 +252,7 @@ export var PayoutStatus;
252
252
  PayoutStatus["New"] = "new";
253
253
  PayoutStatus["Pending"] = "pending";
254
254
  PayoutStatus["Rejected"] = "rejected";
255
+ PayoutStatus["Scheduled"] = "scheduled";
255
256
  PayoutStatus["Unconfirmed"] = "unconfirmed";
256
257
  })(PayoutStatus || (PayoutStatus = {}));
257
258
  export var PayoutStatusChangeOrderBy;
@@ -471,6 +472,7 @@ export var UserRole;
471
472
  UserRole["Admin"] = "ADMIN";
472
473
  UserRole["Demo"] = "DEMO";
473
474
  UserRole["Member"] = "MEMBER";
475
+ UserRole["Restricted"] = "RESTRICTED";
474
476
  })(UserRole || (UserRole = {}));
475
477
  export var UserTransferOrderBy;
476
478
  (function (UserTransferOrderBy) {
@@ -522,4 +524,4 @@ export const MpGetTakeRequestDocument = { "kind": "Document", "definitions": [{
522
524
  export const MpPaginatedPendingTakeRequestsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "MpPaginatedPendingTakeRequests" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "controllerId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "after" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Cursor" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "allTakeRequests" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "condition" }, "value": { "kind": "ObjectValue", "fields": [{ "kind": "ObjectField", "name": { "kind": "Name", "value": "controllerId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "controllerId" } } }, { "kind": "ObjectField", "name": { "kind": "Name", "value": "status" }, "value": { "kind": "EnumValue", "value": "PENDING" } }] } }, { "kind": "Argument", "name": { "kind": "Name", "value": "after" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "after" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "orderBy" }, "value": { "kind": "EnumValue", "value": "ID_ASC" } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "pageInfo" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "endCursor" } }, { "kind": "Field", "name": { "kind": "Name", "value": "hasNextPage" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "edges" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "cursor" } }, { "kind": "Field", "name": { "kind": "Name", "value": "node" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "MpTakeRequestFields" } }] } }] } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "MpTakeRequestFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "TakeRequest" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "amount" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currencyKey" } }, { "kind": "Field", "name": { "kind": "Name", "value": "userId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "experienceId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "experienceTransfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "amount" } }] } }] } }] };
523
525
  export const MpRejectTakeRequestDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "MpRejectTakeRequest" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTakeRequestId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "rejectTakeRequest" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "input" }, "value": { "kind": "ObjectValue", "fields": [{ "kind": "ObjectField", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTakeRequestId" } } }] } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "result" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "RejectTakeRequestSuccess" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "takeRequest" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }] } }] } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "TakeRequestAlreadyTerminal" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "takeRequest" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }] } }] } }] } }] };
524
526
  export const MpTransferTakeRequestDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "MpTransferTakeRequest" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTakeRequestId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "mpExperienceId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "mpUserId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "amount" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "currencyKey" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "transferCurrencyExperienceToUser" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "input" }, "value": { "kind": "ObjectValue", "fields": [{ "kind": "ObjectField", "name": { "kind": "Name", "value": "takeRequestId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTakeRequestId" } } }, { "kind": "ObjectField", "name": { "kind": "Name", "value": "experienceId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "mpExperienceId" } } }, { "kind": "ObjectField", "name": { "kind": "Name", "value": "userId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "mpUserId" } } }, { "kind": "ObjectField", "name": { "kind": "Name", "value": "amount" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "amount" } } }, { "kind": "ObjectField", "name": { "kind": "Name", "value": "currency" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "currencyKey" } } }] } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "result" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "TransferSuccess" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "transfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "TransferMetadataIdExists" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "transfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "TakeRequestAlreadyTerminal" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "takeRequest" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "experienceTransfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }] } }] } }] } }] } }] };
525
- export const CompleteTransfer2Document = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "CompleteTransfer2" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTransferId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "completeTransfer" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "input" }, "value": { "kind": "ObjectValue", "fields": [{ "kind": "ObjectField", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTransferId" } } }] } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "result" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "CompleteTransferSuccess" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "transfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "ExperienceTransfer" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "takeRequest" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }] } }] } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "InvalidTransferStatus" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currentStatus" } }, { "kind": "Field", "name": { "kind": "Name", "value": "message" } }, { "kind": "Field", "name": { "kind": "Name", "value": "transfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "ExperienceTransfer" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "takeRequest" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }] } }] } }] } }] } }] } }] };
527
+ export const CompleteTransfer2Document = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "CompleteTransfer2" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTransferId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UUID" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "completeTransfer" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "input" }, "value": { "kind": "ObjectValue", "fields": [{ "kind": "ObjectField", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "mpTransferId" } } }] } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "result" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "CompleteTransferSuccess" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "Field", "name": { "kind": "Name", "value": "transfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "ExperienceTransfer" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "takeRequest" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }] } }] } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "InsufficientBalance" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "message" } }] } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "InvalidTransferStatus" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "currentStatus" } }, { "kind": "Field", "name": { "kind": "Name", "value": "message" } }, { "kind": "Field", "name": { "kind": "Name", "value": "transfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "__typename" } }, { "kind": "InlineFragment", "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "ExperienceTransfer" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "takeRequest" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }] } }] } }] } }] } }] } }] };
@@ -112,6 +112,7 @@ export type DbTakeRequest = {
112
112
  mp_transfer_status: DbTransferStatusKind | null;
113
113
  transfer_needs_completion: boolean;
114
114
  transfer_completion_attempted_at: Date | null;
115
+ refunded_at: Date | null;
115
116
  updated_at: Date;
116
117
  };
117
118
  export type DbHashChain = {
@@ -1,5 +1,9 @@
1
1
  import { QueryResult, QueryResultRow } from "pg";
2
2
  import { PgClientResult } from "postgraphile/@dataplan/pg";
3
+ import * as pg from "pg";
4
+ export interface QueryExecutor {
5
+ query<T extends pg.QueryResultRow = any>(queryText: string, values?: any[]): Promise<pg.QueryResult<T>>;
6
+ }
3
7
  type ResultType<T> = PgClientResult<T> | QueryResult<T extends QueryResultRow ? T : never>;
4
8
  export declare function maybeOneRow<T>(result: ResultType<T>): T | undefined;
5
9
  export declare function exactlyOneRow<T>(result: ResultType<T>): T;
@@ -15,7 +15,8 @@ declare global {
15
15
  }
16
16
  }
17
17
  }
18
- export { MakeOutcomeBetPlugin, type OutcomeBetConfigMap, type OutcomeBetConfig, type RiskPolicy, type RiskLimits, } from "./plugins/hub-make-outcome-bet.js";
18
+ export { MakeOutcomeBetPlugin, type OutcomeBetConfigMap, type OutcomeBetConfig, } from "./plugins/hub-make-outcome-bet.js";
19
+ export { validateRisk, type RiskPolicy, type RiskPolicyArgs, type RiskLimits, } from "./risk-policy.js";
19
20
  export type PluginContext = Grafast.Context;
20
21
  export { defaultPlugins, type PluginIdentity, type UserSessionContext, } from "./server/graphile.config.js";
21
22
  export type ServerOptions = {
@@ -25,7 +26,7 @@ export type ServerOptions = {
25
26
  exportSchemaSDLPath?: string;
26
27
  userDatabaseMigrationsPath?: string;
27
28
  };
28
- type ListenInfo = {
29
+ export declare function startAndListen(options: ServerOptions): Promise<{
29
30
  port: number;
30
- };
31
- export declare function startAndListen(options: ServerOptions): Promise<ListenInfo>;
31
+ stop: () => Promise<void>;
32
+ }>;
package/dist/src/index.js CHANGED
@@ -6,6 +6,7 @@ import { initializeTransferProcessors } from "./process-transfers/index.js";
6
6
  import { join } from "path";
7
7
  import { logger } from "./logger.js";
8
8
  export { MakeOutcomeBetPlugin, } from "./plugins/hub-make-outcome-bet.js";
9
+ export { validateRisk, } from "./risk-policy.js";
9
10
  export { defaultPlugins, } from "./server/graphile.config.js";
10
11
  async function initialize(options) {
11
12
  if (options.signal.aborted) {
@@ -45,9 +46,11 @@ async function initialize(options) {
45
46
  logger.info("Initialization aborted by graceful shutdown");
46
47
  return;
47
48
  }
48
- initializeTransferProcessors({
49
- signal: options.signal,
50
- });
49
+ if (process.env.NODE_ENV !== "test") {
50
+ initializeTransferProcessors({
51
+ signal: options.signal,
52
+ });
53
+ }
51
54
  }
52
55
  export async function startAndListen(options) {
53
56
  if (options.plugins && options.plugins.some((p) => typeof p === "function")) {
@@ -74,7 +77,7 @@ export async function startAndListen(options) {
74
77
  extraPgSchemas: options.extraPgSchemas,
75
78
  abortSignal: abortController.signal,
76
79
  });
77
- const gracefulShutdown = async () => {
80
+ const gracefulShutdown = async ({ exit = true } = {}) => {
78
81
  if (isShuttingDown) {
79
82
  logger.warn("Already shutting down.");
80
83
  return;
@@ -86,12 +89,13 @@ export async function startAndListen(options) {
86
89
  logger.info("Closing resources...");
87
90
  hubServer.shutdown();
88
91
  try {
92
+ const closeTasks = [db.notifier.close()];
93
+ if (process.env.NODE_ENV !== "test") {
94
+ closeTasks.push(db.postgraphilePool.end());
95
+ closeTasks.push(db.superuserPool.end());
96
+ }
89
97
  await Promise.race([
90
- Promise.all([
91
- db.notifier.close(),
92
- db.postgraphilePool.end(),
93
- db.superuserPool.end(),
94
- ]),
98
+ Promise.all(closeTasks),
95
99
  new Promise((_, reject) => setTimeout(() => reject(new Error("Database cleanup timeout")), 3000)),
96
100
  ]);
97
101
  logger.info("Cleanup complete.");
@@ -99,13 +103,18 @@ export async function startAndListen(options) {
99
103
  catch (err) {
100
104
  logger.warn(err, "Cleanup error (proceeding anyway)");
101
105
  }
102
- process.exit(0);
106
+ if (exit) {
107
+ process.exit(0);
108
+ }
103
109
  };
104
110
  process.on("SIGINT", gracefulShutdown);
105
111
  process.on("SIGTERM", gracefulShutdown);
106
112
  return hubServer.listen().then(() => {
107
113
  return {
108
114
  port: config.PORT,
115
+ stop: async () => {
116
+ await gracefulShutdown({ exit: false });
117
+ },
109
118
  };
110
119
  });
111
120
  }
@@ -0,0 +1 @@
1
+ alter table hub.take_request add column refunded_at timestamptz
@@ -1,6 +1,7 @@
1
1
  import * as z from "zod";
2
2
  import { DbOutcome } from "../db/index.js";
3
3
  import { Result } from "../util.js";
4
+ import { RiskPolicy } from "../risk-policy.js";
4
5
  declare const InputSchema: z.ZodObject<{
5
6
  kind: z.ZodString;
6
7
  clientSeed: z.ZodString;
@@ -75,16 +76,6 @@ export type OutcomeBetConfig = {
75
76
  export type OutcomeBetConfigMap<BetKind extends string> = {
76
77
  [betKind in BetKind]: OutcomeBetConfig;
77
78
  };
78
- type AtLeastOneKey<T, Keys extends keyof T = keyof T> = Keys extends keyof T ? Required<Pick<T, Keys>> & Partial<Omit<T, Keys>> : never;
79
- export type RiskLimits = AtLeastOneKey<{
80
- maxWager?: number;
81
- maxPayout?: number;
82
- }>;
83
- export type RiskPolicy = (args: {
84
- currency: string;
85
- wager: number;
86
- bankroll: number;
87
- }) => RiskLimits;
88
79
  export declare function MakeOutcomeBetPlugin<BetKind extends string>({ betConfigs }: {
89
80
  betConfigs: OutcomeBetConfigMap<BetKind>;
90
81
  }): GraphileConfig.Plugin;
@@ -8,7 +8,7 @@ import { dbInsertHubHash, dbLockHubHashChain, } from "../hash-chain/db-hash-chai
8
8
  import { getIntermediateHash, getPreimageHash, } from "../hash-chain/get-hash.js";
9
9
  import { makeFinalHash, pickRandomOutcome } from "../hash-chain/util.js";
10
10
  import { logger } from "../logger.js";
11
- import { formatCurrency } from "../format-currency.js";
11
+ import { validateRisk } from "../risk-policy.js";
12
12
  const FLOAT_EPSILON = 1e-10;
13
13
  function sum(ns) {
14
14
  return ns.reduce((a, b) => a + b, 0);
@@ -65,15 +65,6 @@ const BetConfigsSchema = z.record(BetKindSchema, z.object({
65
65
  .function()
66
66
  .optional(),
67
67
  }));
68
- const RiskLimitsSchema = z
69
- .object({
70
- maxWager: z.number().int().positive().optional(),
71
- maxPayout: z.number().int().positive().optional(),
72
- })
73
- .strict()
74
- .refine((v) => v.maxWager !== undefined || v.maxPayout !== undefined, {
75
- message: "Provide at least one of maxWager or maxPayout.",
76
- });
77
68
  export function MakeOutcomeBetPlugin({ betConfigs }) {
78
69
  BetConfigsSchema.parse(betConfigs);
79
70
  const betKinds = Object.keys(betConfigs);
@@ -196,47 +187,19 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
196
187
  throw new GraphQLError("You cannot afford the worst outcome");
197
188
  }
198
189
  const maxProfitMultiplier = Math.max(...input.outcomes.map((o) => o.profit));
199
- const maxPayout = input.wager * maxProfitMultiplier;
200
- if (maxPayout > dbHouseBankroll.amount) {
201
- throw new GraphQLError(`House cannot cover potential payout (${formatCurrency(maxPayout, {
202
- displayUnitName: dbCurrency.display_unit_name,
203
- displayUnitScale: dbCurrency.display_unit_scale,
204
- })}). Bankroll: ${formatCurrency(dbHouseBankroll.amount, {
205
- displayUnitName: dbCurrency.display_unit_name,
206
- displayUnitScale: dbCurrency.display_unit_scale,
207
- })}`);
208
- }
209
- const riskLimitsResult = RiskLimitsSchema.safeParse(betConfig.riskPolicy
210
- ? betConfig.riskPolicy({
211
- currency: input.currency,
212
- wager: input.wager,
213
- bankroll: dbHouseBankroll.amount,
214
- })
215
- : {});
216
- if (!riskLimitsResult.success) {
217
- logger.error(riskLimitsResult.error, "Invalid risk policy");
218
- throw new GraphQLError("Invalid risk policy");
219
- }
220
- const riskLimits = riskLimitsResult.data;
221
- if (riskLimits.maxWager != null &&
222
- input.wager > riskLimits.maxWager) {
223
- throw new GraphQLError(`Wager exceeds limit (${formatCurrency(riskLimits.maxWager, {
224
- displayUnitName: dbCurrency.display_unit_name,
225
- displayUnitScale: dbCurrency.display_unit_scale,
226
- })}). Your wager: ${formatCurrency(input.wager, {
227
- displayUnitName: dbCurrency.display_unit_name,
228
- displayUnitScale: dbCurrency.display_unit_scale,
229
- })}`);
230
- }
231
- if (riskLimits.maxPayout != null &&
232
- maxPayout > riskLimits.maxPayout) {
233
- throw new GraphQLError(`Payout exceeds limit (${formatCurrency(riskLimits.maxPayout, {
234
- displayUnitName: dbCurrency.display_unit_name,
235
- displayUnitScale: dbCurrency.display_unit_scale,
236
- })}). Your payout: ${formatCurrency(maxPayout, {
237
- displayUnitName: dbCurrency.display_unit_name,
238
- displayUnitScale: dbCurrency.display_unit_scale,
239
- })}`);
190
+ const maxPotentialPayout = input.wager * maxProfitMultiplier;
191
+ const riskResult = validateRisk({
192
+ currency: input.currency,
193
+ wager: input.wager,
194
+ bankroll: dbHouseBankroll.amount,
195
+ maxPotentialPayout,
196
+ riskPolicy: betConfig.riskPolicy,
197
+ displayUnitName: dbCurrency.display_unit_name,
198
+ displayUnitScale: dbCurrency.display_unit_scale,
199
+ outcomes: input.outcomes,
200
+ });
201
+ if (!riskResult.ok) {
202
+ throw new GraphQLError(riskResult.error);
240
203
  }
241
204
  const dbHashChain = await dbLockHubHashChain(pgClient, {
242
205
  userId: session.user_id,
@@ -7,6 +7,7 @@ import { TRANSFER_FIELDS } from "./graphql.js";
7
7
  import { logger } from "../logger.js";
8
8
  import { processTransfer } from "./process-transfer.js";
9
9
  import assert from "assert";
10
+ import { superuserPool } from "../db/index.js";
10
11
  import { mpGetTakeRequest, processSingleTakeRequest, } from "../take-request/process-take-request.js";
11
12
  function httpToWs(url) {
12
13
  if (url.protocol === "http:") {
@@ -107,6 +108,7 @@ export function startWebsocketProcessor({ casinoId, graphqlUrl, signal, controll
107
108
  mpTakeRequest,
108
109
  casinoId,
109
110
  graphqlClient,
111
+ pool: superuserPool,
110
112
  });
111
113
  });
112
114
  signal.addEventListener("abort", () => {
@@ -0,0 +1,20 @@
1
+ import { DbOutcome } from "./db/types.js";
2
+ import { Result } from "./util.js";
3
+ export type RiskPolicyArgs = {
4
+ currency: string;
5
+ wager: number;
6
+ bankroll: number;
7
+ maxPotentialPayout: number;
8
+ outcomes: DbOutcome[];
9
+ };
10
+ export type RiskLimits = {
11
+ maxWager?: number;
12
+ maxPayout: number;
13
+ };
14
+ export type RiskPolicy = (args: RiskPolicyArgs) => RiskLimits;
15
+ export declare function validateRisk(options: RiskPolicyArgs & {
16
+ riskPolicy: RiskPolicy;
17
+ } & {
18
+ displayUnitName: string;
19
+ displayUnitScale: number;
20
+ }): Result<void, string>;
@@ -0,0 +1,61 @@
1
+ import { formatCurrency } from "./format-currency.js";
2
+ import { logger } from "./logger.js";
3
+ import { z } from "zod";
4
+ const RiskLimitsSchema = z
5
+ .object({
6
+ maxWager: z.number().positive().optional(),
7
+ maxPayout: z.number().positive(),
8
+ })
9
+ .strict();
10
+ export function validateRisk(options) {
11
+ const { wager, bankroll, maxPotentialPayout, riskPolicy } = options;
12
+ if (maxPotentialPayout > bankroll) {
13
+ return {
14
+ ok: false,
15
+ error: `House cannot cover potential payout (${formatCurrency(maxPotentialPayout, {
16
+ displayUnitName: options.displayUnitName,
17
+ displayUnitScale: options.displayUnitScale,
18
+ })}). Bankroll: ${formatCurrency(bankroll, {
19
+ displayUnitName: options.displayUnitName,
20
+ displayUnitScale: options.displayUnitScale,
21
+ })}`,
22
+ };
23
+ }
24
+ if (!riskPolicy) {
25
+ return { ok: true, value: undefined };
26
+ }
27
+ const limitsResult = RiskLimitsSchema.safeParse(riskPolicy(options));
28
+ if (!limitsResult.success) {
29
+ logger.error(limitsResult, "Invalid risk policy");
30
+ return {
31
+ ok: false,
32
+ error: "Invalid risk policy",
33
+ };
34
+ }
35
+ const limits = limitsResult.data;
36
+ if (limits.maxWager !== undefined && wager > limits.maxWager) {
37
+ return {
38
+ ok: false,
39
+ error: `Wager (${formatCurrency(wager, {
40
+ displayUnitName: options.displayUnitName,
41
+ displayUnitScale: options.displayUnitScale,
42
+ })}) exceeds limit (${formatCurrency(limits.maxWager, {
43
+ displayUnitName: options.displayUnitName,
44
+ displayUnitScale: options.displayUnitScale,
45
+ })})`,
46
+ };
47
+ }
48
+ if (maxPotentialPayout > limits.maxPayout) {
49
+ return {
50
+ ok: false,
51
+ error: `Payout (${formatCurrency(maxPotentialPayout, {
52
+ displayUnitName: options.displayUnitName,
53
+ displayUnitScale: options.displayUnitScale,
54
+ })}) exceeds limit (${formatCurrency(limits.maxPayout, {
55
+ displayUnitName: options.displayUnitName,
56
+ displayUnitScale: options.displayUnitScale,
57
+ })})`,
58
+ };
59
+ }
60
+ return { ok: true, value: undefined };
61
+ }
@@ -56,6 +56,7 @@ export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abo
56
56
  if (!exportSchemaSDLPath.endsWith(".graphql")) {
57
57
  throw new Error("exportSchemaSDLPath must end with .graphql");
58
58
  }
59
+ logger.info(`Will save generated graphql schema to ${exportSchemaSDLPath}`);
59
60
  }
60
61
  const mutablePlugins = [...plugins];
61
62
  for (const requiredPlugin of requiredPlugins) {
@@ -64,7 +65,6 @@ export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abo
64
65
  mutablePlugins.unshift(requiredPlugin);
65
66
  }
66
67
  }
67
- logger.info(`Will save generated graphql schema to ${exportSchemaSDLPath}`);
68
68
  const preset = {
69
69
  extends: [PostGraphileAmberPreset],
70
70
  disablePlugins: ["NodePlugin"],
@@ -1,5 +1,6 @@
1
1
  import { GraphQLClient } from "graphql-request";
2
2
  import { MpTakeRequestFieldsFragment } from "../__generated__/graphql.js";
3
+ import * as pg from "pg";
3
4
  export declare const MP_TAKE_REQUEST_FIELDS: import("@graphql-typed-document-node/core").TypedDocumentNode<MpTakeRequestFieldsFragment, unknown>;
4
5
  export declare function mpGetTakeRequest(graphqlClient: GraphQLClient, id: string): Promise<MpTakeRequestFieldsFragment | null>;
5
6
  export declare function processTakeRequests({ abortSignal, controllerId, casinoId, graphqlClient, }: {
@@ -8,9 +9,18 @@ export declare function processTakeRequests({ abortSignal, controllerId, casinoI
8
9
  casinoId: string;
9
10
  graphqlClient: GraphQLClient;
10
11
  }): Promise<void>;
11
- export declare function processSingleTakeRequest({ mpTakeRequestId, mpTakeRequest, casinoId, graphqlClient, }: {
12
+ export declare function processSingleTakeRequest({ mpTakeRequestId, mpTakeRequest, casinoId, graphqlClient, pool, }: {
12
13
  mpTakeRequestId: string;
13
14
  mpTakeRequest?: MpTakeRequestFieldsFragment;
14
15
  casinoId: string;
15
16
  graphqlClient: GraphQLClient;
17
+ pool: pg.Pool;
16
18
  }): Promise<string | null>;
19
+ export declare function completeTransfer({ mpTakeRequestId, takeRequestId, mpTransferId, graphqlClient, casinoId, pool, }: {
20
+ mpTakeRequestId: string;
21
+ takeRequestId: string;
22
+ mpTransferId: string;
23
+ graphqlClient: GraphQLClient;
24
+ casinoId: string;
25
+ pool: pg.Pool;
26
+ }): Promise<void>;
@@ -124,10 +124,10 @@ const MP_COMPLETE_TRANSFER = gql(`
124
124
  mutation CompleteTransfer2($mpTransferId: UUID!) {
125
125
  completeTransfer(input: { id: $mpTransferId }) {
126
126
  result {
127
+ __typename
127
128
  ... on CompleteTransferSuccess {
128
129
  __typename
129
130
  transfer {
130
- __typename
131
131
  id
132
132
  status
133
133
  ... on ExperienceTransfer {
@@ -139,8 +139,10 @@ const MP_COMPLETE_TRANSFER = gql(`
139
139
  }
140
140
  }
141
141
  }
142
+ ... on InsufficientBalance {
143
+ message
144
+ }
142
145
  ... on InvalidTransferStatus {
143
- __typename
144
146
  currentStatus
145
147
  message
146
148
  transfer {
@@ -180,6 +182,7 @@ export async function processTakeRequests({ abortSignal, controllerId, casinoId,
180
182
  mpTakeRequest: takeRequest,
181
183
  casinoId,
182
184
  graphqlClient,
185
+ pool: superuserPool,
183
186
  });
184
187
  }
185
188
  await processPendingTransferCompletions({
@@ -200,8 +203,8 @@ async function fetchPendingTakeRequests(graphqlClient, controllerId) {
200
203
  return useFragment(MP_TAKE_REQUEST_FIELDS, takeRequest);
201
204
  }) || []);
202
205
  }
203
- export async function processSingleTakeRequest({ mpTakeRequestId, mpTakeRequest, casinoId, graphqlClient, }) {
204
- return withPgPoolTransaction(superuserPool, async (pgClient) => {
206
+ export async function processSingleTakeRequest({ mpTakeRequestId, mpTakeRequest, casinoId, graphqlClient, pool, }) {
207
+ return withPgPoolTransaction(pool, async (pgClient) => {
205
208
  await PgAdvisoryLock.forMpTakeRequestProcessing(pgClient, {
206
209
  mpTakeRequestId,
207
210
  casinoId,
@@ -247,10 +250,7 @@ async function createAndProcessNewTakeRequest({ pgClient, mpTakeRequest, casinoI
247
250
  currencyKey: mpTakeRequest.currencyKey,
248
251
  casinoId,
249
252
  });
250
- if (!dbUser || !dbExperience || !dbCurrency || !dbBalance) {
251
- await rejectMpTakeRequest(pgClient, graphqlClient, mpTakeRequest.id);
252
- return null;
253
- }
253
+ assert(dbUser && dbExperience && dbCurrency && dbBalance, "Required entities not found");
254
254
  const amountToTransfer = Math.floor(typeof mpTakeRequest.amount === "number"
255
255
  ? Math.min(mpTakeRequest.amount, dbBalance.amount)
256
256
  : dbBalance.amount);
@@ -476,15 +476,29 @@ async function processPendingTransferCompletions({ casinoId, graphqlClient, abor
476
476
  mpTransferId: request.mp_transfer_id,
477
477
  graphqlClient,
478
478
  casinoId,
479
+ pool: superuserPool,
479
480
  });
480
481
  }
481
482
  }
482
- async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTransferId, graphqlClient, casinoId, }) {
483
- return withPgPoolTransaction(superuserPool, async (pgClient) => {
483
+ export async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTransferId, graphqlClient, casinoId, pool, }) {
484
+ return withPgPoolTransaction(pool, async (pgClient) => {
484
485
  await PgAdvisoryLock.forMpTakeRequestProcessing(pgClient, {
485
486
  mpTakeRequestId,
486
487
  casinoId,
487
488
  });
489
+ const dbTakeRequest = await pgClient
490
+ .query({
491
+ text: `
492
+ SELECT transfer_needs_completion
493
+ FROM hub.take_request
494
+ WHERE id = $1
495
+ `,
496
+ values: [takeRequestId],
497
+ })
498
+ .then(exactlyOneRow);
499
+ if (!dbTakeRequest.transfer_needs_completion) {
500
+ return;
501
+ }
488
502
  await pgClient.query({
489
503
  text: `
490
504
  UPDATE hub.take_request
@@ -553,26 +567,57 @@ async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTransferId,
553
567
  if (!mpStatus) {
554
568
  throw new Error("No MP status returned from MP API");
555
569
  }
570
+ const takeRequestData = await pgClient
571
+ .query({
572
+ text: `
573
+ SELECT *
574
+ FROM hub.take_request
575
+ WHERE id = $1
576
+ `,
577
+ values: [takeRequestId],
578
+ })
579
+ .then(exactlyOneRow);
580
+ if (takeRequestData.refunded_at) {
581
+ logger.warn({ mpTransferId, takeRequestId }, `[completeTransfer] Transfer was already refunded. This should never happen.`);
582
+ break;
583
+ }
584
+ await pgClient.query({
585
+ text: `
586
+ UPDATE hub.balance
587
+ SET amount = amount + $1
588
+ WHERE user_id = $2
589
+ AND experience_id = $3
590
+ AND casino_id = $4
591
+ AND currency_key = $5
592
+ `,
593
+ values: [
594
+ takeRequestData.reserved_amount,
595
+ takeRequestData.user_id,
596
+ takeRequestData.experience_id,
597
+ takeRequestData.casino_id,
598
+ takeRequestData.currency_key,
599
+ ],
600
+ });
556
601
  await pgClient.query({
557
602
  text: `
558
603
  UPDATE hub.take_request
559
604
  SET
560
605
  transfer_needs_completion = FALSE,
561
606
  mp_transfer_status = $2,
562
- status = $3,
563
- mp_status = $4,
564
- debug = $5
607
+ mp_status = $3,
608
+ debug = $4,
609
+ refunded_at = now(),
610
+ updated_at = now()
565
611
  WHERE id = $1
566
612
  `,
567
613
  values: [
568
614
  takeRequestId,
569
615
  currentStatus,
570
- LocalTakeRequestStatus.FAILED,
571
616
  mpStatus,
572
- `MP transfer was ${currentStatus}`,
617
+ `MP transfer was ${currentStatus}. Refunded ${takeRequestData.reserved_amount} to user`,
573
618
  ],
574
619
  });
575
- logger.info(`[completeTransfer] Transfer ${mpTransferId} has status ${currentStatus}`);
620
+ logger.info(`[completeTransfer] Transfer ${mpTransferId} has status ${currentStatus}. Refunded ${takeRequestData.reserved_amount} base units of ${takeRequestData.currency_key} to hub user.`);
576
621
  }
577
622
  else {
578
623
  logger.info(`[completeTransfer] Transfer ${mpTransferId} has status ${currentStatus}, will retry later`);
@@ -665,6 +710,7 @@ async function processStuckRequests({ casinoId, graphqlClient, abortSignal, }) {
665
710
  mpTakeRequestId: request.mp_take_request_id,
666
711
  casinoId,
667
712
  graphqlClient,
713
+ pool: superuserPool,
668
714
  });
669
715
  }
670
716
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moneypot/hub",
3
- "version": "1.9.0-dev.9",
3
+ "version": "1.9.0",
4
4
  "author": "moneypot.com",
5
5
  "homepage": "https://moneypot.com/hub",
6
6
  "keywords": [