create-manifest 1.1.3

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/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # create-manifest
2
+
3
+ The `create-manifest` command adds [Manifest](https://manifest.build) to your project.
4
+
5
+ ```bash
6
+ npx create-manifest@latest
7
+ ```
8
+
9
+ ## Develop
10
+
11
+ ```bash
12
+ npm install
13
+
14
+ # Run from a test folder to prevent messing with project files.
15
+ mkdir test-folder
16
+ cd test-folder
17
+ ../bin/dev.js
18
+ ```
19
+
20
+ However due to the monorepo workspace structure, the launch script will fail as the path to the node modules folder is different than when served. This is normal.
21
+
22
+ ## Publish
23
+
24
+ ```bash
25
+ npm run build
26
+ npm publish
27
+ ```
@@ -0,0 +1,49 @@
1
+ <br>
2
+ <p align="center">
3
+ <a href="https://manifest.build/#gh-light-mode-only">
4
+ <img alt="manifest" src="https://manifest.build/assets/images/logo-transparent.svg" height="55px" alt="Manifest logo" title="Manifest - A backend so simple that it fits in a YAML file" />
5
+ </a>
6
+ <a href="https://manifest.build/#gh-dark-mode-only">
7
+ <img alt="manifest" src="https://manifest.build/assets/images/logo-light.svg" height="55px" alt="Manifest logo" title="Manifest - A backend so simple that it fits in a YAML file" />
8
+ </a>
9
+ </p>
10
+
11
+ <p align='center'>
12
+ <strong>A backend so simple that it fits into 1 YAML file</strong>
13
+
14
+ ## Description
15
+
16
+ Welcome to your [Manifest](https://github.com/mnfst/manifest) project ! Feel free to replace this README by your own.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ $ npm install
22
+ ```
23
+
24
+ ## Running the app
25
+
26
+ To run the app in the development mode:
27
+
28
+ ```bash
29
+ npm run manifest
30
+ ```
31
+
32
+ - Open [http://localhost:1111](http://localhost:1111) to open your admin UI it in your browser
33
+ - Open [http://localhost:1111/api](http://localhost:111/api) to view your REST API documentation
34
+
35
+ The page will reload when you make changes.
36
+
37
+ ## Seed dummy data
38
+
39
+ Seeds some dummy data for your entities:
40
+
41
+ ```bash
42
+ npm run manifest:seed
43
+ ```
44
+
45
+ ## Community & Resources
46
+
47
+ - [Docs](https://manifest.build/docs) - Get started with Manifest
48
+ - [Discord](https://discord.gg/FepAked3W7) - Come chat with the community
49
+ - [Github](https://github.com/mnfst/manifest/issues) - Report bugs and share ideas to improve the product.
@@ -0,0 +1,22 @@
1
+ name: My pet app 🐾
2
+ entities:
3
+ Owner:
4
+ properties:
5
+ - name
6
+ - { name: birthdate, type: date }
7
+
8
+ Cat:
9
+ properties:
10
+ - name
11
+ - { name: age, type: number }
12
+ - { name: birthdate, type: date }
13
+ belongsTo:
14
+ - Owner
15
+
16
+ Homepage:
17
+ nameSingular: Home content
18
+ single: true
19
+ properties:
20
+ - title
21
+ - { name: description, type: richText }
22
+ - { name: cover, type: image }
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "my-manifest-project",
3
+ "version": "0.1.0",
4
+ "description": "A project made with Manifest",
5
+ "scripts": {},
6
+ "dependencies": {}
7
+ }
package/bin/dev.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node --loader ts-node/esm --no-warnings=ExperimentalWarning "%~dp0\dev" %*
package/bin/dev.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env -S node --loader ts-node/esm --no-warnings=ExperimentalWarning
2
+
3
+ import {execute} from '@oclif/core'
4
+
5
+ await execute({development: true, dir: import.meta.url})
package/bin/run.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node "%~dp0\run" %*
package/bin/run.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {execute} from '@oclif/core'
4
+
5
+ await execute({dir: import.meta.url})
@@ -0,0 +1,62 @@
1
+ import { Command } from '@oclif/core';
2
+ export declare class MyCommand extends Command {
3
+ static args: {
4
+ firstArg: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
+ };
6
+ static flags: {
7
+ backendFile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ cursor: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
+ };
10
+ /**
11
+ * The run method is called when the command is run.
12
+ *
13
+ * Steps:
14
+ * 1. Create a folder named after the first arg or ask for it
15
+ * 2. Create a folder with the name `manifest`.
16
+ * 3. Create a file inside the folder with the name `manifest.yml`.
17
+ * 4. Update the `package.json` file with the new packages and scripts.
18
+ * 5. Update the .vscode/extensions.json file with the recommended extensions.
19
+ * 6. Update the .vscode/settings.json file with the recommended settings.
20
+ * 7. Update the .gitignore file with the recommended settings.
21
+ * 8. Update the .env file with the environment variables.
22
+ * 9. If no README.md file exists, create one.
23
+ * 10. Add optional files based on flags
24
+ * 11. Install the new packages.
25
+ * 12. Serve the new app.
26
+ * 13. Wait for the server to start.
27
+ * 14. Seed the database.
28
+ * 15. Open the browser.
29
+ */
30
+ run(): Promise<void>;
31
+ /**
32
+ * Check if the server is ready.
33
+ *
34
+ * @returns {Promise<boolean>} - Returns a promise that resolves to a boolean.
35
+ *
36
+ **/
37
+ isServerReady(): Promise<boolean>;
38
+ /**
39
+ * Wait for the server to be ready.
40
+ *
41
+ * @returns {Promise<void>} - Returns a promise that resolves to void when the server is ready.
42
+ *
43
+ **/
44
+ waitForServerToBeReady(): Promise<void>;
45
+ /**
46
+ * Transform a JSON with comments to a JSON without comments.
47
+ *
48
+ * @param {string} jsonWithComments - The JSON with comments.
49
+ *
50
+ * @returns {string} - The JSON without comments.
51
+ *
52
+ **/
53
+ removeComments(jsonString: string): string;
54
+ /**
55
+ * Kill a process without logging an error if it fails.
56
+ *
57
+ * @param {number} pid - The process ID.
58
+ * @returns {Promise<void>} - A promise that resolves when the process is killed.
59
+ *
60
+ */
61
+ silentKill(pid: number): Promise<void>;
62
+ }
@@ -0,0 +1,318 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import axios from 'axios';
3
+ import { exec as execCp } from 'node:child_process';
4
+ import * as crypto from 'node:crypto';
5
+ import * as fs from 'node:fs';
6
+ import * as path from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { promisify } from 'node:util';
9
+ import ora from 'ora';
10
+ import treeKill from 'tree-kill';
11
+ import { parse } from 'jsonc-parser';
12
+ import { updateExtensionJsonFile } from '../utils/UpdateExtensionJsonFile.js';
13
+ import { updatePackageJsonFile } from '../utils/UpdatePackageJsonFile.js';
14
+ import { updateSettingsJsonFile } from '../utils/UpdateSettingsJsonFile.js';
15
+ import { getLatestPackageVersion } from '../utils/GetLatestPackageVersion.js';
16
+ import { getBackendFileContent } from '../utils/GetBackendFileContent.js';
17
+ import { input } from '@inquirer/prompts';
18
+ const exec = promisify(execCp);
19
+ export class MyCommand extends Command {
20
+ static args = {
21
+ firstArg: Args.string({
22
+ name: 'name',
23
+ description: 'The name for the new workspace and the initial project. It will be used for the root directory.'
24
+ })
25
+ };
26
+ static flags = {
27
+ backendFile: Flags.string({
28
+ summary: 'The remote file to use as a template for the backend.yml file. If not provided, the default file will be used.'
29
+ }),
30
+ cursor: Flags.boolean()
31
+ };
32
+ /**
33
+ * The run method is called when the command is run.
34
+ *
35
+ * Steps:
36
+ * 1. Create a folder named after the first arg or ask for it
37
+ * 2. Create a folder with the name `manifest`.
38
+ * 3. Create a file inside the folder with the name `manifest.yml`.
39
+ * 4. Update the `package.json` file with the new packages and scripts.
40
+ * 5. Update the .vscode/extensions.json file with the recommended extensions.
41
+ * 6. Update the .vscode/settings.json file with the recommended settings.
42
+ * 7. Update the .gitignore file with the recommended settings.
43
+ * 8. Update the .env file with the environment variables.
44
+ * 9. If no README.md file exists, create one.
45
+ * 10. Add optional files based on flags
46
+ * 11. Install the new packages.
47
+ * 12. Serve the new app.
48
+ * 13. Wait for the server to start.
49
+ * 14. Seed the database.
50
+ * 15. Open the browser.
51
+ */
52
+ async run() {
53
+ // * 1 Create a folder named after the first argument or ask for it.
54
+ const { argv } = await this.parse(MyCommand);
55
+ let projectName = argv[0];
56
+ if (!projectName) {
57
+ projectName = await input({
58
+ message: 'What name would you like to use for the new workspace?',
59
+ validate: (input) => {
60
+ if (!input.trim()) {
61
+ return 'The name name cannot be empty';
62
+ }
63
+ // Check for invalid characters in The name names
64
+ if (/[<>:"/\\|?*]/.test(input)) {
65
+ return 'Folder name contains invalid characters';
66
+ }
67
+ return true;
68
+ }
69
+ });
70
+ }
71
+ const spinner = ora(`Creating your Manifest project in ${projectName} folder...`).start();
72
+ const projectFolderPath = path.join(process.cwd(), projectName);
73
+ // Check if the folder already exists
74
+ if (fs.existsSync(projectFolderPath)) {
75
+ spinner.fail(`Error: The "${projectFolderPath}" folder already exists in the current directory. Please find another name.`);
76
+ process.exit(1);
77
+ }
78
+ fs.mkdirSync(projectFolderPath);
79
+ const manifestFolderName = 'manifest';
80
+ const initialFileName = 'backend.yml';
81
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
82
+ const assetFolderPath = path.join(__dirname, '..', '..', 'assets');
83
+ // * 2. Create a folder with the name `manifest`.
84
+ // Construct the folder path. This example creates the folder in the current working directory.
85
+ const manifestFolderPath = path.join(projectFolderPath, manifestFolderName);
86
+ // Create the folder
87
+ fs.mkdirSync(manifestFolderPath);
88
+ // * 3. Create a file inside the folder with the name `manifest.yml`.
89
+ // Path where the new file should be created
90
+ const newFilePath = path.join(manifestFolderPath, initialFileName);
91
+ // Get the content of the file either remote or local.
92
+ const { flags } = await this.parse(MyCommand);
93
+ const remoteBackendFile = flags.backendFile;
94
+ const content = await getBackendFileContent(path.join(assetFolderPath, initialFileName), remoteBackendFile);
95
+ // Write the content to the new file
96
+ fs.writeFileSync(newFilePath, content);
97
+ spinner.succeed();
98
+ spinner.start('Update package.json file...');
99
+ // Update package.json file.
100
+ const packagePath = path.join(projectFolderPath, 'package.json');
101
+ let packageJson;
102
+ if (fs.existsSync(packagePath)) {
103
+ packageJson = parse(fs.readFileSync(packagePath, 'utf8'));
104
+ }
105
+ else {
106
+ packageJson = JSON.parse(fs.readFileSync(path.join(assetFolderPath, 'default-package.json'), 'utf8'));
107
+ }
108
+ const manifestLatestVersion = await getLatestPackageVersion('manifest');
109
+ fs.writeFileSync(packagePath, updatePackageJsonFile({
110
+ fileContent: packageJson,
111
+ newPackages: {
112
+ manifest: `^${manifestLatestVersion}`
113
+ },
114
+ newScripts: {
115
+ manifest: 'node node_modules/manifest/scripts/watch/watch.js',
116
+ 'manifest:seed': 'node node_modules/manifest/dist/manifest/src/seed/scripts/seed.js'
117
+ }
118
+ }));
119
+ spinner.succeed();
120
+ spinner.start('Add settings...');
121
+ // Update .vscode/extensions.json file.
122
+ const vscodeDirPath = path.join(projectFolderPath, '.vscode');
123
+ const extensionsFilePath = path.join(vscodeDirPath, 'extensions.json');
124
+ let extensionsJson;
125
+ // Ensure the `.vscode` Directory Exists
126
+ if (!fs.existsSync(vscodeDirPath)) {
127
+ fs.mkdirSync(vscodeDirPath);
128
+ }
129
+ // Read or Initialize `extensions.json`
130
+ if (fs.existsSync(extensionsFilePath)) {
131
+ extensionsJson = parse(fs.readFileSync(extensionsFilePath, 'utf8'));
132
+ }
133
+ else {
134
+ extensionsJson = { recommendations: [] };
135
+ }
136
+ fs.writeFileSync(extensionsFilePath, updateExtensionJsonFile({
137
+ extensions: ['redhat.vscode-yaml'],
138
+ fileContent: extensionsJson
139
+ }));
140
+ // Update .vscode/extensions.json file.
141
+ const settingsFilePath = path.join(vscodeDirPath, 'settings.json');
142
+ let settingsJson;
143
+ // Read or Initialize `settings.json`
144
+ if (fs.existsSync(settingsFilePath)) {
145
+ settingsJson = parse(fs.readFileSync(settingsFilePath, 'utf8'));
146
+ }
147
+ else {
148
+ settingsJson = {};
149
+ }
150
+ fs.writeFileSync(settingsFilePath, updateSettingsJsonFile({
151
+ fileContent: settingsJson,
152
+ settings: {
153
+ 'yaml.schemas': {
154
+ 'https://schema.manifest.build/schema.json': '**/manifest/**.yml'
155
+ }
156
+ }
157
+ }));
158
+ // * 7. Update the .env file with the environment variables.
159
+ const gitignorePath = path.join(projectFolderPath, '.gitignore');
160
+ let gitignoreContent = '';
161
+ if (fs.existsSync(gitignorePath)) {
162
+ gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
163
+ }
164
+ const newGitignoreLines = [
165
+ 'node_modules',
166
+ '.env',
167
+ 'public',
168
+ 'manifest/backend.db'
169
+ ];
170
+ newGitignoreLines.forEach((line) => {
171
+ if (!gitignoreContent.includes(line)) {
172
+ gitignoreContent += `\n${line}`;
173
+ }
174
+ });
175
+ fs.writeFileSync(gitignorePath, gitignoreContent);
176
+ spinner.succeed();
177
+ // * 9. Add a README.md file if it doesn't exist.
178
+ const readmeFilePath = path.join(projectFolderPath, 'README.md');
179
+ if (!fs.existsSync(readmeFilePath)) {
180
+ fs.writeFileSync(readmeFilePath, fs.readFileSync(path.join(assetFolderPath, 'README.md'), 'utf8'));
181
+ }
182
+ // * 10. Add optional files based on flags
183
+ // Add rules for Cursor IDE.
184
+ if (flags.cursor) {
185
+ spinner.start('Add rules for Cursor IDE...');
186
+ const cursorFolderPath = path.join(projectFolderPath, '.cursor', 'rules');
187
+ const cursorFileName = 'manifest.mdc';
188
+ fs.mkdirSync(cursorFolderPath, { recursive: true });
189
+ let cursorFileContent;
190
+ try {
191
+ const response = await fetch('https://raw.githubusercontent.com/mnfst/rules/refs/heads/main/cursor/manifest.mdc');
192
+ if (!response.ok) {
193
+ throw new Error(`HTTP error! status: ${response.status}`);
194
+ }
195
+ cursorFileContent = await response.text();
196
+ }
197
+ catch (error) {
198
+ console.error('Error fetching YAML:', error);
199
+ throw error;
200
+ }
201
+ // Write the content to the new file
202
+ fs.writeFileSync(path.join(cursorFolderPath, cursorFileName), cursorFileContent);
203
+ spinner.succeed();
204
+ }
205
+ // * 9. Install the new packages.
206
+ spinner.start('Install dependencies...');
207
+ // Install deps.
208
+ try {
209
+ await exec('npm install');
210
+ }
211
+ catch (error) {
212
+ spinner.fail(`Execution error: ${error}`);
213
+ }
214
+ // Serve the new app.
215
+ spinner.succeed();
216
+ spinner.start('Add environment variables...');
217
+ // Add environment variables to .env file
218
+ const envFilePath = path.join(projectFolderPath, '.env');
219
+ const envJWTSecret = `TOKEN_SECRET_KEY=${crypto
220
+ .randomBytes(32)
221
+ .toString('hex')}`;
222
+ let envContent;
223
+ if (fs.existsSync(envFilePath)) {
224
+ envContent = fs.readFileSync(envFilePath, 'utf8');
225
+ envContent += `\n` + envJWTSecret;
226
+ }
227
+ else {
228
+ envContent = envJWTSecret;
229
+ }
230
+ fs.writeFileSync(envFilePath, envContent);
231
+ spinner.succeed();
232
+ spinner.start('Build the database...');
233
+ let serveTask = null;
234
+ try {
235
+ // We run the manifest script to build the database.
236
+ serveTask = exec('npm run manifest');
237
+ await this.waitForServerToBeReady();
238
+ spinner.succeed();
239
+ }
240
+ catch (error) {
241
+ spinner.fail(`Execution error: ${error}`);
242
+ }
243
+ spinner.start('Seed initial data...');
244
+ try {
245
+ await exec('npm run manifest:seed');
246
+ }
247
+ catch (error) {
248
+ spinner.fail(`Execution error: ${error}`);
249
+ }
250
+ spinner.succeed();
251
+ console.log();
252
+ console.log('🎉 Manifest successfully installed !');
253
+ console.log();
254
+ console.log('🚀 Run `npm run manifest` to start the server.');
255
+ console.log();
256
+ await this.silentKill(serveTask?.child?.pid || 0);
257
+ process.exit();
258
+ }
259
+ /**
260
+ * Check if the server is ready.
261
+ *
262
+ * @returns {Promise<boolean>} - Returns a promise that resolves to a boolean.
263
+ *
264
+ **/
265
+ async isServerReady() {
266
+ return axios
267
+ .get('http://localhost:1111/api/health')
268
+ .then(() => true)
269
+ .catch(() => false);
270
+ }
271
+ /**
272
+ * Wait for the server to be ready.
273
+ *
274
+ * @returns {Promise<void>} - Returns a promise that resolves to void when the server is ready.
275
+ *
276
+ **/
277
+ async waitForServerToBeReady() {
278
+ let serverReady = false;
279
+ while (!serverReady) {
280
+ serverReady = await this.isServerReady();
281
+ if (!serverReady) {
282
+ await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1s before retrying
283
+ }
284
+ }
285
+ }
286
+ /**
287
+ * Transform a JSON with comments to a JSON without comments.
288
+ *
289
+ * @param {string} jsonWithComments - The JSON with comments.
290
+ *
291
+ * @returns {string} - The JSON without comments.
292
+ *
293
+ **/
294
+ removeComments(jsonString) {
295
+ return jsonString
296
+ .replace(/\/\*[\s\S]*?\*\//g, '') // Remove multi-line comments
297
+ .replace(/\/\/.*$/gm, ''); // Remove single-line comments
298
+ }
299
+ /**
300
+ * Kill a process without logging an error if it fails.
301
+ *
302
+ * @param {number} pid - The process ID.
303
+ * @returns {Promise<void>} - A promise that resolves when the process is killed.
304
+ *
305
+ */
306
+ silentKill(pid) {
307
+ return new Promise((resolve, reject) => {
308
+ treeKill(pid, 'SIGKILL', (err) => {
309
+ if (err) {
310
+ reject(`Failed to kill process: ${err}`);
311
+ }
312
+ else {
313
+ resolve();
314
+ }
315
+ });
316
+ });
317
+ }
318
+ }
@@ -0,0 +1 @@
1
+ export { run } from '@oclif/core';
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { run } from '@oclif/core';
@@ -0,0 +1 @@
1
+ export declare const getBackendFileContent: (localPath: string, remotePath?: string) => Promise<string>;
@@ -0,0 +1,21 @@
1
+ import * as fs from 'node:fs';
2
+ export const getBackendFileContent = async (localPath, remotePath) => {
3
+ // We use local default example backend file if remotePath is not provided.
4
+ if (!remotePath) {
5
+ return Promise.resolve(fs.readFileSync(localPath, 'utf8'));
6
+ }
7
+ else {
8
+ try {
9
+ const response = await fetch(remotePath);
10
+ if (!response.ok) {
11
+ throw new Error(`HTTP error! status: ${response.status}`);
12
+ }
13
+ const yamlContent = await response.text();
14
+ return yamlContent;
15
+ }
16
+ catch (error) {
17
+ console.error('Error fetching YAML:', error);
18
+ throw error;
19
+ }
20
+ }
21
+ };
@@ -0,0 +1 @@
1
+ export declare const getLatestPackageVersion: (packageName: string) => Promise<string>;
@@ -0,0 +1,5 @@
1
+ export const getLatestPackageVersion = async (packageName) => {
2
+ const response = await fetch(`https://registry.npmjs.org/${packageName}`);
3
+ const data = await response.json();
4
+ return data['dist-tags'].latest;
5
+ };
@@ -0,0 +1,6 @@
1
+ export declare const updateExtensionJsonFile: ({ extensions, fileContent }: {
2
+ extensions: string[];
3
+ fileContent: {
4
+ recommendations: string[];
5
+ };
6
+ }) => string;
@@ -0,0 +1,8 @@
1
+ export const updateExtensionJsonFile = ({ extensions, fileContent }) => {
2
+ extensions.forEach((extension) => {
3
+ if (!fileContent.recommendations.includes(extension)) {
4
+ fileContent.recommendations.push(extension);
5
+ }
6
+ });
7
+ return JSON.stringify(fileContent, null, 2);
8
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Updates the package.json file with new packages and scripts.
3
+ *
4
+ * @param {Object} params - The parameters for updating the package.json file.
5
+ * @param {JSON} params.fileContent - The current content of the package.json file.
6
+ * @param {Record<string, string>} params.newPackages - An object where the keys are the names of the new packages and the values are the versions.
7
+ * @param {Record<string, string>} params.newScripts - An object where the keys are the names of the new scripts and the values are the script commands.
8
+ *
9
+ * @returns {string} The updated content of the package.json file.
10
+ */
11
+ export declare const updatePackageJsonFile: ({ fileContent, newPackages, newScripts }: {
12
+ fileContent: {
13
+ scripts: Record<string, string>;
14
+ dependencies: Record<string, string>;
15
+ };
16
+ newPackages: Record<string, string>;
17
+ newScripts: Record<string, string>;
18
+ }) => string;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Updates the package.json file with new packages and scripts.
3
+ *
4
+ * @param {Object} params - The parameters for updating the package.json file.
5
+ * @param {JSON} params.fileContent - The current content of the package.json file.
6
+ * @param {Record<string, string>} params.newPackages - An object where the keys are the names of the new packages and the values are the versions.
7
+ * @param {Record<string, string>} params.newScripts - An object where the keys are the names of the new scripts and the values are the script commands.
8
+ *
9
+ * @returns {string} The updated content of the package.json file.
10
+ */
11
+ export const updatePackageJsonFile = ({ fileContent, newPackages, newScripts }) => {
12
+ fileContent.scripts = {
13
+ ...fileContent.scripts,
14
+ ...newScripts
15
+ };
16
+ fileContent.dependencies = {
17
+ ...fileContent.dependencies,
18
+ ...newPackages
19
+ };
20
+ return JSON.stringify(fileContent, null, 2);
21
+ };
@@ -0,0 +1,4 @@
1
+ export declare const updateSettingsJsonFile: ({ fileContent, settings }: {
2
+ fileContent: Record<string, unknown>;
3
+ settings: Record<string, unknown>;
4
+ }) => string;
@@ -0,0 +1,6 @@
1
+ export const updateSettingsJsonFile = ({ fileContent, settings }) => {
2
+ Object.keys(settings).forEach((key) => {
3
+ fileContent[key] = settings[key];
4
+ });
5
+ return JSON.stringify(fileContent, null, 2);
6
+ };
@@ -0,0 +1,4 @@
1
+ {
2
+ "commands": {},
3
+ "version": "1.1.3"
4
+ }
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "create-manifest",
3
+ "version": "1.1.3",
4
+ "author": "Manifest",
5
+ "description": "Create a new Manifest backend",
6
+ "homepage": "https://manifest.build",
7
+ "license": "MIT",
8
+ "bin": {
9
+ "create-manifest": "./bin/run.js"
10
+ },
11
+ "scripts": {
12
+ "build": "shx rm -rf dist && tsc -b",
13
+ "watch": "tsc -b --watch",
14
+ "postpack": "shx rm -f oclif.manifest.json",
15
+ "posttest": "npm run lint",
16
+ "prepack": "npm run build && oclif manifest && oclif readme",
17
+ "prepare": "npm run build",
18
+ "version": "oclif readme && git add README.md"
19
+ },
20
+ "oclif": {
21
+ "bin": "create-manifest",
22
+ "dirname": "create-manifest",
23
+ "strategy": "single",
24
+ "target": "./dist/commands/index.js"
25
+ },
26
+ "plugins": [
27
+ "@oclif/plugin-help",
28
+ "@oclif/plugin-plugins"
29
+ ],
30
+ "topicSeparator": " ",
31
+ "topics": {
32
+ "create": {
33
+ "description": "Create a new Manifest backend"
34
+ }
35
+ },
36
+ "dependencies": {
37
+ "@inquirer/prompts": "^7.5.1",
38
+ "@oclif/core": "^4",
39
+ "@oclif/plugin-help": "^6",
40
+ "@oclif/plugin-plugins": "^5",
41
+ "axios": "^1.9.0",
42
+ "chalk": "^5.4.1",
43
+ "fs": "^0.0.1-security",
44
+ "jsonc-parser": "^3.3.1",
45
+ "ora": "^8.2.0",
46
+ "path": "^0.12.7",
47
+ "tree-kill": "^1.2.2",
48
+ "url": "^0.11.4"
49
+ },
50
+ "devDependencies": {
51
+ "@oclif/prettier-config": "^0.2.1",
52
+ "@oclif/test": "^4",
53
+ "oclif": "^4.17.46",
54
+ "shx": "^0.4.0",
55
+ "ts-node": "^10.9.2",
56
+ "typescript": "^5"
57
+ },
58
+ "engines": {
59
+ "node": ">=18.0.0"
60
+ },
61
+ "files": [
62
+ "/bin",
63
+ "/dist",
64
+ "/assets",
65
+ "/oclif.manifest.json"
66
+ ],
67
+ "main": "",
68
+ "repository": {
69
+ "type": "git",
70
+ "url": "git+https://github.com/mnfst/manifest.git"
71
+ },
72
+ "bugs": "https://github.com/mnfst/manifest/issues",
73
+ "keywords": [
74
+ "manifest",
75
+ "micro-backend",
76
+ "backend",
77
+ "headless",
78
+ "install",
79
+ "rest"
80
+ ],
81
+ "types": "dist/index.d.ts",
82
+ "exports": "./lib/index.js",
83
+ "type": "module"
84
+ }