Skip to content

Commit 3792cba

Browse files
Fix error in authproto by using virtual modules to load astro:db or unstorage
1 parent 3778500 commit 3792cba

File tree

12 files changed

+667
-254
lines changed

12 files changed

+667
-254
lines changed

astro-authproto/package.json

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@
2222
"types": "./dist/helpers.d.ts",
2323
"default": "./dist/helpers.js"
2424
}
25+
},
26+
"./stores/unstorage": {
27+
"import": {
28+
"types": "./dist/stores/unstorage.d.ts",
29+
"default": "./dist/stores/unstorage.js"
30+
}
31+
},
32+
"./stores/db": {
33+
"import": {
34+
"types": "./dist/stores/db.d.ts",
35+
"default": "./dist/stores/db.js"
36+
}
2537
}
2638
},
2739
"files": [
@@ -55,7 +67,6 @@
5567
},
5668
"homepage": "https://github.com/FujoWebDev/fujocoded-plugins#readme",
5769
"dependencies": {
58-
"@astrojs/db": "^0.17.1",
5970
"@atproto/api": "^0.17.3",
6071
"@atproto/identity": "^0.4.8",
6172
"@atproto/jwk-jose": "^0.1.4",
@@ -64,9 +75,15 @@
6475
"unstorage": "^1.16.1"
6576
},
6677
"devDependencies": {
67-
"tsdown": "^0.14.1"
78+
"tsdown": "^0.17.2"
6879
},
6980
"peerDependencies": {
81+
"@astrojs/db": "^0.17.1",
7082
"astro": "^5.13.0"
83+
},
84+
"peerDependenciesMeta": {
85+
"@astrojs/db": {
86+
"optional": true
87+
}
7188
}
7289
}

astro-authproto/src/components/Login.astro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface Props {
99
const { redirect: redirectUrl } = Astro.props;
1010
const currentUser = Astro.locals.loggedInUser;
1111
12+
// @ts-expect-error
1213
const { class: cssClass, 'class:list': cssClassList } = Astro.props;
1314
---
1415

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Type definitions for "fujocoded:authproto/config".
3+
*
4+
* This file declares types for fujocoded:authproto's virtual modules. These
5+
* modules are "imports" that don't map to real files, but are injected into the
6+
* application by Vite.
7+
*
8+
* We need a sepate type definition file for virtual modules, because TypeScript has
9+
* two separate modes for .d.ts files:
10+
* 1. "Script" mode, which can declare new modules (does NOT support import/export)
11+
* 2. "Module" mode, which can only augment existing modules (supports import/export)
12+
*
13+
* In this case, we need both types, so we add this file (config-module.d.ts) for module
14+
* declarations.
15+
*
16+
* See: https://www.totaltypescript.com/books/total-typescript-essentials/modules-scripts-and-declaration-files#module-augmentation-vs-module-overriding
17+
*/
18+
declare module "fujocoded:authproto/config" {
19+
export const applicationName: string;
20+
export const applicationDomain: string;
21+
export const defaultDevUser: string | null;
22+
export const externalDomain: string | undefined;
23+
export const storage: import("unstorage").Storage | null;
24+
export const scopes: string[];
25+
export const driverName: string;
26+
export const redirectAfterLogin: string;
27+
export const redirectAfterLogout: string;
28+
}
29+
30+
declare module "fujocoded:authproto/stores" {
31+
export {
32+
StateStore,
33+
SessionStore,
34+
} from "@fujocoded/authproto/stores/unstorage";
35+
}
36+
37+
// astro:db types - @astrojs/db is an optional peer dependency
38+
declare module "astro:db" {
39+
export const db: any;
40+
export function eq(column: any, value: any): any;
41+
export function defineDb(config: any): any;
42+
export function defineTable(config: any): any;
43+
export const column: {
44+
text(): any;
45+
number(): any;
46+
boolean(): any;
47+
date(): any;
48+
json(): any;
49+
};
50+
}

astro-authproto/src/index.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import type { AstroIntegration, InjectedRoute } from "astro";
22
import path from "node:path";
33
import { addVirtualImports } from "astro-integration-kit";
4-
import "@astrojs/db";
5-
import { getConfig, type ConfigOptions } from "./lib/config.js";
4+
import { getConfig, getStoresImport, type ConfigOptions } from "./lib/config.js";
65
import { readFile } from "node:fs/promises";
76

87
export const LOGGED_IN_DID_TEMPLATE = "{loggedInUser.did}";
@@ -34,8 +33,8 @@ const addOAuthRoutes = (injectRoute: (_: InjectedRoute) => void) => {
3433

3534
/**
3635
* Add two routes ATProto OAuth clients must have:
37-
* - `/client-metadata.json`, information about the client's identity
38-
* and requested access
36+
* - `/client-metadata.json`, information about the client's identity and
37+
* requested access
3938
* - `/jwks.json`, information about the cryptographic keys used in the
4039
* authorization request
4140
*/
@@ -82,6 +81,11 @@ export default (
8281
}),
8382
context: "server",
8483
},
84+
{
85+
id: "fujocoded:authproto/stores",
86+
content: getStoresImport(configOptions.driver?.name),
87+
context: "server",
88+
},
8589
],
8690
});
8791

