veryfront 0.1.1167 → 0.1.1168

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 (65) hide show
  1. package/esm/cli/commands/build/command.d.ts +1 -0
  2. package/esm/cli/commands/build/command.d.ts.map +1 -1
  3. package/esm/cli/commands/build/command.js +5 -2
  4. package/esm/cli/commands/demo/demo.d.ts.map +1 -1
  5. package/esm/cli/commands/demo/demo.js +2 -2
  6. package/esm/cli/commands/dev/command.d.ts +2 -0
  7. package/esm/cli/commands/dev/command.d.ts.map +1 -1
  8. package/esm/cli/commands/dev/command.js +48 -53
  9. package/esm/cli/commands/dev/project-selector.d.ts +20 -0
  10. package/esm/cli/commands/dev/project-selector.d.ts.map +1 -0
  11. package/esm/cli/commands/dev/project-selector.js +50 -0
  12. package/esm/cli/commands/init/config-generator.d.ts +1 -1
  13. package/esm/cli/commands/init/config-generator.d.ts.map +1 -1
  14. package/esm/cli/commands/init/config-generator.js +2 -12
  15. package/esm/cli/commands/init/init-command.d.ts.map +1 -1
  16. package/esm/cli/commands/init/init-command.js +58 -69
  17. package/esm/cli/commands/init/interactive-wizard.d.ts +7 -0
  18. package/esm/cli/commands/init/interactive-wizard.d.ts.map +1 -1
  19. package/esm/cli/commands/init/interactive-wizard.js +15 -7
  20. package/esm/cli/commands/push/command.js +3 -3
  21. package/esm/cli/commands/up/command.js +3 -3
  22. package/esm/cli/templates/manifest.js +2 -2
  23. package/esm/cli/ui/colors.d.ts +6 -0
  24. package/esm/cli/ui/colors.d.ts.map +1 -1
  25. package/esm/cli/ui/colors.js +7 -5
  26. package/esm/cli/ui/components/banner.js +2 -2
  27. package/esm/cli/ui/dot-matrix.d.ts.map +1 -1
  28. package/esm/cli/ui/dot-matrix.js +5 -4
  29. package/esm/cli/ui/progress.d.ts +1 -0
  30. package/esm/cli/ui/progress.d.ts.map +1 -1
  31. package/esm/cli/ui/progress.js +5 -0
  32. package/esm/cli/utils/terminal-select.d.ts +7 -0
  33. package/esm/cli/utils/terminal-select.d.ts.map +1 -1
  34. package/esm/cli/utils/terminal-select.js +26 -6
  35. package/esm/deno.js +1 -1
  36. package/esm/src/build/production-build/asset-generation.js +1 -1
  37. package/esm/src/build/production-build/build/build-cleanup.js +1 -1
  38. package/esm/src/build/production-build/build/build-executor.js +4 -4
  39. package/esm/src/build/production-build/build/build-orchestrator.js +1 -1
  40. package/esm/src/build/production-build/build/build-setup.js +3 -3
  41. package/esm/src/build/production-build/build/code-splitter-orchestrator.js +2 -2
  42. package/esm/src/build/production-build/build/output-generator.js +1 -1
  43. package/esm/src/build/production-build/build/route-collector.js +3 -3
  44. package/esm/src/build/production-build/static-generation.js +1 -1
  45. package/esm/src/modules/react-loader/ssr-module-loader/cache/memory.js +1 -1
  46. package/esm/src/platform/compat/http/deno-server.d.ts.map +1 -1
  47. package/esm/src/platform/compat/http/deno-server.js +8 -2
  48. package/esm/src/security/http/config.d.ts +2 -1
  49. package/esm/src/security/http/config.d.ts.map +1 -1
  50. package/esm/src/security/http/config.js +4 -2
  51. package/esm/src/server/context/cache-invalidation.d.ts.map +1 -1
  52. package/esm/src/server/context/cache-invalidation.js +8 -2
  53. package/esm/src/server/dev-server/file-watch-setup.d.ts.map +1 -1
  54. package/esm/src/server/dev-server/file-watch-setup.js +11 -17
  55. package/esm/src/server/dev-server/server.js +3 -3
  56. package/esm/src/server/handlers/dev/scripts/hmr-scripts.d.ts +2 -2
  57. package/esm/src/server/handlers/dev/scripts/hmr-scripts.d.ts.map +1 -1
  58. package/esm/src/server/handlers/dev/scripts/hmr-scripts.js +23 -35
  59. package/esm/src/server/reload-notifier.js +1 -1
  60. package/esm/src/server/runtime-handler/index.d.ts.map +1 -1
  61. package/esm/src/server/runtime-handler/index.js +1 -1
  62. package/esm/src/utils/bundle-manifest.js +1 -1
  63. package/esm/src/utils/version-constant.d.ts +1 -1
  64. package/esm/src/utils/version-constant.js +1 -1
  65. package/package.json +5 -5
