@emeryld/manager 0.3.3 → 0.4.1

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,5 +1,16 @@
1
- import { baseTsConfig, writeFileIfMissing, } from '../shared.js';
2
- const CONTRACT_TS = `import { defineSocketEvents, finalize, resource } from '@emeryld/rrroutes-contract'
1
+ import { BASE_LINT_DEV_DEPENDENCIES, basePackageFiles, basePackageJson, buildReadme, baseScripts, baseTsConfig, writeFileIfMissing, } from '../shared.js';
2
+ const CONTRACT_SCRIPTS = [
3
+ 'dev',
4
+ 'build',
5
+ 'typecheck',
6
+ 'lint',
7
+ 'lint:fix',
8
+ 'format',
9
+ 'format:check',
10
+ 'clean',
11
+ 'test',
12
+ ];
13
+ export const CONTRACT_TS = `import { defineSocketEvents, finalize, resource } from '@emeryld/rrroutes-contract'
3
14
  import { z } from 'zod'
4
15
 
5
16
  const routes = resource('/api')
@@ -70,51 +81,65 @@ export const socketEvents = sockets.events
70
81
  export type AppRegistry = typeof registry
71
82
  `;
72
83
  function contractPackageJson(name) {
73
- return `${JSON.stringify({
84
+ return basePackageJson({
74
85
  name,
75
- version: '0.1.0',
76
86
  private: false,
77
- type: 'module',
78
- main: 'dist/index.js',
79
- types: 'dist/index.d.ts',
80
87
  exports: {
81
88
  '.': {
82
89
  types: './dist/index.d.ts',
83
90
  import: './dist/index.js',
84
91
  },
85
92
  },
86
- files: ['dist'],
87
- scripts: {
88
- build: 'tsc -p tsconfig.json',
89
- typecheck: 'tsc -p tsconfig.json --noEmit',
90
- },
93
+ scripts: baseScripts('tsx watch src/index.ts'),
91
94
  dependencies: {
92
95
  '@emeryld/rrroutes-contract': '^2.5.2',
93
96
  zod: '^4.2.1',
94
97
  },
95
98
  devDependencies: {
96
- typescript: '^5.9.3',
99
+ ...BASE_LINT_DEV_DEPENDENCIES,
97
100
  },
98
- }, null, 2)}\n`;
101
+ });
99
102
  }
100
103
  function contractFiles(pkgName) {
101
104
  return {
102
105
  'package.json': contractPackageJson(pkgName),
103
106
  'tsconfig.json': baseTsConfig(),
107
+ ...basePackageFiles(),
104
108
  'src/index.ts': CONTRACT_TS,
105
- 'README.md': `# ${pkgName}
106
-
107
- Contract package scaffolded by manager-cli.
108
- - edit src/index.ts to add routes and socket events
109
- - build with \`npm run build\`
110
- - import the registry in your server/client packages
111
- `,
109
+ 'README.md': buildReadme({
110
+ name: pkgName,
111
+ description: 'Contract package scaffolded by manager-cli.',
112
+ scripts: CONTRACT_SCRIPTS,
113
+ sections: [
114
+ {
115
+ title: 'Getting Started',
116
+ lines: [
117
+ '- Install deps: `npm install` (or `pnpm install`)',
118
+ '- Start dev mode: `npm run dev`',
119
+ '- Build output: `npm run build`',
120
+ ],
121
+ },
122
+ {
123
+ title: 'Usage',
124
+ lines: [
125
+ '- Edit `src/index.ts` to add routes and socket events.',
126
+ '- Import and share the generated registry in server/client packages.',
127
+ ],
128
+ },
129
+ ],
130
+ }),
112
131
  };
113
132
  }