@@ -99,17 +103,24 @@ export default (
99103
);
100104
}
101105
if (!configOptions.driver) {
102-
logger.warn(
103-
"The ATproto OAuth integration requires a configured session driver in production. This will be ok for dev mode."
104-
);
106+
if (process.env.NODE_ENV === "development") {
107+
logger.warn(
108+
"The ATproto OAuth integration requires a configured session driver in production. This will be ok for dev mode."
109+
);
110+
} else {
111+
throw new Error(
112+
"The ATproto OAuth integration requires a configured session driver in production."
113+
);
114+
}
105115
}
106116
if (!config.server.host && process.env.NODE_ENV === "development") {
107117
logger.error(
108118
"ATproto requires the local redirect URL to be 127.0.0.1 (not localhost) but your site is not running on a network address. Run `astro dev --host` to fix this."
109119
);
110120
}
111121
if (config.output === "static") {
112-
// TODO: check if a static site with some routes marked as dynamic works.
122+
// TODO: check if a static site with some routes marked as dynamic
123+
// works.
113124
logger.warn(
114125
`Your Astro output config is "static". The login status is only available on dynamically rendered pages.`
115126
);

astro-authproto/src/lib/auth.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,17 @@ import { JoseKey } from "@atproto/jwk-jose";
77
import { DidResolver } from "@atproto/identity";
88
import {
99
scopes,
10-
driverName,
1110
applicationName,
1211
externalDomain,
1312
} from "fujocoded:authproto/config";
1413

15-
const REDIRECT_PATH = "/oauth/callback";
14+
// We import the stores from the virtual module "fujocoded:authproto/stores"
15+
// so we don't force projects using this integration to bundle all our dependencies,
16+
// even for stores they don't use. Doing otherwise would cause errors if the consumer
17+
// is (for example) NOT using "astro:db", but our code requires it for the bundle.
18+
import * as Stores from "fujocoded:authproto/stores";
1619

17-
let Stores;
18-
if (driverName == "astro:db") {
19-
Stores = await import("./auth-storage-db.js");
20-
} else {
21-
Stores = await import("./auth-storage-unstorage.js");
22-
}
20+
const REDIRECT_PATH = "/oauth/callback";
2321

2422
/**
2523
* Creates OAuth client metadata for the given domain.

astro-authproto/src/lib/config.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
import type { BuiltinDriverOptions } from "unstorage";
1+
import type { BuiltinDriverOptions, BuiltinDriverName } from "unstorage";
22

33
type AstroDriverOption = { name: "astro:db"; options?: never };
4-
type OptionsType<
5-
T extends keyof BuiltinDriverOptions = keyof BuiltinDriverOptions,
6-
> = {
7-
name: T;
8-
options: BuiltinDriverOptions[T];
9-
};
4+
type OptionsType<T extends BuiltinDriverName = BuiltinDriverName> =
5+
T extends keyof BuiltinDriverOptions
6+
? { name: T; options: BuiltinDriverOptions[T] }
7+
: { name: T; options?: never };
108
export type AllDriverOptions =
119
| {
12-
[K in keyof BuiltinDriverOptions]: OptionsType<K>;
13-
}[keyof BuiltinDriverOptions]
10+
[K in BuiltinDriverName]: OptionsType<K>;
11+
}[BuiltinDriverName]
1412
| { name: "astro:db"; options?: never };
1513

1614
export type OAuthScope =
@@ -65,6 +63,13 @@ export interface ConfigOptions {
6563
*/
6664
}
6765

66+
export const getStoresImport = (driverName?: string) => {
67+
if (driverName === "astro:db") {
68+
return `export { StateStore, SessionStore } from "@fujocoded/authproto/stores/db";`;
69+
}
70+
return `export { StateStore, SessionStore } from "@fujocoded/authproto/stores/unstorage";`;
71+
};
72+
6873
export const getConfig = ({ options, isDev }: { options: ConfigOptions, isDev: boolean }) => {
6974
const finalDriver = options.driver ?? {
7075
name: "memory",
File renamed without changes.
File renamed without changes.

astro-authproto/src/types.d.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
/// <reference types="astro/client" />
2-
31
declare global {
42
namespace App {
53
interface SessionData {
@@ -16,13 +14,4 @@ declare global {
1614
}
1715
}
1816

19-
declare module "fujocoded:authproto/config" {
20-
export const applicationName: string;
21-
export const applicationDomain: string;
22-
export const defaultDevUser: string | null;
23-
export const storage: import("unstorage").Storage;
24-
export const scopes: import("./lib/config.ts").OAuthScope[];
25-
export const driverName: import("./lib/config.ts").AllDriverOptions["name"];
26-
}
27-
2817
export {};

astro-authproto/tsconfig.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
{
2-
"extends": "astro/tsconfigs/strict",
32
"compilerOptions": {
43
/* Base Options: */
54
"esModuleInterop": true,
@@ -8,7 +7,7 @@
87
"lib": ["es2022", "DOM"],
98
"allowJs": true,
109
"resolveJsonModule": true,
11-
"moduleDetection": "force",
10+
"moduleDetection": "auto",
1211
"isolatedModules": true,
1312
/* Strictness */
1413
"strict": true,
@@ -19,9 +18,9 @@
1918
"sourceMap": true,
2019
"declaration": true,
2120
"allowImportingTsExtensions": true,
22-
"noEmit": true,
23-
"types": ["./src/types.d.ts"]
21+
"noEmit": true
2422
},
2523
"include": ["./src/**/*"],
26-
"exclude": ["node_modules"]
24+
"exclude": ["node_modules"],
25+
"files": ["./src/types.d.ts", "./src/config-module.d.ts"]
2726
}

0 commit comments

Comments
 (0)