@moneypot/hub 1.15.0 → 1.16.0-dev.3

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 (36) hide show
  1. package/dist/src/__generated__/gql.d.ts +2 -2
  2. package/dist/src/__generated__/gql.js +1 -1
  3. package/dist/src/__generated__/graphql.d.ts +240 -27
  4. package/dist/src/__generated__/graphql.js +30 -1
  5. package/dist/src/db/index.d.ts +1 -0
  6. package/dist/src/db/index.js +10 -2
  7. package/dist/src/db/types.d.ts +24 -0
  8. package/dist/src/express.d.ts +1 -0
  9. package/dist/src/graphql-queries.js +4 -0
  10. package/dist/src/index.d.ts +2 -1
  11. package/dist/src/index.js +2 -1
  12. package/dist/src/pg-advisory-lock.d.ts +5 -0
  13. package/dist/src/pg-advisory-lock.js +5 -0
  14. package/dist/src/pg-versions/013-chat.sql +221 -0
  15. package/dist/src/plugins/chat/hub-chat-after-id-condition.d.ts +1 -0
  16. package/dist/src/plugins/chat/hub-chat-after-id-condition.js +15 -0
  17. package/dist/src/plugins/chat/hub-chat-create-system-message.d.ts +1 -0
  18. package/dist/src/plugins/chat/hub-chat-create-system-message.js +124 -0
  19. package/dist/src/plugins/chat/hub-chat-create-user-message.d.ts +1 -0
  20. package/dist/src/plugins/chat/hub-chat-create-user-message.js +231 -0
  21. package/dist/src/plugins/chat/hub-chat-mute-user.d.ts +1 -0
  22. package/dist/src/plugins/chat/hub-chat-mute-user.js +186 -0
  23. package/dist/src/plugins/chat/hub-chat-subscription.d.ts +14 -0
  24. package/dist/src/plugins/chat/hub-chat-subscription.js +133 -0
  25. package/dist/src/plugins/chat/hub-chat-unmute-user.d.ts +1 -0
  26. package/dist/src/plugins/chat/hub-chat-unmute-user.js +146 -0
  27. package/dist/src/plugins/hub-authenticate.js +40 -18
  28. package/dist/src/plugins/hub-create-playground-session.js +44 -13
  29. package/dist/src/server/graphile.config.d.ts +13 -1
  30. package/dist/src/server/graphile.config.js +38 -12
  31. package/dist/src/server/index.d.ts +3 -1
  32. package/dist/src/server/index.js +3 -1
  33. package/dist/src/server/middleware/authentication.js +1 -0
  34. package/dist/src/util.d.ts +3 -0
  35. package/dist/src/util.js +9 -0
  36. package/package.json +1 -1
