@gbl-uzh/platform 0.4.13 → 0.4.16

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 (99) hide show
  1. package/LICENSE.md +1 -1
  2. package/dist/index.d.ts +7 -1473
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +11 -2012
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/SSELink.d.ts +9 -0
  7. package/dist/lib/SSELink.d.ts.map +1 -0
  8. package/dist/lib/SSELink.js +24 -0
  9. package/dist/lib/SSELink.js.map +1 -0
  10. package/dist/lib/apollo.d.ts +3 -4
  11. package/dist/lib/apollo.d.ts.map +1 -0
  12. package/dist/lib/apollo.js +50 -108
  13. package/dist/lib/apollo.js.map +1 -0
  14. package/dist/lib/constants.d.ts +8 -0
  15. package/dist/lib/constants.d.ts.map +1 -0
  16. package/dist/lib/logger.d.ts +4 -0
  17. package/dist/lib/logger.d.ts.map +1 -0
  18. package/dist/lib/logger.js +11 -0
  19. package/dist/lib/logger.js.map +1 -0
  20. package/dist/lib/pubsub.d.ts +5 -0
  21. package/dist/lib/pubsub.d.ts.map +1 -0
  22. package/dist/lib/pubsub.js +6 -0
  23. package/dist/lib/pubsub.js.map +1 -0
  24. package/dist/lib/util.d.ts +12 -13
  25. package/dist/lib/util.d.ts.map +1 -0
  26. package/dist/lib/util.js +63 -105
  27. package/dist/lib/util.js.map +1 -0
  28. package/dist/nexus.d.ts +11 -42
  29. package/dist/nexus.d.ts.map +1 -0
  30. package/dist/nexus.js +22 -2605
  31. package/dist/nexus.js.map +1 -0
  32. package/dist/ops/FGameData.graphql +1 -0
  33. package/dist/ops/FPeriodData.graphql +1 -0
  34. package/dist/ops/FPlayerData.graphql +0 -4
  35. package/dist/ops/FSegmentData.graphql +1 -0
  36. package/dist/ops/FStoryElementData.graphql +7 -0
  37. package/dist/ops/MActivateNextSegment.graphql +0 -3
  38. package/dist/ops/MAddGamePeriod.graphql +2 -2
  39. package/dist/ops/MUpdatePlayerData.graphql +1 -3
  40. package/dist/ops/QGame.graphql +2 -3
  41. package/dist/ops/QPastResults.graphql +0 -3
  42. package/dist/ops/QResult.graphql +4 -5
  43. package/dist/ops/QSpecificResults.graphql +11 -0
  44. package/dist/ops/QStoryElements.graphql +7 -0
  45. package/dist/schema.prisma +2 -3
  46. package/dist/services/AccountService.d.ts +65 -0
  47. package/dist/services/AccountService.d.ts.map +1 -0
  48. package/dist/services/AccountService.js +70 -0
  49. package/dist/services/AccountService.js.map +1 -0
  50. package/dist/services/EventService.d.ts +13 -0
  51. package/dist/services/EventService.d.ts.map +1 -0
  52. package/dist/services/EventService.js +180 -0
  53. package/dist/services/EventService.js.map +1 -0
  54. package/dist/services/GameService.d.ts +670 -0
  55. package/dist/services/GameService.d.ts.map +1 -0
  56. package/dist/services/GameService.js +1191 -0
  57. package/dist/services/GameService.js.map +1 -0
  58. package/dist/services/PlayService.d.ts +630 -0
  59. package/dist/services/PlayService.d.ts.map +1 -0
  60. package/dist/services/PlayService.js +534 -0
  61. package/dist/services/PlayService.js.map +1 -0
  62. package/dist/tsconfig.tsbuildinfo +1 -0
  63. package/dist/types/Achievement.d.ts +4 -0
  64. package/dist/types/Achievement.d.ts.map +1 -0
  65. package/dist/types/Achievement.js +35 -0
  66. package/dist/types/Achievement.js.map +1 -0
  67. package/dist/types/Game.d.ts +5 -0
  68. package/dist/types/Game.d.ts.map +1 -0
  69. package/dist/types/Game.js +85 -0
  70. package/dist/types/Game.js.map +1 -0
  71. package/dist/types/LearningElement.d.ts +5 -0
  72. package/dist/types/LearningElement.d.ts.map +1 -0
  73. package/dist/types/LearningElement.js +55 -0
  74. package/dist/types/LearningElement.js.map +1 -0
  75. package/dist/types/Mutation.d.ts +10 -0
  76. package/dist/types/Mutation.d.ts.map +1 -0
  77. package/dist/types/Mutation.js +194 -0
  78. package/dist/types/Mutation.js.map +1 -0
  79. package/dist/types/Player.d.ts +9 -0
  80. package/dist/types/Player.d.ts.map +1 -0
  81. package/dist/types/Player.js +139 -0
  82. package/dist/types/Player.js.map +1 -0
  83. package/dist/types/Query.d.ts +3 -0
  84. package/dist/types/Query.d.ts.map +1 -0
  85. package/dist/types/Query.js +91 -0
  86. package/dist/types/Query.js.map +1 -0
  87. package/dist/types/StoryElement.d.ts +3 -0
  88. package/dist/types/StoryElement.d.ts.map +1 -0
  89. package/dist/types/StoryElement.js +27 -0
  90. package/dist/types/StoryElement.js.map +1 -0
  91. package/dist/types/Subscription.d.ts +3 -0
  92. package/dist/types/Subscription.d.ts.map +1 -0
  93. package/dist/types/Subscription.js +35 -0
  94. package/dist/types/Subscription.js.map +1 -0
  95. package/dist/types.d.ts +139 -0
  96. package/dist/types.d.ts.map +1 -0
  97. package/dist/types.js +26 -0
  98. package/dist/types.js.map +1 -0
  99. package/package.json +42 -38
