@playcademy/sdk 0.2.1 → 0.2.3
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 +20 -17
- package/dist/index.d.ts +486 -480
- package/dist/index.js +1455 -1399
- package/dist/internal.d.ts +4515 -3537
- package/dist/internal.js +2612 -2603
- package/dist/server.d.ts +304 -44
- package/dist/server.js +118 -9
- package/dist/types.d.ts +2779 -996
- package/package.json +5 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import * as _playcademy_realtime_server_types from '@playcademy/realtime/server/types';
|
|
2
|
-
import * as _playcademy_timeback_types from '@playcademy/timeback/types';
|
|
3
1
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
4
2
|
import { AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
5
3
|
|
|
@@ -9,22 +7,146 @@ import { AUTH_PROVIDER_IDS } from '@playcademy/constants';
|
|
|
9
7
|
declare class PlaycademyError extends Error {
|
|
10
8
|
constructor(message: string);
|
|
11
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Error codes returned by the API.
|
|
12
|
+
* These map to specific error types and HTTP status codes.
|
|
13
|
+
*/
|
|
14
|
+
type ApiErrorCode = 'BAD_REQUEST' | 'UNAUTHORIZED' | 'FORBIDDEN' | 'ACCESS_DENIED' | 'NOT_FOUND' | 'METHOD_NOT_ALLOWED' | 'CONFLICT' | 'ALREADY_EXISTS' | 'GONE' | 'PRECONDITION_FAILED' | 'PAYLOAD_TOO_LARGE' | 'VALIDATION_FAILED' | 'TOO_MANY_REQUESTS' | 'RATE_LIMITED' | 'EXPIRED' | 'INTERNAL' | 'INTERNAL_ERROR' | 'NOT_IMPLEMENTED' | 'SERVICE_UNAVAILABLE' | 'TIMEOUT' | string;
|
|
15
|
+
/**
|
|
16
|
+
* Structure of error response bodies returned by API endpoints.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```json
|
|
20
|
+
* {
|
|
21
|
+
* "error": {
|
|
22
|
+
* "code": "NOT_FOUND",
|
|
23
|
+
* "message": "Item not found",
|
|
24
|
+
* "details": { "identifier": "abc123" }
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
interface ErrorResponseBody {
|
|
30
|
+
error?: {
|
|
31
|
+
code?: string;
|
|
32
|
+
message?: string;
|
|
33
|
+
details?: unknown;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* API error thrown when a request fails.
|
|
38
|
+
*
|
|
39
|
+
* Contains structured error information from the API response:
|
|
40
|
+
* - `status` - HTTP status code (e.g., 404)
|
|
41
|
+
* - `code` - API error code (e.g., "NOT_FOUND")
|
|
42
|
+
* - `message` - Human-readable error message
|
|
43
|
+
* - `details` - Optional additional error context
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* try {
|
|
48
|
+
* await client.games.get('nonexistent')
|
|
49
|
+
* } catch (error) {
|
|
50
|
+
* if (error instanceof ApiError) {
|
|
51
|
+
* console.log(error.status) // 404
|
|
52
|
+
* console.log(error.code) // "NOT_FOUND"
|
|
53
|
+
* console.log(error.message) // "Game not found"
|
|
54
|
+
* console.log(error.details) // { identifier: "nonexistent" }
|
|
55
|
+
* }
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
12
59
|
declare class ApiError extends Error {
|
|
13
|
-
status: number;
|
|
14
|
-
|
|
15
|
-
|
|
60
|
+
readonly status: number;
|
|
61
|
+
/**
|
|
62
|
+
* API error code (e.g., "NOT_FOUND", "VALIDATION_FAILED").
|
|
63
|
+
* Use this for programmatic error handling.
|
|
64
|
+
*/
|
|
65
|
+
readonly code: ApiErrorCode;
|
|
66
|
+
/**
|
|
67
|
+
* Additional error context from the API.
|
|
68
|
+
* Structure varies by error type (e.g., validation errors include field details).
|
|
69
|
+
*/
|
|
70
|
+
readonly details: unknown;
|
|
71
|
+
/**
|
|
72
|
+
* Raw response body for debugging.
|
|
73
|
+
* @internal
|
|
74
|
+
*/
|
|
75
|
+
readonly rawBody: unknown;
|
|
76
|
+
constructor(
|
|
77
|
+
/** HTTP status code */
|
|
78
|
+
status: number,
|
|
79
|
+
/** API error code */
|
|
80
|
+
code: ApiErrorCode,
|
|
81
|
+
/** Human-readable error message */
|
|
82
|
+
message: string,
|
|
83
|
+
/** Additional error context */
|
|
84
|
+
details?: unknown,
|
|
85
|
+
/** Raw response body */
|
|
86
|
+
rawBody?: unknown);
|
|
87
|
+
/**
|
|
88
|
+
* Create an ApiError from an HTTP response.
|
|
89
|
+
* Parses the structured error response from the API.
|
|
90
|
+
*
|
|
91
|
+
* @internal
|
|
92
|
+
*/
|
|
93
|
+
static fromResponse(status: number, statusText: string, body: unknown): ApiError;
|
|
94
|
+
/**
|
|
95
|
+
* Check if this is a specific error type.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* if (error.is('NOT_FOUND')) {
|
|
100
|
+
* // Handle not found
|
|
101
|
+
* } else if (error.is('VALIDATION_FAILED')) {
|
|
102
|
+
* // Handle validation error
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
is(code: ApiErrorCode): boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Check if this is a client error (4xx).
|
|
109
|
+
*/
|
|
110
|
+
isClientError(): boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Check if this is a server error (5xx).
|
|
113
|
+
*/
|
|
114
|
+
isServerError(): boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Check if this error is retryable.
|
|
117
|
+
* Server errors and rate limits are typically retryable.
|
|
118
|
+
*/
|
|
119
|
+
isRetryable(): boolean;
|
|
16
120
|
}
|
|
17
121
|
/**
|
|
18
|
-
*
|
|
19
|
-
* Useful for displaying errors to users in a friendly way
|
|
122
|
+
* Extracted error information for display purposes.
|
|
20
123
|
*/
|
|
21
124
|
interface ApiErrorInfo {
|
|
125
|
+
/** HTTP status code */
|
|
22
126
|
status: number;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
message
|
|
127
|
+
/** API error code */
|
|
128
|
+
code: ApiErrorCode;
|
|
129
|
+
/** Human-readable error message */
|
|
130
|
+
message: string;
|
|
131
|
+
/** Additional error context */
|
|
26
132
|
details?: unknown;
|
|
27
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Extract useful error information from an API error.
|
|
136
|
+
* Useful for displaying errors to users in a friendly way.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* try {
|
|
141
|
+
* await client.shop.purchase(itemId)
|
|
142
|
+
* } catch (error) {
|
|
143
|
+
* const info = extractApiErrorInfo(error)
|
|
144
|
+
* if (info) {
|
|
145
|
+
* showToast(`Error: ${info.message}`)
|
|
146
|
+
* }
|
|
147
|
+
* }
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
28
150
|
declare function extractApiErrorInfo(error: unknown): ApiErrorInfo | null;
|
|
29
151
|
|
|
30
152
|
/**
|
|
@@ -256,217 +378,151 @@ declare function parseOAuthState(state: string): {
|
|
|
256
378
|
data?: Record<string, string>;
|
|
257
379
|
};
|
|
258
380
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
data: "none" | "pending" | "approved";
|
|
405
|
-
driverParam: string;
|
|
406
|
-
notNull: true;
|
|
407
|
-
hasDefault: true;
|
|
408
|
-
isPrimaryKey: false;
|
|
409
|
-
isAutoincrement: false;
|
|
410
|
-
hasRuntimeDefault: false;
|
|
411
|
-
enumValues: ["none", "pending", "approved"];
|
|
412
|
-
baseColumn: never;
|
|
413
|
-
identity: undefined;
|
|
414
|
-
generated: undefined;
|
|
415
|
-
}, {}, {}>;
|
|
416
|
-
characterCreated: drizzle_orm_pg_core.PgColumn<{
|
|
417
|
-
name: "character_created";
|
|
418
|
-
tableName: "user";
|
|
419
|
-
dataType: "boolean";
|
|
420
|
-
columnType: "PgBoolean";
|
|
421
|
-
data: boolean;
|
|
422
|
-
driverParam: boolean;
|
|
423
|
-
notNull: true;
|
|
424
|
-
hasDefault: true;
|
|
425
|
-
isPrimaryKey: false;
|
|
426
|
-
isAutoincrement: false;
|
|
427
|
-
hasRuntimeDefault: false;
|
|
428
|
-
enumValues: undefined;
|
|
429
|
-
baseColumn: never;
|
|
430
|
-
identity: undefined;
|
|
431
|
-
generated: undefined;
|
|
432
|
-
}, {}, {}>;
|
|
433
|
-
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
434
|
-
name: "created_at";
|
|
435
|
-
tableName: "user";
|
|
436
|
-
dataType: "date";
|
|
437
|
-
columnType: "PgTimestamp";
|
|
438
|
-
data: Date;
|
|
439
|
-
driverParam: string;
|
|
440
|
-
notNull: true;
|
|
441
|
-
hasDefault: false;
|
|
442
|
-
isPrimaryKey: false;
|
|
443
|
-
isAutoincrement: false;
|
|
444
|
-
hasRuntimeDefault: false;
|
|
445
|
-
enumValues: undefined;
|
|
446
|
-
baseColumn: never;
|
|
447
|
-
identity: undefined;
|
|
448
|
-
generated: undefined;
|
|
449
|
-
}, {}, {}>;
|
|
450
|
-
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
451
|
-
name: "updated_at";
|
|
452
|
-
tableName: "user";
|
|
453
|
-
dataType: "date";
|
|
454
|
-
columnType: "PgTimestamp";
|
|
455
|
-
data: Date;
|
|
456
|
-
driverParam: string;
|
|
457
|
-
notNull: true;
|
|
458
|
-
hasDefault: false;
|
|
459
|
-
isPrimaryKey: false;
|
|
460
|
-
isAutoincrement: false;
|
|
461
|
-
hasRuntimeDefault: false;
|
|
462
|
-
enumValues: undefined;
|
|
463
|
-
baseColumn: never;
|
|
464
|
-
identity: undefined;
|
|
465
|
-
generated: undefined;
|
|
466
|
-
}, {}, {}>;
|
|
467
|
-
};
|
|
468
|
-
dialect: "pg";
|
|
469
|
-
}>;
|
|
381
|
+
/** Permitted HTTP verbs */
|
|
382
|
+
type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* User Types
|
|
386
|
+
*
|
|
387
|
+
* Enums, DTOs and API response types. Database row types are in @playcademy/data/types.
|
|
388
|
+
*
|
|
389
|
+
* @module types/user
|
|
390
|
+
*/
|
|
391
|
+
type UserRoleEnumType = 'admin' | 'player' | 'developer';
|
|
392
|
+
type DeveloperStatusEnumType = 'none' | 'pending' | 'approved';
|
|
393
|
+
type TimebackUserRole = 'administrator' | 'aide' | 'guardian' | 'parent' | 'proctor' | 'relative' | 'student' | 'teacher';
|
|
394
|
+
type TimebackOrgType = 'department' | 'school' | 'district' | 'local' | 'state' | 'national';
|
|
395
|
+
interface UserEnrollment {
|
|
396
|
+
gameId?: string;
|
|
397
|
+
courseId: string;
|
|
398
|
+
grade: number;
|
|
399
|
+
subject: string;
|
|
400
|
+
orgId?: string;
|
|
401
|
+
}
|
|
402
|
+
interface UserOrganization {
|
|
403
|
+
id: string;
|
|
404
|
+
name: string | null;
|
|
405
|
+
type: TimebackOrgType | string;
|
|
406
|
+
isPrimary: boolean;
|
|
407
|
+
}
|
|
408
|
+
interface TimebackStudentProfile {
|
|
409
|
+
role: TimebackUserRole;
|
|
410
|
+
organizations: UserOrganization[];
|
|
411
|
+
}
|
|
412
|
+
interface UserTimebackData extends TimebackStudentProfile {
|
|
413
|
+
id: string;
|
|
414
|
+
enrollments: UserEnrollment[];
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* OpenID Connect UserInfo claims (NOT a database row).
|
|
418
|
+
*/
|
|
419
|
+
interface UserInfo {
|
|
420
|
+
sub: string;
|
|
421
|
+
email: string;
|
|
422
|
+
name: string | null;
|
|
423
|
+
email_verified?: boolean;
|
|
424
|
+
given_name?: string;
|
|
425
|
+
family_name?: string;
|
|
426
|
+
issuer?: string;
|
|
427
|
+
lti_roles?: unknown;
|
|
428
|
+
lti_context?: unknown;
|
|
429
|
+
lti_resource_link?: unknown;
|
|
430
|
+
timeback_id?: string;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Authenticated user for API responses.
|
|
434
|
+
* Differs from UserRow: omits timebackId, adds hasTimebackAccount and timeback.
|
|
435
|
+
*/
|
|
436
|
+
interface AuthenticatedUser {
|
|
437
|
+
id: string;
|
|
438
|
+
email: string;
|
|
439
|
+
emailVerified: boolean;
|
|
440
|
+
name: string | null;
|
|
441
|
+
image: string | null;
|
|
442
|
+
username: string | null;
|
|
443
|
+
role: UserRoleEnumType;
|
|
444
|
+
developerStatus: DeveloperStatusEnumType;
|
|
445
|
+
characterCreated: boolean;
|
|
446
|
+
createdAt: Date;
|
|
447
|
+
updatedAt: Date;
|
|
448
|
+
hasTimebackAccount: boolean;
|
|
449
|
+
timeback?: UserTimebackData;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Valid Caliper subject values.
|
|
454
|
+
* Matches OneRoster subjects, with "None" as a Caliper-specific fallback.
|
|
455
|
+
*/
|
|
456
|
+
type CaliperSubject = 'Reading' | 'Language' | 'Vocabulary' | 'Social Studies' | 'Writing' | 'Science' | 'FastMath' | 'Math' | 'None';
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* TimeBack Client SDK DTOs
|
|
460
|
+
*
|
|
461
|
+
* Data transfer objects for the TimeBack client SDK including
|
|
462
|
+
* progress tracking, session management, and activity completion.
|
|
463
|
+
*
|
|
464
|
+
* Note: TimebackClientConfig lives in @playcademy/timeback as it's
|
|
465
|
+
* SDK configuration, not a DTO.
|
|
466
|
+
*
|
|
467
|
+
* @module types/timeback/client
|
|
468
|
+
*/
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Activity data for ending an activity
|
|
472
|
+
*/
|
|
473
|
+
interface ActivityData {
|
|
474
|
+
/** Unique activity identifier (required) */
|
|
475
|
+
activityId: string;
|
|
476
|
+
/** Grade level for this activity (required for multi-grade course routing) */
|
|
477
|
+
grade: number;
|
|
478
|
+
/** Subject area (required for multi-grade course routing) */
|
|
479
|
+
subject: CaliperSubject;
|
|
480
|
+
/** Activity display name (optional) */
|
|
481
|
+
activityName?: string;
|
|
482
|
+
/** Course identifier (auto-filled from config if not provided) */
|
|
483
|
+
courseId?: string;
|
|
484
|
+
/** Course display name (auto-filled from config if not provided) */
|
|
485
|
+
courseName?: string;
|
|
486
|
+
/** Student email address (optional) */
|
|
487
|
+
studentEmail?: string;
|
|
488
|
+
/** Application name for Caliper events (defaults to 'Game') */
|
|
489
|
+
appName?: string;
|
|
490
|
+
/** Sensor URL for Caliper events (defaults to baseUrl) */
|
|
491
|
+
sensorUrl?: string;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Score data with optional XP override for ending an activity
|
|
495
|
+
*/
|
|
496
|
+
interface EndActivityScoreData {
|
|
497
|
+
/** Number of questions answered correctly */
|
|
498
|
+
correctQuestions: number;
|
|
499
|
+
/** Total number of questions */
|
|
500
|
+
totalQuestions: number;
|
|
501
|
+
/** Optional XP override - bypasses automatic XP calculation */
|
|
502
|
+
xpAwarded?: number;
|
|
503
|
+
/** Number of learning units mastered */
|
|
504
|
+
masteredUnits?: number;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* TimeBack API Request/Response Types
|
|
509
|
+
*
|
|
510
|
+
* Types for TimeBack API endpoints including XP tracking,
|
|
511
|
+
* setup, verification, and activity completion.
|
|
512
|
+
*
|
|
513
|
+
* @module types/timeback/api
|
|
514
|
+
*/
|
|
515
|
+
|
|
516
|
+
interface EndActivityResponse {
|
|
517
|
+
status: 'ok';
|
|
518
|
+
courseId: string;
|
|
519
|
+
xpAwarded: number;
|
|
520
|
+
masteredUnits?: number;
|
|
521
|
+
pctCompleteApp?: number;
|
|
522
|
+
scoreStatus?: string;
|
|
523
|
+
inProgress?: string;
|
|
524
|
+
}
|
|
525
|
+
|
|
470
526
|
declare const items: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
471
527
|
name: "items";
|
|
472
528
|
schema: undefined;
|
|
@@ -561,7 +617,7 @@ declare const items: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
561
617
|
tableName: "items";
|
|
562
618
|
dataType: "string";
|
|
563
619
|
columnType: "PgEnumColumn";
|
|
564
|
-
data: "
|
|
620
|
+
data: "accessory" | "badge" | "collectible" | "consumable" | "currency" | "other" | "trophy" | "unlock" | "upgrade";
|
|
565
621
|
driverParam: string;
|
|
566
622
|
notNull: true;
|
|
567
623
|
hasDefault: true;
|
|
@@ -736,50 +792,11 @@ declare const inventoryItems: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
736
792
|
};
|
|
737
793
|
dialect: "pg";
|
|
738
794
|
}>;
|
|
739
|
-
type Item = typeof items.$inferSelect;
|
|
740
|
-
type InventoryItem = typeof inventoryItems.$inferSelect;
|
|
741
795
|
|
|
742
|
-
type
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
*/
|
|
747
|
-
type AuthenticatedUser = User & {
|
|
748
|
-
/** Whether the user authenticated via Timeback SSO */
|
|
749
|
-
hasTimebackAccount: boolean;
|
|
750
|
-
};
|
|
751
|
-
/**
|
|
752
|
-
* Basic user information in the shape of the claims from identity providers
|
|
753
|
-
*/
|
|
754
|
-
interface UserInfo {
|
|
755
|
-
/** Unique user identifier (sub claim from JWT) */
|
|
756
|
-
sub: string;
|
|
757
|
-
/** User's email address */
|
|
758
|
-
email: string;
|
|
759
|
-
/** User's display name */
|
|
760
|
-
name: string;
|
|
761
|
-
/** Whether the email has been verified */
|
|
762
|
-
email_verified: boolean;
|
|
763
|
-
/** Optional given name (first name) */
|
|
764
|
-
given_name?: string;
|
|
765
|
-
/** Optional family name (last name) */
|
|
766
|
-
family_name?: string;
|
|
767
|
-
/** TimeBack student ID (if user has TimeBack integration) */
|
|
768
|
-
timeback_id?: string;
|
|
769
|
-
/** Additional user attributes from the identity provider */
|
|
770
|
-
[key: string]: unknown;
|
|
771
|
-
}
|
|
772
|
-
type InventoryItemWithItem = Omit<InventoryItem, 'itemId'> & {
|
|
773
|
-
item: Item;
|
|
774
|
-
};
|
|
775
|
-
type EndActivityResponse = {
|
|
776
|
-
status: 'ok';
|
|
777
|
-
courseId: string;
|
|
778
|
-
xpAwarded: number;
|
|
779
|
-
masteredUnits?: number;
|
|
780
|
-
pctCompleteApp?: number;
|
|
781
|
-
scoreStatus?: string;
|
|
782
|
-
inProgress?: string;
|
|
796
|
+
type ItemRow = typeof items.$inferSelect;
|
|
797
|
+
type InventoryItemRow = typeof inventoryItems.$inferSelect;
|
|
798
|
+
type InventoryItemWithItem = InventoryItemRow & {
|
|
799
|
+
item: ItemRow;
|
|
783
800
|
};
|
|
784
801
|
|
|
785
802
|
/**
|
|
@@ -847,208 +864,103 @@ declare function init<T extends PlaycademyClient = PlaycademyClient>(this: new (
|
|
|
847
864
|
*/
|
|
848
865
|
declare function login(baseUrl: string, email: string, password: string): Promise<LoginResponse>;
|
|
849
866
|
|
|
850
|
-
/**
|
|
851
|
-
|
|
867
|
+
/**
|
|
868
|
+
* @fileoverview Authentication Strategy Pattern
|
|
869
|
+
*
|
|
870
|
+
* Provides different authentication strategies for the Playcademy SDK.
|
|
871
|
+
* Each strategy knows how to add its authentication headers to requests.
|
|
872
|
+
*/
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Base interface for authentication strategies
|
|
876
|
+
*/
|
|
877
|
+
interface AuthStrategy {
|
|
878
|
+
/** Get the token value */
|
|
879
|
+
getToken(): string | null;
|
|
880
|
+
/** Get the token type */
|
|
881
|
+
getType(): TokenType;
|
|
882
|
+
/** Get authentication headers for a request */
|
|
883
|
+
getHeaders(): Record<string, string>;
|
|
884
|
+
}
|
|
852
885
|
|
|
853
886
|
/**
|
|
854
|
-
*
|
|
855
|
-
* Provides
|
|
887
|
+
* Base Playcademy SDK client with shared infrastructure.
|
|
888
|
+
* Provides authentication, HTTP requests, events, connection monitoring,
|
|
889
|
+
* and fundamental namespaces used by all clients.
|
|
890
|
+
*
|
|
891
|
+
* Extended by PlaycademyClient (game SDK) and PlaycademyInternalClient (platform SDK).
|
|
856
892
|
*/
|
|
857
|
-
declare class
|
|
893
|
+
declare abstract class PlaycademyBaseClient {
|
|
858
894
|
baseUrl: string;
|
|
859
895
|
gameUrl?: string;
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
896
|
+
protected authStrategy: AuthStrategy;
|
|
897
|
+
protected gameId?: string;
|
|
898
|
+
protected config: Partial<ClientConfig>;
|
|
899
|
+
protected listeners: EventListeners;
|
|
900
|
+
protected internalClientSessionId?: string;
|
|
901
|
+
protected authContext?: {
|
|
902
|
+
isInIframe: boolean;
|
|
903
|
+
};
|
|
904
|
+
protected initPayload?: InitPayload;
|
|
905
|
+
protected connectionManager?: ConnectionManager;
|
|
868
906
|
/**
|
|
869
907
|
* Internal session manager for automatic session lifecycle.
|
|
870
|
-
*
|
|
871
|
-
* This manager handles starting and ending game sessions automatically.
|
|
872
|
-
* Game developers don't need to call these methods directly - they're managed
|
|
873
|
-
* by the SDK during initialization and cleanup.
|
|
874
|
-
*
|
|
875
908
|
* @private
|
|
876
909
|
* @internal
|
|
877
910
|
*/
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
* @param config.token - Authentication token
|
|
885
|
-
* @param config.tokenType - Optional token type (auto-detected if not provided)
|
|
886
|
-
* @param config.gameId - Game ID for automatic session management
|
|
887
|
-
* @param config.autoStartSession - Automatically start a game session?
|
|
888
|
-
*/
|
|
911
|
+
protected _sessionManager: {
|
|
912
|
+
startSession: (gameId: string) => Promise<{
|
|
913
|
+
sessionId: string;
|
|
914
|
+
}>;
|
|
915
|
+
endSession: (sessionId: string, gameId: string) => Promise<void>;
|
|
916
|
+
};
|
|
889
917
|
constructor(config?: Partial<ClientConfig>);
|
|
890
918
|
/**
|
|
891
919
|
* Gets the effective base URL for API requests.
|
|
892
|
-
* Converts relative URLs to absolute URLs in browser environments.
|
|
893
|
-
* Note: baseUrl already includes /api suffix from constructor.
|
|
894
|
-
*
|
|
895
|
-
* @returns The complete base URL for API requests (with /api suffix)
|
|
896
920
|
*/
|
|
897
921
|
getBaseUrl(): string;
|
|
898
922
|
/**
|
|
899
923
|
* Gets the effective game backend URL for integration requests.
|
|
900
|
-
* Throws if gameUrl is not configured.
|
|
901
|
-
*
|
|
902
|
-
* @returns The complete game backend URL for API requests (with /api suffix)
|
|
903
|
-
* @throws PlaycademyError if gameUrl is not set
|
|
904
924
|
*/
|
|
905
|
-
|
|
925
|
+
protected getGameBackendUrl(): string;
|
|
906
926
|
/**
|
|
907
927
|
* Simple ping method for testing connectivity.
|
|
908
|
-
*
|
|
909
|
-
* @returns 'pong' string response
|
|
910
928
|
*/
|
|
911
929
|
ping(): string;
|
|
912
930
|
/**
|
|
913
931
|
* Sets the authentication token for API requests.
|
|
914
|
-
* Emits an 'authChange' event when the token changes.
|
|
915
|
-
*
|
|
916
|
-
* @param token - The authentication token, or null to clear
|
|
917
|
-
* @param tokenType - Optional token type (auto-detected if not provided)
|
|
918
932
|
*/
|
|
919
933
|
setToken(token: string | null, tokenType?: TokenType): void;
|
|
920
934
|
/**
|
|
921
935
|
* Gets the current token type.
|
|
922
|
-
*
|
|
923
|
-
* @returns The token type
|
|
924
936
|
*/
|
|
925
937
|
getTokenType(): TokenType;
|
|
926
938
|
/**
|
|
927
939
|
* Gets the current authentication token.
|
|
928
|
-
*
|
|
929
|
-
* @returns The current token or null if not authenticated
|
|
930
|
-
*
|
|
931
|
-
* @example
|
|
932
|
-
* ```typescript
|
|
933
|
-
* // Send token to your backend for verification
|
|
934
|
-
* const token = client.getToken()
|
|
935
|
-
* const response = await fetch('/api/auth/playcademy', {
|
|
936
|
-
* method: 'POST',
|
|
937
|
-
* body: JSON.stringify({ gameToken: token })
|
|
938
|
-
* })
|
|
939
|
-
* ```
|
|
940
940
|
*/
|
|
941
941
|
getToken(): string | null;
|
|
942
942
|
/**
|
|
943
|
-
* Checks if the client has a valid API token
|
|
944
|
-
*
|
|
945
|
-
* For games (iframe context): Checks if we have a valid token from the parent.
|
|
946
|
-
* For Cademy (standalone): Checks if we have a token from better-auth.
|
|
947
|
-
*
|
|
948
|
-
* Note: This checks for API authentication, not whether a user has linked
|
|
949
|
-
* their identity via OAuth.
|
|
950
|
-
*
|
|
951
|
-
* @returns true if API token exists, false otherwise
|
|
952
|
-
*
|
|
953
|
-
* @example
|
|
954
|
-
* ```typescript
|
|
955
|
-
* if (client.isAuthenticated()) {
|
|
956
|
-
* // Can make API calls
|
|
957
|
-
* const games = await client.games.list()
|
|
958
|
-
* } else {
|
|
959
|
-
* console.error('No API token available')
|
|
960
|
-
* }
|
|
961
|
-
* ```
|
|
943
|
+
* Checks if the client has a valid API token.
|
|
962
944
|
*/
|
|
963
945
|
isAuthenticated(): boolean;
|
|
964
946
|
/**
|
|
965
947
|
* Registers a callback to be called when authentication state changes.
|
|
966
|
-
*
|
|
967
|
-
* @param callback - Function to call when auth state changes
|
|
968
948
|
*/
|
|
969
949
|
onAuthChange(callback: (token: string | null) => void): void;
|
|
970
950
|
/**
|
|
971
951
|
* Registers a callback to be called when connection issues are detected.
|
|
972
|
-
*
|
|
973
|
-
* This is a convenience method that filters connection change events to only
|
|
974
|
-
* fire when the connection degrades (offline or degraded states). Use this
|
|
975
|
-
* when you want to handle disconnects without being notified of recoveries.
|
|
976
|
-
*
|
|
977
|
-
* For all connection state changes, use `client.on('connectionChange', ...)` instead.
|
|
978
|
-
*
|
|
979
|
-
* @param callback - Function to call when connection state changes to offline or degraded
|
|
980
|
-
* @returns Cleanup function to unregister the callback
|
|
981
|
-
*
|
|
982
|
-
* @example
|
|
983
|
-
* ```typescript
|
|
984
|
-
* const cleanup = client.onDisconnect(({ state, reason, displayAlert }) => {
|
|
985
|
-
* console.log(`Connection ${state}: ${reason}`)
|
|
986
|
-
*
|
|
987
|
-
* if (state === 'offline') {
|
|
988
|
-
* // Save state and return to game lobby
|
|
989
|
-
* displayAlert?.('Connection lost. Your progress has been saved.', { type: 'error' })
|
|
990
|
-
* saveGameState()
|
|
991
|
-
* returnToLobby()
|
|
992
|
-
* } else if (state === 'degraded') {
|
|
993
|
-
* displayAlert?.('Slow connection detected.', { type: 'warning' })
|
|
994
|
-
* }
|
|
995
|
-
* })
|
|
996
|
-
*
|
|
997
|
-
* // Later: cleanup() to unregister
|
|
998
|
-
* ```
|
|
999
|
-
*
|
|
1000
|
-
* @see Connection monitoring documentation in SDK Browser docs for detailed usage examples
|
|
1001
|
-
* @see {@link ConnectionManager.onDisconnect} for the underlying implementation
|
|
1002
952
|
*/
|
|
1003
953
|
onDisconnect(callback: (context: DisconnectContext) => void | Promise<void>): () => void;
|
|
1004
954
|
/**
|
|
1005
955
|
* Gets the current connection state.
|
|
1006
|
-
*
|
|
1007
|
-
* Returns the last known connection state without triggering a new check.
|
|
1008
|
-
* Use `checkConnection()` to force an immediate verification.
|
|
1009
|
-
*
|
|
1010
|
-
* @returns Current connection state ('online', 'offline', 'degraded') or 'unknown' if monitoring is disabled
|
|
1011
|
-
*
|
|
1012
|
-
* @example
|
|
1013
|
-
* ```typescript
|
|
1014
|
-
* const state = client.getConnectionState()
|
|
1015
|
-
* if (state === 'offline') {
|
|
1016
|
-
* console.log('No connection available')
|
|
1017
|
-
* }
|
|
1018
|
-
* ```
|
|
1019
|
-
*
|
|
1020
|
-
* @see {@link checkConnection} to trigger an immediate connection check
|
|
1021
|
-
* @see {@link ConnectionManager.getState} for the underlying implementation
|
|
1022
956
|
*/
|
|
1023
957
|
getConnectionState(): ConnectionState | 'unknown';
|
|
1024
958
|
/**
|
|
1025
959
|
* Manually triggers a connection check immediately.
|
|
1026
|
-
*
|
|
1027
|
-
* Forces a heartbeat ping to verify connectivity right now, bypassing the normal
|
|
1028
|
-
* interval. Useful when you need to verify connection status before a critical
|
|
1029
|
-
* operation (e.g., saving important game state).
|
|
1030
|
-
*
|
|
1031
|
-
* @returns Promise resolving to the current connection state after verification
|
|
1032
|
-
*
|
|
1033
|
-
* @example
|
|
1034
|
-
* ```typescript
|
|
1035
|
-
* // Check before critical operation
|
|
1036
|
-
* const state = await client.checkConnection()
|
|
1037
|
-
* if (state !== 'online') {
|
|
1038
|
-
* alert('Please check your internet connection before saving')
|
|
1039
|
-
* return
|
|
1040
|
-
* }
|
|
1041
|
-
*
|
|
1042
|
-
* await client.games.saveState(importantData)
|
|
1043
|
-
* ```
|
|
1044
|
-
*
|
|
1045
|
-
* @see {@link getConnectionState} to get the last known state without checking
|
|
1046
|
-
* @see {@link ConnectionManager.checkNow} for the underlying implementation
|
|
1047
960
|
*/
|
|
1048
961
|
checkConnection(): Promise<ConnectionState | 'unknown'>;
|
|
1049
962
|
/**
|
|
1050
963
|
* Sets the authentication context for the client.
|
|
1051
|
-
* This is called during initialization to store environment info.
|
|
1052
964
|
* @internal
|
|
1053
965
|
*/
|
|
1054
966
|
_setAuthContext(context: {
|
|
@@ -1056,28 +968,14 @@ declare class PlaycademyClient {
|
|
|
1056
968
|
}): void;
|
|
1057
969
|
/**
|
|
1058
970
|
* Registers an event listener for client events.
|
|
1059
|
-
*
|
|
1060
|
-
* @param event - The event type to listen for
|
|
1061
|
-
* @param callback - Function to call when the event is emitted
|
|
1062
971
|
*/
|
|
1063
972
|
on<E extends keyof ClientEvents>(event: E, callback: (payload: ClientEvents[E]) => void): void;
|
|
1064
973
|
/**
|
|
1065
974
|
* Emits an event to all registered listeners.
|
|
1066
|
-
*
|
|
1067
|
-
* @param event - The event type to emit
|
|
1068
|
-
* @param payload - The event payload
|
|
1069
975
|
*/
|
|
1070
|
-
|
|
976
|
+
protected emit<E extends keyof ClientEvents>(event: E, payload: ClientEvents[E]): void;
|
|
1071
977
|
/**
|
|
1072
978
|
* Makes an authenticated HTTP request to the platform API.
|
|
1073
|
-
*
|
|
1074
|
-
* @param path - API endpoint path
|
|
1075
|
-
* @param method - HTTP method
|
|
1076
|
-
* @param options - Optional request configuration
|
|
1077
|
-
* @param options.body - Request body
|
|
1078
|
-
* @param options.headers - Additional headers
|
|
1079
|
-
* @param options.raw - If true, returns raw Response instead of parsing
|
|
1080
|
-
* @returns Promise resolving to the response data or raw Response
|
|
1081
979
|
*/
|
|
1082
980
|
protected request<T>(path: string, method: Method, options?: {
|
|
1083
981
|
body?: unknown;
|
|
@@ -1086,53 +984,65 @@ declare class PlaycademyClient {
|
|
|
1086
984
|
}): Promise<T>;
|
|
1087
985
|
/**
|
|
1088
986
|
* Makes an authenticated HTTP request to the game's backend Worker.
|
|
1089
|
-
* Uses gameUrl if set, otherwise falls back to platform API.
|
|
1090
|
-
*
|
|
1091
|
-
* @param path - API endpoint path
|
|
1092
|
-
* @param method - HTTP method
|
|
1093
|
-
* @param body - Request body (optional)
|
|
1094
|
-
* @param headers - Additional headers (optional)
|
|
1095
|
-
* @param raw - If true, returns raw Response instead of parsing (optional)
|
|
1096
|
-
* @returns Promise resolving to the response data or raw Response
|
|
1097
987
|
*/
|
|
1098
988
|
protected requestGameBackend<T>(path: string, method: Method, body?: unknown, headers?: Record<string, string>, raw?: boolean): Promise<T>;
|
|
1099
989
|
/**
|
|
1100
990
|
* Ensures a gameId is available, throwing an error if not.
|
|
1101
|
-
*
|
|
1102
|
-
* @returns The gameId
|
|
1103
|
-
* @throws PlaycademyError if no gameId is configured
|
|
1104
991
|
*/
|
|
1105
|
-
|
|
992
|
+
protected _ensureGameId(): string;
|
|
1106
993
|
/**
|
|
1107
994
|
* Detects and sets the authentication context (iframe vs standalone).
|
|
1108
|
-
* Safe to call in any environment - isInIframe handles browser detection.
|
|
1109
995
|
*/
|
|
1110
996
|
private _detectAuthContext;
|
|
1111
997
|
/**
|
|
1112
998
|
* Initializes connection monitoring if enabled.
|
|
1113
|
-
* Safe to call in any environment - only runs in browser.
|
|
1114
999
|
*/
|
|
1115
1000
|
private _initializeConnectionMonitor;
|
|
1001
|
+
private _initializeInternalSession;
|
|
1116
1002
|
/**
|
|
1117
|
-
*
|
|
1118
|
-
*
|
|
1119
|
-
*
|
|
1120
|
-
*
|
|
1121
|
-
|
|
1003
|
+
* Current user data and inventory management.
|
|
1004
|
+
* - `me()` - Get authenticated user profile
|
|
1005
|
+
* - `inventory.get()` - List user's items
|
|
1006
|
+
* - `inventory.add(slug, qty)` - Award items to user
|
|
1007
|
+
*/
|
|
1008
|
+
users: {
|
|
1009
|
+
me: () => Promise<AuthenticatedUser>;
|
|
1010
|
+
inventory: {
|
|
1011
|
+
get: () => Promise<InventoryItemWithItem[]>;
|
|
1012
|
+
add: (identifier: string, qty: number) => Promise<InventoryMutationResponse>;
|
|
1013
|
+
remove: (identifier: string, qty: number) => Promise<InventoryMutationResponse>;
|
|
1014
|
+
quantity: (identifier: string) => Promise<number>;
|
|
1015
|
+
has: (identifier: string, minQuantity?: number) => Promise<boolean>;
|
|
1016
|
+
};
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Playcademy SDK client for game developers.
|
|
1022
|
+
* Provides namespaced access to platform features for games running inside Cademy.
|
|
1023
|
+
*/
|
|
1024
|
+
declare class PlaycademyClient extends PlaycademyBaseClient {
|
|
1025
|
+
/**
|
|
1026
|
+
* Connect external identity providers to the user's Playcademy account.
|
|
1027
|
+
* - `connect(provider)` - Link Discord, Google, etc. via OAuth popup
|
|
1122
1028
|
*/
|
|
1123
|
-
private _initializeInternalSession;
|
|
1124
|
-
/** Identity provider connection methods (connect external accounts) */
|
|
1125
1029
|
identity: {
|
|
1126
1030
|
connect: (options: AuthOptions) => Promise<AuthResult>;
|
|
1127
1031
|
_getContext: () => {
|
|
1128
1032
|
isInIframe: boolean;
|
|
1129
1033
|
};
|
|
1130
1034
|
};
|
|
1131
|
-
/**
|
|
1035
|
+
/**
|
|
1036
|
+
* Game runtime lifecycle and asset loading.
|
|
1037
|
+
* - `exit()` - Return to Cademy hub
|
|
1038
|
+
* - `getGameToken()` - Get short-lived auth token
|
|
1039
|
+
* - `assets.url()`, `assets.json()`, `assets.fetch()` - Load game assets
|
|
1040
|
+
* - `on('pause')`, `on('resume')` - Handle visibility changes
|
|
1041
|
+
*/
|
|
1132
1042
|
runtime: {
|
|
1133
1043
|
getGameToken: (gameId: string, options?: {
|
|
1134
|
-
apply?: boolean;
|
|
1135
|
-
}) => Promise<GameTokenResponse>;
|
|
1044
|
+
apply?: boolean | undefined;
|
|
1045
|
+
} | undefined) => Promise<GameTokenResponse>;
|
|
1136
1046
|
exit: () => Promise<void>;
|
|
1137
1047
|
onInit: (handler: (context: GameContextPayload) => void) => void;
|
|
1138
1048
|
onTokenRefresh: (handler: (data: {
|
|
@@ -1156,57 +1066,73 @@ declare class PlaycademyClient {
|
|
|
1156
1066
|
getListenerCounts: () => Record<string, number>;
|
|
1157
1067
|
assets: {
|
|
1158
1068
|
url(pathOrStrings: string | TemplateStringsArray, ...values: unknown[]): string;
|
|
1159
|
-
fetch: (path: string, options?: RequestInit) => Promise<Response>;
|
|
1069
|
+
fetch: (path: string, options?: RequestInit | undefined) => Promise<Response>;
|
|
1160
1070
|
json: <T = unknown>(path: string) => Promise<T>;
|
|
1161
1071
|
blob: (path: string) => Promise<Blob>;
|
|
1162
1072
|
text: (path: string) => Promise<string>;
|
|
1163
1073
|
arrayBuffer: (path: string) => Promise<ArrayBuffer>;
|
|
1164
1074
|
};
|
|
1165
1075
|
};
|
|
1166
|
-
/**
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1076
|
+
/**
|
|
1077
|
+
* TimeBack integration for activity tracking and user context.
|
|
1078
|
+
*
|
|
1079
|
+
* User context (cached from init, refreshable):
|
|
1080
|
+
* - `user.role` - User's role (student, parent, teacher, etc.)
|
|
1081
|
+
* - `user.enrollments` - Courses the player is enrolled in for this game
|
|
1082
|
+
* - `user.organizations` - Schools/districts the player belongs to
|
|
1083
|
+
* - `user.fetch()` - Refresh user context from server
|
|
1084
|
+
*
|
|
1085
|
+
* Activity tracking:
|
|
1086
|
+
* - `startActivity(metadata)` - Begin tracking an activity
|
|
1087
|
+
* - `pauseActivity()` / `resumeActivity()` - Pause/resume timer
|
|
1088
|
+
* - `endActivity(scoreData)` - Submit activity results to TimeBack
|
|
1089
|
+
*/
|
|
1178
1090
|
timeback: {
|
|
1179
|
-
|
|
1091
|
+
readonly user: TimebackUser;
|
|
1092
|
+
startActivity: (metadata: ActivityData) => void;
|
|
1180
1093
|
pauseActivity: () => void;
|
|
1181
1094
|
resumeActivity: () => void;
|
|
1182
|
-
endActivity: (data:
|
|
1095
|
+
endActivity: (data: EndActivityScoreData) => Promise<EndActivityResponse>;
|
|
1183
1096
|
};
|
|
1184
|
-
/**
|
|
1097
|
+
/**
|
|
1098
|
+
* Playcademy Credits (platform currency) management.
|
|
1099
|
+
* - `get()` - Get user's credit balance
|
|
1100
|
+
* - `add(amount)` - Award credits to user
|
|
1101
|
+
*/
|
|
1185
1102
|
credits: {
|
|
1186
1103
|
balance: () => Promise<number>;
|
|
1187
1104
|
add: (amount: number) => Promise<number>;
|
|
1188
1105
|
spend: (amount: number) => Promise<number>;
|
|
1189
1106
|
};
|
|
1190
|
-
/**
|
|
1107
|
+
/**
|
|
1108
|
+
* Game score submission and leaderboards.
|
|
1109
|
+
* - `submit(gameId, score, metadata?)` - Record a game score
|
|
1110
|
+
*/
|
|
1191
1111
|
scores: {
|
|
1192
|
-
submit: (gameId: string, score: number, metadata?: Record<string, unknown>) => Promise<ScoreSubmission>;
|
|
1112
|
+
submit: (gameId: string, score: number, metadata?: Record<string, unknown> | undefined) => Promise<ScoreSubmission>;
|
|
1193
1113
|
};
|
|
1194
|
-
/**
|
|
1114
|
+
/**
|
|
1115
|
+
* Realtime multiplayer authentication.
|
|
1116
|
+
* - `getToken()` - Get token for WebSocket/realtime connections
|
|
1117
|
+
*/
|
|
1195
1118
|
realtime: {
|
|
1196
1119
|
token: {
|
|
1197
1120
|
get: () => Promise<RealtimeTokenResponse>;
|
|
1198
1121
|
};
|
|
1199
|
-
open(channel?: string, url?: string): Promise<_playcademy_realtime_server_types.RealtimeChannel>;
|
|
1200
1122
|
};
|
|
1201
|
-
/**
|
|
1123
|
+
/**
|
|
1124
|
+
* Make requests to your game's custom backend API routes.
|
|
1125
|
+
* - `get(path)`, `post(path, body)`, `put()`, `delete()` - HTTP methods
|
|
1126
|
+
* - Routes are relative to your game's deployment (e.g., '/hello' → your-game.playcademy.gg/api/hello)
|
|
1127
|
+
*/
|
|
1202
1128
|
backend: {
|
|
1203
|
-
get<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
|
|
1204
|
-
post<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
1205
|
-
put<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
1206
|
-
patch<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
1207
|
-
delete<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
|
|
1208
|
-
request<T = unknown>(path: string, method: Method, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
1209
|
-
download(path: string, method?: Method, body?: unknown, headers?: Record<string, string>): Promise<Response>;
|
|
1129
|
+
get<T = unknown>(path: string, headers?: Record<string, string> | undefined): Promise<T>;
|
|
1130
|
+
post<T = unknown>(path: string, body?: unknown, headers?: Record<string, string> | undefined): Promise<T>;
|
|
1131
|
+
put<T = unknown>(path: string, body?: unknown, headers?: Record<string, string> | undefined): Promise<T>;
|
|
1132
|
+
patch<T = unknown>(path: string, body?: unknown, headers?: Record<string, string> | undefined): Promise<T>;
|
|
1133
|
+
delete<T = unknown>(path: string, headers?: Record<string, string> | undefined): Promise<T>;
|
|
1134
|
+
request<T = unknown>(path: string, method: Method, body?: unknown, headers?: Record<string, string> | undefined): Promise<T>;
|
|
1135
|
+
download(path: string, method?: Method, body?: unknown, headers?: Record<string, string> | undefined): Promise<Response>;
|
|
1210
1136
|
url(pathOrStrings: string | TemplateStringsArray, ...values: unknown[]): string;
|
|
1211
1137
|
};
|
|
1212
1138
|
/** Auto-initializes a PlaycademyClient with context from the environment */
|
|
@@ -1219,9 +1145,70 @@ declare class PlaycademyClient {
|
|
|
1219
1145
|
};
|
|
1220
1146
|
}
|
|
1221
1147
|
|
|
1148
|
+
/**
|
|
1149
|
+
* Type definitions for the game timeback namespace.
|
|
1150
|
+
*
|
|
1151
|
+
* SDK-specific types like TimebackInitContext that wrap the core types
|
|
1152
|
+
* from @playcademy/types/user (which are re-exported via types/data.ts).
|
|
1153
|
+
*/
|
|
1154
|
+
|
|
1155
|
+
/**
|
|
1156
|
+
* A TimeBack enrollment for the current game session.
|
|
1157
|
+
* Alias for UserEnrollment without the optional gameId.
|
|
1158
|
+
*/
|
|
1159
|
+
type TimebackEnrollment = Omit<UserEnrollment, 'gameId'>;
|
|
1160
|
+
/**
|
|
1161
|
+
* A TimeBack organization (school/district) for the current user.
|
|
1162
|
+
* Alias for UserOrganization.
|
|
1163
|
+
*/
|
|
1164
|
+
type TimebackOrganization = UserOrganization;
|
|
1165
|
+
/**
|
|
1166
|
+
* TimeBack context passed during game initialization.
|
|
1167
|
+
* This is sent from the platform (cademy) to the game iframe via postMessage.
|
|
1168
|
+
*/
|
|
1169
|
+
interface TimebackInitContext {
|
|
1170
|
+
/** User's TimeBack ID */
|
|
1171
|
+
id: string;
|
|
1172
|
+
/** User's role in TimeBack (student, parent, teacher, etc.) */
|
|
1173
|
+
role: TimebackUserRole;
|
|
1174
|
+
/** User's enrollments for this game (one per grade/subject combo) */
|
|
1175
|
+
enrollments: TimebackEnrollment[];
|
|
1176
|
+
/** User's organizations (schools/districts) */
|
|
1177
|
+
organizations: TimebackOrganization[];
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* TimeBack user context with current data (may be stale from init).
|
|
1181
|
+
* Use `fetch()` to get fresh data from the server.
|
|
1182
|
+
*/
|
|
1183
|
+
interface TimebackUserContext {
|
|
1184
|
+
/** User's TimeBack ID */
|
|
1185
|
+
id: string | undefined;
|
|
1186
|
+
/** User's role in TimeBack (student, parent, teacher, etc.) */
|
|
1187
|
+
role: TimebackUserRole | undefined;
|
|
1188
|
+
/** User's enrollments for this game */
|
|
1189
|
+
enrollments: TimebackEnrollment[];
|
|
1190
|
+
/** User's organizations (schools/districts) */
|
|
1191
|
+
organizations: TimebackOrganization[];
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* TimeBack user object with both cached getters and fetch method.
|
|
1195
|
+
*/
|
|
1196
|
+
interface TimebackUser extends TimebackUserContext {
|
|
1197
|
+
/**
|
|
1198
|
+
* Fetch TimeBack data from the server (cached for 5 min).
|
|
1199
|
+
* Updates the cached values so subsequent property access returns fresh data.
|
|
1200
|
+
* @param options - Cache options (pass { force: true } to bypass cache)
|
|
1201
|
+
* @returns Promise resolving to fresh user context
|
|
1202
|
+
*/
|
|
1203
|
+
fetch(options?: {
|
|
1204
|
+
force?: boolean;
|
|
1205
|
+
}): Promise<TimebackUserContext>;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1222
1208
|
/**
|
|
1223
1209
|
* Core client configuration and lifecycle types
|
|
1224
1210
|
*/
|
|
1211
|
+
|
|
1225
1212
|
type TokenType = 'session' | 'apiKey' | 'gameJwt';
|
|
1226
1213
|
interface ClientConfig {
|
|
1227
1214
|
baseUrl: string;
|
|
@@ -1254,6 +1241,20 @@ interface DisconnectContext {
|
|
|
1254
1241
|
duration?: number;
|
|
1255
1242
|
}) => void;
|
|
1256
1243
|
}
|
|
1244
|
+
interface InitPayload {
|
|
1245
|
+
/** Hub API base URL */
|
|
1246
|
+
baseUrl: string;
|
|
1247
|
+
/** Game deployment URL (serves both frontend assets and backend API) */
|
|
1248
|
+
gameUrl?: string;
|
|
1249
|
+
/** Short-lived game token */
|
|
1250
|
+
token: string;
|
|
1251
|
+
/** Game ID */
|
|
1252
|
+
gameId: string;
|
|
1253
|
+
/** Realtime WebSocket URL */
|
|
1254
|
+
realtimeUrl?: string;
|
|
1255
|
+
/** Timeback context (if user has a Timeback account) */
|
|
1256
|
+
timeback?: TimebackInitContext;
|
|
1257
|
+
}
|
|
1257
1258
|
type GameContextPayload = {
|
|
1258
1259
|
token: string;
|
|
1259
1260
|
baseUrl: string;
|
|
@@ -1261,6 +1262,9 @@ type GameContextPayload = {
|
|
|
1261
1262
|
gameId: string;
|
|
1262
1263
|
forwardKeys?: string[];
|
|
1263
1264
|
};
|
|
1265
|
+
type EventListeners = {
|
|
1266
|
+
[E in keyof ClientEvents]?: Array<(payload: ClientEvents[E]) => void>;
|
|
1267
|
+
};
|
|
1264
1268
|
interface ClientEvents {
|
|
1265
1269
|
authChange: {
|
|
1266
1270
|
token: string | null;
|
|
@@ -1456,6 +1460,8 @@ type DevUploadEvent = {
|
|
|
1456
1460
|
} | {
|
|
1457
1461
|
type: 'finalizeStatus';
|
|
1458
1462
|
message: string;
|
|
1463
|
+
} | {
|
|
1464
|
+
type: 'complete';
|
|
1459
1465
|
} | {
|
|
1460
1466
|
type: 'close';
|
|
1461
1467
|
};
|
|
@@ -2203,4 +2209,4 @@ declare class PlaycademyMessaging {
|
|
|
2203
2209
|
declare const messaging: PlaycademyMessaging;
|
|
2204
2210
|
|
|
2205
2211
|
export { ApiError, ConnectionManager, ConnectionMonitor, MessageEvents, PlaycademyClient, PlaycademyError, extractApiErrorInfo, messaging };
|
|
2206
|
-
export type { ApiErrorInfo, ConnectionMonitorConfig, ConnectionState, ConnectionStatePayload, DevUploadEvent, DevUploadHooks, DisconnectContext, DisconnectHandler, DisplayAlertPayload };
|
|
2212
|
+
export type { ApiErrorCode, ApiErrorInfo, ConnectionMonitorConfig, ConnectionState, ConnectionStatePayload, DevUploadEvent, DevUploadHooks, DisconnectContext, DisconnectHandler, DisplayAlertPayload, ErrorResponseBody };
|