veryfront 0.1.129 → 0.1.130

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 (43) hide show
  1. package/esm/cli/commands/config/command-help.d.ts +3 -0
  2. package/esm/cli/commands/config/command-help.d.ts.map +1 -0
  3. package/esm/cli/commands/config/command-help.js +13 -0
  4. package/esm/cli/commands/config/handler.d.ts +5 -0
  5. package/esm/cli/commands/config/handler.d.ts.map +1 -0
  6. package/esm/cli/commands/config/handler.js +70 -0
  7. package/esm/cli/commands/open/command-help.d.ts +3 -0
  8. package/esm/cli/commands/open/command-help.d.ts.map +1 -0
  9. package/esm/cli/commands/open/command-help.js +17 -0
  10. package/esm/cli/commands/open/command.d.ts +14 -0
  11. package/esm/cli/commands/open/command.d.ts.map +1 -0
  12. package/esm/cli/commands/open/command.js +22 -0
  13. package/esm/cli/commands/open/handler.d.ts +3 -0
  14. package/esm/cli/commands/open/handler.d.ts.map +1 -0
  15. package/esm/cli/commands/open/handler.js +29 -0
  16. package/esm/cli/help/command-definitions.d.ts.map +1 -1
  17. package/esm/cli/help/command-definitions.js +4 -0
  18. package/esm/cli/router.d.ts.map +1 -1
  19. package/esm/cli/router.js +4 -0
  20. package/esm/deno.js +1 -1
  21. package/esm/src/platform/compat/framework-source-resolver.d.ts +8 -0
  22. package/esm/src/platform/compat/framework-source-resolver.d.ts.map +1 -1
  23. package/esm/src/platform/compat/framework-source-resolver.js +77 -1
  24. package/esm/src/transforms/esm/import-parser.d.ts.map +1 -1
  25. package/esm/src/transforms/esm/import-parser.js +6 -0
  26. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/path-resolver.d.ts +1 -1
  27. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/path-resolver.d.ts.map +1 -1
  28. package/esm/src/transforms/pipeline/stages/ssr-vf-modules/path-resolver.js +10 -66
  29. package/esm/src/utils/version-constant.d.ts +1 -1
  30. package/esm/src/utils/version-constant.js +1 -1
  31. package/package.json +1 -1
  32. package/src/cli/commands/config/command-help.ts +15 -0
  33. package/src/cli/commands/config/handler.ts +90 -0
  34. package/src/cli/commands/open/command-help.ts +19 -0
  35. package/src/cli/commands/open/command.ts +28 -0
  36. package/src/cli/commands/open/handler.ts +38 -0
  37. package/src/cli/help/command-definitions.ts +4 -0
  38. package/src/cli/router.ts +4 -0
  39. package/src/deno.js +1 -1
  40. package/src/src/platform/compat/framework-source-resolver.ts +101 -1
  41. package/src/src/transforms/esm/import-parser.ts +12 -0
  42. package/src/src/transforms/pipeline/stages/ssr-vf-modules/path-resolver.ts +10 -69
  43. package/src/src/utils/version-constant.ts +1 -1
