@dcl/sdk-commands 7.0.0-4283968845.commit-bdb933b → 7.0.0-4293371227.commit-54082c6
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 +62 -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 +7 -4
- package/src/commands/build/index.ts +11 -2
- package/src/commands/export-static/index.ts +10 -2
- package/src/commands/init/index.ts +2 -1
- package/src/commands/start/index.ts +12 -4
- package/src/commands/start/server/endpoints.ts +1 -3
- package/src/components/analytics.ts +92 -0
- package/src/components/dcl-info-config.ts +63 -0
- package/src/components/index.ts +11 -3
- package/src/index.ts +2 -2
- package/src/logic/config.ts +45 -0
- package/src/logic/dcl-ignore.ts +1 -0
- package/src/logic/fs.ts +35 -0
- package/src/logic/project-files.ts +16 -0
- package/src/logic/scene-validations.ts +10 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CliComponents } from '../../components';
|
|
2
2
|
interface Options {
|
|
3
3
|
args: Omit<typeof args, '_'>;
|
|
4
|
-
components: Pick<CliComponents, 'fs' | 'logger'>;
|
|
4
|
+
components: Pick<CliComponents, 'fs' | 'logger' | 'dclInfoConfig' | 'analytics'>;
|
|
5
5
|
}
|
|
6
6
|
export declare const args: import("arg").Result<{
|
|
7
7
|
'--help': BooleanConstructor;
|
|
@@ -9,6 +9,8 @@ const args_1 = require("../../logic/args");
|
|
|
9
9
|
const compile_1 = require("@dcl/dcl-rollup/compile");
|
|
10
10
|
const fp_future_1 = __importDefault(require("fp-future"));
|
|
11
11
|
const project_validations_1 = require("../../logic/project-validations");
|
|
12
|
+
const scene_validations_1 = require("../../logic/scene-validations");
|
|
13
|
+
const project_files_1 = require("../../logic/project-files");
|
|
12
14
|
exports.args = (0, args_1.getArgs)({
|
|
13
15
|
'--watch': Boolean,
|
|
14
16
|
'-w': '--watch',
|
|
@@ -51,6 +53,13 @@ async function main(options) {
|
|
|
51
53
|
if (!watch) {
|
|
52
54
|
watchingFuture.resolve(null);
|
|
53
55
|
}
|
|
56
|
+
const sceneJson = await (0, project_files_1.getSceneJson)(options.components, projectRoot);
|
|
57
|
+
const coords = (0, scene_validations_1.getBaseCoords)(sceneJson);
|
|
58
|
+
await options.components.analytics.track('Build scene', {
|
|
59
|
+
projectHash: await (0, project_files_1.b64HashingFunction)(projectRoot),
|
|
60
|
+
coords,
|
|
61
|
+
isWorkspace: false
|
|
62
|
+
});
|
|
54
63
|
await watchingFuture;
|
|
55
64
|
// track stuff...
|
|
56
65
|
// https://github.com/decentraland/cli/blob/main/src/commands/build.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CliComponents } from '../../components';
|
|
2
2
|
interface Options {
|
|
3
3
|
args: typeof args;
|
|
4
|
-
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger'>;
|
|
4
|
+
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger' | 'dclInfoConfig' | 'analytics'>;
|
|
5
5
|
}
|
|
6
6
|
export declare const args: import("arg").Result<{
|
|
7
7
|
'--help': BooleanConstructor;
|
|
@@ -11,6 +11,7 @@ const schemas_1 = require("@dcl/schemas");
|
|
|
11
11
|
const log_1 = require("../../components/log");
|
|
12
12
|
const beautiful_logs_1 = require("../../logic/beautiful-logs");
|
|
13
13
|
const realm_1 = require("../../logic/realm");
|
|
14
|
+
const scene_validations_1 = require("../../logic/scene-validations");
|
|
14
15
|
exports.args = (0, args_1.getArgs)({
|
|
15
16
|
'--dir': String,
|
|
16
17
|
'--destination': String,
|
|
@@ -114,6 +115,12 @@ async function main(options) {
|
|
|
114
115
|
(0, beautiful_logs_1.printProgressInfo)(logger, `> ${realmName}/about -> [REALM FILE]`);
|
|
115
116
|
}
|
|
116
117
|
(0, beautiful_logs_1.printSuccess)(logger, `Export finished!`, `=> The entity URN is ${log_1.colors.bold(urn)}`);
|
|
118
|
+
const sceneJson = await (0, project_files_1.getSceneJson)(options.components, projectRoot);
|
|
119
|
+
const coords = (0, scene_validations_1.getBaseCoords)(sceneJson);
|
|
120
|
+
await options.components.analytics.track('Export static', {
|
|
121
|
+
projectHash: await (0, project_files_1.b64HashingFunction)(projectRoot),
|
|
122
|
+
coords
|
|
123
|
+
});
|
|
117
124
|
return { urn, entityId, destination: destDirectory };
|
|
118
125
|
}
|
|
119
126
|
exports.main = main;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CliComponents } from '../../components';
|
|
2
2
|
interface Options {
|
|
3
3
|
args: typeof args;
|
|
4
|
-
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger'>;
|
|
4
|
+
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger' | 'dclInfoConfig' | 'analytics'>;
|
|
5
5
|
}
|
|
6
6
|
export declare const args: import("arg").Result<{
|
|
7
7
|
'--help': BooleanConstructor;
|
|
@@ -34,6 +34,7 @@ async function main(options) {
|
|
|
34
34
|
if (shouldInstallDeps && !options.args['--skip-install']) {
|
|
35
35
|
await (0, project_validations_1.installDependencies)(options.components, dir);
|
|
36
36
|
}
|
|
37
|
+
await options.components.analytics.track('Scene created', { projectType: scene, url });
|
|
37
38
|
}
|
|
38
39
|
exports.main = main;
|
|
39
40
|
const moveFilesFromDir = async (components, dir, folder) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CliComponents } from '../../components';
|
|
2
2
|
interface Options {
|
|
3
3
|
args: typeof args;
|
|
4
|
-
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger'>;
|
|
4
|
+
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger' | 'dclInfoConfig' | 'analytics'>;
|
|
5
5
|
}
|
|
6
6
|
export declare const args: import("arg").Result<{
|
|
7
7
|
'--help': BooleanConstructor;
|
|
@@ -48,6 +48,7 @@ const log_1 = require("../../components/log");
|
|
|
48
48
|
const file_watch_notifier_1 = require("./server/file-watch-notifier");
|
|
49
49
|
const routes_1 = require("./server/routes");
|
|
50
50
|
const ws_1 = require("./server/ws");
|
|
51
|
+
const project_files_1 = require("../../logic/project-files");
|
|
51
52
|
exports.args = (0, args_1.getArgs)({
|
|
52
53
|
'--dir': String,
|
|
53
54
|
'--help': Boolean,
|
|
@@ -102,7 +103,7 @@ async function main(options) {
|
|
|
102
103
|
const skipBuild = exports.args['--skip-build'];
|
|
103
104
|
const watch = !exports.args['--no-watch'];
|
|
104
105
|
const enableWeb3 = exports.args['--web3'];
|
|
105
|
-
|
|
106
|
+
// TODO: FIX this hardcoded values ?
|
|
106
107
|
const hasPortableExperience = false;
|
|
107
108
|
// first run `npm run build`, this can be disabled with --skip-build
|
|
108
109
|
if (!skipBuild) {
|
|
@@ -113,6 +114,8 @@ async function main(options) {
|
|
|
113
114
|
await (0, build_1.main)({ ...options, args: { '--dir': projectRoot, '--watch': watch } });
|
|
114
115
|
}
|
|
115
116
|
await (0, scene_validations_1.validateSceneJson)(options.components, projectRoot);
|
|
117
|
+
const sceneJson = await (0, project_files_1.getSceneJson)(options.components, projectRoot);
|
|
118
|
+
const baseCoords = (0, scene_validations_1.getBaseCoords)(sceneJson);
|
|
116
119
|
if (await (0, project_validations_1.needsDependencies)(options.components, projectRoot)) {
|
|
117
120
|
const npmModulesPath = path.resolve(projectRoot, 'node_modules');
|
|
118
121
|
throw new error_1.CliError(`Couldn\'t find ${npmModulesPath}, please run: npm install`);
|
|
@@ -164,6 +167,11 @@ async function main(options) {
|
|
|
164
167
|
await startComponents();
|
|
165
168
|
const networkInterfaces = os.networkInterfaces();
|
|
166
169
|
const availableURLs = [];
|
|
170
|
+
await components.analytics.track('Preview started', {
|
|
171
|
+
projectHash: await (0, project_files_1.b64HashingFunction)(projectRoot),
|
|
172
|
+
coords: baseCoords,
|
|
173
|
+
isWorkspace: false
|
|
174
|
+
});
|
|
167
175
|
components.logger.log(`Preview server is now running!`);
|
|
168
176
|
components.logger.log('Available on:\n');
|
|
169
177
|
Object.keys(networkInterfaces).forEach((dev) => {
|
|
@@ -210,7 +210,6 @@ function serveFolders(components, router, baseFolders) {
|
|
|
210
210
|
};
|
|
211
211
|
});
|
|
212
212
|
}
|
|
213
|
-
const b64HashingFunction = async (str) => 'b64-' + Buffer.from(str).toString('base64');
|
|
214
213
|
async function getAllPreviewWearables(components, { baseFolders, baseUrl }) {
|
|
215
214
|
const wearablePathArray = [];
|
|
216
215
|
for (const wearableDir of baseFolders) {
|
|
@@ -238,7 +237,7 @@ async function serveWearable(components, wearableJsonPath, baseUrl) {
|
|
|
238
237
|
console.error(`Unable to validate wearable.json properly, please check it.`, errors);
|
|
239
238
|
throw new Error(`Invalid wearable.json (${wearableJsonPath})`);
|
|
240
239
|
}
|
|
241
|
-
const hashedFiles = await (0, project_files_1.getProjectContentMappings)(components, wearableDir, b64HashingFunction);
|
|
240
|
+
const hashedFiles = await (0, project_files_1.getProjectContentMappings)(components, wearableDir, project_files_1.b64HashingFunction);
|
|
242
241
|
const thumbnailFiltered = hashedFiles.filter(($) => $?.file === 'thumbnail.png');
|
|
243
242
|
const thumbnail = thumbnailFiltered.length > 0 && thumbnailFiltered[0]?.hash && `${baseUrl}/${thumbnailFiltered[0].hash}`;
|
|
244
243
|
const wearableId = 'urn:8dc2d7ad-97e3-44d0-ba89-e8305d795a6a';
|
|
@@ -274,7 +273,7 @@ async function serveWearable(components, wearableJsonPath, baseUrl) {
|
|
|
274
273
|
async function getSceneJson(components, projectRoots, pointers) {
|
|
275
274
|
const requestedPointers = new Set(pointers);
|
|
276
275
|
const resultEntities = [];
|
|
277
|
-
const allDeployments = await Promise.all(projectRoots.map(async (projectRoot) => fakeEntityV3FromFolder(components, projectRoot, b64HashingFunction)));
|
|
276
|
+
const allDeployments = await Promise.all(projectRoots.map(async (projectRoot) => fakeEntityV3FromFolder(components, projectRoot, project_files_1.b64HashingFunction)));
|
|
278
277
|
for (const pointer of Array.from(requestedPointers)) {
|
|
279
278
|
// get deployment by pointer
|
|
280
279
|
const theDeployment = allDeployments.find(($) => $ && $.pointers.includes(pointer));
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Analytics } from '@segment/analytics-node';
|
|
2
|
+
import { CliComponents } from '.';
|
|
3
|
+
export type IAnalyticsComponent = {
|
|
4
|
+
get(): Analytics;
|
|
5
|
+
identify(): Promise<void>;
|
|
6
|
+
track<T extends keyof Events>(eventName: T, eventProps: Events[T]): Promise<void>;
|
|
7
|
+
};
|
|
8
|
+
type Events = {
|
|
9
|
+
'Scene created': {
|
|
10
|
+
projectType: string;
|
|
11
|
+
url: string;
|
|
12
|
+
};
|
|
13
|
+
'Preview started': {
|
|
14
|
+
projectHash: string;
|
|
15
|
+
coords: {
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
};
|
|
19
|
+
isWorkspace: boolean;
|
|
20
|
+
};
|
|
21
|
+
'Build scene': {
|
|
22
|
+
projectHash: string;
|
|
23
|
+
coords: {
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
};
|
|
27
|
+
isWorkspace: boolean;
|
|
28
|
+
};
|
|
29
|
+
'Export static': {
|
|
30
|
+
projectHash: string;
|
|
31
|
+
coords: {
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export declare function createAnalyticsComponent({ dclInfoConfig }: Pick<CliComponents, 'dclInfoConfig'>): Promise<IAnalyticsComponent>;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createAnalyticsComponent = void 0;
|
|
7
|
+
const uuid_1 = require("uuid");
|
|
8
|
+
const analytics_node_1 = require("@segment/analytics-node");
|
|
9
|
+
const fp_future_1 = __importDefault(require("fp-future"));
|
|
10
|
+
const log_1 = require("./log");
|
|
11
|
+
async function createAnalyticsComponent({ dclInfoConfig }) {
|
|
12
|
+
const USER_ID = 'sdk-commands-user';
|
|
13
|
+
const config = await dclInfoConfig.get();
|
|
14
|
+
const analytics = new analytics_node_1.Analytics({ writeKey: config.segmentKey ?? '' });
|
|
15
|
+
return {
|
|
16
|
+
get() {
|
|
17
|
+
return analytics;
|
|
18
|
+
},
|
|
19
|
+
async identify() {
|
|
20
|
+
if (!config.userId) {
|
|
21
|
+
console.log(`Decentraland CLI sends anonymous usage stats to improve their products, if you want to disable it change the configuration at ${log_1.colors.bold('~/.dclinfo')}\n`);
|
|
22
|
+
const userId = (0, uuid_1.v4)();
|
|
23
|
+
await dclInfoConfig.updateDCLInfo({ userId, trackStats: true });
|
|
24
|
+
analytics.identify({
|
|
25
|
+
userId: USER_ID,
|
|
26
|
+
traits: {
|
|
27
|
+
devId: userId,
|
|
28
|
+
createdAt: new Date()
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
async track(eventName, eventProps) {
|
|
34
|
+
const trackFuture = (0, fp_future_1.default)();
|
|
35
|
+
const { userId, trackStats } = await dclInfoConfig.get();
|
|
36
|
+
if (!trackStats) {
|
|
37
|
+
return trackFuture.resolve();
|
|
38
|
+
}
|
|
39
|
+
const trackInfo = {
|
|
40
|
+
userId: USER_ID,
|
|
41
|
+
event: eventName,
|
|
42
|
+
properties: {
|
|
43
|
+
...eventProps,
|
|
44
|
+
os: process.platform,
|
|
45
|
+
nodeVersion: process.version,
|
|
46
|
+
cliVersion: await dclInfoConfig.getVersion(),
|
|
47
|
+
isCI: dclInfoConfig.isCI(),
|
|
48
|
+
isEditor: dclInfoConfig.isEditor(),
|
|
49
|
+
devId: userId
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
analytics.track(trackInfo, () => {
|
|
53
|
+
trackFuture.resolve();
|
|
54
|
+
});
|
|
55
|
+
if (!dclInfoConfig.isProduction()) {
|
|
56
|
+
console.log(trackInfo);
|
|
57
|
+
}
|
|
58
|
+
return trackFuture;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
exports.createAnalyticsComponent = createAnalyticsComponent;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CliComponents } from '.';
|
|
2
|
+
import { DCLInfo } from '../logic/config';
|
|
3
|
+
export type IDCLInfoConfigComponent = {
|
|
4
|
+
get(): Promise<DCLInfo>;
|
|
5
|
+
updateDCLInfo(value: Partial<DCLInfo>): Promise<Partial<DCLInfo>>;
|
|
6
|
+
getVersion(): Promise<string>;
|
|
7
|
+
isCI(): boolean;
|
|
8
|
+
isEditor(): boolean;
|
|
9
|
+
isProduction(): boolean;
|
|
10
|
+
};
|
|
11
|
+
export declare function createDCLInfoConfigComponent({ fs }: Pick<CliComponents, 'fs'>): Promise<IDCLInfoConfigComponent>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.createDCLInfoConfigComponent = void 0;
|
|
27
|
+
const path_1 = __importStar(require("path"));
|
|
28
|
+
const config_1 = require("../logic/config");
|
|
29
|
+
const fs_1 = require("../logic/fs");
|
|
30
|
+
async function createDCLInfoConfigComponent({ fs }) {
|
|
31
|
+
function isProduction() {
|
|
32
|
+
return process.env.NODE_ENV === 'production' || __filename.includes('node_modules');
|
|
33
|
+
}
|
|
34
|
+
const defaultConfig = {
|
|
35
|
+
userId: '',
|
|
36
|
+
trackStats: false,
|
|
37
|
+
segmentKey: isProduction() ? 'sFdziRVDJo0taOnGzTZwafEL9nLIANZ3' : 'mjCV5Dc4VAKXLJAH5g7LyHyW1jrIR3to'
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
async get() {
|
|
41
|
+
const dclInfoConfig = await (0, config_1.getDCLInfoConfig)({ fs });
|
|
42
|
+
const envConfig = (0, config_1.getEnvConfig)();
|
|
43
|
+
const config = { ...defaultConfig, ...dclInfoConfig, ...envConfig };
|
|
44
|
+
return config;
|
|
45
|
+
},
|
|
46
|
+
updateDCLInfo(value) {
|
|
47
|
+
return (0, fs_1.writeJSON)({ fs }, (0, config_1.getDclInfoPath)(), value);
|
|
48
|
+
},
|
|
49
|
+
async getVersion() {
|
|
50
|
+
try {
|
|
51
|
+
/* istanbul ignore next */
|
|
52
|
+
const sdkPath = path_1.default.dirname(require.resolve('@dcl/sdk/package.json', {
|
|
53
|
+
paths: [process.cwd()]
|
|
54
|
+
}));
|
|
55
|
+
/* istanbul ignore next */
|
|
56
|
+
const packageJson = await (0, fs_1.readJSON)({ fs }, (0, path_1.resolve)(sdkPath, 'package.json'));
|
|
57
|
+
/* istanbul ignore next */
|
|
58
|
+
return packageJson.version ?? 'unknown';
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
return 'unknown';
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
isEditor() {
|
|
65
|
+
return process.env.EDITOR === 'true';
|
|
66
|
+
},
|
|
67
|
+
isCI() {
|
|
68
|
+
return process.env.CI === 'true' || process.argv.includes('--ci') || process.argv.includes('--c');
|
|
69
|
+
},
|
|
70
|
+
isProduction() {
|
|
71
|
+
return isProduction();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
exports.createDCLInfoConfigComponent = createDCLInfoConfigComponent;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { ILoggerComponent } from '@well-known-components/interfaces';
|
|
2
|
+
import { IAnalyticsComponent } from './analytics';
|
|
3
|
+
import { IDCLInfoConfigComponent } from './dcl-info-config';
|
|
2
4
|
import { IFetchComponent } from './fetch';
|
|
3
5
|
import { IFileSystemComponent } from './fs';
|
|
4
6
|
export type CliComponents = {
|
|
5
7
|
fs: IFileSystemComponent;
|
|
6
8
|
fetch: IFetchComponent;
|
|
7
9
|
logger: ILoggerComponent.ILogger;
|
|
10
|
+
dclInfoConfig: IDCLInfoConfigComponent;
|
|
11
|
+
analytics: IAnalyticsComponent;
|
|
8
12
|
};
|
|
9
|
-
export declare function initComponents(): CliComponents
|
|
13
|
+
export declare function initComponents(): Promise<CliComponents>;
|
package/dist/components/index.js
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.initComponents = void 0;
|
|
4
|
+
const analytics_1 = require("./analytics");
|
|
5
|
+
const dcl_info_config_1 = require("./dcl-info-config");
|
|
4
6
|
const fetch_1 = require("./fetch");
|
|
5
7
|
const fs_1 = require("./fs");
|
|
6
8
|
const log_1 = require("./log");
|
|
7
|
-
function initComponents() {
|
|
9
|
+
async function initComponents() {
|
|
10
|
+
const fsComponent = (0, fs_1.createFsComponent)();
|
|
11
|
+
const dclInfoConfig = await (0, dcl_info_config_1.createDCLInfoConfigComponent)({ fs: fsComponent });
|
|
8
12
|
return {
|
|
9
|
-
fs:
|
|
13
|
+
fs: fsComponent,
|
|
10
14
|
fetch: (0, fetch_1.createFetchComponent)(),
|
|
11
|
-
logger: (0, log_1.createStdoutCliLogger)()
|
|
15
|
+
logger: (0, log_1.createStdoutCliLogger)(),
|
|
16
|
+
dclInfoConfig,
|
|
17
|
+
analytics: await (0, analytics_1.createAnalyticsComponent)({ dclInfoConfig })
|
|
12
18
|
};
|
|
13
19
|
}
|
|
14
20
|
exports.initComponents = initComponents;
|
package/dist/index.js
CHANGED
|
@@ -24,7 +24,7 @@ async function main() {
|
|
|
24
24
|
const args = (0, args_1.getArgs)();
|
|
25
25
|
const command = process.argv[2];
|
|
26
26
|
const needsHelp = args['--help'];
|
|
27
|
-
const components = (0, components_1.initComponents)();
|
|
27
|
+
const components = await (0, components_1.initComponents)();
|
|
28
28
|
const commands = await (0, commands_1.getCommands)(components);
|
|
29
29
|
if (!commands.includes(command)) {
|
|
30
30
|
if (needsHelp) {
|
|
@@ -36,6 +36,7 @@ async function main() {
|
|
|
36
36
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
37
37
|
const cmd = require(`${commands_1.COMMANDS_PATH}/${command}`);
|
|
38
38
|
if (commandFnsAreValid(cmd)) {
|
|
39
|
+
await components.analytics.identify();
|
|
39
40
|
const options = { args: cmd.args, components };
|
|
40
41
|
if (needsHelp) {
|
|
41
42
|
await cmd.help(options);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { CliComponents } from '../components';
|
|
2
|
+
export interface DCLInfo {
|
|
3
|
+
segmentKey?: string;
|
|
4
|
+
userId?: string;
|
|
5
|
+
trackStats?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const getDclInfoPath: () => string;
|
|
8
|
+
/**
|
|
9
|
+
* Reads the contents of the `.dclinfo` file
|
|
10
|
+
*/
|
|
11
|
+
export declare function getDCLInfoConfig(components: Pick<CliComponents, 'fs'>): Promise<DCLInfo>;
|
|
12
|
+
/**
|
|
13
|
+
* Config that can be override via ENV variables
|
|
14
|
+
*/
|
|
15
|
+
export declare function getEnvConfig(): Partial<DCLInfo>;
|
|
16
|
+
export declare function removeEmptyKeys(obj: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.removeEmptyKeys = exports.getEnvConfig = exports.getDCLInfoConfig = exports.getDclInfoPath = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
/* istanbul ignore next */
|
|
9
|
+
const getDclInfoPath = () => path_1.default.resolve(process.env[process.platform === 'win32' ? 'USERPROFILE' : 'HOME'] ?? '', '.dclinfo');
|
|
10
|
+
exports.getDclInfoPath = getDclInfoPath;
|
|
11
|
+
/**
|
|
12
|
+
* Reads the contents of the `.dclinfo` file
|
|
13
|
+
*/
|
|
14
|
+
async function getDCLInfoConfig(components) {
|
|
15
|
+
try {
|
|
16
|
+
const content = await components.fs.readFile((0, exports.getDclInfoPath)(), 'utf8');
|
|
17
|
+
return JSON.parse(content);
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.getDCLInfoConfig = getDCLInfoConfig;
|
|
24
|
+
/**
|
|
25
|
+
* Config that can be override via ENV variables
|
|
26
|
+
*/
|
|
27
|
+
function getEnvConfig() {
|
|
28
|
+
const { SEGMENT_KEY } = process.env;
|
|
29
|
+
const envConfig = {
|
|
30
|
+
segmentKey: SEGMENT_KEY
|
|
31
|
+
};
|
|
32
|
+
return removeEmptyKeys(envConfig);
|
|
33
|
+
}
|
|
34
|
+
exports.getEnvConfig = getEnvConfig;
|
|
35
|
+
function removeEmptyKeys(obj) {
|
|
36
|
+
const result = {};
|
|
37
|
+
Object.keys(obj)
|
|
38
|
+
.filter((k) => !!obj[k])
|
|
39
|
+
.forEach((k) => (result[k] = obj[k]));
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
exports.removeEmptyKeys = removeEmptyKeys;
|
package/dist/logic/dcl-ignore.js
CHANGED
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getDCLIgnorePatterns = exports.getDCLIgnoreFileContents = exports.defaultDclIgnore = void 0;
|
|
7
|
+
/* istanbul ignore file */
|
|
7
8
|
const path_1 = __importDefault(require("path"));
|
|
8
9
|
exports.defaultDclIgnore = [
|
|
9
10
|
'.*',
|
package/dist/logic/fs.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { IFileSystemComponent } from '../components/fs';
|
|
2
2
|
import { IFetchComponent } from '../components/fetch';
|
|
3
|
+
import { CliComponents } from '../components';
|
|
3
4
|
/**
|
|
4
5
|
* Check's if directory is empty
|
|
5
6
|
* @param dir Directory to check for emptyness
|
|
@@ -22,3 +23,14 @@ export declare function download(components: {
|
|
|
22
23
|
* @param dest Path to where to extract the zip file
|
|
23
24
|
*/
|
|
24
25
|
export declare function extract(path: string, dest: string): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Reads a file and parses it's JSON content
|
|
28
|
+
* @param path The path to the subject json file
|
|
29
|
+
*/
|
|
30
|
+
export declare function readJSON<T>(components: Pick<CliComponents, 'fs'>, path: string): Promise<T>;
|
|
31
|
+
/**
|
|
32
|
+
* Merges the provided content with a json file
|
|
33
|
+
* @param path The path to the subject json file
|
|
34
|
+
* @param content The content to be applied (as a plain object)
|
|
35
|
+
*/
|
|
36
|
+
export declare function writeJSON<T = unknown>(components: Pick<CliComponents, 'fs'>, path: string, content: Partial<T>): Promise<Partial<T>>;
|
package/dist/logic/fs.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.extract = exports.download = exports.isDirectoryEmpty = void 0;
|
|
6
|
+
exports.writeJSON = exports.readJSON = exports.extract = exports.download = exports.isDirectoryEmpty = void 0;
|
|
7
7
|
const extract_zip_1 = __importDefault(require("extract-zip"));
|
|
8
8
|
const path_1 = require("path");
|
|
9
9
|
/**
|
|
@@ -39,3 +39,31 @@ async function extract(path, dest) {
|
|
|
39
39
|
return destPath;
|
|
40
40
|
}
|
|
41
41
|
exports.extract = extract;
|
|
42
|
+
/**
|
|
43
|
+
* Reads a file and parses it's JSON content
|
|
44
|
+
* @param path The path to the subject json file
|
|
45
|
+
*/
|
|
46
|
+
async function readJSON(components, path) {
|
|
47
|
+
const content = await components.fs.readFile(path, 'utf-8');
|
|
48
|
+
return JSON.parse(content);
|
|
49
|
+
}
|
|
50
|
+
exports.readJSON = readJSON;
|
|
51
|
+
/**
|
|
52
|
+
* Merges the provided content with a json file
|
|
53
|
+
* @param path The path to the subject json file
|
|
54
|
+
* @param content The content to be applied (as a plain object)
|
|
55
|
+
*/
|
|
56
|
+
async function writeJSON(components, path, content) {
|
|
57
|
+
let currentFile;
|
|
58
|
+
try {
|
|
59
|
+
currentFile = await readJSON(components, path);
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
currentFile = {};
|
|
63
|
+
}
|
|
64
|
+
const newJson = { ...currentFile, ...content };
|
|
65
|
+
const strContent = JSON.stringify(newJson, null, 2);
|
|
66
|
+
await components.fs.writeFile(path, strContent);
|
|
67
|
+
return newJson;
|
|
68
|
+
}
|
|
69
|
+
exports.writeJSON = writeJSON;
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { ContentMapping } from '@dcl/schemas/dist/misc/content-mapping';
|
|
2
2
|
import { CliComponents } from '../components';
|
|
3
|
+
import { Scene } from '@dcl/schemas';
|
|
3
4
|
/**
|
|
4
5
|
* Returns an array of the publishable files for a given folder.
|
|
6
|
+
*
|
|
5
7
|
*/
|
|
6
8
|
export declare function getPublishableFiles(components: Pick<CliComponents, 'fs'>, projectRoot: string): Promise<Array<string>>;
|
|
7
9
|
/**
|
|
8
10
|
* This function converts paths to decentraland-compatible paths.
|
|
9
11
|
* - From windows separators to unix separators.
|
|
10
12
|
* - All to lowercase
|
|
13
|
+
*
|
|
11
14
|
*/
|
|
12
15
|
export declare function normalizeDecentralandFilename(filename: string): string;
|
|
13
16
|
/**
|
|
14
17
|
* Returns the content mappings for a specific project folder.
|
|
15
18
|
*/
|
|
16
19
|
export declare function getProjectContentMappings(components: Pick<CliComponents, 'fs'>, projectRoot: string, hashingFunction: (filePath: string) => Promise<string>): Promise<ContentMapping[]>;
|
|
20
|
+
export declare function getSceneJson(components: Pick<CliComponents, 'fs'>, projectRoot: string): Promise<Scene>;
|
|
21
|
+
export declare const b64HashingFunction: (str: string) => Promise<string>;
|
|
@@ -3,15 +3,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getProjectContentMappings = exports.normalizeDecentralandFilename = exports.getPublishableFiles = void 0;
|
|
6
|
+
exports.b64HashingFunction = exports.getSceneJson = exports.getProjectContentMappings = exports.normalizeDecentralandFilename = exports.getPublishableFiles = void 0;
|
|
7
7
|
const dcl_ignore_1 = require("./dcl-ignore");
|
|
8
8
|
const glob_1 = require("glob");
|
|
9
9
|
const ignore_1 = __importDefault(require("ignore"));
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
11
|
const error_1 = require("./error");
|
|
12
|
+
const scene_validations_1 = require("./scene-validations");
|
|
12
13
|
/**
|
|
13
14
|
* Returns an array of the publishable files for a given folder.
|
|
15
|
+
*
|
|
14
16
|
*/
|
|
17
|
+
/* istanbul ignore next */
|
|
15
18
|
async function getPublishableFiles(components, projectRoot) {
|
|
16
19
|
const ignorePatterns = await (0, dcl_ignore_1.getDCLIgnorePatterns)(components, projectRoot);
|
|
17
20
|
const ig = (0, ignore_1.default)().add(ignorePatterns);
|
|
@@ -29,7 +32,9 @@ exports.getPublishableFiles = getPublishableFiles;
|
|
|
29
32
|
* This function converts paths to decentraland-compatible paths.
|
|
30
33
|
* - From windows separators to unix separators.
|
|
31
34
|
* - All to lowercase
|
|
35
|
+
*
|
|
32
36
|
*/
|
|
37
|
+
/* istanbul ignore next */
|
|
33
38
|
function normalizeDecentralandFilename(filename) {
|
|
34
39
|
return filename.replace(/(\\)/g, '/').toLowerCase();
|
|
35
40
|
}
|
|
@@ -37,7 +42,10 @@ exports.normalizeDecentralandFilename = normalizeDecentralandFilename;
|
|
|
37
42
|
/**
|
|
38
43
|
* Returns the content mappings for a specific project folder.
|
|
39
44
|
*/
|
|
40
|
-
|
|
45
|
+
/* istanbul ignore next */
|
|
46
|
+
async function getProjectContentMappings(components, projectRoot,
|
|
47
|
+
/* istanbul ignore next */
|
|
48
|
+
hashingFunction) {
|
|
41
49
|
const projectFiles = await getPublishableFiles(components, projectRoot);
|
|
42
50
|
const ret = [];
|
|
43
51
|
const usedFilenames = new Set();
|
|
@@ -60,3 +68,11 @@ async function getProjectContentMappings(components, projectRoot, hashingFunctio
|
|
|
60
68
|
return ret;
|
|
61
69
|
}
|
|
62
70
|
exports.getProjectContentMappings = getProjectContentMappings;
|
|
71
|
+
async function getSceneJson(components, projectRoot) {
|
|
72
|
+
const sceneJsonContent = await components.fs.readFile((0, scene_validations_1.getSceneFilePath)(projectRoot), 'utf8');
|
|
73
|
+
const sceneJson = JSON.parse(sceneJsonContent);
|
|
74
|
+
return sceneJson;
|
|
75
|
+
}
|
|
76
|
+
exports.getSceneJson = getSceneJson;
|
|
77
|
+
const b64HashingFunction = async (str) => 'b64-' + Buffer.from(str).toString('base64');
|
|
78
|
+
exports.b64HashingFunction = b64HashingFunction;
|
|
@@ -11,3 +11,7 @@ export declare function assertValidScene(scene: Scene): Scene;
|
|
|
11
11
|
* Fails the execution if one of the parcel data is invalid
|
|
12
12
|
*/
|
|
13
13
|
export declare function validateSceneJson(components: Pick<CliComponents, 'fs' | 'logger'>, projectRoot: string): Promise<Scene>;
|
|
14
|
+
export declare function getBaseCoords(scene: Scene): {
|
|
15
|
+
x: number;
|
|
16
|
+
y: number;
|
|
17
|
+
};
|
|
@@ -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-4293371227.commit-54082c6",
|
|
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-4293371227.commit-54082c6",
|
|
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,5 @@
|
|
|
46
49
|
"displayName": "SDK",
|
|
47
50
|
"tsconfig": "./tsconfig.json"
|
|
48
51
|
},
|
|
49
|
-
"commit": "
|
|
52
|
+
"commit": "54082c63f87b970864c7e4eab94db193656d6aaa"
|
|
50
53
|
}
|
|
@@ -4,10 +4,12 @@ import { getArgs } from '../../logic/args'
|
|
|
4
4
|
import { compile } from '@dcl/dcl-rollup/compile'
|
|
5
5
|
import future from 'fp-future'
|
|
6
6
|
import { assertValidProjectFolder, installDependencies, needsDependencies } from '../../logic/project-validations'
|
|
7
|
+
import { getBaseCoords } from '../../logic/scene-validations'
|
|
8
|
+
import { b64HashingFunction, getSceneJson } from '../../logic/project-files'
|
|
7
9
|
|
|
8
10
|
interface Options {
|
|
9
11
|
args: Omit<typeof args, '_'>
|
|
10
|
-
components: Pick<CliComponents, 'fs' | 'logger'>
|
|
12
|
+
components: Pick<CliComponents, 'fs' | 'logger' | 'dclInfoConfig' | 'analytics'>
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
export const args = getArgs({
|
|
@@ -37,7 +39,6 @@ export function help() {
|
|
|
37
39
|
|
|
38
40
|
export async function main(options: Options) {
|
|
39
41
|
const projectRoot = resolve(process.cwd(), options.args['--dir'] || '.')
|
|
40
|
-
|
|
41
42
|
await assertValidProjectFolder(options.components, projectRoot)
|
|
42
43
|
|
|
43
44
|
const shouldInstallDeps = await needsDependencies(options.components, projectRoot)
|
|
@@ -60,6 +61,14 @@ export async function main(options: Options) {
|
|
|
60
61
|
if (!watch) {
|
|
61
62
|
watchingFuture.resolve(null)
|
|
62
63
|
}
|
|
64
|
+
const sceneJson = await getSceneJson(options.components, projectRoot)
|
|
65
|
+
const coords = getBaseCoords(sceneJson)
|
|
66
|
+
|
|
67
|
+
await options.components.analytics.track('Build scene', {
|
|
68
|
+
projectHash: await b64HashingFunction(projectRoot),
|
|
69
|
+
coords,
|
|
70
|
+
isWorkspace: false
|
|
71
|
+
})
|
|
63
72
|
|
|
64
73
|
await watchingFuture
|
|
65
74
|
|
|
@@ -3,16 +3,17 @@ import { getArgs } from '../../logic/args'
|
|
|
3
3
|
import { hashV1 } from '@dcl/hashing'
|
|
4
4
|
import { CliComponents } from '../../components'
|
|
5
5
|
import { assertValidProjectFolder } from '../../logic/project-validations'
|
|
6
|
-
import { getProjectContentMappings } from '../../logic/project-files'
|
|
6
|
+
import { b64HashingFunction, getProjectContentMappings, getSceneJson } from '../../logic/project-files'
|
|
7
7
|
import { CliError } from '../../logic/error'
|
|
8
8
|
import { Entity, EntityType } from '@dcl/schemas'
|
|
9
9
|
import { colors } from '../../components/log'
|
|
10
10
|
import { printProgressInfo, printProgressStep, printSuccess } from '../../logic/beautiful-logs'
|
|
11
11
|
import { createStaticRealm } from '../../logic/realm'
|
|
12
|
+
import { getBaseCoords } from '../../logic/scene-validations'
|
|
12
13
|
|
|
13
14
|
interface Options {
|
|
14
15
|
args: typeof args
|
|
15
|
-
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger'>
|
|
16
|
+
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger' | 'dclInfoConfig' | 'analytics'>
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export const args = getArgs({
|
|
@@ -137,6 +138,13 @@ export async function main(options: Options) {
|
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
printSuccess(logger, `Export finished!`, `=> The entity URN is ${colors.bold(urn)}`)
|
|
141
|
+
const sceneJson = await getSceneJson(options.components, projectRoot)
|
|
142
|
+
const coords = getBaseCoords(sceneJson)
|
|
143
|
+
|
|
144
|
+
await options.components.analytics.track('Export static', {
|
|
145
|
+
projectHash: await b64HashingFunction(projectRoot),
|
|
146
|
+
coords
|
|
147
|
+
})
|
|
140
148
|
|
|
141
149
|
return { urn, entityId, destination: destDirectory }
|
|
142
150
|
}
|
|
@@ -10,7 +10,7 @@ import { installDependencies, needsDependencies } from '../../logic/project-vali
|
|
|
10
10
|
|
|
11
11
|
interface Options {
|
|
12
12
|
args: typeof args
|
|
13
|
-
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger'>
|
|
13
|
+
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger' | 'dclInfoConfig' | 'analytics'>
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export const args = getArgs({
|
|
@@ -44,6 +44,7 @@ export async function main(options: Options) {
|
|
|
44
44
|
if (shouldInstallDeps && !options.args['--skip-install']) {
|
|
45
45
|
await installDependencies(options.components, dir)
|
|
46
46
|
}
|
|
47
|
+
await options.components.analytics.track('Scene created', { projectType: scene, url })
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
const moveFilesFromDir = async (components: Pick<CliComponents, 'fs'>, dir: string, folder: string) => {
|
|
@@ -7,7 +7,7 @@ import { CliComponents } from '../../components'
|
|
|
7
7
|
import { main as build } from '../build'
|
|
8
8
|
import { getArgs } from '../../logic/args'
|
|
9
9
|
import { needsDependencies, npmRun } from '../../logic/project-validations'
|
|
10
|
-
import { validateSceneJson } from '../../logic/scene-validations'
|
|
10
|
+
import { getBaseCoords, validateSceneJson } from '../../logic/scene-validations'
|
|
11
11
|
import { CliError } from '../../logic/error'
|
|
12
12
|
import { previewPort } from '../../logic/get-free-port'
|
|
13
13
|
import { ISignalerComponent, PreviewComponents } from './types'
|
|
@@ -22,10 +22,11 @@ import { createStdoutCliLogger } from '../../components/log'
|
|
|
22
22
|
import { wireFileWatcherToWebSockets } from './server/file-watch-notifier'
|
|
23
23
|
import { wireRouter } from './server/routes'
|
|
24
24
|
import { createWsComponent } from './server/ws'
|
|
25
|
+
import { b64HashingFunction, getSceneJson } from '../../logic/project-files'
|
|
25
26
|
|
|
26
27
|
interface Options {
|
|
27
28
|
args: typeof args
|
|
28
|
-
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger'>
|
|
29
|
+
components: Pick<CliComponents, 'fetch' | 'fs' | 'logger' | 'dclInfoConfig' | 'analytics'>
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
export const args = getArgs({
|
|
@@ -83,7 +84,8 @@ export async function main(options: Options) {
|
|
|
83
84
|
const skipBuild = args['--skip-build']
|
|
84
85
|
const watch = !args['--no-watch']
|
|
85
86
|
const enableWeb3 = args['--web3']
|
|
86
|
-
|
|
87
|
+
|
|
88
|
+
// TODO: FIX this hardcoded values ?
|
|
87
89
|
const hasPortableExperience = false
|
|
88
90
|
|
|
89
91
|
// first run `npm run build`, this can be disabled with --skip-build
|
|
@@ -97,6 +99,8 @@ export async function main(options: Options) {
|
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
await validateSceneJson(options.components, projectRoot)
|
|
102
|
+
const sceneJson = await getSceneJson(options.components, projectRoot)
|
|
103
|
+
const baseCoords = getBaseCoords(sceneJson)
|
|
100
104
|
|
|
101
105
|
if (await needsDependencies(options.components, projectRoot)) {
|
|
102
106
|
const npmModulesPath = path.resolve(projectRoot, 'node_modules')
|
|
@@ -154,7 +158,11 @@ export async function main(options: Options) {
|
|
|
154
158
|
|
|
155
159
|
const networkInterfaces = os.networkInterfaces()
|
|
156
160
|
const availableURLs: string[] = []
|
|
157
|
-
|
|
161
|
+
await components.analytics.track('Preview started', {
|
|
162
|
+
projectHash: await b64HashingFunction(projectRoot),
|
|
163
|
+
coords: baseCoords,
|
|
164
|
+
isWorkspace: false
|
|
165
|
+
})
|
|
158
166
|
components.logger.log(`Preview server is now running!`)
|
|
159
167
|
components.logger.log('Available on:\n')
|
|
160
168
|
|
|
@@ -6,7 +6,7 @@ import { Entity, EntityType, Locale, Wearable } from '@dcl/schemas'
|
|
|
6
6
|
import fetch, { Headers } from 'node-fetch'
|
|
7
7
|
import { fetchEntityByPointer } from '../../../logic/catalyst-requests'
|
|
8
8
|
import { CliComponents } from '../../../components'
|
|
9
|
-
import { getProjectContentMappings } from '../../../logic/project-files'
|
|
9
|
+
import { b64HashingFunction, getProjectContentMappings } from '../../../logic/project-files'
|
|
10
10
|
|
|
11
11
|
function getCatalystUrl(): URL {
|
|
12
12
|
return new URL('https://peer.decentraland.org')
|
|
@@ -227,8 +227,6 @@ function serveFolders(components: Pick<CliComponents, 'fs'>, router: Router<Prev
|
|
|
227
227
|
})
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
const b64HashingFunction = async (str: string) => 'b64-' + Buffer.from(str).toString('base64')
|
|
231
|
-
|
|
232
230
|
async function getAllPreviewWearables(
|
|
233
231
|
components: Pick<CliComponents, 'fs'>,
|
|
234
232
|
{ baseFolders, baseUrl }: { baseFolders: string[]; baseUrl: string }
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid'
|
|
2
|
+
import { Analytics } from '@segment/analytics-node'
|
|
3
|
+
import future from 'fp-future'
|
|
4
|
+
|
|
5
|
+
import { CliComponents } from '.'
|
|
6
|
+
import { colors } from './log'
|
|
7
|
+
|
|
8
|
+
export type IAnalyticsComponent = {
|
|
9
|
+
get(): Analytics
|
|
10
|
+
identify(): Promise<void>
|
|
11
|
+
track<T extends keyof Events>(eventName: T, eventProps: Events[T]): Promise<void>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type Events = {
|
|
15
|
+
'Scene created': {
|
|
16
|
+
projectType: string
|
|
17
|
+
url: string
|
|
18
|
+
}
|
|
19
|
+
'Preview started': {
|
|
20
|
+
projectHash: string
|
|
21
|
+
coords: { x: number; y: number }
|
|
22
|
+
isWorkspace: boolean
|
|
23
|
+
}
|
|
24
|
+
'Build scene': {
|
|
25
|
+
projectHash: string
|
|
26
|
+
coords: { x: number; y: number }
|
|
27
|
+
isWorkspace: boolean
|
|
28
|
+
}
|
|
29
|
+
'Export static': {
|
|
30
|
+
projectHash: string
|
|
31
|
+
coords: { x: number; y: number }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function createAnalyticsComponent({
|
|
36
|
+
dclInfoConfig
|
|
37
|
+
}: Pick<CliComponents, 'dclInfoConfig'>): Promise<IAnalyticsComponent> {
|
|
38
|
+
const USER_ID = 'sdk-commands-user'
|
|
39
|
+
const config = await dclInfoConfig.get()
|
|
40
|
+
const analytics: Analytics = new Analytics({ writeKey: config.segmentKey ?? '' })
|
|
41
|
+
return {
|
|
42
|
+
get() {
|
|
43
|
+
return analytics
|
|
44
|
+
},
|
|
45
|
+
async identify() {
|
|
46
|
+
if (!config.userId) {
|
|
47
|
+
console.log(
|
|
48
|
+
`Decentraland CLI sends anonymous usage stats to improve their products, if you want to disable it change the configuration at ${colors.bold(
|
|
49
|
+
'~/.dclinfo'
|
|
50
|
+
)}\n`
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
const userId = uuidv4()
|
|
54
|
+
await dclInfoConfig.updateDCLInfo({ userId, trackStats: true })
|
|
55
|
+
analytics.identify({
|
|
56
|
+
userId: USER_ID,
|
|
57
|
+
traits: {
|
|
58
|
+
devId: userId,
|
|
59
|
+
createdAt: new Date()
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
async track<T extends keyof Events>(eventName: T, eventProps: Events[T]) {
|
|
65
|
+
const trackFuture = future<void>()
|
|
66
|
+
const { userId, trackStats } = await dclInfoConfig.get()
|
|
67
|
+
if (!trackStats) {
|
|
68
|
+
return trackFuture.resolve()
|
|
69
|
+
}
|
|
70
|
+
const trackInfo = {
|
|
71
|
+
userId: USER_ID,
|
|
72
|
+
event: eventName,
|
|
73
|
+
properties: {
|
|
74
|
+
...eventProps,
|
|
75
|
+
os: process.platform,
|
|
76
|
+
nodeVersion: process.version,
|
|
77
|
+
cliVersion: await dclInfoConfig.getVersion(),
|
|
78
|
+
isCI: dclInfoConfig.isCI(),
|
|
79
|
+
isEditor: dclInfoConfig.isEditor(),
|
|
80
|
+
devId: userId
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
analytics.track(trackInfo, () => {
|
|
84
|
+
trackFuture.resolve()
|
|
85
|
+
})
|
|
86
|
+
if (!dclInfoConfig.isProduction()) {
|
|
87
|
+
console.log(trackInfo)
|
|
88
|
+
}
|
|
89
|
+
return trackFuture
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import path, { resolve } from 'path'
|
|
2
|
+
import { CliComponents } from '.'
|
|
3
|
+
import { DCLInfo, getDCLInfoConfig, getDclInfoPath, getEnvConfig } from '../logic/config'
|
|
4
|
+
import { readJSON, writeJSON } from '../logic/fs'
|
|
5
|
+
|
|
6
|
+
export type IDCLInfoConfigComponent = {
|
|
7
|
+
get(): Promise<DCLInfo>
|
|
8
|
+
updateDCLInfo(value: Partial<DCLInfo>): Promise<Partial<DCLInfo>>
|
|
9
|
+
getVersion(): Promise<string>
|
|
10
|
+
isCI(): boolean
|
|
11
|
+
isEditor(): boolean
|
|
12
|
+
isProduction(): boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function createDCLInfoConfigComponent({
|
|
16
|
+
fs
|
|
17
|
+
}: Pick<CliComponents, 'fs'>): Promise<IDCLInfoConfigComponent> {
|
|
18
|
+
function isProduction() {
|
|
19
|
+
return process.env.NODE_ENV === 'production' || __filename.includes('node_modules')
|
|
20
|
+
}
|
|
21
|
+
const defaultConfig: Partial<DCLInfo> = {
|
|
22
|
+
userId: '',
|
|
23
|
+
trackStats: false,
|
|
24
|
+
segmentKey: isProduction() ? 'sFdziRVDJo0taOnGzTZwafEL9nLIANZ3' : 'mjCV5Dc4VAKXLJAH5g7LyHyW1jrIR3to'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
async get() {
|
|
29
|
+
const dclInfoConfig = await getDCLInfoConfig({ fs })
|
|
30
|
+
const envConfig = getEnvConfig()
|
|
31
|
+
const config = { ...defaultConfig, ...dclInfoConfig, ...envConfig }
|
|
32
|
+
return config
|
|
33
|
+
},
|
|
34
|
+
updateDCLInfo(value: Partial<DCLInfo>) {
|
|
35
|
+
return writeJSON({ fs }, getDclInfoPath(), value)
|
|
36
|
+
},
|
|
37
|
+
async getVersion() {
|
|
38
|
+
try {
|
|
39
|
+
/* istanbul ignore next */
|
|
40
|
+
const sdkPath = path.dirname(
|
|
41
|
+
require.resolve('@dcl/sdk/package.json', {
|
|
42
|
+
paths: [process.cwd()]
|
|
43
|
+
})
|
|
44
|
+
)
|
|
45
|
+
/* istanbul ignore next */
|
|
46
|
+
const packageJson = await readJSON<{ version: string }>({ fs }, resolve(sdkPath, 'package.json'))
|
|
47
|
+
/* istanbul ignore next */
|
|
48
|
+
return packageJson.version ?? 'unknown'
|
|
49
|
+
} catch (e) {
|
|
50
|
+
return 'unknown'
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
isEditor() {
|
|
54
|
+
return process.env.EDITOR === 'true'
|
|
55
|
+
},
|
|
56
|
+
isCI() {
|
|
57
|
+
return process.env.CI === 'true' || process.argv.includes('--ci') || process.argv.includes('--c')
|
|
58
|
+
},
|
|
59
|
+
isProduction() {
|
|
60
|
+
return isProduction()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { ILoggerComponent } from '@well-known-components/interfaces'
|
|
2
|
+
import { createAnalyticsComponent, IAnalyticsComponent } from './analytics'
|
|
3
|
+
import { createDCLInfoConfigComponent, IDCLInfoConfigComponent } from './dcl-info-config'
|
|
2
4
|
import { createFetchComponent, IFetchComponent } from './fetch'
|
|
3
5
|
import { createFsComponent, IFileSystemComponent } from './fs'
|
|
4
6
|
import { createStdoutCliLogger } from './log'
|
|
@@ -7,12 +9,18 @@ export type CliComponents = {
|
|
|
7
9
|
fs: IFileSystemComponent
|
|
8
10
|
fetch: IFetchComponent
|
|
9
11
|
logger: ILoggerComponent.ILogger
|
|
12
|
+
dclInfoConfig: IDCLInfoConfigComponent
|
|
13
|
+
analytics: IAnalyticsComponent
|
|
10
14
|
}
|
|
11
15
|
|
|
12
|
-
export function initComponents(): CliComponents {
|
|
16
|
+
export async function initComponents(): Promise<CliComponents> {
|
|
17
|
+
const fsComponent = createFsComponent()
|
|
18
|
+
const dclInfoConfig = await createDCLInfoConfigComponent({ fs: fsComponent })
|
|
13
19
|
return {
|
|
14
|
-
fs:
|
|
20
|
+
fs: fsComponent,
|
|
15
21
|
fetch: createFetchComponent(),
|
|
16
|
-
logger: createStdoutCliLogger()
|
|
22
|
+
logger: createStdoutCliLogger(),
|
|
23
|
+
dclInfoConfig,
|
|
24
|
+
analytics: await createAnalyticsComponent({ dclInfoConfig })
|
|
17
25
|
}
|
|
18
26
|
}
|
package/src/index.ts
CHANGED
|
@@ -41,7 +41,7 @@ async function main() {
|
|
|
41
41
|
const args = getArgs()
|
|
42
42
|
const command = process.argv[2]
|
|
43
43
|
const needsHelp = args['--help']
|
|
44
|
-
const components: CliComponents = initComponents()
|
|
44
|
+
const components: CliComponents = await initComponents()
|
|
45
45
|
|
|
46
46
|
const commands = await getCommands(components)
|
|
47
47
|
|
|
@@ -52,11 +52,11 @@ async function main() {
|
|
|
52
52
|
}
|
|
53
53
|
throw new CliError(`Command ${command} is invalid. ${helpMessage(commands)}`)
|
|
54
54
|
}
|
|
55
|
-
|
|
56
55
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
57
56
|
const cmd = require(`${COMMANDS_PATH}/${command}`)
|
|
58
57
|
|
|
59
58
|
if (commandFnsAreValid(cmd)) {
|
|
59
|
+
await components.analytics.identify()
|
|
60
60
|
const options = { args: cmd.args, components }
|
|
61
61
|
if (needsHelp) {
|
|
62
62
|
await cmd.help(options)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import { CliComponents } from '../components'
|
|
3
|
+
|
|
4
|
+
export interface DCLInfo {
|
|
5
|
+
segmentKey?: string
|
|
6
|
+
userId?: string
|
|
7
|
+
trackStats?: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/* istanbul ignore next */
|
|
11
|
+
export const getDclInfoPath = () =>
|
|
12
|
+
path.resolve(process.env[process.platform === 'win32' ? 'USERPROFILE' : 'HOME'] ?? '', '.dclinfo')
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Reads the contents of the `.dclinfo` file
|
|
16
|
+
*/
|
|
17
|
+
export async function getDCLInfoConfig(components: Pick<CliComponents, 'fs'>): Promise<DCLInfo> {
|
|
18
|
+
try {
|
|
19
|
+
const content = await components.fs.readFile(getDclInfoPath(), 'utf8')
|
|
20
|
+
return JSON.parse(content) as DCLInfo
|
|
21
|
+
} catch (e) {
|
|
22
|
+
return {}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Config that can be override via ENV variables
|
|
28
|
+
*/
|
|
29
|
+
export function getEnvConfig(): Partial<DCLInfo> {
|
|
30
|
+
const { SEGMENT_KEY } = process.env
|
|
31
|
+
|
|
32
|
+
const envConfig = {
|
|
33
|
+
segmentKey: SEGMENT_KEY
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return removeEmptyKeys(envConfig)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function removeEmptyKeys(obj: Record<string, unknown>) {
|
|
40
|
+
const result: Record<string, unknown> = {}
|
|
41
|
+
Object.keys(obj)
|
|
42
|
+
.filter((k) => !!obj[k])
|
|
43
|
+
.forEach((k) => (result[k] = obj[k]))
|
|
44
|
+
return result
|
|
45
|
+
}
|
package/src/logic/dcl-ignore.ts
CHANGED
package/src/logic/fs.ts
CHANGED
|
@@ -2,6 +2,7 @@ import extractZip from 'extract-zip'
|
|
|
2
2
|
import { resolve } from 'path'
|
|
3
3
|
import { IFileSystemComponent } from '../components/fs'
|
|
4
4
|
import { IFetchComponent } from '../components/fetch'
|
|
5
|
+
import { CliComponents } from '../components'
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Check's if directory is empty
|
|
@@ -39,3 +40,37 @@ export async function extract(path: string, dest: string): Promise<string> {
|
|
|
39
40
|
await extractZip(resolve(path), { dir: destPath })
|
|
40
41
|
return destPath
|
|
41
42
|
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Reads a file and parses it's JSON content
|
|
46
|
+
* @param path The path to the subject json file
|
|
47
|
+
*/
|
|
48
|
+
export async function readJSON<T>(components: Pick<CliComponents, 'fs'>, path: string): Promise<T> {
|
|
49
|
+
const content = await components.fs.readFile(path, 'utf-8')
|
|
50
|
+
return JSON.parse(content) as T
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Merges the provided content with a json file
|
|
55
|
+
* @param path The path to the subject json file
|
|
56
|
+
* @param content The content to be applied (as a plain object)
|
|
57
|
+
*/
|
|
58
|
+
export async function writeJSON<T = unknown>(
|
|
59
|
+
components: Pick<CliComponents, 'fs'>,
|
|
60
|
+
path: string,
|
|
61
|
+
content: Partial<T>
|
|
62
|
+
): Promise<Partial<T>> {
|
|
63
|
+
let currentFile
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
currentFile = await readJSON<T>(components, path)
|
|
67
|
+
} catch (e) {
|
|
68
|
+
currentFile = {}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const newJson = { ...currentFile, ...content }
|
|
72
|
+
const strContent = JSON.stringify(newJson, null, 2)
|
|
73
|
+
|
|
74
|
+
await components.fs.writeFile(path, strContent)
|
|
75
|
+
return newJson
|
|
76
|
+
}
|
|
@@ -5,10 +5,14 @@ import { sync as globSync } from 'glob'
|
|
|
5
5
|
import ignore from 'ignore'
|
|
6
6
|
import path from 'path'
|
|
7
7
|
import { CliError } from './error'
|
|
8
|
+
import { getSceneFilePath } from './scene-validations'
|
|
9
|
+
import { Scene } from '@dcl/schemas'
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Returns an array of the publishable files for a given folder.
|
|
13
|
+
*
|
|
11
14
|
*/
|
|
15
|
+
/* istanbul ignore next */
|
|
12
16
|
export async function getPublishableFiles(
|
|
13
17
|
components: Pick<CliComponents, 'fs'>,
|
|
14
18
|
projectRoot: string
|
|
@@ -32,7 +36,9 @@ export async function getPublishableFiles(
|
|
|
32
36
|
* This function converts paths to decentraland-compatible paths.
|
|
33
37
|
* - From windows separators to unix separators.
|
|
34
38
|
* - All to lowercase
|
|
39
|
+
*
|
|
35
40
|
*/
|
|
41
|
+
/* istanbul ignore next */
|
|
36
42
|
export function normalizeDecentralandFilename(filename: string) {
|
|
37
43
|
return filename.replace(/(\\)/g, '/').toLowerCase()
|
|
38
44
|
}
|
|
@@ -40,9 +46,11 @@ export function normalizeDecentralandFilename(filename: string) {
|
|
|
40
46
|
/**
|
|
41
47
|
* Returns the content mappings for a specific project folder.
|
|
42
48
|
*/
|
|
49
|
+
/* istanbul ignore next */
|
|
43
50
|
export async function getProjectContentMappings(
|
|
44
51
|
components: Pick<CliComponents, 'fs'>,
|
|
45
52
|
projectRoot: string,
|
|
53
|
+
/* istanbul ignore next */
|
|
46
54
|
hashingFunction: (filePath: string) => Promise<string>
|
|
47
55
|
): Promise<ContentMapping[]> {
|
|
48
56
|
const projectFiles = await getPublishableFiles(components, projectRoot)
|
|
@@ -74,3 +82,11 @@ export async function getProjectContentMappings(
|
|
|
74
82
|
|
|
75
83
|
return ret
|
|
76
84
|
}
|
|
85
|
+
|
|
86
|
+
export async function getSceneJson(components: Pick<CliComponents, 'fs'>, projectRoot: string): Promise<Scene> {
|
|
87
|
+
const sceneJsonContent = await components.fs.readFile(getSceneFilePath(projectRoot), 'utf8')
|
|
88
|
+
const sceneJson = JSON.parse(sceneJsonContent) as Scene
|
|
89
|
+
return sceneJson
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export const b64HashingFunction = async (str: string) => 'b64-' + Buffer.from(str).toString('base64')
|
|
@@ -3,6 +3,7 @@ import { Scene } from '@dcl/schemas'
|
|
|
3
3
|
import { CliError } from './error'
|
|
4
4
|
import { getObject, inBounds, getBounds, areConnected } from './coordinates'
|
|
5
5
|
import { CliComponents } from '../components'
|
|
6
|
+
import { getSceneJson } from './project-files'
|
|
6
7
|
|
|
7
8
|
export const SCENE_FILE = 'scene.json'
|
|
8
9
|
|
|
@@ -63,11 +64,18 @@ export async function validateSceneJson(
|
|
|
63
64
|
projectRoot: string
|
|
64
65
|
): Promise<Scene> {
|
|
65
66
|
try {
|
|
66
|
-
const
|
|
67
|
-
const sceneJson = JSON.parse(sceneJsonRaw) as Scene
|
|
67
|
+
const sceneJson = await getSceneJson(components, projectRoot)
|
|
68
68
|
|
|
69
69
|
return assertValidScene(sceneJson)
|
|
70
70
|
} catch (err: any) {
|
|
71
71
|
throw new CliError(`Error reading the scene.json file: ${err.message}`)
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
+
|
|
75
|
+
export function getBaseCoords(scene: Scene): { x: number; y: number } {
|
|
76
|
+
const [x, y] = scene.scene.base
|
|
77
|
+
.replace(/\ /g, '')
|
|
78
|
+
.split(',')
|
|
79
|
+
.map((a) => parseInt(a))
|
|
80
|
+
return { x, y }
|
|
81
|
+
}
|