playcademy 0.1.0
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 +293 -0
- package/dist/index.js +34332 -0
- package/dist/templates/backend-config.js.template +6 -0
- package/dist/templates/integrations-config.js.template +7 -0
- package/dist/templates/playcademy.config.js.template +4 -0
- package/dist/templates/playcademy.config.json.template +3 -0
- package/dist/templates/sample-route.ts +38 -0
- package/dist/templates/timeback-config.js.template +17 -0
- package/dist/types.d.ts +628 -0
- package/package.json +48 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sample API route
|
|
3
|
+
*
|
|
4
|
+
* This route will be available at: https://<your-game-slug>.playcademy.gg/api/hello
|
|
5
|
+
*/
|
|
6
|
+
import type { Context } from 'hono'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* GET /api/hello
|
|
10
|
+
*/
|
|
11
|
+
export async function GET(c: Context): Promise<Response> {
|
|
12
|
+
return c.json({
|
|
13
|
+
message: 'Hello from your game backend!',
|
|
14
|
+
timestamp: new Date().toISOString(),
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* POST /api/hello
|
|
20
|
+
*/
|
|
21
|
+
export async function POST(c: Context): Promise<Response> {
|
|
22
|
+
const body = await c.req.json()
|
|
23
|
+
|
|
24
|
+
return c.json({
|
|
25
|
+
message: 'Received your data!',
|
|
26
|
+
received: body,
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Environment variables available via c.env:
|
|
32
|
+
* - c.env.PLAYCADEMY_API_KEY - Game-scoped API key for calling Playcademy APIs
|
|
33
|
+
* - c.env.GAME_ID - Your game's unique ID
|
|
34
|
+
* - c.env.PLAYCADEMY_BASE_URL - Playcademy platform URL
|
|
35
|
+
*
|
|
36
|
+
* Access the SDK client:
|
|
37
|
+
* - const sdk = c.get('sdk') - Pre-initialized PlaycademyClient
|
|
38
|
+
*/
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// TimeBack integration configuration
|
|
2
|
+
// See https://docs.playcademy.com/timeback for more details
|
|
3
|
+
timeback: {
|
|
4
|
+
// Optional: customize organization
|
|
5
|
+
// organization: {
|
|
6
|
+
// name: 'My School',
|
|
7
|
+
// type: 'school',
|
|
8
|
+
// },
|
|
9
|
+
course: {
|
|
10
|
+
subjects: {{SUBJECTS}},
|
|
11
|
+
grades: {{GRADES}},
|
|
12
|
+
// Optional: customize course details
|
|
13
|
+
// title: 'Custom Course Title',
|
|
14
|
+
// courseCode: 'COURSE-101',
|
|
15
|
+
// level: 'Elementary',
|
|
16
|
+
},
|
|
17
|
+
},
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
import { UserInfo, ApiKey, BackendDeploymentResponse } from '@playcademy/data/types';
|
|
2
|
+
import { OrganizationConfig, CourseConfig, ComponentConfig, ResourceConfig, ComponentResourceConfig } from '@playcademy/timeback/types';
|
|
3
|
+
export { ComponentConfig, ComponentResourceConfig, CourseConfig, DerivedComponentConfig, DerivedComponentResourceConfig, DerivedCourseConfig, DerivedOrganizationConfig, DerivedResourceConfig, DerivedTimebackConfig, OrganizationConfig, ResourceConfig, TimebackGrade, TimebackSourcedIds, TimebackSubject } from '@playcademy/timeback/types';
|
|
4
|
+
import { PlaycademyClient } from '@playcademy/sdk';
|
|
5
|
+
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Type of authentication token
|
|
9
|
+
* Duplicated from SDK to avoid circular dependency
|
|
10
|
+
*/
|
|
11
|
+
type TokenType = 'session' | 'apiKey' | 'gameJwt';
|
|
12
|
+
/**
|
|
13
|
+
* Authentication profile stored for a user
|
|
14
|
+
* CLI-specific type for managing stored credentials
|
|
15
|
+
*/
|
|
16
|
+
interface AuthProfile {
|
|
17
|
+
token: string;
|
|
18
|
+
/** Type of token to determine how to use it in API calls */
|
|
19
|
+
tokenType: TokenType;
|
|
20
|
+
/** User ID associated with the token (may not be present for API keys) */
|
|
21
|
+
userId?: string;
|
|
22
|
+
email?: string;
|
|
23
|
+
/** ISO 8601 date string - when the token expires (if applicable) */
|
|
24
|
+
expiresAt?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The complete auth store structure
|
|
28
|
+
* CLI-specific type for ~/.playcademy/auth.json
|
|
29
|
+
*/
|
|
30
|
+
interface AuthStore {
|
|
31
|
+
/** Default authentication profile used when no profile is specified */
|
|
32
|
+
default: AuthProfile | null;
|
|
33
|
+
/** Named authentication profiles for different environments/contexts */
|
|
34
|
+
profiles: Record<string, AuthProfile>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Login credentials for email/password authentication
|
|
38
|
+
*/
|
|
39
|
+
interface LoginCredentials {
|
|
40
|
+
email: string;
|
|
41
|
+
password: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Login response from email/password authentication
|
|
45
|
+
*/
|
|
46
|
+
interface LoginResponse {
|
|
47
|
+
/** Session token received from login */
|
|
48
|
+
token: string;
|
|
49
|
+
/** Always 'session' for email/password login */
|
|
50
|
+
tokenType: 'session';
|
|
51
|
+
/** User information associated with the token */
|
|
52
|
+
user: UserInfo;
|
|
53
|
+
/** ISO 8601 date string - when the session expires */
|
|
54
|
+
expiresAt: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* API key creation response
|
|
58
|
+
* Extends ApiKey with the actual key on creation
|
|
59
|
+
*/
|
|
60
|
+
interface ApiKeyWithSecret extends ApiKey {
|
|
61
|
+
/** The actual API key - only present when creating a new key */
|
|
62
|
+
apiKey: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* API configuration derived from environment
|
|
67
|
+
*/
|
|
68
|
+
interface ApiConfig {
|
|
69
|
+
/** Base URL for API requests (e.g., https://hub.playcademy.com) */
|
|
70
|
+
baseUrl: string;
|
|
71
|
+
/** Current environment being targeted */
|
|
72
|
+
environment: 'staging' | 'production';
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Options for API requests
|
|
76
|
+
*/
|
|
77
|
+
interface ApiRequestOptions {
|
|
78
|
+
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
79
|
+
/** Request body data - will be JSON stringified */
|
|
80
|
+
body?: unknown;
|
|
81
|
+
/** Additional headers to include in the request */
|
|
82
|
+
headers?: Record<string, string>;
|
|
83
|
+
/** Auth profile to use for this request (defaults to 'default') */
|
|
84
|
+
profile?: string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Standard API error response
|
|
88
|
+
*/
|
|
89
|
+
interface ApiErrorResponse {
|
|
90
|
+
/** Error code/type for programmatic handling */
|
|
91
|
+
error: string;
|
|
92
|
+
/** Human-readable error message */
|
|
93
|
+
message: string;
|
|
94
|
+
statusCode: number;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Better-auth sign-in response
|
|
98
|
+
*/
|
|
99
|
+
interface SignInResponse {
|
|
100
|
+
/** Session token */
|
|
101
|
+
token: string;
|
|
102
|
+
/** User information */
|
|
103
|
+
user: {
|
|
104
|
+
id: string;
|
|
105
|
+
email: string;
|
|
106
|
+
};
|
|
107
|
+
/** ISO 8601 date string - when the session expires */
|
|
108
|
+
expiresAt: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Better-auth API key creation response
|
|
112
|
+
*/
|
|
113
|
+
interface CreateApiKeyResponse {
|
|
114
|
+
/** The actual API key - only shown once */
|
|
115
|
+
apiKey: string;
|
|
116
|
+
/** Key metadata */
|
|
117
|
+
key: {
|
|
118
|
+
id: string;
|
|
119
|
+
name: string | null;
|
|
120
|
+
expiresAt: string | null;
|
|
121
|
+
createdAt: string;
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Better-auth API key list item
|
|
126
|
+
*/
|
|
127
|
+
interface ApiKeyListItem {
|
|
128
|
+
id: string;
|
|
129
|
+
name: string | null;
|
|
130
|
+
start: string;
|
|
131
|
+
enabled: boolean;
|
|
132
|
+
expiresAt: string | null;
|
|
133
|
+
createdAt: string;
|
|
134
|
+
updatedAt: string;
|
|
135
|
+
lastRequest: string | null;
|
|
136
|
+
requestCount: number;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @fileoverview Server SDK Type Definitions
|
|
141
|
+
*
|
|
142
|
+
* TypeScript type definitions for the server-side Playcademy SDK.
|
|
143
|
+
* Includes configuration types, client state, and re-exported TimeBack types.
|
|
144
|
+
*/
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* TimeBack integration configuration for Playcademy config file
|
|
148
|
+
*/
|
|
149
|
+
interface TimebackIntegrationConfig {
|
|
150
|
+
/** Organization overrides */
|
|
151
|
+
organization?: Partial<OrganizationConfig>;
|
|
152
|
+
/** Course configuration (subjects and grades REQUIRED) */
|
|
153
|
+
course: CourseConfig;
|
|
154
|
+
/** Component overrides */
|
|
155
|
+
component?: Partial<ComponentConfig>;
|
|
156
|
+
/** Resource overrides */
|
|
157
|
+
resource?: Partial<ResourceConfig>;
|
|
158
|
+
/** Component-Resource link overrides */
|
|
159
|
+
componentResource?: Partial<ComponentResourceConfig>;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Integrations configuration
|
|
163
|
+
*/
|
|
164
|
+
interface IntegrationsConfig {
|
|
165
|
+
/** TimeBack integration (optional) */
|
|
166
|
+
timeback?: TimebackIntegrationConfig;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Unified Playcademy configuration
|
|
170
|
+
* Used for playcademy.config.{js,json}
|
|
171
|
+
*/
|
|
172
|
+
interface PlaycademyConfig {
|
|
173
|
+
/** Game name */
|
|
174
|
+
name: string;
|
|
175
|
+
/** Game description */
|
|
176
|
+
description?: string;
|
|
177
|
+
/** Game emoji icon */
|
|
178
|
+
emoji?: string;
|
|
179
|
+
/** Build command to run before deployment */
|
|
180
|
+
buildCommand?: string[];
|
|
181
|
+
/** Path to build output */
|
|
182
|
+
buildPath?: string;
|
|
183
|
+
/** Game type */
|
|
184
|
+
gameType?: 'hosted' | 'external';
|
|
185
|
+
/** External URL (for external games) */
|
|
186
|
+
externalUrl?: string;
|
|
187
|
+
/** Game platform */
|
|
188
|
+
platform?: 'web' | 'unity' | 'godot';
|
|
189
|
+
/** Backend configuration */
|
|
190
|
+
backend?: {
|
|
191
|
+
/** Custom API routes directory (defaults to 'api') */
|
|
192
|
+
directory?: string;
|
|
193
|
+
};
|
|
194
|
+
/** External integrations */
|
|
195
|
+
integrations?: IntegrationsConfig;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
type GameMetadata = {
|
|
199
|
+
description?: string;
|
|
200
|
+
emoji?: string;
|
|
201
|
+
[key: string]: unknown;
|
|
202
|
+
};
|
|
203
|
+
declare const games: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
204
|
+
name: "games";
|
|
205
|
+
schema: undefined;
|
|
206
|
+
columns: {
|
|
207
|
+
id: drizzle_orm_pg_core.PgColumn<{
|
|
208
|
+
name: "id";
|
|
209
|
+
tableName: "games";
|
|
210
|
+
dataType: "string";
|
|
211
|
+
columnType: "PgUUID";
|
|
212
|
+
data: string;
|
|
213
|
+
driverParam: string;
|
|
214
|
+
notNull: true;
|
|
215
|
+
hasDefault: true;
|
|
216
|
+
isPrimaryKey: true;
|
|
217
|
+
isAutoincrement: false;
|
|
218
|
+
hasRuntimeDefault: false;
|
|
219
|
+
enumValues: undefined;
|
|
220
|
+
baseColumn: never;
|
|
221
|
+
identity: undefined;
|
|
222
|
+
generated: undefined;
|
|
223
|
+
}, {}, {}>;
|
|
224
|
+
developerId: drizzle_orm_pg_core.PgColumn<{
|
|
225
|
+
name: "developer_id";
|
|
226
|
+
tableName: "games";
|
|
227
|
+
dataType: "string";
|
|
228
|
+
columnType: "PgText";
|
|
229
|
+
data: string;
|
|
230
|
+
driverParam: string;
|
|
231
|
+
notNull: false;
|
|
232
|
+
hasDefault: false;
|
|
233
|
+
isPrimaryKey: false;
|
|
234
|
+
isAutoincrement: false;
|
|
235
|
+
hasRuntimeDefault: false;
|
|
236
|
+
enumValues: [string, ...string[]];
|
|
237
|
+
baseColumn: never;
|
|
238
|
+
identity: undefined;
|
|
239
|
+
generated: undefined;
|
|
240
|
+
}, {}, {}>;
|
|
241
|
+
slug: drizzle_orm_pg_core.PgColumn<{
|
|
242
|
+
name: "slug";
|
|
243
|
+
tableName: "games";
|
|
244
|
+
dataType: "string";
|
|
245
|
+
columnType: "PgVarchar";
|
|
246
|
+
data: string;
|
|
247
|
+
driverParam: string;
|
|
248
|
+
notNull: true;
|
|
249
|
+
hasDefault: false;
|
|
250
|
+
isPrimaryKey: false;
|
|
251
|
+
isAutoincrement: false;
|
|
252
|
+
hasRuntimeDefault: false;
|
|
253
|
+
enumValues: [string, ...string[]];
|
|
254
|
+
baseColumn: never;
|
|
255
|
+
identity: undefined;
|
|
256
|
+
generated: undefined;
|
|
257
|
+
}, {}, {
|
|
258
|
+
length: 255;
|
|
259
|
+
}>;
|
|
260
|
+
displayName: drizzle_orm_pg_core.PgColumn<{
|
|
261
|
+
name: "display_name";
|
|
262
|
+
tableName: "games";
|
|
263
|
+
dataType: "string";
|
|
264
|
+
columnType: "PgVarchar";
|
|
265
|
+
data: string;
|
|
266
|
+
driverParam: string;
|
|
267
|
+
notNull: true;
|
|
268
|
+
hasDefault: false;
|
|
269
|
+
isPrimaryKey: false;
|
|
270
|
+
isAutoincrement: false;
|
|
271
|
+
hasRuntimeDefault: false;
|
|
272
|
+
enumValues: [string, ...string[]];
|
|
273
|
+
baseColumn: never;
|
|
274
|
+
identity: undefined;
|
|
275
|
+
generated: undefined;
|
|
276
|
+
}, {}, {
|
|
277
|
+
length: 255;
|
|
278
|
+
}>;
|
|
279
|
+
version: drizzle_orm_pg_core.PgColumn<{
|
|
280
|
+
name: "version";
|
|
281
|
+
tableName: "games";
|
|
282
|
+
dataType: "string";
|
|
283
|
+
columnType: "PgVarchar";
|
|
284
|
+
data: string;
|
|
285
|
+
driverParam: string;
|
|
286
|
+
notNull: true;
|
|
287
|
+
hasDefault: false;
|
|
288
|
+
isPrimaryKey: false;
|
|
289
|
+
isAutoincrement: false;
|
|
290
|
+
hasRuntimeDefault: false;
|
|
291
|
+
enumValues: [string, ...string[]];
|
|
292
|
+
baseColumn: never;
|
|
293
|
+
identity: undefined;
|
|
294
|
+
generated: undefined;
|
|
295
|
+
}, {}, {
|
|
296
|
+
length: 50;
|
|
297
|
+
}>;
|
|
298
|
+
gameType: drizzle_orm_pg_core.PgColumn<{
|
|
299
|
+
name: "game_type";
|
|
300
|
+
tableName: "games";
|
|
301
|
+
dataType: "string";
|
|
302
|
+
columnType: "PgEnumColumn";
|
|
303
|
+
data: "hosted" | "external";
|
|
304
|
+
driverParam: string;
|
|
305
|
+
notNull: true;
|
|
306
|
+
hasDefault: true;
|
|
307
|
+
isPrimaryKey: false;
|
|
308
|
+
isAutoincrement: false;
|
|
309
|
+
hasRuntimeDefault: false;
|
|
310
|
+
enumValues: ["hosted", "external"];
|
|
311
|
+
baseColumn: never;
|
|
312
|
+
identity: undefined;
|
|
313
|
+
generated: undefined;
|
|
314
|
+
}, {}, {}>;
|
|
315
|
+
assetBundleBase: drizzle_orm_pg_core.PgColumn<{
|
|
316
|
+
name: "asset_bundle_base";
|
|
317
|
+
tableName: "games";
|
|
318
|
+
dataType: "string";
|
|
319
|
+
columnType: "PgText";
|
|
320
|
+
data: string;
|
|
321
|
+
driverParam: string;
|
|
322
|
+
notNull: false;
|
|
323
|
+
hasDefault: false;
|
|
324
|
+
isPrimaryKey: false;
|
|
325
|
+
isAutoincrement: false;
|
|
326
|
+
hasRuntimeDefault: false;
|
|
327
|
+
enumValues: [string, ...string[]];
|
|
328
|
+
baseColumn: never;
|
|
329
|
+
identity: undefined;
|
|
330
|
+
generated: undefined;
|
|
331
|
+
}, {}, {}>;
|
|
332
|
+
externalUrl: drizzle_orm_pg_core.PgColumn<{
|
|
333
|
+
name: "external_url";
|
|
334
|
+
tableName: "games";
|
|
335
|
+
dataType: "string";
|
|
336
|
+
columnType: "PgText";
|
|
337
|
+
data: string;
|
|
338
|
+
driverParam: string;
|
|
339
|
+
notNull: false;
|
|
340
|
+
hasDefault: false;
|
|
341
|
+
isPrimaryKey: false;
|
|
342
|
+
isAutoincrement: false;
|
|
343
|
+
hasRuntimeDefault: false;
|
|
344
|
+
enumValues: [string, ...string[]];
|
|
345
|
+
baseColumn: never;
|
|
346
|
+
identity: undefined;
|
|
347
|
+
generated: undefined;
|
|
348
|
+
}, {}, {}>;
|
|
349
|
+
platform: drizzle_orm_pg_core.PgColumn<{
|
|
350
|
+
name: "platform";
|
|
351
|
+
tableName: "games";
|
|
352
|
+
dataType: "string";
|
|
353
|
+
columnType: "PgEnumColumn";
|
|
354
|
+
data: "web" | "godot" | "unity";
|
|
355
|
+
driverParam: string;
|
|
356
|
+
notNull: true;
|
|
357
|
+
hasDefault: true;
|
|
358
|
+
isPrimaryKey: false;
|
|
359
|
+
isAutoincrement: false;
|
|
360
|
+
hasRuntimeDefault: false;
|
|
361
|
+
enumValues: ["web", "godot", "unity"];
|
|
362
|
+
baseColumn: never;
|
|
363
|
+
identity: undefined;
|
|
364
|
+
generated: undefined;
|
|
365
|
+
}, {}, {}>;
|
|
366
|
+
mapElementId: drizzle_orm_pg_core.PgColumn<{
|
|
367
|
+
name: "map_element_id";
|
|
368
|
+
tableName: "games";
|
|
369
|
+
dataType: "string";
|
|
370
|
+
columnType: "PgUUID";
|
|
371
|
+
data: string;
|
|
372
|
+
driverParam: string;
|
|
373
|
+
notNull: false;
|
|
374
|
+
hasDefault: false;
|
|
375
|
+
isPrimaryKey: false;
|
|
376
|
+
isAutoincrement: false;
|
|
377
|
+
hasRuntimeDefault: false;
|
|
378
|
+
enumValues: undefined;
|
|
379
|
+
baseColumn: never;
|
|
380
|
+
identity: undefined;
|
|
381
|
+
generated: undefined;
|
|
382
|
+
}, {}, {}>;
|
|
383
|
+
metadata: drizzle_orm_pg_core.PgColumn<{
|
|
384
|
+
name: "metadata";
|
|
385
|
+
tableName: "games";
|
|
386
|
+
dataType: "json";
|
|
387
|
+
columnType: "PgJsonb";
|
|
388
|
+
data: GameMetadata;
|
|
389
|
+
driverParam: unknown;
|
|
390
|
+
notNull: true;
|
|
391
|
+
hasDefault: true;
|
|
392
|
+
isPrimaryKey: false;
|
|
393
|
+
isAutoincrement: false;
|
|
394
|
+
hasRuntimeDefault: false;
|
|
395
|
+
enumValues: undefined;
|
|
396
|
+
baseColumn: never;
|
|
397
|
+
identity: undefined;
|
|
398
|
+
generated: undefined;
|
|
399
|
+
}, {}, {
|
|
400
|
+
$type: GameMetadata;
|
|
401
|
+
}>;
|
|
402
|
+
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
403
|
+
name: "created_at";
|
|
404
|
+
tableName: "games";
|
|
405
|
+
dataType: "date";
|
|
406
|
+
columnType: "PgTimestamp";
|
|
407
|
+
data: Date;
|
|
408
|
+
driverParam: string;
|
|
409
|
+
notNull: false;
|
|
410
|
+
hasDefault: true;
|
|
411
|
+
isPrimaryKey: false;
|
|
412
|
+
isAutoincrement: false;
|
|
413
|
+
hasRuntimeDefault: false;
|
|
414
|
+
enumValues: undefined;
|
|
415
|
+
baseColumn: never;
|
|
416
|
+
identity: undefined;
|
|
417
|
+
generated: undefined;
|
|
418
|
+
}, {}, {}>;
|
|
419
|
+
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
420
|
+
name: "updated_at";
|
|
421
|
+
tableName: "games";
|
|
422
|
+
dataType: "date";
|
|
423
|
+
columnType: "PgTimestamp";
|
|
424
|
+
data: Date;
|
|
425
|
+
driverParam: string;
|
|
426
|
+
notNull: false;
|
|
427
|
+
hasDefault: true;
|
|
428
|
+
isPrimaryKey: false;
|
|
429
|
+
isAutoincrement: false;
|
|
430
|
+
hasRuntimeDefault: false;
|
|
431
|
+
enumValues: undefined;
|
|
432
|
+
baseColumn: never;
|
|
433
|
+
identity: undefined;
|
|
434
|
+
generated: undefined;
|
|
435
|
+
}, {}, {}>;
|
|
436
|
+
};
|
|
437
|
+
dialect: "pg";
|
|
438
|
+
}>;
|
|
439
|
+
type GameRow = typeof games.$inferSelect;
|
|
440
|
+
type BaseGame = Omit<GameRow, 'gameType' | 'assetBundleBase' | 'externalUrl'>;
|
|
441
|
+
type HostedGame = BaseGame & {
|
|
442
|
+
gameType: 'hosted';
|
|
443
|
+
assetBundleBase: string;
|
|
444
|
+
externalUrl: null;
|
|
445
|
+
};
|
|
446
|
+
type ExternalGame = BaseGame & {
|
|
447
|
+
gameType: 'external';
|
|
448
|
+
assetBundleBase: null;
|
|
449
|
+
externalUrl: string;
|
|
450
|
+
};
|
|
451
|
+
type Game = HostedGame | ExternalGame;
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Deployed game tracking - maps project directories to game IDs
|
|
455
|
+
*/
|
|
456
|
+
interface DeployedGameInfo {
|
|
457
|
+
gameId: string;
|
|
458
|
+
lastDeployedAt: string;
|
|
459
|
+
buildPath?: string;
|
|
460
|
+
buildHash?: string;
|
|
461
|
+
buildSize?: number;
|
|
462
|
+
backendHash?: string;
|
|
463
|
+
backendSize?: number;
|
|
464
|
+
backendDeployedAt?: string;
|
|
465
|
+
}
|
|
466
|
+
interface GameStore {
|
|
467
|
+
[projectPath: string]: DeployedGameInfo;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Backend deployment response with code hash for change detection
|
|
471
|
+
*/
|
|
472
|
+
interface BackendDeploymentWithHash extends BackendDeploymentResponse {
|
|
473
|
+
/** SHA-256 hash of the deployed backend code */
|
|
474
|
+
backendHash: string;
|
|
475
|
+
/** Size of the deployed backend code in bytes */
|
|
476
|
+
backendSize: number;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Deployment context containing all information needed for deployment
|
|
480
|
+
*/
|
|
481
|
+
interface DeploymentContext {
|
|
482
|
+
config: DeployConfig;
|
|
483
|
+
fullConfig: PlaycademyConfig | null;
|
|
484
|
+
configFileName: string | null;
|
|
485
|
+
client: PlaycademyClient;
|
|
486
|
+
projectPath: string;
|
|
487
|
+
existingGame?: Game;
|
|
488
|
+
deployedGameInfo?: DeployedGameInfo;
|
|
489
|
+
isNewDeployment: boolean;
|
|
490
|
+
buildHash?: string;
|
|
491
|
+
buildSize?: number;
|
|
492
|
+
previousBuildHash?: string;
|
|
493
|
+
previousBuildSize?: number;
|
|
494
|
+
previousBackendHash?: string;
|
|
495
|
+
previousBackendSize?: number;
|
|
496
|
+
isDryRun: boolean;
|
|
497
|
+
deployBackend: boolean;
|
|
498
|
+
verbose: boolean;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Analysis of what changed in an update
|
|
502
|
+
*/
|
|
503
|
+
interface DeploymentChanges {
|
|
504
|
+
config: boolean;
|
|
505
|
+
build: boolean | undefined;
|
|
506
|
+
backend: boolean | undefined;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Plan for what needs to be deployed
|
|
510
|
+
*/
|
|
511
|
+
interface DeploymentPlan {
|
|
512
|
+
action: 'deploy-new' | 'update-existing' | 'no-changes';
|
|
513
|
+
gameType: 'hosted' | 'external';
|
|
514
|
+
shouldDeployFrontend: boolean;
|
|
515
|
+
shouldDeployBackend: boolean;
|
|
516
|
+
changes?: DeploymentChanges;
|
|
517
|
+
currentBackendSize?: number;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Result of a deployment
|
|
521
|
+
*/
|
|
522
|
+
interface DeploymentResult {
|
|
523
|
+
game: Game;
|
|
524
|
+
backendDeployment?: BackendDeploymentWithHash | null;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Deployment configuration
|
|
528
|
+
*
|
|
529
|
+
* Configuration for deploying a game to Playcademy.
|
|
530
|
+
* Can be provided via CLI options, playcademy.json file, or package.json.
|
|
531
|
+
*/
|
|
532
|
+
interface DeployConfig {
|
|
533
|
+
/** Game slug (URL-friendly identifier) */
|
|
534
|
+
slug?: string;
|
|
535
|
+
/** Display name for the game */
|
|
536
|
+
displayName?: string;
|
|
537
|
+
/** Game description */
|
|
538
|
+
description?: string;
|
|
539
|
+
/** Emoji icon for the game */
|
|
540
|
+
emoji?: string;
|
|
541
|
+
/** Path to the build directory or zip file */
|
|
542
|
+
buildPath?: string;
|
|
543
|
+
/** Game platform (defaults to 'web') */
|
|
544
|
+
platform?: 'web' | 'unity' | 'godot';
|
|
545
|
+
/** Game type */
|
|
546
|
+
gameType?: 'hosted' | 'external';
|
|
547
|
+
/** External URL for external games */
|
|
548
|
+
externalUrl?: string;
|
|
549
|
+
}
|
|
550
|
+
interface DeployNewGameOptions {
|
|
551
|
+
client: PlaycademyClient;
|
|
552
|
+
config: DeployConfig;
|
|
553
|
+
isDryRun: boolean;
|
|
554
|
+
projectPath: string;
|
|
555
|
+
buildHash?: string;
|
|
556
|
+
backend?: boolean;
|
|
557
|
+
}
|
|
558
|
+
interface UpdateExistingGameOptions {
|
|
559
|
+
configFileName?: string | null;
|
|
560
|
+
client: PlaycademyClient;
|
|
561
|
+
config: DeployConfig;
|
|
562
|
+
backend?: boolean;
|
|
563
|
+
existingGame: Game;
|
|
564
|
+
isDryRun: boolean;
|
|
565
|
+
projectPath: string;
|
|
566
|
+
previousBuildHash?: string;
|
|
567
|
+
currentBuildHash?: string;
|
|
568
|
+
previousBuildSize?: number;
|
|
569
|
+
currentBuildSize?: number;
|
|
570
|
+
previousBackendHash?: string;
|
|
571
|
+
previousBackendSize?: number;
|
|
572
|
+
verbose?: boolean;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Types for the CLI local HTTP server that handles OAuth callbacks
|
|
577
|
+
*/
|
|
578
|
+
/**
|
|
579
|
+
* Callback data received from the Playcademy server after SSO authentication
|
|
580
|
+
*/
|
|
581
|
+
interface SsoCallbackData {
|
|
582
|
+
/** The session token from SSO authentication */
|
|
583
|
+
sessionToken: string;
|
|
584
|
+
/** User's email address */
|
|
585
|
+
email: string;
|
|
586
|
+
/** User's ID */
|
|
587
|
+
userId: string;
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Result from starting and running the callback server
|
|
591
|
+
*/
|
|
592
|
+
interface CallbackServerResult {
|
|
593
|
+
/** Whether the callback was successful */
|
|
594
|
+
success: boolean;
|
|
595
|
+
/** The callback data if successful */
|
|
596
|
+
data?: SsoCallbackData;
|
|
597
|
+
/** Error message if unsuccessful */
|
|
598
|
+
error?: string;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Preview options
|
|
603
|
+
*/
|
|
604
|
+
interface PreviewOptions {
|
|
605
|
+
/** Path to project directory (defaults to current directory) */
|
|
606
|
+
project?: string;
|
|
607
|
+
/** Preview duration in hours (defaults to 24, max 168) */
|
|
608
|
+
duration?: number;
|
|
609
|
+
/** Optional password protection for the preview */
|
|
610
|
+
password?: string;
|
|
611
|
+
/** Description or message for the preview */
|
|
612
|
+
message?: string;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Preview response
|
|
616
|
+
*/
|
|
617
|
+
interface PreviewResponse {
|
|
618
|
+
/** Unique preview identifier */
|
|
619
|
+
id: string;
|
|
620
|
+
/** URL where the preview is accessible */
|
|
621
|
+
url: string;
|
|
622
|
+
/** ISO 8601 date string - when the preview expires */
|
|
623
|
+
expiresAt: string;
|
|
624
|
+
/** Base64 encoded QR code image for easy mobile access */
|
|
625
|
+
qrCode?: string;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
export type { ApiConfig, ApiErrorResponse, ApiKeyListItem, ApiKeyWithSecret, ApiRequestOptions, AuthProfile, AuthStore, BackendDeploymentWithHash, CallbackServerResult, CreateApiKeyResponse, DeployConfig, DeployNewGameOptions, DeployedGameInfo, DeploymentChanges, DeploymentContext, DeploymentPlan, DeploymentResult, GameStore, IntegrationsConfig, LoginCredentials, LoginResponse, PlaycademyConfig, PreviewOptions, PreviewResponse, SignInResponse, SsoCallbackData, TimebackIntegrationConfig, TokenType, UpdateExistingGameOptions };
|