@launch77/cli 1.4.3 → 1.5.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/CHANGELOG.md +19 -0
- package/dist/cli.js +1 -4
- package/dist/cli.js.map +1 -1
- package/dist/infrastructure/npm-package.d.ts +42 -0
- package/dist/infrastructure/npm-package.d.ts.map +1 -0
- package/dist/infrastructure/npm-package.js +46 -0
- package/dist/infrastructure/npm-package.js.map +1 -0
- package/dist/infrastructure/package-resolver.d.ts +117 -0
- package/dist/infrastructure/package-resolver.d.ts.map +1 -0
- package/dist/infrastructure/package-resolver.js +170 -0
- package/dist/infrastructure/package-resolver.js.map +1 -0
- package/dist/infrastructure/package-resolver.test.d.ts +2 -0
- package/dist/infrastructure/package-resolver.test.d.ts.map +1 -0
- package/dist/infrastructure/package-resolver.test.js +251 -0
- package/dist/infrastructure/package-resolver.test.js.map +1 -0
- package/dist/infrastructure/template.d.ts +0 -1
- package/dist/infrastructure/template.d.ts.map +1 -1
- package/dist/infrastructure/template.js.map +1 -1
- package/dist/modules/app/commands/create-app.d.ts.map +1 -1
- package/dist/modules/app/commands/create-app.js +14 -15
- package/dist/modules/app/commands/create-app.js.map +1 -1
- package/dist/modules/app/commands/delete-app.js +1 -1
- package/dist/modules/app/commands/delete-app.js.map +1 -1
- package/dist/modules/app/commands/validate-manifest.d.ts.map +1 -1
- package/dist/modules/app/commands/validate-manifest.js +0 -1
- package/dist/modules/app/commands/validate-manifest.js.map +1 -1
- package/dist/modules/app/index.d.ts +1 -2
- package/dist/modules/app/index.d.ts.map +1 -1
- package/dist/modules/app/index.js +0 -1
- package/dist/modules/app/index.js.map +1 -1
- package/dist/modules/app/lib/app-template-resolver.d.ts +14 -0
- package/dist/modules/app/lib/app-template-resolver.d.ts.map +1 -0
- package/dist/modules/app/lib/app-template-resolver.js +51 -0
- package/dist/modules/app/lib/app-template-resolver.js.map +1 -0
- package/dist/modules/app/lib/manifest-schema.d.ts +0 -7
- package/dist/modules/app/lib/manifest-schema.d.ts.map +1 -1
- package/dist/modules/app/lib/manifest-schema.js +0 -2
- package/dist/modules/app/lib/manifest-schema.js.map +1 -1
- package/dist/modules/app/services/app-svc.d.ts +2 -1
- package/dist/modules/app/services/app-svc.d.ts.map +1 -1
- package/dist/modules/app/services/app-svc.js +77 -12
- package/dist/modules/app/services/app-svc.js.map +1 -1
- package/dist/modules/app/services/manifest-svc.d.ts +2 -2
- package/dist/modules/app/services/manifest-svc.d.ts.map +1 -1
- package/dist/modules/app/services/manifest-svc.js +9 -50
- package/dist/modules/app/services/manifest-svc.js.map +1 -1
- package/dist/modules/app/types/app-types.d.ts +2 -5
- package/dist/modules/app/types/app-types.d.ts.map +1 -1
- package/dist/modules/app/types/app-types.js +1 -4
- package/dist/modules/app/types/app-types.js.map +1 -1
- package/dist/modules/catalog/commands/scan.js +3 -3
- package/dist/modules/catalog/commands/scan.js.map +1 -1
- package/dist/modules/catalog/services/catalog-svc.d.ts +2 -2
- package/dist/modules/catalog/services/catalog-svc.d.ts.map +1 -1
- package/dist/modules/catalog/services/catalog-svc.js +2 -2
- package/dist/modules/catalog/services/catalog-svc.js.map +1 -1
- package/dist/modules/deploy/commands/deploy-init-action.d.ts.map +1 -1
- package/dist/modules/deploy/commands/deploy-init-action.js +21 -20
- package/dist/modules/deploy/commands/deploy-init-action.js.map +1 -1
- package/dist/modules/deploy/commands/deploy-logs-action.d.ts.map +1 -1
- package/dist/modules/deploy/commands/deploy-logs-action.js +16 -13
- package/dist/modules/deploy/commands/deploy-logs-action.js.map +1 -1
- package/dist/modules/deploy/commands/deploy-status-action.d.ts.map +1 -1
- package/dist/modules/deploy/commands/deploy-status-action.js +16 -13
- package/dist/modules/deploy/commands/deploy-status-action.js.map +1 -1
- package/dist/modules/plugin/lib/plugin-resolver.d.ts +10 -72
- package/dist/modules/plugin/lib/plugin-resolver.d.ts.map +1 -1
- package/dist/modules/plugin/lib/plugin-resolver.js +23 -115
- package/dist/modules/plugin/lib/plugin-resolver.js.map +1 -1
- package/dist/modules/plugin/lib/plugin-resolver.test.js +45 -39
- package/dist/modules/plugin/lib/plugin-resolver.test.js.map +1 -1
- package/dist/modules/plugin/services/plugin-svc.d.ts +2 -0
- package/dist/modules/plugin/services/plugin-svc.d.ts.map +1 -1
- package/dist/modules/plugin/services/plugin-svc.js +24 -19
- package/dist/modules/plugin/services/plugin-svc.js.map +1 -1
- package/dist/modules/plugin/services/plugin-svc.test.js +12 -6
- package/dist/modules/plugin/services/plugin-svc.test.js.map +1 -1
- package/dist/templates/plugin/package.json.hbs +1 -1
- package/dist/templates/plugin/plugin.json.hbs +1 -3
- package/dist/utils/validation.d.ts +3 -7
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +7 -31
- package/dist/utils/validation.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +1 -4
- package/src/infrastructure/npm-package.ts +73 -0
- package/src/infrastructure/package-resolver.test.ts +313 -0
- package/src/infrastructure/package-resolver.ts +223 -0
- package/src/infrastructure/template.ts +0 -1
- package/src/modules/app/commands/create-app.ts +14 -18
- package/src/modules/app/commands/delete-app.ts +1 -1
- package/src/modules/app/commands/validate-manifest.ts +0 -1
- package/src/modules/app/index.ts +1 -2
- package/src/modules/app/lib/app-template-resolver.ts +56 -0
- package/src/modules/app/lib/manifest-schema.ts +0 -5
- package/src/modules/app/services/app-svc.ts +89 -13
- package/src/modules/app/services/manifest-svc.ts +8 -57
- package/src/modules/app/types/app-types.ts +2 -9
- package/src/modules/catalog/commands/scan.ts +3 -3
- package/src/modules/catalog/services/catalog-svc.ts +4 -4
- package/src/modules/deploy/commands/deploy-init-action.ts +23 -20
- package/src/modules/deploy/commands/deploy-logs-action.ts +19 -13
- package/src/modules/deploy/commands/deploy-status-action.ts +19 -13
- package/src/modules/plugin/lib/plugin-resolver.test.ts +48 -39
- package/src/modules/plugin/lib/plugin-resolver.ts +22 -141
- package/src/modules/plugin/services/plugin-svc.test.ts +12 -6
- package/src/modules/plugin/services/plugin-svc.ts +27 -18
- package/src/utils/validation.ts +10 -38
- package/templates/plugin/package.json.hbs +1 -1
- package/templates/plugin/plugin.json.hbs +1 -3
- package/dist/modules/app/commands/generate-manifest.d.ts +0 -3
- package/dist/modules/app/commands/generate-manifest.d.ts.map +0 -1
- package/dist/modules/app/commands/generate-manifest.js +0 -62
- package/dist/modules/app/commands/generate-manifest.js.map +0 -1
- package/dist/modules/startup/commands/create-startup.d.ts +0 -3
- package/dist/modules/startup/commands/create-startup.d.ts.map +0 -1
- package/dist/modules/startup/commands/create-startup.js +0 -43
- package/dist/modules/startup/commands/create-startup.js.map +0 -1
- package/dist/modules/startup/errors/startup-errors.d.ts +0 -13
- package/dist/modules/startup/errors/startup-errors.d.ts.map +0 -1
- package/dist/modules/startup/errors/startup-errors.js +0 -25
- package/dist/modules/startup/errors/startup-errors.js.map +0 -1
- package/dist/modules/startup/index.d.ts +0 -5
- package/dist/modules/startup/index.d.ts.map +0 -1
- package/dist/modules/startup/index.js +0 -7
- package/dist/modules/startup/index.js.map +0 -1
- package/dist/modules/startup/services/startup-service.d.ts +0 -7
- package/dist/modules/startup/services/startup-service.d.ts.map +0 -1
- package/dist/modules/startup/services/startup-service.js +0 -43
- package/dist/modules/startup/services/startup-service.js.map +0 -1
- package/dist/modules/startup/types/startup-types.d.ts +0 -8
- package/dist/modules/startup/types/startup-types.d.ts.map +0 -1
- package/dist/modules/startup/types/startup-types.js +0 -2
- package/dist/modules/startup/types/startup-types.js.map +0 -1
- package/dist/modules/startup/utils/startup-validators.d.ts +0 -8
- package/dist/modules/startup/utils/startup-validators.d.ts.map +0 -1
- package/dist/modules/startup/utils/startup-validators.js +0 -17
- package/dist/modules/startup/utils/startup-validators.js.map +0 -1
- package/dist/templates/startup/apps/.gitkeep +0 -8
- package/dist/utils/monorepo.d.ts +0 -19
- package/dist/utils/monorepo.d.ts.map +0 -1
- package/dist/utils/monorepo.js +0 -100
- package/dist/utils/monorepo.js.map +0 -1
- package/src/modules/app/commands/generate-manifest.ts +0 -75
- package/src/modules/startup/commands/create-startup.ts +0 -53
- package/src/modules/startup/errors/startup-errors.ts +0 -23
- package/src/modules/startup/index.ts +0 -11
- package/src/modules/startup/services/startup-service.ts +0 -57
- package/src/modules/startup/types/startup-types.ts +0 -8
- package/src/modules/startup/utils/startup-validators.ts +0 -19
- package/src/utils/monorepo.ts +0 -137
- package/templates/startup/apps/.gitkeep +0 -8
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as path from 'path'
|
|
2
|
+
|
|
3
|
+
import fs from 'fs-extra'
|
|
4
|
+
|
|
5
|
+
import { PackageResolver } from '../../../infrastructure/package-resolver.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* App template resolver implementation
|
|
9
|
+
*
|
|
10
|
+
* Resolves app templates from:
|
|
11
|
+
* - Local workspace app-templates/ directory
|
|
12
|
+
* - npm packages with @launch77-shared/app-template- prefix
|
|
13
|
+
*/
|
|
14
|
+
export class AppTemplateResolver extends PackageResolver {
|
|
15
|
+
protected getFolderName(): string {
|
|
16
|
+
return 'app-templates'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
protected getPackagePrefix(): string {
|
|
20
|
+
return '@launch77-shared/app-template-'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
protected async verify(localPath: string): Promise<boolean> {
|
|
24
|
+
// All Launch77 packages must have package.json with version
|
|
25
|
+
const hasPackageJson = await fs.pathExists(path.join(localPath, 'package.json'))
|
|
26
|
+
if (!hasPackageJson) {
|
|
27
|
+
return false
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Verify package.json has a version field
|
|
31
|
+
try {
|
|
32
|
+
const packageJson = await fs.readJson(path.join(localPath, 'package.json'))
|
|
33
|
+
if (!packageJson.version) {
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Check for either:
|
|
41
|
+
// 1. A 'template' subdirectory (preferred structure for npm packages)
|
|
42
|
+
// 2. Any files at the root (simple local templates)
|
|
43
|
+
const hasTemplateDir = await fs.pathExists(path.join(localPath, 'template'))
|
|
44
|
+
if (hasTemplateDir) {
|
|
45
|
+
return true
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Check if directory has any files (not just an empty directory)
|
|
49
|
+
try {
|
|
50
|
+
const files = await fs.readdir(localPath)
|
|
51
|
+
return files.length > 0
|
|
52
|
+
} catch {
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
|
|
3
|
-
import type { AppType } from '../types/app-types.js'
|
|
4
|
-
|
|
5
3
|
// Deployment configuration
|
|
6
4
|
export type DeploymentConfig = {
|
|
7
5
|
platform: 'vercel'
|
|
@@ -14,7 +12,6 @@ export type DeploymentConfig = {
|
|
|
14
12
|
export type AppManifest = {
|
|
15
13
|
schemaVersion: 1
|
|
16
14
|
name: string
|
|
17
|
-
type: AppType | 'marketing' // Support both 'marketing' and 'marketing-site'
|
|
18
15
|
package: string
|
|
19
16
|
deployment?: DeploymentConfig
|
|
20
17
|
}
|
|
@@ -28,12 +25,10 @@ const deploymentConfigZ = z.object({
|
|
|
28
25
|
})
|
|
29
26
|
|
|
30
27
|
// Main manifest schema - strict mode to reject extra fields
|
|
31
|
-
// Note: Manifests store 'marketing' but we accept 'marketing-site' in commands
|
|
32
28
|
export const manifestZ = z
|
|
33
29
|
.object({
|
|
34
30
|
schemaVersion: z.literal(1),
|
|
35
31
|
name: z.string().min(1),
|
|
36
|
-
type: z.enum(['marketing', 'webapp', 'api']),
|
|
37
32
|
package: z.string().min(1),
|
|
38
33
|
deployment: deploymentConfigZ.optional(),
|
|
39
34
|
})
|
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
import * as path from 'path'
|
|
2
2
|
|
|
3
3
|
import fs from 'fs-extra'
|
|
4
|
+
import { readTemplateMetadata } from '@launch77/plugin-runtime'
|
|
4
5
|
|
|
5
6
|
import { ManifestService } from './manifest-svc.js'
|
|
6
7
|
import * as filesystem from '../../../infrastructure/filesystem.js'
|
|
7
8
|
import * as npm from '../../../infrastructure/npm.js'
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
9
|
+
import { downloadNpmPackage } from '../../../infrastructure/npm-package.js'
|
|
10
|
+
import { processTemplate } from '../../../infrastructure/template.js'
|
|
10
11
|
import { validateWorkspaceContext } from '../../../utils/launch77-validation.js'
|
|
11
12
|
import { validateAppName } from '../../../utils/validation.js'
|
|
13
|
+
import { AppTemplateResolver } from '../lib/app-template-resolver.js'
|
|
12
14
|
|
|
13
|
-
import type { Launch77Context } from '@launch77/plugin-runtime'
|
|
14
15
|
import type { CreateAppRequest, CreateAppResult, DeleteAppRequest, DeleteAppResult } from '../types/app-types.js'
|
|
16
|
+
import type { Launch77Context, TemplateReference, Launch77PackageManifest } from '@launch77/plugin-runtime'
|
|
15
17
|
|
|
16
18
|
export class AppService {
|
|
17
19
|
private manifestService: ManifestService
|
|
20
|
+
private appTemplateResolver: AppTemplateResolver
|
|
18
21
|
|
|
19
22
|
constructor() {
|
|
20
23
|
this.manifestService = new ManifestService()
|
|
24
|
+
this.appTemplateResolver = new AppTemplateResolver()
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
/**
|
|
@@ -38,30 +42,102 @@ export class AppService {
|
|
|
38
42
|
throw new Error(contextValidation.errorMessage)
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
// 3.
|
|
45
|
+
// 3. Validate template name
|
|
46
|
+
const templateValidation = this.appTemplateResolver.validateInput(type)
|
|
47
|
+
if (!templateValidation.isValid) {
|
|
48
|
+
throw new Error(templateValidation.error || `Invalid template name: ${type}`)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 4. Resolve template location
|
|
52
|
+
const templateResolution = await this.appTemplateResolver.resolveLocation(type, context.workspaceRoot)
|
|
53
|
+
|
|
54
|
+
let templatePath: string
|
|
55
|
+
let templateVersion: string
|
|
56
|
+
let packageRootPath: string
|
|
57
|
+
|
|
58
|
+
if (templateResolution.source === 'local') {
|
|
59
|
+
// Use local template
|
|
60
|
+
packageRootPath = templateResolution.localPath!
|
|
61
|
+
templatePath = packageRootPath
|
|
62
|
+
templateVersion = templateResolution.version! // Local templates always have version after verification
|
|
63
|
+
} else {
|
|
64
|
+
// Download npm template
|
|
65
|
+
const downloadResult = await downloadNpmPackage({
|
|
66
|
+
packageName: templateResolution.npmPackage!,
|
|
67
|
+
workspaceRoot: context.workspaceRoot,
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
packageRootPath = downloadResult.packagePath
|
|
71
|
+
|
|
72
|
+
// Check if template has a 'template' subdirectory, otherwise use package root
|
|
73
|
+
const templateSubdir = path.join(packageRootPath, 'template')
|
|
74
|
+
if (await fs.pathExists(templateSubdir)) {
|
|
75
|
+
templatePath = templateSubdir
|
|
76
|
+
} else {
|
|
77
|
+
templatePath = packageRootPath
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Read version from downloaded package
|
|
81
|
+
const packageJsonPath = path.join(packageRootPath, 'package.json')
|
|
82
|
+
const packageJson = await fs.readJson(packageJsonPath)
|
|
83
|
+
templateVersion = packageJson.version
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 5. Determine app path
|
|
42
87
|
const appPath = path.join(context.appsDir, appName)
|
|
43
88
|
|
|
44
|
-
//
|
|
89
|
+
// 6. Check if app already exists
|
|
45
90
|
if (await fs.pathExists(appPath)) {
|
|
46
91
|
throw new Error(`App ${appName} already exists at ${appPath}`)
|
|
47
92
|
}
|
|
48
93
|
|
|
49
|
-
//
|
|
50
|
-
if (!(await
|
|
51
|
-
throw new Error(`
|
|
94
|
+
// 7. Verify template path exists
|
|
95
|
+
if (!(await fs.pathExists(templatePath))) {
|
|
96
|
+
throw new Error(`Template not found at: ${templatePath}`)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 8. Generate from template (context already has packageName computed)
|
|
100
|
+
await processTemplate(templatePath, appPath, {
|
|
101
|
+
appName,
|
|
102
|
+
workspaceName: context.workspaceName,
|
|
103
|
+
packageName: context.packageName,
|
|
104
|
+
port,
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
// 9. Read template metadata (currently empty, placeholder for future config)
|
|
108
|
+
//const templateMetadata = await readTemplateMetadata(templatePath)
|
|
109
|
+
|
|
110
|
+
// 10. Write template reference to app's package.json
|
|
111
|
+
const appPackageJsonPath = path.join(appPath, 'package.json')
|
|
112
|
+
const appPackageJson = await fs.readJson(appPackageJsonPath)
|
|
113
|
+
|
|
114
|
+
// Build template reference - version read from package.json
|
|
115
|
+
const templatePackage = templateResolution.source === 'npm' ? templateResolution.npmPackage! : templateResolution.resolvedName
|
|
116
|
+
const templateRef: TemplateReference = {
|
|
117
|
+
package: templatePackage,
|
|
118
|
+
version: templateVersion,
|
|
119
|
+
source: templateResolution.source,
|
|
120
|
+
createdAt: new Date().toISOString(),
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Initialize launch77 manifest structure
|
|
124
|
+
if (!appPackageJson.launch77) {
|
|
125
|
+
appPackageJson.launch77 = {}
|
|
52
126
|
}
|
|
127
|
+
const launch77Manifest = appPackageJson.launch77 as Launch77PackageManifest
|
|
128
|
+
launch77Manifest.template = templateRef
|
|
53
129
|
|
|
54
|
-
//
|
|
55
|
-
await
|
|
130
|
+
// Write updated package.json
|
|
131
|
+
await fs.writeJson(appPackageJsonPath, appPackageJson, { spaces: 2 })
|
|
56
132
|
|
|
57
|
-
//
|
|
58
|
-
const manifest = this.manifestService.generateManifest(
|
|
133
|
+
// 11. Generate and write app manifest
|
|
134
|
+
const manifest = this.manifestService.generateManifest(appName, context, { port })
|
|
59
135
|
const launchDir = path.join(appPath, '.launch')
|
|
60
136
|
await filesystem.ensureDir(launchDir)
|
|
61
137
|
const manifestPath = path.join(launchDir, 'app.json')
|
|
62
138
|
await filesystem.writeJSON(manifestPath, manifest)
|
|
63
139
|
|
|
64
|
-
//
|
|
140
|
+
// 12. Install dependencies
|
|
65
141
|
await npm.install(context.workspaceRoot)
|
|
66
142
|
|
|
67
143
|
return {
|
|
@@ -8,7 +8,7 @@ import type { AppManifest } from '../lib/manifest-schema.js'
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Convert kebab-case to Title Case
|
|
11
|
-
* e.g., "my-
|
|
11
|
+
* e.g., "my-workspace-name" -> "My Workspace Name"
|
|
12
12
|
*/
|
|
13
13
|
function toTitleCase(str: string): string {
|
|
14
14
|
return str
|
|
@@ -17,66 +17,17 @@ function toTitleCase(str: string): string {
|
|
|
17
17
|
.join(' ')
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
/**
|
|
21
|
-
* Generate a manifest for a marketing app
|
|
22
|
-
*/
|
|
23
|
-
function generateMarketingManifest(appName: string, context: Launch77Context): AppManifest {
|
|
24
|
-
const workspaceName = context.workspaceName
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
schemaVersion: 1,
|
|
28
|
-
name: `${toTitleCase(workspaceName)} Marketing`,
|
|
29
|
-
type: 'marketing',
|
|
30
|
-
package: `@${workspaceName}/${appName}`,
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Generate a manifest for a webapp
|
|
36
|
-
*/
|
|
37
|
-
function generateWebappManifest(appName: string, context: Launch77Context): AppManifest {
|
|
38
|
-
const workspaceName = context.workspaceName
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
schemaVersion: 1,
|
|
42
|
-
name: `${toTitleCase(workspaceName)} Web`,
|
|
43
|
-
type: 'webapp',
|
|
44
|
-
package: `@${workspaceName}/${appName}`,
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Generate a manifest for an API app
|
|
50
|
-
*/
|
|
51
|
-
function generateApiManifest(appName: string, context: Launch77Context): AppManifest {
|
|
52
|
-
const workspaceName = context.workspaceName
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
schemaVersion: 1,
|
|
56
|
-
name: `${toTitleCase(workspaceName)} API`,
|
|
57
|
-
type: 'api',
|
|
58
|
-
package: `@${workspaceName}/${appName}`,
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
20
|
export class ManifestService {
|
|
63
21
|
/**
|
|
64
|
-
* Generate an app manifest
|
|
22
|
+
* Generate an app manifest
|
|
65
23
|
*/
|
|
66
|
-
generateManifest(
|
|
67
|
-
|
|
68
|
-
case 'marketing-site':
|
|
69
|
-
case 'marketing':
|
|
70
|
-
return generateMarketingManifest(appName, context)
|
|
71
|
-
|
|
72
|
-
case 'webapp':
|
|
73
|
-
return generateWebappManifest(appName, context)
|
|
74
|
-
|
|
75
|
-
case 'api':
|
|
76
|
-
return generateApiManifest(appName, context)
|
|
24
|
+
generateManifest(appName: string, context: Launch77Context, _options: { port?: string }): AppManifest {
|
|
25
|
+
const workspaceName = context.workspaceName
|
|
77
26
|
|
|
78
|
-
|
|
79
|
-
|
|
27
|
+
return {
|
|
28
|
+
schemaVersion: 1,
|
|
29
|
+
name: toTitleCase(workspaceName),
|
|
30
|
+
package: `@${workspaceName}/${appName}`,
|
|
80
31
|
}
|
|
81
32
|
}
|
|
82
33
|
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
// Supported app types
|
|
2
|
-
export const APP_TYPES = ['api', 'webapp', 'marketing-site'] as const
|
|
3
|
-
export type AppType = (typeof APP_TYPES)[number]
|
|
4
|
-
|
|
5
|
-
// Display list for error messages
|
|
6
|
-
export const APP_TYPES_LIST = APP_TYPES.join(', ')
|
|
7
|
-
|
|
8
1
|
export interface CreateAppRequest {
|
|
9
|
-
type:
|
|
2
|
+
type: string
|
|
10
3
|
appName: string
|
|
11
4
|
port: string
|
|
12
5
|
}
|
|
@@ -14,7 +7,7 @@ export interface CreateAppRequest {
|
|
|
14
7
|
export interface CreateAppResult {
|
|
15
8
|
appPath: string
|
|
16
9
|
appName: string
|
|
17
|
-
type:
|
|
10
|
+
type: string
|
|
18
11
|
}
|
|
19
12
|
|
|
20
13
|
export interface DeleteAppRequest {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk'
|
|
2
2
|
import { Command } from 'commander'
|
|
3
|
+
import { detectLaunch77Context } from '@launch77/plugin-runtime'
|
|
3
4
|
|
|
4
|
-
import { detectMonorepoContext } from '../../../utils/monorepo.js'
|
|
5
5
|
import { CatalogService } from '../services/catalog-svc.js'
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -17,10 +17,10 @@ export function scanCommand(): Command {
|
|
|
17
17
|
.option('--quiet', 'Suppress quality report output')
|
|
18
18
|
.action(async (options) => {
|
|
19
19
|
try {
|
|
20
|
-
const context = await
|
|
20
|
+
const context = await detectLaunch77Context(process.cwd())
|
|
21
21
|
|
|
22
22
|
if (!context.isValid) {
|
|
23
|
-
console.error(chalk.red('\n✖ Must be run from within a Launch77
|
|
23
|
+
console.error(chalk.red('\n✖ Must be run from within a Launch77 workspace\n'))
|
|
24
24
|
process.exit(1)
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -9,7 +9,7 @@ import { scanUILibrary } from '../scanners/ui-component-scanner.js'
|
|
|
9
9
|
import { generateExamplesFiles } from '../utils/examples-generator.js'
|
|
10
10
|
import { generateQualityReport, printQualityReport } from '../utils/quality-reporter.js'
|
|
11
11
|
|
|
12
|
-
import type {
|
|
12
|
+
import type { Launch77Context } from '@launch77/plugin-runtime'
|
|
13
13
|
import type { ValidationResult, UiComponent } from '../types/catalog-types.js'
|
|
14
14
|
|
|
15
15
|
export interface ScanCatalogOptions {
|
|
@@ -32,13 +32,13 @@ export class CatalogService {
|
|
|
32
32
|
/**
|
|
33
33
|
* Scan Launch77 codebase and generate catalog.json
|
|
34
34
|
*/
|
|
35
|
-
async scanCatalog(context:
|
|
35
|
+
async scanCatalog(context: Launch77Context, options: ScanCatalogOptions = {}): Promise<ScanCatalogResult> {
|
|
36
36
|
const strict = options.strict !== false // Default to true (strict mode)
|
|
37
37
|
const quiet = options.quiet || false
|
|
38
38
|
|
|
39
39
|
console.log(chalk.blue('\n🔍 Scanning Launch77 artifacts...\n'))
|
|
40
40
|
|
|
41
|
-
const launch77Root = path.join(context.
|
|
41
|
+
const launch77Root = path.join(context.workspaceRoot, 'launch77')
|
|
42
42
|
|
|
43
43
|
const spinner = ora('Scanning codebase...').start()
|
|
44
44
|
|
|
@@ -109,7 +109,7 @@ export class CatalogService {
|
|
|
109
109
|
console.log(chalk.green(` ✓ Saved to ${path.relative(process.cwd(), catalogPath)}`))
|
|
110
110
|
|
|
111
111
|
// Sync catalog to Launch77 marketing site
|
|
112
|
-
const marketingSiteCatalogPath = path.join(context.
|
|
112
|
+
const marketingSiteCatalogPath = path.join(context.workspaceRoot, 'apps/marketing/src/catalog.json')
|
|
113
113
|
|
|
114
114
|
if (await fs.pathExists(path.dirname(marketingSiteCatalogPath))) {
|
|
115
115
|
await fs.writeFile(marketingSiteCatalogPath, formatted)
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
import * as path from 'path'
|
|
7
7
|
|
|
8
8
|
import chalk from 'chalk'
|
|
9
|
+
import { detectLaunch77Context } from '@launch77/plugin-runtime'
|
|
9
10
|
import fs from 'fs-extra'
|
|
10
11
|
import ora from 'ora'
|
|
11
12
|
|
|
12
|
-
import { detectMonorepoContext } from '../../../utils/monorepo.js'
|
|
13
13
|
import { DeployService } from '../services/deploy-svc.js'
|
|
14
14
|
import { connectGitRepository, getPackageName, getVercelInstallInstructions, isVercelCliInstalled, loadVercelProject, runVercelCommand, updateProjectRootDirectory, verifyVercelProjectExists } from '../utils/vercel-extended.js'
|
|
15
15
|
|
|
@@ -23,16 +23,15 @@ interface DeployInitOptions {
|
|
|
23
23
|
export async function deployInit(options: DeployInitOptions = {}) {
|
|
24
24
|
const deployService = new DeployService()
|
|
25
25
|
|
|
26
|
-
// Detect
|
|
27
|
-
const context = await
|
|
26
|
+
// Detect Launch77 context
|
|
27
|
+
const context = await detectLaunch77Context(process.cwd())
|
|
28
28
|
|
|
29
|
-
if (context.
|
|
30
|
-
throw new Error('Must be run from within an app directory (e.g.,
|
|
29
|
+
if (context.locationType !== 'workspace-app') {
|
|
30
|
+
throw new Error('Must be run from within an app directory (e.g., apps/myapp)')
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
const appPath = process.cwd()
|
|
34
34
|
const appName = context.appName!
|
|
35
|
-
const startupName = context.startupName!
|
|
36
35
|
|
|
37
36
|
console.log(chalk.blue(`\n🚀 Initializing Vercel deployment for ${appName}...\n`))
|
|
38
37
|
|
|
@@ -116,23 +115,27 @@ export async function deployInit(options: DeployInitOptions = {}) {
|
|
|
116
115
|
throw new Error('Could not read package name from package.json')
|
|
117
116
|
}
|
|
118
117
|
|
|
118
|
+
// Check template type from app's package.json
|
|
119
|
+
const appPackageJsonPath = path.join(appPath, 'package.json')
|
|
120
|
+
const appPackageJson = await fs.readJson(appPackageJsonPath)
|
|
121
|
+
const templatePackage = appPackageJson.launch77?.template?.package
|
|
122
|
+
|
|
119
123
|
console.log(chalk.gray(`App details:`))
|
|
120
124
|
console.log(chalk.gray(` Name: ${manifest.name}`))
|
|
121
|
-
console.log(chalk.gray(` Type: ${manifest.type}`))
|
|
122
125
|
console.log(chalk.gray(` Package: ${packageName}`))
|
|
126
|
+
if (templatePackage) {
|
|
127
|
+
console.log(chalk.gray(` Template: ${templatePackage}`))
|
|
128
|
+
}
|
|
123
129
|
console.log()
|
|
124
130
|
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
console.log(chalk.
|
|
130
|
-
console.log(chalk.
|
|
131
|
-
console.log(chalk.white(' • Fly.io'), chalk.gray('- Global edge deployment'))
|
|
132
|
-
console.log(chalk.white(' • Render.com'), chalk.gray('- Managed cloud hosting'))
|
|
131
|
+
// Only allow webapp apps to deploy to Vercel
|
|
132
|
+
const isWebapp = templatePackage === 'webapp' || templatePackage === '@launch77-shared/app-template-webapp'
|
|
133
|
+
|
|
134
|
+
if (!isWebapp) {
|
|
135
|
+
console.log(chalk.yellow('⚠️ Vercel deployment only supports webapp apps'))
|
|
136
|
+
console.log(chalk.gray('Other app types coming soon'))
|
|
133
137
|
console.log()
|
|
134
|
-
|
|
135
|
-
process.exit(0)
|
|
138
|
+
process.exit(1)
|
|
136
139
|
}
|
|
137
140
|
|
|
138
141
|
// Check if vercel.json exists
|
|
@@ -160,7 +163,7 @@ export async function deployInit(options: DeployInitOptions = {}) {
|
|
|
160
163
|
console.log()
|
|
161
164
|
|
|
162
165
|
try {
|
|
163
|
-
const suggestedProjectName =
|
|
166
|
+
const suggestedProjectName = appName
|
|
164
167
|
await runVercelCommand(['link', '--project', suggestedProjectName, '--yes'], appPath)
|
|
165
168
|
|
|
166
169
|
console.log()
|
|
@@ -172,7 +175,7 @@ export async function deployInit(options: DeployInitOptions = {}) {
|
|
|
172
175
|
|
|
173
176
|
// Read the created .vercel/project.json to get project info
|
|
174
177
|
const vercelProject = await loadVercelProject(appPath)
|
|
175
|
-
const projectName = vercelProject?.projectName ||
|
|
178
|
+
const projectName = vercelProject?.projectName || appName
|
|
176
179
|
|
|
177
180
|
// Update manifest with deployment configuration
|
|
178
181
|
manifest.deployment = {
|
|
@@ -187,7 +190,7 @@ export async function deployInit(options: DeployInitOptions = {}) {
|
|
|
187
190
|
|
|
188
191
|
// Set Root Directory for monorepo deployments
|
|
189
192
|
console.log()
|
|
190
|
-
const rootDirectory = `
|
|
193
|
+
const rootDirectory = `apps/${appName}`
|
|
191
194
|
await updateProjectRootDirectory(projectName, rootDirectory)
|
|
192
195
|
|
|
193
196
|
// Automatically connect to Git repository
|
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/* eslint-disable no-console */
|
|
6
|
+
import * as path from 'path'
|
|
7
|
+
|
|
6
8
|
import chalk from 'chalk'
|
|
9
|
+
import { detectLaunch77Context } from '@launch77/plugin-runtime'
|
|
10
|
+
import fs from 'fs-extra'
|
|
7
11
|
|
|
8
|
-
import { detectMonorepoContext } from '../../../utils/monorepo.js'
|
|
9
12
|
import { DeployService } from '../services/deploy-svc.js'
|
|
10
13
|
import { getVercelInstallInstructions, isVercelCliInstalled, runVercelCommand } from '../utils/vercel-extended.js'
|
|
11
14
|
|
|
@@ -20,11 +23,11 @@ export interface DeployLogsOptions {
|
|
|
20
23
|
export async function deployLogs(options: DeployLogsOptions) {
|
|
21
24
|
const deployService = new DeployService()
|
|
22
25
|
|
|
23
|
-
// Detect
|
|
24
|
-
const context = await
|
|
26
|
+
// Detect Launch77 context
|
|
27
|
+
const context = await detectLaunch77Context(process.cwd())
|
|
25
28
|
|
|
26
|
-
if (context.
|
|
27
|
-
throw new Error('Must be run from within an app directory (e.g.,
|
|
29
|
+
if (context.locationType !== 'workspace-app') {
|
|
30
|
+
throw new Error('Must be run from within an app directory (e.g., apps/myapp)')
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
const appPath = process.cwd()
|
|
@@ -34,14 +37,17 @@ export async function deployLogs(options: DeployLogsOptions) {
|
|
|
34
37
|
// Load manifest
|
|
35
38
|
const manifest = await deployService.loadManifest()
|
|
36
39
|
|
|
37
|
-
// Check
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
// Check template type from app's package.json
|
|
41
|
+
const appPackageJsonPath = path.join(appPath, 'package.json')
|
|
42
|
+
const appPackageJson = await fs.readJson(appPackageJsonPath)
|
|
43
|
+
const templatePackage = appPackageJson.launch77?.template?.package
|
|
44
|
+
|
|
45
|
+
// Only allow webapp apps to deploy to Vercel
|
|
46
|
+
const isWebapp = templatePackage === 'webapp' || templatePackage === '@launch77-shared/app-template-webapp'
|
|
47
|
+
|
|
48
|
+
if (!isWebapp) {
|
|
49
|
+
console.log(chalk.yellow('⚠️ Vercel deployment only supports webapp apps'))
|
|
50
|
+
console.log(chalk.gray('Other app types coming soon'))
|
|
45
51
|
console.log()
|
|
46
52
|
return
|
|
47
53
|
}
|
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/* eslint-disable no-console */
|
|
6
|
+
import * as path from 'path'
|
|
7
|
+
|
|
6
8
|
import chalk from 'chalk'
|
|
9
|
+
import { detectLaunch77Context } from '@launch77/plugin-runtime'
|
|
10
|
+
import fs from 'fs-extra'
|
|
7
11
|
import ora from 'ora'
|
|
8
12
|
|
|
9
|
-
import { detectMonorepoContext } from '../../../utils/monorepo.js'
|
|
10
13
|
import { DeployService } from '../services/deploy-svc.js'
|
|
11
14
|
import { getVercelInstallInstructions, isVercelCliInstalled, runVercelCommand, verifyVercelProjectExists } from '../utils/vercel-extended.js'
|
|
12
15
|
|
|
@@ -16,11 +19,11 @@ import { getVercelInstallInstructions, isVercelCliInstalled, runVercelCommand, v
|
|
|
16
19
|
export async function deployStatus() {
|
|
17
20
|
const deployService = new DeployService()
|
|
18
21
|
|
|
19
|
-
// Detect
|
|
20
|
-
const context = await
|
|
22
|
+
// Detect Launch77 context
|
|
23
|
+
const context = await detectLaunch77Context(process.cwd())
|
|
21
24
|
|
|
22
|
-
if (context.
|
|
23
|
-
throw new Error('Must be run from within an app directory (e.g.,
|
|
25
|
+
if (context.locationType !== 'workspace-app') {
|
|
26
|
+
throw new Error('Must be run from within an app directory (e.g., apps/myapp)')
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
const appPath = process.cwd()
|
|
@@ -30,14 +33,17 @@ export async function deployStatus() {
|
|
|
30
33
|
// Load manifest
|
|
31
34
|
const manifest = await deployService.loadManifest()
|
|
32
35
|
|
|
33
|
-
// Check
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
// Check template type from app's package.json
|
|
37
|
+
const appPackageJsonPath = path.join(appPath, 'package.json')
|
|
38
|
+
const appPackageJson = await fs.readJson(appPackageJsonPath)
|
|
39
|
+
const templatePackage = appPackageJson.launch77?.template?.package
|
|
40
|
+
|
|
41
|
+
// Only allow webapp apps to deploy to Vercel
|
|
42
|
+
const isWebapp = templatePackage === 'webapp' || templatePackage === '@launch77-shared/app-template-webapp'
|
|
43
|
+
|
|
44
|
+
if (!isWebapp) {
|
|
45
|
+
console.log(chalk.yellow('⚠️ Vercel deployment only supports webapp apps'))
|
|
46
|
+
console.log(chalk.gray('Other app types coming soon'))
|
|
41
47
|
console.log()
|
|
42
48
|
return
|
|
43
49
|
}
|