@dcl/sdk-commands 7.1.4 → 7.1.5-4704298040.commit-f6a337a
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.
@@ -114,22 +114,24 @@ async function main(options) {
|
|
114
114
|
if (workspace.projects.length > 1)
|
115
115
|
(0, beautiful_logs_1.printWarning)(options.components.logger, 'Support for multiple projects is still experimental.');
|
116
116
|
for (const project of workspace.projects) {
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
117
|
+
if (project.kind === 'scene') {
|
118
|
+
(0, beautiful_logs_1.printCurrentProjectStarting)(options.components.logger, project, workspace);
|
119
|
+
// first run `npm run build`, this can be disabled with --skip-build
|
120
|
+
// then start the embedded compiler, this can be disabled with --no-watch
|
121
|
+
if (watch) {
|
122
|
+
await (0, build_1.buildScene)({ ...options, args: { '--dir': project.workingDirectory, '--watch': true, _: [] } }, project);
|
123
|
+
}
|
124
|
+
else if (!skipBuild) {
|
125
|
+
await (0, build_1.buildScene)({ ...options, args: { '--dir': project.workingDirectory, '--watch': false, _: [] } }, project);
|
126
|
+
}
|
127
|
+
// track the event
|
128
|
+
baseCoords = (0, scene_validations_1.getBaseCoords)(project.scene);
|
129
|
+
options.components.analytics.track('Preview started', {
|
130
|
+
projectHash: await (0, project_files_1.b64HashingFunction)(project.workingDirectory),
|
131
|
+
coords: baseCoords,
|
132
|
+
isWorkspace: false
|
133
|
+
});
|
125
134
|
}
|
126
|
-
// track the event
|
127
|
-
baseCoords = (0, scene_validations_1.getBaseCoords)(project.scene);
|
128
|
-
options.components.analytics.track('Preview started', {
|
129
|
-
projectHash: await (0, project_files_1.b64HashingFunction)(project.workingDirectory),
|
130
|
-
coords: baseCoords,
|
131
|
-
isWorkspace: false
|
132
|
-
});
|
133
135
|
}
|
134
136
|
(0, beautiful_logs_1.printProgressInfo)(options.components.logger, 'Starting preview server');
|
135
137
|
const port = await (0, get_free_port_1.getPort)(options.args['--port'] || 0);
|
@@ -36,12 +36,11 @@ function smartWearableNameToId(name) {
|
|
36
36
|
}
|
37
37
|
async function setupEcs6Endpoints(components, router, workspace) {
|
38
38
|
const catalystUrl = new URL(await (0, config_1.getCatalystBaseUrl)(components));
|
39
|
-
|
40
|
-
// handle old preview scene.json
|
39
|
+
// handle old preview scene.json DEPRECATED
|
41
40
|
router.get('/scene.json', async () => {
|
42
41
|
return {
|
43
42
|
headers: { 'content-type': 'application/json' },
|
44
|
-
body: components.fs.createReadStream(path.join(
|
43
|
+
body: components.fs.createReadStream(path.join(workspace.projects[0].workingDirectory, 'scene.json'))
|
45
44
|
};
|
46
45
|
});
|
47
46
|
router.get('/lambdas/explore/realms', async (ctx) => {
|
@@ -72,8 +71,7 @@ async function setupEcs6Endpoints(components, router, workspace) {
|
|
72
71
|
router.get('/lambdas/profiles', async (ctx, next) => {
|
73
72
|
const baseUrl = `${ctx.url.protocol}//${ctx.url.host}/content/contents`;
|
74
73
|
try {
|
75
|
-
const previewWearables = await getAllPreviewWearables(components, {
|
76
|
-
baseFolders,
|
74
|
+
const previewWearables = await getAllPreviewWearables(components, workspace, {
|
77
75
|
baseUrl
|
78
76
|
});
|
79
77
|
if (previewWearables.length === 1) {
|
@@ -136,22 +134,43 @@ async function setupEcs6Endpoints(components, router, workspace) {
|
|
136
134
|
});
|
137
135
|
serveStatic(components, workspace, router);
|
138
136
|
// TODO: get workspace scenes & wearables...
|
139
|
-
await serveFolders(components, router,
|
137
|
+
await serveFolders(components, router, workspace);
|
140
138
|
}
|
141
139
|
exports.setupEcs6Endpoints = setupEcs6Endpoints;
|
142
|
-
async function serveFolders(components, router,
|
140
|
+
async function serveFolders(components, router, workspace) {
|
143
141
|
const catalystUrl = await (0, config_1.getCatalystBaseUrl)(components);
|
144
142
|
router.get('/content/contents/:hash', async (ctx, next) => {
|
145
143
|
if (ctx.params.hash && ctx.params.hash.startsWith('b64-')) {
|
146
144
|
const fullPath = path.resolve(Buffer.from(ctx.params.hash.replace(/^b64-/, ''), 'base64').toString('utf8'));
|
145
|
+
// find a project that we are talking about. NOTE: this filter is not exhaustive
|
146
|
+
// relative paths should be used instead
|
147
|
+
const baseProject = workspace.projects.find((project) => fullPath.startsWith(project.workingDirectory));
|
147
148
|
// only return files IF the file is within a baseFolder
|
148
|
-
if (!
|
149
|
+
if (!baseProject) {
|
149
150
|
return next();
|
150
151
|
}
|
152
|
+
if (path.resolve(fullPath) === path.resolve(baseProject.workingDirectory)) {
|
153
|
+
// if we are talking about the root directory, then we must return the json of the entity
|
154
|
+
const entity = await fakeEntityV3FromProject(components, baseProject, project_files_1.b64HashingFunction);
|
155
|
+
if (!entity)
|
156
|
+
return { status: 404 };
|
157
|
+
return {
|
158
|
+
headers: {
|
159
|
+
'x-timestamp': Date.now().toString(),
|
160
|
+
'x-sent': 'true',
|
161
|
+
'cache-control': 'no-cache,private,max-age=1'
|
162
|
+
},
|
163
|
+
body: entity
|
164
|
+
};
|
165
|
+
}
|
166
|
+
if (!(await components.fs.fileExists(fullPath)))
|
167
|
+
return { status: 404 };
|
168
|
+
if (await components.fs.directoryExists(fullPath))
|
169
|
+
return { status: 404 };
|
151
170
|
return {
|
152
171
|
headers: {
|
153
|
-
'x-timestamp': Date.now(),
|
154
|
-
'x-sent': true,
|
172
|
+
'x-timestamp': Date.now().toString(),
|
173
|
+
'x-sent': 'true',
|
155
174
|
'cache-control': 'no-cache,private,max-age=1'
|
156
175
|
},
|
157
176
|
body: components.fs.createReadStream(fullPath)
|
@@ -164,7 +183,7 @@ async function serveFolders(components, router, baseFolders) {
|
|
164
183
|
return [];
|
165
184
|
}
|
166
185
|
const requestedPointers = new Set(pointers && typeof pointers === 'string' ? [pointers] : pointers);
|
167
|
-
const resultEntities = await getSceneJson(components,
|
186
|
+
const resultEntities = await getSceneJson(components, workspace, Array.from(requestedPointers));
|
168
187
|
const remote = (0, catalyst_requests_1.fetchEntityByPointer)(components, catalystUrl.toString(), pointers.filter(($) => !$.match(/-?\d+,-?\d+/)));
|
169
188
|
const serverEntities = Array.isArray(remote) ? remote : [];
|
170
189
|
return [...resultEntities, ...serverEntities];
|
@@ -184,9 +203,8 @@ async function serveFolders(components, router, baseFolders) {
|
|
184
203
|
});
|
185
204
|
router.get('/preview-wearables/:id', async (ctx) => {
|
186
205
|
const baseUrl = `${ctx.url.protocol}//${ctx.url.host}/content/contents`;
|
187
|
-
const wearables = await getAllPreviewWearables(components, {
|
188
|
-
baseUrl
|
189
|
-
baseFolders
|
206
|
+
const wearables = await getAllPreviewWearables(components, workspace, {
|
207
|
+
baseUrl
|
190
208
|
});
|
191
209
|
const wearableId = ctx.params.id;
|
192
210
|
return {
|
@@ -201,40 +219,44 @@ async function serveFolders(components, router, baseFolders) {
|
|
201
219
|
return {
|
202
220
|
body: {
|
203
221
|
ok: true,
|
204
|
-
data: await getAllPreviewWearables(components, { baseUrl
|
222
|
+
data: await getAllPreviewWearables(components, workspace, { baseUrl })
|
205
223
|
}
|
206
224
|
};
|
207
225
|
});
|
208
226
|
}
|
209
|
-
async function getAllPreviewWearables(components, {
|
227
|
+
async function getAllPreviewWearables(components, workspace, { baseUrl }) {
|
228
|
+
// NOTE: the explorers should use the /entities/active endpoint to retrieve the wearables. This endpoint should be removed
|
210
229
|
const wearablePathArray = [];
|
211
|
-
for (const
|
212
|
-
|
213
|
-
|
214
|
-
|
230
|
+
for (const project of workspace.projects) {
|
231
|
+
if (project.kind === 'wearable') {
|
232
|
+
const wearableJsonPath = path.resolve(project.workingDirectory, 'wearable.json');
|
233
|
+
if (await components.fs.fileExists(wearableJsonPath)) {
|
234
|
+
wearablePathArray.push(wearableJsonPath);
|
235
|
+
}
|
215
236
|
}
|
216
237
|
}
|
217
238
|
const ret = [];
|
218
|
-
for (const
|
239
|
+
for (const project of workspace.projects) {
|
219
240
|
try {
|
220
|
-
|
241
|
+
if (project.kind === 'wearable')
|
242
|
+
ret.push(await serveWearable(components, project, baseUrl));
|
221
243
|
}
|
222
244
|
catch (err) {
|
223
|
-
components.logger.error(`Couldn't mock the wearable ${
|
245
|
+
components.logger.error(`Couldn't mock the wearable ${project.workingDirectory}. Please verify the correct format and scheme.` + err);
|
224
246
|
}
|
225
247
|
}
|
226
248
|
return ret;
|
227
249
|
}
|
228
|
-
async function serveWearable(components,
|
229
|
-
const
|
250
|
+
async function serveWearable(components, project, baseUrl) {
|
251
|
+
const wearableJsonPath = path.join(project.workingDirectory, 'wearable.json');
|
230
252
|
const wearableJson = JSON.parse((await components.fs.readFile(wearableJsonPath)).toString());
|
231
253
|
if (!sdk_1.WearableJson.validate(wearableJson)) {
|
232
254
|
const errors = (sdk_1.WearableJson.validate.errors || []).map((a) => `${a.data} ${a.message}`).join('');
|
233
255
|
components.logger.error(`Unable to validate wearable.json properly, please check it.` + errors);
|
234
256
|
throw new Error(`Invalid wearable.json (${wearableJsonPath})`);
|
235
257
|
}
|
236
|
-
const projectFiles = await (0, project_files_1.getProjectPublishableFilesWithHashes)(components,
|
237
|
-
const contentFiles = (0, project_files_1.projectFilesToContentMappings)(
|
258
|
+
const projectFiles = await (0, project_files_1.getProjectPublishableFilesWithHashes)(components, project.workingDirectory, project_files_1.b64HashingFunction);
|
259
|
+
const contentFiles = (0, project_files_1.projectFilesToContentMappings)(project.workingDirectory, projectFiles);
|
238
260
|
const thumbnailFiltered = contentFiles.filter(($) => $.file === 'thumbnail.png');
|
239
261
|
const thumbnail = thumbnailFiltered.length > 0 && thumbnailFiltered[0].hash && `${baseUrl}/${thumbnailFiltered[0].hash}`;
|
240
262
|
const wearableId = 'urn:8dc2d7ad-97e3-44d0-ba89-e8305d795a6a';
|
@@ -267,10 +289,10 @@ async function serveWearable(components, wearableJsonPath, baseUrl) {
|
|
267
289
|
}
|
268
290
|
};
|
269
291
|
}
|
270
|
-
async function getSceneJson(components,
|
292
|
+
async function getSceneJson(components, workspace, pointers) {
|
271
293
|
const requestedPointers = new Set(pointers);
|
272
294
|
const resultEntities = [];
|
273
|
-
const allDeployments = await Promise.all(
|
295
|
+
const allDeployments = await Promise.all(workspace.projects.map((project) => fakeEntityV3FromProject(components, project, project_files_1.b64HashingFunction)));
|
274
296
|
for (const pointer of Array.from(requestedPointers)) {
|
275
297
|
// get deployment by pointer
|
276
298
|
const theDeployment = allDeployments.find(($) => $ && $.pointers.includes(pointer));
|
@@ -326,6 +348,9 @@ function serveStatic(components, workspace, router) {
|
|
326
348
|
if (!(await components.fs.fileExists(fullPath))) {
|
327
349
|
return next();
|
328
350
|
}
|
351
|
+
if (await components.fs.directoryExists(fullPath)) {
|
352
|
+
return { status: 404 };
|
353
|
+
}
|
329
354
|
const headers = {
|
330
355
|
'x-timestamp': Date.now(),
|
331
356
|
'x-sent': true,
|
@@ -354,44 +379,49 @@ function serveStatic(components, workspace, router) {
|
|
354
379
|
};
|
355
380
|
});
|
356
381
|
}
|
357
|
-
async function
|
358
|
-
const
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
try {
|
363
|
-
const wearableJson = JSON.parse(await components.fs.readFile(wearableJsonPath, 'utf-8'));
|
364
|
-
if (!sdk_1.WearableJson.validate(wearableJson)) {
|
365
|
-
const errors = (sdk_1.WearableJson.validate.errors || []).map((a) => `${a.data} ${a.message}`).join('');
|
366
|
-
components.logger.error(`Unable to validate wearable.json properly, please check its schema.` + errors);
|
367
|
-
components.logger.error(`Invalid wearable.json (${wearableJsonPath})`);
|
368
|
-
}
|
369
|
-
else {
|
370
|
-
isParcelScene = false;
|
371
|
-
}
|
372
|
-
}
|
373
|
-
catch (err) {
|
374
|
-
components.logger.error(`Unable to load wearable.json`);
|
375
|
-
components.logger.error(err);
|
376
|
-
}
|
377
|
-
}
|
378
|
-
if ((await components.fs.fileExists(sceneJsonPath)) && isParcelScene) {
|
382
|
+
async function fakeEntityV3FromProject(components, project, hashingFunction) {
|
383
|
+
const projectFiles = await (0, project_files_1.getProjectPublishableFilesWithHashes)(components, project.workingDirectory, hashingFunction);
|
384
|
+
const contentFiles = (0, project_files_1.projectFilesToContentMappings)(project.workingDirectory, projectFiles);
|
385
|
+
if (project.kind === 'scene') {
|
386
|
+
const sceneJsonPath = path.resolve(project.workingDirectory, 'scene.json');
|
379
387
|
const sceneJson = JSON.parse(await components.fs.readFile(sceneJsonPath, 'utf-8'));
|
380
388
|
const { base, parcels } = sceneJson.scene;
|
381
389
|
const pointers = new Set();
|
382
390
|
pointers.add(base);
|
383
391
|
parcels.forEach(($) => pointers.add($));
|
384
|
-
const projectFiles = await (0, project_files_1.getProjectPublishableFilesWithHashes)(components, projectRoot, hashingFunction);
|
385
|
-
const contentFiles = (0, project_files_1.projectFilesToContentMappings)(projectRoot, projectFiles);
|
386
392
|
return {
|
387
393
|
version: 'v3',
|
388
394
|
type: schemas_1.EntityType.SCENE,
|
389
|
-
id: await hashingFunction(
|
395
|
+
id: await hashingFunction(project.workingDirectory),
|
390
396
|
pointers: Array.from(pointers),
|
391
397
|
timestamp: Date.now(),
|
392
398
|
metadata: sceneJson,
|
393
399
|
content: contentFiles
|
394
400
|
};
|
395
401
|
}
|
402
|
+
else if (project.kind === 'wearable') {
|
403
|
+
const wearableJsonPath = path.resolve(project.workingDirectory, 'wearable.json');
|
404
|
+
try {
|
405
|
+
const wearableJson = JSON.parse(await components.fs.readFile(wearableJsonPath, 'utf-8'));
|
406
|
+
if (!sdk_1.WearableJson.validate(wearableJson)) {
|
407
|
+
const errors = (sdk_1.WearableJson.validate.errors || []).map((a) => `${a.data} ${a.message}`).join('');
|
408
|
+
components.logger.error(`Unable to validate wearable.json properly, please check its schema.` + errors);
|
409
|
+
components.logger.error(`Invalid wearable.json (${wearableJsonPath})`);
|
410
|
+
}
|
411
|
+
return {
|
412
|
+
version: 'v3',
|
413
|
+
type: schemas_1.EntityType.WEARABLE,
|
414
|
+
id: await hashingFunction(project.workingDirectory),
|
415
|
+
pointers: Array.from([await hashingFunction(project.workingDirectory)]),
|
416
|
+
timestamp: Date.now(),
|
417
|
+
metadata: wearableJson,
|
418
|
+
content: contentFiles
|
419
|
+
};
|
420
|
+
}
|
421
|
+
catch (err) {
|
422
|
+
components.logger.error(`Unable to load wearable.json`);
|
423
|
+
components.logger.error(err);
|
424
|
+
}
|
425
|
+
}
|
396
426
|
return null;
|
397
427
|
}
|
@@ -7,7 +7,11 @@ export type SceneProject = {
|
|
7
7
|
kind: 'scene';
|
8
8
|
scene: Scene;
|
9
9
|
} & BaseProject;
|
10
|
-
export type
|
10
|
+
export type WearableProject = {
|
11
|
+
kind: 'wearable';
|
12
|
+
wearable: any;
|
13
|
+
} & BaseProject;
|
14
|
+
export type ProjectUnion = SceneProject | WearableProject;
|
11
15
|
/**
|
12
16
|
* Asserts that the workingDirectory is a valid project
|
13
17
|
*/
|
package/package.json
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
{
|
2
2
|
"name": "@dcl/sdk-commands",
|
3
3
|
"description": "",
|
4
|
-
"version": "7.1.
|
4
|
+
"version": "7.1.5-4704298040.commit-f6a337a",
|
5
5
|
"author": "Decentraland",
|
6
6
|
"bin": {
|
7
7
|
"sdk-commands": "./dist/index.js"
|
8
8
|
},
|
9
9
|
"dependencies": {
|
10
10
|
"@dcl/hashing": "1.1.3",
|
11
|
-
"@dcl/inspector": "7.1.
|
11
|
+
"@dcl/inspector": "7.1.5-4704298040.commit-f6a337a",
|
12
12
|
"@dcl/linker-dapp": "0.7.0",
|
13
13
|
"@dcl/mini-comms": "1.0.1-20230216163137.commit-a4c75be",
|
14
14
|
"@dcl/protocol": "1.0.0-4671230683.commit-a8d74c3",
|
@@ -60,5 +60,5 @@
|
|
60
60
|
"displayName": "SDK",
|
61
61
|
"tsconfig": "./tsconfig.json"
|
62
62
|
},
|
63
|
-
"commit": "
|
63
|
+
"commit": "f6a337a9f93f7738174df9448d5a735ebc9468a1"
|
64
64
|
}
|