@@ -1,5 +1,6 @@
1
1
  import type { BuildOptions } from "./types.js";
2
2
  /** @internal */
3
3
  export declare function runWithBundlerShutdown<T>(operation: () => Promise<T>, stopBundler?: () => Promise<void>): Promise<T>;
4
+ export declare function formatBuildOutputPath(projectDir: string, outputDir: string): string;
4
5
  export declare function buildCommand(options: BuildOptions): Promise<void>;
5
6
  //# sourceMappingURL=command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/build/command.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,gBAAgB;AAChB,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,WAAW,GAAE,MAAM,OAAO,CAAC,IAAI,CAG9B,GACA,OAAO,CAAC,CAAC,CAAC,CAiBZ;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAoFjE"}
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/build/command.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,gBAAgB;AAChB,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,WAAW,GAAE,MAAM,OAAO,CAAC,IAAI,CAG9B,GACA,OAAO,CAAC,CAAC,CAAC,CAiBZ;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAyFjE"}
@@ -1,4 +1,4 @@
1
- import { join } from "../../../src/platform/compat/path/index.js";
1
+ import { join, relative, resolve } from "../../../src/platform/compat/path/index.js";
2
2
  import { runtime } from "../../../src/platform/index.js";
3
3
  import { getConfig } from "../../../src/config/index.js";
4
4
  import { buildProduction } from "../../../src/build/index.js";
@@ -32,6 +32,9 @@ export async function runWithBundlerShutdown(operation, stopBundler = async () =
32
32
  await stopBundler();
33
33
  return result;
34
34
  }
35
+ export function formatBuildOutputPath(projectDir, outputDir) {
36
+ return relative(projectDir, resolve(projectDir, outputDir)).replace(/\\/g, "/");
37
+ }
35
38
  export function buildCommand(options) {
36
39
  return withSpan("cli.command.build", async () => {
37
40
  const outputDir = options.outputDir ?? join(options.projectDir, "dist");
@@ -92,7 +95,7 @@ export function buildCommand(options) {
92
95
  });
93
96
  return;
94
97
  }
95
- displayBuildSuccess(stats, startTime, outputDir, dryRun);
98
+ displayBuildSuccess(stats, startTime, formatBuildOutputPath(options.projectDir, outputDir), dryRun);
96
99
  }
