@dcl/sdk-commands 7.0.0-4286109573.commit-baaf951 → 7.0.0-4294380152.commit-0d08b10
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/dist/commands/build/index.d.ts +1 -1
- package/dist/commands/build/index.js +9 -0
- package/dist/commands/export-static/index.d.ts +1 -1
- package/dist/commands/export-static/index.js +7 -0
- package/dist/commands/init/index.d.ts +1 -1
- package/dist/commands/init/index.js +1 -0
- package/dist/commands/start/index.d.ts +1 -1
- package/dist/commands/start/index.js +9 -1
- package/dist/commands/start/server/endpoints.js +2 -3
- package/dist/components/analytics.d.ts +38 -0
- package/dist/components/analytics.js +66 -0
- package/dist/components/dcl-info-config.d.ts +11 -0
- package/dist/components/dcl-info-config.js +75 -0
- package/dist/components/index.d.ts +5 -1
- package/dist/components/index.js +9 -3
- package/dist/index.js +2 -1
- package/dist/logic/config.d.ts +16 -0
- package/dist/logic/config.js +42 -0
- package/dist/logic/dcl-ignore.js +1 -0
- package/dist/logic/fs.d.ts +12 -0
- package/dist/logic/fs.js +29 -1
- package/dist/logic/project-files.d.ts +5 -0
- package/dist/logic/project-files.js +18 -2
- package/dist/logic/scene-validations.d.ts +4 -0
- package/dist/logic/scene-validations.js +11 -3
- package/package.json +10 -4
- package/src/commands/build/index.ts +0 -68
- package/src/commands/export-static/index.ts +0 -142
- package/src/commands/init/index.ts +0 -67
- package/src/commands/init/repos.ts +0 -17
- package/src/commands/start/index.ts +0 -213
- package/src/commands/start/server/endpoints.ts +0 -473
- package/src/commands/start/server/file-watch-notifier.ts +0 -45
- package/src/commands/start/server/realm.ts +0 -63
- package/src/commands/start/server/routes.ts +0 -36
- package/src/commands/start/server/ws.ts +0 -24
- package/src/commands/start/types.ts +0 -26
- package/src/components/eth.ts +0 -3
- package/src/components/fetch.ts +0 -11
- package/src/components/fs.ts +0 -62
- package/src/components/index.ts +0 -18
- package/src/components/log.ts +0 -48
- package/src/index.ts +0 -90
- package/src/logic/args.ts +0 -19
- package/src/logic/beautiful-logs.ts +0 -26
- package/src/logic/catalyst-requests.ts +0 -31
- package/src/logic/commands.ts +0 -28
- package/src/logic/coordinates.ts +0 -95
- package/src/logic/dcl-ignore.ts +0 -49
- package/src/logic/error.ts +0 -1
- package/src/logic/exec.ts +0 -36
- package/src/logic/fs.ts +0 -41
- package/src/logic/get-free-port.ts +0 -15
- package/src/logic/project-files.ts +0 -76
- package/src/logic/project-validations.ts +0 -61
- package/src/logic/realm.ts +0 -28
- package/src/logic/scene-validations.ts +0 -73
- package/tsconfig.json +0 -28
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validateSceneJson = exports.assertValidScene = exports.getSceneFilePath = exports.SCENE_FILE = void 0;
|
|
3
|
+
exports.getBaseCoords = exports.validateSceneJson = exports.assertValidScene = exports.getSceneFilePath = exports.SCENE_FILE = void 0;
|
|
4
4
|
const path_1 = require("path");
|
|
5
5
|
const schemas_1 = require("@dcl/schemas");
|
|
6
6
|
const error_1 = require("./error");
|
|
7
7
|
const coordinates_1 = require("./coordinates");
|
|
8
|
+
const project_files_1 = require("./project-files");
|
|
8
9
|
exports.SCENE_FILE = 'scene.json';
|
|
9
10
|
/**
|
|
10
11
|
* Composes the path to the `scene.json` file based on the provided path.
|
|
@@ -53,8 +54,7 @@ exports.assertValidScene = assertValidScene;
|
|
|
53
54
|
*/
|
|
54
55
|
async function validateSceneJson(components, projectRoot) {
|
|
55
56
|
try {
|
|
56
|
-
const
|
|
57
|
-
const sceneJson = JSON.parse(sceneJsonRaw);
|
|
57
|
+
const sceneJson = await (0, project_files_1.getSceneJson)(components, projectRoot);
|
|
58
58
|
return assertValidScene(sceneJson);
|
|
59
59
|
}
|
|
60
60
|
catch (err) {
|
|
@@ -62,3 +62,11 @@ async function validateSceneJson(components, projectRoot) {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
exports.validateSceneJson = validateSceneJson;
|
|
65
|
+
function getBaseCoords(scene) {
|
|
66
|
+
const [x, y] = scene.scene.base
|
|
67
|
+
.replace(/\ /g, '')
|
|
68
|
+
.split(',')
|
|
69
|
+
.map((a) => parseInt(a));
|
|
70
|
+
return { x, y };
|
|
71
|
+
}
|
|
72
|
+
exports.getBaseCoords = getBaseCoords;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcl/sdk-commands",
|
|
3
|
-
"version": "7.0.0-
|
|
3
|
+
"version": "7.0.0-4294380152.commit-0d08b10",
|
|
4
4
|
"description": "",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "tsc -p tsconfig.json",
|
|
@@ -16,11 +16,12 @@
|
|
|
16
16
|
"author": "Decentraland",
|
|
17
17
|
"license": "Apache-2.0",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@dcl/dcl-rollup": "7.0.6-
|
|
19
|
+
"@dcl/dcl-rollup": "7.0.6-4294380152.commit-0d08b10",
|
|
20
20
|
"@dcl/hashing": "1.1.3",
|
|
21
21
|
"@dcl/mini-comms": "1.0.1-20230216163137.commit-a4c75be",
|
|
22
22
|
"@dcl/protocol": "1.0.0-4114477251.commit-ccb88d6",
|
|
23
23
|
"@dcl/schemas": "6.10.0",
|
|
24
|
+
"@segment/analytics-node": "^1.0.0-beta.22",
|
|
24
25
|
"@well-known-components/env-config-provider": "^1.2.0",
|
|
25
26
|
"@well-known-components/http-server": "^2.0.0-20230216161243.commit-bfe3f0a",
|
|
26
27
|
"@well-known-components/logger": "^3.1.2",
|
|
@@ -33,10 +34,12 @@
|
|
|
33
34
|
"node-fetch": "^2.6.8",
|
|
34
35
|
"open": "^8.4.0",
|
|
35
36
|
"portfinder": "^1.0.32",
|
|
36
|
-
"undici": "^5.19.1"
|
|
37
|
+
"undici": "^5.19.1",
|
|
38
|
+
"uuid": "^9.0.0"
|
|
37
39
|
},
|
|
38
40
|
"devDependencies": {
|
|
39
41
|
"@types/node-fetch": "^2.6.1",
|
|
42
|
+
"@types/uuid": "^9.0.1",
|
|
40
43
|
"@types/ws": "^8.5.4"
|
|
41
44
|
},
|
|
42
45
|
"minCliVersion": "3.14.1",
|
|
@@ -46,5 +49,8 @@
|
|
|
46
49
|
"displayName": "SDK",
|
|
47
50
|
"tsconfig": "./tsconfig.json"
|
|
48
51
|
},
|
|
49
|
-
"
|
|
52
|
+
"files": [
|
|
53
|
+
"dist"
|
|
54
|
+
],
|
|
55
|
+
"commit": "0d08b10653a3c1b7ccac2fec26b0e3fdf2d6e98b"
|
|
50
56
|
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'path'
|
|
2
|
-
import { CliComponents } from '../../components'
|
|
3
|
-
import { getArgs } from '../../logic/args'
|
|
4
|
-
import { compile } from '@dcl/dcl-rollup/compile'
|
|
5
|
-
import future from 'fp-future'
|
|
6
|
-
import { assertValidProjectFolder, installDependencies, needsDependencies } from '../../logic/project-validations'
|
|
7
|
-
|
|
8
|
-
interface Options {
|
|
9
|
-
args: Omit<typeof args, '_'>
|
|
10
|
-
components: Pick<CliComponents, 'fs' | 'logger'>
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const args = getArgs({
|
|
14
|
-
'--watch': Boolean,
|
|
15
|
-
'-w': '--watch',
|
|
16
|
-
'--production': Boolean,
|
|
17
|
-
'-p': '--production',
|
|
18
|
-
'--skip-install': Boolean,
|
|
19
|
-
'--dir': String
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
export function help() {
|
|
23
|
-
return `
|
|
24
|
-
Usage: 'sdk-commands build [options]'
|
|
25
|
-
Options:'
|
|
26
|
-
-h, --help Displays complete help
|
|
27
|
-
-w, --watch Watch for file changes and build on change
|
|
28
|
-
-p, --production Build without sourcemaps
|
|
29
|
-
--skip-install Skip installing dependencies
|
|
30
|
-
--dir Path to directory to build
|
|
31
|
-
|
|
32
|
-
Example:
|
|
33
|
-
- Build your scene:
|
|
34
|
-
'$ sdk-commands build'
|
|
35
|
-
`
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export async function main(options: Options) {
|
|
39
|
-
const projectRoot = resolve(process.cwd(), options.args['--dir'] || '.')
|
|
40
|
-
|
|
41
|
-
await assertValidProjectFolder(options.components, projectRoot)
|
|
42
|
-
|
|
43
|
-
const shouldInstallDeps = await needsDependencies(options.components, projectRoot)
|
|
44
|
-
|
|
45
|
-
if (shouldInstallDeps && !options.args['--skip-install']) {
|
|
46
|
-
await installDependencies(options.components, projectRoot)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const watch = !!options.args['--watch']
|
|
50
|
-
|
|
51
|
-
const watchingFuture = future<any>()
|
|
52
|
-
|
|
53
|
-
await compile({
|
|
54
|
-
project: projectRoot,
|
|
55
|
-
watch,
|
|
56
|
-
production: !!options.args['--production'],
|
|
57
|
-
watchingFuture
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
if (!watch) {
|
|
61
|
-
watchingFuture.resolve(null)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
await watchingFuture
|
|
65
|
-
|
|
66
|
-
// track stuff...
|
|
67
|
-
// https://github.com/decentraland/cli/blob/main/src/commands/build.ts
|
|
68
|
-
}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'path'
|
|
2
|
-
import { getArgs } from '../../logic/args'
|
|
3
|
-
import { hashV1 } from '@dcl/hashing'
|
|
4
|
-
import { CliComponents } from '../../components'
|
|
5
|
-
import { assertValidProjectFolder } from '../../logic/project-validations'
|
|
6
|
-
import { getProjectContentMappings } from '../../logic/project-files'
|
|
7
|
-
import { CliError } from '../../logic/error'
|
|
8
|
-
import { Entity, EntityType } from '@dcl/schemas'
|
|
9
|
-
import { colors } from '../../components/log'
|
|
10
|
-
import { printProgressInfo, printProgressStep, printSuccess } from '../../logic/beautiful-logs'
|
|
11
|
-
import { createStaticRealm } from '../../logic/realm'
|
|
12
|
-
|
|
13
|
-
interface Options {
|
|
14
|
-
args: typeof args
|
|
15
|
-
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger'>
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const args = getArgs({
|
|
19
|
-
'--dir': String,
|
|
20
|
-
'--destination': String,
|
|
21
|
-
'--timestamp': String,
|
|
22
|
-
'--realmName': String,
|
|
23
|
-
'--baseUrl': String
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
export async function help() {
|
|
27
|
-
return `
|
|
28
|
-
Usage:
|
|
29
|
-
sdk-commands export-static --dir <directory> --destination <directory>
|
|
30
|
-
|
|
31
|
-
Description:
|
|
32
|
-
|
|
33
|
-
Exports all the contents of the scene as if they were uploaded to a content server
|
|
34
|
-
|
|
35
|
-
Options:
|
|
36
|
-
|
|
37
|
-
--dir <directory> The project's root folder to export
|
|
38
|
-
--destination <directory> A path in which all the assets will be stored
|
|
39
|
-
--timestamp <timestamp> A date to use in the deployable entity. Defaults to now()
|
|
40
|
-
--realmName <name> Creates a /<name>/about endpoint to expose the current deployment as a realm. Requires --baseUrl
|
|
41
|
-
--baseUrl <baseUrl> It is the public URL in which the --destination directory will be avaiable
|
|
42
|
-
`
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export async function main(options: Options) {
|
|
46
|
-
const { fs, logger } = options.components
|
|
47
|
-
const projectRoot = resolve(process.cwd(), options.args['--dir'] || '.')
|
|
48
|
-
const destDirectory = resolve(process.cwd(), options.args['--destination'] || '.')
|
|
49
|
-
const willCreateRealm = !!args['--realmName']
|
|
50
|
-
let currentStep = 1
|
|
51
|
-
const maxSteps = 3 + (willCreateRealm ? 1 : 0)
|
|
52
|
-
|
|
53
|
-
if (willCreateRealm && !args['--baseUrl']) {
|
|
54
|
-
throw new CliError(`--baseUrl is mandatory when --realmName is provided`)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (willCreateRealm && !/^[a-z][a-z0-9-/]*$/i.test(args['--realmName']!)) {
|
|
58
|
-
throw new CliError(`--realmName has invalid characters`)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
printProgressStep(logger, 'Reading project files...', currentStep++, maxSteps)
|
|
62
|
-
|
|
63
|
-
await fs.mkdir(destDirectory, { recursive: true })
|
|
64
|
-
if (!(await fs.directoryExists(destDirectory))) {
|
|
65
|
-
throw new CliError(`The destination path ${destDirectory} is not a directory`)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const project = await assertValidProjectFolder(options.components, projectRoot)
|
|
69
|
-
const filesToExport = await getProjectContentMappings(options.components, projectRoot, async (file) => {
|
|
70
|
-
return await hashV1(fs.createReadStream(resolve(projectRoot, file)))
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
printProgressStep(logger, 'Copying files...', currentStep++, maxSteps)
|
|
74
|
-
|
|
75
|
-
for (const { file, hash } of filesToExport) {
|
|
76
|
-
const src = resolve(projectRoot, file)
|
|
77
|
-
const dst = resolve(destDirectory, hash)
|
|
78
|
-
|
|
79
|
-
if (src.startsWith(destDirectory)) continue
|
|
80
|
-
|
|
81
|
-
printProgressInfo(logger, `> ${hash} -> ${file}`)
|
|
82
|
-
|
|
83
|
-
if (!(await fs.fileExists(dst))) {
|
|
84
|
-
const content = await fs.readFile(src)
|
|
85
|
-
await fs.writeFile(dst, content)
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// entity with ID are the deployed ones, when we generate the entity the ID is not
|
|
90
|
-
// available because it is the result of hashing the following structure
|
|
91
|
-
const entity: Omit<Entity, 'id'> = {
|
|
92
|
-
content: filesToExport,
|
|
93
|
-
pointers: [],
|
|
94
|
-
timestamp: args['--timestamp'] ? new Date(args['--timestamp']).getTime() : Date.now(),
|
|
95
|
-
type: EntityType.SCENE,
|
|
96
|
-
// for now, the only valid export is for scenes
|
|
97
|
-
metadata: project.scene,
|
|
98
|
-
version: 'v3'
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
printProgressStep(logger, 'Generating files...', currentStep++, maxSteps)
|
|
102
|
-
|
|
103
|
-
// create the entity file and get the entityId
|
|
104
|
-
const entityRaw = Buffer.from(JSON.stringify(entity), 'utf8')
|
|
105
|
-
const entityId = await hashV1(entityRaw)
|
|
106
|
-
const dst = resolve(destDirectory, entityId)
|
|
107
|
-
await fs.writeFile(dst, entityRaw)
|
|
108
|
-
|
|
109
|
-
printProgressInfo(logger, `> ${entityId} -> [ENTITY FILE]`)
|
|
110
|
-
|
|
111
|
-
let urn = `urn:decentraland:entity:${entityId}`
|
|
112
|
-
|
|
113
|
-
if (args['--baseUrl']) {
|
|
114
|
-
urn += '?baseUrl=' + args['--baseUrl']
|
|
115
|
-
// baseUrl must end with /
|
|
116
|
-
if (!urn.endsWith('/')) urn += '/'
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (willCreateRealm) {
|
|
120
|
-
// prepare the realm object
|
|
121
|
-
printProgressStep(logger, 'Creating realm file...', currentStep++, maxSteps)
|
|
122
|
-
const realm = createStaticRealm()
|
|
123
|
-
const realmName = args['--realmName']!
|
|
124
|
-
|
|
125
|
-
realm.configurations!.scenesUrn = [urn]
|
|
126
|
-
realm.configurations!.realmName = realmName
|
|
127
|
-
|
|
128
|
-
// write the realm file
|
|
129
|
-
const realmDirectory = resolve(destDirectory, realmName)
|
|
130
|
-
await fs.mkdir(realmDirectory, { recursive: true })
|
|
131
|
-
if (!(await fs.directoryExists(realmDirectory))) {
|
|
132
|
-
throw new CliError(`The destination path ${realmDirectory} is not a directory`)
|
|
133
|
-
}
|
|
134
|
-
const dst = resolve(realmDirectory, 'about')
|
|
135
|
-
await fs.writeFile(dst, JSON.stringify(realm, null, 2))
|
|
136
|
-
printProgressInfo(logger, `> ${realmName}/about -> [REALM FILE]`)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
printSuccess(logger, `Export finished!`, `=> The entity URN is ${colors.bold(urn)}`)
|
|
140
|
-
|
|
141
|
-
return { urn, entityId, destination: destDirectory }
|
|
142
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { join, resolve } from 'path'
|
|
2
|
-
|
|
3
|
-
import { getArgs } from '../../logic/args'
|
|
4
|
-
import { CliError } from '../../logic/error'
|
|
5
|
-
import { CliComponents } from '../../components'
|
|
6
|
-
import { isDirectoryEmpty, download, extract } from '../../logic/fs'
|
|
7
|
-
|
|
8
|
-
import { get as getRepo } from './repos'
|
|
9
|
-
import { installDependencies, needsDependencies } from '../../logic/project-validations'
|
|
10
|
-
|
|
11
|
-
interface Options {
|
|
12
|
-
args: typeof args
|
|
13
|
-
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger'>
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const args = getArgs({
|
|
17
|
-
'--yes': Boolean,
|
|
18
|
-
'-y': '--yes',
|
|
19
|
-
'--dir': String,
|
|
20
|
-
'--skip-install': Boolean
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
export async function help() {}
|
|
24
|
-
|
|
25
|
-
export async function main(options: Options) {
|
|
26
|
-
const dir = resolve(process.cwd(), options.args['--dir'] || '.')
|
|
27
|
-
const isEmpty = await isDirectoryEmpty(options.components, dir)
|
|
28
|
-
const yes = options.args['--yes']
|
|
29
|
-
|
|
30
|
-
if (!isEmpty && !yes) {
|
|
31
|
-
throw new CliError('The target directory specified is not empty. Run this command with --yes to override.')
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// download and extract template project
|
|
35
|
-
const scene = 'scene-template'
|
|
36
|
-
const { url, contentFolders } = getRepo(scene)
|
|
37
|
-
const zip = await download(options.components, url, join(dir, `${scene}.zip`))
|
|
38
|
-
await extract(zip, dir)
|
|
39
|
-
await options.components.fs.unlink(zip)
|
|
40
|
-
await moveFilesFromDirs(options.components, dir, contentFolders)
|
|
41
|
-
|
|
42
|
-
// npm install
|
|
43
|
-
const shouldInstallDeps = await needsDependencies(options.components, dir)
|
|
44
|
-
if (shouldInstallDeps && !options.args['--skip-install']) {
|
|
45
|
-
await installDependencies(options.components, dir)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const moveFilesFromDir = async (components: Pick<CliComponents, 'fs'>, dir: string, folder: string) => {
|
|
50
|
-
const files = await components.fs.readdir(folder)
|
|
51
|
-
await Promise.all(
|
|
52
|
-
files.map(($) => {
|
|
53
|
-
const filePath = resolve(folder, $)
|
|
54
|
-
return components.fs.rename(filePath, resolve(dir, $))
|
|
55
|
-
})
|
|
56
|
-
)
|
|
57
|
-
await components.fs.rmdir(folder)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const moveFilesFromDirs = async (components: Pick<CliComponents, 'fs'>, dir: string, folders: string[]) => {
|
|
61
|
-
await Promise.all(
|
|
62
|
-
folders.map(($) => {
|
|
63
|
-
const folderPath = resolve(dir, $)
|
|
64
|
-
return moveFilesFromDir(components, dir, folderPath)
|
|
65
|
-
})
|
|
66
|
-
)
|
|
67
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
type Scene = 'scene-template'
|
|
2
|
-
|
|
3
|
-
type Repos = {
|
|
4
|
-
[key in Scene]: {
|
|
5
|
-
url: string
|
|
6
|
-
contentFolders: string[]
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const REPOS: Repos = {
|
|
11
|
-
'scene-template': {
|
|
12
|
-
url: 'https://github.com/decentraland/sdk7-scene-template/archive/refs/heads/main.zip',
|
|
13
|
-
contentFolders: ['sdk7-scene-template-main']
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const get = (scene: Scene): Repos[Scene] => REPOS[scene]
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import * as os from 'os'
|
|
2
|
-
import * as path from 'path'
|
|
3
|
-
import open from 'open'
|
|
4
|
-
import future from 'fp-future'
|
|
5
|
-
|
|
6
|
-
import { CliComponents } from '../../components'
|
|
7
|
-
import { main as build } from '../build'
|
|
8
|
-
import { getArgs } from '../../logic/args'
|
|
9
|
-
import { needsDependencies, npmRun } from '../../logic/project-validations'
|
|
10
|
-
import { validateSceneJson } from '../../logic/scene-validations'
|
|
11
|
-
import { CliError } from '../../logic/error'
|
|
12
|
-
import { previewPort } from '../../logic/get-free-port'
|
|
13
|
-
import { ISignalerComponent, PreviewComponents } from './types'
|
|
14
|
-
import { createTestMetricsComponent } from '@well-known-components/metrics'
|
|
15
|
-
import { Lifecycle, IBaseComponent } from '@well-known-components/interfaces'
|
|
16
|
-
import { createRecordConfigComponent } from '@well-known-components/env-config-provider'
|
|
17
|
-
import { createRoomsComponent, roomsMetrics } from '@dcl/mini-comms/dist/adapters/rooms'
|
|
18
|
-
import { createServerComponent } from '@well-known-components/http-server'
|
|
19
|
-
import { createConsoleLogComponent } from '@well-known-components/logger'
|
|
20
|
-
import { providerInstance } from '../../components/eth'
|
|
21
|
-
import { createStdoutCliLogger } from '../../components/log'
|
|
22
|
-
import { wireFileWatcherToWebSockets } from './server/file-watch-notifier'
|
|
23
|
-
import { wireRouter } from './server/routes'
|
|
24
|
-
import { createWsComponent } from './server/ws'
|
|
25
|
-
|
|
26
|
-
interface Options {
|
|
27
|
-
args: typeof args
|
|
28
|
-
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger'>
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export const args = getArgs({
|
|
32
|
-
'--dir': String,
|
|
33
|
-
'--help': Boolean,
|
|
34
|
-
'--port': Number,
|
|
35
|
-
'--no-debug': Boolean,
|
|
36
|
-
'--no-browser': Boolean,
|
|
37
|
-
'--no-watch': Boolean,
|
|
38
|
-
'--ci': Boolean,
|
|
39
|
-
'--skip-install': Boolean,
|
|
40
|
-
'--web3': Boolean,
|
|
41
|
-
'-h': '--help',
|
|
42
|
-
'-p': '--port',
|
|
43
|
-
'-d': '--no-debug',
|
|
44
|
-
'-b': '--no-browser',
|
|
45
|
-
'-w': '--no-watch',
|
|
46
|
-
'--skip-build': Boolean,
|
|
47
|
-
'--desktop-client': Boolean
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
export function help() {
|
|
51
|
-
return `
|
|
52
|
-
Usage: sdk-commands start [options]
|
|
53
|
-
|
|
54
|
-
Options:
|
|
55
|
-
|
|
56
|
-
-h, --help Displays complete help
|
|
57
|
-
-p, --port [port] Select a custom port for the development server
|
|
58
|
-
-d, --no-debug Disable debugging panel
|
|
59
|
-
-b, --no-browser Do not open a new browser window
|
|
60
|
-
-w, --no-watch Do not open watch for filesystem changes
|
|
61
|
-
-c, --ci Run the parcel previewer on a remote unix server
|
|
62
|
-
--web3 Connects preview to browser wallet to use the associated avatar and account
|
|
63
|
-
--skip-build Skip build and only serve the files in preview mode
|
|
64
|
-
--desktop-client Show URL to launch preview in the desktop client (BETA)
|
|
65
|
-
|
|
66
|
-
Examples:
|
|
67
|
-
|
|
68
|
-
- Start a local development server for a Decentraland Scene at port 3500
|
|
69
|
-
|
|
70
|
-
$ sdk-commands start -p 3500
|
|
71
|
-
|
|
72
|
-
- Start a local development server for a Decentraland Scene at a docker container
|
|
73
|
-
|
|
74
|
-
$ sdk-commands start --ci
|
|
75
|
-
`
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export async function main(options: Options) {
|
|
79
|
-
const projectRoot = path.resolve(process.cwd(), options.args['--dir'] || '.')
|
|
80
|
-
const isCi = args['--ci'] || process.env.CI || false
|
|
81
|
-
const debug = !args['--no-debug'] && !isCi
|
|
82
|
-
const openBrowser = !args['--no-browser'] && !isCi
|
|
83
|
-
const skipBuild = args['--skip-build']
|
|
84
|
-
const watch = !args['--no-watch']
|
|
85
|
-
const enableWeb3 = args['--web3']
|
|
86
|
-
const baseCoords = { x: 0, y: 0 }
|
|
87
|
-
const hasPortableExperience = false
|
|
88
|
-
|
|
89
|
-
// first run `npm run build`, this can be disabled with --skip-build
|
|
90
|
-
if (!skipBuild) {
|
|
91
|
-
await npmRun(projectRoot, 'build')
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// then start the embedded compiler, this can be disabled with --no-watch
|
|
95
|
-
if (watch) {
|
|
96
|
-
await build({ ...options, args: { '--dir': projectRoot, '--watch': watch } })
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
await validateSceneJson(options.components, projectRoot)
|
|
100
|
-
|
|
101
|
-
if (await needsDependencies(options.components, projectRoot)) {
|
|
102
|
-
const npmModulesPath = path.resolve(projectRoot, 'node_modules')
|
|
103
|
-
throw new CliError(`Couldn\'t find ${npmModulesPath}, please run: npm install`)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const port = options.args['--port'] || (await previewPort())
|
|
107
|
-
|
|
108
|
-
const program = await Lifecycle.run<PreviewComponents>({
|
|
109
|
-
async initComponents() {
|
|
110
|
-
const metrics = createTestMetricsComponent(roomsMetrics)
|
|
111
|
-
const config = createRecordConfigComponent({
|
|
112
|
-
HTTP_SERVER_PORT: port.toString(),
|
|
113
|
-
HTTP_SERVER_HOST: '0.0.0.0',
|
|
114
|
-
...process.env
|
|
115
|
-
})
|
|
116
|
-
const logs = await createConsoleLogComponent({})
|
|
117
|
-
const ws = await createWsComponent({ logs })
|
|
118
|
-
const server = await createServerComponent<PreviewComponents>({ config, logs, ws: ws.ws }, {})
|
|
119
|
-
const rooms = await createRoomsComponent({
|
|
120
|
-
metrics,
|
|
121
|
-
logs,
|
|
122
|
-
config
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
const programClosed = future<void>()
|
|
126
|
-
const signaler: IBaseComponent & ISignalerComponent = {
|
|
127
|
-
programClosed,
|
|
128
|
-
async stop() {
|
|
129
|
-
// this promise is resolved upon SIGTERM or SIGHUP
|
|
130
|
-
// or when program.stop is called
|
|
131
|
-
programClosed.resolve()
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return {
|
|
136
|
-
...options.components,
|
|
137
|
-
logger: createStdoutCliLogger(),
|
|
138
|
-
logs,
|
|
139
|
-
ethereumProvider: providerInstance,
|
|
140
|
-
rooms,
|
|
141
|
-
config,
|
|
142
|
-
metrics,
|
|
143
|
-
server,
|
|
144
|
-
ws,
|
|
145
|
-
signaler
|
|
146
|
-
}
|
|
147
|
-
},
|
|
148
|
-
async main({ components, startComponents }) {
|
|
149
|
-
await wireRouter(components, projectRoot)
|
|
150
|
-
if (watch) {
|
|
151
|
-
await wireFileWatcherToWebSockets(components, projectRoot)
|
|
152
|
-
}
|
|
153
|
-
await startComponents()
|
|
154
|
-
|
|
155
|
-
const networkInterfaces = os.networkInterfaces()
|
|
156
|
-
const availableURLs: string[] = []
|
|
157
|
-
|
|
158
|
-
components.logger.log(`Preview server is now running!`)
|
|
159
|
-
components.logger.log('Available on:\n')
|
|
160
|
-
|
|
161
|
-
Object.keys(networkInterfaces).forEach((dev) => {
|
|
162
|
-
;(networkInterfaces[dev] || []).forEach((details) => {
|
|
163
|
-
if (details.family === 'IPv4') {
|
|
164
|
-
let addr = `http://${details.address}:${port}?position=${baseCoords.x}%2C${baseCoords.y}&ENABLE_ECS7`
|
|
165
|
-
if (debug) {
|
|
166
|
-
addr = `${addr}&SCENE_DEBUG_PANEL`
|
|
167
|
-
}
|
|
168
|
-
if (enableWeb3 || hasPortableExperience) {
|
|
169
|
-
addr = `${addr}&ENABLE_WEB3`
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
availableURLs.push(addr)
|
|
173
|
-
}
|
|
174
|
-
})
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
// Push localhost and 127.0.0.1 at top
|
|
178
|
-
const sortedURLs = availableURLs.sort((a, _b) => {
|
|
179
|
-
return a.toLowerCase().includes('localhost') || a.includes('127.0.0.1') || a.includes('0.0.0.0') ? -1 : 1
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
for (const addr of sortedURLs) {
|
|
183
|
-
components.logger.log(` ${addr}`)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (args['--desktop-client']) {
|
|
187
|
-
components.logger.log('\n Desktop client:\n')
|
|
188
|
-
for (const addr of sortedURLs) {
|
|
189
|
-
const searchParams = new URLSearchParams()
|
|
190
|
-
searchParams.append('PREVIEW-MODE', addr)
|
|
191
|
-
components.logger.log(` dcl://${searchParams.toString()}&`)
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
components.logger.log('\n Details:\n')
|
|
196
|
-
components.logger.log('\nPress CTRL+C to exit\n')
|
|
197
|
-
|
|
198
|
-
// Open preferably localhost/127.0.0.1
|
|
199
|
-
if (openBrowser && sortedURLs.length && !args['--desktop-client']) {
|
|
200
|
-
try {
|
|
201
|
-
await open(sortedURLs[0])
|
|
202
|
-
} catch (_) {
|
|
203
|
-
components.logger.warn('Unable to open browser automatically.')
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
// this signal is resolved by: (wkc)program.stop(), SIGTERM, SIGHUP
|
|
210
|
-
// we must wait for it to resolve (when the server stops) to continue with the
|
|
211
|
-
// program
|
|
212
|
-
await program.components.signaler.programClosed
|
|
213
|
-
}
|