An any in a published .d.ts is not a local shortcut - it is a hole in every consumer's typechecker. An app writing db.selectFrom('users') got no help from the compiler because the builder it received had been typed any three files upstream. That is how installed Stacks apps ended up seeing their own models as any.
The published surface goes 91 -> 18, and the two files an app touches on every query reach zero:
| file | before | after |
|---|---|---|
client.d.ts | 29 | 0 |
orm.d.ts | 4 | 0 |
dynamodb-client.d.ts | 18 | 0 |
db.d.ts | 11 | 7 |
| everything else | 29 | 11 |
What replaced them
AnyDatabaseSchema- 21 generic constraints readDB extends DatabaseSchema<any>, which says "a schema of anything" and draggedanyinto every signature mentioning one. A schema is tables, each with columns, a primary key and optional relations, so it now says that.DriverConnectionfor the internalsqlhandle, andEmbeddedValue/asEmbeddedValuefor the three shapes a tagged-template value can take (bind param, nested query, raw marker) - so the branch that fixed #1084 reads properties without anany.toBindings- the single place user values become driver bindings. Unchecked on purpose (bun:sqlite is the validator and throws a clear "can't bind"), but named once instead of ananyat six call sites.DynamoDBValue/DynamoDBClientLike/DynamoDBFilterOperator/DynamoDBConsumedCapacity- DynamoDB's type system is small and closed, so the fluent surface can name it. The AWS SDK is not a dependency, so the client is structural.- Real overloads on the browser client's
where/orWhere/andWhere.WhereOperator | anycollapses toanyand checked nothing; the overloads mean a three-arg call must pass an actual operator. - Inputs widened to
unknownrather than narrowed - nothing breaks, everything is assignable to it.
The survivors are deliberate
Each carries its reason in the source: driver escape hatches in db.ts (narrowing forces a cast at every await sql.unsafe(...) - the same hole, moved somewhere less visible), DeepPartial's function-detection idiom, the faker proxy's dynamic members, and accessor/mutator parameters in schema.ts. That last one matters: a model's own get: { name: (value: string) => ... } is not assignable to (value: unknown) => ... under strictFunctionTypes, so narrowing there would reject every correctly written model. Their returns are unknown, so nothing downstream inherits the looseness.
Verification
bun run typecheckclean- 2000 pass / 0 fail, unchanged from before
bunx --bun pickier .0 errors- A new test pins the count, so the next
anyneeds a justification rather than a silent bump