@playcademy/sdk 0.9.0 → 0.9.1-beta.1
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 +43 -7
- package/dist/index.js +41 -1
- package/dist/internal.d.ts +220 -33
- package/dist/internal.js +73 -15
- package/dist/server/edge.d.ts +8 -0
- package/dist/server.d.ts +8 -0
- package/dist/types.d.ts +46 -9
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { UserRole, AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
1
2
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
2
|
-
import { AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Base error class for Cademy SDK specific errors.
|
|
@@ -498,6 +498,21 @@ interface AdvanceCourseResponse {
|
|
|
498
498
|
promotion: TimebackPromotionResult;
|
|
499
499
|
}
|
|
500
500
|
|
|
501
|
+
/**
|
|
502
|
+
* Cache configuration types for runtime customization
|
|
503
|
+
*/
|
|
504
|
+
/**
|
|
505
|
+
* Runtime configuration for TTL cache behavior
|
|
506
|
+
*/
|
|
507
|
+
interface TTLCacheConfig {
|
|
508
|
+
/** Time-to-live in milliseconds. Set to 0 to disable caching for this call. */
|
|
509
|
+
ttl?: number;
|
|
510
|
+
/** Force refresh, bypassing cache */
|
|
511
|
+
force?: boolean;
|
|
512
|
+
/** Skip cache and fetch fresh data (alias for force) */
|
|
513
|
+
skipCache?: boolean;
|
|
514
|
+
}
|
|
515
|
+
|
|
501
516
|
/**
|
|
502
517
|
* User Types
|
|
503
518
|
*
|
|
@@ -505,13 +520,18 @@ interface AdvanceCourseResponse {
|
|
|
505
520
|
*
|
|
506
521
|
* @module types/user
|
|
507
522
|
*/
|
|
508
|
-
|
|
523
|
+
|
|
524
|
+
type UserRoleEnumType = UserRole;
|
|
509
525
|
type DeveloperStatusEnumType = 'none' | 'pending' | 'approved';
|
|
510
526
|
type TimebackUserRole = 'administrator' | 'aide' | 'guardian' | 'parent' | 'proctor' | 'relative' | 'student' | 'teacher';
|
|
511
527
|
type TimebackOrgType = 'department' | 'school' | 'district' | 'local' | 'state' | 'national';
|
|
512
528
|
interface UserEnrollment {
|
|
513
529
|
gameId?: string;
|
|
514
530
|
courseId: string;
|
|
531
|
+
enrollmentIds?: {
|
|
532
|
+
active: string;
|
|
533
|
+
inactive?: string[];
|
|
534
|
+
};
|
|
515
535
|
grade: number;
|
|
516
536
|
subject: string;
|
|
517
537
|
orgId?: string;
|
|
@@ -1819,6 +1839,7 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
1819
1839
|
* User context (cached from init, refreshable):
|
|
1820
1840
|
* - `user.role` - User's role (student, parent, teacher, etc.)
|
|
1821
1841
|
* - `user.enrollments` - Courses the player is enrolled in for this game
|
|
1842
|
+
* - `user.refresh({ only: ['enrollments'] })` - Refresh enrollments from server
|
|
1822
1843
|
* - `user.organizations` - Schools/districts the player belongs to
|
|
1823
1844
|
* - `user.fetch()` - Refresh user context from server
|
|
1824
1845
|
*
|
|
@@ -1920,7 +1941,9 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
1920
1941
|
|
|
1921
1942
|
/**
|
|
1922
1943
|
* A TimeBack enrollment for the current game session.
|
|
1923
|
-
* Alias for UserEnrollment without the optional gameId.
|
|
1944
|
+
* Alias for UserEnrollment without the optional gameId. Active enrollment IDs
|
|
1945
|
+
* are available at `enrollment.enrollmentIds?.active` when supplied by the
|
|
1946
|
+
* platform.
|
|
1924
1947
|
*/
|
|
1925
1948
|
type TimebackEnrollment = Omit<UserEnrollment, 'gameId'>;
|
|
1926
1949
|
/**
|
|
@@ -1956,6 +1979,14 @@ interface TimebackUserContext {
|
|
|
1956
1979
|
/** User's organizations (schools/districts) */
|
|
1957
1980
|
organizations: TimebackOrganization[];
|
|
1958
1981
|
}
|
|
1982
|
+
/**
|
|
1983
|
+
* Slice options for refreshing the cached TimeBack user context.
|
|
1984
|
+
*/
|
|
1985
|
+
type TimebackUserRefreshField = 'enrollments';
|
|
1986
|
+
interface TimebackUserRefreshOptions extends TTLCacheConfig {
|
|
1987
|
+
/** Refresh only these user data fields */
|
|
1988
|
+
only: readonly TimebackUserRefreshField[];
|
|
1989
|
+
}
|
|
1959
1990
|
/**
|
|
1960
1991
|
* XP data access for the current user.
|
|
1961
1992
|
* Results are cached for 5 seconds to avoid redundant network requests.
|
|
@@ -1996,7 +2027,7 @@ interface TimebackUserXp {
|
|
|
1996
2027
|
fetch(options?: GetXpOptions): Promise<XpResponse>;
|
|
1997
2028
|
}
|
|
1998
2029
|
/**
|
|
1999
|
-
* TimeBack user object with
|
|
2030
|
+
* TimeBack user object with cached getters, fetch, and targeted refresh methods.
|
|
2000
2031
|
*/
|
|
2001
2032
|
interface TimebackUser extends TimebackUserContext {
|
|
2002
2033
|
/**
|
|
@@ -2005,9 +2036,14 @@ interface TimebackUser extends TimebackUserContext {
|
|
|
2005
2036
|
* @param options - Cache options (pass { force: true } to bypass cache)
|
|
2006
2037
|
* @returns Promise resolving to fresh user context
|
|
2007
2038
|
*/
|
|
2008
|
-
fetch(options?:
|
|
2009
|
-
|
|
2010
|
-
|
|
2039
|
+
fetch(options?: TTLCacheConfig): Promise<TimebackUserContext>;
|
|
2040
|
+
/**
|
|
2041
|
+
* Refresh selected TimeBack user data from the server.
|
|
2042
|
+
* Updates the cached user snapshot used by the synchronous getters.
|
|
2043
|
+
* @param options - Refresh fields and cache options
|
|
2044
|
+
* @returns Promise resolving to the updated user context
|
|
2045
|
+
*/
|
|
2046
|
+
refresh(options: TimebackUserRefreshOptions): Promise<TimebackUserContext>;
|
|
2011
2047
|
/**
|
|
2012
2048
|
* XP data for the current user.
|
|
2013
2049
|
* Call `xp.fetch()` to get XP from the server.
|
package/dist/index.js
CHANGED
|
@@ -2095,6 +2095,15 @@ function createTimebackUserStore(client) {
|
|
|
2095
2095
|
enrollments: response.enrollments,
|
|
2096
2096
|
organizations: response.organizations
|
|
2097
2097
|
};
|
|
2098
|
+
},
|
|
2099
|
+
setEnrollments(enrollments) {
|
|
2100
|
+
const base = override ?? client["initPayload"]?.timeback;
|
|
2101
|
+
override = base ? { ...base, enrollments } : {
|
|
2102
|
+
id: undefined,
|
|
2103
|
+
role: undefined,
|
|
2104
|
+
enrollments,
|
|
2105
|
+
organizations: []
|
|
2106
|
+
};
|
|
2098
2107
|
}
|
|
2099
2108
|
};
|
|
2100
2109
|
}
|
|
@@ -2110,20 +2119,50 @@ function createTimebackEngine(client) {
|
|
|
2110
2119
|
ttl: 5000,
|
|
2111
2120
|
keyPrefix: "game.timeback.xp"
|
|
2112
2121
|
});
|
|
2122
|
+
const enrollmentsCache = createTTLCache({
|
|
2123
|
+
ttl: 5 * 60 * 1000,
|
|
2124
|
+
keyPrefix: "game.timeback.enrollments"
|
|
2125
|
+
});
|
|
2113
2126
|
async function applyPromotion(promotion) {
|
|
2114
2127
|
if (promotion.status !== "promoted" && promotion.status !== "already-promoted") {
|
|
2115
2128
|
return;
|
|
2116
2129
|
}
|
|
2117
2130
|
userCache.clear("current");
|
|
2131
|
+
enrollmentsCache.clear("current");
|
|
2118
2132
|
try {
|
|
2119
2133
|
await userStore.refresh();
|
|
2120
2134
|
} catch {}
|
|
2121
2135
|
}
|
|
2122
2136
|
const activityTracker = createTimebackActivityTracker(client);
|
|
2137
|
+
async function refreshUserContext() {
|
|
2138
|
+
const context = await userStore.refresh();
|
|
2139
|
+
enrollmentsCache.clear("current");
|
|
2140
|
+
return context;
|
|
2141
|
+
}
|
|
2142
|
+
async function refreshEnrollmentSlice(options) {
|
|
2143
|
+
const enrollments = await enrollmentsCache.get("current", async () => {
|
|
2144
|
+
const response = await client["request"]("/timeback/user/enrollments", "GET");
|
|
2145
|
+
userStore.setEnrollments(response);
|
|
2146
|
+
userCache.clear("current");
|
|
2147
|
+
return response;
|
|
2148
|
+
}, options);
|
|
2149
|
+
userStore.setEnrollments(enrollments);
|
|
2150
|
+
return userStore.snapshot();
|
|
2151
|
+
}
|
|
2123
2152
|
return {
|
|
2124
2153
|
user: {
|
|
2125
2154
|
snapshot: () => userStore.snapshot(),
|
|
2126
|
-
fetch: (options) => userCache.get("current",
|
|
2155
|
+
fetch: (options) => userCache.get("current", refreshUserContext, options),
|
|
2156
|
+
refresh: (options) => {
|
|
2157
|
+
if (!options?.only.includes("enrollments")) {
|
|
2158
|
+
throw new Error("At least one TimeBack user refresh field must be selected");
|
|
2159
|
+
}
|
|
2160
|
+
return refreshEnrollmentSlice({
|
|
2161
|
+
force: options.force,
|
|
2162
|
+
skipCache: options.skipCache,
|
|
2163
|
+
ttl: options.ttl
|
|
2164
|
+
});
|
|
2165
|
+
},
|
|
2127
2166
|
xp: {
|
|
2128
2167
|
fetch: (options) => {
|
|
2129
2168
|
const cacheKey = [
|
|
@@ -2184,6 +2223,7 @@ function createTimebackNamespace(client) {
|
|
|
2184
2223
|
return engine.user.snapshot()?.organizations ?? [];
|
|
2185
2224
|
},
|
|
2186
2225
|
fetch: (options) => engine.user.fetch(options),
|
|
2226
|
+
refresh: (options) => engine.user.refresh(options),
|
|
2187
2227
|
xp: {
|
|
2188
2228
|
fetch: async (options = {}) => {
|
|
2189
2229
|
const hasGrade = options.grade !== undefined;
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { SchemaInfo } from '@playcademy/cloudflare';
|
|
2
|
+
import { UserRole, AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
2
3
|
import { InferSelectModel } from 'drizzle-orm';
|
|
3
4
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
4
5
|
import * as drizzle_zod from 'drizzle-zod';
|
|
5
6
|
import { z } from 'zod';
|
|
6
|
-
import { AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
7
7
|
|
|
8
8
|
/** Permitted HTTP verbs */
|
|
9
9
|
type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
@@ -918,7 +918,8 @@ interface NotificationStats {
|
|
|
918
918
|
*
|
|
919
919
|
* @module types/user
|
|
920
920
|
*/
|
|
921
|
-
|
|
921
|
+
|
|
922
|
+
type UserRoleEnumType = UserRole;
|
|
922
923
|
type DeveloperStatusEnumType = 'none' | 'pending' | 'approved';
|
|
923
924
|
type DeveloperStatusValue = DeveloperStatusEnumType;
|
|
924
925
|
type TimebackUserRole = 'administrator' | 'aide' | 'guardian' | 'parent' | 'proctor' | 'relative' | 'student' | 'teacher';
|
|
@@ -926,6 +927,10 @@ type TimebackOrgType = 'department' | 'school' | 'district' | 'local' | 'state'
|
|
|
926
927
|
interface UserEnrollment {
|
|
927
928
|
gameId?: string;
|
|
928
929
|
courseId: string;
|
|
930
|
+
enrollmentIds?: {
|
|
931
|
+
active: string;
|
|
932
|
+
inactive?: string[];
|
|
933
|
+
};
|
|
929
934
|
grade: number;
|
|
930
935
|
subject: string;
|
|
931
936
|
orgId?: string;
|
|
@@ -998,6 +1003,7 @@ interface GameUser {
|
|
|
998
1003
|
*
|
|
999
1004
|
* @module types/game
|
|
1000
1005
|
*/
|
|
1006
|
+
|
|
1001
1007
|
type GameType = 'hosted' | 'external';
|
|
1002
1008
|
type GamePlatform = 'web' | 'godot' | 'unity' | (string & {});
|
|
1003
1009
|
/**
|
|
@@ -1846,6 +1852,98 @@ declare const games: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
1846
1852
|
};
|
|
1847
1853
|
dialect: 'pg';
|
|
1848
1854
|
}>;
|
|
1855
|
+
declare const gameMembers: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
1856
|
+
name: "game_members";
|
|
1857
|
+
schema: undefined;
|
|
1858
|
+
columns: {
|
|
1859
|
+
id: drizzle_orm_pg_core.PgColumn<{
|
|
1860
|
+
name: "id";
|
|
1861
|
+
tableName: "game_members";
|
|
1862
|
+
dataType: "string";
|
|
1863
|
+
columnType: "PgUUID";
|
|
1864
|
+
data: string;
|
|
1865
|
+
driverParam: string;
|
|
1866
|
+
notNull: true;
|
|
1867
|
+
hasDefault: true;
|
|
1868
|
+
isPrimaryKey: true;
|
|
1869
|
+
isAutoincrement: false;
|
|
1870
|
+
hasRuntimeDefault: false;
|
|
1871
|
+
enumValues: undefined;
|
|
1872
|
+
baseColumn: never;
|
|
1873
|
+
identity: undefined;
|
|
1874
|
+
generated: undefined;
|
|
1875
|
+
}, {}, {}>;
|
|
1876
|
+
gameId: drizzle_orm_pg_core.PgColumn<{
|
|
1877
|
+
name: "game_id";
|
|
1878
|
+
tableName: "game_members";
|
|
1879
|
+
dataType: "string";
|
|
1880
|
+
columnType: "PgUUID";
|
|
1881
|
+
data: string;
|
|
1882
|
+
driverParam: string;
|
|
1883
|
+
notNull: true;
|
|
1884
|
+
hasDefault: false;
|
|
1885
|
+
isPrimaryKey: false;
|
|
1886
|
+
isAutoincrement: false;
|
|
1887
|
+
hasRuntimeDefault: false;
|
|
1888
|
+
enumValues: undefined;
|
|
1889
|
+
baseColumn: never;
|
|
1890
|
+
identity: undefined;
|
|
1891
|
+
generated: undefined;
|
|
1892
|
+
}, {}, {}>;
|
|
1893
|
+
userId: drizzle_orm_pg_core.PgColumn<{
|
|
1894
|
+
name: "user_id";
|
|
1895
|
+
tableName: "game_members";
|
|
1896
|
+
dataType: "string";
|
|
1897
|
+
columnType: "PgText";
|
|
1898
|
+
data: string;
|
|
1899
|
+
driverParam: string;
|
|
1900
|
+
notNull: true;
|
|
1901
|
+
hasDefault: false;
|
|
1902
|
+
isPrimaryKey: false;
|
|
1903
|
+
isAutoincrement: false;
|
|
1904
|
+
hasRuntimeDefault: false;
|
|
1905
|
+
enumValues: [string, ...string[]];
|
|
1906
|
+
baseColumn: never;
|
|
1907
|
+
identity: undefined;
|
|
1908
|
+
generated: undefined;
|
|
1909
|
+
}, {}, {}>;
|
|
1910
|
+
role: drizzle_orm_pg_core.PgColumn<{
|
|
1911
|
+
name: "role";
|
|
1912
|
+
tableName: "game_members";
|
|
1913
|
+
dataType: "string";
|
|
1914
|
+
columnType: "PgEnumColumn";
|
|
1915
|
+
data: "collaborator" | "owner";
|
|
1916
|
+
driverParam: string;
|
|
1917
|
+
notNull: true;
|
|
1918
|
+
hasDefault: true;
|
|
1919
|
+
isPrimaryKey: false;
|
|
1920
|
+
isAutoincrement: false;
|
|
1921
|
+
hasRuntimeDefault: false;
|
|
1922
|
+
enumValues: ["owner", "collaborator"];
|
|
1923
|
+
baseColumn: never;
|
|
1924
|
+
identity: undefined;
|
|
1925
|
+
generated: undefined;
|
|
1926
|
+
}, {}, {}>;
|
|
1927
|
+
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
1928
|
+
name: "created_at";
|
|
1929
|
+
tableName: "game_members";
|
|
1930
|
+
dataType: "date";
|
|
1931
|
+
columnType: "PgTimestamp";
|
|
1932
|
+
data: Date;
|
|
1933
|
+
driverParam: string;
|
|
1934
|
+
notNull: true;
|
|
1935
|
+
hasDefault: true;
|
|
1936
|
+
isPrimaryKey: false;
|
|
1937
|
+
isAutoincrement: false;
|
|
1938
|
+
hasRuntimeDefault: false;
|
|
1939
|
+
enumValues: undefined;
|
|
1940
|
+
baseColumn: never;
|
|
1941
|
+
identity: undefined;
|
|
1942
|
+
generated: undefined;
|
|
1943
|
+
}, {}, {}>;
|
|
1944
|
+
};
|
|
1945
|
+
dialect: 'pg';
|
|
1946
|
+
}>;
|
|
1849
1947
|
declare const gameSessions: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
1850
1948
|
name: "game_sessions";
|
|
1851
1949
|
schema: undefined;
|
|
@@ -4177,7 +4275,7 @@ declare const UpsertGameMetadataSchema: z.ZodEffects<z.ZodObject<{
|
|
|
4177
4275
|
displayName: z.ZodString;
|
|
4178
4276
|
mapElementId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
4179
4277
|
platform: z.ZodEnum<["web", "godot", "unity"]>;
|
|
4180
|
-
metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown
|
|
4278
|
+
metadata: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodUnknown>, Record<string, unknown>, Record<string, unknown>>>>;
|
|
4181
4279
|
gameType: z.ZodDefault<z.ZodOptional<z.ZodEnum<["hosted", "external"]>>>;
|
|
4182
4280
|
visibility: z.ZodOptional<z.ZodEnum<["visible", "unlisted", "internal"]>>;
|
|
4183
4281
|
externalUrl: z.ZodOptional<z.ZodString>;
|
|
@@ -4214,6 +4312,54 @@ declare const UpsertGameMetadataSchema: z.ZodEffects<z.ZodObject<{
|
|
|
4214
4312
|
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
4215
4313
|
externalUrl?: string | undefined;
|
|
4216
4314
|
}>;
|
|
4315
|
+
declare const PatchGameMetadataSchema: z.ZodObject<{
|
|
4316
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
4317
|
+
visibility: z.ZodOptional<z.ZodEnum<["visible", "unlisted", "internal"]>>;
|
|
4318
|
+
platform: z.ZodOptional<z.ZodEnum<["web", "godot", "unity"]>>;
|
|
4319
|
+
metadata: z.ZodOptional<z.ZodObject<{
|
|
4320
|
+
description: z.ZodOptional<z.ZodString>;
|
|
4321
|
+
emoji: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
4322
|
+
}, "strip", z.ZodTypeAny, {
|
|
4323
|
+
description?: string | undefined;
|
|
4324
|
+
emoji?: string | undefined;
|
|
4325
|
+
}, {
|
|
4326
|
+
description?: string | undefined;
|
|
4327
|
+
emoji?: string | undefined;
|
|
4328
|
+
}>>;
|
|
4329
|
+
}, "strip", z.ZodTypeAny, {
|
|
4330
|
+
displayName?: string | undefined;
|
|
4331
|
+
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
4332
|
+
platform?: "godot" | "unity" | "web" | undefined;
|
|
4333
|
+
metadata?: {
|
|
4334
|
+
description?: string | undefined;
|
|
4335
|
+
emoji?: string | undefined;
|
|
4336
|
+
} | undefined;
|
|
4337
|
+
}, {
|
|
4338
|
+
displayName?: string | undefined;
|
|
4339
|
+
visibility?: "internal" | "unlisted" | "visible" | undefined;
|
|
4340
|
+
platform?: "godot" | "unity" | "web" | undefined;
|
|
4341
|
+
metadata?: {
|
|
4342
|
+
description?: string | undefined;
|
|
4343
|
+
emoji?: string | undefined;
|
|
4344
|
+
} | undefined;
|
|
4345
|
+
}>;
|
|
4346
|
+
declare const AddGameMemberSchema: z.ZodObject<{
|
|
4347
|
+
userId: z.ZodString;
|
|
4348
|
+
role: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"collaborator">>>;
|
|
4349
|
+
}, "strict", z.ZodTypeAny, {
|
|
4350
|
+
userId: string;
|
|
4351
|
+
role: "collaborator";
|
|
4352
|
+
}, {
|
|
4353
|
+
userId: string;
|
|
4354
|
+
role?: "collaborator" | undefined;
|
|
4355
|
+
}>;
|
|
4356
|
+
declare const UpdateGameMemberRoleSchema: z.ZodObject<{
|
|
4357
|
+
role: z.ZodEnum<["owner", "collaborator"]>;
|
|
4358
|
+
}, "strict", z.ZodTypeAny, {
|
|
4359
|
+
role: "collaborator" | "owner";
|
|
4360
|
+
}, {
|
|
4361
|
+
role: "collaborator" | "owner";
|
|
4362
|
+
}>;
|
|
4217
4363
|
|
|
4218
4364
|
declare const InsertItemSchema: drizzle_zod.BuildSchema<"insert", {
|
|
4219
4365
|
id: drizzle_orm_pg_core.PgColumn<{
|
|
@@ -4792,9 +4938,27 @@ type ExternalGame = BaseGame & {
|
|
|
4792
4938
|
};
|
|
4793
4939
|
type Game = HostedGame | ExternalGame;
|
|
4794
4940
|
type GameSessionRow = typeof gameSessions.$inferSelect;
|
|
4941
|
+
type GameMemberRow = typeof gameMembers.$inferSelect;
|
|
4942
|
+
type GameMemberWithUser = GameMemberRow & {
|
|
4943
|
+
user: {
|
|
4944
|
+
id: string;
|
|
4945
|
+
name: string;
|
|
4946
|
+
email: string;
|
|
4947
|
+
image: string | null;
|
|
4948
|
+
};
|
|
4949
|
+
};
|
|
4950
|
+
interface GameMemberSearchResult {
|
|
4951
|
+
id: string;
|
|
4952
|
+
name: string;
|
|
4953
|
+
email: string;
|
|
4954
|
+
image: string | null;
|
|
4955
|
+
}
|
|
4795
4956
|
type GameCustomHostnameRow = typeof gameCustomHostnames.$inferSelect;
|
|
4796
4957
|
|
|
4797
4958
|
type UpsertGameMetadataInput = z.infer<typeof UpsertGameMetadataSchema>;
|
|
4959
|
+
type PatchGameMetadataInput = z.infer<typeof PatchGameMetadataSchema>;
|
|
4960
|
+
type AddGameMemberInput = z.infer<typeof AddGameMemberSchema>;
|
|
4961
|
+
type UpdateGameMemberRoleInput = z.infer<typeof UpdateGameMemberRoleSchema>;
|
|
4798
4962
|
|
|
4799
4963
|
type ItemRow = typeof items.$inferSelect;
|
|
4800
4964
|
type InventoryItemRow = typeof inventoryItems.$inferSelect;
|
|
@@ -6271,6 +6435,30 @@ declare function init<T extends PlaycademyBaseClient = PlaycademyBaseClient>(thi
|
|
|
6271
6435
|
*/
|
|
6272
6436
|
declare function login(baseUrl: string, email: string, password: string): Promise<LoginResponse>;
|
|
6273
6437
|
|
|
6438
|
+
/**
|
|
6439
|
+
* Cache configuration types for runtime customization
|
|
6440
|
+
*/
|
|
6441
|
+
/**
|
|
6442
|
+
* Runtime configuration for TTL cache behavior
|
|
6443
|
+
*/
|
|
6444
|
+
interface TTLCacheConfig {
|
|
6445
|
+
/** Time-to-live in milliseconds. Set to 0 to disable caching for this call. */
|
|
6446
|
+
ttl?: number;
|
|
6447
|
+
/** Force refresh, bypassing cache */
|
|
6448
|
+
force?: boolean;
|
|
6449
|
+
/** Skip cache and fetch fresh data (alias for force) */
|
|
6450
|
+
skipCache?: boolean;
|
|
6451
|
+
}
|
|
6452
|
+
/**
|
|
6453
|
+
* Runtime configuration for cooldown cache behavior
|
|
6454
|
+
*/
|
|
6455
|
+
interface CooldownCacheConfig {
|
|
6456
|
+
/** Cooldown period in milliseconds. Set to 0 to disable cooldown for this call. */
|
|
6457
|
+
cooldown?: number;
|
|
6458
|
+
/** Force refresh, bypassing cooldown */
|
|
6459
|
+
force?: boolean;
|
|
6460
|
+
}
|
|
6461
|
+
|
|
6274
6462
|
/**
|
|
6275
6463
|
* Type definitions for the game timeback namespace.
|
|
6276
6464
|
*
|
|
@@ -6280,7 +6468,9 @@ declare function login(baseUrl: string, email: string, password: string): Promis
|
|
|
6280
6468
|
|
|
6281
6469
|
/**
|
|
6282
6470
|
* A TimeBack enrollment for the current game session.
|
|
6283
|
-
* Alias for UserEnrollment without the optional gameId.
|
|
6471
|
+
* Alias for UserEnrollment without the optional gameId. Active enrollment IDs
|
|
6472
|
+
* are available at `enrollment.enrollmentIds?.active` when supplied by the
|
|
6473
|
+
* platform.
|
|
6284
6474
|
*/
|
|
6285
6475
|
type TimebackEnrollment = Omit<UserEnrollment, 'gameId'>;
|
|
6286
6476
|
/**
|
|
@@ -6316,6 +6506,14 @@ interface TimebackUserContext {
|
|
|
6316
6506
|
/** User's organizations (schools/districts) */
|
|
6317
6507
|
organizations: TimebackOrganization[];
|
|
6318
6508
|
}
|
|
6509
|
+
/**
|
|
6510
|
+
* Slice options for refreshing the cached TimeBack user context.
|
|
6511
|
+
*/
|
|
6512
|
+
type TimebackUserRefreshField = 'enrollments';
|
|
6513
|
+
interface TimebackUserRefreshOptions extends TTLCacheConfig {
|
|
6514
|
+
/** Refresh only these user data fields */
|
|
6515
|
+
only: readonly TimebackUserRefreshField[];
|
|
6516
|
+
}
|
|
6319
6517
|
/**
|
|
6320
6518
|
* XP data access for the current user.
|
|
6321
6519
|
* Results are cached for 5 seconds to avoid redundant network requests.
|
|
@@ -6356,7 +6554,7 @@ interface TimebackUserXp {
|
|
|
6356
6554
|
fetch(options?: GetXpOptions): Promise<XpResponse>;
|
|
6357
6555
|
}
|
|
6358
6556
|
/**
|
|
6359
|
-
* TimeBack user object with
|
|
6557
|
+
* TimeBack user object with cached getters, fetch, and targeted refresh methods.
|
|
6360
6558
|
*/
|
|
6361
6559
|
interface TimebackUser extends TimebackUserContext {
|
|
6362
6560
|
/**
|
|
@@ -6365,9 +6563,14 @@ interface TimebackUser extends TimebackUserContext {
|
|
|
6365
6563
|
* @param options - Cache options (pass { force: true } to bypass cache)
|
|
6366
6564
|
* @returns Promise resolving to fresh user context
|
|
6367
6565
|
*/
|
|
6368
|
-
fetch(options?:
|
|
6369
|
-
|
|
6370
|
-
|
|
6566
|
+
fetch(options?: TTLCacheConfig): Promise<TimebackUserContext>;
|
|
6567
|
+
/**
|
|
6568
|
+
* Refresh selected TimeBack user data from the server.
|
|
6569
|
+
* Updates the cached user snapshot used by the synchronous getters.
|
|
6570
|
+
* @param options - Refresh fields and cache options
|
|
6571
|
+
* @returns Promise resolving to the updated user context
|
|
6572
|
+
*/
|
|
6573
|
+
refresh(options: TimebackUserRefreshOptions): Promise<TimebackUserContext>;
|
|
6371
6574
|
/**
|
|
6372
6575
|
* XP data for the current user.
|
|
6373
6576
|
* Call `xp.fetch()` to get XP from the server.
|
|
@@ -7179,30 +7382,6 @@ declare function parseOAuthState(state: string): {
|
|
|
7179
7382
|
data?: Record<string, string>;
|
|
7180
7383
|
};
|
|
7181
7384
|
|
|
7182
|
-
/**
|
|
7183
|
-
* Cache configuration types for runtime customization
|
|
7184
|
-
*/
|
|
7185
|
-
/**
|
|
7186
|
-
* Runtime configuration for TTL cache behavior
|
|
7187
|
-
*/
|
|
7188
|
-
interface TTLCacheConfig {
|
|
7189
|
-
/** Time-to-live in milliseconds. Set to 0 to disable caching for this call. */
|
|
7190
|
-
ttl?: number;
|
|
7191
|
-
/** Force refresh, bypassing cache */
|
|
7192
|
-
force?: boolean;
|
|
7193
|
-
/** Skip cache and fetch fresh data (alias for force) */
|
|
7194
|
-
skipCache?: boolean;
|
|
7195
|
-
}
|
|
7196
|
-
/**
|
|
7197
|
-
* Runtime configuration for cooldown cache behavior
|
|
7198
|
-
*/
|
|
7199
|
-
interface CooldownCacheConfig {
|
|
7200
|
-
/** Cooldown period in milliseconds. Set to 0 to disable cooldown for this call. */
|
|
7201
|
-
cooldown?: number;
|
|
7202
|
-
/** Force refresh, bypassing cooldown */
|
|
7203
|
-
force?: boolean;
|
|
7204
|
-
}
|
|
7205
|
-
|
|
7206
7385
|
/**
|
|
7207
7386
|
* Internal Playcademy SDK client with all namespaces.
|
|
7208
7387
|
* For use by Cademy platform, CLI, and admin tools.
|
|
@@ -7572,6 +7751,14 @@ declare class PlaycademyInternalClient extends PlaycademyBaseClient {
|
|
|
7572
7751
|
games: {
|
|
7573
7752
|
fetch: (gameIdOrSlug: string, options?: TTLCacheConfig) => Promise<FetchedGame>;
|
|
7574
7753
|
list: (options?: TTLCacheConfig) => Promise<Game[]>;
|
|
7754
|
+
patchMetadata: (gameId: string, metadata: PatchGameMetadataInput) => Promise<Game>;
|
|
7755
|
+
members: {
|
|
7756
|
+
list: (gameId: string) => Promise<GameMemberWithUser[]>;
|
|
7757
|
+
add: (gameId: string, body: AddGameMemberInput) => Promise<GameMemberWithUser>;
|
|
7758
|
+
update: (gameId: string, userId: string, body: UpdateGameMemberRoleInput) => Promise<GameMemberWithUser>;
|
|
7759
|
+
remove: (gameId: string, userId: string) => Promise<void>;
|
|
7760
|
+
search: (gameId: string, query: string) => Promise<GameMemberSearchResult[]>;
|
|
7761
|
+
};
|
|
7575
7762
|
getSubjects: () => Promise<Record<string, string | null>>;
|
|
7576
7763
|
startSession: (gameId?: string) => Promise<StartSessionResponse>;
|
|
7577
7764
|
endSession: (sessionId: string, gameId?: string) => Promise<void>;
|
|
@@ -7855,4 +8042,4 @@ declare class PlaycademyInternalClient extends PlaycademyBaseClient {
|
|
|
7855
8042
|
}
|
|
7856
8043
|
|
|
7857
8044
|
export { AchievementCompletionType, ApiError, ConnectionManager, ConnectionMonitor, MessageEvents, NotificationStatus, NotificationType, PlaycademyInternalClient as PlaycademyClient, PlaycademyError, PlaycademyInternalClient, extractApiErrorInfo, messaging };
|
|
7858
|
-
export type { AchievementCurrent, AchievementHistoryEntry, AchievementProgressResponse, AchievementScopeType, AchievementWithStatus, ApiErrorCode, ApiErrorInfo, AssessmentBankStatus, AssessmentRow, AssessmentSummary, AuthCallbackPayload, AuthOptions, AuthProviderType, AuthResult, AuthServerMessage, AuthStateChangePayload, AuthStateUpdate, AuthenticatedUser, BetterAuthApiKey, BetterAuthApiKeyResponse, BetterAuthSignInResponse, BucketFile, CharacterComponentRow as CharacterComponent, CharacterComponentType, CharacterComponentWithSpriteUrl, CharacterComponentsOptions, ClientConfig, ClientEvents, ConnectionMonitorConfig, ConnectionState, ConnectionStatePayload, CourseXp, CreateCharacterData, CreateMapObjectData, CurrencyRow as Currency, DemoEndOptions, DemoEndPayload, DevUploadEvent, DevUploadHooks, DeveloperStatusEnumType, DeveloperStatusResponse, DeveloperStatusValue, DisconnectContext, DisconnectHandler, DisplayAlertPayload, ErrorResponseBody, EventListeners, ExternalGame, FetchedGame, Game, GameActivityMetrics, GameContextPayload, GameCourseMetrics, GameCustomHostname, GameInitUser, GameLeaderboardEntry, GameManifest, MapRow as GameMap, GameMetricsProxyResponse, GameMetricsResponse, GameMetricsUnsupportedReason, GamePlatform, GameRow as GameRecord, GameSessionRow as GameSession, GameTimebackIntegration, GameTokenResponse, GameType, GameUser, GetXpOptions, HostedGame, InitErrorPayload, InitPayload, InsertCurrencyInput, InsertItemInput, InsertShopListingInput, InteractionType, InventoryItemRow as InventoryItem, InventoryItemWithItem, InventoryMutationResponse, ItemRow as Item, ItemType, KVKeyEntry, KVKeyMetadata, KVSeedEntry, KVStatsResponse, KeyEventPayload, LeaderboardEntry, LeaderboardOptions, LeaderboardTimeframe, LevelConfigRow as LevelConfig, LevelProgressResponse, LevelUpCheckResult, LoginResponse, ManifestV1, ManifestV2, ManifestVersions, MapData, MapElementRow as MapElement, MapElementMetadata, MapElementWithGame, MapObjectRow as MapObject, MapObjectWithItem, MessageEventMap, NotificationRow as Notification, NotificationStats, PlaceableItemMetadata, PlatformTimebackUser, PlatformTimebackUserContext, PlaycademyMode, PlaycademyServerClientConfig, PlaycademyServerClientState, PlayerCharacterRow as PlayerCharacter, PlayerCharacterAccessoryRow as PlayerCharacterAccessory, PlayerCurrency, PlayerInventoryItem, PlayerProfile, PlayerSessionPayload, PopulateStudentResponse, QtiTestQuestionRef, QtiTestQuestionsResponse, RealtimeTokenResponse, ScoreSubmission, ShopCurrency, ShopDisplayItem, ShopListingRow as ShopListing, ShopViewResponse, SpriteAnimationFrame, SpriteConfigWithDimensions, SpriteTemplateRow as SpriteTemplate, SpriteTemplateData, StartSessionResponse, TelemetryPayload, TimebackEnrollment, TimebackInitContext, TimebackOrganization, TimebackUser, TimebackUserContext, TimebackUserXp, TodayXpResponse, TokenRefreshPayload, TokenType, TotalXpResponse, UpdateCharacterData, UpdateCurrencyInput, UpdateItemInput, UpdateShopListingInput, UpsertGameMetadataInput, UserRow as User, UserEnrollment, UserInfo, UserLevelRow as UserLevel, UserLevelWithConfig, UserOrganization, UserRank, UserRankResponse, UserRoleEnumType, UserScore, UserTimebackData, XPAddResult, XpHistoryResponse, XpResponse, XpSummaryResponse };
|
|
8045
|
+
export type { AchievementCurrent, AchievementHistoryEntry, AchievementProgressResponse, AchievementScopeType, AchievementWithStatus, ApiErrorCode, ApiErrorInfo, AssessmentBankStatus, AssessmentRow, AssessmentSummary, AuthCallbackPayload, AuthOptions, AuthProviderType, AuthResult, AuthServerMessage, AuthStateChangePayload, AuthStateUpdate, AuthenticatedUser, BetterAuthApiKey, BetterAuthApiKeyResponse, BetterAuthSignInResponse, BucketFile, CharacterComponentRow as CharacterComponent, CharacterComponentType, CharacterComponentWithSpriteUrl, CharacterComponentsOptions, ClientConfig, ClientEvents, ConnectionMonitorConfig, ConnectionState, ConnectionStatePayload, CourseXp, CreateCharacterData, CreateMapObjectData, CurrencyRow as Currency, DemoEndOptions, DemoEndPayload, DevUploadEvent, DevUploadHooks, DeveloperStatusEnumType, DeveloperStatusResponse, DeveloperStatusValue, DisconnectContext, DisconnectHandler, DisplayAlertPayload, ErrorResponseBody, EventListeners, ExternalGame, FetchedGame, Game, GameActivityMetrics, GameContextPayload, GameCourseMetrics, GameCustomHostname, GameInitUser, GameLeaderboardEntry, GameManifest, MapRow as GameMap, GameMetricsProxyResponse, GameMetricsResponse, GameMetricsUnsupportedReason, GamePlatform, GameRow as GameRecord, GameSessionRow as GameSession, GameTimebackIntegration, GameTokenResponse, GameType, GameUser, GetXpOptions, HostedGame, InitErrorPayload, InitPayload, InsertCurrencyInput, InsertItemInput, InsertShopListingInput, InteractionType, InventoryItemRow as InventoryItem, InventoryItemWithItem, InventoryMutationResponse, ItemRow as Item, ItemType, KVKeyEntry, KVKeyMetadata, KVSeedEntry, KVStatsResponse, KeyEventPayload, LeaderboardEntry, LeaderboardOptions, LeaderboardTimeframe, LevelConfigRow as LevelConfig, LevelProgressResponse, LevelUpCheckResult, LoginResponse, ManifestV1, ManifestV2, ManifestVersions, MapData, MapElementRow as MapElement, MapElementMetadata, MapElementWithGame, MapObjectRow as MapObject, MapObjectWithItem, MessageEventMap, NotificationRow as Notification, NotificationStats, PlaceableItemMetadata, PlatformTimebackUser, PlatformTimebackUserContext, PlaycademyMode, PlaycademyServerClientConfig, PlaycademyServerClientState, PlayerCharacterRow as PlayerCharacter, PlayerCharacterAccessoryRow as PlayerCharacterAccessory, PlayerCurrency, PlayerInventoryItem, PlayerProfile, PlayerSessionPayload, PopulateStudentResponse, QtiTestQuestionRef, QtiTestQuestionsResponse, RealtimeTokenResponse, ScoreSubmission, ShopCurrency, ShopDisplayItem, ShopListingRow as ShopListing, ShopViewResponse, SpriteAnimationFrame, SpriteConfigWithDimensions, SpriteTemplateRow as SpriteTemplate, SpriteTemplateData, StartSessionResponse, TelemetryPayload, TimebackEnrollment, TimebackInitContext, TimebackOrganization, TimebackUser, TimebackUserContext, TimebackUserRefreshField, TimebackUserRefreshOptions, TimebackUserXp, TodayXpResponse, TokenRefreshPayload, TokenType, TotalXpResponse, UpdateCharacterData, UpdateCurrencyInput, UpdateItemInput, UpdateShopListingInput, UpsertGameMetadataInput, UserRow as User, UserEnrollment, UserInfo, UserLevelRow as UserLevel, UserLevelWithConfig, UserOrganization, UserRank, UserRankResponse, UserRoleEnumType, UserScore, UserTimebackData, XPAddResult, XpHistoryResponse, XpResponse, XpSummaryResponse };
|
package/dist/internal.js
CHANGED
|
@@ -2095,6 +2095,15 @@ function createTimebackUserStore(client) {
|
|
|
2095
2095
|
enrollments: response.enrollments,
|
|
2096
2096
|
organizations: response.organizations
|
|
2097
2097
|
};
|
|
2098
|
+
},
|
|
2099
|
+
setEnrollments(enrollments) {
|
|
2100
|
+
const base = override ?? client["initPayload"]?.timeback;
|
|
2101
|
+
override = base ? { ...base, enrollments } : {
|
|
2102
|
+
id: undefined,
|
|
2103
|
+
role: undefined,
|
|
2104
|
+
enrollments,
|
|
2105
|
+
organizations: []
|
|
2106
|
+
};
|
|
2098
2107
|
}
|
|
2099
2108
|
};
|
|
2100
2109
|
}
|
|
@@ -2110,20 +2119,50 @@ function createTimebackEngine(client) {
|
|
|
2110
2119
|
ttl: 5000,
|
|
2111
2120
|
keyPrefix: "game.timeback.xp"
|
|
2112
2121
|
});
|
|
2122
|
+
const enrollmentsCache = createTTLCache({
|
|
2123
|
+
ttl: 5 * 60 * 1000,
|
|
2124
|
+
keyPrefix: "game.timeback.enrollments"
|
|
2125
|
+
});
|
|
2113
2126
|
async function applyPromotion(promotion) {
|
|
2114
2127
|
if (promotion.status !== "promoted" && promotion.status !== "already-promoted") {
|
|
2115
2128
|
return;
|
|
2116
2129
|
}
|
|
2117
2130
|
userCache.clear("current");
|
|
2131
|
+
enrollmentsCache.clear("current");
|
|
2118
2132
|
try {
|
|
2119
2133
|
await userStore.refresh();
|
|
2120
2134
|
} catch {}
|
|
2121
2135
|
}
|
|
2122
2136
|
const activityTracker = createTimebackActivityTracker(client);
|
|
2137
|
+
async function refreshUserContext() {
|
|
2138
|
+
const context = await userStore.refresh();
|
|
2139
|
+
enrollmentsCache.clear("current");
|
|
2140
|
+
return context;
|
|
2141
|
+
}
|
|
2142
|
+
async function refreshEnrollmentSlice(options) {
|
|
2143
|
+
const enrollments = await enrollmentsCache.get("current", async () => {
|
|
2144
|
+
const response = await client["request"]("/timeback/user/enrollments", "GET");
|
|
2145
|
+
userStore.setEnrollments(response);
|
|
2146
|
+
userCache.clear("current");
|
|
2147
|
+
return response;
|
|
2148
|
+
}, options);
|
|
2149
|
+
userStore.setEnrollments(enrollments);
|
|
2150
|
+
return userStore.snapshot();
|
|
2151
|
+
}
|
|
2123
2152
|
return {
|
|
2124
2153
|
user: {
|
|
2125
2154
|
snapshot: () => userStore.snapshot(),
|
|
2126
|
-
fetch: (options) => userCache.get("current",
|
|
2155
|
+
fetch: (options) => userCache.get("current", refreshUserContext, options),
|
|
2156
|
+
refresh: (options) => {
|
|
2157
|
+
if (!options?.only.includes("enrollments")) {
|
|
2158
|
+
throw new Error("At least one TimeBack user refresh field must be selected");
|
|
2159
|
+
}
|
|
2160
|
+
return refreshEnrollmentSlice({
|
|
2161
|
+
force: options.force,
|
|
2162
|
+
skipCache: options.skipCache,
|
|
2163
|
+
ttl: options.ttl
|
|
2164
|
+
});
|
|
2165
|
+
},
|
|
2127
2166
|
xp: {
|
|
2128
2167
|
fetch: (options) => {
|
|
2129
2168
|
const cacheKey = [
|
|
@@ -2184,6 +2223,7 @@ function createTimebackNamespace(client) {
|
|
|
2184
2223
|
return engine.user.snapshot()?.organizations ?? [];
|
|
2185
2224
|
},
|
|
2186
2225
|
fetch: (options) => engine.user.fetch(options),
|
|
2226
|
+
refresh: (options) => engine.user.refresh(options),
|
|
2187
2227
|
xp: {
|
|
2188
2228
|
fetch: async (options = {}) => {
|
|
2189
2229
|
const hasGrade = options.grade !== undefined;
|
|
@@ -2348,7 +2388,7 @@ class DeployPipeline {
|
|
|
2348
2388
|
return this.fetchGameWithRetry(slug);
|
|
2349
2389
|
}
|
|
2350
2390
|
async buildRequestBody(args) {
|
|
2351
|
-
const
|
|
2391
|
+
const game2 = await this.resolveGame(args.slug, args.game);
|
|
2352
2392
|
const requestBody = {};
|
|
2353
2393
|
if (args.uploadToken) {
|
|
2354
2394
|
requestBody.uploadToken = args.uploadToken;
|
|
@@ -2357,7 +2397,7 @@ class DeployPipeline {
|
|
|
2357
2397
|
requestBody.metadata = args.metadata;
|
|
2358
2398
|
}
|
|
2359
2399
|
if (!args.backend) {
|
|
2360
|
-
return { game, requestBody };
|
|
2400
|
+
return { game: game2, requestBody };
|
|
2361
2401
|
}
|
|
2362
2402
|
const backendFields = {
|
|
2363
2403
|
config: args.backend.config,
|
|
@@ -2372,7 +2412,7 @@ class DeployPipeline {
|
|
|
2372
2412
|
code: args.backend.code
|
|
2373
2413
|
};
|
|
2374
2414
|
if (this.serializedSize(inlineBody) <= DeployPipeline.MAX_INLINE_REQUEST_BYTES) {
|
|
2375
|
-
return { game, requestBody: inlineBody };
|
|
2415
|
+
return { game: game2, requestBody: inlineBody };
|
|
2376
2416
|
}
|
|
2377
2417
|
const skeletonBody = {
|
|
2378
2418
|
...requestBody,
|
|
@@ -2382,8 +2422,8 @@ class DeployPipeline {
|
|
|
2382
2422
|
if (this.serializedSize(skeletonBody) > DeployPipeline.MAX_INLINE_REQUEST_BYTES) {
|
|
2383
2423
|
throw new Error("Deploy request is too large even after uploading backend code");
|
|
2384
2424
|
}
|
|
2385
|
-
skeletonBody.codeUploadToken = await this.uploadCode(
|
|
2386
|
-
return { game, requestBody: skeletonBody };
|
|
2425
|
+
skeletonBody.codeUploadToken = await this.uploadCode(game2.id, args.backend.code);
|
|
2426
|
+
return { game: game2, requestBody: skeletonBody };
|
|
2387
2427
|
}
|
|
2388
2428
|
serializedSize(body) {
|
|
2389
2429
|
return DeployPipeline.textEncoder.encode(JSON.stringify(body)).length;
|
|
@@ -2471,8 +2511,8 @@ class DeployPipeline {
|
|
|
2471
2511
|
await new Promise((resolve) => setTimeout(resolve, DeployPipeline.POLL_INTERVAL_MS));
|
|
2472
2512
|
}
|
|
2473
2513
|
}
|
|
2474
|
-
async resolveGame(slug,
|
|
2475
|
-
return
|
|
2514
|
+
async resolveGame(slug, game2) {
|
|
2515
|
+
return game2 ?? await this.client["request"](`/games/${slug}`, "GET");
|
|
2476
2516
|
}
|
|
2477
2517
|
async fetchGameWithRetry(slug) {
|
|
2478
2518
|
const { GAME_FETCH_RETRIES } = DeployPipeline;
|
|
@@ -2505,21 +2545,21 @@ function createDevNamespace(client) {
|
|
|
2505
2545
|
deploy: async (slug, options) => {
|
|
2506
2546
|
const { metadata, file, backend, hooks } = options;
|
|
2507
2547
|
hooks?.onEvent?.({ type: "init" });
|
|
2508
|
-
let
|
|
2548
|
+
let game2;
|
|
2509
2549
|
if (metadata) {
|
|
2510
|
-
|
|
2550
|
+
game2 = await client["request"](`/games/${slug}`, "PUT", {
|
|
2511
2551
|
body: metadata
|
|
2512
2552
|
});
|
|
2513
2553
|
if (metadata.gameType === "external" && !file && !backend) {
|
|
2514
|
-
return
|
|
2554
|
+
return game2;
|
|
2515
2555
|
}
|
|
2516
2556
|
}
|
|
2517
|
-
const uploadToken = file ? await deploy.uploadFile(file,
|
|
2557
|
+
const uploadToken = file ? await deploy.uploadFile(file, game2?.id || slug, hooks) : undefined;
|
|
2518
2558
|
if (uploadToken || backend) {
|
|
2519
|
-
return deploy.submit({ slug, game, uploadToken, metadata, backend, hooks });
|
|
2559
|
+
return deploy.submit({ slug, game: game2, uploadToken, metadata, backend, hooks });
|
|
2520
2560
|
}
|
|
2521
|
-
if (
|
|
2522
|
-
return
|
|
2561
|
+
if (game2) {
|
|
2562
|
+
return game2;
|
|
2523
2563
|
}
|
|
2524
2564
|
throw new Error("No deployment actions specified (need metadata, file, or backend)");
|
|
2525
2565
|
},
|
|
@@ -2675,6 +2715,24 @@ function createGamesNamespace(client) {
|
|
|
2675
2715
|
}, options);
|
|
2676
2716
|
},
|
|
2677
2717
|
list: (options) => gamesListCache.get("all", () => client["request"]("/games", "GET"), options),
|
|
2718
|
+
patchMetadata: async (gameId, metadata) => {
|
|
2719
|
+
const updatedGame = await client["request"](`/games/${gameId}`, "PATCH", {
|
|
2720
|
+
body: metadata
|
|
2721
|
+
});
|
|
2722
|
+
gamesListCache.clear("all");
|
|
2723
|
+
gameFetchCache.clear(gameId);
|
|
2724
|
+
gameFetchCache.clear(updatedGame.slug);
|
|
2725
|
+
return updatedGame;
|
|
2726
|
+
},
|
|
2727
|
+
members: {
|
|
2728
|
+
list: (gameId) => client["request"](`/games/${gameId}/members`, "GET"),
|
|
2729
|
+
add: (gameId, body) => client["request"](`/games/${gameId}/members`, "POST", {
|
|
2730
|
+
body
|
|
2731
|
+
}),
|
|
2732
|
+
update: (gameId, userId, body) => client["request"](`/games/${gameId}/members/${encodeURIComponent(userId)}`, "PATCH", { body }),
|
|
2733
|
+
remove: (gameId, userId) => client["request"](`/games/${gameId}/members/${encodeURIComponent(userId)}`, "DELETE"),
|
|
2734
|
+
search: (gameId, query) => client["request"](`/games/${gameId}/members/search?q=${encodeURIComponent(query)}`, "GET")
|
|
2735
|
+
},
|
|
2678
2736
|
getSubjects: () => client["request"]("/games/subjects", "GET"),
|
|
2679
2737
|
startSession: async (gameId) => {
|
|
2680
2738
|
const idToUse = gameId ?? client["_ensureGameId"]();
|
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
|
*/
|
package/dist/types.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { UserRole, AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
1
2
|
import { InferSelectModel } from 'drizzle-orm';
|
|
2
3
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
3
4
|
import * as drizzle_zod from 'drizzle-zod';
|
|
4
5
|
import { z } from 'zod';
|
|
5
|
-
import { AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* OAuth 2.0 implementation for the Playcademy SDK
|
|
@@ -450,6 +450,21 @@ type GameMetricsProxyResponse = {
|
|
|
450
450
|
details?: string;
|
|
451
451
|
};
|
|
452
452
|
|
|
453
|
+
/**
|
|
454
|
+
* Cache configuration types for runtime customization
|
|
455
|
+
*/
|
|
456
|
+
/**
|
|
457
|
+
* Runtime configuration for TTL cache behavior
|
|
458
|
+
*/
|
|
459
|
+
interface TTLCacheConfig {
|
|
460
|
+
/** Time-to-live in milliseconds. Set to 0 to disable caching for this call. */
|
|
461
|
+
ttl?: number;
|
|
462
|
+
/** Force refresh, bypassing cache */
|
|
463
|
+
force?: boolean;
|
|
464
|
+
/** Skip cache and fetch fresh data (alias for force) */
|
|
465
|
+
skipCache?: boolean;
|
|
466
|
+
}
|
|
467
|
+
|
|
453
468
|
/**
|
|
454
469
|
* @fileoverview Server SDK Type Definitions
|
|
455
470
|
*
|
|
@@ -648,7 +663,8 @@ interface PlaycademyServerClientState {
|
|
|
648
663
|
*
|
|
649
664
|
* @module types/user
|
|
650
665
|
*/
|
|
651
|
-
|
|
666
|
+
|
|
667
|
+
type UserRoleEnumType = UserRole;
|
|
652
668
|
type DeveloperStatusEnumType = 'none' | 'pending' | 'approved';
|
|
653
669
|
type DeveloperStatusValue = DeveloperStatusEnumType;
|
|
654
670
|
type TimebackUserRole = 'administrator' | 'aide' | 'guardian' | 'parent' | 'proctor' | 'relative' | 'student' | 'teacher';
|
|
@@ -656,6 +672,10 @@ type TimebackOrgType = 'department' | 'school' | 'district' | 'local' | 'state'
|
|
|
656
672
|
interface UserEnrollment {
|
|
657
673
|
gameId?: string;
|
|
658
674
|
courseId: string;
|
|
675
|
+
enrollmentIds?: {
|
|
676
|
+
active: string;
|
|
677
|
+
inactive?: string[];
|
|
678
|
+
};
|
|
659
679
|
grade: number;
|
|
660
680
|
subject: string;
|
|
661
681
|
orgId?: string;
|
|
@@ -745,6 +765,7 @@ interface GameUser {
|
|
|
745
765
|
*
|
|
746
766
|
* @module types/game
|
|
747
767
|
*/
|
|
768
|
+
|
|
748
769
|
type GameType = 'hosted' | 'external';
|
|
749
770
|
type GamePlatform = 'web' | 'godot' | 'unity' | (string & {});
|
|
750
771
|
/**
|
|
@@ -3970,7 +3991,7 @@ declare const UpsertGameMetadataSchema: z.ZodEffects<z.ZodObject<{
|
|
|
3970
3991
|
displayName: z.ZodString;
|
|
3971
3992
|
mapElementId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
3972
3993
|
platform: z.ZodEnum<["web", "godot", "unity"]>;
|
|
3973
|
-
metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown
|
|
3994
|
+
metadata: z.ZodDefault<z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodUnknown>, Record<string, unknown>, Record<string, unknown>>>>;
|
|
3974
3995
|
gameType: z.ZodDefault<z.ZodOptional<z.ZodEnum<["hosted", "external"]>>>;
|
|
3975
3996
|
visibility: z.ZodOptional<z.ZodEnum<["visible", "unlisted", "internal"]>>;
|
|
3976
3997
|
externalUrl: z.ZodOptional<z.ZodString>;
|
|
@@ -5404,6 +5425,7 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
5404
5425
|
* User context (cached from init, refreshable):
|
|
5405
5426
|
* - `user.role` - User's role (student, parent, teacher, etc.)
|
|
5406
5427
|
* - `user.enrollments` - Courses the player is enrolled in for this game
|
|
5428
|
+
* - `user.refresh({ only: ['enrollments'] })` - Refresh enrollments from server
|
|
5407
5429
|
* - `user.organizations` - Schools/districts the player belongs to
|
|
5408
5430
|
* - `user.fetch()` - Refresh user context from server
|
|
5409
5431
|
*
|
|
@@ -5505,7 +5527,9 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
|
5505
5527
|
|
|
5506
5528
|
/**
|
|
5507
5529
|
* A TimeBack enrollment for the current game session.
|
|
5508
|
-
* Alias for UserEnrollment without the optional gameId.
|
|
5530
|
+
* Alias for UserEnrollment without the optional gameId. Active enrollment IDs
|
|
5531
|
+
* are available at `enrollment.enrollmentIds?.active` when supplied by the
|
|
5532
|
+
* platform.
|
|
5509
5533
|
*/
|
|
5510
5534
|
type TimebackEnrollment = Omit<UserEnrollment, 'gameId'>;
|
|
5511
5535
|
/**
|
|
@@ -5541,6 +5565,14 @@ interface TimebackUserContext {
|
|
|
5541
5565
|
/** User's organizations (schools/districts) */
|
|
5542
5566
|
organizations: TimebackOrganization[];
|
|
5543
5567
|
}
|
|
5568
|
+
/**
|
|
5569
|
+
* Slice options for refreshing the cached TimeBack user context.
|
|
5570
|
+
*/
|
|
5571
|
+
type TimebackUserRefreshField = 'enrollments';
|
|
5572
|
+
interface TimebackUserRefreshOptions extends TTLCacheConfig {
|
|
5573
|
+
/** Refresh only these user data fields */
|
|
5574
|
+
only: readonly TimebackUserRefreshField[];
|
|
5575
|
+
}
|
|
5544
5576
|
/**
|
|
5545
5577
|
* XP data access for the current user.
|
|
5546
5578
|
* Results are cached for 5 seconds to avoid redundant network requests.
|
|
@@ -5581,7 +5613,7 @@ interface TimebackUserXp {
|
|
|
5581
5613
|
fetch(options?: GetXpOptions): Promise<XpResponse>;
|
|
5582
5614
|
}
|
|
5583
5615
|
/**
|
|
5584
|
-
* TimeBack user object with
|
|
5616
|
+
* TimeBack user object with cached getters, fetch, and targeted refresh methods.
|
|
5585
5617
|
*/
|
|
5586
5618
|
interface TimebackUser extends TimebackUserContext {
|
|
5587
5619
|
/**
|
|
@@ -5590,9 +5622,14 @@ interface TimebackUser extends TimebackUserContext {
|
|
|
5590
5622
|
* @param options - Cache options (pass { force: true } to bypass cache)
|
|
5591
5623
|
* @returns Promise resolving to fresh user context
|
|
5592
5624
|
*/
|
|
5593
|
-
fetch(options?:
|
|
5594
|
-
|
|
5595
|
-
|
|
5625
|
+
fetch(options?: TTLCacheConfig): Promise<TimebackUserContext>;
|
|
5626
|
+
/**
|
|
5627
|
+
* Refresh selected TimeBack user data from the server.
|
|
5628
|
+
* Updates the cached user snapshot used by the synchronous getters.
|
|
5629
|
+
* @param options - Refresh fields and cache options
|
|
5630
|
+
* @returns Promise resolving to the updated user context
|
|
5631
|
+
*/
|
|
5632
|
+
refresh(options: TimebackUserRefreshOptions): Promise<TimebackUserContext>;
|
|
5596
5633
|
/**
|
|
5597
5634
|
* XP data for the current user.
|
|
5598
5635
|
* Call `xp.fetch()` to get XP from the server.
|
|
@@ -6167,4 +6204,4 @@ interface AssessmentBankStatus {
|
|
|
6167
6204
|
}
|
|
6168
6205
|
|
|
6169
6206
|
export { AchievementCompletionType, NotificationStatus, NotificationType, PlaycademyClient };
|
|
6170
|
-
export type { AchievementCurrent, AchievementHistoryEntry, AchievementProgressResponse, AchievementScopeType, AchievementWithStatus, AssessmentBankStatus, AssessmentRow, AssessmentSummary, AuthCallbackPayload, AuthOptions, AuthProviderType, AuthResult, AuthServerMessage, AuthStateChangePayload, AuthStateUpdate, AuthenticatedUser, BetterAuthApiKey, BetterAuthApiKeyResponse, BetterAuthSignInResponse, BucketFile, CharacterComponentRow as CharacterComponent, CharacterComponentType, CharacterComponentWithSpriteUrl, CharacterComponentsOptions, ClientConfig, ClientEvents, ConnectionStatePayload, CourseXp, CreateCharacterData, CreateMapObjectData, CurrencyRow as Currency, DemoEndOptions, DemoEndPayload, DevUploadEvent, DevUploadHooks, DeveloperStatusEnumType, DeveloperStatusResponse, DeveloperStatusValue, DisconnectContext, DisconnectHandler, DisplayAlertPayload, EventListeners, ExternalGame, FetchedGame, Game, GameActivityMetrics, GameContextPayload, GameCourseMetrics, GameCustomHostname, GameInitUser, GameLeaderboardEntry, GameManifest, MapRow as GameMap, GameMetricsProxyResponse, GameMetricsResponse, GameMetricsUnsupportedReason, GamePlatform, GameRow as GameRecord, GameSessionRow as GameSession, GameTimebackIntegration, GameTokenResponse, GameType, GameUser, GetXpOptions, HostedGame, InitErrorPayload, InitPayload, InsertCurrencyInput, InsertItemInput, InsertShopListingInput, InteractionType, InventoryItemRow as InventoryItem, InventoryItemWithItem, InventoryMutationResponse, ItemRow as Item, ItemType, KVKeyEntry, KVKeyMetadata, KVSeedEntry, KVStatsResponse, KeyEventPayload, LeaderboardEntry, LeaderboardOptions, LeaderboardTimeframe, LevelConfigRow as LevelConfig, LevelProgressResponse, LevelUpCheckResult, LoginResponse, ManifestV1, ManifestV2, ManifestVersions, MapData, MapElementRow as MapElement, MapElementMetadata, MapElementWithGame, MapObjectRow as MapObject, MapObjectWithItem, NotificationRow as Notification, NotificationStats, PlaceableItemMetadata, PlatformTimebackUser, PlatformTimebackUserContext, PlaycademyMode, PlaycademyServerClientConfig, PlaycademyServerClientState, PlayerCharacterRow as PlayerCharacter, PlayerCharacterAccessoryRow as PlayerCharacterAccessory, PlayerCurrency, PlayerInventoryItem, PlayerProfile, PlayerSessionPayload, PopulateStudentResponse, QtiTestQuestionRef, QtiTestQuestionsResponse, RealtimeTokenResponse, ScoreSubmission, ShopCurrency, ShopDisplayItem, ShopListingRow as ShopListing, ShopViewResponse, SpriteAnimationFrame, SpriteConfigWithDimensions, SpriteTemplateRow as SpriteTemplate, SpriteTemplateData, StartSessionResponse, TelemetryPayload, TimebackEnrollment, TimebackInitContext, TimebackOrganization, TimebackUser, TimebackUserContext, TimebackUserXp, TodayXpResponse, TokenRefreshPayload, TokenType, TotalXpResponse, UpdateCharacterData, UpdateCurrencyInput, UpdateItemInput, UpdateShopListingInput, UpsertGameMetadataInput, UserRow as User, UserEnrollment, UserInfo, UserLevelRow as UserLevel, UserLevelWithConfig, UserOrganization, UserRank, UserRankResponse, UserRoleEnumType, UserScore, UserTimebackData, XPAddResult, XpHistoryResponse, XpResponse, XpSummaryResponse };
|
|
6207
|
+
export type { AchievementCurrent, AchievementHistoryEntry, AchievementProgressResponse, AchievementScopeType, AchievementWithStatus, AssessmentBankStatus, AssessmentRow, AssessmentSummary, AuthCallbackPayload, AuthOptions, AuthProviderType, AuthResult, AuthServerMessage, AuthStateChangePayload, AuthStateUpdate, AuthenticatedUser, BetterAuthApiKey, BetterAuthApiKeyResponse, BetterAuthSignInResponse, BucketFile, CharacterComponentRow as CharacterComponent, CharacterComponentType, CharacterComponentWithSpriteUrl, CharacterComponentsOptions, ClientConfig, ClientEvents, ConnectionStatePayload, CourseXp, CreateCharacterData, CreateMapObjectData, CurrencyRow as Currency, DemoEndOptions, DemoEndPayload, DevUploadEvent, DevUploadHooks, DeveloperStatusEnumType, DeveloperStatusResponse, DeveloperStatusValue, DisconnectContext, DisconnectHandler, DisplayAlertPayload, EventListeners, ExternalGame, FetchedGame, Game, GameActivityMetrics, GameContextPayload, GameCourseMetrics, GameCustomHostname, GameInitUser, GameLeaderboardEntry, GameManifest, MapRow as GameMap, GameMetricsProxyResponse, GameMetricsResponse, GameMetricsUnsupportedReason, GamePlatform, GameRow as GameRecord, GameSessionRow as GameSession, GameTimebackIntegration, GameTokenResponse, GameType, GameUser, GetXpOptions, HostedGame, InitErrorPayload, InitPayload, InsertCurrencyInput, InsertItemInput, InsertShopListingInput, InteractionType, InventoryItemRow as InventoryItem, InventoryItemWithItem, InventoryMutationResponse, ItemRow as Item, ItemType, KVKeyEntry, KVKeyMetadata, KVSeedEntry, KVStatsResponse, KeyEventPayload, LeaderboardEntry, LeaderboardOptions, LeaderboardTimeframe, LevelConfigRow as LevelConfig, LevelProgressResponse, LevelUpCheckResult, LoginResponse, ManifestV1, ManifestV2, ManifestVersions, MapData, MapElementRow as MapElement, MapElementMetadata, MapElementWithGame, MapObjectRow as MapObject, MapObjectWithItem, NotificationRow as Notification, NotificationStats, PlaceableItemMetadata, PlatformTimebackUser, PlatformTimebackUserContext, PlaycademyMode, PlaycademyServerClientConfig, PlaycademyServerClientState, PlayerCharacterRow as PlayerCharacter, PlayerCharacterAccessoryRow as PlayerCharacterAccessory, PlayerCurrency, PlayerInventoryItem, PlayerProfile, PlayerSessionPayload, PopulateStudentResponse, QtiTestQuestionRef, QtiTestQuestionsResponse, RealtimeTokenResponse, ScoreSubmission, ShopCurrency, ShopDisplayItem, ShopListingRow as ShopListing, ShopViewResponse, SpriteAnimationFrame, SpriteConfigWithDimensions, SpriteTemplateRow as SpriteTemplate, SpriteTemplateData, StartSessionResponse, TelemetryPayload, TimebackEnrollment, TimebackInitContext, TimebackOrganization, TimebackUser, TimebackUserContext, TimebackUserRefreshField, TimebackUserRefreshOptions, TimebackUserXp, TodayXpResponse, TokenRefreshPayload, TokenType, TotalXpResponse, UpdateCharacterData, UpdateCurrencyInput, UpdateItemInput, UpdateShopListingInput, UpsertGameMetadataInput, UserRow as User, UserEnrollment, UserInfo, UserLevelRow as UserLevel, UserLevelWithConfig, UserOrganization, UserRank, UserRankResponse, UserRoleEnumType, UserScore, UserTimebackData, XPAddResult, XpHistoryResponse, XpResponse, XpSummaryResponse };
|