@playdrop/playdrop-cli 0.5.3 → 0.5.5

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.
Files changed (47) hide show
  1. package/config/client-meta.json +4 -4
  2. package/dist/commandContext.d.ts +6 -2
  3. package/dist/commandContext.js +144 -20
  4. package/dist/commands/accounts.d.ts +2 -0
  5. package/dist/commands/accounts.js +48 -0
  6. package/dist/commands/capture.js +30 -9
  7. package/dist/commands/captureListing.js +16 -5
  8. package/dist/commands/dev.js +169 -192
  9. package/dist/commands/devServer.d.ts +26 -3
  10. package/dist/commands/devServer.js +406 -68
  11. package/dist/commands/login.js +10 -2
  12. package/dist/commands/logout.d.ts +6 -1
  13. package/dist/commands/logout.js +25 -3
  14. package/dist/commands/whoami.js +10 -2
  15. package/dist/config.d.ts +37 -0
  16. package/dist/config.js +205 -3
  17. package/dist/index.js +32 -2
  18. package/dist/workspaceAuth.d.ts +14 -0
  19. package/dist/workspaceAuth.js +75 -0
  20. package/node_modules/@playdrop/ai-client/package.json +1 -1
  21. package/node_modules/@playdrop/api-client/dist/client.d.ts +10 -1
  22. package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
  23. package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts +2 -1
  24. package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts.map +1 -1
  25. package/node_modules/@playdrop/api-client/dist/domains/admin.js +11 -0
  26. package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts +4 -1
  27. package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts.map +1 -1
  28. package/node_modules/@playdrop/api-client/dist/domains/apps.js +31 -0
  29. package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts +5 -0
  30. package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts.map +1 -1
  31. package/node_modules/@playdrop/api-client/dist/domains/payments.js +55 -0
  32. package/node_modules/@playdrop/api-client/dist/index.d.ts +11 -0
  33. package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
  34. package/node_modules/@playdrop/api-client/dist/index.js +27 -0
  35. package/node_modules/@playdrop/api-client/package.json +1 -1
  36. package/node_modules/@playdrop/boxel-core/package.json +1 -1
  37. package/node_modules/@playdrop/boxel-three/package.json +1 -1
  38. package/node_modules/@playdrop/config/client-meta.json +4 -4
  39. package/node_modules/@playdrop/config/package.json +1 -1
  40. package/node_modules/@playdrop/types/dist/api.d.ts +26 -0
  41. package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
  42. package/node_modules/@playdrop/types/dist/version.d.ts +1 -1
  43. package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
  44. package/node_modules/@playdrop/types/dist/version.js +1 -0
  45. package/node_modules/@playdrop/types/package.json +1 -1
  46. package/node_modules/@playdrop/vox-three/package.json +1 -1
  47. package/package.json +1 -1
@@ -4,40 +4,15 @@ exports.dev = dev;
4
4
  const node_fs_1 = require("node:fs");
5
5
  const node_path_1 = require("node:path");
6
6
  const types_1 = require("@playdrop/types");
7
- const config_1 = require("../config");
8
- const apiClient_1 = require("../apiClient");
7
+ const commandContext_1 = require("../commandContext");
9
8
  const http_1 = require("../http");
10
- const environment_1 = require("../environment");
11
9
  const messages_1 = require("../messages");
12
10
  const catalogue_utils_1 = require("../catalogue-utils");
13
11
  const devShared_1 = require("./devShared");
12
+ const appUrls_1 = require("../appUrls");
14
13
  const devServer_1 = require("./devServer");
15
- const DEFAULT_DEV_PORT = 8888;
16
14
  const DEFAULT_ROOM_BASE = 'http://localhost:3001';
