@davaux/multisite 0.8.0 → 0.8.1

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 (73) hide show
  1. package/dist/build.d.ts +44 -0
  2. package/dist/build.d.ts.map +1 -0
  3. package/dist/build.js +136 -0
  4. package/dist/build.js.map +1 -0
  5. package/dist/index.d.ts +202 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +944 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/test/fixtures/base/routes/_layout.d.ts +3 -0
  10. package/dist/test/fixtures/base/routes/_layout.d.ts.map +1 -0
  11. package/dist/test/fixtures/base/routes/_layout.js +6 -0
  12. package/dist/test/fixtures/base/routes/_layout.js.map +1 -0
  13. package/dist/test/fixtures/base/routes/about.page.d.ts +3 -0
  14. package/dist/test/fixtures/base/routes/about.page.d.ts.map +1 -0
  15. package/dist/test/fixtures/base/routes/about.page.js +3 -0
  16. package/dist/test/fixtures/base/routes/about.page.js.map +1 -0
  17. package/dist/test/fixtures/base/routes/index.page.d.ts +3 -0
  18. package/dist/test/fixtures/base/routes/index.page.d.ts.map +1 -0
  19. package/dist/test/fixtures/base/routes/index.page.js +3 -0
  20. package/dist/test/fixtures/base/routes/index.page.js.map +1 -0
  21. package/dist/test/fixtures/site-a/routes/_layout.d.ts +3 -0
  22. package/dist/test/fixtures/site-a/routes/_layout.d.ts.map +1 -0
  23. package/dist/test/fixtures/site-a/routes/_layout.js +6 -0
  24. package/dist/test/fixtures/site-a/routes/_layout.js.map +1 -0
  25. package/dist/test/fixtures/site-a/routes/_middleware.d.ts +3 -0
  26. package/dist/test/fixtures/site-a/routes/_middleware.d.ts.map +1 -0
  27. package/dist/test/fixtures/site-a/routes/_middleware.js +6 -0
  28. package/dist/test/fixtures/site-a/routes/_middleware.js.map +1 -0
  29. package/dist/test/fixtures/site-a/routes/config.page.d.ts +3 -0
  30. package/dist/test/fixtures/site-a/routes/config.page.d.ts.map +1 -0
  31. package/dist/test/fixtures/site-a/routes/config.page.js +7 -0
  32. package/dist/test/fixtures/site-a/routes/config.page.js.map +1 -0
  33. package/dist/test/fixtures/site-a/routes/index.page.d.ts +3 -0
  34. package/dist/test/fixtures/site-a/routes/index.page.d.ts.map +1 -0
  35. package/dist/test/fixtures/site-a/routes/index.page.js +3 -0
  36. package/dist/test/fixtures/site-a/routes/index.page.js.map +1 -0
  37. package/dist/test/fixtures/site-a/routes/shop.page.d.ts +3 -0
  38. package/dist/test/fixtures/site-a/routes/shop.page.d.ts.map +1 -0
  39. package/dist/test/fixtures/site-a/routes/shop.page.js +3 -0
  40. package/dist/test/fixtures/site-a/routes/shop.page.js.map +1 -0
  41. package/dist/test/fixtures/site-a/routes/state.page.d.ts +3 -0
  42. package/dist/test/fixtures/site-a/routes/state.page.d.ts.map +1 -0
  43. package/dist/test/fixtures/site-a/routes/state.page.js +3 -0
  44. package/dist/test/fixtures/site-a/routes/state.page.js.map +1 -0
  45. package/dist/test/fixtures/site-b/routes/_error.d.ts +3 -0
  46. package/dist/test/fixtures/site-b/routes/_error.d.ts.map +1 -0
  47. package/dist/test/fixtures/site-b/routes/_error.js +3 -0
  48. package/dist/test/fixtures/site-b/routes/_error.js.map +1 -0
  49. package/dist/test/fixtures/site-b/routes/about.page.d.ts +3 -0
  50. package/dist/test/fixtures/site-b/routes/about.page.d.ts.map +1 -0
  51. package/dist/test/fixtures/site-b/routes/about.page.js +3 -0
  52. package/dist/test/fixtures/site-b/routes/about.page.js.map +1 -0
  53. package/dist/test/multisite.test.d.ts +2 -0
  54. package/dist/test/multisite.test.d.ts.map +1 -0
  55. package/dist/test/multisite.test.js +492 -0
  56. package/dist/test/multisite.test.js.map +1 -0
  57. package/package.json +6 -3
  58. package/CLAUDE.md +0 -133
  59. package/src/build.ts +0 -183
  60. package/src/index.ts +0 -1219
  61. package/src/test/fixtures/base/routes/_layout.ts +0 -6
  62. package/src/test/fixtures/base/routes/about.page.ts +0 -3
  63. package/src/test/fixtures/base/routes/index.page.ts +0 -3
  64. package/src/test/fixtures/site-a/routes/_layout.ts +0 -6
  65. package/src/test/fixtures/site-a/routes/_middleware.ts +0 -6
  66. package/src/test/fixtures/site-a/routes/config.page.ts +0 -7
  67. package/src/test/fixtures/site-a/routes/index.page.ts +0 -3
  68. package/src/test/fixtures/site-a/routes/shop.page.ts +0 -3
  69. package/src/test/fixtures/site-a/routes/state.page.ts +0 -3
  70. package/src/test/fixtures/site-b/routes/_error.ts +0 -3
  71. package/src/test/fixtures/site-b/routes/about.page.ts +0 -3
  72. package/src/test/multisite.test.ts +0 -650
  73. package/tsconfig.json +0 -17
