@isaijs/core 0.1.0 → 0.1.3

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.
Files changed (45) hide show
  1. package/dist/adapters/cache/cloudflare-kv/index.d.ts +1 -1
  2. package/dist/adapters/database/d1/index.d.ts +1 -1
  3. package/dist/adapters/database/durable-object/index.d.ts +1 -1
  4. package/dist/adapters/database/sqlite-node/index.d.ts +1 -1
  5. package/dist/adapters/mail/gmail/index.d.ts +1 -1
  6. package/dist/adapters/pdf/cloudflare-browser/index.d.ts +1 -1
  7. package/dist/adapters/queue/cloudflare/index.d.ts +1 -1
  8. package/dist/adapters/ratelimit/cloudflare/index.d.ts +1 -1
  9. package/dist/adapters/ratelimit/memory/index.d.ts +1 -1
  10. package/dist/adapters/runtime/cloudflare/index.d.ts +1 -1
  11. package/dist/adapters/runtime/cloudflare/index.js +1 -1
  12. package/dist/adapters/storage/disk/index.d.ts +1 -1
  13. package/dist/adapters/storage/memory/index.d.ts +1 -1
  14. package/dist/adapters/storage/r2/index.d.ts +1 -1
  15. package/dist/auth/index.d.ts +2 -2
  16. package/dist/auth/index.js +2 -2
  17. package/dist/{base64url-DwWPqoOT.js → base64url-C5GTYIL5.js} +23 -9
  18. package/dist/cli/index.js +18 -15
  19. package/dist/client/index.d.ts +46 -5
  20. package/dist/client/index.js +156 -8
  21. package/dist/{create-auth-Byf1-VJw.js → create-auth-Ci0PaBoX.js} +5 -5
  22. package/dist/{data-layer-BMviRJaW.d.ts → data-layer-D1BFo3wO.d.ts} +29 -12
  23. package/dist/{data-layer-BNtz40PV.js → data-layer-_TZtuy-F.js} +19 -11
  24. package/dist/db/index.d.ts +3 -3
  25. package/dist/db/index.js +5 -5
  26. package/dist/{index-BVCrbMav.d.ts → index-CYcklQ1l.d.ts} +21 -7
  27. package/dist/{index-BKwTOLop.d.ts → index-Ce5p2-EB.d.ts} +2 -2
  28. package/dist/{index-CBWFoL3s.d.ts → index-DlgVg3D8.d.ts} +38 -26
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.js +152 -56
  31. package/dist/{issues-Bxq4JExX.d.ts → issues-CKto95IW.d.ts} +3 -1
  32. package/dist/{make-DKzPd2b_.js → make-DKBn79cH.js} +17 -2
  33. package/dist/{config-D6PexpSC.js → makers-DeSNM0Nd.js} +13 -39
  34. package/dist/{migrator-C65RM_K-.js → migrator-BU3_PHk8.js} +102 -10
  35. package/dist/{policies-yVzFCjxU.js → policies-CKIdBFKt.js} +3 -3
  36. package/dist/ports/index.d.ts +1 -1
  37. package/dist/{resource-9fjxJgmz.js → resource-CsYksjKc.js} +42 -15
  38. package/dist/{tables-C3Uza4qK.js → tables-IrLjsomf.js} +4 -4
  39. package/dist/testing/index.d.ts +2 -2
  40. package/dist/testing/index.js +6 -6
  41. package/dist/{types-BFc_NEx8.d.ts → types-S6zF5IXV.d.ts} +15 -12
  42. package/dist/validation/index.d.ts +3 -3
  43. package/dist/validation/index.js +1 -1
  44. package/dist/{validation-l5JG-PFn.js → validation-Cppmd0RV.js} +23 -7
  45. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
- import { a as DatabaseDriver, o as DialectName } from "./index-BKwTOLop.js";
2
- import { M as IdInput, q as StoredFile } from "./index-BVCrbMav.js";
3
- import { A as Dialect, G as Model, H as Columns, I as Clock, K as ModelSpec, M as RetiredSnapshot, N as SchemaSnapshot, U as ComputedFields, V as AnyModel, W as Fields, X as Condition, at as count, b as RowOf, dt as Kinds, et as Now, f as seed, ft as SchemaDefaults, ht as Field, i as Row, it as any, mt as AnyField, n as Patch, ot as not, p as Database, q as ModelRegistry, rt as all, yt as Slot } from "./types-BFc_NEx8.js";
1
+ import { a as DatabaseDriver, o as DialectName } from "./index-Ce5p2-EB.js";
2
+ import { t as Issue } from "./issues-CKto95IW.js";
3
+ import { M as IdInput, Y as StoredFile } from "./index-CYcklQ1l.js";
4
+ import { A as Dialect, G as Model, H as Columns, I as Clock, K as ModelSpec, M as RetiredSnapshot, N as SchemaSnapshot, U as ComputedFields, V as AnyModel, W as Fields, X as Condition, at as count, b as RowOf, dt as Kinds, et as Now, f as seed, ft as SchemaDefaults, ht as Field, i as Row, it as any, mt as AnyField, n as Patch, ot as not, p as Database, q as ModelRegistry, rt as all, yt as Slot } from "./types-S6zF5IXV.js";
4
5
  //#region src/db/schema/traits.d.ts
5
6
  type ComputedDefinitions = Record<string, (row: any) => Condition>;