@@ -0,0 +1,3 @@
1
+ import type { CommandHelp } from "../../help/types.js";
2
+ export declare const configHelp: CommandHelp;
3
+ //# sourceMappingURL=command-help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-help.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/config/command-help.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,eAAO,MAAM,UAAU,EAAE,WAYxB,CAAC"}
@@ -0,0 +1,13 @@
1
+ export const configHelp = {
2
+ name: "config",
3
+ category: "project",
4
+ description: "Show effective project configuration",
5
+ usage: "veryfront config [options]",
6
+ options: [
7
+ { flag: "--json", description: "Output as JSON" },
8
+ ],
9
+ examples: [
10
+ "veryfront config",
11
+ "veryfront config --json",
12
+ ],
13
+ };
@@ -0,0 +1,5 @@
1
+ import type { ParsedArgs } from "../../shared/types.js";
2
+ export declare function detectConfigSource(projectDir: string): Promise<string | null>;
3
+ export declare function getEnvOverrides(): string[];
4
+ export declare function handleConfigCommand(_args: ParsedArgs): Promise<void>;
5
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/config/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAexD,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAexB;AAED,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAM1C;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA+C1E"}
@@ -0,0 +1,70 @@
1
+ import { cliLogger } from "../../utils/index.js";
2
+ import { getEnv } from "../../../src/platform/index.js";
3
+ import { createSuccessEnvelope, isJsonMode, outputJson } from "../../shared/json-output.js";
4
+ import { bold, dim } from "../../ui/colors.js";
5
+ const ENV_OVERRIDES = {
6
+ projectSlug: "VERYFRONT_PROJECT_SLUG",
7
+ apiBaseUrl: "VERYFRONT_API_BASE_URL",
8
+ apiToken: "VERYFRONT_API_TOKEN",
9
+ nodeEnv: "NODE_ENV",
10
+ veryfrontEnv: "VERYFRONT_ENV",
11
+ debug: "VERYFRONT_DEBUG",
12
+ };
13
+ export async function detectConfigSource(projectDir) {
14
+ const { createFileSystem } = await import("../../../src/platform/index.js");
15
+ const { join } = await import("../../../src/platform/compat/path/index.js");
16
+ const fs = createFileSystem();
17
+ for (const name of [
18
+ "veryfront.config.ts",
19
+ "veryfront.config.js",
20
+ "veryfront.json",
21
+ ]) {
22
+ if (await fs.exists(join(projectDir, name)))
23
+ return name;
24
+ }
25
+ return null;
26
+ }
27
+ export function getEnvOverrides() {
28
+ const overrides = [];
29
+ for (const [field, envVar] of Object.entries(ENV_OVERRIDES)) {
30
+ if (getEnv(envVar))
31
+ overrides.push(`${field} (${envVar})`);
32
+ }
33
+ return overrides;
34
+ }
35
+ export async function handleConfigCommand(_args) {
36
+ const { getEnvironmentConfig } = await import("../../../src/config/index.js");
37
+ const { cwd } = await import("../../../src/platform/index.js");
38
+ const config = getEnvironmentConfig();
39
+ const projectDir = cwd();
40
+ const configSource = await detectConfigSource(projectDir);
41
+ const envOverrides = getEnvOverrides();
42
+ const configData = {
43
+ projectSlug: config.projectSlug ?? null,
44
+ nodeEnv: config.nodeEnv,
45
+ veryfrontEnv: config.veryfrontEnv || null,
46
+ apiBaseUrl: config.apiBaseUrl,
47
+ debug: config.debug,
48
+ ci: config.ci,
49
+ hasApiToken: !!config.apiToken,
50
+ configSource,
51
+ envOverrides,
52
+ };
53
+ if (isJsonMode()) {
54
+ await outputJson(createSuccessEnvelope("config", configData));
55
+ return;
56
+ }
57
+ cliLogger.info(`\n ${bold("Project Configuration")}\n`);
58
+ cliLogger.info(` ${dim("Project slug:")} ${configData.projectSlug ?? "(not set)"}`);
59
+ cliLogger.info(` ${dim("Environment:")} ${configData.nodeEnv}`);
60
+ cliLogger.info(` ${dim("VF Environment:")} ${configData.veryfrontEnv ?? "(not set)"}`);
61
+ cliLogger.info(` ${dim("API endpoint:")} ${configData.apiBaseUrl}`);
62
+ cliLogger.info(` ${dim("Debug:")} ${configData.debug}`);
63
+ cliLogger.info(` ${dim("CI:")} ${configData.ci}`);
64
+ cliLogger.info(` ${dim("Authenticated:")} ${configData.hasApiToken ? "yes" : "no"}`);
65
+ cliLogger.info(` ${dim("Config file:")} ${configData.configSource ?? "(none)"}`);
66
+ if (envOverrides.length > 0) {
67
+ cliLogger.info(` ${dim("Env overrides:")} ${envOverrides.join(", ")}`);
68
+ }
69
+ cliLogger.info("");
70
+ }
@@ -0,0 +1,3 @@
1
+ import type { CommandHelp } from "../../help/types.js";
2
+ export declare const openHelp: CommandHelp;
3
+ //# sourceMappingURL=command-help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-help.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/open/command-help.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,eAAO,MAAM,QAAQ,EAAE,WAgBtB,CAAC"}
@@ -0,0 +1,17 @@
1
+ export const openHelp = {
2
+ name: "open",
3
+ category: "project",
4
+ description: "Open project URLs in the browser",
5
+ usage: "veryfront open [options]",
6
+ options: [
7
+ { flag: "--env <name>", description: "Open a specific environment URL" },
8
+ { flag: "--studio", description: "Open Veryfront Studio" },
9
+ { flag: "--json", description: "Output URL as JSON instead of opening" },
10
+ ],
11
+ examples: [
12
+ "veryfront open",
13
+ "veryfront open --env staging",
14
+ "veryfront open --studio",
15
+ "veryfront open --json",
16
+ ],
17
+ };
@@ -0,0 +1,14 @@
1
+ import { z } from "zod";
2
+ export declare const OpenArgsSchema: z.ZodObject<{
3
+ env: z.ZodOptional<z.ZodString>;
4
+ studio: z.ZodDefault<z.ZodBoolean>;
5
+ projectSlug: z.ZodOptional<z.ZodString>;
6
+ }, z.core.$strip>;
7
+ export type OpenOptions = z.infer<typeof OpenArgsSchema>;
8
+ export declare const parseOpenArgs: (args: import("../../shared/types.js").ParsedArgs) => import("../../shared/args.js").SafeParseResult<{
9
+ studio: boolean;
10
+ env?: string | undefined;
11
+ projectSlug?: string | undefined;
12
+ }>;
13
+ export declare function buildUrl(projectSlug: string, options: OpenOptions): string;
14
+ //# sourceMappingURL=command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/open/command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,cAAc;;;;iBAIzB,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEzD,eAAO,MAAM,aAAa;;;;EAIxB,CAAC;AAIH,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM,CAQ1E"}
@@ -0,0 +1,22 @@
1
+ import { z } from "zod";
2
+ import { createArgParser } from "../../shared/args.js";
3
+ export const OpenArgsSchema = z.object({
4
+ env: z.string().optional(),
5
+ studio: z.boolean().default(false),
6
+ projectSlug: z.string().optional(),
7
+ });
8
+ export const parseOpenArgs = createArgParser(OpenArgsSchema, {
9
+ env: { keys: ["env"], type: "string" },
10
+ studio: { keys: ["studio"], type: "boolean" },
11
+ projectSlug: { keys: ["project-slug", "project", "p"], type: "string" },
12
+ });
13
+ const DASHBOARD_BASE = "https://veryfront.com";
14
+ export function buildUrl(projectSlug, options) {
15
+ if (options.studio) {
16
+ return `${DASHBOARD_BASE}/studio/${projectSlug}`;
17
+ }
18
+ if (options.env) {
19
+ return `${DASHBOARD_BASE}/projects/${projectSlug}/environments/${options.env}`;
20
+ }
21
+ return `${DASHBOARD_BASE}/projects/${projectSlug}`;
22
+ }
@@ -0,0 +1,3 @@
1
+ import type { ParsedArgs } from "../../shared/types.js";
2
+ export declare function handleOpenCommand(args: ParsedArgs): Promise<void>;
3
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/open/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAMxD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BvE"}
@@ -0,0 +1,29 @@
1
+ import { parseArgsOrThrow } from "../../shared/args.js";
2
+ import { cliLogger, exitProcess } from "../../utils/index.js";
3
+ import { createSuccessEnvelope, isJsonMode, outputJson } from "../../shared/json-output.js";
4
+ import { buildUrl, parseOpenArgs } from "./command.js";
5
+ export async function handleOpenCommand(args) {
6
+ const opts = parseArgsOrThrow(parseOpenArgs, "open", args);
7
+ let projectSlug = opts.projectSlug;
8
+ if (!projectSlug) {
9
+ const { cwd } = await import("../../../src/platform/index.js");
10
+ const { getEnvironmentConfig } = await import("../../../src/config/index.js");
11
+ const { readConfigFile } = await import("../../shared/config.js");
12
+ projectSlug = getEnvironmentConfig().projectSlug ??
13
+ (await readConfigFile(cwd()))?.projectSlug ??
14
+ undefined;
15
+ }
16
+ if (!projectSlug) {
17
+ cliLogger.error("No project found. Run from a project directory or use --project-slug");
18
+ exitProcess(1);
19
+ return;
20
+ }
21
+ const url = buildUrl(projectSlug, opts);
22
+ if (isJsonMode()) {
23
+ await outputJson(createSuccessEnvelope("open", { url }));
24
+ return;
25
+ }
26
+ const { openBrowser } = await import("../../auth/browser.js");
27
+ await openBrowser(url);
28
+ console.log(` Opening ${url}`);
29
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"command-definitions.d.ts","sourceRoot":"","sources":["../../../src/cli/help/command-definitions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAuClD;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,eAqCtB,CAAC"}
1
+ {"version":3,"file":"command-definitions.d.ts","sourceRoot":"","sources":["../../../src/cli/help/command-definitions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAyClD;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,eAuCtB,CAAC"}
@@ -39,6 +39,8 @@ import { schemaHelp } from "../commands/schema/command-help.js";
39
39
  import { testHelp } from "../commands/test/command-help.js";
40
40
  import { lintHelp } from "../commands/lint/command-help.js";
41
41
  import { skillsHelp } from "../commands/skills/command-help.js";
42
+ import { configHelp } from "../commands/config/command-help.js";
43
+ import { openHelp } from "../commands/open/command-help.js";
42
44
  import { completionsHelp } from "../commands/completions/command-help.js";
43
45
  /**
44
46
  * Central registry of all command help definitions.
@@ -80,5 +82,7 @@ export const COMMANDS = {
80
82
  test: testHelp,
81
83
  lint: lintHelp,
82
84
  skills: skillsHelp,
85
+ config: configHelp,
86
+ open: openHelp,
83
87
  completions: completionsHelp,
84
88
  };
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/cli/router.ts"],"names":[],"mappings":"AAwDA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAiEpD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA0FlE"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/cli/router.ts"],"names":[],"mappings":"AA0DA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAmEpD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA0FlE"}
package/esm/cli/router.js CHANGED
@@ -38,6 +38,8 @@ import { handleSchemaCommand } from "./commands/schema/handler.js";
38
38
  import { handleTestCommand } from "./commands/test/handler.js";
39
39
  import { handleLintCommand } from "./commands/lint/handler.js";
40
40
  import { handleSkillsCommand } from "./commands/skills/handler.js";
41
+ import { handleConfigCommand } from "./commands/config/handler.js";
42
+ import { handleOpenCommand } from "./commands/open/handler.js";
41
43
  import { handleCompletionsCommand } from "./commands/completions/handler.js";
42
44
  import { login, logout, whoami } from "./auth/index.js";
43
45
  import { parseLoginMethod } from "./auth/utils.js";
@@ -95,6 +97,8 @@ const commands = {
95
97
  "test": handleTestCommand,
96
98
  "lint": handleLintCommand,
97
99
  "skills": handleSkillsCommand,
100
+ "config": handleConfigCommand,
101
+ "open": handleOpenCommand,
98
102
  "completions": handleCompletionsCommand,
99
103
  };
100
104
  /**
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.129",
3
+ "version": "0.1.130",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -1,5 +1,6 @@
1
1
  import type { FileInfo } from "../adapters/base.js";
2
2
  export declare const FRAMEWORK_ROOT: string;
3
+ export declare const FRAMEWORK_SRC_DIR: string;
3
4
  export declare const FRAMEWORK_EMBEDDED_SRC_DIR: string;
4
5
  export declare const DEFAULT_FRAMEWORK_SOURCE_EXTENSIONS: readonly [".tsx.src", ".ts.src", ".jsx.src", ".js.src", ".mdx.src", ".md.src", ".tsx", ".ts", ".jsx", ".js", ".mdx", ".md"];
5
6
  export interface FrameworkSourceFileSystem {
@@ -15,6 +16,13 @@ export interface ResolveFrameworkSourcePathOptions {
15
16
  extensions?: readonly string[];
16
17
  includeIndexFallback?: boolean;
17
18
  }
19
+ export interface ResolveRelativeFrameworkSourceImportOptions {
20
+ fileSystem?: FrameworkSourceFileSystem;
21
+ exists?: (path: string) => Promise<boolean>;
22
+ extensions?: readonly string[];
23
+ }
18
24
  export declare function getFrameworkSourceLookupDirs(extraLookupDirs?: string[]): string[];
25
+ export declare function isFrameworkSourcePath(path: string): boolean;
19
26
  export declare function resolveFrameworkSourcePath(relativePathWithoutExt: string, options?: ResolveFrameworkSourcePathOptions): Promise<FrameworkSourceLookupResult | null>;
27
+ export declare function resolveRelativeFrameworkSourceImport(specifier: string, fromSourcePath: string, options?: ResolveRelativeFrameworkSourceImportOptions): Promise<string | null>;
20
28
  //# sourceMappingURL=framework-source-resolver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"framework-source-resolver.d.ts","sourceRoot":"","sources":["../../../../src/src/platform/compat/framework-source-resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAIpD,eAAO,MAAM,cAAc,QAA4C,CAAC;AACxE,eAAO,MAAM,0BAA0B,QAAgD,CAAC;AAExF,eAAO,MAAM,mCAAmC,6HAatC,CAAC;AAEX,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iCAAiC;IAChD,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAgB,4BAA4B,CAAC,eAAe,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAarF;AAED,wBAAsB,0BAA0B,CAC9C,sBAAsB,EAAE,MAAM,EAC9B,OAAO,GAAE,iCAAsC,GAC9C,OAAO,CAAC,2BAA2B,GAAG,IAAI,CAAC,CA+B7C"}
1
+ {"version":3,"file":"framework-source-resolver.d.ts","sourceRoot":"","sources":["../../../../src/src/platform/compat/framework-source-resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAIpD,eAAO,MAAM,cAAc,QAA4C,CAAC;AACxE,eAAO,MAAM,iBAAiB,QAA8B,CAAC;AAC7D,eAAO,MAAM,0BAA0B,QAAgD,CAAC;AAExF,eAAO,MAAM,mCAAmC,6HAatC,CAAC;AAEX,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iCAAiC;IAChD,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,2CAA2C;IAC1D,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5C,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAED,wBAAgB,4BAA4B,CAAC,eAAe,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAarF;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAG3D;AAuCD,wBAAsB,0BAA0B,CAC9C,sBAAsB,EAAE,MAAM,EAC9B,OAAO,GAAE,iCAAsC,GAC9C,OAAO,CAAC,2BAA2B,GAAG,IAAI,CAAC,CA+B7C;AAED,wBAAsB,oCAAoC,CACxD,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE,2CAAgD,GACxD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6CxB"}
@@ -1,7 +1,8 @@
1
1
  import { join } from "./path/index.js";
2
2
  import { createFileSystem } from "./fs.js";
3
- import { getFrameworkRootFromMeta } from "./vfs-paths.js";
3
+ import { getFrameworkRoot, getFrameworkRootFromMeta } from "./vfs-paths.js";
4
4
  export const FRAMEWORK_ROOT = getFrameworkRootFromMeta(globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).url);
5
+ export const FRAMEWORK_SRC_DIR = join(FRAMEWORK_ROOT, "src");
5
6
  export const FRAMEWORK_EMBEDDED_SRC_DIR = join(FRAMEWORK_ROOT, "dist", "framework-src");
6
7
  export const DEFAULT_FRAMEWORK_SOURCE_EXTENSIONS = [
7
8
  ".tsx.src",
@@ -31,6 +32,40 @@ export function getFrameworkSourceLookupDirs(extraLookupDirs = []) {
31
32
  return true;
32
33
  });
33
34
  }
35
+ export function isFrameworkSourcePath(path) {
36
+ return path.startsWith(`${FRAMEWORK_SRC_DIR}/`) ||
37
+ path.startsWith(`${FRAMEWORK_EMBEDDED_SRC_DIR}/`);
38
+ }
39
+ function expandFrameworkCandidatePaths(candidatePath) {
40
+ const candidates = [candidatePath];
41
+ const candidateRoot = getFrameworkRoot(candidatePath);
42
+ const candidateSrcDir = candidateRoot ? join(candidateRoot, "src") : FRAMEWORK_SRC_DIR;
43
+ const candidateEmbeddedDir = candidateRoot
44
+ ? join(candidateRoot, "dist", "framework-src")
45
+ : FRAMEWORK_EMBEDDED_SRC_DIR;
46
+ if (candidatePath.startsWith(`${candidateSrcDir}/`)) {
47
+ const relativePath = candidatePath.slice(candidateSrcDir.length + 1);
48
+ candidates.push(join(candidateEmbeddedDir, relativePath));
49
+ }
50
+ return [...new Set(candidates)];
51
+ }
52
+ async function findExistingFrameworkCandidate(candidatePath, options = {}) {
53
+ const fs = options.fileSystem ?? createFileSystem();
54
+ const exists = options.exists ?? (async (path) => {
55
+ try {
56
+ const stat = await fs.stat(path);
57
+ return stat.isFile;
58
+ }
59
+ catch {
60
+ return false;
61
+ }
62
+ });
63
+ for (const candidate of expandFrameworkCandidatePaths(candidatePath)) {
64
+ if (await exists(candidate))
65
+ return candidate;
66
+ }
67
+ return null;
68
+ }
34
69
  export async function resolveFrameworkSourcePath(relativePathWithoutExt, options = {}) {
35
70
  const fs = options.fileSystem ?? createFileSystem();
36
71
  const lookupDirs = getFrameworkSourceLookupDirs(options.extraLookupDirs);
@@ -60,3 +95,44 @@ export async function resolveFrameworkSourcePath(relativePathWithoutExt, options
60
95
  }
61
96
  return null;
62
97
  }
98
+ export async function resolveRelativeFrameworkSourceImport(specifier, fromSourcePath, options = {}) {
99
+ const extensions = options.extensions ?? DEFAULT_FRAMEWORK_SOURCE_EXTENSIONS;
100
+ const fromDir = fromSourcePath.substring(0, fromSourcePath.lastIndexOf("/"));
101
+ const parts = fromDir.split("/").filter(Boolean);
102
+ const importParts = specifier.split("/").filter(Boolean);
103
+ for (const part of importParts) {
104
+ if (part === "..") {
105
+ parts.pop();
106
+ }
107
+ else if (part !== ".") {
108
+ parts.push(part);
109
+ }
110
+ }
111
+ const basePath = "/" + parts.join("/");
112
+ if (/\.(tsx?|jsx?|mjs)$/.test(specifier)) {
113
+ const explicitCandidates = [basePath, `${basePath}.src`];
114
+ if (basePath.endsWith(".js") || basePath.endsWith(".mjs")) {
115
+ const stem = basePath.replace(/\.(?:m?js)$/, "");
116
+ for (const ext of [".ts", ".tsx", ".jsx", ".js", ".mjs"]) {
117
+ explicitCandidates.push(`${stem}${ext}.src`, `${stem}${ext}`);
118
+ }
119
+ }
120
+ for (const candidate of explicitCandidates) {
121
+ const resolved = await findExistingFrameworkCandidate(candidate, options);
122
+ if (resolved)
123
+ return resolved;
124
+ }
125
+ return null;
126
+ }
127
+ for (const ext of extensions) {
128
+ const candidate = await findExistingFrameworkCandidate(basePath + ext, options);
129
+ if (candidate)
130
+ return candidate;
131
+ }
132
+ for (const ext of extensions) {
133
+ const candidate = await findExistingFrameworkCandidate(join(basePath, "index" + ext), options);
134
+ if (candidate)
135
+ return candidate;
136
+ }
137
+ return null;
138
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"import-parser.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/import-parser.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAKtE,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,uBAAuB;IAC/B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,UAAU,EAAE,WAAW,EAAE,CAAC;IAC1B,mBAAmB,EAAE,kBAAkB,EAAE,CAAC;IAC1C,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAKD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,uBAAuB,CAAC,CAiFlC"}
1
+ {"version":3,"file":"import-parser.d.ts","sourceRoot":"","sources":["../../../../src/src/transforms/esm/import-parser.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAKtE,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,uBAAuB;IAC/B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,UAAU,EAAE,WAAW,EAAE,CAAC;IAC1B,mBAAmB,EAAE,kBAAkB,EAAE,CAAC;IAC1C,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAKD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,uBAAuB,CAAC,CAiFlC"}
@@ -1,6 +1,7 @@
1
1
  import { getEsbuild } from "../../platform/compat/esbuild.js";
2
2
  import { join } from "../../platform/compat/path/index.js";
3
3
  import { createFileSystem } from "../../platform/compat/fs.js";
4
+ import { isFrameworkSourcePath, resolveRelativeFrameworkSourceImport, } from "../../platform/compat/framework-source-resolver.js";
4
5
  import { isCrossProjectImport, parseCrossProjectImport } from "./path-resolver.js";
5
6
  import { parseImports } from "./lexer.js";
6
7
  import { getLoaderFromPath } from "./transform-utils.js";
@@ -94,6 +95,11 @@ async function checkFileExists(path, adapter) {
94
95
  }
95
96
  }
96
97
  async function resolveLocalImportPath(fromFile, importSpecifier, adapter) {
98
+ if (isFrameworkSourcePath(fromFile)) {
99
+ const resolvedFrameworkImport = await resolveRelativeFrameworkSourceImport(importSpecifier, fromFile);
100
+ if (resolvedFrameworkImport)
101
+ return resolvedFrameworkImport;
102
+ }
97
103
  const fromDir = fromFile.substring(0, fromFile.lastIndexOf("/"));
98
104
  const basePath = resolveRelative(fromDir, importSpecifier);
99
105
  if (adapter?.fs.resolveFile) {
@@ -32,5 +32,5 @@ export declare function resolveVeryfrontSourcePath(specifier: string, existsFn?:
32
32
  * Handles both regular source files (.tsx, .ts) and embedded sources (.tsx.src, .ts.src)
33
33
  * for compiled binaries.
34
34
  */
35
- export declare function resolveRelativeFrameworkImport(specifier: string, fromSourcePath: string, _fs: ReturnType<typeof createFileSystem>, existsFn?: (path: string) => Promise<boolean>): Promise<string | null>;
35
+ export declare function resolveRelativeFrameworkImport(specifier: string, fromSourcePath: string, fs: ReturnType<typeof createFileSystem>, existsFn?: (path: string) => Promise<boolean>): Promise<string | null>;
36
36
  //# sourceMappingURL=path-resolver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"path-resolver.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/path-resolver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAU,MAAM,mCAAmC,CAAC;AAY7E,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EACvC,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAU,GACpD,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAmBzD;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EACvC,QAAQ,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAU,GACpD,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA6DzD;AAED;;;;;;;GAOG;AACH,wBAAsB,0BAA0B,CAC9C,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAU,GACpD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkExB;AAED;;;;;;GAMG;AACH,wBAAsB,8BAA8B,CAClD,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,GAAG,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EACxC,QAAQ,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAU,GACpD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAqExB"}
1
+ {"version":3,"file":"path-resolver.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/path-resolver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAU,MAAM,mCAAmC,CAAC;AAa7E,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EACvC,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAU,GACpD,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAmBzD;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EACvC,QAAQ,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAU,GACpD,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA6DzD;AAED;;;;;;;GAOG;AACH,wBAAsB,0BAA0B,CAC9C,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAU,GACpD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkExB;AAED;;;;;;GAMG;AACH,wBAAsB,8BAA8B,CAClD,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,EACvC,QAAQ,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAU,GACpD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASxB"}
@@ -7,6 +7,7 @@
7
7
  import { exists } from "../../../../platform/compat/fs.js";
8
8
  import { join } from "../../../../platform/compat/path/index.js";
9
9
  import { rendererLogger as logger } from "../../../../utils/index.js";
10
+ import { resolveRelativeFrameworkSourceImport } from "../../../../platform/compat/framework-source-resolver.js";
10
11
  import { resolveInternalModuleTarget } from "../../../veryfront-module-urls.js";
11
12
  import { EMBEDDED_SRC_DIR, EXTENSIONS, FRAMEWORK_LOOKUPS, FRAMEWORK_ROOT, LOG_PREFIX, } from "./constants.js";
12
13
  export async function tryReadWithExtensions(fs, basePath, existsFn = exists) {
@@ -168,70 +169,13 @@ export async function resolveVeryfrontSourcePath(specifier, existsFn = exists) {
168
169
  * Handles both regular source files (.tsx, .ts) and embedded sources (.tsx.src, .ts.src)
169
170
  * for compiled binaries.
170
171
  */
171
- export async function resolveRelativeFrameworkImport(specifier, fromSourcePath, _fs, existsFn = exists) {
172
- const fromDir = fromSourcePath.substring(0, fromSourcePath.lastIndexOf("/"));
173
- const parts = fromDir.split("/").filter(Boolean);
174
- const importParts = specifier.split("/").filter(Boolean);
175
- for (const part of importParts) {
176
- if (part === "..") {
177
- parts.pop();
178
- }
179
- else if (part !== ".") {
180
- parts.push(part);
181
- }
182
- }
183
- const basePath = "/" + parts.join("/");
184
- // If specifier already has extension (e.g., ./Head.tsx), we need to try:
185
- // 1. The exact path (basePath)
186
- // 2. The path with .src suffix (basePath.src) for embedded sources
187
- // 3. For transpiled .js/.mjs imports, fall back to sibling TS/TSX/JSX sources
188
- if (/\.(tsx?|jsx?|mjs)$/.test(specifier)) {
189
- const explicitCandidates = [basePath, `${basePath}.src`];
190
- // esbuild rewrites TS/TSX relative imports to .js in transformed output.
191
- // When the original source only exists as .ts/.tsx (or embedded .src),
192
- // probe those sibling source extensions before giving up.
193
- if (basePath.endsWith(".js") || basePath.endsWith(".mjs")) {
194
- const stem = basePath.replace(/\.(?:m?js)$/, "");
195
- for (const ext of [".ts", ".tsx", ".jsx", ".js", ".mjs"]) {
196
- explicitCandidates.push(`${stem}${ext}.src`, `${stem}${ext}`);
197
- }
198
- }
199
- for (const candidate of explicitCandidates) {
200
- try {
201
- if (await existsFn(candidate))
202
- return candidate;
203
- }
204
- catch (_) {
205
- /* expected: file may not exist at this path */
206
- }
207
- }
208
- return null;
209
- }
210
- // No extension provided - try all extensions (including .src for embedded sources)
211
- const allExtensions = [
212
- ...EXTENSIONS.map((ext) => ext + ".src"),
213
- ...EXTENSIONS,
214
- ];
215
- for (const ext of allExtensions) {
216
- const pathWithExt = basePath + ext;
217
- try {
218
- if (await existsFn(pathWithExt))
219
- return pathWithExt;
220
- }
221
- catch (_) {
222
- /* expected: file may not exist at this path */
223
- }
224
- }
225
- // Try index file
226
- for (const ext of allExtensions) {
227
- const indexPath = join(basePath, "index" + ext);
228
- try {
229
- if (await existsFn(indexPath))
230
- return indexPath;
231
- }
232
- catch (_) {
233
- /* expected: file may not exist at this path */
234
- }
235
- }
236
- return null;
172
+ export async function resolveRelativeFrameworkImport(specifier, fromSourcePath, fs, existsFn = exists) {
173
+ return await resolveRelativeFrameworkSourceImport(specifier, fromSourcePath, {
174
+ fileSystem: fs,
175
+ exists: existsFn,
176
+ extensions: [
177
+ ...EXTENSIONS.map((ext) => `${ext}.src`),
178
+ ...EXTENSIONS,
179
+ ],
180
+ });
237
181
  }
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.1.129";
1
+ export declare const VERSION = "0.1.130";
2
2
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.129";
3
+ export const VERSION = "0.1.130";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.129",
3
+ "version": "0.1.130",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
@@ -0,0 +1,15 @@
1
+ import type { CommandHelp } from "../../help/types.js";
2
+
3
+ export const configHelp: CommandHelp = {
4
+ name: "config",
5
+ category: "project",
6
+ description: "Show effective project configuration",
7
+ usage: "veryfront config [options]",
8
+ options: [
9
+ { flag: "--json", description: "Output as JSON" },
10
+ ],
11
+ examples: [
12
+ "veryfront config",
13
+ "veryfront config --json",
14
+ ],
15
+ };
@@ -0,0 +1,90 @@
1
+ import type { ParsedArgs } from "../../shared/types.js";
2
+ import { cliLogger } from "../../utils/index.js";
3
+ import { getEnv } from "../../../src/platform/index.js";
4
+ import { createSuccessEnvelope, isJsonMode, outputJson } from "../../shared/json-output.js";
5
+ import { bold, dim } from "../../ui/colors.js";
6
+
7
+ const ENV_OVERRIDES: Record<string, string> = {
8
+ projectSlug: "VERYFRONT_PROJECT_SLUG",
9
+ apiBaseUrl: "VERYFRONT_API_BASE_URL",
10
+ apiToken: "VERYFRONT_API_TOKEN",
11
+ nodeEnv: "NODE_ENV",
12
+ veryfrontEnv: "VERYFRONT_ENV",
13
+ debug: "VERYFRONT_DEBUG",
14
+ };
15
+
16
+ export async function detectConfigSource(
17
+ projectDir: string,
18
+ ): Promise<string | null> {
19
+ const { createFileSystem } = await import("../../../src/platform/index.js");
20
+ const { join } = await import("../../../src/platform/compat/path/index.js");
21
+ const fs = createFileSystem();
22
+
23
+ for (
24
+ const name of [
25
+ "veryfront.config.ts",
26
+ "veryfront.config.js",
27
+ "veryfront.json",
28
+ ]
29
+ ) {
30
+ if (await fs.exists(join(projectDir, name))) return name;
31
+ }
32
+ return null;
33
+ }
34
+
35
+ export function getEnvOverrides(): string[] {
36
+ const overrides: string[] = [];
37
+ for (const [field, envVar] of Object.entries(ENV_OVERRIDES)) {
38
+ if (getEnv(envVar)) overrides.push(`${field} (${envVar})`);
39
+ }
40
+ return overrides;
41
+ }
42
+
43
+ export async function handleConfigCommand(_args: ParsedArgs): Promise<void> {
44
+ const { getEnvironmentConfig } = await import("../../../src/config/index.js");
45
+ const { cwd } = await import("../../../src/platform/index.js");
46
+ const config = getEnvironmentConfig();
47
+
48
+ const projectDir = cwd();
49
+ const configSource = await detectConfigSource(projectDir);
50
+ const envOverrides = getEnvOverrides();
51
+
52
+ const configData = {
53
+ projectSlug: config.projectSlug ?? null,
54
+ nodeEnv: config.nodeEnv,
55
+ veryfrontEnv: config.veryfrontEnv || null,
56
+ apiBaseUrl: config.apiBaseUrl,
57
+ debug: config.debug,
58
+ ci: config.ci,
59
+ hasApiToken: !!config.apiToken,
60
+ configSource,
61
+ envOverrides,
62
+ };
63
+
64
+ if (isJsonMode()) {
65
+ await outputJson(createSuccessEnvelope("config", configData));
66
+ return;
67
+ }
68
+
69
+ cliLogger.info(`\n ${bold("Project Configuration")}\n`);
70
+ cliLogger.info(
71
+ ` ${dim("Project slug:")} ${configData.projectSlug ?? "(not set)"}`,
72
+ );
73
+ cliLogger.info(` ${dim("Environment:")} ${configData.nodeEnv}`);
74
+ cliLogger.info(
75
+ ` ${dim("VF Environment:")} ${configData.veryfrontEnv ?? "(not set)"}`,
76
+ );
77
+ cliLogger.info(` ${dim("API endpoint:")} ${configData.apiBaseUrl}`);
78
+ cliLogger.info(` ${dim("Debug:")} ${configData.debug}`);
79
+ cliLogger.info(` ${dim("CI:")} ${configData.ci}`);
80
+ cliLogger.info(
81
+ ` ${dim("Authenticated:")} ${configData.hasApiToken ? "yes" : "no"}`,
82
+ );
83
+ cliLogger.info(
84
+ ` ${dim("Config file:")} ${configData.configSource ?? "(none)"}`,
85
+ );
86
+ if (envOverrides.length > 0) {
87
+ cliLogger.info(` ${dim("Env overrides:")} ${envOverrides.join(", ")}`);
88
+ }
89
+ cliLogger.info("");
90
+ }
@@ -0,0 +1,19 @@
1
+ import type { CommandHelp } from "../../help/types.js";
2
+
3
+ export const openHelp: CommandHelp = {
4
+ name: "open",
5
+ category: "project",
6
+ description: "Open project URLs in the browser",
7
+ usage: "veryfront open [options]",
8
+ options: [
9
+ { flag: "--env <name>", description: "Open a specific environment URL" },
10
+ { flag: "--studio", description: "Open Veryfront Studio" },
11
+ { flag: "--json", description: "Output URL as JSON instead of opening" },
12
+ ],
13
+ examples: [
14
+ "veryfront open",
15
+ "veryfront open --env staging",
16
+ "veryfront open --studio",
17
+ "veryfront open --json",
18
+ ],
19
+ };
@@ -0,0 +1,28 @@
1
+ import { z } from "zod";
2
+ import { createArgParser } from "../../shared/args.js";
3
+
4
+ export const OpenArgsSchema = z.object({
5
+ env: z.string().optional(),
6
+ studio: z.boolean().default(false),
7
+ projectSlug: z.string().optional(),
8
+ });
9
+
10
+ export type OpenOptions = z.infer<typeof OpenArgsSchema>;
11
+
12
+ export const parseOpenArgs = createArgParser(OpenArgsSchema, {
13
+ env: { keys: ["env"], type: "string" },
14
+ studio: { keys: ["studio"], type: "boolean" },
15
+ projectSlug: { keys: ["project-slug", "project", "p"], type: "string" },
16
+ });
17
+
18
+ const DASHBOARD_BASE = "https://veryfront.com";
19
+
20
+ export function buildUrl(projectSlug: string, options: OpenOptions): string {
21
+ if (options.studio) {
22
+ return `${DASHBOARD_BASE}/studio/${projectSlug}`;
23
+ }
24
+ if (options.env) {
25
+ return `${DASHBOARD_BASE}/projects/${projectSlug}/environments/${options.env}`;
26
+ }
27
+ return `${DASHBOARD_BASE}/projects/${projectSlug}`;
28
+ }
@@ -0,0 +1,38 @@
1
+ import type { ParsedArgs } from "../../shared/types.js";
2
+ import { parseArgsOrThrow } from "../../shared/args.js";
3
+ import { cliLogger, exitProcess } from "../../utils/index.js";
4
+ import { createSuccessEnvelope, isJsonMode, outputJson } from "../../shared/json-output.js";
5
+ import { buildUrl, parseOpenArgs } from "./command.js";
6
+
7
+ export async function handleOpenCommand(args: ParsedArgs): Promise<void> {
8
+ const opts = parseArgsOrThrow(parseOpenArgs, "open", args);
9
+
10
+ let projectSlug = opts.projectSlug;
11
+ if (!projectSlug) {
12
+ const { cwd } = await import("../../../src/platform/index.js");
13
+ const { getEnvironmentConfig } = await import("../../../src/config/index.js");
14
+ const { readConfigFile } = await import("../../shared/config.js");
15
+ projectSlug = getEnvironmentConfig().projectSlug ??
16
+ (await readConfigFile(cwd()))?.projectSlug ??
17
+ undefined;
18
+ }
19
+
20
+ if (!projectSlug) {
21
+ cliLogger.error(
22
+ "No project found. Run from a project directory or use --project-slug",
23
+ );
24
+ exitProcess(1);
25
+ return;
26
+ }
27
+
28
+ const url = buildUrl(projectSlug, opts);
29
+
30
+ if (isJsonMode()) {
31
+ await outputJson(createSuccessEnvelope("open", { url }));
32
+ return;
33
+ }
34
+
35
+ const { openBrowser } = await import("../../auth/browser.js");
36
+ await openBrowser(url);
37
+ console.log(` Opening ${url}`);
38
+ }
@@ -42,6 +42,8 @@ import { schemaHelp } from "../commands/schema/command-help.js";
42
42
  import { testHelp } from "../commands/test/command-help.js";
43
43
  import { lintHelp } from "../commands/lint/command-help.js";
44
44
  import { skillsHelp } from "../commands/skills/command-help.js";
45
+ import { configHelp } from "../commands/config/command-help.js";
46
+ import { openHelp } from "../commands/open/command-help.js";
45
47
  import { completionsHelp } from "../commands/completions/command-help.js";
46
48
 
47
49
  /**
@@ -84,5 +86,7 @@ export const COMMANDS: CommandRegistry = {
84
86
  test: testHelp,
85
87
  lint: lintHelp,
86
88
  skills: skillsHelp,
89
+ config: configHelp,
90
+ open: openHelp,
87
91
  completions: completionsHelp,
88
92
  };
package/src/cli/router.ts CHANGED
@@ -40,6 +40,8 @@ import { handleSchemaCommand } from "./commands/schema/handler.js";
40
40
  import { handleTestCommand } from "./commands/test/handler.js";
41
41
  import { handleLintCommand } from "./commands/lint/handler.js";
42
42
  import { handleSkillsCommand } from "./commands/skills/handler.js";
43
+ import { handleConfigCommand } from "./commands/config/handler.js";
44
+ import { handleOpenCommand } from "./commands/open/handler.js";
43
45
  import { handleCompletionsCommand } from "./commands/completions/handler.js";
44
46
  import { login, logout, whoami } from "./auth/index.js";
45
47
  import { parseLoginMethod } from "./auth/utils.js";
@@ -105,6 +107,8 @@ const commands: Record<string, (args: ParsedArgs) => Promise<void>> = {
105
107
  "test": handleTestCommand,
106
108
  "lint": handleLintCommand,
107
109
  "skills": handleSkillsCommand,
110
+ "config": handleConfigCommand,
111
+ "open": handleOpenCommand,
108
112
  "completions": handleCompletionsCommand,
109
113
  };
110
114
 
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.129",
3
+ "version": "0.1.130",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -1,9 +1,10 @@
1
1
  import { join } from "./path/index.js";
2
2
  import type { FileInfo } from "../adapters/base.js";
3
3
  import { createFileSystem } from "./fs.js";
4
- import { getFrameworkRootFromMeta } from "./vfs-paths.js";
4
+ import { getFrameworkRoot, getFrameworkRootFromMeta } from "./vfs-paths.js";
5
5
 
6
6
  export const FRAMEWORK_ROOT = getFrameworkRootFromMeta(import.meta.url);
7
+ export const FRAMEWORK_SRC_DIR = join(FRAMEWORK_ROOT, "src");
7
8
  export const FRAMEWORK_EMBEDDED_SRC_DIR = join(FRAMEWORK_ROOT, "dist", "framework-src");
8
9
 
9
10
  export const DEFAULT_FRAMEWORK_SOURCE_EXTENSIONS = [
@@ -37,6 +38,12 @@ export interface ResolveFrameworkSourcePathOptions {
37
38
  includeIndexFallback?: boolean;
38
39
  }
39
40
 
41
+ export interface ResolveRelativeFrameworkSourceImportOptions {
42
+ fileSystem?: FrameworkSourceFileSystem;
43
+ exists?: (path: string) => Promise<boolean>;
44
+ extensions?: readonly string[];
45
+ }
46
+
40
47
  export function getFrameworkSourceLookupDirs(extraLookupDirs: string[] = []): string[] {
41
48
  const seen = new Set<string>();
42
49
  const ordered = [
@@ -52,6 +59,48 @@ export function getFrameworkSourceLookupDirs(extraLookupDirs: string[] = []): st
52
59
  });
53
60
  }
54
61
 
62
+ export function isFrameworkSourcePath(path: string): boolean {
63
+ return path.startsWith(`${FRAMEWORK_SRC_DIR}/`) ||
64
+ path.startsWith(`${FRAMEWORK_EMBEDDED_SRC_DIR}/`);
65
+ }
66
+
67
+ function expandFrameworkCandidatePaths(candidatePath: string): string[] {
68
+ const candidates = [candidatePath];
69
+ const candidateRoot = getFrameworkRoot(candidatePath);
70
+ const candidateSrcDir = candidateRoot ? join(candidateRoot, "src") : FRAMEWORK_SRC_DIR;
71
+ const candidateEmbeddedDir = candidateRoot
72
+ ? join(candidateRoot, "dist", "framework-src")
73
+ : FRAMEWORK_EMBEDDED_SRC_DIR;
74
+
75
+ if (candidatePath.startsWith(`${candidateSrcDir}/`)) {
76
+ const relativePath = candidatePath.slice(candidateSrcDir.length + 1);
77
+ candidates.push(join(candidateEmbeddedDir, relativePath));
78
+ }
79
+
80
+ return [...new Set(candidates)];
81
+ }
82
+
83
+ async function findExistingFrameworkCandidate(
84
+ candidatePath: string,
85
+ options: ResolveRelativeFrameworkSourceImportOptions = {},
86
+ ): Promise<string | null> {
87
+ const fs = options.fileSystem ?? createFileSystem();
88
+ const exists = options.exists ?? (async (path: string) => {
89
+ try {
90
+ const stat = await fs.stat(path);
91
+ return stat.isFile;
92
+ } catch {
93
+ return false;
94
+ }
95
+ });
96
+
97
+ for (const candidate of expandFrameworkCandidatePaths(candidatePath)) {
98
+ if (await exists(candidate)) return candidate;
99
+ }
100
+
101
+ return null;
102
+ }
103
+
55
104
  export async function resolveFrameworkSourcePath(
56
105
  relativePathWithoutExt: string,
57
106
  options: ResolveFrameworkSourcePathOptions = {},
@@ -87,3 +136,54 @@ export async function resolveFrameworkSourcePath(
87
136
 
88
137
  return null;
89
138
  }
139
+
140
+ export async function resolveRelativeFrameworkSourceImport(
141
+ specifier: string,
142
+ fromSourcePath: string,
143
+ options: ResolveRelativeFrameworkSourceImportOptions = {},
144
+ ): Promise<string | null> {
145
+ const extensions = options.extensions ?? DEFAULT_FRAMEWORK_SOURCE_EXTENSIONS;
146
+ const fromDir = fromSourcePath.substring(0, fromSourcePath.lastIndexOf("/"));
147
+ const parts = fromDir.split("/").filter(Boolean);
148
+ const importParts = specifier.split("/").filter(Boolean);
149
+
150
+ for (const part of importParts) {
151
+ if (part === "..") {
152
+ parts.pop();
153
+ } else if (part !== ".") {
154
+ parts.push(part);
155
+ }
156
+ }
157
+
158
+ const basePath = "/" + parts.join("/");
159
+
160
+ if (/\.(tsx?|jsx?|mjs)$/.test(specifier)) {
161
+ const explicitCandidates = [basePath, `${basePath}.src`];
162
+
163
+ if (basePath.endsWith(".js") || basePath.endsWith(".mjs")) {
164
+ const stem = basePath.replace(/\.(?:m?js)$/, "");
165
+ for (const ext of [".ts", ".tsx", ".jsx", ".js", ".mjs"]) {
166
+ explicitCandidates.push(`${stem}${ext}.src`, `${stem}${ext}`);
167
+ }
168
+ }
169
+
170
+ for (const candidate of explicitCandidates) {
171
+ const resolved = await findExistingFrameworkCandidate(candidate, options);
172
+ if (resolved) return resolved;
173
+ }
174
+
175
+ return null;
176
+ }
177
+
178
+ for (const ext of extensions) {
179
+ const candidate = await findExistingFrameworkCandidate(basePath + ext, options);
180
+ if (candidate) return candidate;
181
+ }
182
+
183
+ for (const ext of extensions) {
184
+ const candidate = await findExistingFrameworkCandidate(join(basePath, "index" + ext), options);
185
+ if (candidate) return candidate;
186
+ }
187
+
188
+ return null;
189
+ }
@@ -1,6 +1,10 @@
1
1
  import { getEsbuild } from "../../platform/compat/esbuild.js";
2
2
  import { join } from "../../platform/compat/path/index.js";
3
3
  import { createFileSystem } from "../../platform/compat/fs.js";
4
+ import {
5
+ isFrameworkSourcePath,
6
+ resolveRelativeFrameworkSourceImport,
7
+ } from "../../platform/compat/framework-source-resolver.js";
4
8
  import type { RuntimeAdapter } from "../../platform/adapters/base.js";
5
9
  import { isCrossProjectImport, parseCrossProjectImport } from "./path-resolver.js";
6
10
  import { parseImports } from "./lexer.js";
@@ -138,6 +142,14 @@ async function resolveLocalImportPath(
138
142
  importSpecifier: string,
139
143
  adapter?: RuntimeAdapter,
140
144
  ): Promise<string | null> {
145
+ if (isFrameworkSourcePath(fromFile)) {
146
+ const resolvedFrameworkImport = await resolveRelativeFrameworkSourceImport(
147
+ importSpecifier,
148
+ fromFile,
149
+ );
150
+ if (resolvedFrameworkImport) return resolvedFrameworkImport;
151
+ }
152
+
141
153
  const fromDir = fromFile.substring(0, fromFile.lastIndexOf("/"));
142
154
  const basePath = resolveRelative(fromDir, importSpecifier);
143
155
 
@@ -8,6 +8,7 @@
8
8
  import { createFileSystem, exists } from "../../../../platform/compat/fs.js";
9
9
  import { join } from "../../../../platform/compat/path/index.js";
10
10
  import { rendererLogger as logger } from "../../../../utils/index.js";
11
+ import { resolveRelativeFrameworkSourceImport } from "../../../../platform/compat/framework-source-resolver.js";
11
12
  import { resolveInternalModuleTarget } from "../../../veryfront-module-urls.js";
12
13
  import {
13
14
  EMBEDDED_SRC_DIR,
@@ -201,75 +202,15 @@ export async function resolveVeryfrontSourcePath(
201
202
  export async function resolveRelativeFrameworkImport(
202
203
  specifier: string,
203
204
  fromSourcePath: string,
204
- _fs: ReturnType<typeof createFileSystem>,
205
+ fs: ReturnType<typeof createFileSystem>,
205
206
  existsFn: (path: string) => Promise<boolean> = exists,
206
207
  ): Promise<string | null> {
207
- const fromDir = fromSourcePath.substring(0, fromSourcePath.lastIndexOf("/"));
208
- const parts = fromDir.split("/").filter(Boolean);
209
- const importParts = specifier.split("/").filter(Boolean);
210
-
211
- for (const part of importParts) {
212
- if (part === "..") {
213
- parts.pop();
214
- } else if (part !== ".") {
215
- parts.push(part);
216
- }
217
- }
218
-
219
- const basePath = "/" + parts.join("/");
220
-
221
- // If specifier already has extension (e.g., ./Head.tsx), we need to try:
222
- // 1. The exact path (basePath)
223
- // 2. The path with .src suffix (basePath.src) for embedded sources
224
- // 3. For transpiled .js/.mjs imports, fall back to sibling TS/TSX/JSX sources
225
- if (/\.(tsx?|jsx?|mjs)$/.test(specifier)) {
226
- const explicitCandidates = [basePath, `${basePath}.src`];
227
-
228
- // esbuild rewrites TS/TSX relative imports to .js in transformed output.
229
- // When the original source only exists as .ts/.tsx (or embedded .src),
230
- // probe those sibling source extensions before giving up.
231
- if (basePath.endsWith(".js") || basePath.endsWith(".mjs")) {
232
- const stem = basePath.replace(/\.(?:m?js)$/, "");
233
- for (const ext of [".ts", ".tsx", ".jsx", ".js", ".mjs"]) {
234
- explicitCandidates.push(`${stem}${ext}.src`, `${stem}${ext}`);
235
- }
236
- }
237
-
238
- for (const candidate of explicitCandidates) {
239
- try {
240
- if (await existsFn(candidate)) return candidate;
241
- } catch (_) {
242
- /* expected: file may not exist at this path */
243
- }
244
- }
245
-
246
- return null;
247
- }
248
-
249
- // No extension provided - try all extensions (including .src for embedded sources)
250
- const allExtensions = [
251
- ...EXTENSIONS.map((ext) => ext + ".src"),
252
- ...EXTENSIONS,
253
- ];
254
-
255
- for (const ext of allExtensions) {
256
- const pathWithExt = basePath + ext;
257
- try {
258
- if (await existsFn(pathWithExt)) return pathWithExt;
259
- } catch (_) {
260
- /* expected: file may not exist at this path */
261
- }
262
- }
263
-
264
- // Try index file
265
- for (const ext of allExtensions) {
266
- const indexPath = join(basePath, "index" + ext);
267
- try {
268
- if (await existsFn(indexPath)) return indexPath;
269
- } catch (_) {
270
- /* expected: file may not exist at this path */
271
- }
272
- }
273
-
274
- return null;
208
+ return await resolveRelativeFrameworkSourceImport(specifier, fromSourcePath, {
209
+ fileSystem: fs,
210
+ exists: existsFn,
211
+ extensions: [
212
+ ...EXTENSIONS.map((ext) => `${ext}.src`),
213
+ ...EXTENSIONS,
214
+ ],
215
+ });
275
216
  }
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.129";
3
+ export const VERSION = "0.1.130";