@@ -0,0 +1,146 @@
1
+ import { extendSchema, gql } from "postgraphile/utils";
2
+ import { context, inhibitOnNull, sideEffect } from "../../grafast.js";
3
+ import { GraphQLError } from "graphql";
4
+ import z, { object } from "zod/v4";
5
+ import { extractFirstZodErrorMessage } from "../../util.js";
6
+ import { maybeOneRow, withPgPoolTransaction, } from "../../db/index.js";
7
+ import { PgAdvisoryLock } from "../../pg-advisory-lock.js";
8
+ import { logger } from "../../logger.js";
9
+ const InputSchema = z.object({
10
+ userId: z.uuid("Invalid user ID"),
11
+ });
12
+ export const HubChatUnmuteUserPlugin = extendSchema((build) => {
13
+ const chatMuteTable = build.input.pgRegistry.pgResources.hub_chat_mute;
14
+ return {
15
+ typeDefs: gql `
16
+ input HubChatUnmuteUserInput {
17
+ userId: UUID!
18
+ }
19
+
20
+ type HubChatUnmuteUserPayload {
21
+ chatMute: HubChatMute!
22
+ }
23
+
24
+ extend type Mutation {
25
+ hubChatUnmuteUser(
26
+ input: HubChatUnmuteUserInput!
27
+ ): HubChatUnmuteUserPayload
28
+ }
29
+ `,
30
+ objects: {
31
+ Mutation: {
32
+ plans: {
33
+ hubChatUnmuteUser(_, { $input }) {
34
+ const $identity = context().get("identity");
35
+ const $superuserPool = context().get("superuserPool");
36
+ const $muteId = sideEffect([$input, $identity, $superuserPool], async ([rawInput, identity, superuserPool]) => {
37
+ if (identity?.kind !== "user") {
38
+ throw new GraphQLError("Unauthorized");
39
+ }
40
+ let input;
41
+ try {
42
+ input = InputSchema.parse(rawInput);
43
+ }
44
+ catch (e) {
45
+ if (e instanceof z.ZodError) {
46
+ throw new GraphQLError(extractFirstZodErrorMessage(e));
47
+ }
48
+ throw e;
49
+ }
50
+ const currentUserIsChatMod = await superuserPool
51
+ .query({
52
+ text: `
53
+ SELECT id, user_id
54
+ FROM hub.chat_mod
55
+ WHERE casino_id = $1 AND experience_id = $2 AND user_id = $3
56
+ `,
57
+ values: [
58
+ identity.session.casino_id,
59
+ identity.session.experience_id,
60
+ identity.session.user_id,
61
+ ],
62
+ })
63
+ .then(maybeOneRow);
64
+ if (!identity.session.is_experience_owner &&
65
+ !currentUserIsChatMod) {
66
+ throw new GraphQLError("Unauthorized");
67
+ }
68
+ const dbTargetUser = await superuserPool
69
+ .query({
70
+ text: `
71
+ SELECT id
72
+ FROM hub.user
73
+ WHERE casino_id = $1 AND id = $2
74
+ `,
75
+ values: [identity.session.casino_id, input.userId],
76
+ })
77
+ .then(maybeOneRow);
78
+ if (!dbTargetUser) {
79
+ throw new GraphQLError("User not found");
80
+ }
81
+ return withPgPoolTransaction(superuserPool, async (pgClient) => {
82
+ await PgAdvisoryLock.forChatUserAction(pgClient, {
83
+ userId: dbTargetUser.id,
84
+ experienceId: identity.session.experience_id,
85
+ casinoId: identity.session.casino_id,
86
+ });
87
+ const dbActiveMute = await pgClient
88
+ .query({
89
+ text: `
90
+ SELECT id
91
+ FROM hub.active_chat_mute
92
+ WHERE user_id = $1 AND experience_id = $2 AND casino_id = $3
93
+ `,
94
+ values: [
95
+ dbTargetUser.id,
96
+ identity.session.experience_id,
97
+ identity.session.casino_id,
98
+ ],
99
+ })
100
+ .then(maybeOneRow);
101
+ if (!dbActiveMute) {
102
+ throw new GraphQLError("User is not muted");
103
+ }
104
+ await pgClient
105
+ .query({
106
+ text: `
107
+ UPDATE hub.chat_mute
108
+ SET revoked_at = now()
109
+ WHERE user_id = $1
110
+ AND experience_id = $2
111
+ AND casino_id = $3
112
+ AND revoked_at IS NULL
113
+ `,
114
+ values: [
115
+ dbTargetUser.id,
116
+ identity.session.experience_id,
117
+ identity.session.casino_id,
118
+ ],
119
+ })
120
+ .then((res) => {
121
+ if (res.rowCount !== 1) {
122
+ logger.warn("Expected 1 chat_mute row to be revoked when unmuting user, got %s", res.rowCount);
123
+ }
124
+ });
125
+ const notifyPayload = {
126
+ type: "unmute",
127
+ user_id: dbTargetUser.id,
128
+ };
129
+ await pgClient.query({
130
+ text: `
131
+ SELECT pg_notify('hub:chat:${identity.session.experience_id}', $1::text)
132
+ `,
133
+ values: [JSON.stringify(notifyPayload)],
134
+ });
135
+ return dbActiveMute.id;
136
+ });
137
+ });
138
+ return object({
139
+ chatMute: chatMuteTable.get({ id: inhibitOnNull($muteId) }),
140
+ });
141
+ },
142
+ },
143
+ },
144
+ },
145
+ };
146
+ });
@@ -1,5 +1,5 @@
1
1
  import { GraphQLError } from "graphql";
