@playcademy/sdk 0.0.7 → 0.0.9
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.d.ts +794 -72
- package/dist/index.js +566 -225
- package/dist/server.d.ts +309 -16
- package/dist/server.js +321 -5
- package/dist/types.d.ts +955 -250
- package/package.json +11 -8
package/dist/index.js
CHANGED
|
@@ -14,7 +14,14 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
14
14
|
var isBrowser = () => {
|
|
15
15
|
const g = globalThis;
|
|
16
16
|
return typeof g.window !== "undefined" && typeof g.document !== "undefined";
|
|
17
|
-
}, colors,
|
|
17
|
+
}, colors, shouldUseColor = () => {
|
|
18
|
+
const preference = (process.env.LOG_COLOR ?? "auto").toLowerCase();
|
|
19
|
+
if (preference === "always")
|
|
20
|
+
return true;
|
|
21
|
+
if (preference === "never")
|
|
22
|
+
return false;
|
|
23
|
+
return Boolean(process.stdout && process.stdout.isTTY && true);
|
|
24
|
+
}, getLevelColor = (level) => {
|
|
18
25
|
switch (level) {
|
|
19
26
|
case "debug":
|
|
20
27
|
return colors.blue;
|
|
@@ -38,7 +45,7 @@ var isBrowser = () => {
|
|
|
38
45
|
}
|
|
39
46
|
}, logOnServer = (level, message, context) => {
|
|
40
47
|
const consoleMethod = getConsoleMethod(level);
|
|
41
|
-
if (
|
|
48
|
+
if (shouldUseColor()) {
|
|
42
49
|
const timestamp = new Date().toISOString();
|
|
43
50
|
const levelColor = getLevelColor(level);
|
|
44
51
|
const levelUpper = level.toUpperCase().padEnd(5);
|
|
@@ -48,7 +55,10 @@ var isBrowser = () => {
|
|
|
48
55
|
} else {
|
|
49
56
|
consoleMethod(`${coloredPrefix} ${message}`);
|
|
50
57
|
}
|
|
51
|
-
} else {
|
|
58
|
+
} else {
|
|
59
|
+
const formatted = formatLog(level, message, context);
|
|
60
|
+
consoleMethod(formatted);
|
|
61
|
+
}
|
|
52
62
|
}, getConsoleMethod = (level) => {
|
|
53
63
|
switch (level) {
|
|
54
64
|
case "debug":
|
|
@@ -62,6 +72,18 @@ var isBrowser = () => {
|
|
|
62
72
|
default:
|
|
63
73
|
return console.log;
|
|
64
74
|
}
|
|
75
|
+
}, formatLog = (level, message, context) => {
|
|
76
|
+
const timestamp = new Date().toISOString();
|
|
77
|
+
const logEntry = {
|
|
78
|
+
timestamp,
|
|
79
|
+
level: level.toUpperCase(),
|
|
80
|
+
message,
|
|
81
|
+
...context && Object.keys(context).length > 0 && { context }
|
|
82
|
+
};
|
|
83
|
+
if (true) {
|
|
84
|
+
return JSON.stringify(logEntry, null, 2);
|
|
85
|
+
}
|
|
86
|
+
return JSON.stringify(logEntry);
|
|
65
87
|
}, performLog = (level, message, context) => {
|
|
66
88
|
if (level === "debug" && false) {}
|
|
67
89
|
if (isBrowser()) {
|
|
@@ -91,6 +113,85 @@ var init_src = __esm(() => {
|
|
|
91
113
|
log = createLogger();
|
|
92
114
|
});
|
|
93
115
|
|
|
116
|
+
// src/core/auth/strategies.ts
|
|
117
|
+
class ApiKeyAuth {
|
|
118
|
+
apiKey;
|
|
119
|
+
constructor(apiKey) {
|
|
120
|
+
this.apiKey = apiKey;
|
|
121
|
+
}
|
|
122
|
+
getToken() {
|
|
123
|
+
return this.apiKey;
|
|
124
|
+
}
|
|
125
|
+
getType() {
|
|
126
|
+
return "apiKey";
|
|
127
|
+
}
|
|
128
|
+
getHeaders() {
|
|
129
|
+
return { "x-api-key": this.apiKey };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
class SessionAuth {
|
|
134
|
+
sessionToken;
|
|
135
|
+
constructor(sessionToken) {
|
|
136
|
+
this.sessionToken = sessionToken;
|
|
137
|
+
}
|
|
138
|
+
getToken() {
|
|
139
|
+
return this.sessionToken;
|
|
140
|
+
}
|
|
141
|
+
getType() {
|
|
142
|
+
return "session";
|
|
143
|
+
}
|
|
144
|
+
getHeaders() {
|
|
145
|
+
return { Authorization: `Bearer ${this.sessionToken}` };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
class GameJwtAuth {
|
|
150
|
+
gameToken;
|
|
151
|
+
constructor(gameToken) {
|
|
152
|
+
this.gameToken = gameToken;
|
|
153
|
+
}
|
|
154
|
+
getToken() {
|
|
155
|
+
return this.gameToken;
|
|
156
|
+
}
|
|
157
|
+
getType() {
|
|
158
|
+
return "gameJwt";
|
|
159
|
+
}
|
|
160
|
+
getHeaders() {
|
|
161
|
+
return { Authorization: `Bearer ${this.gameToken}` };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
class NoAuth {
|
|
166
|
+
getToken() {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
getType() {
|
|
170
|
+
return "session";
|
|
171
|
+
}
|
|
172
|
+
getHeaders() {
|
|
173
|
+
return {};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function createAuthStrategy(token, tokenType) {
|
|
177
|
+
if (!token) {
|
|
178
|
+
return new NoAuth;
|
|
179
|
+
}
|
|
180
|
+
if (tokenType === "apiKey") {
|
|
181
|
+
return new ApiKeyAuth(token);
|
|
182
|
+
}
|
|
183
|
+
if (tokenType === "session") {
|
|
184
|
+
return new SessionAuth(token);
|
|
185
|
+
}
|
|
186
|
+
if (tokenType === "gameJwt") {
|
|
187
|
+
return new GameJwtAuth(token);
|
|
188
|
+
}
|
|
189
|
+
if (token.startsWith("cademy")) {
|
|
190
|
+
return new ApiKeyAuth(token);
|
|
191
|
+
}
|
|
192
|
+
return new GameJwtAuth(token);
|
|
193
|
+
}
|
|
194
|
+
|
|
94
195
|
// src/core/auth/utils.ts
|
|
95
196
|
function openPopupWindow(url, name = "auth-popup", width = 500, height = 600) {
|
|
96
197
|
const left = window.screenX + (window.outerWidth - width) / 2;
|
|
@@ -146,9 +247,14 @@ function createAuthNamespace(client) {
|
|
|
146
247
|
return {
|
|
147
248
|
login: async (credentials) => {
|
|
148
249
|
try {
|
|
149
|
-
const response = await client["request"]("/auth/
|
|
150
|
-
client.setToken(response.token);
|
|
151
|
-
return {
|
|
250
|
+
const response = await client["request"]("/auth/sign-in/email", "POST", credentials);
|
|
251
|
+
client.setToken(response.token, "session");
|
|
252
|
+
return {
|
|
253
|
+
success: true,
|
|
254
|
+
token: response.token,
|
|
255
|
+
user: response.user,
|
|
256
|
+
expiresAt: response.expiresAt
|
|
257
|
+
};
|
|
152
258
|
} catch (error) {
|
|
153
259
|
return {
|
|
154
260
|
success: false,
|
|
@@ -157,8 +263,29 @@ function createAuthNamespace(client) {
|
|
|
157
263
|
}
|
|
158
264
|
},
|
|
159
265
|
logout: async () => {
|
|
160
|
-
|
|
266
|
+
try {
|
|
267
|
+
await client["request"]("/auth/sign-out", "POST");
|
|
268
|
+
} catch {}
|
|
161
269
|
client.setToken(null);
|
|
270
|
+
},
|
|
271
|
+
apiKeys: {
|
|
272
|
+
create: async (options) => {
|
|
273
|
+
return client["request"]("/dev/api-keys", "POST", {
|
|
274
|
+
name: options?.name || `SDK Key - ${new Date().toISOString()}`,
|
|
275
|
+
expiresIn: options?.expiresIn !== undefined ? options.expiresIn : null,
|
|
276
|
+
permissions: options?.permissions || {
|
|
277
|
+
games: ["read", "write", "delete"],
|
|
278
|
+
users: ["read:self", "write:self"],
|
|
279
|
+
dev: ["read", "write"]
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
},
|
|
283
|
+
list: async () => {
|
|
284
|
+
return client["request"]("/auth/api-key/list", "GET");
|
|
285
|
+
},
|
|
286
|
+
revoke: async (keyId) => {
|
|
287
|
+
await client["request"]("/auth/api-key/revoke", "POST", { id: keyId });
|
|
288
|
+
}
|
|
162
289
|
}
|
|
163
290
|
};
|
|
164
291
|
}
|
|
@@ -736,7 +863,6 @@ function createTTLCache(options) {
|
|
|
736
863
|
async function request({
|
|
737
864
|
path,
|
|
738
865
|
baseUrl,
|
|
739
|
-
token,
|
|
740
866
|
method = "GET",
|
|
741
867
|
body,
|
|
742
868
|
extraHeaders = {}
|
|
@@ -750,8 +876,6 @@ async function request({
|
|
|
750
876
|
payload = JSON.stringify(body);
|
|
751
877
|
headers["Content-Type"] = "application/json";
|
|
752
878
|
}
|
|
753
|
-
if (token)
|
|
754
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
755
879
|
const res = await fetch(url, {
|
|
756
880
|
method,
|
|
757
881
|
headers,
|
|
@@ -819,7 +943,7 @@ function createGamesNamespace(client) {
|
|
|
819
943
|
const promise = client["request"](`/games/${gameIdOrSlug}`, "GET");
|
|
820
944
|
return gameFetchCache.get(gameIdOrSlug, async () => {
|
|
821
945
|
const baseGameData = await promise;
|
|
822
|
-
if (baseGameData.gameType === "hosted" && baseGameData.assetBundleBase !== null) {
|
|
946
|
+
if (baseGameData.gameType === "hosted" && baseGameData.assetBundleBase !== null && baseGameData.assetBundleBase !== "") {
|
|
823
947
|
const manifestData = await fetchManifest(baseGameData.assetBundleBase);
|
|
824
948
|
return { ...baseGameData, manifest: manifestData };
|
|
825
949
|
}
|
|
@@ -1009,153 +1133,163 @@ function createDevNamespace(client) {
|
|
|
1009
1133
|
}
|
|
1010
1134
|
},
|
|
1011
1135
|
games: {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
if (hooks?.onEvent) {
|
|
1024
|
-
await new Promise((resolve, reject) => {
|
|
1025
|
-
const xhr = new XMLHttpRequest;
|
|
1026
|
-
xhr.open("PUT", initiateResponse.presignedUrl, true);
|
|
1027
|
-
const contentType = file.type || "application/octet-stream";
|
|
1028
|
-
try {
|
|
1029
|
-
xhr.setRequestHeader("Content-Type", contentType);
|
|
1030
|
-
} catch {}
|
|
1031
|
-
xhr.upload.onprogress = (event) => {
|
|
1032
|
-
if (event.lengthComputable) {
|
|
1033
|
-
const percent = event.loaded / event.total;
|
|
1034
|
-
hooks.onEvent?.({
|
|
1035
|
-
type: "s3Progress",
|
|
1036
|
-
loaded: event.loaded,
|
|
1037
|
-
total: event.total,
|
|
1038
|
-
percent
|
|
1039
|
-
});
|
|
1040
|
-
}
|
|
1041
|
-
};
|
|
1042
|
-
xhr.onload = () => {
|
|
1043
|
-
if (xhr.status >= 200 && xhr.status < 300)
|
|
1044
|
-
resolve();
|
|
1045
|
-
else
|
|
1046
|
-
reject(new Error(`File upload failed: ${xhr.status} ${xhr.statusText}`));
|
|
1047
|
-
};
|
|
1048
|
-
xhr.onerror = () => reject(new Error("File upload failed: network error"));
|
|
1049
|
-
xhr.send(file);
|
|
1136
|
+
deploy: {
|
|
1137
|
+
frontend: async (slug, metadata, file, hooks) => {
|
|
1138
|
+
hooks?.onEvent?.({ type: "init" });
|
|
1139
|
+
const game = await client["request"](`/games/${slug}`, "PUT", metadata);
|
|
1140
|
+
if (metadata.gameType === "external" || file === null) {
|
|
1141
|
+
return game;
|
|
1142
|
+
}
|
|
1143
|
+
const fileName = file instanceof File ? file.name : "game.zip";
|
|
1144
|
+
const initiateResponse = await client["request"]("/games/uploads/initiate/", "POST", {
|
|
1145
|
+
fileName,
|
|
1146
|
+
gameId: game.id
|
|
1050
1147
|
});
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1148
|
+
if (hooks?.onEvent && typeof XMLHttpRequest !== "undefined") {
|
|
1149
|
+
await new Promise((resolve, reject) => {
|
|
1150
|
+
const xhr = new XMLHttpRequest;
|
|
1151
|
+
xhr.open("PUT", initiateResponse.presignedUrl, true);
|
|
1152
|
+
const contentType = file.type || "application/octet-stream";
|
|
1153
|
+
try {
|
|
1154
|
+
xhr.setRequestHeader("Content-Type", contentType);
|
|
1155
|
+
} catch {}
|
|
1156
|
+
xhr.upload.onprogress = (event) => {
|
|
1157
|
+
if (event.lengthComputable) {
|
|
1158
|
+
const percent = event.loaded / event.total;
|
|
1159
|
+
hooks.onEvent?.({
|
|
1160
|
+
type: "s3Progress",
|
|
1161
|
+
loaded: event.loaded,
|
|
1162
|
+
total: event.total,
|
|
1163
|
+
percent
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
};
|
|
1167
|
+
xhr.onload = () => {
|
|
1168
|
+
if (xhr.status >= 200 && xhr.status < 300)
|
|
1169
|
+
resolve();
|
|
1170
|
+
else
|
|
1171
|
+
reject(new Error(`File upload failed: ${xhr.status} ${xhr.statusText}`));
|
|
1172
|
+
};
|
|
1173
|
+
xhr.onerror = () => reject(new Error("File upload failed: network error"));
|
|
1174
|
+
xhr.send(file);
|
|
1175
|
+
});
|
|
1176
|
+
} else {
|
|
1177
|
+
const uploadResponse = await fetch(initiateResponse.presignedUrl, {
|
|
1178
|
+
method: "PUT",
|
|
1179
|
+
body: file,
|
|
1180
|
+
headers: {
|
|
1181
|
+
"Content-Type": file.type || "application/octet-stream"
|
|
1182
|
+
}
|
|
1183
|
+
});
|
|
1184
|
+
if (!uploadResponse.ok) {
|
|
1185
|
+
throw new Error(`File upload failed: ${uploadResponse.status} ${uploadResponse.statusText}`);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
const baseUrl = (() => {
|
|
1189
|
+
const anyClient = client;
|
|
1190
|
+
try {
|
|
1191
|
+
return typeof anyClient.getBaseUrl === "function" ? anyClient.getBaseUrl() : "/api";
|
|
1192
|
+
} catch {
|
|
1193
|
+
return "/api";
|
|
1194
|
+
}
|
|
1195
|
+
})();
|
|
1196
|
+
const finalizeUrl = baseUrl.replace(/\/$/, "") + "/games/uploads/finalize/";
|
|
1197
|
+
const authToken = client.getToken();
|
|
1198
|
+
const tokenType = client.getTokenType();
|
|
1199
|
+
const headers = {
|
|
1200
|
+
"Content-Type": "application/json"
|
|
1201
|
+
};
|
|
1202
|
+
if (authToken) {
|
|
1203
|
+
if (tokenType === "apiKey") {
|
|
1204
|
+
headers["x-api-key"] = authToken;
|
|
1205
|
+
} else {
|
|
1206
|
+
headers["Authorization"] = `Bearer ${authToken}`;
|
|
1057
1207
|
}
|
|
1208
|
+
}
|
|
1209
|
+
const finalizeResponse = await fetch(finalizeUrl, {
|
|
1210
|
+
method: "POST",
|
|
1211
|
+
headers,
|
|
1212
|
+
body: JSON.stringify({
|
|
1213
|
+
tempS3Key: initiateResponse.tempS3Key,
|
|
1214
|
+
gameId: initiateResponse.gameId,
|
|
1215
|
+
version: initiateResponse.version,
|
|
1216
|
+
slug,
|
|
1217
|
+
metadata,
|
|
1218
|
+
originalFileName: fileName
|
|
1219
|
+
}),
|
|
1220
|
+
credentials: "omit"
|
|
1058
1221
|
});
|
|
1059
|
-
if (!
|
|
1060
|
-
|
|
1222
|
+
if (!finalizeResponse.ok) {
|
|
1223
|
+
const errText = await finalizeResponse.text().catch(() => "");
|
|
1224
|
+
throw new Error(`Finalize request failed: ${finalizeResponse.status} ${finalizeResponse.statusText}${errText ? ` - ${errText}` : ""}`);
|
|
1061
1225
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
const anyClient = client;
|
|
1065
|
-
try {
|
|
1066
|
-
return typeof anyClient.getBaseUrl === "function" ? anyClient.getBaseUrl() : "/api";
|
|
1067
|
-
} catch {
|
|
1068
|
-
return "/api";
|
|
1226
|
+
if (!finalizeResponse.body) {
|
|
1227
|
+
throw new Error("Finalize response body missing");
|
|
1069
1228
|
}
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
version: initiateResponse.version,
|
|
1083
|
-
slug,
|
|
1084
|
-
metadata,
|
|
1085
|
-
originalFileName: fileName
|
|
1086
|
-
}),
|
|
1087
|
-
credentials: "omit"
|
|
1088
|
-
});
|
|
1089
|
-
if (!finalizeResponse.ok) {
|
|
1090
|
-
const errText = await finalizeResponse.text().catch(() => "");
|
|
1091
|
-
throw new Error(`Finalize request failed: ${finalizeResponse.status} ${finalizeResponse.statusText}${errText ? ` - ${errText}` : ""}`);
|
|
1092
|
-
}
|
|
1093
|
-
if (!finalizeResponse.body) {
|
|
1094
|
-
throw new Error("Finalize response body missing");
|
|
1095
|
-
}
|
|
1096
|
-
hooks?.onEvent?.({ type: "finalizeStart" });
|
|
1097
|
-
let sawAnyServerEvent = false;
|
|
1098
|
-
const reader = finalizeResponse.body.pipeThrough(new TextDecoderStream).getReader();
|
|
1099
|
-
let buffer = "";
|
|
1100
|
-
while (true) {
|
|
1101
|
-
const { done, value } = await reader.read();
|
|
1102
|
-
if (done) {
|
|
1103
|
-
if (!sawAnyServerEvent) {
|
|
1104
|
-
hooks?.onClose?.();
|
|
1105
|
-
hooks?.onEvent?.({ type: "close" });
|
|
1229
|
+
hooks?.onEvent?.({ type: "finalizeStart" });
|
|
1230
|
+
let sawAnyServerEvent = false;
|
|
1231
|
+
const reader = finalizeResponse.body.pipeThrough(new TextDecoderStream).getReader();
|
|
1232
|
+
let buffer = "";
|
|
1233
|
+
while (true) {
|
|
1234
|
+
const { done, value } = await reader.read();
|
|
1235
|
+
if (done) {
|
|
1236
|
+
if (!sawAnyServerEvent) {
|
|
1237
|
+
hooks?.onClose?.();
|
|
1238
|
+
hooks?.onEvent?.({ type: "close" });
|
|
1239
|
+
}
|
|
1240
|
+
break;
|
|
1106
1241
|
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
let eolIndex;
|
|
1111
|
-
while ((eolIndex = buffer.indexOf(`
|
|
1242
|
+
buffer += value;
|
|
1243
|
+
let eolIndex;
|
|
1244
|
+
while ((eolIndex = buffer.indexOf(`
|
|
1112
1245
|
|
|
1113
1246
|
`)) >= 0) {
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
hooks?.onEvent?.({
|
|
1125
|
-
type: "finalizeProgress",
|
|
1126
|
-
percent,
|
|
1127
|
-
currentFileLabel: eventData.currentFileLabel || ""
|
|
1128
|
-
});
|
|
1129
|
-
} else if (eventType === "status") {
|
|
1130
|
-
sawAnyServerEvent = true;
|
|
1131
|
-
if (eventData.message) {
|
|
1247
|
+
const message = buffer.slice(0, eolIndex);
|
|
1248
|
+
buffer = buffer.slice(eolIndex + 2);
|
|
1249
|
+
const eventLine = message.match(/^event: (.*)$/m);
|
|
1250
|
+
const dataLine = message.match(/^data: (.*)$/m);
|
|
1251
|
+
if (eventLine && dataLine) {
|
|
1252
|
+
const eventType = eventLine[1];
|
|
1253
|
+
const eventData = JSON.parse(dataLine[1]);
|
|
1254
|
+
if (eventType === "uploadProgress") {
|
|
1255
|
+
sawAnyServerEvent = true;
|
|
1256
|
+
const percent = (eventData.value ?? 0) / 100;
|
|
1132
1257
|
hooks?.onEvent?.({
|
|
1133
|
-
type: "
|
|
1134
|
-
|
|
1258
|
+
type: "finalizeProgress",
|
|
1259
|
+
percent,
|
|
1260
|
+
currentFileLabel: eventData.currentFileLabel || ""
|
|
1135
1261
|
});
|
|
1262
|
+
} else if (eventType === "status") {
|
|
1263
|
+
sawAnyServerEvent = true;
|
|
1264
|
+
if (eventData.message) {
|
|
1265
|
+
hooks?.onEvent?.({
|
|
1266
|
+
type: "finalizeStatus",
|
|
1267
|
+
message: eventData.message
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
} else if (eventType === "complete") {
|
|
1271
|
+
sawAnyServerEvent = true;
|
|
1272
|
+
reader.cancel();
|
|
1273
|
+
return eventData;
|
|
1274
|
+
} else if (eventType === "error") {
|
|
1275
|
+
sawAnyServerEvent = true;
|
|
1276
|
+
reader.cancel();
|
|
1277
|
+
throw new Error(eventData.message);
|
|
1136
1278
|
}
|
|
1137
|
-
} else if (eventType === "complete") {
|
|
1138
|
-
sawAnyServerEvent = true;
|
|
1139
|
-
reader.cancel();
|
|
1140
|
-
return eventData;
|
|
1141
|
-
} else if (eventType === "error") {
|
|
1142
|
-
sawAnyServerEvent = true;
|
|
1143
|
-
reader.cancel();
|
|
1144
|
-
throw new Error(eventData.message);
|
|
1145
1279
|
}
|
|
1146
1280
|
}
|
|
1147
1281
|
}
|
|
1282
|
+
throw new Error("Upload completed but no final game data received");
|
|
1283
|
+
},
|
|
1284
|
+
backend: async (slug, bundle) => {
|
|
1285
|
+
return client["request"](`/games/${slug}/backend/deploy`, "POST", bundle);
|
|
1148
1286
|
}
|
|
1149
|
-
throw new Error("Upload completed but no final game data received");
|
|
1150
1287
|
},
|
|
1151
|
-
|
|
1288
|
+
upsert: async (slug, metadata) => {
|
|
1289
|
+
return client.dev.games.deploy.frontend(slug, metadata, null);
|
|
1290
|
+
},
|
|
1152
1291
|
delete: (gameId) => client["request"](`/games/${gameId}`, "DELETE")
|
|
1153
1292
|
},
|
|
1154
|
-
keys: {
|
|
1155
|
-
create: (label) => client["request"](`/dev/keys`, "POST", { label }),
|
|
1156
|
-
list: () => client["request"](`/dev/keys`, "GET"),
|
|
1157
|
-
revoke: (keyId) => client["request"](`/dev/keys/${keyId}`, "DELETE")
|
|
1158
|
-
},
|
|
1159
1293
|
items: {
|
|
1160
1294
|
create: (gameId, slug, itemData) => client["request"](`/games/${gameId}/items`, "POST", {
|
|
1161
1295
|
slug,
|
|
@@ -1191,9 +1325,17 @@ function createDevNamespace(client) {
|
|
|
1191
1325
|
|
|
1192
1326
|
// src/core/namespaces/maps.ts
|
|
1193
1327
|
function createMapsNamespace(client) {
|
|
1328
|
+
const mapDataCache = createTTLCache({
|
|
1329
|
+
ttl: 5 * 60 * 1000,
|
|
1330
|
+
keyPrefix: "maps.data"
|
|
1331
|
+
});
|
|
1332
|
+
const mapElementsCache = createTTLCache({
|
|
1333
|
+
ttl: 60 * 1000,
|
|
1334
|
+
keyPrefix: "maps.elements"
|
|
1335
|
+
});
|
|
1194
1336
|
return {
|
|
1195
|
-
get: (identifier) => client["request"](`/maps/${identifier}`, "GET"),
|
|
1196
|
-
elements: (mapId) => client["request"](`/map/elements?mapId=${mapId}`, "GET"),
|
|
1337
|
+
get: (identifier, options) => mapDataCache.get(identifier, () => client["request"](`/maps/${identifier}`, "GET"), options),
|
|
1338
|
+
elements: (mapId, options) => mapElementsCache.get(mapId, () => client["request"](`/map/elements?mapId=${mapId}`, "GET"), options),
|
|
1197
1339
|
objects: {
|
|
1198
1340
|
list: (mapId) => client["request"](`/maps/${mapId}/objects`, "GET"),
|
|
1199
1341
|
create: (mapId, objectData) => client["request"](`/maps/${mapId}/objects`, "POST", objectData),
|
|
@@ -1201,6 +1343,7 @@ function createMapsNamespace(client) {
|
|
|
1201
1343
|
}
|
|
1202
1344
|
};
|
|
1203
1345
|
}
|
|
1346
|
+
var init_maps = () => {};
|
|
1204
1347
|
|
|
1205
1348
|
// src/core/namespaces/admin.ts
|
|
1206
1349
|
function createAdminNamespace(client) {
|
|
@@ -1320,6 +1463,7 @@ var init_levels = () => {};
|
|
|
1320
1463
|
|
|
1321
1464
|
// ../data/src/domains/game/table.ts
|
|
1322
1465
|
import {
|
|
1466
|
+
boolean,
|
|
1323
1467
|
jsonb,
|
|
1324
1468
|
pgEnum,
|
|
1325
1469
|
pgTable,
|
|
@@ -1329,7 +1473,7 @@ import {
|
|
|
1329
1473
|
uuid,
|
|
1330
1474
|
varchar
|
|
1331
1475
|
} from "drizzle-orm/pg-core";
|
|
1332
|
-
var gamePlatformEnum, gameBootModeEnum, gameTypeEnum, games, gameSessions, gameStates;
|
|
1476
|
+
var gamePlatformEnum, gameBootModeEnum, gameTypeEnum, games, gameSessions, gameStates, deploymentProviderEnum, gameBackendDeployments;
|
|
1333
1477
|
var init_table = __esm(() => {
|
|
1334
1478
|
init_table3();
|
|
1335
1479
|
init_table4();
|
|
@@ -1368,12 +1512,23 @@ var init_table = __esm(() => {
|
|
|
1368
1512
|
data: jsonb("data").default("{}"),
|
|
1369
1513
|
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow()
|
|
1370
1514
|
}, (table) => [uniqueIndex("unique_user_game_idx").on(table.userId, table.gameId)]);
|
|
1515
|
+
deploymentProviderEnum = pgEnum("deployment_provider", ["cloudflare", "aws"]);
|
|
1516
|
+
gameBackendDeployments = pgTable("game_backend_deployments", {
|
|
1517
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
1518
|
+
gameId: uuid("game_id").notNull().references(() => games.id, { onDelete: "cascade" }),
|
|
1519
|
+
deploymentId: text("deployment_id").notNull(),
|
|
1520
|
+
provider: deploymentProviderEnum("provider").notNull(),
|
|
1521
|
+
url: text("url").notNull(),
|
|
1522
|
+
codeHash: text("code_hash"),
|
|
1523
|
+
isActive: boolean("is_active").notNull().default(false),
|
|
1524
|
+
deployedAt: timestamp("deployed_at", { withTimezone: true }).notNull().defaultNow()
|
|
1525
|
+
});
|
|
1371
1526
|
});
|
|
1372
1527
|
|
|
1373
1528
|
// ../data/src/domains/inventory/table.ts
|
|
1374
1529
|
import { relations, sql } from "drizzle-orm";
|
|
1375
1530
|
import {
|
|
1376
|
-
boolean,
|
|
1531
|
+
boolean as boolean2,
|
|
1377
1532
|
integer,
|
|
1378
1533
|
jsonb as jsonb2,
|
|
1379
1534
|
pgEnum as pgEnum2,
|
|
@@ -1408,7 +1563,7 @@ var init_table2 = __esm(() => {
|
|
|
1408
1563
|
displayName: text2("display_name").notNull(),
|
|
1409
1564
|
description: text2("description"),
|
|
1410
1565
|
type: itemTypeEnum("type").notNull().default("other"),
|
|
1411
|
-
isPlaceable:
|
|
1566
|
+
isPlaceable: boolean2("is_placeable").default(false).notNull(),
|
|
1412
1567
|
imageUrl: text2("image_url"),
|
|
1413
1568
|
metadata: jsonb2("metadata").default({}),
|
|
1414
1569
|
createdAt: timestamp2("created_at").defaultNow().notNull()
|
|
@@ -1427,7 +1582,7 @@ var init_table2 = __esm(() => {
|
|
|
1427
1582
|
id: uuid2("id").primaryKey().defaultRandom(),
|
|
1428
1583
|
itemId: uuid2("item_id").notNull().references(() => items.id, { onDelete: "cascade" }),
|
|
1429
1584
|
symbol: text2("symbol"),
|
|
1430
|
-
isPrimary:
|
|
1585
|
+
isPrimary: boolean2("is_primary").default(false).notNull(),
|
|
1431
1586
|
createdAt: timestamp2("created_at").defaultNow().notNull(),
|
|
1432
1587
|
updatedAt: timestamp2("updated_at", { withTimezone: true }).defaultNow().$onUpdate(() => new Date)
|
|
1433
1588
|
}, (table) => [uniqueIndex2("currency_item_id_idx").on(table.itemId)]);
|
|
@@ -1438,7 +1593,7 @@ var init_table2 = __esm(() => {
|
|
|
1438
1593
|
price: integer("price").notNull(),
|
|
1439
1594
|
sellBackPercentage: integer("sell_back_percentage"),
|
|
1440
1595
|
stock: integer("stock"),
|
|
1441
|
-
isActive:
|
|
1596
|
+
isActive: boolean2("is_active").default(true).notNull(),
|
|
1442
1597
|
availableFrom: timestamp2("available_from", { withTimezone: true }),
|
|
1443
1598
|
availableUntil: timestamp2("available_until", { withTimezone: true }),
|
|
1444
1599
|
createdAt: timestamp2("created_at").defaultNow().notNull(),
|
|
@@ -1572,7 +1727,7 @@ var init_table3 = __esm(() => {
|
|
|
1572
1727
|
|
|
1573
1728
|
// ../data/src/domains/user/table.ts
|
|
1574
1729
|
import { relations as relations3 } from "drizzle-orm";
|
|
1575
|
-
import { boolean as
|
|
1730
|
+
import { boolean as boolean3, pgEnum as pgEnum4, pgTable as pgTable4, text as text4, timestamp as timestamp4, uniqueIndex as uniqueIndex4 } from "drizzle-orm/pg-core";
|
|
1576
1731
|
var userRoleEnum, developerStatusEnum, users, accounts, sessions, verification, ssoProvider, usersRelations;
|
|
1577
1732
|
var init_table4 = __esm(() => {
|
|
1578
1733
|
init_table3();
|
|
@@ -1584,11 +1739,11 @@ var init_table4 = __esm(() => {
|
|
|
1584
1739
|
username: text4("username").unique(),
|
|
1585
1740
|
email: text4("email").notNull().unique(),
|
|
1586
1741
|
timebackId: text4("timeback_id").unique(),
|
|
1587
|
-
emailVerified:
|
|
1742
|
+
emailVerified: boolean3("email_verified").notNull().default(false),
|
|
1588
1743
|
image: text4("image"),
|
|
1589
1744
|
role: userRoleEnum("role").notNull().default("player"),
|
|
1590
1745
|
developerStatus: developerStatusEnum("developer_status").notNull().default("none"),
|
|
1591
|
-
characterCreated:
|
|
1746
|
+
characterCreated: boolean3("character_created").notNull().default(false),
|
|
1592
1747
|
createdAt: timestamp4("created_at", {
|
|
1593
1748
|
mode: "date",
|
|
1594
1749
|
withTimezone: true
|
|
@@ -1677,16 +1832,32 @@ var init_table4 = __esm(() => {
|
|
|
1677
1832
|
});
|
|
1678
1833
|
|
|
1679
1834
|
// ../data/src/domains/developer/table.ts
|
|
1680
|
-
import { pgTable as pgTable5, text as text5, timestamp as timestamp5, uuid as uuid4
|
|
1681
|
-
var
|
|
1835
|
+
import { boolean as boolean4, integer as integer3, pgTable as pgTable5, text as text5, timestamp as timestamp5, uuid as uuid4 } from "drizzle-orm/pg-core";
|
|
1836
|
+
var apikey;
|
|
1682
1837
|
var init_table5 = __esm(() => {
|
|
1683
1838
|
init_table4();
|
|
1684
|
-
|
|
1839
|
+
apikey = pgTable5("api_key", {
|
|
1685
1840
|
id: uuid4("id").primaryKey().defaultRandom(),
|
|
1841
|
+
name: text5("name"),
|
|
1842
|
+
start: text5("start"),
|
|
1843
|
+
prefix: text5("prefix"),
|
|
1844
|
+
key: text5("key").notNull(),
|
|
1686
1845
|
userId: text5("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1846
|
+
refillInterval: integer3("refill_interval"),
|
|
1847
|
+
refillAmount: integer3("refill_amount"),
|
|
1848
|
+
lastRefillAt: timestamp5("last_refill_at", { withTimezone: true }),
|
|
1849
|
+
enabled: boolean4("enabled").notNull().default(true),
|
|
1850
|
+
rateLimitEnabled: boolean4("rate_limit_enabled").notNull().default(false),
|
|
1851
|
+
rateLimitTimeWindow: integer3("rate_limit_time_window"),
|
|
1852
|
+
rateLimitMax: integer3("rate_limit_max"),
|
|
1853
|
+
requestCount: integer3("request_count").notNull().default(0),
|
|
1854
|
+
remaining: integer3("remaining"),
|
|
1855
|
+
lastRequest: timestamp5("last_request", { withTimezone: true }),
|
|
1856
|
+
expiresAt: timestamp5("expires_at", { withTimezone: true }),
|
|
1857
|
+
createdAt: timestamp5("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1858
|
+
updatedAt: timestamp5("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1859
|
+
permissions: text5("permissions"),
|
|
1860
|
+
metadata: text5("metadata")
|
|
1690
1861
|
});
|
|
1691
1862
|
});
|
|
1692
1863
|
|
|
@@ -1694,7 +1865,7 @@ var init_table5 = __esm(() => {
|
|
|
1694
1865
|
import { relations as relations4 } from "drizzle-orm";
|
|
1695
1866
|
import {
|
|
1696
1867
|
doublePrecision as doublePrecision2,
|
|
1697
|
-
integer as
|
|
1868
|
+
integer as integer4,
|
|
1698
1869
|
pgTable as pgTable6,
|
|
1699
1870
|
text as text6,
|
|
1700
1871
|
timestamp as timestamp6,
|
|
@@ -1706,7 +1877,7 @@ var init_table6 = __esm(() => {
|
|
|
1706
1877
|
init_table4();
|
|
1707
1878
|
userLevels = pgTable6("user_levels", {
|
|
1708
1879
|
userId: text6("user_id").primaryKey().references(() => users.id, { onDelete: "cascade" }),
|
|
1709
|
-
currentLevel:
|
|
1880
|
+
currentLevel: integer4("current_level").notNull().default(1),
|
|
1710
1881
|
currentXp: doublePrecision2("current_xp").notNull().default(0),
|
|
1711
1882
|
totalXP: doublePrecision2("total_xp").notNull().default(0),
|
|
1712
1883
|
lastLevelUpAt: timestamp6("last_level_up_at", { withTimezone: true }),
|
|
@@ -1715,9 +1886,9 @@ var init_table6 = __esm(() => {
|
|
|
1715
1886
|
});
|
|
1716
1887
|
levelConfigs = pgTable6("level_configs", {
|
|
1717
1888
|
id: uuid5("id").primaryKey().defaultRandom(),
|
|
1718
|
-
level:
|
|
1719
|
-
xpRequired:
|
|
1720
|
-
creditsReward:
|
|
1889
|
+
level: integer4("level").notNull().unique(),
|
|
1890
|
+
xpRequired: integer4("xp_required").notNull(),
|
|
1891
|
+
creditsReward: integer4("credits_reward").notNull().default(0),
|
|
1721
1892
|
createdAt: timestamp6("created_at").defaultNow().notNull()
|
|
1722
1893
|
}, (table) => [uniqueIndex5("unique_level_config_idx").on(table.level)]);
|
|
1723
1894
|
userLevelsRelations = relations4(userLevels, ({ one }) => ({
|
|
@@ -1730,7 +1901,7 @@ var init_table6 = __esm(() => {
|
|
|
1730
1901
|
|
|
1731
1902
|
// ../data/src/domains/leaderboard/table.ts
|
|
1732
1903
|
import { relations as relations5 } from "drizzle-orm";
|
|
1733
|
-
import { index as index2, integer as
|
|
1904
|
+
import { index as index2, integer as integer5, jsonb as jsonb4, pgTable as pgTable7, text as text7, timestamp as timestamp7, uuid as uuid6 } from "drizzle-orm/pg-core";
|
|
1734
1905
|
var gameScores, gameScoresRelations;
|
|
1735
1906
|
var init_table7 = __esm(() => {
|
|
1736
1907
|
init_table();
|
|
@@ -1739,7 +1910,7 @@ var init_table7 = __esm(() => {
|
|
|
1739
1910
|
id: uuid6("id").primaryKey().defaultRandom(),
|
|
1740
1911
|
userId: text7("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
1741
1912
|
gameId: uuid6("game_id").notNull().references(() => games.id, { onDelete: "cascade" }),
|
|
1742
|
-
score:
|
|
1913
|
+
score: integer5("score").notNull(),
|
|
1743
1914
|
metadata: jsonb4("metadata").default("{}"),
|
|
1744
1915
|
achievedAt: timestamp7("achieved_at", { withTimezone: true }).defaultNow().notNull(),
|
|
1745
1916
|
sessionId: uuid6("session_id").references(() => gameSessions.id, { onDelete: "set null" })
|
|
@@ -1766,22 +1937,22 @@ var init_table7 = __esm(() => {
|
|
|
1766
1937
|
|
|
1767
1938
|
// ../data/src/domains/sprite/table.ts
|
|
1768
1939
|
import { relations as relations6 } from "drizzle-orm";
|
|
1769
|
-
import { integer as
|
|
1940
|
+
import { integer as integer6, pgTable as pgTable8, timestamp as timestamp8, uuid as uuid7, varchar as varchar3 } from "drizzle-orm/pg-core";
|
|
1770
1941
|
var spriteTemplates, spriteSheets, spriteTemplatesRelations, spriteSheetsRelations;
|
|
1771
1942
|
var init_table8 = __esm(() => {
|
|
1772
1943
|
spriteTemplates = pgTable8("sprite_templates", {
|
|
1773
1944
|
id: uuid7("id").primaryKey().defaultRandom(),
|
|
1774
|
-
slug:
|
|
1775
|
-
url:
|
|
1945
|
+
slug: varchar3("slug", { length: 64 }).notNull().unique(),
|
|
1946
|
+
url: varchar3("url", { length: 255 }).notNull(),
|
|
1776
1947
|
createdAt: timestamp8("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1777
1948
|
updatedAt: timestamp8("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
1778
1949
|
});
|
|
1779
1950
|
spriteSheets = pgTable8("sprite_sheets", {
|
|
1780
1951
|
id: uuid7("id").primaryKey().defaultRandom(),
|
|
1781
1952
|
templateId: uuid7("template_id").notNull().references(() => spriteTemplates.id, { onDelete: "cascade" }),
|
|
1782
|
-
width:
|
|
1783
|
-
height:
|
|
1784
|
-
url:
|
|
1953
|
+
width: integer6("width").notNull(),
|
|
1954
|
+
height: integer6("height").notNull(),
|
|
1955
|
+
url: varchar3("url", { length: 255 }).notNull(),
|
|
1785
1956
|
createdAt: timestamp8("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1786
1957
|
updatedAt: timestamp8("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
1787
1958
|
});
|
|
@@ -1799,14 +1970,14 @@ var init_table8 = __esm(() => {
|
|
|
1799
1970
|
// ../data/src/domains/character/table.ts
|
|
1800
1971
|
import { relations as relations7 } from "drizzle-orm";
|
|
1801
1972
|
import {
|
|
1802
|
-
integer as
|
|
1973
|
+
integer as integer7,
|
|
1803
1974
|
pgEnum as pgEnum5,
|
|
1804
1975
|
pgTable as pgTable9,
|
|
1805
1976
|
text as text8,
|
|
1806
1977
|
timestamp as timestamp9,
|
|
1807
1978
|
uniqueIndex as uniqueIndex6,
|
|
1808
1979
|
uuid as uuid8,
|
|
1809
|
-
varchar as
|
|
1980
|
+
varchar as varchar4
|
|
1810
1981
|
} from "drizzle-orm/pg-core";
|
|
1811
1982
|
var characterComponentTypeEnum, characterComponents, playerCharacters, playerCharacterAccessories, characterComponentsRelations, playerCharactersRelations, playerCharacterAccessoriesRelations;
|
|
1812
1983
|
var init_table9 = __esm(() => {
|
|
@@ -1822,12 +1993,12 @@ var init_table9 = __esm(() => {
|
|
|
1822
1993
|
characterComponents = pgTable9("character_components", {
|
|
1823
1994
|
id: uuid8("id").primaryKey().defaultRandom(),
|
|
1824
1995
|
componentType: characterComponentTypeEnum("component_type").notNull(),
|
|
1825
|
-
slug:
|
|
1826
|
-
displayName:
|
|
1827
|
-
slot:
|
|
1996
|
+
slug: varchar4("slug", { length: 128 }).notNull().unique(),
|
|
1997
|
+
displayName: varchar4("display_name", { length: 128 }).notNull(),
|
|
1998
|
+
slot: varchar4("slot", { length: 64 }).notNull(),
|
|
1828
1999
|
spriteSheetId: uuid8("sprite_sheet_id").notNull().references(() => spriteSheets.id, { onDelete: "cascade" }),
|
|
1829
|
-
unlockLevel:
|
|
1830
|
-
variant:
|
|
2000
|
+
unlockLevel: integer7("unlock_level").notNull().default(0),
|
|
2001
|
+
variant: integer7("variant").notNull().default(0),
|
|
1831
2002
|
createdAt: timestamp9("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1832
2003
|
updatedAt: timestamp9("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
1833
2004
|
});
|
|
@@ -1845,7 +2016,7 @@ var init_table9 = __esm(() => {
|
|
|
1845
2016
|
id: uuid8("id").primaryKey().defaultRandom(),
|
|
1846
2017
|
playerCharacterId: uuid8("player_character_id").notNull().references(() => playerCharacters.id, { onDelete: "cascade" }),
|
|
1847
2018
|
accessoryComponentId: uuid8("accessory_component_id").notNull().references(() => characterComponents.id, { onDelete: "cascade" }),
|
|
1848
|
-
slot:
|
|
2019
|
+
slot: varchar4("slot", { length: 64 }).notNull(),
|
|
1849
2020
|
equippedAt: timestamp9("equipped_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1850
2021
|
updatedAt: timestamp9("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
1851
2022
|
}, (table) => [
|
|
@@ -1895,8 +2066,9 @@ var init_table9 = __esm(() => {
|
|
|
1895
2066
|
|
|
1896
2067
|
// ../data/src/domains/timeback/table.ts
|
|
1897
2068
|
import { doublePrecision as doublePrecision3, pgTable as pgTable10, text as text9, timestamp as timestamp10, uniqueIndex as uniqueIndex7, uuid as uuid9 } from "drizzle-orm/pg-core";
|
|
1898
|
-
var timebackDailyXp, timebackXpEvents;
|
|
2069
|
+
var timebackDailyXp, timebackXpEvents, gameTimebackIntegrations;
|
|
1899
2070
|
var init_table10 = __esm(() => {
|
|
2071
|
+
init_table();
|
|
1900
2072
|
init_table4();
|
|
1901
2073
|
timebackDailyXp = pgTable10("timeback_daily_xp", {
|
|
1902
2074
|
userId: text9("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
@@ -1917,14 +2089,22 @@ var init_table10 = __esm(() => {
|
|
|
1917
2089
|
createdAt: timestamp10("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1918
2090
|
updatedAt: timestamp10("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
1919
2091
|
}, (table) => [uniqueIndex7("timeback_xp_events_source_id_idx").on(table.source, table.sourceId)]);
|
|
2092
|
+
gameTimebackIntegrations = pgTable10("game_timeback_integrations", {
|
|
2093
|
+
id: uuid9("id").primaryKey().defaultRandom(),
|
|
2094
|
+
gameId: uuid9("game_id").notNull().unique().references(() => games.id, { onDelete: "cascade" }),
|
|
2095
|
+
courseId: text9("course_id").notNull(),
|
|
2096
|
+
lastVerifiedAt: timestamp10("last_verified_at", { withTimezone: true }),
|
|
2097
|
+
createdAt: timestamp10("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
2098
|
+
updatedAt: timestamp10("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
2099
|
+
});
|
|
1920
2100
|
});
|
|
1921
2101
|
|
|
1922
2102
|
// ../data/src/domains/achievement/table.ts
|
|
1923
2103
|
import { relations as relations8 } from "drizzle-orm";
|
|
1924
2104
|
import {
|
|
1925
|
-
boolean as
|
|
2105
|
+
boolean as boolean5,
|
|
1926
2106
|
index as index3,
|
|
1927
|
-
integer as
|
|
2107
|
+
integer as integer8,
|
|
1928
2108
|
jsonb as jsonb5,
|
|
1929
2109
|
pgEnum as pgEnum6,
|
|
1930
2110
|
pgTable as pgTable11,
|
|
@@ -1932,45 +2112,55 @@ import {
|
|
|
1932
2112
|
timestamp as timestamp11,
|
|
1933
2113
|
uniqueIndex as uniqueIndex8,
|
|
1934
2114
|
uuid as uuid10,
|
|
1935
|
-
varchar as
|
|
2115
|
+
varchar as varchar5
|
|
1936
2116
|
} from "drizzle-orm/pg-core";
|
|
1937
|
-
var
|
|
2117
|
+
var achievementScopeEnum, achievements, userAchievementProgress, userAchievementClaims, userAchievementProgressRelations, userAchievementClaimsRelations;
|
|
1938
2118
|
var init_table11 = __esm(() => {
|
|
1939
2119
|
init_table4();
|
|
1940
|
-
|
|
2120
|
+
achievementScopeEnum = pgEnum6("achievement_scope", [
|
|
2121
|
+
"daily",
|
|
2122
|
+
"weekly",
|
|
2123
|
+
"monthly",
|
|
2124
|
+
"yearly",
|
|
2125
|
+
"game",
|
|
2126
|
+
"global",
|
|
2127
|
+
"map",
|
|
2128
|
+
"level",
|
|
2129
|
+
"event"
|
|
2130
|
+
]);
|
|
1941
2131
|
achievements = pgTable11("achievements", {
|
|
1942
|
-
id:
|
|
1943
|
-
title:
|
|
2132
|
+
id: varchar5("id", { length: 255 }).primaryKey(),
|
|
2133
|
+
title: varchar5("title", { length: 255 }).notNull(),
|
|
1944
2134
|
description: text10("description"),
|
|
1945
|
-
|
|
1946
|
-
rewardCredits:
|
|
1947
|
-
|
|
1948
|
-
completionType:
|
|
2135
|
+
scope: achievementScopeEnum("scope").notNull(),
|
|
2136
|
+
rewardCredits: integer8("reward_credits").notNull().default(0),
|
|
2137
|
+
limit: integer8("limit").notNull().default(1),
|
|
2138
|
+
completionType: varchar5("completion_type", { length: 50 }).notNull(),
|
|
1949
2139
|
completionConfig: jsonb5("completion_config").notNull().default({}),
|
|
1950
|
-
|
|
1951
|
-
active:
|
|
2140
|
+
target: jsonb5("target").notNull().default({}),
|
|
2141
|
+
active: boolean5("active").notNull().default(true),
|
|
1952
2142
|
createdAt: timestamp11("created_at", { withTimezone: true }).defaultNow(),
|
|
1953
2143
|
updatedAt: timestamp11("updated_at", { withTimezone: true }).defaultNow()
|
|
1954
2144
|
});
|
|
1955
2145
|
userAchievementProgress = pgTable11("user_achievement_progress", {
|
|
1956
2146
|
id: uuid10("id").primaryKey().defaultRandom(),
|
|
1957
2147
|
userId: text10("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
1958
|
-
achievementId:
|
|
1959
|
-
|
|
2148
|
+
achievementId: varchar5("achievement_id", { length: 255 }).notNull().references(() => achievements.id, { onDelete: "cascade" }),
|
|
2149
|
+
scopeKey: text10("scope_key").notNull(),
|
|
1960
2150
|
progress: jsonb5("progress").notNull().default({}),
|
|
1961
2151
|
updatedAt: timestamp11("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
1962
2152
|
}, (table) => [
|
|
1963
|
-
index3("user_achievement_progress_idx").on(table.userId, table.achievementId, table.
|
|
2153
|
+
index3("user_achievement_progress_idx").on(table.userId, table.achievementId, table.scopeKey)
|
|
1964
2154
|
]);
|
|
1965
2155
|
userAchievementClaims = pgTable11("user_achievement_claims", {
|
|
1966
2156
|
id: uuid10("id").primaryKey().defaultRandom(),
|
|
1967
2157
|
userId: text10("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
1968
|
-
achievementId:
|
|
1969
|
-
|
|
1970
|
-
rewardCredits:
|
|
2158
|
+
achievementId: varchar5("achievement_id", { length: 255 }).notNull().references(() => achievements.id, { onDelete: "cascade" }),
|
|
2159
|
+
scopeKey: text10("scope_key").notNull(),
|
|
2160
|
+
rewardCredits: integer8("reward_credits").notNull(),
|
|
1971
2161
|
createdAt: timestamp11("created_at", { withTimezone: true }).defaultNow().notNull()
|
|
1972
2162
|
}, (table) => [
|
|
1973
|
-
uniqueIndex8("user_achievement_claims_unique").on(table.userId, table.achievementId, table.
|
|
2163
|
+
uniqueIndex8("user_achievement_claims_unique").on(table.userId, table.achievementId, table.scopeKey)
|
|
1974
2164
|
]);
|
|
1975
2165
|
userAchievementProgressRelations = relations8(userAchievementProgress, ({ one }) => ({
|
|
1976
2166
|
user: one(users, {
|
|
@@ -1994,6 +2184,58 @@ var init_table11 = __esm(() => {
|
|
|
1994
2184
|
}));
|
|
1995
2185
|
});
|
|
1996
2186
|
|
|
2187
|
+
// ../data/src/domains/notification/table.ts
|
|
2188
|
+
import { relations as relations9 } from "drizzle-orm";
|
|
2189
|
+
import { index as index4, jsonb as jsonb6, pgEnum as pgEnum7, pgTable as pgTable12, text as text11, timestamp as timestamp12, uuid as uuid11, varchar as varchar6 } from "drizzle-orm/pg-core";
|
|
2190
|
+
var notificationPriorityEnum, notificationStatusEnum, notifications, notificationsRelations;
|
|
2191
|
+
var init_table12 = __esm(() => {
|
|
2192
|
+
init_table4();
|
|
2193
|
+
notificationPriorityEnum = pgEnum7("notification_priority", [
|
|
2194
|
+
"low",
|
|
2195
|
+
"normal",
|
|
2196
|
+
"high",
|
|
2197
|
+
"urgent"
|
|
2198
|
+
]);
|
|
2199
|
+
notificationStatusEnum = pgEnum7("notification_status", [
|
|
2200
|
+
"pending",
|
|
2201
|
+
"delivered",
|
|
2202
|
+
"seen",
|
|
2203
|
+
"clicked",
|
|
2204
|
+
"dismissed",
|
|
2205
|
+
"expired"
|
|
2206
|
+
]);
|
|
2207
|
+
notifications = pgTable12("notifications", {
|
|
2208
|
+
id: uuid11("id").primaryKey().defaultRandom(),
|
|
2209
|
+
userId: text11("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
2210
|
+
type: varchar6("type", { length: 50 }).notNull(),
|
|
2211
|
+
title: varchar6("title", { length: 255 }).notNull(),
|
|
2212
|
+
message: text11("message").notNull(),
|
|
2213
|
+
data: jsonb6("data").notNull().default({}),
|
|
2214
|
+
priority: notificationPriorityEnum("priority").notNull().default("normal"),
|
|
2215
|
+
status: notificationStatusEnum("status").notNull().default("pending"),
|
|
2216
|
+
createdAt: timestamp12("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
2217
|
+
deliveredAt: timestamp12("delivered_at", { withTimezone: true }),
|
|
2218
|
+
seenAt: timestamp12("seen_at", { withTimezone: true }),
|
|
2219
|
+
clickedAt: timestamp12("clicked_at", { withTimezone: true }),
|
|
2220
|
+
expiresAt: timestamp12("expires_at", { withTimezone: true }),
|
|
2221
|
+
method: varchar6("method", { length: 50 }),
|
|
2222
|
+
clickUrl: text11("click_url"),
|
|
2223
|
+
metadata: jsonb6("metadata").notNull().default({})
|
|
2224
|
+
}, (table) => [
|
|
2225
|
+
index4("notifications_user_id_idx").on(table.userId),
|
|
2226
|
+
index4("notifications_status_idx").on(table.status),
|
|
2227
|
+
index4("notifications_type_idx").on(table.type),
|
|
2228
|
+
index4("notifications_created_at_idx").on(table.createdAt),
|
|
2229
|
+
index4("notifications_user_status_idx").on(table.userId, table.status)
|
|
2230
|
+
]);
|
|
2231
|
+
notificationsRelations = relations9(notifications, ({ one }) => ({
|
|
2232
|
+
user: one(users, {
|
|
2233
|
+
fields: [notifications.userId],
|
|
2234
|
+
references: [users.id]
|
|
2235
|
+
})
|
|
2236
|
+
}));
|
|
2237
|
+
});
|
|
2238
|
+
|
|
1997
2239
|
// ../data/src/tables.index.ts
|
|
1998
2240
|
var init_tables_index = __esm(() => {
|
|
1999
2241
|
init_table4();
|
|
@@ -2007,10 +2249,11 @@ var init_tables_index = __esm(() => {
|
|
|
2007
2249
|
init_table9();
|
|
2008
2250
|
init_table10();
|
|
2009
2251
|
init_table11();
|
|
2252
|
+
init_table12();
|
|
2010
2253
|
});
|
|
2011
2254
|
|
|
2012
2255
|
// ../data/src/constants.ts
|
|
2013
|
-
var ITEM_SLUGS, CURRENCIES, BADGES,
|
|
2256
|
+
var ITEM_SLUGS, CURRENCIES, BADGES, INTERACTION_TYPE;
|
|
2014
2257
|
var init_constants = __esm(() => {
|
|
2015
2258
|
init_tables_index();
|
|
2016
2259
|
ITEM_SLUGS = {
|
|
@@ -2035,12 +2278,6 @@ var init_constants = __esm(() => {
|
|
|
2035
2278
|
EARLY_ADOPTER: ITEM_SLUGS.EARLY_ADOPTER_BADGE,
|
|
2036
2279
|
FIRST_GAME: ITEM_SLUGS.FIRST_GAME_BADGE
|
|
2037
2280
|
};
|
|
2038
|
-
ACHIEVEMENT_COMPLETION_TYPES = [
|
|
2039
|
-
"time_played_session",
|
|
2040
|
-
"interaction",
|
|
2041
|
-
"leaderboard_rank"
|
|
2042
|
-
];
|
|
2043
|
-
ACHIEVEMENT_COMPLETION_TYPE = Object.fromEntries(ACHIEVEMENT_COMPLETION_TYPES.map((value) => [value, value]));
|
|
2044
2281
|
INTERACTION_TYPE = Object.fromEntries(interactionTypeEnum.enumValues.map((value) => [value, value]));
|
|
2045
2282
|
});
|
|
2046
2283
|
|
|
@@ -2517,6 +2754,32 @@ var init_achievements = () => {};
|
|
|
2517
2754
|
// src/core/namespaces/timeback.ts
|
|
2518
2755
|
function createTimebackNamespace(client) {
|
|
2519
2756
|
return {
|
|
2757
|
+
recordProgress: (progressData) => {
|
|
2758
|
+
return client["request"]("/api/integrations/timeback/progress", "POST", { progressData });
|
|
2759
|
+
},
|
|
2760
|
+
recordSessionEnd: (sessionData) => {
|
|
2761
|
+
return client["request"]("/api/integrations/timeback/session-end", "POST", { sessionData });
|
|
2762
|
+
},
|
|
2763
|
+
awardXP: (xpAmount, metadata) => {
|
|
2764
|
+
return client["request"]("/api/integrations/timeback/award-xp", "POST", { xpAmount, metadata });
|
|
2765
|
+
},
|
|
2766
|
+
management: {
|
|
2767
|
+
setup: (request2) => {
|
|
2768
|
+
return client["request"]("/timeback/setup", "POST", request2);
|
|
2769
|
+
},
|
|
2770
|
+
verify: (gameId) => {
|
|
2771
|
+
return client["request"](`/timeback/verify/${gameId}`, "GET");
|
|
2772
|
+
},
|
|
2773
|
+
cleanup: (gameId) => {
|
|
2774
|
+
return client["request"](`/timeback/integrations/${gameId}`, "DELETE");
|
|
2775
|
+
},
|
|
2776
|
+
get: (gameId) => {
|
|
2777
|
+
return client["request"](`/timeback/integrations/${gameId}`, "GET");
|
|
2778
|
+
},
|
|
2779
|
+
getConfig: (gameId) => {
|
|
2780
|
+
return client["request"](`/timeback/config/${gameId}`, "GET");
|
|
2781
|
+
}
|
|
2782
|
+
},
|
|
2520
2783
|
xp: {
|
|
2521
2784
|
today: async (options) => {
|
|
2522
2785
|
const params = new URLSearchParams;
|
|
@@ -2560,18 +2823,88 @@ function createTimebackNamespace(client) {
|
|
|
2560
2823
|
};
|
|
2561
2824
|
}
|
|
2562
2825
|
|
|
2826
|
+
// src/core/namespaces/notifications.ts
|
|
2827
|
+
function createNotificationsNamespace(client) {
|
|
2828
|
+
const notificationsListCache = createTTLCache({
|
|
2829
|
+
ttl: 5 * 1000,
|
|
2830
|
+
keyPrefix: "notifications.list"
|
|
2831
|
+
});
|
|
2832
|
+
const notificationStatsCache = createTTLCache({
|
|
2833
|
+
ttl: 30 * 1000,
|
|
2834
|
+
keyPrefix: "notifications.stats"
|
|
2835
|
+
});
|
|
2836
|
+
return {
|
|
2837
|
+
list: async (queryOptions, cacheOptions) => {
|
|
2838
|
+
const params = new URLSearchParams;
|
|
2839
|
+
if (queryOptions?.status)
|
|
2840
|
+
params.append("status", queryOptions.status);
|
|
2841
|
+
if (queryOptions?.type)
|
|
2842
|
+
params.append("type", queryOptions.type);
|
|
2843
|
+
if (queryOptions?.limit)
|
|
2844
|
+
params.append("limit", String(queryOptions.limit));
|
|
2845
|
+
if (queryOptions?.offset)
|
|
2846
|
+
params.append("offset", String(queryOptions.offset));
|
|
2847
|
+
const qs = params.toString();
|
|
2848
|
+
const path = qs ? `/notifications?${qs}` : "/notifications";
|
|
2849
|
+
const cacheKey = qs ? `list-${qs}` : "list";
|
|
2850
|
+
return notificationsListCache.get(cacheKey, () => client["request"](path, "GET"), cacheOptions);
|
|
2851
|
+
},
|
|
2852
|
+
markAsSeen: async (notificationId) => {
|
|
2853
|
+
const result = await client["request"](`/notifications/${notificationId}/status`, "PATCH", {
|
|
2854
|
+
id: notificationId,
|
|
2855
|
+
status: "seen"
|
|
2856
|
+
});
|
|
2857
|
+
notificationsListCache.clear();
|
|
2858
|
+
return result;
|
|
2859
|
+
},
|
|
2860
|
+
markAsClicked: async (notificationId) => {
|
|
2861
|
+
const result = await client["request"](`/notifications/${notificationId}/status`, "PATCH", {
|
|
2862
|
+
id: notificationId,
|
|
2863
|
+
status: "clicked"
|
|
2864
|
+
});
|
|
2865
|
+
notificationsListCache.clear();
|
|
2866
|
+
return result;
|
|
2867
|
+
},
|
|
2868
|
+
dismiss: async (notificationId) => {
|
|
2869
|
+
const result = await client["request"](`/notifications/${notificationId}/status`, "PATCH", {
|
|
2870
|
+
id: notificationId,
|
|
2871
|
+
status: "dismissed"
|
|
2872
|
+
});
|
|
2873
|
+
notificationsListCache.clear();
|
|
2874
|
+
return result;
|
|
2875
|
+
},
|
|
2876
|
+
stats: {
|
|
2877
|
+
get: async (queryOptions, cacheOptions) => {
|
|
2878
|
+
const user = await client.users.me();
|
|
2879
|
+
const params = new URLSearchParams;
|
|
2880
|
+
if (queryOptions?.from)
|
|
2881
|
+
params.append("from", queryOptions.from);
|
|
2882
|
+
if (queryOptions?.to)
|
|
2883
|
+
params.append("to", queryOptions.to);
|
|
2884
|
+
const qs = params.toString();
|
|
2885
|
+
const path = qs ? `/notifications/stats/${user.id}?${qs}` : `/notifications/stats/${user.id}`;
|
|
2886
|
+
const cacheKey = qs ? `stats-${qs}` : "stats";
|
|
2887
|
+
return notificationStatsCache.get(cacheKey, () => client["request"](path, "GET"), cacheOptions);
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
};
|
|
2891
|
+
}
|
|
2892
|
+
var init_notifications = () => {};
|
|
2893
|
+
|
|
2563
2894
|
// src/core/namespaces/index.ts
|
|
2564
2895
|
var init_namespaces = __esm(() => {
|
|
2565
2896
|
init_identity();
|
|
2566
2897
|
init_runtime();
|
|
2567
2898
|
init_games();
|
|
2568
2899
|
init_users();
|
|
2900
|
+
init_maps();
|
|
2569
2901
|
init_levels();
|
|
2570
2902
|
init_credits();
|
|
2571
2903
|
init_character();
|
|
2572
2904
|
init_sprites();
|
|
2573
2905
|
init_realtime();
|
|
2574
2906
|
init_achievements();
|
|
2907
|
+
init_notifications();
|
|
2575
2908
|
});
|
|
2576
2909
|
|
|
2577
2910
|
// src/core/static/init.ts
|
|
@@ -2596,11 +2929,12 @@ function getReferrerOrigin() {
|
|
|
2596
2929
|
function buildAllowedOrigins(explicit) {
|
|
2597
2930
|
if (Array.isArray(explicit) && explicit.length > 0)
|
|
2598
2931
|
return explicit;
|
|
2599
|
-
const
|
|
2600
|
-
return
|
|
2932
|
+
const ref = getReferrerOrigin();
|
|
2933
|
+
return ref ? [ref] : [];
|
|
2601
2934
|
}
|
|
2602
2935
|
function isOriginAllowed(origin, allowlist) {
|
|
2603
2936
|
if (!allowlist || allowlist.length === 0) {
|
|
2937
|
+
console.error("[Playcademy SDK] No allowed origins configured. Consider passing allowedParentOrigins explicitly to init().");
|
|
2604
2938
|
return false;
|
|
2605
2939
|
}
|
|
2606
2940
|
return allowlist.includes(origin);
|
|
@@ -2610,11 +2944,18 @@ async function waitForPlaycademyInit(allowedParentOrigins) {
|
|
|
2610
2944
|
let contextReceived = false;
|
|
2611
2945
|
const timeoutDuration = 5000;
|
|
2612
2946
|
const allowlist = buildAllowedOrigins(allowedParentOrigins);
|
|
2947
|
+
let hasWarnedAboutUntrustedOrigin = false;
|
|
2948
|
+
function warnAboutUntrustedOrigin(origin) {
|
|
2949
|
+
if (hasWarnedAboutUntrustedOrigin)
|
|
2950
|
+
return;
|
|
2951
|
+
hasWarnedAboutUntrustedOrigin = true;
|
|
2952
|
+
console.warn("[Playcademy SDK] Ignoring INIT from untrusted origin:", origin);
|
|
2953
|
+
}
|
|
2613
2954
|
const handleMessage = (event) => {
|
|
2614
2955
|
if (event.data?.type !== "PLAYCADEMY_INIT" /* INIT */)
|
|
2615
2956
|
return;
|
|
2616
2957
|
if (!isOriginAllowed(event.origin, allowlist)) {
|
|
2617
|
-
|
|
2958
|
+
warnAboutUntrustedOrigin(event.origin);
|
|
2618
2959
|
return;
|
|
2619
2960
|
}
|
|
2620
2961
|
contextReceived = true;
|
|
@@ -2731,7 +3072,7 @@ var init_client = __esm(() => {
|
|
|
2731
3072
|
init_static();
|
|
2732
3073
|
PlaycademyClient = class PlaycademyClient {
|
|
2733
3074
|
baseUrl;
|
|
2734
|
-
|
|
3075
|
+
authStrategy;
|
|
2735
3076
|
gameId;
|
|
2736
3077
|
config;
|
|
2737
3078
|
listeners = {};
|
|
@@ -2739,16 +3080,10 @@ var init_client = __esm(() => {
|
|
|
2739
3080
|
authContext;
|
|
2740
3081
|
initPayload;
|
|
2741
3082
|
constructor(config) {
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
this.token = undefined;
|
|
2745
|
-
this.gameId = undefined;
|
|
2746
|
-
} else {
|
|
2747
|
-
this.baseUrl = config.baseUrl || "/api";
|
|
2748
|
-
this.token = config.token;
|
|
2749
|
-
this.gameId = config.gameId;
|
|
2750
|
-
}
|
|
3083
|
+
this.baseUrl = config?.baseUrl || "/api";
|
|
3084
|
+
this.gameId = config?.gameId;
|
|
2751
3085
|
this.config = config || {};
|
|
3086
|
+
this.authStrategy = createAuthStrategy(config?.token ?? null, config?.tokenType);
|
|
2752
3087
|
this._detectAuthContext();
|
|
2753
3088
|
this._initializeInternalSession().catch(() => {});
|
|
2754
3089
|
}
|
|
@@ -2760,15 +3095,18 @@ var init_client = __esm(() => {
|
|
|
2760
3095
|
ping() {
|
|
2761
3096
|
return "pong";
|
|
2762
3097
|
}
|
|
2763
|
-
setToken(token) {
|
|
2764
|
-
this.
|
|
2765
|
-
this.emit("authChange", { token
|
|
3098
|
+
setToken(token, tokenType) {
|
|
3099
|
+
this.authStrategy = createAuthStrategy(token, tokenType);
|
|
3100
|
+
this.emit("authChange", { token });
|
|
3101
|
+
}
|
|
3102
|
+
getTokenType() {
|
|
3103
|
+
return this.authStrategy.getType();
|
|
2766
3104
|
}
|
|
2767
3105
|
getToken() {
|
|
2768
|
-
return this.
|
|
3106
|
+
return this.authStrategy.getToken();
|
|
2769
3107
|
}
|
|
2770
3108
|
isAuthenticated() {
|
|
2771
|
-
return
|
|
3109
|
+
return this.authStrategy.getToken() !== null;
|
|
2772
3110
|
}
|
|
2773
3111
|
onAuthChange(callback) {
|
|
2774
3112
|
this.on("authChange", (payload) => callback(payload.token));
|
|
@@ -2786,13 +3124,15 @@ var init_client = __esm(() => {
|
|
|
2786
3124
|
});
|
|
2787
3125
|
}
|
|
2788
3126
|
async request(path, method, body, headers) {
|
|
2789
|
-
const effectiveHeaders = {
|
|
3127
|
+
const effectiveHeaders = {
|
|
3128
|
+
...headers,
|
|
3129
|
+
...this.authStrategy.getHeaders()
|
|
3130
|
+
};
|
|
2790
3131
|
return request({
|
|
2791
3132
|
path,
|
|
2792
3133
|
method,
|
|
2793
3134
|
body,
|
|
2794
3135
|
baseUrl: this.baseUrl,
|
|
2795
|
-
token: this.token,
|
|
2796
3136
|
extraHeaders: effectiveHeaders
|
|
2797
3137
|
});
|
|
2798
3138
|
}
|
|
@@ -2844,6 +3184,7 @@ var init_client = __esm(() => {
|
|
|
2844
3184
|
sprites = createSpritesNamespace(this);
|
|
2845
3185
|
realtime = createRealtimeNamespace(this);
|
|
2846
3186
|
achievements = createAchievementsNamespace(this);
|
|
3187
|
+
notifications = createNotificationsNamespace(this);
|
|
2847
3188
|
static init = init;
|
|
2848
3189
|
static login = login2;
|
|
2849
3190
|
static identity = identity;
|