retrex-extensibles-core 2.1.8 → 2.2.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.
- package/dist/cmds.cjs +22 -16
- package/dist/cmds.cjs.map +1 -1
- package/dist/cmds.js +22 -16
- package/dist/cmds.js.map +1 -1
- package/dist/commands/compile.cjs +11 -5
- package/dist/commands/compile.cjs.map +1 -1
- package/dist/commands/compile.js +11 -5
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/createModule.cjs +17 -11
- package/dist/commands/createModule.cjs.map +1 -1
- package/dist/commands/createModule.js +17 -11
- package/dist/commands/createModule.js.map +1 -1
- package/dist/commands/createService.cjs +17 -11
- package/dist/commands/createService.cjs.map +1 -1
- package/dist/commands/createService.js +17 -11
- package/dist/commands/createService.js.map +1 -1
- package/dist/commands/createTemplate.cjs +16 -10
- package/dist/commands/createTemplate.cjs.map +1 -1
- package/dist/commands/createTemplate.js +16 -10
- package/dist/commands/createTemplate.js.map +1 -1
- package/dist/core/hooks/useEvents.cjs +15 -9
- package/dist/core/hooks/useEvents.cjs.map +1 -1
- package/dist/core/hooks/useEvents.js +18 -12
- package/dist/core/hooks/useEvents.js.map +1 -1
- package/dist/core/hooks/useExtensibles.cjs +180 -63
- package/dist/core/hooks/useExtensibles.cjs.map +1 -1
- package/dist/core/hooks/useExtensibles.js +180 -63
- package/dist/core/hooks/useExtensibles.js.map +1 -1
- package/dist/core/hooks/useModules.cjs +21 -15
- package/dist/core/hooks/useModules.cjs.map +1 -1
- package/dist/core/hooks/useModules.js +21 -15
- package/dist/core/hooks/useModules.js.map +1 -1
- package/dist/core/hooks/useNav.cjs +33 -27
- package/dist/core/hooks/useNav.cjs.map +1 -1
- package/dist/core/hooks/useNav.js +33 -27
- package/dist/core/hooks/useNav.js.map +1 -1
- package/dist/core/hooks/useProviders.cjs +225 -0
- package/dist/core/hooks/useProviders.cjs.map +1 -0
- package/dist/core/hooks/useProviders.d.cts +14 -0
- package/dist/core/hooks/useProviders.d.ts +14 -0
- package/dist/core/hooks/useProviders.js +190 -0
- package/dist/core/hooks/useProviders.js.map +1 -0
- package/dist/core/hooks/useServices.cjs +23 -17
- package/dist/core/hooks/useServices.cjs.map +1 -1
- package/dist/core/hooks/useServices.js +23 -17
- package/dist/core/hooks/useServices.js.map +1 -1
- package/dist/core/hooks/useSettings.cjs +11 -5
- package/dist/core/hooks/useSettings.cjs.map +1 -1
- package/dist/core/hooks/useSettings.js +11 -5
- package/dist/core/hooks/useSettings.js.map +1 -1
- package/dist/core/hooks/useTemplateProvider.cjs +19 -13
- package/dist/core/hooks/useTemplateProvider.cjs.map +1 -1
- package/dist/core/hooks/useTemplateProvider.js +19 -13
- package/dist/core/hooks/useTemplateProvider.js.map +1 -1
- package/dist/core/hooks/useTemplates.cjs +26 -20
- package/dist/core/hooks/useTemplates.cjs.map +1 -1
- package/dist/core/hooks/useTemplates.js +26 -20
- package/dist/core/hooks/useTemplates.js.map +1 -1
- package/dist/core/hooks/useTranslator.cjs +30 -18
- package/dist/core/hooks/useTranslator.cjs.map +1 -1
- package/dist/core/hooks/useTranslator.js +26 -15
- package/dist/core/hooks/useTranslator.js.map +1 -1
- package/dist/core/hooks/useUtils.cjs +33 -27
- package/dist/core/hooks/useUtils.cjs.map +1 -1
- package/dist/core/hooks/useUtils.js +33 -27
- package/dist/core/hooks/useUtils.js.map +1 -1
- package/dist/core/types/index.cjs.map +1 -1
- package/dist/core/types/index.d.cts +14 -1
- package/dist/core/types/index.d.ts +14 -1
- package/dist/index.cjs +268 -138
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +268 -139
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cmds.cjs
CHANGED
|
@@ -28,20 +28,26 @@ var import_yargs = __toESM(require("yargs"), 1);
|
|
|
28
28
|
var import_helpers = require("yargs/helpers");
|
|
29
29
|
|
|
30
30
|
// src/commands/createModule.ts
|
|
31
|
-
var
|
|
31
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
32
32
|
|
|
33
33
|
// src/core/hooks/useSettings.ts
|
|
34
|
-
var
|
|
34
|
+
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
35
35
|
|
|
36
36
|
// src/core/hooks/useExtensibles.ts
|
|
37
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
38
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
39
|
+
|
|
40
|
+
// src/core/hooks/useProviders.ts
|
|
37
41
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
38
42
|
var import_node_path = __toESM(require("path"), 1);
|
|
43
|
+
|
|
44
|
+
// src/core/hooks/useExtensibles.ts
|
|
39
45
|
function loadJSON(filePath) {
|
|
40
|
-
if (!
|
|
41
|
-
return JSON.parse(
|
|
46
|
+
if (!import_node_fs2.default.existsSync(filePath)) return null;
|
|
47
|
+
return JSON.parse(import_node_fs2.default.readFileSync(filePath, "utf-8"));
|
|
42
48
|
}
|
|
43
49
|
function saveJSON(filePath, data) {
|
|
44
|
-
|
|
50
|
+
import_node_fs2.default.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
// src/core/hooks/useSettings.ts
|
|
@@ -64,7 +70,7 @@ var useSettings = {
|
|
|
64
70
|
if (isServer) {
|
|
65
71
|
for (const key of Object.keys(defaultPaths)) {
|
|
66
72
|
const candidate = extensiblePaths[key];
|
|
67
|
-
if (!candidate || !
|
|
73
|
+
if (!candidate || !import_node_fs3.default.existsSync(candidate)) {
|
|
68
74
|
extensiblePaths[key] = defaultPaths[key];
|
|
69
75
|
}
|
|
70
76
|
}
|
|
@@ -100,7 +106,7 @@ var import_chalk = __toESM(require("chalk"), 1);
|
|
|
100
106
|
|
|
101
107
|
// src/utils/github.ts
|
|
102
108
|
var import_promises = require("fs/promises");
|
|
103
|
-
var
|
|
109
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
104
110
|
var import_adm_zip = __toESM(require("adm-zip"), 1);
|
|
105
111
|
async function downloadGitHubFolderZip(repo, folderPath, dest) {
|
|
106
112
|
try {
|
|
@@ -118,11 +124,11 @@ async function downloadGitHubFolderZip(repo, folderPath, dest) {
|
|
|
118
124
|
if (!entry.entryName.startsWith(prefix)) continue;
|
|
119
125
|
const relativePath = entry.entryName.slice(prefix.length + 1);
|
|
120
126
|
if (!relativePath) continue;
|
|
121
|
-
const outPath =
|
|
127
|
+
const outPath = import_node_path3.default.join(dest, relativePath);
|
|
122
128
|
if (entry.isDirectory) {
|
|
123
129
|
await (0, import_promises.mkdir)(outPath, { recursive: true });
|
|
124
130
|
} else {
|
|
125
|
-
await (0, import_promises.mkdir)(
|
|
131
|
+
await (0, import_promises.mkdir)(import_node_path3.default.dirname(outPath), { recursive: true });
|
|
126
132
|
await (0, import_promises.writeFile)(outPath, entry.getData());
|
|
127
133
|
}
|
|
128
134
|
}
|
|
@@ -155,13 +161,13 @@ async function createModule({ name }) {
|
|
|
155
161
|
throw new Error(`Invalid GitHub repository URL: ${GITHUB_REPO}. It should be in the format`);
|
|
156
162
|
}
|
|
157
163
|
const basePath = useSettings.getPaths().modules;
|
|
158
|
-
const modulePath =
|
|
164
|
+
const modulePath = import_node_path4.default.join(basePath, name);
|
|
159
165
|
await downloadGitHubFolderZip(
|
|
160
166
|
"RetroPeak-Solutions/retrex-extensibles-templates",
|
|
161
167
|
`modules/default`,
|
|
162
168
|
modulePath
|
|
163
169
|
);
|
|
164
|
-
const jsonPath =
|
|
170
|
+
const jsonPath = import_node_path4.default.join(modulePath, "module.json");
|
|
165
171
|
const json = {
|
|
166
172
|
name,
|
|
167
173
|
lowerName: name.toLowerCase()
|
|
@@ -175,19 +181,19 @@ async function createModule({ name }) {
|
|
|
175
181
|
}
|
|
176
182
|
|
|
177
183
|
// src/commands/createService.ts
|
|
178
|
-
var
|
|
184
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
179
185
|
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
180
186
|
async function createService({ name }) {
|
|
181
187
|
console.log(import_chalk2.default.cyan(`Creating service "${name}"...`));
|
|
182
188
|
try {
|
|
183
189
|
const basePath = useSettings.getPaths().services;
|
|
184
|
-
const servicePath =
|
|
190
|
+
const servicePath = import_node_path5.default.join(basePath, name);
|
|
185
191
|
await downloadGitHubFolderZip(
|
|
186
192
|
"RetroPeak-Solutions/retrex-extensibles-templates",
|
|
187
193
|
`services/default`,
|
|
188
194
|
servicePath
|
|
189
195
|
);
|
|
190
|
-
const jsonPath =
|
|
196
|
+
const jsonPath = import_node_path5.default.join(servicePath, "service.json");
|
|
191
197
|
const json = {
|
|
192
198
|
name,
|
|
193
199
|
lowerName: name.toLowerCase()
|
|
@@ -201,7 +207,7 @@ async function createService({ name }) {
|
|
|
201
207
|
}
|
|
202
208
|
|
|
203
209
|
// src/commands/createTemplate.ts
|
|
204
|
-
var
|
|
210
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
205
211
|
var import_chalk3 = __toESM(require("chalk"), 1);
|
|
206
212
|
async function createTemplate({
|
|
207
213
|
type,
|
|
@@ -221,7 +227,7 @@ async function createTemplate({
|
|
|
221
227
|
}
|
|
222
228
|
const paths = useSettings.getPaths();
|
|
223
229
|
const basePath = paths.templates;
|
|
224
|
-
const fullPath =
|
|
230
|
+
const fullPath = import_node_path6.default.join(basePath, type, name);
|
|
225
231
|
console.log(import_chalk3.default.cyan(`Downloading ${type} template "${name}" from ${repoUrl}`));
|
|
226
232
|
await downloadGitHubFolderZip(
|
|
227
233
|
repoUrl,
|
package/dist/cmds.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cmds.ts","../src/commands/createModule.ts","../src/core/hooks/useSettings.ts","../src/core/hooks/useExtensibles.ts","../src/utils/github.ts","../src/utils/files.ts","../src/commands/createService.ts","../src/commands/createTemplate.ts","../src/commands/compile.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { createModule } from '@cmds/createModule';\nimport { createService } from '@cmds/createService';\nimport { createTemplate } from '@cmds/createTemplate';\nimport { compileExtensible, CompileOptionsType } from '@cmds/compile';\n\nyargs(hideBin(process.argv))\n .command(\n 'create-module <name>',\n 'Create a new extensible module',\n (yargs) => yargs.positional('name', { type: 'string', describe: 'Module name' }),\n async (argv) => await createModule({ name: argv.name as string })\n )\n .command(\n 'create-service <name>',\n 'Create a new extensible service',\n (yargs) => yargs.positional('name', { type: 'string', describe: 'Service name' }),\n async (argv) => await createService({ name: argv.name as string })\n )\n .command(\n 'create-template <type> <name>',\n 'Create a new template',\n (yargs) =>\n yargs\n .positional('type', {\n type: 'string',\n describe: 'Template type',\n choices: ['admin', 'client', 'portal', 'email']\n })\n .positional('name', { type: 'string', describe: 'Template name' }),\n async (argv) => await createTemplate({ type: argv.type as any, name: argv.name as string })\n )\n .command(\n 'compile <type> <name>',\n 'Compiles an Extensible for Production',\n (yargs) =>\n yargs\n .positional('type', {\n type: 'string',\n describe: 'Template type',\n choices: ['module', 'service', 'admin-theme', 'client-theme', 'portal', 'email']\n })\n .positional('name', { type: 'string', describe: 'Extensible name' }),\n async (argv) => await compileExtensible({ type: argv.type as CompileOptionsType, name: argv.name as string })\n )\n .demandCommand(1, 'You need to specify a command [create-module, create-service, create-template, compile]')\n .help().argv;","import path from 'node:path';\nimport { useSettings } from '!/core/hooks/useSettings';\nimport chalk from 'chalk';\nimport { downloadGitHubFolderZip } from '../utils/github.js';\nimport { writeJson } from '../utils/files.js';\n\nconst GITHUB_REPO = process.env.RETREX_TEMPLATE_REPO || 'https://github.com/RetroPeak-Solutions/retrex-extensibles-templates';\n\ninterface Options {\n name: string;\n}\nexport async function createModule({ name }: Options) {\n console.log(chalk.cyan(`Creating module \"${name}\"...`));\n try {\n if (!name) {\n throw new Error('Module name is required.');\n }\n\n // Ensure the name is valid\n if (!/^[a-zA-Z0-9-_]+$/.test(name)) {\n throw new Error(`Invalid module name: \"${name}\". Only alphanumeric characters, dashes, and underscores are allowed.`);\n }\n\n // Ensure the repo URL is valid\n if (!/^https:\\/\\/github\\.com\\/[a-zA-Z0-9-_]+\\/[a-zA-Z0-9-_]+$/.test(GITHUB_REPO)) {\n throw new Error(`Invalid GitHub repository URL: ${GITHUB_REPO}. It should be in the format`);\n }\n const basePath = useSettings.getPaths().modules;\n const modulePath = path.join(basePath, name);\n\n await downloadGitHubFolderZip(\n 'RetroPeak-Solutions/retrex-extensibles-templates',\n `modules/default`,\n modulePath\n );\n\n const jsonPath = path.join(modulePath, 'module.json');\n const json = {\n name,\n lowerName: name.toLowerCase()\n };\n\n await writeJson(jsonPath, json);\n console.log(chalk.green(`[Module Created] ${name} created at ${modulePath}`));\n } catch (error: any) {\n console.error(chalk.red(`[Module Creation | Error] Failed to create module: ${error.message}`));\n throw error;\n }\n}","// src/hooks/useSettings.ts\n\nimport path from 'node:path';\nimport fs from 'node:fs';\n\nimport { loadJSON, saveJSON } from './useExtensibles';\nimport type { ExtensiblePaths } from '../types'; // Adjust the import path as necessary\n\nconst defaultPaths: ExtensiblePaths = {\n modules: './app/modules',\n templates: './app/resources/themes',\n services: './app/services',\n events: './app/events',\n langs: './public/langs',\n providers: './app/providers',\n};\n\nlet extensiblePaths: ExtensiblePaths = { ...defaultPaths };\nconst isServer = typeof window === 'undefined';\n\n\nexport const useSettings = {\n getPaths(): ExtensiblePaths {\n if (isServer) {\n const json = loadJSON('./app/extensiblePaths.json');\n if (json) extensiblePaths = json;\n }\n\n if (isServer) {\n for (const key of Object.keys(defaultPaths) as Array<keyof ExtensiblePaths>) {\n const candidate = extensiblePaths[key];\n if (!candidate || !fs.existsSync(candidate)) {\n extensiblePaths[key] = defaultPaths[key];\n }\n }\n }\n\n extensiblePaths = {\n ...extensiblePaths,\n langs: './langs',\n };\n // extensiblePaths = loadJSON(\"./app/extensiblePaths.json\");\n return extensiblePaths;\n },\n\n setPaths(paths: Partial<ExtensiblePaths>): void {\n if (isServer) {\n saveJSON('./app/extensiblePaths.json', {\n ...extensiblePaths,\n ...paths,\n });\n }\n\n extensiblePaths = {\n ...extensiblePaths,\n ...paths,\n };\n },\n \n getKeyValue(key: string): string {\n return 'Coming Soon'\n },\n setKeyValue(key: string, value: string): void {\n return;\n },\n};\n","// src/hooks/useExtensibles.ts\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { useSettings } from './useSettings';\nimport type { TemplateType, ExtensibleMeta, ExtensiblePaths } from '../types';\n\nlet paths: ExtensiblePaths;\n\nfunction toFileUrl(filePath: string): string {\n const normalized = filePath.replace(/\\\\/g, '/');\n if (normalized.startsWith('file://')) return normalized;\n const prefix = normalized.startsWith('/') ? 'file://' : 'file:///';\n return `${prefix}${encodeURI(normalized)}`;\n}\n\nexport function registerExtensibles(extensiblePaths: ExtensiblePaths) {\n paths = extensiblePaths;\n}\n\nexport function loadJSON(filePath: string): any {\n if (!fs.existsSync(filePath)) return null;\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n}\n\nexport function saveJSON(filePath: string, data: any) {\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\n// --- MODULES ---\n\nexport function getModules(): ExtensibleMeta[] {\n if (!useSettings.getPaths().modules) throw new Error('Modules path not registered.');\n\n const dirs = fs\n .readdirSync(useSettings.getPaths().modules)\n .filter((d: any) => fs.statSync(path.join(useSettings.getPaths().modules, d)).isDirectory());\n\n return dirs.map((dir: any) => {\n const meta = loadJSON(path.join(useSettings.getPaths().modules, dir, 'module.json')) || {};\n return {\n name: meta.name || dir,\n lowerName: meta.lowerName || dir.toLowerCase(),\n version: meta.version,\n description: meta.description,\n author: meta.author,\n icon: meta.icon,\n enabled: meta.enabled ?? false,\n };\n });\n}\n\nexport function isModuleEnabled(name: string) {\n const modules = getModules();\n return modules.find((m) => m.lowerName === name.toLowerCase())?.enabled ?? false;\n}\n\nexport function toggleModule(name: string, enabled: boolean) {\n const modules = getModules();\n const mod = modules.find((m) => m.lowerName === name.toLowerCase());\n if (!mod) throw new Error(`Module ${name} not found`);\n\n const metaPath = path.join(useSettings.getPaths().modules, mod.lowerName, 'module.json');\n const meta = loadJSON(metaPath) || {};\n meta.enabled = enabled;\n saveJSON(metaPath, meta);\n\n if (enabled) onModuleEnabled(mod.name);\n else onModuleDisabled(mod.name);\n}\n\n// --- SERVICES ---\n\nexport function getServices(): ExtensibleMeta[] {\n if (!useSettings.getPaths().services) throw new Error('Services path not registered.');\n\n const dirs = fs\n .readdirSync(useSettings.getPaths().services)\n .filter((d: any) => fs.statSync(path.join(useSettings.getPaths().services, d)).isDirectory());\n\n return dirs.map((dir: any) => {\n const meta = loadJSON(path.join(useSettings.getPaths().services, dir, 'service.json')) || {};\n return {\n name: meta.name || dir,\n lowerName: meta.lowerName || dir.toLowerCase(),\n version: meta.version,\n description: meta.description,\n author: meta.author,\n icon: meta.icon,\n enabled: meta.enabled ?? false,\n };\n });\n}\n\nexport function isServiceEnabled(name: string) {\n const services = getServices();\n return services.find((s) => s.lowerName === name.toLowerCase())?.enabled ?? false;\n}\n\nexport function toggleService(name: string, enabled: boolean) {\n const services = getServices();\n const svc = services.find((s) => s.lowerName === name.toLowerCase());\n if (!svc) throw new Error(`Service ${name} not found`);\n\n const metaPath = path.join(useSettings.getPaths().services, svc.lowerName, 'service.json');\n const meta = loadJSON(metaPath) || {};\n meta.enabled = enabled;\n saveJSON(metaPath, meta);\n\n if (enabled) onServiceEnabled(svc.name);\n else onServiceDisabled(svc.name);\n}\n\n// --- TEMPLATES ---\n\n// Helper to get base path for a template type\nfunction getTemplateBasePath(type: TemplateType): string {\n if (!useSettings.getPaths().templates) throw new Error('Templates path not registered.');\n switch (type) {\n case 'admin-theme':\n case 'client-theme':\n return path.join(useSettings.getPaths().templates, 'themes');\n case 'portal':\n return path.join(useSettings.getPaths().templates, 'portals');\n case 'email':\n return path.join(useSettings.getPaths().templates, 'emails');\n default:\n throw new Error(`Unknown template type: ${type}`);\n }\n}\n\nexport function getTemplates(type: TemplateType): ExtensibleMeta[] {\n const basePath = getTemplateBasePath(type);\n if (!fs.existsSync(basePath)) return [];\n\n const dirs = fs\n .readdirSync(basePath)\n .filter((d: any) => fs.statSync(path.join(basePath, d)).isDirectory());\n\n return dirs.map((dir: any) => {\n const meta = loadJSON(path.join(basePath, dir, 'template.json')) || {};\n return {\n name: meta.name || dir,\n lowerName: dir.toLowerCase(),\n version: meta.version,\n description: meta.description,\n author: meta.author,\n icon: meta.icon,\n enabled: meta.enabled ?? false,\n };\n });\n}\n\nexport function isTemplateActive(type: TemplateType, name: string) {\n const templates = getTemplates(type);\n return templates.find((t) => t.lowerName === name.toLowerCase())?.enabled ?? false;\n}\n\n// Toggle templates: only 1 active per type allowed\nexport function toggleTemplate(type: TemplateType, name: string) {\n const templates = getTemplates(type);\n\n templates.forEach((tpl) => {\n const metaPath = path.join(getTemplateBasePath(type), tpl.lowerName, 'template.json');\n const meta = loadJSON(metaPath) || {};\n meta.enabled = tpl.lowerName === name.toLowerCase();\n saveJSON(metaPath, meta);\n });\n\n onTemplateSelect(type, name);\n}\n\n// --- EVENTS (replace with your event system integration) ---\n\nexport function onModuleEnabled(name: string) {\n console.log(`Module enabled: ${name}`);\n // emit event or custom logic here\n}\n\nexport function onModuleDisabled(name: string) {\n console.log(`Module disabled: ${name}`);\n}\n\nexport function onServiceEnabled(name: string) {\n console.log(`Service enabled: ${name}`);\n}\n\nexport function onServiceDisabled(name: string) {\n console.log(`Service disabled: ${name}`);\n}\n\nexport function onTemplateSelect(type: TemplateType, name: string) {\n console.log(`Template selected: type=${type}, name=${name}`);\n}\n\n// --- REGISTER HOOKS FOR MODULES ---\n\nexport async function registerEvents() {\n if (!useSettings.getPaths().modules) throw new Error('Modules path not registered.');\n const modules = getModules().filter((m) => m.enabled);\n for (const mod of modules) {\n const eventsFile = path.join(useSettings.getPaths().modules, mod.lowerName, 'events.server.js');\n if (fs.existsSync(eventsFile)) {\n const modEvents = await import(eventsFile);\n if (modEvents?.registerEvents) await modEvents.registerEvents();\n }\n }\n}\n\nexport async function registerMiddleware() {\n if (!useSettings.getPaths().modules) throw new Error('Modules path not registered.');\n const modules = getModules().filter((m) => m.enabled);\n for (const mod of modules) {\n const middlewareFile = path.join(useSettings.getPaths().modules, mod.lowerName, 'middleware.server.js');\n if (fs.existsSync(middlewareFile)) {\n const modMiddleware = await import(middlewareFile);\n if (modMiddleware?.registerMiddleware) await modMiddleware.registerMiddleware();\n }\n }\n}\n\n/**\n * Registers routes given a path to routes folder (for pages and API routes)\n * @param routesFolderPath string - path to module/service routes folder\n */\nexport async function registerRoutes(routesFolderPath: string) {\n if (!fs.existsSync(routesFolderPath)) return;\n\n const routeFiles = fs.readdirSync(routesFolderPath).filter((f: any) => /\\.(js|ts|jsx|tsx)$/.test(f));\n for (const file of routeFiles) {\n const routeModule = await import(path.join(routesFolderPath, file));\n if (routeModule?.registerRoute) {\n await routeModule.registerRoute();\n }\n }\n}\n\nexport async function loadProviders() {\n const paths = useSettings.getPaths();\n\n const all = [\n { type: 'module', list: getModules(), basePath: paths.modules },\n { type: 'service', list: getServices(), basePath: paths.services },\n ];\n\n for (const { type, list, basePath } of all) {\n for (const item of list) {\n if (!item.enabled) continue;\n\n const metaPath = path.join(path.resolve(basePath), item.lowerName, `${type}.json`);\n const meta = loadJSON(metaPath);\n if (!meta?.providers || !Array.isArray(meta.providers)) continue;\n\n for (const providerRelPath of meta.providers) {\n try {\n let providerAbsPath = path.join(path.resolve(basePath), item.lowerName, providerRelPath);\n\n // Try .js fallback if file is .ts or .tsx\n const ext = path.extname(providerAbsPath);\n if (ext === '.ts' || ext === '.tsx') {\n const jsPath = providerAbsPath.replace(/\\.(ts|tsx)$/, '.js');\n try {\n await fs.accessSync(jsPath); // Check if compiled JS file exists\n providerAbsPath = jsPath;\n } catch {\n throw new Error(`Compiled JS version not found for provider: ${providerRelPath}`);\n }\n }\n\n const providerUrl = toFileUrl(providerAbsPath);\n const providerModule = await import(providerUrl);\n\n if (typeof providerModule.default === 'function') {\n // Expose context so nav registration can auto-tag module/service\n (globalThis as any).__retrex_provider_context__ = {\n type,\n name: item.lowerName,\n };\n await providerModule.default();\n (globalThis as any).__retrex_provider_context__ = undefined;\n console.log(`[${type}] ✅ Provider loaded: ${providerRelPath}`);\n } else {\n console.warn(`[${type}] ⚠️ Provider ${providerRelPath} has no default export.`);\n }\n } catch (err) {\n console.error(`[${type}] ❌ Failed to load provider ${providerRelPath}:`, err);\n }\n }\n }\n }\n}\n\n\n// export async function loadProviders() {\n// paths = {\n// modules: useSettings.getPaths().modules,\n// templates: useSettings.getPaths().templates,\n// services: useSettings.getPaths().services,\n// events: useSettings.getPaths().events,\n// }\n// const all = [\n// { type: 'module', list: getModules(), basePath: useSettings.getPaths().modules },\n// { type: 'service', list: getServices(), basePath: useSettings.getPaths().services },\n// ];\n\n// for (const { type, list, basePath } of all) {\n// for (const item of list) {\n// if (!item.enabled) continue;\n\n// const metaPath = path.join(basePath, item.lowerName, `${type}.json`);\n// const meta = loadJSON(metaPath);\n// if (!meta?.providers || !Array.isArray(meta.providers)) continue;\n\n// for (const providerRelPath of meta.providers) {\n// try {\n// const providerPath = path.join(basePath, item.lowerName, providerRelPath);\n// const providerModule = await import(providerPath);\n// if (typeof providerModule.default === 'function') {\n// await providerModule.default(); // Call provider\n// console.log(`[${type}] Provider loaded: ${providerRelPath}`);\n// } else {\n// console.warn(`[${type}] Provider ${providerRelPath} has no default export.`);\n// }\n// } catch (err) {\n// console.error(`[${type}] Failed to load provider ${providerRelPath}:`, err);\n// }\n// }\n// }\n// }\n// }\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\nimport AdmZip from 'adm-zip';\n\nexport async function downloadGitHubFolderZip(\n repo: string,\n folderPath: string,\n dest: string\n) {\n try {\n const [owner, repoName] = repo.split('/');\n const branch = 'main';\n const zipUrl = `https://github.com/${owner}/${repoName}/archive/refs/heads/${branch}.zip`;\n\n const res = await fetch(zipUrl);\n if (!res.ok) throw new Error(`Failed to fetch from GitHub: ${res.status}`);\n\n const buffer = Buffer.from(await res.arrayBuffer());\n const zip = new AdmZip(buffer);\n\n const prefix = `${repoName}-${branch}/${folderPath}`;\n\n const zipEntries = zip.getEntries();\n\n await mkdir(dest, { recursive: true });\n\n for (const entry of zipEntries) {\n if (!entry.entryName.startsWith(prefix)) continue;\n\n const relativePath = entry.entryName.slice(prefix.length + 1);\n if (!relativePath) continue; // skip the folder root\n\n const outPath = path.join(dest, relativePath);\n\n if (entry.isDirectory) {\n await mkdir(outPath, { recursive: true });\n } else {\n await mkdir(path.dirname(outPath), { recursive: true });\n await writeFile(outPath, entry.getData());\n }\n }\n\n console.log(`✓ Extracted ${folderPath} from ${repo} to ${dest}`);\n } catch (error: any) {\n console.error('[Github Download | Error]', error);\n console.error(`[Github Download | Error] Error downloading GitHub folder: ${error.message}`);\n throw new Error(`[Github Download | Error] Failed to download folder from github repo: ${error.message}`);\n }\n}\n","import { mkdir, writeFile, readFile, rm, access } from 'node:fs/promises';\n\nexport async function ensureDir(dirPath: string) {\n try {\n await mkdir(dirPath, { recursive: true });\n } catch {}\n}\n\nexport async function writeJson(filePath: string, data: any) {\n await writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\nexport async function readJson(filePath: string) {\n const content = await readFile(filePath, 'utf-8');\n return JSON.parse(content);\n}\n\nexport async function deleteDir(dirPath: string) {\n await rm(dirPath, { recursive: true, force: true });\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n","import path from 'node:path';\nimport { useSettings } from '!/core/hooks/useSettings';\nimport { downloadGitHubFolderZip } from '../utils/github';\nimport { writeJson } from '../utils/files';\nimport chalk from 'chalk';\n\ninterface Options {\n name: string;\n}\n\nexport async function createService({ name }: Options) {\n console.log(chalk.cyan(`Creating service \"${name}\"...`));\n try {\n const basePath = useSettings.getPaths().services;\n const servicePath = path.join(basePath, name);\n\n await downloadGitHubFolderZip(\n 'RetroPeak-Solutions/retrex-extensibles-templates',\n `services/default`,\n servicePath\n );\n\n const jsonPath = path.join(servicePath, 'service.json');\n const json = {\n name,\n lowerName: name.toLowerCase()\n };\n\n await writeJson(jsonPath, json);\n console.log(chalk.green(`[Service Created] ${name} created at ${servicePath}`));\n } catch (error: any) {\n console.error(chalk.red(`[Service Creation | Error] Failed to create service: ${error.message}`));\n throw error;\n }\n}","import path from 'node:path';\nimport { useSettings } from '!/core/hooks/useSettings';\nimport chalk from 'chalk';\nimport { downloadGitHubFolderZip } from '../utils/github.js';\nimport { writeJson } from '../utils/files.js';\n\nexport type TemplateTypeCLI = 'admin' | 'client' | 'portal' | 'email';\n\ninterface CreateTemplateOptions {\n type: TemplateTypeCLI;\n name: string;\n repoUrl?: string; // optional override for GitHub template repo\n}\n\nexport async function createTemplate({\n type,\n name,\n repoUrl = 'RetroPeak-Solutions/retrex-extensibles-templates'\n}: CreateTemplateOptions) {\n console.log(chalk.cyan(`Creating ${type} template \"${name}\"...`));\n try {\n if (!['admin', 'client', 'portal', 'email'].includes(type)) {\n throw new Error(`Invalid template type: ${type}. Valid types are: admin, client, portal, email.`);\n }\n\n if (!name) {\n throw new Error('Template name is required.');\n }\n\n // Ensure the name is valid\n if (!/^[a-zA-Z0-9-_]+$/.test(name)) {\n throw new Error(`Invalid template name: \"${name}\". Only alphanumeric characters, dashes, and underscores are allowed.`);\n }\n\n // // Ensure the repo URL is valid\n // if (!/^https:\\/\\/github\\.com\\/[a-zA-Z0-9-_]+\\/[a-zA-Z0-9-_]+$/.test(repoUrl)) {\n // throw new Error(`Invalid GitHub repository URL: ${repoUrl}. It should be in the format `);\n // }\n\n const paths = useSettings.getPaths();\n const basePath = paths.templates;\n\n const fullPath = path.join(basePath, type, name);\n\n console.log(chalk.cyan(`Downloading ${type} template \"${name}\" from ${repoUrl}`));\n\n await downloadGitHubFolderZip(\n repoUrl,\n `themes/${type}/default`, // assumes folder structure matches repo layout\n fullPath\n );\n\n // const jsonPath = path.join(fullPath, `template.json`);\n // await writeJson(jsonPath, {\n // name,\n // lowerName: name.toLowerCase()\n // });\n\n console.log(chalk.green(`[Template Created] ${type} template \"${name}\" created at ${fullPath}`));\n } catch (error: any) {\n console.error(chalk.red(`[Template Creation | Error] Failed to create template: ${error.message}`));\n throw error;\n }\n}","import { build } from 'esbuild';\nimport fg from 'fast-glob';\nimport chalk from 'chalk';\nimport { useSettings } from '!/core/hooks/useSettings';\n\nexport type CompileOptionsType =\n | 'module'\n | 'service'\n | 'admin-theme'\n | 'client-theme'\n | 'portal'\n | 'email';\n\ninterface CompileOptions {\n type: CompileOptionsType;\n name: string;\n}\n\nfunction join(...segments: string[]) {\n return segments.join('/').replace(/\\/+/g, '/');\n}\n\nexport async function compileExtensible({ type, name }: CompileOptions) {\n try {\n console.log(chalk.cyan(`Compiling ${type} files for ${name}`));\n\n const patterns: string[] = [];\n const paths = useSettings.getPaths();\n\n if (type && name) {\n let basePath = '';\n let subPath = '';\n\n if (type !== 'client-theme' && type !== 'admin-theme') {\n // @ts-ignore\n basePath = paths[`${type}s`];\n patterns.push(join(basePath, name, '**/*.ts'));\n patterns.push(join(basePath, name, '**/*.tsx'));\n } else {\n basePath = paths.templates;\n subPath = type === 'client-theme' ? 'client' : 'admin';\n patterns.push(join(basePath, subPath, name, '**/*.ts'));\n patterns.push(join(basePath, subPath, name, '**/*.tsx'));\n }\n } else {\n patterns.push(join(paths.modules, '**/**/*.ts'));\n patterns.push(join(paths.modules, '**/**/*.tsx'));\n patterns.push(join(paths.services, '**/**/*.ts'));\n patterns.push(join(paths.services, '**/**/*.tsx'));\n patterns.push(join(paths.templates, '**/**/*.ts'));\n patterns.push(join(paths.templates, '**/**/*.tsx'));\n }\n\n const files = await fg(patterns, {\n ignore: ['**/*.test.ts', '**/*.test.tsx'],\n });\n\n for (const file of files) {\n const outFile = file.replace(/\\.(ts|tsx)$/, '.js');\n\n await build({\n entryPoints: [file],\n outfile: outFile,\n format: 'esm',\n platform: 'node',\n target: 'node20',\n sourcemap: true,\n bundle: false,\n loader: {\n '.ts': 'ts',\n '.tsx': 'tsx',\n },\n external: ['fs', 'path', 'node:fs', 'node:path'],\n }).catch((error) => {\n console.error(\n chalk.redBright(\n `[Compiler | Error] Failed to compile ${file}: ${error.message}`\n )\n );\n throw error;\n });\n\n console.log(chalk.blue(`✓ Compiled ${file}`));\n }\n\n console.log(chalk.green(`[Compiler | Success] ✓ Compilation finished.`));\n } catch (e: any) {\n console.error(\n chalk.redBright(\n '[Compiler | Error] Failed to Complete the Compile Process:',\n e?.message\n )\n );\n }\n}\n"],"mappings":"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","names":["import_node_path","import_node_fs","fs","fs","import_node_path","AdmZip","path","import_promises","chalk","path","import_node_path","import_chalk","chalk","path","import_node_path","import_chalk","chalk","path","import_chalk","chalk","fg","yargs"]}
|
|
1
|
+
{"version":3,"sources":["../src/cmds.ts","../src/commands/createModule.ts","../src/core/hooks/useSettings.ts","../src/core/hooks/useExtensibles.ts","../src/core/hooks/useProviders.ts","../src/utils/github.ts","../src/utils/files.ts","../src/commands/createService.ts","../src/commands/createTemplate.ts","../src/commands/compile.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { createModule } from '@cmds/createModule';\nimport { createService } from '@cmds/createService';\nimport { createTemplate } from '@cmds/createTemplate';\nimport { compileExtensible, CompileOptionsType } from '@cmds/compile';\n\nyargs(hideBin(process.argv))\n .command(\n 'create-module <name>',\n 'Create a new extensible module',\n (yargs) => yargs.positional('name', { type: 'string', describe: 'Module name' }),\n async (argv) => await createModule({ name: argv.name as string })\n )\n .command(\n 'create-service <name>',\n 'Create a new extensible service',\n (yargs) => yargs.positional('name', { type: 'string', describe: 'Service name' }),\n async (argv) => await createService({ name: argv.name as string })\n )\n .command(\n 'create-template <type> <name>',\n 'Create a new template',\n (yargs) =>\n yargs\n .positional('type', {\n type: 'string',\n describe: 'Template type',\n choices: ['admin', 'client', 'portal', 'email']\n })\n .positional('name', { type: 'string', describe: 'Template name' }),\n async (argv) => await createTemplate({ type: argv.type as any, name: argv.name as string })\n )\n .command(\n 'compile <type> <name>',\n 'Compiles an Extensible for Production',\n (yargs) =>\n yargs\n .positional('type', {\n type: 'string',\n describe: 'Template type',\n choices: ['module', 'service', 'admin-theme', 'client-theme', 'portal', 'email']\n })\n .positional('name', { type: 'string', describe: 'Extensible name' }),\n async (argv) => await compileExtensible({ type: argv.type as CompileOptionsType, name: argv.name as string })\n )\n .demandCommand(1, 'You need to specify a command [create-module, create-service, create-template, compile]')\n .help().argv;","import path from 'node:path';\nimport { useSettings } from '!/core/hooks/useSettings';\nimport chalk from 'chalk';\nimport { downloadGitHubFolderZip } from '../utils/github.js';\nimport { writeJson } from '../utils/files.js';\n\nconst GITHUB_REPO = process.env.RETREX_TEMPLATE_REPO || 'https://github.com/RetroPeak-Solutions/retrex-extensibles-templates';\n\ninterface Options {\n name: string;\n}\nexport async function createModule({ name }: Options) {\n console.log(chalk.cyan(`Creating module \"${name}\"...`));\n try {\n if (!name) {\n throw new Error('Module name is required.');\n }\n\n // Ensure the name is valid\n if (!/^[a-zA-Z0-9-_]+$/.test(name)) {\n throw new Error(`Invalid module name: \"${name}\". Only alphanumeric characters, dashes, and underscores are allowed.`);\n }\n\n // Ensure the repo URL is valid\n if (!/^https:\\/\\/github\\.com\\/[a-zA-Z0-9-_]+\\/[a-zA-Z0-9-_]+$/.test(GITHUB_REPO)) {\n throw new Error(`Invalid GitHub repository URL: ${GITHUB_REPO}. It should be in the format`);\n }\n const basePath = useSettings.getPaths().modules;\n const modulePath = path.join(basePath, name);\n\n await downloadGitHubFolderZip(\n 'RetroPeak-Solutions/retrex-extensibles-templates',\n `modules/default`,\n modulePath\n );\n\n const jsonPath = path.join(modulePath, 'module.json');\n const json = {\n name,\n lowerName: name.toLowerCase()\n };\n\n await writeJson(jsonPath, json);\n console.log(chalk.green(`[Module Created] ${name} created at ${modulePath}`));\n } catch (error: any) {\n console.error(chalk.red(`[Module Creation | Error] Failed to create module: ${error.message}`));\n throw error;\n }\n}","// src/hooks/useSettings.ts\n\nimport path from 'node:path';\nimport fs from 'node:fs';\n\nimport { loadJSON, saveJSON } from './useExtensibles';\nimport type { ExtensiblePaths } from '../types'; // Adjust the import path as necessary\n\nconst defaultPaths: ExtensiblePaths = {\n modules: './app/modules',\n templates: './app/resources/themes',\n services: './app/services',\n events: './app/events',\n langs: './public/langs',\n providers: './app/providers',\n};\n\nlet extensiblePaths: ExtensiblePaths = { ...defaultPaths };\nconst isServer = typeof window === 'undefined';\n\n\nexport const useSettings = {\n getPaths(): ExtensiblePaths {\n if (isServer) {\n const json = loadJSON('./app/extensiblePaths.json');\n if (json) extensiblePaths = json;\n }\n\n if (isServer) {\n for (const key of Object.keys(defaultPaths) as Array<keyof ExtensiblePaths>) {\n const candidate = extensiblePaths[key];\n if (!candidate || !fs.existsSync(candidate)) {\n extensiblePaths[key] = defaultPaths[key];\n }\n }\n }\n\n extensiblePaths = {\n ...extensiblePaths,\n langs: './langs',\n };\n // extensiblePaths = loadJSON(\"./app/extensiblePaths.json\");\n return extensiblePaths;\n },\n\n setPaths(paths: Partial<ExtensiblePaths>): void {\n if (isServer) {\n saveJSON('./app/extensiblePaths.json', {\n ...extensiblePaths,\n ...paths,\n });\n }\n\n extensiblePaths = {\n ...extensiblePaths,\n ...paths,\n };\n },\n \n getKeyValue(key: string): string {\n return 'Coming Soon'\n },\n setKeyValue(key: string, value: string): void {\n return;\n },\n};\n","// src/hooks/useExtensibles.ts\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { useSettings } from './useSettings';\nimport { useProviders } from './useProviders';\nimport type { TemplateType, ExtensibleMeta, ExtensiblePaths } from '../types';\n\nlet paths: ExtensiblePaths;\n\nfunction toFileUrl(filePath: string): string {\n const normalized = filePath.replace(/\\\\/g, '/');\n if (normalized.startsWith('file://')) return normalized;\n const prefix = normalized.startsWith('/') ? 'file://' : 'file:///';\n return `${prefix}${encodeURI(normalized)}`;\n}\n\nexport function registerExtensibles(extensiblePaths: ExtensiblePaths) {\n paths = extensiblePaths;\n}\n\nexport function loadJSON(filePath: string): any {\n if (!fs.existsSync(filePath)) return null;\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n}\n\nexport function saveJSON(filePath: string, data: any) {\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\n// --- MODULES ---\n\nexport function getModules(): ExtensibleMeta[] {\n if (!useSettings.getPaths().modules) throw new Error('Modules path not registered.');\n\n const dirs = fs\n .readdirSync(useSettings.getPaths().modules)\n .filter((d: any) => fs.statSync(path.join(useSettings.getPaths().modules, d)).isDirectory());\n\n return dirs.map((dir: any) => {\n const meta = loadJSON(path.join(useSettings.getPaths().modules, dir, 'module.json')) || {};\n return {\n name: meta.name || dir,\n lowerName: meta.lowerName || dir.toLowerCase(),\n version: meta.version,\n description: meta.description,\n author: meta.author,\n icon: meta.icon,\n enabled: meta.enabled ?? false,\n };\n });\n}\n\nexport function isModuleEnabled(name: string) {\n const modules = getModules();\n return modules.find((m) => m.lowerName === name.toLowerCase())?.enabled ?? false;\n}\n\nexport function toggleModule(name: string, enabled: boolean) {\n const modules = getModules();\n const mod = modules.find((m) => m.lowerName === name.toLowerCase());\n if (!mod) throw new Error(`Module ${name} not found`);\n\n const metaPath = path.join(useSettings.getPaths().modules, mod.lowerName, 'module.json');\n const meta = loadJSON(metaPath) || {};\n meta.enabled = enabled;\n saveJSON(metaPath, meta);\n\n if (enabled) onModuleEnabled(mod.name);\n else onModuleDisabled(mod.name);\n}\n\n// --- SERVICES ---\n\nexport function getServices(): ExtensibleMeta[] {\n if (!useSettings.getPaths().services) throw new Error('Services path not registered.');\n\n const dirs = fs\n .readdirSync(useSettings.getPaths().services)\n .filter((d: any) => fs.statSync(path.join(useSettings.getPaths().services, d)).isDirectory());\n\n return dirs.map((dir: any) => {\n const meta = loadJSON(path.join(useSettings.getPaths().services, dir, 'service.json')) || {};\n return {\n name: meta.name || dir,\n lowerName: meta.lowerName || dir.toLowerCase(),\n version: meta.version,\n description: meta.description,\n author: meta.author,\n icon: meta.icon,\n enabled: meta.enabled ?? false,\n };\n });\n}\n\nexport function isServiceEnabled(name: string) {\n const services = getServices();\n return services.find((s) => s.lowerName === name.toLowerCase())?.enabled ?? false;\n}\n\nexport function toggleService(name: string, enabled: boolean) {\n const services = getServices();\n const svc = services.find((s) => s.lowerName === name.toLowerCase());\n if (!svc) throw new Error(`Service ${name} not found`);\n\n const metaPath = path.join(useSettings.getPaths().services, svc.lowerName, 'service.json');\n const meta = loadJSON(metaPath) || {};\n meta.enabled = enabled;\n saveJSON(metaPath, meta);\n\n if (enabled) onServiceEnabled(svc.name);\n else onServiceDisabled(svc.name);\n}\n\n// --- TEMPLATES ---\n\n// Helper to get base path for a template type\nfunction getTemplateBasePath(type: TemplateType): string {\n if (!useSettings.getPaths().templates) throw new Error('Templates path not registered.');\n switch (type) {\n case 'admin-theme':\n case 'client-theme':\n return path.join(useSettings.getPaths().templates, 'themes');\n case 'portal':\n return path.join(useSettings.getPaths().templates, 'portals');\n case 'email':\n return path.join(useSettings.getPaths().templates, 'emails');\n default:\n throw new Error(`Unknown template type: ${type}`);\n }\n}\n\nexport function getTemplates(type: TemplateType): ExtensibleMeta[] {\n const basePath = getTemplateBasePath(type);\n if (!fs.existsSync(basePath)) return [];\n\n const dirs = fs\n .readdirSync(basePath)\n .filter((d: any) => fs.statSync(path.join(basePath, d)).isDirectory());\n\n return dirs.map((dir: any) => {\n const meta = loadJSON(path.join(basePath, dir, 'template.json')) || {};\n return {\n name: meta.name || dir,\n lowerName: dir.toLowerCase(),\n version: meta.version,\n description: meta.description,\n author: meta.author,\n icon: meta.icon,\n enabled: meta.enabled ?? false,\n };\n });\n}\n\nexport function isTemplateActive(type: TemplateType, name: string) {\n const templates = getTemplates(type);\n return templates.find((t) => t.lowerName === name.toLowerCase())?.enabled ?? false;\n}\n\n// Toggle templates: only 1 active per type allowed\nexport function toggleTemplate(type: TemplateType, name: string) {\n const templates = getTemplates(type);\n\n templates.forEach((tpl) => {\n const metaPath = path.join(getTemplateBasePath(type), tpl.lowerName, 'template.json');\n const meta = loadJSON(metaPath) || {};\n meta.enabled = tpl.lowerName === name.toLowerCase();\n saveJSON(metaPath, meta);\n });\n\n onTemplateSelect(type, name);\n}\n\n// --- EVENTS (replace with your event system integration) ---\n\nexport function onModuleEnabled(name: string) {\n console.log(`Module enabled: ${name}`);\n // emit event or custom logic here\n}\n\nexport function onModuleDisabled(name: string) {\n console.log(`Module disabled: ${name}`);\n}\n\nexport function onServiceEnabled(name: string) {\n console.log(`Service enabled: ${name}`);\n}\n\nexport function onServiceDisabled(name: string) {\n console.log(`Service disabled: ${name}`);\n}\n\nexport function onTemplateSelect(type: TemplateType, name: string) {\n console.log(`Template selected: type=${type}, name=${name}`);\n}\n\n// --- REGISTER HOOKS FOR MODULES ---\n\nexport async function registerEvents() {\n if (!useSettings.getPaths().modules) throw new Error('Modules path not registered.');\n const modules = getModules().filter((m) => m.enabled);\n for (const mod of modules) {\n const eventsFile = path.join(useSettings.getPaths().modules, mod.lowerName, 'events.server.js');\n if (fs.existsSync(eventsFile)) {\n const modEvents = await import(eventsFile);\n if (modEvents?.registerEvents) await modEvents.registerEvents();\n }\n }\n}\n\nexport async function registerMiddleware() {\n if (!useSettings.getPaths().modules) throw new Error('Modules path not registered.');\n const modules = getModules().filter((m) => m.enabled);\n for (const mod of modules) {\n const middlewareFile = path.join(useSettings.getPaths().modules, mod.lowerName, 'middleware.server.js');\n if (fs.existsSync(middlewareFile)) {\n const modMiddleware = await import(middlewareFile);\n if (modMiddleware?.registerMiddleware) await modMiddleware.registerMiddleware();\n }\n }\n}\n\n/**\n * Registers routes given a path to routes folder (for pages and API routes)\n * @param routesFolderPath string - path to module/service routes folder\n */\nexport async function registerRoutes(routesFolderPath: string) {\n if (!fs.existsSync(routesFolderPath)) return;\n\n const routeFiles = fs.readdirSync(routesFolderPath).filter((f: any) => /\\.(js|ts|jsx|tsx)$/.test(f));\n for (const file of routeFiles) {\n const routeModule = await import(path.join(routesFolderPath, file));\n if (routeModule?.registerRoute) {\n await routeModule.registerRoute();\n }\n }\n}\n\nexport async function loadProviders() {\n const providers = useProviders.getProviders({ enabledOnly: true });\n\n for (const provider of providers) {\n try {\n let providerAbsPath = provider.filePath;\n\n const ext = path.extname(providerAbsPath);\n if (ext === '.ts' || ext === '.tsx') {\n const jsPath = providerAbsPath.replace(/\\.(ts|tsx)$/, '.js');\n try {\n fs.accessSync(jsPath);\n providerAbsPath = jsPath;\n } catch {\n throw new Error(`Compiled JS version not found for provider: ${provider.relativePath}`);\n }\n }\n\n const providerUrl = toFileUrl(providerAbsPath);\n const providerModule = await import(providerUrl);\n\n if (typeof providerModule.default === 'function') {\n (globalThis as any).__retrex_provider_context__ = {\n type: provider.ownerType,\n name: provider.ownerLowerName,\n provider: provider.name,\n tags: provider.tags,\n };\n await providerModule.default();\n (globalThis as any).__retrex_provider_context__ = undefined;\n console.log(\n `[${provider.ownerType}] ✅ Provider loaded: ${provider.name} (${provider.relativePath})`,\n );\n } else {\n console.warn(\n `[${provider.ownerType}] ⚠️ Provider ${provider.relativePath} has no default export.`,\n );\n }\n } catch (err) {\n console.error(\n `[${provider.ownerType}] ❌ Failed to load provider ${provider.relativePath}:`,\n err,\n );\n }\n }\n}\n\n\n// export async function loadProviders() {\n// paths = {\n// modules: useSettings.getPaths().modules,\n// templates: useSettings.getPaths().templates,\n// services: useSettings.getPaths().services,\n// events: useSettings.getPaths().events,\n// }\n// const all = [\n// { type: 'module', list: getModules(), basePath: useSettings.getPaths().modules },\n// { type: 'service', list: getServices(), basePath: useSettings.getPaths().services },\n// ];\n\n// for (const { type, list, basePath } of all) {\n// for (const item of list) {\n// if (!item.enabled) continue;\n\n// const metaPath = path.join(basePath, item.lowerName, `${type}.json`);\n// const meta = loadJSON(metaPath);\n// if (!meta?.providers || !Array.isArray(meta.providers)) continue;\n\n// for (const providerRelPath of meta.providers) {\n// try {\n// const providerPath = path.join(basePath, item.lowerName, providerRelPath);\n// const providerModule = await import(providerPath);\n// if (typeof providerModule.default === 'function') {\n// await providerModule.default(); // Call provider\n// console.log(`[${type}] Provider loaded: ${providerRelPath}`);\n// } else {\n// console.warn(`[${type}] Provider ${providerRelPath} has no default export.`);\n// }\n// } catch (err) {\n// console.error(`[${type}] Failed to load provider ${providerRelPath}:`, err);\n// }\n// }\n// }\n// }\n// }\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { useSettings } from './useSettings';\nimport type { ProviderMeta, ProviderOwnerType } from '../types';\n\ntype ManifestRecord = {\n providers?: string[];\n enabled?: boolean;\n lowerName?: string;\n name?: string;\n};\n\ntype ProviderSource = {\n ownerType: ProviderOwnerType;\n ownerName: string;\n ownerLowerName: string;\n enabled: boolean;\n manifestPath: string;\n baseDir: string;\n providerPaths: string[];\n};\n\nconst PROVIDER_MARKER_REGEX =\n /\\/\\*\\s*@retrex-provider\\s*=\\s*(\\[[\\s\\S]*?\\]|\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*')\\s*\\*\\//;\n\nfunction loadManifest(filePath: string): ManifestRecord | null {\n if (!fs.existsSync(filePath)) return null;\n\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf-8')) as ManifestRecord;\n } catch {\n return null;\n }\n}\n\nfunction getAppProvidersSource(): ProviderSource | null {\n const appRoot = path.resolve('./app');\n const manifestPath = path.join(appRoot, 'app.json');\n const manifest = loadManifest(manifestPath);\n if (!manifest?.providers || !Array.isArray(manifest.providers)) return null;\n\n return {\n ownerType: 'app',\n ownerName: manifest.name || 'App',\n ownerLowerName: manifest.lowerName || 'app',\n enabled: true,\n manifestPath,\n baseDir: appRoot,\n providerPaths: manifest.providers,\n };\n}\n\nfunction getDirectorySources(\n rootDir: string,\n ownerType: Extract<ProviderOwnerType, 'module' | 'service'>,\n): ProviderSource[] {\n if (!fs.existsSync(rootDir)) return [];\n\n const manifestFileName = ownerType === 'module' ? 'module.json' : 'service.json';\n\n return fs\n .readdirSync(rootDir)\n .filter((entry) => {\n const entryPath = path.join(rootDir, entry);\n return fs.existsSync(entryPath) && fs.statSync(entryPath).isDirectory();\n })\n .flatMap((entry) => {\n const baseDir = path.join(rootDir, entry);\n const manifestPath = path.join(baseDir, manifestFileName);\n const manifest = loadManifest(manifestPath);\n if (!manifest?.providers || !Array.isArray(manifest.providers)) return [];\n\n return [\n {\n ownerType,\n ownerName: manifest.name || entry,\n ownerLowerName: manifest.lowerName || entry.toLowerCase(),\n enabled: manifest.enabled ?? false,\n manifestPath,\n baseDir,\n providerPaths: manifest.providers,\n },\n ];\n });\n}\n\nfunction extractProviderTags(filePath: string): string[] | null {\n if (!fs.existsSync(filePath)) return null;\n\n const source = fs.readFileSync(filePath, 'utf-8');\n const head = source.slice(0, 2048);\n const match = head.match(PROVIDER_MARKER_REGEX);\n if (!match?.[1]) return null;\n\n const raw = match[1].trim();\n\n try {\n if (raw.startsWith('[')) {\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return null;\n\n const tags = parsed\n .map((value) => (typeof value === 'string' ? value.trim() : ''))\n .filter(Boolean);\n\n return tags.length > 0 ? tags : null;\n }\n\n const normalized = raw.startsWith(\"'\")\n ? `\"${raw.slice(1, -1).replace(/\"/g, '\\\\\"')}\"`\n : raw;\n const parsed = JSON.parse(normalized);\n return typeof parsed === 'string' && parsed.trim() ? [parsed.trim()] : null;\n } catch {\n return null;\n }\n}\n\nfunction normalizeProviderPath(baseDir: string, providerPath: string): string {\n return path.resolve(baseDir, providerPath);\n}\n\nfunction buildProviderMeta(source: ProviderSource, providerPath: string): ProviderMeta | null {\n const absolutePath = normalizeProviderPath(source.baseDir, providerPath);\n const tags = extractProviderTags(absolutePath);\n if (!tags) return null;\n\n return {\n id: `${source.ownerType}:${source.ownerLowerName}:${providerPath}`,\n name: tags[0],\n tags,\n filePath: absolutePath,\n relativePath: providerPath,\n manifestPath: source.manifestPath,\n ownerType: source.ownerType,\n ownerName: source.ownerName,\n ownerLowerName: source.ownerLowerName,\n enabled: source.enabled,\n };\n}\n\nexport const useProviders = {\n load(options?: { enabledOnly?: boolean }): ProviderMeta[] {\n const paths = useSettings.getPaths();\n\n const sources: ProviderSource[] = [\n ...getDirectorySources(path.resolve(paths.modules), 'module'),\n ...getDirectorySources(path.resolve(paths.services), 'service'),\n ];\n\n const appSource = getAppProvidersSource();\n if (appSource) sources.unshift(appSource);\n\n const providers = sources.flatMap((source) =>\n source.providerPaths\n .map((providerPath) => buildProviderMeta(source, providerPath))\n .filter((provider): provider is ProviderMeta => provider !== null),\n );\n\n return options?.enabledOnly ? providers.filter((provider) => provider.enabled) : providers;\n },\n\n getProviders(options?: { enabledOnly?: boolean }): ProviderMeta[] {\n return useProviders.load(options);\n },\n\n allEnabled(): ProviderMeta[] {\n return useProviders.load({ enabledOnly: true });\n },\n\n forOwner(ownerType: ProviderOwnerType, ownerName: string): ProviderMeta[] {\n const normalizedName = ownerName.toLowerCase();\n return useProviders.load().filter(\n (provider) =>\n provider.ownerType === ownerType &&\n provider.ownerLowerName.toLowerCase() === normalizedName,\n );\n },\n};\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\nimport AdmZip from 'adm-zip';\n\nexport async function downloadGitHubFolderZip(\n repo: string,\n folderPath: string,\n dest: string\n) {\n try {\n const [owner, repoName] = repo.split('/');\n const branch = 'main';\n const zipUrl = `https://github.com/${owner}/${repoName}/archive/refs/heads/${branch}.zip`;\n\n const res = await fetch(zipUrl);\n if (!res.ok) throw new Error(`Failed to fetch from GitHub: ${res.status}`);\n\n const buffer = Buffer.from(await res.arrayBuffer());\n const zip = new AdmZip(buffer);\n\n const prefix = `${repoName}-${branch}/${folderPath}`;\n\n const zipEntries = zip.getEntries();\n\n await mkdir(dest, { recursive: true });\n\n for (const entry of zipEntries) {\n if (!entry.entryName.startsWith(prefix)) continue;\n\n const relativePath = entry.entryName.slice(prefix.length + 1);\n if (!relativePath) continue; // skip the folder root\n\n const outPath = path.join(dest, relativePath);\n\n if (entry.isDirectory) {\n await mkdir(outPath, { recursive: true });\n } else {\n await mkdir(path.dirname(outPath), { recursive: true });\n await writeFile(outPath, entry.getData());\n }\n }\n\n console.log(`✓ Extracted ${folderPath} from ${repo} to ${dest}`);\n } catch (error: any) {\n console.error('[Github Download | Error]', error);\n console.error(`[Github Download | Error] Error downloading GitHub folder: ${error.message}`);\n throw new Error(`[Github Download | Error] Failed to download folder from github repo: ${error.message}`);\n }\n}\n","import { mkdir, writeFile, readFile, rm, access } from 'node:fs/promises';\n\nexport async function ensureDir(dirPath: string) {\n try {\n await mkdir(dirPath, { recursive: true });\n } catch {}\n}\n\nexport async function writeJson(filePath: string, data: any) {\n await writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\nexport async function readJson(filePath: string) {\n const content = await readFile(filePath, 'utf-8');\n return JSON.parse(content);\n}\n\nexport async function deleteDir(dirPath: string) {\n await rm(dirPath, { recursive: true, force: true });\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n","import path from 'node:path';\nimport { useSettings } from '!/core/hooks/useSettings';\nimport { downloadGitHubFolderZip } from '../utils/github';\nimport { writeJson } from '../utils/files';\nimport chalk from 'chalk';\n\ninterface Options {\n name: string;\n}\n\nexport async function createService({ name }: Options) {\n console.log(chalk.cyan(`Creating service \"${name}\"...`));\n try {\n const basePath = useSettings.getPaths().services;\n const servicePath = path.join(basePath, name);\n\n await downloadGitHubFolderZip(\n 'RetroPeak-Solutions/retrex-extensibles-templates',\n `services/default`,\n servicePath\n );\n\n const jsonPath = path.join(servicePath, 'service.json');\n const json = {\n name,\n lowerName: name.toLowerCase()\n };\n\n await writeJson(jsonPath, json);\n console.log(chalk.green(`[Service Created] ${name} created at ${servicePath}`));\n } catch (error: any) {\n console.error(chalk.red(`[Service Creation | Error] Failed to create service: ${error.message}`));\n throw error;\n }\n}","import path from 'node:path';\nimport { useSettings } from '!/core/hooks/useSettings';\nimport chalk from 'chalk';\nimport { downloadGitHubFolderZip } from '../utils/github.js';\nimport { writeJson } from '../utils/files.js';\n\nexport type TemplateTypeCLI = 'admin' | 'client' | 'portal' | 'email';\n\ninterface CreateTemplateOptions {\n type: TemplateTypeCLI;\n name: string;\n repoUrl?: string; // optional override for GitHub template repo\n}\n\nexport async function createTemplate({\n type,\n name,\n repoUrl = 'RetroPeak-Solutions/retrex-extensibles-templates'\n}: CreateTemplateOptions) {\n console.log(chalk.cyan(`Creating ${type} template \"${name}\"...`));\n try {\n if (!['admin', 'client', 'portal', 'email'].includes(type)) {\n throw new Error(`Invalid template type: ${type}. Valid types are: admin, client, portal, email.`);\n }\n\n if (!name) {\n throw new Error('Template name is required.');\n }\n\n // Ensure the name is valid\n if (!/^[a-zA-Z0-9-_]+$/.test(name)) {\n throw new Error(`Invalid template name: \"${name}\". Only alphanumeric characters, dashes, and underscores are allowed.`);\n }\n\n // // Ensure the repo URL is valid\n // if (!/^https:\\/\\/github\\.com\\/[a-zA-Z0-9-_]+\\/[a-zA-Z0-9-_]+$/.test(repoUrl)) {\n // throw new Error(`Invalid GitHub repository URL: ${repoUrl}. It should be in the format `);\n // }\n\n const paths = useSettings.getPaths();\n const basePath = paths.templates;\n\n const fullPath = path.join(basePath, type, name);\n\n console.log(chalk.cyan(`Downloading ${type} template \"${name}\" from ${repoUrl}`));\n\n await downloadGitHubFolderZip(\n repoUrl,\n `themes/${type}/default`, // assumes folder structure matches repo layout\n fullPath\n );\n\n // const jsonPath = path.join(fullPath, `template.json`);\n // await writeJson(jsonPath, {\n // name,\n // lowerName: name.toLowerCase()\n // });\n\n console.log(chalk.green(`[Template Created] ${type} template \"${name}\" created at ${fullPath}`));\n } catch (error: any) {\n console.error(chalk.red(`[Template Creation | Error] Failed to create template: ${error.message}`));\n throw error;\n }\n}","import { build } from 'esbuild';\nimport fg from 'fast-glob';\nimport chalk from 'chalk';\nimport { useSettings } from '!/core/hooks/useSettings';\n\nexport type CompileOptionsType =\n | 'module'\n | 'service'\n | 'admin-theme'\n | 'client-theme'\n | 'portal'\n | 'email';\n\ninterface CompileOptions {\n type: CompileOptionsType;\n name: string;\n}\n\nfunction join(...segments: string[]) {\n return segments.join('/').replace(/\\/+/g, '/');\n}\n\nexport async function compileExtensible({ type, name }: CompileOptions) {\n try {\n console.log(chalk.cyan(`Compiling ${type} files for ${name}`));\n\n const patterns: string[] = [];\n const paths = useSettings.getPaths();\n\n if (type && name) {\n let basePath = '';\n let subPath = '';\n\n if (type !== 'client-theme' && type !== 'admin-theme') {\n // @ts-ignore\n basePath = paths[`${type}s`];\n patterns.push(join(basePath, name, '**/*.ts'));\n patterns.push(join(basePath, name, '**/*.tsx'));\n } else {\n basePath = paths.templates;\n subPath = type === 'client-theme' ? 'client' : 'admin';\n patterns.push(join(basePath, subPath, name, '**/*.ts'));\n patterns.push(join(basePath, subPath, name, '**/*.tsx'));\n }\n } else {\n patterns.push(join(paths.modules, '**/**/*.ts'));\n patterns.push(join(paths.modules, '**/**/*.tsx'));\n patterns.push(join(paths.services, '**/**/*.ts'));\n patterns.push(join(paths.services, '**/**/*.tsx'));\n patterns.push(join(paths.templates, '**/**/*.ts'));\n patterns.push(join(paths.templates, '**/**/*.tsx'));\n }\n\n const files = await fg(patterns, {\n ignore: ['**/*.test.ts', '**/*.test.tsx'],\n });\n\n for (const file of files) {\n const outFile = file.replace(/\\.(ts|tsx)$/, '.js');\n\n await build({\n entryPoints: [file],\n outfile: outFile,\n format: 'esm',\n platform: 'node',\n target: 'node20',\n sourcemap: true,\n bundle: false,\n loader: {\n '.ts': 'ts',\n '.tsx': 'tsx',\n },\n external: ['fs', 'path', 'node:fs', 'node:path'],\n }).catch((error) => {\n console.error(\n chalk.redBright(\n `[Compiler | Error] Failed to compile ${file}: ${error.message}`\n )\n );\n throw error;\n });\n\n console.log(chalk.blue(`✓ Compiled ${file}`));\n }\n\n console.log(chalk.green(`[Compiler | Success] ✓ Compilation finished.`));\n } catch (e: any) {\n console.error(\n chalk.redBright(\n '[Compiler | Error] Failed to Complete the Compile Process:',\n e?.message\n )\n );\n }\n}\n"],"mappings":"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","names":["import_node_path","import_node_fs","import_node_fs","import_node_path","fs","fs","import_node_path","AdmZip","path","import_promises","chalk","path","import_node_path","import_chalk","chalk","path","import_node_path","import_chalk","chalk","path","import_chalk","chalk","fg","yargs"]}
|
package/dist/cmds.js
CHANGED
|
@@ -5,20 +5,26 @@ import yargs from "yargs";
|
|
|
5
5
|
import { hideBin } from "yargs/helpers";
|
|
6
6
|
|
|
7
7
|
// src/commands/createModule.ts
|
|
8
|
-
import
|
|
8
|
+
import path4 from "path";
|
|
9
9
|
|
|
10
10
|
// src/core/hooks/useSettings.ts
|
|
11
|
-
import
|
|
11
|
+
import fs3 from "fs";
|
|
12
12
|
|
|
13
13
|
// src/core/hooks/useExtensibles.ts
|
|
14
|
+
import fs2 from "fs";
|
|
15
|
+
import path2 from "path";
|
|
16
|
+
|
|
17
|
+
// src/core/hooks/useProviders.ts
|
|
14
18
|
import fs from "fs";
|
|
15
19
|
import path from "path";
|
|
20
|
+
|
|
21
|
+
// src/core/hooks/useExtensibles.ts
|
|
16
22
|
function loadJSON(filePath) {
|
|
17
|
-
if (!
|
|
18
|
-
return JSON.parse(
|
|
23
|
+
if (!fs2.existsSync(filePath)) return null;
|
|
24
|
+
return JSON.parse(fs2.readFileSync(filePath, "utf-8"));
|
|
19
25
|
}
|
|
20
26
|
function saveJSON(filePath, data) {
|
|
21
|
-
|
|
27
|
+
fs2.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
// src/core/hooks/useSettings.ts
|
|
@@ -41,7 +47,7 @@ var useSettings = {
|
|
|
41
47
|
if (isServer) {
|
|
42
48
|
for (const key of Object.keys(defaultPaths)) {
|
|
43
49
|
const candidate = extensiblePaths[key];
|
|
44
|
-
if (!candidate || !
|
|
50
|
+
if (!candidate || !fs3.existsSync(candidate)) {
|
|
45
51
|
extensiblePaths[key] = defaultPaths[key];
|
|
46
52
|
}
|
|
47
53
|
}
|
|
@@ -77,7 +83,7 @@ import chalk from "chalk";
|
|
|
77
83
|
|
|
78
84
|
// src/utils/github.ts
|
|
79
85
|
import { mkdir, writeFile } from "fs/promises";
|
|
80
|
-
import
|
|
86
|
+
import path3 from "path";
|
|
81
87
|
import AdmZip from "adm-zip";
|
|
82
88
|
async function downloadGitHubFolderZip(repo, folderPath, dest) {
|
|
83
89
|
try {
|
|
@@ -95,11 +101,11 @@ async function downloadGitHubFolderZip(repo, folderPath, dest) {
|
|
|
95
101
|
if (!entry.entryName.startsWith(prefix)) continue;
|
|
96
102
|
const relativePath = entry.entryName.slice(prefix.length + 1);
|
|
97
103
|
if (!relativePath) continue;
|
|
98
|
-
const outPath =
|
|
104
|
+
const outPath = path3.join(dest, relativePath);
|
|
99
105
|
if (entry.isDirectory) {
|
|
100
106
|
await mkdir(outPath, { recursive: true });
|
|
101
107
|
} else {
|
|
102
|
-
await mkdir(
|
|
108
|
+
await mkdir(path3.dirname(outPath), { recursive: true });
|
|
103
109
|
await writeFile(outPath, entry.getData());
|
|
104
110
|
}
|
|
105
111
|
}
|
|
@@ -132,13 +138,13 @@ async function createModule({ name }) {
|
|
|
132
138
|
throw new Error(`Invalid GitHub repository URL: ${GITHUB_REPO}. It should be in the format`);
|
|
133
139
|
}
|
|
134
140
|
const basePath = useSettings.getPaths().modules;
|
|
135
|
-
const modulePath =
|
|
141
|
+
const modulePath = path4.join(basePath, name);
|
|
136
142
|
await downloadGitHubFolderZip(
|
|
137
143
|
"RetroPeak-Solutions/retrex-extensibles-templates",
|
|
138
144
|
`modules/default`,
|
|
139
145
|
modulePath
|
|
140
146
|
);
|
|
141
|
-
const jsonPath =
|
|
147
|
+
const jsonPath = path4.join(modulePath, "module.json");
|
|
142
148
|
const json = {
|
|
143
149
|
name,
|
|
144
150
|
lowerName: name.toLowerCase()
|
|
@@ -152,19 +158,19 @@ async function createModule({ name }) {
|
|
|
152
158
|
}
|
|
153
159
|
|
|
154
160
|
// src/commands/createService.ts
|
|
155
|
-
import
|
|
161
|
+
import path5 from "path";
|
|
156
162
|
import chalk2 from "chalk";
|
|
157
163
|
async function createService({ name }) {
|
|
158
164
|
console.log(chalk2.cyan(`Creating service "${name}"...`));
|
|
159
165
|
try {
|
|
160
166
|
const basePath = useSettings.getPaths().services;
|
|
161
|
-
const servicePath =
|
|
167
|
+
const servicePath = path5.join(basePath, name);
|
|
162
168
|
await downloadGitHubFolderZip(
|
|
163
169
|
"RetroPeak-Solutions/retrex-extensibles-templates",
|
|
164
170
|
`services/default`,
|
|
165
171
|
servicePath
|
|
166
172
|
);
|
|
167
|
-
const jsonPath =
|
|
173
|
+
const jsonPath = path5.join(servicePath, "service.json");
|
|
168
174
|
const json = {
|
|
169
175
|
name,
|
|
170
176
|
lowerName: name.toLowerCase()
|
|
@@ -178,7 +184,7 @@ async function createService({ name }) {
|
|
|
178
184
|
}
|
|
179
185
|
|
|
180
186
|
// src/commands/createTemplate.ts
|
|
181
|
-
import
|
|
187
|
+
import path6 from "path";
|
|
182
188
|
import chalk3 from "chalk";
|
|
183
189
|
async function createTemplate({
|
|
184
190
|
type,
|
|
@@ -198,7 +204,7 @@ async function createTemplate({
|
|
|
198
204
|
}
|
|
199
205
|
const paths = useSettings.getPaths();
|
|
200
206
|
const basePath = paths.templates;
|
|
201
|
-
const fullPath =
|
|
207
|
+
const fullPath = path6.join(basePath, type, name);
|
|
202
208
|
console.log(chalk3.cyan(`Downloading ${type} template "${name}" from ${repoUrl}`));
|
|
203
209
|
await downloadGitHubFolderZip(
|
|
204
210
|
repoUrl,
|
package/dist/cmds.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cmds.ts","../src/commands/createModule.ts","../src/core/hooks/useSettings.ts","../src/core/hooks/useExtensibles.ts","../src/utils/github.ts","../src/utils/files.ts","../src/commands/createService.ts","../src/commands/createTemplate.ts","../src/commands/compile.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { createModule } from '@cmds/createModule';\nimport { createService } from '@cmds/createService';\nimport { createTemplate } from '@cmds/createTemplate';\nimport { compileExtensible, CompileOptionsType } from '@cmds/compile';\n\nyargs(hideBin(process.argv))\n .command(\n 'create-module <name>',\n 'Create a new extensible module',\n (yargs) => yargs.positional('name', { type: 'string', describe: 'Module name' }),\n async (argv) => await createModule({ name: argv.name as string })\n )\n .command(\n 'create-service <name>',\n 'Create a new extensible service',\n (yargs) => yargs.positional('name', { type: 'string', describe: 'Service name' }),\n async (argv) => await createService({ name: argv.name as string })\n )\n .command(\n 'create-template <type> <name>',\n 'Create a new template',\n (yargs) =>\n yargs\n .positional('type', {\n type: 'string',\n describe: 'Template type',\n choices: ['admin', 'client', 'portal', 'email']\n })\n .positional('name', { type: 'string', describe: 'Template name' }),\n async (argv) => await createTemplate({ type: argv.type as any, name: argv.name as string })\n )\n .command(\n 'compile <type> <name>',\n 'Compiles an Extensible for Production',\n (yargs) =>\n yargs\n .positional('type', {\n type: 'string',\n describe: 'Template type',\n choices: ['module', 'service', 'admin-theme', 'client-theme', 'portal', 'email']\n })\n .positional('name', { type: 'string', describe: 'Extensible name' }),\n async (argv) => await compileExtensible({ type: argv.type as CompileOptionsType, name: argv.name as string })\n )\n .demandCommand(1, 'You need to specify a command [create-module, create-service, create-template, compile]')\n .help().argv;","import path from 'node:path';\nimport { useSettings } from '!/core/hooks/useSettings';\nimport chalk from 'chalk';\nimport { downloadGitHubFolderZip } from '../utils/github.js';\nimport { writeJson } from '../utils/files.js';\n\nconst GITHUB_REPO = process.env.RETREX_TEMPLATE_REPO || 'https://github.com/RetroPeak-Solutions/retrex-extensibles-templates';\n\ninterface Options {\n name: string;\n}\nexport async function createModule({ name }: Options) {\n console.log(chalk.cyan(`Creating module \"${name}\"...`));\n try {\n if (!name) {\n throw new Error('Module name is required.');\n }\n\n // Ensure the name is valid\n if (!/^[a-zA-Z0-9-_]+$/.test(name)) {\n throw new Error(`Invalid module name: \"${name}\". Only alphanumeric characters, dashes, and underscores are allowed.`);\n }\n\n // Ensure the repo URL is valid\n if (!/^https:\\/\\/github\\.com\\/[a-zA-Z0-9-_]+\\/[a-zA-Z0-9-_]+$/.test(GITHUB_REPO)) {\n throw new Error(`Invalid GitHub repository URL: ${GITHUB_REPO}. It should be in the format`);\n }\n const basePath = useSettings.getPaths().modules;\n const modulePath = path.join(basePath, name);\n\n await downloadGitHubFolderZip(\n 'RetroPeak-Solutions/retrex-extensibles-templates',\n `modules/default`,\n modulePath\n );\n\n const jsonPath = path.join(modulePath, 'module.json');\n const json = {\n name,\n lowerName: name.toLowerCase()\n };\n\n await writeJson(jsonPath, json);\n console.log(chalk.green(`[Module Created] ${name} created at ${modulePath}`));\n } catch (error: any) {\n console.error(chalk.red(`[Module Creation | Error] Failed to create module: ${error.message}`));\n throw error;\n }\n}","// src/hooks/useSettings.ts\n\nimport path from 'node:path';\nimport fs from 'node:fs';\n\nimport { loadJSON, saveJSON } from './useExtensibles';\nimport type { ExtensiblePaths } from '../types'; // Adjust the import path as necessary\n\nconst defaultPaths: ExtensiblePaths = {\n modules: './app/modules',\n templates: './app/resources/themes',\n services: './app/services',\n events: './app/events',\n langs: './public/langs',\n providers: './app/providers',\n};\n\nlet extensiblePaths: ExtensiblePaths = { ...defaultPaths };\nconst isServer = typeof window === 'undefined';\n\n\nexport const useSettings = {\n getPaths(): ExtensiblePaths {\n if (isServer) {\n const json = loadJSON('./app/extensiblePaths.json');\n if (json) extensiblePaths = json;\n }\n\n if (isServer) {\n for (const key of Object.keys(defaultPaths) as Array<keyof ExtensiblePaths>) {\n const candidate = extensiblePaths[key];\n if (!candidate || !fs.existsSync(candidate)) {\n extensiblePaths[key] = defaultPaths[key];\n }\n }\n }\n\n extensiblePaths = {\n ...extensiblePaths,\n langs: './langs',\n };\n // extensiblePaths = loadJSON(\"./app/extensiblePaths.json\");\n return extensiblePaths;\n },\n\n setPaths(paths: Partial<ExtensiblePaths>): void {\n if (isServer) {\n saveJSON('./app/extensiblePaths.json', {\n ...extensiblePaths,\n ...paths,\n });\n }\n\n extensiblePaths = {\n ...extensiblePaths,\n ...paths,\n };\n },\n \n getKeyValue(key: string): string {\n return 'Coming Soon'\n },\n setKeyValue(key: string, value: string): void {\n return;\n },\n};\n","// src/hooks/useExtensibles.ts\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { useSettings } from './useSettings';\nimport type { TemplateType, ExtensibleMeta, ExtensiblePaths } from '../types';\n\nlet paths: ExtensiblePaths;\n\nfunction toFileUrl(filePath: string): string {\n const normalized = filePath.replace(/\\\\/g, '/');\n if (normalized.startsWith('file://')) return normalized;\n const prefix = normalized.startsWith('/') ? 'file://' : 'file:///';\n return `${prefix}${encodeURI(normalized)}`;\n}\n\nexport function registerExtensibles(extensiblePaths: ExtensiblePaths) {\n paths = extensiblePaths;\n}\n\nexport function loadJSON(filePath: string): any {\n if (!fs.existsSync(filePath)) return null;\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n}\n\nexport function saveJSON(filePath: string, data: any) {\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\n// --- MODULES ---\n\nexport function getModules(): ExtensibleMeta[] {\n if (!useSettings.getPaths().modules) throw new Error('Modules path not registered.');\n\n const dirs = fs\n .readdirSync(useSettings.getPaths().modules)\n .filter((d: any) => fs.statSync(path.join(useSettings.getPaths().modules, d)).isDirectory());\n\n return dirs.map((dir: any) => {\n const meta = loadJSON(path.join(useSettings.getPaths().modules, dir, 'module.json')) || {};\n return {\n name: meta.name || dir,\n lowerName: meta.lowerName || dir.toLowerCase(),\n version: meta.version,\n description: meta.description,\n author: meta.author,\n icon: meta.icon,\n enabled: meta.enabled ?? false,\n };\n });\n}\n\nexport function isModuleEnabled(name: string) {\n const modules = getModules();\n return modules.find((m) => m.lowerName === name.toLowerCase())?.enabled ?? false;\n}\n\nexport function toggleModule(name: string, enabled: boolean) {\n const modules = getModules();\n const mod = modules.find((m) => m.lowerName === name.toLowerCase());\n if (!mod) throw new Error(`Module ${name} not found`);\n\n const metaPath = path.join(useSettings.getPaths().modules, mod.lowerName, 'module.json');\n const meta = loadJSON(metaPath) || {};\n meta.enabled = enabled;\n saveJSON(metaPath, meta);\n\n if (enabled) onModuleEnabled(mod.name);\n else onModuleDisabled(mod.name);\n}\n\n// --- SERVICES ---\n\nexport function getServices(): ExtensibleMeta[] {\n if (!useSettings.getPaths().services) throw new Error('Services path not registered.');\n\n const dirs = fs\n .readdirSync(useSettings.getPaths().services)\n .filter((d: any) => fs.statSync(path.join(useSettings.getPaths().services, d)).isDirectory());\n\n return dirs.map((dir: any) => {\n const meta = loadJSON(path.join(useSettings.getPaths().services, dir, 'service.json')) || {};\n return {\n name: meta.name || dir,\n lowerName: meta.lowerName || dir.toLowerCase(),\n version: meta.version,\n description: meta.description,\n author: meta.author,\n icon: meta.icon,\n enabled: meta.enabled ?? false,\n };\n });\n}\n\nexport function isServiceEnabled(name: string) {\n const services = getServices();\n return services.find((s) => s.lowerName === name.toLowerCase())?.enabled ?? false;\n}\n\nexport function toggleService(name: string, enabled: boolean) {\n const services = getServices();\n const svc = services.find((s) => s.lowerName === name.toLowerCase());\n if (!svc) throw new Error(`Service ${name} not found`);\n\n const metaPath = path.join(useSettings.getPaths().services, svc.lowerName, 'service.json');\n const meta = loadJSON(metaPath) || {};\n meta.enabled = enabled;\n saveJSON(metaPath, meta);\n\n if (enabled) onServiceEnabled(svc.name);\n else onServiceDisabled(svc.name);\n}\n\n// --- TEMPLATES ---\n\n// Helper to get base path for a template type\nfunction getTemplateBasePath(type: TemplateType): string {\n if (!useSettings.getPaths().templates) throw new Error('Templates path not registered.');\n switch (type) {\n case 'admin-theme':\n case 'client-theme':\n return path.join(useSettings.getPaths().templates, 'themes');\n case 'portal':\n return path.join(useSettings.getPaths().templates, 'portals');\n case 'email':\n return path.join(useSettings.getPaths().templates, 'emails');\n default:\n throw new Error(`Unknown template type: ${type}`);\n }\n}\n\nexport function getTemplates(type: TemplateType): ExtensibleMeta[] {\n const basePath = getTemplateBasePath(type);\n if (!fs.existsSync(basePath)) return [];\n\n const dirs = fs\n .readdirSync(basePath)\n .filter((d: any) => fs.statSync(path.join(basePath, d)).isDirectory());\n\n return dirs.map((dir: any) => {\n const meta = loadJSON(path.join(basePath, dir, 'template.json')) || {};\n return {\n name: meta.name || dir,\n lowerName: dir.toLowerCase(),\n version: meta.version,\n description: meta.description,\n author: meta.author,\n icon: meta.icon,\n enabled: meta.enabled ?? false,\n };\n });\n}\n\nexport function isTemplateActive(type: TemplateType, name: string) {\n const templates = getTemplates(type);\n return templates.find((t) => t.lowerName === name.toLowerCase())?.enabled ?? false;\n}\n\n// Toggle templates: only 1 active per type allowed\nexport function toggleTemplate(type: TemplateType, name: string) {\n const templates = getTemplates(type);\n\n templates.forEach((tpl) => {\n const metaPath = path.join(getTemplateBasePath(type), tpl.lowerName, 'template.json');\n const meta = loadJSON(metaPath) || {};\n meta.enabled = tpl.lowerName === name.toLowerCase();\n saveJSON(metaPath, meta);\n });\n\n onTemplateSelect(type, name);\n}\n\n// --- EVENTS (replace with your event system integration) ---\n\nexport function onModuleEnabled(name: string) {\n console.log(`Module enabled: ${name}`);\n // emit event or custom logic here\n}\n\nexport function onModuleDisabled(name: string) {\n console.log(`Module disabled: ${name}`);\n}\n\nexport function onServiceEnabled(name: string) {\n console.log(`Service enabled: ${name}`);\n}\n\nexport function onServiceDisabled(name: string) {\n console.log(`Service disabled: ${name}`);\n}\n\nexport function onTemplateSelect(type: TemplateType, name: string) {\n console.log(`Template selected: type=${type}, name=${name}`);\n}\n\n// --- REGISTER HOOKS FOR MODULES ---\n\nexport async function registerEvents() {\n if (!useSettings.getPaths().modules) throw new Error('Modules path not registered.');\n const modules = getModules().filter((m) => m.enabled);\n for (const mod of modules) {\n const eventsFile = path.join(useSettings.getPaths().modules, mod.lowerName, 'events.server.js');\n if (fs.existsSync(eventsFile)) {\n const modEvents = await import(eventsFile);\n if (modEvents?.registerEvents) await modEvents.registerEvents();\n }\n }\n}\n\nexport async function registerMiddleware() {\n if (!useSettings.getPaths().modules) throw new Error('Modules path not registered.');\n const modules = getModules().filter((m) => m.enabled);\n for (const mod of modules) {\n const middlewareFile = path.join(useSettings.getPaths().modules, mod.lowerName, 'middleware.server.js');\n if (fs.existsSync(middlewareFile)) {\n const modMiddleware = await import(middlewareFile);\n if (modMiddleware?.registerMiddleware) await modMiddleware.registerMiddleware();\n }\n }\n}\n\n/**\n * Registers routes given a path to routes folder (for pages and API routes)\n * @param routesFolderPath string - path to module/service routes folder\n */\nexport async function registerRoutes(routesFolderPath: string) {\n if (!fs.existsSync(routesFolderPath)) return;\n\n const routeFiles = fs.readdirSync(routesFolderPath).filter((f: any) => /\\.(js|ts|jsx|tsx)$/.test(f));\n for (const file of routeFiles) {\n const routeModule = await import(path.join(routesFolderPath, file));\n if (routeModule?.registerRoute) {\n await routeModule.registerRoute();\n }\n }\n}\n\nexport async function loadProviders() {\n const paths = useSettings.getPaths();\n\n const all = [\n { type: 'module', list: getModules(), basePath: paths.modules },\n { type: 'service', list: getServices(), basePath: paths.services },\n ];\n\n for (const { type, list, basePath } of all) {\n for (const item of list) {\n if (!item.enabled) continue;\n\n const metaPath = path.join(path.resolve(basePath), item.lowerName, `${type}.json`);\n const meta = loadJSON(metaPath);\n if (!meta?.providers || !Array.isArray(meta.providers)) continue;\n\n for (const providerRelPath of meta.providers) {\n try {\n let providerAbsPath = path.join(path.resolve(basePath), item.lowerName, providerRelPath);\n\n // Try .js fallback if file is .ts or .tsx\n const ext = path.extname(providerAbsPath);\n if (ext === '.ts' || ext === '.tsx') {\n const jsPath = providerAbsPath.replace(/\\.(ts|tsx)$/, '.js');\n try {\n await fs.accessSync(jsPath); // Check if compiled JS file exists\n providerAbsPath = jsPath;\n } catch {\n throw new Error(`Compiled JS version not found for provider: ${providerRelPath}`);\n }\n }\n\n const providerUrl = toFileUrl(providerAbsPath);\n const providerModule = await import(providerUrl);\n\n if (typeof providerModule.default === 'function') {\n // Expose context so nav registration can auto-tag module/service\n (globalThis as any).__retrex_provider_context__ = {\n type,\n name: item.lowerName,\n };\n await providerModule.default();\n (globalThis as any).__retrex_provider_context__ = undefined;\n console.log(`[${type}] ✅ Provider loaded: ${providerRelPath}`);\n } else {\n console.warn(`[${type}] ⚠️ Provider ${providerRelPath} has no default export.`);\n }\n } catch (err) {\n console.error(`[${type}] ❌ Failed to load provider ${providerRelPath}:`, err);\n }\n }\n }\n }\n}\n\n\n// export async function loadProviders() {\n// paths = {\n// modules: useSettings.getPaths().modules,\n// templates: useSettings.getPaths().templates,\n// services: useSettings.getPaths().services,\n// events: useSettings.getPaths().events,\n// }\n// const all = [\n// { type: 'module', list: getModules(), basePath: useSettings.getPaths().modules },\n// { type: 'service', list: getServices(), basePath: useSettings.getPaths().services },\n// ];\n\n// for (const { type, list, basePath } of all) {\n// for (const item of list) {\n// if (!item.enabled) continue;\n\n// const metaPath = path.join(basePath, item.lowerName, `${type}.json`);\n// const meta = loadJSON(metaPath);\n// if (!meta?.providers || !Array.isArray(meta.providers)) continue;\n\n// for (const providerRelPath of meta.providers) {\n// try {\n// const providerPath = path.join(basePath, item.lowerName, providerRelPath);\n// const providerModule = await import(providerPath);\n// if (typeof providerModule.default === 'function') {\n// await providerModule.default(); // Call provider\n// console.log(`[${type}] Provider loaded: ${providerRelPath}`);\n// } else {\n// console.warn(`[${type}] Provider ${providerRelPath} has no default export.`);\n// }\n// } catch (err) {\n// console.error(`[${type}] Failed to load provider ${providerRelPath}:`, err);\n// }\n// }\n// }\n// }\n// }\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\nimport AdmZip from 'adm-zip';\n\nexport async function downloadGitHubFolderZip(\n repo: string,\n folderPath: string,\n dest: string\n) {\n try {\n const [owner, repoName] = repo.split('/');\n const branch = 'main';\n const zipUrl = `https://github.com/${owner}/${repoName}/archive/refs/heads/${branch}.zip`;\n\n const res = await fetch(zipUrl);\n if (!res.ok) throw new Error(`Failed to fetch from GitHub: ${res.status}`);\n\n const buffer = Buffer.from(await res.arrayBuffer());\n const zip = new AdmZip(buffer);\n\n const prefix = `${repoName}-${branch}/${folderPath}`;\n\n const zipEntries = zip.getEntries();\n\n await mkdir(dest, { recursive: true });\n\n for (const entry of zipEntries) {\n if (!entry.entryName.startsWith(prefix)) continue;\n\n const relativePath = entry.entryName.slice(prefix.length + 1);\n if (!relativePath) continue; // skip the folder root\n\n const outPath = path.join(dest, relativePath);\n\n if (entry.isDirectory) {\n await mkdir(outPath, { recursive: true });\n } else {\n await mkdir(path.dirname(outPath), { recursive: true });\n await writeFile(outPath, entry.getData());\n }\n }\n\n console.log(`✓ Extracted ${folderPath} from ${repo} to ${dest}`);\n } catch (error: any) {\n console.error('[Github Download | Error]', error);\n console.error(`[Github Download | Error] Error downloading GitHub folder: ${error.message}`);\n throw new Error(`[Github Download | Error] Failed to download folder from github repo: ${error.message}`);\n }\n}\n","import { mkdir, writeFile, readFile, rm, access } from 'node:fs/promises';\n\nexport async function ensureDir(dirPath: string) {\n try {\n await mkdir(dirPath, { recursive: true });\n } catch {}\n}\n\nexport async function writeJson(filePath: string, data: any) {\n await writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\nexport async function readJson(filePath: string) {\n const content = await readFile(filePath, 'utf-8');\n return JSON.parse(content);\n}\n\nexport async function deleteDir(dirPath: string) {\n await rm(dirPath, { recursive: true, force: true });\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n","import path from 'node:path';\nimport { useSettings } from '!/core/hooks/useSettings';\nimport { downloadGitHubFolderZip } from '../utils/github';\nimport { writeJson } from '../utils/files';\nimport chalk from 'chalk';\n\ninterface Options {\n name: string;\n}\n\nexport async function createService({ name }: Options) {\n console.log(chalk.cyan(`Creating service \"${name}\"...`));\n try {\n const basePath = useSettings.getPaths().services;\n const servicePath = path.join(basePath, name);\n\n await downloadGitHubFolderZip(\n 'RetroPeak-Solutions/retrex-extensibles-templates',\n `services/default`,\n servicePath\n );\n\n const jsonPath = path.join(servicePath, 'service.json');\n const json = {\n name,\n lowerName: name.toLowerCase()\n };\n\n await writeJson(jsonPath, json);\n console.log(chalk.green(`[Service Created] ${name} created at ${servicePath}`));\n } catch (error: any) {\n console.error(chalk.red(`[Service Creation | Error] Failed to create service: ${error.message}`));\n throw error;\n }\n}","import path from 'node:path';\nimport { useSettings } from '!/core/hooks/useSettings';\nimport chalk from 'chalk';\nimport { downloadGitHubFolderZip } from '../utils/github.js';\nimport { writeJson } from '../utils/files.js';\n\nexport type TemplateTypeCLI = 'admin' | 'client' | 'portal' | 'email';\n\ninterface CreateTemplateOptions {\n type: TemplateTypeCLI;\n name: string;\n repoUrl?: string; // optional override for GitHub template repo\n}\n\nexport async function createTemplate({\n type,\n name,\n repoUrl = 'RetroPeak-Solutions/retrex-extensibles-templates'\n}: CreateTemplateOptions) {\n console.log(chalk.cyan(`Creating ${type} template \"${name}\"...`));\n try {\n if (!['admin', 'client', 'portal', 'email'].includes(type)) {\n throw new Error(`Invalid template type: ${type}. Valid types are: admin, client, portal, email.`);\n }\n\n if (!name) {\n throw new Error('Template name is required.');\n }\n\n // Ensure the name is valid\n if (!/^[a-zA-Z0-9-_]+$/.test(name)) {\n throw new Error(`Invalid template name: \"${name}\". Only alphanumeric characters, dashes, and underscores are allowed.`);\n }\n\n // // Ensure the repo URL is valid\n // if (!/^https:\\/\\/github\\.com\\/[a-zA-Z0-9-_]+\\/[a-zA-Z0-9-_]+$/.test(repoUrl)) {\n // throw new Error(`Invalid GitHub repository URL: ${repoUrl}. It should be in the format `);\n // }\n\n const paths = useSettings.getPaths();\n const basePath = paths.templates;\n\n const fullPath = path.join(basePath, type, name);\n\n console.log(chalk.cyan(`Downloading ${type} template \"${name}\" from ${repoUrl}`));\n\n await downloadGitHubFolderZip(\n repoUrl,\n `themes/${type}/default`, // assumes folder structure matches repo layout\n fullPath\n );\n\n // const jsonPath = path.join(fullPath, `template.json`);\n // await writeJson(jsonPath, {\n // name,\n // lowerName: name.toLowerCase()\n // });\n\n console.log(chalk.green(`[Template Created] ${type} template \"${name}\" created at ${fullPath}`));\n } catch (error: any) {\n console.error(chalk.red(`[Template Creation | Error] Failed to create template: ${error.message}`));\n throw error;\n }\n}","import { build } from 'esbuild';\nimport fg from 'fast-glob';\nimport chalk from 'chalk';\nimport { useSettings } from '!/core/hooks/useSettings';\n\nexport type CompileOptionsType =\n | 'module'\n | 'service'\n | 'admin-theme'\n | 'client-theme'\n | 'portal'\n | 'email';\n\ninterface CompileOptions {\n type: CompileOptionsType;\n name: string;\n}\n\nfunction join(...segments: string[]) {\n return segments.join('/').replace(/\\/+/g, '/');\n}\n\nexport async function compileExtensible({ type, name }: CompileOptions) {\n try {\n console.log(chalk.cyan(`Compiling ${type} files for ${name}`));\n\n const patterns: string[] = [];\n const paths = useSettings.getPaths();\n\n if (type && name) {\n let basePath = '';\n let subPath = '';\n\n if (type !== 'client-theme' && type !== 'admin-theme') {\n // @ts-ignore\n basePath = paths[`${type}s`];\n patterns.push(join(basePath, name, '**/*.ts'));\n patterns.push(join(basePath, name, '**/*.tsx'));\n } else {\n basePath = paths.templates;\n subPath = type === 'client-theme' ? 'client' : 'admin';\n patterns.push(join(basePath, subPath, name, '**/*.ts'));\n patterns.push(join(basePath, subPath, name, '**/*.tsx'));\n }\n } else {\n patterns.push(join(paths.modules, '**/**/*.ts'));\n patterns.push(join(paths.modules, '**/**/*.tsx'));\n patterns.push(join(paths.services, '**/**/*.ts'));\n patterns.push(join(paths.services, '**/**/*.tsx'));\n patterns.push(join(paths.templates, '**/**/*.ts'));\n patterns.push(join(paths.templates, '**/**/*.tsx'));\n }\n\n const files = await fg(patterns, {\n ignore: ['**/*.test.ts', '**/*.test.tsx'],\n });\n\n for (const file of files) {\n const outFile = file.replace(/\\.(ts|tsx)$/, '.js');\n\n await build({\n entryPoints: [file],\n outfile: outFile,\n format: 'esm',\n platform: 'node',\n target: 'node20',\n sourcemap: true,\n bundle: false,\n loader: {\n '.ts': 'ts',\n '.tsx': 'tsx',\n },\n external: ['fs', 'path', 'node:fs', 'node:path'],\n }).catch((error) => {\n console.error(\n chalk.redBright(\n `[Compiler | Error] Failed to compile ${file}: ${error.message}`\n )\n );\n throw error;\n });\n\n console.log(chalk.blue(`✓ Compiled ${file}`));\n }\n\n console.log(chalk.green(`[Compiler | Success] ✓ Compilation finished.`));\n } catch (e: any) {\n console.error(\n chalk.redBright(\n '[Compiler | Error] Failed to Complete the Compile Process:',\n e?.message\n )\n );\n }\n}\n"],"mappings":"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","names":["path","fs","fs","path","mkdir","writeFile","writeFile","path","path","chalk","path","path","chalk","chalk","path","chalk","chalk","yargs"]}
|
|
1
|
+
{"version":3,"sources":["../src/cmds.ts","../src/commands/createModule.ts","../src/core/hooks/useSettings.ts","../src/core/hooks/useExtensibles.ts","../src/core/hooks/useProviders.ts","../src/utils/github.ts","../src/utils/files.ts","../src/commands/createService.ts","../src/commands/createTemplate.ts","../src/commands/compile.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { createModule } from '@cmds/createModule';\nimport { createService } from '@cmds/createService';\nimport { createTemplate } from '@cmds/createTemplate';\nimport { compileExtensible, CompileOptionsType } from '@cmds/compile';\n\nyargs(hideBin(process.argv))\n .command(\n 'create-module <name>',\n 'Create a new extensible module',\n (yargs) => yargs.positional('name', { type: 'string', describe: 'Module name' }),\n async (argv) => await createModule({ name: argv.name as string })\n )\n .command(\n 'create-service <name>',\n 'Create a new extensible service',\n (yargs) => yargs.positional('name', { type: 'string', describe: 'Service name' }),\n async (argv) => await createService({ name: argv.name as string })\n )\n .command(\n 'create-template <type> <name>',\n 'Create a new template',\n (yargs) =>\n yargs\n .positional('type', {\n type: 'string',\n describe: 'Template type',\n choices: ['admin', 'client', 'portal', 'email']\n })\n .positional('name', { type: 'string', describe: 'Template name' }),\n async (argv) => await createTemplate({ type: argv.type as any, name: argv.name as string })\n )\n .command(\n 'compile <type> <name>',\n 'Compiles an Extensible for Production',\n (yargs) =>\n yargs\n .positional('type', {\n type: 'string',\n describe: 'Template type',\n choices: ['module', 'service', 'admin-theme', 'client-theme', 'portal', 'email']\n })\n .positional('name', { type: 'string', describe: 'Extensible name' }),\n async (argv) => await compileExtensible({ type: argv.type as CompileOptionsType, name: argv.name as string })\n )\n .demandCommand(1, 'You need to specify a command [create-module, create-service, create-template, compile]')\n .help().argv;","import path from 'node:path';\nimport { useSettings } from '!/core/hooks/useSettings';\nimport chalk from 'chalk';\nimport { downloadGitHubFolderZip } from '../utils/github.js';\nimport { writeJson } from '../utils/files.js';\n\nconst GITHUB_REPO = process.env.RETREX_TEMPLATE_REPO || 'https://github.com/RetroPeak-Solutions/retrex-extensibles-templates';\n\ninterface Options {\n name: string;\n}\nexport async function createModule({ name }: Options) {\n console.log(chalk.cyan(`Creating module \"${name}\"...`));\n try {\n if (!name) {\n throw new Error('Module name is required.');\n }\n\n // Ensure the name is valid\n if (!/^[a-zA-Z0-9-_]+$/.test(name)) {\n throw new Error(`Invalid module name: \"${name}\". Only alphanumeric characters, dashes, and underscores are allowed.`);\n }\n\n // Ensure the repo URL is valid\n if (!/^https:\\/\\/github\\.com\\/[a-zA-Z0-9-_]+\\/[a-zA-Z0-9-_]+$/.test(GITHUB_REPO)) {\n throw new Error(`Invalid GitHub repository URL: ${GITHUB_REPO}. It should be in the format`);\n }\n const basePath = useSettings.getPaths().modules;\n const modulePath = path.join(basePath, name);\n\n await downloadGitHubFolderZip(\n 'RetroPeak-Solutions/retrex-extensibles-templates',\n `modules/default`,\n modulePath\n );\n\n const jsonPath = path.join(modulePath, 'module.json');\n const json = {\n name,\n lowerName: name.toLowerCase()\n };\n\n await writeJson(jsonPath, json);\n console.log(chalk.green(`[Module Created] ${name} created at ${modulePath}`));\n } catch (error: any) {\n console.error(chalk.red(`[Module Creation | Error] Failed to create module: ${error.message}`));\n throw error;\n }\n}","// src/hooks/useSettings.ts\n\nimport path from 'node:path';\nimport fs from 'node:fs';\n\nimport { loadJSON, saveJSON } from './useExtensibles';\nimport type { ExtensiblePaths } from '../types'; // Adjust the import path as necessary\n\nconst defaultPaths: ExtensiblePaths = {\n modules: './app/modules',\n templates: './app/resources/themes',\n services: './app/services',\n events: './app/events',\n langs: './public/langs',\n providers: './app/providers',\n};\n\nlet extensiblePaths: ExtensiblePaths = { ...defaultPaths };\nconst isServer = typeof window === 'undefined';\n\n\nexport const useSettings = {\n getPaths(): ExtensiblePaths {\n if (isServer) {\n const json = loadJSON('./app/extensiblePaths.json');\n if (json) extensiblePaths = json;\n }\n\n if (isServer) {\n for (const key of Object.keys(defaultPaths) as Array<keyof ExtensiblePaths>) {\n const candidate = extensiblePaths[key];\n if (!candidate || !fs.existsSync(candidate)) {\n extensiblePaths[key] = defaultPaths[key];\n }\n }\n }\n\n extensiblePaths = {\n ...extensiblePaths,\n langs: './langs',\n };\n // extensiblePaths = loadJSON(\"./app/extensiblePaths.json\");\n return extensiblePaths;\n },\n\n setPaths(paths: Partial<ExtensiblePaths>): void {\n if (isServer) {\n saveJSON('./app/extensiblePaths.json', {\n ...extensiblePaths,\n ...paths,\n });\n }\n\n extensiblePaths = {\n ...extensiblePaths,\n ...paths,\n };\n },\n \n getKeyValue(key: string): string {\n return 'Coming Soon'\n },\n setKeyValue(key: string, value: string): void {\n return;\n },\n};\n","// src/hooks/useExtensibles.ts\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { useSettings } from './useSettings';\nimport { useProviders } from './useProviders';\nimport type { TemplateType, ExtensibleMeta, ExtensiblePaths } from '../types';\n\nlet paths: ExtensiblePaths;\n\nfunction toFileUrl(filePath: string): string {\n const normalized = filePath.replace(/\\\\/g, '/');\n if (normalized.startsWith('file://')) return normalized;\n const prefix = normalized.startsWith('/') ? 'file://' : 'file:///';\n return `${prefix}${encodeURI(normalized)}`;\n}\n\nexport function registerExtensibles(extensiblePaths: ExtensiblePaths) {\n paths = extensiblePaths;\n}\n\nexport function loadJSON(filePath: string): any {\n if (!fs.existsSync(filePath)) return null;\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n}\n\nexport function saveJSON(filePath: string, data: any) {\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\n// --- MODULES ---\n\nexport function getModules(): ExtensibleMeta[] {\n if (!useSettings.getPaths().modules) throw new Error('Modules path not registered.');\n\n const dirs = fs\n .readdirSync(useSettings.getPaths().modules)\n .filter((d: any) => fs.statSync(path.join(useSettings.getPaths().modules, d)).isDirectory());\n\n return dirs.map((dir: any) => {\n const meta = loadJSON(path.join(useSettings.getPaths().modules, dir, 'module.json')) || {};\n return {\n name: meta.name || dir,\n lowerName: meta.lowerName || dir.toLowerCase(),\n version: meta.version,\n description: meta.description,\n author: meta.author,\n icon: meta.icon,\n enabled: meta.enabled ?? false,\n };\n });\n}\n\nexport function isModuleEnabled(name: string) {\n const modules = getModules();\n return modules.find((m) => m.lowerName === name.toLowerCase())?.enabled ?? false;\n}\n\nexport function toggleModule(name: string, enabled: boolean) {\n const modules = getModules();\n const mod = modules.find((m) => m.lowerName === name.toLowerCase());\n if (!mod) throw new Error(`Module ${name} not found`);\n\n const metaPath = path.join(useSettings.getPaths().modules, mod.lowerName, 'module.json');\n const meta = loadJSON(metaPath) || {};\n meta.enabled = enabled;\n saveJSON(metaPath, meta);\n\n if (enabled) onModuleEnabled(mod.name);\n else onModuleDisabled(mod.name);\n}\n\n// --- SERVICES ---\n\nexport function getServices(): ExtensibleMeta[] {\n if (!useSettings.getPaths().services) throw new Error('Services path not registered.');\n\n const dirs = fs\n .readdirSync(useSettings.getPaths().services)\n .filter((d: any) => fs.statSync(path.join(useSettings.getPaths().services, d)).isDirectory());\n\n return dirs.map((dir: any) => {\n const meta = loadJSON(path.join(useSettings.getPaths().services, dir, 'service.json')) || {};\n return {\n name: meta.name || dir,\n lowerName: meta.lowerName || dir.toLowerCase(),\n version: meta.version,\n description: meta.description,\n author: meta.author,\n icon: meta.icon,\n enabled: meta.enabled ?? false,\n };\n });\n}\n\nexport function isServiceEnabled(name: string) {\n const services = getServices();\n return services.find((s) => s.lowerName === name.toLowerCase())?.enabled ?? false;\n}\n\nexport function toggleService(name: string, enabled: boolean) {\n const services = getServices();\n const svc = services.find((s) => s.lowerName === name.toLowerCase());\n if (!svc) throw new Error(`Service ${name} not found`);\n\n const metaPath = path.join(useSettings.getPaths().services, svc.lowerName, 'service.json');\n const meta = loadJSON(metaPath) || {};\n meta.enabled = enabled;\n saveJSON(metaPath, meta);\n\n if (enabled) onServiceEnabled(svc.name);\n else onServiceDisabled(svc.name);\n}\n\n// --- TEMPLATES ---\n\n// Helper to get base path for a template type\nfunction getTemplateBasePath(type: TemplateType): string {\n if (!useSettings.getPaths().templates) throw new Error('Templates path not registered.');\n switch (type) {\n case 'admin-theme':\n case 'client-theme':\n return path.join(useSettings.getPaths().templates, 'themes');\n case 'portal':\n return path.join(useSettings.getPaths().templates, 'portals');\n case 'email':\n return path.join(useSettings.getPaths().templates, 'emails');\n default:\n throw new Error(`Unknown template type: ${type}`);\n }\n}\n\nexport function getTemplates(type: TemplateType): ExtensibleMeta[] {\n const basePath = getTemplateBasePath(type);\n if (!fs.existsSync(basePath)) return [];\n\n const dirs = fs\n .readdirSync(basePath)\n .filter((d: any) => fs.statSync(path.join(basePath, d)).isDirectory());\n\n return dirs.map((dir: any) => {\n const meta = loadJSON(path.join(basePath, dir, 'template.json')) || {};\n return {\n name: meta.name || dir,\n lowerName: dir.toLowerCase(),\n version: meta.version,\n description: meta.description,\n author: meta.author,\n icon: meta.icon,\n enabled: meta.enabled ?? false,\n };\n });\n}\n\nexport function isTemplateActive(type: TemplateType, name: string) {\n const templates = getTemplates(type);\n return templates.find((t) => t.lowerName === name.toLowerCase())?.enabled ?? false;\n}\n\n// Toggle templates: only 1 active per type allowed\nexport function toggleTemplate(type: TemplateType, name: string) {\n const templates = getTemplates(type);\n\n templates.forEach((tpl) => {\n const metaPath = path.join(getTemplateBasePath(type), tpl.lowerName, 'template.json');\n const meta = loadJSON(metaPath) || {};\n meta.enabled = tpl.lowerName === name.toLowerCase();\n saveJSON(metaPath, meta);\n });\n\n onTemplateSelect(type, name);\n}\n\n// --- EVENTS (replace with your event system integration) ---\n\nexport function onModuleEnabled(name: string) {\n console.log(`Module enabled: ${name}`);\n // emit event or custom logic here\n}\n\nexport function onModuleDisabled(name: string) {\n console.log(`Module disabled: ${name}`);\n}\n\nexport function onServiceEnabled(name: string) {\n console.log(`Service enabled: ${name}`);\n}\n\nexport function onServiceDisabled(name: string) {\n console.log(`Service disabled: ${name}`);\n}\n\nexport function onTemplateSelect(type: TemplateType, name: string) {\n console.log(`Template selected: type=${type}, name=${name}`);\n}\n\n// --- REGISTER HOOKS FOR MODULES ---\n\nexport async function registerEvents() {\n if (!useSettings.getPaths().modules) throw new Error('Modules path not registered.');\n const modules = getModules().filter((m) => m.enabled);\n for (const mod of modules) {\n const eventsFile = path.join(useSettings.getPaths().modules, mod.lowerName, 'events.server.js');\n if (fs.existsSync(eventsFile)) {\n const modEvents = await import(eventsFile);\n if (modEvents?.registerEvents) await modEvents.registerEvents();\n }\n }\n}\n\nexport async function registerMiddleware() {\n if (!useSettings.getPaths().modules) throw new Error('Modules path not registered.');\n const modules = getModules().filter((m) => m.enabled);\n for (const mod of modules) {\n const middlewareFile = path.join(useSettings.getPaths().modules, mod.lowerName, 'middleware.server.js');\n if (fs.existsSync(middlewareFile)) {\n const modMiddleware = await import(middlewareFile);\n if (modMiddleware?.registerMiddleware) await modMiddleware.registerMiddleware();\n }\n }\n}\n\n/**\n * Registers routes given a path to routes folder (for pages and API routes)\n * @param routesFolderPath string - path to module/service routes folder\n */\nexport async function registerRoutes(routesFolderPath: string) {\n if (!fs.existsSync(routesFolderPath)) return;\n\n const routeFiles = fs.readdirSync(routesFolderPath).filter((f: any) => /\\.(js|ts|jsx|tsx)$/.test(f));\n for (const file of routeFiles) {\n const routeModule = await import(path.join(routesFolderPath, file));\n if (routeModule?.registerRoute) {\n await routeModule.registerRoute();\n }\n }\n}\n\nexport async function loadProviders() {\n const providers = useProviders.getProviders({ enabledOnly: true });\n\n for (const provider of providers) {\n try {\n let providerAbsPath = provider.filePath;\n\n const ext = path.extname(providerAbsPath);\n if (ext === '.ts' || ext === '.tsx') {\n const jsPath = providerAbsPath.replace(/\\.(ts|tsx)$/, '.js');\n try {\n fs.accessSync(jsPath);\n providerAbsPath = jsPath;\n } catch {\n throw new Error(`Compiled JS version not found for provider: ${provider.relativePath}`);\n }\n }\n\n const providerUrl = toFileUrl(providerAbsPath);\n const providerModule = await import(providerUrl);\n\n if (typeof providerModule.default === 'function') {\n (globalThis as any).__retrex_provider_context__ = {\n type: provider.ownerType,\n name: provider.ownerLowerName,\n provider: provider.name,\n tags: provider.tags,\n };\n await providerModule.default();\n (globalThis as any).__retrex_provider_context__ = undefined;\n console.log(\n `[${provider.ownerType}] ✅ Provider loaded: ${provider.name} (${provider.relativePath})`,\n );\n } else {\n console.warn(\n `[${provider.ownerType}] ⚠️ Provider ${provider.relativePath} has no default export.`,\n );\n }\n } catch (err) {\n console.error(\n `[${provider.ownerType}] ❌ Failed to load provider ${provider.relativePath}:`,\n err,\n );\n }\n }\n}\n\n\n// export async function loadProviders() {\n// paths = {\n// modules: useSettings.getPaths().modules,\n// templates: useSettings.getPaths().templates,\n// services: useSettings.getPaths().services,\n// events: useSettings.getPaths().events,\n// }\n// const all = [\n// { type: 'module', list: getModules(), basePath: useSettings.getPaths().modules },\n// { type: 'service', list: getServices(), basePath: useSettings.getPaths().services },\n// ];\n\n// for (const { type, list, basePath } of all) {\n// for (const item of list) {\n// if (!item.enabled) continue;\n\n// const metaPath = path.join(basePath, item.lowerName, `${type}.json`);\n// const meta = loadJSON(metaPath);\n// if (!meta?.providers || !Array.isArray(meta.providers)) continue;\n\n// for (const providerRelPath of meta.providers) {\n// try {\n// const providerPath = path.join(basePath, item.lowerName, providerRelPath);\n// const providerModule = await import(providerPath);\n// if (typeof providerModule.default === 'function') {\n// await providerModule.default(); // Call provider\n// console.log(`[${type}] Provider loaded: ${providerRelPath}`);\n// } else {\n// console.warn(`[${type}] Provider ${providerRelPath} has no default export.`);\n// }\n// } catch (err) {\n// console.error(`[${type}] Failed to load provider ${providerRelPath}:`, err);\n// }\n// }\n// }\n// }\n// }\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { useSettings } from './useSettings';\nimport type { ProviderMeta, ProviderOwnerType } from '../types';\n\ntype ManifestRecord = {\n providers?: string[];\n enabled?: boolean;\n lowerName?: string;\n name?: string;\n};\n\ntype ProviderSource = {\n ownerType: ProviderOwnerType;\n ownerName: string;\n ownerLowerName: string;\n enabled: boolean;\n manifestPath: string;\n baseDir: string;\n providerPaths: string[];\n};\n\nconst PROVIDER_MARKER_REGEX =\n /\\/\\*\\s*@retrex-provider\\s*=\\s*(\\[[\\s\\S]*?\\]|\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*')\\s*\\*\\//;\n\nfunction loadManifest(filePath: string): ManifestRecord | null {\n if (!fs.existsSync(filePath)) return null;\n\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf-8')) as ManifestRecord;\n } catch {\n return null;\n }\n}\n\nfunction getAppProvidersSource(): ProviderSource | null {\n const appRoot = path.resolve('./app');\n const manifestPath = path.join(appRoot, 'app.json');\n const manifest = loadManifest(manifestPath);\n if (!manifest?.providers || !Array.isArray(manifest.providers)) return null;\n\n return {\n ownerType: 'app',\n ownerName: manifest.name || 'App',\n ownerLowerName: manifest.lowerName || 'app',\n enabled: true,\n manifestPath,\n baseDir: appRoot,\n providerPaths: manifest.providers,\n };\n}\n\nfunction getDirectorySources(\n rootDir: string,\n ownerType: Extract<ProviderOwnerType, 'module' | 'service'>,\n): ProviderSource[] {\n if (!fs.existsSync(rootDir)) return [];\n\n const manifestFileName = ownerType === 'module' ? 'module.json' : 'service.json';\n\n return fs\n .readdirSync(rootDir)\n .filter((entry) => {\n const entryPath = path.join(rootDir, entry);\n return fs.existsSync(entryPath) && fs.statSync(entryPath).isDirectory();\n })\n .flatMap((entry) => {\n const baseDir = path.join(rootDir, entry);\n const manifestPath = path.join(baseDir, manifestFileName);\n const manifest = loadManifest(manifestPath);\n if (!manifest?.providers || !Array.isArray(manifest.providers)) return [];\n\n return [\n {\n ownerType,\n ownerName: manifest.name || entry,\n ownerLowerName: manifest.lowerName || entry.toLowerCase(),\n enabled: manifest.enabled ?? false,\n manifestPath,\n baseDir,\n providerPaths: manifest.providers,\n },\n ];\n });\n}\n\nfunction extractProviderTags(filePath: string): string[] | null {\n if (!fs.existsSync(filePath)) return null;\n\n const source = fs.readFileSync(filePath, 'utf-8');\n const head = source.slice(0, 2048);\n const match = head.match(PROVIDER_MARKER_REGEX);\n if (!match?.[1]) return null;\n\n const raw = match[1].trim();\n\n try {\n if (raw.startsWith('[')) {\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return null;\n\n const tags = parsed\n .map((value) => (typeof value === 'string' ? value.trim() : ''))\n .filter(Boolean);\n\n return tags.length > 0 ? tags : null;\n }\n\n const normalized = raw.startsWith(\"'\")\n ? `\"${raw.slice(1, -1).replace(/\"/g, '\\\\\"')}\"`\n : raw;\n const parsed = JSON.parse(normalized);\n return typeof parsed === 'string' && parsed.trim() ? [parsed.trim()] : null;\n } catch {\n return null;\n }\n}\n\nfunction normalizeProviderPath(baseDir: string, providerPath: string): string {\n return path.resolve(baseDir, providerPath);\n}\n\nfunction buildProviderMeta(source: ProviderSource, providerPath: string): ProviderMeta | null {\n const absolutePath = normalizeProviderPath(source.baseDir, providerPath);\n const tags = extractProviderTags(absolutePath);\n if (!tags) return null;\n\n return {\n id: `${source.ownerType}:${source.ownerLowerName}:${providerPath}`,\n name: tags[0],\n tags,\n filePath: absolutePath,\n relativePath: providerPath,\n manifestPath: source.manifestPath,\n ownerType: source.ownerType,\n ownerName: source.ownerName,\n ownerLowerName: source.ownerLowerName,\n enabled: source.enabled,\n };\n}\n\nexport const useProviders = {\n load(options?: { enabledOnly?: boolean }): ProviderMeta[] {\n const paths = useSettings.getPaths();\n\n const sources: ProviderSource[] = [\n ...getDirectorySources(path.resolve(paths.modules), 'module'),\n ...getDirectorySources(path.resolve(paths.services), 'service'),\n ];\n\n const appSource = getAppProvidersSource();\n if (appSource) sources.unshift(appSource);\n\n const providers = sources.flatMap((source) =>\n source.providerPaths\n .map((providerPath) => buildProviderMeta(source, providerPath))\n .filter((provider): provider is ProviderMeta => provider !== null),\n );\n\n return options?.enabledOnly ? providers.filter((provider) => provider.enabled) : providers;\n },\n\n getProviders(options?: { enabledOnly?: boolean }): ProviderMeta[] {\n return useProviders.load(options);\n },\n\n allEnabled(): ProviderMeta[] {\n return useProviders.load({ enabledOnly: true });\n },\n\n forOwner(ownerType: ProviderOwnerType, ownerName: string): ProviderMeta[] {\n const normalizedName = ownerName.toLowerCase();\n return useProviders.load().filter(\n (provider) =>\n provider.ownerType === ownerType &&\n provider.ownerLowerName.toLowerCase() === normalizedName,\n );\n },\n};\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\nimport AdmZip from 'adm-zip';\n\nexport async function downloadGitHubFolderZip(\n repo: string,\n folderPath: string,\n dest: string\n) {\n try {\n const [owner, repoName] = repo.split('/');\n const branch = 'main';\n const zipUrl = `https://github.com/${owner}/${repoName}/archive/refs/heads/${branch}.zip`;\n\n const res = await fetch(zipUrl);\n if (!res.ok) throw new Error(`Failed to fetch from GitHub: ${res.status}`);\n\n const buffer = Buffer.from(await res.arrayBuffer());\n const zip = new AdmZip(buffer);\n\n const prefix = `${repoName}-${branch}/${folderPath}`;\n\n const zipEntries = zip.getEntries();\n\n await mkdir(dest, { recursive: true });\n\n for (const entry of zipEntries) {\n if (!entry.entryName.startsWith(prefix)) continue;\n\n const relativePath = entry.entryName.slice(prefix.length + 1);\n if (!relativePath) continue; // skip the folder root\n\n const outPath = path.join(dest, relativePath);\n\n if (entry.isDirectory) {\n await mkdir(outPath, { recursive: true });\n } else {\n await mkdir(path.dirname(outPath), { recursive: true });\n await writeFile(outPath, entry.getData());\n }\n }\n\n console.log(`✓ Extracted ${folderPath} from ${repo} to ${dest}`);\n } catch (error: any) {\n console.error('[Github Download | Error]', error);\n console.error(`[Github Download | Error] Error downloading GitHub folder: ${error.message}`);\n throw new Error(`[Github Download | Error] Failed to download folder from github repo: ${error.message}`);\n }\n}\n","import { mkdir, writeFile, readFile, rm, access } from 'node:fs/promises';\n\nexport async function ensureDir(dirPath: string) {\n try {\n await mkdir(dirPath, { recursive: true });\n } catch {}\n}\n\nexport async function writeJson(filePath: string, data: any) {\n await writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');\n}\n\nexport async function readJson(filePath: string) {\n const content = await readFile(filePath, 'utf-8');\n return JSON.parse(content);\n}\n\nexport async function deleteDir(dirPath: string) {\n await rm(dirPath, { recursive: true, force: true });\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n","import path from 'node:path';\nimport { useSettings } from '!/core/hooks/useSettings';\nimport { downloadGitHubFolderZip } from '../utils/github';\nimport { writeJson } from '../utils/files';\nimport chalk from 'chalk';\n\ninterface Options {\n name: string;\n}\n\nexport async function createService({ name }: Options) {\n console.log(chalk.cyan(`Creating service \"${name}\"...`));\n try {\n const basePath = useSettings.getPaths().services;\n const servicePath = path.join(basePath, name);\n\n await downloadGitHubFolderZip(\n 'RetroPeak-Solutions/retrex-extensibles-templates',\n `services/default`,\n servicePath\n );\n\n const jsonPath = path.join(servicePath, 'service.json');\n const json = {\n name,\n lowerName: name.toLowerCase()\n };\n\n await writeJson(jsonPath, json);\n console.log(chalk.green(`[Service Created] ${name} created at ${servicePath}`));\n } catch (error: any) {\n console.error(chalk.red(`[Service Creation | Error] Failed to create service: ${error.message}`));\n throw error;\n }\n}","import path from 'node:path';\nimport { useSettings } from '!/core/hooks/useSettings';\nimport chalk from 'chalk';\nimport { downloadGitHubFolderZip } from '../utils/github.js';\nimport { writeJson } from '../utils/files.js';\n\nexport type TemplateTypeCLI = 'admin' | 'client' | 'portal' | 'email';\n\ninterface CreateTemplateOptions {\n type: TemplateTypeCLI;\n name: string;\n repoUrl?: string; // optional override for GitHub template repo\n}\n\nexport async function createTemplate({\n type,\n name,\n repoUrl = 'RetroPeak-Solutions/retrex-extensibles-templates'\n}: CreateTemplateOptions) {\n console.log(chalk.cyan(`Creating ${type} template \"${name}\"...`));\n try {\n if (!['admin', 'client', 'portal', 'email'].includes(type)) {\n throw new Error(`Invalid template type: ${type}. Valid types are: admin, client, portal, email.`);\n }\n\n if (!name) {\n throw new Error('Template name is required.');\n }\n\n // Ensure the name is valid\n if (!/^[a-zA-Z0-9-_]+$/.test(name)) {\n throw new Error(`Invalid template name: \"${name}\". Only alphanumeric characters, dashes, and underscores are allowed.`);\n }\n\n // // Ensure the repo URL is valid\n // if (!/^https:\\/\\/github\\.com\\/[a-zA-Z0-9-_]+\\/[a-zA-Z0-9-_]+$/.test(repoUrl)) {\n // throw new Error(`Invalid GitHub repository URL: ${repoUrl}. It should be in the format `);\n // }\n\n const paths = useSettings.getPaths();\n const basePath = paths.templates;\n\n const fullPath = path.join(basePath, type, name);\n\n console.log(chalk.cyan(`Downloading ${type} template \"${name}\" from ${repoUrl}`));\n\n await downloadGitHubFolderZip(\n repoUrl,\n `themes/${type}/default`, // assumes folder structure matches repo layout\n fullPath\n );\n\n // const jsonPath = path.join(fullPath, `template.json`);\n // await writeJson(jsonPath, {\n // name,\n // lowerName: name.toLowerCase()\n // });\n\n console.log(chalk.green(`[Template Created] ${type} template \"${name}\" created at ${fullPath}`));\n } catch (error: any) {\n console.error(chalk.red(`[Template Creation | Error] Failed to create template: ${error.message}`));\n throw error;\n }\n}","import { build } from 'esbuild';\nimport fg from 'fast-glob';\nimport chalk from 'chalk';\nimport { useSettings } from '!/core/hooks/useSettings';\n\nexport type CompileOptionsType =\n | 'module'\n | 'service'\n | 'admin-theme'\n | 'client-theme'\n | 'portal'\n | 'email';\n\ninterface CompileOptions {\n type: CompileOptionsType;\n name: string;\n}\n\nfunction join(...segments: string[]) {\n return segments.join('/').replace(/\\/+/g, '/');\n}\n\nexport async function compileExtensible({ type, name }: CompileOptions) {\n try {\n console.log(chalk.cyan(`Compiling ${type} files for ${name}`));\n\n const patterns: string[] = [];\n const paths = useSettings.getPaths();\n\n if (type && name) {\n let basePath = '';\n let subPath = '';\n\n if (type !== 'client-theme' && type !== 'admin-theme') {\n // @ts-ignore\n basePath = paths[`${type}s`];\n patterns.push(join(basePath, name, '**/*.ts'));\n patterns.push(join(basePath, name, '**/*.tsx'));\n } else {\n basePath = paths.templates;\n subPath = type === 'client-theme' ? 'client' : 'admin';\n patterns.push(join(basePath, subPath, name, '**/*.ts'));\n patterns.push(join(basePath, subPath, name, '**/*.tsx'));\n }\n } else {\n patterns.push(join(paths.modules, '**/**/*.ts'));\n patterns.push(join(paths.modules, '**/**/*.tsx'));\n patterns.push(join(paths.services, '**/**/*.ts'));\n patterns.push(join(paths.services, '**/**/*.tsx'));\n patterns.push(join(paths.templates, '**/**/*.ts'));\n patterns.push(join(paths.templates, '**/**/*.tsx'));\n }\n\n const files = await fg(patterns, {\n ignore: ['**/*.test.ts', '**/*.test.tsx'],\n });\n\n for (const file of files) {\n const outFile = file.replace(/\\.(ts|tsx)$/, '.js');\n\n await build({\n entryPoints: [file],\n outfile: outFile,\n format: 'esm',\n platform: 'node',\n target: 'node20',\n sourcemap: true,\n bundle: false,\n loader: {\n '.ts': 'ts',\n '.tsx': 'tsx',\n },\n external: ['fs', 'path', 'node:fs', 'node:path'],\n }).catch((error) => {\n console.error(\n chalk.redBright(\n `[Compiler | Error] Failed to compile ${file}: ${error.message}`\n )\n );\n throw error;\n });\n\n console.log(chalk.blue(`✓ Compiled ${file}`));\n }\n\n console.log(chalk.green(`[Compiler | Success] ✓ Compilation finished.`));\n } catch (e: any) {\n console.error(\n chalk.redBright(\n '[Compiler | Error] Failed to Complete the Compile Process:',\n e?.message\n )\n );\n }\n}\n"],"mappings":";;;AAEA,OAAO,WAAW;AAClB,SAAS,eAAe;;;ACHxB,OAAOA,WAAU;;;ACGjB,OAAOC,SAAQ;;;ACDf,OAAOC,SAAQ;AACf,OAAOC,WAAU;;;ACHjB,OAAO,QAAQ;AACf,OAAO,UAAU;;;ADoBV,SAAS,SAAS,UAAuB;AAC9C,MAAI,CAACC,IAAG,WAAW,QAAQ,EAAG,QAAO;AACrC,SAAO,KAAK,MAAMA,IAAG,aAAa,UAAU,OAAO,CAAC;AACtD;AAEO,SAAS,SAAS,UAAkB,MAAW;AACpD,EAAAA,IAAG,cAAc,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,OAAO;AACnE;;;ADpBA,IAAM,eAAgC;AAAA,EACpC,SAAS;AAAA,EACT,WAAW;AAAA,EACX,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,WAAW;AACb;AAEA,IAAI,kBAAmC,EAAE,GAAG,aAAa;AACzD,IAAM,WAAW,OAAO,WAAW;AAG5B,IAAM,cAAc;AAAA,EACzB,WAA4B;AAC1B,QAAI,UAAU;AACZ,YAAM,OAAO,SAAS,4BAA4B;AAClD,UAAI,KAAM,mBAAkB;AAAA,IAC9B;AAEA,QAAI,UAAU;AACZ,iBAAW,OAAO,OAAO,KAAK,YAAY,GAAmC;AAC3E,cAAM,YAAY,gBAAgB,GAAG;AACrC,YAAI,CAAC,aAAa,CAACC,IAAG,WAAW,SAAS,GAAG;AAC3C,0BAAgB,GAAG,IAAI,aAAa,GAAG;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAEA,sBAAkB;AAAA,MAChB,GAAG;AAAA,MACH,OAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,SAAS,OAAuC;AAC9C,QAAI,UAAU;AACZ,eAAS,8BAA8B;AAAA,QACrC,GAAG;AAAA,QACH,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAEA,sBAAkB;AAAA,MAChB,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAAA,EACF;AAAA,EAEA,YAAY,KAAqB;AAC/B,WAAO;AAAA,EACT;AAAA,EACA,YAAY,KAAa,OAAqB;AAC5C;AAAA,EACF;AACF;;;AD/DA,OAAO,WAAW;;;AIFlB,SAAS,OAAO,iBAAiB;AACjC,OAAOC,WAAU;AAEjB,OAAO,YAAY;AAEnB,eAAsB,wBACpB,MACA,YACA,MACA;AACA,MAAI;AACF,UAAM,CAAC,OAAO,QAAQ,IAAI,KAAK,MAAM,GAAG;AACxC,UAAM,SAAS;AACf,UAAM,SAAS,sBAAsB,KAAK,IAAI,QAAQ,uBAAuB,MAAM;AAEnF,UAAM,MAAM,MAAM,MAAM,MAAM;AAC9B,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,gCAAgC,IAAI,MAAM,EAAE;AAEzE,UAAM,SAAS,OAAO,KAAK,MAAM,IAAI,YAAY,CAAC;AAClD,UAAM,MAAM,IAAI,OAAO,MAAM;AAE7B,UAAM,SAAS,GAAG,QAAQ,IAAI,MAAM,IAAI,UAAU;AAElD,UAAM,aAAa,IAAI,WAAW;AAElC,UAAM,MAAM,MAAM,EAAE,WAAW,KAAK,CAAC;AAErC,eAAW,SAAS,YAAY;AAC9B,UAAI,CAAC,MAAM,UAAU,WAAW,MAAM,EAAG;AAEzC,YAAM,eAAe,MAAM,UAAU,MAAM,OAAO,SAAS,CAAC;AAC5D,UAAI,CAAC,aAAc;AAEnB,YAAM,UAAUA,MAAK,KAAK,MAAM,YAAY;AAE5C,UAAI,MAAM,aAAa;AACrB,cAAM,MAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,MAC1C,OAAO;AACL,cAAM,MAAMA,MAAK,QAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AACtD,cAAM,UAAU,SAAS,MAAM,QAAQ,CAAC;AAAA,MAC1C;AAAA,IACF;AAEA,YAAQ,IAAI,oBAAe,UAAU,SAAS,IAAI,OAAO,IAAI,EAAE;AAAA,EACjE,SAAS,OAAY;AACnB,YAAQ,MAAM,6BAA6B,KAAK;AAChD,YAAQ,MAAM,8DAA8D,MAAM,OAAO,EAAE;AAC3F,UAAM,IAAI,MAAM,yEAAyE,MAAM,OAAO,EAAE;AAAA,EAC1G;AACF;;;ACjDA,SAAS,SAAAC,QAAO,aAAAC,YAAW,UAAU,IAAI,cAAc;AAQvD,eAAsB,UAAU,UAAkB,MAAW;AAC3D,QAAMC,WAAU,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,OAAO;AAClE;;;ALJA,IAAM,cAAc,QAAQ,IAAI,wBAAwB;AAKxD,eAAsB,aAAa,EAAE,KAAK,GAAY;AACpD,UAAQ,IAAI,MAAM,KAAK,oBAAoB,IAAI,MAAM,CAAC;AACtD,MAAI;AACF,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAGA,QAAI,CAAC,mBAAmB,KAAK,IAAI,GAAG;AAClC,YAAM,IAAI,MAAM,yBAAyB,IAAI,uEAAuE;AAAA,IACtH;AAGA,QAAI,CAAC,0DAA0D,KAAK,WAAW,GAAG;AAChF,YAAM,IAAI,MAAM,kCAAkC,WAAW,8BAA8B;AAAA,IAC7F;AACA,UAAM,WAAW,YAAY,SAAS,EAAE;AACxC,UAAM,aAAaC,MAAK,KAAK,UAAU,IAAI;AAE3C,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,WAAWA,MAAK,KAAK,YAAY,aAAa;AACpD,UAAM,OAAO;AAAA,MACX;AAAA,MACA,WAAW,KAAK,YAAY;AAAA,IAC9B;AAEA,UAAM,UAAU,UAAU,IAAI;AAC9B,YAAQ,IAAI,MAAM,MAAM,oBAAoB,IAAI,eAAe,UAAU,EAAE,CAAC;AAAA,EAC9E,SAAS,OAAY;AACnB,YAAQ,MAAM,MAAM,IAAI,sDAAsD,MAAM,OAAO,EAAE,CAAC;AAC9F,UAAM;AAAA,EACR;AACF;;;AMhDA,OAAOC,WAAU;AAIjB,OAAOC,YAAW;AAMlB,eAAsB,cAAc,EAAE,KAAK,GAAY;AACrD,UAAQ,IAAIA,OAAM,KAAK,qBAAqB,IAAI,MAAM,CAAC;AACvD,MAAI;AACF,UAAM,WAAW,YAAY,SAAS,EAAE;AACxC,UAAM,cAAcC,MAAK,KAAK,UAAU,IAAI;AAE5C,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,WAAWA,MAAK,KAAK,aAAa,cAAc;AACtD,UAAM,OAAO;AAAA,MACX;AAAA,MACA,WAAW,KAAK,YAAY;AAAA,IAC9B;AAEA,UAAM,UAAU,UAAU,IAAI;AAC9B,YAAQ,IAAID,OAAM,MAAM,qBAAqB,IAAI,eAAe,WAAW,EAAE,CAAC;AAAA,EAChF,SAAS,OAAY;AACnB,YAAQ,MAAMA,OAAM,IAAI,wDAAwD,MAAM,OAAO,EAAE,CAAC;AAChG,UAAM;AAAA,EACR;AACF;;;AClCA,OAAOE,WAAU;AAEjB,OAAOC,YAAW;AAYlB,eAAsB,eAAe;AAAA,EACnC;AAAA,EACA;AAAA,EACA,UAAU;AACZ,GAA0B;AACxB,UAAQ,IAAIC,OAAM,KAAK,YAAY,IAAI,cAAc,IAAI,MAAM,CAAC;AAChE,MAAI;AACF,QAAI,CAAC,CAAC,SAAS,UAAU,UAAU,OAAO,EAAE,SAAS,IAAI,GAAG;AAC1D,YAAM,IAAI,MAAM,0BAA0B,IAAI,kDAAkD;AAAA,IAClG;AAEA,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,4BAA4B;AAAA,IAC9C;AAGA,QAAI,CAAC,mBAAmB,KAAK,IAAI,GAAG;AAClC,YAAM,IAAI,MAAM,2BAA2B,IAAI,uEAAuE;AAAA,IACxH;AAOA,UAAM,QAAQ,YAAY,SAAS;AACnC,UAAM,WAAW,MAAM;AAEvB,UAAM,WAAWC,MAAK,KAAK,UAAU,MAAM,IAAI;AAE/C,YAAQ,IAAID,OAAM,KAAK,eAAe,IAAI,cAAc,IAAI,UAAU,OAAO,EAAE,CAAC;AAEhF,UAAM;AAAA,MACJ;AAAA,MACA,UAAU,IAAI;AAAA;AAAA,MACd;AAAA,IACF;AAQA,YAAQ,IAAIA,OAAM,MAAM,sBAAsB,IAAI,cAAc,IAAI,gBAAgB,QAAQ,EAAE,CAAC;AAAA,EACjG,SAAS,OAAY;AACnB,YAAQ,MAAMA,OAAM,IAAI,0DAA0D,MAAM,OAAO,EAAE,CAAC;AAClG,UAAM;AAAA,EACR;AACF;;;AC/DA,SAAS,aAAa;AACtB,OAAO,QAAQ;AACf,OAAOE,YAAW;AAgBlB,SAAS,QAAQ,UAAoB;AACnC,SAAO,SAAS,KAAK,GAAG,EAAE,QAAQ,QAAQ,GAAG;AAC/C;AAEA,eAAsB,kBAAkB,EAAE,MAAM,KAAK,GAAmB;AACtE,MAAI;AACF,YAAQ,IAAIC,OAAM,KAAK,aAAa,IAAI,cAAc,IAAI,EAAE,CAAC;AAE7D,UAAM,WAAqB,CAAC;AAC5B,UAAM,QAAQ,YAAY,SAAS;AAEnC,QAAI,QAAQ,MAAM;AAChB,UAAI,WAAW;AACf,UAAI,UAAU;AAEd,UAAI,SAAS,kBAAkB,SAAS,eAAe;AAErD,mBAAW,MAAM,GAAG,IAAI,GAAG;AAC3B,iBAAS,KAAK,KAAK,UAAU,MAAM,SAAS,CAAC;AAC7C,iBAAS,KAAK,KAAK,UAAU,MAAM,UAAU,CAAC;AAAA,MAChD,OAAO;AACL,mBAAW,MAAM;AACjB,kBAAU,SAAS,iBAAiB,WAAW;AAC/C,iBAAS,KAAK,KAAK,UAAU,SAAS,MAAM,SAAS,CAAC;AACtD,iBAAS,KAAK,KAAK,UAAU,SAAS,MAAM,UAAU,CAAC;AAAA,MACzD;AAAA,IACF,OAAO;AACL,eAAS,KAAK,KAAK,MAAM,SAAS,YAAY,CAAC;AAC/C,eAAS,KAAK,KAAK,MAAM,SAAS,aAAa,CAAC;AAChD,eAAS,KAAK,KAAK,MAAM,UAAU,YAAY,CAAC;AAChD,eAAS,KAAK,KAAK,MAAM,UAAU,aAAa,CAAC;AACjD,eAAS,KAAK,KAAK,MAAM,WAAW,YAAY,CAAC;AACjD,eAAS,KAAK,KAAK,MAAM,WAAW,aAAa,CAAC;AAAA,IACpD;AAEA,UAAM,QAAQ,MAAM,GAAG,UAAU;AAAA,MAC/B,QAAQ,CAAC,gBAAgB,eAAe;AAAA,IAC1C,CAAC;AAED,eAAW,QAAQ,OAAO;AACxB,YAAM,UAAU,KAAK,QAAQ,eAAe,KAAK;AAEjD,YAAM,MAAM;AAAA,QACV,aAAa,CAAC,IAAI;AAAA,QAClB,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,QAAQ;AAAA,UACN,OAAO;AAAA,UACP,QAAQ;AAAA,QACV;AAAA,QACA,UAAU,CAAC,MAAM,QAAQ,WAAW,WAAW;AAAA,MACjD,CAAC,EAAE,MAAM,CAAC,UAAU;AAClB,gBAAQ;AAAA,UACNA,OAAM;AAAA,YACJ,wCAAwC,IAAI,KAAK,MAAM,OAAO;AAAA,UAChE;AAAA,QACF;AACA,cAAM;AAAA,MACR,CAAC;AAED,cAAQ,IAAIA,OAAM,KAAK,mBAAc,IAAI,EAAE,CAAC;AAAA,IAC9C;AAEA,YAAQ,IAAIA,OAAM,MAAM,mDAA8C,CAAC;AAAA,EACzE,SAAS,GAAQ;AACf,YAAQ;AAAA,MACNA,OAAM;AAAA,QACJ;AAAA,QACA,GAAG;AAAA,MACL;AAAA,IACF;AAAA,EACF;AACF;;;ATrFA,MAAM,QAAQ,QAAQ,IAAI,CAAC,EACxB;AAAA,EACC;AAAA,EACA;AAAA,EACA,CAACC,WAAUA,OAAM,WAAW,QAAQ,EAAE,MAAM,UAAU,UAAU,cAAc,CAAC;AAAA,EAC/E,OAAO,SAAS,MAAM,aAAa,EAAE,MAAM,KAAK,KAAe,CAAC;AAClE,EACC;AAAA,EACC;AAAA,EACA;AAAA,EACA,CAACA,WAAUA,OAAM,WAAW,QAAQ,EAAE,MAAM,UAAU,UAAU,eAAe,CAAC;AAAA,EAChF,OAAO,SAAS,MAAM,cAAc,EAAE,MAAM,KAAK,KAAe,CAAC;AACnE,EACC;AAAA,EACC;AAAA,EACA;AAAA,EACA,CAACA,WACCA,OACG,WAAW,QAAQ;AAAA,IAClB,MAAM;AAAA,IACN,UAAU;AAAA,IACV,SAAS,CAAC,SAAS,UAAU,UAAU,OAAO;AAAA,EAChD,CAAC,EACA,WAAW,QAAQ,EAAE,MAAM,UAAU,UAAU,gBAAgB,CAAC;AAAA,EACrE,OAAO,SAAS,MAAM,eAAe,EAAE,MAAM,KAAK,MAAa,MAAM,KAAK,KAAe,CAAC;AAC5F,EACC;AAAA,EACC;AAAA,EACA;AAAA,EACA,CAACA,WACCA,OACG,WAAW,QAAQ;AAAA,IAClB,MAAM;AAAA,IACN,UAAU;AAAA,IACV,SAAS,CAAC,UAAU,WAAW,eAAe,gBAAgB,UAAU,OAAO;AAAA,EACjF,CAAC,EACA,WAAW,QAAQ,EAAE,MAAM,UAAU,UAAU,kBAAkB,CAAC;AAAA,EACvE,OAAO,SAAS,MAAM,kBAAkB,EAAE,MAAM,KAAK,MAA4B,MAAM,KAAK,KAAe,CAAC;AAC9G,EACC,cAAc,GAAG,yFAAyF,EAC1G,KAAK,EAAE;","names":["path","fs","fs","path","fs","fs","path","mkdir","writeFile","writeFile","path","path","chalk","path","path","chalk","chalk","path","chalk","chalk","yargs"]}
|