@playcademy/sdk 0.9.0 → 0.9.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/index.d.ts +408 -367
- package/dist/index.js +53 -3
- package/dist/internal.d.ts +5567 -5328
- package/dist/internal.js +89 -18
- package/dist/server/edge.d.ts +8 -0
- package/dist/server.d.ts +8 -0
- package/dist/types.d.ts +1228 -1186
- package/package.json +1 -1
package/dist/internal.js
CHANGED
|
@@ -1953,17 +1953,21 @@ function createTimebackActivityTracker(client) {
|
|
|
1953
1953
|
}
|
|
1954
1954
|
}
|
|
1955
1955
|
return {
|
|
1956
|
+
currentRunId() {
|
|
1957
|
+
return currentActivity?.runId;
|
|
1958
|
+
},
|
|
1956
1959
|
startActivity(metadata, options) {
|
|
1957
1960
|
if (options?.runId !== undefined && !isValidUUID(options.runId)) {
|
|
1958
1961
|
throw new Error(`startActivity: \`runId\` must be a UUID (received \`${JSON.stringify(options.runId)}\`). Use crypto.randomUUID() or persist a previously-generated UUID.`);
|
|
1959
1962
|
}
|
|
1960
1963
|
cleanupListeners();
|
|
1961
1964
|
const now = Date.now();
|
|
1965
|
+
const runId = options?.runId ?? crypto.randomUUID();
|
|
1962
1966
|
const heartbeatIntervalMs = normalizeDelayMs(options?.heartbeatIntervalMs, DEFAULT_HEARTBEAT_INTERVAL_MS, false);
|
|
1963
1967
|
const pausedHeartbeatTimeoutMs = normalizeDelayMs(options?.pausedHeartbeatTimeoutMs ?? options?.hiddenTimeoutMs, DEFAULT_PAUSED_HEARTBEAT_TIMEOUT_MS, false);
|
|
1964
1968
|
const inactivityTimeoutMs = normalizeDelayMs(options?.inactivityTimeoutMs, DEFAULT_INACTIVITY_TIMEOUT_MS, false);
|
|
1965
1969
|
currentActivity = {
|
|
1966
|
-
runId
|
|
1970
|
+
runId,
|
|
1967
1971
|
resumeId: crypto.randomUUID(),
|
|
1968
1972
|
startTime: now,
|
|
1969
1973
|
metadata,
|
|
@@ -2006,6 +2010,7 @@ function createTimebackActivityTracker(client) {
|
|
|
2006
2010
|
messaging.listen("PLAYCADEMY_PAUSE" /* PAUSE */, boundShellPauseHandler);
|
|
2007
2011
|
messaging.listen("PLAYCADEMY_RESUME" /* RESUME */, boundShellResumeHandler);
|
|
2008
2012
|
syncInactivityTracking();
|
|
2013
|
+
return { runId };
|
|
2009
2014
|
},
|
|
2010
2015
|
pauseActivity() {
|
|
2011
2016
|
if (!currentActivity) {
|
|
@@ -2095,6 +2100,15 @@ function createTimebackUserStore(client) {
|
|
|
2095
2100
|
enrollments: response.enrollments,
|
|
2096
2101
|
organizations: response.organizations
|
|
2097
2102
|
};
|
|
2103
|
+
},
|
|
2104
|
+
setEnrollments(enrollments) {
|
|
2105
|
+
const base = override ?? client["initPayload"]?.timeback;
|
|
2106
|
+
override = base ? { ...base, enrollments } : {
|
|
2107
|
+
id: undefined,
|
|
2108
|
+
role: undefined,
|
|
2109
|
+
enrollments,
|
|
2110
|
+
organizations: []
|
|
2111
|
+
};
|
|
2098
2112
|
}
|
|
2099
2113
|
};
|
|
2100
2114
|
}
|
|
@@ -2110,20 +2124,50 @@ function createTimebackEngine(client) {
|
|
|
2110
2124
|
ttl: 5000,
|
|
2111
2125
|
keyPrefix: "game.timeback.xp"
|
|
2112
2126
|
});
|
|
2127
|
+
const enrollmentsCache = createTTLCache({
|
|
2128
|
+
ttl: 5 * 60 * 1000,
|
|
2129
|
+
keyPrefix: "game.timeback.enrollments"
|
|
2130
|
+
});
|
|
2113
2131
|
async function applyPromotion(promotion) {
|
|
2114
2132
|
if (promotion.status !== "promoted" && promotion.status !== "already-promoted") {
|
|
2115
2133
|
return;
|
|
2116
2134
|
}
|
|
2117
2135
|
userCache.clear("current");
|
|
2136
|
+
enrollmentsCache.clear("current");
|
|
2118
2137
|
try {
|
|
2119
2138
|
await userStore.refresh();
|
|
2120
2139
|
} catch {}
|
|
2121
2140
|
}
|
|
2122
2141
|
const activityTracker = createTimebackActivityTracker(client);
|
|
2142
|
+
async function refreshUserContext() {
|
|
2143
|
+
const context = await userStore.refresh();
|
|
2144
|
+
enrollmentsCache.clear("current");
|
|
2145
|
+
return context;
|
|
2146
|
+
}
|
|
2147
|
+
async function refreshEnrollmentSlice(options) {
|
|
2148
|
+
const enrollments = await enrollmentsCache.get("current", async () => {
|
|
2149
|
+
const response = await client["request"]("/timeback/user/enrollments", "GET");
|
|
2150
|
+
userStore.setEnrollments(response);
|
|
2151
|
+
userCache.clear("current");
|
|
2152
|
+
return response;
|
|
2153
|
+
}, options);
|
|
2154
|
+
userStore.setEnrollments(enrollments);
|
|
2155
|
+
return userStore.snapshot();
|
|
2156
|
+
}
|
|
2123
2157
|
return {
|
|
2124
2158
|
user: {
|
|
2125
2159
|
snapshot: () => userStore.snapshot(),
|
|
2126
|
-
fetch: (options) => userCache.get("current",
|
|
2160
|
+
fetch: (options) => userCache.get("current", refreshUserContext, options),
|
|
2161
|
+
refresh: (options) => {
|
|
2162
|
+
if (!options?.only.includes("enrollments")) {
|
|
2163
|
+
throw new Error("At least one TimeBack user refresh field must be selected");
|
|
2164
|
+
}
|
|
2165
|
+
return refreshEnrollmentSlice({
|
|
2166
|
+
force: options.force,
|
|
2167
|
+
skipCache: options.skipCache,
|
|
2168
|
+
ttl: options.ttl
|
|
2169
|
+
});
|
|
2170
|
+
},
|
|
2127
2171
|
xp: {
|
|
2128
2172
|
fetch: (options) => {
|
|
2129
2173
|
const cacheKey = [
|
|
@@ -2150,6 +2194,7 @@ function createTimebackEngine(client) {
|
|
|
2150
2194
|
}
|
|
2151
2195
|
},
|
|
2152
2196
|
activity: {
|
|
2197
|
+
currentRunId: activityTracker.currentRunId,
|
|
2153
2198
|
start: activityTracker.startActivity,
|
|
2154
2199
|
pause: activityTracker.pauseActivity,
|
|
2155
2200
|
resume: activityTracker.resumeActivity,
|
|
@@ -2184,6 +2229,7 @@ function createTimebackNamespace(client) {
|
|
|
2184
2229
|
return engine.user.snapshot()?.organizations ?? [];
|
|
2185
2230
|
},
|
|
2186
2231
|
fetch: (options) => engine.user.fetch(options),
|
|
2232
|
+
refresh: (options) => engine.user.refresh(options),
|
|
2187
2233
|
xp: {
|
|
2188
2234
|
fetch: async (options = {}) => {
|
|
2189
2235
|
const hasGrade = options.grade !== undefined;
|
|
@@ -2209,9 +2255,13 @@ function createTimebackNamespace(client) {
|
|
|
2209
2255
|
}
|
|
2210
2256
|
};
|
|
2211
2257
|
},
|
|
2258
|
+
get currentRunId() {
|
|
2259
|
+
assertPlatformMode(client, "timeback.currentRunId");
|
|
2260
|
+
return engine.activity.currentRunId();
|
|
2261
|
+
},
|
|
2212
2262
|
startActivity: (metadata, options) => {
|
|
2213
2263
|
assertPlatformMode(client, "timeback.startActivity()");
|
|
2214
|
-
engine.activity.start(metadata, options);
|
|
2264
|
+
return engine.activity.start(metadata, options);
|
|
2215
2265
|
},
|
|
2216
2266
|
pauseActivity: () => {
|
|
2217
2267
|
assertPlatformMode(client, "timeback.pauseActivity()");
|
|
@@ -2348,7 +2398,7 @@ class DeployPipeline {
|
|
|
2348
2398
|
return this.fetchGameWithRetry(slug);
|
|
2349
2399
|
}
|
|
2350
2400
|
async buildRequestBody(args) {
|
|
2351
|
-
const
|
|
2401
|
+
const game2 = await this.resolveGame(args.slug, args.game);
|
|
2352
2402
|
const requestBody = {};
|
|
2353
2403
|
if (args.uploadToken) {
|
|
2354
2404
|
requestBody.uploadToken = args.uploadToken;
|
|
@@ -2357,7 +2407,7 @@ class DeployPipeline {
|
|
|
2357
2407
|
requestBody.metadata = args.metadata;
|
|
2358
2408
|
}
|
|
2359
2409
|
if (!args.backend) {
|
|
2360
|
-
return { game, requestBody };
|
|
2410
|
+
return { game: game2, requestBody };
|
|
2361
2411
|
}
|
|
2362
2412
|
const backendFields = {
|
|
2363
2413
|
config: args.backend.config,
|
|
@@ -2372,7 +2422,7 @@ class DeployPipeline {
|
|
|
2372
2422
|
code: args.backend.code
|
|
2373
2423
|
};
|
|
2374
2424
|
if (this.serializedSize(inlineBody) <= DeployPipeline.MAX_INLINE_REQUEST_BYTES) {
|
|
2375
|
-
return { game, requestBody: inlineBody };
|
|
2425
|
+
return { game: game2, requestBody: inlineBody };
|
|
2376
2426
|
}
|
|
2377
2427
|
const skeletonBody = {
|
|
2378
2428
|
...requestBody,
|
|
@@ -2382,8 +2432,8 @@ class DeployPipeline {
|
|
|
2382
2432
|
if (this.serializedSize(skeletonBody) > DeployPipeline.MAX_INLINE_REQUEST_BYTES) {
|
|
2383
2433
|
throw new Error("Deploy request is too large even after uploading backend code");
|
|
2384
2434
|
}
|
|
2385
|
-
skeletonBody.codeUploadToken = await this.uploadCode(
|
|
2386
|
-
return { game, requestBody: skeletonBody };
|
|
2435
|
+
skeletonBody.codeUploadToken = await this.uploadCode(game2.id, args.backend.code);
|
|
2436
|
+
return { game: game2, requestBody: skeletonBody };
|
|
2387
2437
|
}
|
|
2388
2438
|
serializedSize(body) {
|
|
2389
2439
|
return DeployPipeline.textEncoder.encode(JSON.stringify(body)).length;
|
|
@@ -2471,8 +2521,8 @@ class DeployPipeline {
|
|
|
2471
2521
|
await new Promise((resolve) => setTimeout(resolve, DeployPipeline.POLL_INTERVAL_MS));
|
|
2472
2522
|
}
|
|
2473
2523
|
}
|
|
2474
|
-
async resolveGame(slug,
|
|
2475
|
-
return
|
|
2524
|
+
async resolveGame(slug, game2) {
|
|
2525
|
+
return game2 ?? await this.client["request"](`/games/${slug}`, "GET");
|
|
2476
2526
|
}
|
|
2477
2527
|
async fetchGameWithRetry(slug) {
|
|
2478
2528
|
const { GAME_FETCH_RETRIES } = DeployPipeline;
|
|
@@ -2505,21 +2555,21 @@ function createDevNamespace(client) {
|
|
|
2505
2555
|
deploy: async (slug, options) => {
|
|
2506
2556
|
const { metadata, file, backend, hooks } = options;
|
|
2507
2557
|
hooks?.onEvent?.({ type: "init" });
|
|
2508
|
-
let
|
|
2558
|
+
let game2;
|
|
2509
2559
|
if (metadata) {
|
|
2510
|
-
|
|
2560
|
+
game2 = await client["request"](`/games/${slug}`, "PUT", {
|
|
2511
2561
|
body: metadata
|
|
2512
2562
|
});
|
|
2513
2563
|
if (metadata.gameType === "external" && !file && !backend) {
|
|
2514
|
-
return
|
|
2564
|
+
return game2;
|
|
2515
2565
|
}
|
|
2516
2566
|
}
|
|
2517
|
-
const uploadToken = file ? await deploy.uploadFile(file,
|
|
2567
|
+
const uploadToken = file ? await deploy.uploadFile(file, game2?.id || slug, hooks) : undefined;
|
|
2518
2568
|
if (uploadToken || backend) {
|
|
2519
|
-
return deploy.submit({ slug, game, uploadToken, metadata, backend, hooks });
|
|
2569
|
+
return deploy.submit({ slug, game: game2, uploadToken, metadata, backend, hooks });
|
|
2520
2570
|
}
|
|
2521
|
-
if (
|
|
2522
|
-
return
|
|
2571
|
+
if (game2) {
|
|
2572
|
+
return game2;
|
|
2523
2573
|
}
|
|
2524
2574
|
throw new Error("No deployment actions specified (need metadata, file, or backend)");
|
|
2525
2575
|
},
|
|
@@ -2675,6 +2725,24 @@ function createGamesNamespace(client) {
|
|
|
2675
2725
|
}, options);
|
|
2676
2726
|
},
|
|
2677
2727
|
list: (options) => gamesListCache.get("all", () => client["request"]("/games", "GET"), options),
|
|
2728
|
+
patchMetadata: async (gameId, metadata) => {
|
|
2729
|
+
const updatedGame = await client["request"](`/games/${gameId}`, "PATCH", {
|
|
2730
|
+
body: metadata
|
|
2731
|
+
});
|
|
2732
|
+
gamesListCache.clear("all");
|
|
2733
|
+
gameFetchCache.clear(gameId);
|
|
2734
|
+
gameFetchCache.clear(updatedGame.slug);
|
|
2735
|
+
return updatedGame;
|
|
2736
|
+
},
|
|
2737
|
+
members: {
|
|
2738
|
+
list: (gameId) => client["request"](`/games/${gameId}/members`, "GET"),
|
|
2739
|
+
add: (gameId, body) => client["request"](`/games/${gameId}/members`, "POST", {
|
|
2740
|
+
body
|
|
2741
|
+
}),
|
|
2742
|
+
update: (gameId, userId, body) => client["request"](`/games/${gameId}/members/${encodeURIComponent(userId)}`, "PATCH", { body }),
|
|
2743
|
+
remove: (gameId, userId) => client["request"](`/games/${gameId}/members/${encodeURIComponent(userId)}`, "DELETE"),
|
|
2744
|
+
search: (gameId, query) => client["request"](`/games/${gameId}/members/search?q=${encodeURIComponent(query)}`, "GET")
|
|
2745
|
+
},
|
|
2678
2746
|
getSubjects: () => client["request"]("/games/subjects", "GET"),
|
|
2679
2747
|
startSession: async (gameId) => {
|
|
2680
2748
|
const idToUse = gameId ?? client["_ensureGameId"]();
|
|
@@ -3099,7 +3167,10 @@ function createTimebackNamespace2(client) {
|
|
|
3099
3167
|
};
|
|
3100
3168
|
},
|
|
3101
3169
|
populateStudent: async (names) => client["request"]("/timeback/populate-student", "POST", names ? { body: names } : undefined),
|
|
3102
|
-
|
|
3170
|
+
get currentRunId() {
|
|
3171
|
+
throw new Error(NOT_SUPPORTED);
|
|
3172
|
+
},
|
|
3173
|
+
startActivity: (_metadata, _options) => {
|
|
3103
3174
|
throw new Error(NOT_SUPPORTED);
|
|
3104
3175
|
},
|
|
3105
3176
|
pauseActivity: () => {
|
package/dist/server/edge.d.ts
CHANGED
|
@@ -553,6 +553,14 @@ interface BackendDeploymentBundle {
|
|
|
553
553
|
compatibilityFlags?: string[];
|
|
554
554
|
}
|
|
555
555
|
|
|
556
|
+
/**
|
|
557
|
+
* User Types
|
|
558
|
+
*
|
|
559
|
+
* Enums, DTOs and API response types. Database row types are in @playcademy/data/types.
|
|
560
|
+
*
|
|
561
|
+
* @module types/user
|
|
562
|
+
*/
|
|
563
|
+
|
|
556
564
|
/**
|
|
557
565
|
* OpenID Connect UserInfo claims (NOT a database row).
|
|
558
566
|
*/
|
package/dist/server.d.ts
CHANGED
|
@@ -553,6 +553,14 @@ interface BackendDeploymentBundle {
|
|
|
553
553
|
compatibilityFlags?: string[];
|
|
554
554
|
}
|
|
555
555
|
|
|
556
|
+
/**
|
|
557
|
+
* User Types
|
|
558
|
+
*
|
|
559
|
+
* Enums, DTOs and API response types. Database row types are in @playcademy/data/types.
|
|
560
|
+
*
|
|
561
|
+
* @module types/user
|
|
562
|
+
*/
|
|
563
|
+
|
|
556
564
|
/**
|
|
557
565
|
* OpenID Connect UserInfo claims (NOT a database row).
|
|
558
566
|
*/
|