@playdrop/playdrop-cli 0.14.4 → 0.14.6
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/config/client-meta.json +2 -2
- package/dist/apps/staticHtml.js +1 -0
- package/dist/apps/upload.js +1 -0
- package/dist/catalogue.d.ts +16 -5
- package/dist/catalogue.js +122 -158
- package/node_modules/@playdrop/config/client-meta.json +2 -2
- package/node_modules/@playdrop/config/dist/src/game-arena.d.ts +14 -0
- package/node_modules/@playdrop/config/dist/src/game-arena.d.ts.map +1 -0
- package/node_modules/@playdrop/config/dist/src/game-arena.js +30 -0
- package/node_modules/@playdrop/config/dist/src/index.d.ts +1 -0
- package/node_modules/@playdrop/config/dist/src/index.d.ts.map +1 -1
- package/node_modules/@playdrop/config/dist/src/index.js +1 -0
- package/node_modules/@playdrop/config/dist/test/game-arena.test.d.ts +2 -0
- package/node_modules/@playdrop/config/dist/test/game-arena.test.d.ts.map +1 -0
- package/node_modules/@playdrop/config/dist/test/game-arena.test.js +16 -0
- package/node_modules/@playdrop/config/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@playdrop/config/package.json +4 -0
- package/node_modules/@playdrop/types/dist/api.d.ts +28 -1
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/version.d.ts +20 -0
- package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/version.js +6 -0
- package/package.json +1 -1
package/config/client-meta.json
CHANGED
package/dist/apps/staticHtml.js
CHANGED
package/dist/apps/upload.js
CHANGED
|
@@ -285,6 +285,7 @@ async function uploadAppVersion(client, task, artifacts, options) {
|
|
|
285
285
|
status: definition.status,
|
|
286
286
|
})),
|
|
287
287
|
externalUrl: task.hostingMode === 'EXTERNAL' ? task.externalUrl : undefined,
|
|
288
|
+
listingMedia: listing?.mediaMetadata,
|
|
288
289
|
files: preparedSessionFiles.map((file) => ({
|
|
289
290
|
fileKey: file.fileKey,
|
|
290
291
|
filename: file.filename,
|
package/dist/catalogue.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AppAchievementCatalogueDefinition, type AppAuthMode, type AppControllerMode, type AppHostingMode, type AppLeaderboardCatalogueDefinition, type AppMetadataAssetSpecSupport, type AppPlaytestTapes, type AppSurface, type AppType, type AppVersionDesign, type AppVersionVisibility, type AssetSpecContract, type AssetSpecStatus, type AssetSpecValidationKind, type CatalogueTagGroupDefinition, type ContentLicense, type PlayerMetaDefinitionStatus } from '@playdrop/types';
|
|
1
|
+
import { type AppAchievementCatalogueDefinition, type AppAuthMode, type AppControllerMode, type AppHostingMode, type AppLeaderboardCatalogueDefinition, type AppListingMediaMetadata, type AppMetadataAssetSpecSupport, type AppPlaytestTapes, type AppSurface, type AppType, type AppVersionDesign, type AppVersionVisibility, type AssetSpecContract, type AssetSpecStatus, type AssetSpecValidationKind, type CatalogueTagGroupDefinition, type ContentLicense, type PlayerMetaDefinitionStatus } from '@playdrop/types';
|
|
2
2
|
import { type AssetSpecSupportDeclaration } from './assetSpecs';
|
|
3
3
|
export type CatalogueJson = {
|
|
4
4
|
apps?: Array<Record<string, unknown>>;
|
|
@@ -7,6 +7,8 @@ export type CatalogueJson = {
|
|
|
7
7
|
assets?: Array<Record<string, unknown>>;
|
|
8
8
|
assetPacks?: Array<Record<string, unknown>>;
|
|
9
9
|
} & Record<string, unknown>;
|
|
10
|
+
export declare const APP_DESCRIPTION_RECOMMENDED_MIN_CHARACTERS = 120;
|
|
11
|
+
export declare const APP_DESCRIPTION_RECOMMENDED_MIN_WORDS = 20;
|
|
10
12
|
/**
|
|
11
13
|
* Listing assets configuration for an app version.
|
|
12
14
|
* All paths are relative to the catalogue.json directory.
|
|
@@ -15,12 +17,20 @@ export type AppListingConfig = {
|
|
|
15
17
|
icon?: string;
|
|
16
18
|
heroPortrait?: string;
|
|
17
19
|
heroLandscape?: string;
|
|
18
|
-
screenshotsPortrait?:
|
|
19
|
-
screenshotsLandscape?:
|
|
20
|
-
videosPortrait?:
|
|
21
|
-
videosLandscape?:
|
|
20
|
+
screenshotsPortrait?: AppListingMediaConfig[];
|
|
21
|
+
screenshotsLandscape?: AppListingMediaConfig[];
|
|
22
|
+
videosPortrait?: AppListingMediaConfig[];
|
|
23
|
+
videosLandscape?: AppListingMediaConfig[];
|
|
22
24
|
captureReport?: string;
|
|
23
25
|
};
|
|
26
|
+
export type AppListingMediaConfig = string | {
|
|
27
|
+
path: string;
|
|
28
|
+
slug?: string;
|
|
29
|
+
title?: string;
|
|
30
|
+
alt?: string;
|
|
31
|
+
caption?: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
};
|
|
24
34
|
export type ResolvedAppAchievementDefinition = Omit<AppAchievementCatalogueDefinition, 'status'> & {
|
|
25
35
|
iconPath: string;
|
|
26
36
|
status: PlayerMetaDefinitionStatus;
|
|
@@ -156,6 +166,7 @@ export type ResolvedListingAssets = {
|
|
|
156
166
|
screenshotLandscapePaths: string[];
|
|
157
167
|
videoPortraitPaths: string[];
|
|
158
168
|
videoLandscapePaths: string[];
|
|
169
|
+
mediaMetadata: AppListingMediaMetadata[];
|
|
159
170
|
captureReportPath?: string;
|
|
160
171
|
};
|
|
161
172
|
export type AppDependencyAssetRef = {
|
package/dist/catalogue.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.APP_DESCRIPTION_RECOMMENDED_MIN_WORDS = exports.APP_DESCRIPTION_RECOMMENDED_MIN_CHARACTERS = void 0;
|
|
3
4
|
exports.validateAppMetadata = validateAppMetadata;
|
|
4
5
|
exports.resolveCatalogueTagGroups = resolveCatalogueTagGroups;
|
|
5
6
|
exports.resolveCatalogueEntries = resolveCatalogueEntries;
|
|
@@ -18,6 +19,8 @@ const LEGACY_CATALOGUE_VERSION_KEY = ['schema', 'Version'].join('');
|
|
|
18
19
|
const ASSET_CATEGORY_SET = new Set(types_1.ASSET_CATEGORY_VALUES);
|
|
19
20
|
const LISTING_IMAGE_EXTENSIONS = new Set(['.png']);
|
|
20
21
|
const LISTING_VIDEO_EXTENSIONS = new Set(['.mp4']);
|
|
22
|
+
exports.APP_DESCRIPTION_RECOMMENDED_MIN_CHARACTERS = 120;
|
|
23
|
+
exports.APP_DESCRIPTION_RECOMMENDED_MIN_WORDS = 20;
|
|
21
24
|
const BOXEL_GENERATED_FILE_ROLES = new Set(['mesh', 'preview']);
|
|
22
25
|
const BOXEL_REQUIRED_FILE_ROLES = ['primary', 'mesh', 'preview'];
|
|
23
26
|
const VOX_GENERATED_FILE_ROLES = new Set(['boxel', 'mesh', 'preview']);
|
|
@@ -177,6 +180,74 @@ function validateListingAssetExtension(relativePath, fieldName, kind) {
|
|
|
177
180
|
function resolveListingAssetPath(baseDir, relativePath) {
|
|
178
181
|
return (0, node_path_1.resolve)(baseDir, relativePath);
|
|
179
182
|
}
|
|
183
|
+
const LISTING_MEDIA_SLUG_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
184
|
+
const LISTING_MEDIA_TEXT_LIMITS = {
|
|
185
|
+
title: 120,
|
|
186
|
+
alt: 200,
|
|
187
|
+
caption: 300,
|
|
188
|
+
description: 300,
|
|
189
|
+
};
|
|
190
|
+
function resolveListingMediaEntries(input) {
|
|
191
|
+
if (input.value === undefined) {
|
|
192
|
+
return { paths: [], metadata: [] };
|
|
193
|
+
}
|
|
194
|
+
if (!Array.isArray(input.value)) {
|
|
195
|
+
return { paths: [], metadata: [], error: `${input.fieldName} must be an array` };
|
|
196
|
+
}
|
|
197
|
+
const paths = [];
|
|
198
|
+
const metadata = [];
|
|
199
|
+
for (let index = 0; index < input.value.length; index += 1) {
|
|
200
|
+
const value = input.value[index];
|
|
201
|
+
const fieldName = `${input.fieldName}[${index}]`;
|
|
202
|
+
const objectValue = value && typeof value === 'object' && !Array.isArray(value)
|
|
203
|
+
? value
|
|
204
|
+
: null;
|
|
205
|
+
const relativePath = typeof value === 'string'
|
|
206
|
+
? value.trim()
|
|
207
|
+
: typeof objectValue?.path === 'string'
|
|
208
|
+
? objectValue.path.trim()
|
|
209
|
+
: '';
|
|
210
|
+
if (!relativePath) {
|
|
211
|
+
return { paths, metadata, error: `${fieldName} must be a path string or an object with a non-empty path` };
|
|
212
|
+
}
|
|
213
|
+
const extensionError = validateListingAssetExtension(relativePath, fieldName, input.kind);
|
|
214
|
+
if (extensionError) {
|
|
215
|
+
return { paths, metadata, error: extensionError };
|
|
216
|
+
}
|
|
217
|
+
const pathError = validateListingAssetPath(input.baseDir, relativePath, fieldName);
|
|
218
|
+
if (pathError) {
|
|
219
|
+
return { paths, metadata, error: pathError };
|
|
220
|
+
}
|
|
221
|
+
const item = {
|
|
222
|
+
fileKey: `${input.fileKeyPrefix}:${index}`,
|
|
223
|
+
};
|
|
224
|
+
if (objectValue) {
|
|
225
|
+
for (const key of ['title', 'alt', 'caption', 'description']) {
|
|
226
|
+
const raw = objectValue[key];
|
|
227
|
+
if (raw === undefined) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (typeof raw !== 'string' || raw.trim().length === 0) {
|
|
231
|
+
return { paths, metadata, error: `${fieldName}.${key} must be a non-empty string when provided` };
|
|
232
|
+
}
|
|
233
|
+
const normalized = raw.trim();
|
|
234
|
+
if (normalized.length > LISTING_MEDIA_TEXT_LIMITS[key]) {
|
|
235
|
+
return { paths, metadata, error: `${fieldName}.${key} must be ${LISTING_MEDIA_TEXT_LIMITS[key]} characters or fewer` };
|
|
236
|
+
}
|
|
237
|
+
item[key] = normalized;
|
|
238
|
+
}
|
|
239
|
+
if (objectValue.slug !== undefined) {
|
|
240
|
+
if (typeof objectValue.slug !== 'string' || !LISTING_MEDIA_SLUG_REGEX.test(objectValue.slug.trim())) {
|
|
241
|
+
return { paths, metadata, error: `${fieldName}.slug must use lowercase words separated by hyphens` };
|
|
242
|
+
}
|
|
243
|
+
item.slug = objectValue.slug.trim();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
paths.push(resolveListingAssetPath(input.baseDir, relativePath));
|
|
247
|
+
metadata.push(item);
|
|
248
|
+
}
|
|
249
|
+
return { paths, metadata };
|
|
250
|
+
}
|
|
180
251
|
function normalizeCatalogueRemixRef(value, expectedKind, errors, context) {
|
|
181
252
|
if (value === undefined || value === null) {
|
|
182
253
|
return undefined;
|
|
@@ -869,6 +940,13 @@ function validateAppMetadata(entry) {
|
|
|
869
940
|
let description;
|
|
870
941
|
if (typeof entry.description === 'string') {
|
|
871
942
|
description = entry.description;
|
|
943
|
+
const normalizedDescription = description.trim();
|
|
944
|
+
const wordCount = normalizedDescription ? normalizedDescription.split(/\s+/).length : 0;
|
|
945
|
+
if (normalizedDescription
|
|
946
|
+
&& (normalizedDescription.length < exports.APP_DESCRIPTION_RECOMMENDED_MIN_CHARACTERS
|
|
947
|
+
|| wordCount < exports.APP_DESCRIPTION_RECOMMENDED_MIN_WORDS)) {
|
|
948
|
+
warnings.push(`description is ${normalizedDescription.length} characters and ${wordCount} words. Aim for at least ${exports.APP_DESCRIPTION_RECOMMENDED_MIN_CHARACTERS} characters and ${exports.APP_DESCRIPTION_RECOMMENDED_MIN_WORDS} words describing what the player does, the objective, and the game's distinctive hook.`);
|
|
949
|
+
}
|
|
872
950
|
}
|
|
873
951
|
let surfaceTargetsList = [];
|
|
874
952
|
let surfaceTargetsMap = { desktop: false, mobileLandscape: false, mobilePortrait: false };
|
|
@@ -1169,6 +1247,7 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
1169
1247
|
screenshotLandscapePaths: [],
|
|
1170
1248
|
videoPortraitPaths: [],
|
|
1171
1249
|
videoLandscapePaths: [],
|
|
1250
|
+
mediaMetadata: [],
|
|
1172
1251
|
};
|
|
1173
1252
|
// Icon
|
|
1174
1253
|
if (typeof rawListing.icon === 'string' && rawListing.icon.trim()) {
|
|
@@ -1236,87 +1315,28 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
1236
1315
|
}
|
|
1237
1316
|
}
|
|
1238
1317
|
}
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
if (!listingValidationFailed && Array.isArray(rawListing.screenshotsLandscape)) {
|
|
1261
|
-
for (const p of rawListing.screenshotsLandscape) {
|
|
1262
|
-
if (typeof p === 'string' && p.trim()) {
|
|
1263
|
-
const screenshotPath = p.trim();
|
|
1264
|
-
const extensionError = validateListingAssetExtension(screenshotPath, 'listing.screenshotsLandscape item', 'image');
|
|
1265
|
-
if (extensionError) {
|
|
1266
|
-
errors.push(`[${label}] Skipping ${rawName}: ${extensionError}`);
|
|
1267
|
-
listingValidationFailed = true;
|
|
1268
|
-
break;
|
|
1269
|
-
}
|
|
1270
|
-
const validationError = validateListingAssetPath(file.directory, screenshotPath, 'listing.screenshotsLandscape item');
|
|
1271
|
-
if (validationError) {
|
|
1272
|
-
errors.push(`[${label}] Skipping ${rawName}: ${validationError}`);
|
|
1273
|
-
listingValidationFailed = true;
|
|
1274
|
-
break;
|
|
1275
|
-
}
|
|
1276
|
-
resolvedListing.screenshotLandscapePaths.push(resolveListingAssetPath(file.directory, screenshotPath));
|
|
1277
|
-
}
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
// Videos
|
|
1281
|
-
if (!listingValidationFailed && Array.isArray(rawListing.videosPortrait)) {
|
|
1282
|
-
for (const p of rawListing.videosPortrait) {
|
|
1283
|
-
if (typeof p === 'string' && p.trim()) {
|
|
1284
|
-
const videoPath = p.trim();
|
|
1285
|
-
const extensionError = validateListingAssetExtension(videoPath, 'listing.videosPortrait item', 'video');
|
|
1286
|
-
if (extensionError) {
|
|
1287
|
-
errors.push(`[${label}] Skipping ${rawName}: ${extensionError}`);
|
|
1288
|
-
listingValidationFailed = true;
|
|
1289
|
-
break;
|
|
1290
|
-
}
|
|
1291
|
-
const validationError = validateListingAssetPath(file.directory, videoPath, 'listing.videosPortrait item');
|
|
1292
|
-
if (validationError) {
|
|
1293
|
-
errors.push(`[${label}] Skipping ${rawName}: ${validationError}`);
|
|
1294
|
-
listingValidationFailed = true;
|
|
1295
|
-
break;
|
|
1296
|
-
}
|
|
1297
|
-
resolvedListing.videoPortraitPaths.push(resolveListingAssetPath(file.directory, videoPath));
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
}
|
|
1301
|
-
if (!listingValidationFailed && Array.isArray(rawListing.videosLandscape)) {
|
|
1302
|
-
for (const p of rawListing.videosLandscape) {
|
|
1303
|
-
if (typeof p === 'string' && p.trim()) {
|
|
1304
|
-
const videoPath = p.trim();
|
|
1305
|
-
const extensionError = validateListingAssetExtension(videoPath, 'listing.videosLandscape item', 'video');
|
|
1306
|
-
if (extensionError) {
|
|
1307
|
-
errors.push(`[${label}] Skipping ${rawName}: ${extensionError}`);
|
|
1308
|
-
listingValidationFailed = true;
|
|
1309
|
-
break;
|
|
1310
|
-
}
|
|
1311
|
-
const validationError = validateListingAssetPath(file.directory, videoPath, 'listing.videosLandscape item');
|
|
1312
|
-
if (validationError) {
|
|
1313
|
-
errors.push(`[${label}] Skipping ${rawName}: ${validationError}`);
|
|
1314
|
-
listingValidationFailed = true;
|
|
1315
|
-
break;
|
|
1316
|
-
}
|
|
1317
|
-
resolvedListing.videoLandscapePaths.push(resolveListingAssetPath(file.directory, videoPath));
|
|
1318
|
-
}
|
|
1318
|
+
for (const mediaField of [
|
|
1319
|
+
{ value: rawListing.screenshotsPortrait, fieldName: 'listing.screenshotsPortrait', kind: 'image', fileKeyPrefix: 'screenshotsPortrait', target: resolvedListing.screenshotPortraitPaths },
|
|
1320
|
+
{ value: rawListing.screenshotsLandscape, fieldName: 'listing.screenshotsLandscape', kind: 'image', fileKeyPrefix: 'screenshotsLandscape', target: resolvedListing.screenshotLandscapePaths },
|
|
1321
|
+
{ value: rawListing.videosPortrait, fieldName: 'listing.videosPortrait', kind: 'video', fileKeyPrefix: 'videosPortrait', target: resolvedListing.videoPortraitPaths },
|
|
1322
|
+
{ value: rawListing.videosLandscape, fieldName: 'listing.videosLandscape', kind: 'video', fileKeyPrefix: 'videosLandscape', target: resolvedListing.videoLandscapePaths },
|
|
1323
|
+
]) {
|
|
1324
|
+
if (listingValidationFailed)
|
|
1325
|
+
break;
|
|
1326
|
+
const resolvedMedia = resolveListingMediaEntries({
|
|
1327
|
+
value: mediaField.value,
|
|
1328
|
+
baseDir: file.directory,
|
|
1329
|
+
fieldName: mediaField.fieldName,
|
|
1330
|
+
kind: mediaField.kind,
|
|
1331
|
+
fileKeyPrefix: mediaField.fileKeyPrefix,
|
|
1332
|
+
});
|
|
1333
|
+
if (resolvedMedia.error) {
|
|
1334
|
+
errors.push(`[${label}] Skipping ${rawName}: ${resolvedMedia.error}`);
|
|
1335
|
+
listingValidationFailed = true;
|
|
1336
|
+
break;
|
|
1319
1337
|
}
|
|
1338
|
+
mediaField.target.push(...resolvedMedia.paths);
|
|
1339
|
+
resolvedListing.mediaMetadata.push(...resolvedMedia.metadata);
|
|
1320
1340
|
}
|
|
1321
1341
|
if (!listingValidationFailed && typeof rawListing.captureReport === 'string' && rawListing.captureReport.trim()) {
|
|
1322
1342
|
const captureReportPath = rawListing.captureReport.trim();
|
|
@@ -2117,6 +2137,7 @@ function buildAssetPackTasks(catalogues) {
|
|
|
2117
2137
|
screenshotLandscapePaths: [],
|
|
2118
2138
|
videoPortraitPaths: [],
|
|
2119
2139
|
videoLandscapePaths: [],
|
|
2140
|
+
mediaMetadata: [],
|
|
2120
2141
|
};
|
|
2121
2142
|
if (typeof rawListing.icon === 'string' && rawListing.icon.trim()) {
|
|
2122
2143
|
const iconPath = rawListing.icon.trim();
|
|
@@ -2172,85 +2193,28 @@ function buildAssetPackTasks(catalogues) {
|
|
|
2172
2193
|
}
|
|
2173
2194
|
}
|
|
2174
2195
|
}
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
}
|
|
2195
|
-
if (!listingValidationFailed && Array.isArray(rawListing.screenshotsLandscape)) {
|
|
2196
|
-
for (const p of rawListing.screenshotsLandscape) {
|
|
2197
|
-
if (typeof p === 'string' && p.trim()) {
|
|
2198
|
-
const screenshotPath = p.trim();
|
|
2199
|
-
const extensionError = validateListingAssetExtension(screenshotPath, 'assetPacks.listing.screenshotsLandscape item', 'image');
|
|
2200
|
-
if (extensionError) {
|
|
2201
|
-
errors.push(`[${label}] Skipping asset pack "${name}": ${extensionError}`);
|
|
2202
|
-
listingValidationFailed = true;
|
|
2203
|
-
break;
|
|
2204
|
-
}
|
|
2205
|
-
const validationError = validateListingAssetPath(file.directory, screenshotPath, 'assetPacks.listing.screenshotsLandscape item');
|
|
2206
|
-
if (validationError) {
|
|
2207
|
-
errors.push(`[${label}] Skipping asset pack "${name}": ${validationError}`);
|
|
2208
|
-
listingValidationFailed = true;
|
|
2209
|
-
break;
|
|
2210
|
-
}
|
|
2211
|
-
resolvedListing.screenshotLandscapePaths.push(resolveListingAssetPath(file.directory, screenshotPath));
|
|
2212
|
-
}
|
|
2213
|
-
}
|
|
2214
|
-
}
|
|
2215
|
-
if (!listingValidationFailed && Array.isArray(rawListing.videosPortrait)) {
|
|
2216
|
-
for (const p of rawListing.videosPortrait) {
|
|
2217
|
-
if (typeof p === 'string' && p.trim()) {
|
|
2218
|
-
const videoPath = p.trim();
|
|
2219
|
-
const extensionError = validateListingAssetExtension(videoPath, 'assetPacks.listing.videosPortrait item', 'video');
|
|
2220
|
-
if (extensionError) {
|
|
2221
|
-
errors.push(`[${label}] Skipping asset pack "${name}": ${extensionError}`);
|
|
2222
|
-
listingValidationFailed = true;
|
|
2223
|
-
break;
|
|
2224
|
-
}
|
|
2225
|
-
const validationError = validateListingAssetPath(file.directory, videoPath, 'assetPacks.listing.videosPortrait item');
|
|
2226
|
-
if (validationError) {
|
|
2227
|
-
errors.push(`[${label}] Skipping asset pack "${name}": ${validationError}`);
|
|
2228
|
-
listingValidationFailed = true;
|
|
2229
|
-
break;
|
|
2230
|
-
}
|
|
2231
|
-
resolvedListing.videoPortraitPaths.push(resolveListingAssetPath(file.directory, videoPath));
|
|
2232
|
-
}
|
|
2233
|
-
}
|
|
2234
|
-
}
|
|
2235
|
-
if (!listingValidationFailed && Array.isArray(rawListing.videosLandscape)) {
|
|
2236
|
-
for (const p of rawListing.videosLandscape) {
|
|
2237
|
-
if (typeof p === 'string' && p.trim()) {
|
|
2238
|
-
const videoPath = p.trim();
|
|
2239
|
-
const extensionError = validateListingAssetExtension(videoPath, 'assetPacks.listing.videosLandscape item', 'video');
|
|
2240
|
-
if (extensionError) {
|
|
2241
|
-
errors.push(`[${label}] Skipping asset pack "${name}": ${extensionError}`);
|
|
2242
|
-
listingValidationFailed = true;
|
|
2243
|
-
break;
|
|
2244
|
-
}
|
|
2245
|
-
const validationError = validateListingAssetPath(file.directory, videoPath, 'assetPacks.listing.videosLandscape item');
|
|
2246
|
-
if (validationError) {
|
|
2247
|
-
errors.push(`[${label}] Skipping asset pack "${name}": ${validationError}`);
|
|
2248
|
-
listingValidationFailed = true;
|
|
2249
|
-
break;
|
|
2250
|
-
}
|
|
2251
|
-
resolvedListing.videoLandscapePaths.push(resolveListingAssetPath(file.directory, videoPath));
|
|
2252
|
-
}
|
|
2196
|
+
for (const mediaField of [
|
|
2197
|
+
{ value: rawListing.screenshotsPortrait, fieldName: 'assetPacks.listing.screenshotsPortrait', kind: 'image', fileKeyPrefix: 'screenshotsPortrait', target: resolvedListing.screenshotPortraitPaths },
|
|
2198
|
+
{ value: rawListing.screenshotsLandscape, fieldName: 'assetPacks.listing.screenshotsLandscape', kind: 'image', fileKeyPrefix: 'screenshotsLandscape', target: resolvedListing.screenshotLandscapePaths },
|
|
2199
|
+
{ value: rawListing.videosPortrait, fieldName: 'assetPacks.listing.videosPortrait', kind: 'video', fileKeyPrefix: 'videosPortrait', target: resolvedListing.videoPortraitPaths },
|
|
2200
|
+
{ value: rawListing.videosLandscape, fieldName: 'assetPacks.listing.videosLandscape', kind: 'video', fileKeyPrefix: 'videosLandscape', target: resolvedListing.videoLandscapePaths },
|
|
2201
|
+
]) {
|
|
2202
|
+
if (listingValidationFailed)
|
|
2203
|
+
break;
|
|
2204
|
+
const resolvedMedia = resolveListingMediaEntries({
|
|
2205
|
+
value: mediaField.value,
|
|
2206
|
+
baseDir: file.directory,
|
|
2207
|
+
fieldName: mediaField.fieldName,
|
|
2208
|
+
kind: mediaField.kind,
|
|
2209
|
+
fileKeyPrefix: mediaField.fileKeyPrefix,
|
|
2210
|
+
});
|
|
2211
|
+
if (resolvedMedia.error) {
|
|
2212
|
+
errors.push(`[${label}] Skipping asset pack "${name}": ${resolvedMedia.error}`);
|
|
2213
|
+
listingValidationFailed = true;
|
|
2214
|
+
break;
|
|
2253
2215
|
}
|
|
2216
|
+
mediaField.target.push(...resolvedMedia.paths);
|
|
2217
|
+
resolvedListing.mediaMetadata.push(...resolvedMedia.metadata);
|
|
2254
2218
|
}
|
|
2255
2219
|
if (listingValidationFailed) {
|
|
2256
2220
|
continue;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const GAME_ARENA_ROUND_ONE: Readonly<{
|
|
2
|
+
id: "round-1";
|
|
3
|
+
label: "Round 1";
|
|
4
|
+
modelsLabel: "Opus 5 vs Sol 5.6";
|
|
5
|
+
description: "Opus 5 vs Sol 5.6 · casual games";
|
|
6
|
+
revealAt: "2026-08-06T17:00:00-04:00";
|
|
7
|
+
revealLabel: "Thursday · 5:00 PM ET";
|
|
8
|
+
comparisonMode: "BARE_SOL_OPUS";
|
|
9
|
+
opusModel: "opus-max";
|
|
10
|
+
solModel: "gpt-5.6-sol-xhigh";
|
|
11
|
+
}>;
|
|
12
|
+
export declare function resolveGameArenaRevealAt(envValue: string | null | undefined): string;
|
|
13
|
+
export declare function areGameArenaStandingsRevealed(revealAt: string, now?: number): boolean;
|
|
14
|
+
//# sourceMappingURL=game-arena.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"game-arena.d.ts","sourceRoot":"","sources":["../../src/game-arena.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB;;;;;;;;;;EAU/B,CAAC;AAEH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAIpF;AAED,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,OAAO,CAKzF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GAME_ARENA_ROUND_ONE = void 0;
|
|
4
|
+
exports.resolveGameArenaRevealAt = resolveGameArenaRevealAt;
|
|
5
|
+
exports.areGameArenaStandingsRevealed = areGameArenaStandingsRevealed;
|
|
6
|
+
exports.GAME_ARENA_ROUND_ONE = Object.freeze({
|
|
7
|
+
id: 'round-1',
|
|
8
|
+
label: 'Round 1',
|
|
9
|
+
modelsLabel: 'Opus 5 vs Sol 5.6',
|
|
10
|
+
description: 'Opus 5 vs Sol 5.6 · casual games',
|
|
11
|
+
revealAt: '2026-08-06T17:00:00-04:00',
|
|
12
|
+
revealLabel: 'Thursday · 5:00 PM ET',
|
|
13
|
+
comparisonMode: 'BARE_SOL_OPUS',
|
|
14
|
+
opusModel: 'opus-max',
|
|
15
|
+
solModel: 'gpt-5.6-sol-xhigh',
|
|
16
|
+
});
|
|
17
|
+
function resolveGameArenaRevealAt(envValue) {
|
|
18
|
+
const value = envValue?.trim() || exports.GAME_ARENA_ROUND_ONE.revealAt;
|
|
19
|
+
if (Number.isNaN(Date.parse(value)))
|
|
20
|
+
throw new Error('invalid_game_arena_reveal_at');
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function areGameArenaStandingsRevealed(revealAt, now = Date.now()) {
|
|
24
|
+
const target = Date.parse(revealAt);
|
|
25
|
+
if (Number.isNaN(target))
|
|
26
|
+
throw new Error('invalid_game_arena_reveal_at');
|
|
27
|
+
if (!Number.isFinite(now))
|
|
28
|
+
throw new Error('invalid_game_arena_now');
|
|
29
|
+
return now >= target;
|
|
30
|
+
}
|
|
@@ -6,6 +6,7 @@ export declare function getClientBuild(): number;
|
|
|
6
6
|
export declare function getClientVersionLabel(): string;
|
|
7
7
|
export * from './constants';
|
|
8
8
|
export * from './deployment';
|
|
9
|
+
export * from './game-arena';
|
|
9
10
|
export * from './server/fastify';
|
|
10
11
|
export * from './server/logging';
|
|
11
12
|
export * from './types';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EAEvB,MAAM,SAAS,CAAC;AAEjB,wBAAgB,cAAc,IAAI,gBAAgB,CAEjD;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAG9C;AAED,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAE/B,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUxF;AAwBD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,iBAAiB,GAAG,sBAAsB,CAqEzF"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EAEvB,MAAM,SAAS,CAAC;AAEjB,wBAAgB,cAAc,IAAI,gBAAgB,CAEjD;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAG9C;AAED,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAE/B,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUxF;AAwBD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,iBAAiB,GAAG,sBAAsB,CAqEzF"}
|
|
@@ -39,6 +39,7 @@ function getClientVersionLabel() {
|
|
|
39
39
|
}
|
|
40
40
|
__exportStar(require("./constants"), exports);
|
|
41
41
|
__exportStar(require("./deployment"), exports);
|
|
42
|
+
__exportStar(require("./game-arena"), exports);
|
|
42
43
|
__exportStar(require("./server/fastify"), exports);
|
|
43
44
|
__exportStar(require("./server/logging"), exports);
|
|
44
45
|
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"game-arena.test.d.ts","sourceRoot":"","sources":["../../test/game-arena.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const game_arena_1 = require("../src/game-arena");
|
|
9
|
+
(0, node_test_1.default)('Game Arena round one keeps the launch framing and configured reveal', () => {
|
|
10
|
+
strict_1.default.equal(game_arena_1.GAME_ARENA_ROUND_ONE.description, 'Opus 5 vs Sol 5.6 · casual games');
|
|
11
|
+
strict_1.default.equal((0, game_arena_1.resolveGameArenaRevealAt)(undefined), '2026-08-06T17:00:00-04:00');
|
|
12
|
+
strict_1.default.equal((0, game_arena_1.resolveGameArenaRevealAt)('2026-08-13T17:00:00-04:00'), '2026-08-13T17:00:00-04:00');
|
|
13
|
+
strict_1.default.equal((0, game_arena_1.areGameArenaStandingsRevealed)(game_arena_1.GAME_ARENA_ROUND_ONE.revealAt, Date.parse('2026-08-06T16:59:59-04:00')), false);
|
|
14
|
+
strict_1.default.equal((0, game_arena_1.areGameArenaStandingsRevealed)(game_arena_1.GAME_ARENA_ROUND_ONE.revealAt, Date.parse('2026-08-06T17:00:00-04:00')), true);
|
|
15
|
+
strict_1.default.throws(() => (0, game_arena_1.resolveGameArenaRevealAt)('not-a-date'), /invalid_game_arena_reveal_at/);
|
|
16
|
+
});
|