@remix-run/assets 0.4.4 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +322 -56
  2. package/dist/assets.d.ts +2 -1
  3. package/dist/assets.d.ts.map +1 -1
  4. package/dist/assets.js +2 -2
  5. package/dist/lib/access.d.ts +6 -2
  6. package/dist/lib/access.d.ts.map +1 -1
  7. package/dist/lib/access.js +300 -5
  8. package/dist/lib/asset-server.d.ts +118 -5
  9. package/dist/lib/asset-server.d.ts.map +1 -1
  10. package/dist/lib/asset-server.js +260 -24
  11. package/dist/lib/compilation-error.d.ts +1 -1
  12. package/dist/lib/compilation-error.d.ts.map +1 -1
  13. package/dist/lib/file-matcher.js +1 -1
  14. package/dist/lib/files/compiler.d.ts.map +1 -1
  15. package/dist/lib/files/compiler.js +7 -6
  16. package/dist/lib/files/config.js +1 -1
  17. package/dist/lib/hmr.d.ts +37 -0
  18. package/dist/lib/hmr.d.ts.map +1 -0
  19. package/dist/lib/hmr.js +357 -0
  20. package/dist/lib/injected-packages.d.ts.map +1 -1
  21. package/dist/lib/injected-packages.js +36 -13
  22. package/dist/lib/loaders.d.ts +57 -0
  23. package/dist/lib/loaders.d.ts.map +1 -0
  24. package/dist/lib/loaders.js +1 -0
  25. package/dist/lib/module-store.d.ts +24 -0
  26. package/dist/lib/module-store.d.ts.map +1 -1
  27. package/dist/lib/module-store.js +136 -11
  28. package/dist/lib/routes.js +1 -1
  29. package/dist/lib/scripts/compiler.d.ts +24 -1
  30. package/dist/lib/scripts/compiler.d.ts.map +1 -1
  31. package/dist/lib/scripts/compiler.js +183 -29
  32. package/dist/lib/scripts/conditions.d.ts +2 -0
  33. package/dist/lib/scripts/conditions.d.ts.map +1 -0
  34. package/dist/lib/scripts/conditions.js +1 -0
  35. package/dist/lib/scripts/emit.d.ts +3 -0
  36. package/dist/lib/scripts/emit.d.ts.map +1 -1
  37. package/dist/lib/scripts/emit.js +24 -5
  38. package/dist/lib/scripts/resolve.d.ts +4 -0
  39. package/dist/lib/scripts/resolve.d.ts.map +1 -1
  40. package/dist/lib/scripts/resolve.js +70 -5
  41. package/dist/lib/scripts/transform.d.ts +9 -0
  42. package/dist/lib/scripts/transform.d.ts.map +1 -1
  43. package/dist/lib/scripts/transform.js +222 -18
  44. package/dist/lib/source-maps.js +1 -1
  45. package/dist/lib/styles/compiler.d.ts +14 -1
  46. package/dist/lib/styles/compiler.d.ts.map +1 -1
  47. package/dist/lib/styles/compiler.js +78 -14
  48. package/dist/lib/styles/emit.js +4 -4
  49. package/dist/lib/styles/resolve.d.ts.map +1 -1
  50. package/dist/lib/styles/resolve.js +8 -7
  51. package/dist/lib/styles/transform.js +3 -3
  52. package/dist/lib/target.d.ts +1 -1
  53. package/dist/lib/target.d.ts.map +1 -1
  54. package/dist/lib/watch.js +1 -1
  55. package/dist/types/hmr.d.ts +36 -0
  56. package/package.json +17 -11
  57. package/src/assets.ts +2 -1
  58. package/src/lib/access.ts +386 -5
  59. package/src/lib/asset-server.ts +429 -18
  60. package/src/lib/compilation-error.ts +1 -0
  61. package/src/lib/files/compiler.ts +7 -3
  62. package/src/lib/hmr.ts +397 -0
  63. package/src/lib/injected-packages.ts +41 -11
  64. package/src/lib/loaders.ts +80 -0
  65. package/src/lib/module-store.ts +190 -9
  66. package/src/lib/scripts/compiler.ts +248 -24
  67. package/src/lib/scripts/conditions.ts +1 -0
  68. package/src/lib/scripts/emit.ts +50 -5
  69. package/src/lib/scripts/resolve.ts +124 -2
  70. package/src/lib/scripts/transform.ts +290 -19
  71. package/src/lib/styles/compiler.ts +108 -8
  72. package/src/lib/styles/emit.ts +1 -1
  73. package/src/lib/styles/resolve.ts +11 -7
  74. package/src/types/hmr.d.ts +36 -0
