@quenty/nevermore-cli 4.39.0 → 4.41.0

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/commands/batch-command/batch-deploy-command.d.ts.map +1 -1
  3. package/dist/commands/batch-command/batch-deploy-command.js +3 -2
  4. package/dist/commands/batch-command/batch-deploy-command.js.map +1 -1
  5. package/dist/commands/deploy-command/index.d.ts.map +1 -1
  6. package/dist/commands/deploy-command/index.js +8 -3
  7. package/dist/commands/deploy-command/index.js.map +1 -1
  8. package/dist/utils/batch/changed-packages-utils.d.ts +8 -1
  9. package/dist/utils/batch/changed-packages-utils.d.ts.map +1 -1
  10. package/dist/utils/batch/changed-packages-utils.js +10 -2
  11. package/dist/utils/batch/changed-packages-utils.js.map +1 -1
  12. package/dist/utils/build/deploy-config.d.ts +14 -0
  13. package/dist/utils/build/deploy-config.d.ts.map +1 -1
  14. package/dist/utils/build/deploy-config.js +8 -0
  15. package/dist/utils/build/deploy-config.js.map +1 -1
  16. package/dist/utils/deploy/deploy-metadata.d.ts +9 -1
  17. package/dist/utils/deploy/deploy-metadata.d.ts.map +1 -1
  18. package/dist/utils/deploy/deploy-metadata.js +15 -1
  19. package/dist/utils/deploy/deploy-metadata.js.map +1 -1
  20. package/dist/utils/deploy/deploy-metadata.test.js +33 -0
  21. package/dist/utils/deploy/deploy-metadata.test.js.map +1 -1
  22. package/dist/utils/nevermore-cli-utils.d.ts +1 -0
  23. package/dist/utils/nevermore-cli-utils.d.ts.map +1 -1
  24. package/dist/utils/nevermore-cli-utils.js +10 -0
  25. package/dist/utils/nevermore-cli-utils.js.map +1 -1
  26. package/dist/utils/testing/runner/test-runner.d.ts.map +1 -1
  27. package/dist/utils/testing/runner/test-runner.js +2 -0
  28. package/dist/utils/testing/runner/test-runner.js.map +1 -1
  29. package/package.json +2 -2
  30. package/src/commands/batch-command/batch-deploy-command.ts +16 -8
  31. package/src/commands/deploy-command/index.ts +22 -8
  32. package/src/utils/batch/changed-packages-utils.ts +18 -1
  33. package/src/utils/build/deploy-config.ts +22 -0
  34. package/src/utils/deploy/deploy-metadata.test.ts +41 -0
  35. package/src/utils/deploy/deploy-metadata.ts +20 -1
  36. package/src/utils/nevermore-cli-utils.ts +15 -0
  37. package/src/utils/testing/runner/test-runner.ts +2 -0
  38. package/tsconfig.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"test-runner.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"test-runner.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/nevermore-cli",
3
- "version": "4.39.0",
3
+ "version": "4.41.0",
4
4
  "description": "CLI interface for Nevermore",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -57,5 +57,5 @@
57
57
  "engines": {
58
58
  "node": ">=16"
59
59
  },
60
- "gitHead": "647acfad93dca41c38f59cda247d2bfc0fff36d4"
60
+ "gitHead": "8bd905a5c7e7f1fd4e178b54beeadef94a615d1d"
61
61
  }
@@ -34,7 +34,10 @@ import {
34
34
  discoverChangedTargetPackagesAsync,
35
35
  flattenToBatchTargets,
36
36
  } from '../../utils/batch/changed-packages-utils.js';
37
- import { isCI } from '../../utils/nevermore-cli-utils.js';
37
+ import {
38
+ isCI,
39
+ readPackageVersionAsync,
40
+ } from '../../utils/nevermore-cli-utils.js';
38
41
  import { parseTestLogs } from '../../utils/testing/test-log-parser.js';
39
42
 