2
- import { gql, makeExtendSchemaPlugin } from "postgraphile/utils";
2
+ import { extendSchema, gql } from "postgraphile/utils";
3
3
  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";
@@ -22,7 +22,7 @@ const InputSchema = z.object({
22
22
  casinoBaseUrl: BaseUrlSchema,
23
23
  userToken: z.string().min(1, "User token required"),
24
24
  });
25
- export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
25
+ export const HubAuthenticatePlugin = extendSchema(() => {
26
26
  return {
27
27
  typeDefs: gql `
28
28
  input HubAuthenticateInput {
@@ -124,34 +124,53 @@ export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
124
124
  assert(mpUserId);
125
125
  const uname = result.user.uname;
126
126
  assert(uname);
127
- const dbUser = await pgClient
127
+ const mpExperience = result.experience;
128
+ assert(mpExperience);
129
+ assert(mpExperience.userByUserId, "Expected mpExperience.userByUserId");
130
+ const userInsertResult = await pgClient
128
131
  .query({
129
132
  text: `
130
- INSERT INTO hub.user(casino_id, mp_user_id, uname)
131
- VALUES($1, $2, $3)
132
- ON CONFLICT (casino_id, mp_user_id) DO UPDATE
133
- SET uname = EXCLUDED.uname
134
- RETURNING id, uname
135
- `,
136
- values: [casino.id, mpUserId, uname],
133
+ WITH user_inserts AS (
134
+ INSERT INTO hub.user(casino_id, mp_user_id, uname)
135
+ VALUES
136
+ ($1, $2, $3),
137
+ ($1, $4, $5)
138
+ ON CONFLICT (casino_id, mp_user_id) DO UPDATE
139
+ SET uname = EXCLUDED.uname
140
+ WHERE hub.user.uname IS DISTINCT FROM EXCLUDED.uname
141
+ RETURNING id, mp_user_id
142
+ )
143
+ SELECT
144
+ MAX(CASE WHEN mp_user_id = $2 THEN id END) as auth_user_id,
145
+ MAX(CASE WHEN mp_user_id = $2 THEN uname END) as auth_user_uname,
146
+ MAX(CASE WHEN mp_user_id = $4 THEN id END) as owner_user_id,
147
+ MAX(CASE WHEN mp_user_id = $4 THEN uname END) as owner_user_uname
148
+ FROM user_inserts
149
+ `,
150
+ values: [
151
+ casino.id,
152
+ mpUserId,
153
+ uname,
154
+ mpExperience.userByUserId.id,
155
+ mpExperience.userByUserId.uname,
156
+ ],
137
157
  })
138
158
  .then(exactlyOneRow);
139
- const userId = dbUser.id;
140
- const mpExperience = result.experience;
141
- assert(mpExperience);
159
+ const userId = userInsertResult.auth_user_id;
142
160
  const dbExperience = await pgClient
143
161
  .query({
144
162
  text: `
145
- INSERT INTO hub.experience(casino_id, mp_experience_id, name)
146
- VALUES($1, $2, $3)
163
+ INSERT INTO hub.experience(casino_id, mp_experience_id, name, user_id)
164
+ VALUES($1, $2, $3, $4)
147
165
  ON CONFLICT (casino_id, mp_experience_id) DO UPDATE
148
166
  SET name = EXCLUDED.name
149
- RETURNING id
167
+ RETURNING id, user_id
150
168
  `,
151
169
  values: [
152
170
  casino.id,
153
171
  mpExperience.id,
154
172
  mpExperience.name,
173
+ userInsertResult.owner_user_id,
155
174
  ],
156
175
  })
157
176
  .then(exactlyOneRow);
@@ -172,7 +191,7 @@ export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
172
191
  .then(exactlyOneRow);
173
192
  const ret = {
174
193
  userId,
175
- uname: dbUser.uname,
194
+ uname: userInsertResult.auth_user_uname,
176
195
  experienceId: dbExperience.id,
177
196
  sessionKey: dbSession.key,
178
197
  };
@@ -185,14 +204,17 @@ export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
185
204
  experience_id: dbExperience.id,
186
205
  session_id: dbSession.id,
187
206
  is_playground: false,
207
+ is_experience_owner: dbExperience.user_id === userId,
188
208
  },