package/dist/nexus.js CHANGED
@@ -1,2608 +1,25 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/nexus.ts
31
- var nexus_exports = {};
32
- __export(nexus_exports, {
33
- DateScalar: () => DateScalar,
34
- Event: () => Event,
35
- Game: () => Game,
36
- GameStatus: () => GameStatus2,
37
- JsonScalar: () => JsonScalar,
38
- LearningAnswerOption: () => LearningAnswerOption,
39
- LearningElement: () => LearningElement,
40
- LearningElementAttempt: () => LearningElementAttempt,
41
- LearningElementState: () => LearningElementState,
42
- Mutation: () => Mutation,
43
- Period: () => Period,
44
- PeriodSegment: () => PeriodSegment,
45
- Player: () => Player,
46
- PlayerAction: () => PlayerAction,
47
- PlayerDecision: () => PlayerDecision,
48
- PlayerDecisionType: () => PlayerDecisionType2,
49
- PlayerLevel: () => PlayerLevel,
50
- PlayerResult: () => PlayerResult,
51
- PlayerResultType: () => PlayerResultType2,
52
- PlayerState: () => PlayerState,
53
- Query: () => Query,
54
- Subscription: () => Subscription,
55
- UserRole: () => UserRole3,
56
- generateBaseMutations: () => generateBaseMutations,
57
- generateBaseQueries: () => generateBaseQueries,
58
- generateBaseSubscriptions: () => generateBaseSubscriptions
59
- });
60
- module.exports = __toCommonJS(nexus_exports);
61
- var DB9 = __toESM(require("@prisma/client"));
62
- var import_graphql_scalars = require("graphql-scalars");
63
- var import_nexus10 = require("nexus");
64
-
65
- // src/types/Game.ts
66
- var DB4 = __toESM(require("@prisma/client"));
67
- var import_nexus5 = require("nexus");
68
-
69
- // src/types/LearningElement.ts
70
- var import_nexus4 = require("nexus");
71
-
72
- // src/types/Player.ts
73
- var DB3 = __toESM(require("@prisma/client"));
74
- var import_nexus3 = require("nexus");
75
-
76
- // src/types/Achievement.ts
77
- var DB = __toESM(require("@prisma/client"));
78
- var import_nexus = require("nexus");
79
- var AchievementFrequency2 = (0, import_nexus.enumType)({
80
- name: "AchievementFrequency",
81
- members: Object.values(DB.AchievementFrequency)
82
- });
83
- var Achievement = (0, import_nexus.objectType)({
84
- name: "Achievement",
85
- definition(t) {
86
- t.nonNull.id("id");
87
- t.nonNull.string("name");
88
- t.nonNull.string("description");
89
- t.string("image");
90
- t.nonNull.field("when", {
91
- type: AchievementFrequency2
92
- });
93
- t.field("reward", {
94
- type: "JSONObject"
95
- });
96
- }
97
- });
98
- var AchievementInstance = (0, import_nexus.objectType)({
99
- name: "AchievementInstance",
100
- definition(t) {
101
- t.nonNull.int("id");
102
- t.nonNull.int("count");
103
- t.nonNull.field("achievement", {
104
- type: Achievement
105
- });
106
- }
107
- });
108
-
109
- // src/types/StoryElement.ts
110
- var DB2 = __toESM(require("@prisma/client"));
111
- var import_nexus2 = require("nexus");
112
- var StoryElementType2 = (0, import_nexus2.enumType)({
113
- name: "StoryElementType",
114
- members: Object.values(DB2.StoryElementType)
115
- });
116
- var StoryElement = (0, import_nexus2.objectType)({
117
- name: "StoryElement",
118
- definition(t) {
119
- t.nonNull.id("id");
120
- t.nonNull.field("type", {
121
- type: StoryElementType2
122
- });
123
- t.nonNull.string("title");
124
- t.string("content");
125
- t.field("contentRole", {
126
- type: "JSONObject"
127
- });
128
- t.field("reward", {
129
- type: "JSONObject"
130
- });
131
- }
132
- });
133
-
134
- // src/types/Player.ts
135
- var PlayerDecisionType2 = (0, import_nexus3.enumType)({
136
- name: "PlayerDecisionType",
137
- members: Object.values(DB3.PlayerDecisionType)
138
- });
139
- var PlayerResultType2 = (0, import_nexus3.enumType)({
140
- name: "PlayerResultType",
141
- members: Object.values(DB3.PlayerResultType)
142
- });
143
- var PlayerLevel = (0, import_nexus3.objectType)({
144
- name: "PlayerLevel",
145
- definition(t) {
146
- t.nonNull.id("id");
147
- t.nonNull.int("index");
148
- t.nonNull.string("description");
149
- t.nonNull.int("requiredXP");
150
- }
151
- });
152
- var PlayerState = (0, import_nexus3.objectType)({
153
- name: "PlayerState",
154
- definition(t) {
155
- t.field("playerResult", {
156
- type: PlayerResult
157
- });
158
- t.field("currentGame", {
159
- type: Game
160
- });
161
- t.list.nonNull.field("previousResults", {
162
- type: PlayerResult
163
- });
164
- t.list.nonNull.field("transactions", {
165
- type: PlayerAction
166
- });
167
- }
168
- });
169
- var Player = (0, import_nexus3.objectType)({
170
- name: "Player",
171
- definition(t) {
172
- t.nonNull.id("id");
173
- t.nonNull.boolean("isReady");
174
- t.nonNull.int("number");
175
- t.nonNull.string("name");
176
- t.nonNull.string("avatar");
177
- t.nonNull.string("location");
178
- t.nonNull.string("color");
179
- t.nonNull.string("token");
180
- t.nonNull.boolean("tutorialCompleted");
181
- t.string("role");
182
- t.nonNull.int("experience");
183
- t.nonNull.int("experienceToNext");
184
- t.nonNull.field("facts", {
185
- type: "JSONObject"
186
- });
187
- t.nonNull.field("level", {
188
- type: PlayerLevel
189
- });
190
- t.nonNull.int("levelIx");
191
- t.nonNull.list.nonNull.string("achievementKeys");
192
- t.nonNull.list.nonNull.string("achievementIds");
193
- t.nonNull.list.nonNull.field("achievements", {
194
- type: AchievementInstance
195
- });
196
- t.nonNull.list.nonNull.field("completedLearningElements", {
197
- type: LearningElement
198
- });
199
- t.nonNull.list.nonNull.string("completedLearningElementIds");
200
- t.nonNull.list.nonNull.field("visitedStoryElements", {
201
- type: StoryElement
202
- });
203
- t.nonNull.list.nonNull.string("visitedStoryElementIds");
204
- }
205
- });
206
- var PlayerResult = (0, import_nexus3.objectType)({
207
- name: "PlayerResult",
208
- definition(t) {
209
- t.nonNull.id("id");
210
- t.field("type", {
211
- type: PlayerResultType2
212
- });
213
- t.field("facts", {
214
- type: "JSONObject"
215
- });
216
- t.nonNull.field("player", {
217
- type: Player
218
- });
219
- t.nonNull.field("period", {
220
- type: Period
221
- });
222
- t.field("segment", {
223
- type: PeriodSegment
224
- });
225
- }
226
- });
227
- var PlayerAction = (0, import_nexus3.objectType)({
228
- name: "PlayerAction",
229
- definition(t) {
230
- t.nonNull.id("id");
231
- t.nonNull.string("type");
232
- t.field("facts", {
233
- type: "JSONObject"
234
- });
235
- t.nonNull.field("player", {
236
- type: Player
237
- });
238
- t.nonNull.field("period", {
239
- type: Period
240
- });
241
- t.nonNull.int("periodIx");
242
- t.field("segment", {
243
- type: PeriodSegment
244
- });
245
- t.int("segmentIx");
246
- }
247
- });
248
- var PlayerDecision = (0, import_nexus3.objectType)({
249
- name: "PlayerDecision",
250
- definition(t) {
251
- t.nonNull.id("id");
252
- t.nonNull.field("player", {
253
- type: Player
254
- });
255
- t.nonNull.field("period", {
256
- type: Period
257
- });
258
- t.nonNull.int("periodIx");
259
- t.nonNull.field("type", {
260
- type: PlayerDecisionType2
261
- });
262
- t.nonNull.field("facts", {
263
- type: "JSONObject"
264
- });
265
- }
266
- });
267
-
268
- // src/types/LearningElement.ts
269
- var LearningAnswerOption = (0, import_nexus4.objectType)({
270
- name: "LearningAnswerOption",
271
- definition(t) {
272
- t.nonNull.id("id");
273
- t.nonNull.string("content");
274
- t.nonNull.boolean("correct");
275
- }
276
- });
277
- var LearningElementState = (0, import_nexus4.objectType)({
278
- name: "LearningElementState",
279
- definition(t) {
280
- t.id("id");
281
- t.field("element", {
282
- type: LearningElement
283
- });
284
- t.string("state");
285
- t.string("solution");
286
- }
287
- });
288
- var LearningElementAttempt = (0, import_nexus4.objectType)({
289
- name: "LearningElementAttempt",
290
- definition(t) {
291
- t.id("id");
292
- t.int("pointsAchieved");
293
- t.int("pointsMax");
294
- t.field("element", {
295
- type: LearningElement
296
- });
297
- t.field("player", {
298
- type: Player
299
- });
300
- }
301
- });
302
- var LearningElement = (0, import_nexus4.objectType)({
303
- name: "LearningElement",
304
- definition(t) {
305
- t.nonNull.id("id");
306
- t.nonNull.string("title");
307
- t.nonNull.string("question");
308
- t.field("reward", {
309
- type: "JSONObject"
310
- });
311
- t.string("motivation");
312
- t.nonNull.list.nonNull.field("options", {
313
- type: LearningAnswerOption
314
- });
315
- t.string("feedback");
316
- }
317
- });
318
-
319
- // src/types/Game.ts
320
- var GameStatus2 = (0, import_nexus5.enumType)({
321
- name: "GameStatus",
322
- members: Object.values(DB4.GameStatus)
323
- });
324
- var Game = (0, import_nexus5.objectType)({
325
- name: "Game",
326
- definition(t) {
327
- t.nonNull.id("id");
328
- t.nonNull.field("status", {
329
- type: GameStatus2
330
- });
331
- t.nonNull.string("name");
332
- t.int("activePeriodIx");
333
- t.field("activePeriod", {
334
- type: Period
335
- });
336
- t.nonNull.list.nonNull.field("players", {
337
- type: Player
338
- });
339
- t.nonNull.list.nonNull.field("periods", {
340
- type: Period
341
- });
342
- }
343
- });
344
- var Period = (0, import_nexus5.objectType)({
345
- name: "Period",
346
- definition(t) {
347
- t.nonNull.id("id");
348
- t.nonNull.int("index");
349
- t.int("activeSegmentIx");
350
- t.field("activeSegment", {
351
- type: PeriodSegment
352
- });
353
- t.nonNull.list.nonNull.field("actions", {
354
- type: PlayerAction
355
- });
356
- t.nonNull.list.nonNull.field("results", {
357
- type: PlayerResult
358
- });
359
- t.nonNull.list.nonNull.field("segments", {
360
- type: PeriodSegment
361
- });
362
- t.nonNull.field("facts", {
363
- type: "JSONObject"
364
- });
365
- }
366
- });
367
- var PeriodSegment = (0, import_nexus5.objectType)({
368
- name: "PeriodSegment",
369
- definition(t) {
370
- t.nonNull.id("id");
371
- t.nonNull.int("index");
372
- t.nonNull.int("periodIx");
373
- t.field("countdownExpiresAt", {
374
- type: "DateTime"
375
- });
376
- t.nonNull.list.nonNull.field("actions", {
377
- type: PlayerAction
378
- });
379
- t.nonNull.list.nonNull.field("results", {
380
- type: PlayerResult
381
- });
382
- t.nonNull.list.nonNull.field("learningElements", {
383
- type: LearningElement
384
- });
385
- t.nonNull.list.nonNull.field("storyElements", {
386
- type: StoryElement
387
- });
388
- t.nonNull.field("facts", {
389
- type: "JSONObject"
390
- });
391
- }
392
- });
393
-
394
- // src/types/Mutation.ts
395
- var DB8 = __toESM(require("@prisma/client"));
396
- var import_nexus6 = require("nexus");
397
-
398
- // src/services/AccountService.ts
399
- var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
400
- var import_node_assert = require("assert");
401
- var import_nookies = require("nookies");
402
- function createLoginToken({
403
- sub,
404
- role,
405
- ...extra
406
- }) {
407
- (0, import_node_assert.strict)(typeof process.env.NEXTAUTH_SECRET === "string");
408
- return import_jsonwebtoken.default.sign({ sub, role, ...extra }, process.env.NEXTAUTH_SECRET, {
409
- expiresIn: "1 week"
410
- });
411
- }
412
- async function loginAsTeam({ token }, ctx) {
413
- const matchingPlayer = await ctx.prisma.player.findUnique({
414
- where: { token },
415
- include: {
416
- level: true,
417
- achievements: {
418
- include: {
419
- achievement: true
420
- }
421
- }
422
- }
423
- });
424
- if (!matchingPlayer) {
425
- throw new Error("INVALID_TOKEN");
426
- }
427
- try {
428
- const jwt = createLoginToken({
429
- gameId: matchingPlayer.gameId,
430
- sub: matchingPlayer.id,
431
- role: "PLAYER" /* PLAYER */,
432
- token: matchingPlayer.token
433
- });
434
- const cookieName = process.env.NODE_ENV === "production" ? "__Secure-next-auth.session-token" : "next-auth.session-token";
435
- (0, import_nookies.setCookie)(ctx, cookieName, jwt, {
436
- path: "/",
437
- maxAge: 60 * 60 * 24 * 7,
438
- httpOnly: process.env.NODE_ENV === "production",
439
- secure: process.env.NODE_ENV === "production"
440
- });
441
- } catch (err) {
442
- console.error(err);
443
- return null;
444
- }
445
- return matchingPlayer;
446
- }
447
- async function logoutAsTeam(ctx) {
448
- if (!ctx.user?.sub)
449
- return false;
450
- const matchingPlayer = await ctx.prisma.player.findUnique({
451
- where: {
452
- id: ctx.user.sub
453
- }
454
- });
455
- if (matchingPlayer) {
456
- const cookieName = process.env.NODE_ENV === "production" ? "__Secure-next-auth.session-token" : "next-auth.session-token";
457
- (0, import_nookies.destroyCookie)(ctx, cookieName);
458
- return true;
459
- }
460
- return false;
461
- }
462
-
463
- // src/services/GameService.ts
464
- var DB6 = __toESM(require("@prisma/client"));
465
- var import_nanoid = require("nanoid");
466
- var import_ramda = require("ramda");
467
- var yup = __toESM(require("yup"));
468
-
469
- // src/lib/logger.ts
470
- var import_winston = __toESM(require("winston"));
471
- var logger = import_winston.default.createLogger({
472
- level: process.env.NODE_ENV === "development" ? "debug" : "info",
473
- format: import_winston.default.format.combine(
474
- import_winston.default.format.timestamp(),
475
- import_winston.default.format.json()
476
- ),
477
- defaultMeta: { service: "@gbl-uzh/platform" },
478
- transports: [new import_winston.default.transports.Console()]
479
- });
480
- var logger_default = logger;
481
-
482
- // src/services/EventService.ts
483
- var DB5 = __toESM(require("@prisma/client"));
484
-
485
- // src/lib/pubsub.ts
486
- var import_graphql_yoga = require("graphql-yoga");
487
- var pubSub = (0, import_graphql_yoga.createPubSub)();
488
-
489
- // src/services/EventService.ts
490
- async function receiveEvents({ events, ctx, prisma }) {
491
- if (!Array.isArray(events))
492
- return;
493
- const definedEvents = await prisma.event.findMany({
494
- include: {
495
- achievements: true
496
- }
497
- });
498
- const definedLevels = await prisma.playerLevel.findMany();
499
- const promises = await Promise.all(
500
- events.map(
501
- async (event) => receiveEvent({ ...event, ctx }, definedEvents, definedLevels, prisma)
502
- )
503
- );
504
- const results = prisma.$transaction(promises.flat());
505
- return results;
506
- }
507
- function prepareAchievementData({
508
- achievementId,
509
- gameId,
510
- periodIx,
511
- playerId,
512
- count
513
- }) {
514
- return {
515
- count,
516
- achievement: { connect: { id: achievementId } },
517
- game: { connect: { id: gameId } },
518
- period: { connect: { gameId_index: { gameId, index: periodIx } } },
519
- player: { connect: { id: playerId } }
520
- };
521
- }
522
- async function receiveEvent(event, definedEvents, definedLevels, prisma) {
523
- const matchingEvent = definedEvents.find((item) => item.id === event.type);
524
- if (matchingEvent && matchingEvent.achievements?.length > 0) {
525
- const awardedAchievements = await matchingEvent.achievements.reduce(
526
- async (acc, achievement) => {
527
- if (achievement.when === DB5.AchievementFrequency.FIRST && event.ctx.achievements.includes(achievement.id)) {
528
- return acc;
529
- }
530
- const existingInstance = await prisma.achievementInstance.findFirst({
531
- where: {
532
- achievement: {
533
- id: achievement.id
534
- },
535
- player: {
536
- id: event.ctx.args.playerId
537
- }
538
- }
539
- });
540
- let achievementInstance;
541
- if (existingInstance) {
542
- achievementInstance = await prisma.achievementInstance.update({
543
- where: {
544
- id: existingInstance.id
545
- },
546
- data: prepareAchievementData({
547
- count: existingInstance.count + 1,
548
- achievementId: achievement.id,
549
- gameId: event.ctx.args.gameId,
550
- periodIx: event.ctx.args.periodIx,
551
- playerId: event.ctx.args.playerId
552
- })
553
- });
554
- } else {
555
- achievementInstance = await prisma.achievementInstance.create({
556
- data: prepareAchievementData({
557
- count: 1,
558
- achievementId: achievement.id,
559
- gameId: event.ctx.args.gameId,
560
- periodIx: event.ctx.args.periodIx,
561
- playerId: event.ctx.args.playerId
562
- })
563
- });
564
- }
565
- return {
566
- achievements: [
567
- ...acc.achievements,
568
- {
569
- achievement,
570
- achievementInstance
571
- }
572
- ],
573
- achievementKeys: [...acc.achievementKeys, achievement.id],
574
- rewards: {
575
- ...acc.rewards,
576
- xp: (acc.rewards.xp ?? 0) + (achievement.reward?.xp ?? 0)
577
- }
578
- };
579
- },
580
- {
581
- achievements: [],
582
- achievementKeys: [],
583
- rewards: {}
584
- }
585
- );
586
- const currentLevelPlus1 = definedLevels.find(
587
- (level) => level.index === event.ctx.currentLevelIx + 1
588
- );
589
- const currentLevelPlus2 = definedLevels.find(
590
- (level) => level.index === event.ctx.currentLevelIx + 2
591
- );
592
- if (awardedAchievements.achievements.length > 0) {
593
- if (event.ctx.experience + awardedAchievements.rewards.xp >= currentLevelPlus1.requiredXP) {
594
- publishUserNotification(
595
- {
596
- user: {
597
- sub: event.ctx.args.playerId
598
- }
599
- },
600
- [
601
- {
602
- type: "ACHIEVEMENT_RECEIVED" /* ACHIEVEMENT_RECEIVED */
603
- }
604
- ]
605
- );
606
- publishUserNotification(
607
- {
608
- user: {
609
- sub: event.ctx.args.playerId
610
- }
611
- },
612
- [
613
- {
614
- type: "LEVEL_UP" /* LEVEL_UP */
615
- }
616
- ]
617
- );
618
- return [
619
- prisma.player.update({
620
- where: {
621
- id: event.ctx.args.playerId
622
- },
623
- data: {
624
- experience: {
625
- increment: awardedAchievements.rewards.xp
626
- },
627
- experienceToNext: currentLevelPlus2.requiredXP,
628
- level: {
629
- connect: {
630
- index: currentLevelPlus1.index
631
- }
632
- },
633
- achievementKeys: {
634
- push: awardedAchievements.achievementKeys
635
- }
636
- }
637
- })
638
- ];
639
- } else {
640
- publishUserNotification(
641
- {
642
- user: {
643
- sub: event.ctx.args.playerId
644
- }
645
- },
646
- [
647
- {
648
- type: "ACHIEVEMENT_RECEIVED" /* ACHIEVEMENT_RECEIVED */
649
- }
650
- ]
651
- );
652
- return [
653
- prisma.player.update({
654
- where: {
655
- id: event.ctx.args.playerId
656
- },
657
- data: {
658
- experience: {
659
- increment: awardedAchievements.rewards.xp
660
- },
661
- achievementKeys: {
662
- push: awardedAchievements.achievementKeys
663
- }
664
- }
665
- })
666
- ];
667
- }
668
- }
669
- return [];
670
- }
671
- return [];
672
- }
673
- function publishUserNotification(ctx, events) {
674
- if (events && events.length > 0) {
675
- pubSub.publish("user:events", ctx.user.sub, events);
676
- }
677
- }
678
-
679
- // src/services/GameService.ts
680
- async function createGame({ name, playerCount }, ctx, { roleAssigner }) {
681
- return ctx.prisma.game.create({
682
- data: {
683
- name,
684
- owner: {
685
- connect: {
686
- id: ctx.user.sub
687
- }
688
- },
689
- players: {
690
- create: (0, import_ramda.repeat)(0, playerCount).map((_, ix) => {
691
- return {
692
- facts: {},
693
- token: (0, import_nanoid.nanoid)(),
694
- role: roleAssigner(ix),
695
- number: playerCount - ix,
696
- name: `Team ${playerCount - ix}`,
697
- level: {
698
- connect: {
699
- index: 0
700
- }
701
- }
702
- };
703
- })
704
- }
705
- },
706
- include: {
707
- players: true,
708
- periods: true
709
- }
710
- });
711
- }
712
- async function addGamePeriod({ gameId, facts }, ctx, { schema, reducers }) {
713
- const validatedFacts = schema.validateSync(facts);
714
- const game = await ctx.prisma.game.findUnique({
715
- where: {
716
- id: gameId
717
- },
718
- include: {
719
- periods: {
720
- orderBy: {
721
- index: "desc"
722
- },
723
- take: 1,
724
- include: {
725
- segments: {
726
- orderBy: {
727
- index: "desc"
728
- },
729
- take: 1
730
- }
731
- }
732
- }
733
- }
734
- });
735
- if (!game)
736
- return null;
737
- const index = game.periods[0]?.index + 1 || 0;
738
- const { result: initializedFacts } = reducers.Period.apply(validatedFacts, {
739
- type: reducers.Period.ActionTypes.PERIOD_INITIALIZE,
740
- payload: {
741
- periodFacts: validatedFacts,
742
- previousPeriodFacts: game.periods[0]?.facts,
743
- previousSegmentFacts: game.periods[0]?.segments[0]?.facts,
744
- periodIx: index
745
- }
746
- });
747
- console.log(
748
- game.periods[0]?.facts,
749
- game.periods[0]?.segments[0]?.facts,
750
- initializedFacts
751
- );
752
- return ctx.prisma.period.upsert({
753
- where: {
754
- gameId_index: {
755
- gameId,
756
- index
757
- }
758
- },
759
- create: {
760
- index,
761
- facts: initializedFacts,
762
- game: {
763
- connect: {
764
- id: gameId
765
- }
766
- },
767
- previousPeriod: {
768
- connect: index > 0 ? {
769
- gameId_index: {
770
- gameId,
771
- index: index - 1
772
- }
773
- } : []
774
- }
775
- },
776
- update: {
777
- facts: initializedFacts
778
- },
779
- include: {
780
- segments: {
781
- include: {
782
- learningElements: true,
783
- storyElements: true
784
- }
785
- }
786
- }
787
- });
788
- }
789
- async function addPeriodSegment({
790
- gameId,
791
- periodIx,
792
- facts,
793
- learningElements,
794
- storyElements
795
- }, ctx, { schema, reducers }) {
796
- const validatedFacts = schema.validateSync(facts);
797
- const period = await ctx.prisma.period.findUnique({
798
- where: {
799
- gameId_index: {
800
- gameId,
801
- index: periodIx
802
- }
803
- },
804
- include: {
805
- segments: {
806
- orderBy: {
807
- index: "desc"
808
- },
809
- take: 1
810
- }
811
- }
812
- });
813
- if (!period)
814
- return null;
815
- const index = period.segments[0]?.index + 1 || 0;
816
- const { result: initializedFacts } = reducers.Segment.apply(validatedFacts, {
817
- type: reducers.Segment.ActionTypes.SEGMENT_INITIALIZE,
818
- payload: {
819
- periodFacts: period.facts,
820
- previousSegmentFacts: period.segments[0]?.facts,
821
- segmentIx: index,
822
- segmentCount: 4,
823
- periodIx
824
- }
825
- });
826
- return ctx.prisma.periodSegment.upsert({
827
- where: {
828
- gameId_periodIx_index: {
829
- gameId,
830
- periodIx,
831
- index
832
- }
833
- },
834
- create: {
835
- index,
836
- facts: initializedFacts,
837
- learningElements: {
838
- connect: learningElements ? learningElements.map((item) => ({ id: item })) : []
839
- },
840
- storyElements: {
841
- connect: storyElements ? storyElements.map((item) => ({ id: item })) : []
842
- },
843
- game: {
844
- connect: {
845
- id: gameId
846
- }
847
- },
848
- periodIx,
849
- period: {
850
- connect: {
851
- gameId_index: {
852
- gameId,
853
- index: periodIx
854
- }
855
- }
856
- },
857
- previousSegment: {
858
- connect: index > 0 ? {
859
- gameId_periodIx_index: {
860
- gameId,
861
- periodIx,
862
- index: index - 1
863
- }
864
- } : []
865
- }
866
- },
867
- update: {
868
- facts: initializedFacts,
869
- learningElements: {
870
- connect: learningElements ? learningElements.map((item) => ({ id: item })) : []
871
- },
872
- storyElements: {
873
- connect: storyElements ? storyElements.map((item) => ({ id: item })) : []
874
- }
875
- },
876
- include: {
877
- learningElements: true,
878
- storyElements: true
879
- }
880
- });
881
- }
882
- async function activateNextPeriod({ gameId }, ctx, { reducers }) {
883
- logger_default.info("activating next period");
884
- const game = await ctx.prisma.game.findUnique({
885
- where: {
886
- id: gameId
887
- },
888
- include: {
889
- players: true,
890
- periods: true,
891
- activePeriod: {
892
- include: {
893
- results: {
894
- include: {
895
- player: true
896
- }
897
- },
898
- nextPeriod: true,
899
- previousPeriod: {
900
- include: {
901
- results: {
902
- include: {
903
- player: true
904
- }
905
- }
906
- }
907
- },
908
- activeSegment: {
909
- include: {
910
- results: {
911
- include: {
912
- player: true
913
- }
914
- }
915
- }
916
- },
917
- decisions: {
918
- include: {
919
- player: true
920
- }
921
- }
922
- }
923
- }
924
- }
925
- });
926
- if (!game)
927
- return null;
928
- logger_default.info(`game found, status ${game.status}`);
929
- const currentPeriodIx = game.activePeriodIx;
930
- const currentSegmentIx = game.activePeriod?.activeSegmentIx;
931
- const nextPeriodIx = currentPeriodIx + 1;
932
- switch (game.status) {
933
- case DB6.GameStatus.SCHEDULED: {
934
- const { results, extras } = computePeriodStartResults(
935
- {
936
- results: void 0,
937
- players: game.players,
938
- activePeriodIx: currentPeriodIx,
939
- gameId: game.id,
940
- periodFacts: game.periods?.[0].facts
941
- },
942
- ctx,
943
- { reducers }
944
- );
945
- const result = await ctx.prisma.$transaction([
946
- ctx.prisma.game.update({
947
- where: {
948
- id: gameId
949
- },
950
- include: {
951
- periods: {
952
- include: {
953
- segments: true
954
- }
955
- }
956
- },
957
- data: {
958
- status: DB6.GameStatus.PREPARATION,
959
- activePeriodIx: nextPeriodIx,
960
- activePeriod: {
961
- connect: {
962
- gameId_index: {
963
- gameId,
964
- index: nextPeriodIx
965
- }
966
- }
967
- }
968
- }
969
- }),
970
- ctx.prisma.period.update({
971
- where: {
972
- gameId_index: {
973
- gameId,
974
- index: nextPeriodIx
975
- }
976
- },
977
- data: {
978
- results: {
979
- create: results
980
- }
981
- }
982
- }),
983
- ...extras
984
- ]);
985
- return result;
986
- }
987
- case DB6.GameStatus.RUNNING: {
988
- if (!game.activePeriod?.activeSegment || !currentSegmentIx)
989
- return null;
990
- const { results, extras } = computeSegmentEndResults(game, ctx, {
991
- reducers
992
- });
993
- const { result: consolidatedFacts } = reducers.Period.apply(
994
- game.activePeriod.facts,
995
- {
996
- type: reducers.Period.ActionTypes.PERIOD_CONSOLIDATE,
997
- payload: {
998
- previousSegmentFacts: game.activePeriod.activeSegment.facts,
999
- periodIx: currentPeriodIx
1000
- }
1001
- }
1002
- );
1003
- const result = await ctx.prisma.$transaction([
1004
- ctx.prisma.game.update({
1005
- data: {
1006
- status: DB6.GameStatus.CONSOLIDATION
1007
- },
1008
- include: {
1009
- periods: {
1010
- include: {
1011
- segments: true
1012
- }
1013
- }
1014
- },
1015
- where: {
1016
- id: gameId
1017
- }
1018
- }),
1019
- ctx.prisma.period.update({
1020
- where: {
1021
- gameId_index: {
1022
- gameId,
1023
- index: currentPeriodIx
1024
- }
1025
- },
1026
- data: {
1027
- facts: consolidatedFacts
1028
- }
1029
- }),
1030
- ctx.prisma.periodSegment.update({
1031
- where: {
1032
- gameId_periodIx_index: {
1033
- gameId,
1034
- periodIx: currentPeriodIx,
1035
- index: currentSegmentIx
1036
- }
1037
- },
1038
- data: {
1039
- results: {
1040
- // compute SEGMENT_END results using model
1041
- update: results
1042
- }
1043
- },
1044
- include: {
1045
- results: {
1046
- include: {
1047
- player: true
1048
- }
1049
- }
1050
- }
1051
- }),
1052
- ...extras
1053
- ]);
1054
- return result;
1055
- }
1056
- case DB6.GameStatus.CONSOLIDATION: {
1057
- if (!game.activePeriod?.activeSegment)
1058
- return null;
1059
- const { results, extras, promises } = await computePeriodEndResults(
1060
- {
1061
- segmentResults: game.activePeriod.activeSegment.results,
1062
- segmentFacts: game.activePeriod.activeSegment.facts,
1063
- periodFacts: game.activePeriod.facts,
1064
- periodDecisions: game.activePeriod.decisions,
1065
- activePeriodIx: currentPeriodIx,
1066
- activeSegmentIx: currentSegmentIx,
1067
- gameId: game.id
1068
- },
1069
- ctx,
1070
- { reducers }
1071
- );
1072
- await Promise.all(promises);
1073
- const result = await ctx.prisma.$transaction([
1074
- // update the status and active period of the current game
1075
- ctx.prisma.game.update({
1076
- where: {
1077
- id: gameId
1078
- },
1079
- include: {
1080
- periods: {
1081
- include: {
1082
- segments: true
1083
- }
1084
- }
1085
- },
1086
- data: {
1087
- status: DB6.GameStatus.RESULTS,
1088
- activePeriodIx: nextPeriodIx,
1089
- activePeriod: {
1090
- connect: {
1091
- gameId_index: {
1092
- gameId,
1093
- index: nextPeriodIx
1094
- }
1095
- }
1096
- }
1097
- }
1098
- }),
1099
- // create PERIOD_END results based on the previous SEGMENT_END results
1100
- ctx.prisma.period.update({
1101
- where: {
1102
- gameId_index: {
1103
- gameId,
1104
- index: currentPeriodIx
1105
- }
1106
- },
1107
- data: {
1108
- results: {
1109
- create: results
1110
- }
1111
- },
1112
- include: {
1113
- results: true
1114
- }
1115
- }),
1116
- ...extras
1117
- ]);
1118
- return result;
1119
- }
1120
- case DB6.GameStatus.RESULTS: {
1121
- if (!game.activePeriod) {
1122
- logger_default.warn("no next period available");
1123
- return null;
1124
- }
1125
- const { results, extras } = computePeriodStartResults(
1126
- {
1127
- results: game.activePeriod.previousPeriod[0].results,
1128
- players: game.players,
1129
- activePeriodIx: currentPeriodIx,
1130
- gameId: game.id,
1131
- periodFacts: game.activePeriod.facts
1132
- },
1133
- ctx,
1134
- { reducers }
1135
- );
1136
- const result = await ctx.prisma.$transaction([
1137
- // update the status and active period of the current game
1138
- ctx.prisma.game.update({
1139
- where: {
1140
- id: gameId
1141
- },
1142
- include: {
1143
- periods: {
1144
- include: {
1145
- segments: true
1146
- }
1147
- }
1148
- },
1149
- data: {
1150
- status: DB6.GameStatus.PREPARATION
1151
- }
1152
- }),
1153
- // create PERIOD_START results based on the previous PERIOD_END results
1154
- ctx.prisma.period.update({
1155
- where: {
1156
- gameId_index: {
1157
- gameId,
1158
- index: currentPeriodIx
1159
- }
1160
- },
1161
- data: {
1162
- results: {
1163
- create: results
1164
- }
1165
- }
1166
- }),
1167
- ...extras
1168
- ]);
1169
- return result;
1170
- }
1171
- default:
1172
- return null;
1173
- }
1174
- }
1175
- async function activateNextSegment({ gameId }, ctx, { reducers }) {
1176
- const game = await ctx.prisma.game.findUnique({
1177
- where: {
1178
- id: gameId
1
+ import * as DB from '@prisma/client';
2
+ import { JSONObjectResolver, DateTimeResolver } from 'graphql-scalars';
3
+ import { asNexusMethod, enumType, objectType } from 'nexus';
4
+ export { Game, GameStatus, Period, PeriodSegment } from './types/Game.js';
5
+ export { LearningAnswerOption, LearningElement, LearningElementAttempt, LearningElementState } from './types/LearningElement.js';
6
+ export { Mutation, generateBaseMutations } from './types/Mutation.js';
7
+ export { Player, PlayerAction, PlayerDecision, PlayerDecisionType, PlayerLevel, PlayerResult, PlayerResultType, PlayerState } from './types/Player.js';
8
+ export { Query, generateBaseQueries } from './types/Query.js';
9
+ export { Subscription, generateBaseSubscriptions } from './types/Subscription.js';
10
+
11
+ const JsonScalar = asNexusMethod(JSONObjectResolver, 'json');
12
+ const DateScalar = asNexusMethod(DateTimeResolver, 'date');
13
+ const UserRole = enumType({
14
+ name: 'UserRole',
15
+ members: Object.values(DB.UserRole),
16
+ });
17
+ const Event = objectType({
18
+ name: 'Event',
19
+ definition(t) {
20
+ t.string('type');
1179
21
  },
1180
- include: {
1181
- players: true,
1182
- periods: true,
1183
- segments: true,
1184
- activePeriod: {
1185
- include: {
1186
- results: {
1187
- include: {
1188
- player: true
1189
- }
1190
- },
1191
- activeSegment: {
1192
- include: {
1193
- nextSegment: true,
1194
- results: {
1195
- include: {
1196
- player: true
1197
- }
1198
- }
1199
- }
1200
- }
1201
- }
1202
- }
1203
- }
1204
- });
1205
- if (!game?.activePeriod)
1206
- return null;
1207
- const currentPeriodIx = game.activePeriodIx;
1208
- const currentSegmentIx = game.activePeriod.activeSegmentIx;
1209
- const nextSegmentIx = currentSegmentIx + 1;
1210
- switch (game.status) {
1211
- case DB6.GameStatus.PREPARATION:
1212
- case DB6.GameStatus.PAUSED: {
1213
- const { results, extras } = computeSegmentStartResults(game, ctx, {
1214
- reducers
1215
- });
1216
- const result = await ctx.prisma.$transaction([
1217
- ctx.prisma.game.update({
1218
- where: {
1219
- id: gameId
1220
- },
1221
- include: {
1222
- periods: {
1223
- include: {
1224
- segments: true
1225
- }
1226
- },
1227
- players: true
1228
- },
1229
- data: {
1230
- status: DB6.GameStatus.RUNNING
1231
- }
1232
- }),
1233
- // update the active segment of the current period
1234
- ctx.prisma.period.update({
1235
- where: {
1236
- gameId_index: {
1237
- gameId,
1238
- index: currentPeriodIx
1239
- }
1240
- },
1241
- data: {
1242
- activeSegmentIx: nextSegmentIx,
1243
- activeSegment: {
1244
- connect: {
1245
- gameId_periodIx_index: {
1246
- gameId,
1247
- periodIx: currentPeriodIx,
1248
- index: nextSegmentIx
1249
- }
1250
- }
1251
- }
1252
- }
1253
- }),
1254
- // SEGMENT INITIALIZATION
1255
- ctx.prisma.periodSegment.update({
1256
- where: {
1257
- gameId_periodIx_index: {
1258
- gameId,
1259
- periodIx: currentPeriodIx,
1260
- index: nextSegmentIx
1261
- }
1262
- },
1263
- data: {
1264
- results: {
1265
- create: results
1266
- }
1267
- }
1268
- }),
1269
- ...extras
1270
- ]);
1271
- return result;
1272
- }
1273
- case DB6.GameStatus.RUNNING: {
1274
- if (!game.activePeriod?.activeSegment?.nextSegment) {
1275
- return null;
1276
- }
1277
- const { results, extras } = computeSegmentEndResults(game, ctx, {
1278
- reducers
1279
- });
1280
- const result = await ctx.prisma.$transaction([
1281
- ctx.prisma.game.update({
1282
- where: { id: gameId },
1283
- include: {
1284
- periods: {
1285
- include: {
1286
- segments: true
1287
- }
1288
- },
1289
- players: true
1290
- },
1291
- data: {
1292
- status: DB6.GameStatus.PAUSED
1293
- }
1294
- }),
1295
- ctx.prisma.periodSegment.update({
1296
- where: {
1297
- gameId_periodIx_index: {
1298
- gameId,
1299
- periodIx: currentPeriodIx,
1300
- index: currentSegmentIx
1301
- }
1302
- },
1303
- data: {
1304
- results: {
1305
- update: results
1306
- }
1307
- },
1308
- include: {
1309
- results: true
1310
- }
1311
- }),
1312
- // reset player readiness
1313
- ctx.prisma.player.updateMany({
1314
- where: {
1315
- game: {
1316
- id: gameId
1317
- }
1318
- },
1319
- data: {
1320
- isReady: false
1321
- }
1322
- }),
1323
- ...extras
1324
- ]);
1325
- return result;
1326
- }
1327
- default:
1328
- return null;
1329
- }
1330
- }
1331
- var PlayerFactsSchema = yup.object({
1332
- location: yup.string().default("Zurich")
1333
22
  });
1334
- async function updatePlayerData({ name, avatar, color, facts }, ctx) {
1335
- if ((0, import_ramda.none)(Boolean, [name, avatar, color, facts])) {
1336
- return null;
1337
- }
1338
- let data = {};
1339
- if (name) {
1340
- data["name"] = name;
1341
- }
1342
- if (avatar) {
1343
- data["avatar"] = avatar;
1344
- }
1345
- if (color) {
1346
- data["color"] = color;
1347
- }
1348
- if (facts) {
1349
- data["facts"] = PlayerFactsSchema.validateSync(facts, {
1350
- stripUnknown: true
1351
- });
1352
- }
1353
- const player = await ctx.prisma.player.update({
1354
- where: {
1355
- id: ctx.user.sub
1356
- },
1357
- data,
1358
- include: {
1359
- level: true,
1360
- achievements: {
1361
- include: {
1362
- achievement: true
1363
- }
1364
- }
1365
- }
1366
- });
1367
- return player;
1368
- }
1369
- async function getGames(args, ctx) {
1370
- return ctx.prisma.game.findMany();
1371
- }
1372
- async function getGame(args, ctx) {
1373
- const gameId = args.id ?? ctx.user.gameId;
1374
- if (!gameId) {
1375
- return null;
1376
- }
1377
- return ctx.prisma.game.findUnique({
1378
- where: {
1379
- id: args.id
1380
- },
1381
- include: {
1382
- players: {
1383
- include: {
1384
- level: true,
1385
- achievements: true
1386
- },
1387
- orderBy: {
1388
- number: "asc"
1389
- }
1390
- },
1391
- periods: {
1392
- orderBy: {
1393
- index: "asc"
1394
- },
1395
- include: {
1396
- segments: {
1397
- orderBy: {
1398
- index: "asc"
1399
- },
1400
- include: {
1401
- learningElements: true,
1402
- storyElements: true
1403
- }
1404
- }
1405
- }
1406
- },
1407
- activePeriod: {
1408
- include: {
1409
- segments: true,
1410
- activeSegment: true
1411
- }
1412
- }
1413
- }
1414
- });
1415
- }
1416
- async function getGameFromContext(ctx) {
1417
- return ctx.prisma.game.findUnique({
1418
- where: {
1419
- id: ctx.user.gameId
1420
- },
1421
- include: {
1422
- activePeriod: true
1423
- }
1424
- });
1425
- }
1426
- async function getLearningElements(args, ctx) {
1427
- return ctx.prisma.learningElement.findMany({
1428
- include: {
1429
- options: true
1430
- }
1431
- });
1432
- }
1433
- function mapAction({ ctx, gameId, activePeriodIx, playerId }) {
1434
- return (action) => ctx.prisma.playerAction.create({
1435
- data: {
1436
- type: action.type,
1437
- facts: action.facts,
1438
- game: {
1439
- connect: { id: gameId }
1440
- },
1441
- player: {
1442
- connect: { id: playerId }
1443
- },
1444
- periodIx: activePeriodIx,
1445
- period: {
1446
- connect: {
1447
- gameId_index: {
1448
- gameId,
1449
- index: activePeriodIx
1450
- }
1451
- }
1452
- },
1453
- segmentIx: typeof action.segment === "number" ? action.segment : void 0,
1454
- segment: typeof action.segment === "number" ? {
1455
- connect: {
1456
- gameId_periodIx_index: {
1457
- gameId,
1458
- periodIx: activePeriodIx,
1459
- index: action.segment
1460
- }
1461
- }
1462
- } : void 0
1463
- }
1464
- });
1465
- }
1466
- function computePeriodStartResults({ results, players, activePeriodIx, gameId, periodFacts }, ctx, { reducers }) {
1467
- const currentPeriodIx = activePeriodIx;
1468
- const nextPeriodIx = currentPeriodIx + 1;
1469
- let extras = [];
1470
- if (currentPeriodIx >= 0) {
1471
- const result2 = results.filter((result3) => result3.type === DB6.PlayerResultType.PERIOD_END).map((result3, ix, allResults) => {
1472
- const { result: facts, actions } = reducers.PeriodResult.apply(result3, {
1473
- type: reducers.PeriodResult.ActionTypes.PERIOD_RESULTS_START,
1474
- payload: {
1475
- playerRole: result3.player.role ?? result3.player.connect.role,
1476
- periodFacts
1477
- }
1478
- });
1479
- const mapper = mapAction({
1480
- ctx,
1481
- gameId,
1482
- activePeriodIx: currentPeriodIx,
1483
- playerId: result3.player.id
1484
- });
1485
- if (actions && actions.length > 0) {
1486
- extras = [...extras, ...actions.map(mapper)];
1487
- }
1488
- return {
1489
- type: DB6.PlayerResultType.PERIOD_START,
1490
- periodIx: currentPeriodIx,
1491
- facts,
1492
- player: {
1493
- connect: {
1494
- id: result3.player.id ?? result3.player.connect.id
1495
- }
1496
- },
1497
- game: {
1498
- connect: {
1499
- id: gameId
1500
- }
1501
- }
1502
- };
1503
- });
1504
- return {
1505
- results: result2,
1506
- extras
1507
- };
1508
- }
1509
- const result = players.map((player, ix, allPlayers) => {
1510
- const { result: facts, actions } = reducers.PeriodResult.apply(
1511
- {},
1512
- {
1513
- type: reducers.PeriodResult.ActionTypes.PERIOD_RESULTS_INITIALIZE,
1514
- payload: {
1515
- playerRole: player.role,
1516
- periodFacts
1517
- }
1518
- }
1519
- );
1520
- const mapper = mapAction({
1521
- ctx,
1522
- gameId,
1523
- activePeriodIx: nextPeriodIx,
1524
- playerId: player.id
1525
- });
1526
- if (actions && actions.length > 0) {
1527
- extras = [...extras, ...actions.map(mapper)];
1528
- }
1529
- return {
1530
- type: DB6.PlayerResultType.PERIOD_START,
1531
- periodIx: nextPeriodIx,
1532
- facts,
1533
- player: {
1534
- connect: {
1535
- id: player.id
1536
- }
1537
- },
1538
- game: {
1539
- connect: {
1540
- id: gameId
1541
- }
1542
- }
1543
- };
1544
- });
1545
- return {
1546
- results: result,
1547
- extras
1548
- };
1549
- }
1550
- async function computePeriodEndResults({
1551
- segmentResults,
1552
- periodFacts,
1553
- periodDecisions,
1554
- segmentFacts,
1555
- activePeriodIx,
1556
- activeSegmentIx,
1557
- gameId
1558
- }, ctx, { reducers }) {
1559
- let extras = [];
1560
- let promises = [];
1561
- const results = segmentResults.filter((result) => result.type === DB6.PlayerResultType.SEGMENT_END).map((result, ix, allResults) => {
1562
- const consolidationDecisions = periodDecisions.find(
1563
- (decision) => decision.playerId === result.playerId
1564
- );
1565
- const {
1566
- result: facts,
1567
- actions,
1568
- events
1569
- } = reducers.PeriodResult.apply(result.facts, {
1570
- type: reducers.PeriodResult.ActionTypes.PERIOD_RESULTS_END,
1571
- payload: {
1572
- periodFacts,
1573
- segmentFacts,
1574
- playerRole: result.player.role,
1575
- playerLevel: result.player.levelIx + 1,
1576
- playerExperience: result.player.experience,
1577
- consolidationDecisions,
1578
- periodIx: activePeriodIx,
1579
- segmentIx: activeSegmentIx
1580
- }
1581
- });
1582
- logger_default.debug(actions);
1583
- const mapper = mapAction({
1584
- ctx,
1585
- gameId,
1586
- activePeriodIx,
1587
- playerId: result.player.id
1588
- });
1589
- if (actions && actions.length > 0) {
1590
- extras = [...extras, ...actions.map(mapper)];
1591
- }
1592
- promises = [
1593
- ...promises,
1594
- receiveEvents({
1595
- events,
1596
- ctx: {
1597
- args: {
1598
- playerId: result.player.id,
1599
- periodIx: activePeriodIx,
1600
- gameId
1601
- },
1602
- user: ctx.user,
1603
- achievements: result.player.achievementKeys,
1604
- experience: result.player.experience,
1605
- currentLevelIx: result.player.levelIx
1606
- },
1607
- prisma: ctx.prisma
1608
- })
1609
- ];
1610
- return {
1611
- type: DB6.PlayerResultType.PERIOD_END,
1612
- periodIx: activePeriodIx,
1613
- facts,
1614
- player: {
1615
- connect: {
1616
- id: result.playerId
1617
- }
1618
- },
1619
- game: {
1620
- connect: {
1621
- id: gameId
1622
- }
1623
- }
1624
- };
1625
- });
1626
- return {
1627
- extras,
1628
- results,
1629
- promises
1630
- };
1631
- }
1632
- function computeSegmentStartResults(game, ctx, { reducers }) {
1633
- const currentSegmentIx = game.activePeriod.activeSegmentIx;
1634
- const nextSegmentIx = currentSegmentIx + 1;
1635
- let extras = [];
1636
- if (currentSegmentIx >= 0) {
1637
- const results2 = game.activePeriod.activeSegment.results.filter((result) => result.type === DB6.PlayerResultType.SEGMENT_END).reduce((acc, result, ix, allResults) => {
1638
- const { result: facts, actions } = reducers.SegmentResult.apply(
1639
- result.facts,
1640
- {
1641
- type: reducers.SegmentResult.ActionTypes.SEGMENT_RESULTS_START,
1642
- payload: {
1643
- playerRole: result.player.role,
1644
- periodFacts: game.activePeriod.facts,
1645
- segmentFacts: game.activePeriod.activeSegment.facts,
1646
- nextSegmentFacts: game.activePeriod.activeSegment.nextSegment?.facts,
1647
- segmentIx: nextSegmentIx
1648
- }
1649
- }
1650
- );
1651
- const mapper = mapAction({
1652
- ctx,
1653
- gameId: game.id,
1654
- activePeriodIx: game.activePeriodIx,
1655
- playerId: result.player.id
1656
- });
1657
- if (actions && actions.length > 0) {
1658
- extras = [...extras, ...actions.map(mapper)];
1659
- }
1660
- const common = {
1661
- facts,
1662
- periodIx: game.activePeriodIx,
1663
- segmentIx: nextSegmentIx,
1664
- player: {
1665
- connect: {
1666
- id: result.playerId
1667
- }
1668
- },
1669
- period: {
1670
- connect: {
1671
- id: game.activePeriodId
1672
- }
1673
- },
1674
- game: {
1675
- connect: {
1676
- id: game.id
1677
- }
1678
- }
1679
- };
1680
- return [
1681
- ...acc,
1682
- {
1683
- ...common,
1684
- type: DB6.PlayerResultType.SEGMENT_START
1685
- },
1686
- {
1687
- ...common,
1688
- type: DB6.PlayerResultType.SEGMENT_END
1689
- }
1690
- ];
1691
- }, []);
1692
- return {
1693
- results: results2,
1694
- extras
1695
- };
1696
- }
1697
- const results = game.activePeriod.results.filter((result) => result.type === DB6.PlayerResultType.PERIOD_START).reduce((acc, result, ix, allResults) => {
1698
- const { result: facts } = reducers.SegmentResult.apply(result.facts, {
1699
- type: reducers.SegmentResult.ActionTypes.SEGMENT_RESULTS_INITIALIZE,
1700
- payload: {
1701
- playerRole: result.player.role,
1702
- periodFacts: game.activePeriod.facts,
1703
- segmentFacts: game.activePeriod.activeSegment?.facts,
1704
- nextSegmentFacts: game.activePeriod.activeSegment?.nextSegment?.facts,
1705
- segmentIx: nextSegmentIx
1706
- }
1707
- });
1708
- const common = {
1709
- facts,
1710
- periodIx: game.activePeriodIx,
1711
- segmentIx: nextSegmentIx,
1712
- player: {
1713
- connect: {
1714
- id: result.playerId
1715
- }
1716
- },
1717
- period: {
1718
- connect: {
1719
- id: game.activePeriodId
1720
- }
1721
- },
1722
- game: {
1723
- connect: {
1724
- id: game.id
1725
- }
1726
- }
1727
- };
1728
- return [
1729
- ...acc,
1730
- {
1731
- ...common,
1732
- type: DB6.PlayerResultType.SEGMENT_START
1733
- },
1734
- {
1735
- ...common,
1736
- type: DB6.PlayerResultType.SEGMENT_END
1737
- }
1738
- ];
1739
- }, []);
1740
- return {
1741
- results,
1742
- extras
1743
- };
1744
- }
1745
- function computeSegmentEndResults(game, ctx, { reducers }) {
1746
- let extras = [];
1747
- const results = game.activePeriod.activeSegment.results.filter((result) => result.type === DB6.PlayerResultType.SEGMENT_END).map((result, ix, allResults) => {
1748
- const { result: facts, actions } = reducers.SegmentResult.apply(
1749
- result.facts,
1750
- {
1751
- type: reducers.SegmentResult.ActionTypes.SEGMENT_RESULTS_END,
1752
- payload: {
1753
- playerRole: result.player.role,
1754
- periodFacts: game.activePeriod.facts,
1755
- segmentFacts: game.activePeriod.activeSegment.facts,
1756
- segmentIx: game.activePeriod.activeSegmentIx
1757
- }
1758
- }
1759
- );
1760
- const mapper = mapAction({
1761
- ctx,
1762
- gameId: game.id,
1763
- activePeriodIx: game.activePeriodIx,
1764
- playerId: result.player.id
1765
- });
1766
- if (actions && actions.length > 0) {
1767
- extras = [...extras, ...actions.map(mapper)];
1768
- }
1769
- return {
1770
- where: {
1771
- periodIx_segmentIx_playerId_type: {
1772
- periodIx: game.activePeriodIx,
1773
- segmentIx: game.activePeriod.activeSegmentIx,
1774
- playerId: result.playerId,
1775
- type: DB6.PlayerResultType.SEGMENT_END
1776
- }
1777
- },
1778
- data: {
1779
- facts,
1780
- game: {
1781
- connect: {
1782
- id: game.id
1783
- }
1784
- }
1785
- }
1786
- };
1787
- });
1788
- return {
1789
- results,
1790
- extras
1791
- };
1792
- }
1793
23
 
1794
- // src/services/PlayService.ts
1795
- var DB7 = __toESM(require("@prisma/client"));
1796
- async function performAction(args, ctx, { reducers }) {
1797
- const periodIx_segmentIx_playerId_type = {
1798
- periodIx: args.periodIx,
1799
- segmentIx: args.segmentIx,
1800
- playerId: args.playerId,
1801
- type: DB7.PlayerResultType.SEGMENT_END
1802
- };
1803
- const previousResult = await ctx.prisma.playerResult.findUnique({
1804
- where: {
1805
- periodIx_segmentIx_playerId_type
1806
- },
1807
- include: {
1808
- game: true,
1809
- segment: true,
1810
- period: true,
1811
- player: true
1812
- }
1813
- });
1814
- if (!previousResult)
1815
- return null;
1816
- if (previousResult.game.status !== DB7.GameStatus.RUNNING) {
1817
- throw new Error("ACTIONS_NOT_ALLOWED");
1818
- }
1819
- const { result, events, notifications, isDirty, extras } = reducers.Actions.apply(previousResult.facts, {
1820
- type: args.actionType,
1821
- payload: {
1822
- playerArgs: args.facts,
1823
- segmentFacts: previousResult.segment?.facts,
1824
- periodFacts: previousResult.period.facts
1825
- }
1826
- });
1827
- publishUserNotification(ctx, notifications);
1828
- await receiveEvents({
1829
- events,
1830
- ctx: {
1831
- user: ctx.user,
1832
- args,
1833
- achievements: previousResult.player.achievementKeys,
1834
- experience: previousResult.player.experience,
1835
- currentLevelIx: previousResult.player.levelIx
1836
- },
1837
- prisma: ctx.prisma
1838
- });
1839
- if (!isDirty) {
1840
- return previousResult;
1841
- }
1842
- const [updatedResult, _] = await ctx.prisma.$transaction([
1843
- ctx.prisma.playerResult.update({
1844
- where: {
1845
- periodIx_segmentIx_playerId_type
1846
- },
1847
- data: {
1848
- facts: result
1849
- },
1850
- include: {
1851
- period: true
1852
- }
1853
- }),
1854
- ctx.prisma.playerAction.create({
1855
- data: {
1856
- periodIx: args.periodIx,
1857
- period: {
1858
- connect: {
1859
- gameId_index: {
1860
- gameId: args.gameId,
1861
- index: args.periodIx
1862
- }
1863
- }
1864
- },
1865
- segmentIx: args.segmentIx,
1866
- segment: {
1867
- connect: {
1868
- gameId_periodIx_index: {
1869
- gameId: args.gameId,
1870
- periodIx: args.periodIx,
1871
- index: args.segmentIx
1872
- }
1873
- }
1874
- },
1875
- game: {
1876
- connect: {
1877
- id: args.gameId
1878
- }
1879
- },
1880
- player: {
1881
- connect: {
1882
- id: args.playerId
1883
- }
1884
- },
1885
- type: args.actionType,
1886
- facts: {
1887
- ...args.facts,
1888
- ...extras
1889
- }
1890
- }
1891
- })
1892
- ]);
1893
- return updatedResult;
1894
- }
1895
- async function saveDecisions(args, ctx) {
1896
- const game = await ctx.prisma.game.findUnique({
1897
- where: {
1898
- id: ctx.user.gameId
1899
- },
1900
- include: {
1901
- activePeriod: {
1902
- include: {
1903
- activeSegment: true
1904
- }
1905
- }
1906
- }
1907
- });
1908
- if (!game?.activePeriod)
1909
- return null;
1910
- if (args.decisionType !== game.status) {
1911
- throw new Error("INVALID_DECISION");
1912
- }
1913
- const periodIx = game.activePeriod.index;
1914
- const savedDecision = ctx.prisma.playerDecision.upsert({
1915
- where: {
1916
- playerId_periodIx_type: {
1917
- periodIx,
1918
- playerId: ctx.user.sub,
1919
- type: args.decisionType
1920
- }
1921
- },
1922
- create: {
1923
- facts: args.facts,
1924
- type: args.decisionType,
1925
- periodIx,
1926
- period: {
1927
- connect: {
1928
- gameId_index: {
1929
- gameId: game.id,
1930
- index: periodIx
1931
- }
1932
- }
1933
- },
1934
- game: {
1935
- connect: {
1936
- id: game.id
1937
- }
1938
- },
1939
- player: {
1940
- connect: {
1941
- id: ctx.user.sub
1942
- }
1943
- }
1944
- },
1945
- update: {
1946
- facts: args.facts
1947
- }
1948
- });
1949
- return savedDecision;
1950
- }
1951
- async function getPlayerResult(args, ctx) {
1952
- const currentGame = await ctx.prisma.game.findUnique({
1953
- where: {
1954
- id: args.gameId
1955
- },
1956
- include: {
1957
- activePeriod: {
1958
- include: {
1959
- activeSegment: {
1960
- include: {
1961
- learningElements: true,
1962
- storyElements: true
1963
- }
1964
- },
1965
- segments: {
1966
- include: {
1967
- learningElements: true,
1968
- storyElements: true
1969
- }
1970
- }
1971
- }
1972
- },
1973
- periods: {
1974
- include: {
1975
- segments: {
1976
- include: {
1977
- learningElements: true,
1978
- storyElements: true
1979
- }
1980
- }
1981
- }
1982
- }
1983
- }
1984
- });
1985
- if (!currentGame?.activePeriod)
1986
- return null;
1987
- const previousResults = ctx.prisma.playerResult.findMany({
1988
- where: {
1989
- playerId: args.playerId,
1990
- periodIx: {
1991
- lte: currentGame.activePeriod.index
1992
- }
1993
- },
1994
- include: {
1995
- period: true,
1996
- segment: true
1997
- }
1998
- });
1999
- const playerResult = await ctx.prisma.playerResult.findUnique({
2000
- where: {
2001
- periodIx_segmentIx_playerId_type: {
2002
- periodIx: currentGame.activePeriodIx,
2003
- segmentIx: currentGame.activePeriod.activeSegmentIx,
2004
- playerId: args.playerId,
2005
- type: DB7.PlayerResultType.SEGMENT_END
2006
- }
2007
- },
2008
- include: {
2009
- period: true,
2010
- player: {
2011
- include: {
2012
- completedLearningElements: true,
2013
- visitedStoryElements: true
2014
- }
2015
- }
2016
- }
2017
- });
2018
- const transactions = ctx.prisma.playerAction.findMany({
2019
- where: {
2020
- player: {
2021
- id: args.playerId
2022
- }
2023
- },
2024
- orderBy: {
2025
- createdAt: "asc"
2026
- }
2027
- });
2028
- return {
2029
- currentGame,
2030
- playerResult,
2031
- previousResults,
2032
- transactions
2033
- };
2034
- }
2035
- async function getPlayerData(args, ctx) {
2036
- return ctx.prisma.player.findUnique({
2037
- where: {
2038
- id: args.playerId
2039
- },
2040
- include: {
2041
- level: true,
2042
- achievements: {
2043
- include: {
2044
- achievement: true
2045
- }
2046
- }
2047
- }
2048
- });
2049
- }
2050
- async function getLearningElement(args, ctx) {
2051
- const playerWithLearningElements = await ctx.prisma.player.findUnique({
2052
- where: {
2053
- id: ctx.user.sub
2054
- },
2055
- include: {
2056
- completedLearningElements: {
2057
- where: {
2058
- id: args.id
2059
- }
2060
- }
2061
- }
2062
- });
2063
- if (!playerWithLearningElements)
2064
- return null;
2065
- const elementSolved = playerWithLearningElements.completedLearningElements.length > 0;
2066
- const element = await ctx.prisma.learningElement.findUnique({
2067
- where: {
2068
- id: args.id
2069
- },
2070
- include: {
2071
- options: true
2072
- }
2073
- });
2074
- if (!element)
2075
- return null;
2076
- return {
2077
- id: args.id,
2078
- element: {
2079
- ...element,
2080
- feedback: elementSolved ? element.feedback : null
2081
- },
2082
- state: elementSolved ? "SOLVED" /* SOLVED */ : "NEW" /* NEW */,
2083
- solution: elementSolved ? JSON.stringify(
2084
- element.options.flatMap((option, ix) => option.correct ? [ix] : [])
2085
- ) : null
2086
- };
2087
- }
2088
- async function attemptLearningElement(args, ctx) {
2089
- const learningElement = await ctx.prisma.learningElement.findUnique({
2090
- where: { id: args.elementId },
2091
- include: { options: true }
2092
- });
2093
- if (!learningElement)
2094
- return null;
2095
- try {
2096
- const selectedOptions = JSON.parse(args.selection);
2097
- const pointsAchieved = learningElement.options.reduce((acc, option, ix) => {
2098
- if (option.correct && selectedOptions.includes(ix)) {
2099
- return acc + 1;
2100
- }
2101
- if (!option.correct && !selectedOptions.includes(ix)) {
2102
- return acc + 1;
2103
- }
2104
- return acc;
2105
- }, 0);
2106
- const pointsMax = learningElement.options.length;
2107
- let updatedPlayer;
2108
- if (pointsAchieved === pointsMax) {
2109
- updatedPlayer = await ctx.prisma.player.update({
2110
- where: {
2111
- id: ctx.user.sub
2112
- },
2113
- data: {
2114
- completedLearningElements: {
2115
- connect: {
2116
- id: args.elementId
2117
- }
2118
- },
2119
- completedLearningElementIds: {
2120
- push: args.elementId
2121
- }
2122
- },
2123
- include: {
2124
- game: {
2125
- select: {
2126
- activePeriodIx: true
2127
- }
2128
- }
2129
- }
2130
- });
2131
- await receiveEvents({
2132
- events: [
2133
- {
2134
- type: "LEARNING_ELEMENT_SOLVED" /* LEARNING_ELEMENT_SOLVED */,
2135
- facts: {
2136
- elementId: args.elementId
2137
- }
2138
- }
2139
- ],
2140
- ctx: {
2141
- user: ctx.user,
2142
- args: {
2143
- gameId: ctx.user.gameId,
2144
- periodIx: updatedPlayer.game.activePeriodIx,
2145
- playerId: ctx.user.sub
2146
- },
2147
- achievements: updatedPlayer.achievementKeys,
2148
- experience: updatedPlayer.experience,
2149
- currentLevelIx: updatedPlayer.levelIx
2150
- },
2151
- prisma: ctx.prisma
2152
- });
2153
- } else {
2154
- publishUserNotification(ctx, [
2155
- {
2156
- type: "LEARNING_ELEMENT_INCORRECT" /* LEARNING_ELEMENT_INCORRECT */
2157
- }
2158
- ]);
2159
- }
2160
- return {
2161
- id: args.elementId,
2162
- pointsAchieved,
2163
- pointsMax,
2164
- element: {
2165
- id: args.elementId,
2166
- feedback: learningElement.feedback
2167
- },
2168
- player: updatedPlayer
2169
- };
2170
- } catch (e) {
2171
- console.warn(e);
2172
- return null;
2173
- }
2174
- }
2175
- async function markStoryElement(args, ctx) {
2176
- const storyElement = await ctx.prisma.storyElement.findUnique({
2177
- where: { id: args.elementId }
2178
- });
2179
- if (!storyElement)
2180
- return null;
2181
- return ctx.prisma.player.update({
2182
- where: {
2183
- id: ctx.user.sub
2184
- },
2185
- data: {
2186
- visitedStoryElements: {
2187
- connect: {
2188
- id: args.elementId
2189
- }
2190
- },
2191
- visitedStoryElementIds: {
2192
- push: args.elementId
2193
- }
2194
- }
2195
- });
2196
- }
2197
- async function getPlayerResults(args, ctx) {
2198
- const playerResults = await ctx.prisma.playerResult.findMany({
2199
- where: {
2200
- gameId: ctx.user.gameId
2201
- },
2202
- include: {
2203
- period: true,
2204
- player: true,
2205
- segment: true
2206
- }
2207
- });
2208
- return playerResults;
2209
- }
2210
- async function getPastResults(args, ctx) {
2211
- const currentGame = await ctx.prisma.game.findUnique({
2212
- where: { id: ctx.user.gameId }
2213
- });
2214
- if (!currentGame)
2215
- return null;
2216
- const playerResults = await ctx.prisma.playerResult.findMany({
2217
- where: {
2218
- gameId: ctx.user.gameId,
2219
- periodIx: {
2220
- lt: currentGame.activePeriodIx
2221
- },
2222
- type: "PERIOD_END"
2223
- },
2224
- include: {
2225
- period: true,
2226
- player: {
2227
- include: {
2228
- level: true
2229
- }
2230
- }
2231
- }
2232
- });
2233
- return playerResults;
2234
- }
2235
- async function updateReadyState(args, ctx) {
2236
- return ctx.prisma.player.update({
2237
- where: {
2238
- id: ctx.user.sub
2239
- },
2240
- data: {
2241
- isReady: args.isReady
2242
- }
2243
- });
2244
- }
2245
- async function addCountdown(args, ctx) {
2246
- const currentGame = await ctx.prisma.game.findUnique({
2247
- where: { id: args.gameId },
2248
- include: {
2249
- activePeriod: {
2250
- include: {
2251
- activeSegment: true
2252
- }
2253
- }
2254
- }
2255
- });
2256
- if (!currentGame?.activePeriod?.activeSegment)
2257
- return null;
2258
- await ctx.prisma.periodSegment.update({
2259
- where: {
2260
- id: currentGame.activePeriod.activeSegment.id
2261
- },
2262
- data: {
2263
- countdownExpiresAt: new Date(Date.now() + args.seconds * 1e3)
2264
- }
2265
- });
2266
- return true;
2267
- }
2268
-
2269
- // src/types/Mutation.ts
2270
- var defaultReducers = {};
2271
- var defaultSchemas = {};
2272
- var defaultInputTypes = {};
2273
- function generateBaseMutations({
2274
- reducers = defaultReducers,
2275
- roleAssigner = () => "UNSET",
2276
- schemas = defaultSchemas,
2277
- inputTypes = defaultInputTypes
2278
- } = {}) {
2279
- return (0, import_nexus6.objectType)({
2280
- name: "Mutation",
2281
- definition(t) {
2282
- t.field("updateReadyState", {
2283
- type: Player,
2284
- args: {
2285
- isReady: (0, import_nexus6.nonNull)((0, import_nexus6.booleanArg)())
2286
- },
2287
- async resolve(_, args, ctx) {
2288
- return updateReadyState(args, ctx);
2289
- }
2290
- });
2291
- t.field("loginAsTeam", {
2292
- type: Player,
2293
- args: {
2294
- token: (0, import_nexus6.nonNull)((0, import_nexus6.stringArg)())
2295
- },
2296
- async resolve(_, args, ctx) {
2297
- return loginAsTeam(args, ctx);
2298
- }
2299
- });
2300
- t.boolean("logoutAsTeam", {
2301
- async resolve(_, __, ctx) {
2302
- return logoutAsTeam(ctx);
2303
- }
2304
- });
2305
- t.field("createGame", {
2306
- type: Game,
2307
- args: {
2308
- name: (0, import_nexus6.nonNull)((0, import_nexus6.stringArg)()),
2309
- playerCount: (0, import_nexus6.nonNull)((0, import_nexus6.intArg)())
2310
- },
2311
- async resolve(_, args, ctx) {
2312
- return createGame(args, ctx, {
2313
- roleAssigner
2314
- });
2315
- }
2316
- });
2317
- t.field("addGamePeriod", {
2318
- type: Period,
2319
- args: {
2320
- gameId: (0, import_nexus6.nonNull)((0, import_nexus6.intArg)()),
2321
- facts: (0, import_nexus6.arg)({
2322
- type: (0, import_nexus6.nonNull)(inputTypes.PeriodFactsInput)
2323
- })
2324
- },
2325
- async resolve(_, args, ctx) {
2326
- return addGamePeriod(args, ctx, {
2327
- schema: schemas.PeriodFactsSchema,
2328
- reducers
2329
- });
2330
- }
2331
- });
2332
- t.field("addPeriodSegment", {
2333
- type: PeriodSegment,
2334
- args: {
2335
- gameId: (0, import_nexus6.nonNull)((0, import_nexus6.intArg)()),
2336
- periodIx: (0, import_nexus6.nonNull)((0, import_nexus6.intArg)()),
2337
- facts: (0, import_nexus6.arg)({
2338
- type: (0, import_nexus6.nonNull)(inputTypes.PeriodSegmentFactsInput)
2339
- }),
2340
- storyElements: (0, import_nexus6.list)((0, import_nexus6.stringArg)()),
2341
- learningElements: (0, import_nexus6.list)((0, import_nexus6.stringArg)())
2342
- },
2343
- async resolve(_, args, ctx) {
2344
- return addPeriodSegment(args, ctx, {
2345
- schema: schemas.PeriodSegmentFactsSchema,
2346
- reducers
2347
- });
2348
- }
2349
- });
2350
- t.field("activateNextPeriod", {
2351
- type: Game,
2352
- args: {
2353
- gameId: (0, import_nexus6.nonNull)((0, import_nexus6.intArg)())
2354
- },
2355
- async resolve(_, args, ctx) {
2356
- const results = await activateNextPeriod(args, ctx, {
2357
- reducers
2358
- });
2359
- if (!results)
2360
- return;
2361
- return results[0];
2362
- }
2363
- });
2364
- t.field("activateNextSegment", {
2365
- type: Game,
2366
- args: {
2367
- gameId: (0, import_nexus6.nonNull)((0, import_nexus6.intArg)())
2368
- },
2369
- async resolve(_, args, ctx) {
2370
- const results = await activateNextSegment(args, ctx, {
2371
- reducers
2372
- });
2373
- if (!results)
2374
- return;
2375
- return results[0];
2376
- }
2377
- });
2378
- t.field("performAction", {
2379
- type: PlayerResult,
2380
- args: {
2381
- type: (0, import_nexus6.nonNull)((0, import_nexus6.stringArg)()),
2382
- payload: (0, import_nexus6.nonNull)((0, import_nexus6.stringArg)())
2383
- },
2384
- async resolve(_, args, ctx) {
2385
- const currentGame = await getGameFromContext(ctx);
2386
- if (!currentGame?.activePeriod)
2387
- return null;
2388
- const facts = JSON.parse(args.payload);
2389
- const result = await performAction(
2390
- {
2391
- gameId: currentGame.id,
2392
- actionType: args.type,
2393
- playerId: ctx.user.sub,
2394
- periodIx: currentGame.activePeriodIx,
2395
- segmentIx: currentGame.activePeriod.activeSegmentIx,
2396
- facts
2397
- },
2398
- ctx,
2399
- { reducers }
2400
- );
2401
- return result;
2402
- }
2403
- });
2404
- t.field("attemptLearningElement", {
2405
- type: LearningElementAttempt,
2406
- args: {
2407
- elementId: (0, import_nexus6.nonNull)((0, import_nexus6.idArg)()),
2408
- selection: (0, import_nexus6.nonNull)((0, import_nexus6.stringArg)())
2409
- },
2410
- async resolve(_, args, ctx) {
2411
- return attemptLearningElement(args, ctx);
2412
- }
2413
- });
2414
- t.field("markStoryElement", {
2415
- type: Player,
2416
- args: {
2417
- elementId: (0, import_nexus6.nonNull)((0, import_nexus6.idArg)())
2418
- },
2419
- async resolve(_, args, ctx) {
2420
- return markStoryElement(args, ctx);
2421
- }
2422
- });
2423
- t.field("updatePlayerData", {
2424
- type: Player,
2425
- args: {
2426
- name: (0, import_nexus6.stringArg)(),
2427
- avatar: (0, import_nexus6.stringArg)(),
2428
- color: (0, import_nexus6.stringArg)(),
2429
- facts: (0, import_nexus6.stringArg)()
2430
- },
2431
- async resolve(_, args, ctx) {
2432
- const facts = args.facts ? JSON.parse(args.facts) : {};
2433
- return updatePlayerData({ ...args, facts }, ctx);
2434
- }
2435
- });
2436
- t.field("saveConsolidationDecision", {
2437
- type: PlayerDecision,
2438
- args: {
2439
- payload: (0, import_nexus6.nonNull)((0, import_nexus6.stringArg)())
2440
- },
2441
- async resolve(_, args, ctx) {
2442
- const facts = JSON.parse(args.payload);
2443
- return saveDecisions(
2444
- {
2445
- decisionType: DB8.PlayerDecisionType.CONSOLIDATION,
2446
- facts
2447
- },
2448
- ctx
2449
- );
2450
- }
2451
- });
2452
- t.boolean("addCountdown", {
2453
- args: {
2454
- gameId: (0, import_nexus6.nonNull)((0, import_nexus6.intArg)()),
2455
- seconds: (0, import_nexus6.nonNull)((0, import_nexus6.intArg)())
2456
- },
2457
- async resolve(_, args, ctx) {
2458
- return addCountdown(args, ctx);
2459
- }
2460
- });
2461
- }
2462
- });
2463
- }
2464
- var Mutation = generateBaseMutations();
2465
-
2466
- // src/types/Query.ts
2467
- var import_nexus7 = require("nexus");
2468
- function generateBaseQueries() {
2469
- return (0, import_nexus7.objectType)({
2470
- name: "Query",
2471
- definition(t) {
2472
- t.list.nonNull.field("games", {
2473
- type: Game,
2474
- async resolve(_, args, ctx) {
2475
- return getGames(args, ctx);
2476
- }
2477
- });
2478
- t.field("game", {
2479
- type: Game,
2480
- args: {
2481
- id: (0, import_nexus7.intArg)()
2482
- },
2483
- async resolve(_, args, ctx) {
2484
- return getGame(args, ctx);
2485
- }
2486
- });
2487
- t.field("result", {
2488
- type: PlayerState,
2489
- async resolve(_, args, ctx) {
2490
- return getPlayerResult(
2491
- { gameId: ctx.user.gameId, playerId: ctx.user.sub },
2492
- ctx
2493
- );
2494
- }
2495
- });
2496
- t.field("self", {
2497
- type: Player,
2498
- async resolve(_, args, ctx) {
2499
- if (!ctx.user)
2500
- return null;
2501
- return getPlayerData({ playerId: ctx.user.sub }, ctx);
2502
- }
2503
- });
2504
- t.list.nonNull.field("learningElements", {
2505
- type: LearningElement,
2506
- async resolve(_, args, ctx) {
2507
- return getLearningElements(args, ctx);
2508
- }
2509
- });
2510
- t.field("learningElement", {
2511
- type: LearningElementState,
2512
- args: {
2513
- id: (0, import_nexus7.nonNull)((0, import_nexus7.idArg)())
2514
- },
2515
- async resolve(_, args, ctx) {
2516
- return getLearningElement(args, ctx);
2517
- }
2518
- });
2519
- t.list.nonNull.field("results", {
2520
- type: PlayerResult,
2521
- async resolve(_, args, ctx) {
2522
- return getPlayerResults(args, ctx);
2523
- }
2524
- });
2525
- t.list.nonNull.field("pastResults", {
2526
- type: PlayerResult,
2527
- async resolve(_, args, ctx) {
2528
- return getPastResults(args, ctx);
2529
- }
2530
- });
2531
- }
2532
- });
2533
- }
2534
- var Query = generateBaseQueries();
2535
-
2536
- // src/types/Subscription.ts
2537
- var import_nexus8 = require("nexus");
2538
- function generateBaseSubscriptions() {
2539
- return (0, import_nexus8.subscriptionType)({
2540
- definition(t) {
2541
- t.list.nonNull.field("eventsGlobal", {
2542
- type: Event,
2543
- async subscribe(_, args, ctx) {
2544
- return pubSub.subscribe("global:events");
2545
- },
2546
- async resolve(payload) {
2547
- return payload;
2548
- }
2549
- });
2550
- t.list.nonNull.field("eventsUser", {
2551
- type: Event,
2552
- async subscribe(_, args, ctx) {
2553
- if (ctx.user) {
2554
- return pubSub.subscribe("user:events", String(ctx.user.sub));
2555
- }
2556
- return pubSub.subscribe("user:events", "anonymous");
2557
- },
2558
- async resolve(payload) {
2559
- return payload;
2560
- }
2561
- });
2562
- }
2563
- });
2564
- }
2565
- var Subscription = generateBaseSubscriptions();
2566
-
2567
- // src/nexus.ts
2568
- var JsonScalar = (0, import_nexus10.asNexusMethod)(import_graphql_scalars.JSONObjectResolver, "json");
2569
- var DateScalar = (0, import_nexus10.asNexusMethod)(import_graphql_scalars.DateTimeResolver, "date");
2570
- var UserRole3 = (0, import_nexus10.enumType)({
2571
- name: "UserRole",
2572
- members: Object.values(DB9.UserRole)
2573
- });
2574
- var Event = (0, import_nexus10.objectType)({
2575
- name: "Event",
2576
- definition(t) {
2577
- t.string("type");
2578
- }
2579
- });
2580
- // Annotate the CommonJS export names for ESM import in node:
2581
- 0 && (module.exports = {
2582
- DateScalar,
2583
- Event,
2584
- Game,
2585
- GameStatus,
2586
- JsonScalar,
2587
- LearningAnswerOption,
2588
- LearningElement,
2589
- LearningElementAttempt,
2590
- LearningElementState,
2591
- Mutation,
2592
- Period,
2593
- PeriodSegment,
2594
- Player,
2595
- PlayerAction,
2596
- PlayerDecision,
2597
- PlayerDecisionType,
2598
- PlayerLevel,
2599
- PlayerResult,
2600
- PlayerResultType,
2601
- PlayerState,
2602
- Query,
2603
- Subscription,
2604
- UserRole,
2605
- generateBaseMutations,
2606
- generateBaseQueries,
2607
- generateBaseSubscriptions
2608
- });
24
+ export { DateScalar, Event, JsonScalar, UserRole };
25
+ //# sourceMappingURL=nexus.js.map