Skip to content

Commit 6c034f9

Browse files
authored
Merge pull request #701 from dahlia/bugfix/astro
Fix npm entrypoints for @fedify/astro
2 parents 75dabd2 + 82b694f commit 6c034f9

5 files changed

Lines changed: 199 additions & 2 deletions

File tree

.agents/skills/commit/SKILL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ EOF
4242

4343
Don't put `Generated with [Claude Code](https://claude.ai/code)`, or
4444
`Co-authored-by` trailers at the end of the commit message. Instead,
45-
use the `Assiged-by` trailer to indicate that the commit was generated by
46-
an AI assistant, if necessary. The format of the `Assiged-by` trailer should
45+
use the `Assisted-by` trailer to indicate that the commit was generated by
46+
an AI assistant, if necessary. The format of the `Assisted-by` trailer should
4747
be:
4848

4949
~~~~

CHANGES.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ Version 2.1.6
88

99
To be released.
1010

11+
### @fedify/astro
12+
13+
- Restored the npm entrypoint contract for `@fedify/astro` by making the
14+
build emit _dist/\*.js_ and _dist/\*.d.ts_ files that match the published
15+
package metadata again. This fixes package resolution failures caused by
16+
_package.json_ exporting files that did not exist in the npm tarball.
17+
[[#699], [#701]]
18+
19+
[#699]: https://github.com/fedify-dev/fedify/issues/699
20+
[#701]: https://github.com/fedify-dev/fedify/pull/701
21+
1122
### @fedify/cli
1223

1324
- Fixed `fedify lookup` failing to look up URLs on private or localhost

packages/astro/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"build": "pnpm --filter @fedify/astro... run build:self",
6262
"prepack": "pnpm build",
6363
"prepublish": "pnpm build",
64+
"pretest": "pnpm build",
6465
"test": "node --experimental-transform-types --test"
6566
}
6667
}

packages/astro/src/package.test.ts

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import { deepStrictEqual, strictEqual } from "node:assert/strict";
2+
import { access, readFile } from "node:fs/promises";
3+
import { createRequire } from "node:module";
4+
import { dirname, resolve } from "node:path";
5+
import test from "node:test";
6+
import { fileURLToPath } from "node:url";
7+
import type {
8+
Federation,
9+
FederationFetchOptions,
10+
} from "@fedify/fedify/federation";
11+
import type { APIContext } from "astro";
12+
13+
const require = createRequire(import.meta.url);
14+
const packageDir = resolve(dirname(fileURLToPath(import.meta.url)), "..");
15+
16+
type MockFederation<TContextData> = Pick<Federation<TContextData>, "fetch">;
17+
18+
function toFederation<TContextData>(
19+
federation: MockFederation<TContextData>,
20+
): Federation<TContextData> {
21+
return federation as Federation<TContextData>;
22+
}
23+
24+
function toApiContext(context: Pick<APIContext, "request">): APIContext {
25+
return context as APIContext;
26+
}
27+
28+
function expectResponse(response: void | Response): Response {
29+
if (!(response instanceof Response)) {
30+
throw new TypeError("Expected middleware to return a Response");
31+
}
32+
return response;
33+
}
34+
35+
function expectTarget(actual: unknown, expected: string, key: string): string {
36+
strictEqual(actual, expected, `Expected ${key} to be ${expected}`);
37+
return actual;
38+
}
39+
40+
async function assertTargetExists(path: string): Promise<void> {
41+
await access(resolve(packageDir, path));
42+
}
43+
44+
test("self-reference ESM import exposes working Astro integration API", async () => {
45+
const mod = await import("@fedify/astro");
46+
47+
strictEqual(typeof mod.fedifyIntegration, "function");
48+
strictEqual(typeof mod.fedifyMiddleware, "function");
49+
50+
const integration = mod.fedifyIntegration();
51+
strictEqual(integration.name, "@fedify/astro");
52+
53+
let capturedConfig: unknown;
54+
(
55+
integration.hooks as Record<
56+
"astro:config:setup",
57+
(args: { updateConfig(config: unknown): void }) => void
58+
>
59+
)["astro:config:setup"]({
60+
updateConfig(config) {
61+
capturedConfig = config;
62+
},
63+
});
64+
deepStrictEqual(capturedConfig, {
65+
vite: {
66+
ssr: {
67+
noExternal: ["@fedify/fedify", "@fedify/vocab"],
68+
},
69+
},
70+
});
71+
72+
let capturedRequest: Request | undefined;
73+
let capturedContextData: unknown;
74+
const middleware = mod.fedifyMiddleware(
75+
toFederation<string>({
76+
async fetch(
77+
request: Request,
78+
options: FederationFetchOptions<string>,
79+
) {
80+
capturedRequest = request;
81+
capturedContextData = options.contextData;
82+
if (options.onNotAcceptable == null) {
83+
throw new TypeError("Expected onNotAcceptable to be defined");
84+
}
85+
return await options.onNotAcceptable(request);
86+
},
87+
}),
88+
() => "test-context",
89+
);
90+
91+
const request = new Request("https://example.com/");
92+
const response = expectResponse(
93+
await middleware(
94+
toApiContext({ request }),
95+
() => Promise.resolve(new Response("Not found", { status: 404 })),
96+
),
97+
);
98+
strictEqual(capturedRequest, request);
99+
strictEqual(capturedContextData, "test-context");
100+
strictEqual(response.status, 406);
101+
strictEqual(response.headers.get("Vary"), "Accept");
102+
});
103+
104+
test(
105+
"self-reference CommonJS require exposes working Astro middleware API",
106+
{ skip: "Deno" in globalThis },
107+
async () => {
108+
const packageJson = JSON.parse(
109+
await readFile(resolve(packageDir, "package.json"), "utf8"),
110+
);
111+
const exportMap = packageJson.exports["."];
112+
const targets = [
113+
expectTarget(packageJson.main, "./dist/mod.cjs", "package.json main"),
114+
expectTarget(packageJson.module, "./dist/mod.js", "package.json module"),
115+
expectTarget(packageJson.types, "./dist/mod.d.ts", "package.json types"),
116+
expectTarget(
117+
exportMap.require.types,
118+
"./dist/mod.d.cts",
119+
'package.json exports["."].require.types',
120+
),
121+
expectTarget(
122+
exportMap.require.default,
123+
"./dist/mod.cjs",
124+
'package.json exports["."].require.default',
125+
),
126+
expectTarget(
127+
exportMap.import.types,
128+
"./dist/mod.d.ts",
129+
'package.json exports["."].import.types',
130+
),
131+
expectTarget(
132+
exportMap.import.default,
133+
"./dist/mod.js",
134+
'package.json exports["."].import.default',
135+
),
136+
];
137+
138+
for (const target of new Set(targets)) {
139+
await assertTargetExists(target);
140+
}
141+
142+
const mod = require("@fedify/astro") as typeof import("@fedify/astro");
143+
144+
strictEqual(typeof mod.fedifyIntegration, "function");
145+
strictEqual(typeof mod.fedifyMiddleware, "function");
146+
147+
let nextCalled = false;
148+
const middleware = mod.fedifyMiddleware(
149+
toFederation<void>({
150+
async fetch(
151+
_request: Request,
152+
options: FederationFetchOptions<void>,
153+
) {
154+
if (options.onNotFound == null) {
155+
throw new TypeError("Expected onNotFound to be defined");
156+
}
157+
return await options.onNotFound(
158+
new Request("https://example.com/actor"),
159+
);
160+
},
161+
}),
162+
() => undefined,
163+
);
164+
165+
const response = expectResponse(
166+
await middleware(
167+
toApiContext({ request: new Request("https://example.com/inbox") }),
168+
() => {
169+
nextCalled = true;
170+
return Promise.resolve(new Response("Handled by Astro"));
171+
},
172+
),
173+
);
174+
175+
strictEqual(nextCalled, true);
176+
strictEqual(response.status, 200);
177+
strictEqual(await response.text(), "Handled by Astro");
178+
},
179+
);

packages/astro/tsdown.config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,10 @@ export default defineConfig({
55
dts: true,
66
format: ["esm", "cjs"],
77
platform: "node",
8+
outExtensions({ format }) {
9+
return {
10+
js: format === "cjs" ? ".cjs" : ".js",
11+
dts: format === "cjs" ? ".d.cts" : ".d.ts",
12+
};
13+
},
814
});

0 commit comments

Comments
 (0)