miniflare 0.0.0-a64aa1b94 → 0.0.0-a67cdbfc4

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.
@@ -58,6 +58,13 @@ export declare class __MiniflareFunctionWrapper {
58
58
 
59
59
  export declare type AnyHeaders = http.IncomingHttpHeaders | string[];
60
60
 
61
+ export declare type AssetReverseMap = {
62
+ [pathHash: string]: {
63
+ filePath: string;
64
+ contentType: string;
65
+ };
66
+ };
67
+
61
68
  export declare const ASSETS_PLUGIN: Plugin<typeof AssetsOptionsSchema>;
62
69
 
63
70
  export declare const AssetsOptionsSchema: z.ZodObject<{
@@ -141,7 +148,19 @@ export declare function base64Encode(value: string): string;
141
148
 
142
149
  export { BodyInit }
143
150
 
144
- export declare const buildAssetsManifest: (dir: string) => Promise<Uint8Array>;
151
+ /**
152
+ * The Asset Manifest and Asset Reverse Map are used to map a request path to an asset.
153
+ * 1. Hash path of request
154
+ * 2. Use this path hash to find the manifest entry
155
+ * 3. Get content hash from manifest entry
156
+ * 4a. In prod, use content hash to get asset from KV
157
+ * 4b. In dev, we fake out the KV store and use the file system instead.
158
+ * Use content hash to get file path from asset reverse map.
159
+ */
160
+ export declare const buildAssetManifest: (dir: string) => Promise<{
161
+ encodedAssetManifest: Uint8Array;
162
+ assetsReverseMap: AssetReverseMap;
163
+ }>;
145
164
 
146
165
  export declare const CACHE_PLUGIN: Plugin<typeof CacheOptionsSchema, typeof CacheSharedOptionsSchema>;
147
166
 
@@ -1475,6 +1494,30 @@ export declare function getGlobalServices({ sharedOptions, allWorkerRoutes, fall
1475
1494
 
1476
1495
  export declare function getMiniflareObjectBindings(unsafeStickyBlobs: boolean): Worker_Binding[];
1477
1496
 
1497
+ /**
1498
+ * Computes the Node.js compatibility mode we are running.
1499
+ *
1500
+ * NOTES:
1501
+ * - The v2 mode is configured via `nodejs_compat_v2` compat flag or via `nodejs_compat` plus a compatibility date of Sept 23rd. 2024 or later.
1502
+ * - See `EnvironmentInheritable` for `nodeCompat` and `noBundle`.
1503
+ *
1504
+ * @param compatibilityDateStr The compatibility date
1505
+ * @param compatibilityFlags The compatibility flags
1506
+ * @param opts.nodeCompat Whether the legacy node_compat arg is being used
1507
+ * @returns the mode and flags to indicate specific configuration for validating.
1508
+ */
1509
+ export declare function getNodeCompat(compatibilityDate: string | undefined, // Default to some arbitrary old date
1510
+ compatibilityFlags: string[], opts?: {
1511
+ nodeCompat?: boolean;
1512
+ }): {
1513
+ mode: NodeJSCompatMode;
1514
+ hasNodejsAlsFlag: boolean;
1515
+ hasNodejsCompatFlag: boolean;
1516
+ hasNodejsCompatV2Flag: boolean;
1517
+ hasNoNodejsCompatV2Flag: boolean;
1518
+ hasExperimentalNodejsCompatV2Flag: boolean;
1519
+ };
1520
+
1478
1521
  export declare function getPersistPath(pluginName: string, tmpPath: string, persist: Persistence): string;
1479
1522
 
1480
1523
  export declare function getRootPath(opts: unknown): string;
@@ -1673,6 +1716,11 @@ export declare interface LogOptions {
1673
1716
  suffix?: string;
1674
1717
  }
1675
1718
 
1719
+ export declare type ManifestEntry = {
1720
+ pathHash: Uint8Array;
1721
+ contentHash: Uint8Array;
1722
+ };
1723
+
1676
1724
  export declare interface MatcherRegExps {
1677
1725
  include: RegExp[];
1678
1726
  exclude: RegExp[];
@@ -1797,6 +1845,17 @@ export declare interface Network {
1797
1845
 
1798
1846
  export declare const NODE_PLATFORM_IMPL: PlatformImpl<ReadableStream_2>;
1799
1847
 
1848
+ /**
1849
+ * We can provide Node.js compatibility in a number of different modes:
1850
+ * - "legacy" - this mode adds compile-time polyfills that are not well maintained and cannot work with workerd runtime builtins.
1851
+ * - "als": this mode tells the workerd runtime to enable only the Async Local Storage builtin library (accessible via `node:async_hooks`).
1852
+ * - "v1" - this mode tells the workerd runtime to enable some Node.js builtin libraries (accessible only via `node:...` imports) but no globals.
1853
+ * - "v2" - this mode tells the workerd runtime to enable more Node.js builtin libraries (accessible both with and without the `node:` prefix)
1854
+ * and also some Node.js globals such as `Buffer`; it also turns on additional compile-time polyfills for those that are not provided by the runtime.
1855
+ * - null - no Node.js compatibility.
1856
+ */
1857
+ export declare type NodeJSCompatMode = "legacy" | "als" | "v1" | "v2" | null;
1858
+
1800
1859
  export declare class NoOpLog extends Log {
1801
1860
  constructor();
1802
1861
  protected log(): void;
package/dist/src/index.js CHANGED
@@ -2547,7 +2547,7 @@ __export(src_exports, {
2547
2547
  _transformsForContentEncodingAndContentType: () => _transformsForContentEncodingAndContentType,
2548
2548
  base64Decode: () => base64Decode,
2549
2549
  base64Encode: () => base64Encode,
2550
- buildAssetsManifest: () => buildAssetsManifest,
2550
+ buildAssetManifest: () => buildAssetManifest,
2551
2551
  compileModuleRules: () => compileModuleRules,
2552
2552
  coupleWebSocket: () => coupleWebSocket,
2553
2553
  createFetchMock: () => createFetchMock,
@@ -2567,6 +2567,7 @@ __export(src_exports, {
2567
2567
  getFreshSourceMapSupport: () => getFreshSourceMapSupport,
2568
2568
  getGlobalServices: () => getGlobalServices,
2569
2569
  getMiniflareObjectBindings: () => getMiniflareObjectBindings,
2570
+ getNodeCompat: () => getNodeCompat,
2570
2571
  getPersistPath: () => getPersistPath,
2571
2572
  getRootPath: () => getRootPath,
2572
2573
  globsToRegExps: () => globsToRegExps,
@@ -4587,7 +4588,7 @@ var import_undici4 = require("undici");
4587
4588
  // src/plugins/assets/index.ts
4588
4589
  var import_node_crypto = __toESM(require("node:crypto"));
4589
4590
  var import_promises7 = __toESM(require("node:fs/promises"));
4590
- var import_node_path = __toESM(require("node:path"));
4591
+ var import_node_path2 = __toESM(require("node:path"));
4591
4592
 
4592
4593
  // ../workers-shared/utils/constants.ts
4593
4594
  var HEADER_SIZE = 20;
@@ -4616,10 +4617,13 @@ var AssetConfigSchema = import_zod4.z.object({
4616
4617
  });
4617
4618
 
4618
4619
  // ../workers-shared/utils/helpers.ts
4620
+ var import_node_path = require("node:path");
4619
4621
  var import_mime = __toESM(require_mime());
4620
- var encodeFilePath = (filePath, sep) => {
4621
- const encodedPath = filePath.split(sep).map((segment) => encodeURIComponent(segment)).join("/");
4622
- return "/" + encodedPath;
4622
+ var normalizeFilePath = (relativeFilepath) => {
4623
+ if ((0, import_node_path.isAbsolute)(relativeFilepath)) {
4624
+ throw new Error(`Expected relative path`);
4625
+ }
4626
+ return "/" + relativeFilepath.split(import_node_path.sep).join("/");
4623
4627
  };
4624
4628
  var getContentType = (absFilePath) => {
4625
4629
  let contentType = (0, import_mime.getType)(absFilePath) || "application/octet-stream";
@@ -5482,6 +5486,51 @@ var import_util = require("util");
5482
5486
  var import_acorn = require("acorn");
5483
5487
  var import_acorn_walk = require("acorn-walk");
5484
5488
  var import_zod9 = require("zod");
5489
+
5490
+ // src/plugins/core/node-compat.ts
5491
+ function getNodeCompat(compatibilityDate = "2000-01-01", compatibilityFlags, opts) {
5492
+ const { nodeCompat = false } = opts ?? {};
5493
+ const {
5494
+ hasNodejsAlsFlag,
5495
+ hasNodejsCompatFlag,
5496
+ hasNodejsCompatV2Flag,
5497
+ hasNoNodejsCompatV2Flag,
5498
+ hasExperimentalNodejsCompatV2Flag
5499
+ } = parseNodeCompatibilityFlags(compatibilityFlags);
5500
+ const nodeCompatSwitchOverDate = "2024-09-23";
5501
+ const legacy = nodeCompat === true;
5502
+ let mode = null;
5503
+ if (hasNodejsCompatV2Flag || hasNodejsCompatFlag && compatibilityDate >= nodeCompatSwitchOverDate && !hasNoNodejsCompatV2Flag) {
5504
+ mode = "v2";
5505
+ } else if (hasNodejsCompatFlag) {
5506
+ mode = "v1";
5507
+ } else if (hasNodejsAlsFlag) {
5508
+ mode = "als";
5509
+ } else if (legacy) {
5510
+ mode = "legacy";
5511
+ }
5512
+ return {
5513
+ mode,
5514
+ hasNodejsAlsFlag,
5515
+ hasNodejsCompatFlag,
5516
+ hasNodejsCompatV2Flag,
5517
+ hasNoNodejsCompatV2Flag,
5518
+ hasExperimentalNodejsCompatV2Flag
5519
+ };
5520
+ }
5521
+ function parseNodeCompatibilityFlags(compatibilityFlags) {
5522
+ return {
5523
+ hasNodejsAlsFlag: compatibilityFlags.includes("nodejs_als"),
5524
+ hasNodejsCompatFlag: compatibilityFlags.includes("nodejs_compat"),
5525
+ hasNodejsCompatV2Flag: compatibilityFlags.includes("nodejs_compat_v2"),
5526
+ hasNoNodejsCompatV2Flag: compatibilityFlags.includes("no_nodejs_compat_v2"),
5527
+ hasExperimentalNodejsCompatV2Flag: compatibilityFlags.includes(
5528
+ "experimental:nodejs_compat_v2"
5529
+ )
5530
+ };
5531
+ }
5532
+
5533
+ // src/plugins/core/modules.ts
5485
5534
  var SUGGEST_BUNDLE = "If you're trying to import an npm package, you'll need to bundle your Worker first.";
5486
5535
  var SUGGEST_NODE = "If you're trying to import a Node.js built-in module, or an npm package that uses Node.js built-ins, you'll either need to:\n- Bundle your Worker, configuring your bundler to polyfill Node.js built-ins\n- Configure your bundler to load Workers-compatible builds by changing the main fields/conditions\n- Enable the `nodejs_compat` compatibility flag and use the `NodeJsCompatModule` module type\n- Find an alternative package that doesn't require Node.js built-ins";
5487
5536
  var builtinModulesWithPrefix = import_module.builtinModules.concat(
@@ -5589,15 +5638,18 @@ function getResolveErrorPrefix(referencingPath) {
5589
5638
  return `Unable to resolve "${relative}" dependency`;
5590
5639
  }
5591
5640
  var ModuleLocator = class {
5592
- constructor(modulesRoot, additionalModuleNames, rules = [], compatibilityFlags) {
5641
+ constructor(modulesRoot, additionalModuleNames, rules = [], compatibilityDate, compatibilityFlags) {
5593
5642
  this.modulesRoot = modulesRoot;
5594
5643
  this.additionalModuleNames = additionalModuleNames;
5595
5644
  rules = rules.concat(DEFAULT_MODULE_RULES);
5596
5645
  this.#compiledRules = compileModuleRules(rules);
5597
- this.#nodejsCompat = compatibilityFlags?.includes("nodejs_compat") ?? false;
5646
+ this.#nodejsCompatMode = getNodeCompat(
5647
+ compatibilityDate,
5648
+ compatibilityFlags ?? []
5649
+ ).mode;
5598
5650
  }
5599
5651
  #compiledRules;
5600
- #nodejsCompat;
5652
+ #nodejsCompatMode;
5601
5653
  #visitedPaths = /* @__PURE__ */ new Set();
5602
5654
  modules = [];
5603
5655
  visitEntrypoint(code, modulePath) {
@@ -5681,7 +5733,14 @@ ${dim(modulesConfig)}`;
5681
5733
  }
5682
5734
  const spec = specExpression.value;
5683
5735
  const isNodeJsCompatModule = referencingType === "NodeJsCompatModule";
5684
- if (this.#nodejsCompat && spec.startsWith("node:") || spec.startsWith("cloudflare:") || spec.startsWith("workerd:") || isNodeJsCompatModule && builtinModulesWithPrefix.includes(spec) || this.additionalModuleNames.includes(spec)) {
5736
+ if (
5737
+ // `cloudflare:` and `workerd:` imports don't need to be included explicitly
5738
+ spec.startsWith("cloudflare:") || spec.startsWith("workerd:") || // Node.js compat v1 requires imports to be prefixed with `node:`
5739
+ this.#nodejsCompatMode === "v1" && spec.startsWith("node:") || // Node.js compat modules and v2 can also handle non-prefixed imports
5740
+ (this.#nodejsCompatMode === "v2" || isNodeJsCompatModule) && builtinModulesWithPrefix.includes(spec) || // Async Local Storage mode (node_als) only deals with `node:async_hooks` imports
5741
+ this.#nodejsCompatMode === "als" && spec === "node:async_hooks" || // Any "additional" external modules can be ignored
5742
+ this.additionalModuleNames.includes(spec)
5743
+ ) {
5685
5744
  return;
5686
5745
  }
5687
5746
  if (maybeGetStringScriptPathIndex(referencingName) !== void 0) {
@@ -7444,6 +7503,7 @@ function getWorkerScript(options, workerIndex, additionalModuleNames) {
7444
7503
  modulesRoot,
7445
7504
  additionalModuleNames,
7446
7505
  options.modulesRules,
7506
+ options.compatibilityDate,
7447
7507
  options.compatibilityFlags
7448
7508
  );
7449
7509
  locator.visitEntrypoint(code, scriptPath);
@@ -7499,12 +7559,14 @@ var ASSETS_PLUGIN = {
7499
7559
  if (!options.assets) {
7500
7560
  return [];
7501
7561
  }
7502
- const assetsReverseMap = await createReverseMap(options.assets?.path);
7503
7562
  const storageServiceName = `${ASSETS_PLUGIN_NAME}:storage`;
7504
7563
  const storageService = {
7505
7564
  name: storageServiceName,
7506
7565
  disk: { path: options.assets.path, writable: true }
7507
7566
  };
7567
+ const { encodedAssetManifest, assetsReverseMap } = await buildAssetManifest(
7568
+ options.assets.path
7569
+ );
7508
7570
  const namespaceService = {
7509
7571
  name: ASSETS_KV_SERVICE_NAME,
7510
7572
  worker: {
@@ -7523,12 +7585,11 @@ var ASSETS_PLUGIN = {
7523
7585
  },
7524
7586
  {
7525
7587
  name: "ASSETS_REVERSE_MAP",
7526
- json: assetsReverseMap
7588
+ json: JSON.stringify(assetsReverseMap)
7527
7589
  }
7528
7590
  ]
7529
7591
  }
7530
7592
  };
7531
- const assetsManifest = await buildAssetsManifest(options.assets.path);
7532
7593
  const assetService = {
7533
7594
  name: ASSETS_SERVICE_NAME,
7534
7595
  worker: {
@@ -7546,7 +7607,7 @@ var ASSETS_PLUGIN = {
7546
7607
  },
7547
7608
  {
7548
7609
  name: "ASSETS_MANIFEST",
7549
- data: assetsManifest
7610
+ data: encodedAssetManifest
7550
7611
  },
7551
7612
  {
7552
7613
  name: "CONFIG",
@@ -7584,20 +7645,21 @@ var ASSETS_PLUGIN = {
7584
7645
  return [storageService, namespaceService, assetService, routerService];
7585
7646
  }
7586
7647
  };
7587
- var buildAssetsManifest = async (dir) => {
7588
- const manifest = await walk(dir);
7648
+ var buildAssetManifest = async (dir) => {
7649
+ const { manifest, assetsReverseMap } = await walk(dir);
7589
7650
  const sortedAssetManifest = sortManifest(manifest);
7590
7651
  const encodedAssetManifest = encodeManifest(sortedAssetManifest);
7591
- return encodedAssetManifest;
7652
+ return { encodedAssetManifest, assetsReverseMap };
7592
7653
  };
7593
7654
  var walk = async (dir) => {
7594
7655
  const files = await import_promises7.default.readdir(dir, { recursive: true });
7595
7656
  const manifest = [];
7657
+ const assetsReverseMap = {};
7596
7658
  let counter = 0;
7597
7659
  await Promise.all(
7598
7660
  files.map(async (file) => {
7599
- const filepath = import_node_path.default.join(dir, file);
7600
- const relativeFilepath = import_node_path.default.relative(dir, filepath);
7661
+ const filepath = import_node_path2.default.join(dir, file);
7662
+ const relativeFilepath = import_node_path2.default.relative(dir, filepath);
7601
7663
  const filestat = await import_promises7.default.stat(filepath);
7602
7664
  if (filestat.isSymbolicLink() || filestat.isDirectory()) {
7603
7665
  return;
@@ -7619,9 +7681,19 @@ Cloudflare Workers supports assets with sizes of up to ${prettyBytes(
7619
7681
  Ensure all assets in your assets directory "${dir}" conform with the Workers maximum size requirement.`
7620
7682
  );
7621
7683
  }
7622
- manifest.push(
7623
- await hashPath(encodeFilePath(relativeFilepath, import_node_path.default.sep))
7624
- );
7684
+ const [pathHash, contentHash] = await Promise.all([
7685
+ hashPath(normalizeFilePath(relativeFilepath)),
7686
+ // used absolute filepath here so that changes to the enclosing asset folder will be registered
7687
+ hashPath(filepath + filestat.mtimeMs.toString())
7688
+ ]);
7689
+ manifest.push({
7690
+ pathHash,
7691
+ contentHash
7692
+ });
7693
+ assetsReverseMap[bytesToHex(contentHash)] = {
7694
+ filePath: relativeFilepath,
7695
+ contentType: getContentType(filepath)
7696
+ };
7625
7697
  counter++;
7626
7698
  }
7627
7699
  })
@@ -7633,23 +7705,23 @@ Cloudflare Workers supports up to ${MAX_ASSET_COUNT.toLocaleString()} assets in
7633
7705
  Ensure your assets directory contains a maximum of ${MAX_ASSET_COUNT.toLocaleString()} files, and that you have specified your assets directory correctly.`
7634
7706
  );
7635
7707
  }
7636
- return manifest;
7708
+ return { manifest, assetsReverseMap };
7637
7709
  };
7638
7710
  var sortManifest = (manifest) => {
7639
7711
  return manifest.sort(comparisonFn);
7640
7712
  };
7641
7713
  var comparisonFn = (a, b) => {
7642
- if (a.length < b.length) {
7714
+ if (a.pathHash.length < b.pathHash.length) {
7643
7715
  return -1;
7644
7716
  }
7645
- if (a.length > b.length) {
7717
+ if (a.pathHash.length > b.pathHash.length) {
7646
7718
  return 1;
7647
7719
  }
7648
- for (const [i, v] of a.entries()) {
7649
- if (v < b[i]) {
7720
+ for (const [i, v] of a.pathHash.entries()) {
7721
+ if (v < b.pathHash[i]) {
7650
7722
  return -1;
7651
7723
  }
7652
- if (v > b[i]) {
7724
+ if (v > b.pathHash[i]) {
7653
7725
  return 1;
7654
7726
  }
7655
7727
  }
@@ -7661,34 +7733,14 @@ var encodeManifest = (manifest) => {
7661
7733
  );
7662
7734
  for (const [i, entry] of manifest.entries()) {
7663
7735
  const entryOffset = HEADER_SIZE + i * ENTRY_SIZE;
7664
- assetManifestBytes.set(entry, entryOffset + PATH_HASH_OFFSET);
7665
- assetManifestBytes.set(entry, entryOffset + CONTENT_HASH_OFFSET);
7736
+ assetManifestBytes.set(entry.pathHash, entryOffset + PATH_HASH_OFFSET);
7737
+ assetManifestBytes.set(
7738
+ entry.contentHash,
7739
+ entryOffset + CONTENT_HASH_OFFSET
7740
+ );
7666
7741
  }
7667
7742
  return assetManifestBytes;
7668
7743
  };
7669
- var createReverseMap = async (dir) => {
7670
- const files = await import_promises7.default.readdir(dir, { recursive: true });
7671
- const assetsReverseMap = {};
7672
- await Promise.all(
7673
- files.map(async (file) => {
7674
- const filepath = import_node_path.default.join(dir, file);
7675
- const relativeFilepath = import_node_path.default.relative(dir, filepath);
7676
- const filestat = await import_promises7.default.stat(filepath);
7677
- if (filestat.isSymbolicLink() || filestat.isDirectory()) {
7678
- return;
7679
- } else {
7680
- const pathHash = bytesToHex(
7681
- await hashPath(encodeFilePath(relativeFilepath, import_node_path.default.sep))
7682
- );
7683
- assetsReverseMap[pathHash] = {
7684
- filePath: relativeFilepath,
7685
- contentType: getContentType(filepath)
7686
- };
7687
- }
7688
- })
7689
- );
7690
- return JSON.stringify(assetsReverseMap);
7691
- };
7692
7744
  var bytesToHex = (buffer) => {
7693
7745
  return [...new Uint8Array(buffer)].map((b) => b.toString(16).padStart(2, "0")).join("");
7694
7746
  };
@@ -10202,7 +10254,7 @@ var Miniflare2 = class {
10202
10254
  _transformsForContentEncodingAndContentType,
10203
10255
  base64Decode,
10204
10256
  base64Encode,
10205
- buildAssetsManifest,
10257
+ buildAssetManifest,
10206
10258
  compileModuleRules,
10207
10259
  coupleWebSocket,
10208
10260
  createFetchMock,
@@ -10222,6 +10274,7 @@ var Miniflare2 = class {
10222
10274
  getFreshSourceMapSupport,
10223
10275
  getGlobalServices,
10224
10276
  getMiniflareObjectBindings,
10277
+ getNodeCompat,
10225
10278
  getPersistPath,
10226
10279
  getRootPath,
10227
10280
  globsToRegExps,