@mettlecast/domain-cli 0.2.87 → 0.2.88

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.
@@ -1,7 +1,6 @@
1
1
  import { mkdir, writeFile } from 'node:fs/promises';
2
2
  import { join, resolve } from 'node:path';
3
3
  import { createInterface } from 'node:readline';
4
- import { Readable } from 'node:stream';
5
4
  import { execSync } from 'node:child_process';
6
5
  import * as tar from 'tar';
7
6
  import { cliLogger } from '../utils/logger.js';
@@ -60,27 +59,24 @@ function topoSort(modules, selected) {
60
59
  async function parseTarball(buf) {
61
60
  const entries = [];
62
61
  await new Promise((resolve, reject) => {
63
- const parser = new tar.Parser({
64
- gzip: true,
65
- onentry(entry) {
66
- if (entry.type !== 'File') {
67
- entry.resume();
68
- return;
69
- }
70
- const chunks = [];
71
- entry.on('data', (chunk) => {
72
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
73
- });
74
- entry.on('end', () => {
75
- entries.push({ path: entry.path, content: Buffer.concat(chunks) });
76
- });
77
- entry.on('error', reject);
78
- },
62
+ const parser = new tar.Parser({ gzip: true });
63
+ parser.on('entry', (entry) => {
64
+ if (entry.type !== 'File') {
65
+ entry.resume();
66
+ return;
67
+ }
68
+ const chunks = [];
69
+ entry.on('data', (chunk) => {
70
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
71
+ });
72
+ entry.on('end', () => {
73
+ entries.push({ path: entry.path, content: Buffer.concat(chunks) });
74
+ });
75
+ entry.on('error', reject);
79
76
  });
80
77
  parser.on('finish', resolve);
81
78
  parser.on('error', reject);
82
- const readable = Readable.from(buf);
83
- readable.pipe(parser);
79
+ parser.end(buf);
84
80
  });
85
81
  return entries;
86
82
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mettlecast/domain-cli",
3
- "version": "0.2.87",
3
+ "version": "0.2.88",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",
@@ -22,8 +22,8 @@
22
22
  "dependencies": {
23
23
  "@aws-sdk/client-s3": "^3.0.0",
24
24
  "@aws-sdk/client-sfn": "^3.0.0",
25
- "@mettlecast/domain-cdk-packer": "0.2.88",
26
- "@mettlecast/domain-runtime": "0.2.87",
25
+ "@mettlecast/domain-cdk-packer": "0.2.89",
26
+ "@mettlecast/domain-runtime": "0.2.88",
27
27
  "commander": "^12.0.0",
28
28
  "dotenv": "^16.0.0",
29
29
  "fastify": "^5.0.0",
@@ -28,7 +28,7 @@ import {
28
28
  } from 'vitest';
29
29
  import { createHash } from 'node:crypto';
30
30
  import { spawnSync, type SpawnSyncReturns } from 'node:child_process';
31
- import { mkdir, mkdtemp, readdir, readFile, rm, stat } from 'node:fs/promises';
31
+ import { mkdir, mkdtemp, readdir, readFile, rm, stat, writeFile } from 'node:fs/promises';
32
32
  import { tmpdir } from 'node:os';
33
33
  import { dirname, join, resolve } from 'node:path';
34
34
  import { fileURLToPath } from 'node:url';
@@ -51,9 +51,13 @@ vi.mock('node:readline', () => ({
51
51
  createInterface: vi.fn(),
52
52
  }));
53
53
 
54
- vi.mock('node:child_process', () => ({
55
- execSync: vi.fn(),
56
- }));
54
+ vi.mock('node:child_process', async (importOriginal) => {
55
+ const actual = await importOriginal<typeof import('node:child_process')>();
56
+ return {
57
+ ...actual,
58
+ execSync: vi.fn(),
59
+ };
60
+ });
57
61
 
58
62
  vi.mock('../../utils/logger.js', () => ({
59
63
  cliLogger: {
@@ -163,54 +167,59 @@ async function packModuleTarball(moduleId: string): Promise<PackResult> {
163
167
  const overrides = await readFileOverrides(moduleId);
164
168
  const files = await walkDir(moduleDir);
165
169
 
166
- const tarFiles: Array<{ path: string; content: string }> = [];
167
- const manifestEntries: TarballEntry[] = [];
168
-
169
- for (const file of files) {
170
- const content = (await readFile(file.fullPath)).toString('utf-8');
171
- const isTemplate = file.relPath.endsWith('.tpl');
172
-
173
- // Strip .tpl to get the "manifest path" (the canonical install path
174
- // before any installedAs override).
175
- const manifestPath = isTemplate ? file.relPath.slice(0, -4) : file.relPath;
176
- const override = overrides.find(
177
- (o) => o.path === file.relPath || o.path === manifestPath,
178
- );
170
+ // Stage the virtual files in a temp directory so tar.c can create a
171
+ // proper tarball (tar v7 no longer supports the stream-based Pack with
172
+ // plain-object entries).
173
+ const stageDir = await mkdtemp(join(tmpdir(), 'mc-stage-'));
174
+ const tarballPath = join(stageDir, 'module.tar.gz');
175
+ try {
176
+ const tarFiles: Array<{ path: string; content: string }> = [];
177
+ const manifestEntries: TarballEntry[] = [];
178
+
179
+ for (const file of files) {
180
+ const content = (await readFile(file.fullPath)).toString('utf-8');
181
+ const isTemplate = file.relPath.endsWith('.tpl');
182
+
183
+ // Strip .tpl to get the "manifest path" (the canonical install path
184
+ // before any installedAs override).
185
+ const manifestPath = isTemplate ? file.relPath.slice(0, -4) : file.relPath;
186
+ const override = overrides.find(
187
+ (o) => o.path === file.relPath || o.path === manifestPath,
188
+ );
179
189
 
180
- manifestEntries.push({
181
- path: file.relPath,
182
- sha256: sha256(content),
183
- isTemplate,
184
- ...(override?.installedAs ? { installedAs: override.installedAs } : {}),
185
- ...(override?.policy ? { policy: override.policy } : {}),
186
- });
190
+ manifestEntries.push({
191
+ path: file.relPath,
192
+ sha256: sha256(content),
193
+ isTemplate,
194
+ ...(override?.installedAs ? { installedAs: override.installedAs } : {}),
195
+ ...(override?.policy ? { policy: override.policy } : {}),
196
+ });
187
197
 
188
- tarFiles.push({ path: file.relPath, content });
189
- }
198
+ tarFiles.push({ path: file.relPath, content });
199
+ }
190
200
 
191
- // Synthesise MANIFEST.json — the CLI's create-project.ts parses this
192
- // verbatim to know which files to extract from the tarball.
193
- const manifestJson = JSON.stringify(manifestEntries, null, 2);
194
- tarFiles.push({ path: 'MANIFEST.json', content: manifestJson });
201
+ // Synthesise MANIFEST.json — the CLI's create-project.ts parses this
202
+ // verbatim to know which files to extract from the tarball.
203
+ const manifestJson = JSON.stringify(manifestEntries, null, 2);
204
+ tarFiles.push({ path: 'MANIFEST.json', content: manifestJson });
195
205
 
196
- const tarball = await new Promise<Buffer>((resolvePack, reject) => {
197
- const chunks: Buffer[] = [];
198
- const pack = tar.create({ gzip: true, cwd: '.' }, []);
199
- pack.on('data', (chunk: Buffer) => {
200
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
201
- });
202
- pack.on('end', () => resolvePack(Buffer.concat(chunks)));
203
- pack.on('error', reject);
206
+ // Write every file to the staging directory.
204
207
  for (const f of tarFiles) {
205
- // tar's Pack.write accepts a path string OR a ReadEntry-shaped object
206
- // with { path, content }. The TypeScript types only model the string
207
- // form, so we cast through `unknown` to keep strict mode happy.
208
- pack.write({ path: f.path, content: f.content } as unknown as string);
208
+ const dest = join(stageDir, f.path);
209
+ await mkdir(dirname(dest), { recursive: true });
210
+ await writeFile(dest, f.content, 'utf-8');
209
211
  }
210
- pack.end();
211
- });
212
212
 
213
- return { tarball, entries: manifestEntries };
213
+ // Create a gzipped tarball from the staging directory. tar.c in v7
214
+ // writes the tarball to the file specified by options.file.
215
+ const paths = tarFiles.map((f) => f.path);
216
+ await tar.c({ gzip: true, cwd: stageDir, file: tarballPath }, paths);
217
+
218
+ const tarball = await readFile(tarballPath);
219
+ return { tarball, entries: manifestEntries };
220
+ } finally {
221
+ await rm(stageDir, { recursive: true, force: true });
222
+ }
214
223
  }
215
224
 
216
225
  /** Drive readline with a fixed sequence of answers. */
@@ -435,8 +444,10 @@ describe('scaffold smoke test (issue #3831)', () => {
435
444
  expect(allDeps['@tanstack/react-router']).toMatch(/\^1\./);
436
445
  expect(allDeps['@tanstack/react-query']).toMatch(/\^5\./);
437
446
  expect(allDeps['@tanstack/react-query-devtools']).toMatch(/\^5\./);
438
- expect(allDeps['react']).toMatch(/\^19\./);
439
- expect(allDeps['react-dom']).toMatch(/\^19\./);
447
+ expect(allDeps['react']).toBe('19.2.7');
448
+ expect(allDeps['react-dom']).toBe('19.2.7');
449
+ expect(allDeps['@types/react']).toBe('19.2.17');
450
+ expect(allDeps['@types/react-dom']).toBe('19.2.3');
440
451
  // zod may be ^3 or ^4 depending on the seed file
441
452
  expect(allDeps['zod']).toMatch(/\^[34]\./);
442
453
  });
@@ -105,30 +105,26 @@ async function parseTarball(buf: Buffer): Promise<TarEntry[]> {
105
105
  const entries: TarEntry[] = [];
106
106
 
107
107
  await new Promise<void>((resolve, reject) => {
108
- const parser = new tar.Parser({
109
- gzip: true,
110
- onentry(entry: tar.ReadEntry) {
111
- if (entry.type !== 'File') {
112
- entry.resume();
113
- return;
114
- }
108
+ const parser = new tar.Parser({ gzip: true });
109
+ parser.on('entry', (entry: tar.ReadEntry) => {
110
+ if (entry.type !== 'File') {
111
+ entry.resume();
112
+ return;
113
+ }
115
114
 
116
- const chunks: Buffer[] = [];
117
- entry.on('data', (chunk: Buffer) => {
118
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk as ArrayBuffer));
119
- });
120
- entry.on('end', () => {
121
- entries.push({ path: entry.path, content: Buffer.concat(chunks) });
122
- });
123
- entry.on('error', reject);
124
- },
115
+ const chunks: Buffer[] = [];
116
+ entry.on('data', (chunk: Buffer) => {
117
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk as ArrayBuffer));
118
+ });
119
+ entry.on('end', () => {
120
+ entries.push({ path: entry.path, content: Buffer.concat(chunks) });
121
+ });
122
+ entry.on('error', reject);
125
123
  });
126
-
127
124
  parser.on('finish', resolve);
128
125
  parser.on('error', reject);
129
126
 
130
- const readable = Readable.from(buf);
131
- readable.pipe(parser);
127
+ parser.end(buf);
132
128
  });
133
129
 
134
130
  return entries;
@@ -2,8 +2,8 @@ import { stat } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import type {
4
4
  RegistryEntry,
5
- ActionRegistryEntry,
6
5
  } from '@mettlecast/domain-cdk-packer';
6
+ import type { ActionRegistryEntry } from '../types.js';
7
7
  import { validRange } from 'semver';
8
8
  import type { DomainModuleConfig } from '@mettlecast/domain-runtime/types';
9
9
  import { buildRegistry } from '../builder/build-registry.js';
@@ -2,9 +2,9 @@
2
2
  "schemaVersion": 1,
3
3
  "registrySchemaVersion": "1",
4
4
  "packages": {
5
- "domainCli": "0.2.87",
6
- "domainCdkPacker": "0.2.88",
7
- "domainRuntime": "0.2.87",
8
- "eslintPluginDomainModule": "0.2.87"
5
+ "domainCli": "0.2.88",
6
+ "domainCdkPacker": "0.2.89",
7
+ "domainRuntime": "0.2.88",
8
+ "eslintPluginDomainModule": "0.2.88"
9
9
  }
10
10
  }