neutrinos-cli 1.0.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 (57) hide show
  1. package/.configs/auth.json +5 -0
  2. package/.configs/preferences.json +5 -0
  3. package/.env +6 -0
  4. package/README.md +173 -0
  5. package/bin/cli.js +239 -0
  6. package/cli-auth/auth.js +54 -0
  7. package/cli-auth/publish.js +7 -0
  8. package/cli-auth/server.js +44 -0
  9. package/cli-auth/services/auth-utils.js +68 -0
  10. package/commands/alpha-publish.js +219 -0
  11. package/commands/attribute.js +155 -0
  12. package/commands/build.js +83 -0
  13. package/commands/deprecate.js +88 -0
  14. package/commands/dev.js +21 -0
  15. package/commands/generate.js +19 -0
  16. package/commands/new-workspace.js +142 -0
  17. package/commands/publish.js +334 -0
  18. package/commands/select-packages.mjs +36 -0
  19. package/commands/serve.js +27 -0
  20. package/package.json +34 -0
  21. package/setup.js +55 -0
  22. package/templates/assets/default-icon.png +0 -0
  23. package/templates/component/.component.ts.hbs +126 -0
  24. package/templates/component/.spec.ts.hbs +15 -0
  25. package/templates/component/.styles.ts.hbs +2 -0
  26. package/templates/module/.module.js.hbs +11 -0
  27. package/templates/plugins-server/index.js +18 -0
  28. package/templates/project/.vscode/extensions.json +6 -0
  29. package/templates/project/ATTRIBUTE.md +127 -0
  30. package/templates/project/Dockerfile +15 -0
  31. package/templates/project/helmchart/.helmignore +23 -0
  32. package/templates/project/helmchart/Chart.yaml +24 -0
  33. package/templates/project/helmchart/templates/NOTES.txt +22 -0
  34. package/templates/project/helmchart/templates/_helpers.tpl +62 -0
  35. package/templates/project/helmchart/templates/deployment.yaml +69 -0
  36. package/templates/project/helmchart/templates/ingress.yaml +62 -0
  37. package/templates/project/helmchart/templates/service.yaml +14 -0
  38. package/templates/project/helmchart/values.yaml +74 -0
  39. package/templates/project/index.html +24 -0
  40. package/templates/project/index.ts +86 -0
  41. package/templates/project/public-api.ts +0 -0
  42. package/templates/project/tsconfig.json +27 -0
  43. package/utils/attribute-utils.js +149 -0
  44. package/utils/check-valid-ws.js +21 -0
  45. package/utils/copy-utils.js +68 -0
  46. package/utils/create-client.js +23 -0
  47. package/utils/file-utils.js +43 -0
  48. package/utils/generate-component.js +101 -0
  49. package/utils/generate-module.js +51 -0
  50. package/utils/get-package-info.js +53 -0
  51. package/utils/get-packages.js +15 -0
  52. package/utils/inquirer-utils.js +49 -0
  53. package/utils/logger.js +35 -0
  54. package/utils/marketplace-api-utils.js +34 -0
  55. package/utils/path-utils.js +40 -0
  56. package/utils/prettify.js +36 -0
  57. package/utils/user-seesion-utils.js +43 -0