@@ -1,17 +1,312 @@
1
- import { createFileMatcher } from "./file-matcher.js";
2
- import { isInjectedPackageFilePath } from "./injected-packages.js";
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { createFileMatcher } from './file-matcher.js';
4
+ import { isInjectedPackageFilePath } from './injected-packages.js';
5
+ import { normalizeFilePath } from './paths.js';
6
+ const packageStateFileNames = new Set([
7
+ 'bun.lock',
8
+ 'bun.lockb',
9
+ 'npm-shrinkwrap.json',
10
+ 'package-lock.json',
11
+ 'pnpm-lock.yaml',
12
+ 'pnpm-workspace.yaml',
13
+ 'yarn.lock',
14
+ ]);
15
+ const packageManagerRootFileNames = packageStateFileNames;
16
+ const packageNamePartPattern = /^[A-Za-z0-9._~-]+$/;
3
17
  export function createAccessPolicy(options) {
4
- let allowMatchers = options.allow.map((pattern) => createFileMatcher(pattern, options.rootDir));
5
- let denyMatchers = (options.deny ?? []).map((pattern) => createFileMatcher(pattern, options.rootDir));
18
+ let allowMatchers = options.allowFiles.map((pattern) => createFileMatcher(pattern, options.rootDir));
19
+ let allowPackageNames = normalizePackageNames(options.allowPackages, 'allowPackages');
20
+ let denyMatchers = (options.denyFiles ?? []).map((pattern) => createFileMatcher(pattern, options.rootDir));
21
+ let packageSearchRoots = [options.rootDir, ...(options.packageSearchRoots ?? [])];
22
+ let packageRootPaths = createPackageRootPaths({
23
+ allowPackageNames,
24
+ searchRoots: packageSearchRoots,
25
+ });
26
+ let allowPackageRootPathTrie = createPackageRootPathTrie(packageRootPaths);
27
+ let packageStateDirectories = allowPackageNames.size === 0 ? [] : getPackageStateDirectories(packageSearchRoots);
28
+ let packageRootsDirty = false;
29
+ function refreshPackageRootPathTries() {
30
+ if (!packageRootsDirty)
31
+ return;
32
+ packageRootPaths = createPackageRootPaths({
33
+ allowPackageNames,
34
+ searchRoots: packageSearchRoots,
35
+ });
36
+ allowPackageRootPathTrie = createPackageRootPathTrie(packageRootPaths);
37
+ packageRootsDirty = false;
38
+ }
39
+ function isAllowedPackage(filePath) {
40
+ if (allowPackageNames.size === 0)
41
+ return false;
42
+ refreshPackageRootPathTries();
43
+ return isPathInPackageRootPathTrie(filePath, allowPackageRootPathTrie);
44
+ }
6
45
  return {
46
+ getPackageWatchDirectories() {
47
+ if (allowPackageNames.size === 0)
48
+ return [];
49
+ return packageStateDirectories;
50
+ },
51
+ handleFileEvent(filePath) {
52
+ if (allowPackageNames.size === 0)
53
+ return;
54
+ if (!isPackageStateFileEvent(filePath, packageStateDirectories))
55
+ return;
56
+ packageRootsDirty = true;
57
+ },
7
58
  isAllowed(filePath) {
8
59
  if (isInjectedPackageFilePath(filePath))
9
60
  return true;
10
- if (!allowMatchers.some((matcher) => matcher(filePath)))
61
+ if (!allowMatchers.some((matcher) => matcher(filePath)) && !isAllowedPackage(filePath)) {
11
62
  return false;
63
+ }
12
64
  if (denyMatchers.length > 0 && denyMatchers.some((matcher) => matcher(filePath)))
13
65
  return false;
14
66
  return true;
15
67
  },
16
68
  };
17
69
  }