114
133
  export const contractVariant = {
115
134
  id: 'rrr-contract',
116
135
  label: 'rrr contract',
117
136
  defaultDir: 'packages/rrr-contract',
137
+ summary: 'Shared RRRoutes registry + sockets to be consumed by server/client packages.',
138
+ keyFiles: ['src/index.ts', 'README.md'],
139
+ scripts: CONTRACT_SCRIPTS,
140
+ notes: [
141
+ 'Edit src/index.ts to define routes and socket events; exports registry/socket config.',
142
+ ],
118
143
  async scaffold(ctx) {
119
144
  const files = contractFiles(ctx.pkgName);
120
145
  for (const [relative, contents] of Object.entries(files)) {
@@ -1,38 +1,49 @@
1
- import { baseTsConfig, writeFileIfMissing, } from '../shared.js';
1
+ import { BASE_LINT_DEV_DEPENDENCIES, basePackageFiles, basePackageJson, buildReadme, baseScripts, baseTsConfig, writeFileIfMissing, } from '../shared.js';
2
+ const DOCKER_SCRIPTS = [
3
+ 'dev',
4
+ 'build',
5
+ 'typecheck',
6
+ 'lint',
7
+ 'lint:fix',
8
+ 'format',
9
+ 'format:check',
10
+ 'clean',
11
+ 'test',
12
+ 'start',
13
+ 'docker:build',
14
+ 'docker:up',
15
+ 'docker:dev',
16
+ 'docker:logs',
17
+ 'docker:stop',
18
+ 'docker:clean',
19
+ 'docker:reset',
20
+ ];
2
21
  function dockerPackageJson(name) {
3
- return `${JSON.stringify({
22
+ return basePackageJson({
4
23
  name,
5
- version: '0.1.0',
6
- private: true,
7
- type: 'module',
8
- main: 'dist/index.js',
9
- types: 'dist/index.d.ts',
10
- files: ['dist'],
11
- scripts: {
12
- dev: 'tsx watch src/index.ts',
13
- build: 'tsc -p tsconfig.json',
14
- typecheck: 'tsc -p tsconfig.json --noEmit',
24
+ scripts: baseScripts('tsx watch src/index.ts', {
15
25
  start: 'node dist/index.js',
16
26
  'docker:cli': 'tsx scripts/docker.ts',
17
27
  'docker:build': 'npm run docker:cli -- build',
18
28
  'docker:up': 'npm run docker:cli -- up',
29
+ 'docker:dev': 'npm run docker:cli -- dev',
19
30
  'docker:logs': 'npm run docker:cli -- logs',
20
31
  'docker:stop': 'npm run docker:cli -- stop',
21
32
  'docker:clean': 'npm run docker:cli -- clean',
22
- },
33
+ 'docker:reset': 'npm run docker:cli -- reset',
34
+ }),
23
35
  dependencies: {
24
36
  cors: '^2.8.5',
25
37
  express: '^5.1.0',
26
38
  },
27
39
  devDependencies: {
40
+ ...BASE_LINT_DEV_DEPENDENCIES,
28
41
  '@types/cors': '^2.8.5',
29
42
  '@types/express': '^5.0.6',
30
43
  '@types/node': '^24.10.2',
31
44
  'docker-cli-js': '^3.0.9',
32
- tsx: '^4.19.0',
33
- typescript: '^5.9.3',
34
45
  },
35
- }, null, 2)}\n`;
46
+ });
36
47
  }
37
48
  function dockerIndexTs() {
38
49
  return `import express from 'express'
@@ -91,14 +102,40 @@ function dockerFiles(pkgName) {
91
102
  'src/index.ts': dockerIndexTs(),
92
103
  'scripts/docker.ts': dockerCliScript(pkgName),
93
104
  '.dockerignore': DOCKER_DOCKERIGNORE,
105
+ ...basePackageFiles(),
94
106
  Dockerfile: dockerDockerfile(),
95
- 'README.md': `# ${pkgName}
96
-
97
- Dockerized service scaffolded by manager-cli.
98
- - develop locally with \`npm run dev\`
99
- - build with \`npm run build\` and start with \`npm start\`
100
- - docker helper: \`npm run docker:up\` (build + run), \`npm run docker:logs\`, \`npm run docker:stop\`
101
- `,
107
+ 'README.md': buildReadme({
108
+ name: pkgName,
109
+ description: 'Dockerized service scaffolded by manager-cli.',
110
+ scripts: DOCKER_SCRIPTS,
111
+ sections: [
112
+ {
113
+ title: 'Getting Started',
114
+ lines: [
115
+ '- Install deps: `npm install` (or `pnpm install`)',
116
+ '- Local dev: `npm run dev`',
117
+ '- Build output: `npm run build`',
118
+ '- Start built app: `npm start`',
119
+ ],
120
+ },
121
+ {
122
+ title: 'Docker Helpers',
123
+ lines: [
124
+ '- Build image: `npm run docker:build`',
125
+ '- Build + run detached: `npm run docker:up`',
126
+ '- Build + run + tail logs: `npm run docker:dev`',
127
+ '- Tail logs: `npm run docker:logs`',
128
+ '- Stop container: `npm run docker:stop`',
129
+ '- Clean container: `npm run docker:clean`',
130
+ '- Reset container/image: `npm run docker:reset`',
131
+ ],
132
+ },
133
+ {
134
+ title: 'Environment',
135
+ lines: ['- `PORT` sets the exposed port (default 3000).'],
136
+ },
137
+ ],
138
+ }),
102
139
  };
103
140
  }
