@gbl-uzh/platform 0.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1941 @@
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
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
25
+
26
+ // src/index.ts
27
+ var src_exports = {};
28
+ __export(src_exports, {
29
+ AccountService: () => AccountService_exports,
30
+ BaseGlobalNotificationType: () => BaseGlobalNotificationType,
31
+ BaseUserNotificationType: () => BaseUserNotificationType,
32
+ EventService: () => EventService_exports,
33
+ GameService: () => GameService_exports,
34
+ LearningElementState: () => LearningElementState,
35
+ PlayService: () => PlayService_exports,
36
+ UserRole: () => UserRole
37
+ });
38
+ module.exports = __toCommonJS(src_exports);
39
+
40
+ // src/services/AccountService.ts
41
+ var AccountService_exports = {};
42
+ __export(AccountService_exports, {
43
+ createLoginToken: () => createLoginToken,
44
+ loginAsTeam: () => loginAsTeam
45
+ });
46
+ var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
47
+ var import_node_assert = require("assert");
48
+ var import_nookies = require("nookies");
49
+
50
+ // src/types.ts
51
+ var UserRole = /* @__PURE__ */ ((UserRole2) => {
52
+ UserRole2["PLAYER"] = "PLAYER";
53
+ UserRole2["ADMIN"] = "ADMIN";
54
+ return UserRole2;
55
+ })(UserRole || {});
56
+ var LearningElementState = /* @__PURE__ */ ((LearningElementState2) => {
57
+ LearningElementState2["NEW"] = "NEW";
58
+ LearningElementState2["ATTEMPTED"] = "ATTEMPTED";
59
+ LearningElementState2["SOLVED"] = "SOLVED";
60
+ return LearningElementState2;
61
+ })(LearningElementState || {});
62
+ var BaseGlobalNotificationType = /* @__PURE__ */ ((BaseGlobalNotificationType2) => {
63
+ BaseGlobalNotificationType2["PERIOD_ACTIVATED"] = "PERIOD_ACTIVATED";
64
+ BaseGlobalNotificationType2["SEGMENT_ACTIVATED"] = "SEGMENT_ACTIVATED";
65
+ return BaseGlobalNotificationType2;
66
+ })(BaseGlobalNotificationType || {});
67
+ var BaseUserNotificationType = /* @__PURE__ */ ((BaseUserNotificationType2) => {
68
+ BaseUserNotificationType2["LEARNING_ELEMENT_SOLVED"] = "LEARNING_ELEMENT_SOLVED";
69
+ BaseUserNotificationType2["LEARNING_ELEMENT_INCORRECT"] = "LEARNING_ELEMENT_INCORRECT";
70
+ BaseUserNotificationType2["ACHIEVEMENT_RECEIVED"] = "ACHIEVEMENT_RECEIVED";
71
+ BaseUserNotificationType2["LEVEL_UP"] = "LEVEL_UP";
72
+ return BaseUserNotificationType2;
73
+ })(BaseUserNotificationType || {});
74
+
75
+ // src/services/AccountService.ts
76
+ function createLoginToken({
77
+ sub,
78
+ role,
79
+ ...extra
80
+ }) {
81
+ (0, import_node_assert.strict)(typeof process.env.NEXTAUTH_SECRET === "string");
82
+ return import_jsonwebtoken.default.sign({ sub, role, ...extra }, process.env.NEXTAUTH_SECRET, {
83
+ expiresIn: "1 week"
84
+ });
85
+ }
86
+ async function loginAsTeam({ token }, ctx) {
87
+ const matchingPlayer = await ctx.prisma.player.findUnique({
88
+ where: { token },
89
+ include: {
90
+ level: true,
91
+ achievements: {
92
+ include: {
93
+ achievement: true
94
+ }
95
+ }
96
+ }
97
+ });
98
+ if (!matchingPlayer) {
99
+ throw new Error("INVALID_TOKEN");
100
+ }
101
+ try {
102
+ const jwt = createLoginToken({
103
+ gameId: matchingPlayer.gameId,
104
+ sub: matchingPlayer.id,
105
+ role: "PLAYER" /* PLAYER */,
106
+ token: matchingPlayer.token
107
+ });
108
+ (0, import_nookies.setCookie)(
109
+ ctx,
110
+ process.env.NODE_ENV === "production" ? "__Secure-next-auth.session-token" : "next-auth.session-token",
111
+ jwt,
112
+ {
113
+ path: "/",
114
+ maxAge: 60 * 60 * 24 * 7,
115
+ httpOnly: process.env.NODE_ENV === "production",
116
+ secure: process.env.NODE_ENV === "production"
117
+ }
118
+ );
119
+ } catch (err) {
120
+ console.error(err);
121
+ return null;
122
+ }
123
+ return matchingPlayer;
124
+ }
125
+
126
+ // src/services/EventService.ts
127
+ var EventService_exports = {};
128
+ __export(EventService_exports, {
129
+ publishGlobalNotification: () => publishGlobalNotification,
130
+ publishUserNotification: () => publishUserNotification,
131
+ receiveEvent: () => receiveEvent,
132
+ receiveEvents: () => receiveEvents
133
+ });
134
+
135
+ // src/generated/ops.ts
136
+ var GameDataFragmentDoc = { "kind": "Document", "definitions": [{ "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "GameData" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Game" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "activePeriodIx" } }] } }] };
137
+ var LearningElementDataFragmentDoc = { "kind": "Document", "definitions": [{ "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "LearningElementData" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "LearningElement" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "title" } }, { "kind": "Field", "name": { "kind": "Name", "value": "question" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reward" } }, { "kind": "Field", "name": { "kind": "Name", "value": "motivation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "feedback" } }] } }] };
138
+ var SegmentDataFragmentDoc = { "kind": "Document", "definitions": [{ "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "SegmentData" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "PeriodSegment" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "index" } }, { "kind": "Field", "name": { "kind": "Name", "value": "facts" } }, { "kind": "Field", "name": { "kind": "Name", "value": "learningElements" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "storyElements" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }] } }] } }] };
139
+ var PeriodDataFragmentDoc = { "kind": "Document", "definitions": [{ "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "PeriodData" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Period" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "index" } }, { "kind": "Field", "name": { "kind": "Name", "value": "activeSegmentIx" } }, { "kind": "Field", "name": { "kind": "Name", "value": "facts" } }, { "kind": "Field", "name": { "kind": "Name", "value": "segments" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "SegmentData" } }] } }] } }, ...SegmentDataFragmentDoc.definitions] };
140
+ var PlayerActionDataFragmentDoc = { "kind": "Document", "definitions": [{ "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "PlayerActionData" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "PlayerAction" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "periodIx" } }, { "kind": "Field", "name": { "kind": "Name", "value": "segmentIx" } }, { "kind": "Field", "name": { "kind": "Name", "value": "type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "facts" } }] } }] };
141
+ var PlayerDataFragmentDoc = { "kind": "Document", "definitions": [{ "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "PlayerData" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Player" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "isReady" } }, { "kind": "Field", "name": { "kind": "Name", "value": "role" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "avatar" } }, { "kind": "Field", "name": { "kind": "Name", "value": "location" } }, { "kind": "Field", "name": { "kind": "Name", "value": "color" } }, { "kind": "Field", "name": { "kind": "Name", "value": "facts" } }, { "kind": "Field", "name": { "kind": "Name", "value": "experience" } }, { "kind": "Field", "name": { "kind": "Name", "value": "experienceToNext" } }, { "kind": "Field", "name": { "kind": "Name", "value": "achievementKeys" } }, { "kind": "Field", "name": { "kind": "Name", "value": "achievements" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "achievement" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reward" } }] } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "level" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "index" } }] } }] } }] };
142
+ var ResultDataFragmentDoc = { "kind": "Document", "definitions": [{ "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ResultData" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "PlayerResult" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "facts" } }, { "kind": "Field", "name": { "kind": "Name", "value": "period" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "index" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "segment" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "index" } }] } }] } }] };
143
+ var ActivateNextPeriodDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "ActivateNextPeriod" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "gameId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "activateNextPeriod" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "gameId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "gameId" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "GameData" } }, { "kind": "Field", "name": { "kind": "Name", "value": "periods" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "PeriodData" } }] } }] } }] } }, ...GameDataFragmentDoc.definitions, ...PeriodDataFragmentDoc.definitions] };
144
+ var ActivateNextSegmentDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "ActivateNextSegment" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "gameId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "activateNextSegment" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "gameId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "gameId" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "GameData" } }, { "kind": "Field", "name": { "kind": "Name", "value": "periods" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "PeriodData" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "players" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "PlayerData" } }] } }] } }] } }, ...GameDataFragmentDoc.definitions, ...PeriodDataFragmentDoc.definitions, ...PlayerDataFragmentDoc.definitions] };
145
+ var AddGamePeriodDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "AddGamePeriod" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "gameId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "facts" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "PeriodFactsInput" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "addGamePeriod" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "gameId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "gameId" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "facts" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "facts" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "PeriodData" } }] } }] } }, ...PeriodDataFragmentDoc.definitions] };
146
+ var AddPeriodSegmentDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "AddPeriodSegment" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "gameId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "periodIx" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "facts" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "PeriodSegmentFactsInput" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "storyElements" } }, "type": { "kind": "ListType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "learningElements" } }, "type": { "kind": "ListType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "addPeriodSegment" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "gameId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "gameId" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "periodIx" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "periodIx" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "facts" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "facts" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "storyElements" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "storyElements" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "learningElements" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "learningElements" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "SegmentData" } }] } }] } }, ...SegmentDataFragmentDoc.definitions] };
147
+ var CreateGameDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "CreateGame" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "name" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "playerCount" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "createGame" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "name" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "name" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "playerCount" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "playerCount" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "GameData" } }] } }] } }, ...GameDataFragmentDoc.definitions] };
148
+ var LoginAsTeamDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "LoginAsTeam" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "token" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "loginAsTeam" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "token" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "token" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "PlayerData" } }] } }] } }, ...PlayerDataFragmentDoc.definitions] };
149
+ var PerformActionDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "PerformAction" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "type" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "payload" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "performAction" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "type" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "type" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "payload" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "payload" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ResultData" } }] } }] } }, ...ResultDataFragmentDoc.definitions] };
150
+ var UpdatePlayerDataDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "UpdatePlayerData" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "name" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "avatar" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "color" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "facts" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "updatePlayerData" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "name" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "name" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "avatar" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "avatar" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "color" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "color" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "facts" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "facts" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "PlayerData" } }] } }] } }, ...PlayerDataFragmentDoc.definitions] };
151
+ var GameDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "Game" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "game" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "GameData" } }, { "kind": "Field", "name": { "kind": "Name", "value": "activePeriod" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "activeSegmentIx" } }, { "kind": "Field", "name": { "kind": "Name", "value": "segments" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }] } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "periods" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "PeriodData" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "players" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "isReady" } }, { "kind": "Field", "name": { "kind": "Name", "value": "role" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "avatar" } }, { "kind": "Field", "name": { "kind": "Name", "value": "location" } }, { "kind": "Field", "name": { "kind": "Name", "value": "color" } }, { "kind": "Field", "name": { "kind": "Name", "value": "facts" } }, { "kind": "Field", "name": { "kind": "Name", "value": "experience" } }, { "kind": "Field", "name": { "kind": "Name", "value": "experienceToNext" } }, { "kind": "Field", "name": { "kind": "Name", "value": "token" } }] } }] } }] } }, ...GameDataFragmentDoc.definitions, ...PeriodDataFragmentDoc.definitions] };
152
+ var GamesDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "Games" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "games" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "GameData" } }] } }] } }, ...GameDataFragmentDoc.definitions] };
153
+ var LearningElementDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "LearningElement" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "ID" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "learningElement" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "element" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "LearningElementData" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "content" } }] } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "state" } }, { "kind": "Field", "name": { "kind": "Name", "value": "solution" } }] } }] } }, ...LearningElementDataFragmentDoc.definitions] };
154
+ var LearningElementsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "LearningElements" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "learningElements" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "LearningElementData" } }] } }] } }, ...LearningElementDataFragmentDoc.definitions] };
155
+ var PastResultsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "PastResults" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "result" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "currentGame" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "pastResults" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ResultData" } }, { "kind": "Field", "name": { "kind": "Name", "value": "player" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "role" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "avatar" } }, { "kind": "Field", "name": { "kind": "Name", "value": "color" } }, { "kind": "Field", "name": { "kind": "Name", "value": "facts" } }, { "kind": "Field", "name": { "kind": "Name", "value": "experience" } }, { "kind": "Field", "name": { "kind": "Name", "value": "experienceToNext" } }, { "kind": "Field", "name": { "kind": "Name", "value": "level" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "index" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "completedLearningElementIds" } }, { "kind": "Field", "name": { "kind": "Name", "value": "visitedStoryElementIds" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "period" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "index" } }, { "kind": "Field", "name": { "kind": "Name", "value": "facts" } }] } }] } }] } }, ...ResultDataFragmentDoc.definitions] };
156
+ var ResultDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "Result" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "result" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "playerResult" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ResultData" } }, { "kind": "Field", "name": { "kind": "Name", "value": "player" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "completedLearningElementIds" } }, { "kind": "Field", "name": { "kind": "Name", "value": "visitedStoryElementIds" } }] } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "previousResults" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ResultData" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "currentGame" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "periods" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "PeriodData" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "activePeriod" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "PeriodData" } }, { "kind": "Field", "name": { "kind": "Name", "value": "activeSegment" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "index" } }, { "kind": "Field", "name": { "kind": "Name", "value": "facts" } }, { "kind": "Field", "name": { "kind": "Name", "value": "learningElements" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "title" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "storyElements" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "title" } }, { "kind": "Field", "name": { "kind": "Name", "value": "content" } }, { "kind": "Field", "name": { "kind": "Name", "value": "contentRole" } }] } }] } }] } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "transactions" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "PlayerActionData" } }] } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "self" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "PlayerData" } }] } }] } }, ...ResultDataFragmentDoc.definitions, ...PeriodDataFragmentDoc.definitions, ...PlayerActionDataFragmentDoc.definitions, ...PlayerDataFragmentDoc.definitions] };
157
+ var ResultsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "Results" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "results" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ResultData" } }, { "kind": "Field", "name": { "kind": "Name", "value": "player" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }] } }] } }] } }, ...ResultDataFragmentDoc.definitions] };
158
+ var SelfDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "Self" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "self" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "PlayerData" } }] } }] } }, ...PlayerDataFragmentDoc.definitions] };
159
+
160
+ // src/lib/pubsub.ts
161
+ var import_graphql_yoga = require("graphql-yoga");
162
+ var pubSub = (0, import_graphql_yoga.createPubSub)();
163
+
164
+ // src/services/EventService.ts
165
+ async function receiveEvents({ events, ctx, prisma }) {
166
+ if (!Array.isArray(events))
167
+ return;
168
+ const definedEvents = await prisma.event.findMany({
169
+ include: {
170
+ achievements: true
171
+ }
172
+ });
173
+ const definedLevels = await prisma.playerLevel.findMany();
174
+ const promises = await Promise.all(
175
+ events.map(
176
+ async (event) => receiveEvent({ ...event, ctx }, definedEvents, definedLevels, prisma)
177
+ )
178
+ );
179
+ const results = prisma.$transaction(promises.flat());
180
+ return results;
181
+ }
182
+ function prepareAchievementData({
183
+ achievementId,
184
+ gameId,
185
+ periodIx,
186
+ playerId,
187
+ count
188
+ }) {
189
+ return {
190
+ count,
191
+ achievement: { connect: { id: achievementId } },
192
+ game: { connect: { id: gameId } },
193
+ period: { connect: { gameId_index: { gameId, index: periodIx } } },
194
+ player: { connect: { id: playerId } }
195
+ };
196
+ }
197
+ async function receiveEvent(event, definedEvents, definedLevels, prisma) {
198
+ var _a;
199
+ const matchingEvent = definedEvents.find((item) => item.id === event.type);
200
+ if (matchingEvent && ((_a = matchingEvent.achievements) == null ? void 0 : _a.length) > 0) {
201
+ const awardedAchievements = await matchingEvent.achievements.reduce(
202
+ async (acc, achievement) => {
203
+ var _a2;
204
+ if (achievement.when === "FIRST" /* First */ && event.ctx.achievements.includes(achievement.id)) {
205
+ return acc;
206
+ }
207
+ const existingInstance = await prisma.achievementInstance.findFirst({
208
+ where: {
209
+ achievement: {
210
+ id: achievement.id
211
+ },
212
+ player: {
213
+ id: event.ctx.args.playerId
214
+ }
215
+ }
216
+ });
217
+ let achievementInstance;
218
+ if (existingInstance) {
219
+ achievementInstance = await prisma.achievementInstance.update({
220
+ where: {
221
+ id: existingInstance.id
222
+ },
223
+ data: prepareAchievementData({
224
+ count: existingInstance.count + 1,
225
+ achievementId: achievement.id,
226
+ gameId: event.ctx.args.gameId,
227
+ periodIx: event.ctx.args.periodIx,
228
+ playerId: event.ctx.args.playerId
229
+ })
230
+ });
231
+ } else {
232
+ achievementInstance = await prisma.achievementInstance.create({
233
+ data: prepareAchievementData({
234
+ count: 1,
235
+ achievementId: achievement.id,
236
+ gameId: event.ctx.args.gameId,
237
+ periodIx: event.ctx.args.periodIx,
238
+ playerId: event.ctx.args.playerId
239
+ })
240
+ });
241
+ }
242
+ return {
243
+ achievements: [
244
+ ...acc.achievements,
245
+ {
246
+ achievement,
247
+ achievementInstance
248
+ }
249
+ ],
250
+ achievementKeys: [...acc.achievementKeys, achievement.id],
251
+ rewards: {
252
+ ...acc.rewards,
253
+ xp: (acc.rewards.xp ?? 0) + (((_a2 = achievement.reward) == null ? void 0 : _a2.xp) ?? 0)
254
+ }
255
+ };
256
+ },
257
+ {
258
+ achievements: [],
259
+ achievementKeys: [],
260
+ rewards: {}
261
+ }
262
+ );
263
+ const currentLevelPlus1 = definedLevels.find(
264
+ (level) => level.index === event.ctx.currentLevelIx + 1
265
+ );
266
+ const currentLevelPlus2 = definedLevels.find(
267
+ (level) => level.index === event.ctx.currentLevelIx + 2
268
+ );
269
+ if (awardedAchievements.achievements.length > 0) {
270
+ if (event.ctx.experience + awardedAchievements.rewards.xp >= currentLevelPlus1.requiredXP) {
271
+ publishUserNotification(
272
+ {
273
+ user: {
274
+ sub: event.ctx.args.playerId
275
+ }
276
+ },
277
+ [
278
+ {
279
+ type: "ACHIEVEMENT_RECEIVED" /* ACHIEVEMENT_RECEIVED */
280
+ }
281
+ ]
282
+ );
283
+ publishUserNotification(
284
+ {
285
+ user: {
286
+ sub: event.ctx.args.playerId
287
+ }
288
+ },
289
+ [
290
+ {
291
+ type: "LEVEL_UP" /* LEVEL_UP */
292
+ }
293
+ ]
294
+ );
295
+ return [
296
+ prisma.player.update({
297
+ where: {
298
+ id: event.ctx.args.playerId
299
+ },
300
+ data: {
301
+ experience: {
302
+ increment: awardedAchievements.rewards.xp
303
+ },
304
+ experienceToNext: currentLevelPlus2.requiredXP,
305
+ level: {
306
+ connect: {
307
+ index: currentLevelPlus1.index
308
+ }
309
+ },
310
+ achievementKeys: {
311
+ push: awardedAchievements.achievementKeys
312
+ }
313
+ }
314
+ })
315
+ ];
316
+ } else {
317
+ publishUserNotification(
318
+ {
319
+ user: {
320
+ sub: event.ctx.args.playerId
321
+ }
322
+ },
323
+ [
324
+ {
325
+ type: "ACHIEVEMENT_RECEIVED" /* ACHIEVEMENT_RECEIVED */
326
+ }
327
+ ]
328
+ );
329
+ return [
330
+ prisma.player.update({
331
+ where: {
332
+ id: event.ctx.args.playerId
333
+ },
334
+ data: {
335
+ experience: {
336
+ increment: awardedAchievements.rewards.xp
337
+ },
338
+ achievementKeys: {
339
+ push: awardedAchievements.achievementKeys
340
+ }
341
+ }
342
+ })
343
+ ];
344
+ }
345
+ }
346
+ return [];
347
+ }
348
+ return [];
349
+ }
350
+ function publishGlobalNotification(event) {
351
+ pubSub.publish("global:events", event);
352
+ }
353
+ function publishUserNotification(ctx, events) {
354
+ if (events && events.length > 0) {
355
+ pubSub.publish("user:events", ctx.user.sub, events);
356
+ }
357
+ }
358
+
359
+ // src/services/GameService.ts
360
+ var GameService_exports = {};
361
+ __export(GameService_exports, {
362
+ activateNextPeriod: () => activateNextPeriod,
363
+ activateNextSegment: () => activateNextSegment,
364
+ addGamePeriod: () => addGamePeriod,
365
+ addPeriodSegment: () => addPeriodSegment,
366
+ computePeriodEndResults: () => computePeriodEndResults,
367
+ computePeriodStartResults: () => computePeriodStartResults,
368
+ computeSegmentEndResults: () => computeSegmentEndResults,
369
+ computeSegmentStartResults: () => computeSegmentStartResults,
370
+ createGame: () => createGame,
371
+ getGame: () => getGame,
372
+ getGameFromContext: () => getGameFromContext,
373
+ getGames: () => getGames,
374
+ getLearningElements: () => getLearningElements,
375
+ updatePlayerData: () => updatePlayerData
376
+ });
377
+
378
+ // ../../node_modules/nanoid/index.js
379
+ var import_crypto = __toESM(require("crypto"), 1);
380
+
381
+ // ../../node_modules/nanoid/url-alphabet/index.js
382
+ var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
383
+
384
+ // ../../node_modules/nanoid/index.js
385
+ var POOL_SIZE_MULTIPLIER = 128;
386
+ var pool;
387
+ var poolOffset;
388
+ var fillPool = (bytes) => {
389
+ if (!pool || pool.length < bytes) {
390
+ pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
391
+ import_crypto.default.randomFillSync(pool);
392
+ poolOffset = 0;
393
+ } else if (poolOffset + bytes > pool.length) {
394
+ import_crypto.default.randomFillSync(pool);
395
+ poolOffset = 0;
396
+ }
397
+ poolOffset += bytes;
398
+ };
399
+ var nanoid = (size = 21) => {
400
+ fillPool(size -= 0);
401
+ let id = "";
402
+ for (let i = poolOffset - size; i < poolOffset; i++) {
403
+ id += urlAlphabet[pool[i] & 63];
404
+ }
405
+ return id;
406
+ };
407
+
408
+ // src/services/GameService.ts
409
+ var import_ramda = require("ramda");
410
+ var yup = __toESM(require("yup"));
411
+ async function createGame({ name, playerCount }, ctx, { roleAssigner }) {
412
+ return ctx.prisma.game.create({
413
+ data: {
414
+ name,
415
+ owner: {
416
+ connect: {
417
+ id: ctx.user.sub
418
+ }
419
+ },
420
+ players: {
421
+ create: (0, import_ramda.repeat)(0, playerCount).map((_, ix) => {
422
+ return {
423
+ facts: {},
424
+ token: nanoid(),
425
+ role: roleAssigner(ix),
426
+ level: {
427
+ connect: {
428
+ index: 0
429
+ }
430
+ }
431
+ };
432
+ })
433
+ }
434
+ },
435
+ include: {
436
+ players: true,
437
+ periods: true
438
+ }
439
+ });
440
+ }
441
+ async function addGamePeriod({ gameId, facts }, ctx, { schema, reducers }) {
442
+ var _a, _b, _c, _d;
443
+ const validatedFacts = schema.validateSync(facts);
444
+ const game = await ctx.prisma.game.findUnique({
445
+ where: {
446
+ id: gameId
447
+ },
448
+ include: {
449
+ periods: {
450
+ orderBy: {
451
+ index: "desc"
452
+ },
453
+ take: 1,
454
+ include: {
455
+ segments: {
456
+ orderBy: {
457
+ index: "desc"
458
+ },
459
+ take: 1
460
+ }
461
+ }
462
+ }
463
+ }
464
+ });
465
+ if (!game)
466
+ return null;
467
+ const index = ((_a = game.periods[0]) == null ? void 0 : _a.index) + 1 || 0;
468
+ const { result: initializedFacts } = reducers.Period.apply(validatedFacts, {
469
+ type: reducers.Period.ActionTypes.PERIOD_INITIALIZE,
470
+ payload: {
471
+ periodFacts: validatedFacts,
472
+ previousPeriodFacts: (_b = game.periods[0]) == null ? void 0 : _b.facts,
473
+ previousSegmentFacts: (_d = (_c = game.periods[0]) == null ? void 0 : _c.segments[0]) == null ? void 0 : _d.facts,
474
+ periodIx: index
475
+ }
476
+ });
477
+ return ctx.prisma.period.upsert({
478
+ where: {
479
+ gameId_index: {
480
+ gameId,
481
+ index
482
+ }
483
+ },
484
+ create: {
485
+ index,
486
+ facts: initializedFacts,
487
+ game: {
488
+ connect: {
489
+ id: gameId
490
+ }
491
+ },
492
+ previousPeriod: {
493
+ connect: index > 0 ? {
494
+ gameId_index: {
495
+ gameId,
496
+ index: index - 1
497
+ }
498
+ } : []
499
+ }
500
+ },
501
+ update: {
502
+ facts: initializedFacts
503
+ },
504
+ include: {
505
+ segments: {
506
+ include: {
507
+ learningElements: true,
508
+ storyElements: true
509
+ }
510
+ }
511
+ }
512
+ });
513
+ }
514
+ async function addPeriodSegment({
515
+ gameId,
516
+ periodIx,
517
+ facts,
518
+ learningElements,
519
+ storyElements
520
+ }, ctx, { schema, reducers }) {
521
+ var _a, _b;
522
+ const validatedFacts = schema.validateSync(facts);
523
+ const period = await ctx.prisma.period.findUnique({
524
+ where: {
525
+ gameId_index: {
526
+ gameId,
527
+ index: periodIx
528
+ }
529
+ },
530
+ include: {
531
+ segments: {
532
+ orderBy: {
533
+ index: "desc"
534
+ },
535
+ take: 1
536
+ }
537
+ }
538
+ });
539
+ if (!period)
540
+ return null;
541
+ const index = ((_a = period.segments[0]) == null ? void 0 : _a.index) + 1 || 0;
542
+ const { result: initializedFacts } = reducers.Segment.apply(validatedFacts, {
543
+ type: reducers.Segment.ActionTypes.SEGMENT_INITIALIZE,
544
+ payload: {
545
+ periodFacts: period.facts,
546
+ previousSegmentFacts: (_b = period.segments[0]) == null ? void 0 : _b.facts,
547
+ segmentIx: index,
548
+ segmentCount: 4,
549
+ periodIx
550
+ }
551
+ });
552
+ return ctx.prisma.periodSegment.upsert({
553
+ where: {
554
+ gameId_periodIx_index: {
555
+ gameId,
556
+ periodIx,
557
+ index
558
+ }
559
+ },
560
+ create: {
561
+ index,
562
+ facts: initializedFacts,
563
+ learningElements: {
564
+ connect: learningElements ? learningElements.map((item) => ({ id: item })) : []
565
+ },
566
+ storyElements: {
567
+ connect: storyElements ? storyElements.map((item) => ({ id: item })) : []
568
+ },
569
+ game: {
570
+ connect: {
571
+ id: gameId
572
+ }
573
+ },
574
+ periodIx,
575
+ period: {
576
+ connect: {
577
+ gameId_index: {
578
+ gameId,
579
+ index: periodIx
580
+ }
581
+ }
582
+ },
583
+ previousSegment: {
584
+ connect: index > 0 ? {
585
+ gameId_periodIx_index: {
586
+ gameId,
587
+ periodIx,
588
+ index: index - 1
589
+ }
590
+ } : []
591
+ }
592
+ },
593
+ update: {
594
+ facts: initializedFacts,
595
+ learningElements: {
596
+ connect: learningElements ? learningElements.map((item) => ({ id: item })) : []
597
+ },
598
+ storyElements: {
599
+ connect: storyElements ? storyElements.map((item) => ({ id: item })) : []
600
+ }
601
+ },
602
+ include: {
603
+ learningElements: true,
604
+ storyElements: true
605
+ }
606
+ });
607
+ }
608
+ async function activateNextPeriod({ gameId }, ctx, { reducers }) {
609
+ var _a, _b, _c, _d, _e;
610
+ const game = await ctx.prisma.game.findUnique({
611
+ where: {
612
+ id: gameId
613
+ },
614
+ include: {
615
+ players: true,
616
+ periods: true,
617
+ activePeriod: {
618
+ include: {
619
+ results: {
620
+ include: {
621
+ player: true
622
+ }
623
+ },
624
+ nextPeriod: true,
625
+ previousPeriod: {
626
+ include: {
627
+ results: {
628
+ include: {
629
+ player: true
630
+ }
631
+ }
632
+ }
633
+ },
634
+ activeSegment: {
635
+ include: {
636
+ results: {
637
+ include: {
638
+ player: true
639
+ }
640
+ }
641
+ }
642
+ },
643
+ decisions: {
644
+ include: {
645
+ player: true
646
+ }
647
+ }
648
+ }
649
+ }
650
+ }
651
+ });
652
+ if (!game)
653
+ return null;
654
+ const currentPeriodIx = game.activePeriodIx;
655
+ const currentSegmentIx = (_a = game.activePeriod) == null ? void 0 : _a.activeSegmentIx;
656
+ const nextPeriodIx = currentPeriodIx + 1;
657
+ switch (game.status) {
658
+ case "SCHEDULED" /* Scheduled */: {
659
+ const { results, extras } = computePeriodStartResults(
660
+ {
661
+ results: void 0,
662
+ players: game.players,
663
+ activePeriodIx: currentPeriodIx,
664
+ gameId: game.id,
665
+ periodFacts: (_b = game.periods) == null ? void 0 : _b[0].facts
666
+ },
667
+ ctx,
668
+ { reducers }
669
+ );
670
+ const result = await ctx.prisma.$transaction([
671
+ ctx.prisma.game.update({
672
+ where: {
673
+ id: gameId
674
+ },
675
+ data: {
676
+ status: "PREPARATION" /* Preparation */,
677
+ activePeriodIx: nextPeriodIx,
678
+ activePeriod: {
679
+ connect: {
680
+ gameId_index: {
681
+ gameId,
682
+ index: nextPeriodIx
683
+ }
684
+ }
685
+ }
686
+ }
687
+ }),
688
+ ctx.prisma.period.update({
689
+ where: {
690
+ gameId_index: {
691
+ gameId,
692
+ index: nextPeriodIx
693
+ }
694
+ },
695
+ data: {
696
+ results: {
697
+ create: results
698
+ }
699
+ }
700
+ }),
701
+ ...extras
702
+ ]);
703
+ return result;
704
+ }
705
+ case "RUNNING" /* Running */: {
706
+ if (!((_c = game.activePeriod) == null ? void 0 : _c.activeSegment) || !currentSegmentIx)
707
+ return null;
708
+ const { results, extras } = computeSegmentEndResults(game, ctx, {
709
+ reducers
710
+ });
711
+ const { result: consolidatedFacts } = reducers.Period.apply(
712
+ game.activePeriod.facts,
713
+ {
714
+ type: reducers.Period.ActionTypes.PERIOD_CONSOLIDATE,
715
+ payload: {
716
+ previousSegmentFacts: game.activePeriod.activeSegment.facts,
717
+ periodIx: currentPeriodIx
718
+ }
719
+ }
720
+ );
721
+ const result = await ctx.prisma.$transaction([
722
+ ctx.prisma.game.update({
723
+ data: {
724
+ status: "CONSOLIDATION" /* Consolidation */
725
+ },
726
+ where: {
727
+ id: gameId
728
+ }
729
+ }),
730
+ ctx.prisma.period.update({
731
+ where: {
732
+ gameId_index: {
733
+ gameId,
734
+ index: currentPeriodIx
735
+ }
736
+ },
737
+ data: {
738
+ facts: consolidatedFacts
739
+ }
740
+ }),
741
+ ctx.prisma.periodSegment.update({
742
+ where: {
743
+ gameId_periodIx_index: {
744
+ gameId,
745
+ periodIx: currentPeriodIx,
746
+ index: currentSegmentIx
747
+ }
748
+ },
749
+ data: {
750
+ results: {
751
+ update: results
752
+ }
753
+ },
754
+ include: {
755
+ results: {
756
+ include: {
757
+ player: true
758
+ }
759
+ }
760
+ }
761
+ }),
762
+ ...extras
763
+ ]);
764
+ return result;
765
+ }
766
+ case "CONSOLIDATION" /* Consolidation */: {
767
+ if (!((_d = game.activePeriod) == null ? void 0 : _d.activeSegment))
768
+ return null;
769
+ const { results, extras, promises } = await computePeriodEndResults(
770
+ {
771
+ segmentResults: game.activePeriod.activeSegment.results,
772
+ segmentFacts: game.activePeriod.activeSegment.facts,
773
+ periodFacts: game.activePeriod.facts,
774
+ periodDecisions: game.activePeriod.decisions,
775
+ activePeriodIx: currentPeriodIx,
776
+ gameId: game.id
777
+ },
778
+ ctx,
779
+ { reducers }
780
+ );
781
+ await Promise.all(promises);
782
+ const result = await ctx.prisma.$transaction([
783
+ ctx.prisma.game.update({
784
+ where: {
785
+ id: gameId
786
+ },
787
+ data: {
788
+ status: "RESULTS" /* Results */,
789
+ activePeriodIx: nextPeriodIx,
790
+ activePeriod: {
791
+ connect: {
792
+ gameId_index: {
793
+ gameId,
794
+ index: nextPeriodIx
795
+ }
796
+ }
797
+ }
798
+ }
799
+ }),
800
+ ctx.prisma.period.update({
801
+ where: {
802
+ gameId_index: {
803
+ gameId,
804
+ index: currentPeriodIx
805
+ }
806
+ },
807
+ data: {
808
+ results: {
809
+ create: results
810
+ }
811
+ },
812
+ include: {
813
+ results: true
814
+ }
815
+ }),
816
+ ...extras
817
+ ]);
818
+ return result;
819
+ }
820
+ case "RESULTS" /* Results */: {
821
+ if (!((_e = game.activePeriod) == null ? void 0 : _e.nextPeriod)) {
822
+ return null;
823
+ }
824
+ const { results, extras } = computePeriodStartResults(
825
+ {
826
+ results: game.activePeriod.previousPeriod[0].results,
827
+ players: game.players,
828
+ activePeriodIx: currentPeriodIx,
829
+ gameId: game.id,
830
+ periodFacts: game.activePeriod.facts
831
+ },
832
+ ctx,
833
+ { reducers }
834
+ );
835
+ const result = await ctx.prisma.$transaction([
836
+ ctx.prisma.game.update({
837
+ where: {
838
+ id: gameId
839
+ },
840
+ data: {
841
+ status: "PREPARATION" /* Preparation */
842
+ }
843
+ }),
844
+ ctx.prisma.period.update({
845
+ where: {
846
+ gameId_index: {
847
+ gameId,
848
+ index: currentPeriodIx
849
+ }
850
+ },
851
+ data: {
852
+ results: {
853
+ create: results
854
+ }
855
+ }
856
+ }),
857
+ ...extras
858
+ ]);
859
+ return result;
860
+ }
861
+ default:
862
+ return null;
863
+ }
864
+ }
865
+ async function activateNextSegment({ gameId }, ctx, { reducers }) {
866
+ var _a, _b;
867
+ const game = await ctx.prisma.game.findUnique({
868
+ where: {
869
+ id: gameId
870
+ },
871
+ include: {
872
+ players: true,
873
+ periods: true,
874
+ segments: true,
875
+ activePeriod: {
876
+ include: {
877
+ results: {
878
+ include: {
879
+ player: true
880
+ }
881
+ },
882
+ activeSegment: {
883
+ include: {
884
+ nextSegment: true,
885
+ results: {
886
+ include: {
887
+ player: true
888
+ }
889
+ }
890
+ }
891
+ }
892
+ }
893
+ }
894
+ }
895
+ });
896
+ if (!(game == null ? void 0 : game.activePeriod))
897
+ return null;
898
+ const currentPeriodIx = game.activePeriodIx;
899
+ const currentSegmentIx = game.activePeriod.activeSegmentIx;
900
+ const nextSegmentIx = currentSegmentIx + 1;
901
+ switch (game.status) {
902
+ case "PREPARATION" /* Preparation */:
903
+ case "PAUSED" /* Paused */: {
904
+ const { results, extras } = computeSegmentStartResults(game, ctx, {
905
+ reducers
906
+ });
907
+ const result = await ctx.prisma.$transaction([
908
+ ctx.prisma.game.update({
909
+ where: {
910
+ id: gameId
911
+ },
912
+ data: {
913
+ status: "RUNNING" /* Running */
914
+ }
915
+ }),
916
+ ctx.prisma.period.update({
917
+ where: {
918
+ gameId_index: {
919
+ gameId,
920
+ index: currentPeriodIx
921
+ }
922
+ },
923
+ data: {
924
+ activeSegmentIx: nextSegmentIx,
925
+ activeSegment: {
926
+ connect: {
927
+ gameId_periodIx_index: {
928
+ gameId,
929
+ periodIx: currentPeriodIx,
930
+ index: nextSegmentIx
931
+ }
932
+ }
933
+ }
934
+ }
935
+ }),
936
+ ctx.prisma.periodSegment.update({
937
+ where: {
938
+ gameId_periodIx_index: {
939
+ gameId,
940
+ periodIx: currentPeriodIx,
941
+ index: nextSegmentIx
942
+ }
943
+ },
944
+ data: {
945
+ results: {
946
+ create: results
947
+ }
948
+ }
949
+ }),
950
+ ...extras
951
+ ]);
952
+ try {
953
+ await ctx.prisma.player.updateMany({
954
+ where: {
955
+ game: {
956
+ id: gameId
957
+ }
958
+ },
959
+ data: {
960
+ isReady: false
961
+ }
962
+ });
963
+ } catch (e) {
964
+ console.error(e);
965
+ }
966
+ return result;
967
+ }
968
+ case "RUNNING" /* Running */: {
969
+ if (!((_b = (_a = game.activePeriod) == null ? void 0 : _a.activeSegment) == null ? void 0 : _b.nextSegment)) {
970
+ return null;
971
+ }
972
+ const { results, extras } = computeSegmentEndResults(game, ctx, {
973
+ reducers
974
+ });
975
+ const result = await ctx.prisma.$transaction([
976
+ ctx.prisma.game.update({
977
+ where: { id: gameId },
978
+ data: {
979
+ status: "PAUSED" /* Paused */
980
+ }
981
+ }),
982
+ ctx.prisma.periodSegment.update({
983
+ where: {
984
+ gameId_periodIx_index: {
985
+ gameId,
986
+ periodIx: currentPeriodIx,
987
+ index: currentSegmentIx
988
+ }
989
+ },
990
+ data: {
991
+ results: {
992
+ update: results
993
+ }
994
+ },
995
+ include: {
996
+ results: true
997
+ }
998
+ }),
999
+ ...extras
1000
+ ]);
1001
+ return result;
1002
+ }
1003
+ default:
1004
+ return null;
1005
+ }
1006
+ }
1007
+ var PlayerFactsSchema = yup.object({
1008
+ location: yup.string().default("Zurich")
1009
+ });
1010
+ async function updatePlayerData({ name, avatar, color, facts }, ctx) {
1011
+ if ((0, import_ramda.none)(Boolean, [name, avatar, color, facts])) {
1012
+ return null;
1013
+ }
1014
+ let data = {};
1015
+ if (name) {
1016
+ data["name"] = name;
1017
+ }
1018
+ if (avatar) {
1019
+ data["avatar"] = avatar;
1020
+ }
1021
+ if (color) {
1022
+ data["color"] = color;
1023
+ }
1024
+ if (facts) {
1025
+ data["facts"] = PlayerFactsSchema.validateSync(facts, {
1026
+ stripUnknown: true
1027
+ });
1028
+ }
1029
+ const player = await ctx.prisma.player.update({
1030
+ where: {
1031
+ id: ctx.user.sub
1032
+ },
1033
+ data,
1034
+ include: {
1035
+ level: true,
1036
+ achievements: {
1037
+ include: {
1038
+ achievement: true
1039
+ }
1040
+ }
1041
+ }
1042
+ });
1043
+ return player;
1044
+ }
1045
+ async function getGames(args, ctx) {
1046
+ return ctx.prisma.game.findMany();
1047
+ }
1048
+ async function getGame(args, ctx) {
1049
+ const gameId = args.id ?? ctx.user.gameId;
1050
+ if (!gameId) {
1051
+ return null;
1052
+ }
1053
+ return ctx.prisma.game.findUnique({
1054
+ where: {
1055
+ id: args.id
1056
+ },
1057
+ include: {
1058
+ players: {
1059
+ include: {
1060
+ level: true,
1061
+ achievements: true
1062
+ }
1063
+ },
1064
+ periods: {
1065
+ orderBy: {
1066
+ index: "asc"
1067
+ },
1068
+ include: {
1069
+ segments: {
1070
+ orderBy: {
1071
+ index: "asc"
1072
+ },
1073
+ include: {
1074
+ learningElements: true,
1075
+ storyElements: true
1076
+ }
1077
+ }
1078
+ }
1079
+ },
1080
+ activePeriod: {
1081
+ include: {
1082
+ segments: true,
1083
+ activeSegment: true
1084
+ }
1085
+ }
1086
+ }
1087
+ });
1088
+ }
1089
+ async function getGameFromContext(ctx) {
1090
+ return ctx.prisma.game.findUnique({
1091
+ where: {
1092
+ id: ctx.user.gameId
1093
+ },
1094
+ include: {
1095
+ activePeriod: true
1096
+ }
1097
+ });
1098
+ }
1099
+ async function getLearningElements(args, ctx) {
1100
+ return ctx.prisma.learningElement.findMany({
1101
+ include: {
1102
+ options: true
1103
+ }
1104
+ });
1105
+ }
1106
+ function mapAction({ ctx, gameId, activePeriodIx, playerId }) {
1107
+ return (action) => ctx.prisma.playerAction.create({
1108
+ data: {
1109
+ type: action.type,
1110
+ facts: action.facts,
1111
+ game: {
1112
+ connect: { id: gameId }
1113
+ },
1114
+ player: {
1115
+ connect: { id: playerId }
1116
+ },
1117
+ periodIx: activePeriodIx,
1118
+ period: {
1119
+ connect: {
1120
+ gameId_index: {
1121
+ gameId,
1122
+ index: activePeriodIx
1123
+ }
1124
+ }
1125
+ },
1126
+ segmentIx: typeof action.segment === "number" ? action.segment : void 0,
1127
+ segment: typeof action.segment === "number" ? {
1128
+ connect: {
1129
+ gameId_periodIx_index: {
1130
+ gameId,
1131
+ periodIx: activePeriodIx,
1132
+ index: action.segment
1133
+ }
1134
+ }
1135
+ } : void 0
1136
+ }
1137
+ });
1138
+ }
1139
+ function computePeriodStartResults({ results, players, activePeriodIx, gameId, periodFacts }, ctx, { reducers }) {
1140
+ const currentPeriodIx = activePeriodIx;
1141
+ const nextPeriodIx = currentPeriodIx + 1;
1142
+ let extras = [];
1143
+ if (currentPeriodIx >= 0) {
1144
+ const result2 = results.filter((result3) => result3.type === "PERIOD_END" /* PeriodEnd */).map((result3, ix, allResults) => {
1145
+ const { result: facts, actions } = reducers.PeriodResult.apply(result3, {
1146
+ type: reducers.PeriodResult.ActionTypes.PERIOD_RESULTS_START,
1147
+ payload: {
1148
+ playerRole: result3.player.role ?? result3.player.connect.role,
1149
+ initialCash: periodFacts.initialCash
1150
+ }
1151
+ });
1152
+ const mapper = mapAction({
1153
+ ctx,
1154
+ gameId,
1155
+ activePeriodIx: currentPeriodIx,
1156
+ playerId: result3.player.id
1157
+ });
1158
+ if (actions && actions.length > 0) {
1159
+ extras = [...extras, ...actions.map(mapper)];
1160
+ }
1161
+ return {
1162
+ type: "PERIOD_START" /* PeriodStart */,
1163
+ periodIx: currentPeriodIx,
1164
+ facts,
1165
+ player: {
1166
+ connect: {
1167
+ id: result3.player.id ?? result3.player.connect.id
1168
+ }
1169
+ },
1170
+ game: {
1171
+ connect: {
1172
+ id: gameId
1173
+ }
1174
+ }
1175
+ };
1176
+ });
1177
+ return {
1178
+ results: result2,
1179
+ extras
1180
+ };
1181
+ }
1182
+ const result = players.map((player, ix, allPlayers) => {
1183
+ const { result: facts, actions } = reducers.PeriodResult.apply(
1184
+ {},
1185
+ {
1186
+ type: reducers.PeriodResult.ActionTypes.PERIOD_RESULTS_INITIALIZE,
1187
+ payload: {
1188
+ playerRole: player.role,
1189
+ initialCash: periodFacts.initialCash
1190
+ }
1191
+ }
1192
+ );
1193
+ const mapper = mapAction({
1194
+ ctx,
1195
+ gameId,
1196
+ activePeriodIx: nextPeriodIx,
1197
+ playerId: player.id
1198
+ });
1199
+ if (actions && actions.length > 0) {
1200
+ extras = [...extras, ...actions.map(mapper)];
1201
+ }
1202
+ return {
1203
+ type: "PERIOD_START" /* PeriodStart */,
1204
+ periodIx: nextPeriodIx,
1205
+ facts,
1206
+ player: {
1207
+ connect: {
1208
+ id: player.id
1209
+ }
1210
+ },
1211
+ game: {
1212
+ connect: {
1213
+ id: gameId
1214
+ }
1215
+ }
1216
+ };
1217
+ });
1218
+ return {
1219
+ results: result,
1220
+ extras
1221
+ };
1222
+ }
1223
+ async function computePeriodEndResults({
1224
+ segmentResults,
1225
+ periodFacts,
1226
+ periodDecisions,
1227
+ segmentFacts,
1228
+ activePeriodIx,
1229
+ gameId
1230
+ }, ctx, { reducers }) {
1231
+ let extras = [];
1232
+ let promises = [];
1233
+ const results = segmentResults.filter((result) => result.type === "SEGMENT_END" /* SegmentEnd */).map((result, ix, allResults) => {
1234
+ const consolidationDecisions = periodDecisions.find(
1235
+ (decision) => decision.playerId === result.playerId
1236
+ );
1237
+ const {
1238
+ result: facts,
1239
+ actions,
1240
+ events
1241
+ } = reducers.PeriodResult.apply(result.facts, {
1242
+ type: reducers.PeriodResult.ActionTypes.PERIOD_RESULTS_END,
1243
+ payload: {
1244
+ interestRate: periodFacts.interestRate,
1245
+ spotPrice: segmentFacts.spotPrice,
1246
+ futuresPrice: segmentFacts.futuresPrice,
1247
+ randomSeed: periodFacts.randomSeed,
1248
+ initialSpotPrice: periodFacts.initialSpotPrice,
1249
+ playerRole: result.player.role,
1250
+ playerLevel: result.player.levelIx + 1,
1251
+ playerExperience: result.player.experience,
1252
+ storageCostPerItem: periodFacts.storageCostPerItem,
1253
+ trendE: periodFacts.trendE,
1254
+ trendGap: periodFacts.trendGap,
1255
+ consolidationDecisions,
1256
+ cashInflowTotal: segmentFacts.cashInflowTotal,
1257
+ periodIx: activePeriodIx
1258
+ }
1259
+ });
1260
+ const mapper = mapAction({
1261
+ ctx,
1262
+ gameId,
1263
+ activePeriodIx,
1264
+ playerId: result.player.id
1265
+ });
1266
+ if (actions && actions.length > 0) {
1267
+ extras = [...extras, ...actions.map(mapper)];
1268
+ }
1269
+ promises = [
1270
+ ...promises,
1271
+ receiveEvents({
1272
+ events,
1273
+ ctx: {
1274
+ args: {
1275
+ playerId: result.player.id,
1276
+ periodIx: activePeriodIx,
1277
+ gameId
1278
+ },
1279
+ user: ctx.user,
1280
+ achievements: result.player.achievementKeys,
1281
+ experience: result.player.experience,
1282
+ currentLevelIx: result.player.levelIx
1283
+ },
1284
+ prisma: ctx.prisma
1285
+ })
1286
+ ];
1287
+ return {
1288
+ type: "PERIOD_END" /* PeriodEnd */,
1289
+ periodIx: activePeriodIx,
1290
+ facts,
1291
+ player: {
1292
+ connect: {
1293
+ id: result.playerId
1294
+ }
1295
+ },
1296
+ game: {
1297
+ connect: {
1298
+ id: gameId
1299
+ }
1300
+ }
1301
+ };
1302
+ });
1303
+ return {
1304
+ extras,
1305
+ results,
1306
+ promises
1307
+ };
1308
+ }
1309
+ function computeSegmentStartResults(game, ctx, { reducers }) {
1310
+ const currentSegmentIx = game.activePeriod.activeSegmentIx;
1311
+ const nextSegmentIx = currentSegmentIx + 1;
1312
+ let extras = [];
1313
+ if (currentSegmentIx >= 0) {
1314
+ const results2 = game.activePeriod.activeSegment.results.filter((result) => result.type === "SEGMENT_END" /* SegmentEnd */).reduce((acc, result, ix, allResults) => {
1315
+ const { result: facts, actions } = reducers.SegmentResult.apply(
1316
+ result.facts,
1317
+ {
1318
+ type: reducers.SegmentResult.ActionTypes.SEGMENT_RESULTS_START,
1319
+ payload: {
1320
+ playerRole: result.player.role,
1321
+ interestRate: game.activePeriod.facts.interestRate,
1322
+ futuresPriceNext: game.activePeriod.activeSegment.nextSegment.facts.futuresPrice,
1323
+ futuresPriceCurrent: game.activePeriod.activeSegment.facts.futuresPrice,
1324
+ spotPriceNext: game.activePeriod.activeSegment.nextSegment.facts.spotPrice,
1325
+ segmentIx: nextSegmentIx,
1326
+ cashInflow: game.activePeriod.activeSegment.nextSegment.facts.cashInflow
1327
+ }
1328
+ }
1329
+ );
1330
+ const mapper = mapAction({
1331
+ ctx,
1332
+ gameId: game.id,
1333
+ activePeriodIx: game.activePeriodIx,
1334
+ playerId: result.player.id
1335
+ });
1336
+ if (actions && actions.length > 0) {
1337
+ extras = [...extras, ...actions.map(mapper)];
1338
+ }
1339
+ const common = {
1340
+ facts,
1341
+ periodIx: game.activePeriodIx,
1342
+ segmentIx: nextSegmentIx,
1343
+ player: {
1344
+ connect: {
1345
+ id: result.playerId
1346
+ }
1347
+ },
1348
+ period: {
1349
+ connect: {
1350
+ id: game.activePeriodId
1351
+ }
1352
+ },
1353
+ game: {
1354
+ connect: {
1355
+ id: game.id
1356
+ }
1357
+ }
1358
+ };
1359
+ return [
1360
+ ...acc,
1361
+ {
1362
+ ...common,
1363
+ type: "SEGMENT_START" /* SegmentStart */
1364
+ },
1365
+ {
1366
+ ...common,
1367
+ type: "SEGMENT_END" /* SegmentEnd */
1368
+ }
1369
+ ];
1370
+ }, []);
1371
+ return {
1372
+ results: results2,
1373
+ extras
1374
+ };
1375
+ }
1376
+ const results = game.activePeriod.results.filter((result) => result.type === "PERIOD_START" /* PeriodStart */).reduce((acc, result, ix, allResults) => {
1377
+ const { result: facts } = reducers.SegmentResult.apply(result.facts, {
1378
+ type: reducers.SegmentResult.ActionTypes.SEGMENT_RESULTS_INITIALIZE,
1379
+ payload: {
1380
+ cashBalance: result.facts.cashBalance,
1381
+ storageAmount: result.facts.storageAmount,
1382
+ spotPrice: game.activePeriod.facts.initialSpotPrice,
1383
+ playerRole: result.player.role
1384
+ }
1385
+ });
1386
+ const common = {
1387
+ facts,
1388
+ periodIx: game.activePeriodIx,
1389
+ segmentIx: nextSegmentIx,
1390
+ player: {
1391
+ connect: {
1392
+ id: result.playerId
1393
+ }
1394
+ },
1395
+ period: {
1396
+ connect: {
1397
+ id: game.activePeriodId
1398
+ }
1399
+ },
1400
+ game: {
1401
+ connect: {
1402
+ id: game.id
1403
+ }
1404
+ }
1405
+ };
1406
+ return [
1407
+ ...acc,
1408
+ {
1409
+ ...common,
1410
+ type: "SEGMENT_START" /* SegmentStart */
1411
+ },
1412
+ {
1413
+ ...common,
1414
+ type: "SEGMENT_END" /* SegmentEnd */
1415
+ }
1416
+ ];
1417
+ }, []);
1418
+ return {
1419
+ results,
1420
+ extras
1421
+ };
1422
+ }
1423
+ function computeSegmentEndResults(game, ctx, { reducers }) {
1424
+ let extras = [];
1425
+ const results = game.activePeriod.activeSegment.results.filter((result) => result.type === "SEGMENT_END" /* SegmentEnd */).map((result, ix, allResults) => {
1426
+ const { result: facts, actions } = reducers.SegmentResult.apply(
1427
+ result.facts,
1428
+ {
1429
+ type: reducers.SegmentResult.ActionTypes.SEGMENT_RESULTS_END,
1430
+ payload: {
1431
+ storageCostPerItem: game.activePeriod.facts.storageCostPerItem,
1432
+ segmentIx: game.activePeriod.activeSegmentIx
1433
+ }
1434
+ }
1435
+ );
1436
+ const mapper = mapAction({
1437
+ ctx,
1438
+ gameId: game.id,
1439
+ activePeriodIx: game.activePeriodIx,
1440
+ playerId: result.player.id
1441
+ });
1442
+ if (actions && actions.length > 0) {
1443
+ extras = [...extras, ...actions.map(mapper)];
1444
+ }
1445
+ return {
1446
+ where: {
1447
+ periodIx_segmentIx_playerId_type: {
1448
+ periodIx: game.activePeriodIx,
1449
+ segmentIx: game.activePeriod.activeSegmentIx,
1450
+ playerId: result.playerId,
1451
+ type: "SEGMENT_END" /* SegmentEnd */
1452
+ }
1453
+ },
1454
+ data: {
1455
+ facts,
1456
+ game: {
1457
+ connect: {
1458
+ id: game.id
1459
+ }
1460
+ }
1461
+ }
1462
+ };
1463
+ });
1464
+ return {
1465
+ results,
1466
+ extras
1467
+ };
1468
+ }
1469
+
1470
+ // src/services/PlayService.ts
1471
+ var PlayService_exports = {};
1472
+ __export(PlayService_exports, {
1473
+ attemptLearningElement: () => attemptLearningElement,
1474
+ getLearningElement: () => getLearningElement,
1475
+ getPastResults: () => getPastResults,
1476
+ getPlayerData: () => getPlayerData,
1477
+ getPlayerResult: () => getPlayerResult,
1478
+ getPlayerResults: () => getPlayerResults,
1479
+ getPlayerTransactions: () => getPlayerTransactions,
1480
+ markStoryElement: () => markStoryElement,
1481
+ performAction: () => performAction,
1482
+ saveDecisions: () => saveDecisions,
1483
+ updateReadyState: () => updateReadyState
1484
+ });
1485
+ async function performAction(args, ctx, { reducers }) {
1486
+ var _a;
1487
+ const periodIx_segmentIx_playerId_type = {
1488
+ periodIx: args.periodIx,
1489
+ segmentIx: args.segmentIx,
1490
+ playerId: args.playerId,
1491
+ type: "SEGMENT_END" /* SegmentEnd */
1492
+ };
1493
+ const previousResult = await ctx.prisma.playerResult.findUnique({
1494
+ where: {
1495
+ periodIx_segmentIx_playerId_type
1496
+ },
1497
+ include: {
1498
+ game: true,
1499
+ segment: true,
1500
+ period: true,
1501
+ player: true
1502
+ }
1503
+ });
1504
+ if (!previousResult)
1505
+ return null;
1506
+ if (previousResult.game.status !== "RUNNING" /* Running */) {
1507
+ throw new Error("ACTIONS_NOT_ALLOWED");
1508
+ }
1509
+ const { result, events, notifications, isDirty, extras } = reducers.Actions.apply(previousResult.facts, {
1510
+ type: args.actionType,
1511
+ payload: {
1512
+ playerArgs: args.facts,
1513
+ segmentFacts: (_a = previousResult.segment) == null ? void 0 : _a.facts,
1514
+ periodFacts: previousResult.period.facts
1515
+ }
1516
+ });
1517
+ publishUserNotification(ctx, notifications);
1518
+ await receiveEvents({
1519
+ events,
1520
+ ctx: {
1521
+ user: ctx.user,
1522
+ args,
1523
+ achievements: previousResult.player.achievementKeys,
1524
+ experience: previousResult.player.experience,
1525
+ currentLevelIx: previousResult.player.levelIx
1526
+ },
1527
+ prisma: ctx.prisma
1528
+ });
1529
+ if (!isDirty) {
1530
+ return previousResult;
1531
+ }
1532
+ const [updatedResult, _] = await ctx.prisma.$transaction([
1533
+ ctx.prisma.playerResult.update({
1534
+ where: {
1535
+ periodIx_segmentIx_playerId_type
1536
+ },
1537
+ data: {
1538
+ facts: result
1539
+ },
1540
+ include: {
1541
+ period: true
1542
+ }
1543
+ }),
1544
+ ctx.prisma.playerAction.create({
1545
+ data: {
1546
+ periodIx: args.periodIx,
1547
+ period: {
1548
+ connect: {
1549
+ gameId_index: {
1550
+ gameId: args.gameId,
1551
+ index: args.periodIx
1552
+ }
1553
+ }
1554
+ },
1555
+ segmentIx: args.segmentIx,
1556
+ segment: {
1557
+ connect: {
1558
+ gameId_periodIx_index: {
1559
+ gameId: args.gameId,
1560
+ periodIx: args.periodIx,
1561
+ index: args.segmentIx
1562
+ }
1563
+ }
1564
+ },
1565
+ game: {
1566
+ connect: {
1567
+ id: args.gameId
1568
+ }
1569
+ },
1570
+ player: {
1571
+ connect: {
1572
+ id: args.playerId
1573
+ }
1574
+ },
1575
+ type: args.actionType,
1576
+ facts: {
1577
+ ...args.facts,
1578
+ ...extras
1579
+ }
1580
+ }
1581
+ })
1582
+ ]);
1583
+ return updatedResult;
1584
+ }
1585
+ async function saveDecisions(args, ctx) {
1586
+ const game = await ctx.prisma.game.findUnique({
1587
+ where: {
1588
+ id: ctx.user.gameId
1589
+ },
1590
+ include: {
1591
+ activePeriod: {
1592
+ include: {
1593
+ activeSegment: true
1594
+ }
1595
+ }
1596
+ }
1597
+ });
1598
+ if (!(game == null ? void 0 : game.activePeriod))
1599
+ return null;
1600
+ if (args.decisionType !== game.status) {
1601
+ throw new Error("INVALID_DECISION");
1602
+ }
1603
+ const periodIx = game.activePeriod.index;
1604
+ const savedDecision = ctx.prisma.playerDecision.upsert({
1605
+ where: {
1606
+ playerId_periodIx_type: {
1607
+ periodIx,
1608
+ playerId: ctx.user.sub,
1609
+ type: args.decisionType
1610
+ }
1611
+ },
1612
+ create: {
1613
+ facts: args.facts,
1614
+ type: args.decisionType,
1615
+ periodIx,
1616
+ period: {
1617
+ connect: {
1618
+ gameId_index: {
1619
+ gameId: game.id,
1620
+ index: periodIx
1621
+ }
1622
+ }
1623
+ },
1624
+ game: {
1625
+ connect: {
1626
+ id: game.id
1627
+ }
1628
+ },
1629
+ player: {
1630
+ connect: {
1631
+ id: ctx.user.sub
1632
+ }
1633
+ }
1634
+ },
1635
+ update: {
1636
+ facts: args.facts
1637
+ }
1638
+ });
1639
+ return savedDecision;
1640
+ }
1641
+ async function getPlayerResult(args, ctx) {
1642
+ const currentGame = await ctx.prisma.game.findUnique({
1643
+ where: {
1644
+ id: args.gameId
1645
+ },
1646
+ include: {
1647
+ activePeriod: {
1648
+ include: {
1649
+ activeSegment: {
1650
+ include: {
1651
+ learningElements: true,
1652
+ storyElements: true
1653
+ }
1654
+ },
1655
+ segments: {
1656
+ include: {
1657
+ learningElements: true,
1658
+ storyElements: true
1659
+ }
1660
+ }
1661
+ }
1662
+ },
1663
+ periods: {
1664
+ include: {
1665
+ segments: {
1666
+ include: {
1667
+ learningElements: true,
1668
+ storyElements: true
1669
+ }
1670
+ }
1671
+ }
1672
+ }
1673
+ }
1674
+ });
1675
+ if (!(currentGame == null ? void 0 : currentGame.activePeriod))
1676
+ return null;
1677
+ const previousResults = ctx.prisma.playerResult.findMany({
1678
+ where: {
1679
+ playerId: args.playerId,
1680
+ periodIx: {
1681
+ lte: currentGame.activePeriod.index
1682
+ }
1683
+ },
1684
+ include: {
1685
+ period: true
1686
+ }
1687
+ });
1688
+ const playerResult = await ctx.prisma.playerResult.findUnique({
1689
+ where: {
1690
+ periodIx_segmentIx_playerId_type: {
1691
+ periodIx: currentGame.activePeriodIx,
1692
+ segmentIx: currentGame.activePeriod.activeSegmentIx,
1693
+ playerId: args.playerId,
1694
+ type: "SEGMENT_END" /* SegmentEnd */
1695
+ }
1696
+ },
1697
+ include: {
1698
+ period: true,
1699
+ player: {
1700
+ include: {
1701
+ completedLearningElements: true,
1702
+ visitedStoryElements: true
1703
+ }
1704
+ }
1705
+ }
1706
+ });
1707
+ const transactions = ctx.prisma.playerAction.findMany({
1708
+ where: {
1709
+ player: {
1710
+ id: args.playerId
1711
+ }
1712
+ }
1713
+ });
1714
+ return {
1715
+ currentGame,
1716
+ playerResult,
1717
+ previousResults,
1718
+ transactions
1719
+ };
1720
+ }
1721
+ async function getPlayerData(args, ctx) {
1722
+ return ctx.prisma.player.findUnique({
1723
+ where: {
1724
+ id: args.playerId
1725
+ },
1726
+ include: {
1727
+ level: true,
1728
+ achievements: {
1729
+ include: {
1730
+ achievement: true
1731
+ }
1732
+ }
1733
+ }
1734
+ });
1735
+ }
1736
+ async function getLearningElement(args, ctx) {
1737
+ const playerWithLearningElements = await ctx.prisma.player.findUnique({
1738
+ where: {
1739
+ id: ctx.user.sub
1740
+ },
1741
+ include: {
1742
+ completedLearningElements: {
1743
+ where: {
1744
+ id: args.id
1745
+ }
1746
+ }
1747
+ }
1748
+ });
1749
+ if (!playerWithLearningElements)
1750
+ return null;
1751
+ const elementSolved = playerWithLearningElements.completedLearningElements.length > 0;
1752
+ const element = await ctx.prisma.learningElement.findUnique({
1753
+ where: {
1754
+ id: args.id
1755
+ },
1756
+ include: {
1757
+ options: true
1758
+ }
1759
+ });
1760
+ if (!element)
1761
+ return null;
1762
+ return {
1763
+ id: args.id,
1764
+ element: {
1765
+ ...element,
1766
+ feedback: elementSolved ? element.feedback : null
1767
+ },
1768
+ state: elementSolved ? "SOLVED" /* SOLVED */ : "NEW" /* NEW */,
1769
+ solution: elementSolved ? JSON.stringify(
1770
+ element.options.flatMap((option, ix) => option.correct ? [ix] : [])
1771
+ ) : null
1772
+ };
1773
+ }
1774
+ async function attemptLearningElement(args, ctx) {
1775
+ const learningElement = await ctx.prisma.learningElement.findUnique({
1776
+ where: { id: args.elementId },
1777
+ include: { options: true }
1778
+ });
1779
+ if (!learningElement)
1780
+ return null;
1781
+ try {
1782
+ const selectedOptions = JSON.parse(args.selection);
1783
+ const pointsAchieved = learningElement.options.reduce((acc, option, ix) => {
1784
+ if (option.correct && selectedOptions.includes(ix)) {
1785
+ return acc + 1;
1786
+ }
1787
+ if (!option.correct && !selectedOptions.includes(ix)) {
1788
+ return acc + 1;
1789
+ }
1790
+ return acc;
1791
+ }, 0);
1792
+ const pointsMax = learningElement.options.length;
1793
+ let updatedPlayer;
1794
+ if (pointsAchieved === pointsMax) {
1795
+ updatedPlayer = await ctx.prisma.player.update({
1796
+ where: {
1797
+ id: ctx.user.sub
1798
+ },
1799
+ data: {
1800
+ completedLearningElements: {
1801
+ connect: {
1802
+ id: args.elementId
1803
+ }
1804
+ }
1805
+ },
1806
+ include: {
1807
+ game: {
1808
+ select: {
1809
+ activePeriodIx: true
1810
+ }
1811
+ }
1812
+ }
1813
+ });
1814
+ await receiveEvents({
1815
+ events: [
1816
+ {
1817
+ type: "LEARNING_ELEMENT_SOLVED" /* LEARNING_ELEMENT_SOLVED */,
1818
+ facts: {
1819
+ elementId: args.elementId
1820
+ }
1821
+ }
1822
+ ],
1823
+ ctx: {
1824
+ user: ctx.user,
1825
+ args: {
1826
+ gameId: ctx.user.gameId,
1827
+ periodIx: updatedPlayer.game.activePeriodIx,
1828
+ playerId: ctx.user.sub
1829
+ },
1830
+ achievements: updatedPlayer.achievementKeys,
1831
+ experience: updatedPlayer.experience,
1832
+ currentLevelIx: updatedPlayer.levelIx
1833
+ },
1834
+ prisma: ctx.prisma
1835
+ });
1836
+ } else {
1837
+ publishUserNotification(ctx, [
1838
+ {
1839
+ type: "LEARNING_ELEMENT_INCORRECT" /* LEARNING_ELEMENT_INCORRECT */
1840
+ }
1841
+ ]);
1842
+ }
1843
+ return {
1844
+ id: args.elementId,
1845
+ pointsAchieved,
1846
+ pointsMax,
1847
+ element: {
1848
+ id: args.elementId,
1849
+ feedback: learningElement.feedback
1850
+ },
1851
+ player: updatedPlayer
1852
+ };
1853
+ } catch (e) {
1854
+ console.warn(e);
1855
+ return null;
1856
+ }
1857
+ }
1858
+ async function markStoryElement(args, ctx) {
1859
+ const storyElement = await ctx.prisma.storyElement.findUnique({
1860
+ where: { id: args.elementId }
1861
+ });
1862
+ if (!storyElement)
1863
+ return null;
1864
+ return ctx.prisma.player.update({
1865
+ where: {
1866
+ id: ctx.user.sub
1867
+ },
1868
+ data: {
1869
+ visitedStoryElements: {
1870
+ connect: {
1871
+ id: args.elementId
1872
+ }
1873
+ }
1874
+ }
1875
+ });
1876
+ }
1877
+ async function getPlayerTransactions(args, ctx) {
1878
+ const playerActions = ctx.prisma.playerAction.findMany({
1879
+ where: {
1880
+ player: {
1881
+ id: ctx.user.sub
1882
+ }
1883
+ }
1884
+ });
1885
+ return playerActions;
1886
+ }
1887
+ async function getPlayerResults(args, ctx) {
1888
+ const playerResults = await ctx.prisma.playerResult.findMany({
1889
+ where: {
1890
+ gameId: ctx.user.gameId
1891
+ },
1892
+ include: {
1893
+ period: true,
1894
+ player: true,
1895
+ segment: true
1896
+ }
1897
+ });
1898
+ return playerResults;
1899
+ }
1900
+ async function getPastResults(args, ctx) {
1901
+ const currentGame = await ctx.prisma.game.findUnique({
1902
+ where: { id: ctx.user.gameId }
1903
+ });
1904
+ if (!currentGame)
1905
+ return null;
1906
+ const playerResults = await ctx.prisma.playerResult.findMany({
1907
+ where: {
1908
+ gameId: ctx.user.gameId,
1909
+ periodIx: {
1910
+ lt: currentGame.activePeriodIx
1911
+ },
1912
+ type: "PERIOD_END"
1913
+ },
1914
+ include: {
1915
+ period: true,
1916
+ player: true
1917
+ }
1918
+ });
1919
+ return playerResults;
1920
+ }
1921
+ async function updateReadyState(args, ctx) {
1922
+ return ctx.prisma.player.update({
1923
+ where: {
1924
+ id: ctx.user.sub
1925
+ },
1926
+ data: {
1927
+ isReady: args.isReady
1928
+ }
1929
+ });
1930
+ }
1931
+ // Annotate the CommonJS export names for ESM import in node:
1932
+ 0 && (module.exports = {
1933
+ AccountService,
1934
+ BaseGlobalNotificationType,
1935
+ BaseUserNotificationType,
1936
+ EventService,
1937
+ GameService,
1938
+ LearningElementState,
1939
+ PlayService,
1940
+ UserRole
1941
+ });