70
+ function normalizePackageNames(packageOption, optionName) {
71
+ let packageNames = new Set();
72
+ for (let packageName of packageOption ?? []) {
73
+ if (typeof packageName !== 'string') {
74
+ throw new TypeError(`${optionName} values must be strings`);
75
+ }
76
+ let normalizedPackageName = packageName.trim();
77
+ if (!isValidPackageName(normalizedPackageName)) {
78
+ throw new TypeError(`${optionName} values must be package names. Received "${packageName}".`);
79
+ }
80
+ packageNames.add(normalizedPackageName);
81
+ }
82
+ return packageNames;
83
+ }
84
+ function validatePackageName(packageName, message) {
85
+ if (!isValidPackageName(packageName)) {
86
+ throw new TypeError(message);
87
+ }
88
+ }
89
+ function createPackageRootPaths(options) {
90
+ let allowPackageRootPaths = new Set();
91
+ let allowQueue = [];
92
+ let seenAllowedPackageRoots = new Set();
93
+ let searchRoots = normalizePackageSearchRoots(options.searchRoots);
94
+ for (let packageName of options.allowPackageNames) {
95
+ let foundPackage = false;
96
+ for (let searchRoot of searchRoots) {
97
+ let packageJsonPath = findPackageJsonPath(packageName, searchRoot);
98
+ if (packageJsonPath === null)
99
+ continue;
100
+ foundPackage = true;
101
+ allowQueue.push({ packageJsonPath, packageName });
102
+ }
103
+ if (!foundPackage) {
104
+ throw new TypeError(`Could not resolve allowed package "${packageName}".`);
105
+ }
106
+ }
107
+ while (allowQueue.length > 0) {
108
+ let { packageJsonPath } = allowQueue.shift();
109
+ let packageRootPath = normalizeFilePath(path.dirname(packageJsonPath));
110
+ if (seenAllowedPackageRoots.has(packageRootPath))
111
+ continue;
112
+ seenAllowedPackageRoots.add(packageRootPath);
113
+ let packageJson = readPackageJson(packageJsonPath);
114
+ allowPackageRootPaths.add(packageRootPath);
115
+ for (let dependencyName of Object.keys(packageJson.dependencies ?? {})) {
116
+ validatePackageName(dependencyName, `Dependency "${dependencyName}" from ${packageJsonPath} must be a package name.`);
117
+ let dependencyPackageJsonPath = findPackageJsonPath(dependencyName, packageRootPath);
118
+ if (dependencyPackageJsonPath === null) {
119
+ throw new TypeError(`Could not resolve dependency "${dependencyName}" from ${packageJsonPath}.`);
120
+ }
121
+ allowQueue.push({
122
+ packageJsonPath: dependencyPackageJsonPath,
123
+ packageName: dependencyName,
124
+ });
125
+ }
126
+ for (let dependencyName of Object.keys(packageJson.optionalDependencies ?? {})) {
127
+ validatePackageName(dependencyName, `Optional dependency "${dependencyName}" from ${packageJsonPath} must be a package name.`);
128
+ let dependencyPackageJsonPath = findPackageJsonPath(dependencyName, packageRootPath);
129
+ if (dependencyPackageJsonPath !== null) {
130
+ allowQueue.push({
131
+ packageJsonPath: dependencyPackageJsonPath,
132
+ packageName: dependencyName,
133
+ });
134
+ }
135
+ }
136
+ }
137
+ return allowPackageRootPaths;
138
+ }
139
+ function createPackageRootPathTrie(packageRootPaths) {
140
+ let rootNode = createPackageRootPathTrieNode();
141
+ for (let packageRootPath of packageRootPaths) {
142
+ let node = rootNode;
143
+ for (let segment of getFilePathSegments(packageRootPath)) {
144
+ let childNode = node.children.get(segment);
145
+ if (!childNode) {
146
+ childNode = createPackageRootPathTrieNode();
147
+ node.children.set(segment, childNode);
148
+ }
149
+ node = childNode;
150
+ }
151
+ node.packageRoot = true;
152
+ }
153
+ return rootNode;
154
+ }
155
+ function createPackageRootPathTrieNode() {
156
+ return {
157
+ children: new Map(),
158
+ packageRoot: false,
159
+ };
160
+ }
161
+ function isPathInPackageRootPathTrie(filePath, trie) {
162
+ let node = trie;
163
+ if (node.packageRoot)
164
+ return true;
165
+ for (let segment of getFilePathSegments(filePath)) {
166
+ let childNode = node.children.get(segment);
167
+ if (!childNode)
168
+ return false;
169
+ if (childNode.packageRoot)
170
+ return true;
171
+ node = childNode;
172
+ }
173
+ return false;
174
+ }
175
+ function getFilePathSegments(filePath) {
176
+ return normalizeFilePath(filePath).split('/');
177
+ }
178
+ function normalizePackageSearchRoots(searchRoots) {
179
+ let normalizedSearchRoots = new Set();
180
+ for (let searchRoot of searchRoots) {
181
+ let normalizedSearchRoot = normalizeFilePath(searchRoot);
182
+ normalizedSearchRoots.add(normalizedSearchRoot);
183
+ if (path.basename(normalizedSearchRoot) === 'node_modules') {
184
+ normalizedSearchRoots.add(path.dirname(normalizedSearchRoot));
185
+ }
186
+ }
187
+ return [...normalizedSearchRoots];
188
+ }
189
+ function getPackageStateDirectories(searchRoots) {
190
+ let packageStateDirectories = new Set();
191
+ for (let searchRoot of searchRoots) {
192
+ let packageManagerRoot = findPackageManagerRoot(searchRoot);
193
+ if (packageManagerRoot !== null) {
194
+ packageStateDirectories.add(packageManagerRoot);
195
+ }
196
+ }
197
+ return [...packageStateDirectories];
198
+ }
199
+ function isPackageStateFileEvent(filePath, packageStateDirectories) {
200
+ let normalizedFilePath = normalizeFilePath(filePath);
201
+ let fileName = path.basename(normalizedFilePath);
202
+ if (!packageStateFileNames.has(fileName))
203
+ return false;
204
+ let directory = path.dirname(normalizedFilePath);
205
+ return packageStateDirectories.some((packageStateDirectory) => directory === packageStateDirectory);
206
+ }
207
+ function findPackageManagerRoot(startDirectory) {
208
+ let directory = normalizePackageStateSearchRoot(startDirectory);
209
+ while (true) {
210
+ if (hasPackageManagerRootFile(directory))
211
+ return directory;
212
+ let parentDirectory = path.dirname(directory);
213
+ if (parentDirectory === directory)
214
+ return null;
215
+ directory = parentDirectory;
216
+ }
217
+ }
218
+ function normalizePackageStateSearchRoot(searchRoot) {
219
+ let normalizedSearchRoot = normalizeFilePath(searchRoot);
220
+ return path.basename(normalizedSearchRoot) === 'node_modules'
221
+ ? path.dirname(normalizedSearchRoot)
222
+ : normalizedSearchRoot;
223
+ }
224
+ function hasPackageManagerRootFile(directory) {
225
+ for (let fileName of packageManagerRootFileNames) {
226
+ try {
227
+ let stat = fs.statSync(path.join(directory, fileName));
228
+ if (stat.isFile())
229
+ return true;
230
+ }
231
+ catch (error) {
232
+ if (isPathNotFoundError(error))
233
+ continue;
234
+ throw error;
235
+ }
236
+ }
237
+ return false;
238
+ }
239
+ function findPackageJsonPath(packageName, startDirectory) {
240
+ let directory = normalizeFilePath(startDirectory);
241
+ while (true) {
242
+ let packageJsonPath = resolvePackageJsonPath(directory, packageName);
243
+ if (packageJsonPath !== null)
244
+ return packageJsonPath;
245
+ let parentDirectory = path.dirname(directory);
246
+ if (parentDirectory === directory)
247
+ return null;
248
+ directory = parentDirectory;
249
+ }
250
+ }
251
+ function resolvePackageJsonPath(directory, packageName) {
252
+ let packagePath = path.basename(directory) === 'node_modules'
253
+ ? path.join(directory, packageName, 'package.json')
254
+ : path.join(directory, 'node_modules', packageName, 'package.json');
255
+ try {
256
+ return normalizeFilePath(fs.realpathSync(packagePath));
257
+ }
258
+ catch (error) {
259
+ if (isPathNotFoundError(error))
260
+ return null;
261
+ throw error;
262
+ }
263
+ }
264
+ function readPackageJson(packageJsonPath) {
265
+ let packageJson;
266
+ try {
267
+ packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
268
+ }
269
+ catch (error) {
270
+ if (isPathNotFoundError(error))
271
+ return {};
272
+ throw error;
273
+ }
274
+ if (packageJson === null || typeof packageJson !== 'object') {
275
+ return {};
276
+ }
277
+ return {
278
+ dependencies: readDependencyMap(packageJson, 'dependencies'),
279
+ optionalDependencies: readDependencyMap(packageJson, 'optionalDependencies'),
280
+ };
281
+ }
282
+ function readDependencyMap(packageJson, key) {
283
+ if (!(key in packageJson))
284
+ return undefined;
285
+ let value = packageJson[key];
286
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
287
+ return undefined;
288
+ }
289
+ let dependencies = {};
290
+ for (let [dependencyName, dependencyVersion] of Object.entries(value)) {
291
+ if (typeof dependencyVersion === 'string') {
292
+ dependencies[dependencyName] = dependencyVersion;
293
+ }
294
+ }
295
+ return dependencies;
296
+ }
297
+ function isValidPackageName(packageName) {
298
+ if (packageName.length === 0)
299
+ return false;
300
+ let packageNameParts = packageName.startsWith('@')
301
+ ? packageName.slice(1).split('/')
302
+ : packageName.split('/');
303
+ if (packageNameParts.length !== (packageName.startsWith('@') ? 2 : 1))
304
+ return false;
305
+ return packageNameParts.every((part) => part.length > 0 && part !== '.' && part !== '..' && packageNamePartPattern.test(part));
306
+ }
307
+ function isPathNotFoundError(error) {
308
+ return (error instanceof Error &&
309
+ 'code' in error &&
310
+ (error.code === 'ENOENT' ||
311
+ error.code === 'ENOTDIR'));
312
+ }
@@ -1,4 +1,7 @@
1
1
  import type { AssetRequestTransformMap, AssetServerFilesOptions, AssetTransformInvocation } from './files/config.ts';
