@playdrop/playdrop-cli 0.5.4 → 0.5.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/README.md +2 -1
- package/config/client-meta.json +4 -4
- package/dist/apps/upload.js +226 -80
- package/dist/assetSpecs.d.ts +1 -0
- package/dist/assetSpecs.js +22 -1
- package/dist/assets/model-artifacts.d.ts +2 -2
- package/dist/assets/model-artifacts.js +1 -1
- package/dist/captureRuntime.d.ts +1 -0
- package/dist/captureRuntime.js +3 -2
- package/dist/catalogue.d.ts +33 -8
- package/dist/catalogue.js +364 -46
- package/dist/commandContext.d.ts +5 -1
- package/dist/commandContext.js +90 -29
- package/dist/commands/browse.d.ts +3 -0
- package/dist/commands/browse.js +90 -17
- package/dist/commands/build.js +1 -1
- package/dist/commands/capture.d.ts +3 -0
- package/dist/commands/capture.js +121 -9
- package/dist/commands/captureListing.d.ts +2 -0
- package/dist/commands/captureListing.js +157 -61
- package/dist/commands/create.js +6 -28
- package/dist/commands/createRemixContent.js +4 -26
- package/dist/commands/creations.js +2 -3
- package/dist/commands/detail.js +24 -2
- package/dist/commands/dev.d.ts +8 -1
- package/dist/commands/dev.js +180 -2
- package/dist/commands/devRuntimeAssets.d.ts +34 -0
- package/dist/commands/devRuntimeAssets.js +308 -0
- package/dist/commands/devServer.d.ts +11 -0
- package/dist/commands/devServer.js +196 -13
- package/dist/commands/init.js +6 -24
- package/dist/commands/search.d.ts +4 -0
- package/dist/commands/search.js +68 -11
- package/dist/commands/upload-content.d.ts +3 -3
- package/dist/commands/upload-content.js +19 -38
- package/dist/commands/upload.js +67 -77
- package/dist/commands/validate.js +13 -20
- package/dist/commands/whoami.js +23 -26
- package/dist/devAuth.d.ts +16 -0
- package/dist/devAuth.js +60 -0
- package/dist/index.js +22 -4
- package/dist/taskSelection.js +4 -3
- package/dist/taskUtils.d.ts +2 -2
- package/dist/taskUtils.js +1 -1
- package/dist/uploadLog.d.ts +1 -1
- package/node_modules/@playdrop/ai-client/package.json +1 -1
- package/node_modules/@playdrop/api-client/dist/client.d.ts +44 -114
- package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/client.js +22 -0
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts +2 -1
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/admin.js +11 -0
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts +11 -19
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/apps.js +116 -106
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts +2 -1
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/assets.js +13 -0
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts +5 -5
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/payments.js +8 -8
- package/node_modules/@playdrop/api-client/dist/domains/search.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/search.js +24 -2
- package/node_modules/@playdrop/api-client/dist/domains/tags.d.ts +13 -1
- package/node_modules/@playdrop/api-client/dist/domains/tags.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/tags.js +52 -0
- package/node_modules/@playdrop/api-client/dist/index.d.ts +28 -29
- package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.js +26 -8
- package/node_modules/@playdrop/api-client/package.json +1 -1
- package/node_modules/@playdrop/boxel-core/package.json +1 -1
- package/node_modules/@playdrop/boxel-three/package.json +1 -1
- package/node_modules/@playdrop/config/client-meta.json +4 -4
- package/node_modules/@playdrop/config/package.json +1 -1
- package/node_modules/@playdrop/types/dist/api.d.ts +130 -3
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +23 -0
- package/node_modules/@playdrop/types/dist/app-capability-filters.d.ts +24 -0
- package/node_modules/@playdrop/types/dist/app-capability-filters.d.ts.map +1 -0
- package/node_modules/@playdrop/types/dist/app-capability-filters.js +72 -0
- package/node_modules/@playdrop/types/dist/asset-pack.d.ts +3 -2
- package/node_modules/@playdrop/types/dist/asset-pack.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/asset.d.ts +2 -3
- package/node_modules/@playdrop/types/dist/asset.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/asset.js +1 -1
- package/node_modules/@playdrop/types/dist/index.d.ts +2 -0
- package/node_modules/@playdrop/types/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/index.js +2 -0
- package/node_modules/@playdrop/types/dist/owned-assets.d.ts +21 -0
- package/node_modules/@playdrop/types/dist/owned-assets.d.ts.map +1 -0
- package/node_modules/@playdrop/types/dist/owned-assets.js +35 -0
- package/node_modules/@playdrop/types/dist/player-meta.d.ts +28 -0
- package/node_modules/@playdrop/types/dist/player-meta.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/version.d.ts +111 -1
- package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/version.js +4 -0
- package/node_modules/@playdrop/types/package.json +1 -1
- package/node_modules/@playdrop/vox-three/package.json +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/* eslint-disable max-lines */
|
|
2
3
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
4
|
if (k2 === undefined) k2 = k;
|
|
4
5
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -33,6 +34,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
34
|
};
|
|
34
35
|
})();
|
|
35
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.resolveListingCaptureRouteSegment = resolveListingCaptureRouteSegment;
|
|
38
|
+
exports.resolveListingCaptureSceneId = resolveListingCaptureSceneId;
|
|
36
39
|
exports.parseCaptureListingOptions = parseCaptureListingOptions;
|
|
37
40
|
exports.assertSupportedListingEnvironment = assertSupportedListingEnvironment;
|
|
38
41
|
exports.resolveListingRecorderPath = resolveListingRecorderPath;
|
|
@@ -47,7 +50,6 @@ const commandContext_1 = require("../commandContext");
|
|
|
47
50
|
const http_1 = require("../http");
|
|
48
51
|
const messages_1 = require("../messages");
|
|
49
52
|
const playwright_1 = require("../playwright");
|
|
50
|
-
const sessionCookie_1 = require("../sessionCookie");
|
|
51
53
|
const devShared_1 = require("./devShared");
|
|
52
54
|
const devServer_1 = require("./devServer");
|
|
53
55
|
const appUrls_1 = require("../appUrls");
|
|
@@ -63,6 +65,12 @@ const MIN_DIMENSION = 16;
|
|
|
63
65
|
const MAX_DIMENSION = 8192;
|
|
64
66
|
const MAX_FPS = 120;
|
|
65
67
|
const SUPPORTED_MACOS_PREFIX = '26.4';
|
|
68
|
+
function resolveListingCaptureRouteSegment(previewable) {
|
|
69
|
+
return previewable ? 'dev-preview' : 'dev';
|
|
70
|
+
}
|
|
71
|
+
function resolveListingCaptureSceneId(width, height) {
|
|
72
|
+
return height > width ? 'listing-portrait' : 'listing-landscape';
|
|
73
|
+
}
|
|
66
74
|
function parsePositiveNumber(raw, fallback, fieldName, { minimum = 0, maximum = Number.POSITIVE_INFINITY, integer = false, } = {}) {
|
|
67
75
|
if (raw === undefined) {
|
|
68
76
|
return fallback;
|
|
@@ -223,30 +231,6 @@ async function launchListingBrowser(initialViewport) {
|
|
|
223
231
|
throw (0, playwright_1.createPlaywrightLaunchError)('playdrop', error);
|
|
224
232
|
}
|
|
225
233
|
}
|
|
226
|
-
async function bootstrapAuthState(context, page, targetUrl, token, user) {
|
|
227
|
-
const cookies = (0, sessionCookie_1.buildCaptureAccessTokenCookies)(targetUrl, token);
|
|
228
|
-
await context.addCookies(cookies);
|
|
229
|
-
await page.addInitScript(({ bootstrapToken, bootstrapUser }) => {
|
|
230
|
-
try {
|
|
231
|
-
window.localStorage.setItem('playdrop.accessToken', bootstrapToken);
|
|
232
|
-
}
|
|
233
|
-
catch {
|
|
234
|
-
// ignore storage failures
|
|
235
|
-
}
|
|
236
|
-
try {
|
|
237
|
-
window.localStorage.setItem('playdrop.user', JSON.stringify(bootstrapUser));
|
|
238
|
-
}
|
|
239
|
-
catch {
|
|
240
|
-
// ignore storage failures
|
|
241
|
-
}
|
|
242
|
-
try {
|
|
243
|
-
window.sessionStorage.removeItem('playdrop.logoutReason');
|
|
244
|
-
}
|
|
245
|
-
catch {
|
|
246
|
-
// ignore storage failures
|
|
247
|
-
}
|
|
248
|
-
}, { bootstrapToken: token, bootstrapUser: user });
|
|
249
|
-
}
|
|
250
234
|
async function waitForHostedGameMeasurement(page, timeoutMs) {
|
|
251
235
|
const startedAt = Date.now();
|
|
252
236
|
let lastSignature = '';
|
|
@@ -310,6 +294,74 @@ async function waitForHostedGameMeasurement(page, timeoutMs) {
|
|
|
310
294
|
}
|
|
311
295
|
throw new Error('hosted_game_measurement_timeout');
|
|
312
296
|
}
|
|
297
|
+
async function waitForHostedGameFrame(page, timeoutMs) {
|
|
298
|
+
const frameHandle = await page.waitForSelector(CAPTURE_FRAME_SELECTOR, {
|
|
299
|
+
state: 'attached',
|
|
300
|
+
timeout: timeoutMs,
|
|
301
|
+
});
|
|
302
|
+
const startedAt = Date.now();
|
|
303
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
304
|
+
const frame = await frameHandle.contentFrame();
|
|
305
|
+
if (frame) {
|
|
306
|
+
return frame;
|
|
307
|
+
}
|
|
308
|
+
await page.waitForTimeout(200);
|
|
309
|
+
}
|
|
310
|
+
throw new Error('hosted_game_frame_missing');
|
|
311
|
+
}
|
|
312
|
+
async function prepareHostedListingScene(page, sceneId) {
|
|
313
|
+
const frame = await waitForHostedGameFrame(page, 20000);
|
|
314
|
+
await frame.waitForFunction(() => {
|
|
315
|
+
const captureWindow = window;
|
|
316
|
+
return typeof captureWindow.__listingCapture?.prepare === 'function';
|
|
317
|
+
}, undefined, { timeout: 20000 });
|
|
318
|
+
await frame.evaluate(async (requestedSceneId) => {
|
|
319
|
+
const captureWindow = window;
|
|
320
|
+
const hook = captureWindow.__listingCapture;
|
|
321
|
+
if (!hook || typeof hook.prepare !== 'function') {
|
|
322
|
+
throw new Error('listing_capture_hook_missing');
|
|
323
|
+
}
|
|
324
|
+
await hook.prepare(requestedSceneId);
|
|
325
|
+
}, sceneId);
|
|
326
|
+
}
|
|
327
|
+
async function startHostedListingAudioCapture(page) {
|
|
328
|
+
const frame = await waitForHostedGameFrame(page, 20000);
|
|
329
|
+
await frame.waitForFunction(() => {
|
|
330
|
+
const captureWindow = window;
|
|
331
|
+
return typeof captureWindow.__listingCapture?.startAudioCapture === 'function';
|
|
332
|
+
}, undefined, { timeout: 20000 });
|
|
333
|
+
await frame.evaluate(async () => {
|
|
334
|
+
const captureWindow = window;
|
|
335
|
+
const hook = captureWindow.__listingCapture;
|
|
336
|
+
if (!hook || typeof hook.startAudioCapture !== 'function') {
|
|
337
|
+
throw new Error('listing_audio_capture_hook_missing');
|
|
338
|
+
}
|
|
339
|
+
await hook.startAudioCapture();
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
function resolveExportedAudioFileName(mimeType) {
|
|
343
|
+
if (mimeType.includes('webm')) {
|
|
344
|
+
return 'listing-audio.webm';
|
|
345
|
+
}
|
|
346
|
+
if (mimeType.includes('mp4') || mimeType.includes('aac') || mimeType.includes('m4a')) {
|
|
347
|
+
return 'listing-audio.m4a';
|
|
348
|
+
}
|
|
349
|
+
throw new Error(`unsupported_listing_audio_mime_type:${mimeType}`);
|
|
350
|
+
}
|
|
351
|
+
async function stopHostedListingAudioCapture(page, outputDir) {
|
|
352
|
+
const frame = await waitForHostedGameFrame(page, 20000);
|
|
353
|
+
const exportedAudio = await frame.evaluate(async () => {
|
|
354
|
+
const captureWindow = window;
|
|
355
|
+
const hook = captureWindow.__listingCapture;
|
|
356
|
+
if (!hook || typeof hook.stopAudioCapture !== 'function') {
|
|
357
|
+
throw new Error('listing_audio_capture_hook_missing');
|
|
358
|
+
}
|
|
359
|
+
return hook.stopAudioCapture();
|
|
360
|
+
});
|
|
361
|
+
const filePath = (0, node_path_1.join)(outputDir, resolveExportedAudioFileName(exportedAudio.mimeType));
|
|
362
|
+
await (0, promises_1.writeFile)(filePath, Buffer.from(exportedAudio.base64, 'base64'));
|
|
363
|
+
return filePath;
|
|
364
|
+
}
|
|
313
365
|
async function fitWindowToRequestedGameplay(page, requestedWidth, requestedHeight) {
|
|
314
366
|
const cdpSession = await page.context().newCDPSession(page);
|
|
315
367
|
let measurement = await waitForHostedGameMeasurement(page, 15000);
|
|
@@ -531,6 +583,23 @@ async function encodeListingVideo(rawVideoPath, finalVideoPath, posterPath, crop
|
|
|
531
583
|
posterPath,
|
|
532
584
|
], 'ffmpeg_failed');
|
|
533
585
|
}
|
|
586
|
+
async function muxListingAudio(finalVideoPath, audioPath) {
|
|
587
|
+
const muxedVideoPath = `${finalVideoPath}.muxed.mp4`;
|
|
588
|
+
runTool('ffmpeg', [
|
|
589
|
+
'-y',
|
|
590
|
+
'-i',
|
|
591
|
+
finalVideoPath,
|
|
592
|
+
'-i',
|
|
593
|
+
audioPath,
|
|
594
|
+
'-c:v',
|
|
595
|
+
'copy',
|
|
596
|
+
'-c:a',
|
|
597
|
+
'aac',
|
|
598
|
+
'-shortest',
|
|
599
|
+
muxedVideoPath,
|
|
600
|
+
], 'ffmpeg_failed');
|
|
601
|
+
await (0, promises_1.rename)(muxedVideoPath, finalVideoPath);
|
|
602
|
+
}
|
|
534
603
|
function ensureTolerance(actual, expected, tolerance, failureCode) {
|
|
535
604
|
if (Math.abs(actual - expected) > tolerance) {
|
|
536
605
|
throw new Error(`${failureCode}:${actual}:${expected}`);
|
|
@@ -544,44 +613,30 @@ function createWarnings(finalProbe, requestedAudio) {
|
|
|
544
613
|
}
|
|
545
614
|
return warnings;
|
|
546
615
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
parsedOptions = parseCaptureListingOptions(targetArg, options);
|
|
551
|
-
assertSupportedListingEnvironment();
|
|
552
|
-
}
|
|
553
|
-
catch (error) {
|
|
554
|
-
const detail = formatCommandError(error instanceof Error ? error : new Error(String(error)));
|
|
555
|
-
(0, messages_1.printErrorWithHelp)(detail.message, detail.suggestions, { command: 'project capture listing' });
|
|
556
|
-
process.exitCode = 1;
|
|
557
|
-
return;
|
|
558
|
-
}
|
|
559
|
-
if (!commandExists('ffmpeg')) {
|
|
560
|
-
(0, messages_1.printErrorWithHelp)('ffmpeg is required for listing capture.', ['Install ffmpeg and make sure it is available on PATH.'], {
|
|
561
|
-
command: 'project capture listing',
|
|
562
|
-
});
|
|
563
|
-
process.exitCode = 1;
|
|
564
|
-
return;
|
|
616
|
+
function ensureCaptureListingToolAvailable(command) {
|
|
617
|
+
if (commandExists(command)) {
|
|
618
|
+
return true;
|
|
565
619
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
const recorderPath = resolveListingRecorderPath();
|
|
620
|
+
(0, messages_1.printErrorWithHelp)(`${command} is required for listing capture.`, [`Install ${command} and make sure it is available on PATH.`], {
|
|
621
|
+
command: 'project capture listing',
|
|
622
|
+
});
|
|
623
|
+
process.exitCode = 1;
|
|
624
|
+
return false;
|
|
625
|
+
}
|
|
626
|
+
async function ensureListingRecorderAvailable(recorderPath) {
|
|
574
627
|
try {
|
|
575
628
|
await ensureExecutableFile(recorderPath);
|
|
629
|
+
return true;
|
|
576
630
|
}
|
|
577
631
|
catch {
|
|
578
632
|
(0, messages_1.printErrorWithHelp)(`Native recorder binary was not found at ${recorderPath}.`, ['Build it with: (cd clients/apple/playdrop-listing-recorder && swift build -c release)'], { command: 'project capture listing' });
|
|
579
633
|
process.exitCode = 1;
|
|
580
|
-
return;
|
|
634
|
+
return false;
|
|
581
635
|
}
|
|
582
|
-
|
|
636
|
+
}
|
|
637
|
+
function resolveCaptureListingTarget(parsedOptions) {
|
|
583
638
|
try {
|
|
584
|
-
|
|
639
|
+
return (0, devShared_1.resolveDevTarget)(parsedOptions.targetArg, parsedOptions.appName);
|
|
585
640
|
}
|
|
586
641
|
catch (error) {
|
|
587
642
|
const code = error?.code;
|
|
@@ -593,6 +648,30 @@ async function captureListing(targetArg, options = {}) {
|
|
|
593
648
|
: ['Provide a valid app target or HTML file path.'];
|
|
594
649
|
(0, messages_1.printErrorWithHelp)(message, suggestions, { command: 'project capture listing' });
|
|
595
650
|
process.exitCode = 1;
|
|
651
|
+
return null;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
async function captureListing(targetArg, options = {}) {
|
|
655
|
+
let parsedOptions;
|
|
656
|
+
try {
|
|
657
|
+
parsedOptions = parseCaptureListingOptions(targetArg, options);
|
|
658
|
+
assertSupportedListingEnvironment();
|
|
659
|
+
}
|
|
660
|
+
catch (error) {
|
|
661
|
+
const detail = formatCommandError(error instanceof Error ? error : new Error(String(error)));
|
|
662
|
+
(0, messages_1.printErrorWithHelp)(detail.message, detail.suggestions, { command: 'project capture listing' });
|
|
663
|
+
process.exitCode = 1;
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
if (!ensureCaptureListingToolAvailable('ffmpeg') || !ensureCaptureListingToolAvailable('ffprobe')) {
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
const recorderPath = resolveListingRecorderPath();
|
|
670
|
+
if (!await ensureListingRecorderAvailable(recorderPath)) {
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
const resolvedTarget = resolveCaptureListingTarget(parsedOptions);
|
|
674
|
+
if (!resolvedTarget) {
|
|
596
675
|
return;
|
|
597
676
|
}
|
|
598
677
|
let appName = resolvedTarget.appName;
|
|
@@ -609,11 +688,11 @@ async function captureListing(targetArg, options = {}) {
|
|
|
609
688
|
const projectInfo = (0, devShared_1.findProjectInfo)(resolvedTarget.htmlPath);
|
|
610
689
|
const devScriptAvailable = Boolean(projectInfo.projectDir && projectInfo.packageJson && typeof projectInfo.packageJson.scripts?.dev === 'string');
|
|
611
690
|
// eslint-disable-next-line complexity
|
|
612
|
-
await (0, commandContext_1.withEnvironment)('project capture listing', 'Capturing listing media', async ({ client, env, envConfig
|
|
613
|
-
let currentUser = null;
|
|
691
|
+
await (0, commandContext_1.withEnvironment)('project capture listing', 'Capturing listing media', async ({ client, env, envConfig }) => {
|
|
614
692
|
let currentUsername = '';
|
|
693
|
+
let registeredApp = null;
|
|
615
694
|
try {
|
|
616
|
-
currentUser = await (0, devShared_1.fetchDevUser)(client);
|
|
695
|
+
const currentUser = await (0, devShared_1.fetchDevUser)(client);
|
|
617
696
|
currentUsername = currentUser.username.trim();
|
|
618
697
|
}
|
|
619
698
|
catch (error) {
|
|
@@ -641,7 +720,7 @@ async function captureListing(targetArg, options = {}) {
|
|
|
641
720
|
throw error;
|
|
642
721
|
}
|
|
643
722
|
try {
|
|
644
|
-
await (0, devShared_1.assertAppRegistered)(client, currentUsername, appName);
|
|
723
|
+
registeredApp = await (0, devShared_1.assertAppRegistered)(client, currentUsername, appName);
|
|
645
724
|
}
|
|
646
725
|
catch (error) {
|
|
647
726
|
if (error instanceof http_1.CLIUnsupportedClientError) {
|
|
@@ -717,18 +796,32 @@ async function captureListing(targetArg, options = {}) {
|
|
|
717
796
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
718
797
|
}
|
|
719
798
|
const webBase = envConfig.webBase ?? 'https://www.playdrop.ai';
|
|
720
|
-
const
|
|
799
|
+
const routeSegment = resolveListingCaptureRouteSegment(Boolean(registeredApp?.previewable));
|
|
800
|
+
const frameUrl = `${webBase}/creators/${encodeURIComponent(currentUsername)}/apps/${appTypeSlug}/${encodeURIComponent(appName)}/${routeSegment}`;
|
|
801
|
+
const captureSceneId = resolveListingCaptureSceneId(parsedOptions.width, parsedOptions.height);
|
|
802
|
+
const shouldExportPreviewAudio = parsedOptions.audio && routeSegment === 'dev-preview';
|
|
721
803
|
browserHandle = await launchListingBrowser({
|
|
722
804
|
width: parsedOptions.width,
|
|
723
805
|
height: parsedOptions.height,
|
|
724
806
|
});
|
|
725
|
-
await bootstrapAuthState(browserHandle.context, browserHandle.page, frameUrl, token, currentUser);
|
|
726
807
|
await browserHandle.page.goto(frameUrl, { waitUntil: 'domcontentloaded' });
|
|
727
808
|
await browserHandle.page.waitForTimeout(1000);
|
|
809
|
+
if (routeSegment === 'dev-preview') {
|
|
810
|
+
console.log(`[listing] Preparing preview scene ${captureSceneId}.`);
|
|
811
|
+
await prepareHostedListingScene(browserHandle.page, captureSceneId);
|
|
812
|
+
await browserHandle.page.waitForTimeout(1000);
|
|
813
|
+
}
|
|
814
|
+
if (shouldExportPreviewAudio) {
|
|
815
|
+
console.log('[listing] Starting in-app preview audio capture.');
|
|
816
|
+
await startHostedListingAudioCapture(browserHandle.page);
|
|
817
|
+
}
|
|
728
818
|
const measurement = await fitWindowToRequestedGameplay(browserHandle.page, parsedOptions.width, parsedOptions.height);
|
|
729
819
|
console.log(`[listing] Gameplay frame ${Math.round(measurement.iframeRect.width)}x${Math.round(measurement.iframeRect.height)} in window ${Math.round(measurement.outerWidth)}x${Math.round(measurement.outerHeight)}.`);
|
|
730
820
|
await browserHandle.page.waitForTimeout(750);
|
|
731
|
-
const recorderMetadata = await runListingRecorder(recorderPath, browserHandle.processId, parsedOptions.durationSeconds, outputPaths.rawVideoPath, outputPaths.metadataPath, parsedOptions.audio);
|
|
821
|
+
const recorderMetadata = await runListingRecorder(recorderPath, browserHandle.processId, parsedOptions.durationSeconds, outputPaths.rawVideoPath, outputPaths.metadataPath, shouldExportPreviewAudio ? false : parsedOptions.audio);
|
|
822
|
+
const exportedAudioPath = shouldExportPreviewAudio
|
|
823
|
+
? await stopHostedListingAudioCapture(browserHandle.page, outputPaths.outputDir)
|
|
824
|
+
: null;
|
|
732
825
|
const rawProbe = await probeMediaFile(outputPaths.rawVideoPath);
|
|
733
826
|
const rawVideoStream = extractVideoStream(rawProbe);
|
|
734
827
|
const rawDurationSeconds = readDurationSeconds(rawProbe);
|
|
@@ -736,6 +829,9 @@ async function captureListing(targetArg, options = {}) {
|
|
|
736
829
|
const crop = computeRecordedCrop(measurement, rawVideoStream.width, rawVideoStream.height);
|
|
737
830
|
console.log(`[listing] Cropping raw capture to gameplay at ${crop.width}x${crop.height}+${crop.x}+${crop.y}.`);
|
|
738
831
|
await encodeListingVideo(outputPaths.rawVideoPath, outputPaths.finalVideoPath, outputPaths.posterPath, crop, parsedOptions.width, parsedOptions.height, parsedOptions.fps, parsedOptions.posterAtSeconds);
|
|
832
|
+
if (exportedAudioPath) {
|
|
833
|
+
await muxListingAudio(outputPaths.finalVideoPath, exportedAudioPath);
|
|
834
|
+
}
|
|
739
835
|
const finalProbe = await probeMediaFile(outputPaths.finalVideoPath);
|
|
740
836
|
const finalVideoStream = extractVideoStream(finalProbe);
|
|
741
837
|
const finalDurationSeconds = readDurationSeconds(finalProbe);
|
package/dist/commands/create.js
CHANGED
|
@@ -12,10 +12,8 @@ const node_path_1 = require("node:path");
|
|
|
12
12
|
const node_child_process_1 = require("node:child_process");
|
|
13
13
|
const fflate_1 = require("fflate");
|
|
14
14
|
const types_1 = require("@playdrop/types");
|
|
15
|
-
const
|
|
16
|
-
const apiClient_1 = require("../apiClient");
|
|
15
|
+
const commandContext_1 = require("../commandContext");
|
|
17
16
|
const http_1 = require("../http");
|
|
18
|
-
const environment_1 = require("../environment");
|
|
19
17
|
const messages_1 = require("../messages");
|
|
20
18
|
const init_1 = require("./init");
|
|
21
19
|
const app_1 = require("@playdrop/types/app");
|
|
@@ -635,7 +633,7 @@ function buildPendingExternalRemixTask(name, metadata, sourceInfo, cataloguePath
|
|
|
635
633
|
remix: typeof entry.remix === 'string' ? entry.remix : undefined,
|
|
636
634
|
achievements: [],
|
|
637
635
|
leaderboards: [],
|
|
638
|
-
|
|
636
|
+
ownedAssets: [],
|
|
639
637
|
uses: { assets: [], packs: [] },
|
|
640
638
|
graph: { relations: [] },
|
|
641
639
|
};
|
|
@@ -1047,31 +1045,11 @@ async function create(name, options = {}) {
|
|
|
1047
1045
|
}
|
|
1048
1046
|
const templateOption = templateOptionRaw || undefined;
|
|
1049
1047
|
const remixOption = remixOptionRaw || undefined;
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1052
|
-
if (!envName) {
|
|
1053
|
-
(0, messages_1.printLoginRequired)('Creating an app', 'project create app');
|
|
1054
|
-
process.exitCode = 1;
|
|
1055
|
-
return;
|
|
1056
|
-
}
|
|
1057
|
-
const envConfig = (0, environment_1.resolveEnvironmentConfig)(envName);
|
|
1058
|
-
if (!envConfig) {
|
|
1059
|
-
const choices = (0, environment_1.formatEnvironmentList)();
|
|
1060
|
-
(0, messages_1.printErrorWithHelp)(`Environment "${envName}" from your Playdrop config is not supported.`, [
|
|
1061
|
-
`Available environments: ${choices}.`,
|
|
1062
|
-
'Run "playdrop auth login --env <env>" to save a supported environment before creating apps.'
|
|
1063
|
-
], { command: 'project create app', includeGeneralHelp: false });
|
|
1064
|
-
process.exitCode = 1;
|
|
1048
|
+
const ctx = await (0, commandContext_1.resolveAuthenticatedEnvironmentContext)('project create app', 'Creating an app', { workspacePath: process.cwd() });
|
|
1049
|
+
if (!ctx) {
|
|
1065
1050
|
return;
|
|
1066
1051
|
}
|
|
1067
|
-
|
|
1068
|
-
(0, messages_1.printLoginRequired)('Creating an app', 'project create app');
|
|
1069
|
-
process.exitCode = 1;
|
|
1070
|
-
return;
|
|
1071
|
-
}
|
|
1072
|
-
if (envConfig.allowInsecureRequests) {
|
|
1073
|
-
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
1074
|
-
}
|
|
1052
|
+
const envName = ctx.env;
|
|
1075
1053
|
const currentDir = process.cwd();
|
|
1076
1054
|
const localCataloguePath = (0, node_path_1.resolve)(currentDir, CATALOGUE_FILENAME);
|
|
1077
1055
|
let initSummary = null;
|
|
@@ -1080,7 +1058,7 @@ async function create(name, options = {}) {
|
|
|
1080
1058
|
let projectCatalogueResult = null;
|
|
1081
1059
|
let cataloguePathToUse = null;
|
|
1082
1060
|
let projectCataloguePath = null;
|
|
1083
|
-
const client =
|
|
1061
|
+
const client = ctx.client;
|
|
1084
1062
|
const sourceInfo = {};
|
|
1085
1063
|
let remixSourceTarget = null;
|
|
1086
1064
|
let scaffold = null;
|
|
@@ -6,9 +6,7 @@ exports.createRemixContent = createRemixContent;
|
|
|
6
6
|
const node_fs_1 = require("node:fs");
|
|
7
7
|
const node_path_1 = require("node:path");
|
|
8
8
|
const types_1 = require("@playdrop/types");
|
|
9
|
-
const
|
|
10
|
-
const config_1 = require("../config");
|
|
11
|
-
const environment_1 = require("../environment");
|
|
9
|
+
const commandContext_1 = require("../commandContext");
|
|
12
10
|
const http_1 = require("../http");
|
|
13
11
|
const messages_1 = require("../messages");
|
|
14
12
|
const init_1 = require("./init");
|
|
@@ -104,31 +102,11 @@ function assertWorkspaceRootCanOwnEntries(cataloguePath) {
|
|
|
104
102
|
}
|
|
105
103
|
}
|
|
106
104
|
async function createAuthenticatedClient(commandLabel) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
if (!envName) {
|
|
110
|
-
(0, messages_1.printLoginRequired)(commandLabel, commandLabel);
|
|
111
|
-
process.exitCode = 1;
|
|
112
|
-
throw new Error('missing_env');
|
|
113
|
-
}
|
|
114
|
-
const envConfig = (0, environment_1.resolveEnvironmentConfig)(envName);
|
|
115
|
-
if (!envConfig) {
|
|
116
|
-
(0, messages_1.printErrorWithHelp)(`Environment "${envName}" from your Playdrop config is not supported.`, [
|
|
117
|
-
`Available environments: ${(0, environment_1.formatEnvironmentList)()}.`,
|
|
118
|
-
'Run "playdrop auth login --env <env>" to save a supported environment before retrying.',
|
|
119
|
-
], { command: commandLabel, includeGeneralHelp: false });
|
|
120
|
-
process.exitCode = 1;
|
|
121
|
-
throw new Error('unsupported_env');
|
|
122
|
-
}
|
|
123
|
-
if (!cfg.token) {
|
|
124
|
-
(0, messages_1.printLoginRequired)(commandLabel, commandLabel);
|
|
125
|
-
process.exitCode = 1;
|
|
105
|
+
const ctx = await (0, commandContext_1.resolveAuthenticatedEnvironmentContext)(commandLabel, commandLabel, { workspacePath: process.cwd() });
|
|
106
|
+
if (!ctx) {
|
|
126
107
|
throw new Error('missing_token');
|
|
127
108
|
}
|
|
128
|
-
|
|
129
|
-
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
130
|
-
}
|
|
131
|
-
return (0, apiClient_1.createCliApiClient)({ baseUrl: envConfig.apiBase, token: cfg.token });
|
|
109
|
+
return ctx.client;
|
|
132
110
|
}
|
|
133
111
|
function ensureUniqueEntryName(catalogue, kind, name) {
|
|
134
112
|
const entries = kind === 'asset' ? catalogue.assets : catalogue.assetPacks;
|
|
@@ -105,11 +105,10 @@ function buildCountsSuffix(item) {
|
|
|
105
105
|
}
|
|
106
106
|
parts.push(`launch ${formatCountValue(item.item.playCount)}`);
|
|
107
107
|
}
|
|
108
|
-
if (item.kind === 'asset'
|
|
109
|
-
if (typeof item.item.viewCount === 'number') {
|
|
108
|
+
if (item.kind === 'asset') {
|
|
109
|
+
if ('viewCount' in item.item && typeof item.item.viewCount === 'number') {
|
|
110
110
|
parts.push(`view ${formatCountValue(item.item.viewCount)}`);
|
|
111
111
|
}
|
|
112
|
-
parts.push(`play ${formatCountValue(item.item.playCount)}`);
|
|
113
112
|
}
|
|
114
113
|
if (item.kind === 'asset-pack' && 'downloadCount' in item.item && typeof item.item.downloadCount === 'number') {
|
|
115
114
|
parts.push(`download ${formatCountValue(item.item.downloadCount)}`);
|
package/dist/commands/detail.js
CHANGED
|
@@ -42,9 +42,10 @@ function extractAssetFileUrls(asset) {
|
|
|
42
42
|
.filter((entry) => typeof entry?.role === 'string' && typeof entry?.url === 'string' && entry.url.trim().length > 0)
|
|
43
43
|
.map((entry) => ({ role: entry.role, url: entry.url.trim() }));
|
|
44
44
|
}
|
|
45
|
-
function decorateApp(app, webBase) {
|
|
45
|
+
function decorateApp(app, webBase, dependencies) {
|
|
46
46
|
return {
|
|
47
47
|
...app,
|
|
48
|
+
dependencies,
|
|
48
49
|
urls: {
|
|
49
50
|
play: (0, appUrls_1.buildPlatformPlayUrl)(webBase, {
|
|
50
51
|
creatorUsername: app.creatorUsername,
|
|
@@ -80,6 +81,16 @@ function formatTagSummary(tags) {
|
|
|
80
81
|
}
|
|
81
82
|
return normalizedTags.map((tag) => `${tag.ref} (${tag.displayName})`).join(', ');
|
|
82
83
|
}
|
|
84
|
+
function printAppDependencyLines(label, items) {
|
|
85
|
+
if (items.length === 0) {
|
|
86
|
+
console.log(`${label}: none`);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
console.log(`${label}:`);
|
|
90
|
+
for (const item of items) {
|
|
91
|
+
console.log(`- ${item}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
83
94
|
function printAppText(ref, app) {
|
|
84
95
|
console.log(`[app] ${ref}`);
|
|
85
96
|
console.log(`Display name: ${(0, output_1.formatOptionalValue)(app.displayName)}`);
|
|
@@ -90,6 +101,17 @@ function printAppText(ref, app) {
|
|
|
90
101
|
console.log(`Updated: ${(0, output_1.formatTimestamp)(app.updatedAt)}`);
|
|
91
102
|
console.log(`Current version: ${(0, output_1.formatOptionalValue)(app.currentVersion)}`);
|
|
92
103
|
console.log(`Tags: ${formatTagSummary(app.tags)}`);
|
|
104
|
+
console.log(`Owned assets: ${app.dependencies?.ownedAssets.length ?? 0}`);
|
|
105
|
+
console.log(`Direct assets: ${app.dependencies?.directAssets.length ?? 0}`);
|
|
106
|
+
console.log(`Packs: ${app.dependencies?.packs.length ?? 0}`);
|
|
107
|
+
printAppDependencyLines('Registered assets', (app.dependencies?.ownedAssets ?? []).map((item) => {
|
|
108
|
+
const runtimeKey = typeof item.runtimeKey === 'string' && item.runtimeKey.trim().length > 0
|
|
109
|
+
? `runtimeKey=${item.runtimeKey} `
|
|
110
|
+
: '';
|
|
111
|
+
return `${runtimeKey}${item.assetRef}`;
|
|
112
|
+
}));
|
|
113
|
+
printAppDependencyLines('Linked assets', (app.dependencies?.directAssets ?? []).map((item) => item.assetRef));
|
|
114
|
+
printAppDependencyLines('Linked packs', (app.dependencies?.packs ?? []).map((item) => item.packRef));
|
|
93
115
|
console.log(`Play URL: ${(0, output_1.formatOptionalValue)(app.urls.play)}`);
|
|
94
116
|
console.log(`Source URL: ${(0, output_1.formatOptionalValue)(app.urls.source)}`);
|
|
95
117
|
console.log('\nNext: run "playdrop versions browse ' + ref + '" to inspect version history.');
|
|
@@ -156,7 +178,7 @@ async function detail(rawRef, options = {}) {
|
|
|
156
178
|
try {
|
|
157
179
|
if (ref.kind === 'app') {
|
|
158
180
|
const response = await client.fetchAppBySlug(ref.creator, ref.name);
|
|
159
|
-
const item = decorateApp(response.app, envConfig.webBase);
|
|
181
|
+
const item = decorateApp(response.app, envConfig.webBase, response.dependencies);
|
|
160
182
|
if (options.json) {
|
|
161
183
|
(0, output_1.printJson)({ kind: ref.kind, ref: ref.ref, item });
|
|
162
184
|
return;
|
package/dist/commands/dev.d.ts
CHANGED
|
@@ -1 +1,8 @@
|
|
|
1
|
-
export declare function
|
|
1
|
+
export declare function formatDevRuntimeAssetManifestFailure(error: unknown): {
|
|
2
|
+
message: string;
|
|
3
|
+
suggestions: string[];
|
|
4
|
+
};
|
|
5
|
+
export declare function dev(targetArg: string | undefined, _port?: number, appOption?: string, devOptions?: {
|
|
6
|
+
devAuth?: string;
|
|
7
|
+
player?: string | number;
|
|
8
|
+
}): Promise<void>;
|