@@ -0,0 +1,142 @@
1
+ import { bold } from 'colorette';
2
+ import { execSync } from 'node:child_process';
3
+ // prettier-ignore
4
+ import { cpSync,mkdirSync,readFileSync,rmSync,writeFileSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { exit } from 'node:process';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { done, failed, inprogress } from '../utils/logger.js';
9
+ // prettier-ignore
10
+ import { pluginJsonPath,pluginServerTemplatesPath } from '../utils/path-utils.js';
11
+ import { prettify } from '../utils/prettify.js';
12
+
13
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
14
+
15
+ export const createWorkspace = async (dir, name) => {
16
+ process.on('SIGINT', () => {
17
+ cleanUp(dir);
18
+ exit(0);
19
+ });
20
+ process.on('SIGTERM', () => {
21
+ cleanUp(dir);
22
+ exit(0);
23
+ });
24
+ try {
25
+ createWorkspaceDirectory(dir);
26
+ } catch (err) {
27
+ handleWorkspaceDirectoryCreationError(err, dir);
28
+ }
29
+ try {
30
+ initializeNpmProject(dir);
31
+ copyProjectTemplate(dir);
32
+ await createPluginJson(dir, name);
33
+ await initializePackages(dir);
34
+ await createReadme(dir, name);
35
+ initializeGit(dir);
36
+ initializeStaticServer(dir);
37
+ done(`Plugin Workspace created successfully: ${bold(dir)}`);
38
+ } catch (err) {
39
+ handleWorkspaceCreationError(err, dir);
40
+ }
41
+ };
42
+
43
+ const createWorkspaceDirectory = (dir) => {
44
+ mkdirSync(dir);
45
+ done(`Created workspace directory: ${bold(dir)}`);
46
+ };
47
+
48
+ const initializeNpmProject = (dir) => {
49
+ execSync(`npm init -y`, {
50
+ cwd: dir,
51
+ });
52
+ done(`Initialized npm project in workspace`);
53
+ };
54
+
55
+ const copyProjectTemplate = (dir) => {
56
+ cpSync(join(__dirname, '../templates/project'), dir, {
57
+ recursive: true,
58
+ });
59
+ };
60
+
61
+ const createPluginJson = async (dir, name) => {
62
+ writeFileSync(
63
+ pluginJsonPath(dir),
64
+ await prettify(
65
+ {
66
+ name,
67
+ components: { selectorPrefix: 'comp' },
68
+ modules: { idPrefix: 'mod' },
69
+ },
70
+ 'json',
71
+ ),
72
+ );
73
+ done(`Created plugin.json in workspace`);
74
+ };
75
+
76
+ const createReadme = async (dir, name) => {
77
+ writeFileSync(
78
+ join(dir, 'README.md'),
79
+ await prettify(`# ${name}\n\nThis is a new workspace for creating plugins for studio`, 'markdown'),
80
+ );
81
+ done(`Created README.md in workspace`);
82
+ };
83
+
84
+ const initializeGit = (dir) => {
85
+ writeFileSync(join(dir, '.gitignore'), ['node_modules', 'dist', 'build', 'coverage'].join('\n'));
86
+ execSync(`git init`, {
87
+ cwd: dir,
88
+ });
89
+ done(`Initialized git in workspace`);
90
+ };
91
+
92
+ const cleanUp = (dir) => {
93
+ inprogress('Cleaning up...');
94
+ rmSync(dir, { recursive: true });
95
+ done('Cleaned up workspace');
96
+ };
97
+
98
+ const initializePackages = async (dir) => {
99
+ inprogress(`Adding default npm scripts to workspace...`);
100
+ const pkgJson = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'));
101
+ const scripts = {
102
+ build: 'alpha build',
103
+ start: 'alpha start',
104
+ serve: 'alpha serve',
105
+ };
106
+ pkgJson.devDependencies = {
107
+ lit: '^3.1.4',
108
+ typescript: '^5.2.2',
109
+ };
110
+ pkgJson.dependencies = {
111
+ express: '^4.19.2',
112
+ '@jatahworx/alpha-annotations-lib': '^1.0.9',
113
+ };
114
+
115
+ pkgJson.workspaces = ['packages/*'];
116
+ pkgJson.type = 'module';
117
+ Object.assign(pkgJson.scripts, {}, scripts);
118
+ writeFileSync(join(dir, 'package.json'), await prettify(pkgJson, 'json'));
119
+ execSync(`npm install`, {
120
+ cwd: dir,
121
+ });
122
+ done(`Installed default packages in workspace: ${bold(dir)}`);
123
+ done(`Added default npm scripts to workspace: ${bold(dir)}`);
124
+ };
125
+
126
+ const initializeStaticServer = (dir) => {
127
+ cpSync(pluginServerTemplatesPath(), join(dir, 'plugins-server'), {
128
+ recursive: true,
129
+ });
130
+ done(`Initialized static server in workspace`);
131
+ };
132
+
133
+ const handleWorkspaceDirectoryCreationError = (err, dir) => {
134
+ failed(`Failed to create workspace directory: ${bold(dir)}`, err);
135
+ exit(1);
136
+ };
137
+
138
+ const handleWorkspaceCreationError = (err, dir) => {
139
+ failed(`Failed to create workspace: ${bold(dir)}`, err);
140
+ cleanUp(dir);
141
+ return;
142
+ };
@@ -0,0 +1,334 @@
1
+ //@ts-check
2
+ import AdmZip from 'adm-zip';
3
+ import FormData from 'form-data';
4
+ import { remove } from 'fs-extra';
5
+ import { execSync } from 'node:child_process';
6
+ import { createReadStream, existsSync, readFileSync, writeFileSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+ import { copyIconToAsset, copyImagesToAsset, getPackageIcon, getPackageImages } from '../utils/copy-utils.js';
9
+ import { getPackageMetadata } from '../utils/get-package-info.js';
10
+ import { inquiry, multipleInquiry } from '../utils/inquirer-utils.js';
11
+ import { done, failed, inprogress } from '../utils/logger.js';
12
+ import { publishToMarketplace } from '../utils/marketplace-api-utils.js';
13
+ import { getLoggedInUserSession } from '../utils/user-seesion-utils.js';
14
+
15
+ const DISPLAY_NAME_QUERY = {
16
+ type: 'input',
17
+ name: 'name',
18
+ message: 'Enter the Display Name of the package :',
19
+ };
20
+ const ICON_FILE_PATH_QUERY = {
21
+ type: 'input',
22
+ name: 'value',
23
+ message: 'Enter the path to the icon of the package :',
24
+ };
25
+ const IMAGES_FILE_PATH_QUERY = {
26
+ type: 'input',
27
+ name: 'value',
28
+ message: 'Enter the path to images of the package :',
29
+ };
30
+
31
+ /**
32
+ *
33
+ * @param {string} name
34
+ * @param {string} wsPath
35
+ * @param {any} options
36
+ */
37
+ export const publish = async (name, wsPath, options) => {
38
+ const session = await getLoggedInUserSession();
39
+ const { packageName, componentDirPath } = await getPackageMetadata(wsPath, name);
40
+ await handlePackagePublish(packageName, componentDirPath, wsPath, options, session);
41
+ done('Published Successfully');
42
+ };
43
+
44
+ /**
45
+ *
46
+ * @param {string} packageName
47
+ * @param {string} componentDirPath
48
+ * @param {string} wsPath
49
+ * @param {any} options
50
+ * @param {any} session
51
+ */
52
+ const handlePackagePublish = async (packageName, componentDirPath, wsPath, options, session) => {
53
+ const pkgJsonPath = join(componentDirPath, 'package.json');
54
+ let pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
55
+ if (!pkgJson.alpha) {
56
+ throw new Error('It is not an alpha package');
57
+ }
58
+ if (pkgJson.alpha.deprecated) {
59
+ throw new Error('This is a deprecated package');
60
+ }
61
+ if (pkgJson.alpha.packageId) {
62
+ await publishPackageVersion(packageName, wsPath, pkgJson, options, componentDirPath, pkgJsonPath, session);
63
+ } else {
64
+ await publishNewPackage(packageName, wsPath, pkgJson, options, componentDirPath, pkgJsonPath, session);
65
+ }
66
+ };
67
+
68
+ /**
69
+ *
70
+ * @param {string} name
71
+ * @param {string} wsPath
72
+ * @param {any} pkgJson
73
+ * @param {any} options
74
+ * @param {string} componentDirPath
75
+ * @param {string} pkgJsonPath
76
+ * @param {any} session
77
+ */
78
+ const publishPackageVersion = async (name, wsPath, pkgJson, options, componentDirPath, pkgJsonPath, session) => {
79
+ await incrementPackageVersion(wsPath, pkgJson.name, options);
80
+ pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
81
+
82
+ const iconForPkg = options.icon || (await getIconPath(componentDirPath));
83
+ const imagesForPkg = options.images?.length
84
+ ? JSON.stringify(options.images)
85
+ : JSON.stringify(await getImagesPath(componentDirPath));
86
+
87
+ const publishArgs = createVersionPublishArgs(name, pkgJson, iconForPkg, imagesForPkg);
88
+ inprogress('Publishing...');
89
+ const { version } = await uploadPackageFiles(
90
+ wsPath,
91
+ componentDirPath,
92
+ publishArgs,
93
+ pkgJson.alpha.packageId,
94
+ session,
95
+ );
96
+ if (version.version_id) {
97
+ updatePackageJson(pkgJsonPath, pkgJson, pkgJson.alpha.packageId, version.version_id);
98
+ }
99
+ };
100
+
101
+ /**
102
+ *
103
+ * @param {string} name
104
+ * @param {string} wsPath
105
+ * @param {any} pkgJson
106
+ * @param {any} options
107
+ * @param {string} componentDirPath
108
+ * @param {string} pkgJsonPath
109
+ * @param {any} session
110
+ */
111
+ const publishNewPackage = async (name, wsPath, pkgJson, options, componentDirPath, pkgJsonPath, session) => {
112
+ const displayName = options.displayName || (await inquiry(DISPLAY_NAME_QUERY)).name || name;
113
+ const iconForPkg = options.icon || (await getIconPath(componentDirPath));
114
+ const imagesForPkg = options.images?.length ? options.images : await getImagesPath(componentDirPath);
115
+
116
+ const publishArgs = createNewPackagePublishArgs(name, pkgJson, displayName, iconForPkg, imagesForPkg);
117
+ inprogress('Publishing...');
118
+ const response = await uploadPackageFiles(wsPath, componentDirPath, publishArgs, '', session);
119
+ if (response.package) {
120
+ updatePackageJson(
121
+ pkgJsonPath,
122
+ pkgJson,
123
+ response.package.package_id,
124
+ response.package.latest_version.version_id,
125
+ );
126
+ }
127
+ };
128
+
129
+ /**
130
+ *
131
+ * @param {string} componentDirPath
132
+ * @returns
133
+ */
134
+ const getIconPath = async (componentDirPath) => {
135
+ const icon = getPackageIcon(componentDirPath);
136
+ return icon || (await inquiry(ICON_FILE_PATH_QUERY)).value;
137
+ };
138
+
139
+ /**
140
+ *
141
+ * @param {string} componentDirPath
142
+ * @returns
143
+ */
144
+ const getImagesPath = async (componentDirPath) => {
145
+ const images = getPackageImages(componentDirPath);
146
+ if (images.length) {
147
+ return images;
148
+ }
149
+ const imagesAns = await multipleInquiry(IMAGES_FILE_PATH_QUERY);
150
+ return imagesAns.map((img) => img.value);
151
+ };
152
+
153
+ /**
154
+ *
155
+ * @param {string} name
156
+ * @param {any} pkgJson
157
+ * @param {string} iconForPkg
158
+ * @param {string} imagesForPkg
159
+ * @returns
160
+ */
161
+ const createVersionPublishArgs = (name, pkgJson, iconForPkg, imagesForPkg) => ({
162
+ name,
163
+ version_number: pkgJson.version,
164
+ metadata: JSON.stringify({
165
+ platform: 'alpha',
166
+ type: pkgJson.alpha.component ? 'component' : 'module',
167
+ }),
168
+ icon_file_path: iconForPkg,
169
+ image_file_path: imagesForPkg,
170
+ });
171
+
172
+ /**
173
+ *
174
+ * @param {string} name
175
+ * @param {any} pkgJson
176
+ * @param {string} displayName
177
+ * @param {string} iconForPkg
178
+ * @param {string[]} imagesForPkg
179
+ * @returns
180
+ */
181
+ const createNewPackagePublishArgs = (name, pkgJson, displayName, iconForPkg, imagesForPkg) => ({
182
+ package_metadata: JSON.stringify({
183
+ platform: 'alpha',
184
+ type: pkgJson.alpha.component ? 'component' : 'module',
185
+ }),
186
+ display_name: displayName,
187
+ name,
188
+ version_number: pkgJson.version,
189
+ package_type: 'zip',
190
+ version_metadata: JSON.stringify({
191
+ platform: 'alpha',
192
+ type: pkgJson.alpha.component ? 'component' : 'module',
193
+ }),
194
+ description: pkgJson.description || 'Package published by CLI',
195
+ icon_file_path: iconForPkg,
196
+ image_file_path: JSON.stringify(imagesForPkg),
197
+ });
198
+
199
+ /**
200
+ *
201
+ * @param {string} wsPath
202
+ * @param {string} pkgName
203
+ * @param {any} options
204
+ */
205
+ const incrementPackageVersion = async (wsPath, pkgName, options) => {
206
+ if (!pkgName) throw new Error('Package name is required');
207
+ const versionType =
208
+ options.versionType ||
209
+ (
210
+ await inquiry({
211
+ type: 'list',
212
+ name: 'type',
213
+ choices: ['patch', 'minor', 'major'],
214
+ message: 'Choose the Version type :',
215
+ })
216
+ ).type;
217
+ execSync(`npm version ${versionType} -w ${pkgName}`, {
218
+ cwd: wsPath,
219
+ stdio: 'inherit',
220
+ });
221
+ };
222
+
223
+ /**
224
+ *
225
+ * @param {string} wsPath
226
+ * @param {string} componentDirPath
227
+ * @param {any} publishArgs
228
+ * @param {string} path
229
+ * @param {any} session
230
+ * @returns
231
+ */
232
+ const uploadPackageFiles = async (wsPath, componentDirPath, publishArgs, path = '', session) => {
233
+ const form = createFormData(publishArgs, componentDirPath);
234
+
235
+ const zipFile = await createZipFile(wsPath, componentDirPath, publishArgs.name);
236
+ form.append('zip_file', zipFile);
237
+
238
+ return publishToMarketplace(form, path, session, false);
239
+ };
240
+
241
+ /**
242
+ *
243
+ * @param {any} publishArgs
244
+ * @param {string} componentDirPath
245
+ * @returns
246
+ */
247
+ const createFormData = (publishArgs, componentDirPath) => {
248
+ const form = new FormData();
249
+ for (let key in publishArgs) {
250
+ form.append(key, publishArgs[key]);
251
+ }
252
+
253
+ appendIconToForm(form, publishArgs.icon_file_path, componentDirPath);
254
+ appendImagesToForm(form, JSON.parse(publishArgs.image_file_path), componentDirPath);
255
+
256
+ return form;
257
+ };
258
+
259
+ /**
260
+ *
261
+ * @param {FormData} form
262
+ * @param {string} iconPath
263
+ * @param {string} componentDirPath
264
+ */
265
+ const appendIconToForm = (form, iconPath, componentDirPath) => {
266
+ if (existsSync(iconPath)) {
267
+ copyIconToAsset(iconPath, componentDirPath);
268
+ form.append('icon', createReadStream(iconPath));
269
+ } else {
270
+ failed("Invalid icon path or icon doesn't exist");
271
+ }
272
+ };
273
+
274
+ /**
275
+ *
276
+ * @param {FormData} form
277
+ * @param {string[]} imagesPaths
278
+ * @param {string} componentDirPath
279
+ */
280
+ const appendImagesToForm = (form, imagesPaths, componentDirPath) => {
281
+ //@ts-ignore
282
+ imagesPaths.forEach((imgPath) => {
283
+ if (existsSync(imgPath)) {
284
+ copyImagesToAsset(imgPath, componentDirPath);
285
+ form.append('images', createReadStream(imgPath));
286
+ } else {
287
+ failed("Invalid images path or image doesn't exist");
288
+ }
289
+ });
290
+ };
291
+
292
+ /**
293
+ *
294
+ * @param {string} wsPath
295
+ * @param {string} componentDirPath
296
+ * @param {string} packageName
297
+ * @returns
298
+ */
299
+ const createZipFile = async (wsPath, componentDirPath, packageName) => {
300
+ const componentDistPath = join(componentDirPath, 'dist');
301
+ execSync(`npm run build plugins ${packageName}`, {
302
+ cwd: wsPath,
303
+ stdio: 'inherit',
304
+ });
305
+
306
+ //@ts-ignore
307
+ const zip = new AdmZip();
308
+ zip.addLocalFolder(componentDistPath);
309
+ const zipBuffer = zip.toBuffer();
310
+
311
+ const zipFilePath = join(componentDistPath, `${packageName.toLowerCase()}.zip`);
312
+ writeFileSync(zipFilePath, zipBuffer);
313
+
314
+ const readStream = createReadStream(zipFilePath);
315
+ readStream.on('close', () =>
316
+ remove(zipFilePath, (err) => {
317
+ if (err) console.error('Error deleting file:', err);
318
+ }),
319
+ );
320
+
321
+ return readStream;
322
+ };
323
+
324
+ /**
325
+ *
326
+ * @param {string} pkgJsonPath
327
+ * @param {any} pkgJson
328
+ * @param {string} packageId
329
+ * @param {string} versionId
330
+ */
331
+ const updatePackageJson = (pkgJsonPath, pkgJson, packageId, versionId) => {
332
+ Object.assign(pkgJson.alpha, { packageId, versionId });
333
+ writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
334
+ };
@@ -0,0 +1,36 @@
1
+ //@ts-check
2
+ import checkbox from '@inquirer/checkbox';
3
+ import { existsSync, globSync, readFileSync } from 'node:fs';
4
+ import { basename, join, sep } from 'node:path';
5
+
6
+ export const selectPackages = async (dirname, all = false, pluginName) => {
7
+ /**@type {string[]} */
8
+ const packagesDir = JSON.parse(readFileSync(join(dirname, 'package.json'), 'utf-8')).workspaces;
9
+ const packageNames = globSync(packagesDir, { cwd: join(dirname) });
10
+ const packages = packageNames
11
+ .map((name) => join(dirname, name))
12
+ .filter((p) => {
13
+ return existsSync(join(p, 'package.json'));
14
+ });
15
+ if (pluginName) {
16
+ const pluginPath = packages.filter((p) => basename(p) === pluginName);
17
+ return pluginPath;
18
+ }
19
+ if (all) {
20
+ return packages;
21
+ }
22
+ const selectedPackages = await checkbox({
23
+ message: 'Select the packages',
24
+ instructions: ' [NOTE: Press <space> to toggle selection, <return> to submit]',
25
+ choices: packages.map((p) => {
26
+ return {
27
+ name: p.split(sep).pop(),
28
+ value: p,
29
+ // checked: true,
30
+ };
31
+ }),
32
+ required: true,
33
+ pageSize: 10,
34
+ });
35
+ return selectedPackages;
36
+ };
@@ -0,0 +1,27 @@
1
+ import { execSync } from 'child_process';
2
+ import { existsSync } from 'fs';
3
+ import { platform } from 'node:process';
4
+ import { failed } from '../utils/logger.js';
5
+ import { pluginServerRoot } from '../utils/path-utils.js';
6
+
7
+ export const startPluginsServer = async (wsPath) => {
8
+ const serverRoot = pluginServerRoot(wsPath);
9
+ if (!existsSync(serverRoot)) {
10
+ failed('The plugins server is not found in the workspace');
11
+ return;
12
+ }
13
+ const index = 'index.js';
14
+ const cmd = platform === 'win32' ? `node.exe` : `node`;
15
+ const args = ['--watch', `"${index}"`];
16
+ const execuatable = `${cmd} ${args.join(' ')}`;
17
+ execSync(execuatable, {
18
+ cwd: serverRoot,
19
+ stdio: 'inherit',
20
+ env: {
21
+ ...process.env,
22
+ PORT: '666',
23
+ BASE_PATH: '/plugins-service',
24
+ PLUGIN_DIR_ROOT: 'plugins',
25
+ },
26
+ });
27
+ };
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "neutrinos-cli",
3
+ "version": "1.0.0",
4
+ "main": "./bin/cli.js",
5
+ "type": "module",
6
+ "bin": {
7
+ "neutrinos": "bin/cli.js"
8
+ },
9
+ "files": [
10
+ ".configs",
11
+ "bin",
12
+ "cli-auth",
13
+ "commands",
14
+ "templates",
15
+ "utils",
16
+ "setup.js",
17
+ ".env",
18
+ "package.json"
19
+ ],
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "scripts": {
24
+ "test": "echo \"Error: no test specified\" && exit 1",
25
+ "postinstall": "node ./setup.js"
26
+ },
27
+ "author": "",
28
+ "license": "ISC",
29
+ "keywords": [],
30
+ "description": "",
31
+ "dependencies": {
32
+ "fastify": "^5.4.0"
33
+ }
34
+ }
package/setup.js ADDED
@@ -0,0 +1,55 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises';
2
+
3
+ /**
4
+ * Ensure that the config folder exists
5
+ * @param {string} configDir
6
+ */
7
+ export const ensureConfigFolder = async (configDir) => {
8
+ try {
9
+ await mkdir(configDir, { recursive: true });
10
+ } catch (error) {
11
+ if (error.code !== 'EEXIST') {
12
+ throw error;
13
+ }
14
+ }
15
+ };
16
+
17
+ export const ensureDefaultPreferences = async (configDir, preferences) => {
18
+ const preferencesPath = `${configDir}/preferences.json`;
19
+ try {
20
+ await mkdir(configDir, { recursive: true });
21
+ await writeFile(preferencesPath, JSON.stringify(preferences, null, 4));
22
+ } catch (error) {
23
+ if (error.code !== 'EEXIST') {
24
+ throw error;
25
+ }
26
+ }
27
+ };
28
+
29
+ export const ensureAuthConfig = async (configDir, authConfig) => {
30
+ const authConfigPath = `${configDir}/auth.json`;
31
+ try {
32
+ await mkdir(configDir, { recursive: true });
33
+ await writeFile(authConfigPath, JSON.stringify(authConfig, null, 4));
34
+ } catch (error) {
35
+ if (error.code !== 'EEXIST') {
36
+ throw error;
37
+ }
38
+ }
39
+ };
40
+
41
+ const CONFIG_DIR = './.configs';
42
+
43
+ ensureConfigFolder(CONFIG_DIR);
44
+
45
+ ensureAuthConfig(CONFIG_DIR, {
46
+ clientId: 'your-client-id',
47
+ clientSecret: 'your-client-secret',
48
+ redirectUri: 'http://localhost:3000/callback',
49
+ });
50
+
51
+ ensureDefaultPreferences(CONFIG_DIR, {
52
+ theme: 'light',
53
+ language: 'en',
54
+ showNotifications: true,
55
+ });