6
7
  interface TraitSpec {
@@ -79,12 +80,20 @@ declare class CheckFailed extends DatabaseError {
79
80
  readonly name = "CheckFailed";
80
81
  constructor(model: string, check: string, options?: ErrorOptions);
81
82
  }
82
- /** A unique field (or combination) already has this value. */
83
+ /**
84
+ * A unique field (or combination) already has this value. `fields` are the unique's own; `issues`
85
+ * put one on each for a form, except that a field made from another (a slug from its title) puts
86
+ * it on that one, the field a person typed.
87
+ */
83
88
  declare class UniqueFailed extends DatabaseError {
84
89
  readonly model: string;
85
90
  readonly fields: readonly string[];
86
91
  readonly name = "UniqueFailed";
87
- constructor(model: string, fields: readonly string[], options?: ErrorOptions);
92
+ readonly issues: readonly Issue[];
93
+ constructor(model: string, fields: readonly string[], options?: ErrorOptions & {
94
+ /** The field each generated one is made from: `{ slug: "title" }`. */
95
+ readonly from?: Readonly<Record<string, string>>;
96
+ });
88
97
  }
89
98
  /** A ref points at a row that doesn't exist, or a delete is restricted by rows that reference it. */
90
99
  declare class ReferenceFailed extends DatabaseError {
@@ -268,7 +277,7 @@ declare class UnsafeMigration extends Error {
268
277
  //#region src/db/migrations/errors.d.ts
269
278
  /**
270
279
  * The migrator's errors: one type with a code, a message and a hint, so the CLI prints the same
271
- * shape for each and picks its exit code from the code (planning/migrations.md → Errors).
280
+ * shape for each and picks its exit code from the code.
272
281
  */
273
282
  type MigrationErrorCode = "migrations.conflict" | "migrations.tampered" | "database.ahead" | "cleanup.notLive" | "migrations.todo" | "migrations.missing" | "migrations.question" | "migrations.rename" | "migrations.uniqueFill" | "data.loops" | "lock.held" | "deploy.held" | "rollback.unknownRelease" | "rollback.beyondCleanup";
274
283
  declare class MigrationError extends Error {
@@ -708,7 +717,7 @@ declare function authTables(f: Kinds, options: AuthTablesOptions): TableSet<{
708
717
  };
709
718
  }>;
710
719
  /**
711
- * Held by the platform (planning/tenancy.md → End of v1): the tenant's people, the owner
720
+ * Held by the platform: the tenant's people, the owner
712
721
  * included, can't take it away or suspend its holder.
713
722
  */
714
723
  held: Field<"platform", "platform", true, false, {}>;
@@ -911,6 +920,11 @@ declare function tenancyTables(f: Kinds, options: TenancyOptions): TableSet<{
911
920
  //#region src/db/schema/data-layer.d.ts
912
921
  /** A project kind: a preset field (`base.line().max(120)`), or a factory for parameterized kinds. */
913
922
  type ProjectKind = AnyField | ((...args: any[]) => AnyField);
923
+ /** What a model may say before its traits and fields. */
924
+ interface ModelOptions {
925
+ /** It lives in the platform's database (with tenancy), as its folder does: `db/schema/platform/`. */
926
+ readonly database: "platform";
927
+ }
914
928
  interface DataLayerDefinition<P extends Record<string, ProjectKind>, U extends readonly AnyTableSet[]> {
915
929
  /**
916
930
  * Built-in tables to switch on (`[base.authTables({ database: "tenant" }), base.tenancy({ database: "platform" })]`):
@@ -922,20 +936,23 @@ interface DataLayerDefinition<P extends Record<string, ProjectKind>, U extends r
922
936
  }
923
937
  /** What `define` gets: the built-in kinds, and the built-in table sets it may `use`. */
924
938
  type Base = Kinds & {
925
- /** User, Session, Account, Verification, Invite, Role and UserRole, in the app's data database (planning/auth.md). */
939
+ /** User, Session, Account, Verification, Invite, Role and UserRole, in the app's data database. */
926
940
  readonly authTables: (options: AuthTablesOptions) => ReturnType<typeof authTables>;
927
- /** `Tenant` and `Domain`, in the platform's database (planning/tenancy.md). */
941
+ /** `Tenant` and `Domain`, in the platform's database. */
928
942
  readonly tenancy: (options: TenancyOptions) => ReturnType<typeof tenancyTables>;
929
- /** `Upload` (files uploaded and not yet attached), in the app's data database (planning/uploads.md). */
943
+ /** `Upload` (files uploaded and not yet attached), in the app's data database. */
930
944
  readonly uploads: (options: UploadTablesOptions) => ReturnType<typeof uploadTables>;
931
- /** `AuditEntry` (the audit log), in the database whose writes it records (planning/audit.md). */
945
+ /** `AuditEntry` (the audit log), in the database whose writes it records. */
932
946
  readonly audit: (options: AuditTablesOptions) => AuditTables;
933
947
  };
934
948
  type ProjectKinds<P> = { readonly [K in keyof P]: P[K] extends AnyField ? () => P[K] : P[K]; };
935
949
  /** The placeholder for conditions over a model's rows: `const event = row(Event)`. */
936
950
  declare function row<M extends AnyModel>(target: M): Columns<M["~fields"], M["name"]>;
937
951
  declare function createDataLayer<P extends Record<string, ProjectKind> = {}, const U extends readonly AnyTableSet[] = []>(define?: (base: Base) => DataLayerDefinition<P, U>): {
938
- model: <const Name extends string, const T extends readonly AnyTrait[], F extends Fields>(name: Name, ...rest: [...traits: T, fields: F]) => Model<Name, TraitFields<T> & F>;
952
+ model: {
953
+ <const Name extends string, const T extends readonly AnyTrait[], F extends Fields>(name: Name, ...rest: [...traits: T, fields: F]): Model<Name, TraitFields<T> & F>;
954
+ <const Name extends string, const T extends readonly AnyTrait[], F extends Fields>(name: Name, options: ModelOptions, ...rest: [...traits: T, fields: F]): Model<Name, TraitFields<T> & F>;
955
+ };
939
956
  f: Kinds & ProjectKinds<P>;
940
957
  builtins: Builtins<U>;
941
958
  slots: {
@@ -1,6 +1,7 @@
1
- import { O as datetime, P as quantity, p as host, r as isPhoneRegion } from "./validation-l5JG-PFn.js";
2
- import { C as not, M as field, N as fieldKinds, S as count, s as defineModel, u as rowOf, v as all, w as now, y as any } from "./base64url-DwWPqoOT.js";
3
- import { a as TableSet, i as platformAuthDefinitions, o as defineBuiltins, r as authTables } from "./tables-C3Uza4qK.js";
1
+ import { F as quantity, k as datetime, m as host, r as isPhoneRegion } from "./validation-Cppmd0RV.js";
2
+ import "./migrator-BU3_PHk8.js";
3
+ import { C as not, M as field, N as fieldKinds, S as count, s as defineModel, u as rowOf, v as all, w as now, y as any } from "./base64url-C5GTYIL5.js";
4
+ import { a as TableSet, i as platformAuthDefinitions, o as defineBuiltins, r as authTables } from "./tables-IrLjsomf.js";
4
5
  import { n as seed } from "./seed-BObmdKdP.js";
5
6
  //#region src/db/fields/slot.ts
6
7
  var Slot = class {
@@ -89,13 +90,13 @@ function uploadTables(f, options) {
89
90
  //#endregion
90
91
  //#region src/tenancy/tables.ts
91
92
  /**
92
- * The platform's built-in tables (planning/tenancy.md → The platform database), switched on with
93
+ * The platform's built-in tables, switched on with
93
94
  * `use: [base.tenancy({ database: "platform" })]` in `db/index.ts`:
94
95
  *
95
96
  * Tenant the registry: what the front door finds behind a host, and whether it may answer
96
97
  * Domain every host a tenant answers on (its subdomain and custom domains alike)
97
98
  * PlatformUser, PlatformSession… the platform's own people (the auth tables, prefixed): who
98
- * signs in on the platform's host (planning/tenancy.md → End of v1)
99
+ * signs in on the platform's host
99
100
  *
100
101
  * Feature switches are the app's own columns: `builtins.Tenant.extend({ coupons: f.flag() })`.
101
102
  */
@@ -171,8 +172,10 @@ var ModelRegistry = class {
171
172
  //#region src/db/schema/traits.ts
172
173
  /**
173
174
  * Traits: behaviour a model takes whole, written before its fields (`model(name, ...traits,
174
- * fields)`, planning/traits-and-slots.md). A trait adds fields (so the model's own fields already
175
- * see them), computed fields, and a name the framework reads (`singleton`).
175
+ * fields)`), Laravel's traits typed. A trait adds fields (so the model's own fields already see
176
+ * them; declaring one of them again is an error), computed fields, and a name the framework reads
177
+ * (`singleton`). Always written `traits.x()`, never imported bare: a bare `publishable()` reads like
178
+ * an action.
176
179
  */
177
180
  var Trait = class {
178
181
  spec;
@@ -224,6 +227,8 @@ function builtinTraits() {
224
227
  * `slots`, `builtins`, the condition language and `seed`. One call serves every database the app
225
228
  * has (with isolated tenancy, the tenants' and the platform's).
226
229
  */
230
+ /** A model's options: `{ database: "…" }`, never fields (a field is a kind, not a string). */
231
+ const isOptions = (value) => typeof value === "object" && value !== null && !(value instanceof Trait) && Object.keys(value).length === 1 && typeof value.database === "string";
227
232
  /** The placeholder for conditions over a model's rows: `const event = row(Event)`. */
228
233
  function row(target) {
229
234
  return rowOf(target.spec, target.registry);
@@ -258,15 +263,18 @@ function createDataLayer(define) {
258
263
  byDefault
259
264
  };
260
265
  }
261
- /** `model(name, fields)`, or with traits first: `model(name, traits.ordered({ within: "event" }), fields)`. */
262
- const model = (name, ...rest) => {
266
+ function model(name, ...given) {
263
267
  if (Object.hasOwn(builtins, name)) throw new TypeError(`isai: ${name} is a built-in table; add columns with builtins.${name}.extend({ … })`);
268
+ const first = given[0];
269
+ const options = given.length > 1 && isOptions(first) ? first : void 0;
270
+ const rest = options ? given.slice(1) : given;
271
+ if (options && options.database !== "platform") throw new TypeError(`isai: model("${name}") takes { database: "platform" } only`);
264
272
  const fields = rest.at(-1);
265
273
  if (!fields || fields instanceof Trait) throw new TypeError(`isai: model("${name}") needs its fields last`);
266
274
  const traits = rest.slice(0, -1);
267
275
  if (!traits.every((trait) => trait instanceof Trait)) throw new TypeError(`isai: model("${name}") takes traits, then its fields`);
268
- return defineModel(registry, name, fields, traits);
269
- };
276
+ return defineModel(registry, name, fields, traits, { ...options ? { database: options.database } : {} });
277
+ }
270
278
  return {
271
279
  model,
272
280
  f: {
@@ -1,4 +1,4 @@
1
- import { a as ValidationError } from "../issues-Bxq4JExX.js";
2
- import { $ as Expr, A as Dialect, B as newSecretKey, F as snapshotOf, G as Model, I as Clock, J as Models, K as ModelSpec, L as FixedClock, M as RetiredSnapshot, N as SchemaSnapshot, O as Write, P as emptySnapshot, R as fixedClock, V as AnyModel, X as Condition, Y as Column, _ as database, _t as Storage, a as Visible, at as count, bt as slot, c as Many, d as SeedContext, dt as Kinds, et as Now, ft as SchemaDefaults, g as Transaction, gt as FieldSpec, h as RawValue, ht as Field, i as Row, it as any, j as Rule, k as WriteListener, l as Overrides, lt as ConditionNode, m as DatabaseOptions, n as Patch, nt as Total, o as Make, ot as not, p as Database, pt as fieldKinds, r as Planned, rt as all, st as now, t as Insert, tt as Relation, u as Seed, v as OrderKey, vt as sensitivity, y as Query, yt as Slot, z as systemClock } from "../types-BFc_NEx8.js";
3
- import { A as MigrateOptions, B as NotFound, C as MigrationErrorCode, D as Cleanup, E as UnsafeMigration, F as DataStep, H as UniqueFailed, I as TODO, L as dataStep, M as migrate, N as migrateFresh, O as cleanupMigration, P as sync, R as CheckFailed, S as MigrationError, T as UnsafeChange, U as dialectFor, V as ReferenceFailed, W as sqlite, _ as Generated, b as manifest, c as acquireLock, d as setReleaseStatus, f as startRelease, g as makeMigrations, h as makeCleanup, j as Migration, k as Manifest, l as releaseLock, m as checkMigrations, n as row, o as Release, p as applyRules, s as ReleaseStatus, t as createDataLayer, u as rollback, v as generateMigration, w as SuspectedRename, x as structureStep, y as cleanupStep, z as DatabaseError } from "../data-layer-BMviRJaW.js";
1
+ import { a as ValidationError } from "../issues-CKto95IW.js";
2
+ import { $ as Expr, A as Dialect, B as newSecretKey, F as snapshotOf, G as Model, I as Clock, J as Models, K as ModelSpec, L as FixedClock, M as RetiredSnapshot, N as SchemaSnapshot, O as Write, P as emptySnapshot, R as fixedClock, V as AnyModel, X as Condition, Y as Column, _ as database, _t as Storage, a as Visible, at as count, bt as slot, c as Many, d as SeedContext, dt as Kinds, et as Now, ft as SchemaDefaults, g as Transaction, gt as FieldSpec, h as RawValue, ht as Field, i as Row, it as any, j as Rule, k as WriteListener, l as Overrides, lt as ConditionNode, m as DatabaseOptions, n as Patch, nt as Total, o as Make, ot as not, p as Database, pt as fieldKinds, r as Planned, rt as all, st as now, t as Insert, tt as Relation, u as Seed, v as OrderKey, vt as sensitivity, y as Query, yt as Slot, z as systemClock } from "../types-S6zF5IXV.js";
3
+ import { A as MigrateOptions, B as NotFound, C as MigrationErrorCode, D as Cleanup, E as UnsafeMigration, F as DataStep, H as UniqueFailed, I as TODO, L as dataStep, M as migrate, N as migrateFresh, O as cleanupMigration, P as sync, R as CheckFailed, S as MigrationError, T as UnsafeChange, U as dialectFor, V as ReferenceFailed, W as sqlite, _ as Generated, b as manifest, c as acquireLock, d as setReleaseStatus, f as startRelease, g as makeMigrations, h as makeCleanup, j as Migration, k as Manifest, l as releaseLock, m as checkMigrations, n as row, o as Release, p as applyRules, s as ReleaseStatus, t as createDataLayer, u as rollback, v as generateMigration, w as SuspectedRename, x as structureStep, y as cleanupStep, z as DatabaseError } from "../data-layer-D1BFo3wO.js";
4
4
  export { type AnyModel, CheckFailed, type Cleanup, type Clock, Column, Condition, type ConditionNode, type DataStep, Database, DatabaseError, type DatabaseOptions, type Dialect, Expr, Field, type FieldSpec, type FixedClock, type Generated, type Insert, type Kinds, type Make, type Manifest, type Many, type MigrateOptions, type Migration, MigrationError, type MigrationErrorCode, Model, type ModelSpec, type Models, NotFound, Now, type OrderKey, type Overrides, type Patch, type Planned, Query, type RawValue, ReferenceFailed, Relation, type Release, type ReleaseStatus, type RetiredSnapshot, type Row, type Rule, type SchemaDefaults, type SchemaSnapshot, Seed, type SeedContext, Slot, type Storage, type SuspectedRename, TODO, Total, Transaction, UniqueFailed, type UnsafeChange, UnsafeMigration, ValidationError, type Visible, type Write, type WriteListener, acquireLock, all, any, applyRules, checkMigrations, cleanupMigration, cleanupStep, count, createDataLayer, dataStep, database, dialectFor, emptySnapshot, fieldKinds, fixedClock, generateMigration, makeCleanup, makeMigrations, manifest, migrate, migrateFresh, newSecretKey, not, now, releaseLock, rollback, row, sensitivity, setReleaseStatus, slot, snapshotOf, sqlite, startRelease, structureStep, sync, systemClock };
package/dist/db/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import { W as ValidationError } from "../validation-l5JG-PFn.js";
2
- import { A as Query, C as database, F as systemClock, G as UniqueFailed, H as DatabaseError, I as newSecretKey, M as dialectFor, N as sqlite, P as fixedClock, U as NotFound, V as CheckFailed, W as ReferenceFailed, _ as TODO, b as Database, c as rollback, d as applyRules, g as UnsafeMigration, h as snapshotOf, i as acquireLock, l as setReleaseStatus, m as emptySnapshot, n as migrateFresh, p as generateMigration, r as sync, s as releaseLock, t as migrate, u as startRelease, v as dataStep, x as Transaction, y as MigrationError } from "../migrator-C65RM_K-.js";
3
- import { C as not, F as sensitivity, N as fieldKinds, P as Field, S as count, _ as Total, d as Column, f as Condition, g as Relation, h as Now, m as Expr, r as Model, v as all, w as now, y as any } from "../base64url-DwWPqoOT.js";
4
- import { i as slot, n as row, r as Slot, t as createDataLayer } from "../data-layer-BNtz40PV.js";
1
+ import { G as ValidationError } from "../validation-Cppmd0RV.js";
2
+ import { A as Query, C as database, F as systemClock, G as DatabaseError, I as newSecretKey, J as UniqueFailed, K as NotFound, M as dialectFor, N as sqlite, P as fixedClock, W as CheckFailed, _ as TODO, b as Database, c as rollback, d as applyRules, g as UnsafeMigration, h as snapshotOf, i as acquireLock, l as setReleaseStatus, m as emptySnapshot, n as migrateFresh, p as generateMigration, q as ReferenceFailed, r as sync, s as releaseLock, t as migrate, u as startRelease, v as dataStep, x as Transaction, y as MigrationError } from "../migrator-BU3_PHk8.js";
3
+ import { C as not, F as sensitivity, N as fieldKinds, P as Field, S as count, _ as Total, d as Column, f as Condition, g as Relation, h as Now, m as Expr, r as Model, v as all, w as now, y as any } from "../base64url-C5GTYIL5.js";
4
+ import { i as slot, n as row, r as Slot, t as createDataLayer } from "../data-layer-_TZtuy-F.js";
5
5
  import { t as Seed } from "../seed-BObmdKdP.js";
6
- import { a as cleanupMigration, i as makeMigrations, r as makeCleanup, t as checkMigrations } from "../make-DKzPd2b_.js";
6
+ import { a as cleanupMigration, i as makeMigrations, r as makeCleanup, t as checkMigrations } from "../make-DKBn79cH.js";
7
7
  //#region src/db/migrations/files.ts
8
8
  /** A structure step file: adds tables and columns. Applied once, never edited. */
9
9
  function structureStep(options) {
@@ -1,4 +1,4 @@
1
- import { i as Result, r as Path } from "./issues-Bxq4JExX.js";
1
+ import { i as Result, r as Path } from "./issues-CKto95IW.js";
2
2
  //#region src/validation/standard.d.ts
3
3
  /**
4
4
  * Standard Schema v1 (standardschema.dev), the interface Zod, Valibot and ArkType share. Every
@@ -39,7 +39,7 @@ interface Measure {
39
39
  }
40
40
  /**
41
41
  * How sensitive a value is: `hidden` never leaves the server; `personal` is redacted in logs,
42
- * exports and AI context. The output layer applies it (planning/fields.md → Sensitive fields).
42
+ * exports and AI context. The output layer applies it.
43
43
  */
44
44
  type Sensitivity = "hidden" | "personal";
45
45
  interface KindSpec {
@@ -76,7 +76,7 @@ interface KindSpec {
76
76
  */
77
77
  readonly fake: (fake: Fake, context: FakeContext) => unknown;
78
78
  }
79
- /** What a file kind accepts, and where its files go (planning/uploads.md). */
79
+ /** What a file kind accepts, and where its files go. */
80
80
  interface FileSpec {
81
81
  /** The storage its files go to: a key of `storage` in `app.ts`. */
82
82
  readonly storage: string;
@@ -176,7 +176,22 @@ interface StoredFile {
176
176
  /** An image's size in pixels, when its format says. */
177
177
  readonly width?: number;
178
178
  readonly height?: number;
179
+ /**
180
+ * An image's smaller copies, each in its own key: the client makes them before uploading (`srcset`
181
+ * picks one). None means the file itself serves every size.
182
+ */
183
+ readonly sizes?: readonly ImageSize[];
184
+ }
185
+ /** One smaller copy of an image: where it's stored, and what it is. */
186
+ interface ImageSize {
187
+ readonly key: string;
188
+ readonly size: number;
189
+ readonly type: string;
190
+ readonly width: number;
191
+ readonly height: number;
179
192
  }
193
+ /** At most this many smaller copies of one image. */
194
+ declare const SIZES_MAX = 4;
180
195
  /** File types by their usual name, with the media types each covers. */
181
196
  declare const FILE_TYPES: {
182
197
  readonly pdf: readonly ["application/pdf"];
@@ -346,9 +361,8 @@ declare const slug: () => Kind<string, string, false, false>;
346
361
  */
347
362
  declare const host: () => Kind<string, string, false, false>;
348
363
  /**
349
- * One DNS label for a tenant's host on the platform (`demo` in `demo.thiraiangadi.shop`,
350
- * planning/tenancy.md → End of v1): lowercase letters, digits and inner dashes, 3–63 characters,
351
- * none of the reserved names.
364
+ * One DNS label for a tenant's host on the platform (`demo` in `demo.thiraiangadi.shop`):
365
+ * lowercase letters, digits and inner dashes, 3–63 characters, none of the reserved names.
352
366
  */
353
367
  declare const subdomain: () => Kind<string, string, false, false>;
354
368
  /** A slug made from text: `"Summer Fest 2026!"` → `"summer-fest-2026"`. Empty when nothing survives. */
@@ -368,4 +382,4 @@ declare const email: () => Kind<string, string, false, false>;
368
382
  /** An http(s) URL, up to 2,048 characters. */
369
383
  declare const url: () => Kind<string, string, false, false>;
370
384
  //#endregion
371
- export { FakeContext as $, validate as A, money as B, ObjectShape as C, object as D, list as E, datetime as F, FileType as G, sequence as H, fakeUlid as I, file as J, ImageType as K, flag as L, IdInput as M, choice as N, serialize as O, date as P, Fake as Q, id as R, LIST_MAX as S, Shape as T, phone as U, quantity as V, phoneKind as W, image as X, files as Y, images as Z, define as _, newToken as a, Measure as at, CarriesKind as b, slug as c, kind as ct, text as d, StandardResult as dt, AnyKind as et, textKind as f, StandardSchemaV1 as ft, KindDefinition as g, Definable as h, markdown as i, KindTypes as it, CalendarDate as j, toKind as k, slugify as l, StandardIssue as lt, url as m, host as n, Kind as nt, personName as o, Sensitivity as ot, token as p, StoredFile as q, line as r, KindSpec as rt, secret as s, TypeText as st, email as t, FileSpec as tt, subdomain as u, StandardProps as ut, json as v, Output as w, Input as x, urls as y, int as z };
385
+ export { images as $, validate as A, money as B, ObjectShape as C, object as D, list as E, datetime as F, FileType as G, sequence as H, fakeUlid as I, SIZES_MAX as J, ImageSize as K, flag as L, IdInput as M, choice as N, serialize as O, date as P, image as Q, id as R, LIST_MAX as S, Shape as T, phone as U, quantity as V, phoneKind as W, file as X, StoredFile as Y, files as Z, define as _, newToken as a, KindSpec as at, CarriesKind as b, slug as c, Sensitivity as ct, text as d, StandardIssue as dt, Fake as et, textKind as f, StandardProps as ft, KindDefinition as g, Definable as h, markdown as i, Kind as it, CalendarDate as j, toKind as k, slugify as l, TypeText as lt, url as m, StandardSchemaV1 as mt, host as n, AnyKind as nt, personName as o, KindTypes as ot, token as p, StandardResult as pt, ImageType as q, line as r, FileSpec as rt, secret as s, Measure as st, email as t, FakeContext as tt, subdomain as u, kind as ut, json as v, Output as w, Input as x, urls as y, int as z };
@@ -31,7 +31,7 @@ interface AppCore {
31
31
  readonly seeded: boolean;
32
32
  }>;
33
33
  }
34
- /** A tenant's entry points, where its database lives (planning/tenancy.md → Tenant databases). */
34
+ /** A tenant's entry points, where its database lives. */
35
35
  interface TenantCore {
36
36
  /** Brings the tenant's database to the deployed schema: on wake, before any request. */
37
37
  wake(): Promise<void>;
@@ -125,7 +125,7 @@ interface StoredObject {
125
125
  readonly contentType?: string;
126
126
  }
127
127
  /**
128
- * Where files live (planning/uploads.md). A storage with a `publicUrl` is public: its files are
128
+ * Where files live. A storage with a `publicUrl` is public: its files are
129
129
  * served from there, by the bucket. Without one it's private, and the app serves its files
130
130
  * through signed links.
131
131
  */
@@ -1,7 +1,7 @@
1
- import { a as DatabaseDriver, b as TenantDatabases, d as RateLimiter, g as Storage, l as PdfRenderer, n as Body, p as Runtime, r as Cache, s as MailDriver, u as Queue } from "./index-BKwTOLop.js";
2
- import { C as ObjectShape, q as StoredFile, w as Output } from "./index-BVCrbMav.js";
3
- import { $ as Expr, C as WithIncludes, D as PageOptions, E as Page, J as Models, Q as Embed, S as Key, T as NumberedPageOptions, V as AnyModel, X as Condition, Z as Conditional, b as RowOf, ct as ColumnNode, gt as FieldSpec, i as Row, lt as ConditionNode, n as Patch, p as Database, t as Insert, ut as Operand, v as OrderKey, w as NumberedPage, x as IncludePath } from "./types-BFc_NEx8.js";
4
- import { a as PROVIDERS, i as HELD, k as Manifest } from "./data-layer-BMviRJaW.js";
1
+ import { a as DatabaseDriver, b as TenantDatabases, d as RateLimiter, g as Storage, l as PdfRenderer, n as Body, p as Runtime, r as Cache, s as MailDriver, u as Queue } from "./index-Ce5p2-EB.js";
2
+ import { C as ObjectShape, Y as StoredFile, w as Output } from "./index-CYcklQ1l.js";
3
+ import { $ as Expr, C as WithIncludes, D as PageOptions, E as Page, J as Models, Q as Embed, S as Key, T as NumberedPageOptions, V as AnyModel, X as Condition, Z as Conditional, b as RowOf, ct as ColumnNode, gt as FieldSpec, i as Row, lt as ConditionNode, n as Patch, p as Database, t as Insert, ut as Operand, v as OrderKey, w as NumberedPage, x as IncludePath } from "./types-S6zF5IXV.js";
4
+ import { a as PROVIDERS, i as HELD, k as Manifest } from "./data-layer-D1BFo3wO.js";
5
5
  //#region src/auth/policies.d.ts
6
6
  /** The actions every model's policy has. */
7
7
  declare const STANDARD_ACTIONS: readonly ["read", "create", "update", "delete"];
@@ -58,7 +58,7 @@ interface DefinePolicy {
58
58
  //#region src/api/fail.d.ts
59
59
  /**
60
60
  * `fail(code, message)`: the app's own business rules, for what can't be a `.check()`, a flow or a
61
- * unique. Always a 409; app code never picks a status (planning/requests.md → Errors).
61
+ * unique. Always a 409; app code never picks a status.
62
62
  */
63
63
  declare class Rejected extends Error {
64
64
  /** Stable and machine-readable (`alreadyCheckedIn`). */
@@ -148,7 +148,7 @@ type User = Models extends {
148
148
  readonly id: string;
149
149
  };
150
150
  /**
151
- * Who signs in on the platform's host (planning/tenancy.md → End of v1): the `PlatformUser` row,
151
+ * Who signs in on the platform's host: the `PlatformUser` row,
152
152
  * once it's in the `Models` registry.
153
153
  */
154
154
  type PlatformUser = Models extends {
@@ -165,8 +165,8 @@ interface RouteOptions<S extends ObjectShape = ObjectShape, A extends boolean =
165
165
  /** Callable without a session; `user` is then `User | undefined`. Signed in by default. */
166
166
  readonly anonymous?: A;
167
167
  /**
168
- * Served on the platform's host, in the front door, with no tenant (isolated tenancy,
169
- * planning/tenancy.md → End of v1): `db` is the platform's, `user` a platform user.
168
+ * Served on the platform's host, in the front door, with no tenant (isolated tenancy): `db` is
169
+ * the platform's, `user` a platform user.
170
170
  */
171
171
  readonly platform?: Pl;
172
172
  }
@@ -190,13 +190,13 @@ interface RouteContext<P extends string, S extends ObjectShape, A extends boolea
190
190
  readonly input: Output<S>;
191
191
  /** The raw request, for headers. */
192
192
  readonly request: Request;
193
- /** The tenant this request is for (planning/tenancy.md); undefined without tenancy, and on the platform's host. */
193
+ /** The tenant this request is for; undefined without tenancy, and on the platform's host. */
194
194
  readonly tenant: Pl extends true ? undefined : TenantRow;
195
195
  }
196
196
  type RouteHandler<P extends string, S extends ObjectShape, A extends boolean, R = unknown, Pl extends boolean = false> = (context: RouteContext<P, S, A, Pl>) => R;
197
197
  /**
198
198
  * One declared route. The pipeline finds these among an app module's exports. `O` is what its
199
- * handler returns, awaited: the typed client reads it (planning/client.md).
199
+ * handler returns, awaited: the typed client reads it.
200
200
  */
201
201
  declare class Route<O = unknown> {
202
202
  readonly method: Method;
@@ -284,7 +284,7 @@ interface AppConfig {
284
284
  * `durableObject(env.TENANT)`) and `platform`. Without: one database, named freely (`main`).
285
285
  */
286
286
  readonly databases: Readonly<Record<string, DatabaseDriver | TenantDatabases>>;
287
- /** Many tenants (planning/tenancy.md); left out, the app has one. Needs `databases.platform`. */
287
+ /** Many tenants; left out, the app has one. Needs `databases.platform`. */
288
288
  readonly tenancy?: TenancyConfig;
289
289
  /** Who signs in and how: `auth` from `auth.ts` (createAuth). */
290
290
  readonly auth?: Auth<any>;
@@ -330,11 +330,19 @@ type AnyColumn = {
330
330
  interface ResourceOptions {
331
331
  /** ANDed with the policy for every action (a view's `WHERE`); `byRole` is the action's permission. */
332
332
  readonly filter?: Conditional;
333
- /** The output: exactly these columns, or `"all"` (hidden kinds never leave either way). */
333
+ /**
334
+ * The output: exactly these columns, or `"all"` (hidden kinds never leave either way). Refs and
335
+ * relations are embedded with `.pick(...)`, whose paths may follow relations
336
+ * (`product.variants.pick("price", "tiers.price")`); each level keeps only the rows its own
337
+ * model's `read` rule allows.
338
+ */
334
339
  readonly fields: readonly (AnyColumn | Embed)[] | "all";
335
340
  /** Named values computed in SQL (counts, sums, conditions), beside the fields. */
336
341
  readonly computed?: Readonly<Record<string, AnyColumn | Condition>>;
337
- /** The only fields create and update accept, or `"all"`. */
342
+ /**
343
+ * The only fields create and update accept (a mass-assignment guard), or `"all"`. With `create`,
344
+ * it covers every required field without a default.
345
+ */
338
346
  readonly writable?: readonly AnyColumn[] | "all";
339
347
  /** Fields (or ref paths: `product.category.slug`) a client may filter by. */
340
348
  readonly filterable?: readonly AnyColumn[];
@@ -342,7 +350,7 @@ interface ResourceOptions {
342
350
  readonly sortable?: readonly (AnyColumn | string)[];
343
351
  /** Named conditions a client switches on: `?onSale`. */
344
352
  readonly filters?: Readonly<Record<string, Conditional>>;
345
- /** Text fields `?q=` searches. */
353
+ /** Fields (or ref paths: `product.category.name`) `?search=` matches, any of them, ignoring case. */
346
354
  readonly search?: readonly AnyColumn[];
347
355
  /** The column `/:key` looks up (unique). The id by default; a singleton has none. */
348
356
  readonly key?: AnyColumn;
@@ -358,7 +366,7 @@ interface SearchField {
358
366
  }
359
367
  /**
360
368
  * A declared resource, with what the engine reads from it. `C` is its custom actions, as declared:
361
- * the typed client reads what each returns (planning/client.md).
369
+ * the typed client reads what each returns.
362
370
  */
363
371
  declare class Resource<C = Readonly<Record<string, CustomAction>>> {
364
372
  readonly model: AnyModel;
@@ -396,6 +404,8 @@ interface PutOptions {
396
404
  readonly storage?: string;
397
405
  /** The body's length in bytes: needed for a stream, read from bytes and text. */
398
406
  readonly size?: number;
407
+ /** An image's smaller copies, as bytes (each smaller than it): `srcset` picks one. */
408
+ readonly sizes?: readonly (ArrayBuffer | Uint8Array)[];
399
409
  }
400
410
  interface AppFiles {
401
411
  /** Stores a file (its type read from its bytes) in the current tenant's space, and returns it for a write. */
@@ -409,7 +419,7 @@ interface AppFiles {
409
419
  url(file: StoredFile, options?: {
410
420
  readonly origin?: string;
411
421
  }): Promise<string>;
412
- /** Removes the file from its storage. */
422
+ /** Removes the file (and its sizes) from its storage. */
413
423
  delete(file: StoredFile): Promise<void>;
414
424
  }
415
425
  //#endregion
@@ -431,13 +441,13 @@ interface App {
431
441
  readonly db: Database;
432
442
  /**
433
443
  * The platform's database (isolated tenancy): for the platform's routes, services and seeds,
434
- * refused inside a tenant, where `app.db` is the tenant's (planning/tenancy.md → End of v1).
444
+ * refused inside a tenant, where `app.db` is the tenant's.
435
445
  */
436
446
  readonly platform: {
437
447
  readonly db: Database;
438
448
  };
439
449
  /**
440
- * Files from code (planning/uploads.md): `put` stores one for a write (in the current tenant's
450
+ * Files from code: `put` stores one for a write (in the current tenant's
441
451
  * space), `get` reads it, `url` links to it, `delete` removes it.
442
452
  */
443
453
  readonly files: AppFiles;
@@ -456,7 +466,7 @@ interface AppOptions {
456
466
  /**
457
467
  * The tenant database's history: `() => import("#migrations/tenant")`, through a
458
468
  * `#migrations/<name>` alias to `./migrations/<name>/index.ts` in `package.json` imports. Needed with
459
- * isolated tenancy, where each tenant's database applies it on wake (planning/tenancy.md).
469
+ * isolated tenancy, where each tenant's database applies it on wake.
460
470
  */
461
471
  readonly migrations?: AppMigrations;
462
472
  /**
@@ -480,7 +490,7 @@ interface CreatedApp<Served, TenantHost = undefined> {
480
490
  */
481
491
  readonly Tenant: TenantHost;
482
492
  readonly route: RouteBuilder;
483
- /** `resource(Model, options)`: what the API exposes over a model (planning/resources.md). */
493
+ /** `resource(Model, options)`: what the API exposes over a model. */
484
494
  readonly resource: typeof resource;
485
495
  readonly fail: typeof fail;
486
496
  }
@@ -491,7 +501,7 @@ interface CreatedApp<Served, TenantHost = undefined> {
491
501
  declare function createApp<Env, Served, TenantHost = undefined>(runtime: Runtime<Env, Served, TenantHost>, configure: (env: Env) => AppConfig, options?: AppOptions): CreatedApp<Served, TenantHost>;
492
502
  //#endregion
493
503
  //#region src/app/core.d.ts
494
- /** The app modules (`apps/*\/routes.ts`, `resources.ts`), each a lazy import (planning/README.md → Instances). */
504
+ /** The app modules (`apps/*\/routes.ts`, `resources.ts`), each a lazy import. */
495
505
  type AppModules = () => readonly Promise<object>[];
496
506
  /**
497
507
  * The tenant database's history, as a lazy import of the manifest `isai makemigrations` writes
@@ -525,7 +535,7 @@ declare class NotImplementedError extends Error {
525
535
  interface InviteInput {
526
536
  readonly email: string;
527
537
  readonly role: string;
528
- /** `"platform"`: the tenant's people can't take the role away (planning/tenancy.md → End of v1). */
538
+ /** `"platform"`: the tenant's people can't take the role away. */
529
539
  readonly held?: (typeof HELD)[number];
530
540
  }
531
541
  //#endregion
@@ -556,8 +566,10 @@ interface AuthDefinition {
556
566
  /** Who may make an account by signing in: anyone (`"open"`, the default), or the invited. */
557
567
  readonly signUp?: "open" | "invite";
558
568
  /**
559
- * Signs what crosses the browser during sign-in (Google's `state`, the hand-off between hosts):
560
- * 32 random bytes, base64url, kept as a secret of the deployment (`env.AUTH_SECRET`).
569
+ * Signs what crosses the browser during sign-in (Google's `state`, the hand-off between hosts)
570
+ * and private files' links: 32 random bytes, base64url, kept as a secret of the deployment
571
+ * (`env.AUTH_SECRET`). Sessions don't depend on it, so rotating it only ends sign-ins in progress
572
+ * and links already given out.
561
573
  */
562
574
  readonly secret: string;
563
575
  }
@@ -580,7 +592,7 @@ declare class Auth<Env = unknown> {
580
592
  readonly invite: "auth.invite";
581
593
  /** See the people with accounts, give and take their roles, suspend them. */
582
594
  readonly manageUsers: "auth.manageUsers";
583
- /** Read the whole audit log (`GET /api/audit`), with the log on (planning/audit.md). */
595
+ /** Read the whole audit log (`GET /api/audit`), with the log on. */
584
596
  readonly readAudit: "audit.read";
585
597
  };
586
598
  /** The policies made with this instance's `policy()`. */
@@ -591,7 +603,7 @@ declare class Auth<Env = unknown> {
591
603
  /**
592
604
  * Gives `email` a role from `app.ts`, from code (a tenant's setup service, a seed): now, if it has
593
605
  * an account in the current database, else when it first signs in. Safe to repeat.
594
- * `held: "platform"` puts the assignment beyond the tenant's reach (planning/tenancy.md → End of v1).
606
+ * `held: "platform"` puts the assignment beyond the tenant's reach.
595
607
  */
596
608
  invite(input: InviteInput): Promise<void>;
597
609
  /** The core's: where `invite` writes. */
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { p as Runtime, t as AppCore } from "./index-BKwTOLop.js";
2
- import { C as Params, D as RouteHandler, E as RouteContext, M as fail, O as RouteOptions, S as Method, T as RouteBuilder, _ as CustomAction, b as AppConfig, d as NotImplementedError, f as AppModules, g as createApp, h as CreatedApp, j as Rejected, k as User, m as AppOptions, p as App, v as Resource, w as Route, x as Named, y as ResourceOptions } from "./index-CBWFoL3s.js";
1
+ import { p as Runtime, t as AppCore } from "./index-Ce5p2-EB.js";
2
+ import { C as Params, D as RouteHandler, E as RouteContext, M as fail, O as RouteOptions, S as Method, T as RouteBuilder, _ as CustomAction, b as AppConfig, d as NotImplementedError, f as AppModules, g as createApp, h as CreatedApp, j as Rejected, k as User, m as AppOptions, p as App, v as Resource, w as Route, x as Named, y as ResourceOptions } from "./index-DlgVg3D8.js";
3
3
  export { type App, type AppConfig, type AppCore, type AppModules, type AppOptions, type CreatedApp, type CustomAction, type Method, type Named, NotImplementedError, type Params, Rejected, type Resource, type ResourceOptions, Route, type RouteBuilder, type RouteContext, type RouteHandler, type RouteOptions, type Runtime, type User, createApp, fail };