@timber-js/app 0.1.27 → 0.1.29

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/dist/cli.d.ts CHANGED
@@ -13,17 +13,23 @@ export interface CommandOptions {
13
13
  * Accepts: timber <command> [--config|-c <path>]
14
14
  */
15
15
  export declare function parseArgs(args: string[]): ParsedArgs;
16
+ /** @internal Dependency injection for testing. */
17
+ export interface ViteDeps {
18
+ createServer?: typeof import('vite').createServer;
19
+ createBuilder?: typeof import('vite').createBuilder;
20
+ preview?: typeof import('vite').preview;
21
+ }
16
22
  /**
17
23
  * Start the Vite dev server.
18
24
  * Middleware re-runs on file change via HMR wiring in timber-routing.
19
25
  */
20
- export declare function runDev(options: CommandOptions): Promise<void>;
26
+ export declare function runDev(options: CommandOptions, _deps?: ViteDeps): Promise<void>;
21
27
  /**
22
28
  * Run the production build using createBuilder + buildApp.
23
29
  * Direct build() calls do NOT trigger the RSC plugin's multi-environment
24
30
  * pipeline — createBuilder/buildApp is required.
25
31
  */
26
- export declare function runBuild(options: CommandOptions): Promise<void>;
32
+ export declare function runBuild(options: CommandOptions, _deps?: ViteDeps): Promise<void>;
27
33
  /**
28
34
  * Determine whether to use the adapter's preview or Vite's built-in preview.
29
35
  * Exported for testing — the actual runPreview function uses this internally.
@@ -34,7 +40,7 @@ export declare function resolvePreviewStrategy(adapter: import('./adapters/types
34
40
  * If the adapter provides a preview() method, it takes priority.
35
41
  * Otherwise falls back to Vite's built-in preview server.
36
42
  */
37
- export declare function runPreview(options: CommandOptions): Promise<void>;
43
+ export declare function runPreview(options: CommandOptions, _deps?: ViteDeps): Promise<void>;
38
44
  /**
39
45
  * Validate types and routes without producing build output.
40
46
  * Runs tsgo --noEmit for type checking.
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAaA,QAAA,MAAM,QAAQ,+CAAgD,CAAC;AAC/D,KAAK,OAAO,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzC,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAuBpD;AAID;;;GAGG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAOnE;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,kBAAkB,EAAE,qBAAqB,GAAG,SAAS,GACpE,SAAS,GAAG,MAAM,CAKpB;AA2BD;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBvE;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAerE"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAaA,QAAA,MAAM,QAAQ,+CAAgD,CAAC;AAC/D,KAAK,OAAO,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzC,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAuBpD;AAID,kDAAkD;AAClD,MAAM,WAAW,QAAQ;IACvB,YAAY,CAAC,EAAE,cAAc,MAAM,EAAE,YAAY,CAAC;IAClD,aAAa,CAAC,EAAE,cAAc,MAAM,EAAE,aAAa,CAAC;IACpD,OAAO,CAAC,EAAE,cAAc,MAAM,EAAE,OAAO,CAAC;CACzC;AAED;;;GAGG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAOrF;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,OAAO,kBAAkB,EAAE,qBAAqB,GAAG,SAAS,GACpE,SAAS,GAAG,MAAM,CAKpB;AA2BD;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBzF;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAerE"}
package/dist/cli.js CHANGED
@@ -28,9 +28,8 @@ function parseArgs(args) {
28
28
  * Start the Vite dev server.
29
29
  * Middleware re-runs on file change via HMR wiring in timber-routing.
30
30
  */
31
- async function runDev(options) {
32
- const { createServer } = await import("vite");
33
- const server = await createServer({ configFile: options.config });
31
+ async function runDev(options, _deps) {
32
+ const server = await (_deps?.createServer ?? (await import("vite")).createServer)({ configFile: options.config });
34
33
  await server.listen();
35
34
  server.printUrls();
36
35
  }
@@ -39,9 +38,8 @@ async function runDev(options) {
39
38
  * Direct build() calls do NOT trigger the RSC plugin's multi-environment
40
39
  * pipeline — createBuilder/buildApp is required.
41
40
  */
42
- async function runBuild(options) {
43
- const { createBuilder } = await import("vite");
44
- await (await createBuilder({ configFile: options.config })).buildApp();
41
+ async function runBuild(options, _deps) {
42
+ await (await (_deps?.createBuilder ?? (await import("vite")).createBuilder)({ configFile: options.config })).buildApp();
45
43
  }
46
44
  /**
47
45
  * Determine whether to use the adapter's preview or Vite's built-in preview.
@@ -78,7 +76,7 @@ async function loadTimberConfig(root) {
78
76
  * If the adapter provides a preview() method, it takes priority.
79
77
  * Otherwise falls back to Vite's built-in preview server.
80
78
  */
81
- async function runPreview(options) {
79
+ async function runPreview(options, _deps) {
82
80
  const { join } = await import("node:path");
83
81
  const root = process.cwd();
84
82
  const config = await loadTimberConfig(root).catch(() => null);
@@ -89,8 +87,7 @@ async function runPreview(options) {
89
87
  await adapter.preview(timberConfig, buildDir);
90
88
  return;
91
89
  }
92
- const { preview } = await import("vite");
93
- (await preview({ configFile: options.config })).printUrls();
90
+ (await (_deps?.preview ?? (await import("vite")).preview)({ configFile: options.config })).printUrls();
94
91
  }
95
92
  /**
96
93
  * Validate types and routes without producing build output.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\n// timber.js CLI\n//\n// Wraps Vite commands with timber-specific behavior.\n// See design/18-build-system.md §\"CLI\".\n//\n// Commands:\n// timber dev — Start Vite dev server with HMR\n// timber build — Run multi-environment build via createBuilder/buildApp\n// timber preview — Serve the production build\n// timber check — Validate types + routes without building\n\nconst COMMANDS = ['dev', 'build', 'preview', 'check'] as const;\ntype Command = (typeof COMMANDS)[number];\n\nexport interface ParsedArgs {\n command: Command;\n config: string | undefined;\n}\n\nexport interface CommandOptions {\n config?: string;\n}\n\n/**\n * Parse CLI arguments into a structured command + options.\n * Accepts: timber <command> [--config|-c <path>]\n */\nexport function parseArgs(args: string[]): ParsedArgs {\n if (args.length === 0) {\n throw new Error(\n 'No command provided. Usage: timber <dev|build|preview|check> [--config <path>]'\n );\n }\n\n const command = args[0];\n if (!COMMANDS.includes(command as Command)) {\n throw new Error(`Unknown command: ${command}. Available commands: ${COMMANDS.join(', ')}`);\n }\n\n let config: string | undefined;\n for (let i = 1; i < args.length; i++) {\n if (args[i] === '--config' || args[i] === '-c') {\n config = args[++i];\n if (!config) {\n throw new Error('--config requires a path argument');\n }\n }\n }\n\n return { command: command as Command, config };\n}\n\n// ─── Command Implementations ─────────────────────────────────────────────────\n\n/**\n * Start the Vite dev server.\n * Middleware re-runs on file change via HMR wiring in timber-routing.\n */\nexport async function runDev(options: CommandOptions): Promise<void> {\n const { createServer } = await import('vite');\n const server = await createServer({\n configFile: options.config,\n });\n await server.listen();\n server.printUrls();\n}\n\n/**\n * Run the production build using createBuilder + buildApp.\n * Direct build() calls do NOT trigger the RSC plugin's multi-environment\n * pipeline — createBuilder/buildApp is required.\n */\nexport async function runBuild(options: CommandOptions): Promise<void> {\n const { createBuilder } = await import('vite');\n const builder = await createBuilder({\n configFile: options.config,\n });\n await builder.buildApp();\n}\n\n/**\n * Determine whether to use the adapter's preview or Vite's built-in preview.\n * Exported for testing — the actual runPreview function uses this internally.\n */\nexport function resolvePreviewStrategy(\n adapter: import('./adapters/types').TimberPlatformAdapter | undefined\n): 'adapter' | 'vite' {\n if (adapter && typeof adapter.preview === 'function') {\n return 'adapter';\n }\n return 'vite';\n}\n\n/**\n * Load timber.config.ts from the project root.\n * Returns the config object with adapter, output, etc.\n * Returns null if no config file is found.\n */\nasync function loadTimberConfig(\n root: string\n): Promise<{ adapter?: import('./adapters/types').TimberPlatformAdapter; output?: string } | null> {\n const { existsSync } = await import('node:fs');\n const { join } = await import('node:path');\n const { pathToFileURL } = await import('node:url');\n\n const configNames = ['timber.config.ts', 'timber.config.js', 'timber.config.mjs'];\n\n for (const name of configNames) {\n const configPath = join(root, name);\n if (existsSync(configPath)) {\n // Use Vite's built-in config loading to handle TypeScript\n const mod = await import(pathToFileURL(configPath).href);\n return mod.default ?? mod;\n }\n }\n return null;\n}\n\n/**\n * Serve the production build for local testing.\n * If the adapter provides a preview() method, it takes priority.\n * Otherwise falls back to Vite's built-in preview server.\n */\nexport async function runPreview(options: CommandOptions): Promise<void> {\n const { join } = await import('node:path');\n\n // Try to load timber config for adapter-specific preview\n const root = process.cwd();\n const config = await loadTimberConfig(root).catch(() => null);\n const adapter = config?.adapter as import('./adapters/types').TimberPlatformAdapter | undefined;\n\n if (resolvePreviewStrategy(adapter) === 'adapter') {\n const buildDir = join(root, 'dist');\n const timberConfig = { output: (config?.output ?? 'server') as 'server' | 'static' };\n await adapter!.preview!(timberConfig, buildDir);\n return;\n }\n\n // Fallback: Vite's built-in preview server\n const { preview } = await import('vite');\n const server = await preview({\n configFile: options.config,\n });\n server.printUrls();\n}\n\n/**\n * Validate types and routes without producing build output.\n * Runs tsgo --noEmit for type checking.\n */\nexport async function runCheck(options: CommandOptions): Promise<void> {\n const { execFile } = await import('node:child_process');\n\n await new Promise<void>((resolve, reject) => {\n const configArgs = options.config ? ['--project', options.config] : [];\n execFile('tsgo', ['--noEmit', ...configArgs], (err, stdout, stderr) => {\n if (stdout) process.stdout.write(stdout);\n if (stderr) process.stderr.write(stderr);\n if (err) {\n reject(new Error(`Type check failed with exit code ${err.code}`));\n } else {\n resolve();\n }\n });\n });\n}\n\n// ─── Main Entry Point ────────────────────────────────────────────────────────\n\nasync function main(): Promise<void> {\n const parsed = parseArgs(process.argv.slice(2));\n const options: CommandOptions = { config: parsed.config };\n\n switch (parsed.command) {\n case 'dev':\n await runDev(options);\n break;\n case 'build':\n await runBuild(options);\n break;\n case 'preview':\n await runPreview(options);\n break;\n case 'check':\n await runCheck(options);\n break;\n }\n}\n\n// Run main when executed as a CLI (not imported in tests).\n// The bin shim (bin/timber.mjs) does `import '../dist/cli.js'`, so\n// process.argv[1] points to the shim, not this file. We check both:\n// direct execution AND being imported by the timber bin shim.\nconst isDirectExecution =\n typeof process !== 'undefined' &&\n process.argv[1] &&\n (import.meta.url.endsWith(process.argv[1]) ||\n process.argv[1].endsWith('bin/timber.mjs') ||\n process.argv[1].endsWith('bin/timber'));\n\nif (isDirectExecution) {\n main().catch((err) => {\n console.error(err.message);\n process.exit(1);\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\n// timber.js CLI\n//\n// Wraps Vite commands with timber-specific behavior.\n// See design/18-build-system.md §\"CLI\".\n//\n// Commands:\n// timber dev — Start Vite dev server with HMR\n// timber build — Run multi-environment build via createBuilder/buildApp\n// timber preview — Serve the production build\n// timber check — Validate types + routes without building\n\nconst COMMANDS = ['dev', 'build', 'preview', 'check'] as const;\ntype Command = (typeof COMMANDS)[number];\n\nexport interface ParsedArgs {\n command: Command;\n config: string | undefined;\n}\n\nexport interface CommandOptions {\n config?: string;\n}\n\n/**\n * Parse CLI arguments into a structured command + options.\n * Accepts: timber <command> [--config|-c <path>]\n */\nexport function parseArgs(args: string[]): ParsedArgs {\n if (args.length === 0) {\n throw new Error(\n 'No command provided. Usage: timber <dev|build|preview|check> [--config <path>]'\n );\n }\n\n const command = args[0];\n if (!COMMANDS.includes(command as Command)) {\n throw new Error(`Unknown command: ${command}. Available commands: ${COMMANDS.join(', ')}`);\n }\n\n let config: string | undefined;\n for (let i = 1; i < args.length; i++) {\n if (args[i] === '--config' || args[i] === '-c') {\n config = args[++i];\n if (!config) {\n throw new Error('--config requires a path argument');\n }\n }\n }\n\n return { command: command as Command, config };\n}\n\n// ─── Command Implementations ─────────────────────────────────────────────────\n\n/** @internal Dependency injection for testing. */\nexport interface ViteDeps {\n createServer?: typeof import('vite').createServer;\n createBuilder?: typeof import('vite').createBuilder;\n preview?: typeof import('vite').preview;\n}\n\n/**\n * Start the Vite dev server.\n * Middleware re-runs on file change via HMR wiring in timber-routing.\n */\nexport async function runDev(options: CommandOptions, _deps?: ViteDeps): Promise<void> {\n const createServer = _deps?.createServer ?? (await import('vite')).createServer;\n const server = await createServer({\n configFile: options.config,\n });\n await server.listen();\n server.printUrls();\n}\n\n/**\n * Run the production build using createBuilder + buildApp.\n * Direct build() calls do NOT trigger the RSC plugin's multi-environment\n * pipeline — createBuilder/buildApp is required.\n */\nexport async function runBuild(options: CommandOptions, _deps?: ViteDeps): Promise<void> {\n const createBuilder = _deps?.createBuilder ?? (await import('vite')).createBuilder;\n const builder = await createBuilder({\n configFile: options.config,\n });\n await builder.buildApp();\n}\n\n/**\n * Determine whether to use the adapter's preview or Vite's built-in preview.\n * Exported for testing — the actual runPreview function uses this internally.\n */\nexport function resolvePreviewStrategy(\n adapter: import('./adapters/types').TimberPlatformAdapter | undefined\n): 'adapter' | 'vite' {\n if (adapter && typeof adapter.preview === 'function') {\n return 'adapter';\n }\n return 'vite';\n}\n\n/**\n * Load timber.config.ts from the project root.\n * Returns the config object with adapter, output, etc.\n * Returns null if no config file is found.\n */\nasync function loadTimberConfig(\n root: string\n): Promise<{ adapter?: import('./adapters/types').TimberPlatformAdapter; output?: string } | null> {\n const { existsSync } = await import('node:fs');\n const { join } = await import('node:path');\n const { pathToFileURL } = await import('node:url');\n\n const configNames = ['timber.config.ts', 'timber.config.js', 'timber.config.mjs'];\n\n for (const name of configNames) {\n const configPath = join(root, name);\n if (existsSync(configPath)) {\n // Use Vite's built-in config loading to handle TypeScript\n const mod = await import(pathToFileURL(configPath).href);\n return mod.default ?? mod;\n }\n }\n return null;\n}\n\n/**\n * Serve the production build for local testing.\n * If the adapter provides a preview() method, it takes priority.\n * Otherwise falls back to Vite's built-in preview server.\n */\nexport async function runPreview(options: CommandOptions, _deps?: ViteDeps): Promise<void> {\n const { join } = await import('node:path');\n\n // Try to load timber config for adapter-specific preview\n const root = process.cwd();\n const config = await loadTimberConfig(root).catch(() => null);\n const adapter = config?.adapter as import('./adapters/types').TimberPlatformAdapter | undefined;\n\n if (resolvePreviewStrategy(adapter) === 'adapter') {\n const buildDir = join(root, 'dist');\n const timberConfig = { output: (config?.output ?? 'server') as 'server' | 'static' };\n await adapter!.preview!(timberConfig, buildDir);\n return;\n }\n\n // Fallback: Vite's built-in preview server\n const preview = _deps?.preview ?? (await import('vite')).preview;\n const server = await preview({\n configFile: options.config,\n });\n server.printUrls();\n}\n\n/**\n * Validate types and routes without producing build output.\n * Runs tsgo --noEmit for type checking.\n */\nexport async function runCheck(options: CommandOptions): Promise<void> {\n const { execFile } = await import('node:child_process');\n\n await new Promise<void>((resolve, reject) => {\n const configArgs = options.config ? ['--project', options.config] : [];\n execFile('tsgo', ['--noEmit', ...configArgs], (err, stdout, stderr) => {\n if (stdout) process.stdout.write(stdout);\n if (stderr) process.stderr.write(stderr);\n if (err) {\n reject(new Error(`Type check failed with exit code ${err.code}`));\n } else {\n resolve();\n }\n });\n });\n}\n\n// ─── Main Entry Point ────────────────────────────────────────────────────────\n\nasync function main(): Promise<void> {\n const parsed = parseArgs(process.argv.slice(2));\n const options: CommandOptions = { config: parsed.config };\n\n switch (parsed.command) {\n case 'dev':\n await runDev(options);\n break;\n case 'build':\n await runBuild(options);\n break;\n case 'preview':\n await runPreview(options);\n break;\n case 'check':\n await runCheck(options);\n break;\n }\n}\n\n// Run main when executed as a CLI (not imported in tests).\n// The bin shim (bin/timber.mjs) does `import '../dist/cli.js'`, so\n// process.argv[1] points to the shim, not this file. We check both:\n// direct execution AND being imported by the timber bin shim.\nconst isDirectExecution =\n typeof process !== 'undefined' &&\n process.argv[1] &&\n (import.meta.url.endsWith(process.argv[1]) ||\n process.argv[1].endsWith('bin/timber.mjs') ||\n process.argv[1].endsWith('bin/timber'));\n\nif (isDirectExecution) {\n main().catch((err) => {\n console.error(err.message);\n process.exit(1);\n });\n}\n"],"mappings":"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"}
@@ -4,9 +4,8 @@ import { n as useQueryStates, t as bindUseQueryStates } from "../_chunks/use-que
4
4
  import { t as useCookie } from "../_chunks/use-cookie-dDbpCTx-.js";
5
5
  import { TimberErrorBoundary } from "./error-boundary.js";
6
6
  import React, { createContext, createElement, useActionState as useActionState$1, useContext, useEffect, useMemo, useRef, useSyncExternalStore, useTransition } from "react";
7
- import { jsxDEV } from "react/jsx-dev-runtime";
7
+ import { jsx } from "react/jsx-runtime";
8
8
  //#region src/client/link-navigate-interceptor.tsx
9
- var _jsxFileName$2 = "/Users/dsaewitz/y/timber-js-fresh/packages/timber-app/src/client/link-navigate-interceptor.tsx";
10
9
  /** Symbol used to store the onNavigate callback on anchor elements. */
11
10
  var ON_NAVIGATE_KEY = "__timberOnNavigate";
12
11
  /**
@@ -26,15 +25,11 @@ function LinkNavigateInterceptor({ onNavigate, children }) {
26
25
  delete anchor[ON_NAVIGATE_KEY];
27
26
  };
28
27
  }, [onNavigate]);
29
- return /* @__PURE__ */ jsxDEV("span", {
28
+ return /* @__PURE__ */ jsx("span", {
30
29
  ref,
31
30
  style: { display: "contents" },
32
31
  children
33
- }, void 0, false, {
34
- fileName: _jsxFileName$2,
35
- lineNumber: 58,
36
- columnNumber: 5
37
- }, this);
32
+ });
38
33
  }
39
34
  //#endregion
40
35
  //#region src/client/use-link-status.ts
@@ -97,7 +92,6 @@ function getRouterOrNull() {
97
92
  }
98
93
  //#endregion
99
94
  //#region src/client/link-status-provider.tsx
100
- var _jsxFileName$1 = "/Users/dsaewitz/y/timber-js-fresh/packages/timber-app/src/client/link-status-provider.tsx";
101
95
  var NOT_PENDING = { pending: false };
102
96
  var IS_PENDING = { pending: true };
103
97
  /**
@@ -120,18 +114,13 @@ function LinkStatusProvider({ href, children }) {
120
114
  return NOT_PENDING;
121
115
  }
122
116
  }, () => NOT_PENDING);
123
- return /* @__PURE__ */ jsxDEV(LinkStatusContext.Provider, {
117
+ return /* @__PURE__ */ jsx(LinkStatusContext.Provider, {
124
118
  value: status,
125
119
  children
126
- }, void 0, false, {
127
- fileName: _jsxFileName$1,
128
- lineNumber: 39,
129
- columnNumber: 10
130
- }, this);
120
+ });
131
121
  }
132
122
  //#endregion
133
123
  //#region src/client/link.tsx
134
- var _jsxFileName = "/Users/dsaewitz/y/timber-js-fresh/packages/timber-app/src/client/link.tsx";
135
124
  /**
136
125
  * Reject dangerous URL schemes that could execute script.
137
126
  * Security: design/13-security.md § Link scheme injection (test #9)
@@ -227,30 +216,18 @@ function Link({ href, prefetch, scroll, params, searchParams, onNavigate, childr
227
216
  params,
228
217
  searchParams
229
218
  });
230
- const inner = /* @__PURE__ */ jsxDEV(LinkStatusProvider, {
219
+ const inner = /* @__PURE__ */ jsx(LinkStatusProvider, {
231
220
  href: linkProps.href,
232
221
  children
233
- }, void 0, false, {
234
- fileName: _jsxFileName,
235
- lineNumber: 301,
236
- columnNumber: 17
237
- }, this);
238
- return /* @__PURE__ */ jsxDEV("a", {
222
+ });
223
+ return /* @__PURE__ */ jsx("a", {
239
224
  ...rest,
240
225
  ...linkProps,
241
- children: onNavigate ? /* @__PURE__ */ jsxDEV(LinkNavigateInterceptor, {
226
+ children: onNavigate ? /* @__PURE__ */ jsx(LinkNavigateInterceptor, {
242
227
  onNavigate,
243
228
  children: inner
244
- }, void 0, false, {
245
- fileName: _jsxFileName,
246
- lineNumber: 306,
247
- columnNumber: 9
248
- }, this) : inner
249
- }, void 0, false, {
250
- fileName: _jsxFileName,
251
- lineNumber: 304,
252
- columnNumber: 5
253
- }, this);
229
+ }) : inner
230
+ });
254
231
  }
255
232
  //#endregion
256
233
  //#region src/client/segment-cache.ts