97
100
  catch (error) {
98
101
  if (isJsonMode()) {
@@ -1 +1 @@
1
- {"version":3,"file":"demo.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/demo/demo.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAyCH,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,uCAAuC,CAAC;AAC7F,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAgBtF,KAAK,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAC;AAS9D,wBAAsB,0BAA0B,CAC9C,aAAa,EAAE,aAAa,EAC5B,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,SAIN,GACD,OAAO,CAAC,aAAa,CAAC,CAMxB;AAwYD,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,8CAA8C;IAC9C,WAAW,CAAC,EAAE,UAAU,CAAC;CAC1B;AA+DD,wBAAsB,WAAW,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmH1E"}
1
+ {"version":3,"file":"demo.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/demo/demo.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA0CH,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,uCAAuC,CAAC;AAC7F,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAgBtF,KAAK,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAC;AAS9D,wBAAsB,0BAA0B,CAC9C,aAAa,EAAE,aAAa,EAC5B,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,SAIN,GACD,OAAO,CAAC,aAAa,CAAC,CAMxB;AAwYD,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,8CAA8C;IAC9C,WAAW,CAAC,EAAE,UAAU,CAAC;CAC1B;AA+DD,wBAAsB,WAAW,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmH1E"}
@@ -6,7 +6,7 @@
6
6
  import { chdir, cwd, promptSync, writeStdout } from "../../../src/platform/index.js";
7
7
  import { getStdinReader, setRawMode } from "../../../src/platform/index.js";
8
8
  import { join } from "../../../src/platform/compat/path/index.js";
9
- import { AnimatedDotMatrix, bold, brand, dim, error, formatDuration, HIDE_CURSOR, muted, SHOW_CURSOR, success, successBanner, typeCommand, typeLine, } from "../../ui/index.js";
9
+ import { AnimatedDotMatrix, bold, brand, BRAND_TRUECOLOR, dim, error, formatDuration, HIDE_CURSOR, muted, SHOW_CURSOR, success, successBanner, typeCommand, typeLine, } from "../../ui/index.js";
10
10
  import { exitProcess, isTTY } from "../../utils/index.js";
11
11
  import { createOAuthAuthorizationUrl, createOAuthState, readToken, saveToken, validateToken, } from "../../auth/index.js";
12
12
  import { canOpenBrowser, openBrowser } from "../../auth/browser.js";
@@ -438,7 +438,7 @@ export async function demoCommand(options = {}) {
438
438
  try {
439
439
  write(CLEAR_SCREEN + MOVE_HOME);
440
440
  console.log();
441
- const matrix = new AnimatedDotMatrix({ litColor: "\x1b[38;2;252;143;93m" });
441
+ const matrix = new AnimatedDotMatrix({ litColor: BRAND_TRUECOLOR });
442
442
  const textLines = [
443
443
  bold(brand("Veryfront")),
444
444
  muted(`Interactive Demo${autoMode ? " (Auto Mode)" : ""}`),
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { type AuthIdentity } from "../../auth/login.js";
5
5
  import { type RemoteProject } from "../../sync/index.js";
6
+ import { type PushOptions } from "../push/index.js";
6
7
  export interface DevOptions {
7
8
  port: number;
8
9
  projectDir: string;
@@ -22,5 +23,6 @@ export declare function preloadDevAuth(apiToken?: string): Promise<{
22
23
  identity: AuthIdentity | null;
23
24
  projects: RemoteProject[];
24
25
  }>;
26
+ export declare function createSelectedProjectPushOptions(projectDir: string, project: RemoteProject): PushOptions;
25
27
  export declare function devCommand(options: DevOptions): Promise<DevCommandResult>;
26
28
  //# sourceMappingURL=command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/dev/command.ts"],"names":[],"mappings":"AAAA;;GAEG;AAkBH,OAAO,EACL,KAAK,YAAY,EAIlB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAI9E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACpB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAQD,wBAAsB,cAAc,CAClC,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC,CAQvE;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAmSzE"}
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/dev/command.ts"],"names":[],"mappings":"AAAA;;GAEG;AAkBH,OAAO,EAAE,KAAK,YAAY,EAA2B,MAAM,qBAAqB,CAAC;AACjF,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE9E,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGjE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACpB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAQD,wBAAsB,cAAc,CAClC,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC,CAQvE;AAED,wBAAgB,gCAAgC,CAC9C,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,aAAa,GACrB,WAAW,CAOb;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwQzE"}
@@ -11,16 +11,17 @@ import { startDevServer } from "../../../src/server/index.js";
11
11
  import { validateProviderConfig } from "../../../src/discovery/index.js";
12
12
  import { yellow } from "../../ui/index.js";
13
13
  import { exitProcess, registerTerminationSignals } from "../../utils/index.js";
14
- import { brand, dim, error as errorColor, success } from "../../ui/index.js";
14
+ import { brand, dim, error as errorColor } from "../../ui/index.js";
15
15
  import { applyRuntimeAuthContext, resolveLinkedProjectSlug } from "../../shared/runtime-auth.js";
16
16
  import { createKeyboardHandler } from "../../ui/keyboard.js";
17
17
  import { openBrowser } from "../../auth/browser.js";
18
18
  import { createMCPServer } from "../../mcp/server.js";
19
19
  import { withSpan } from "../../../src/observability/tracing/otlp-setup.js";
20
- import { isApiKeyIdentity, login, validateCredential, } from "../../auth/login.js";
20
+ import { isApiKeyIdentity, login } from "../../auth/login.js";
21
21
  import { fetchRemoteProjects } from "../../sync/index.js";
22
22
  import { pullCommand } from "../pull/index.js";
23
23
  import { pushCommand } from "../push/index.js";
24
+ import { createProjectSelector } from "./project-selector.js";
24
25
  function authStatus(identity) {
25
26
  return isApiKeyIdentity(identity)
26
27
  ? "Authenticated with an API key"
@@ -29,12 +30,20 @@ function authStatus(identity) {
29
30
  export async function preloadDevAuth(apiToken) {
30
31
  if (!apiToken)
31
32
  return { identity: null, projects: [] };
32
- const identity = await validateCredential(apiToken);
33
- if (!identity)
34
- return { identity: null, projects: [] };
35
33
  const result = await fetchRemoteProjects(apiToken);
34
+ const identity = result.credentialType === "apiKey"
35
+ ? result.error ? null : { authenticated: true, type: "apiKey" }
36
+ : result.user;
36
37
  return { identity, projects: result.projects };
37
38
  }
39
+ export function createSelectedProjectPushOptions(projectDir, project) {
40
+ return {
41
+ projectDir,
42
+ projectSlug: project.slug,
43
+ force: true,
44
+ quiet: true,
45
+ };
46
+ }
38
47
  export function devCommand(options) {
39
48
  return withSpan("cli.command.dev", async () => {
40
49
  const { port, projectDir, hmr = true, open = false, demoMode = false } = options;
@@ -65,6 +74,10 @@ export function devCommand(options) {
65
74
  const runtimeAuth = await applyRuntimeAuthContext({
66
75
  linkedProjectSlug,
67
76
  });
77
+ const initialAuthPromise = preloadDevAuth(runtimeAuth.apiToken).catch(() => ({
78
+ identity: null,
79
+ projects: [],
80
+ }));
68
81
  // Validate provider config and print warnings (framework returns plain text, CLI adds colors)
69
82
  const aiValidation = validateProviderConfig(config);
70
83
  if (aiValidation.warnings.length > 0) {
@@ -120,17 +133,31 @@ export function devCommand(options) {
120
133
  catch {
121
134
  // MCP server failed to start - non-fatal, continue without it
122
135
  }
123
- // Check for existing auth
124
- try {
125
- const initialAuth = await preloadDevAuth(runtimeAuth.apiToken);
136
+ const authReady = initialAuthPromise.then((initialAuth) => {
126
137
  identity = initialAuth.identity;
127
138
  projects = initialAuth.projects;
128
- }
129
- catch {
130
- // Auth check failed - non-fatal
131
- }
139
+ });
140
+ void authReady;
132
141
  let keyboardHandler = null;
133
142
  let shuttingDown = false;
143
+ const projectSelector = createProjectSelector({
144
+ prepare: () => authReady,
145
+ getProjects: () => projects,
146
+ getSelectedProjectId: () => selectedProject?.id ?? null,
147
+ pauseKeyboard: () => keyboardHandler?.stop(),
148
+ resumeKeyboard: () => keyboardHandler?.start(),
149
+ onEmpty: () => {
150
+ if (!identity) {
151
+ console.log(` Press ${brand("a")} to sign in`);
152
+ return;
153
+ }
154
+ console.log(" No projects found");
155
+ },
156
+ onInterrupt: () => void shutdown(),
157
+ onSelect: (project) => {
158
+ selectedProject = project;
159
+ },
160
+ });
134
161
  async function runSyncAction(action, successMsg) {
135
162
  try {
136
163
  await action();
@@ -177,22 +204,9 @@ export function devCommand(options) {
177
204
  }
178
205
  const serverUrl = `http://veryfront.me:${finalPort}`;
179
206
  console.log();
180
- console.log(` ✓ Server ready at ${brand(serverUrl)}`);
207
+ console.log(` ✓ Ready at ${brand(serverUrl)}`);
181
208
  if (mcpServer) {
182
- console.log(` MCP ready at ${brand(`http://veryfront.me:${mcpPort}/mcp`)}`);
183
- }
184
- console.log();
185
- // Context-aware next step hint
186
- if (!identity) {
187
- console.log(` ${dim("To sync with Veryfront: press")} ${brand("a")} ${dim("to login")}`);
188
- }
189
- else if (projects.length > 0) {
190
- console.log(` ✓ ${authStatus(identity)}`);
191
- console.log(` ${dim("Press")} ${brand("s")} ${dim("to select a project, then")} ${brand("p")} ${dim("to pull")}`);
192
- }
193
- else {
194
- console.log(` ✓ ${authStatus(identity)}`);
195
- console.log(` ${dim("Press")} ${brand("s")} ${dim("to see your projects")}`);
209
+ console.log(` MCP ${brand(`http://veryfront.me:${mcpPort}/mcp`)}`);
196
210
  }
197
211
  console.log();
198
212
  if (open) {
@@ -209,6 +223,7 @@ export function devCommand(options) {
209
223
  onClear: () => console.clear(),
210
224
  onQuit: () => void shutdown(),
211
225
  onAuth: async () => {
226
+ await authReady;
212
227
  if (identity) {
213
228
  console.log(` ${dim(authStatus(identity))}${dim(", press s to select a project")}`);
214
229
  return;
@@ -222,44 +237,24 @@ export function devCommand(options) {
222
237
  projects = projectResult.projects;
223
238
  console.log(` ✓ ${authStatus(identity)}${dim(`, ${projects.length} projects`)}`);
224
239
  },
225
- onSync: () => {
226
- if (!identity) {
227
- console.log(` ${dim("Press")} ${brand("a")} ${dim("to login")}`);
228
- return;
229
- }
230
- if (projects.length === 0) {
231
- console.log(` ${dim("No projects")}`);
232
- return;
233
- }
234
- projects.forEach((p, i) => {
235
- const active = selectedProject?.id === p.id;
236
- console.log(` ${active ? success("●") : dim("○")} ${brand(String(i + 1))} ${p.name}`);
237
- });
238
- },
239
- onNumber: async (n) => {
240
- const project = projects[n - 1];
241
- if (!project)
242
- return;
243
- selectedProject = project;
244
- console.log(` ${success("●")} ${project.name} ${dim("— pulling...")}`);
245
- await runSyncAction(() => pullCommand({ projectSlug: project.slug, projectDir, force: true, quiet: true }), `Ready ${dim("— p pull / u push")}`);
246
- },
240
+ onSync: () => void projectSelector.open(),
247
241
  onPull: async () => {
248
242
  const project = selectedProject;
249
243
  if (!project) {
250
- console.log(` ${dim("Press s to select project")}`);
244
+ console.log(` Press ${brand("s")} to select a project`);
251
245
  return;
252
246
  }
253
247
  console.log(` ${dim("Pulling...")}`);
254
248
  await runSyncAction(() => pullCommand({ projectSlug: project.slug, projectDir, force: true, quiet: true }), "Pulled");
255
249
  },
256
250
  onPush: async () => {
257
- if (!selectedProject) {
258
- console.log(` ${dim("Press s to select project")}`);
251
+ const project = selectedProject;
252
+ if (!project) {
253
+ console.log(` Press ${brand("s")} to select a project`);
259
254
  return;
260
255
  }
261
256
  console.log(` ${dim("Pushing...")}`);
262
- await runSyncAction(() => pushCommand({ projectDir, force: true, quiet: true }), `Pushed ${dim("— merge in Studio")}`);
257
+ await runSyncAction(() => pushCommand(createSelectedProjectPushOptions(projectDir, project)), `Pushed ${dim("— merge in Studio")}`);
263
258
  },
264
259
  });
265
260
  keyboardHandler.start();
@@ -0,0 +1,20 @@
1
+ import type { RemoteProject } from "../../sync/index.js";
2
+ import { type PromptDisplayOptions, type SelectOption } from "../../utils/terminal-select.js";
3
+ type SelectOptionFn = (question: string, options: SelectOption[], defaultIndex?: number, display?: PromptDisplayOptions) => Promise<string | null>;
4
+ interface ProjectSelectorOptions {
5
+ prepare?: () => Promise<void>;
6
+ getProjects: () => RemoteProject[];
7
+ getSelectedProjectId: () => string | null;
8
+ pauseKeyboard: () => void;
9
+ resumeKeyboard: () => void;
10
+ onEmpty?: () => void;
11
+ onInterrupt?: () => void;
12
+ onSelect: (project: RemoteProject) => void;
13
+ selectOption?: SelectOptionFn;
14
+ }
15
+ export interface ProjectSelector {
16
+ open: () => Promise<void>;
17
+ }
18
+ export declare function createProjectSelector(options: ProjectSelectorOptions): ProjectSelector;
19
+ export {};
20
+ //# sourceMappingURL=project-selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-selector.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/dev/project-selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EACL,KAAK,oBAAoB,EAGzB,KAAK,YAAY,EAClB,MAAM,gCAAgC,CAAC;AAExC,KAAK,cAAc,GAAG,CACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,YAAY,EAAE,EACvB,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,oBAAoB,KAC3B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAE5B,UAAU,sBAAsB;IAC9B,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,WAAW,EAAE,MAAM,aAAa,EAAE,CAAC;IACnC,oBAAoB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAC1C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,QAAQ,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,YAAY,CAAC,EAAE,cAAc,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAUD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CA+CtF"}
@@ -0,0 +1,50 @@
1
+ import { PromptInterruptedError, select, } from "../../utils/terminal-select.js";
2
+ const PROJECT_PROMPT_DISPLAY = {
3
+ showMarker: false,
4
+ showInstructions: false,
5
+ showDescriptions: false,
6
+ clearOnCancel: true,
7
+ interruptOnCtrlC: true,
8
+ };
9
+ export function createProjectSelector(options) {
10
+ let isOpen = false;
11
+ return {
12
+ async open() {
13
+ if (isOpen)
14
+ return;
15
+ isOpen = true;
16
+ let interrupted = false;
17
+ options.pauseKeyboard();
18
+ try {
19
+ if (options.prepare)
20
+ await options.prepare();
21
+ const projects = options.getProjects();
22
+ if (projects.length === 0) {
23
+ options.onEmpty?.();
24
+ return;
25
+ }
26
+ const selectedId = options.getSelectedProjectId();
27
+ const selectedIndex = Math.max(0, projects.findIndex((project) => project.id === selectedId));
28
+ const projectId = await (options.selectOption ?? select)("Select project:", projects.map((project) => ({ value: project.id, label: project.name })), selectedIndex, PROJECT_PROMPT_DISPLAY);
29
+ if (!projectId)
30
+ return;
31
+ const project = projects.find((candidate) => candidate.id === projectId);
32
+ if (project)
33
+ options.onSelect(project);
34
+ }
35
+ catch (error) {
36
+ if (error instanceof PromptInterruptedError) {
37
+ interrupted = true;
38
+ options.onInterrupt?.();
39
+ return;
40
+ }
41
+ throw error;
42
+ }
43
+ finally {
44
+ isOpen = false;
45
+ if (!interrupted || !options.onInterrupt)
46
+ options.resumeKeyboard();
47
+ }
48
+ },
49
+ };
50
+ }
@@ -7,7 +7,7 @@ export interface CreatePackageJsonOptions {
7
7
  * Selected integrations whose `connector.json#npmDependencies` should be
8
8
  * merged into the generated project's `package.json#dependencies`.
9
9
  * First declaration wins on version collisions; framework pins
10
- * (react, react-dom, veryfront, zod) always take precedence.
10
+ * (react, react-dom, veryfront) always take precedence.
11
11
  */
12
12
  integrations?: Array<{
13
13
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"config-generator.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/config-generator.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,wBAAwB;IACvC,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,sFAAsF;IACtF,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC1C,CAAC,CAAC;CACJ;AAED,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAuEf"}
1
+ {"version":3,"file":"config-generator.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/config-generator.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,wBAAwB;IACvC,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,sFAAsF;IACtF,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC1C,CAAC,CAAC;CACJ;AAED,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAmEf"}
@@ -3,12 +3,6 @@ import { join } from "../../../src/platform/compat/path/index.js";
3
3
  import { createFileSystem } from "../../../src/platform/index.js";
4
4
  // Keep init scaffold aligned with current framework default React major/minor.
5
5
  const DEFAULT_INIT_REACT_VERSION = "19.2.4";
6
- const REQUIRED_INIT_EXTENSION_PACKAGES = [
7
- "@veryfront/ext-bundler-esbuild",
8
- "@veryfront/ext-content-mdx",
9
- "@veryfront/ext-css-tailwind",
10
- "@veryfront/ext-parser-babel",
11
- ];
12
6
  export async function createPackageJson(projectDir, projectName, options = {}) {
13
7
  const fs = createFileSystem();
14
8
  // Read any existing package.json (e.g. from template) to merge dependencies
@@ -33,10 +27,7 @@ export async function createPackageJson(projectDir, projectName, options = {}) {
33
27
  }
34
28
  const dirName = projectDir.split(/[/\\]/).pop();
35
29
  const veryfrontVersionRange = `^${VERSION}`;
36
- const firstPartyExtensionPackages = [
37
- ...REQUIRED_INIT_EXTENSION_PACKAGES,
38
- ...(options.firstPartyExtensions ?? []),
39
- ];
30
+ const firstPartyExtensionPackages = options.firstPartyExtensions ?? [];
40
31
  const requiredExtensionDeps = Object.fromEntries([...new Set(firstPartyExtensionPackages)].map((packageName) => [
41
32
  packageName,
42
33
  veryfrontVersionRange,
@@ -52,7 +43,7 @@ export async function createPackageJson(projectDir, projectName, options = {}) {
52
43
  eval: "veryfront eval",
53
44
  },
54
45
  pnpm: {
55
- onlyBuiltDependencies: ["esbuild", "veryfront"],
46
+ onlyBuiltDependencies: ["esbuild"],
56
47
  },
57
48
  dependencies: {
58
49
  ...templateDeps,
@@ -61,7 +52,6 @@ export async function createPackageJson(projectDir, projectName, options = {}) {
61
52
  react: `^${DEFAULT_INIT_REACT_VERSION}`,
62
53
  "react-dom": `^${DEFAULT_INIT_REACT_VERSION}`,
63
54
  veryfront: veryfrontVersionRange,
64
- zod: "^3.24.0",
65
55
  },
66
56
  };
67
57
  await fs.writeTextFile(join(projectDir, "package.json"), JSON.stringify(packageJson, null, 2));
@@ -1 +1 @@
1
- {"version":3,"file":"init-command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/init-command.ts"],"names":[],"mappings":"AAAA;;;iCAGiC;AAUjC,OAAO,KAAK,EAAE,WAAW,EAA6B,MAAM,YAAY,CAAC;AAwKzE,UAAU,uBAAuB;IAC/B,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACzD;AAyFD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,EACpB,YAAY,GAAE,uBAA4B,GACzC,OAAO,CAAC,IAAI,CAAC,CAqZf"}
1
+ {"version":3,"file":"init-command.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/init-command.ts"],"names":[],"mappings":"AAAA;;;iCAGiC;AAUjC,OAAO,KAAK,EAAE,WAAW,EAA6B,MAAM,YAAY,CAAC;AAwKzE,UAAU,uBAAuB;IAC/B,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACzD;AAyFD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,EACpB,YAAY,GAAE,uBAA4B,GACzC,OAAO,CAAC,IAAI,CAAC,CAuYf"}
@@ -4,7 +4,7 @@
4
4
  *******************************/
5
5
  import { cliLogger as logger, isVerbose } from "../../utils/index.js";
6
6
  import { brand, dim, red } from "../../ui/index.js";
7
- import { createSpinner } from "../../ui/progress.js";
7
+ import { createTransientSpinner } from "../../ui/progress.js";
8
8
  import { ensureDir } from "../../../deps/jsr.io/@std/fs/1.0.23/mod.js";
9
9
  import { join } from "../../../src/platform/compat/path/index.js";
10
10
  import { createPackageJson } from "./config-generator.js";
@@ -353,76 +353,69 @@ export async function initCommand(options, dependencies = {}) {
353
353
  }
354
354
  if (projectName)
355
355
  await ensureDir(projectDir);
356
- // Create project files with progress spinner
357
- const filesSpinner = quiet ? null : createSpinner("Creating project files...");
358
356
  const createdPaths = [];
359
- try {
360
- for (const file of templateFiles) {
361
- if (file.path === ".env" || file.path === ".env.example")
362
- continue;
363
- const filePath = join(projectDir, file.path);
364
- const fileDir = join(projectDir, ...file.path.split("/").slice(0, -1));
365
- if (fileDir !== projectDir)
366
- await ensureDir(fileDir);
367
- await fs.writeTextFile(filePath, file.content);
368
- createdPaths.push(file.path);
369
- logger.debug(`Created file: ${file.path}`);
370
- }
371
- // Skip in quiet/TUI mode since local dev uses CDN and package.json can cause hydration issues
372
- if (!options.quiet) {
373
- await createPackageJson(projectDir, projectName, {
374
- dependencies: templateConfig?.npmDependencies,
375
- firstPartyExtensions: templateConfig?.firstPartyExtensions,
376
- integrations: loadedIntegrations.map((integration) => ({
377
- name: integration.config.name,
378
- npmDependencies: integration.config.npmDependencies,
379
- })),
380
- });
381
- createdPaths.push("package.json");
382
- if (runtime === "deno") {
383
- await createDenoConfig(projectDir);
384
- createdPaths.push("deno.json");
385
- }
386
- }
387
- if (allEnvVars.length) {
388
- const envResult = await promptForEnvVars(dedupeEnvVars(allEnvVars), {
389
- skipPrompt: options.skipEnvPrompt,
390
- prefilledValues: options.env,
391
- });
392
- await fs.writeTextFile(join(projectDir, ".env"), envResult.envContent);
393
- createdPaths.push(".env");
394
- logger.debug("Created file: .env");
395
- await fs.writeTextFile(join(projectDir, ".env.example"), envResult.envExampleContent);
396
- createdPaths.push(".env.example");
397
- logger.debug("Created file: .env.example");
398
- }
399
- const gitignorePath = join(projectDir, ".gitignore");
400
- let existingGitignore;
401
- try {
402
- existingGitignore = await fs.readTextFile(gitignorePath);
403
- }
404
- catch {
405
- existingGitignore = undefined;
357
+ for (const file of templateFiles) {
358
+ if (file.path === ".env" || file.path === ".env.example")
359
+ continue;
360
+ const filePath = join(projectDir, file.path);
361
+ const fileDir = join(projectDir, ...file.path.split("/").slice(0, -1));
362
+ if (fileDir !== projectDir)
363
+ await ensureDir(fileDir);
364
+ await fs.writeTextFile(filePath, file.content);
365
+ createdPaths.push(file.path);
366
+ logger.debug(`Created file: ${file.path}`);
367
+ }
368
+ // Skip in quiet/TUI mode since local dev uses CDN and package.json can cause hydration issues
369
+ if (!options.quiet) {
370
+ await createPackageJson(projectDir, projectName, {
371
+ dependencies: templateConfig?.npmDependencies,
372
+ firstPartyExtensions: templateConfig?.firstPartyExtensions,
373
+ integrations: loadedIntegrations.map((integration) => ({
374
+ name: integration.config.name,
375
+ npmDependencies: integration.config.npmDependencies,
376
+ })),
377
+ });
378
+ createdPaths.push("package.json");
379
+ if (runtime === "deno") {
380
+ await createDenoConfig(projectDir);
381
+ createdPaths.push("deno.json");
406
382
  }
407
- await fs.writeTextFile(gitignorePath, generateGitignoreContent(existingGitignore));
408
- createdPaths.push(".gitignore");
409
- logger.debug("Updated file: .gitignore");
410
- filesSpinner?.success("Project files created");
411
383
  }
412
- catch (err) {
413
- filesSpinner?.error("Failed to create project files");
414
- throw err;
384
+ if (allEnvVars.length) {
385
+ const envResult = await promptForEnvVars(dedupeEnvVars(allEnvVars), {
386
+ skipPrompt: options.skipEnvPrompt,
387
+ prefilledValues: options.env,
388
+ });
389
+ await fs.writeTextFile(join(projectDir, ".env"), envResult.envContent);
390
+ createdPaths.push(".env");
391
+ logger.debug("Created file: .env");
392
+ await fs.writeTextFile(join(projectDir, ".env.example"), envResult.envExampleContent);
393
+ createdPaths.push(".env.example");
394
+ logger.debug("Created file: .env.example");
395
+ }
396
+ const gitignorePath = join(projectDir, ".gitignore");
397
+ let existingGitignore;
398
+ try {
399
+ existingGitignore = await fs.readTextFile(gitignorePath);
415
400
  }
401
+ catch {
402
+ existingGitignore = undefined;
403
+ }
404
+ await fs.writeTextFile(gitignorePath, generateGitignoreContent(existingGitignore));
405
+ createdPaths.push(".gitignore");
406
+ logger.debug("Updated file: .gitignore");
416
407
  options._featureTips = featureTips;
417
408
  if (!options.skipInstall) {
418
409
  const pm = await detectPackageManager(projectDir, pmPreference);
419
- const installSpinner = quiet ? null : createSpinner(`Installing dependencies with ${pm}...`);
410
+ const installSpinner = quiet
411
+ ? null
412
+ : createTransientSpinner(`Installing dependencies with ${pm}...`);
420
413
  const installSuccess = await installDependencies(projectDir, {
421
414
  silent: true,
422
415
  packageManager: pm,
423
416
  });
424
417
  if (installSuccess) {
425
- installSpinner?.success("Dependencies installed");
418
+ installSpinner?.stop();
426
419
  }
427
420
  else {
428
421
  installSpinner?.error("Dependency installation failed");
@@ -433,19 +426,15 @@ export async function initCommand(options, dependencies = {}) {
433
426
  }
434
427
  // Initialize git if requested
435
428
  if (initGit) {
436
- const gitSpinner = quiet ? null : createSpinner("Initializing git repository...");
437
429
  try {
438
430
  const { initializeGitRepo } = await import("../../utils/git.js");
439
431
  const success = await initializeGitRepo(projectDir, projectName ?? "veryfront project");
440
- if (success) {
441
- gitSpinner?.success("Git repository initialized");
442
- }
443
- else {
444
- gitSpinner?.error("Git initialization failed");
445
- }
432
+ if (!success && !quiet)
433
+ logger.warn("Git initialization failed");
446
434
  }
447
435
  catch {
448
- gitSpinner?.error("Git initialization failed");
436
+ if (!quiet)
437
+ logger.warn("Git initialization failed");
449
438
  }
450
439
  }
451
440
  // Deploy to cloud if --deploy flag is set
@@ -536,11 +525,11 @@ export async function initCommand(options, dependencies = {}) {
536
525
  }
537
526
  if (deployedUrl) {
538
527
  console.log("");
539
- console.log(` ${dim("Live:")} ${brand(deployedUrl)}`);
528
+ console.log(` Live: ${brand(deployedUrl)}`);
540
529
  }
541
530
  else {
542
531
  console.log("");
543
- console.log(` ${dim("Deploy:")} ${brand(deployCommandHint)}`);
532
+ console.log(` Deploy: ${brand(deployCommandHint)}`);
544
533
  }
545
534
  const tips = [];
546
535
  const displayFeatureTips = options._featureTips;
@@ -10,6 +10,13 @@ export interface WizardResult {
10
10
  cancelled: boolean;
11
11
  }
12
12
  export declare function formatWizardIntro(): string;
13
+ export declare const SETUP_COPY: {
14
+ readonly intro: "Let's set up your project.";
15
+ readonly location: "Create project in:";
16
+ readonly template: "Choose a starter template:";
17
+ readonly runtime: "Select runtime:";
18
+ readonly git: "Initialize Git?";
19
+ };
13
20
  export declare function runInteractiveWizard(existingName?: string, presetRuntime?: InitRuntime): Promise<WizardResult>;
14
21
  export declare function shouldRunWizard(options: {
15
22
  template?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"interactive-wizard.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/interactive-wizard.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5D,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI/D;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB;AAMD,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAOD,wBAAsB,oBAAoB,CACxC,YAAY,CAAC,EAAE,MAAM,EACrB,aAAa,CAAC,EAAE,WAAW,GAC1B,OAAO,CAAC,YAAY,CAAC,CAkKvB;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAGvE"}
1
+ {"version":3,"file":"interactive-wizard.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/interactive-wizard.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5D,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI/D;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB;AAMD,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,eAAO,MAAM,UAAU;;;;;;CAMb,CAAC;AAQX,wBAAsB,oBAAoB,CACxC,YAAY,CAAC,EAAE,MAAM,EACrB,aAAa,CAAC,EAAE,WAAW,GAC1B,OAAO,CAAC,YAAY,CAAC,CAkKvB;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAGvE"}