@doubledigit/cli 0.1.0 → 0.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.
Files changed (44) hide show
  1. package/LICENSE +1 -1
  2. package/dist/codegen.d.ts +6 -2
  3. package/dist/codegen.d.ts.map +1 -1
  4. package/dist/codegen.js +81 -13
  5. package/dist/commands/add.d.ts.map +1 -1
  6. package/dist/commands/add.js +36 -3
  7. package/dist/commands/create.js +2 -2
  8. package/dist/commands/db.d.ts.map +1 -1
  9. package/dist/commands/db.js +24 -11
  10. package/dist/commands/doctor.d.ts.map +1 -1
  11. package/dist/commands/doctor.js +46 -12
  12. package/dist/commands/init.d.ts +2 -0
  13. package/dist/commands/init.d.ts.map +1 -0
  14. package/dist/commands/init.js +163 -0
  15. package/dist/commands/onboard.d.ts.map +1 -1
  16. package/dist/commands/onboard.js +6 -1
  17. package/dist/commands/run.d.ts.map +1 -1
  18. package/dist/commands/run.js +1 -0
  19. package/dist/commands/sync.d.ts.map +1 -1
  20. package/dist/commands/sync.js +5 -1
  21. package/dist/commands/uninstall.d.ts.map +1 -1
  22. package/dist/commands/uninstall.js +25 -0
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +15 -5
  26. package/dist/lib/marketplace-schema.d.ts +24 -24
  27. package/dist/lib/onboarding.d.ts +3 -3
  28. package/dist/lib/onboarding.d.ts.map +1 -1
  29. package/dist/lib/onboarding.js +282 -237
  30. package/dist/lib/package-entry.d.ts +6 -0
  31. package/dist/lib/package-entry.d.ts.map +1 -0
  32. package/dist/lib/package-entry.js +63 -0
  33. package/dist/lib/scoped-migrations.d.ts +11 -0
  34. package/dist/lib/scoped-migrations.d.ts.map +1 -0
  35. package/dist/lib/scoped-migrations.js +156 -0
  36. package/dist/lib/validators.d.ts.map +1 -1
  37. package/dist/lib/validators.js +12 -49
  38. package/dist/paths.d.ts +4 -0
  39. package/dist/paths.d.ts.map +1 -1
  40. package/dist/paths.js +2 -0
  41. package/dist/scanner.d.ts +4 -0
  42. package/dist/scanner.d.ts.map +1 -1
  43. package/dist/scanner.js +21 -0
  44. package/package.json +10 -4