189
209
  };
190
- context.pgSettings = {
210
+ const pgSettings = {
191
211
  "session.user_id": userId,
192
212
  "session.casino_id": casino.id,
193
213
  "session.experience_id": dbExperience.id,
194
214
  "session.session_id": dbSession.id,
215
+ "session.is_experience_owner": dbExperience.user_id === userId ? "1" : undefined,
195
216
  };
217
+ context.pgSettings = pgSettings;
196
218
  return ret;
197
219
  });
198
220
  });
@@ -4,16 +4,18 @@ import { exactlyOneRow, maybeOneRow } from "../db/util.js";
4
4
  import { constant, context, object, sideEffect } from "postgraphile/grafast";
5
5
  import { withPgPoolTransaction, } from "../db/index.js";
6
6
  import { logger } from "../logger.js";
7
- import { z } from "zod";
7
+ import { z } from "zod/v4";
8
8
  import { prettifyError } from "zod/v4";
9
9
  const InputSchema = z.object({
10
- dummy: z.string().optional(),
10
+ experienceClientId: z.uuid().optional(),
11
+ userClientId: z.uuid().optional(),
11
12
  });
12
13
  export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
13
14
  return {
14
15
  typeDefs: gql `
15
16
  input HubCreatePlaygroundSessionInput {
16
- dummy: String
17
+ experienceClientId: UUID
18
+ userClientId: UUID
17
19
  }
18
20
 
19
21
  extend type Mutation {
@@ -31,9 +33,9 @@ export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
31
33
  const $superuserPool = $context.get("superuserPool");
32
34
  const $success = sideEffect([$input, $superuserPool, $context], ([rawInput, superuserPool, context]) => {
33
35
  return withPgPoolTransaction(superuserPool, async (pgClient) => {
34
- let _input;
36
+ let input;
35
37
  try {
36
- _input = InputSchema.parse(rawInput);
38
+ input = InputSchema.parse(rawInput);
37
39
  }
38
40
  catch (e) {
39
41
  if (e instanceof z.ZodError) {
@@ -47,6 +49,7 @@ export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
47
49
  SELECT c.*
48
50
  FROM hub.casino c
49
51
  WHERE c.is_playground = true
52
+ ORDER BY c.id ASC
50
53
  LIMIT 1
51
54
  `,
52
55
  values: [],
@@ -60,28 +63,51 @@ export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
60
63
  const dbUser = await pgClient
61
64
  .query({
62
65
  text: `
63
- INSERT INTO hub.user(casino_id, mp_user_id, uname)
64
- VALUES($1, $2, $3)
65
- RETURNING id, uname, mp_user_id
66
+ with ins as (
67
+ insert into hub.user (casino_id, mp_user_id, uname, client_id)
68
+ values ($1, $2, $3, $4)
69
+ on conflict (casino_id, client_id) where client_id is not null
70
+ do nothing
71
+ returning id, uname, mp_user_id
72
+ )
73
+ select id, uname, mp_user_id from ins
74
+ union all
75
+ select id, uname, mp_user_id
76
+ from hub.user
77
+ where casino_id = $1 and client_id = $4
78
+ limit 1
66
79
  `,
67
80
  values: [
68
81
  dbPlaygroundCasino.id,
69
82
  DUMMY_MP_ID,
70
83
  randomUname,
84
+ input.userClientId ?? null,
71
85
  ],
72
86
  })
73
87
  .then(exactlyOneRow);
74
88
  const dbExperience = await pgClient
75
89
  .query({
76
90
  text: `
77
- INSERT INTO hub.experience(casino_id, mp_experience_id, name)
78
- VALUES($1, $2, $3)
79
- RETURNING id
91
+ with ins as (
92
+ insert into hub.experience (casino_id, mp_experience_id, name, client_id, user_id)
93
+ values ($1, $2, $3, $4, $5)
94
+ on conflict (casino_id, client_id) where client_id is not null
95
+ do nothing
96
+ returning id, user_id
97
+ )
98
+ select id, user_id from ins
99
+ union all
100
+ select id, user_id
101
+ from hub.experience
102
+ where casino_id = $1 and client_id = $4
103
+ limit 1
80
104
  `,
81
105
  values: [
82
106
  dbPlaygroundCasino.id,
83
107
  DUMMY_MP_ID,
84
108
  `Playground Experience ${randomUname}`,
109
+ input.experienceClientId ?? null,
110
+ dbUser.id,
85
111
  ],
86
112
  })
87
113
  .then(exactlyOneRow);
@@ -89,6 +115,8 @@ export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
89
115
  text: `
90
116
  INSERT INTO hub.balance(user_id, experience_id, casino_id, currency_key, amount)
91
117
  VALUES($1, $2, $3, $4, 1000)
118
+ ON CONFLICT (user_id, experience_id, casino_id, currency_key) DO UPDATE
119
+ SET amount = 1000
92
120
  `,
93
121
  values: [
94
122
  dbUser.id,
@@ -101,7 +129,7 @@ export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
101
129
  .query({
102
130
  text: `
103
131
  INSERT INTO hub.session(casino_id, user_id, experience_id, user_token, expired_at)
104
- VALUES($1, $2, $3, $4, now() + interval '1 hour')
132
+ VALUES($1, $2, $3, $4, now() + interval '1 week')
105
133
  RETURNING id, key
106
134
  `,
107
135
  values: [
@@ -127,14 +155,17 @@ export const HubCreatePlaygroundSessionPlugin = extendSchema(() => {
127
155
  experience_id: dbExperience.id,
128
156
  session_id: dbSession.id,
129
157
  is_playground: true,
158
+ is_experience_owner: dbExperience.user_id === dbUser.id,
130
159
  },
131
160
  };
132
- context.pgSettings = {
161
+ const pgSettings = {
133
162
  "session.user_id": dbUser.id,
134
163
  "session.casino_id": dbPlaygroundCasino.id,
135
164
  "session.experience_id": dbExperience.id,
136
165
  "session.session_id": dbSession.id,
166
+ "session.is_experience_owner": dbExperience.user_id === dbUser.id ? "1" : undefined,
137
167
  };
168
+ context.pgSettings = pgSettings;
138
169
  return ret;
139
170
  });
140
171
  });
@@ -8,6 +8,7 @@ export type UserSessionContext = {
8
8
  experience_id: string;
9
9
  session_id: string;
10
10
  is_playground: boolean;
11
+ is_experience_owner: boolean;
11
12
  };
12
13
  export type PluginIdentity = {
13
14
  kind: "user";
@@ -15,12 +16,23 @@ export type PluginIdentity = {
15
16
  } | {
16
17
  kind: "operator";
17
18
  };
19
+ export type OurPgSettings = {
20
+ "session.user_id": string;
21
+ "session.experience_id": string;
22
+ "session.casino_id": string;
23
+ "session.session_id": string;
24
+ "session.is_experience_owner": "1" | undefined;
25
+ } | {
26
+ "operator.api_key": string;
27
+ };
18
28
  export declare const requiredPlugins: readonly GraphileConfig.Plugin[];
19
29
  export declare const defaultPlugins: readonly GraphileConfig.Plugin[];
20
- export declare function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, }: {
30
+ export declare function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, }: {
21
31
  plugins: readonly GraphileConfig.Plugin[];
22
32
  exportSchemaSDLPath?: string;
23
33
  extraPgSchemas: string[];
24
34
  abortSignal: AbortSignal;
25
35
  context: ServerContext;
36
+ enableChat: boolean;
37
+ enablePlayground: boolean;
26
38
  }): GraphileConfig.Preset;
@@ -25,6 +25,13 @@ import { HubOutcomeInputNonNullFieldsPlugin } from "../plugins/hub-outcome-input
25
25
  import { HubPutAlertPlugin } from "../plugins/hub-put-alert.js";
26
26
  import { HubRevealHashChainPlugin } from "../hash-chain/plugins/hub-reveal-hash-chain.js";
27
27
  import { HubPreimageHashFieldPlugin } from "../hash-chain/plugins/hub-preimage-hash-field.js";
28
+ import { HubChatCreateUserMessagePlugin } from "../plugins/chat/hub-chat-create-user-message.js";
29
+ import { HubChatSubscriptionPlugin } from "../plugins/chat/hub-chat-subscription.js";
30
+ import { HubCreatePlaygroundSessionPlugin } from "../plugins/hub-create-playground-session.js";
31
+ import { HubChatUnmuteUserPlugin } from "../plugins/chat/hub-chat-unmute-user.js";
32
+ import { HubChatMuteUserPlugin } from "../plugins/chat/hub-chat-mute-user.js";
33
+ import { HubChatCreateSystemMessagePlugin } from "../plugins/chat/hub-chat-create-system-message.js";
34
+ import { HubChatAfterIdConditionPlugin } from "../plugins/chat/hub-chat-after-id-condition.js";
28
35
  export const requiredPlugins = [
29
36
  SmartTagsPlugin,
30
37
  IdToNodeIdPlugin,
@@ -48,7 +55,7 @@ export const defaultPlugins = [
48
55
  HubPreimageHashFieldPlugin,
49
56
  customPgOmitArchivedPlugin("deleted"),
50
57
  ];
51
- export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, }) {
58
+ export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, }) {
52
59
  if (exportSchemaSDLPath) {
53
60
  if (!exportSchemaSDLPath.startsWith("/")) {
54
61
  throw new Error("exportSchemaSDLPath must be an absolute path");
@@ -65,6 +72,12 @@ export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abo
65
72
  mutablePlugins.unshift(requiredPlugin);
66
73
  }
67
74
  }
75
+ if (enablePlayground) {
76
+ mutablePlugins.push(HubCreatePlaygroundSessionPlugin);
77
+ }
78
+ if (enableChat) {
79
+ mutablePlugins.push(HubChatCreateUserMessagePlugin, HubChatCreateSystemMessagePlugin, HubChatSubscriptionPlugin, HubChatMuteUserPlugin, HubChatUnmuteUserPlugin, HubChatAfterIdConditionPlugin);
80
+ }
68
81
  const preset = {
69
82
  extends: [PostGraphileAmberPreset],
70
83
  disablePlugins: ["NodePlugin"],
@@ -116,19 +129,29 @@ export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abo
116
129
  experience_id: reqIdentity.user.experience_id,
117
130
  session_id: reqIdentity.sessionId,
118
131
  is_playground: reqIdentity.isPlayground,
132
+ is_experience_owner: reqIdentity.isExperienceOwner,
119
133
  },
120
134
  };
