@moneypot/hub 1.17.0-dev.1 → 1.17.0-dev.2

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.
Files changed (32) hide show
  1. package/dist/cli/add-casino.js +6 -3
  2. package/dist/dashboard/assets/index-32DtKox_.css +5 -0
  3. package/dist/dashboard/assets/index-B4xPUnuF.js +412 -0
  4. package/dist/dashboard/index.html +2 -2
  5. package/dist/src/__generated__/graphql.d.ts +74 -32
  6. package/dist/src/__generated__/graphql.js +23 -14
  7. package/dist/src/db/index.js +29 -13
  8. package/dist/src/db/transaction.js +1 -1
  9. package/dist/src/hash-chain/db-hash-chain.d.ts +2 -1
  10. package/dist/src/hash-chain/db-hash-chain.js +11 -16
  11. package/dist/src/hash-chain/plugins/hub-reveal-hash-chain.js +9 -10
  12. package/dist/src/hash-chain/reveal-hash-chain.d.ts +3 -3
  13. package/dist/src/hash-chain/reveal-hash-chain.js +28 -5
  14. package/dist/src/plugins/chat/hub-chat-subscription.d.ts +1 -1
  15. package/dist/src/plugins/hub-authenticate.js +5 -5
  16. package/dist/src/plugins/hub-make-outcome-bet.d.ts +4 -44
  17. package/dist/src/plugins/hub-make-outcome-bet.js +2 -1
  18. package/dist/src/plugins/hub-put-alert.js +2 -2
  19. package/dist/src/plugins/listen-with-filter.d.ts +4 -3
  20. package/dist/src/plugins/listen-with-filter.js +65 -8
  21. package/dist/src/plugins/validate-fields.js +25 -33
  22. package/dist/src/process-transfers/index.js +1 -1
  23. package/dist/src/risk-policy.js +1 -1
  24. package/dist/src/services/jwt-service.js +1 -1
  25. package/dist/src/take-request/process-take-request.js +19 -13
  26. package/dist/src/validate-zod.d.ts +3 -0
  27. package/dist/src/validate-zod.js +19 -0
  28. package/package.json +3 -4
  29. package/dist/dashboard/assets/index-D7SlWXgD.js +0 -383
  30. package/dist/dashboard/assets/index-LZVcTrKv.css +0 -5
  31. package/dist/src/validate.d.ts +0 -9
  32. package/dist/src/validate.js +0 -91
@@ -4,12 +4,12 @@ import { assert } from "tsafe";
4
4
  import { GET_USER_FROM_USER_TOKEN } from "../graphql-queries.js";
5
5
  import { exactlyOneRow, maybeOneRow } from "../db/util.js";
6
6
  import { createGraphqlClient } from "../graphql-client.js";
7
- import { constant, context, error, object, sideEffect, } from "postgraphile/grafast";
8
- import { withPgPoolTransaction, } from "../db/index.js";
7
+ import { constant, context, object, sideEffect } from "postgraphile/grafast";
8
+ import { IsolationLevel, withPgPoolTransaction, } from "../db/index.js";
9
9
  import { logger } from "../logger.js";
10
10
  import * as jwtService from "../services/jwt-service.js";
11
11
  import { extractGraphQLErrorInfo, isGraphQLError } from "../GraphQLError.js";
12
- import { z } from "zod";
12
+ import { z } from "zod/v4";
13
13
  import { prettifyError } from "zod/v4";
14
14
  const BaseUrlSchema = z
15
15
  .string()
@@ -64,7 +64,7 @@ export const HubAuthenticatePlugin = extendSchema(() => {
64
64
  }
65
65
  throw e;
66
66
  }
