@zenithbuild/cli 0.6.5 → 0.6.7
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/build.d.ts +32 -0
- package/dist/build.js +193 -548
- package/dist/compiler-bridge-runner.d.ts +5 -0
- package/dist/compiler-bridge-runner.js +70 -0
- package/dist/component-instance-ir.d.ts +6 -0
- package/dist/component-instance-ir.js +0 -20
- package/dist/component-occurrences.d.ts +6 -0
- package/dist/component-occurrences.js +6 -28
- package/dist/dev-server.d.ts +18 -0
- package/dist/dev-server.js +76 -116
- package/dist/dev-watch.d.ts +1 -0
- package/dist/dev-watch.js +19 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +6 -28
- package/dist/manifest.d.ts +23 -0
- package/dist/manifest.js +22 -48
- package/dist/preview.d.ts +100 -0
- package/dist/preview.js +418 -488
- package/dist/resolve-components.d.ts +39 -0
- package/dist/resolve-components.js +30 -104
- package/dist/server/resolve-request-route.d.ts +39 -0
- package/dist/server/resolve-request-route.js +104 -113
- package/dist/server-contract.d.ts +39 -0
- package/dist/server-contract.js +15 -67
- package/dist/toolchain-paths.d.ts +23 -0
- package/dist/toolchain-paths.js +111 -39
- package/dist/toolchain-runner.d.ts +33 -0
- package/dist/toolchain-runner.js +170 -0
- package/dist/types/generate-env-dts.d.ts +5 -0
- package/dist/types/generate-env-dts.js +4 -2
- package/dist/types/generate-routes-dts.d.ts +8 -0
- package/dist/types/generate-routes-dts.js +7 -5
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.js +16 -7
- package/dist/ui/env.d.ts +18 -0
- package/dist/ui/env.js +0 -12
- package/dist/ui/format.d.ts +33 -0
- package/dist/ui/format.js +7 -45
- package/dist/ui/logger.d.ts +59 -0
- package/dist/ui/logger.js +3 -32
- package/dist/version-check.d.ts +54 -0
- package/dist/version-check.js +41 -98
- package/package.json +17 -5
package/dist/version-check.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
2
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
readCliPackageVersion,
|
|
6
|
-
readInstalledPackageVersion,
|
|
7
|
-
resolveBundlerBin
|
|
8
|
-
} from './toolchain-paths.js';
|
|
9
|
-
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { readCliPackageVersion, readInstalledPackageVersion, resolveBundlerBin } from './toolchain-paths.js';
|
|
10
5
|
const PACKAGE_KEYS = [
|
|
11
6
|
['core', '@zenithbuild/core'],
|
|
12
7
|
['compiler', '@zenithbuild/compiler'],
|
|
@@ -14,7 +9,6 @@ const PACKAGE_KEYS = [
|
|
|
14
9
|
['router', '@zenithbuild/router'],
|
|
15
10
|
['bundlerPackage', '@zenithbuild/bundler']
|
|
16
11
|
];
|
|
17
|
-
|
|
18
12
|
function parseVersion(version) {
|
|
19
13
|
const raw = String(version || '').trim();
|
|
20
14
|
const match = raw.match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/);
|
|
@@ -30,7 +24,6 @@ function parseVersion(version) {
|
|
|
30
24
|
prereleaseParts: match[4] ? match[4].split('.') : []
|
|
31
25
|
};
|
|
32
26
|
}
|
|
33
|
-
|
|
34
27
|
function compareIdentifiers(left, right) {
|
|
35
28
|
const leftNumeric = /^\d+$/.test(left);
|
|
36
29
|
const rightNumeric = /^\d+$/.test(right);
|
|
@@ -45,23 +38,21 @@ function compareIdentifiers(left, right) {
|
|
|
45
38
|
}
|
|
46
39
|
return left.localeCompare(right);
|
|
47
40
|
}
|
|
48
|
-
|
|
49
41
|
export function compareVersions(leftVersion, rightVersion) {
|
|
50
42
|
const left = parseVersion(leftVersion);
|
|
51
43
|
const right = parseVersion(rightVersion);
|
|
52
|
-
if (!left && !right)
|
|
53
|
-
|
|
54
|
-
if (!
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
44
|
+
if (!left && !right)
|
|
45
|
+
return 0;
|
|
46
|
+
if (!left)
|
|
47
|
+
return -1;
|
|
48
|
+
if (!right)
|
|
49
|
+
return 1;
|
|
50
|
+
const numberDelta = ((left.major - right.major)
|
|
58
51
|
|| (left.minor - right.minor)
|
|
59
|
-
|| (left.patch - right.patch)
|
|
60
|
-
);
|
|
52
|
+
|| (left.patch - right.patch));
|
|
61
53
|
if (numberDelta !== 0) {
|
|
62
54
|
return numberDelta;
|
|
63
55
|
}
|
|
64
|
-
|
|
65
56
|
if (!left.prerelease && !right.prerelease) {
|
|
66
57
|
return 0;
|
|
67
58
|
}
|
|
@@ -71,7 +62,6 @@ export function compareVersions(leftVersion, rightVersion) {
|
|
|
71
62
|
if (!right.prerelease) {
|
|
72
63
|
return -1;
|
|
73
64
|
}
|
|
74
|
-
|
|
75
65
|
const len = Math.max(left.prereleaseParts.length, right.prereleaseParts.length);
|
|
76
66
|
for (let index = 0; index < len; index += 1) {
|
|
77
67
|
const leftPart = left.prereleaseParts[index];
|
|
@@ -87,10 +77,8 @@ export function compareVersions(leftVersion, rightVersion) {
|
|
|
87
77
|
return delta;
|
|
88
78
|
}
|
|
89
79
|
}
|
|
90
|
-
|
|
91
80
|
return 0;
|
|
92
81
|
}
|
|
93
|
-
|
|
94
82
|
function prereleaseChannel(parsed) {
|
|
95
83
|
if (!parsed || !parsed.prerelease) {
|
|
96
84
|
return 'stable';
|
|
@@ -101,7 +89,6 @@ function prereleaseChannel(parsed) {
|
|
|
101
89
|
}
|
|
102
90
|
return label;
|
|
103
91
|
}
|
|
104
|
-
|
|
105
92
|
function classifyDifference(expectedVersion, actualVersion) {
|
|
106
93
|
if (!expectedVersion || !actualVersion) {
|
|
107
94
|
return 'unknown';
|
|
@@ -122,7 +109,6 @@ function classifyDifference(expectedVersion, actualVersion) {
|
|
|
122
109
|
}
|
|
123
110
|
return 'soft';
|
|
124
111
|
}
|
|
125
|
-
|
|
126
112
|
function readProjectPackage(projectRoot) {
|
|
127
113
|
if (!projectRoot) {
|
|
128
114
|
return null;
|
|
@@ -133,11 +119,11 @@ function readProjectPackage(projectRoot) {
|
|
|
133
119
|
return null;
|
|
134
120
|
}
|
|
135
121
|
return JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
136
|
-
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
137
124
|
return null;
|
|
138
125
|
}
|
|
139
126
|
}
|
|
140
|
-
|
|
141
127
|
function buildFixCommand(projectRoot, targetVersion) {
|
|
142
128
|
const manifest = readProjectPackage(projectRoot);
|
|
143
129
|
const dependencyNames = [
|
|
@@ -148,7 +134,6 @@ function buildFixCommand(projectRoot, targetVersion) {
|
|
|
148
134
|
'@zenithbuild/router',
|
|
149
135
|
'@zenithbuild/bundler'
|
|
150
136
|
];
|
|
151
|
-
|
|
152
137
|
const deps = [];
|
|
153
138
|
const devDeps = [];
|
|
154
139
|
for (const name of dependencyNames) {
|
|
@@ -158,7 +143,6 @@ function buildFixCommand(projectRoot, targetVersion) {
|
|
|
158
143
|
}
|
|
159
144
|
devDeps.push(`${name}@${targetVersion}`);
|
|
160
145
|
}
|
|
161
|
-
|
|
162
146
|
const commands = [];
|
|
163
147
|
if (deps.length > 0) {
|
|
164
148
|
commands.push(`npm i ${deps.join(' ')}`);
|
|
@@ -171,7 +155,6 @@ function buildFixCommand(projectRoot, targetVersion) {
|
|
|
171
155
|
}
|
|
172
156
|
return commands.join(' && ');
|
|
173
157
|
}
|
|
174
|
-
|
|
175
158
|
function describeVersions(versions) {
|
|
176
159
|
const entries = [
|
|
177
160
|
['cli', versions.cli],
|
|
@@ -184,17 +167,15 @@ function describeVersions(versions) {
|
|
|
184
167
|
['bundler bin', versions.bundlerBinary]
|
|
185
168
|
];
|
|
186
169
|
return entries
|
|
187
|
-
.filter((
|
|
170
|
+
.filter((entry) => typeof entry[1] === 'string' && entry[1].length > 0)
|
|
188
171
|
.map(([label, version]) => `${label}=${version}`)
|
|
189
172
|
.join(' ');
|
|
190
173
|
}
|
|
191
|
-
|
|
192
174
|
function summarizeIssues(issues) {
|
|
193
175
|
const preview = issues.slice(0, 3).map((issue) => issue.summary);
|
|
194
176
|
const suffix = issues.length > 3 ? ` +${issues.length - 3} more` : '';
|
|
195
177
|
return `${preview.join('; ')}${suffix}`;
|
|
196
178
|
}
|
|
197
|
-
|
|
198
179
|
function determineTargetVersion(versions) {
|
|
199
180
|
const candidates = [
|
|
200
181
|
versions.projectCli,
|
|
@@ -205,11 +186,9 @@ function determineTargetVersion(versions) {
|
|
|
205
186
|
versions.bundlerPackage,
|
|
206
187
|
versions.cli
|
|
207
188
|
].filter((value) => typeof value === 'string' && value.length > 0);
|
|
208
|
-
|
|
209
189
|
if (candidates.length === 0) {
|
|
210
190
|
return '0.0.0';
|
|
211
191
|
}
|
|
212
|
-
|
|
213
192
|
let highest = candidates[0];
|
|
214
193
|
for (const candidate of candidates.slice(1)) {
|
|
215
194
|
if (compareVersions(candidate, highest) > 0) {
|
|
@@ -218,7 +197,6 @@ function determineTargetVersion(versions) {
|
|
|
218
197
|
}
|
|
219
198
|
return highest;
|
|
220
199
|
}
|
|
221
|
-
|
|
222
200
|
export function getBundlerVersion(bundlerBinPath) {
|
|
223
201
|
const path = String(bundlerBinPath || '').trim();
|
|
224
202
|
if (!path) {
|
|
@@ -233,7 +211,6 @@ export function getBundlerVersion(bundlerBinPath) {
|
|
|
233
211
|
ok: false
|
|
234
212
|
};
|
|
235
213
|
}
|
|
236
|
-
|
|
237
214
|
const rawOutput = `${result.stdout || ''}\n${result.stderr || ''}`.trim();
|
|
238
215
|
const versionMatch = rawOutput.match(/(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)/);
|
|
239
216
|
return {
|
|
@@ -243,32 +220,32 @@ export function getBundlerVersion(bundlerBinPath) {
|
|
|
243
220
|
ok: result.status === 0 && Boolean(versionMatch)
|
|
244
221
|
};
|
|
245
222
|
}
|
|
246
|
-
|
|
247
223
|
export function getLocalZenithVersions({ projectRoot, bundlerBinPath } = {}) {
|
|
248
|
-
const resolvedBundlerBin = bundlerBinPath || resolveBundlerBin(projectRoot);
|
|
224
|
+
const resolvedBundlerBin = bundlerBinPath || resolveBundlerBin(projectRoot ?? null);
|
|
249
225
|
const bundlerVersion = getBundlerVersion(resolvedBundlerBin);
|
|
250
226
|
const versions = {
|
|
251
227
|
cli: readCliPackageVersion(),
|
|
252
|
-
projectCli: readInstalledPackageVersion('@zenithbuild/cli', projectRoot),
|
|
228
|
+
projectCli: readInstalledPackageVersion('@zenithbuild/cli', projectRoot ?? null),
|
|
229
|
+
core: null,
|
|
230
|
+
compiler: null,
|
|
231
|
+
runtime: null,
|
|
232
|
+
router: null,
|
|
233
|
+
bundlerPackage: null,
|
|
253
234
|
bundlerBinary: bundlerVersion.version,
|
|
254
235
|
bundlerBinPath: bundlerVersion.path,
|
|
255
236
|
bundlerBinRawOutput: bundlerVersion.rawOutput,
|
|
256
237
|
targetVersion: null
|
|
257
238
|
};
|
|
258
|
-
|
|
259
239
|
for (const [key, packageName] of PACKAGE_KEYS) {
|
|
260
|
-
versions[key] = readInstalledPackageVersion(packageName, projectRoot);
|
|
240
|
+
versions[key] = readInstalledPackageVersion(packageName, projectRoot ?? null);
|
|
261
241
|
}
|
|
262
|
-
|
|
263
242
|
versions.targetVersion = determineTargetVersion(versions);
|
|
264
243
|
return versions;
|
|
265
244
|
}
|
|
266
|
-
|
|
267
245
|
export function checkCompatibility(versions) {
|
|
268
|
-
const targetVersion = versions
|
|
246
|
+
const targetVersion = versions.targetVersion || determineTargetVersion(versions);
|
|
269
247
|
const issues = [];
|
|
270
|
-
const fixCommand = buildFixCommand(versions
|
|
271
|
-
|
|
248
|
+
const fixCommand = buildFixCommand(versions.projectRoot, targetVersion);
|
|
272
249
|
const addIssue = (code, summary, message) => {
|
|
273
250
|
issues.push({
|
|
274
251
|
code,
|
|
@@ -278,16 +255,10 @@ export function checkCompatibility(versions) {
|
|
|
278
255
|
fixCommand
|
|
279
256
|
});
|
|
280
257
|
};
|
|
281
|
-
|
|
282
258
|
if (versions.projectCli && versions.cli && versions.projectCli !== versions.cli) {
|
|
283
259
|
const severity = classifyDifference(versions.projectCli, versions.cli);
|
|
284
|
-
addIssue(
|
|
285
|
-
severity === 'hard' ? 'CLI_TRAIN_MISMATCH' : 'CLI_OUTDATED',
|
|
286
|
-
`cli ${versions.cli} != project ${versions.projectCli}`,
|
|
287
|
-
`Version mismatch detected (may break HMR/refs): executing CLI ${versions.cli} does not match project CLI ${versions.projectCli}.`
|
|
288
|
-
);
|
|
260
|
+
addIssue(severity === 'hard' ? 'CLI_TRAIN_MISMATCH' : 'CLI_OUTDATED', `cli ${versions.cli} != project ${versions.projectCli}`, `Version mismatch detected (may break HMR/refs): executing CLI ${versions.cli} does not match project CLI ${versions.projectCli}.`);
|
|
289
261
|
}
|
|
290
|
-
|
|
291
262
|
for (const [key, label] of [
|
|
292
263
|
['core', 'core'],
|
|
293
264
|
['compiler', 'compiler'],
|
|
@@ -295,39 +266,23 @@ export function checkCompatibility(versions) {
|
|
|
295
266
|
['router', 'router'],
|
|
296
267
|
['bundlerPackage', 'bundler package']
|
|
297
268
|
]) {
|
|
298
|
-
const actual = versions[key];
|
|
269
|
+
const actual = versions[key] ?? null;
|
|
299
270
|
const difference = classifyDifference(targetVersion, actual);
|
|
300
271
|
if (difference === 'hard') {
|
|
301
|
-
addIssue(
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
);
|
|
306
|
-
} else if (difference === 'soft') {
|
|
307
|
-
addIssue(
|
|
308
|
-
'VERSION_OUTDATED',
|
|
309
|
-
`${label} ${actual} != ${targetVersion}`,
|
|
310
|
-
`Version mismatch detected (may break HMR/refs): ${label} ${actual} is not aligned with ${targetVersion}.`
|
|
311
|
-
);
|
|
272
|
+
addIssue('VERSION_TRAIN_MISMATCH', `${label} ${actual} != ${targetVersion}`, `Version mismatch detected (may break HMR/refs): ${label} ${actual} is on a different Zenith train than ${targetVersion}.`);
|
|
273
|
+
}
|
|
274
|
+
else if (difference === 'soft') {
|
|
275
|
+
addIssue('VERSION_OUTDATED', `${label} ${actual} != ${targetVersion}`, `Version mismatch detected (may break HMR/refs): ${label} ${actual} is not aligned with ${targetVersion}.`);
|
|
312
276
|
}
|
|
313
277
|
}
|
|
314
|
-
|
|
315
278
|
const bundlerExpected = versions.bundlerPackage || targetVersion;
|
|
316
279
|
const bundlerDifference = classifyDifference(bundlerExpected, versions.bundlerBinary);
|
|
317
280
|
if (bundlerDifference === 'hard') {
|
|
318
|
-
addIssue(
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
} else if (bundlerDifference === 'soft') {
|
|
324
|
-
addIssue(
|
|
325
|
-
'BUNDLER_BINARY_OUTDATED',
|
|
326
|
-
`bundler bin ${versions.bundlerBinary} != ${bundlerExpected}`,
|
|
327
|
-
`Version mismatch detected (may break build/IR contracts): bundler binary ${versions.bundlerBinary} is not aligned with ${bundlerExpected}.`
|
|
328
|
-
);
|
|
329
|
-
}
|
|
330
|
-
|
|
281
|
+
addIssue('BUNDLER_BINARY_MISMATCH', `bundler bin ${versions.bundlerBinary || 'missing'} != ${bundlerExpected}`, `Version mismatch detected (may break build/IR contracts): bundler binary ${versions.bundlerBinary || 'missing'} does not match ${bundlerExpected}.`);
|
|
282
|
+
}
|
|
283
|
+
else if (bundlerDifference === 'soft') {
|
|
284
|
+
addIssue('BUNDLER_BINARY_OUTDATED', `bundler bin ${versions.bundlerBinary} != ${bundlerExpected}`, `Version mismatch detected (may break build/IR contracts): bundler binary ${versions.bundlerBinary} is not aligned with ${bundlerExpected}.`);
|
|
285
|
+
}
|
|
331
286
|
return {
|
|
332
287
|
status: issues.length === 0 ? 'ok' : 'warn',
|
|
333
288
|
issues,
|
|
@@ -340,36 +295,24 @@ export function checkCompatibility(versions) {
|
|
|
340
295
|
}
|
|
341
296
|
};
|
|
342
297
|
}
|
|
343
|
-
|
|
344
|
-
export async function maybeWarnAboutZenithVersionMismatch({
|
|
345
|
-
projectRoot,
|
|
346
|
-
logger,
|
|
347
|
-
command = 'build',
|
|
348
|
-
bundlerBinPath = null
|
|
349
|
-
} = {}) {
|
|
298
|
+
export async function maybeWarnAboutZenithVersionMismatch({ projectRoot, logger, command = 'build', bundlerBinPath = null } = {}) {
|
|
350
299
|
if (!logger || process.env.ZENITH_SKIP_VERSION_CHECK === '1') {
|
|
351
|
-
return { status: 'ok', issues: [], details: {} };
|
|
300
|
+
return { status: 'ok', issues: [], details: { targetVersion: '0.0.0', versions: {}, summary: '' } };
|
|
352
301
|
}
|
|
353
|
-
|
|
354
302
|
const versions = getLocalZenithVersions({ projectRoot, bundlerBinPath });
|
|
355
|
-
versions.projectRoot = projectRoot;
|
|
303
|
+
versions.projectRoot = projectRoot ?? null;
|
|
356
304
|
const result = checkCompatibility(versions);
|
|
357
305
|
const onceKey = `zenith-version-check:${describeVersions(versions)}:${result.status}`;
|
|
358
306
|
const verboseTag = command === 'dev' ? 'DEV' : 'BUILD';
|
|
359
|
-
|
|
360
307
|
if (result.status === 'ok') {
|
|
361
308
|
logger.verbose(verboseTag, `toolchain versions ok ${result.details.summary}`);
|
|
362
309
|
return result;
|
|
363
310
|
}
|
|
364
|
-
|
|
365
311
|
const primary = result.issues[0];
|
|
366
|
-
logger.warn(
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
hint: primary.hint
|
|
371
|
-
}
|
|
372
|
-
);
|
|
312
|
+
logger.warn(`${primary.message} ${summarizeIssues(result.issues)}`, {
|
|
313
|
+
onceKey,
|
|
314
|
+
hint: primary.hint
|
|
315
|
+
});
|
|
373
316
|
logger.verbose(verboseTag, `toolchain versions ${result.details.summary}`);
|
|
374
317
|
if (versions.bundlerBinPath) {
|
|
375
318
|
logger.verbose(verboseTag, `bundler bin path=${versions.bundlerBinPath}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenithbuild/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.7",
|
|
4
4
|
"description": "Deterministic project orchestrator for Zenith framework",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -15,22 +15,34 @@
|
|
|
15
15
|
"dist/**",
|
|
16
16
|
"package.json"
|
|
17
17
|
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/zenithbuild/framework",
|
|
21
|
+
"directory": "packages/cli"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/zenithbuild/framework/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/zenithbuild/framework#readme",
|
|
18
27
|
"publishConfig": {
|
|
19
28
|
"access": "public"
|
|
20
29
|
},
|
|
21
30
|
"scripts": {
|
|
22
|
-
"build": "
|
|
23
|
-
"
|
|
31
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json && node -e \"const fs=require('fs');if(fs.existsSync('dist/index.js')) fs.chmodSync('dist/index.js',0o755)\"",
|
|
32
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
33
|
+
"test": "bun run build && node --experimental-vm-modules $(node -e \"const path=require('node:path');const pkg=require.resolve('jest/package.json');process.stdout.write(path.join(path.dirname(pkg),'bin/jest.js'))\") --config jest.config.js --forceExit --runInBand",
|
|
24
34
|
"prepublishOnly": "npm run build"
|
|
25
35
|
},
|
|
26
36
|
"dependencies": {
|
|
27
|
-
"@zenithbuild/compiler": "
|
|
37
|
+
"@zenithbuild/compiler": "0.6.7",
|
|
28
38
|
"picocolors": "^1.1.1"
|
|
29
39
|
},
|
|
30
40
|
"devDependencies": {
|
|
41
|
+
"@types/node": "latest",
|
|
31
42
|
"@jest/globals": "^30.2.0",
|
|
32
43
|
"jest": "^30.2.0",
|
|
33
|
-
"jest-environment-jsdom": "^30.2.0"
|
|
44
|
+
"jest-environment-jsdom": "^30.2.0",
|
|
45
|
+
"typescript": "^5.7.3"
|
|
34
46
|
},
|
|
35
47
|
"private": false
|
|
36
48
|
}
|