@@ -0,0 +1,44 @@
1
+ import { type DavauxPlugin } from 'davaux/config';
2
+ import type { MultisiteConfig } from './index.js';
3
+ export interface BuildMultisiteOptions {
4
+ /** Project root directory. Defaults to `process.cwd()`. */
5
+ cwd?: string;
6
+ /** Output directory. Defaults to `{cwd}/dist`. */
7
+ outDir?: string;
8
+ /** Extra packages to mark as external in addition to `node:*`, `davaux`, and `@davaux/multisite`. */
9
+ external?: string[];
10
+ /**
11
+ * Davaux plugins to apply during the build — contributes esbuild transforms and scanner
12
+ * suffix extensions. Use the same plugins here as in your `davaux.config.ts`.
13
+ *
14
+ * @example
15
+ * import { mdx } from '@davaux/mdx'
16
+ * await buildMultisite(sites, { cwd: import.meta.dirname, plugins: [mdx()] })
17
+ */
18
+ plugins?: DavauxPlugin[];
19
+ /**
20
+ * tsconfig-style path aliases forwarded to esbuild `alias`. Same format as
21
+ * `compilerOptions.paths` — e.g. `{ '~/*': ['./src/*'] }`.
22
+ */
23
+ paths?: Record<string, string>;
24
+ }
25
+ /**
26
+ * Compile a multisite project to JavaScript.
27
+ *
28
+ * Reads route and island directories directly from the `MultisiteConfig` so the
29
+ * config is the single source of truth. Discovers and compiles all route, layout,
30
+ * middleware, and error-page files, per-site client island bundles, plus
31
+ * `server.ts` / `multisite.config.ts` if they exist at the project root.
32
+ *
33
+ * Requires `esbuild` to be installed (it is present in any project that
34
+ * depends on `davaux`).
35
+ *
36
+ * @example
37
+ * // build.ts
38
+ * import { buildMultisite } from '@davaux/multisite/build'
39
+ * import { sites } from './multisite.config.js'
40
+ *
41
+ * await buildMultisite(sites, { cwd: import.meta.dirname })
42
+ */
43
+ export declare function buildMultisite<T>(config: MultisiteConfig<T>, options?: BuildMultisiteOptions): Promise<void>;
44
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,YAAY,EAElB,MAAM,eAAe,CAAA;AAEtB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,MAAM,WAAW,qBAAqB;IACpC,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,qGAAqG;IACrG,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;IACxB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,EAC1B,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CA8Hf"}
package/dist/build.js ADDED
@@ -0,0 +1,136 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { collectCss, generateIslandsEntry, islandServerPlugin } from 'davaux/build';
4
+ import { collectEsbuildPlugins, collectScannerSuffixes, pathsToAlias, } from 'davaux/config';
5
+ import { scanIslands, scanRoutes } from 'davaux/scanner';
6
+ /**
7
+ * Compile a multisite project to JavaScript.
8
+ *
9
+ * Reads route and island directories directly from the `MultisiteConfig` so the
10
+ * config is the single source of truth. Discovers and compiles all route, layout,
11
+ * middleware, and error-page files, per-site client island bundles, plus
12
+ * `server.ts` / `multisite.config.ts` if they exist at the project root.
13
+ *
14
+ * Requires `esbuild` to be installed (it is present in any project that
15
+ * depends on `davaux`).
16
+ *
17
+ * @example
18
+ * // build.ts
19
+ * import { buildMultisite } from '@davaux/multisite/build'
20
+ * import { sites } from './multisite.config.js'
21
+ *
22
+ * await buildMultisite(sites, { cwd: import.meta.dirname })
23
+ */
24
+ export async function buildMultisite(config, options = {}) {
25
+ const { build } = await import('esbuild');
26
+ const cwd = options.cwd ?? process.cwd();
27
+ const outDir = options.outDir ?? resolve(cwd, 'dist');
28
+ const davauxPlugins = options.plugins ?? [];
29
+ const extraSuffixes = [...(config.extraSuffixes ?? []), ...collectScannerSuffixes(davauxPlugins)];
30
+ const userAlias = pathsToAlias(options.paths ?? {});
31
+ // All island directories (for the server-side island plugin)
32
+ const allIslandDirs = [
33
+ ...(config.islandsDir ? [config.islandsDir] : []),
34
+ ...config.sites.flatMap((s) => (s.islandsDir ? [s.islandsDir] : [])),
35
+ ];
36
+ // Collect route directories directly from config — no re-discovery needed
37
+ const routeDirs = [];
38
+ if (config.baseDir)
39
+ routeDirs.push(config.baseDir);
40
+ for (const site of config.sites) {
41
+ if (site.routesDir)
42
+ routeDirs.push(site.routesDir);
43
+ }
44
+ // Scan for compilable files in each routes directory
45
+ const routeFiles = [];
46
+ for (const dir of routeDirs) {
47
+ if (!existsSync(dir))
48
+ continue;
49
+ const { routes, layouts, middlewares, errorPage } = await scanRoutes(dir, extraSuffixes);
50
+ routeFiles.push(...routes.map((r) => r.filePath), ...layouts.map((l) => l.filePath), ...middlewares.map((m) => m.filePath), ...(errorPage ? [errorPage] : []));
51
+ }
52
+ // Include server.ts and multisite.config.ts at the project root if present
53
+ const entryPoints = [...routeFiles];
54
+ for (const name of ['server.ts', 'multisite.config.ts']) {
55
+ const p = resolve(cwd, name);
56
+ if (existsSync(p))
57
+ entryPoints.push(p);
58
+ }
59
+ const baseExternal = ['node:*', 'davaux', '@davaux/multisite', ...(options.external ?? [])];
60
+ // Include src/middleware.ts if present (app-level middleware runs before route matching)
61
+ const middlewareSrc = resolve(cwd, 'src', 'middleware.ts');
62
+ if (existsSync(middlewareSrc))
63
+ entryPoints.push(middlewareSrc);
64
+ // Compile routes (with island server wrapping + plugin transforms)
65
+ await build({
66
+ entryPoints,
67
+ outdir: outDir,
68
+ outbase: cwd,
69
+ format: 'esm',
70
+ platform: 'node',
71
+ target: 'node22',
72
+ bundle: true,
73
+ jsx: 'automatic',
74
+ jsxImportSource: 'davaux',
75
+ external: baseExternal,
76
+ sourcemap: true,
77
+ alias: { ...userAlias, 'davaux/client': 'davaux/signal' },
78
+ plugins: [
79
+ ...(allIslandDirs.length > 0 ? [islandServerPlugin(allIslandDirs)] : []),
80
+ ...collectEsbuildPlugins(davauxPlugins),
81
+ ],
82
+ });
83
+ // Collect CSS side-effect outputs into dist/_davaux/styles.css
84
+ const stylesOutFile = join(outDir, '_davaux', 'styles.css');
85
+ await collectCss(outDir, stylesOutFile);
86
+ // Compile per-site client island bundles to dist/_davaux/<name>/islands.js
87
+ const baseIslands = config.islandsDir ? await scanIslands(config.islandsDir) : [];
88
+ let islandBundles = 0;
89
+ for (const site of config.sites) {
90
+ const siteIslands = site.islandsDir ? await scanIslands(site.islandsDir) : [];
91
+ const allIslands = [...baseIslands, ...siteIslands];
92
+ if (allIslands.length === 0)
93
+ continue;
94
+ await build({
95
+ stdin: {
96
+ contents: generateIslandsEntry(allIslands),
97
+ loader: 'ts',
98
+ resolveDir: cwd,
99
+ },
100
+ outfile: join(outDir, '_davaux', site.name, 'islands.js'),
101
+ format: 'esm',
102
+ platform: 'browser',
103
+ target: 'es2022',
104
+ bundle: true,
105
+ jsx: 'automatic',
106
+ jsxImportSource: 'davaux/client',
107
+ sourcemap: true,
108
+ alias: userAlias,
109
+ plugins: collectEsbuildPlugins(davauxPlugins),
110
+ });
111
+ islandBundles++;
112
+ }
113
+ // Compile per-site client bundles to dist/_davaux/<name>/client.js
114
+ let clientBundles = 0;
115
+ for (const site of config.sites) {
116
+ const clientEntry = site.clientEntry ?? config.clientEntry;
117
+ if (!clientEntry || !existsSync(clientEntry))
118
+ continue;
119
+ await build({
120
+ entryPoints: [clientEntry],
121
+ outfile: join(outDir, '_davaux', site.name, 'client.js'),
122
+ format: 'esm',
123
+ platform: 'browser',
124
+ target: 'es2022',
125
+ bundle: true,
126
+ jsx: 'automatic',
127
+ jsxImportSource: 'davaux/client',
128
+ sourcemap: true,
129
+ alias: userAlias,
130
+ plugins: collectEsbuildPlugins(davauxPlugins),
131
+ });
132
+ clientBundles++;
133
+ }
134
+ console.log(`[davaux/multisite] Built ${routeFiles.length} route file(s), ${islandBundles} island bundle(s), ${clientBundles} client bundle(s)`);
135
+ }
136
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,202 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { createServer } from 'node:http';
3
+ import type { RequestContext, RouteType, ScanResult } from 'davaux';
4
+ import { type DavauxPlugin } from 'davaux/config';
5
+ import type { CompiledApp } from 'davaux/handler';
6
+ export interface SiteDefinition<T = Record<string, unknown>> {
7
+ /** Unique name for this site. Used in logging. */
8
+ name: string;
9
+ /**
10
+ * Hostname(s) that route to this site. Supply `'*'` as a catch-all fallback.
11
+ * Port is stripped before matching, so `'example.com'` matches both
12
+ * `example.com` and `example.com:3000`.
13
+ */
14
+ hostname: string | string[];
15
+ /**
16
+ * Absolute path to the site-specific routes directory. Routes here are
17
+ * overlaid on top of `baseDir`: same URL pattern + type in the overlay wins.
18
+ * Omit to run the base routes without any site-specific overrides.
19
+ */
20
+ routesDir?: string;
21
+ /**
22
+ * Absolute path to the site-specific islands directory. Islands here are
23
+ * merged with those in `MultisiteConfig.islandsDir` for this site's client bundle.
24
+ */
25
+ islandsDir?: string;
26
+ /**
27
+ * Absolute path to the site-specific public directory. Static files here are
28
+ * served at their URL path before route dispatch, taking priority over the
29
+ * shared `publicDir` when both contain a file at the same path.
30
+ */
31
+ publicDir?: string;
32
+ /**
33
+ * Absolute path to a site-specific client-side entry file. Overrides
34
+ * `MultisiteConfig.clientEntry` for this site when set.
35
+ */
36
+ clientEntry?: string;
37
+ /** Arbitrary per-site config — accessible via `getSite<T>(ctx)` in any handler, layout, or middleware. */
38
+ config?: T;
39
+ }
40
+ export interface MultisiteConfig<T = Record<string, unknown>> {
41
+ /** Absolute path to the shared base routes directory. */
42
+ baseDir?: string;
43
+ /** Absolute path to the shared islands directory. Islands here are included in every site's client bundle. */
44
+ islandsDir?: string;
45
+ /** Absolute path to the shared public directory. Static files are served at their URL path before route dispatch. */
46
+ publicDir?: string;
47
+ /**
48
+ * Absolute path to a shared client-side entry file compiled to `/_davaux/client.js` and
49
+ * injected into every page. Per-site `clientEntry` overrides this when set.
50
+ */
51
+ clientEntry?: string;
52
+ /** Site definitions — one entry per hostname (or hostname group). */
53
+ sites: SiteDefinition<T>[];
54
+ /** Extra route suffixes forwarded from plugins (e.g. `[['.page.md', 'page']]`). */
55
+ extraSuffixes?: [string, RouteType][];
56
+ }
57
+ export interface BuildOptions {
58
+ isDev?: boolean;
59
+ clientScripts?: string[];
60
+ clientStylesheets?: string[];
61
+ basePath?: string;
62
+ /** Absolute path to a compiled app-level middleware file (runs before route matching on every request). */
63
+ appMiddlewarePath?: string;
64
+ /**
65
+ * Absolute path to the `src/middleware.ts` source file. In dev mode it is
66
+ * compiled alongside route files and used as `appMiddlewarePath`.
67
+ * `startMultisite` auto-detects `<cwd>/src/middleware.ts` when `cwd` is set.
68
+ */
69
+ middlewareSrc?: string;
70
+ /**
71
+ * Absolute path to the project root — used in dev mode to locate the esbuild
72
+ * temp directory (`.davaux-multisite/`). Defaults to `process.cwd()`.
73
+ * Pass `import.meta.dirname` from your `server.ts` for reliable resolution.
74
+ */
75
+ cwd?: string;
76
+ /**
77
+ * Davaux plugins to apply — contributes esbuild transforms and scanner suffix
78
+ * extensions. Use the same list here as in `buildMultisite`.
79
+ *
80
+ * @example
81
+ * import { mdx } from '@davaux/mdx'
82
+ * startMultisite(sites, { plugins: [mdx()] })
83
+ */
84
+ plugins?: DavauxPlugin[];
85
+ /**
86
+ * tsconfig-style path aliases forwarded to esbuild `alias` in every build context.
87
+ * Same format as `compilerOptions.paths` — use `{ '~/*': ['./src/*'] }`.
88
+ */
89
+ paths?: Record<string, string>;
90
+ /**
91
+ * Extra packages to mark as external beyond the defaults (`node:*`, `davaux`,
92
+ * `@davaux/multisite`). Useful for native or CJS-only packages like `canvas` or
93
+ * `better-sqlite3`.
94
+ */
95
+ external?: string[];
96
+ }
97
+ export interface ServerOptions {
98
+ port?: number;
99
+ hostname?: string;
100
+ }
101
+ export interface StartMultisiteOptions extends BuildOptions, ServerOptions {
102
+ }
103
+ interface SiteEntry<T> {
104
+ app: CompiledApp;
105
+ config: T | undefined;
106
+ /** Absolute path to the compiled client islands bundle, if any. */
107
+ islandsPath?: string;
108
+ /** Absolute path to the compiled CSS stylesheet, if any. */
109
+ stylesPath?: string;
110
+ /** Absolute path to the compiled client entry bundle, if any. */
111
+ clientPath?: string;
112
+ /** Ordered list of public directories to serve static files from (per-site first, then shared). */
113
+ publicDirs: string[];
114
+ }
115
+ /**
116
+ * Merge a site-specific `ScanResult` on top of a base `ScanResult`.
117
+ *
118
+ * - **Routes**: overlay wins at the same `urlPattern + type`. The merged list
119
+ * is re-sorted so static routes still precede dynamic ones.
120
+ * - **Layouts**: overlay wins at the same `dirPath` (directory-level override).
121
+ * Layouts in directories unique to either tree are kept as-is.
122
+ * - **Middlewares**: overlay wins at the same `dirPath`. Middlewares unique to
123
+ * the base still run; overlapping ones are replaced by the site version.
124
+ * - **Error page**: overlay wins if present, otherwise falls back to base.
125
+ */
126
+ export declare function mergeScanResults(base: ScanResult, overlay: ScanResult): ScanResult;
127
+ /** Identity function — returns config unchanged. Provides TypeScript inference for the site config type `T`. */
128
+ export declare function defineSites<T = Record<string, unknown>>(config: MultisiteConfig<T>): MultisiteConfig<T>;
129
+ /**
130
+ * Scan all site route directories, merge each with the shared base, and return
131
+ * a per-hostname map of compiled apps ready for dispatch.
132
+ *
133
+ * In dev mode (`isDev: true`), all route files are compiled with esbuild
134
+ * (applying plugin transforms and wrapping island imports server-side) and
135
+ * per-site client island bundles are built before the server starts.
136
+ *
137
+ * @example
138
+ * const apps = await buildMultisiteApps(sites, { isDev: true, cwd: import.meta.dirname })
139
+ * startMultisiteServer(apps, { port: 3000 })
140
+ */
141
+ export declare function buildMultisiteApps<T = Record<string, unknown>>(config: MultisiteConfig<T>, options?: BuildOptions): Promise<Map<string, SiteEntry<T>>>;
142
+ /**
143
+ * Start an HTTP server that dispatches each request to the matching site by
144
+ * hostname. Falls back to the `'*'` entry if the hostname is not explicitly
145
+ * registered. Responds 404 if neither matches.
146
+ *
147
+ * `sites` may be a `() => Map` factory so the caller can hot-swap compiled apps
148
+ * in dev mode without restarting the server.
149
+ */
150
+ export declare function startMultisiteServer<T = Record<string, unknown>>(sites: Map<string, SiteEntry<T>> | (() => Map<string, SiteEntry<T>>), options?: ServerOptions): ReturnType<typeof createServer>;
151
+ /**
152
+ * Look up the correct site by the request's `host` header, inject the site
153
+ * config into the WeakMap, and dispatch the request. Returns `false` if no
154
+ * site is registered for the host (including the `'*'` fallback).
155
+ *
156
+ * Useful for embedding multisite dispatch into a custom server or for testing
157
+ * without spinning up a real HTTP server.
158
+ *
159
+ * @example
160
+ * const server = createServer(async (req, res) => {
161
+ * const handled = await dispatchToSite(sites, req, res)
162
+ * if (!handled) { res.writeHead(404); res.end('No site') }
163
+ * })
164
+ */
165
+ export declare function dispatchToSite<T = Record<string, unknown>>(sites: Map<string, SiteEntry<T>>, req: IncomingMessage, res: ServerResponse): Promise<boolean>;
166
+ /**
167
+ * Start a multisite dev server with file watching, live reload, and TypeScript type checking.
168
+ * Called automatically by `startMultisite` when `NODE_ENV !== 'production'`.
169
+ */
170
+ export declare function startMultisiteDev<T = Record<string, unknown>>(config: MultisiteConfig<T>, options?: StartMultisiteOptions): Promise<ReturnType<typeof createServer>>;
171
+ /**
172
+ * Build and start a multisite server in one call.
173
+ *
174
+ * Combines `buildMultisiteApps` and `startMultisiteServer`. Automatically sets
175
+ * `isDev` from `NODE_ENV` unless explicitly provided — `true` in development
176
+ * (cache-busting for TypeScript routes), `false` in production.
177
+ *
178
+ * @example
179
+ * // server.ts
180
+ * import { startMultisite } from '@davaux/multisite'
181
+ * import { sites } from './multisite.config.js'
182
+ *
183
+ * startMultisite(sites, { port: 3000, hostname: 'localhost' })
184
+ */
185
+ export declare function startMultisite<T = Record<string, unknown>>(config: MultisiteConfig<T>, options?: StartMultisiteOptions): Promise<ReturnType<typeof createServer>>;
186
+ /**
187
+ * Retrieve the current site's config from a request context.
188
+ *
189
+ * Returns `undefined` when called outside of a multisite server (e.g. in tests
190
+ * using a single-site `startServer`).
191
+ *
192
+ * @example
193
+ * import { getSite } from '@davaux/multisite'
194
+ *
195
+ * export default definePage((ctx) => {
196
+ * const site = getSite<MySiteConfig>(ctx)
197
+ * return <Layout theme={site?.theme}>...</Layout>
198
+ * })
199
+ */
200
+ export declare function getSite<T = Record<string, unknown>>(ctx: RequestContext): T | undefined;
201
+ export {};
202
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}