17
15
  async function dev(targetArg, _port, appOption) {
18
- const cfg = (0, config_1.loadConfig)();
19
- if (!cfg.env) {
20
- (0, messages_1.printConfigEnvironmentMissing)('project dev');
21
- process.exitCode = 1;
22
- return;
23
- }
24
- if (!cfg.token) {
25
- (0, messages_1.printLoginRequired)('Starting the dev server', 'project dev');
26
- process.exitCode = 1;
27
- return;
28
- }
29
- const envConfig = (0, environment_1.resolveEnvironmentConfig)(cfg.env);
30
- if (!envConfig) {
31
- const choices = (0, environment_1.formatEnvironmentList)();
32
- (0, messages_1.printUnknownEnvironment)(cfg.env, choices, 'project dev');
33
- process.exitCode = 1;
34
- return;
35
- }
36
- if (envConfig.allowInsecureRequests) {
37
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
38
- }
39
- const client = (0, apiClient_1.createCliApiClient)({ baseUrl: envConfig.apiBase, token: cfg.token });
40
- const portToUse = DEFAULT_DEV_PORT;
41
16
  let resolvedTarget;
42
17
  try {
43
18
  resolvedTarget = (0, devShared_1.resolveDevTarget)(targetArg, appOption);
@@ -86,14 +61,7 @@ async function dev(targetArg, _port, appOption) {
86
61
  try {
87
62
  const match = (0, catalogue_utils_1.findAppDefinition)(filePath);
88
63
  appName = match.name;
89
- appTypeSlug =
90
- match.type === 'TOOL'
91
- ? 'tool'
92
- : match.type === 'TEMPLATE'
93
- ? 'template'
94
- : match.type === 'DEMO'
95
- ? 'demo'
96
- : 'game';
64
+ appTypeSlug = (0, appUrls_1.getAppTypeSlug)(match.type);
97
65
  }
98
66
  catch (error) {
99
67
  if (resolvedTarget.cataloguePath) {
@@ -105,179 +73,188 @@ async function dev(targetArg, _port, appOption) {
105
73
  return;
106
74
  }
107
75
  }
108
- let currentUsername = '';
109
- try {
110
- currentUsername = await (0, devShared_1.fetchDevUsername)(client);
111
- }
112
- catch (error) {
113
- if (error instanceof http_1.CLIUnsupportedClientError) {
114
- return;
115
- }
116
- if (error instanceof types_1.UnsupportedClientError) {
117
- (0, http_1.handleUnsupportedError)(error, 'Authentication');
118
- process.exitCode = 1;
119
- return;
120
- }
121
- if (error instanceof types_1.ApiError) {
122
- (0, messages_1.printErrorWithHelp)(`Could not fetch your account (status ${error.status}).`, [
123
- 'Run "playdrop auth login" to refresh your session and ensure the API is reachable.',
124
- 'Use "playdrop auth whoami" afterwards to confirm your status.',
125
- ], { command: 'project dev' });
126
- process.exitCode = 1;
127
- return;
128
- }
129
- if ((0, devShared_1.isNetworkError)(error)) {
130
- (0, messages_1.printNetworkIssue)('Could not reach the Playdrop API to resolve your account.', 'project dev');
131
- process.exitCode = 1;
132
- return;
133
- }
134
- if (error instanceof Error && error.message === 'DEV_USERNAME_EMPTY') {
135
- (0, messages_1.printErrorWithHelp)('Could not determine your Playdrop creator username.', [
136
- 'Retry "playdrop project dev" in a moment.',
137
- 'If the problem persists, contact the Playdrop team.'
138
- ], { command: 'project dev' });
139
- process.exitCode = 1;
140
- return;
141
- }
142
- throw error;
143
- }
144
- let appResponse = null;
145
- if (resolvedTarget.cataloguePath) {
146
- try {
147
- appResponse = await (0, devShared_1.assertAppRegistered)(client, currentUsername, appName);
76
+ const workspacePath = resolvedTarget.cataloguePath ?? (0, node_path_1.dirname)(filePath);
77
+ await (0, commandContext_1.withEnvironment)('project dev', 'Starting the dev server',
78
+ // eslint-disable-next-line complexity
79
+ async ({ client, env, envConfig, account }) => {
80
+ let currentUsername = account?.username?.trim() ?? '';
81
+ if (!currentUsername) {
82
+ try {
83
+ currentUsername = await (0, devShared_1.fetchDevUsername)(client);
84
+ }
85
+ catch (error) {
86
+ if (error instanceof http_1.CLIUnsupportedClientError) {
87
+ return;
88
+ }
89
+ if (error instanceof types_1.UnsupportedClientError) {
90
+ (0, http_1.handleUnsupportedError)(error, 'Authentication');
91
+ process.exitCode = 1;
92
+ return;
93
+ }
94
+ if (error instanceof types_1.ApiError) {
95
+ (0, messages_1.printErrorWithHelp)(`Could not fetch your account (status ${error.status}).`, [
96
+ 'Run "playdrop auth login" to refresh your session and ensure the API is reachable.',
97
+ 'Use "playdrop auth whoami" afterwards to confirm your status.',
98
+ ], { command: 'project dev' });
99
+ process.exitCode = 1;
100
+ return;
101
+ }
102
+ if ((0, devShared_1.isNetworkError)(error)) {
103
+ (0, messages_1.printNetworkIssue)('Could not reach the Playdrop API to resolve your account.', 'project dev');
104
+ process.exitCode = 1;
105
+ return;
106
+ }
107
+ throw error;
108
+ }
148
109
  }
149
- catch (error) {
150
- if (error instanceof http_1.CLIUnsupportedClientError) {
151
- return;
110
+ let appResponse = null;
111
+ if (resolvedTarget.cataloguePath) {
112
+ try {
113
+ appResponse = await (0, devShared_1.assertAppRegistered)(client, currentUsername, appName);
152
114
  }
153
- if (error instanceof types_1.UnsupportedClientError) {
154
- (0, http_1.handleUnsupportedError)(error, 'Dev');
155
- process.exitCode = 1;
156
- return;
115
+ catch (error) {
116
+ if (error instanceof http_1.CLIUnsupportedClientError) {
117
+ return;
118
+ }
119
+ if (error instanceof types_1.UnsupportedClientError) {
120
+ (0, http_1.handleUnsupportedError)(error, 'Dev');
121
+ process.exitCode = 1;
122
+ return;
123
+ }
124
+ if (error instanceof types_1.ApiError) {
125
+ if (error.status === 404) {
126
+ (0, messages_1.printErrorWithHelp)(`App ${currentUsername}/${appName} is not registered on ${env}.`, [
127
+ `Run "playdrop project create app ${appName}" to register the app before starting the dev server.`,
128
+ 'If you expected it to exist, ensure you are logged into the correct environment.'
129
+ ], { command: 'project dev' });
130
+ }
131
+ else {
132
+ (0, messages_1.printErrorWithHelp)(`Failed to verify app registration (status ${error.status}).`, [
133
+ 'Retry in a moment.',
134
+ 'If the issue persists, contact the Playdrop team.'
135
+ ], { command: 'project dev' });
136
+ }
137
+ process.exitCode = 1;
138
+ return;
139
+ }
140
+ if ((0, devShared_1.isNetworkError)(error)) {
141
+ (0, messages_1.printNetworkIssue)('Could not reach the Playdrop API to verify the app registration.', 'project dev');
142
+ process.exitCode = 1;
143
+ return;
144
+ }
145
+ throw error;
157
146
  }
158
- if (error instanceof types_1.ApiError) {
159
- if (error.status === 404) {
160
- (0, messages_1.printErrorWithHelp)(`App ${currentUsername}/${appName} is not registered on ${cfg.env}.`, [
161
- `Run "playdrop project create app ${appName}" to register the app before starting the dev server.`,
162
- 'If you expected it to exist, ensure you are logged into the correct environment.'
163
- ], { command: 'project dev' });
147
+ }
148
+ const projectInfo = (0, devShared_1.findProjectInfo)(filePath);
149
+ const devScriptAvailable = Boolean(projectInfo.projectDir && projectInfo.packageJson && typeof projectInfo.packageJson.scripts?.dev === 'string');
150
+ if (resolvedTarget.ecsPath && resolvedTarget.serverScriptPath && appResponse?.id) {
151
+ try {
152
+ if (!(0, node_fs_1.existsSync)(resolvedTarget.ecsPath) || !(0, node_fs_1.existsSync)(resolvedTarget.serverScriptPath)) {
153
+ throw new Error('ecs_or_server_missing');
164
154
  }
165
- else {
166
- (0, messages_1.printErrorWithHelp)(`Failed to verify app registration (status ${error.status}).`, [
167
- 'Retry in a moment.',
168
- 'If the issue persists, contact the Playdrop team.'
169
- ], { command: 'project dev' });
155
+ const ecsRaw = (0, node_fs_1.readFileSync)(resolvedTarget.ecsPath, 'utf8');
156
+ const ecsJson = JSON.parse(ecsRaw);
157
+ const serverJs = (0, node_fs_1.readFileSync)(resolvedTarget.serverScriptPath, 'utf8');
158
+ const roomBase = (process.env.PLAYDROP_ROOM_BASE || DEFAULT_ROOM_BASE).replace(/\/$/, '');
159
+ const response = await fetch(`${roomBase}/rooms/dev_config`, {
160
+ method: 'POST',
161
+ headers: { 'Content-Type': 'application/json' },
162
+ body: JSON.stringify({
163
+ app_id: appResponse.id,
164
+ ecs: ecsJson,
165
+ server_js: serverJs,
166
+ }),
167
+ });
168
+ if (!response.ok) {
169
+ let reason = `${response.status}`;
170
+ try {
171
+ const payload = await response.json();
172
+ if (payload?.error) {
173
+ reason = payload.error;
174
+ }
175
+ }
176
+ catch {
177
+ // ignore parse errors
178
+ }
179
+ throw new Error(`room_dev_config_failed:${reason}`);
170
180
  }
171
- process.exitCode = 1;
172
- return;
181
+ console.log(`Uploaded dev ECS config to engine-server for app ${appName}.`);
173
182
  }
174
- if ((0, devShared_1.isNetworkError)(error)) {
175
- (0, messages_1.printNetworkIssue)('Could not reach the Playdrop API to verify the app registration.', 'project dev');
183
+ catch (error) {
184
+ (0, messages_1.printErrorWithHelp)(error?.message || 'Failed to upload dev ECS config to engine-server.', [
185
+ 'Ensure catalogue entry includes valid "ecs" and "server" paths.',
186
+ 'Check PLAYDROP_ROOM_BASE or the default http://localhost:3001 is reachable.',
187
+ ], { command: 'project dev' });
176
188
  process.exitCode = 1;
177
189
  return;
178
190
  }
179
- throw error;
180
191
  }
181
- }
182
- const projectInfo = (0, devShared_1.findProjectInfo)(filePath);
183
- const devScriptAvailable = Boolean(projectInfo.projectDir && projectInfo.packageJson && typeof projectInfo.packageJson.scripts?.dev === 'string');
184
- // Upload ECS dev assets to engine-server if configured.
185
- if (resolvedTarget.ecsPath && resolvedTarget.serverScriptPath && appResponse?.id) {
192
+ let handle;
186
193
  try {
187
- if (!(0, node_fs_1.existsSync)(resolvedTarget.ecsPath) || !(0, node_fs_1.existsSync)(resolvedTarget.serverScriptPath)) {
188
- throw new Error('ecs_or_server_missing');
189
- }
190
- const ecsRaw = (0, node_fs_1.readFileSync)(resolvedTarget.ecsPath, 'utf8');
191
- const ecsJson = JSON.parse(ecsRaw);
192
- const serverJs = (0, node_fs_1.readFileSync)(resolvedTarget.serverScriptPath, 'utf8');
193
- const roomBase = (process.env.PLAYDROP_ROOM_BASE || DEFAULT_ROOM_BASE).replace(/\/$/, '');
194
- const response = await fetch(`${roomBase}/rooms/dev_config`, {
195
- method: 'POST',
196
- headers: { 'Content-Type': 'application/json' },
197
- body: JSON.stringify({
198
- app_id: appResponse.id,
199
- ecs: ecsJson,
200
- server_js: serverJs,
201
- }),
194
+ handle = await (0, devServer_1.startDevServer)({
195
+ appName,
196
+ appType: appTypeSlug,
197
+ creatorUsername: currentUsername,
198
+ htmlPath: filePath,
199
+ port: devServer_1.DEV_ROUTER_PORT,
200
+ projectInfo,
202
201
  });
203
- if (!response.ok) {
204
- let reason = `${response.status}`;
205
- try {
206
- const payload = await response.json();
207
- if (payload?.error) {
208
- reason = payload.error;
209
- }
210
- }
211
- catch {
212
- // ignore parse errors
213
- }
214
- throw new Error(`room_dev_config_failed:${reason}`);
215
- }
216
- console.log(`Uploaded dev ECS config to engine-server for app ${appName}.`);
217
202
  }
218
203
  catch (error) {
219
- (0, messages_1.printErrorWithHelp)(error?.message || 'Failed to upload dev ECS config to engine-server.', [
220
- 'Ensure catalogue entry includes valid "ecs" and "server" paths.',
221
- 'Check PLAYDROP_ROOM_BASE or the default http://localhost:3001 is reachable.',
222
- ], { command: 'project dev' });
204
+ const message = typeof error?.message === 'string' ? error.message : '';
205
+ const mountConflict = (0, devServer_1.parseMountConflictError)(message);
206
+ if (mountConflict) {
207
+ (0, messages_1.printErrorWithHelp)(`A different dev session already owns ${mountConflict.ref}.`, [
208
+ `Active owner pid: ${mountConflict.ownerPid}.`,
209
+ `Mounted repo root: ${mountConflict.repoRoot}.`,
210
+ `Mounted HTML path: ${mountConflict.htmlPath}.`,
211
+ ], { command: 'project dev' });
212
+ }
213
+ else {
214
+ (0, messages_1.printErrorWithHelp)(error?.message || `Failed to start the shared dev router on port ${devServer_1.DEV_ROUTER_PORT}.`, [
215
+ 'Close the conflicting process or wait for the stale mount to exit.',
216
+ 'Ensure the app HTML file exists and is readable.',
217
+ ], { command: 'project dev' });
218
+ }
223
219
  process.exitCode = 1;
224
220
  return;
225
221
  }
226
- }
227
- let handle;
228
- try {
229
- handle = await (0, devServer_1.startDevServer)({
230
- appName,
231
- htmlPath: filePath,
232
- port: portToUse,
233
- projectInfo,
234
- });
235
- }
236
- catch (error) {
237
- (0, messages_1.printErrorWithHelp)(error?.message || `Failed to start dev server on port ${portToUse}.`, [
238
- 'Check if another process is already using the port.',
239
- 'Ensure the HTML file exists and is readable.',
240
- ], { command: 'project dev' });
241
- process.exitCode = 1;
242
- return;
243
- }
244
- let shuttingDown = false;
245
- const handleShutdown = () => {
246
- if (shuttingDown)
247
- return;
248
- shuttingDown = true;
249
- handle
250
- .close()
251
- .catch(closeError => {
252
- console.error(closeError instanceof Error ? closeError.message : closeError);
253
- });
254
- };
255
- process.on('SIGINT', handleShutdown);
256
- process.on('SIGTERM', handleShutdown);
257
- handle.server.on('close', () => {
258
- process.off('SIGINT', handleShutdown);
259
- process.off('SIGTERM', handleShutdown);
260
- });
261
- const webUrl = envConfig.webBase;
262
- const entryLabel = (0, node_path_1.relative)(process.cwd(), filePath) || filePath;
263
- const runtimeRootLabel = (0, node_path_1.relative)(process.cwd(), (0, node_path_1.dirname)(filePath)) || (0, node_path_1.dirname)(filePath);
264
- console.log(`šŸš€ App dev server running at http://localhost:${portToUse}`);
265
- console.log(`Serving ${entryLabel}`);
266
- console.log(`Static root ${runtimeRootLabel}`);
267
- if (projectInfo.projectDir && !devScriptAvailable && projectInfo.packageJsonPath) {
268
- const projectLabel = (0, devShared_1.formatProjectLabel)(projectInfo);
269
- if (projectLabel) {
270
- console.log(`ā„¹ļø package.json detected at ${projectLabel}, but no "dev" script was found. Run your build/watch scripts manually if needed.`);
222
+ let shuttingDown = false;
223
+ const handleShutdown = () => {
224
+ if (shuttingDown)
225
+ return;
226
+ shuttingDown = true;
227
+ process.off('SIGINT', handleShutdown);
228
+ process.off('SIGTERM', handleShutdown);
229
+ handle
230
+ .close()
231
+ .catch(closeError => {
232
+ console.error(closeError instanceof Error ? closeError.message : closeError);
233
+ });
234
+ };
235
+ process.on('SIGINT', handleShutdown);
236
+ process.on('SIGTERM', handleShutdown);
237
+ const webUrl = envConfig.webBase;
238
+ const entryLabel = (0, node_path_1.relative)(process.cwd(), filePath) || filePath;
239
+ const runtimeRootLabel = (0, node_path_1.relative)(process.cwd(), (0, node_path_1.dirname)(filePath)) || (0, node_path_1.dirname)(filePath);
240
+ console.log(`App dev router mounted at ${handle.appUrl}`);
241
+ console.log(`Serving ${entryLabel}`);
242
+ console.log(`Static root ${runtimeRootLabel}`);
243
+ if (projectInfo.projectDir && !devScriptAvailable && projectInfo.packageJsonPath) {
244
+ const projectLabel = (0, devShared_1.formatProjectLabel)(projectInfo);
245
+ if (projectLabel) {
246
+ console.log(`package.json detected at ${projectLabel}, but no "dev" script was found. Run your build/watch scripts manually if needed.`);
247
+ }
271
248
  }
272
- }
273
- if (webUrl) {
274
- const iframeUrl = `${webUrl}/creators/${encodeURIComponent(currentUsername)}/apps/${appTypeSlug}/${encodeURIComponent(appName)}/dev`;
275
- console.log(`\nšŸŽ® Test your app at:`);
276
- console.log(` ${iframeUrl}`);
277
- console.log('\nMake something fun then share it with');
278
- console.log(`playdrop project publish ${appName}`);
279
- }
280
- else {
281
- console.log(`\nOpen ${handle.appUrl} in your browser to test locally.`);
282
- }
249
+ if (webUrl) {
250
+ const iframeUrl = `${webUrl}/creators/${encodeURIComponent(currentUsername)}/apps/${appTypeSlug}/${encodeURIComponent(appName)}/dev`;
251
+ console.log('\nTest your app at:');
252
+ console.log(` ${iframeUrl}`);
253
+ console.log('\nMake something fun then share it with');
254
+ console.log(`playdrop project publish ${appName}`);
255
+ }
256
+ else {
257
+ console.log(`\nOpen ${handle.appUrl} in your browser to test locally.`);
258
+ }
259
+ }, { workspacePath });
283
260
  }
@@ -1,18 +1,41 @@
1
- import http from 'node:http';
2
1
  import { type ChildProcess } from 'node:child_process';
3
2
  import type { ProjectInfo } from './devShared';
4
3
  export interface StartDevServerOptions {
5
4
  appName: string;
5
+ appType: string;
6
+ creatorUsername: string;
6
7
  htmlPath: string;
7
8
  port: number;
8
9
  projectInfo: ProjectInfo;
9
10
  }
10
11
  export interface DevServerHandle {
11
- server: http.Server;
12
+ server: null;
12
13
  devProcess: ChildProcess | null;
13
14
  startedDevProcess: boolean;
14
15
  appUrl: string;
15
16
  close(): Promise<void>;
16
17
  }
18
+ export declare const DEV_ROUTER_PORT = 8888;
19
+ type MountConflictDetails = {
20
+ ref: string;
21
+ ownerPid: number;
22
+ repoRoot: string;
23
+ htmlPath: string;
24
+ };
25
+ export declare function parseMountConflictError(message: string): MountConflictDetails | null;
26
+ export declare function buildLocalDevAppUrl(input: {
27
+ creatorUsername: string;
28
+ appType: string;
29
+ appName: string;
30
+ port?: number;
31
+ }): string;
32
+ export declare function ensureDevRouterRunning(port?: number): Promise<void>;
17
33
  export declare function startDevServer(options: StartDevServerOptions): Promise<DevServerHandle>;
18
- export declare function isDevServerAvailable(appName: string, port: number, timeoutMs?: number): Promise<boolean>;
34
+ export declare function isDevServerAvailable(input: {
35
+ creatorUsername: string;
36
+ appType: string;
37
+ appName: string;
38
+ port?: number;
39
+ }, timeoutMs?: number): Promise<boolean>;
40
+ export declare function runDevRouterServer(port?: number): Promise<void>;
41
+ export {};