@playdrop/playdrop-cli 0.4.0 → 0.4.2
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 +7 -7
- package/dist/appUrls.d.ts +9 -0
- package/dist/appUrls.js +33 -0
- package/dist/browser.d.ts +5 -0
- package/dist/browser.js +45 -0
- package/dist/captureRuntime.d.ts +31 -0
- package/dist/captureRuntime.js +413 -0
- package/dist/commands/browse.js +1 -1
- package/dist/commands/capture.js +182 -479
- package/dist/commands/captureRemote.d.ts +2 -1
- package/dist/commands/captureRemote.js +144 -47
- package/dist/commands/comments.js +3 -3
- package/dist/commands/create.js +6 -6
- package/dist/commands/createRemixContent.js +1 -1
- package/dist/commands/creations.js +2 -2
- package/dist/commands/credits.js +2 -2
- package/dist/commands/detail.js +9 -4
- package/dist/commands/dev.js +2 -2
- package/dist/commands/feedback.js +26 -11
- package/dist/commands/generation.js +2 -2
- package/dist/commands/gettingStarted.js +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/login.d.ts +2 -4
- package/dist/commands/login.js +16 -51
- package/dist/commands/logout.js +1 -1
- package/dist/commands/notifications.js +3 -3
- package/dist/commands/play.d.ts +5 -0
- package/dist/commands/play.js +102 -0
- package/dist/commands/upload.js +10 -11
- package/dist/commands/versionsBrowse.js +11 -3
- package/dist/commands/whoami.js +3 -3
- package/dist/index.js +15 -3
- package/dist/messages.js +5 -5
- package/dist/playwright.d.ts +2 -1
- package/dist/playwright.js +18 -1
- package/dist/uploadLog.d.ts +2 -0
- package/dist/uploadLog.js +14 -0
- package/node_modules/@playdrop/ai-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/ai-client/dist/index.js +136 -3
- package/node_modules/@playdrop/api-client/dist/client.d.ts +9 -1
- package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/client.js +10 -1
- package/node_modules/@playdrop/api-client/dist/domains/auth.d.ts +3 -1
- package/node_modules/@playdrop/api-client/dist/domains/auth.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/auth.js +21 -0
- package/node_modules/@playdrop/api-client/dist/domains/free-credits.d.ts +27 -0
- package/node_modules/@playdrop/api-client/dist/domains/free-credits.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/free-credits.js +66 -0
- package/node_modules/@playdrop/api-client/dist/index.d.ts +10 -2
- package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.js +31 -2
- package/node_modules/@playdrop/config/client-meta.json +7 -7
- package/node_modules/@playdrop/types/dist/api.d.ts +85 -1
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +15 -0
- package/package.json +2 -2
package/dist/commands/login.js
CHANGED
|
@@ -1,54 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setOpenBrowserForTests =
|
|
4
|
-
exports.resetOpenBrowserForTests = resetOpenBrowserForTests;
|
|
3
|
+
exports.setOpenBrowserForTests = exports.resetOpenBrowserForTests = void 0;
|
|
5
4
|
exports.login = login;
|
|
6
|
-
const node_child_process_1 = require("node:child_process");
|
|
7
5
|
const types_1 = require("@playdrop/types");
|
|
8
6
|
const config_1 = require("../config");
|
|
9
7
|
const apiClient_1 = require("../apiClient");
|
|
10
8
|
const http_1 = require("../http");
|
|
11
9
|
const environment_1 = require("../environment");
|
|
10
|
+
const browser_1 = require("../browser");
|
|
11
|
+
Object.defineProperty(exports, "resetOpenBrowserForTests", { enumerable: true, get: function () { return browser_1.resetOpenBrowserForTests; } });
|
|
12
|
+
Object.defineProperty(exports, "setOpenBrowserForTests", { enumerable: true, get: function () { return browser_1.setOpenBrowserForTests; } });
|
|
12
13
|
const messages_1 = require("../messages");
|
|
13
14
|
function sleep(ms) {
|
|
14
15
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
15
16
|
}
|
|
16
|
-
function getBrowserCommand(url) {
|
|
17
|
-
if (process.platform === 'darwin') {
|
|
18
|
-
return { command: 'open', args: [url] };
|
|
19
|
-
}
|
|
20
|
-
if (process.platform === 'win32') {
|
|
21
|
-
return { command: 'cmd', args: ['/c', 'start', '', url] };
|
|
22
|
-
}
|
|
23
|
-
if (process.platform === 'linux') {
|
|
24
|
-
return { command: 'xdg-open', args: [url] };
|
|
25
|
-
}
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
async function defaultOpenBrowser(url) {
|
|
29
|
-
const command = getBrowserCommand(url);
|
|
30
|
-
if (!command) {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
return await new Promise((resolve) => {
|
|
34
|
-
const child = (0, node_child_process_1.spawn)(command.command, command.args, {
|
|
35
|
-
detached: true,
|
|
36
|
-
stdio: 'ignore',
|
|
37
|
-
});
|
|
38
|
-
child.once('error', () => resolve(false));
|
|
39
|
-
child.once('spawn', () => {
|
|
40
|
-
child.unref();
|
|
41
|
-
resolve(true);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
let openBrowser = defaultOpenBrowser;
|
|
46
|
-
function setOpenBrowserForTests(fn) {
|
|
47
|
-
openBrowser = fn;
|
|
48
|
-
}
|
|
49
|
-
function resetOpenBrowserForTests() {
|
|
50
|
-
openBrowser = defaultOpenBrowser;
|
|
51
|
-
}
|
|
52
17
|
function extractAccessToken(data) {
|
|
53
18
|
return data.accessToken
|
|
54
19
|
?? (typeof data === 'object' && data !== null && 'token' in data ? data.token : undefined);
|
|
@@ -69,7 +34,7 @@ function storeLogin(env, data) {
|
|
|
69
34
|
(0, config_1.saveConfig)({ token, env });
|
|
70
35
|
const username = data.user?.username ?? 'unknown';
|
|
71
36
|
console.log(`Logged in as ${username} on ${env}.`);
|
|
72
|
-
console.log('Next: run "playdrop whoami" to confirm your session.');
|
|
37
|
+
console.log('Next: run "playdrop auth whoami" to confirm your session.');
|
|
73
38
|
}
|
|
74
39
|
async function loginWithUsernamePassword(env, baseUrl, username, password) {
|
|
75
40
|
const client = (0, apiClient_1.createCliApiClient)({ baseUrl });
|
|
@@ -84,8 +49,8 @@ async function loginWithUsernamePassword(env, baseUrl, username, password) {
|
|
|
84
49
|
}
|
|
85
50
|
if (unknownError instanceof types_1.ApiError) {
|
|
86
51
|
(0, messages_1.printErrorWithHelp)(`Login failed with status ${unknownError.status}.`, [
|
|
87
|
-
'Verify your username and password, then rerun "playdrop login".',
|
|
88
|
-
'Use "playdrop whoami" after logging in to confirm your status.',
|
|
52
|
+
'Verify your username and password, then rerun "playdrop auth login".',
|
|
53
|
+
'Use "playdrop auth whoami" after logging in to confirm your status.',
|
|
89
54
|
], { command: 'login' });
|
|
90
55
|
process.exitCode = 1;
|
|
91
56
|
return;
|
|
@@ -106,8 +71,8 @@ async function loginWithKey(env, baseUrl, apiKey) {
|
|
|
106
71
|
}
|
|
107
72
|
if (unknownError instanceof types_1.ApiError) {
|
|
108
73
|
(0, messages_1.printErrorWithHelp)(`Login failed with status ${unknownError.status}.`, [
|
|
109
|
-
'Verify your API key, then rerun "playdrop login --key <api-key>".',
|
|
110
|
-
'Use "playdrop whoami" after logging in to confirm your status.',
|
|
74
|
+
'Verify your API key, then rerun "playdrop auth login --key <api-key>".',
|
|
75
|
+
'Use "playdrop auth whoami" after logging in to confirm your status.',
|
|
111
76
|
], { command: 'login' });
|
|
112
77
|
process.exitCode = 1;
|
|
113
78
|
return;
|
|
@@ -137,7 +102,7 @@ async function loginInBrowser(env, baseUrl) {
|
|
|
137
102
|
throw unknownError;
|
|
138
103
|
}
|
|
139
104
|
console.log(`Open this URL to continue: ${flow.loginUrl}`);
|
|
140
|
-
const opened = await
|
|
105
|
+
const opened = await (0, browser_1.openBrowserUrl)(flow.loginUrl).catch(() => false);
|
|
141
106
|
if (opened) {
|
|
142
107
|
console.log('Opened the login page in your browser.');
|
|
143
108
|
}
|
|
@@ -170,13 +135,13 @@ async function loginInBrowser(env, baseUrl) {
|
|
|
170
135
|
if (unknownError instanceof types_1.ApiError) {
|
|
171
136
|
if (unknownError.status === 410 || unknownError.code === 'cli_login_expired') {
|
|
172
137
|
(0, messages_1.printErrorWithHelp)('Browser login expired before it was approved.', [
|
|
173
|
-
'Rerun "playdrop login" to start a new browser login request.',
|
|
138
|
+
'Rerun "playdrop auth login" to start a new browser login request.',
|
|
174
139
|
], { command: 'login' });
|
|
175
140
|
process.exitCode = 1;
|
|
176
141
|
return;
|
|
177
142
|
}
|
|
178
143
|
(0, messages_1.printErrorWithHelp)(`Browser login failed with status ${unknownError.status}.`, [
|
|
179
|
-
'Rerun "playdrop login" to try again.',
|
|
144
|
+
'Rerun "playdrop auth login" to try again.',
|
|
180
145
|
], { command: 'login' });
|
|
181
146
|
process.exitCode = 1;
|
|
182
147
|
return;
|
|
@@ -185,7 +150,7 @@ async function loginInBrowser(env, baseUrl) {
|
|
|
185
150
|
}
|
|
186
151
|
}
|
|
187
152
|
(0, messages_1.printErrorWithHelp)('Browser login timed out after 10 minutes.', [
|
|
188
|
-
'Rerun "playdrop login" to start a new browser login request.',
|
|
153
|
+
'Rerun "playdrop auth login" to start a new browser login request.',
|
|
189
154
|
], { command: 'login' });
|
|
190
155
|
process.exitCode = 1;
|
|
191
156
|
}
|
|
@@ -205,7 +170,7 @@ async function login(env, options = {}) {
|
|
|
205
170
|
const apiKey = options.key?.trim();
|
|
206
171
|
if (apiKey && (username || password)) {
|
|
207
172
|
(0, messages_1.printErrorWithHelp)('Choose exactly one login method.', [
|
|
208
|
-
'Use "playdrop login" for browser login.',
|
|
173
|
+
'Use "playdrop auth login" for browser login.',
|
|
209
174
|
'Use "--username" with "--password" for direct login.',
|
|
210
175
|
'Use "--key" by itself for API key login.',
|
|
211
176
|
], { command: 'login' });
|
|
@@ -214,8 +179,8 @@ async function login(env, options = {}) {
|
|
|
214
179
|
}
|
|
215
180
|
if ((username && !password) || (!username && password)) {
|
|
216
181
|
(0, messages_1.printErrorWithHelp)('Provide both "--username" and "--password" together.', [
|
|
217
|
-
'Rerun "playdrop login --username <username> --password <password>".',
|
|
218
|
-
'Or run "playdrop login" to use browser login instead.',
|
|
182
|
+
'Rerun "playdrop auth login --username <username> --password <password>".',
|
|
183
|
+
'Or run "playdrop auth login" to use browser login instead.',
|
|
219
184
|
], { command: 'login' });
|
|
220
185
|
process.exitCode = 1;
|
|
221
186
|
return;
|
package/dist/commands/logout.js
CHANGED
|
@@ -5,5 +5,5 @@ const config_1 = require("../config");
|
|
|
5
5
|
function logout() {
|
|
6
6
|
(0, config_1.clearConfig)();
|
|
7
7
|
console.log('Logged out.');
|
|
8
|
-
console.log('Next: run "playdrop login" when you need a new session.');
|
|
8
|
+
console.log('Next: run "playdrop auth login" when you need a new session.');
|
|
9
9
|
}
|
|
@@ -116,7 +116,7 @@ async function browseNotifications(options = {}) {
|
|
|
116
116
|
const handled = (0, errors_1.handleCommandFailure)(error, 'notifications browse', 'Notification lookup', {
|
|
117
117
|
apiMessage: (apiError) => ({
|
|
118
118
|
problem: `Notification lookup failed with status ${apiError.status}.`,
|
|
119
|
-
suggestions: ['Run "playdrop login" and retry.'],
|
|
119
|
+
suggestions: ['Run "playdrop auth login" and retry.'],
|
|
120
120
|
}),
|
|
121
121
|
});
|
|
122
122
|
if (!handled) {
|
|
@@ -145,7 +145,7 @@ async function readNotification(rawId, options = {}) {
|
|
|
145
145
|
const handled = (0, errors_1.handleCommandFailure)(error, 'notifications read', 'Notification update', {
|
|
146
146
|
apiMessage: (apiError) => ({
|
|
147
147
|
problem: `Notification update failed with status ${apiError.status}.`,
|
|
148
|
-
suggestions: ['Run "playdrop login" and retry.'],
|
|
148
|
+
suggestions: ['Run "playdrop auth login" and retry.'],
|
|
149
149
|
}),
|
|
150
150
|
});
|
|
151
151
|
if (!handled) {
|
|
@@ -168,7 +168,7 @@ async function readAllNotifications(options = {}) {
|
|
|
168
168
|
const handled = (0, errors_1.handleCommandFailure)(error, 'notifications read-all', 'Notification update', {
|
|
169
169
|
apiMessage: (apiError) => ({
|
|
170
170
|
problem: `Notification update failed with status ${apiError.status}.`,
|
|
171
|
-
suggestions: ['Run "playdrop login" and retry.'],
|
|
171
|
+
suggestions: ['Run "playdrop auth login" and retry.'],
|
|
172
172
|
}),
|
|
173
173
|
});
|
|
174
174
|
if (!handled) {
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.play = play;
|
|
4
|
+
const types_1 = require("@playdrop/types");
|
|
5
|
+
const commandContext_1 = require("../commandContext");
|
|
6
|
+
const appUrls_1 = require("../appUrls");
|
|
7
|
+
const browser_1 = require("../browser");
|
|
8
|
+
const http_1 = require("../http");
|
|
9
|
+
const messages_1 = require("../messages");
|
|
10
|
+
const output_1 = require("../output");
|
|
11
|
+
const refs_1 = require("../refs");
|
|
12
|
+
const devShared_1 = require("./devShared");
|
|
13
|
+
function printPlayRefValidationError(rawRef) {
|
|
14
|
+
(0, messages_1.printErrorWithHelp)('A canonical app ref is required.', [
|
|
15
|
+
'Use the format <creator>/app/<name>.',
|
|
16
|
+
'Example: playdrop play playdrop/app/hangingout',
|
|
17
|
+
], { command: 'play' });
|
|
18
|
+
process.exitCode = 1;
|
|
19
|
+
}
|
|
20
|
+
async function play(rawRef, options = {}) {
|
|
21
|
+
let ref;
|
|
22
|
+
try {
|
|
23
|
+
ref = (0, refs_1.parseContentRef)(rawRef ?? '');
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
printPlayRefValidationError(rawRef);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (ref.kind !== 'app') {
|
|
30
|
+
(0, messages_1.printErrorWithHelp)('The play command only supports app refs.', [
|
|
31
|
+
'Use the format <creator>/app/<name>.',
|
|
32
|
+
'Assets and asset packs do not have authenticated play routes.',
|
|
33
|
+
], { command: 'play' });
|
|
34
|
+
process.exitCode = 1;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
await (0, commandContext_1.withEnvironment)('play', 'Launching a published app', async ({ client, envConfig }) => {
|
|
38
|
+
try {
|
|
39
|
+
const response = await client.fetchAppBySlug(ref.creator, ref.name);
|
|
40
|
+
const playUrl = (0, appUrls_1.buildPlatformPlayUrl)(envConfig.webBase, {
|
|
41
|
+
creatorUsername: response.app.creatorUsername,
|
|
42
|
+
appName: response.app.name,
|
|
43
|
+
appType: response.app.type,
|
|
44
|
+
});
|
|
45
|
+
const playPath = new URL(playUrl).pathname;
|
|
46
|
+
const launch = await client.startCliWebLaunch({
|
|
47
|
+
redirectPath: playPath,
|
|
48
|
+
});
|
|
49
|
+
const payload = {
|
|
50
|
+
ref: ref.ref,
|
|
51
|
+
playUrl,
|
|
52
|
+
launchUrl: launch.launchUrl,
|
|
53
|
+
expiresAt: launch.expiresAt,
|
|
54
|
+
};
|
|
55
|
+
if (options.json) {
|
|
56
|
+
(0, output_1.printJson)(payload);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
console.log(`Play URL: ${playUrl}`);
|
|
60
|
+
console.log(`Launch URL: ${launch.launchUrl}`);
|
|
61
|
+
const opened = await (0, browser_1.openBrowserUrl)(launch.launchUrl).catch(() => false);
|
|
62
|
+
if (opened) {
|
|
63
|
+
console.log('Opened the app in your browser.');
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
console.log('Open the launch URL above in your browser.');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error instanceof http_1.CLIUnsupportedClientError) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (error instanceof types_1.UnsupportedClientError) {
|
|
74
|
+
(0, http_1.handleUnsupportedError)(error, 'Play');
|
|
75
|
+
process.exitCode = 1;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (error instanceof types_1.ApiError) {
|
|
79
|
+
if (error.status === 404) {
|
|
80
|
+
(0, messages_1.printErrorWithHelp)(`No app was found for "${ref.ref}".`, [
|
|
81
|
+
'Check the ref and retry.',
|
|
82
|
+
'Run "playdrop browse --kind app" to discover public apps.',
|
|
83
|
+
], { command: 'play' });
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
(0, messages_1.printErrorWithHelp)(`Could not launch "${ref.ref}" (status ${error.status}).`, [
|
|
88
|
+
'Run "playdrop auth whoami" to confirm your session.',
|
|
89
|
+
'Retry in a moment if the platform was just updated.',
|
|
90
|
+
], { command: 'play' });
|
|
91
|
+
process.exitCode = 1;
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if ((0, devShared_1.isNetworkError)(error)) {
|
|
95
|
+
(0, messages_1.printNetworkIssue)('Could not reach the Playdrop API to launch the app.', 'play');
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
package/dist/commands/upload.js
CHANGED
|
@@ -9,14 +9,8 @@ const taskSelection_1 = require("../taskSelection");
|
|
|
9
9
|
const taskUtils_1 = require("../taskUtils");
|
|
10
10
|
const uploadLog_1 = require("../uploadLog");
|
|
11
11
|
const upload_content_1 = require("./upload-content");
|
|
12
|
+
const appUrls_1 = require("../appUrls");
|
|
12
13
|
const upload_graph_1 = require("./upload-graph");
|
|
13
|
-
const DEFAULT_PORTAL_BASE = 'https://www.playdrop.ai';
|
|
14
|
-
const APP_TYPE_TO_SLUG = {
|
|
15
|
-
GAME: 'game',
|
|
16
|
-
DEMO: 'demo',
|
|
17
|
-
TOOL: 'tool',
|
|
18
|
-
TEMPLATE: 'template',
|
|
19
|
-
};
|
|
20
14
|
function buildApiUnavailableMessage(apiBase) {
|
|
21
15
|
if (apiBase && typeof apiBase === 'string') {
|
|
22
16
|
return `Could not reach the Playdrop API at ${apiBase}. Check your internet connection, then ensure the server is running before retrying.`;
|
|
@@ -57,8 +51,7 @@ async function fetchCurrentUserInfo(client, apiBase) {
|
|
|
57
51
|
}
|
|
58
52
|
}
|
|
59
53
|
function normalizePortalBase(webBase) {
|
|
60
|
-
|
|
61
|
-
return base.replace(/\/$/, '');
|
|
54
|
+
return (0, appUrls_1.normalizePlaydropWebBase)(webBase);
|
|
62
55
|
}
|
|
63
56
|
function normalizeCreatorUsername(username) {
|
|
64
57
|
if (!username)
|
|
@@ -70,7 +63,7 @@ function normalizeCreatorUsername(username) {
|
|
|
70
63
|
return trimmed;
|
|
71
64
|
}
|
|
72
65
|
function buildAppOverviewUrl(base, creator, task) {
|
|
73
|
-
const typeSlug =
|
|
66
|
+
const typeSlug = (0, appUrls_1.getAppTypeSlug)(task.type ?? 'GAME');
|
|
74
67
|
const encodedCreator = encodeURIComponent(creator);
|
|
75
68
|
const encodedName = encodeURIComponent(task.name);
|
|
76
69
|
return `${base}/creators/${encodedCreator}/apps/${typeSlug}/${encodedName}/overview`;
|
|
@@ -194,6 +187,11 @@ async function uploadAppTask(state, task, taskCreator, options) {
|
|
|
194
187
|
entityId: buildTaskEntityId(task, taskCreator),
|
|
195
188
|
catalogue: task.cataloguePath,
|
|
196
189
|
detail: `version ${upload.version} created`,
|
|
190
|
+
playUrl: (0, appUrls_1.buildPlatformPlayUrl)(state.portalBase, {
|
|
191
|
+
creatorUsername: taskCreator,
|
|
192
|
+
appName: task.name,
|
|
193
|
+
appType: task.type ?? 'GAME',
|
|
194
|
+
}),
|
|
197
195
|
};
|
|
198
196
|
appendOverviewLink(entry, task, state.portalBase, taskCreator);
|
|
199
197
|
return entry;
|
|
@@ -345,7 +343,7 @@ async function flushGraphState(client, graphState, results) {
|
|
|
345
343
|
}
|
|
346
344
|
}
|
|
347
345
|
async function processUploadTasks(client, tasks, owner, ownerUsername, currentUserRole, webBase, options) {
|
|
348
|
-
const portalBase =
|
|
346
|
+
const portalBase = normalizePortalBase(webBase);
|
|
349
347
|
const defaultCreator = normalizeCreatorUsername(ownerUsername) ?? owner;
|
|
350
348
|
const results = [];
|
|
351
349
|
let aborted = false;
|
|
@@ -427,5 +425,6 @@ async function upload(pathOrName, options) {
|
|
|
427
425
|
}
|
|
428
426
|
const results = await processUploadTasks(client, tasks, owner, userInfo.username, userInfo.role, envConfig.webBase, options);
|
|
429
427
|
(0, uploadLog_1.printTaskSummary)(results, warnings, { action: 'upload', environment: env });
|
|
428
|
+
(0, uploadLog_1.printPublishedAppNextSteps)(results);
|
|
430
429
|
});
|
|
431
430
|
}
|
|
@@ -6,6 +6,7 @@ const errors_1 = require("../errors");
|
|
|
6
6
|
const messages_1 = require("../messages");
|
|
7
7
|
const output_1 = require("../output");
|
|
8
8
|
const refs_1 = require("../refs");
|
|
9
|
+
const appUrls_1 = require("../appUrls");
|
|
9
10
|
function parsePositiveInteger(raw, label, fallback) {
|
|
10
11
|
if (raw === undefined) {
|
|
11
12
|
return fallback;
|
|
@@ -88,7 +89,10 @@ async function browseVersions(rawRef, options = {}) {
|
|
|
88
89
|
let entries = [];
|
|
89
90
|
let pagination;
|
|
90
91
|
if (ref.kind === 'app') {
|
|
91
|
-
const response = await
|
|
92
|
+
const [appDetail, response] = await Promise.all([
|
|
93
|
+
client.fetchAppBySlug(ref.creator, ref.name),
|
|
94
|
+
client.listAppVersions(ref.creator, ref.name),
|
|
95
|
+
]);
|
|
92
96
|
const listed = response.versions ?? [];
|
|
93
97
|
const selected = listed.slice(offset, offset + limit);
|
|
94
98
|
const details = await Promise.all(selected.map(async (version) => {
|
|
@@ -102,7 +106,11 @@ async function browseVersions(rawRef, options = {}) {
|
|
|
102
106
|
releaseNotes: version.releaseNotes ?? null,
|
|
103
107
|
isCurrent: Boolean(version.isCurrent),
|
|
104
108
|
urls: {
|
|
105
|
-
play:
|
|
109
|
+
play: (0, appUrls_1.buildPlatformPlayUrl)(envConfig.webBase, {
|
|
110
|
+
creatorUsername: ref.creator,
|
|
111
|
+
appName: ref.name,
|
|
112
|
+
appType: appDetail.app.type,
|
|
113
|
+
}),
|
|
106
114
|
source: typeof detail.version.sourceUrl === 'string' ? detail.version.sourceUrl : null,
|
|
107
115
|
},
|
|
108
116
|
};
|
|
@@ -195,7 +203,7 @@ async function browseVersions(rawRef, options = {}) {
|
|
|
195
203
|
if (apiError.status === 401 || apiError.status === 403) {
|
|
196
204
|
return {
|
|
197
205
|
problem: `You do not have access to version history for "${ref.ref}".`,
|
|
198
|
-
suggestions: ['Run "playdrop login" if this is private content you own.'],
|
|
206
|
+
suggestions: ['Run "playdrop auth login" if this is private content you own.'],
|
|
199
207
|
};
|
|
200
208
|
}
|
|
201
209
|
return {
|
package/dist/commands/whoami.js
CHANGED
|
@@ -36,8 +36,8 @@ async function whoami() {
|
|
|
36
36
|
}
|
|
37
37
|
if (unknownError instanceof types_1.ApiError) {
|
|
38
38
|
(0, messages_1.printErrorWithHelp)(`Request failed with status ${unknownError.status}.`, [
|
|
39
|
-
'Run "playdrop login" to refresh your credentials.',
|
|
40
|
-
'Use "playdrop whoami" again after logging in to confirm your status.',
|
|
39
|
+
'Run "playdrop auth login" to refresh your credentials.',
|
|
40
|
+
'Use "playdrop auth whoami" again after logging in to confirm your status.',
|
|
41
41
|
], { command: 'whoami' });
|
|
42
42
|
process.exitCode = 1;
|
|
43
43
|
return null;
|
|
@@ -62,7 +62,7 @@ async function whoami() {
|
|
|
62
62
|
const username = data.user?.username;
|
|
63
63
|
if (!username) {
|
|
64
64
|
(0, messages_1.printErrorWithHelp)('The Playdrop API returned an unexpected response.', [
|
|
65
|
-
'Retry "playdrop whoami" in a moment.',
|
|
65
|
+
'Retry "playdrop auth whoami" in a moment.',
|
|
66
66
|
'If the problem continues, contact the Playdrop team.',
|
|
67
67
|
], { command: 'whoami' });
|
|
68
68
|
process.exitCode = 1;
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ const logout_1 = require("./commands/logout");
|
|
|
11
11
|
const browse_1 = require("./commands/browse");
|
|
12
12
|
const search_1 = require("./commands/search");
|
|
13
13
|
const detail_1 = require("./commands/detail");
|
|
14
|
+
const play_1 = require("./commands/play");
|
|
14
15
|
const comments_1 = require("./commands/comments");
|
|
15
16
|
const versionsBrowse_1 = require("./commands/versionsBrowse");
|
|
16
17
|
const credits_1 = require("./commands/credits");
|
|
@@ -174,6 +175,13 @@ program
|
|
|
174
175
|
.action(async (ref, opts) => {
|
|
175
176
|
await (0, detail_1.detail)(ref, opts);
|
|
176
177
|
});
|
|
178
|
+
program
|
|
179
|
+
.command('play <ref>')
|
|
180
|
+
.description('Open one published app in your browser with your current session')
|
|
181
|
+
.option('--json', 'Output JSON')
|
|
182
|
+
.action(async (ref, opts) => {
|
|
183
|
+
await (0, play_1.play)(ref, opts);
|
|
184
|
+
});
|
|
177
185
|
const comments = program.command('comments').description('Comments for apps, assets, and asset packs');
|
|
178
186
|
comments
|
|
179
187
|
.command('browse <ref>')
|
|
@@ -559,11 +567,15 @@ projectCapture
|
|
|
559
567
|
.option('--timeout <seconds>', 'Capture timeout in seconds')
|
|
560
568
|
.option('--screenshot <path>', 'Screenshot output path')
|
|
561
569
|
.option('--log <path>', 'Log output path')
|
|
570
|
+
.option('--expected-url <url>', 'Expected final URL after redirects')
|
|
562
571
|
.option('--username <username>', 'Login username')
|
|
563
572
|
.option('--password <password>', 'Login password')
|
|
564
573
|
.option('--login-url <url>', 'Explicit login URL')
|
|
565
|
-
.action(async (url,
|
|
566
|
-
await (0, captureRemote_1.captureRemote)(url,
|
|
574
|
+
.action(async (url, _opts, command) => {
|
|
575
|
+
await (0, captureRemote_1.captureRemote)(url, {
|
|
576
|
+
...(command.parent?.opts() ?? {}),
|
|
577
|
+
...command.opts(),
|
|
578
|
+
});
|
|
567
579
|
});
|
|
568
580
|
project
|
|
569
581
|
.command('validate [target]')
|
|
@@ -627,7 +639,7 @@ feedback
|
|
|
627
639
|
await (0, feedback_1.browseFeedback)(opts);
|
|
628
640
|
});
|
|
629
641
|
feedback
|
|
630
|
-
.command('delete <id>')
|
|
642
|
+
.command('delete <id>', { hidden: true })
|
|
631
643
|
.description('Delete one feedback entry')
|
|
632
644
|
.option('--json', 'Output JSON')
|
|
633
645
|
.action(async (id, opts) => {
|
package/dist/messages.js
CHANGED
|
@@ -28,22 +28,22 @@ function printErrorWithHelp(problem, suggestions, options = {}) {
|
|
|
28
28
|
}
|
|
29
29
|
function printLoginRequired(context, command) {
|
|
30
30
|
printErrorWithHelp(`${context} requires you to be logged in.`, [
|
|
31
|
-
'Run "playdrop login" to authenticate.',
|
|
32
|
-
'Use "playdrop whoami" to verify your current status.',
|
|
31
|
+
'Run "playdrop auth login" to authenticate.',
|
|
32
|
+
'Use "playdrop auth whoami" to verify your current status.',
|
|
33
33
|
], { command });
|
|
34
34
|
}
|
|
35
35
|
function printUnknownEnvironment(env, available, command) {
|
|
36
36
|
const listLine = available ? `Available environments: ${available}.` : '';
|
|
37
37
|
const suggestions = [
|
|
38
38
|
listLine,
|
|
39
|
-
'Run "playdrop login --env <env>" to store a supported environment before retrying.',
|
|
39
|
+
'Run "playdrop auth login --env <env>" to store a supported environment before retrying.',
|
|
40
40
|
].filter(Boolean);
|
|
41
41
|
printErrorWithHelp(`Environment "${env}" is not supported.`, suggestions, { command });
|
|
42
42
|
}
|
|
43
43
|
function printConfigEnvironmentMissing(command) {
|
|
44
44
|
printErrorWithHelp('No environment is configured yet.', [
|
|
45
|
-
'Run "playdrop login" to choose an environment and save your credentials.',
|
|
46
|
-
'Use "playdrop whoami" after logging in to confirm your status.',
|
|
45
|
+
'Run "playdrop auth login" to choose an environment and save your credentials.',
|
|
46
|
+
'Use "playdrop auth whoami" after logging in to confirm your status.',
|
|
47
47
|
], { command });
|
|
48
48
|
}
|
|
49
49
|
function printNetworkIssue(context, command) {
|
package/dist/playwright.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Browser, BrowserContextOptions, Page } from 'playwright-core';
|
|
1
|
+
import type { Browser, BrowserContext, BrowserContextOptions, Page } from 'playwright-core';
|
|
2
2
|
type PlaywrightModule = {
|
|
3
3
|
chromium: {
|
|
4
4
|
launch(options: {
|
|
@@ -12,6 +12,7 @@ export declare function setPlaywrightLoader(loader: (() => Promise<PlaywrightMod
|
|
|
12
12
|
export declare function createPlaywrightLaunchError(tool: string, error: unknown): Error;
|
|
13
13
|
type PageCallback<T> = (context: {
|
|
14
14
|
browser: Browser;
|
|
15
|
+
context: BrowserContext;
|
|
15
16
|
page: Page;
|
|
16
17
|
}) => Promise<T>;
|
|
17
18
|
export declare function withChromiumPage<T>(callback: PageCallback<T>, contextOptions?: BrowserContextOptions): Promise<T>;
|
package/dist/playwright.js
CHANGED
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.setPlaywrightLoader = setPlaywrightLoader;
|
|
37
37
|
exports.createPlaywrightLaunchError = createPlaywrightLaunchError;
|
|
38
38
|
exports.withChromiumPage = withChromiumPage;
|
|
39
|
+
const node_url_1 = require("node:url");
|
|
39
40
|
const TOOL_NAME = 'playdrop';
|
|
40
41
|
// Force software WebGL so headless model preview generation remains stable on local/dev machines.
|
|
41
42
|
const CHROMIUM_ARGS = [
|
|
@@ -47,6 +48,7 @@ const CHROMIUM_ARGS = [
|
|
|
47
48
|
'--ignore-gpu-blocklist',
|
|
48
49
|
];
|
|
49
50
|
let customLoader = null;
|
|
51
|
+
const nativeImport = new Function('specifier', 'return import(specifier);');
|
|
50
52
|
function setPlaywrightLoader(loader) {
|
|
51
53
|
customLoader = loader;
|
|
52
54
|
}
|
|
@@ -54,6 +56,21 @@ async function loadPlaywright() {
|
|
|
54
56
|
if (customLoader) {
|
|
55
57
|
return customLoader();
|
|
56
58
|
}
|
|
59
|
+
const loaderPath = process.env.PLAYDROP_PLAYWRIGHT_LOADER_PATH?.trim();
|
|
60
|
+
if (loaderPath) {
|
|
61
|
+
const loaderModule = await nativeImport((0, node_url_1.pathToFileURL)(loaderPath).href);
|
|
62
|
+
const candidate = loaderModule.loadPlaywright
|
|
63
|
+
?? loaderModule.createPlaywrightModule
|
|
64
|
+
?? loaderModule.default
|
|
65
|
+
?? loaderModule;
|
|
66
|
+
if (typeof candidate === 'function') {
|
|
67
|
+
return await candidate();
|
|
68
|
+
}
|
|
69
|
+
if (candidate && typeof candidate === 'object' && typeof candidate.chromium?.launch === 'function') {
|
|
70
|
+
return candidate;
|
|
71
|
+
}
|
|
72
|
+
throw new Error(`Invalid Playwright loader module at ${loaderPath}.`);
|
|
73
|
+
}
|
|
57
74
|
return Promise.resolve().then(() => __importStar(require('playwright-core')));
|
|
58
75
|
}
|
|
59
76
|
function createPlaywrightLaunchError(tool, error) {
|
|
@@ -85,7 +102,7 @@ async function withChromiumPage(callback, contextOptions = {}) {
|
|
|
85
102
|
try {
|
|
86
103
|
context = await browser.newContext(contextOptions);
|
|
87
104
|
const page = await context.newPage();
|
|
88
|
-
return await callback({ browser, page });
|
|
105
|
+
return await callback({ browser, context, page });
|
|
89
106
|
}
|
|
90
107
|
finally {
|
|
91
108
|
if (context) {
|
package/dist/uploadLog.d.ts
CHANGED
|
@@ -7,9 +7,11 @@ export type TaskLogEntry = {
|
|
|
7
7
|
entityId: string;
|
|
8
8
|
catalogue: string;
|
|
9
9
|
detail?: string;
|
|
10
|
+
playUrl?: string | null;
|
|
10
11
|
};
|
|
11
12
|
export declare function formatTaskLogLine(entry: TaskLogEntry): string;
|
|
12
13
|
export declare function printTaskSummary(entries: TaskLogEntry[], warnings: Iterable<string>, options: {
|
|
13
14
|
action: TaskAction;
|
|
14
15
|
environment?: string;
|
|
15
16
|
}): void;
|
|
17
|
+
export declare function printPublishedAppNextSteps(entries: TaskLogEntry[]): void;
|
package/dist/uploadLog.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.formatTaskLogLine = formatTaskLogLine;
|
|
4
4
|
exports.printTaskSummary = printTaskSummary;
|
|
5
|
+
exports.printPublishedAppNextSteps = printPublishedAppNextSteps;
|
|
5
6
|
const STATUS_EMOJI = {
|
|
6
7
|
success: '✅',
|
|
7
8
|
skipped: '➖',
|
|
@@ -116,3 +117,16 @@ function printTaskSummary(entries, warnings, options) {
|
|
|
116
117
|
}
|
|
117
118
|
console.log(parts.join(', '));
|
|
118
119
|
}
|
|
120
|
+
function printPublishedAppNextSteps(entries) {
|
|
121
|
+
const apps = entries.filter((entry) => entry.status === 'success' && entry.entityType === 'app' && entry.playUrl);
|
|
122
|
+
for (const entry of apps) {
|
|
123
|
+
const playUrl = entry.playUrl;
|
|
124
|
+
console.log('');
|
|
125
|
+
console.log(`Next steps for ${entry.entityId}:`);
|
|
126
|
+
console.log(`- Manually test the game at ${playUrl} and make sure it is working and up to spec.`);
|
|
127
|
+
console.log(`- Once satisfied, share the game URL on social media to start having people play it: ${playUrl}`);
|
|
128
|
+
console.log('- Publish the code on GitHub in a public repo with the playable game link in the README.');
|
|
129
|
+
console.log('- Set up automation to check player feedback every day using play count, likes, and comments, then come up with improvement ideas from it.');
|
|
130
|
+
console.log('- Send feedback to Playdrop with "playdrop feedback send" for any bugs or improvement ideas you encountered.');
|
|
131
|
+
}
|
|
132
|
+
}
|