@runmist/frameworks 1.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daniel Chavez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # @bitclaw/frameworks
2
+
3
+ Framework, ORM, runtime, and monorepo detection for deployment pipelines. Built on Bun.
4
+
5
+ ## Features
6
+
7
+ - **Framework detection** Identifies Next.js, Remix, Astro, SvelteKit, Nuxt, and more from `package.json` deps
8
+ - **ORM detection** Detects Prisma, Drizzle, Sequelize, TypeORM, Mongoose, and others
9
+ - **Runtime detection** Identifies Bun vs Node.js with version resolution
10
+ - **Monorepo detection** Detects Turborepo, Nx, PNPM workspaces, Bun workspaces, Lerna
11
+ - **Repo analysis** Full `analyzeRepo` combining all detections in one pass
12
+ - **Presets** Deployment presets per framework (build command, output dir, install command)
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ bun add @bitclaw/frameworks
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ```typescript
23
+ import { analyzeRepo } from '@bitclaw/frameworks'
24
+
25
+ const result = await analyzeRepo('/path/to/repo')
26
+ console.log(result)
27
+ // {
28
+ // framework: { name: 'nextjs', confidence: 'high' },
29
+ // orm: { name: 'prisma' },
30
+ // runtime: { name: 'bun', version: '1.3.0' },
31
+ // monorepo: null,
32
+ // packageManager: 'bun'
33
+ // }
34
+ ```
35
+
36
+ ## API
37
+
38
+ ```typescript
39
+ analyzeRepo(dir) // → Promise<RepoDetectionResult>
40
+ detectFramework(packageJson) // → DetectedApp | null
41
+ detectOrm(packageJson) // → OrmPreset | null
42
+ detectRuntime(dir) // → Promise<{ name, version }>
43
+ detectMonorepo(dir) // → Promise<MonorepoInfo | null>
44
+ detectPackageManager(dir) // → Promise<'bun' | 'npm' | 'pnpm' | 'yarn'>
45
+ getPreset(frameworkName) // → FrameworkPreset | null
46
+ getOrmPreset(ormName) // → OrmPreset | null
47
+ ```
48
+
49
+ ## Testing
50
+
51
+ ```bash
52
+ bun test
53
+ ```
@@ -0,0 +1,10 @@
1
+ import type { RepoDetectionResult } from './types';
2
+ /**
3
+ * Analyze a repository's file tree and package.json contents to detect
4
+ * monorepo structure, frameworks, and runtimes.
5
+ *
6
+ * @param filePaths - All file paths in the repo (from git tree API)
7
+ * @param packageJsonContents - Map of file path to parsed package.json content string
8
+ */
9
+ export declare function analyzeRepo(filePaths: string[], packageJsonContents: Map<string, string>): RepoDetectionResult;
10
+ //# sourceMappingURL=analyze-repo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze-repo.d.ts","sourceRoot":"","sources":["../src/analyze-repo.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAe,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEhE;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EAAE,EACnB,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACvC,mBAAmB,CAsErB"}
@@ -0,0 +1,80 @@
1
+ import { detectFramework } from './detect-framework';
2
+ import { detectMonorepo } from './detect-monorepo';
3
+ import { detectOrm } from './detect-orm';
4
+ import { detectPackageManager, detectRuntime } from './detect-runtime';
5
+ /**
6
+ * Analyze a repository's file tree and package.json contents to detect
7
+ * monorepo structure, frameworks, and runtimes.
8
+ *
9
+ * @param filePaths - All file paths in the repo (from git tree API)
10
+ * @param packageJsonContents - Map of file path to parsed package.json content string
11
+ */
12
+ export function analyzeRepo(filePaths, packageJsonContents) {
13
+ const packageManager = detectPackageManager(filePaths);
14
+ const monorepo = detectMonorepo(filePaths);
15
+ // Detect root-level framework
16
+ let rootFramework = null;
17
+ let rootRuntime = null;
18
+ let rootParsed = null;
19
+ const rootPkgJson = packageJsonContents.get('package.json');
20
+ if (rootPkgJson) {
21
+ try {
22
+ rootParsed = JSON.parse(rootPkgJson);
23
+ rootFramework = detectFramework(rootParsed);
24
+ rootRuntime = detectRuntime(rootFramework, filePaths);
25
+ }
26
+ catch {
27
+ // Invalid JSON, skip
28
+ }
29
+ }
30
+ if (!monorepo.isMonorepo) {
31
+ // Single-app repo
32
+ const apps = [];
33
+ if (rootFramework) {
34
+ apps.push({
35
+ name: '.',
36
+ path: '.',
37
+ framework: rootFramework,
38
+ runtime: rootRuntime,
39
+ orm: detectOrm(rootParsed ?? {})
40
+ });
41
+ }
42
+ return {
43
+ isMonorepo: false,
44
+ apps,
45
+ rootFramework,
46
+ rootRuntime,
47
+ packageManager
48
+ };
49
+ }
50
+ // Monorepo: analyze each app directory
51
+ const apps = [];
52
+ for (const appDir of monorepo.appDirs) {
53
+ const pkgPath = `apps/${appDir}/package.json`;
54
+ const pkgContent = packageJsonContents.get(pkgPath);
55
+ if (!pkgContent)
56
+ continue;
57
+ try {
58
+ const parsed = JSON.parse(pkgContent);
59
+ const framework = detectFramework(parsed);
60
+ const runtime = detectRuntime(framework, filePaths);
61
+ apps.push({
62
+ name: appDir,
63
+ path: `apps/${appDir}`,
64
+ framework,
65
+ runtime,
66
+ orm: detectOrm(parsed)
67
+ });
68
+ }
69
+ catch {
70
+ // Invalid JSON, skip this app
71
+ }
72
+ }
73
+ return {
74
+ isMonorepo: true,
75
+ apps,
76
+ rootFramework,
77
+ rootRuntime,
78
+ packageManager
79
+ };
80
+ }
@@ -0,0 +1,7 @@
1
+ type PackageJson = {
2
+ dependencies?: Record<string, string>;
3
+ devDependencies?: Record<string, string>;
4
+ };
5
+ export declare function detectFramework(packageJson: PackageJson): string | null;
6
+ export {};
7
+ //# sourceMappingURL=detect-framework.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-framework.d.ts","sourceRoot":"","sources":["../src/detect-framework.ts"],"names":[],"mappings":"AAAA,KAAK,WAAW,GAAG;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C,CAAC;AAgCF,wBAAgB,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAkBvE"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Ordered by specificity: meta-frameworks first, then base tools last.
3
+ * Higher-specificity frameworks supersede lower ones (e.g. TanStack Start supersedes Nitro and Vite).
4
+ */
5
+ const DETECTION_RULES = [
6
+ { id: 'tanstack-start', matchPackages: ['@tanstack/react-start'] },
7
+ { id: 'nextjs', matchPackages: ['next'] },
8
+ { id: 'nuxt', matchPackages: ['nuxt', 'nuxt3'] },
9
+ { id: 'sveltekit', matchPackages: ['@sveltejs/kit'] },
10
+ { id: 'astro', matchPackages: ['astro'] },
11
+ {
12
+ id: 'react-router',
13
+ matchPackages: ['@react-router/dev', '@remix-run/dev']
14
+ },
15
+ { id: 'nitro', matchPackages: ['nitropack', 'nitro'] },
16
+ { id: 'hono', matchPackages: ['hono'] },
17
+ { id: 'elysia', matchPackages: ['elysia'] },
18
+ { id: 'express', matchPackages: ['express'] },
19
+ { id: 'fastify', matchPackages: ['fastify'] },
20
+ { id: 'vite', matchPackages: ['vite'], devOnly: true }
21
+ ];
22
+ export function detectFramework(packageJson) {
23
+ const deps = packageJson.dependencies ?? {};
24
+ const devDeps = packageJson.devDependencies ?? {};
25
+ for (const rule of DETECTION_RULES) {
26
+ const hasDep = rule.matchPackages.some(pkg => {
27
+ if (rule.devOnly) {
28
+ return pkg in devDeps;
29
+ }
30
+ return pkg in deps || pkg in devDeps;
31
+ });
32
+ if (hasDep) {
33
+ return rule.id;
34
+ }
35
+ }
36
+ return null;
37
+ }
@@ -0,0 +1,3 @@
1
+ import type { MonorepoInfo } from './types';
2
+ export declare function detectMonorepo(filePaths: string[]): MonorepoInfo;
3
+ //# sourceMappingURL=detect-monorepo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-monorepo.d.ts","sourceRoot":"","sources":["../src/detect-monorepo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAW5C,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,YAAY,CAkBhE"}
@@ -0,0 +1,23 @@
1
+ const MONOREPO_INDICATORS = [
2
+ 'pnpm-workspace.yaml',
3
+ 'turbo.json',
4
+ 'lerna.json',
5
+ 'nx.json'
6
+ ];
7
+ const APP_DIR_PATTERN = /^apps\/([^/]+)\/package\.json$/;
8
+ export function detectMonorepo(filePaths) {
9
+ const hasIndicator = filePaths.some(p => MONOREPO_INDICATORS.includes(p));
10
+ // Also check for workspaces in root package.json (handled by caller via packageJsonContents)
11
+ // Here we just detect via file-based indicators
12
+ const appDirs = [];
13
+ for (const fp of filePaths) {
14
+ const match = APP_DIR_PATTERN.exec(fp);
15
+ if (match?.[1]) {
16
+ appDirs.push(match[1]);
17
+ }
18
+ }
19
+ return {
20
+ isMonorepo: hasIndicator && appDirs.length > 0,
21
+ appDirs
22
+ };
23
+ }
@@ -0,0 +1,8 @@
1
+ import type { OrmPresetId } from './types';
2
+ type PackageJson = {
3
+ dependencies?: Record<string, string>;
4
+ devDependencies?: Record<string, string>;
5
+ };
6
+ export declare function detectOrm(packageJson: PackageJson): OrmPresetId;
7
+ export {};
8
+ //# sourceMappingURL=detect-orm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-orm.d.ts","sourceRoot":"","sources":["../src/detect-orm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,KAAK,WAAW,GAAG;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C,CAAC;AAEF,wBAAgB,SAAS,CAAC,WAAW,EAAE,WAAW,GAAG,WAAW,CAc/D"}
@@ -0,0 +1,19 @@
1
+ export function detectOrm(packageJson) {
2
+ const deps = {
3
+ ...packageJson.dependencies,
4
+ ...packageJson.devDependencies
5
+ };
6
+ if (deps.prisma || deps['@prisma/client'])
7
+ return 'prisma';
8
+ if (deps['drizzle-orm'])
9
+ return 'drizzle';
10
+ if (deps.typeorm)
11
+ return 'typeorm';
12
+ if (deps.knex)
13
+ return 'knex';
14
+ if (deps['@mikro-orm/core'] || deps['mikro-orm'])
15
+ return 'mikro-orm';
16
+ if (deps.sequelize)
17
+ return 'sequelize';
18
+ return 'none';
19
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Detect the runtime for a given framework.
3
+ * Uses the framework preset's default runtime.
4
+ */
5
+ export declare function detectRuntime(detectedFramework: string | null, _filePaths: string[]): 'bun' | 'node' | null;
6
+ /**
7
+ * Detect the package manager from lockfiles in the file tree.
8
+ * Checks root-level lockfiles only.
9
+ */
10
+ export declare function detectPackageManager(filePaths: string[]): 'bun' | 'npm' | 'yarn' | 'pnpm' | null;
11
+ //# sourceMappingURL=detect-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-runtime.d.ts","sourceRoot":"","sources":["../src/detect-runtime.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,UAAU,EAAE,MAAM,EAAE,GACnB,KAAK,GAAG,MAAM,GAAG,IAAI,CAIvB;AAUD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EAAE,GAClB,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAMxC"}
@@ -0,0 +1,30 @@
1
+ import { getPreset } from './presets';
2
+ /**
3
+ * Detect the runtime for a given framework.
4
+ * Uses the framework preset's default runtime.
5
+ */
6
+ export function detectRuntime(detectedFramework, _filePaths) {
7
+ if (!detectedFramework)
8
+ return null;
9
+ const preset = getPreset(detectedFramework);
10
+ return preset?.runtime ?? null;
11
+ }
12
+ const LOCKFILE_MAP = {
13
+ 'bun.lockb': 'bun',
14
+ 'bun.lock': 'bun',
15
+ 'package-lock.json': 'npm',
16
+ 'yarn.lock': 'yarn',
17
+ 'pnpm-lock.yaml': 'pnpm'
18
+ };
19
+ /**
20
+ * Detect the package manager from lockfiles in the file tree.
21
+ * Checks root-level lockfiles only.
22
+ */
23
+ export function detectPackageManager(filePaths) {
24
+ for (const fp of filePaths) {
25
+ const pm = LOCKFILE_MAP[fp];
26
+ if (pm)
27
+ return pm;
28
+ }
29
+ return null;
30
+ }
@@ -0,0 +1,11 @@
1
+ export { analyzeRepo } from './analyze-repo';
2
+ export { detectFramework } from './detect-framework';
3
+ export { detectMonorepo } from './detect-monorepo';
4
+ export { detectOrm } from './detect-orm';
5
+ export { detectPackageManager, detectRuntime } from './detect-runtime';
6
+ export { getOrmPreset, ORM_PRESET_OPTIONS, ORM_PRESETS } from './orm-presets';
7
+ export { FRAMEWORK_PRESET_OPTIONS, FRAMEWORK_PRESETS, getPreset } from './presets';
8
+ export type { BunVersion, NodeVersion } from './runtime-versions';
9
+ export { BUN_VERSIONS, DEFAULT_BUN_VERSION, DEFAULT_NODE_VERSION, NODE_VERSIONS } from './runtime-versions';
10
+ export type { DeployHookId, DetectedApp, FrameworkPreset, MonorepoInfo, OrmPreset, OrmPresetId, RepoDetectionResult } from './types';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACZ,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,SAAS,EACV,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,EACpB,aAAa,EACd,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,YAAY,EACZ,WAAW,EACX,eAAe,EACf,YAAY,EACZ,SAAS,EACT,WAAW,EACX,mBAAmB,EACpB,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { analyzeRepo } from './analyze-repo';
2
+ export { detectFramework } from './detect-framework';
3
+ export { detectMonorepo } from './detect-monorepo';
4
+ export { detectOrm } from './detect-orm';
5
+ export { detectPackageManager, detectRuntime } from './detect-runtime';
6
+ export { getOrmPreset, ORM_PRESET_OPTIONS, ORM_PRESETS } from './orm-presets';
7
+ export { FRAMEWORK_PRESET_OPTIONS, FRAMEWORK_PRESETS, getPreset } from './presets';
8
+ export { BUN_VERSIONS, DEFAULT_BUN_VERSION, DEFAULT_NODE_VERSION, NODE_VERSIONS } from './runtime-versions';
@@ -0,0 +1,9 @@
1
+ import type { OrmPreset } from './types';
2
+ export declare const ORM_PRESETS: OrmPreset[];
3
+ export declare function getOrmPreset(id: string): OrmPreset | undefined;
4
+ export declare const ORM_PRESET_OPTIONS: {
5
+ value: import("./types").OrmPresetId;
6
+ label: string;
7
+ description: string;
8
+ }[];
9
+ //# sourceMappingURL=orm-presets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orm-presets.d.ts","sourceRoot":"","sources":["../src/orm-presets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,eAAO,MAAM,WAAW,EAAE,SAAS,EAyDlC,CAAC;AAEF,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAE9D;AAED,eAAO,MAAM,kBAAkB;;;;GAI5B,CAAC"}
@@ -0,0 +1,66 @@
1
+ export const ORM_PRESETS = [
2
+ {
3
+ id: 'none',
4
+ name: 'None',
5
+ description: 'No ORM — manage migrations manually'
6
+ },
7
+ {
8
+ id: 'prisma',
9
+ name: 'Prisma',
10
+ description: 'Type-safe ORM with auto-generated client',
11
+ hooks: {
12
+ 'after-install': [
13
+ 'PRISMA_SCHEMA_DISABLE_ADVISORY_LOCK=1 npx prisma generate',
14
+ 'PRISMA_SCHEMA_DISABLE_ADVISORY_LOCK=1 npx prisma migrate deploy'
15
+ ]
16
+ }
17
+ },
18
+ {
19
+ id: 'drizzle',
20
+ name: 'Drizzle',
21
+ description: 'Lightweight TypeScript ORM',
22
+ hooks: {
23
+ 'after-install': ['npx drizzle-kit migrate']
24
+ }
25
+ },
26
+ {
27
+ id: 'knex',
28
+ name: 'Knex.js',
29
+ description: 'SQL query builder with migrations',
30
+ hooks: {
31
+ 'after-install': ['npx knex migrate:latest']
32
+ }
33
+ },
34
+ {
35
+ id: 'typeorm',
36
+ name: 'TypeORM',
37
+ description: 'ORM for TypeScript and JavaScript',
38
+ hooks: {
39
+ 'after-install': ['npx typeorm migration:run -d ./data-source.ts']
40
+ }
41
+ },
42
+ {
43
+ id: 'mikro-orm',
44
+ name: 'MikroORM',
45
+ description: 'TypeScript ORM with unit of work',
46
+ hooks: {
47
+ 'after-install': ['npx mikro-orm migration:up']
48
+ }
49
+ },
50
+ {
51
+ id: 'sequelize',
52
+ name: 'Sequelize',
53
+ description: 'Promise-based Node.js ORM',
54
+ hooks: {
55
+ 'after-install': ['npx sequelize-cli db:migrate']
56
+ }
57
+ }
58
+ ];
59
+ export function getOrmPreset(id) {
60
+ return ORM_PRESETS.find(p => p.id === id);
61
+ }
62
+ export const ORM_PRESET_OPTIONS = ORM_PRESETS.map(p => ({
63
+ value: p.id,
64
+ label: p.name,
65
+ description: p.description
66
+ }));
@@ -0,0 +1,10 @@
1
+ import type { FrameworkPreset } from './types';
2
+ export declare const FRAMEWORK_PRESETS: FrameworkPreset[];
3
+ export declare function getPreset(id: string): FrameworkPreset | undefined;
4
+ /** Pre-computed combobox items -- avoids re-creating on every render. */
5
+ export declare const FRAMEWORK_PRESET_OPTIONS: {
6
+ value: string;
7
+ label: string;
8
+ description: string;
9
+ }[];
10
+ //# sourceMappingURL=presets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,eAAO,MAAM,iBAAiB,EAAE,eAAe,EAgJ9C,CAAC;AAEF,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAEjE;AAED,yEAAyE;AACzE,eAAO,MAAM,wBAAwB;;;;GAIlC,CAAC"}
@@ -0,0 +1,154 @@
1
+ export const FRAMEWORK_PRESETS = [
2
+ {
3
+ id: 'tanstack-start',
4
+ name: 'TanStack Start',
5
+ description: 'TanStack Start with Nitro',
6
+ runtime: 'bun',
7
+ installCommand: 'bun install --frozen-lockfile',
8
+ buildCommand: 'bun run build',
9
+ startCommand: 'bun .output/server/index.mjs',
10
+ outputDirectory: '.output/public',
11
+ staticUrlPath: '/assets/*'
12
+ },
13
+ {
14
+ id: 'nitro',
15
+ name: 'Nitro',
16
+ description: 'UnJS Nitro server framework',
17
+ runtime: 'bun',
18
+ installCommand: 'bun install --frozen-lockfile',
19
+ buildCommand: 'bun run build',
20
+ startCommand: 'bun .output/server/index.mjs',
21
+ outputDirectory: '.output/public',
22
+ staticUrlPath: '/assets/*'
23
+ },
24
+ {
25
+ id: 'react-router',
26
+ name: 'React Router',
27
+ description: 'React Router v7 / Remix',
28
+ runtime: 'node',
29
+ installCommand: 'npm install',
30
+ buildCommand: 'npm run build',
31
+ startCommand: 'node index.js',
32
+ outputDirectory: 'build/client',
33
+ staticUrlPath: '/build/*'
34
+ },
35
+ {
36
+ id: 'nextjs',
37
+ name: 'Next.js',
38
+ description: 'React framework by Vercel',
39
+ runtime: 'node',
40
+ installCommand: 'npm install',
41
+ buildCommand: 'npm run build',
42
+ startCommand: 'node server.js',
43
+ outputDirectory: '.next',
44
+ staticUrlPath: '/_next/*'
45
+ },
46
+ {
47
+ id: 'nuxt',
48
+ name: 'Nuxt',
49
+ description: 'Vue.js full-stack framework',
50
+ runtime: 'node',
51
+ installCommand: 'npm install',
52
+ buildCommand: 'npm run build',
53
+ startCommand: 'node .output/server/index.mjs',
54
+ outputDirectory: '.output/public',
55
+ staticUrlPath: '/_nuxt/*'
56
+ },
57
+ {
58
+ id: 'sveltekit',
59
+ name: 'SvelteKit',
60
+ description: 'Svelte app framework',
61
+ runtime: 'node',
62
+ installCommand: 'npm install',
63
+ buildCommand: 'npm run build',
64
+ startCommand: 'node build/index.js',
65
+ outputDirectory: 'build/client',
66
+ staticUrlPath: '/_app/immutable/*'
67
+ },
68
+ {
69
+ id: 'astro',
70
+ name: 'Astro',
71
+ description: 'Content-focused web framework',
72
+ runtime: 'node',
73
+ installCommand: 'npm install',
74
+ buildCommand: 'npm run build',
75
+ startCommand: 'node ./dist/server/entry.mjs',
76
+ outputDirectory: 'dist/client',
77
+ staticUrlPath: '/_astro/*'
78
+ },
79
+ {
80
+ id: 'vite',
81
+ name: 'Vite',
82
+ description: 'Frontend build tool',
83
+ runtime: 'bun',
84
+ installCommand: 'bun install --frozen-lockfile',
85
+ buildCommand: 'bun run build',
86
+ startCommand: 'bun run preview',
87
+ outputDirectory: 'dist',
88
+ staticUrlPath: '/assets/*'
89
+ },
90
+ {
91
+ id: 'hono',
92
+ name: 'Hono',
93
+ description: 'Lightweight web framework',
94
+ runtime: 'bun',
95
+ installCommand: 'bun install --frozen-lockfile',
96
+ buildCommand: 'bun run build',
97
+ startCommand: 'bun run start',
98
+ outputDirectory: 'dist',
99
+ staticUrlPath: null
100
+ },
101
+ {
102
+ id: 'elysia',
103
+ name: 'Elysia',
104
+ description: 'Bun-first web framework',
105
+ runtime: 'bun',
106
+ installCommand: 'bun install --frozen-lockfile',
107
+ buildCommand: 'bun run build',
108
+ startCommand: 'bun run start',
109
+ outputDirectory: 'dist',
110
+ staticUrlPath: null
111
+ },
112
+ {
113
+ id: 'express',
114
+ name: 'Express',
115
+ description: 'Node.js web framework',
116
+ runtime: 'node',
117
+ installCommand: 'npm install',
118
+ buildCommand: 'npm run build',
119
+ startCommand: 'node dist/index.js',
120
+ outputDirectory: 'dist',
121
+ staticUrlPath: null
122
+ },
123
+ {
124
+ id: 'fastify',
125
+ name: 'Fastify',
126
+ description: 'Fast Node.js web framework',
127
+ runtime: 'node',
128
+ installCommand: 'npm install',
129
+ buildCommand: 'npm run build',
130
+ startCommand: 'node dist/index.js',
131
+ outputDirectory: 'dist',
132
+ staticUrlPath: null
133
+ },
134
+ {
135
+ id: 'other',
136
+ name: 'Other',
137
+ description: 'Custom application',
138
+ runtime: 'bun',
139
+ installCommand: 'bun install',
140
+ buildCommand: 'bun run build',
141
+ startCommand: 'bun run start',
142
+ outputDirectory: 'dist',
143
+ staticUrlPath: null
144
+ }
145
+ ];
146
+ export function getPreset(id) {
147
+ return FRAMEWORK_PRESETS.find(p => p.id === id);
148
+ }
149
+ /** Pre-computed combobox items -- avoids re-creating on every render. */
150
+ export const FRAMEWORK_PRESET_OPTIONS = FRAMEWORK_PRESETS.map(p => ({
151
+ value: p.id,
152
+ label: p.name,
153
+ description: p.description
154
+ }));
@@ -0,0 +1,7 @@
1
+ export declare const NODE_VERSIONS: readonly ["22.x", "20.x", "18.x"];
2
+ export declare const DEFAULT_NODE_VERSION = "22.x";
3
+ export declare const BUN_VERSIONS: readonly ["latest", "1.3", "1.2", "1.1"];
4
+ export declare const DEFAULT_BUN_VERSION = "latest";
5
+ export type NodeVersion = (typeof NODE_VERSIONS)[number];
6
+ export type BunVersion = (typeof BUN_VERSIONS)[number];
7
+ //# sourceMappingURL=runtime-versions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-versions.d.ts","sourceRoot":"","sources":["../src/runtime-versions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,mCAAoC,CAAC;AAC/D,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAI3C,eAAO,MAAM,YAAY,0CAA2C,CAAC;AACrE,eAAO,MAAM,mBAAmB,WAAW,CAAC;AAE5C,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AACzD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export const NODE_VERSIONS = ['22.x', '20.x', '18.x'];
2
+ export const DEFAULT_NODE_VERSION = '22.x';
3
+ // Bun versions — "latest" installs whatever is current at deploy time
4
+ // Pinned versions (1.3, 1.2, 1.1) resolve to latest patch via the official installer
5
+ export const BUN_VERSIONS = ['latest', '1.3', '1.2', '1.1'];
6
+ export const DEFAULT_BUN_VERSION = 'latest';
@@ -0,0 +1,41 @@
1
+ export type DeployHookId = 'after-install' | 'before-activate' | 'after-activate' | 'on-fail';
2
+ export type OrmPresetId = 'prisma' | 'drizzle' | 'knex' | 'typeorm' | 'mikro-orm' | 'sequelize' | 'none';
3
+ export type OrmPreset = {
4
+ id: OrmPresetId;
5
+ name: string;
6
+ description: string;
7
+ hooks?: Partial<Record<DeployHookId, string[]>>;
8
+ };
9
+ export type FrameworkPreset = {
10
+ id: string;
11
+ name: string;
12
+ description: string;
13
+ runtime: 'bun' | 'node';
14
+ installCommand: string;
15
+ buildCommand: string;
16
+ startCommand: string;
17
+ outputDirectory: string;
18
+ /** Caddy URL path for static asset interception (e.g. "/build/*", "/assets/*"). Null for API-only frameworks. */
19
+ staticUrlPath: string | null;
20
+ /** Deploy hook commands keyed by hook point in the pipeline */
21
+ hooks?: Partial<Record<DeployHookId, string[]>>;
22
+ };
23
+ export type DetectedApp = {
24
+ name: string;
25
+ path: string;
26
+ framework: string | null;
27
+ runtime: 'bun' | 'node' | null;
28
+ orm: OrmPresetId;
29
+ };
30
+ export type MonorepoInfo = {
31
+ isMonorepo: boolean;
32
+ appDirs: string[];
33
+ };
34
+ export type RepoDetectionResult = {
35
+ isMonorepo: boolean;
36
+ apps: DetectedApp[];
37
+ rootFramework: string | null;
38
+ rootRuntime: 'bun' | 'node' | null;
39
+ packageManager: 'bun' | 'npm' | 'yarn' | 'pnpm' | null;
40
+ };
41
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GACpB,eAAe,GACf,iBAAiB,GACjB,gBAAgB,GAChB,SAAS,CAAC;AAEd,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,SAAS,GACT,MAAM,GACN,SAAS,GACT,WAAW,GACX,WAAW,GACX,MAAM,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,WAAW,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,KAAK,GAAG,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,iHAAiH;IACjH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,+DAA+D;IAC/D,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI,CAAC;IAC/B,GAAG,EAAE,WAAW,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI,CAAC;IACnC,cAAc,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACxD,CAAC"}
package/dist/types.js ADDED
File without changes
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@runmist/frameworks",
3
+ "version": "1.1.0",
4
+ "description": "Framework, ORM, runtime, and monorepo detection for deployment pipelines",
5
+ "files": [
6
+ "dist",
7
+ "LICENSE",
8
+ "README.md"
9
+ ],
10
+ "type": "module",
11
+ "main": "./dist/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.build.json",
21
+ "test": "bun test",
22
+ "test:watch": "bun test --watch",
23
+ "typecheck": "tsc --noEmit",
24
+ "lint": "biome check",
25
+ "lint:fix": "biome check --write",
26
+ "format": "biome format --write",
27
+ "knip": "knip",
28
+ "prepublishOnly": "npm run build && npm test",
29
+ "publish:dev": "npm run build && npm publish --tag dev --access public",
30
+ "publish:patch": "npm whoami && npm version patch && git push --follow-tags && npm publish --access public",
31
+ "publish:minor": "npm whoami && npm version minor && git push --follow-tags && npm publish --access public",
32
+ "publish:major": "npm whoami && npm version major && git push --follow-tags && npm publish --access public"
33
+ },
34
+ "keywords": [
35
+ "framework-detection",
36
+ "orm",
37
+ "monorepo",
38
+ "runtime",
39
+ "deploy",
40
+ "analysis"
41
+ ],
42
+ "author": "bitclaw",
43
+ "license": "MIT",
44
+ "devDependencies": {
45
+ "@biomejs/biome": "^2.4.15",
46
+ "knip": "^6.12.1",
47
+ "@types/bun": "^1.3.9",
48
+ "typescript": "^5.8.3"
49
+ },
50
+ "engines": {
51
+ "bun": ">=1.3.0"
52
+ }
53
+ }