@crustjs/crust-windows-arm64 0.5.4 → 0.5.5

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.
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/bin/crust-bun-windows-arm64.exe
3
- size: 77742592 bytes
4
- sha256: 55cbde278a141b0e9b8ff5d7e1a0738abb01c2207c614b77ed03b857fe684ecb
3
+ size: 77745152 bytes
4
+ sha256: 5f64f9337b97aeeab855413f233d5f2e026c846e3e81ca4ecc758d0a7efbd346
@@ -73,12 +73,13 @@ type BuildResult = {
73
73
  * `bin` entry, each the command's bundle (artifact `package`) or a Node
74
74
  * launcher (artifact `binary`), plus for binaries one platform package per
75
75
  * target holding one executable per command. Command names and source entries
76
- * come from `bin`; the runtime, artifact, Bun plugins, and extra directories
77
- * from package.json `crust`. Bundling and Command Snapshots run in bun
78
- * subprocesses (bun on PATH, or the running Bun executable), so this works
79
- * under Node as well when Bun is installed; Deno binaries and Deno runtime
80
- * packages (experimental, deno 2.5.0 or newer) need deno on PATH, and Node
81
- * binaries a node on PATH that Crust's tsdown can build executables with.
76
+ * come from `bin`; the runtime, artifact, Bun plugins, extra directories, and
77
+ * external dependencies from package.json `crust`. Bundling and Command
78
+ * Snapshots run in bun subprocesses (bun on PATH, or the running Bun
79
+ * executable), so this works under Node as well when Bun is installed; Deno
80
+ * binaries and Deno runtime packages (experimental, deno 2.5.0 or newer) need
81
+ * deno on PATH, and Node binaries a node on PATH that Crust's tsdown can build
82
+ * executables with.
82
83
  *
83
84
  * Throws on any failure. Planning and compiler-selection failures (bad
84
85
  * options or package.json, a missing or hung compiler, an engines mismatch) leave the
package/bin/dist/index.js CHANGED
@@ -3117,13 +3117,14 @@ async function runBuildProcess(runner, args, outfilePath, cwd) {
3117
3117
  * Node, or Bun-targeted so the installed bin launches with Bun rather than Node.
3118
3118
  */
3119
3119
  async function execScriptBuild(target, entryPath, outfilePath, settings, runner = resolveBunBuildRunner()) {
3120
- const { cwd, minify, envFiles } = settings;
3120
+ const { cwd, minify, envFiles, external } = settings;
3121
3121
  if (settings.bunPlugins.length > 0) await runBunPluginDriver({
3122
3122
  entrypoints: [entryPath],
3123
3123
  minify,
3124
3124
  env: "PUBLIC_*",
3125
3125
  target,
3126
- format: "esm"
3126
+ format: "esm",
3127
+ external
3127
3128
  }, outfilePath, settings, runner);
3128
3129
  else await runBuildProcess(runner, [
3129
3130
  "build",
@@ -3135,6 +3136,7 @@ async function execScriptBuild(target, entryPath, outfilePath, settings, runner
3135
3136
  target,
3136
3137
  "--format",
3137
3138
  "esm",
3139
+ ...external.flatMap((name) => ["--external", name]),
3138
3140
  "--outfile",
3139
3141
  outfilePath,
3140
3142
  ...minify ? ["--minify"] : [],
@@ -3319,6 +3321,7 @@ function buildDistributionRootPackageJson(metadata, commands, targets, { artifac
3319
3321
  type: "module",
3320
3322
  files: ["bin", ...artifactDirs],
3321
3323
  bin: Object.fromEntries(commands.map((command) => [command, `bin/${command}.js`])),
3324
+ dependencies: metadata.dependencies,
3322
3325
  ...targets.length > 0 ? { optionalDependencies: Object.fromEntries(targets.map((target) => [target.packageName, metadata.version])) } : {},
3323
3326
  ...manPages.length > 0 ? { man: manPages.map((page) => `./man/${page}`) } : {},
3324
3327
  exports: metadata.exports,
@@ -3384,16 +3387,23 @@ function validateStagedExports(exports, rootDir, sourceType) {
3384
3387
  checkTarget(exports, "\".\"");
3385
3388
  }
3386
3389
  /**
3390
+ * The staged manifests go to npm as written, so a range the registry cannot
3391
+ * resolve (a workspace, catalog, or local path protocol) would leak into it.
3392
+ * Bare paths and scheme-less tarball names are local too, except GitHub
3393
+ * owner/repo[#ref] shorthand: npm resolves hosted Git before its file fallback.
3394
+ */
3395
+ function assertPublishableRange(range, label) {
3396
+ if (range === void 0 || !isString$1(range) || /^(?:(?:workspace|catalog|file|link|portal):|[.]|~[/\\]|[/\\]|[a-zA-Z]:)/.test(range) || !/^[a-z][a-z+]*:/i.test(range) && !/^[^@\s/:#\\]+\/[^@\s/:#\\]+(?:#.*)?$/.test(range) && /[.](?:tgz|tar\.gz|tar)$/i.test(range)) throw new Error(`${label} must be a publishable range, not ${JSON.stringify(range)}.\n crust build publishes the staged root package as written; workspace:, catalog:, file:, link:, portal:, and local path ranges are never rewritten.`);
3397
+ }
3398
+ /**
3387
3399
  * Carries `peerDependencies` (and `peerDependenciesMeta`) into the root package
3388
3400
  * so a library `exports` entry can declare what its published types import.
3389
- * Ranges must be publishable as written: the staged manifests go to npm
3390
- * directly, so `workspace:` and `catalog:` ranges would leak into the registry.
3391
3401
  */
3392
3402
  function validatePeerDependencies(peerDependencies, peerDependenciesMeta) {
3393
3403
  if (!isJsonObject(peerDependencies)) throw new Error("package.json peerDependencies must be an object of package names to ranges.");
3394
3404
  const ranges = {};
3395
3405
  for (const [name, range] of Object.entries(peerDependencies)) {
3396
- if (!isString$1(range) || /^(workspace|catalog):/.test(range)) throw new Error(`package.json peerDependencies[${JSON.stringify(name)}] must be a publishable range, not ${JSON.stringify(range)}.\n crust build publishes the staged root package as written; workspace: and catalog: ranges are never rewritten.`);
3406
+ assertPublishableRange(range, `package.json peerDependencies[${JSON.stringify(name)}]`);
3397
3407
  ranges[name] = range;
3398
3408
  }
3399
3409
  if (peerDependenciesMeta === void 0) return { peerDependencies: ranges };
@@ -3430,7 +3440,16 @@ function pickRootMetadata(pkgJson) {
3430
3440
  function validatePackageNameLength(packageName) {
3431
3441
  if (packageName.length > MAX_PACKAGE_NAME_LENGTH) throw new Error(`Generated package name is too long for npm: ${packageName}\n Keep package names at or below ${MAX_PACKAGE_NAME_LENGTH} characters after the platform suffix is added.`);
3432
3442
  }
3433
- function resolveDistributionMetadata(pkgJson) {
3443
+ /** `crust.external` ranges, already validated by `planBuild`; re-asserted for their type. */
3444
+ function externalDependencies(pkgJson, external) {
3445
+ const dependencies = pkgJson.dependencies !== void 0 && isJsonObject(pkgJson.dependencies) ? pkgJson.dependencies : {};
3446
+ return Object.fromEntries(external.map((name) => {
3447
+ const range = dependencies[name];
3448
+ assertPublishableRange(range, `package.json dependencies[${JSON.stringify(name)}]`);
3449
+ return [name, range];
3450
+ }));
3451
+ }
3452
+ function resolveDistributionMetadata(pkgJson, external) {
3434
3453
  validatePackageNameLength(pkgJson.name);
3435
3454
  return {
3436
3455
  rootPackageName: pkgJson.name,
@@ -3438,7 +3457,8 @@ function resolveDistributionMetadata(pkgJson) {
3438
3457
  rootPackageJson: pickRootMetadata(pkgJson),
3439
3458
  sourceType: pkgJson.type,
3440
3459
  ...pkgJson.exports !== void 0 ? { exports: pkgJson.exports } : {},
3441
- ...pkgJson.peerDependencies !== void 0 ? validatePeerDependencies(pkgJson.peerDependencies, pkgJson.peerDependenciesMeta) : {}
3460
+ ...pkgJson.peerDependencies !== void 0 ? validatePeerDependencies(pkgJson.peerDependencies, pkgJson.peerDependenciesMeta) : {},
3461
+ ...external.length > 0 ? { dependencies: externalDependencies(pkgJson, external) } : {}
3442
3462
  };
3443
3463
  }
3444
3464
  function resolveDistributionTarget(table, stageDir, rootPackageName, target) {
@@ -3528,7 +3548,7 @@ function stageDistributionPackages(cwd, stageDir, metadata, platformMetadata, co
3528
3548
  * Returns every generated package.json, launcher, and compiled command in staging order.
3529
3549
  */
3530
3550
  async function runDistributeBuild(plan, distribution, io, build) {
3531
- const sourceMetadata = resolveDistributionMetadata(plan.userPackageJson);
3551
+ const sourceMetadata = resolveDistributionMetadata(plan.userPackageJson, plan.external);
3532
3552
  const commands = plan.entries.map((entry) => entry.command);
3533
3553
  const table = distribution.table;
3534
3554
  const platformMetadata = plan.runtime === "node" && table ? {
@@ -3813,7 +3833,8 @@ async function execNodeBinaryBuild(entryPath, outfilePath, target, settings, com
3813
3833
  const exeDir = join(workDir, "exe");
3814
3834
  await execScriptBuild("node", resolve(cwd, entryPath), bunBundle, {
3815
3835
  ...settings,
3816
- bunPlugins: []
3836
+ bunPlugins: [],
3837
+ external: []
3817
3838
  }, bunRunner);
3818
3839
  await writeFile(scriptPath, createNodeExeBuildScript({
3819
3840
  tsdownPackageJson: compiler.backend.packageJsonPath,
@@ -4074,7 +4095,8 @@ const CRUST_CONFIG_KEYS = [
4074
4095
  "artifact",
4075
4096
  "targets",
4076
4097
  "bunPlugins",
4077
- "include"
4098
+ "include",
4099
+ "external"
4078
4100
  ];
4079
4101
  function isBuildRuntime(value) {
4080
4102
  return typeof value === "string" && BUILD_RUNTIMES.some((runtime) => runtime === value);
@@ -4116,11 +4138,54 @@ function readCrustConfig(pkg) {
4116
4138
  if (!isStringArray(crust.include)) throw new Error("package.json crust.include must be an array of directory names relative to the project root, e.g. [\"templates\"].");
4117
4139
  config.include = crust.include;
4118
4140
  }
4141
+ const external = crust.external;
4142
+ if (external !== void 0) {
4143
+ if (!isStringArray(external)) throw new Error("package.json crust.external must be an array of package names from dependencies, e.g. [\"better-sqlite3\"].");
4144
+ const duplicate = external.find((name, index) => external.indexOf(name) !== index);
4145
+ if (duplicate !== void 0) throw new Error(`package.json crust.external lists ${JSON.stringify(duplicate)} more than once.`);
4146
+ config.external = external;
4147
+ }
4119
4148
  return config;
4120
4149
  }
4121
4150
  function hasDependency(pkg, name) {
4122
4151
  return [pkg.dependencies, pkg.devDependencies].some((deps) => deps !== void 0 && isJsonObject(deps) && name in deps);
4123
4152
  }
4153
+ const NON_DEPENDENCY_SECTIONS = [
4154
+ "devDependencies",
4155
+ "optionalDependencies",
4156
+ "peerDependencies"
4157
+ ];
4158
+ /**
4159
+ * `crust.external` names ship as root `dependencies` of a Node or Bun runtime
4160
+ * package, so each needs a publishable `dependencies` range. Crust packages
4161
+ * stay bundled: core reads `process.env.CRUST_INTERNAL_BUILD`, which the
4162
+ * bundler defines only in bundled code, and an external `@crustjs/*` package
4163
+ * would load a second copy of core.
4164
+ */
4165
+ function validateExternal(external, pkg, runtime, artifact) {
4166
+ if (external.length === 0) return;
4167
+ if (artifact === "binary") throw new Error("package.json crust.external is not supported for standalone binaries (artifact binary).\n A binary bundles every dependency; remove crust.external or use artifact package.");
4168
+ if (runtime === "deno") throw new Error("package.json crust.external is not supported with the deno runtime.\n crust.external applies to Node and Bun runtime packages; remove crust.external or set crust.runtime to node or bun.");
4169
+ const dependencies = pkg.dependencies !== void 0 && isJsonObject(pkg.dependencies) ? pkg.dependencies : {};
4170
+ const rejectCrustPackage = (quoted, detail) => {
4171
+ throw new Error(`package.json crust.external cannot name ${quoted}${detail}.\n Crust packages must stay bundled: core detects a packaged build through a define the bundler injects, and an external Crust package would load a second copy of core.`);
4172
+ };
4173
+ for (const name of external) {
4174
+ const quoted = JSON.stringify(name);
4175
+ if (name.startsWith("@crustjs/")) rejectCrustPackage(quoted, "");
4176
+ if (!Object.hasOwn(dependencies, name)) {
4177
+ const sections = NON_DEPENDENCY_SECTIONS.filter((section) => {
4178
+ const deps = pkg[section];
4179
+ return deps !== void 0 && isJsonObject(deps) && Object.hasOwn(deps, name);
4180
+ });
4181
+ throw new Error(sections.length > 0 ? `package.json crust.external entry ${quoted} is in ${sections.join(" and ")}, not dependencies.\n Only dependencies ship with the staged package; move ${quoted} to dependencies.` : `package.json crust.external entry ${quoted} is not in package.json dependencies.\n crust.external names packages from dependencies, which ship with the staged package; add ${quoted} to dependencies.`);
4182
+ }
4183
+ const range = dependencies[name];
4184
+ assertPublishableRange(range, `package.json dependencies[${quoted}]`);
4185
+ const aliased = /^npm:(@crustjs\/[^@]+)/.exec(range)?.[1];
4186
+ if (aliased !== void 0) rejectCrustPackage(quoted, ` (an alias of ${aliased})`);
4187
+ }
4188
+ }
4124
4189
  const DENO_CONFIG_FILES = ["deno.json", "deno.jsonc"];
4125
4190
  /**
4126
4191
  * package.json `crust.runtime` > inference > Bun. Inference uses only
@@ -4248,6 +4313,7 @@ function planBuild(options, cwd) {
4248
4313
  validatePackageIdentity(userPackageJson, "package.json");
4249
4314
  const envFiles = resolveEnvFilePaths(cwd, options.envFiles);
4250
4315
  const bunPlugins = config.bunPlugins ?? [];
4316
+ const external = config.external ?? [];
4251
4317
  if (artifact === "package" && options.targets?.length) throw new Error("--target cannot be used with runtime packages (artifact package).\n A runtime package is one portable JavaScript bundle; drop --target or use artifact binary.");
4252
4318
  if (artifact === "package" && config.targets !== void 0) throw new Error("package.json crust.targets is not supported for runtime packages (artifact package).\n A runtime package is one portable JavaScript bundle; remove crust.targets or set \"artifact\": \"binary\".");
4253
4319
  const denoTool = artifact === "binary" ? "deno compile" : "deno bundle";
@@ -4255,6 +4321,7 @@ function planBuild(options, cwd) {
4255
4321
  if (runtime === "deno" && envFiles.length > 0) throw new Error(artifact === "binary" ? "--env-file is not supported with the deno runtime.\n deno compile embeds every variable from the file into the binary — secrets included —\n with no PUBLIC_* filter. Load configuration at runtime instead (e.g. deno run --env-file)." : "--env-file is not supported with the deno runtime.\n deno bundle has no PUBLIC_* build-time constants. Load configuration at runtime instead (e.g. deno run --env-file).");
4256
4322
  if (runtime === "deno" && bunPlugins.length > 0) throw new Error(`package.json crust.bunPlugins is not supported with the deno runtime.\n ${denoTool} has no Bun bundler; remove crust.bunPlugins or set crust.runtime to bun.`);
4257
4323
  if (runtime === "node" && artifact === "binary" && bunPlugins.length > 0) throw new Error("package.json crust.bunPlugins is not supported for node standalone binaries.\n Remove crust.bunPlugins, or use artifact package or the bun runtime.");
4324
+ validateExternal(external, userPackageJson, runtime, artifact);
4258
4325
  const stageDir = resolve(cwd, CRUST_DIR);
4259
4326
  const common = {
4260
4327
  cwd,
@@ -4264,6 +4331,7 @@ function planBuild(options, cwd) {
4264
4331
  envFiles,
4265
4332
  bunPlugins,
4266
4333
  include: config.include ?? [],
4334
+ external,
4267
4335
  outDir: join(stageDir, "artifacts"),
4268
4336
  stageDir,
4269
4337
  validate: options.validate ?? true,
@@ -4398,12 +4466,13 @@ async function prepareEntries(plan, io, runner) {
4398
4466
  * `bin` entry, each the command's bundle (artifact `package`) or a Node
4399
4467
  * launcher (artifact `binary`), plus for binaries one platform package per
4400
4468
  * target holding one executable per command. Command names and source entries
4401
- * come from `bin`; the runtime, artifact, Bun plugins, and extra directories
4402
- * from package.json `crust`. Bundling and Command Snapshots run in bun
4403
- * subprocesses (bun on PATH, or the running Bun executable), so this works
4404
- * under Node as well when Bun is installed; Deno binaries and Deno runtime
4405
- * packages (experimental, deno 2.5.0 or newer) need deno on PATH, and Node
4406
- * binaries a node on PATH that Crust's tsdown can build executables with.
4469
+ * come from `bin`; the runtime, artifact, Bun plugins, extra directories, and
4470
+ * external dependencies from package.json `crust`. Bundling and Command
4471
+ * Snapshots run in bun subprocesses (bun on PATH, or the running Bun
4472
+ * executable), so this works under Node as well when Bun is installed; Deno
4473
+ * binaries and Deno runtime packages (experimental, deno 2.5.0 or newer) need
4474
+ * deno on PATH, and Node binaries a node on PATH that Crust's tsdown can build
4475
+ * executables with.
4407
4476
  *
4408
4477
  * Throws on any failure. Planning and compiler-selection failures (bad
4409
4478
  * options or package.json, a missing or hung compiler, an engines mismatch) leave the
@@ -52,6 +52,14 @@
52
52
  "items": {
53
53
  "type": "string"
54
54
  }
55
+ },
56
+ "external": {
57
+ "description": "Packages left out of a node or bun runtime package's bundle and shipped as `dependencies` of the staged root package with their package.json `dependencies` range, e.g. native addons, packages the CLI reads files from or runs, or very large dependencies. Each must be a `dependencies` key with a publishable range (no workspace:, catalog:, file:, link:, portal:, local paths, or local tarballs); @crustjs/* packages and npm aliases of them are rejected. Rejected for binaries and for Deno.",
58
+ "type": "array",
59
+ "uniqueItems": true,
60
+ "items": {
61
+ "type": "string"
62
+ }
55
63
  }
56
64
  }
57
65
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crustjs/crust-windows-arm64",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "CLI to build and publish Crust apps as npm packages or standalone binaries",
5
5
  "license": "MIT",
6
6
  "author": "chenxin-yan",