@dcl/sdk 7.0.6-4197661608.commit-41efaad → 7.0.6-4217957637.commit-a393ef7
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/package.json +6 -33
- package/cli/commands/build/helpers.d.ts +0 -21
- package/cli/commands/build/helpers.js +0 -50
- package/cli/commands/build/helpers.ts +0 -89
- package/cli/commands/build/index.d.ts +0 -19
- package/cli/commands/build/index.js +0 -69
- package/cli/commands/build/index.ts +0 -91
- package/cli/commands/init/index.d.ts +0 -17
- package/cli/commands/init/index.js +0 -53
- package/cli/commands/init/index.ts +0 -69
- package/cli/commands/init/repos.d.ts +0 -9
- package/cli/commands/init/repos.js +0 -12
- package/cli/commands/init/repos.ts +0 -17
- package/cli/commands/preview/bff.d.ts +0 -3
- package/cli/commands/preview/bff.js +0 -54
- package/cli/commands/preview/bff.ts +0 -63
- package/cli/commands/preview/catalyst.d.ts +0 -5
- package/cli/commands/preview/catalyst.js +0 -24
- package/cli/commands/preview/catalyst.ts +0 -31
- package/cli/commands/preview/coordinates.d.ts +0 -20
- package/cli/commands/preview/coordinates.js +0 -90
- package/cli/commands/preview/coordinates.ts +0 -146
- package/cli/commands/preview/endpoints.d.ts +0 -10
- package/cli/commands/preview/endpoints.js +0 -485
- package/cli/commands/preview/endpoints.ts +0 -578
- package/cli/commands/preview/eth.d.ts +0 -2
- package/cli/commands/preview/eth.js +0 -6
- package/cli/commands/preview/eth.ts +0 -3
- package/cli/commands/preview/index.d.ts +0 -20
- package/cli/commands/preview/index.js +0 -71
- package/cli/commands/preview/index.ts +0 -91
- package/cli/commands/preview/port.d.ts +0 -1
- package/cli/commands/preview/port.js +0 -21
- package/cli/commands/preview/port.ts +0 -15
- package/cli/commands/preview/project.d.ts +0 -14
- package/cli/commands/preview/project.js +0 -77
- package/cli/commands/preview/project.ts +0 -112
- package/cli/commands/preview/types.d.ts +0 -18
- package/cli/commands/preview/types.js +0 -3
- package/cli/commands/preview/types.ts +0 -26
- package/cli/commands/preview/wire.d.ts +0 -2
- package/cli/commands/preview/wire.js +0 -92
- package/cli/commands/preview/wire.ts +0 -107
- package/cli/commands/preview/ws.d.ts +0 -7
- package/cli/commands/preview/ws.js +0 -16
- package/cli/commands/preview/ws.ts +0 -24
- package/cli/commands/start/index.d.ts +0 -29
- package/cli/commands/start/index.js +0 -126
- package/cli/commands/start/index.ts +0 -145
- package/cli/components/fetch.d.ts +0 -5
- package/cli/components/fetch.js +0 -34
- package/cli/components/fetch.ts +0 -11
- package/cli/components/fs.d.ts +0 -11
- package/cli/components/fs.js +0 -60
- package/cli/components/fs.ts +0 -53
- package/cli/components/index.d.ts +0 -7
- package/cli/components/index.js +0 -13
- package/cli/components/index.ts +0 -14
- package/cli/index.d.ts +0 -7
- package/cli/index.js +0 -76
- package/cli/index.ts +0 -85
- package/cli/utils/args.d.ts +0 -10
- package/cli/utils/args.js +0 -16
- package/cli/utils/args.ts +0 -18
- package/cli/utils/commands.d.ts +0 -3
- package/cli/utils/commands.js +0 -24
- package/cli/utils/commands.ts +0 -28
- package/cli/utils/error.d.ts +0 -2
- package/cli/utils/error.js +0 -7
- package/cli/utils/error.ts +0 -1
- package/cli/utils/exec.d.ts +0 -8
- package/cli/utils/exec.js +0 -32
- package/cli/utils/exec.ts +0 -42
- package/cli/utils/fs.d.ts +0 -10
- package/cli/utils/fs.js +0 -26
- package/cli/utils/fs.ts +0 -41
- package/cli/utils/log.d.ts +0 -5
- package/cli/utils/log.js +0 -29
- package/cli/utils/log.ts +0 -39
- package/cli/utils/object.d.ts +0 -9
- package/cli/utils/object.js +0 -45
- package/cli/utils/object.ts +0 -62
- package/cli/utils/out-messages.d.ts +0 -1
- package/cli/utils/out-messages.js +0 -8
- package/cli/utils/out-messages.ts +0 -3
- package/cli/utils/prompt.d.ts +0 -1
- package/cli/utils/prompt.js +0 -17
- package/cli/utils/prompt.ts +0 -11
@@ -1,578 +0,0 @@
|
|
1
|
-
import { Router } from '@well-known-components/http-server'
|
2
|
-
import { PreviewComponents } from './types'
|
3
|
-
import * as path from 'path'
|
4
|
-
import * as fs from 'fs'
|
5
|
-
import { sync as globSync } from 'glob'
|
6
|
-
import { WearableJson } from '@dcl/schemas/dist/sdk'
|
7
|
-
import { ContentMapping, Entity, EntityType } from '@dcl/schemas'
|
8
|
-
import ignore from 'ignore'
|
9
|
-
import fetch, { Headers } from 'node-fetch'
|
10
|
-
import { fetchEntityByPointer } from './catalyst'
|
11
|
-
|
12
|
-
function getCatalystUrl(): URL {
|
13
|
-
return new URL('https://peer.decentraland.org')
|
14
|
-
}
|
15
|
-
|
16
|
-
function smartWearableNameToId(name: string) {
|
17
|
-
return name.toLocaleLowerCase().replace(/ /g, '-')
|
18
|
-
}
|
19
|
-
|
20
|
-
export function setupEcs6Endpoints(dir: string, router: Router<PreviewComponents>) {
|
21
|
-
const baseFolders = [dir]
|
22
|
-
// handle old preview scene.json
|
23
|
-
router.get('/scene.json', async () => {
|
24
|
-
return {
|
25
|
-
headers: { 'content-type': 'application/json' },
|
26
|
-
body: fs.createReadStream(path.join(dir, 'scene.json'))
|
27
|
-
}
|
28
|
-
})
|
29
|
-
|
30
|
-
router.get('/lambdas/explore/realms', async (ctx) => {
|
31
|
-
return {
|
32
|
-
body: [
|
33
|
-
{
|
34
|
-
serverName: 'localhost',
|
35
|
-
url: `http://${ctx.url.host}`,
|
36
|
-
layer: 'stub',
|
37
|
-
usersCount: 0,
|
38
|
-
maxUsers: 100,
|
39
|
-
userParcels: []
|
40
|
-
}
|
41
|
-
]
|
42
|
-
}
|
43
|
-
})
|
44
|
-
|
45
|
-
router.get('/lambdas/contracts/servers', async (ctx) => {
|
46
|
-
return {
|
47
|
-
body: [
|
48
|
-
{
|
49
|
-
address: `http://${ctx.url.host}`,
|
50
|
-
owner: '0x0000000000000000000000000000000000000000',
|
51
|
-
id: '0x0000000000000000000000000000000000000000000000000000000000000000'
|
52
|
-
}
|
53
|
-
]
|
54
|
-
}
|
55
|
-
})
|
56
|
-
|
57
|
-
router.get('/lambdas/profiles', async (ctx, next) => {
|
58
|
-
const baseUrl = `${ctx.url.protocol}//${ctx.url.host}/content/contents`
|
59
|
-
|
60
|
-
try {
|
61
|
-
const previewWearables = getAllPreviewWearables({
|
62
|
-
baseFolders,
|
63
|
-
baseUrl
|
64
|
-
}).map((wearable) => wearable.id)
|
65
|
-
|
66
|
-
if (previewWearables.length === 1) {
|
67
|
-
const catalystUrl = getCatalystUrl()
|
68
|
-
|
69
|
-
const u = new URL(ctx.url.toString())
|
70
|
-
u.host = catalystUrl.host
|
71
|
-
u.protocol = catalystUrl.protocol
|
72
|
-
u.port = catalystUrl.port
|
73
|
-
const req = await fetch(u.toString(), {
|
74
|
-
headers: {
|
75
|
-
connection: 'close'
|
76
|
-
},
|
77
|
-
method: ctx.request.method,
|
78
|
-
body: ctx.request.method === 'get' ? undefined : ctx.request.body
|
79
|
-
})
|
80
|
-
|
81
|
-
const deployedProfile = (await req.json()) as any[]
|
82
|
-
|
83
|
-
if (deployedProfile?.length === 1) {
|
84
|
-
deployedProfile[0].avatars[0].avatar.wearables.push(...previewWearables)
|
85
|
-
return {
|
86
|
-
headers: {
|
87
|
-
'content-type': req.headers.get('content-type') || 'application/binary'
|
88
|
-
},
|
89
|
-
body: deployedProfile
|
90
|
-
}
|
91
|
-
}
|
92
|
-
}
|
93
|
-
} catch (err) {
|
94
|
-
console.warn(`Failed to catch profile and fill with preview wearables.`, err)
|
95
|
-
}
|
96
|
-
|
97
|
-
return next()
|
98
|
-
})
|
99
|
-
|
100
|
-
router.all('/lambdas/:path+', async (ctx) => {
|
101
|
-
const catalystUrl = getCatalystUrl()
|
102
|
-
const u = new URL(ctx.url.toString())
|
103
|
-
u.host = catalystUrl.host
|
104
|
-
u.protocol = catalystUrl.protocol
|
105
|
-
u.port = catalystUrl.port
|
106
|
-
const req = await fetch(u.toString(), {
|
107
|
-
headers: {
|
108
|
-
connection: 'close'
|
109
|
-
},
|
110
|
-
method: ctx.request.method,
|
111
|
-
body: ctx.request.method === 'get' ? undefined : ctx.request.body
|
112
|
-
})
|
113
|
-
|
114
|
-
return {
|
115
|
-
headers: {
|
116
|
-
'content-type': req.headers.get('content-type') || 'application/binary'
|
117
|
-
},
|
118
|
-
body: req.body
|
119
|
-
}
|
120
|
-
})
|
121
|
-
|
122
|
-
router.post('/content/entities', async (ctx) => {
|
123
|
-
const catalystUrl = getCatalystUrl()
|
124
|
-
const headers = new Headers()
|
125
|
-
console.log(ctx.request.headers)
|
126
|
-
const res = await fetch(`${catalystUrl.toString()}/content/entities`, {
|
127
|
-
method: 'post',
|
128
|
-
headers,
|
129
|
-
body: ctx.request.body
|
130
|
-
})
|
131
|
-
|
132
|
-
return res
|
133
|
-
})
|
134
|
-
|
135
|
-
serveStatic(dir, router)
|
136
|
-
|
137
|
-
// TODO: get workspace scenes & wearables...
|
138
|
-
|
139
|
-
serveFolders(router, baseFolders)
|
140
|
-
}
|
141
|
-
|
142
|
-
function serveFolders(router: Router<PreviewComponents>, baseFolders: string[]) {
|
143
|
-
router.get('/content/contents/:hash', async (ctx: any, next: any) => {
|
144
|
-
if (ctx.params.hash && ctx.params.hash.startsWith('b64-')) {
|
145
|
-
const fullPath = path.resolve(Buffer.from(ctx.params.hash.replace(/^b64-/, ''), 'base64').toString('utf8'))
|
146
|
-
|
147
|
-
// only return files IF the file is within a baseFolder
|
148
|
-
if (!baseFolders.find((folder: string) => fullPath.startsWith(folder))) {
|
149
|
-
return next()
|
150
|
-
}
|
151
|
-
|
152
|
-
return {
|
153
|
-
headers: {
|
154
|
-
'x-timestamp': Date.now(),
|
155
|
-
'x-sent': true,
|
156
|
-
'cache-control': 'no-cache,private,max-age=1'
|
157
|
-
},
|
158
|
-
body: fs.createReadStream(fullPath)
|
159
|
-
}
|
160
|
-
}
|
161
|
-
|
162
|
-
return next()
|
163
|
-
})
|
164
|
-
|
165
|
-
async function pointerRequestHandler(pointers: string[]) {
|
166
|
-
if (!pointers || pointers.length === 0) {
|
167
|
-
return []
|
168
|
-
}
|
169
|
-
|
170
|
-
const requestedPointers = new Set<string>(
|
171
|
-
pointers && typeof pointers === 'string' ? [pointers as string] : (pointers as string[])
|
172
|
-
)
|
173
|
-
|
174
|
-
const resultEntities = getSceneJson({
|
175
|
-
baseFolders,
|
176
|
-
pointers: Array.from(requestedPointers)
|
177
|
-
})
|
178
|
-
const catalystUrl = getCatalystUrl()
|
179
|
-
const remote = fetchEntityByPointer(
|
180
|
-
catalystUrl.toString(),
|
181
|
-
pointers.filter(($: string) => !$.match(/-?\d+,-?\d+/))
|
182
|
-
)
|
183
|
-
|
184
|
-
const serverEntities = Array.isArray(remote) ? remote : []
|
185
|
-
|
186
|
-
return [...resultEntities, ...serverEntities]
|
187
|
-
}
|
188
|
-
|
189
|
-
// REVIEW RESPONSE FORMAT
|
190
|
-
router.get('/content/entities/scene', async (ctx) => {
|
191
|
-
return {
|
192
|
-
body: await pointerRequestHandler(ctx.url.searchParams.getAll('pointer'))
|
193
|
-
}
|
194
|
-
})
|
195
|
-
|
196
|
-
// REVIEW RESPONSE FORMAT
|
197
|
-
router.post('/content/entities/active', async (ctx) => {
|
198
|
-
const body = await ctx.request.json()
|
199
|
-
return {
|
200
|
-
body: await pointerRequestHandler(body.pointers)
|
201
|
-
}
|
202
|
-
})
|
203
|
-
|
204
|
-
router.get('/preview-wearables/:id', async (ctx) => {
|
205
|
-
const baseUrl = `${ctx.url.protocol}//${ctx.url.host}/content/contents`
|
206
|
-
const wearables = getAllPreviewWearables({
|
207
|
-
baseUrl,
|
208
|
-
baseFolders
|
209
|
-
})
|
210
|
-
const wearableId = ctx.params.id
|
211
|
-
return {
|
212
|
-
body: {
|
213
|
-
ok: true,
|
214
|
-
data: wearables.filter((wearable) => smartWearableNameToId(wearable?.name) === wearableId)
|
215
|
-
}
|
216
|
-
}
|
217
|
-
})
|
218
|
-
|
219
|
-
router.get('/preview-wearables', async (ctx) => {
|
220
|
-
const baseUrl = `${ctx.url.protocol}//${ctx.url.host}/content/contents`
|
221
|
-
return {
|
222
|
-
body: {
|
223
|
-
ok: true,
|
224
|
-
data: getAllPreviewWearables({ baseUrl, baseFolders })
|
225
|
-
}
|
226
|
-
}
|
227
|
-
})
|
228
|
-
}
|
229
|
-
|
230
|
-
const defaultHashMaker = (str: string) => 'b64-' + Buffer.from(str).toString('base64')
|
231
|
-
|
232
|
-
function getAllPreviewWearables({ baseFolders, baseUrl }: { baseFolders: string[]; baseUrl: string }) {
|
233
|
-
const wearablePathArray: string[] = []
|
234
|
-
for (const wearableDir of baseFolders) {
|
235
|
-
const wearableJsonPath = path.resolve(wearableDir, 'wearable.json')
|
236
|
-
if (fs.existsSync(wearableJsonPath)) {
|
237
|
-
wearablePathArray.push(wearableJsonPath)
|
238
|
-
}
|
239
|
-
}
|
240
|
-
|
241
|
-
const ret: ReturnType<typeof serveWearable>[] = []
|
242
|
-
for (const wearableJsonPath of wearablePathArray) {
|
243
|
-
try {
|
244
|
-
ret.push(serveWearable({ wearableJsonPath, baseUrl }))
|
245
|
-
} catch (err) {
|
246
|
-
console.error(`Couldn't mock the wearable ${wearableJsonPath}. Please verify the correct format and scheme.`, err)
|
247
|
-
}
|
248
|
-
}
|
249
|
-
return ret
|
250
|
-
}
|
251
|
-
|
252
|
-
function serveWearable({ wearableJsonPath, baseUrl }: { wearableJsonPath: string; baseUrl: string }) {
|
253
|
-
const wearableDir = path.dirname(wearableJsonPath)
|
254
|
-
const wearableJson = JSON.parse(fs.readFileSync(wearableJsonPath).toString())
|
255
|
-
|
256
|
-
if (!WearableJson.validate(wearableJson)) {
|
257
|
-
const errors = (WearableJson.validate.errors || []).map((a) => `${a.data} ${a.message}`).join('')
|
258
|
-
|
259
|
-
console.error(`Unable to validate wearable.json properly, please check it.`, errors)
|
260
|
-
throw new Error(`Invalid wearable.json (${wearableJsonPath})`)
|
261
|
-
}
|
262
|
-
|
263
|
-
const dclIgnorePath = path.resolve(wearableDir, '.dclignore')
|
264
|
-
let ignoreFileContent = ''
|
265
|
-
if (fs.existsSync(dclIgnorePath)) {
|
266
|
-
ignoreFileContent = fs.readFileSync(path.resolve(wearableDir, '.dclignore'), 'utf-8')
|
267
|
-
}
|
268
|
-
|
269
|
-
const hashedFiles = getFilesFromFolder({
|
270
|
-
folder: wearableDir,
|
271
|
-
addOriginalPath: false,
|
272
|
-
ignorePattern: ignoreFileContent
|
273
|
-
})
|
274
|
-
|
275
|
-
const thumbnailFiltered = hashedFiles.filter(($) => $?.file === 'thumbnail.png')
|
276
|
-
const thumbnail =
|
277
|
-
thumbnailFiltered.length > 0 && thumbnailFiltered[0]?.hash && `${baseUrl}/${thumbnailFiltered[0].hash}`
|
278
|
-
|
279
|
-
const wearableId = 'urn:8dc2d7ad-97e3-44d0-ba89-e8305d795a6a'
|
280
|
-
|
281
|
-
const representations = wearableJson.data.representations.map((representation) => ({
|
282
|
-
...representation,
|
283
|
-
mainFile: `male/${representation.mainFile}`,
|
284
|
-
contents: hashedFiles.map(($) => ({
|
285
|
-
key: `male/${$?.file}`,
|
286
|
-
url: `${baseUrl}/${$?.hash}`,
|
287
|
-
hash: $?.hash
|
288
|
-
}))
|
289
|
-
}))
|
290
|
-
|
291
|
-
return {
|
292
|
-
id: wearableId,
|
293
|
-
rarity: wearableJson.rarity,
|
294
|
-
i18n: [{ code: 'en', text: wearableJson.name }],
|
295
|
-
description: wearableJson.description,
|
296
|
-
thumbnail: thumbnail || '',
|
297
|
-
baseUrl: `${baseUrl}/`,
|
298
|
-
name: wearableJson.name || '',
|
299
|
-
data: {
|
300
|
-
category: wearableJson.data.category,
|
301
|
-
replaces: [],
|
302
|
-
hides: [],
|
303
|
-
tags: [],
|
304
|
-
scene: hashedFiles,
|
305
|
-
representations: representations as any
|
306
|
-
}
|
307
|
-
}
|
308
|
-
}
|
309
|
-
|
310
|
-
function getSceneJson({
|
311
|
-
baseFolders,
|
312
|
-
pointers,
|
313
|
-
customHashMaker
|
314
|
-
}: {
|
315
|
-
baseFolders: string[]
|
316
|
-
pointers: string[]
|
317
|
-
customHashMaker?: (str: string) => string
|
318
|
-
}): Entity[] {
|
319
|
-
const requestedPointers = new Set<string>(pointers)
|
320
|
-
const resultEntities: Entity[] = []
|
321
|
-
|
322
|
-
const allDeployments = baseFolders.map((folder) => {
|
323
|
-
const dclIgnorePath = path.resolve(folder, '.dclignore')
|
324
|
-
let ignoreFileContent = ''
|
325
|
-
if (fs.existsSync(dclIgnorePath)) {
|
326
|
-
ignoreFileContent = fs.readFileSync(path.resolve(folder, '.dclignore'), 'utf-8')
|
327
|
-
}
|
328
|
-
|
329
|
-
return entityV3FromFolder({
|
330
|
-
folder,
|
331
|
-
addOriginalPath: false,
|
332
|
-
ignorePattern: ignoreFileContent,
|
333
|
-
customHashMaker
|
334
|
-
})
|
335
|
-
})
|
336
|
-
|
337
|
-
for (const pointer of Array.from(requestedPointers)) {
|
338
|
-
// get deployment by pointer
|
339
|
-
const theDeployment = allDeployments.find(($) => $ && $.pointers.includes(pointer))
|
340
|
-
if (theDeployment) {
|
341
|
-
// remove all the required pointers from the requestedPointers set
|
342
|
-
// to prevent sending duplicated entities
|
343
|
-
theDeployment.pointers.forEach(($) => requestedPointers.delete($))
|
344
|
-
|
345
|
-
// add the deployment to the results
|
346
|
-
resultEntities.push(theDeployment)
|
347
|
-
}
|
348
|
-
}
|
349
|
-
|
350
|
-
return resultEntities
|
351
|
-
}
|
352
|
-
|
353
|
-
function serveStatic(dir: string, router: Router<PreviewComponents>) {
|
354
|
-
const sdkPath = path.dirname(
|
355
|
-
require.resolve('@dcl/sdk/package.json', {
|
356
|
-
paths: [dir]
|
357
|
-
})
|
358
|
-
)
|
359
|
-
const dclExplorerJsonPath = path.dirname(
|
360
|
-
require.resolve('@dcl/explorer/package.json', {
|
361
|
-
paths: [dir, sdkPath]
|
362
|
-
})
|
363
|
-
)
|
364
|
-
|
365
|
-
const dclKernelDefaultProfilePath = path.resolve(dclExplorerJsonPath, 'default-profile')
|
366
|
-
const dclKernelImagesDecentralandConnect = path.resolve(dclExplorerJsonPath, 'images', 'decentraland-connect')
|
367
|
-
|
368
|
-
const routes = [
|
369
|
-
{
|
370
|
-
route: '/',
|
371
|
-
path: path.resolve(dclExplorerJsonPath, 'preview.html'),
|
372
|
-
type: 'text/html'
|
373
|
-
},
|
374
|
-
{
|
375
|
-
route: '/favicon.ico',
|
376
|
-
path: path.resolve(dclExplorerJsonPath, 'favicon.ico'),
|
377
|
-
type: 'text/html'
|
378
|
-
},
|
379
|
-
{
|
380
|
-
route: '/@/explorer/index.js',
|
381
|
-
path: path.resolve(dclExplorerJsonPath, 'index.js'),
|
382
|
-
type: 'text/javascript'
|
383
|
-
}
|
384
|
-
]
|
385
|
-
|
386
|
-
for (const route of routes) {
|
387
|
-
router.get(route.route, async (_ctx) => {
|
388
|
-
return {
|
389
|
-
headers: { 'Content-Type': route.type },
|
390
|
-
body: fs.createReadStream(route.path)
|
391
|
-
}
|
392
|
-
})
|
393
|
-
}
|
394
|
-
|
395
|
-
function createStaticRoutes(route: string, folder: string, transform = (str: string) => str) {
|
396
|
-
router.get(route, async (ctx, next) => {
|
397
|
-
const file = ctx.params.path
|
398
|
-
const fullPath = path.resolve(folder, transform(file))
|
399
|
-
|
400
|
-
// only return files IF the file is within a baseFolder
|
401
|
-
if (!fs.existsSync(fullPath)) {
|
402
|
-
return next()
|
403
|
-
}
|
404
|
-
|
405
|
-
const headers: Record<string, any> = {
|
406
|
-
'x-timestamp': Date.now(),
|
407
|
-
'x-sent': true,
|
408
|
-
'cache-control': 'no-cache,private,max-age=1'
|
409
|
-
}
|
410
|
-
|
411
|
-
if (fullPath.endsWith('.wasm')) {
|
412
|
-
headers['content-type'] = 'application/wasm'
|
413
|
-
}
|
414
|
-
|
415
|
-
return {
|
416
|
-
headers,
|
417
|
-
body: fs.createReadStream(fullPath)
|
418
|
-
}
|
419
|
-
})
|
420
|
-
}
|
421
|
-
|
422
|
-
createStaticRoutes('/images/decentraland-connect/:path+', dclKernelImagesDecentralandConnect)
|
423
|
-
createStaticRoutes('/default-profile/:path+', dclKernelDefaultProfilePath)
|
424
|
-
createStaticRoutes('/@/explorer/:path+', dclExplorerJsonPath, (filePath) => filePath.replace(/.br+$/, ''))
|
425
|
-
|
426
|
-
router.get('/feature-flags/:file', async (ctx) => {
|
427
|
-
const res = await fetch(`https://feature-flags.decentraland.zone/${ctx.params.file}`, {
|
428
|
-
headers: {
|
429
|
-
connection: 'close'
|
430
|
-
}
|
431
|
-
})
|
432
|
-
return {
|
433
|
-
body: await res.arrayBuffer()
|
434
|
-
}
|
435
|
-
})
|
436
|
-
}
|
437
|
-
|
438
|
-
function entityV3FromFolder({
|
439
|
-
folder,
|
440
|
-
addOriginalPath,
|
441
|
-
ignorePattern,
|
442
|
-
customHashMaker
|
443
|
-
}: {
|
444
|
-
folder: string
|
445
|
-
addOriginalPath?: boolean
|
446
|
-
ignorePattern?: string
|
447
|
-
customHashMaker?: (str: string) => string
|
448
|
-
}): Entity | null {
|
449
|
-
const sceneJsonPath = path.resolve(folder, './scene.json')
|
450
|
-
let isParcelScene = true
|
451
|
-
|
452
|
-
const wearableJsonPath = path.resolve(folder, './wearable.json')
|
453
|
-
if (fs.existsSync(wearableJsonPath)) {
|
454
|
-
try {
|
455
|
-
const wearableJson = JSON.parse(fs.readFileSync(wearableJsonPath).toString())
|
456
|
-
if (!WearableJson.validate(wearableJson)) {
|
457
|
-
const errors = (WearableJson.validate.errors || []).map((a) => `${a.data} ${a.message}`).join('')
|
458
|
-
|
459
|
-
console.error(`Unable to validate wearable.json properly, please check it.`, errors)
|
460
|
-
console.error(`Invalid wearable.json (${wearableJsonPath})`)
|
461
|
-
} else {
|
462
|
-
isParcelScene = false
|
463
|
-
}
|
464
|
-
} catch (err) {
|
465
|
-
console.error(`Unable to load wearable.json properly`, err)
|
466
|
-
}
|
467
|
-
}
|
468
|
-
|
469
|
-
const hashMaker = customHashMaker ? customHashMaker : defaultHashMaker
|
470
|
-
|
471
|
-
if (fs.existsSync(sceneJsonPath) && isParcelScene) {
|
472
|
-
const sceneJson = JSON.parse(fs.readFileSync(sceneJsonPath).toString())
|
473
|
-
const { base, parcels }: { base: string; parcels: string[] } = sceneJson.scene
|
474
|
-
const pointers = new Set<string>()
|
475
|
-
pointers.add(base)
|
476
|
-
parcels.forEach(($) => pointers.add($))
|
477
|
-
|
478
|
-
const mappedFiles = getFilesFromFolder({
|
479
|
-
folder,
|
480
|
-
addOriginalPath,
|
481
|
-
ignorePattern,
|
482
|
-
customHashMaker
|
483
|
-
})
|
484
|
-
|
485
|
-
return {
|
486
|
-
version: 'v3',
|
487
|
-
type: EntityType.SCENE,
|
488
|
-
id: hashMaker(folder),
|
489
|
-
pointers: Array.from(pointers),
|
490
|
-
timestamp: Date.now(),
|
491
|
-
metadata: sceneJson,
|
492
|
-
content: mappedFiles
|
493
|
-
}
|
494
|
-
}
|
495
|
-
|
496
|
-
return null
|
497
|
-
}
|
498
|
-
|
499
|
-
const defaultDclIgnore = () =>
|
500
|
-
[
|
501
|
-
'.*',
|
502
|
-
'package.json',
|
503
|
-
'package-lock.json',
|
504
|
-
'yarn-lock.json',
|
505
|
-
'build.json',
|
506
|
-
'export',
|
507
|
-
'tsconfig.json',
|
508
|
-
'tslint.json',
|
509
|
-
'node_modules',
|
510
|
-
'*.ts',
|
511
|
-
'*.tsx',
|
512
|
-
'Dockerfile',
|
513
|
-
'dist',
|
514
|
-
'README.md',
|
515
|
-
'*.blend',
|
516
|
-
'*.fbx',
|
517
|
-
'*.zip',
|
518
|
-
'*.rar'
|
519
|
-
].join('\n')
|
520
|
-
|
521
|
-
export function getFilesFromFolder({
|
522
|
-
folder,
|
523
|
-
addOriginalPath,
|
524
|
-
ignorePattern,
|
525
|
-
customHashMaker
|
526
|
-
}: {
|
527
|
-
folder: string
|
528
|
-
addOriginalPath?: boolean
|
529
|
-
ignorePattern?: string
|
530
|
-
customHashMaker?: (str: string) => string
|
531
|
-
}): ContentMapping[] {
|
532
|
-
const hashMaker = customHashMaker ? customHashMaker : defaultHashMaker
|
533
|
-
|
534
|
-
const allFiles = globSync('**/*', {
|
535
|
-
cwd: folder,
|
536
|
-
dot: false,
|
537
|
-
absolute: true
|
538
|
-
})
|
539
|
-
.map((file) => {
|
540
|
-
try {
|
541
|
-
if (!fs.statSync(file).isFile()) return
|
542
|
-
} catch (err) {
|
543
|
-
return
|
544
|
-
}
|
545
|
-
const _folder = folder.replace(/\\/gi, '/')
|
546
|
-
const key = file.replace(_folder, '').replace(/^\/+/, '')
|
547
|
-
return key
|
548
|
-
})
|
549
|
-
.filter(($) => !!$) as string[]
|
550
|
-
|
551
|
-
const ensureIgnorePattern = ignorePattern && ignorePattern !== '' ? ignorePattern : defaultDclIgnore()
|
552
|
-
const ig = ignore().add(ensureIgnorePattern)
|
553
|
-
const filteredFiles = ig.filter(allFiles)
|
554
|
-
|
555
|
-
const ret: (ContentMapping & { original_path: string | undefined })[] = []
|
556
|
-
|
557
|
-
for (const file of filteredFiles) {
|
558
|
-
const absolutePath = path.resolve(folder, file)
|
559
|
-
try {
|
560
|
-
if (!fs.statSync(absolutePath).isFile()) continue
|
561
|
-
} catch (err) {
|
562
|
-
console.log(err)
|
563
|
-
continue
|
564
|
-
}
|
565
|
-
|
566
|
-
const absoluteFolder = folder.replace(/\\/gi, '/')
|
567
|
-
|
568
|
-
const relativeFilePathToFolder = file.replace(absoluteFolder, '').replace(/^\/+/, '')
|
569
|
-
|
570
|
-
ret.push({
|
571
|
-
file: relativeFilePathToFolder.toLowerCase(),
|
572
|
-
original_path: addOriginalPath ? absolutePath : undefined,
|
573
|
-
hash: hashMaker(absolutePath)
|
574
|
-
})
|
575
|
-
}
|
576
|
-
|
577
|
-
return ret
|
578
|
-
}
|
@@ -1,6 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.providerInstance = void 0;
|
4
|
-
const eth_connect_1 = require("eth-connect");
|
5
|
-
exports.providerInstance = new eth_connect_1.HTTPProvider('https://goerli.infura.io/');
|
6
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXRoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZXRoLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDZDQUEwQztBQUU3QixRQUFBLGdCQUFnQixHQUFHLElBQUksMEJBQVksQ0FBQywyQkFBMkIsQ0FBQyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSFRUUFByb3ZpZGVyIH0gZnJvbSAnZXRoLWNvbm5lY3QnXG5cbmV4cG9ydCBjb25zdCBwcm92aWRlckluc3RhbmNlID0gbmV3IEhUVFBQcm92aWRlcignaHR0cHM6Ly9nb2VybGkuaW5mdXJhLmlvLycpXG4iXX0=
|
@@ -1,20 +0,0 @@
|
|
1
|
-
import { Lifecycle } from '@well-known-components/interfaces';
|
2
|
-
import { CliComponents } from '../../components';
|
3
|
-
import { PreviewComponents } from './types';
|
4
|
-
export declare function help(): string;
|
5
|
-
interface Options {
|
6
|
-
args: Omit<typeof args, '_'>;
|
7
|
-
components: Pick<CliComponents, 'fetch' | 'fs'>;
|
8
|
-
}
|
9
|
-
export declare const args: import("arg").Result<{
|
10
|
-
'--help': BooleanConstructor;
|
11
|
-
'-h': string;
|
12
|
-
} & {
|
13
|
-
'--watch': BooleanConstructor;
|
14
|
-
'-w': string;
|
15
|
-
'--dir': StringConstructor;
|
16
|
-
'--port': NumberConstructor;
|
17
|
-
'-p': string;
|
18
|
-
}>;
|
19
|
-
export declare function main(options: Options): Promise<Lifecycle.ComponentBasedProgram<PreviewComponents>>;
|
20
|
-
export {};
|
@@ -1,71 +0,0 @@
|
|
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.main = exports.args = exports.help = void 0;
|
7
|
-
const path_1 = require("path");
|
8
|
-
const fp_future_1 = __importDefault(require("fp-future"));
|
9
|
-
const interfaces_1 = require("@well-known-components/interfaces");
|
10
|
-
const rooms_1 = require("@dcl/mini-comms/dist/adapters/rooms");
|
11
|
-
const env_config_provider_1 = require("@well-known-components/env-config-provider");
|
12
|
-
const http_server_1 = require("@well-known-components/http-server");
|
13
|
-
const logger_1 = require("@well-known-components/logger");
|
14
|
-
const metrics_1 = require("@well-known-components/metrics");
|
15
|
-
const ws_1 = require("./ws");
|
16
|
-
const args_1 = require("../../utils/args");
|
17
|
-
const project_1 = require("./project");
|
18
|
-
const port_1 = require("./port");
|
19
|
-
const eth_1 = require("./eth");
|
20
|
-
const wire_1 = require("./wire");
|
21
|
-
function help() {
|
22
|
-
return ``;
|
23
|
-
}
|
24
|
-
exports.help = help;
|
25
|
-
exports.args = (0, args_1.getArgs)({
|
26
|
-
'--watch': Boolean,
|
27
|
-
'-w': '--watch',
|
28
|
-
'--dir': String,
|
29
|
-
'--port': Number,
|
30
|
-
'-p': '--port'
|
31
|
-
});
|
32
|
-
async function main(options) {
|
33
|
-
const dir = (0, path_1.resolve)(process.cwd(), options.args['--dir'] || '.');
|
34
|
-
await (0, project_1.validateExistingProject)(options.components, dir);
|
35
|
-
await (0, project_1.validateSceneOptions)(options.components, dir);
|
36
|
-
const port = options.args['--port'] || (await (0, port_1.previewPort)());
|
37
|
-
const program = await interfaces_1.Lifecycle.run({
|
38
|
-
async initComponents() {
|
39
|
-
const metrics = (0, metrics_1.createTestMetricsComponent)(rooms_1.roomsMetrics);
|
40
|
-
const config = (0, env_config_provider_1.createRecordConfigComponent)(Object.assign({ HTTP_SERVER_PORT: port.toString(), HTTP_SERVER_HOST: '0.0.0.0' }, process.env));
|
41
|
-
const logs = await (0, logger_1.createConsoleLogComponent)({});
|
42
|
-
const ws = await (0, ws_1.createWsComponent)({ logs });
|
43
|
-
const server = await (0, http_server_1.createServerComponent)({ config, logs, ws: ws.ws }, { cors: {} });
|
44
|
-
const rooms = await (0, rooms_1.createRoomsComponent)({
|
45
|
-
metrics,
|
46
|
-
logs,
|
47
|
-
config
|
48
|
-
});
|
49
|
-
const programClosed = (0, fp_future_1.default)();
|
50
|
-
const signaler = {
|
51
|
-
programClosed,
|
52
|
-
async stop() {
|
53
|
-
programClosed.resolve();
|
54
|
-
}
|
55
|
-
};
|
56
|
-
return Object.assign(Object.assign({}, options.components), { logs, ethereumProvider: eth_1.providerInstance, rooms,
|
57
|
-
config,
|
58
|
-
metrics,
|
59
|
-
server,
|
60
|
-
ws,
|
61
|
-
signaler });
|
62
|
-
},
|
63
|
-
async main({ components, startComponents }) {
|
64
|
-
await (0, wire_1.wire)(components, dir, !!options.args['--watch']);
|
65
|
-
await startComponents();
|
66
|
-
}
|
67
|
-
});
|
68
|
-
return program;
|
69
|
-
}
|
70
|
-
exports.main = main;
|
71
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSwrQkFBOEI7QUFDOUIsMERBQThCO0FBQzlCLGtFQUE2RTtBQUM3RSwrREFBd0Y7QUFDeEYsb0ZBQXdGO0FBQ3hGLG9FQUEwRTtBQUMxRSwwREFBeUU7QUFDekUsNERBQTJFO0FBQzNFLDZCQUF3QztBQUd4QywyQ0FBMEM7QUFFMUMsdUNBQXlFO0FBQ3pFLGlDQUFvQztBQUNwQywrQkFBd0M7QUFDeEMsaUNBQTZCO0FBRTdCLFNBQWdCLElBQUk7SUFDbEIsT0FBTyxFQUFFLENBQUE7QUFDWCxDQUFDO0FBRkQsb0JBRUM7QUFPWSxRQUFBLElBQUksR0FBRyxJQUFBLGNBQU8sRUFBQztJQUMxQixTQUFTLEVBQUUsT0FBTztJQUNsQixJQUFJLEVBQUUsU0FBUztJQUNmLE9BQU8sRUFBRSxNQUFNO0lBQ2YsUUFBUSxFQUFFLE1BQU07SUFDaEIsSUFBSSxFQUFFLFFBQVE7Q0FDZixDQUFDLENBQUE7QUFJSyxLQUFLLFVBQVUsSUFBSSxDQUFDLE9BQWdCO0lBQ3pDLE1BQU0sR0FBRyxHQUFHLElBQUEsY0FBTyxFQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFBO0lBQ2hFLE1BQU0sSUFBQSxpQ0FBdUIsRUFBQyxPQUFPLENBQUMsVUFBVSxFQUFFLEdBQUcsQ0FBQyxDQUFBO0lBQ3RELE1BQU0sSUFBQSw4QkFBb0IsRUFBQyxPQUFPLENBQUMsVUFBVSxFQUFFLEdBQUcsQ0FBQyxDQUFBO0lBRW5ELE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLElBQUEsa0JBQVcsR0FBRSxDQUFDLENBQUE7SUFFNUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxzQkFBUyxDQUFDLEdBQUcsQ0FBb0I7UUFDckQsS0FBSyxDQUFDLGNBQWM7WUFDbEIsTUFBTSxPQUFPLEdBQUcsSUFBQSxvQ0FBMEIsRUFBQyxvQkFBWSxDQUFDLENBQUE7WUFDeEQsTUFBTSxNQUFNLEdBQUcsSUFBQSxpREFBMkIsa0JBQ3hDLGdCQUFnQixFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUUsRUFDakMsZ0JBQWdCLEVBQUUsU0FBUyxJQUN4QixPQUFPLENBQUMsR0FBRyxFQUNkLENBQUE7WUFDRixNQUFNLElBQUksR0FBRyxNQUFNLElBQUEsa0NBQXlCLEVBQUMsRUFBRSxDQUFDLENBQUE7WUFDaEQsTUFBTSxFQUFFLEdBQUcsTUFBTSxJQUFBLHNCQUFpQixFQUFDLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQTtZQUM1QyxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUEsbUNBQXFCLEVBQW9CLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUE7WUFDeEcsTUFBTSxLQUFLLEdBQUcsTUFBTSxJQUFBLDRCQUFvQixFQUFDO2dCQUN2QyxPQUFPO2dCQUNQLElBQUk7Z0JBQ0osTUFBTTthQUNQLENBQUMsQ0FBQTtZQUVGLE1BQU0sYUFBYSxHQUFHLElBQUEsbUJBQU0sR0FBUSxDQUFBO1lBQ3BDLE1BQU0sUUFBUSxHQUF3QztnQkFDcEQsYUFBYTtnQkFDYixLQUFLLENBQUMsSUFBSTtvQkFHUixhQUFhLENBQUMsT0FBTyxFQUFFLENBQUE7Z0JBQ3pCLENBQUM7YUFDRixDQUFBO1lBRUQsdUNBQ0ssT0FBTyxDQUFDLFVBQVUsS0FDckIsSUFBSSxFQUNKLGdCQUFnQixFQUFFLHNCQUFnQixFQUNsQyxLQUFLO2dCQUNMLE1BQU07Z0JBQ04sT0FBTztnQkFDUCxNQUFNO2dCQUNOLEVBQUU7Z0JBQ0YsUUFBUSxJQUNUO1FBQ0gsQ0FBQztRQUNELEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxVQUFVLEVBQUUsZUFBZSxFQUFFO1lBQ3hDLE1BQU0sSUFBQSxXQUFJLEVBQUMsVUFBVSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFBO1lBQ3RELE1BQU0sZUFBZSxFQUFFLENBQUE7UUFDekIsQ0FBQztLQUNGLENBQUMsQ0FBQTtJQUVGLE9BQU8sT0FBTyxDQUFBO0FBQ2hCLENBQUM7QUFyREQsb0JBcURDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcmVzb2x2ZSB9IGZyb20gJ3BhdGgnXG5pbXBvcnQgZnV0dXJlIGZyb20gJ2ZwLWZ1dHVyZSdcbmltcG9ydCB7IExpZmVjeWNsZSwgSUJhc2VDb21wb25lbnQgfSBmcm9tICdAd2VsbC1rbm93bi1jb21wb25lbnRzL2ludGVyZmFjZXMnXG5pbXBvcnQgeyByb29tc01ldHJpY3MsIGNyZWF0ZVJvb21zQ29tcG9uZW50IH0gZnJvbSAnQGRjbC9taW5pLWNvbW1zL2Rpc3QvYWRhcHRlcnMvcm9vbXMnXG5pbXBvcnQgeyBjcmVhdGVSZWNvcmRDb25maWdDb21wb25lbnQgfSBmcm9tICdAd2VsbC1rbm93bi1jb21wb25lbnRzL2Vudi1jb25maWctcHJvdmlkZXInXG5pbXBvcnQgeyBjcmVhdGVTZXJ2ZXJDb21wb25lbnQgfSBmcm9tICdAd2VsbC1rbm93bi1jb21wb25lbnRzL2h0dHAtc2VydmVyJ1xuaW1wb3J0IHsgY3JlYXRlQ29uc29sZUxvZ0NvbXBvbmVudCB9IGZyb20gJ0B3ZWxsLWtub3duLWNvbXBvbmVudHMvbG9nZ2VyJ1xuaW1wb3J0IHsgY3JlYXRlVGVzdE1ldHJpY3NDb21wb25lbnQgfSBmcm9tICdAd2VsbC1rbm93bi1jb21wb25lbnRzL21ldHJpY3MnXG5pbXBvcnQgeyBjcmVhdGVXc0NvbXBvbmVudCB9IGZyb20gJy4vd3MnXG5cbmltcG9ydCB7IENsaUNvbXBvbmVudHMgfSBmcm9tICcuLi8uLi9jb21wb25lbnRzJ1xuaW1wb3J0IHsgZ2V0QXJncyB9IGZyb20gJy4uLy4uL3V0aWxzL2FyZ3MnXG5pbXBvcnQgeyBJU2lnbmFsZXJDb21wb25lbnQsIFByZXZpZXdDb21wb25lbnRzIH0gZnJvbSAnLi90eXBlcydcbmltcG9ydCB7IHZhbGlkYXRlRXhpc3RpbmdQcm9qZWN0LCB2YWxpZGF0ZVNjZW5lT3B0aW9ucyB9IGZyb20gJy4vcHJvamVjdCdcbmltcG9ydCB7IHByZXZpZXdQb3J0IH0gZnJvbSAnLi9wb3J0J1xuaW1wb3J0IHsgcHJvdmlkZXJJbnN0YW5jZSB9IGZyb20gJy4vZXRoJ1xuaW1wb3J0IHsgd2lyZSB9IGZyb20gJy4vd2lyZSdcblxuZXhwb3J0IGZ1bmN0aW9uIGhlbHAoKSB7XG4gIHJldHVybiBgYFxufVxuXG5pbnRlcmZhY2UgT3B0aW9ucyB7XG4gIGFyZ3M6IE9taXQ8dHlwZW9mIGFyZ3MsICdfJz5cbiAgY29tcG9uZW50czogUGljazxDbGlDb21wb25lbnRzLCAnZmV0Y2gnIHwgJ2ZzJz5cbn1cblxuZXhwb3J0IGNvbnN0IGFyZ3MgPSBnZXRBcmdzKHtcbiAgJy0td2F0Y2gnOiBCb29sZWFuLFxuICAnLXcnOiAnLS13YXRjaCcsXG4gICctLWRpcic6IFN0cmluZyxcbiAgJy0tcG9ydCc6IE51bWJlcixcbiAgJy1wJzogJy0tcG9ydCdcbn0pXG5cbi8vIGNvcHkvcGFzdGUgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vZGVjZW50cmFsYW5kL2NsaS9ibG9iLzMyZGU5NmJjZmM0ZWYxYzI2YzU1ODBjNzc2N2FkNmM4Y2FjM2IzNjcvc3JjL2xpYi9EZWNlbnRyYWxhbmQudHNcbi8vIFRPRE86IHJlZmFjdG9yIHRoaXMgc3R1ZmYgY29tcGxldGVseVxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG1haW4ob3B0aW9uczogT3B0aW9ucykge1xuICBjb25zdCBkaXIgPSByZXNvbHZlKHByb2Nlc3MuY3dkKCksIG9wdGlvbnMuYXJnc1snLS1kaXInXSB8fCAnLicpXG4gIGF3YWl0IHZhbGlkYXRlRXhpc3RpbmdQcm9qZWN0KG9wdGlvbnMuY29tcG9uZW50cywgZGlyKVxuICBhd2FpdCB2YWxpZGF0ZVNjZW5lT3B0aW9ucyhvcHRpb25zLmNvbXBvbmVudHMsIGRpcilcblxuICBjb25zdCBwb3J0ID0gb3B0aW9ucy5hcmdzWyctLXBvcnQnXSB8fCAoYXdhaXQgcHJldmlld1BvcnQoKSlcblxuICBjb25zdCBwcm9ncmFtID0gYXdhaXQgTGlmZWN5Y2xlLnJ1bjxQcmV2aWV3Q29tcG9uZW50cz4oe1xuICAgIGFzeW5jIGluaXRDb21wb25lbnRzKCkge1xuICAgICAgY29uc3QgbWV0cmljcyA9IGNyZWF0ZVRlc3RNZXRyaWNzQ29tcG9uZW50KHJvb21zTWV0cmljcylcbiAgICAgIGNvbnN0IGNvbmZpZyA9IGNyZWF0ZVJlY29yZENvbmZpZ0NvbXBvbmVudCh7XG4gICAgICAgIEhUVFBfU0VSVkVSX1BPUlQ6IHBvcnQudG9TdHJpbmcoKSxcbiAgICAgICAgSFRUUF9TRVJWRVJfSE9TVDogJzAuMC4wLjAnLFxuICAgICAgICAuLi5wcm9jZXNzLmVudlxuICAgICAgfSlcbiAgICAgIGNvbnN0IGxvZ3MgPSBhd2FpdCBjcmVhdGVDb25zb2xlTG9nQ29tcG9uZW50KHt9KVxuICAgICAgY29uc3Qgd3MgPSBhd2FpdCBjcmVhdGVXc0NvbXBvbmVudCh7IGxvZ3MgfSlcbiAgICAgIGNvbnN0IHNlcnZlciA9IGF3YWl0IGNyZWF0ZVNlcnZlckNvbXBvbmVudDxQcmV2aWV3Q29tcG9uZW50cz4oeyBjb25maWcsIGxvZ3MsIHdzOiB3cy53cyB9LCB7IGNvcnM6IHt9IH0pXG4gICAgICBjb25zdCByb29tcyA9IGF3YWl0IGNyZWF0ZVJvb21zQ29tcG9uZW50KHtcbiAgICAgICAgbWV0cmljcyxcbiAgICAgICAgbG9ncyxcbiAgICAgICAgY29uZmlnXG4gICAgICB9KVxuXG4gICAgICBjb25zdCBwcm9ncmFtQ2xvc2VkID0gZnV0dXJlPHZvaWQ+KClcbiAgICAgIGNvbnN0IHNpZ25hbGVyOiBJQmFzZUNvbXBvbmVudCAmIElTaWduYWxlckNvbXBvbmVudCA9IHtcbiAgICAgICAgcHJvZ3JhbUNsb3NlZCxcbiAgICAgICAgYXN5bmMgc3RvcCgpIHtcbiAgICAgICAgICAvLyB0aGlzIHByb21pc2UgaXMgcmVzb2x2ZWQgdXBvbiBTSUdURVJNIG9yIFNJR0hVUFxuICAgICAgICAgIC8vIG9yIHdoZW4gcHJvZ3JhbS5zdG9wIGlzIGNhbGxlZFxuICAgICAgICAgIHByb2dyYW1DbG9zZWQucmVzb2x2ZSgpXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4ub3B0aW9ucy5jb21wb25lbnRzLFxuICAgICAgICBsb2dzLFxuICAgICAgICBldGhlcmV1bVByb3ZpZGVyOiBwcm92aWRlckluc3RhbmNlLFxuICAgICAgICByb29tcyxcbiAgICAgICAgY29uZmlnLFxuICAgICAgICBtZXRyaWNzLFxuICAgICAgICBzZXJ2ZXIsXG4gICAgICAgIHdzLFxuICAgICAgICBzaWduYWxlclxuICAgICAgfVxuICAgIH0sXG4gICAgYXN5bmMgbWFpbih7IGNvbXBvbmVudHMsIHN0YXJ0Q29tcG9uZW50cyB9KSB7XG4gICAgICBhd2FpdCB3aXJlKGNvbXBvbmVudHMsIGRpciwgISFvcHRpb25zLmFyZ3NbJy0td2F0Y2gnXSlcbiAgICAgIGF3YWl0IHN0YXJ0Q29tcG9uZW50cygpXG4gICAgfVxuICB9KVxuXG4gIHJldHVybiBwcm9ncmFtXG59XG4iXX0=
|