121
135
  }
122
136
  const pgSettings = {};
137
+ let ourPgSettings;
123
138
  if (reqIdentity?.kind === "user") {
124
- pgSettings["session.user_id"] = reqIdentity.user.id;
125
- pgSettings["session.experience_id"] = reqIdentity.user.experience_id;
126
- pgSettings["session.casino_id"] = reqIdentity.user.casino_id;
127
- pgSettings["session.session_id"] = reqIdentity.sessionId;
139
+ ourPgSettings = {
140
+ "session.user_id": reqIdentity.user.id,
141
+ "session.experience_id": reqIdentity.user.experience_id,
142
+ "session.casino_id": reqIdentity.user.casino_id,
143
+ "session.session_id": reqIdentity.sessionId,
144
+ "session.is_experience_owner": reqIdentity.isExperienceOwner
145
+ ? "1"
146
+ : undefined,
147
+ };
128
148
  }
129
149
  else if (reqIdentity?.kind === "operator") {
130
- pgSettings["operator.api_key"] = reqIdentity.apiKey;
150
+ ourPgSettings = {
151
+ "operator.api_key": reqIdentity.apiKey,
152
+ };
131
153
  }
154
+ Object.assign(pgSettings, ourPgSettings);
132
155
  return {
133
156
  pgSettings,
134
157
  identity: pluginIdentity,
@@ -165,14 +188,17 @@ async function handleWebsocketContext(context, ws) {
165
188
  experience_id: result.user.experience_id,
166
189
  session_id: result.sessionId,
167
190
  is_playground: result.isPlayground,
191
+ is_experience_owner: result.isExperienceOwner,
192
+ };
193
+ const pgSettings = {
194
+ "session.user_id": result.user.id,
195
+ "session.experience_id": result.user.experience_id,
196
+ "session.casino_id": result.user.casino_id,
197
+ "session.session_id": result.sessionId,
198
+ "session.is_experience_owner": result.isExperienceOwner ? "1" : undefined,
168
199
  };
169
200
  return {
170
- pgSettings: {
171
- "session.user_id": result.user.id,
172
- "session.experience_id": result.user.experience_id,
173
- "session.casino_id": result.user.casino_id,
174
- "session.session_id": result.sessionId,
175
- },
201
+ pgSettings,
176
202
  identity: {
177
203
  kind: "user",
178
204
  session,
@@ -4,7 +4,9 @@ export type HubServer = {
4
4
  listen: () => Promise<void>;
5
5
  shutdown: () => Promise<void>;
6
6
  };
7
- export declare function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, }: Pick<ServerOptions, "plugins" | "exportSchemaSDLPath" | "extraPgSchemas" | "configureApp"> & {
7
+ export declare function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, }: Pick<ServerOptions, "plugins" | "exportSchemaSDLPath" | "extraPgSchemas" | "configureApp"> & {
8
8
  abortSignal: AbortSignal;
9
9
  context: ServerContext;
10
+ enableChat: boolean;
11
+ enablePlayground: boolean;
10
12
  }): HubServer;
@@ -45,7 +45,7 @@ function createExpressServer(context) {
45
45
  });