67
- return withPgPoolTransaction(superuserPool, async (pgClient) => {
67
+ return withPgPoolTransaction(superuserPool, IsolationLevel.READ_COMMITTED, async (pgClient) => {
68
68
  const { userToken: jwt, casinoBaseUrl } = input;
69
69
  const casino = await pgClient
70
70
  .query({
@@ -114,7 +114,7 @@ export const HubAuthenticatePlugin = extendSchema(() => {
114
114
  throw new GraphQLError(errorInfo.message);
115
115
  }
116
116
  }
117
- throw error;
117
+ throw e;
118
118
  }
119
119
  const result = res.userFromUserToken;
120
120
  if (!result || !result.user || !result.experience) {
@@ -1,4 +1,4 @@
1
- import * as z from "zod";
1
+ import * as z from "zod/v4";
2
2
  import { DbOutcome } from "../db/index.js";
3
3
  import { Result } from "../util.js";
4
4
  import { RiskPolicy } from "../risk-policy.js";
@@ -7,53 +7,13 @@ declare const InputSchema: z.ZodObject<{
7
7
  clientSeed: z.ZodString;
8
8
  wager: z.ZodNumber;
9
9
  currency: z.ZodString;
10
- outcomes: z.ZodEffects<z.ZodEffects<z.ZodArray<z.ZodObject<{
10
+ outcomes: z.ZodArray<z.ZodObject<{
11
11
  weight: z.ZodNumber;
12
12
  profit: z.ZodNumber;
13
- }, "strict", z.ZodTypeAny, {
14
- profit: number;
15
- weight: number;
16
- }, {
17
- profit: number;
18
- weight: number;
19
- }>, "many">, {
20
- profit: number;
21
- weight: number;
22
- }[], {
23
- profit: number;
24
- weight: number;
25
- }[]>, {
26
- profit: number;
27
- weight: number;
28
- }[], {
29
- profit: number;
30
- weight: number;
31
- }[]>;
13
+ }, z.core.$strict>>;
32
14
  hashChainId: z.ZodString;
33
15
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
34
- }, "strict", z.ZodTypeAny, {
35
- currency: string;
36
- hashChainId: string;
37
- kind: string;
38
- clientSeed: string;
39
- outcomes: {
40
- profit: number;
41
- weight: number;
42
- }[];
43
- wager: number;
44
- metadata?: Record<string, unknown> | undefined;
45
- }, {
46
- currency: string;
47
- hashChainId: string;
48
- kind: string;
49
- clientSeed: string;
50
- outcomes: {
51
- profit: number;
52
- weight: number;
53
- }[];
54
- wager: number;
55
- metadata?: Record<string, unknown> | undefined;
56
- }>;
16
+ }, z.core.$strict>;
57
17
  type Input = z.infer<typeof InputSchema>;
58
18
  type Metadata = NonNullable<Input["metadata"]>;
59
19
  type FinalizeMetadataData = {
@@ -1,6 +1,6 @@
1
1
  import { access, context, object, ObjectStep, sideEffect, } from "postgraphile/grafast";
2
2
  import { gql, extendSchema } from "postgraphile/utils";
3
- import * as z from "zod";
3
+ import * as z from "zod/v4";
4
4
  import { GraphQLError } from "graphql";
5
5
  import { DbHashKind, dbLockHouseBankroll, dbLockPlayerBalance, exactlyOneRow, maybeOneRow, withPgPoolTransaction, } from "../db/index.js";
6
6
  import { assert } from "tsafe";
@@ -199,6 +199,7 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
199
199
  experienceId: session.experience_id,
200
200
  casinoId: session.casino_id,
201
201
  hashChainId: input.hashChainId,
202
+ active: "must-be-active",
202
203
  });
203
204
  if (!dbHashChain || !dbHashChain.active) {
204
205
  return {
@@ -1,9 +1,9 @@
1
1
  import { context, lambda } from "postgraphile/grafast";
2
- import { gql, makeExtendSchemaPlugin } from "postgraphile/utils";
2
+ import { gql, extendSchema } from "postgraphile/utils";
3
3
  import { jsonParse } from "postgraphile/@dataplan/json";
4
4
  import { listenWithFilter } from "./listen-with-filter.js";
5
5
  import { logger } from "../logger.js";
6
- export const HubPutAlertPlugin = makeExtendSchemaPlugin(() => {
6
+ export const HubPutAlertPlugin = extendSchema((_build) => {
7
7
  return {
8
8
  typeDefs: gql `
9
9
  extend type Subscription {
@@ -6,7 +6,7 @@ export declare class ListenWithFilterStep<TTopics extends {
6
6
  }, TTopic extends keyof TTopics, TPayloadStep extends Step, TFilterInput> extends Step<TTopics[TTopic][]> {
7
7
  itemPlan: (itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep;
8
8
  filterFn: (item: unknown, filterInput: TFilterInput) => boolean;
9
- static $$export: {
9
+ static $export: {
10
10
  moduleName: string;
11
11
  exportName: string;
12
12
  };
@@ -14,9 +14,10 @@ export declare class ListenWithFilterStep<TTopics extends {
14
14
  private pubsubDep;
15
15
  private topicDep;
16
16
  private filterInputDep;
17
- constructor(pubsubOrPlan: Step<GrafastSubscriber<TTopics> | null> | GrafastSubscriber<TTopics> | null, topicOrPlan: Step<TTopic> | string, itemPlan: ((itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep) | undefined, filterInputPlan: Step<TFilterInput>, filterFn: (item: unknown, filterInput: TFilterInput) => boolean);
17
+ private initialEventDep;
18
+ constructor(pubsubOrPlan: Step<GrafastSubscriber<TTopics> | null> | GrafastSubscriber<TTopics> | null, topicOrPlan: Step<TTopic> | string, itemPlan: ((itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep) | undefined, filterInputPlan: Step<TFilterInput>, filterFn: (item: unknown, filterInput: TFilterInput) => boolean, $initialEvent?: Step<TTopics[TTopic]>);
18
19
  execute({ indexMap, values, stream, }: ExecutionDetails<readonly [GrafastSubscriber<TTopics>, TTopic]>): GrafastResultStreamList<TTopics[TTopic]>;
19
20
  }
20
21
  export declare function listenWithFilter<TTopics extends {
21
22
  [topic: string]: any;
22
- }, TTopic extends keyof TTopics, TPayloadStep extends Step, TFilterInput>(pubsubOrPlan: Step<GrafastSubscriber<TTopics> | null> | GrafastSubscriber<TTopics> | null, topicOrPlan: Step<TTopic> | string, itemPlan: ((itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep) | undefined, filterInputPlan: Step<TFilterInput>, filterFn: (item: unknown, filterInput: TFilterInput) => boolean): ListenWithFilterStep<TTopics, TTopic, TPayloadStep, TFilterInput>;
23
+ }, TTopic extends keyof TTopics, TPayloadStep extends Step, TFilterInput>(pubsubOrPlan: Step<GrafastSubscriber<TTopics> | null> | GrafastSubscriber<TTopics> | null, topicOrPlan: Step<TTopic> | string, itemPlan: ((itemPlan: __ItemStep<TTopics[TTopic]>) => TPayloadStep) | undefined, filterInputPlan: Step<TFilterInput>, filterFn: (item: unknown, filterInput: TFilterInput) => boolean, $initialEvent?: Step<TTopics[TTopic]>): ListenWithFilterStep<TTopics, TTopic, TPayloadStep, TFilterInput>;
@@ -1,9 +1,9 @@
1
- import { constant, isDev, isExecutableStep, SafeError, } from "postgraphile/grafast";
1
+ import { constant, isDev, isStep, SafeError, } from "postgraphile/grafast";
2
2
  import { Step } from "postgraphile/grafast";
3
3
  export class ListenWithFilterStep extends Step {
4
4
  itemPlan;
5
5
  filterFn;
6
- static $$export = {
6
+ static $export = {
7
7
  moduleName: "grafast",
8
8
  exportName: "ListenWithFilterStep",
9
9
  };
@@ -11,17 +11,21 @@ export class ListenWithFilterStep extends Step {
11
11
  pubsubDep;
12
12
  topicDep;
13
13
  filterInputDep;
14
- constructor(pubsubOrPlan, topicOrPlan, itemPlan = ($item) => $item, filterInputPlan, filterFn) {
14
+ initialEventDep = null;
15
+ constructor(pubsubOrPlan, topicOrPlan, itemPlan = ($item) => $item, filterInputPlan, filterFn, $initialEvent) {
15
16
  super();
16
17
  this.itemPlan = itemPlan;
17
18
  this.filterFn = filterFn;
18
19
  const $topic = typeof topicOrPlan === "string" ? constant(topicOrPlan) : topicOrPlan;
19
- const $pubsub = isExecutableStep(pubsubOrPlan)
20
+ const $pubsub = isStep(pubsubOrPlan)
20
21
  ? pubsubOrPlan
21
22
  : constant(pubsubOrPlan, false);
22
23
  this.pubsubDep = this.addDependency($pubsub);
23
24
  this.topicDep = this.addDependency($topic);
24
25
  this.filterInputDep = this.addDependency(filterInputPlan);
26
+ if ($initialEvent) {
27
+ this.initialEventDep = this.addDependency($initialEvent);
28
+ }
25
29
  }
26
30
  execute({ indexMap, values, stream, }) {
27
31
  if (!stream) {
@@ -30,20 +34,22 @@ export class ListenWithFilterStep extends Step {
30
34
  const pubsubValue = values[this.pubsubDep];
31
35
  const topicValue = values[this.topicDep];
32
36
  const filterInputValue = values[this.filterInputDep];
37
+ const initialEventValue = this.initialEventDep !== null ? values[this.initialEventDep] : null;
33
38
  return indexMap((i) => {
34
39
  const pubsub = pubsubValue.at(i);
35
40
  if (!pubsub) {
36
41
  throw new SafeError("Subscription not supported", isDev
37
42
  ? {
38
- hint: `${this.dependencies[this.pubsubDep]} did not provide a GrafastSubscriber; perhaps you forgot to add the relevant property to context?`,
43
+ hint: `Pubsub did not provide a GrafastSubscriber; perhaps you forgot to add the relevant property to context?`,
39
44
  }
40
45
  : {});
41
46
  }
42
47
  const topic = topicValue.at(i);
43
48
  const filterInput = filterInputValue.at(i);
44
49
  const origStream = pubsub.subscribe(topic);
50
+ const initialEvent = initialEventValue?.at(i);
45
51
  const filterFn = this.filterFn;
46
- return {
52
+ const filteredStream = {
47
53
  [Symbol.asyncIterator]: async function* () {
48
54
  const iterator = await origStream;
49
55
  for await (const item of iterator) {
@@ -53,9 +59,60 @@ export class ListenWithFilterStep extends Step {
53
59
  }
54
60
  },
55
61
  };
62
+ if (initialEvent === undefined) {
63
+ return filteredStream;
64
+ }
65
+ else {
66
+ if (filterFn(initialEvent, filterInput)) {
67
+ return withInitialValue(initialEvent, filteredStream);
68
+ }
69
+ else {
70
+ return filteredStream;
71
+ }
72
+ }
56
73
  });
57
74
  }
58
75
  }
59
- export function listenWithFilter(pubsubOrPlan, topicOrPlan, itemPlan = ($item) => $item, filterInputPlan, filterFn) {
60
- return new ListenWithFilterStep(pubsubOrPlan, topicOrPlan, itemPlan, filterInputPlan, filterFn);
76
+ export function listenWithFilter(pubsubOrPlan, topicOrPlan, itemPlan = ($item) => $item, filterInputPlan, filterFn, $initialEvent) {
77
+ return new ListenWithFilterStep(pubsubOrPlan, topicOrPlan, itemPlan, filterInputPlan, filterFn, $initialEvent);
61
78
  }
79
+ const DONE = Object.freeze({ value: undefined, done: true });
80
+ const withInitialValue = (initialVal, source) => ({
81
+ [Symbol.asyncIterator]() {
82
+ const sourceIterator = source[Symbol.asyncIterator]();
83
+ let first = true;
84
+ let done = null;
85
+ return {
86
+ async next() {
87
+ if (done)
88
+ return done;
89
+ if (first) {
90
+ first = false;
91
+ return { value: initialVal, done: false };
92
+ }
93
+ const res = await sourceIterator.next();
94
+ if (res.done)
95
+ done = res;
96
+ return res;
97
+ },
98
+ async return(value) {
99
+ done ??= { value: value, done: true };
100
+ if (typeof sourceIterator.return === "function") {
101
+ try {
102
+ await sourceIterator.return();
103
+ }
104
+ catch {
105
+ }
106
+ }
107
+ return done;
108
+ },
109
+ async throw(err) {
110
+ done ??= DONE;
111
+ if (typeof sourceIterator.throw === "function") {
112
+ return sourceIterator.throw(err);
113
+ }
114
+ throw err;
115
+ },
116
+ };
117
+ },
118
+ });
@@ -1,15 +1,16 @@
1
1
  import { sideEffect } from "postgraphile/grafast";
2
2
  import { GraphQLError } from "postgraphile/graphql";
3
- import { makeWrapPlansPlugin } from "postgraphile/utils";
4
- import * as v from "../validate.js";
5
- import * as Yup from "yup";
3
+ import { wrapPlans } from "postgraphile/utils";
4
+ import * as v from "../validate-zod.js";
5
+ import z, { prettifyError } from "zod/v4";
6
6
  function validate(value, schema) {
7
7
  try {
8
- schema.validateSync(value, { strict: true, abortEarly: true });
8
+ schema.parse(value);
9
9
  }
10
10
  catch (e) {
11
- if (e instanceof Yup.ValidationError) {
12
- const errorMessage = e.path ? `${e.path}: ${e.errors[0]}` : e.errors[0];
11
+ if (e instanceof z.ZodError) {
12
+ const fieldPath = e.issues.map((issue) => issue.path.join(".")).join(".");
13
+ const errorMessage = `Field "${fieldPath}": ${prettifyError(e)}`;
13
14
  throw new GraphQLError(errorMessage);
14
15
  }
15
16
  else {
@@ -17,45 +18,36 @@ function validate(value, schema) {
17
18
  }
18
19
  }
19
20
  }
20
- const casinoPatchSchema = Yup.object()
21
- .shape({
22
- name: Yup.string().trim().min(1),
23
- graphqlUrl: v.graphqlUrl(),
21
+ const CasinoPatchSchema = z.strictObject({
22
+ name: z.string().trim().min(1).optional(),
23
+ graphqlUrl: v.graphqlUrl().optional(),
24
+ baseUrl: v.baseUrl().optional(),
25
+ });
26
+ const AddCasinoSchema = z.strictObject({
27
+ name: z.string().trim().min(1),
24
28
  baseUrl: v.baseUrl(),
25
- })
26
- .strict()
27
- .noUnknown();
28
- const addCasinoSchema = Yup.object()
29
- .shape({
30
- name: Yup.string().trim().min(1).required(),
31
- baseUrl: v.baseUrl().required(),
32
- graphqlUrl: v.graphqlUrl().required(),
33
- apiKey: v.uuid().required(),
34
- })
35
- .strict()
36
- .noUnknown();
37
- const updateBankrollSchema = Yup.object()
38
- .shape({
39
- amount: Yup.number().integer().min(0).required(),
40
- })
41
- .strict()
42
- .noUnknown();
43
- export const ValidateCasinoFieldsPlugin = makeWrapPlansPlugin({
29
+ graphqlUrl: v.graphqlUrl(),
30
+ apiKey: z.uuid(),
31
+ });
32
+ const UpdateBankrollSchema = z.strictObject({
33
+ amount: z.number().int().min(0),
34
+ });
35
+ export const ValidateCasinoFieldsPlugin = wrapPlans(() => ({
44
36
  Mutation: {
45
37
  updateHubCasinoById: (plan, $source, fieldArgs) => {
46
38
  const $patch = fieldArgs.getRaw(["input", "hubCasinoPatch"]);
47
- sideEffect($patch, (patch) => validate(patch, casinoPatchSchema));
39
+ sideEffect($patch, (patch) => validate(patch, CasinoPatchSchema));
48
40
  return plan();
49
41
  },
50
42
  hubAddCasino: (plan, $source, fieldArgs) => {
51
43
  const $input = fieldArgs.getRaw(["input"]);
52
- sideEffect($input, (input) => validate(input, addCasinoSchema));
44
+ sideEffect($input, (input) => validate(input, AddCasinoSchema));
53
45
  return plan();
54
46
  },
55
47
  updateHubBankrollById: (plan, $source, fieldArgs) => {
56
48
  const $patch = fieldArgs.getRaw(["input", "hubBankrollPatch"]);
57
- sideEffect($patch, (patch) => validate(patch, updateBankrollSchema));
49
+ sideEffect($patch, (patch) => validate(patch, UpdateBankrollSchema));
58
50
  return plan();
59
51
  },
60
52
  },
61
- });
53
+ }));
@@ -6,7 +6,7 @@ import { logger } from "../logger.js";
6
6
  import * as config from "../config.js";
7
7
  import * as db from "../db/index.js";
8
8
  import * as pg from "pg";
9
- import { z } from "zod";
9
+ import { z } from "zod/v4";
10
10
  const activeCasinos = new Set();
11
11
  export async function startCasinoTransferProcessor({ casinoId, signal, pool, }) {
12
12
  if (activeCasinos.has(casinoId)) {
@@ -1,6 +1,6 @@
1
1
  import { formatCurrency } from "./format-currency.js";
2
2
  import { logger } from "./logger.js";
3
- import { z } from "zod";
3
+ import { z } from "zod/v4";
4
4
  const RiskLimitsSchema = z
5
5
  .object({
6
6
  maxWager: z.number().positive().optional(),
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import { z } from "zod/v4";
2
2
  import * as jose from "jose";
3
3
  import { gql } from "../__generated__/gql.js";
4
4
  import { maybeOneRow } from "../db/util.js";
@@ -589,20 +589,18 @@ export async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTrans
589
589
  logger.warn({ mpTransferId, takeRequestId }, `[completeTransfer] Transfer was already refunded. This should never happen.`);
590
590
  break;
591
591
  }
592
- const dbBalanceAfterUpdate = await pgClient
592
+ const dbLockedBalance = await pgClient
593
593
  .query({
594
594
  text: `
595
- UPDATE hub.balance
596
- SET amount = amount + $1
597
- WHERE user_id = $2
598
- AND experience_id = $3
599
- AND casino_id = $4
600
- AND currency_key = $5
601
-
602
- RETURNING id, amount
595
+ SELECT id, amount
596
+ FROM hub.balance
597
+ WHERE user_id = $1
598
+ AND experience_id = $2
599
+ AND casino_id = $3
600
+ AND currency_key = $4
601
+ FOR UPDATE
603
602
  `,
604
603
  values: [
605
- takeRequestData.reserved_amount,
606
604
  takeRequestData.user_id,
607
605
  takeRequestData.experience_id,
608
606
  takeRequestData.casino_id,
@@ -610,10 +608,18 @@ export async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTrans
610
608
  ],
611
609
  })
612
610
  .then(exactlyOneRow);
611
+ await pgClient.query({
612
+ text: `
613
+ UPDATE hub.balance
614
+ SET amount = amount + $1
615
+ WHERE id = $2
616
+ `,
617
+ values: [takeRequestData.reserved_amount, dbLockedBalance.id],
618
+ });
613
619
  await insertAuditLog(pgClient, "player-balance", {
614
- balanceId: dbBalanceAfterUpdate.id,
615
- balanceOld: dbBalanceAfterUpdate.amount - takeRequestData.reserved_amount,
616
- balanceNew: dbBalanceAfterUpdate.amount,
620
+ balanceId: dbLockedBalance.id,
621
+ balanceOld: dbLockedBalance.amount,
622
+ balanceNew: dbLockedBalance.amount + takeRequestData.reserved_amount,
617
623
  balanceDelta: takeRequestData.reserved_amount,
618
624
  action: "hub:take_request:refund",
619
625
  refType: "hub.take_request",
@@ -0,0 +1,3 @@
1
+ import z from "zod/v4";
2
+ export declare const baseUrl: () => z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<URL, string>>, z.ZodTransform<string, URL>>;
3
+ export declare const graphqlUrl: () => z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<URL, string>>, z.ZodTransform<string, URL>>;
@@ -0,0 +1,19 @@
1
+ import z from "zod/v4";
2
+ export const baseUrl = () => z
3
+ .string()
4
+ .trim()
5
+ .min(1, "Base URL is required")
6
+ .refine((val) => URL.canParse(val), "Base URL is not a valid URL")
7
+ .transform((val) => new URL(val))
8
+ .refine((val) => val.protocol === "http:" || val.protocol === "https:", "Base URL must use http or https protocol")
9
+ .refine((val) => val.pathname === "/" && val.search === "" && val.hash === "", "Base URL must have no path, query, nor hash")
10
+ .transform((val) => val.toString().replace(/\/$/, ""));
11
+ export const graphqlUrl = () => z
12
+ .string()
13
+ .trim()
14
+ .min(1, "GraphQL URL is required")
15
+ .refine((val) => URL.canParse(val), "GraphQL URL is not a valid URL")
16
+ .transform((val) => new URL(val))
17
+ .refine((val) => val.protocol === "http:" || val.protocol === "https:", "GraphQL URL must use http or https protocol")
18
+ .refine((val) => val.pathname === "/graphql", "GraphQL URL must have /graphql path")
19
+ .transform((val) => val.toString().replace(/\/$/, ""));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moneypot/hub",
3
- "version": "1.17.0-dev.1",
3
+ "version": "1.17.0-dev.2",
4
4
  "author": "moneypot.com",
5
5
  "homepage": "https://moneypot.com/hub",
6
6
  "keywords": [
@@ -59,10 +59,9 @@
59
59
  "pg": "^8.12.0",
60
60
  "pg-connection-string": "^2.6.4",
61
61
  "pino": "^9.7.0",
62
- "postgraphile": "^5.0.0-beta.48",
62
+ "postgraphile": "^5.0.0-beta.49",
63
63
  "tsafe": "^1.6.6",
64
- "yup": "^1.6.1",
65
- "zod": "^3.23.5"
64
+ "zod": "^4.1.12"
66
65
  },
67
66
  "devDependencies": {
68
67
  "@eslint/js": "^9.8.0",