2
+ import type { HmrPayload } from './hmr.ts';
3
+ import type { ModuleLoader } from './loaders.ts';
4
+ import type { ScriptHmrUpdate } from './scripts/compiler.ts';
2
5
  import type { AssetTarget } from './target.ts';
3
6
  import type { ChokidarWatcher } from './watch.ts';
4
7
  interface AssetServerWatchOptions {
@@ -16,6 +19,88 @@ interface AssetServerWatchOptions {
16
19
  */
17
20
  pollInterval?: number;
18
21
  }
22
+ /**
23
+ * Bridge used by an asset server to watch browser source files and publish update events through a
24
+ * server-level HMR runtime.
25
+ *
26
+ * The asset server registers its file handler, keeps the channel's watched-file set in sync with
27
+ * compiled assets, injects `url` into its browser HMR client, and closes the channel when the asset
28
+ * server closes.
29
+ */
30
+ export interface BrowserHmrChannel {
31
+ /** Absolute EventSource URL that receives the browser HMR events produced by this channel. */
32
+ readonly url: string;
33
+ /** Releases the channel and all file-watching resources it owns. */
34
+ close(): void;
35
+ /**
36
+ * Registers the asset server's handler for file changes reported by the channel's watcher.
37
+ *
38
+ * @param handler Callback that converts a batch of file changes into browser update or reload
39
+ * events.
40
+ * @returns A cleanup function that stops forwarding file changes to this handler.
41
+ */
42
+ onFileEvents(handler: BrowserHmrFileEventHandler): () => void;
43
+ /**
44
+ * Applies additions and removals to the channel's set of watched absolute file paths.
45
+ *
46
+ * @param delta Files to add and remove from the watcher.
47
+ */
48
+ updateWatchedFiles(delta: BrowserHmrWatchedFileDelta): void;
49
+ }
50
+ /**
51
+ * Creates the browser HMR channel owned by an asset server instance.
52
+ *
53
+ * Returning `undefined` leaves browser HMR inactive. The asset server invokes this factory once,
54
+ * after construction, and closes a returned channel from `assetServer.close()`.
55
+ *
56
+ * @returns A channel, no channel, or a promise for either result.
57
+ */
58
+ export type BrowserHmrChannelFactory = () => BrowserHmrChannel | undefined | Promise<BrowserHmrChannel | undefined>;
59
+ /**
60
+ * Converts a watcher batch into ordered browser update or reload events.
61
+ *
62
+ * @param events File additions, changes, and removals reported together by the watcher.
63
+ * @returns Browser events to publish in their returned order.
64
+ */
65
+ export type BrowserHmrFileEventHandler = (events: readonly BrowserHmrFileEvent[]) => Promise<readonly BrowserHmrEvent[]>;
66
+ /**
67
+ * Watched file delta for a browser HMR channel.
68
+ */
69
+ export interface BrowserHmrWatchedFileDelta {
70
+ /** Absolute source file paths newly required by the asset server's compiled module graph. */
71
+ add: readonly string[];
72
+ /** Absolute source file paths no longer required by the asset server's compiled module graph. */
73
+ remove: readonly string[];
74
+ }
75
+ /**
76
+ * File watcher event reported to a browser HMR channel.
77
+ */
78
+ export type BrowserHmrFileEvent = {
79
+ /** Filesystem operation observed by the channel's watcher. */
80
+ event: 'add' | 'change' | 'unlink';
81
+ /** Absolute path of the source file that changed. */
82
+ filePath: string;
83
+ };
84
+ /**
85
+ * Browser HMR event emitted to connected clients.
86
+ */
87
+ export type BrowserHmrEvent = {
88
+ /** Absolute source file paths that triggered this update. */
89
+ files?: string[];
90
+ /** Update time used to bypass browser module and stylesheet caches. */
91
+ timestamp: number;
92
+ /** Browser update event. */
93
+ type: 'update';
94
+ /** Accepted JavaScript and CSS module updates for the browser to apply in place. */
95
+ updates: Extract<HmrPayload, {
96
+ type: 'browser:update';
97
+ }>['updates'];
98
+ } | {
99
+ /** Absolute source file paths that could not be handled in place. */
100
+ files?: string[];
101
+ /** Browser reload event. */
102
+ type: 'reload';
103
+ };
19
104
  interface FingerprintOptions {
20
105
  /**
21
106
  * Per-build invalidation token that must change whenever fingerprinted asset URLs
@@ -33,6 +118,16 @@ interface AssetServerScriptOptions {
33
118
  define?: Record<string, string>;
34
119
  /** Import specifiers to leave unrewritten (CDN URLs, import map entries, etc.) */
35
120
  external?: string[];
121
+ /**
122
+ * Synchronous loaders that post-process compiled JavaScript.
123
+ *
124
+ * Loaders use Node's synchronous `load` hook signature. Later loaders wrap earlier loaders: for
125
+ * `[first, second]`, `second` is entered first and delegates through `first` to the default
126
+ * behavior. As a result, transformations performed after `nextLoad()` are applied in array order.
127
+ * Loaders run after TypeScript/JavaScript transformation and before HMR analysis and minification.
128
+ * Only `format: 'module'` is supported, and import attributes are unsupported.
129
+ */
130
+ loaders?: readonly ModuleLoader[];
36
131
  }
37
132
  /**
38
133
  * Options used to construct an {@link AssetServer} via {@link createAssetServer}.
@@ -40,7 +135,6 @@ interface AssetServerScriptOptions {
40
135
  export interface AssetServerOptions<transforms extends AssetRequestTransformMap = {}> {
41
136
  /** Public mount path for this asset server, e.g. `'/assets'`. */
42
137
  basePath: string;
43
- /** File patterns keyed by public URL patterns relative to `basePath`. */
44
138
  /** File patterns keyed by public URL patterns. */
45
139
  fileMap: Readonly<Record<string, string>>;
46
140
  /**
@@ -50,11 +144,16 @@ export interface AssetServerOptions<transforms extends AssetRequestTransformMap
50
144
  /**
51
145
  * Glob patterns or file paths that are allowed to be served. Relative values are resolved from `rootDir`.
52
146
  */
53
- allow: readonly string[];
147
+ allowFiles: readonly string[];
148
+ /**
149
+ * Exact package names whose files are allowed to be served. Dependencies and installed optional
150
+ * dependencies are allowed automatically. Package files must still match `fileMap`.
151
+ */
152
+ allowPackages?: readonly string[];
54
153
  /**
55
154
  * Glob patterns or file paths that are denied from being served. Relative values are resolved from `rootDir`.
56
155
  */
57
- deny?: readonly string[];
156
+ denyFiles?: readonly string[];
58
157
  /**
59
158
  * Controls optional source-based URL fingerprinting for rewritten asset URLs.
60
159
  *
@@ -93,6 +192,13 @@ export interface AssetServerOptions<transforms extends AssetRequestTransformMap
93
192
  * module extensions are not allowed here.
94
193
  */
95
194
  files?: AssetServerFilesOptions<transforms>;
195
+ /**
196
+ * Enables `import.meta.hot` and coordinates browser updates through a server-level HMR runtime.
197
+ *
198
+ * HMR requires `watch` to be enabled. The factory is called once for this asset server. Returning
199
+ * `undefined` leaves HMR inactive; a returned channel is closed by `assetServer.close()`.
200
+ */
201
+ hmr?: BrowserHmrChannelFactory;
96
202
  /**
97
203
  * Enable filesystem-backed cache invalidation for long-lived server instances.
98
204
  * Enabled by default. Pass `true` to use the default watcher options, an options
@@ -132,7 +238,9 @@ export interface AssetServer<transforms extends AssetRequestTransformMap = {}> {
132
238
  */
133
239
  getPreloads(filePath: string | readonly string[]): Promise<string[]>;
134
240
  /**
135
- * Closes any watcher resources owned by this server instance.
241
+ * Closes this server's filesystem watcher and browser HMR channel.
242
+ *
243
+ * @returns A promise that resolves after owned development resources have been released.
136
244
  */
137
245
  close(): Promise<void>;
138
246
  }