104
141
  function dockerCliScript(pkgName) {
@@ -126,32 +163,50 @@ async function main() {
126
163
  await docker.command(\`build -t \${image} .\`)
127
164
  return docker.command(\`run -d --rm -p \${port}:\${port} --name \${container} \${image}\`)
128
165
  }
166
+ if (command === 'dev') {
167
+ await docker.command(\`build -t \${image} .\`)
168
+ await docker.command(\`run -d --rm -p \${port}:\${port} --name \${container} \${image}\`)
169
+ return docker.command(\`logs -f \${container}\`)
170
+ }
129
171
  if (command === 'run') {
130
172
  return docker.command(\`run -d --rm -p \${port}:\${port} --name \${container} \${image}\`)
131
173
  }
132
174
  if (command === 'logs') return docker.command(\`logs -f \${container}\`)
133
175
  if (command === 'stop') return docker.command(\`stop \${container}\`)
134
176
  if (command === 'clean') {
135
- try {
136
- await docker.command(\`rm -f \${container}\`)
137
- } catch (error) {
138
- console.warn(String(error))
139
- }
177
+ await safe(() => docker.command(\`stop \${container}\`))
178
+ await safe(() => docker.command(\`rm -f \${container}\`))
179
+ return
180
+ }
181
+ if (command === 'reset') {
182
+ await safe(() => docker.command(\`stop \${container}\`))
183
+ await safe(() => docker.command(\`rm -f \${container}\`))
184
+ await safe(() => docker.command(\`rmi -f \${image}\`))
140
185
  return
141
186
  }
142
187
  return printHelp()
143
188
  }
144
189
 
190
+ async function safe(run: () => Promise<unknown>) {
191
+ try {
192
+ await run()
193
+ } catch (error) {
194
+ console.warn(String(error))
195
+ }
196
+ }
197
+
145
198
  function printHelp() {
146
199
  console.log(
147
200
  [
148
201
  'Docker helper commands:',
149
202
  ' build -> docker build -t ${pkgName}:latest .',
150
203
  ' up -> build then run in detached mode',
204
+ ' dev -> build, run, and tail logs',
151
205
  ' run -> run existing image detached',
152
206
  ' logs -> docker logs -f <container>',
153
207
  ' stop -> docker stop <container>',
154
- ' clean -> docker rm -f <container>',
208
+ ' clean -> docker stop/rm <container>',
209
+ ' reset -> clean container and remove image',
155
210
  ].join('\\n'),
156
211
  )
157
212
  }
@@ -166,6 +221,18 @@ export const dockerVariant = {
166
221
  id: 'rrr-docker',
167
222
  label: 'dockerized service',
168
223
  defaultDir: 'packages/rrr-docker',
224
+ summary: 'Express service plus Dockerfile and a helper CLI for local runs.',
225
+ keyFiles: [
226
+ 'src/index.ts',
227
+ 'scripts/docker.ts',
228
+ 'Dockerfile',
229
+ 'README.md',
230
+ ],
231
+ scripts: DOCKER_SCRIPTS,
232
+ notes: [
233
+ 'Use docker:dev or docker:up to build and run the container quickly.',
234
+ 'scripts/docker.ts wraps common docker commands with consistent naming.',
235
+ ],
169
236
  async scaffold(ctx) {
170
237
  const files = dockerFiles(ctx.pkgName);
171
238
  for (const [relative, contents] of Object.entries(files)) {
@@ -1,39 +1,59 @@
1
- import { baseTsConfig, writeFileIfMissing, } from '../shared.js';
1
+ import { BASE_LINT_DEV_DEPENDENCIES, basePackageFiles, basePackageJson, buildReadme, baseScripts, baseTsConfig, writeFileIfMissing, } from '../shared.js';
2
+ const EMPTY_SCRIPTS = [
3
+ 'dev',
4
+ 'build',
5
+ 'typecheck',
6
+ 'lint',
7
+ 'lint:fix',
8
+ 'format',
9
+ 'format:check',
10
+ 'clean',
11
+ 'test',
12
+ ];
2
13
  function emptyPackageJson(name) {
3
- return `${JSON.stringify({
14
+ return basePackageJson({
4
15
  name,
5
- version: '0.1.0',
6
- private: true,
7
- type: 'module',
8
- main: 'dist/index.js',
9
- types: 'dist/index.d.ts',
10
- files: ['dist'],
11
- scripts: {
12
- build: 'tsc -p tsconfig.json',
13
- typecheck: 'tsc -p tsconfig.json --noEmit',
14
- },
16
+ scripts: baseScripts('tsx watch src/index.ts'),
15
17
  devDependencies: {
16
- typescript: '^5.9.3',
18
+ ...BASE_LINT_DEV_DEPENDENCIES,
17
19
  },
18
- }, null, 2)}\n`;
20
+ });
19
21
  }
20
22
  function emptyFiles(pkgName) {
21
23
  return {
22
24
  'package.json': emptyPackageJson(pkgName),
23
25
  'tsconfig.json': baseTsConfig({ types: ['node'] }),
26
+ ...basePackageFiles(),
24
27
  'src/index.ts': "export const hello = 'world'\n",
25
- 'README.md': `# ${pkgName}
26
-
27
- Empty package scaffolded by manager-cli.
28
- - edit src/index.ts to start coding
29
- - build with \`npm run build\`
30
- `,
28
+ 'README.md': buildReadme({
29
+ name: pkgName,
30
+ description: 'Empty package scaffolded by manager-cli.',
31
+ scripts: EMPTY_SCRIPTS,
32
+ sections: [
33
+ {
34
+ title: 'Getting Started',
35
+ lines: [
36
+ '- Install deps: `npm install` (or `pnpm install`)',
37
+ '- Start dev mode: `npm run dev`',
38
+ '- Build output: `npm run build`',
39
+ ],
40
+ },
41
+ {
42
+ title: 'Notes',
43
+ lines: ['- Edit `src/index.ts` to start coding.'],
44
+ },
45
+ ],
46
+ }),
31
47
  };
32
48
  }
33
49
  export const emptyVariant = {
34
50
  id: 'rrr-empty',
35
51
  label: 'empty package',
36
52
  defaultDir: 'packages/rrr-empty',
53
+ summary: 'Minimal TypeScript package with lint/format/test scaffolding.',
54
+ keyFiles: ['src/index.ts', 'README.md'],
55
+ scripts: EMPTY_SCRIPTS,
56
+ notes: ['Start coding in src/index.ts; everything else is wired up.'],
37
57
  async scaffold(ctx) {
38
58
  const files = emptyFiles(ctx.pkgName);
39
59
  for (const [relative, contents] of Object.entries(files)) {