feat(core-shared): add rate-limit type primitives and manifest field

Adds IRateLimit, RateLimitBudget, RateLimitDecision to a new
rate-limit sub-module; adds RateLimited<F> brand and isRateLimited
predicate following the Captured/ConsentChecked pattern; extends
UseCaseManifest with rateLimit?: readonly RateLimitBudget[] so
features can declare rate-limit gates in their manifests.

Exports new types from @repo/core-shared/rate-limit and
@repo/core-shared/conformance. Blocks stories 02, 03, and 04.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 08:21:42 +00:00
parent a633561c82
commit c62de6fce9
12 changed files with 154 additions and 23 deletions

View File

@@ -1,18 +1,18 @@
{ {
"generatedAt": "2026-05-19T21:51:40.371Z", "generatedAt": "2026-05-20T08:21:18.294Z",
"commit": "5151454", "commit": "a633561",
"repo": { "repo": {
"statements": 97.38, "statements": 97.38,
"branches": 92.19, "branches": 92.2,
"functions": 97.1, "functions": 97.11,
"lines": 97.38, "lines": 97.38,
"counts": { "counts": {
"lf": 5801, "lf": 5807,
"lh": 5649, "lh": 5655,
"brf": 1165, "brf": 1166,
"brh": 1074, "brh": 1075,
"fnf": 345, "fnf": 346,
"fnh": 335 "fnh": 336
} }
}, },
"byPackage": { "byPackage": {
@@ -101,17 +101,17 @@
} }
}, },
"@repo/core-shared": { "@repo/core-shared": {
"statements": 98.03, "statements": 98.04,
"branches": 95.89, "branches": 95.9,
"functions": 92.08, "functions": 92.16,
"lines": 98.03, "lines": 98.04,
"counts": { "counts": {
"lf": 1067, "lf": 1073,
"lh": 1046, "lh": 1052,
"brf": 316, "brf": 317,
"brh": 303, "brh": 304,
"fnf": 101, "fnf": 102,
"fnh": 93 "fnh": 94
} }
}, },
"@repo/core-ui": { "@repo/core-ui": {

View File

@@ -6,6 +6,7 @@
"exports": { "exports": {
".": "./src/index.ts", ".": "./src/index.ts",
"./audit": "./src/audit/index.ts", "./audit": "./src/audit/index.ts",
"./rate-limit": "./src/rate-limit/index.ts",
"./conformance": "./src/conformance/index.ts", "./conformance": "./src/conformance/index.ts",
"./conformance/coverage": "./src/conformance/coverage.ts", "./conformance/coverage": "./src/conformance/coverage.ts",
"./di": "./src/di/index.ts", "./di": "./src/di/index.ts",

View File

@@ -5,6 +5,7 @@ import {
isCaptured, isCaptured,
isAudited, isAudited,
isAnalyzed, isAnalyzed,
isRateLimited,
} from "@/conformance/brand-runtime"; } from "@/conformance/brand-runtime";
describe("brand-runtime", () => { describe("brand-runtime", () => {
@@ -23,6 +24,7 @@ describe("brand-runtime", () => {
expect(isCaptured(fn)).toBe(false); expect(isCaptured(fn)).toBe(false);
expect(isAudited(fn)).toBe(false); expect(isAudited(fn)).toBe(false);
expect(isAnalyzed(fn)).toBe(false); expect(isAnalyzed(fn)).toBe(false);
expect(isRateLimited(fn)).toBe(false);
}); });
it("predicates discriminate between brands", () => { it("predicates discriminate between brands", () => {
@@ -45,6 +47,11 @@ describe("brand-runtime", () => {
const analyzed = () => {}; const analyzed = () => {};
attachBrand(analyzed, "__analyzed"); attachBrand(analyzed, "__analyzed");
expect(isAnalyzed(analyzed)).toBe(true); expect(isAnalyzed(analyzed)).toBe(true);
const rateLimited = () => {};
attachBrand(rateLimited, "__rateLimited");
expect(isRateLimited(rateLimited)).toBe(true);
expect(isInstrumented(rateLimited)).toBe(false);
}); });
it("composing brands stacks them on the same function", () => { it("composing brands stacks them on the same function", () => {
@@ -53,10 +60,12 @@ describe("brand-runtime", () => {
attachBrand(fn, "__captured"); attachBrand(fn, "__captured");
attachBrand(fn, "__audited"); attachBrand(fn, "__audited");
attachBrand(fn, "__analyzed"); attachBrand(fn, "__analyzed");
attachBrand(fn, "__rateLimited");
expect(isInstrumented(fn)).toBe(true); expect(isInstrumented(fn)).toBe(true);
expect(isCaptured(fn)).toBe(true); expect(isCaptured(fn)).toBe(true);
expect(isAudited(fn)).toBe(true); expect(isAudited(fn)).toBe(true);
expect(isAnalyzed(fn)).toBe(true); expect(isAnalyzed(fn)).toBe(true);
expect(isRateLimited(fn)).toBe(true);
}); });
it("attached brands are non-writable and non-configurable", () => { it("attached brands are non-writable and non-configurable", () => {

View File

@@ -13,14 +13,15 @@
* commitment, not a mutable flag. * commitment, not a mutable flag.
*/ */
import type { Analyzed, ConsentChecked } from "./brands"; import type { Analyzed, ConsentChecked, RateLimited } from "./brands";
type Brand = type Brand =
| "__instrumented" | "__instrumented"
| "__captured" | "__captured"
| "__audited" | "__audited"
| "__analyzed" | "__analyzed"
| "__consentChecked"; | "__consentChecked"
| "__rateLimited";
/** /**
* Attaches the brand as a non-enumerable property on the given function. * Attaches the brand as a non-enumerable property on the given function.
@@ -68,3 +69,9 @@ export function isConsentChecked<F extends object>(
): fn is ConsentChecked<F> { ): fn is ConsentChecked<F> {
return hasBrand(fn, "__consentChecked"); return hasBrand(fn, "__consentChecked");
} }
export function isRateLimited<F extends object>(
fn: unknown,
): fn is RateLimited<F> {
return hasBrand(fn, "__rateLimited");
}

View File

@@ -1,5 +1,5 @@
import { describe, it, expectTypeOf } from "vitest"; import { describe, it, expectTypeOf } from "vitest";
import type { Instrumented, Captured } from "@/conformance/brands"; import type { Instrumented, Captured, RateLimited } from "@/conformance/brands";
describe("brand types", () => { describe("brand types", () => {
it("Instrumented<F> is structurally F plus a phantom flag", () => { it("Instrumented<F> is structurally F plus a phantom flag", () => {
@@ -16,6 +16,12 @@ describe("brand types", () => {
expectTypeOf<Captured<Fn>["__captured"]>().toEqualTypeOf<true>(); expectTypeOf<Captured<Fn>["__captured"]>().toEqualTypeOf<true>();
}); });
it("RateLimited<F> is structurally F plus a phantom flag", () => {
type Fn = (n: number) => Promise<string>;
expectTypeOf<RateLimited<Fn>>().toBeCallableWith(1);
expectTypeOf<RateLimited<Fn>["__rateLimited"]>().toEqualTypeOf<true>();
});
it("brands compose without conflict", () => { it("brands compose without conflict", () => {
type Fn = (n: number) => Promise<string>; type Fn = (n: number) => Promise<string>;
type Both = Instrumented<Fn> & Captured<Fn>; type Both = Instrumented<Fn> & Captured<Fn>;

View File

@@ -11,3 +11,4 @@ export type Instrumented<F> = F & { readonly __instrumented: true };
export type Captured<F> = F & { readonly __captured: true }; export type Captured<F> = F & { readonly __captured: true };
export type Analyzed<F> = F & { readonly __analyzed: true }; export type Analyzed<F> = F & { readonly __analyzed: true };
export type ConsentChecked<F> = F & { readonly __consentChecked: true }; export type ConsentChecked<F> = F & { readonly __consentChecked: true };
export type RateLimited<F> = F & { readonly __rateLimited: true };

View File

@@ -2,7 +2,9 @@ import { describe, it, expect, expectTypeOf } from "vitest";
import { import {
defineFeature, defineFeature,
type FeatureManifest, type FeatureManifest,
type UseCaseManifest,
} from "@/conformance/define-feature"; } from "@/conformance/define-feature";
import type { RateLimitBudget } from "@/rate-limit/rate-limit.interface";
import { import {
DEFAULT_COVERAGE_BANDS, DEFAULT_COVERAGE_BANDS,
DEFAULT_MUTATION_SCORE, DEFAULT_MUTATION_SCORE,
@@ -58,6 +60,41 @@ describe("defineFeature", () => {
expectTypeOf(manifest).toMatchTypeOf<FeatureManifest>(); expectTypeOf(manifest).toMatchTypeOf<FeatureManifest>();
}); });
it("accepts an optional rateLimit array on a use case", () => {
const manifest = defineFeature({
name: "auth",
requiredCores: [],
useCases: {
signIn: {
mutates: false,
audits: [],
publishes: [],
consumes: [],
rateLimit: [{ name: "login", window: "1m", budget: 5 }],
},
},
realtimeChannels: [],
jobs: [],
} as const);
expectTypeOf(manifest).toMatchTypeOf<FeatureManifest>();
expectTypeOf(manifest.useCases.signIn.rateLimit).toMatchTypeOf<
readonly RateLimitBudget[] | undefined
>();
});
it("use case without rateLimit satisfies UseCaseManifest", () => {
const uc: UseCaseManifest = {
mutates: false,
audits: [],
publishes: [],
consumes: [],
};
expectTypeOf(uc.rateLimit).toEqualTypeOf<
readonly RateLimitBudget[] | undefined
>();
});
it("accepts an optional coverage section", () => { it("accepts an optional coverage section", () => {
const manifest = defineFeature({ const manifest = defineFeature({
name: "auth", name: "auth",

View File

@@ -1,4 +1,5 @@
import type { CoverageManifest } from "./coverage"; import type { CoverageManifest } from "./coverage";
import type { RateLimitBudget } from "../rate-limit/rate-limit.interface";
/** /**
* Per-use-case manifest entry. Declares what the use case does at the contract * Per-use-case manifest entry. Declares what the use case does at the contract
@@ -12,6 +13,7 @@ export type UseCaseManifest = {
readonly publishes: readonly string[]; readonly publishes: readonly string[];
readonly consumes: readonly string[]; readonly consumes: readonly string[];
readonly analyticsEvents?: readonly string[]; readonly analyticsEvents?: readonly string[];
readonly rateLimit?: readonly RateLimitBudget[];
}; };
/** /**

View File

@@ -3,6 +3,7 @@ export type {
Captured, Captured,
Analyzed, Analyzed,
ConsentChecked, ConsentChecked,
RateLimited,
} from "./brands"; } from "./brands";
export type { FeatureManifest, UseCaseManifest } from "./define-feature"; export type { FeatureManifest, UseCaseManifest } from "./define-feature";
export { defineFeature } from "./define-feature"; export { defineFeature } from "./define-feature";
@@ -29,6 +30,7 @@ export {
isAudited, isAudited,
isAnalyzed, isAnalyzed,
isConsentChecked, isConsentChecked,
isRateLimited,
} from "./brand-runtime"; } from "./brand-runtime";
export { ConformanceError } from "./conformance-error"; export { ConformanceError } from "./conformance-error";
export { assertFeatureConformance } from "./assert-bindings"; export { assertFeatureConformance } from "./assert-bindings";

View File

@@ -0,0 +1,5 @@
export type {
IRateLimit,
RateLimitBudget,
RateLimitDecision,
} from "./rate-limit.interface";

View File

@@ -0,0 +1,41 @@
import { describe, it, expectTypeOf } from "vitest";
import type {
IRateLimit,
RateLimitBudget,
RateLimitDecision,
} from "@/rate-limit/rate-limit.interface";
describe("rate-limit types", () => {
it("RateLimitBudget has the expected shape", () => {
expectTypeOf<RateLimitBudget>().toMatchTypeOf<{
name: string;
window: string;
budget: number;
}>();
});
it("RateLimitDecision has the expected shape", () => {
expectTypeOf<RateLimitDecision>().toMatchTypeOf<{
allowed: boolean;
remaining: number;
resetAt: Date;
}>();
});
it("IRateLimit.consume returns Promise<RateLimitDecision>", () => {
expectTypeOf<
IRateLimit["consume"]
>().returns.resolves.toEqualTypeOf<RateLimitDecision>();
});
it("IRateLimit.consume accepts optional weight", () => {
type ConsumeParams = Parameters<IRateLimit["consume"]>;
expectTypeOf<ConsumeParams[0]>().toEqualTypeOf<string>();
expectTypeOf<ConsumeParams[1]>().toEqualTypeOf<string>();
expectTypeOf<ConsumeParams[2]>().toEqualTypeOf<number | undefined>();
});
it("IRateLimit.reset returns Promise<void>", () => {
expectTypeOf<IRateLimit["reset"]>().returns.resolves.toEqualTypeOf<void>();
});
});

View File

@@ -0,0 +1,20 @@
export type RateLimitBudget = {
name: string;
window: string;
budget: number;
};
export type RateLimitDecision = {
allowed: boolean;
remaining: number;
resetAt: Date;
};
export interface IRateLimit {
consume(
budgetName: string,
key: string,
weight?: number,
): Promise<RateLimitDecision>;
reset(budgetName: string, key: string): Promise<void>;
}