@doubledigit/cli 0.1.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/LICENSE +21 -0
- package/dist/codegen.d.ts +12 -0
- package/dist/codegen.d.ts.map +1 -0
- package/dist/codegen.js +107 -0
- package/dist/commands/add.d.ts +26 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +548 -0
- package/dist/commands/browse.d.ts +8 -0
- package/dist/commands/browse.d.ts.map +1 -0
- package/dist/commands/browse.js +116 -0
- package/dist/commands/create.d.ts +12 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +218 -0
- package/dist/commands/db.d.ts +2 -0
- package/dist/commands/db.d.ts.map +1 -0
- package/dist/commands/db.js +64 -0
- package/dist/commands/disable.d.ts +5 -0
- package/dist/commands/disable.d.ts.map +1 -0
- package/dist/commands/disable.js +29 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +88 -0
- package/dist/commands/enable.d.ts +5 -0
- package/dist/commands/enable.d.ts.map +1 -0
- package/dist/commands/enable.js +29 -0
- package/dist/commands/info.d.ts +8 -0
- package/dist/commands/info.d.ts.map +1 -0
- package/dist/commands/info.js +84 -0
- package/dist/commands/list.d.ts +5 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +44 -0
- package/dist/commands/marketplace.d.ts +11 -0
- package/dist/commands/marketplace.d.ts.map +1 -0
- package/dist/commands/marketplace.js +205 -0
- package/dist/commands/onboard.d.ts +2 -0
- package/dist/commands/onboard.d.ts.map +1 -0
- package/dist/commands/onboard.js +58 -0
- package/dist/commands/outdated.d.ts +8 -0
- package/dist/commands/outdated.d.ts.map +1 -0
- package/dist/commands/outdated.js +107 -0
- package/dist/commands/reconcile.d.ts +12 -0
- package/dist/commands/reconcile.d.ts.map +1 -0
- package/dist/commands/reconcile.js +175 -0
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +37 -0
- package/dist/commands/sync.d.ts +5 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +34 -0
- package/dist/commands/uninstall.d.ts +14 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +190 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +37 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +181 -0
- package/dist/lib/github-auth.d.ts +8 -0
- package/dist/lib/github-auth.d.ts.map +1 -0
- package/dist/lib/github-auth.js +30 -0
- package/dist/lib/lock-file.d.ts +67 -0
- package/dist/lib/lock-file.d.ts.map +1 -0
- package/dist/lib/lock-file.js +117 -0
- package/dist/lib/marketplace-schema.d.ts +607 -0
- package/dist/lib/marketplace-schema.d.ts.map +1 -0
- package/dist/lib/marketplace-schema.js +111 -0
- package/dist/lib/marketplace.d.ts +57 -0
- package/dist/lib/marketplace.d.ts.map +1 -0
- package/dist/lib/marketplace.js +270 -0
- package/dist/lib/onboarding.d.ts +84 -0
- package/dist/lib/onboarding.d.ts.map +1 -0
- package/dist/lib/onboarding.js +1004 -0
- package/dist/lib/rewrite-extension-tsconfig.d.ts +22 -0
- package/dist/lib/rewrite-extension-tsconfig.d.ts.map +1 -0
- package/dist/lib/rewrite-extension-tsconfig.js +80 -0
- package/dist/lib/source-parser.d.ts +35 -0
- package/dist/lib/source-parser.d.ts.map +1 -0
- package/dist/lib/source-parser.js +121 -0
- package/dist/lib/validators.d.ts +73 -0
- package/dist/lib/validators.d.ts.map +1 -0
- package/dist/lib/validators.js +435 -0
- package/dist/paths.d.ts +46 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +85 -0
- package/dist/scanner.d.ts +41 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +100 -0
- package/package.json +49 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dd create <name> ā Scaffold a new micro-app from the template.
|
|
3
|
+
*
|
|
4
|
+
* Steps:
|
|
5
|
+
* 1. Copy template-micro-app ā packages/<name>/
|
|
6
|
+
* 2. Replace template tokens in files
|
|
7
|
+
* 3. Add dependency to main-app/package.json
|
|
8
|
+
* 4. Add entry to dd-apps.config.json
|
|
9
|
+
* 5. Run sync to regenerate micro-apps.ts
|
|
10
|
+
*/
|
|
11
|
+
export declare function create(name: string): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAwFH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8JxD"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dd create <name> ā Scaffold a new micro-app from the template.
|
|
3
|
+
*
|
|
4
|
+
* Steps:
|
|
5
|
+
* 1. Copy template-micro-app ā packages/<name>/
|
|
6
|
+
* 2. Replace template tokens in files
|
|
7
|
+
* 3. Add dependency to main-app/package.json
|
|
8
|
+
* 4. Add entry to dd-apps.config.json
|
|
9
|
+
* 5. Run sync to regenerate micro-apps.ts
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { execSync } from 'node:child_process';
|
|
14
|
+
import { resolveWorkspacePaths, installDirForKind, installRelPath, allInstallRoots, allScanRoots, } from '../paths.js';
|
|
15
|
+
import { readConfig, writeConfig } from '../config.js';
|
|
16
|
+
import { sync } from './sync.js';
|
|
17
|
+
import { rewriteExtensionTsconfig } from '../lib/rewrite-extension-tsconfig.js';
|
|
18
|
+
import { validateNoNameCollision, validateSlugPrefix, } from '../lib/validators.js';
|
|
19
|
+
const SLUG_PREFIX_PATTERN = /^[a-z][a-z0-9]*(-[a-z][a-z0-9]*)*$/;
|
|
20
|
+
function toSlugPrefix(name) {
|
|
21
|
+
// Take first letter of each hyphenated word, max 3 chars
|
|
22
|
+
const parts = name.split('-');
|
|
23
|
+
return parts
|
|
24
|
+
.map((p) => p[0])
|
|
25
|
+
.join('')
|
|
26
|
+
.slice(0, 3)
|
|
27
|
+
.toLowerCase();
|
|
28
|
+
}
|
|
29
|
+
function toPascalCase(name) {
|
|
30
|
+
return name
|
|
31
|
+
.split('-')
|
|
32
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
33
|
+
.join('');
|
|
34
|
+
}
|
|
35
|
+
function toCamelCase(name) {
|
|
36
|
+
const pascal = toPascalCase(name);
|
|
37
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
38
|
+
}
|
|
39
|
+
function toTitleCase(name) {
|
|
40
|
+
return name
|
|
41
|
+
.split('-')
|
|
42
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
43
|
+
.join(' ');
|
|
44
|
+
}
|
|
45
|
+
function copyDirRecursive(src, dest, replacements, name) {
|
|
46
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
47
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
48
|
+
for (const entry of entries) {
|
|
49
|
+
const srcPath = path.join(src, entry.name);
|
|
50
|
+
const destPath = path.join(dest, entry.name);
|
|
51
|
+
// Skip node_modules, dist, .turbo, etc.
|
|
52
|
+
if (['node_modules', 'dist', '.turbo', 'tsconfig.tsbuildinfo'].includes(entry.name)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (entry.isDirectory()) {
|
|
56
|
+
copyDirRecursive(srcPath, destPath, replacements, name);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
let content = fs.readFileSync(srcPath, 'utf-8');
|
|
60
|
+
// Apply replacements
|
|
61
|
+
for (const [search, replace] of replacements) {
|
|
62
|
+
content = content.replaceAll(search, replace);
|
|
63
|
+
}
|
|
64
|
+
// Rename file if necessary
|
|
65
|
+
let finalDestName = entry.name;
|
|
66
|
+
if (entry.name === 'template-client.tsx') {
|
|
67
|
+
finalDestName = `${name}-client.tsx`;
|
|
68
|
+
}
|
|
69
|
+
const finalDestPath = path.join(dest, finalDestName);
|
|
70
|
+
fs.writeFileSync(finalDestPath, content, 'utf-8');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export async function create(name) {
|
|
75
|
+
// Validate name
|
|
76
|
+
if (!SLUG_PREFIX_PATTERN.test(name)) {
|
|
77
|
+
console.error(`ā Invalid name "${name}". Must be lowercase kebab-case (e.g. "invoice-tracker").`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
const paths = resolveWorkspacePaths();
|
|
81
|
+
const targetDir = installDirForKind(paths, 'micro-app', name);
|
|
82
|
+
const targetRelPath = installRelPath('micro-app', name);
|
|
83
|
+
const templateDir = path.join(paths.packagesDir, 'template-micro-app');
|
|
84
|
+
// Check template exists
|
|
85
|
+
if (!fs.existsSync(templateDir)) {
|
|
86
|
+
console.error(`ā Template not found at ${templateDir}`);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
// Check target doesn't already exist
|
|
90
|
+
if (fs.existsSync(targetDir)) {
|
|
91
|
+
console.error(`ā Directory already exists: ${targetDir}`);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
const slugPrefix = toSlugPrefix(name);
|
|
95
|
+
const pascalName = toPascalCase(name);
|
|
96
|
+
const camelName = toCamelCase(name);
|
|
97
|
+
const titleName = toTitleCase(name);
|
|
98
|
+
const npmName = `@doubledigit/${name}`;
|
|
99
|
+
const collisionResult = validateNoNameCollision(allInstallRoots(paths), name);
|
|
100
|
+
if (!collisionResult.valid) {
|
|
101
|
+
for (const error of collisionResult.errors) {
|
|
102
|
+
console.error(`ā ${error}`);
|
|
103
|
+
}
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
const slugResult = validateSlugPrefix(allScanRoots(paths), slugPrefix, name);
|
|
107
|
+
if (!slugResult.valid) {
|
|
108
|
+
for (const error of slugResult.errors) {
|
|
109
|
+
console.error(`ā ${error}`);
|
|
110
|
+
}
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
console.log(`\nš¦ Creating micro-app: ${name}`);
|
|
114
|
+
console.log(` Slug prefix: ${slugPrefix}`);
|
|
115
|
+
console.log(` Package: ${npmName}`);
|
|
116
|
+
console.log(` Directory: ${targetRelPath}\n`);
|
|
117
|
+
// Replacements map (template tokens ā actual values)
|
|
118
|
+
const replacements = new Map([
|
|
119
|
+
// Package name
|
|
120
|
+
['@doubledigit/template-micro-app', npmName],
|
|
121
|
+
// DDApp key
|
|
122
|
+
['template-micro-app', name],
|
|
123
|
+
// Slug prefix (tp- ā new prefix)
|
|
124
|
+
['tp-', `${slugPrefix}-`],
|
|
125
|
+
// PascalCase identifiers
|
|
126
|
+
['TemplateClient', `${pascalName}Client`],
|
|
127
|
+
['Template App', titleName],
|
|
128
|
+
['Template', pascalName],
|
|
129
|
+
// camelCase identifiers
|
|
130
|
+
['templateMicroApp', `${camelName}MicroApp`],
|
|
131
|
+
['templateCollections', `${camelName}Collections`],
|
|
132
|
+
['templateManifest', `${camelName}Manifest`],
|
|
133
|
+
['templateApiHandler', `${camelName}ApiHandler`],
|
|
134
|
+
// Description
|
|
135
|
+
['Template for scaffolding new Payload Micro-Apps', `${titleName} micro-app`],
|
|
136
|
+
// File names inside imports
|
|
137
|
+
['template-client', `${name}-client`],
|
|
138
|
+
// Static strings
|
|
139
|
+
["'/template'", `'/${name}'`],
|
|
140
|
+
['Template Micro-App', `${titleName} App`],
|
|
141
|
+
]);
|
|
142
|
+
// 1. Copy template (ensure parent dir exists for extensions/ layout)
|
|
143
|
+
fs.mkdirSync(path.dirname(targetDir), { recursive: true });
|
|
144
|
+
copyDirRecursive(templateDir, targetDir, replacements, name);
|
|
145
|
+
// 1b. Rewrite tsconfig relative paths for the new installation depth
|
|
146
|
+
rewriteExtensionTsconfig(targetDir, paths.root);
|
|
147
|
+
// 2. Fix package.json in target
|
|
148
|
+
const targetPkgPath = path.join(targetDir, 'package.json');
|
|
149
|
+
if (fs.existsSync(targetPkgPath)) {
|
|
150
|
+
const pkg = JSON.parse(fs.readFileSync(targetPkgPath, 'utf-8'));
|
|
151
|
+
pkg.name = npmName;
|
|
152
|
+
pkg.ddapp = true;
|
|
153
|
+
pkg.version = '0.1.0';
|
|
154
|
+
pkg.private = true;
|
|
155
|
+
pkg.description = `${titleName} micro-app`;
|
|
156
|
+
// Remove publishConfig if present (template has it)
|
|
157
|
+
delete pkg.publishConfig;
|
|
158
|
+
fs.writeFileSync(targetPkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
|
|
159
|
+
}
|
|
160
|
+
// 3. Add dependency to main-app/package.json
|
|
161
|
+
const mainPkg = JSON.parse(fs.readFileSync(paths.mainAppPackageJsonPath, 'utf-8'));
|
|
162
|
+
if (!mainPkg.dependencies)
|
|
163
|
+
mainPkg.dependencies = {};
|
|
164
|
+
mainPkg.dependencies[npmName] = 'workspace:*';
|
|
165
|
+
// Sort dependencies alphabetically
|
|
166
|
+
mainPkg.dependencies = Object.fromEntries(Object.entries(mainPkg.dependencies).sort(([a], [b]) => a.localeCompare(b)));
|
|
167
|
+
fs.writeFileSync(paths.mainAppPackageJsonPath, JSON.stringify(mainPkg, null, 2) + '\n', 'utf-8');
|
|
168
|
+
// 3b. Add TS path mappings
|
|
169
|
+
const baseTsConfigPath = path.join(paths.root, 'tsconfig.base.json');
|
|
170
|
+
if (fs.existsSync(baseTsConfigPath)) {
|
|
171
|
+
const tsconfig = JSON.parse(fs.readFileSync(baseTsConfigPath, 'utf-8'));
|
|
172
|
+
if (!tsconfig.compilerOptions)
|
|
173
|
+
tsconfig.compilerOptions = {};
|
|
174
|
+
if (!tsconfig.compilerOptions.paths)
|
|
175
|
+
tsconfig.compilerOptions.paths = {};
|
|
176
|
+
tsconfig.compilerOptions.paths[npmName] = [`${targetRelPath}/src/index.tsx`];
|
|
177
|
+
tsconfig.compilerOptions.paths[`${npmName}/*`] = [`${targetRelPath}/src/*`];
|
|
178
|
+
fs.writeFileSync(baseTsConfigPath, JSON.stringify(tsconfig, null, 2) + '\n', 'utf-8');
|
|
179
|
+
}
|
|
180
|
+
const mainTsConfigPath = path.join(paths.packagesDir, '../apps/main-app/tsconfig.json');
|
|
181
|
+
if (fs.existsSync(mainTsConfigPath)) {
|
|
182
|
+
const tsconfig = JSON.parse(fs.readFileSync(mainTsConfigPath, 'utf-8'));
|
|
183
|
+
if (!tsconfig.compilerOptions)
|
|
184
|
+
tsconfig.compilerOptions = {};
|
|
185
|
+
if (!tsconfig.compilerOptions.paths)
|
|
186
|
+
tsconfig.compilerOptions.paths = {};
|
|
187
|
+
tsconfig.compilerOptions.paths[npmName] = [`../../${targetRelPath}/src/index.tsx`];
|
|
188
|
+
tsconfig.compilerOptions.paths[`${npmName}/*`] = [`../../${targetRelPath}/src/*`];
|
|
189
|
+
fs.writeFileSync(mainTsConfigPath, JSON.stringify(tsconfig, null, 2) + '\n', 'utf-8');
|
|
190
|
+
}
|
|
191
|
+
// 4. Add entry to dd-apps.config.json
|
|
192
|
+
const config = readConfig(paths.configPath);
|
|
193
|
+
if (!config.apps)
|
|
194
|
+
config.apps = {};
|
|
195
|
+
config.apps[name] = true;
|
|
196
|
+
writeConfig(paths.configPath, config);
|
|
197
|
+
// 5. Run sync
|
|
198
|
+
await sync();
|
|
199
|
+
// 6. Run pnpm install
|
|
200
|
+
console.log('\nš¦ Running pnpm install...');
|
|
201
|
+
try {
|
|
202
|
+
execSync('pnpm install', { cwd: paths.root, stdio: 'inherit' });
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
console.warn('ā pnpm install failed. Run it manually.');
|
|
206
|
+
}
|
|
207
|
+
console.log(`
|
|
208
|
+
ā
Micro-app "${name}" created successfully!
|
|
209
|
+
|
|
210
|
+
Next steps:
|
|
211
|
+
1. Edit ${targetRelPath}/src/micro-app/index.tsx to define your routes, widgets, and API entrypoints
|
|
212
|
+
2. Edit ${targetRelPath}/src/collections to define your collections
|
|
213
|
+
3. Run: pnpm db:migrate:create
|
|
214
|
+
4. Run: pnpm db:migrate
|
|
215
|
+
5. Run: pnpm payload:generate-types:main
|
|
216
|
+
6. Run: pnpm dev
|
|
217
|
+
`);
|
|
218
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/commands/db.ts"],"names":[],"mappings":"AAyEA,wBAAsB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBtD"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { resolveWorkspacePaths } from '../paths.js';
|
|
2
|
+
import { applyRuntimeDatabaseUrl, captureCommand, checkDatabaseReachability, inspectLocalEnv, parseDatabaseUrl, resolveDatabasePreference, databaseRuntimeToEnvOptions, ensureDatabaseReady, ensureLocalEnv, runChecked, } from '../lib/onboarding.js';
|
|
3
|
+
async function dbStatus() {
|
|
4
|
+
const paths = resolveWorkspacePaths();
|
|
5
|
+
const envInspection = inspectLocalEnv(paths);
|
|
6
|
+
const databasePreference = resolveDatabasePreference(envInspection.env);
|
|
7
|
+
const databaseMode = databasePreference.mode;
|
|
8
|
+
const databaseUrl = databasePreference.databaseUrl;
|
|
9
|
+
if (!databaseUrl) {
|
|
10
|
+
console.error('Error: no database configuration is available. Run `pnpm dd onboard` first.');
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
const info = parseDatabaseUrl(databaseUrl);
|
|
14
|
+
const reachable = await checkDatabaseReachability(databaseUrl);
|
|
15
|
+
console.log('\nšļø Database status\n');
|
|
16
|
+
console.log(`Mode: ${databaseMode}`);
|
|
17
|
+
console.log(`Host: ${info.host}`);
|
|
18
|
+
console.log(`Port: ${info.port}`);
|
|
19
|
+
console.log(`Database: ${info.database}`);
|
|
20
|
+
console.log(`Reachable: ${reachable ? 'yes' : 'no'}`);
|
|
21
|
+
const migrationStatus = captureCommand('pnpm', ['db:migrate:status'], paths.root);
|
|
22
|
+
console.log('\nMigration status:\n');
|
|
23
|
+
console.log(migrationStatus.output || 'Unavailable');
|
|
24
|
+
if (!reachable || !migrationStatus.ok) {
|
|
25
|
+
process.exitCode = 1;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function dbMigrate() {
|
|
29
|
+
const paths = resolveWorkspacePaths();
|
|
30
|
+
const runtime = await ensureDatabaseReady(paths, {
|
|
31
|
+
yes: true,
|
|
32
|
+
allowDockerFallback: true,
|
|
33
|
+
});
|
|
34
|
+
applyRuntimeDatabaseUrl(ensureLocalEnv(paths, databaseRuntimeToEnvOptions(runtime)).env, runtime);
|
|
35
|
+
runChecked('pnpm', ['db:migrate'], paths.root, 'Migration run');
|
|
36
|
+
console.log('ā Migrations applied');
|
|
37
|
+
}
|
|
38
|
+
const HELP = `
|
|
39
|
+
dd db ā Database helpers
|
|
40
|
+
|
|
41
|
+
Subcommands:
|
|
42
|
+
status Show database connectivity and migration status
|
|
43
|
+
migrate Apply committed migrations
|
|
44
|
+
`;
|
|
45
|
+
export async function db(args) {
|
|
46
|
+
const subcommand = args[0];
|
|
47
|
+
switch (subcommand) {
|
|
48
|
+
case 'status':
|
|
49
|
+
await dbStatus();
|
|
50
|
+
break;
|
|
51
|
+
case 'migrate':
|
|
52
|
+
await dbMigrate();
|
|
53
|
+
break;
|
|
54
|
+
case '--help':
|
|
55
|
+
case '-h':
|
|
56
|
+
case undefined:
|
|
57
|
+
console.log(HELP);
|
|
58
|
+
break;
|
|
59
|
+
default:
|
|
60
|
+
console.error(`Unknown db subcommand: ${subcommand}`);
|
|
61
|
+
console.log(HELP);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disable.d.ts","sourceRoot":"","sources":["../../src/commands/disable.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBzD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dd disable <name> ā Disable a micro-app in dd-apps.config.json and run sync.
|
|
3
|
+
*/
|
|
4
|
+
import { resolveWorkspacePaths } from '../paths.js';
|
|
5
|
+
import { readConfig, writeConfig } from '../config.js';
|
|
6
|
+
import { scanWorkspace } from '../scanner.js';
|
|
7
|
+
import { sync } from './sync.js';
|
|
8
|
+
export async function disable(name) {
|
|
9
|
+
const paths = resolveWorkspacePaths();
|
|
10
|
+
const { microApps: allApps, payloadPlugins } = scanWorkspace(paths);
|
|
11
|
+
const app = allApps.find((a) => a.key === name);
|
|
12
|
+
if (!app) {
|
|
13
|
+
const plugin = payloadPlugins.find((p) => p.key === name);
|
|
14
|
+
if (plugin) {
|
|
15
|
+
console.error(`ā "${name}" is a payload plugin ā payload plugins are always-on and cannot be enabled or disabled.`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
console.error(`ā Micro-app "${name}" not found in workspace.`);
|
|
19
|
+
console.error(` Available: ${allApps.map((a) => a.key).join(', ')}`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const config = readConfig(paths.configPath);
|
|
23
|
+
if (!config.apps)
|
|
24
|
+
config.apps = {};
|
|
25
|
+
config.apps[name] = false;
|
|
26
|
+
writeConfig(paths.configPath, config);
|
|
27
|
+
console.log(`ā Disabled "${name}" in dd-apps.config.json`);
|
|
28
|
+
await sync();
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAsBA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAmG5C"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { resolveWorkspacePaths } from '../paths.js';
|
|
3
|
+
import { captureCommand, checkDatabaseReachability, commandExists, dockerAvailable, getGeneratedTypesPath, probeEmbeddedPostgresSupport, inspectLocalEnv, resolveDatabasePreference, requiredEnvKeysMissing, trimOutput, } from '../lib/onboarding.js';
|
|
4
|
+
export async function doctor() {
|
|
5
|
+
const paths = resolveWorkspacePaths();
|
|
6
|
+
const checks = [];
|
|
7
|
+
const nodeOk = commandExists('node');
|
|
8
|
+
checks.push({
|
|
9
|
+
label: 'Node.js',
|
|
10
|
+
ok: nodeOk,
|
|
11
|
+
detail: nodeOk ? process.version : 'Install Node.js 20+.',
|
|
12
|
+
});
|
|
13
|
+
const pnpmResult = captureCommand('pnpm', ['--version'], paths.root);
|
|
14
|
+
checks.push({
|
|
15
|
+
label: 'pnpm',
|
|
16
|
+
ok: pnpmResult.ok,
|
|
17
|
+
detail: pnpmResult.ok ? pnpmResult.output.trim() : 'Install pnpm 9+ with corepack.',
|
|
18
|
+
});
|
|
19
|
+
const envInspection = inspectLocalEnv(paths);
|
|
20
|
+
const missingKeys = requiredEnvKeysMissing(envInspection.env);
|
|
21
|
+
const databasePreference = resolveDatabasePreference(envInspection.env);
|
|
22
|
+
const databaseMode = databasePreference.mode;
|
|
23
|
+
checks.push({
|
|
24
|
+
label: '.env',
|
|
25
|
+
ok: envInspection.exists && missingKeys.length === 0,
|
|
26
|
+
detail: missingKeys.length === 0
|
|
27
|
+
? envInspection.exists
|
|
28
|
+
? `present at ${envInspection.envPath.replace(`${paths.root}/`, '')}`
|
|
29
|
+
: 'Missing apps/main-app/.env.'
|
|
30
|
+
: `Missing keys: ${missingKeys.join(', ')}`,
|
|
31
|
+
});
|
|
32
|
+
checks.push({
|
|
33
|
+
label: 'Database mode',
|
|
34
|
+
ok: true,
|
|
35
|
+
detail: databaseMode,
|
|
36
|
+
});
|
|
37
|
+
const dbReachable = databasePreference.databaseUrl
|
|
38
|
+
? await checkDatabaseReachability(databasePreference.databaseUrl)
|
|
39
|
+
: false;
|
|
40
|
+
const embeddedSupport = databaseMode === 'embedded'
|
|
41
|
+
? await probeEmbeddedPostgresSupport()
|
|
42
|
+
: { supported: true };
|
|
43
|
+
checks.push({
|
|
44
|
+
label: 'Database reachability',
|
|
45
|
+
ok: databaseMode === 'embedded' ? embeddedSupport.supported : dbReachable,
|
|
46
|
+
detail: databaseMode === 'embedded'
|
|
47
|
+
? embeddedSupport.supported
|
|
48
|
+
? dbReachable
|
|
49
|
+
? 'Embedded PostgreSQL is reachable.'
|
|
50
|
+
: 'Embedded PostgreSQL is not running yet. `pnpm dev` or `dd run` will start it automatically.'
|
|
51
|
+
: embeddedSupport.reason || 'Embedded PostgreSQL is not supported on this host.'
|
|
52
|
+
: dbReachable
|
|
53
|
+
? 'PostgreSQL is reachable from DATABASE_URL.'
|
|
54
|
+
: dockerAvailable()
|
|
55
|
+
? 'Database is not reachable yet. Run `pnpm dd onboard` or start Docker/Postgres manually.'
|
|
56
|
+
: 'Database is not reachable. Start PostgreSQL or update DATABASE_URL.',
|
|
57
|
+
});
|
|
58
|
+
const migrationStatus = captureCommand('pnpm', ['db:migrate:status'], paths.root);
|
|
59
|
+
checks.push({
|
|
60
|
+
label: 'Migration status',
|
|
61
|
+
ok: migrationStatus.ok,
|
|
62
|
+
detail: migrationStatus.ok
|
|
63
|
+
? trimOutput(migrationStatus.output)
|
|
64
|
+
: trimOutput(migrationStatus.output) || 'Could not read migration status.',
|
|
65
|
+
});
|
|
66
|
+
const generatedTypesPath = getGeneratedTypesPath(paths);
|
|
67
|
+
const generatedTypesExists = fs.existsSync(generatedTypesPath);
|
|
68
|
+
checks.push({
|
|
69
|
+
label: 'Generated Payload types',
|
|
70
|
+
ok: generatedTypesExists,
|
|
71
|
+
detail: generatedTypesExists
|
|
72
|
+
? 'packages/shared/src/types/payload-types.ts exists.'
|
|
73
|
+
: 'Run `pnpm payload:generate-types:main`.',
|
|
74
|
+
});
|
|
75
|
+
console.log('\n𩺠Double Digit doctor\n');
|
|
76
|
+
for (const check of checks) {
|
|
77
|
+
console.log(`${check.ok ? 'ā' : 'ā'} ${check.label}`);
|
|
78
|
+
console.log(` ${check.detail}`);
|
|
79
|
+
}
|
|
80
|
+
const failed = checks.filter((check) => !check.ok);
|
|
81
|
+
if (failed.length > 0) {
|
|
82
|
+
console.log('\nDoctor found issues. Recommended next step:\n');
|
|
83
|
+
console.log(' pnpm dd onboard\n');
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
console.log('\nAll checks passed.\n');
|
|
88
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enable.d.ts","sourceRoot":"","sources":["../../src/commands/enable.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBxD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dd enable <name> ā Enable a micro-app in dd-apps.config.json and run sync.
|
|
3
|
+
*/
|
|
4
|
+
import { resolveWorkspacePaths } from '../paths.js';
|
|
5
|
+
import { readConfig, writeConfig } from '../config.js';
|
|
6
|
+
import { scanWorkspace } from '../scanner.js';
|
|
7
|
+
import { sync } from './sync.js';
|
|
8
|
+
export async function enable(name) {
|
|
9
|
+
const paths = resolveWorkspacePaths();
|
|
10
|
+
const { microApps: allApps, payloadPlugins } = scanWorkspace(paths);
|
|
11
|
+
const app = allApps.find((a) => a.key === name);
|
|
12
|
+
if (!app) {
|
|
13
|
+
const plugin = payloadPlugins.find((p) => p.key === name);
|
|
14
|
+
if (plugin) {
|
|
15
|
+
console.error(`ā "${name}" is a payload plugin ā payload plugins are always-on and cannot be enabled or disabled.`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
console.error(`ā Micro-app "${name}" not found in workspace.`);
|
|
19
|
+
console.error(` Available: ${allApps.map((a) => a.key).join(', ')}`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const config = readConfig(paths.configPath);
|
|
23
|
+
if (!config.apps)
|
|
24
|
+
config.apps = {};
|
|
25
|
+
config.apps[name] = true;
|
|
26
|
+
writeConfig(paths.configPath, config);
|
|
27
|
+
console.log(`ā
Enabled "${name}" in dd-apps.config.json`);
|
|
28
|
+
await sync();
|
|
29
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dd info <name> ā Show detailed info about an installed extension.
|
|
3
|
+
*
|
|
4
|
+
* Reads from the lock file and cross-references with marketplace cache
|
|
5
|
+
* if the extension was installed from a marketplace.
|
|
6
|
+
*/
|
|
7
|
+
export declare function info(name: string): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=info.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"info.d.ts","sourceRoot":"","sources":["../../src/commands/info.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8EtD"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dd info <name> ā Show detailed info about an installed extension.
|
|
3
|
+
*
|
|
4
|
+
* Reads from the lock file and cross-references with marketplace cache
|
|
5
|
+
* if the extension was installed from a marketplace.
|
|
6
|
+
*/
|
|
7
|
+
import { resolveWorkspacePaths } from '../paths.js';
|
|
8
|
+
import { readLockFile } from '../lib/lock-file.js';
|
|
9
|
+
import { readCachedMarketplace, readKnownMarketplaces, } from '../lib/marketplace.js';
|
|
10
|
+
export async function info(name) {
|
|
11
|
+
const paths = resolveWorkspacePaths();
|
|
12
|
+
const lock = readLockFile(paths.lockFilePath);
|
|
13
|
+
const entry = lock.apps[name];
|
|
14
|
+
if (!entry) {
|
|
15
|
+
console.error(`Error: "${name}" is not installed (not found in lock file).`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
console.log(`\nš¦ ${name}\n`);
|
|
19
|
+
console.log(` Kind: ${entry.kind ?? 'unknown'}`);
|
|
20
|
+
console.log(` Source: ${entry.source}`);
|
|
21
|
+
console.log(` Resolved source: ${entry.resolvedSource}`);
|
|
22
|
+
if (entry.ref) {
|
|
23
|
+
console.log(` Ref: ${entry.ref}`);
|
|
24
|
+
}
|
|
25
|
+
if (entry.sha) {
|
|
26
|
+
console.log(` SHA: ${entry.sha}`);
|
|
27
|
+
}
|
|
28
|
+
if (entry.marketplaceVersion) {
|
|
29
|
+
console.log(` Marketplace ver: ${entry.marketplaceVersion}`);
|
|
30
|
+
}
|
|
31
|
+
if (entry.npmName) {
|
|
32
|
+
console.log(` npm name: ${entry.npmName}`);
|
|
33
|
+
}
|
|
34
|
+
console.log(` Content hash: ${entry.contentHash}`);
|
|
35
|
+
console.log(` Install path: ${entry.installPath ?? 'unknown'}`);
|
|
36
|
+
console.log(` Install strategy: ${entry.installStrategy ?? 'unknown'}`);
|
|
37
|
+
console.log(` Installed at: ${entry.installedAt}`);
|
|
38
|
+
console.log(` Updated at: ${entry.updatedAt}`);
|
|
39
|
+
// Cross-reference with marketplace cache
|
|
40
|
+
if (entry.marketplace) {
|
|
41
|
+
console.log(`\n Marketplace: ${entry.marketplace}`);
|
|
42
|
+
const known = readKnownMarketplaces(paths.root);
|
|
43
|
+
const mpEntry = known.marketplaces[entry.marketplace];
|
|
44
|
+
if (mpEntry) {
|
|
45
|
+
console.log(` Marketplace src: ${mpEntry.source}`);
|
|
46
|
+
if (mpEntry.cachedAt) {
|
|
47
|
+
console.log(` Catalog cached: ${mpEntry.cachedAt}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const cached = readCachedMarketplace(paths.root, entry.marketplace);
|
|
51
|
+
if (cached) {
|
|
52
|
+
const ext = cached.manifest.extensions.find((e) => e.name === name);
|
|
53
|
+
if (ext) {
|
|
54
|
+
console.log(`\n Marketplace entry:`);
|
|
55
|
+
if (ext.description) {
|
|
56
|
+
console.log(` Description: ${ext.description}`);
|
|
57
|
+
}
|
|
58
|
+
if (ext.version) {
|
|
59
|
+
console.log(` Version: ${ext.version}`);
|
|
60
|
+
}
|
|
61
|
+
if (ext.author) {
|
|
62
|
+
console.log(` Author: ${ext.author}`);
|
|
63
|
+
}
|
|
64
|
+
console.log(` Verified: ${ext.verified ? 'yes' : 'no'}`);
|
|
65
|
+
if (ext.tags.length > 0) {
|
|
66
|
+
console.log(` Tags: ${ext.tags.join(', ')}`);
|
|
67
|
+
}
|
|
68
|
+
if (ext.source.sha) {
|
|
69
|
+
console.log(` Latest SHA: ${ext.source.sha}`);
|
|
70
|
+
}
|
|
71
|
+
if (ext.source.ref) {
|
|
72
|
+
console.log(` Latest ref: ${ext.source.ref}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
console.log(` ā Extension not found in current marketplace catalog`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
console.log(` ā Marketplace catalog not cached ā run: dd marketplace update ${entry.marketplace}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
console.log('');
|
|
84
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CA4C1C"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dd list ā Show all discovered micro-apps with their enabled/disabled status.
|
|
3
|
+
*/
|
|
4
|
+
import { resolveWorkspacePaths } from '../paths.js';
|
|
5
|
+
import { readConfig, isEntryEnabled } from '../config.js';
|
|
6
|
+
import { scanWorkspace } from '../scanner.js';
|
|
7
|
+
export async function list() {
|
|
8
|
+
const paths = resolveWorkspacePaths();
|
|
9
|
+
const config = readConfig(paths.configPath);
|
|
10
|
+
const { microApps: allApps, payloadPlugins } = scanWorkspace(paths);
|
|
11
|
+
if (allApps.length === 0 && payloadPlugins.length === 0) {
|
|
12
|
+
console.log('No extensions found. Add "ddapp": true or "ddPackageType": "payload-plugin" to a package.json to register one.');
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
// Apply DD_APPS env var override for display
|
|
16
|
+
const envApps = process.env.DD_APPS;
|
|
17
|
+
const whitelist = envApps
|
|
18
|
+
? new Set(envApps.split(',').map((s) => s.trim()).filter(Boolean))
|
|
19
|
+
: null;
|
|
20
|
+
if (allApps.length > 0) {
|
|
21
|
+
console.log(`\nMicro-Apps (${allApps.length} discovered):\n`);
|
|
22
|
+
for (const app of allApps) {
|
|
23
|
+
let status;
|
|
24
|
+
if (whitelist) {
|
|
25
|
+
status = whitelist.has(app.key) ? 'ā
' : 'ā (DD_APPS override)';
|
|
26
|
+
}
|
|
27
|
+
else if (config.apps && !isEntryEnabled(config.apps[app.key])) {
|
|
28
|
+
status = 'ā (disabled in config)';
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
status = 'ā
';
|
|
32
|
+
}
|
|
33
|
+
console.log(` ${status} ${app.key.padEnd(20)} ${app.npmName}`);
|
|
34
|
+
}
|
|
35
|
+
console.log('');
|
|
36
|
+
}
|
|
37
|
+
if (payloadPlugins.length > 0) {
|
|
38
|
+
console.log(`Payload Plugins (${payloadPlugins.length} discovered):\n`);
|
|
39
|
+
for (const plugin of payloadPlugins) {
|
|
40
|
+
console.log(` š always-on ${plugin.key.padEnd(20)} ${plugin.npmName}`);
|
|
41
|
+
}
|
|
42
|
+
console.log('');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dd marketplace <subcommand> ā Manage marketplace registrations.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* add <source> Register a marketplace (GitHub repo with .doubledigit/marketplace.json)
|
|
6
|
+
* list List registered marketplaces
|
|
7
|
+
* update [name] Update marketplace catalog(s)
|
|
8
|
+
* remove <name> Remove a registered marketplace
|
|
9
|
+
*/
|
|
10
|
+
export declare function marketplace(args: string[]): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=marketplace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketplace.d.ts","sourceRoot":"","sources":["../../src/commands/marketplace.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA+NH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA8B/D"}
|