40
43
  const SMOKE_TEST_SCRIPT_PATH = resolvePackagePath(
@@ -236,13 +239,18 @@ async function _runAsync(args: BatchDeployArgs): Promise<void> {
236
239
 
237
240
  const injected = await injectDeployMetadataAsync(
238
241
  builtPlace,
239
- buildDeployMetadataAttributes(deployGitInfo, {
240
- target: targetName,
241
- published: publish,
242
- timestamp: deployTimestamp,
243
- universeId: buildTarget.target.universeId,
244
- placeId: buildTarget.target.placeId,
245
- })
242
+ buildDeployMetadataAttributes(
243
+ deployGitInfo,
244
+ {
245
+ target: targetName,
246
+ published: publish,
247
+ timestamp: deployTimestamp,
248
+ universeId: buildTarget.target.universeId,
249
+ placeId: buildTarget.target.placeId,
250
+ packageVersion: await readPackageVersionAsync(buildTarget.path),
251
+ },
252
+ buildTarget.manifestPlaces
253
+ )
246
254
  );
247
255
 
248
256
  let version: number;
@@ -29,11 +29,16 @@ import { RateLimiter } from '../../utils/open-cloud/rate-limiter.js';
29
29
  import { CloudJobContext } from '../../utils/job-context/cloud-job-context.js';
30
30
  import { runBatchAsync } from '../../utils/batch/batch-runner.js';
31
31
  import { type BatchTarget } from '../../utils/batch/changed-packages-utils.js';
32
- import { isCI, readPackageNameAsync } from '../../utils/nevermore-cli-utils.js';
32
+ import {
33
+ isCI,
34
+ readPackageNameAsync,
35
+ readPackageVersionAsync,
36
+ } from '../../utils/nevermore-cli-utils.js';
33
37
  import {
34
38
  loadDeployConfigAsync,
35
39
  resolveDeployConfigPath,
36
40
  resolveDeployTargetPlaces,
41
+ toManifestPlaceInfo,
37
42
  } from '../../utils/build/deploy-config.js';
38
43
  import { handleInitAsync } from './deploy-init.js';
39
44
  import {
@@ -247,6 +252,7 @@ export class DeployCommand<T> implements CommandModule<T, DeployArgs> {
247
252
 
248
253
  const cwd = process.cwd();
249
254
  const packageName = (await readPackageNameAsync(cwd)) ?? path.basename(cwd);
255
+ const packageVersion = await readPackageVersionAsync(cwd);
250
256
 
251
257
  const { targetName, autoDetected: targetAutoDetected } =
252
258
  await selectTargetAsync(cwd, {
@@ -256,6 +262,7 @@ export class DeployCommand<T> implements CommandModule<T, DeployArgs> {
256
262
 
257
263
  const config = await loadDeployConfigAsync(resolveDeployConfigPath(cwd));
258
264
  const places = resolveDeployTargetPlaces(config, targetName);
265
+ const manifestPlaces = places.map(toManifestPlaceInfo);
259
266
  const isMultiPlace = places.length > 1;
260
267
 
261
268
  if (isMultiPlace) {
@@ -279,6 +286,7 @@ export class DeployCommand<T> implements CommandModule<T, DeployArgs> {
279
286
  packageName,
280
287
  path: cwd,
281
288
  target: place,
289
+ manifestPlaces,
282
290
  };
283
291
  })
284
292
  : [
@@ -287,6 +295,7 @@ export class DeployCommand<T> implements CommandModule<T, DeployArgs> {
287
295
  packageName,
288
296
  path: cwd,
289
297
  target: places[0]!,
298
+ manifestPlaces,
290
299
  },
291
300
  ];
292
301
 
@@ -402,13 +411,18 @@ export class DeployCommand<T> implements CommandModule<T, DeployArgs> {
402
411
 
403
412
  const injected = await injectDeployMetadataAsync(
404
413
  builtPlace,
405
- buildDeployMetadataAttributes(deployGitInfo, {
406
- target: targetName,
407
- published: publish,
408
- timestamp: deployTimestamp,
409
- universeId: args.universeId ?? buildTarget.target.universeId,
410
- placeId: args.placeId ?? buildTarget.target.placeId,
411
- })
414
+ buildDeployMetadataAttributes(
415
+ deployGitInfo,
416
+ {
417
+ target: targetName,
418
+ published: publish,
419
+ timestamp: deployTimestamp,
420
+ universeId: args.universeId ?? buildTarget.target.universeId,
421
+ placeId: args.placeId ?? buildTarget.target.placeId,
422
+ packageVersion,
423
+ },
424
+ buildTarget.manifestPlaces
425
+ )
412
426
  );
413
427
 
414
428
  let uploadResult: Awaited<ReturnType<typeof uploadPlaceAsync>>;
@@ -3,9 +3,11 @@ import { execa } from 'execa';
3
3
  import { OutputHelper } from '@quenty/cli-output-helpers';
4
4
  import {
5
5
  DeployTarget,
6
+ ManifestPlaceInfo,
6
7
  loadDeployConfigAsync,
7
8
  resolveDeployConfigPath,
8
9
  resolveDeployTargetPlaces,
10
+ toManifestPlaceInfo,
9
11
  } from '../build/deploy-config.js';
10
12
 
11
13
  export interface TargetPackage {
@@ -33,6 +35,13 @@ export interface BatchTarget {
33
35
  path: string;
34
36
  /** The single resolved place this BatchTarget represents. */
35
37
  target: DeployTarget;
38
+ /**
39
+ * Every place of this package's target (including `target` itself), stamped
40
+ * into the runtime manifest so a deployed place can resolve its siblings' IDs.
41
+ * Same for every BatchTarget fanned out from one package. Only the deploy
42
+ * paths populate this; test/script BatchTargets omit it.
43
+ */
44
+ manifestPlaces?: ManifestPlaceInfo[];
36
45
  }
37
46
 
38
47
  /**
@@ -119,19 +128,27 @@ export function flattenToBatchTargets(
119
128
  ): BatchTarget[] {
120
129
  const result: BatchTarget[] = [];
121
130
  for (const pkg of packages) {
131
+ const manifestPlaces = pkg.activeTargets.map(toManifestPlaceInfo);
122
132
  if (pkg.activeTargets.length === 1) {
123
133
  result.push({
124
134
  name: pkg.name,
125
135
  packageName: pkg.name,
126
136
  path: pkg.path,
127
137
  target: pkg.activeTargets[0]!,
138
+ manifestPlaces,
128
139
  });
129
140
  continue;
130
141
  }
131
142
  for (const target of pkg.activeTargets) {
132
143
  const suffix = target.name;
133
144
  const name = suffix ? `${pkg.name} - ${suffix}` : pkg.name;
134
- result.push({ name, packageName: pkg.name, path: pkg.path, target });
145
+ result.push({
146
+ name,
147
+ packageName: pkg.name,
148
+ path: pkg.path,
149
+ target,
150
+ manifestPlaces,
151
+ });
135
152
  }
136
153
  }
137
154
  return result;
@@ -36,6 +36,28 @@ export interface DeployConfig {
36
36
  targets: Record<string, DeployTargetConfig>;
37
37
  }
38
38
 
39
+ /**
40
+ * The subset of a resolved place that gets baked into the runtime manifest
41
+ * (see the nevermore-cli-manifest package). A deployed place carries the whole
42
+ * target's place table so it can resolve its siblings' IDs at runtime — e.g. a
43
+ * chapter place teleporting to another chapter without hard-coding place IDs.
44
+ */
45
+ export interface ManifestPlaceInfo {
46
+ /** Place name from a multi-place target (e.g. "chapter0"); absent for single-place targets. */
47
+ name?: string;
48
+ placeId: number;
49
+ universeId: number;
50
+ }
51
+
52
+ /** Project a resolved deploy place down to the fields stamped into the manifest. */
53
+ export function toManifestPlaceInfo(place: DeployTarget): ManifestPlaceInfo {
54
+ return {
55
+ name: place.name,
56
+ placeId: place.placeId,
57
+ universeId: place.universeId,
58
+ };
59
+ }
60
+
39
61
  function _isMultiPlace(
40
62
  target: DeployTargetConfig
41
63
  ): target is MultiPlaceTargetConfig {
@@ -77,6 +77,19 @@ describe('buildDeployMetadataAttributes', () => {
77
77
  expect('Branch' in attributes).toBe(false);
78
78
  });
79
79
 
80
+ it('includes the package version when present', () => {
81
+ const attributes = buildDeployMetadataAttributes(
82
+ {},
83
+ { ...PLACE, packageVersion: '1.0.0' }
84
+ );
85
+ expect(attributes.PackageVersion).toBe('1.0.0');
86
+ });
87
+
88
+ it('omits the package version when unavailable', () => {
89
+ const attributes = buildDeployMetadataAttributes({}, PLACE);
90
+ expect('PackageVersion' in attributes).toBe(false);
91
+ });
92
+
80
93
  it('reflects a Saved (unpublished) deploy', () => {
81
94
  const attributes = buildDeployMetadataAttributes(
82
95
  {},
@@ -84,6 +97,34 @@ describe('buildDeployMetadataAttributes', () => {
84
97
  );
85
98
  expect(attributes.Published).toBe(false);
86
99
  });
100
+
101
+ it('omits Places when no place table is given', () => {
102
+ const attributes = buildDeployMetadataAttributes({}, PLACE);
103
+ expect('Places' in attributes).toBe(false);
104
+ });
105
+
106
+ it('stamps Places as a JSON string preserving large IDs exactly', () => {
107
+ const attributes = buildDeployMetadataAttributes({}, PLACE, [
108
+ { name: 'chapter0', placeId: 97235312452456, universeId: 10192566764 },
109
+ { name: 'chapter1', placeId: 87639818897831, universeId: 10192566764 },
110
+ ]);
111
+ expect(typeof attributes.Places).toBe('string');
112
+ const parsed = JSON.parse(attributes.Places as string);
113
+ // Large place IDs must survive exactly (JSON text, not a float32 attribute).
114
+ expect(parsed).toEqual([
115
+ { name: 'chapter0', placeId: 97235312452456, universeId: 10192566764 },
116
+ { name: 'chapter1', placeId: 87639818897831, universeId: 10192566764 },
117
+ ]);
118
+ });
119
+
120
+ it('omits the name key for a single-place (nameless) target', () => {
121
+ const attributes = buildDeployMetadataAttributes({}, PLACE, [
122
+ { placeId: 123, universeId: 456 },
123
+ ]);
124
+ const parsed = JSON.parse(attributes.Places as string);
125
+ expect(parsed).toEqual([{ placeId: 123, universeId: 456 }]);
126
+ expect('name' in parsed[0]).toBe(false);
127
+ });
87
128
  });
88
129
 
89
130
  describe('packageUsesManifestAsync', () => {
@@ -7,6 +7,7 @@ import {
7
7
  } from '@quenty/nevermore-template-helpers';
8
8
  import { OutputHelper } from '@quenty/cli-output-helpers';
9
9
  import { type BuiltPlace } from '../build/build.js';
10
+ import { type ManifestPlaceInfo } from '../build/deploy-config.js';
10
11
 
11
12
  /** npm name of the package that ships the manifest module. */
12
13
  export const MANIFEST_PACKAGE_NAME = '@quenty/nevermoreclimanifest';
@@ -74,6 +75,8 @@ export interface DeployPlaceInfo {
74
75
  timestamp: string;
75
76
  placeId: number;
76
77
  universeId: number;
78
+ /** `version` from the deploying package's package.json (e.g. "1.0.0"), if any. */
79
+ packageVersion?: string;
77
80
  }
78
81
 
79
82
  /**
@@ -85,10 +88,16 @@ export interface DeployPlaceInfo {
85
88
  * round-trip through Lune serialization as float32, which silently corrupts IDs
86
89
  * above 2^24 (e.g. 123456789 -> 123456792). Strings are exact; the Luau reader
87
90
  * converts them back with `tonumber`.
91
+ *
92
+ * When `places` is given (the whole target's place table), it is stamped as a
93
+ * `Places` JSON-string attribute. The IDs inside stay numeric — a JSON string
94
+ * is exact text, and the Luau reader decodes it to 64-bit numbers, so the
95
+ * float32 hazard that forces the top-level IDs to be stringified doesn't apply.
88
96
  */
89
97
  export function buildDeployMetadataAttributes(
90
98
  git: GitDeployInfo,
91
- place: DeployPlaceInfo
99
+ place: DeployPlaceInfo,
100
+ places?: readonly ManifestPlaceInfo[]
92
101
  ): DeployMetadataAttributes {
93
102
  const attributes: DeployMetadataAttributes = {
94
103
  Deployed: true,
@@ -101,6 +110,16 @@ export function buildDeployMetadataAttributes(
101
110
  if (git.commit) attributes.Commit = git.commit;
102
111
  if (git.version) attributes.Version = git.version;
103
112
  if (git.branch) attributes.Branch = git.branch;
113
+ if (place.packageVersion) attributes.PackageVersion = place.packageVersion;
114
+ if (places && places.length > 0) {
115
+ attributes.Places = JSON.stringify(
116
+ places.map((p) => ({
117
+ name: p.name,
118
+ placeId: p.placeId,
119
+ universeId: p.universeId,
120
+ }))
121
+ );
122
+ }
104
123
  return attributes;
105
124
  }
106
125
 
@@ -51,6 +51,21 @@ export async function readPackageNameAsync(
51
51
  }
52
52
  }
53
53
 
54
+ export async function readPackageVersionAsync(
55
+ packagePath: string
56
+ ): Promise<string | undefined> {
57
+ try {
58
+ const content = await fs.readFile(
59
+ path.join(packagePath, 'package.json'),
60
+ 'utf-8'
61
+ );
62
+ const pkg = JSON.parse(content) as { version?: string };
63
+ return pkg.version;
64
+ } catch {
65
+ return undefined;
66
+ }
67
+ }
68
+
54
69
  export async function fileExistsAsync(filePath: string): Promise<boolean> {
55
70
  try {
56
71
  await fs.access(filePath);
@@ -14,6 +14,7 @@ import {
14
14
  injectDeployMetadataInPlaceAsync,
15
15
  packageUsesManifestAsync,
16
16
  } from '../../deploy/deploy-metadata.js';
17
+ import { readPackageVersionAsync } from '../../nevermore-cli-utils.js';
17
18
 
18
19
  export interface SingleTestResult {
19
20
  success: boolean;
@@ -78,6 +79,7 @@ export async function runSingleTestAsync(
78
79
  timestamp: new Date().toISOString(),
79
80
  placeId: builtPlace.target.placeId,
80
81
  universeId: builtPlace.target.universeId,
82
+ packageVersion: await readPackageVersionAsync(packagePath),
81
83
  })
82
84
  );
83
85
  }