@zerotal/orm 1.1.0 → 1.4.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.
@@ -4,7 +4,7 @@
4
4
  // workflow carry the API — `transitionTo` / `forceState` / `onTransition` / the
5
5
  // `states` + `stateField` statics never appear on models that don't use them.
6
6
  //
7
- // import { BaseModelWith } from "@zerotal/orm";
7
+ // import { Model, State } from "@zerotal/orm";
8
8
  //
9
9
  // const States = {
10
10
  // pending: { canTransitionTo: ["active", "cancelled"] as const },
@@ -14,7 +14,7 @@
14
14
  // cancelled: { canTransitionTo: [] as const },
15
15
  // } as const;
16
16
  //
17
- // class Subscription extends BaseModelWith(State) {
17
+ // class Subscription extends Model.using(State) {
18
18
  // static states = States;
19
19
  // @column() status!: keyof typeof States;
20
20
  // }
@@ -132,7 +132,7 @@ interface StateModelClass {
132
132
  * cancelled: { canTransitionTo: [] as const },
133
133
  * } as const;
134
134
  *
135
- * class Subscription extends BaseModelWith(State) {
135
+ * class Subscription extends Model.using(State) {
136
136
  * static states = States;
137
137
  * @column() status!: keyof typeof States;
138
138
  * }
@@ -29,6 +29,8 @@ export { columnRegistry };
29
29
  * | `"date"` | `{ type: "datetime", cast: "date" }` |
30
30
  * | `"json"` | `{ type: "json", cast: "json" }` |
31
31
  * | `"array"` | `{ type: "json", cast: "array" }` |
32
+ * | `"encrypted"` | `{ type: "text", cast: "encrypted" }` |
33
+ * | `"encrypted:json"` | `{ type: "text", cast: "encrypted:json" }` |
32
34
  */
33
35
  export type ColumnShorthand =
34
36
  | "string"
@@ -40,7 +42,9 @@ export type ColumnShorthand =
40
42
  | "datetime"
41
43
  | "date"
42
44
  | "json"
43
- | "array";
45
+ | "array"
46
+ | "encrypted"
47
+ | "encrypted:json";
44
48
 
45
49
  /**
46
50
  * Full option object accepted by `@column({ ... })`.
@@ -105,6 +109,12 @@ export interface ColumnOptions {
105
109
  * - 'integer' — parseInt on both read and write
106
110
  * - 'float' — parseFloat on both read and write
107
111
  * - 'enum' — pass-through; pairs with `enumValues` for TS enum columns
112
+ * - 'encrypted' — AES-256-GCM at rest under `APP_KEY`, plaintext on the model
113
+ * - 'encrypted:json' — the same, for a structured value (stringified, then encrypted)
114
+ *
115
+ * Encrypted columns need `type: "text"` (a payload outgrows the plaintext) and
116
+ * cannot be filtered on — `where()` against one throws, because a fresh IV per
117
+ * write means the ciphertext never repeats. See `casts/encrypted.ts`.
108
118
  */
109
119
  cast?:
110
120
  | "datetime"
@@ -116,6 +126,8 @@ export interface ColumnOptions {
116
126
  | "float"
117
127
  | "enum"
118
128
  | "immutable_datetime"
129
+ | "encrypted"
130
+ | "encrypted:json"
119
131
  | `decimal:${number}`
120
132
  | {
121
133
  get?: (dbValue: unknown) => unknown;
@@ -140,6 +152,10 @@ const SHORTHAND_MAP: Record<ColumnShorthand, ColumnOptions> = {
140
152
  date: { type: "datetime", cast: "date" },
141
153
  json: { type: "json", cast: "json" },
142
154
  array: { type: "json", cast: "array" },
155
+ // TEXT, not string: the stored payload is ~1.4× the plaintext plus 28 bytes of
156
+ // IV and auth tag, so a VARCHAR that held the value will not hold its ciphertext.
157
+ encrypted: { type: "text", cast: "encrypted" },
158
+ "encrypted:json": { type: "text", cast: "encrypted:json" },
143
159
  };
144
160
 
145
161
  /**
@@ -46,7 +46,7 @@ interface TableConfig {
46
46
  * export class Post extends BaseModel { ... }
47
47
  *
48
48
  * Soft deletes are opt-in via the `SoftDeletes` mixin, not `@table`:
49
- * `class Post extends BaseModelWith(SoftDeletes) {}` — see /docs/orm/lifecycle.
49
+ * `class Post extends Model.using(SoftDeletes) {}` — see /docs/orm/lifecycle.
50
50
  */
51
51
  export interface TableDecoratorBuilder {
52
52
  /** Apply the decorator to a class constructor (called automatically by TS). */
@@ -77,7 +77,7 @@ export interface TableDecoratorBuilder {
77
77
  * ```
78
78
  *
79
79
  * Timestamps are **on by default** — use `.withoutTimestamps()` to opt out. Soft
80
- * deletes are **opt-in via the `SoftDeletes` mixin**: `extends BaseModelWith(SoftDeletes)`.
80
+ * deletes are **opt-in via the `SoftDeletes` mixin**: `extends Model.using(SoftDeletes)`.
81
81
  *
82
82
  * `@table` is the single, required way to configure a model: besides setting the
83
83
  * table name and options, it anchors the class's `@column`/relation registrations at