diff --git a/deno.json b/deno.json index 0eed3f0c4..6f9d94247 100644 --- a/deno.json +++ b/deno.json @@ -90,7 +90,7 @@ "packages/vocab-runtime/src/contexts/fep-22cd.json" ] }, - "nodeModulesDir": "auto", + "nodeModulesDir": "none", "tasks": { "build": { "command": "pnpm --recursive --filter '@fedify/*' --parallel --silent build", diff --git a/docs/package.json b/docs/package.json index 4b04a1e13..b27984966 100644 --- a/docs/package.json +++ b/docs/package.json @@ -23,12 +23,15 @@ "@fedify/vocab": "workspace:^", "@fedify/vocab-runtime": "workspace:^", "@fedify/relay": "workspace:^", + "@fedify/webfinger": "workspace:^", "@hono/node-server": "^1.13.7", "@js-temporal/polyfill": "catalog:", "@logtape/file": "catalog:", "@logtape/logtape": "catalog:", "@nestjs/common": "catalog:", "@opentelemetry/api": "catalog:", + "@opentelemetry/context-async-hooks": "catalog:", + "@opentelemetry/core": "catalog:", "@opentelemetry/exporter-trace-otlp-proto": "catalog:", "@opentelemetry/sdk-node": "catalog:", "@opentelemetry/sdk-trace-base": "catalog:", diff --git a/examples/fresh/deno.json b/examples/fresh/deno.json index e36f9c41b..36138585b 100644 --- a/examples/fresh/deno.json +++ b/examples/fresh/deno.json @@ -1,8 +1,8 @@ { "tasks": { "check": "deno fmt --check . && deno lint . && deno check", - "dev": "vite", - "build": "vite build", + "dev": "deno run -A npm:vite@^7.1.3 --configLoader native", + "build": "deno run -A npm:vite@^7.1.3 build --configLoader native", "start": "deno serve -A _fresh/server.js", "update": "deno run -A -r jsr:@fresh/update ." }, diff --git a/mise.toml b/mise.toml index 4cf727f5e..d45b38da4 100644 --- a/mise.toml +++ b/mise.toml @@ -70,9 +70,19 @@ depends = [ "check:md", "check-versions", "check:manifest:workspace-protocol", + "check:node-modules", ] run = "sacho check" +[tasks."check:node-modules"] +description = "Check that Deno leaves pnpm's node_modules directories alone" +run = ''' +if ! jq -e '.nodeModulesDir == "none"' deno.json > /dev/null; then + echo 'Set nodeModulesDir to "none" so Deno preserves pnpm workspace links.' + exit 1 +fi +''' + [tasks."check:fmt"] description = "Check code formatting" run = "deno fmt --check" @@ -159,6 +169,10 @@ done ''' # Testing +[tasks."test:pack"] +description = "Check that Deno preserves pnpm links and package packing" +run = "node scripts/test_pack.mjs" + [tasks."test:deno"] description = "Run the test suite using Deno" depends = ["prepare"] diff --git a/packages/fastify/package.json b/packages/fastify/package.json index bb8fbcca8..b0d0d3bf8 100644 --- a/packages/fastify/package.json +++ b/packages/fastify/package.json @@ -51,6 +51,7 @@ "fastify": "catalog:" }, "devDependencies": { + "@fedify/vocab": "workspace:^", "@types/node": "catalog:", "tsdown": "catalog:", "typescript": "catalog:" diff --git a/packages/sqlite/package.json b/packages/sqlite/package.json index 89961a58b..81ed52f00 100644 --- a/packages/sqlite/package.json +++ b/packages/sqlite/package.json @@ -75,6 +75,7 @@ "@fedify/fedify": "workspace:^" }, "devDependencies": { + "@fedify/fixture": "workspace:^", "@fedify/testing": "workspace:^", "@std/async": "catalog:", "tsdown": "catalog:", diff --git a/packages/testing/package.json b/packages/testing/package.json index 642c7e23a..96a1d0452 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -57,6 +57,8 @@ }, "devDependencies": { "@fedify/fixture": "workspace:^", + "@fedify/vocab": "workspace:^", + "@fedify/vocab-runtime": "workspace:^", "@js-temporal/polyfill": "catalog:", "@std/assert": "catalog:", "@std/async": "catalog:", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b4986aaf0..24be96f09 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -225,6 +225,9 @@ importers: '@fedify/vocab-runtime': specifier: workspace:^ version: link:../packages/vocab-runtime + '@fedify/webfinger': + specifier: workspace:^ + version: link:../packages/webfinger '@hono/node-server': specifier: ^1.13.7 version: 1.14.4(hono@4.8.3) @@ -243,6 +246,12 @@ importers: '@opentelemetry/api': specifier: 'catalog:' version: 1.9.0 + '@opentelemetry/context-async-hooks': + specifier: 'catalog:' + version: 2.5.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': + specifier: 'catalog:' + version: 2.5.0(@opentelemetry/api@1.9.0) '@opentelemetry/exporter-trace-otlp-proto': specifier: 'catalog:' version: 0.211.0(@opentelemetry/api@1.9.0) @@ -995,6 +1004,9 @@ importers: specifier: 'catalog:' version: 5.1.0 devDependencies: + '@fedify/vocab': + specifier: workspace:^ + version: link:../vocab '@types/node': specifier: 'catalog:' version: 22.19.1 @@ -1392,6 +1404,9 @@ importers: specifier: ^1.31.0 version: 1.39.5 devDependencies: + '@fedify/fixture': + specifier: workspace:^ + version: link:../fixture '@fedify/testing': specifier: workspace:^ version: link:../testing @@ -1433,6 +1448,12 @@ importers: '@fedify/fixture': specifier: workspace:^ version: link:../fixture + '@fedify/vocab': + specifier: workspace:^ + version: link:../vocab + '@fedify/vocab-runtime': + specifier: workspace:^ + version: link:../vocab-runtime '@js-temporal/polyfill': specifier: 'catalog:' version: 0.5.1 diff --git a/scripts/test_pack.mjs b/scripts/test_pack.mjs new file mode 100644 index 000000000..c239a701f --- /dev/null +++ b/scripts/test_pack.mjs @@ -0,0 +1,118 @@ +import { deepStrictEqual, strictEqual } from "node:assert/strict"; +import { execFileSync } from "node:child_process"; +import { + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + readlinkSync, + rmSync, + writeFileSync, +} from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import process from "node:process"; +import { gunzipSync } from "node:zlib"; + +// Use the repository's setting, but never let the negative control damage its +// installed dependencies. Run through mise; DENO_TEST_BINARY may select a +// different installed Deno without changing the pinned toolchain. +const config = JSON.parse( + readFileSync(new URL("../deno.json", import.meta.url), "utf8"), +); +const deno = process.env.DENO_TEST_BINARY ?? "deno"; +const root = mkdtempSync(join(tmpdir(), "fedify-pack-")); +function write(path, data) { + writeFileSync(join(root, path), data); +} +function json(path, value) { + write(path, JSON.stringify(value)); +} +function run(command, args, cwd = root) { + return execFileSync(command, args, { cwd, encoding: "utf8", stdio: "pipe" }); +} +function links() { + return [ + readlinkSync(join(root, "packages/adapter/node_modules/@fedify/pack-core")), + readlinkSync(join(root, "packages/adapter/node_modules/chalk")), + readdirSync(join(root, "node_modules")).sort(), + ]; +} +function packedManifest(path) { + const tar = gunzipSync(readFileSync(path)); + for (let offset = 0; offset < tar.length;) { + const name = tar.subarray(offset, offset + 100).toString().split("\0")[0]; + const size = parseInt( + tar.subarray(offset + 124, offset + 136).toString().replace(/\0/g, ""), + 8, + ); + if (!name) break; + if (name === "package/package.json") { + return JSON.parse(tar.subarray(offset + 512, offset + 512 + size)); + } + offset += 512 + Math.ceil(size / 512) * 512; + } + throw new Error("Packed package.json not found"); +} + +try { + mkdirSync(join(root, "packages/core"), { recursive: true }); + mkdirSync(join(root, "packages/adapter"), { recursive: true }); + json("package.json", { private: true }); + write("pnpm-workspace.yaml", "packages:\n - packages/*\n"); + json("deno.json", { + nodeModulesDir: config.nodeModulesDir, + workspace: ["./packages/core", "./packages/adapter"], + imports: { chalk: "npm:chalk@5.6.2" }, + }); + json("packages/core/deno.json", { + name: "@fedify/pack-core", + version: "1.2.3", + exports: "./mod.js", + }); + json("packages/core/package.json", { + name: "@fedify/pack-core", + version: "1.2.3", + type: "module", + exports: "./mod.js", + }); + write("packages/core/mod.js", "export const value = 42;\n"); + json("packages/adapter/deno.json", { exports: "./mod.js" }); + json("packages/adapter/package.json", { + name: "@fedify/pack-adapter", + version: "1.2.3", + type: "module", + peerDependencies: { "@fedify/pack-core": "workspace:^" }, + devDependencies: { chalk: "5.6.2" }, + scripts: { prepack: "node prepack.js" }, + }); + write( + "packages/adapter/mod.js", + 'import chalk from "chalk";\nimport { value } from "@fedify/pack-core";\nconsole.log(chalk.green(String(value)));\n', + ); + write( + "packages/adapter/prepack.js", + 'import "./mod.js";\nimport { writeFileSync } from "node:fs";\nwriteFileSync("lifecycle.txt", "prepack ran");\n', + ); + run("pnpm", ["install", "--ignore-scripts", "--no-frozen-lockfile"]); + const before = links(); + console.log(run(deno, ["--version"]).trim()); + run(deno, ["check", "packages/adapter/mod.js"]); + deepStrictEqual(links(), before, "Deno changed pnpm's node_modules"); + run( + "pnpm", + ["pack", "--pack-destination", root], + join(root, "packages/adapter"), + ); + strictEqual( + readFileSync(join(root, "packages/adapter/lifecycle.txt"), "utf8"), + "prepack ran", + ); + const manifest = packedManifest(join(root, "fedify-pack-adapter-1.2.3.tgz")); + strictEqual(manifest.peerDependencies["@fedify/pack-core"], "^1.2.3"); + console.log( + "Deno preserved pnpm links and lifecycle-enabled packing passed.", + ); +} finally { + rmSync(root, { recursive: true, force: true }); +}