@@ -0,0 +1,6 @@
1
+ export declare function listPackageEntryCandidates(pkg: Record<string, unknown>, fallbackCandidates?: string[]): string[];
2
+ export declare function resolvePackageEntryPoint(packageDir: string, pkg: Record<string, unknown>, options?: {
3
+ fallbackCandidates?: string[];
4
+ allowDistFallback?: boolean;
5
+ }): string | null;
6
+ //# sourceMappingURL=package-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-entry.d.ts","sourceRoot":"","sources":["../../src/lib/package-entry.ts"],"names":[],"mappings":"AAyBA,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,kBAAkB,GAAE,MAAM,EAAO,GAChC,MAAM,EAAE,CA2BV;AAiBD,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,OAAO,CAAC,EAAE;IACR,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,GACA,MAAM,GAAG,IAAI,CAUf"}
@@ -0,0 +1,63 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ function isRecord(value) {
4
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
5
+ }
6
+ function normalizeCandidate(candidate) {
7
+ return candidate.replace(/^\.\//, '');
8
+ }
9
+ function addCandidate(candidates, seen, candidate) {
10
+ if (typeof candidate !== 'string' || candidate.length === 0)
11
+ return;
12
+ const normalized = normalizeCandidate(candidate);
13
+ if (seen.has(normalized))
14
+ return;
15
+ seen.add(normalized);
16
+ candidates.push(normalized);
17
+ }
18
+ export function listPackageEntryCandidates(pkg, fallbackCandidates = []) {
19
+ const candidates = [];
20
+ const seen = new Set();
21
+ addCandidate(candidates, seen, pkg.source);
22
+ const exportsField = pkg.exports;
23
+ if (typeof exportsField === 'string') {
24
+ addCandidate(candidates, seen, exportsField);
25
+ }
26
+ else if (isRecord(exportsField)) {
27
+ const rootExport = exportsField['.'];
28
+ if (typeof rootExport === 'string') {
29
+ addCandidate(candidates, seen, rootExport);
30
+ }
31
+ else if (isRecord(rootExport)) {
32
+ addCandidate(candidates, seen, rootExport.default);
33
+ addCandidate(candidates, seen, rootExport.source);
34
+ addCandidate(candidates, seen, rootExport.import);
35
+ }
36
+ }
37
+ addCandidate(candidates, seen, pkg.main);
38
+ for (const fallback of fallbackCandidates) {
39
+ addCandidate(candidates, seen, fallback);
40
+ }
41
+ return candidates;
42
+ }
43
+ function findExistingEntry(packageDir, candidates, includeDist) {
44
+ for (const candidate of candidates) {
45
+ const resolved = path.resolve(packageDir, candidate);
46
+ if (!fs.existsSync(resolved))
47
+ continue;
48
+ if (!includeDist && resolved.includes(`${path.sep}dist${path.sep}`))
49
+ continue;
50
+ return candidate;
51
+ }
52
+ return null;
53
+ }
54
+ export function resolvePackageEntryPoint(packageDir, pkg, options) {
55
+ const candidates = listPackageEntryCandidates(pkg, options?.fallbackCandidates);
56
+ const sourceEntry = findExistingEntry(packageDir, candidates, false);
57
+ if (sourceEntry)
58
+ return sourceEntry;
59
+ if (options?.allowDistFallback === false) {
60
+ return null;
61
+ }
62
+ return findExistingEntry(packageDir, candidates, true);
63
+ }
@@ -0,0 +1,11 @@
1
+ import type { WorkspacePaths } from '../paths.js';
2
+ export type ScopedMigrationAction = 'create' | 'migrate' | 'status';
3
+ interface ScopedMigrationArgs {
4
+ target: string;
5
+ migrationName?: string;
6
+ }
7
+ export declare function parseScopedMigrationArgs(args: string[]): ScopedMigrationArgs;
8
+ export declare function getScopedMigrationTargets(appConfigs: string[], target: string): string[];
9
+ export declare function runScopedMigrations(paths: WorkspacePaths, action: ScopedMigrationAction, args?: string[]): void;
10
+ export {};
11
+ //# sourceMappingURL=scoped-migrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoped-migrations.d.ts","sourceRoot":"","sources":["../../src/lib/scoped-migrations.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AAOpE,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,mBAAmB,CAsB5E;AAED,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,EAAE,EACpB,MAAM,EAAE,MAAM,GACb,MAAM,EAAE,CAUV;AAkKD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,qBAAqB,EAC7B,IAAI,GAAE,MAAM,EAAO,QAyBpB"}
@@ -0,0 +1,156 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ const CONFIG_SUFFIX = '.config.ts';
5
+ const SHARED_CONFIG = 'shared';
6
+ const SHARED_TARGET = '--shared';
7
+ const ALL_TARGET = '--all';
8
+ export function parseScopedMigrationArgs(args) {
9
+ const [targetOrName, maybeMigrationName] = args;
10
+ if (!targetOrName) {
11
+ return { target: ALL_TARGET };
12
+ }
13
+ if (targetOrName === ALL_TARGET || targetOrName === SHARED_TARGET) {
14
+ return maybeMigrationName
15
+ ? {
16
+ target: targetOrName,
17
+ migrationName: maybeMigrationName,
18
+ }
19
+ : { target: targetOrName };
20
+ }
21
+ return maybeMigrationName
22
+ ? {
23
+ target: targetOrName,
24
+ migrationName: maybeMigrationName,
25
+ }
26
+ : { target: targetOrName };
27
+ }
28
+ export function getScopedMigrationTargets(appConfigs, target) {
29
+ if (target === SHARED_TARGET) {
30
+ return [SHARED_CONFIG];
31
+ }
32
+ if (target === ALL_TARGET) {
33
+ return [SHARED_CONFIG, ...appConfigs];
34
+ }
35
+ return [target];
36
+ }
37
+ function getAppConfigs(paths) {
38
+ if (!fs.existsSync(paths.payloadConfigsDir)) {
39
+ return [];
40
+ }
41
+ return fs
42
+ .readdirSync(paths.payloadConfigsDir)
43
+ .filter((file) => file.endsWith(CONFIG_SUFFIX))
44
+ .map((file) => file.slice(0, -CONFIG_SUFFIX.length))
45
+ .filter((appKey) => !appKey.startsWith('_') && appKey !== SHARED_CONFIG)
46
+ .sort();
47
+ }
48
+ function getConfigPath(paths, appKey) {
49
+ const configPath = path.join(paths.payloadConfigsDir, `${appKey}${CONFIG_SUFFIX}`);
50
+ if (!fs.existsSync(configPath)) {
51
+ const available = [SHARED_CONFIG, ...getAppConfigs(paths)].join(', ');
52
+ throw new Error(`Unknown scoped migration target "${appKey}". Available targets: ${available || '(none)'}.`);
53
+ }
54
+ return path.relative(paths.mainAppDir, configPath);
55
+ }
56
+ function getAppMigrationDir(paths, appKey) {
57
+ return path.join(paths.extensionsMicroAppsDir, appKey, 'src', 'migrations');
58
+ }
59
+ function getMigrationFiles(dir) {
60
+ if (!fs.existsSync(dir)) {
61
+ return [];
62
+ }
63
+ return fs
64
+ .readdirSync(dir)
65
+ .filter((file) => file.endsWith('.ts') && file !== 'index.ts')
66
+ .sort();
67
+ }
68
+ function formatCommand(args) {
69
+ return ['pnpm', ...args].join(' ');
70
+ }
71
+ function runCommand(paths, args, envOverrides = {}) {
72
+ const startedAt = Date.now();
73
+ const env = Object.entries(envOverrides)
74
+ .map(([key, value]) => `${key}=${value}`)
75
+ .join(' ');
76
+ console.log(` cwd: ${paths.mainAppDir}`);
77
+ console.log(` command: ${formatCommand(args)}`);
78
+ if (env) {
79
+ console.log(` env: ${env}`);
80
+ }
81
+ const result = spawnSync('pnpm', args, {
82
+ cwd: paths.mainAppDir,
83
+ env: {
84
+ ...process.env,
85
+ ...envOverrides,
86
+ },
87
+ stdio: 'inherit',
88
+ });
89
+ if (result.error) {
90
+ console.error(` failed after ${Date.now() - startedAt}ms`);
91
+ throw result.error;
92
+ }
93
+ if (result.status !== 0) {
94
+ console.error(` exit: ${result.status ?? 1} (${Date.now() - startedAt}ms)`);
95
+ process.exit(result.status ?? 1);
96
+ }
97
+ console.log(` exit: 0 (${Date.now() - startedAt}ms)`);
98
+ }
99
+ function runForConfig(paths, action, label, configPath, migrationName, migrationDir) {
100
+ console.log(`\n==> ${label}: ${action}`);
101
+ console.log(` config: ${configPath}`);
102
+ if (migrationDir) {
103
+ const migrationFiles = getMigrationFiles(migrationDir);
104
+ console.log(` migrationDir: ${migrationDir}`);
105
+ console.log(` migrationFiles: ${migrationFiles.length ? migrationFiles.join(', ') : '(none)'}`);
106
+ }
107
+ if (action === 'create') {
108
+ runCommand(paths, [
109
+ 'exec',
110
+ 'tsx',
111
+ 'scripts/create-scoped-migration.ts',
112
+ configPath,
113
+ ...(migrationName ? [migrationName] : []),
114
+ ]);
115
+ return;
116
+ }
117
+ runCommand(paths, ['exec', 'payload', action === 'status' ? 'migrate:status' : 'migrate'], {
118
+ PAYLOAD_CONFIG_PATH: configPath,
119
+ });
120
+ }
121
+ function runShared(paths, action, migrationName) {
122
+ runForConfig(paths, action, SHARED_CONFIG, getConfigPath(paths, SHARED_CONFIG), migrationName, path.join(paths.mainAppDir, 'src', 'migrations', 'shared'));
123
+ }
124
+ function runForApp(paths, action, appKey, migrationName) {
125
+ const configPath = getConfigPath(paths, appKey);
126
+ const migrationDir = getAppMigrationDir(paths, appKey);
127
+ const migrationFiles = getMigrationFiles(migrationDir);
128
+ if (action !== 'create' && !migrationFiles.length) {
129
+ console.log(`\n==> ${appKey}: no migrations found, skipping`);
130
+ console.log(` config: ${configPath}`);
131
+ console.log(` migrationDir: ${migrationDir}`);
132
+ console.log(' migrationFiles: (none)');
133
+ return;
134
+ }
135
+ runForConfig(paths, action, appKey, configPath, migrationName, migrationDir);
136
+ }
137
+ export function runScopedMigrations(paths, action, args = []) {
138
+ const { target, migrationName } = parseScopedMigrationArgs(args);
139
+ if (target === SHARED_TARGET) {
140
+ runShared(paths, action, migrationName);
141
+ return;
142
+ }
143
+ if (target === ALL_TARGET) {
144
+ const appConfigs = getAppConfigs(paths);
145
+ const targets = getScopedMigrationTargets(appConfigs, target);
146
+ console.log(`Scoped migration run: ${action} --all`);
147
+ console.log(`Config directory: ${paths.payloadConfigsDir}`);
148
+ console.log(`Targets: ${targets.join(', ')}`);
149
+ runShared(paths, action, migrationName);
150
+ for (const appKey of appConfigs) {
151
+ runForApp(paths, action, appKey, migrationName);
152
+ }
153
+ return;
154
+ }
155
+ runForApp(paths, action, target, migrationName);
156
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/lib/validators.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG7D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AA0BD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,MAAM,GACd,gBAAgB,CAWlB;AAMD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,MAAM,GACd,gBAAgB,CAgClB;AAMD;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,gBAAgB,CAAC,CA2E3B;AAMD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CAEnE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,MAAM,GACjB,sBAAsB,CAsBxB;AAMD;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE,aAAa,GACnB,gBAAgB,CA+ClB;AAED,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,MAAM,GAAG,IAAI,CAgCf;AAqDD,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,mBAAmB,CAAC,EAAE,MAAM,GAC3B;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAwBvC;AAMD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EAAE,EACnB,UAAU,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,gBAAgB,CAyClB;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,GAClB,gBAAgB,CAiClB;AAMD;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,gBAAgB,CAAC,CAY3B"}
1
+ {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/lib/validators.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG7D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AA0BD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,MAAM,GACd,gBAAgB,CAWlB;AAMD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,MAAM,GACd,gBAAgB,CAgClB;AAMD;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,gBAAgB,CAAC,CA2E3B;AAMD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CAEnE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,MAAM,GACjB,sBAAsB,CAsBxB;AAMD;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE,aAAa,GACnB,gBAAgB,CA+ClB;AASD,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,MAAM,GAAG,IAAI,CAIf;AAiCD,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,mBAAmB,CAAC,EAAE,MAAM,GAC3B;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAwBvC;AAMD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EAAE,EACnB,UAAU,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,gBAAgB,CAyClB;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,GAClB,gBAAgB,CAiClB;AAMD;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,gBAAgB,CAAC,CAY3B"}
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import fs from 'node:fs';
9
9
  import path from 'node:path';
10
+ import { listPackageEntryCandidates, resolvePackageEntryPoint as resolvePackageEntryCandidate, } from './package-entry.js';
10
11
  import { resolveGitHubToken } from './github-auth.js';
11
12
  function ok(warnings = []) {
12
13
  return { valid: true, errors: [], warnings };
@@ -230,40 +231,20 @@ export function validateDownloadedPackage(packageDir, kind) {
230
231
  // 4. Check entry point exists
231
232
  const entryPoint = resolvePackageEntryPoint(packageDir, pkg);
232
233
  if (!entryPoint) {
233
- warnings.push('No entry point found (checked src/index.ts, src/index.tsx, exports["."], and main)');
234
+ warnings.push('No entry point found (checked package.json source/exports/main plus common src entry files)');
234
235
  }
235
236
  return errors.length > 0 ? fail(errors, warnings) : ok(warnings);
236
237
  }
238
+ const COMMON_ENTRY_FALLBACKS = [
239
+ 'src/index.ts',
240
+ 'src/index.tsx',
241
+ 'src/micro-app/index.ts',
242
+ 'src/micro-app/index.tsx',
243
+ ];
237
244
  export function resolvePackageEntryPoint(packageDir, pkg) {
238
- // Check common entry points
239
- const commonEntries = ['src/index.ts', 'src/index.tsx'];
240
- for (const entry of commonEntries) {
241
- if (fs.existsSync(path.join(packageDir, entry)))
242
- return entry;
243
- }
244
- // Check exports["."] in package.json
245
- const exports = pkg.exports;
246
- if (exports && typeof exports === 'object' && '.' in exports) {
247
- const dotExport = exports['.'];
248
- const exportPath = typeof dotExport === 'string'
249
- ? dotExport
250
- : typeof dotExport === 'object' && dotExport !== null
251
- ? dotExport.import ||
252
- dotExport.default
253
- : undefined;
254
- if (typeof exportPath === 'string') {
255
- const resolved = path.join(packageDir, exportPath);
256
- if (fs.existsSync(resolved))
257
- return exportPath;
258
- }
259
- }
260
- const main = pkg.main;
261
- if (typeof main === 'string') {
262
- const resolved = path.join(packageDir, main);
263
- if (fs.existsSync(resolved))
264
- return main;
265
- }
266
- return null;
245
+ return resolvePackageEntryCandidate(packageDir, pkg, {
246
+ fallbackCandidates: COMMON_ENTRY_FALLBACKS,
247
+ });
267
248
  }
268
249
  const DDAPP_KEY_RE = /key:\s*['"]([^'"]+)['"]/;
269
250
  const DDAPP_SLUG_RE = /slugPrefix:\s*['"]([^'"]+)['"]/;
@@ -278,27 +259,9 @@ function addCandidateEntry(candidates, packageDir, entry) {
278
259
  function getMicroAppMetadataCandidates(packageDir, pkg, preferredEntryPoint) {
279
260
  const candidates = new Set();
280
261
  addCandidateEntry(candidates, packageDir, preferredEntryPoint);
281
- addCandidateEntry(candidates, packageDir, resolvePackageEntryPoint(packageDir, pkg));
282
- for (const entry of [
283
- 'src/index.ts',
284
- 'src/index.tsx',
285
- 'src/micro-app/index.ts',
286
- 'src/micro-app/index.tsx',
287
- ]) {
262
+ for (const entry of listPackageEntryCandidates(pkg, COMMON_ENTRY_FALLBACKS)) {
288
263
  addCandidateEntry(candidates, packageDir, entry);
289
264
  }
290
- const exports = pkg.exports;
291
- if (exports && typeof exports === 'object' && '.' in exports) {
292
- const dotExport = exports['.'];
293
- if (typeof dotExport === 'string') {
294
- addCandidateEntry(candidates, packageDir, dotExport);
295
- }
296
- else if (typeof dotExport === 'object' && dotExport !== null) {
297
- addCandidateEntry(candidates, packageDir, dotExport.import);
298
- addCandidateEntry(candidates, packageDir, dotExport.default);
299
- }
300
- }
301
- addCandidateEntry(candidates, packageDir, pkg.main);
302
265
  return [...candidates];
303
266
  }
304
267
  export function extractMicroAppMetadata(packageDir, pkg, preferredEntryPoint) {
package/dist/paths.d.ts CHANGED
@@ -21,8 +21,12 @@ export interface WorkspacePaths {
21
21
  lockFilePath: string;
22
22
  /** Generated micro-apps.ts path */
23
23
  microAppsOutputPath: string;
24
+ /** Generated micro-app package list consumed by next.config.ts */
25
+ microAppTranspilePackagesOutputPath: string;
24
26
  /** Generated payload-plugins.ts path */
25
27
  payloadPluginsOutputPath: string;
28
+ /** Scoped Payload config directory */
29
+ payloadConfigsDir: string;
26
30
  /** main-app package.json */
27
31
  mainAppPackageJsonPath: string;
28
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,4CAA4C;IAC5C,2BAA2B,EAAE,MAAM,CAAC;IACpC,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wCAAwC;IACxC,wBAAwB,EAAE,MAAM,CAAC;IACjC,4BAA4B;IAC5B,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAgBD,wBAAgB,qBAAqB,CAAC,GAAG,SAAgB,GAAG,cAAc,CAoBzE;AAED,qEAAqE;AACrE,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,WAAW,GAAG,gBAAgB,EACpC,IAAI,EAAE,MAAM,GACX,MAAM,CAKR;AAED,oEAAoE;AACpE,wBAAgB,cAAc,CAC5B,IAAI,EAAE,WAAW,GAAG,gBAAgB,EACpC,IAAI,EAAE,MAAM,GACX,MAAM,CAIR;AAED,uFAAuF;AACvF,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,EAAE,CAM/D;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,EAAE,CAO5D;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,MAAM,GACX,MAAM,CAER;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,MAAM,EACZ,aAAa,CAAC,EAAE,WAAW,GAAG,gBAAgB,GAC7C,MAAM,EAAE,CAcV"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,4CAA4C;IAC5C,2BAA2B,EAAE,MAAM,CAAC;IACpC,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kEAAkE;IAClE,mCAAmC,EAAE,MAAM,CAAC;IAC5C,wCAAwC;IACxC,wBAAwB,EAAE,MAAM,CAAC;IACjC,sCAAsC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,4BAA4B;IAC5B,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAgBD,wBAAgB,qBAAqB,CAAC,GAAG,SAAgB,GAAG,cAAc,CAsBzE;AAED,qEAAqE;AACrE,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,WAAW,GAAG,gBAAgB,EACpC,IAAI,EAAE,MAAM,GACX,MAAM,CAKR;AAED,oEAAoE;AACpE,wBAAgB,cAAc,CAC5B,IAAI,EAAE,WAAW,GAAG,gBAAgB,EACpC,IAAI,EAAE,MAAM,GACX,MAAM,CAIR;AAED,uFAAuF;AACvF,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,EAAE,CAM/D;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,EAAE,CAO5D;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,MAAM,GACX,MAAM,CAER;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,MAAM,EACZ,aAAa,CAAC,EAAE,WAAW,GAAG,gBAAgB,GAC7C,MAAM,EAAE,CAcV"}
package/dist/paths.js CHANGED
@@ -32,7 +32,9 @@ export function resolveWorkspacePaths(cwd = process.cwd()) {
32
32
  configPath: path.join(mainAppDir, 'dd-apps.config.json'),
33
33
  lockFilePath: path.join(root, 'dd-apps.lock.json'),
34
34
  microAppsOutputPath: path.join(mainAppDir, 'src', 'lib', 'micro-apps.ts'),
35
+ microAppTranspilePackagesOutputPath: path.join(mainAppDir, 'src', 'lib', 'micro-app-transpile-packages.ts'),
35
36
  payloadPluginsOutputPath: path.join(mainAppDir, 'src', 'lib', 'payload-plugins.ts'),
37
+ payloadConfigsDir: path.join(mainAppDir, 'payload-configs'),
36
38
  mainAppPackageJsonPath: path.join(mainAppDir, 'package.json'),
37
39
  };
38
40
  }
package/dist/scanner.d.ts CHANGED
@@ -12,6 +12,8 @@ export interface DiscoveredApp {
12
12
  importName: string;
13
13
  /** Absolute path to the package directory */
14
14
  dir: string;
15
+ /** Absolute path to the local source entry file used by generated registries */
16
+ entryFile: string;
15
17
  }
16
18
  export interface DiscoveredPayloadPlugin {
17
19
  /** Folder name */
@@ -22,6 +24,8 @@ export interface DiscoveredPayloadPlugin {
22
24
  importName: string;
23
25
  /** Absolute path to the package directory */
24
26
  dir: string;
27
+ /** Absolute path to the local source entry file used by generated registries */
28
+ entryFile: string;
25
29
  }
26
30
  /** Unified result from scanning the workspace. */
27
31
  export interface ScanResult {
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,uBAAuB;IACtC,kBAAkB;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAC;CACb;AAED,kDAAkD;AAClD,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,cAAc,EAAE,uBAAuB,EAAE,CAAC;CAC3C;AA6ED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,GAAG,UAAU,CAgB/D;AAED,kGAAkG;AAClG,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,EAAE,CAMlE"}
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,kBAAkB;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,kDAAkD;AAClD,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,cAAc,EAAE,uBAAuB,EAAE,CAAC;CAC3C;AAyGD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,GAAG,UAAU,CAgB/D;AAED,kGAAkG;AAClG,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,EAAE,CAMlE"}
package/dist/scanner.js CHANGED
@@ -4,9 +4,20 @@
4
4
  */
5
5
  import fs from 'node:fs';
6
6
  import path from 'node:path';
7
+ import { resolvePackageEntryPoint } from './lib/package-entry.js';
7
8
  function toImportName(key) {
8
9
  return key.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
9
10
  }
11
+ function requireWorkspaceEntryFile(pkgDir, pkg, fallbackCandidates) {
12
+ const entryPoint = resolvePackageEntryPoint(pkgDir, pkg, {
13
+ fallbackCandidates,
14
+ allowDistFallback: false,
15
+ });
16
+ if (entryPoint) {
17
+ return path.resolve(pkgDir, entryPoint);
18
+ }
19
+ throw new Error(`Could not resolve a local source entry file for ${String(pkg.name ?? pkgDir)} at ${pkgDir}`);
20
+ }
10
21
  /**
11
22
  * Classify a single package directory.
12
23
  * Returns the package type or null if unrecognised.
@@ -25,6 +36,10 @@ function classifyPackage(pkgDir, key) {
25
36
  npmName: pkg.name,
26
37
  importName: toImportName(key),
27
38
  dir: pkgDir,
39
+ entryFile: requireWorkspaceEntryFile(pkgDir, pkg, [
40
+ './src/index.ts',
41
+ './src/index.tsx',
42
+ ]),
28
43
  },
29
44
  };
30
45
  }
@@ -36,6 +51,12 @@ function classifyPackage(pkgDir, key) {
36
51
  npmName: pkg.name,
37
52
  importName: toImportName(key),
38
53
  dir: pkgDir,
54
+ entryFile: requireWorkspaceEntryFile(pkgDir, pkg, [
55
+ './src/index.tsx',
56
+ './src/index.ts',
57
+ './src/micro-app/index.tsx',
58
+ './src/micro-app/index.ts',
59
+ ]),
39
60
  },
40
61
  };
41
62
  }
package/package.json CHANGED
@@ -1,18 +1,22 @@
1
1
  {
2
2
  "name": "@doubledigit/cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "description": "CLI for Double Digit local setup and extension management.",
6
6
  "license": "MIT",
7
- "homepage": "https://github.com/vaishnavagrawal/micro-apps",
7
+ "homepage": "https://github.com/crystalphantom/double-digit",
8
8
  "bugs": {
9
- "url": "https://github.com/vaishnavagrawal/micro-apps/issues"
9
+ "url": "https://github.com/crystalphantom/double-digit/issues"
10
10
  },
11
11
  "repository": {
12
12
  "type": "git",
13
- "url": "https://github.com/vaishnavagrawal/micro-apps.git",
13
+ "url": "https://github.com/crystalphantom/double-digit.git",
14
14
  "directory": "packages/cli"
15
15
  },
16
+ "engines": {
17
+ "node": ">=20.0.0",
18
+ "pnpm": ">=9.0.0"
19
+ },
16
20
  "type": "module",
17
21
  "main": "./dist/index.js",
18
22
  "module": "./dist/index.js",
@@ -37,12 +41,14 @@
37
41
  "zod": "^3.23.0"
38
42
  },
39
43
  "devDependencies": {
44
+ "tsx": "^4.21.0",
40
45
  "typescript": "^5.7.0"
41
46
  },
42
47
  "publishConfig": {
43
48
  "access": "public"
44
49
  },
45
50
  "scripts": {
51
+ "test": "tsx --test test/*.test.ts",
46
52
  "build": "tsc -p tsconfig.json",
47
53
  "typecheck": "tsc -p tsconfig.json --noEmit"
48
54
  }