import { describe, expect, it } from "vitest"; import { isSiloHttpRateLimitExempt, SiloFixedWindowRateLimiter, } from "../../src/deployment/siloRateLimit.js"; describe("Silo fixed-window rate limiter", () => { it("returns an explicit retry interval and resets at the next window", () => { const limiter = new SiloFixedWindowRateLimiter(2, 60_000, 1_000); expect(limiter.consume(1_000)).toEqual({ allowed: true }); expect(limiter.consume(2_000)).toEqual({ allowed: true }); expect(limiter.consume(3_000)).toEqual({ allowed: false, retryAfterSeconds: 58 }); expect(limiter.consume(61_000)).toEqual({ allowed: true }); }); }); describe("isSiloHttpRateLimitExempt", () => { it("exempts healthz, SPA static assets, and the admin HTML shell", () => { expect(isSiloHttpRateLimitExempt("/api/healthz")).toBe(true); expect(isSiloHttpRateLimitExempt("/_app/version.json")).toBe(true); expect(isSiloHttpRateLimitExempt("/_app/immutable/chunks/foo.js?v=1")).toBe(true); expect(isSiloHttpRateLimitExempt("/favicon.ico")).toBe(true); expect(isSiloHttpRateLimitExempt("/favicon.svg")).toBe(true); expect(isSiloHttpRateLimitExempt("/robots.txt")).toBe(true); expect(isSiloHttpRateLimitExempt("/admin")).toBe(true); expect(isSiloHttpRateLimitExempt("/admin/members")).toBe(true); expect(isSiloHttpRateLimitExempt("/admin/org/para-26071100/members")).toBe(true); }); it("exempts the filelib-web SPA assets and both of its mount prefixes", () => { // appDir 改名为 `_filelib`(见 src/database/static.ts):同一份产物服务 // 老师端 /app 与管理后台 /database。 expect(isSiloHttpRateLimitExempt("/_filelib/version.json")).toBe(true); expect(isSiloHttpRateLimitExempt("/_filelib/immutable/chunks/foo.js?v=1")).toBe(true); expect(isSiloHttpRateLimitExempt("/app")).toBe(true); expect(isSiloHttpRateLimitExempt("/app/dev-login-teacher")).toBe(true); expect(isSiloHttpRateLimitExempt("/database")).toBe(true); expect(isSiloHttpRateLimitExempt("/database/dashboard/users")).toBe(true); }); it("still rate-limits APIs and auth", () => { expect(isSiloHttpRateLimitExempt("/api/me")).toBe(false); expect(isSiloHttpRateLimitExempt("/api/org/x/members")).toBe(false); expect(isSiloHttpRateLimitExempt("/auth/feishu/x")).toBe(false); expect(isSiloHttpRateLimitExempt("/auth/feishu/callback?code=1")).toBe(false); expect(isSiloHttpRateLimitExempt("/")).toBe(false); }); });