astro 2.0.14 → 2.0.15
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/@types/astro.d.ts +1 -0
- package/dist/content/server-listeners.js +3 -3
- package/dist/content/types-generator.js +17 -7
- package/dist/content/utils.d.ts +1 -1
- package/dist/content/utils.js +3 -3
- package/dist/core/add/index.js +14 -1
- package/dist/core/app/index.js +2 -3
- package/dist/core/build/plugins/plugin-prerender.js +1 -0
- package/dist/core/constants.js +1 -1
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/errors/errors-data.d.ts +63 -6
- package/dist/core/messages.js +2 -2
- package/dist/core/routing/manifest/create.js +4 -2
- package/dist/core/routing/manifest/serialization.js +2 -1
- package/dist/core/routing/match.d.ts +0 -2
- package/dist/core/routing/match.js +0 -13
- package/dist/vite-plugin-astro-server/response.js +1 -1
- package/package.json +2 -2
package/dist/@types/astro.d.ts
CHANGED
|
@@ -13,9 +13,6 @@ async function attachContentServerListeners({
|
|
|
13
13
|
settings
|
|
14
14
|
}) {
|
|
15
15
|
const contentPaths = getContentPaths(settings.config, fs);
|
|
16
|
-
const maybeTsConfigStats = getTSConfigStatsWhenAllowJsFalse({ contentPaths, settings });
|
|
17
|
-
if (maybeTsConfigStats)
|
|
18
|
-
warnAllowJsIsFalse({ ...maybeTsConfigStats, logging });
|
|
19
16
|
if (fs.existsSync(contentPaths.contentDir)) {
|
|
20
17
|
info(
|
|
21
18
|
logging,
|
|
@@ -24,6 +21,9 @@ async function attachContentServerListeners({
|
|
|
24
21
|
contentPaths.contentDir.href.replace(settings.config.root.href, "")
|
|
25
22
|
)} for changes`
|
|
26
23
|
);
|
|
24
|
+
const maybeTsConfigStats = getTSConfigStatsWhenAllowJsFalse({ contentPaths, settings });
|
|
25
|
+
if (maybeTsConfigStats)
|
|
26
|
+
warnAllowJsIsFalse({ ...maybeTsConfigStats, logging });
|
|
27
27
|
await attachListeners();
|
|
28
28
|
} else {
|
|
29
29
|
viteServer.watcher.on("addDir", contentDirListener);
|
|
@@ -34,7 +34,10 @@ async function createContentTypesGenerator({
|
|
|
34
34
|
if (!fs.existsSync(contentPaths.contentDir)) {
|
|
35
35
|
return { typesGenerated: false, reason: "no-content-dir" };
|
|
36
36
|
}
|
|
37
|
-
events.push(
|
|
37
|
+
events.push({
|
|
38
|
+
type: { name: "add", entry: contentPaths.config.url },
|
|
39
|
+
opts: { logLevel: "warn" }
|
|
40
|
+
});
|
|
38
41
|
const globResult = await glob("**", {
|
|
39
42
|
cwd: fileURLToPath(contentPaths.contentDir),
|
|
40
43
|
fs: {
|
|
@@ -46,7 +49,7 @@ async function createContentTypesGenerator({
|
|
|
46
49
|
(e) => !e.href.startsWith(contentPaths.config.url.href)
|
|
47
50
|
);
|
|
48
51
|
for (const entry of entries) {
|
|
49
|
-
events.push(
|
|
52
|
+
events.push({ type: { name: "add", entry }, opts: { logLevel: "warn" } });
|
|
50
53
|
}
|
|
51
54
|
await runEvents();
|
|
52
55
|
return { typesGenerated: true };
|
|
@@ -156,12 +159,15 @@ async function createContentTypesGenerator({
|
|
|
156
159
|
}
|
|
157
160
|
function queueEvent(rawEvent, opts) {
|
|
158
161
|
const event = {
|
|
159
|
-
|
|
160
|
-
|
|
162
|
+
type: {
|
|
163
|
+
entry: pathToFileURL(rawEvent.entry),
|
|
164
|
+
name: rawEvent.name
|
|
165
|
+
},
|
|
166
|
+
opts
|
|
161
167
|
};
|
|
162
|
-
if (!event.entry.pathname.startsWith(contentPaths.contentDir.pathname))
|
|
168
|
+
if (!event.type.entry.pathname.startsWith(contentPaths.contentDir.pathname))
|
|
163
169
|
return;
|
|
164
|
-
events.push(
|
|
170
|
+
events.push(event);
|
|
165
171
|
debounceTimeout && clearTimeout(debounceTimeout);
|
|
166
172
|
debounceTimeout = setTimeout(
|
|
167
173
|
async () => runEvents(opts),
|
|
@@ -170,7 +176,11 @@ async function createContentTypesGenerator({
|
|
|
170
176
|
}
|
|
171
177
|
async function runEvents(opts) {
|
|
172
178
|
const logLevel = (opts == null ? void 0 : opts.logLevel) ?? "info";
|
|
173
|
-
const eventResponses =
|
|
179
|
+
const eventResponses = [];
|
|
180
|
+
for (const event of events) {
|
|
181
|
+
const response = await handleEvent(event.type, event.opts);
|
|
182
|
+
eventResponses.push(response);
|
|
183
|
+
}
|
|
174
184
|
events = [];
|
|
175
185
|
let unsupportedFiles = [];
|
|
176
186
|
for (const response of eventResponses) {
|
package/dist/content/utils.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export declare function getEntryInfo(params: Pick<ContentPaths, 'contentDir'> &
|
|
|
61
61
|
entry: URL;
|
|
62
62
|
allowFilesOutsideCollection?: true;
|
|
63
63
|
}): EntryInfo;
|
|
64
|
-
export declare function getEntryType(entryPath: string, paths: Pick<ContentPaths, 'config'>): 'content' | 'config' | 'ignored' | 'unsupported';
|
|
64
|
+
export declare function getEntryType(entryPath: string, paths: Pick<ContentPaths, 'config' | 'contentDir'>): 'content' | 'config' | 'ignored' | 'unsupported';
|
|
65
65
|
/**
|
|
66
66
|
* Match YAML exception handling from Astro core errors
|
|
67
67
|
* @see 'astro/src/core/errors.ts'
|
package/dist/content/utils.js
CHANGED
|
@@ -106,7 +106,7 @@ function getEntryInfo({
|
|
|
106
106
|
function getEntryType(entryPath, paths) {
|
|
107
107
|
const { ext, base } = path.parse(entryPath);
|
|
108
108
|
const fileUrl = pathToFileURL(entryPath);
|
|
109
|
-
if (
|
|
109
|
+
if (hasUnderscoreBelowContentDirectoryPath(fileUrl, paths.contentDir) || isOnIgnoreList(base)) {
|
|
110
110
|
return "ignored";
|
|
111
111
|
} else if (contentFileExts.includes(ext)) {
|
|
112
112
|
return "content";
|
|
@@ -119,8 +119,8 @@ function getEntryType(entryPath, paths) {
|
|
|
119
119
|
function isOnIgnoreList(fileName) {
|
|
120
120
|
return [".DS_Store"].includes(fileName);
|
|
121
121
|
}
|
|
122
|
-
function
|
|
123
|
-
const parts = fileUrl.pathname.split("/");
|
|
122
|
+
function hasUnderscoreBelowContentDirectoryPath(fileUrl, contentDir) {
|
|
123
|
+
const parts = fileUrl.pathname.replace(contentDir.pathname, "").split("/");
|
|
124
124
|
for (const part of parts) {
|
|
125
125
|
if (part.startsWith("_"))
|
|
126
126
|
return true;
|
package/dist/core/add/index.js
CHANGED
|
@@ -381,7 +381,20 @@ async function setAdapter(ast, adapter, exportName) {
|
|
|
381
381
|
}
|
|
382
382
|
return false;
|
|
383
383
|
});
|
|
384
|
-
|
|
384
|
+
let adapterCall;
|
|
385
|
+
switch (adapter.id) {
|
|
386
|
+
case "node": {
|
|
387
|
+
adapterCall = t.callExpression(adapterId, [
|
|
388
|
+
t.objectExpression([
|
|
389
|
+
t.objectProperty(t.identifier("mode"), t.stringLiteral("standalone"))
|
|
390
|
+
])
|
|
391
|
+
]);
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
default: {
|
|
395
|
+
adapterCall = t.callExpression(adapterId, []);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
385
398
|
if (!adapterProp) {
|
|
386
399
|
configObject.properties.push(t.objectProperty(t.identifier("adapter"), adapterCall));
|
|
387
400
|
return;
|
package/dist/core/app/index.js
CHANGED
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
createLinkStylesheetElementSet,
|
|
38
38
|
createModuleScriptElement
|
|
39
39
|
} from "../render/ssr-element.js";
|
|
40
|
-
import {
|
|
40
|
+
import { matchRoute } from "../routing/match.js";
|
|
41
41
|
import { deserializeManifest } from "./common.js";
|
|
42
42
|
const pagesVirtualModuleId = "@astrojs-pages-virtual-entry";
|
|
43
43
|
const resolvedPagesVirtualModuleId = "\0" + pagesVirtualModuleId;
|
|
@@ -104,8 +104,7 @@ class App {
|
|
|
104
104
|
let pathname = "/" + this.removeBase(url.pathname);
|
|
105
105
|
let routeData = matchRoute(pathname, __privateGet(this, _manifestData));
|
|
106
106
|
if (routeData) {
|
|
107
|
-
|
|
108
|
-
if (asset)
|
|
107
|
+
if (routeData.prerender)
|
|
109
108
|
return void 0;
|
|
110
109
|
return routeData;
|
|
111
110
|
} else if (matchNotFound) {
|
|
@@ -12,6 +12,7 @@ function vitePluginPrerender(opts, internals) {
|
|
|
12
12
|
const pageInfo = internals.pagesByViteID.get(id);
|
|
13
13
|
if (pageInfo) {
|
|
14
14
|
if ((_c = (_b = (_a = meta.getModuleInfo(id)) == null ? void 0 : _a.meta.astro) == null ? void 0 : _b.pageOptions) == null ? void 0 : _c.prerender) {
|
|
15
|
+
pageInfo.route.prerender = true;
|
|
15
16
|
return "prerender";
|
|
16
17
|
}
|
|
17
18
|
return `pages/all`;
|
package/dist/core/constants.js
CHANGED
package/dist/core/dev/dev.js
CHANGED
|
@@ -31,7 +31,7 @@ async function dev(settings, options) {
|
|
|
31
31
|
isRestart: options.isRestart
|
|
32
32
|
})
|
|
33
33
|
);
|
|
34
|
-
const currentVersion = "2.0.
|
|
34
|
+
const currentVersion = "2.0.15";
|
|
35
35
|
if (currentVersion.includes("-")) {
|
|
36
36
|
warn(options.logging, null, msg.prerelease({ currentVersion }));
|
|
37
37
|
}
|
|
@@ -6,16 +6,27 @@ export interface ErrorData {
|
|
|
6
6
|
hint?: string | ((...params: any) => string);
|
|
7
7
|
}
|
|
8
8
|
export declare const AstroErrorData: {
|
|
9
|
-
readonly UnknownCompilerError: {
|
|
10
|
-
readonly title: "Unknown compiler error.";
|
|
11
|
-
readonly code: 1000;
|
|
12
|
-
readonly hint: "This is almost always a problem with the Astro compiler, not your code. Please open an issue at https://astro.build/issues/compiler.";
|
|
13
|
-
};
|
|
14
9
|
/**
|
|
15
10
|
* @docs
|
|
16
11
|
* @kind heading
|
|
17
12
|
* @name Astro Errors
|
|
18
13
|
*/
|
|
14
|
+
/**
|
|
15
|
+
* @docs
|
|
16
|
+
* @message
|
|
17
|
+
* Unknown compiler error.
|
|
18
|
+
* @see
|
|
19
|
+
* - [withastro/compiler issues list](https://astro.build/issues/compiler)
|
|
20
|
+
* @description
|
|
21
|
+
* Astro encountered an unknown error while compiling your files. In most cases, this is not your fault, but an issue in our compiler.
|
|
22
|
+
*
|
|
23
|
+
* If there isn't one already, please [create an issue](https://astro.build/issues/compiler).
|
|
24
|
+
*/
|
|
25
|
+
readonly UnknownCompilerError: {
|
|
26
|
+
readonly title: "Unknown compiler error.";
|
|
27
|
+
readonly code: 1000;
|
|
28
|
+
readonly hint: "This is almost always a problem with the Astro compiler, not your code. Please open an issue at https://astro.build/issues/compiler.";
|
|
29
|
+
};
|
|
19
30
|
/**
|
|
20
31
|
* @docs
|
|
21
32
|
* @see
|
|
@@ -386,6 +397,15 @@ export declare const AstroErrorData: {
|
|
|
386
397
|
readonly message: (paramName: string) => string;
|
|
387
398
|
readonly hint: "Rename your file to `[page].astro` or `[...page].astro`.";
|
|
388
399
|
};
|
|
400
|
+
/**
|
|
401
|
+
* @docs
|
|
402
|
+
* @see
|
|
403
|
+
* - [Vite troubleshooting guide](https://vitejs.dev/guide/troubleshooting.html)
|
|
404
|
+
* @description
|
|
405
|
+
* Vite encountered an unknown error while rendering your project. We unfortunately do not know what happened (or we would tell you!)
|
|
406
|
+
*
|
|
407
|
+
* If you can reliably cause this error to happen, we'd appreciate if you could [open an issue](https://astro.build/issues/)
|
|
408
|
+
*/
|
|
389
409
|
readonly UnknownViteError: {
|
|
390
410
|
readonly title: "Unknown Vite Error.";
|
|
391
411
|
readonly code: 4000;
|
|
@@ -423,6 +443,13 @@ export declare const AstroErrorData: {
|
|
|
423
443
|
* @kind heading
|
|
424
444
|
* @name CSS Errors
|
|
425
445
|
*/
|
|
446
|
+
/**
|
|
447
|
+
* @docs
|
|
448
|
+
* @see
|
|
449
|
+
* - [Styles and CSS](https://docs.astro.build/en/guides/styling/)
|
|
450
|
+
* @description
|
|
451
|
+
* Astro encountered an unknown error while parsing your CSS. Oftentimes, this is caused by a syntax error and the error message should contain more information.
|
|
452
|
+
*/
|
|
426
453
|
readonly UnknownCSSError: {
|
|
427
454
|
readonly title: "Unknown CSS Error.";
|
|
428
455
|
readonly code: 5000;
|
|
@@ -434,7 +461,7 @@ export declare const AstroErrorData: {
|
|
|
434
461
|
* CSSSyntaxError: Missed semicolon<br/>
|
|
435
462
|
* CSSSyntaxError: Unclosed string<br/>
|
|
436
463
|
* @description
|
|
437
|
-
* Astro encountered an error while parsing your CSS, due to a syntax error. This is often caused by a missing semicolon
|
|
464
|
+
* Astro encountered an error while parsing your CSS, due to a syntax error. This is often caused by a missing semicolon.
|
|
438
465
|
*/
|
|
439
466
|
readonly CSSSyntaxError: {
|
|
440
467
|
readonly title: "CSS Syntax Error.";
|
|
@@ -445,6 +472,11 @@ export declare const AstroErrorData: {
|
|
|
445
472
|
* @kind heading
|
|
446
473
|
* @name Markdown Errors
|
|
447
474
|
*/
|
|
475
|
+
/**
|
|
476
|
+
* @docs
|
|
477
|
+
* @description
|
|
478
|
+
* Astro encountered an unknown error while parsing your Markdown. Oftentimes, this is caused by a syntax error and the error message should contain more information.
|
|
479
|
+
*/
|
|
448
480
|
readonly UnknownMarkdownError: {
|
|
449
481
|
readonly title: "Unknown Markdown Error.";
|
|
450
482
|
readonly code: 6000;
|
|
@@ -490,6 +522,16 @@ export declare const AstroErrorData: {
|
|
|
490
522
|
readonly message: (file: string) => string;
|
|
491
523
|
readonly hint: "See the MDX integration docs for installation and usage instructions: https://docs.astro.build/en/guides/integrations-guide/mdx/";
|
|
492
524
|
};
|
|
525
|
+
/**
|
|
526
|
+
* @docs
|
|
527
|
+
* @see
|
|
528
|
+
* - [Configuration Reference](https://docs.astro.build/en/reference/configuration-reference/)
|
|
529
|
+
* @description
|
|
530
|
+
* Astro encountered an unknown error loading your Astro configuration file.
|
|
531
|
+
* This is often caused by a syntax error in your config and the message should offer more information.
|
|
532
|
+
*
|
|
533
|
+
* If you can reliably cause this error to happen, we'd appreciate if you could [open an issue](https://astro.build/issues/)
|
|
534
|
+
*/
|
|
493
535
|
readonly UnknownConfigError: {
|
|
494
536
|
readonly title: "Unknown configuration error.";
|
|
495
537
|
readonly code: 7000;
|
|
@@ -524,6 +566,13 @@ export declare const AstroErrorData: {
|
|
|
524
566
|
* @kind heading
|
|
525
567
|
* @name CLI Errors
|
|
526
568
|
*/
|
|
569
|
+
/**
|
|
570
|
+
* @docs
|
|
571
|
+
* @description
|
|
572
|
+
* Astro encountered an unknown error while starting one of its CLI commands. The error message should contain more information.
|
|
573
|
+
*
|
|
574
|
+
* If you can reliably cause this error to happen, we'd appreciate if you could [open an issue](https://astro.build/issues/)
|
|
575
|
+
*/
|
|
527
576
|
readonly UnknownCLIError: {
|
|
528
577
|
readonly title: "Unknown CLI Error.";
|
|
529
578
|
readonly code: 8000;
|
|
@@ -546,6 +595,14 @@ export declare const AstroErrorData: {
|
|
|
546
595
|
* @kind heading
|
|
547
596
|
* @name Content Collection Errors
|
|
548
597
|
*/
|
|
598
|
+
/**
|
|
599
|
+
* @docs
|
|
600
|
+
* @description
|
|
601
|
+
* Astro encountered an unknown error loading your content collections.
|
|
602
|
+
* This can be caused by certain errors inside your `src/content/config.ts` file or some internal errors.
|
|
603
|
+
*
|
|
604
|
+
* If you can reliably cause this error to happen, we'd appreciate if you could [open an issue](https://astro.build/issues/)
|
|
605
|
+
*/
|
|
549
606
|
readonly UnknownContentCollectionError: {
|
|
550
607
|
readonly title: "Unknown Content Collection Error.";
|
|
551
608
|
readonly code: 9000;
|
package/dist/core/messages.js
CHANGED
|
@@ -47,7 +47,7 @@ function serverStart({
|
|
|
47
47
|
base,
|
|
48
48
|
isRestart = false
|
|
49
49
|
}) {
|
|
50
|
-
const version = "2.0.
|
|
50
|
+
const version = "2.0.15";
|
|
51
51
|
const localPrefix = `${dim("\u2503")} Local `;
|
|
52
52
|
const networkPrefix = `${dim("\u2503")} Network `;
|
|
53
53
|
const emptyPrefix = " ".repeat(11);
|
|
@@ -233,7 +233,7 @@ function printHelp({
|
|
|
233
233
|
message.push(
|
|
234
234
|
linebreak(),
|
|
235
235
|
` ${bgGreen(black(` ${commandName} `))} ${green(
|
|
236
|
-
`v${"2.0.
|
|
236
|
+
`v${"2.0.15"}`
|
|
237
237
|
)} ${headline}`
|
|
238
238
|
);
|
|
239
239
|
}
|
|
@@ -225,7 +225,8 @@ function createRouteManifest({ settings, cwd, fsMod }, logging) {
|
|
|
225
225
|
params,
|
|
226
226
|
component,
|
|
227
227
|
generate,
|
|
228
|
-
pathname: pathname || void 0
|
|
228
|
+
pathname: pathname || void 0,
|
|
229
|
+
prerender: false
|
|
229
230
|
});
|
|
230
231
|
}
|
|
231
232
|
});
|
|
@@ -275,7 +276,8 @@ This route collides with: "${collision.component}".`
|
|
|
275
276
|
params,
|
|
276
277
|
component,
|
|
277
278
|
generate,
|
|
278
|
-
pathname: pathname || void 0
|
|
279
|
+
pathname: pathname || void 0,
|
|
280
|
+
prerender: false
|
|
279
281
|
});
|
|
280
282
|
});
|
|
281
283
|
return {
|
|
@@ -16,7 +16,8 @@ function deserializeRouteData(rawRouteData) {
|
|
|
16
16
|
component: rawRouteData.component,
|
|
17
17
|
generate: getRouteGenerator(rawRouteData.segments, rawRouteData._meta.trailingSlash),
|
|
18
18
|
pathname: rawRouteData.pathname || void 0,
|
|
19
|
-
segments: rawRouteData.segments
|
|
19
|
+
segments: rawRouteData.segments,
|
|
20
|
+
prerender: rawRouteData.prerender
|
|
20
21
|
};
|
|
21
22
|
}
|
|
22
23
|
export {
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { ManifestData, RouteData } from '../../@types/astro';
|
|
2
2
|
/** Find matching route from pathname */
|
|
3
3
|
export declare function matchRoute(pathname: string, manifest: ManifestData): RouteData | undefined;
|
|
4
|
-
/** Find matching static asset from pathname */
|
|
5
|
-
export declare function matchAssets(route: RouteData, assets: Set<string>): string | undefined;
|
|
6
4
|
/** Finds all matching routes from pathname */
|
|
7
5
|
export declare function matchAllRoutes(pathname: string, manifest: ManifestData): RouteData[];
|
|
@@ -1,23 +1,10 @@
|
|
|
1
1
|
function matchRoute(pathname, manifest) {
|
|
2
2
|
return manifest.routes.find((route) => route.pattern.test(decodeURI(pathname)));
|
|
3
3
|
}
|
|
4
|
-
function matchAssets(route, assets) {
|
|
5
|
-
for (const asset of assets) {
|
|
6
|
-
if (!asset.endsWith(".html"))
|
|
7
|
-
continue;
|
|
8
|
-
if (route.pattern.test(asset)) {
|
|
9
|
-
return asset;
|
|
10
|
-
}
|
|
11
|
-
if (route.pattern.test(asset.replace(/index\.html$/, ""))) {
|
|
12
|
-
return asset;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
4
|
function matchAllRoutes(pathname, manifest) {
|
|
17
5
|
return manifest.routes.filter((route) => route.pattern.test(pathname));
|
|
18
6
|
}
|
|
19
7
|
export {
|
|
20
8
|
matchAllRoutes,
|
|
21
|
-
matchAssets,
|
|
22
9
|
matchRoute
|
|
23
10
|
};
|
|
@@ -39,7 +39,7 @@ function writeHtmlResponse(res, statusCode, html) {
|
|
|
39
39
|
async function writeWebResponse(res, webResponse) {
|
|
40
40
|
const { status, headers, body } = webResponse;
|
|
41
41
|
const _headers = Object.fromEntries(headers.entries());
|
|
42
|
-
if (
|
|
42
|
+
if ("getSetCookie" in headers && typeof headers.getSetCookie === "function") {
|
|
43
43
|
_headers["set-cookie"] = headers.getSetCookie();
|
|
44
44
|
}
|
|
45
45
|
const setCookieHeaders = Array.from(getSetCookiesFromResponse(webResponse));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.15",
|
|
4
4
|
"description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "withastro",
|
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
"rollup": "^3.9.0",
|
|
175
175
|
"sass": "^1.52.2",
|
|
176
176
|
"srcset-parse": "^1.1.0",
|
|
177
|
-
"undici": "^5.
|
|
177
|
+
"undici": "^5.20.0",
|
|
178
178
|
"unified": "^10.1.2"
|
|
179
179
|
},
|
|
180
180
|
"engines": {
|