46
46
  return app;
47
47
  }
48
- export function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, }) {
48
+ export function createHubServer({ configureApp, plugins, exportSchemaSDLPath, extraPgSchemas, abortSignal, context, enableChat, enablePlayground, }) {
49
49
  const expressServer = createExpressServer(context);
50
50
  const preset = createPreset({
51
51
  plugins: plugins ?? defaultPlugins,
@@ -53,6 +53,8 @@ export function createHubServer({ configureApp, plugins, exportSchemaSDLPath, ex
53
53
  extraPgSchemas: extraPgSchemas ?? [],
54
54
  abortSignal,
55
55
  context,
56
+ enableChat,
57
+ enablePlayground,
56
58
  });
57
59
  const pgl = postgraphile.default(preset);
58
60
  const serv = pgl.createServ(grafserv);
@@ -35,6 +35,7 @@ const authentication = (context) => {
35
35
  user: result.user,
36
36
  sessionId: result.sessionId,
37
37
  isPlayground: result.isPlayground,
38
+ isExperienceOwner: result.isExperienceOwner,
38
39
  };
39
40
  }
40
41
  return next();
@@ -1,3 +1,4 @@
1
+ import z from "zod/v4";
1
2
  export declare function isUuid(input: any): boolean;
2
3
  export type Result<V, E> = {
3
4
  ok: true;
@@ -6,3 +7,5 @@ export type Result<V, E> = {
6
7
  ok: false;
7
8
  error: E;
8
9
  };
10
+ export declare function extractFirstZodErrorMessage(e: z.ZodError): string;
11
+ export declare function uuidEqual(a: string, b: string): boolean;
package/dist/src/util.js CHANGED
@@ -2,3 +2,12 @@ const UUID_REGEX = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA
2
2
  export function isUuid(input) {
3
3
  return typeof input === "string" && UUID_REGEX.test(input);
4
4
  }
5
+ export function extractFirstZodErrorMessage(e) {
6
+ return e.issues[0].message;
7
+ }
8
+ export function uuidEqual(a, b) {
9
+ return normalizeUuid(a) === normalizeUuid(b);
10
+ }
11
+ function normalizeUuid(uuid) {
12
+ return uuid.toLowerCase();
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moneypot/hub",
3
- "version": "1.15.0",
3
+ "version": "1.16.0-dev.3",
4
4
  "author": "moneypot.com",
5
5
  "homepage": "https://moneypot.com/hub",
6
6
  "keywords": [