@haruhimemoe/next-kit 0.1.0
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.
- package/CHANGELOG.md +21 -0
- package/LICENSE +21 -0
- package/README.md +210 -0
- package/dist/auth/create.d.ts +204 -0
- package/dist/auth/create.js +102 -0
- package/dist/auth/index.d.ts +13 -0
- package/dist/auth/index.js +13 -0
- package/dist/auth/indexes.d.ts +23 -0
- package/dist/auth/indexes.js +44 -0
- package/dist/auth/osu-id.d.ts +10 -0
- package/dist/auth/osu-id.js +10 -0
- package/dist/auth/osu.d.ts +80 -0
- package/dist/auth/osu.js +67 -0
- package/dist/auth/session.d.ts +48 -0
- package/dist/auth/session.js +32 -0
- package/dist/auth-react/RestoreSignedIn.d.ts +33 -0
- package/dist/auth-react/RestoreSignedIn.js +38 -0
- package/dist/auth-react/account-store.d.ts +55 -0
- package/dist/auth-react/account-store.js +78 -0
- package/dist/auth-react/index.d.ts +17 -0
- package/dist/auth-react/index.js +17 -0
- package/dist/auth-react/marker.d.ts +35 -0
- package/dist/auth-react/marker.js +30 -0
- package/dist/auth-react/sign-in.d.ts +24 -0
- package/dist/auth-react/sign-in.js +24 -0
- package/dist/auth-react/use-account.d.ts +52 -0
- package/dist/auth-react/use-account.js +52 -0
- package/dist/env/errors.d.ts +18 -0
- package/dist/env/errors.js +21 -0
- package/dist/env/index.d.ts +13 -0
- package/dist/env/index.js +13 -0
- package/dist/env/optional.d.ts +54 -0
- package/dist/env/optional.js +84 -0
- package/dist/env/osu-app.d.ts +24 -0
- package/dist/env/osu-app.js +32 -0
- package/dist/env/server-env.d.ts +63 -0
- package/dist/env/server-env.js +88 -0
- package/dist/mongo/client.d.ts +56 -0
- package/dist/mongo/client.js +72 -0
- package/dist/mongo/collections.d.ts +16 -0
- package/dist/mongo/collections.js +29 -0
- package/dist/mongo/duplicate.d.ts +16 -0
- package/dist/mongo/duplicate.js +16 -0
- package/dist/mongo/index.d.ts +13 -0
- package/dist/mongo/index.js +13 -0
- package/dist/mongo/indexes.d.ts +55 -0
- package/dist/mongo/indexes.js +81 -0
- package/dist/server/body.d.ts +57 -0
- package/dist/server/body.js +74 -0
- package/dist/server/budget.d.ts +39 -0
- package/dist/server/budget.js +46 -0
- package/dist/server/client-ip.d.ts +30 -0
- package/dist/server/client-ip.js +92 -0
- package/dist/server/counter.d.ts +80 -0
- package/dist/server/counter.js +76 -0
- package/dist/server/cross-site.d.ts +32 -0
- package/dist/server/cross-site.js +36 -0
- package/dist/server/errors.d.ts +57 -0
- package/dist/server/errors.js +55 -0
- package/dist/server/index.d.ts +20 -0
- package/dist/server/index.js +20 -0
- package/dist/server/machine-auth.d.ts +55 -0
- package/dist/server/machine-auth.js +74 -0
- package/dist/server/rate-limit.d.ts +75 -0
- package/dist/server/rate-limit.js +101 -0
- package/dist/server/safe-next.d.ts +36 -0
- package/dist/server/safe-next.js +42 -0
- package/dist/server/security-txt.d.ts +32 -0
- package/dist/server/security-txt.js +31 -0
- package/dist/testing/env.d.ts +29 -0
- package/dist/testing/env.js +33 -0
- package/dist/testing/index.d.ts +13 -0
- package/dist/testing/index.js +13 -0
- package/dist/testing/mongo.d.ts +44 -0
- package/dist/testing/mongo.js +46 -0
- package/dist/testing/msw.d.ts +18 -0
- package/dist/testing/msw.js +24 -0
- package/package.json +140 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/server/safe-next.ts
|
|
3
|
+
* @desc Where to go after sign-in. Only same-site absolute paths pass; anything else (other
|
|
4
|
+
* hosts, protocol-relative, backslashes, control characters, the sign-in page itself)
|
|
5
|
+
* becomes the caller's fallback, a page every signed-in user can open. Browser-safe, so
|
|
6
|
+
* @haruhimemoe/next-kit/auth-react exports it too. Moved from pools (src/utils/safe-next.ts);
|
|
7
|
+
* packs' copy let /signin through.
|
|
8
|
+
* @author David @dvhsh (https://dvh.sh)
|
|
9
|
+
* @created Mon Sep 28, 2026
|
|
10
|
+
* @modified Mon Sep 28, 2026
|
|
11
|
+
*/
|
|
12
|
+
/** The sign-in page both sites use. */
|
|
13
|
+
export const DEFAULT_SIGN_IN_PATH = "/signin";
|
|
14
|
+
/** A `next` longer than this is refused unread. */
|
|
15
|
+
export const MAX_NEXT_LENGTH = 512;
|
|
16
|
+
const hasControlCharacter = (value) => [...value].some((char) => char.charCodeAt(0) < 0x20 || char.charCodeAt(0) === 0x7f);
|
|
17
|
+
const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
18
|
+
/**
|
|
19
|
+
* @function safeNextPath
|
|
20
|
+
* @param raw {string | null | undefined} untrusted ?next= value
|
|
21
|
+
* @param options {SafeNextOptions} the fallback and the sign-in page
|
|
22
|
+
* @returns {string} a same-site path, or the fallback
|
|
23
|
+
*/
|
|
24
|
+
export const safeNextPath = (raw, { fallback, signInPath = DEFAULT_SIGN_IN_PATH }) => {
|
|
25
|
+
if (!raw || raw.length > MAX_NEXT_LENGTH)
|
|
26
|
+
return fallback;
|
|
27
|
+
if (!raw.startsWith("/") || raw.startsWith("//"))
|
|
28
|
+
return fallback;
|
|
29
|
+
if (raw.includes("\\") || hasControlCharacter(raw))
|
|
30
|
+
return fallback;
|
|
31
|
+
// The sign-in page with a session goes on to `next`: back to itself would never end.
|
|
32
|
+
if (new RegExp(`^${escapeRegExp(signInPath)}(?:[/?#]|$)`).test(raw))
|
|
33
|
+
return fallback;
|
|
34
|
+
return raw;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* @function signInHref
|
|
38
|
+
* @param next {string} where to land after signing in
|
|
39
|
+
* @param signInPath {string} the sign-in page (default DEFAULT_SIGN_IN_PATH)
|
|
40
|
+
* @returns {string} the sign-in link carrying it, like /signin?next=%2Fpacks
|
|
41
|
+
*/
|
|
42
|
+
export const signInHref = (next, signInPath = DEFAULT_SIGN_IN_PATH) => `${signInPath}?next=${encodeURIComponent(next)}`;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/server/security-txt.ts
|
|
3
|
+
* @desc /.well-known/security.txt (RFC 9116): where to report a vulnerability, when the file goes
|
|
4
|
+
* stale (a year after it was built, so a deploy rebuilds it), and the policy. Byte-identical
|
|
5
|
+
* in packs and pools (src/utils/security-txt.ts), which read their SITE constants; the
|
|
6
|
+
* caller passes them here.
|
|
7
|
+
* @author David @dvhsh (https://dvh.sh)
|
|
8
|
+
* @created Mon Sep 28, 2026
|
|
9
|
+
* @modified Mon Sep 28, 2026
|
|
10
|
+
*/
|
|
11
|
+
/** RFC 9116 asks for an Expires less than a year out. */
|
|
12
|
+
export declare const SECURITY_TXT_LIFETIME_DAYS = 365;
|
|
13
|
+
/** Where the file is served. */
|
|
14
|
+
export declare const SECURITY_TXT_PATH = "/.well-known/security.txt";
|
|
15
|
+
/** buildSecurityTxt's input. */
|
|
16
|
+
export type SecurityTxtOptions = {
|
|
17
|
+
/** Where to report, as an email address (becomes a mailto: Contact). */
|
|
18
|
+
contactEmail: string;
|
|
19
|
+
/** The site's origin, like https://pools.haruhime.moe (no trailing slash). */
|
|
20
|
+
siteUrl: string;
|
|
21
|
+
/** The security policy, like the repo's SECURITY.md. */
|
|
22
|
+
policyUrl: string;
|
|
23
|
+
/** When the file is built (build time for a static route). */
|
|
24
|
+
now: Date;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* @function buildSecurityTxt
|
|
28
|
+
* @param options {SecurityTxtOptions} contact, site, policy and build time
|
|
29
|
+
* @returns {string} the security.txt body: Contact, Expires, Preferred-Languages, Canonical,
|
|
30
|
+
* Policy, one field per line, ending in one newline
|
|
31
|
+
*/
|
|
32
|
+
export declare const buildSecurityTxt: ({ contactEmail, siteUrl, policyUrl, now, }: SecurityTxtOptions) => string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/server/security-txt.ts
|
|
3
|
+
* @desc /.well-known/security.txt (RFC 9116): where to report a vulnerability, when the file goes
|
|
4
|
+
* stale (a year after it was built, so a deploy rebuilds it), and the policy. Byte-identical
|
|
5
|
+
* in packs and pools (src/utils/security-txt.ts), which read their SITE constants; the
|
|
6
|
+
* caller passes them here.
|
|
7
|
+
* @author David @dvhsh (https://dvh.sh)
|
|
8
|
+
* @created Mon Sep 28, 2026
|
|
9
|
+
* @modified Mon Sep 28, 2026
|
|
10
|
+
*/
|
|
11
|
+
/** RFC 9116 asks for an Expires less than a year out. */
|
|
12
|
+
export const SECURITY_TXT_LIFETIME_DAYS = 365;
|
|
13
|
+
/** Where the file is served. */
|
|
14
|
+
export const SECURITY_TXT_PATH = "/.well-known/security.txt";
|
|
15
|
+
/**
|
|
16
|
+
* @function buildSecurityTxt
|
|
17
|
+
* @param options {SecurityTxtOptions} contact, site, policy and build time
|
|
18
|
+
* @returns {string} the security.txt body: Contact, Expires, Preferred-Languages, Canonical,
|
|
19
|
+
* Policy, one field per line, ending in one newline
|
|
20
|
+
*/
|
|
21
|
+
export const buildSecurityTxt = ({ contactEmail, siteUrl, policyUrl, now, }) => {
|
|
22
|
+
const expires = new Date(now.getTime() + SECURITY_TXT_LIFETIME_DAYS * 86_400_000);
|
|
23
|
+
const lines = [
|
|
24
|
+
`Contact: mailto:${contactEmail}`,
|
|
25
|
+
`Expires: ${expires.toISOString()}`,
|
|
26
|
+
"Preferred-Languages: en",
|
|
27
|
+
`Canonical: ${siteUrl}${SECURITY_TXT_PATH}`,
|
|
28
|
+
`Policy: ${policyUrl}`,
|
|
29
|
+
];
|
|
30
|
+
return `${lines.join("\n")}\n`;
|
|
31
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/testing/env.ts
|
|
3
|
+
* @desc Fake env for tests: a complete, valid set of the osu! app's five variables (no real
|
|
4
|
+
* secrets) and stubEnv, which puts values in process.env through Vitest (undo with
|
|
5
|
+
* vi.unstubAllEnvs). Moved from packs and pools (tests/helpers/server-env.ts, identical).
|
|
6
|
+
* @author David @dvhsh (https://dvh.sh)
|
|
7
|
+
* @created Mon Sep 28, 2026
|
|
8
|
+
* @modified Mon Sep 28, 2026
|
|
9
|
+
*/
|
|
10
|
+
/** A complete, valid osu! app env. MONGODB_URI equals the placeholder; tests replace it. */
|
|
11
|
+
export declare const TEST_OSU_APP_ENV: Readonly<{
|
|
12
|
+
MONGODB_URI: "mongodb://127.0.0.1:27017";
|
|
13
|
+
BETTER_AUTH_SECRET: "t8Vq2Lm5Xr9Kc1Wz4Hn7Pb3Jd6Fs0Gy2Qe5R";
|
|
14
|
+
BETTER_AUTH_URL: "http://localhost:3000";
|
|
15
|
+
OSU_CLIENT_ID: "1";
|
|
16
|
+
OSU_CLIENT_SECRET: "test-osu-client-secret";
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* @function stubEnv
|
|
20
|
+
* @param values {Record<string, string>} variables to set
|
|
21
|
+
* @returns {void} stubs each into process.env with vi.stubEnv
|
|
22
|
+
*/
|
|
23
|
+
export declare const stubEnv: (values: Record<string, string>) => void;
|
|
24
|
+
/**
|
|
25
|
+
* @function stubOsuAppEnv
|
|
26
|
+
* @param overrides {Record<string, string>} values to change or add
|
|
27
|
+
* @returns {void} stubs TEST_OSU_APP_ENV, with the overrides, into process.env
|
|
28
|
+
*/
|
|
29
|
+
export declare const stubOsuAppEnv: (overrides?: Record<string, string>) => void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/testing/env.ts
|
|
3
|
+
* @desc Fake env for tests: a complete, valid set of the osu! app's five variables (no real
|
|
4
|
+
* secrets) and stubEnv, which puts values in process.env through Vitest (undo with
|
|
5
|
+
* vi.unstubAllEnvs). Moved from packs and pools (tests/helpers/server-env.ts, identical).
|
|
6
|
+
* @author David @dvhsh (https://dvh.sh)
|
|
7
|
+
* @created Mon Sep 28, 2026
|
|
8
|
+
* @modified Mon Sep 28, 2026
|
|
9
|
+
*/
|
|
10
|
+
import { vi } from "vitest";
|
|
11
|
+
/** A complete, valid osu! app env. MONGODB_URI equals the placeholder; tests replace it. */
|
|
12
|
+
export const TEST_OSU_APP_ENV = Object.freeze({
|
|
13
|
+
MONGODB_URI: "mongodb://127.0.0.1:27017",
|
|
14
|
+
BETTER_AUTH_SECRET: "t8Vq2Lm5Xr9Kc1Wz4Hn7Pb3Jd6Fs0Gy2Qe5R",
|
|
15
|
+
BETTER_AUTH_URL: "http://localhost:3000",
|
|
16
|
+
OSU_CLIENT_ID: "1",
|
|
17
|
+
OSU_CLIENT_SECRET: "test-osu-client-secret",
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* @function stubEnv
|
|
21
|
+
* @param values {Record<string, string>} variables to set
|
|
22
|
+
* @returns {void} stubs each into process.env with vi.stubEnv
|
|
23
|
+
*/
|
|
24
|
+
export const stubEnv = (values) => {
|
|
25
|
+
for (const [key, value] of Object.entries(values))
|
|
26
|
+
vi.stubEnv(key, value);
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* @function stubOsuAppEnv
|
|
30
|
+
* @param overrides {Record<string, string>} values to change or add
|
|
31
|
+
* @returns {void} stubs TEST_OSU_APP_ENV, with the overrides, into process.env
|
|
32
|
+
*/
|
|
33
|
+
export const stubOsuAppEnv = (overrides = {}) => stubEnv({ ...TEST_OSU_APP_ENV, ...overrides });
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/testing/index.ts
|
|
3
|
+
* @desc @haruhimemoe/next-kit/testing: Vitest helpers both apps shared. One in-memory MongoDB per
|
|
4
|
+
* run (a globalSetup) and per-file collection clearing, an msw server that refuses unhandled
|
|
5
|
+
* requests, and a fake osu! app env. Needs vitest, and msw or mongodb-memory-server for
|
|
6
|
+
* their helpers. Never import it from app code.
|
|
7
|
+
* @author David @dvhsh (https://dvh.sh)
|
|
8
|
+
* @created Mon Sep 28, 2026
|
|
9
|
+
* @modified Mon Sep 28, 2026
|
|
10
|
+
*/
|
|
11
|
+
export { stubEnv, stubOsuAppEnv, TEST_OSU_APP_ENV } from "./env.js";
|
|
12
|
+
export { BETTER_AUTH_COLLECTIONS, setupTestDb, startMemoryMongo, type TestDbOptions, } from "./mongo.js";
|
|
13
|
+
export { setupMsw } from "./msw.js";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/testing/index.ts
|
|
3
|
+
* @desc @haruhimemoe/next-kit/testing: Vitest helpers both apps shared. One in-memory MongoDB per
|
|
4
|
+
* run (a globalSetup) and per-file collection clearing, an msw server that refuses unhandled
|
|
5
|
+
* requests, and a fake osu! app env. Needs vitest, and msw or mongodb-memory-server for
|
|
6
|
+
* their helpers. Never import it from app code.
|
|
7
|
+
* @author David @dvhsh (https://dvh.sh)
|
|
8
|
+
* @created Mon Sep 28, 2026
|
|
9
|
+
* @modified Mon Sep 28, 2026
|
|
10
|
+
*/
|
|
11
|
+
export { stubEnv, stubOsuAppEnv, TEST_OSU_APP_ENV } from "./env.js";
|
|
12
|
+
export { BETTER_AUTH_COLLECTIONS, setupTestDb, startMemoryMongo, } from "./mongo.js";
|
|
13
|
+
export { setupMsw } from "./msw.js";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/testing/mongo.ts
|
|
3
|
+
* @desc Test databases: a Vitest global setup that starts one in-memory MongoDB for the run and
|
|
4
|
+
* hands its URI to test files (inject("mongoUri")), and setupTestDb, which empties the
|
|
5
|
+
* given collections before each test and closes the client after the file. Moved from
|
|
6
|
+
* packs and pools (tests/setup/integration-global.ts, identical, and tests/helpers/db.ts).
|
|
7
|
+
* @author David @dvhsh (https://dvh.sh)
|
|
8
|
+
* @created Mon Sep 28, 2026
|
|
9
|
+
* @modified Mon Sep 28, 2026
|
|
10
|
+
*/
|
|
11
|
+
import type { Db } from "mongodb";
|
|
12
|
+
import type { TestProject } from "vitest/node";
|
|
13
|
+
declare module "vitest" {
|
|
14
|
+
interface ProvidedContext {
|
|
15
|
+
/** The in-memory MongoDB's URI, from startMemoryMongo. */
|
|
16
|
+
mongoUri: string;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** The collections better-auth's MongoDB adapter creates (with its default names). */
|
|
20
|
+
export declare const BETTER_AUTH_COLLECTIONS: readonly string[];
|
|
21
|
+
/**
|
|
22
|
+
* @function startMemoryMongo
|
|
23
|
+
* @param project {TestProject} the Vitest project (a globalSetup's argument)
|
|
24
|
+
* @returns {Promise<() => Promise<void>>} provides "mongoUri"; the returned teardown stops the
|
|
25
|
+
* server. Use it as a globalSetup's default export.
|
|
26
|
+
*/
|
|
27
|
+
export declare const startMemoryMongo: (project: TestProject) => Promise<() => Promise<void>>;
|
|
28
|
+
/** setupTestDb's options: how the app connects, reaches and closes its database. */
|
|
29
|
+
export type TestDbOptions = {
|
|
30
|
+
/** Connects (and runs the app's start-up work, like index builds). */
|
|
31
|
+
connect: () => Promise<unknown>;
|
|
32
|
+
/** The connected database. */
|
|
33
|
+
db: () => Db;
|
|
34
|
+
/** Closes and forgets the client. */
|
|
35
|
+
close: () => Promise<unknown>;
|
|
36
|
+
/** Every collection a test may write to; emptied before each test. */
|
|
37
|
+
collections: readonly string[];
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* @function setupTestDb
|
|
41
|
+
* @param options {TestDbOptions} connect, db, close and the collections to empty
|
|
42
|
+
* @returns {void} registers beforeEach (connect, then empty) and afterAll (close) hooks
|
|
43
|
+
*/
|
|
44
|
+
export declare const setupTestDb: ({ connect, db, close, collections }: TestDbOptions) => void;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/testing/mongo.ts
|
|
3
|
+
* @desc Test databases: a Vitest global setup that starts one in-memory MongoDB for the run and
|
|
4
|
+
* hands its URI to test files (inject("mongoUri")), and setupTestDb, which empties the
|
|
5
|
+
* given collections before each test and closes the client after the file. Moved from
|
|
6
|
+
* packs and pools (tests/setup/integration-global.ts, identical, and tests/helpers/db.ts).
|
|
7
|
+
* @author David @dvhsh (https://dvh.sh)
|
|
8
|
+
* @created Mon Sep 28, 2026
|
|
9
|
+
* @modified Mon Sep 28, 2026
|
|
10
|
+
*/
|
|
11
|
+
import { MongoMemoryServer } from "mongodb-memory-server";
|
|
12
|
+
import { afterAll, beforeEach } from "vitest";
|
|
13
|
+
/** The collections better-auth's MongoDB adapter creates (with its default names). */
|
|
14
|
+
export const BETTER_AUTH_COLLECTIONS = Object.freeze([
|
|
15
|
+
"user",
|
|
16
|
+
"session",
|
|
17
|
+
"account",
|
|
18
|
+
"verification",
|
|
19
|
+
]);
|
|
20
|
+
/**
|
|
21
|
+
* @function startMemoryMongo
|
|
22
|
+
* @param project {TestProject} the Vitest project (a globalSetup's argument)
|
|
23
|
+
* @returns {Promise<() => Promise<void>>} provides "mongoUri"; the returned teardown stops the
|
|
24
|
+
* server. Use it as a globalSetup's default export.
|
|
25
|
+
*/
|
|
26
|
+
export const startMemoryMongo = async (project) => {
|
|
27
|
+
const server = await MongoMemoryServer.create();
|
|
28
|
+
project.provide("mongoUri", server.getUri());
|
|
29
|
+
return async () => {
|
|
30
|
+
await server.stop();
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* @function setupTestDb
|
|
35
|
+
* @param options {TestDbOptions} connect, db, close and the collections to empty
|
|
36
|
+
* @returns {void} registers beforeEach (connect, then empty) and afterAll (close) hooks
|
|
37
|
+
*/
|
|
38
|
+
export const setupTestDb = ({ connect, db, close, collections }) => {
|
|
39
|
+
beforeEach(async () => {
|
|
40
|
+
await connect();
|
|
41
|
+
await Promise.all(collections.map((name) => db().collection(name).deleteMany({})));
|
|
42
|
+
});
|
|
43
|
+
afterAll(async () => {
|
|
44
|
+
await close();
|
|
45
|
+
});
|
|
46
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/testing/msw.ts
|
|
3
|
+
* @desc setupMsw(...handlers): an msw server for the test file, listening before the tests with
|
|
4
|
+
* every unhandled request an error (so nothing reaches osu!, the mirror or another app),
|
|
5
|
+
* reset after each test, closed after the file. Moved from packs and pools
|
|
6
|
+
* (tests/helpers/msw.ts).
|
|
7
|
+
* @author David @dvhsh (https://dvh.sh)
|
|
8
|
+
* @created Mon Sep 28, 2026
|
|
9
|
+
* @modified Mon Sep 28, 2026
|
|
10
|
+
*/
|
|
11
|
+
import type { RequestHandler } from "msw";
|
|
12
|
+
import { type SetupServer } from "msw/node";
|
|
13
|
+
/**
|
|
14
|
+
* @function setupMsw
|
|
15
|
+
* @param handlers {RequestHandler[]} the file's default handlers
|
|
16
|
+
* @returns {SetupServer} the server (use server.use() to add handlers in a test)
|
|
17
|
+
*/
|
|
18
|
+
export declare const setupMsw: (...handlers: RequestHandler[]) => SetupServer;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file src/testing/msw.ts
|
|
3
|
+
* @desc setupMsw(...handlers): an msw server for the test file, listening before the tests with
|
|
4
|
+
* every unhandled request an error (so nothing reaches osu!, the mirror or another app),
|
|
5
|
+
* reset after each test, closed after the file. Moved from packs and pools
|
|
6
|
+
* (tests/helpers/msw.ts).
|
|
7
|
+
* @author David @dvhsh (https://dvh.sh)
|
|
8
|
+
* @created Mon Sep 28, 2026
|
|
9
|
+
* @modified Mon Sep 28, 2026
|
|
10
|
+
*/
|
|
11
|
+
import { setupServer } from "msw/node";
|
|
12
|
+
import { afterAll, afterEach, beforeAll } from "vitest";
|
|
13
|
+
/**
|
|
14
|
+
* @function setupMsw
|
|
15
|
+
* @param handlers {RequestHandler[]} the file's default handlers
|
|
16
|
+
* @returns {SetupServer} the server (use server.use() to add handlers in a test)
|
|
17
|
+
*/
|
|
18
|
+
export const setupMsw = (...handlers) => {
|
|
19
|
+
const server = setupServer(...handlers);
|
|
20
|
+
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
|
|
21
|
+
afterEach(() => server.resetHandlers());
|
|
22
|
+
afterAll(() => server.close());
|
|
23
|
+
return server;
|
|
24
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@haruhimemoe/next-kit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The Next.js server plumbing packs.haruhime.moe and pools.haruhime.moe share: JSON route helpers, rate limits and budgets in MongoDB, bearer machine auth, zod env parsing, a connect-once MongoDB client with safe index builds, better-auth with osu! sign-in, and the signed-in marker and account store for the browser.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"nextjs",
|
|
7
|
+
"next.js",
|
|
8
|
+
"better-auth",
|
|
9
|
+
"osu",
|
|
10
|
+
"osu!",
|
|
11
|
+
"mongodb",
|
|
12
|
+
"rate limit",
|
|
13
|
+
"zod"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/haruhimemoe/next-kit#readme",
|
|
16
|
+
"bugs": "https://github.com/haruhimemoe/next-kit/issues",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/haruhimemoe/next-kit.git"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "David (https://dvh.sh)",
|
|
23
|
+
"type": "module",
|
|
24
|
+
"exports": {
|
|
25
|
+
"./server": {
|
|
26
|
+
"types": "./dist/server/index.d.ts",
|
|
27
|
+
"default": "./dist/server/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./env": {
|
|
30
|
+
"types": "./dist/env/index.d.ts",
|
|
31
|
+
"default": "./dist/env/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./mongo": {
|
|
34
|
+
"types": "./dist/mongo/index.d.ts",
|
|
35
|
+
"default": "./dist/mongo/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./auth": {
|
|
38
|
+
"types": "./dist/auth/index.d.ts",
|
|
39
|
+
"default": "./dist/auth/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./auth-react": {
|
|
42
|
+
"types": "./dist/auth-react/index.d.ts",
|
|
43
|
+
"default": "./dist/auth-react/index.js"
|
|
44
|
+
},
|
|
45
|
+
"./testing": {
|
|
46
|
+
"types": "./dist/testing/index.d.ts",
|
|
47
|
+
"default": "./dist/testing/index.js"
|
|
48
|
+
},
|
|
49
|
+
"./package.json": "./package.json"
|
|
50
|
+
},
|
|
51
|
+
"files": [
|
|
52
|
+
"dist",
|
|
53
|
+
"CHANGELOG.md"
|
|
54
|
+
],
|
|
55
|
+
"sideEffects": false,
|
|
56
|
+
"engines": {
|
|
57
|
+
"node": ">=22.12"
|
|
58
|
+
},
|
|
59
|
+
"packageManager": "bun@1.4.2",
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"access": "public",
|
|
62
|
+
"provenance": true
|
|
63
|
+
},
|
|
64
|
+
"scripts": {
|
|
65
|
+
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
66
|
+
"build": "bun run clean && tsc -p tsconfig.build.json",
|
|
67
|
+
"check": "biome check .",
|
|
68
|
+
"check:fix": "biome check --write .",
|
|
69
|
+
"typecheck": "tsc --noEmit",
|
|
70
|
+
"test": "vitest run",
|
|
71
|
+
"test:coverage": "vitest run --coverage",
|
|
72
|
+
"test:watch": "vitest",
|
|
73
|
+
"test:dist": "bun run build && node scripts/smoke.mjs",
|
|
74
|
+
"prepublishOnly": "bun run check && bun run typecheck && bun run test && bun run test:dist",
|
|
75
|
+
"check:consumer": "bun run build && node scripts/check-consumer.mjs"
|
|
76
|
+
},
|
|
77
|
+
"peerDependencies": {
|
|
78
|
+
"@haruhimemoe/osu": "^0.2.0 || ^0.3.0",
|
|
79
|
+
"better-auth": "^1.7.5",
|
|
80
|
+
"mongodb": "^7.6.0",
|
|
81
|
+
"mongodb-memory-server": "^11.3.0",
|
|
82
|
+
"mongoose": "^9.10.2",
|
|
83
|
+
"msw": "^2.15.0",
|
|
84
|
+
"next": "^16.3.6",
|
|
85
|
+
"react": "^19.3.0",
|
|
86
|
+
"vitest": "^5.0.1",
|
|
87
|
+
"zod": "^4.6.5"
|
|
88
|
+
},
|
|
89
|
+
"peerDependenciesMeta": {
|
|
90
|
+
"@haruhimemoe/osu": {
|
|
91
|
+
"optional": true
|
|
92
|
+
},
|
|
93
|
+
"better-auth": {
|
|
94
|
+
"optional": true
|
|
95
|
+
},
|
|
96
|
+
"mongodb": {
|
|
97
|
+
"optional": true
|
|
98
|
+
},
|
|
99
|
+
"mongodb-memory-server": {
|
|
100
|
+
"optional": true
|
|
101
|
+
},
|
|
102
|
+
"mongoose": {
|
|
103
|
+
"optional": true
|
|
104
|
+
},
|
|
105
|
+
"msw": {
|
|
106
|
+
"optional": true
|
|
107
|
+
},
|
|
108
|
+
"next": {
|
|
109
|
+
"optional": true
|
|
110
|
+
},
|
|
111
|
+
"react": {
|
|
112
|
+
"optional": true
|
|
113
|
+
},
|
|
114
|
+
"vitest": {
|
|
115
|
+
"optional": true
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"devDependencies": {
|
|
119
|
+
"@biomejs/biome": "2.5.14",
|
|
120
|
+
"@haruhimemoe/osu": "0.2.0",
|
|
121
|
+
"@testing-library/dom": "10.4.2",
|
|
122
|
+
"@testing-library/react": "16.3.3",
|
|
123
|
+
"@types/node": "26.6.2",
|
|
124
|
+
"@types/react": "19.3.0",
|
|
125
|
+
"@types/react-dom": "19.3.0",
|
|
126
|
+
"@vitest/coverage-v8": "5.0.1",
|
|
127
|
+
"better-auth": "1.7.5",
|
|
128
|
+
"jsdom": "30.1.1",
|
|
129
|
+
"mongodb": "7.6.0",
|
|
130
|
+
"mongodb-memory-server": "11.3.0",
|
|
131
|
+
"mongoose": "9.10.2",
|
|
132
|
+
"msw": "2.15.0",
|
|
133
|
+
"next": "16.3.6",
|
|
134
|
+
"react": "19.3.0",
|
|
135
|
+
"react-dom": "19.3.0",
|
|
136
|
+
"typescript": "7.0.2",
|
|
137
|
+
"vitest": "5.0.1",
|
|
138
|
+
"zod": "4.6.5"
|
|
139
|
+
}
|
|
140
|
+
}
|