@@ -154,12 +262,17 @@ export declare function getInternalWatchTargets<transforms extends AssetRequestT
154
262
  * fileMap: {
155
263
  * '/app/*path': 'app/*path',
156
264
  * },
157
- * allow: ['app/**'],
265
+ * allowFiles: ['app/routes.ts', 'app/**\/public/**'],
266
+ * allowPackages: ['remix'],
267
+ * denyFiles: ['app/**\/*.test.*'],
158
268
  * })
159
269
  *
160
270
  * route('/assets/*path', ({ request }) => assetServer.fetch(request))
161
271
  * ```
162
272
  */
163
273
  export declare function createAssetServer<const transforms extends AssetRequestTransformMap = {}>(options: AssetServerCreateOptions<transforms>): AssetServer<transforms>;
274
+ export declare function createScriptHmrPayload(updates: ScriptHmrUpdate[]): Extract<HmrPayload, {
275
+ type: 'browser:reload' | 'browser:update';
276
+ }> | null;
164
277
  export {};
165
278
  //# sourceMappingURL=asset-server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"asset-server.d.ts","sourceRoot":"","sources":["../../src/lib/asset-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"asset-server.d.ts","sourceRoot":"","sources":["../../src/lib/asset-server.ts"],"names":[],"mappings":"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"}