@shohaghinfo/aerojs 0.4.0 → 0.4.1
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.
- package/AGENTS.md +10 -10
- package/README.md +17 -17
- package/dist/audit/audit-trail.d.ts +5 -6
- package/dist/audit/audit-trail.d.ts.map +1 -1
- package/dist/audit/audit-trail.js +5 -6
- package/dist/audit/audit-trail.js.map +1 -1
- package/dist/auth/auth-manager.d.ts +5 -5
- package/dist/auth/auth-manager.js +5 -5
- package/dist/auth/bouncer.d.ts +8 -15
- package/dist/auth/bouncer.d.ts.map +1 -1
- package/dist/auth/bouncer.js +10 -17
- package/dist/auth/bouncer.js.map +1 -1
- package/dist/auth/guards/api-token-guard.d.ts +2 -4
- package/dist/auth/guards/api-token-guard.d.ts.map +1 -1
- package/dist/auth/guards/api-token-guard.js +2 -4
- package/dist/auth/guards/api-token-guard.js.map +1 -1
- package/dist/auth/guards/jwt-guard.d.ts +3 -4
- package/dist/auth/guards/jwt-guard.d.ts.map +1 -1
- package/dist/auth/guards/jwt-guard.js +2 -3
- package/dist/auth/guards/jwt-guard.js.map +1 -1
- package/dist/auth/guards/session-guard.d.ts +2 -4
- package/dist/auth/guards/session-guard.d.ts.map +1 -1
- package/dist/auth/guards/session-guard.js +2 -4
- package/dist/auth/guards/session-guard.js.map +1 -1
- package/dist/auth/policy.js +1 -1
- package/dist/auth/policy.js.map +1 -1
- package/dist/cli/commands/make.js +1 -1
- package/dist/cli/runner.js +1 -1
- package/dist/database/model-hooks.d.ts +5 -5
- package/dist/database/model-hooks.js +11 -11
- package/dist/database/model.d.ts +43 -59
- package/dist/database/model.d.ts.map +1 -1
- package/dist/database/model.js +43 -59
- package/dist/database/model.js.map +1 -1
- package/dist/database/query-builder.d.ts +6 -7
- package/dist/database/query-builder.d.ts.map +1 -1
- package/dist/database/query-builder.js +6 -7
- package/dist/database/query-builder.js.map +1 -1
- package/dist/events/event-bus.d.ts +47 -75
- package/dist/events/event-bus.d.ts.map +1 -1
- package/dist/events/event-bus.js +14 -23
- package/dist/events/event-bus.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/notifications/notification-manager.d.ts +1 -1
- package/dist/notifications/notification-manager.js +1 -1
- package/dist/scheduler/scheduler.d.ts +5 -5
- package/dist/scheduler/scheduler.js +5 -5
- package/dist/session/session-driver.d.ts +2 -2
- package/dist/session/session-driver.js +2 -2
- package/dist/session/session-manager.d.ts +4 -4
- package/dist/session/session-manager.js +3 -3
- package/dist/tcp/mllp.d.ts +1 -1
- package/dist/tcp/mllp.js +2 -2
- package/dist/tcp/mllp.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file session-guard.ts
|
|
3
3
|
* @description Server-side Session Authentication Guard for AeroJS.
|
|
4
|
-
* Handles
|
|
5
|
-
* Hospital use-case: Cashier logs in → session tagged with Shift_Session_ID + Terminal_ID.
|
|
4
|
+
* Handles web portal logins, user state persistence, and session fixation prevention.
|
|
6
5
|
*/
|
|
7
6
|
import type { AeroContext } from '../../core/context.js';
|
|
8
7
|
import type { GuardContract, AuthUser, LoginOptions } from './guard.js';
|
|
@@ -38,12 +37,11 @@ export declare class SessionGuard implements GuardContract {
|
|
|
38
37
|
silentCheck(): Promise<boolean>;
|
|
39
38
|
/**
|
|
40
39
|
* Logs a user into the session.
|
|
41
|
-
*
|
|
40
|
+
* Example: ctx.auth.use('session').login(user, { remember: true });
|
|
42
41
|
*/
|
|
43
42
|
login(user: AuthUser, options?: LoginOptions): Promise<void>;
|
|
44
43
|
/**
|
|
45
44
|
* Logs the authenticated user out and destroys their session.
|
|
46
|
-
* Hospital use: cashier shift end → session destroyed, terminal freed.
|
|
47
45
|
*/
|
|
48
46
|
logout(): Promise<void>;
|
|
49
47
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-guard.d.ts","sourceRoot":"","sources":["../../../src/auth/guards/session-guard.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"session-guard.d.ts","sourceRoot":"","sources":["../../../src/auth/guards/session-guard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAIvE,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;CAC7D;AAED,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoD;IAC7E,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,GAAG,CAAc;gBAEb,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,kBAAkB;IAO1E,IAAI,IAAI,QAAQ,GAAG,IAAI;IAIvB,KAAK,IAAI,OAAO;IAIvB;;OAEG;IACU,YAAY,IAAI,OAAO,CAAC,QAAQ,CAAC;IAuB9C;;OAEG;IACU,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAS5C;;;OAGG;IACU,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAc7E;;OAEG;IACU,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAOpC;;;OAGG;IACU,OAAO,CAClB,IAAI,EAAE,QAAQ,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,EACrC,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,OAAO,CAAC;CASpB"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file session-guard.ts
|
|
3
3
|
* @description Server-side Session Authentication Guard for AeroJS.
|
|
4
|
-
* Handles
|
|
5
|
-
* Hospital use-case: Cashier logs in → session tagged with Shift_Session_ID + Terminal_ID.
|
|
4
|
+
* Handles web portal logins, user state persistence, and session fixation prevention.
|
|
6
5
|
*/
|
|
7
6
|
import { UnauthorizedError, ForbiddenError } from '../../core/errors.js';
|
|
8
7
|
import { hash, hashVerify } from '../../security/hash.js';
|
|
@@ -61,7 +60,7 @@ export class SessionGuard {
|
|
|
61
60
|
}
|
|
62
61
|
/**
|
|
63
62
|
* Logs a user into the session.
|
|
64
|
-
*
|
|
63
|
+
* Example: ctx.auth.use('session').login(user, { remember: true });
|
|
65
64
|
*/
|
|
66
65
|
async login(user, options = {}) {
|
|
67
66
|
await this.session.put(this.userKey, { id: user.id });
|
|
@@ -76,7 +75,6 @@ export class SessionGuard {
|
|
|
76
75
|
}
|
|
77
76
|
/**
|
|
78
77
|
* Logs the authenticated user out and destroys their session.
|
|
79
|
-
* Hospital use: cashier shift end → session destroyed, terminal freed.
|
|
80
78
|
*/
|
|
81
79
|
async logout() {
|
|
82
80
|
await this.session.forget(this.userKey);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-guard.js","sourceRoot":"","sources":["../../../src/auth/guards/session-guard.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"session-guard.js","sourceRoot":"","sources":["../../../src/auth/guards/session-guard.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/policy.js
CHANGED
|
@@ -20,7 +20,7 @@ export class PolicyEngine {
|
|
|
20
20
|
async check(user, module, action, resource) {
|
|
21
21
|
if (!user)
|
|
22
22
|
return false;
|
|
23
|
-
// Check wildcard action for module (e.g. '
|
|
23
|
+
// Check wildcard action for module (e.g. 'Post:*')
|
|
24
24
|
const wildcardKey = `${module}:*`;
|
|
25
25
|
if (this.policies.has(wildcardKey)) {
|
|
26
26
|
const fn = this.policies.get(wildcardKey);
|
package/dist/auth/policy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/auth/policy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAInD,MAAM,OAAO,YAAY;IACf,QAAQ,GAAG,IAAI,GAAG,EAA0B,CAAC;IAErD;;;OAGG;IACI,MAAM,CAAC,YAAoB,EAAE,QAAwB;QAC1D,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,KAAK,CAAC,IAAS,EAAE,MAAc,EAAE,MAAc,EAAE,QAAc;QAC1E,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QAExB,
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/auth/policy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAInD,MAAM,OAAO,YAAY;IACf,QAAQ,GAAG,IAAI,GAAG,EAA0B,CAAC;IAErD;;;OAGG;IACI,MAAM,CAAC,YAAoB,EAAE,QAAwB;QAC1D,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,KAAK,CAAC,IAAS,EAAE,MAAc,EAAE,MAAc,EAAE,QAAc;QAC1E,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QAExB,mDAAmD;QACnD,MAAM,WAAW,GAAG,GAAG,MAAM,IAAI,CAAC;QAClC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YACnC,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC;YAC3C,IAAI,MAAM,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC5C,CAAC;QAED,wBAAwB;QACxB,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC;YACnC,OAAO,MAAM,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAClC,CAAC;QAED,oCAAoC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAED,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC/C,MAAM,MAAM,GAAG,UAAU,GAAQ;QAC/B,kDAAkD;QAClD,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;IACxD,CAAC,CAAC;IACD,MAAc,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;IACtC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -220,7 +220,7 @@ export function makePolicy(name, targetDir = 'app/policies') {
|
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
public create(user: any): boolean {
|
|
223
|
-
return user.role === 'admin' || user.role === '
|
|
223
|
+
return user.role === 'admin' || user.role === 'editor';
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
public update(user: any, resource: any): boolean {
|
package/dist/cli/runner.js
CHANGED
|
@@ -250,7 +250,7 @@ Options:
|
|
|
250
250
|
|
|
251
251
|
Available Commands:
|
|
252
252
|
init [dir] Scaffold a complete production AeroJS application
|
|
253
|
-
new <name> [--template] Create a new AeroJS app (api-starter, react-inertia, vue-inertia,
|
|
253
|
+
new <name> [--template] Create a new AeroJS app (api-starter, react-inertia, vue-inertia, fullstack)
|
|
254
254
|
|
|
255
255
|
make:controller <name> Create a new RESTful controller class
|
|
256
256
|
make:model <name> [-m] Create a new Active Record Model (optionally with migration)
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* @poppinss/hooks pattern. Supports multiple handlers per event, async execution,
|
|
5
5
|
* decorator-based registration, and one-time hooks.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* @beforeSave()
|
|
9
|
-
* @beforeCreate() → generate
|
|
10
|
-
* @afterCreate()
|
|
11
|
-
* @beforeDelete() → block
|
|
7
|
+
* Typical use-cases:
|
|
8
|
+
* @beforeSave() → auto-hash password before saving
|
|
9
|
+
* @beforeCreate() → generate unique reference code or UUID
|
|
10
|
+
* @afterCreate() → dispatch UserRegistered domain event or send welcome notification
|
|
11
|
+
* @beforeDelete() → block deletion or enforce soft-delete policy
|
|
12
12
|
* @afterUpdate() → write immutable audit trail
|
|
13
13
|
*/
|
|
14
14
|
export type ModelHookEvent = 'beforeCreate' | 'afterCreate' | 'beforeSave' | 'afterSave' | 'beforeUpdate' | 'afterUpdate' | 'beforeDelete' | 'afterDelete' | 'beforeFind' | 'afterFind' | 'beforeFetch' | 'afterFetch';
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* @poppinss/hooks pattern. Supports multiple handlers per event, async execution,
|
|
5
5
|
* decorator-based registration, and one-time hooks.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* @beforeSave()
|
|
9
|
-
* @beforeCreate() → generate
|
|
10
|
-
* @afterCreate()
|
|
11
|
-
* @beforeDelete() → block
|
|
7
|
+
* Typical use-cases:
|
|
8
|
+
* @beforeSave() → auto-hash password before saving
|
|
9
|
+
* @beforeCreate() → generate unique reference code or UUID
|
|
10
|
+
* @afterCreate() → dispatch UserRegistered domain event or send welcome notification
|
|
11
|
+
* @beforeDelete() → block deletion or enforce soft-delete policy
|
|
12
12
|
* @afterUpdate() → write immutable audit trail
|
|
13
13
|
*/
|
|
14
14
|
// ─── Hook Registry ────────────────────────────────────────────────────────────
|
|
@@ -69,22 +69,22 @@ export function getHookRegistry(ModelClass) {
|
|
|
69
69
|
* as a lifecycle hook handler.
|
|
70
70
|
*
|
|
71
71
|
* @example
|
|
72
|
-
* class
|
|
72
|
+
* class User extends Model {
|
|
73
73
|
* @beforeCreate()
|
|
74
|
-
* public static
|
|
75
|
-
* instance.
|
|
74
|
+
* public static generateUuid(instance: User) {
|
|
75
|
+
* instance.uuid = crypto.randomUUID();
|
|
76
76
|
* }
|
|
77
77
|
*
|
|
78
78
|
* @beforeSave()
|
|
79
|
-
* public static async hashPassword(instance:
|
|
79
|
+
* public static async hashPassword(instance: User) {
|
|
80
80
|
* if (instance.$dirty.password) {
|
|
81
81
|
* instance.password = await hash(instance.password);
|
|
82
82
|
* }
|
|
83
83
|
* }
|
|
84
84
|
*
|
|
85
85
|
* @beforeDelete()
|
|
86
|
-
* public static
|
|
87
|
-
*
|
|
86
|
+
* public static enforceSoftDelete(_instance: User) {
|
|
87
|
+
* // Enforce soft-delete logic
|
|
88
88
|
* }
|
|
89
89
|
* }
|
|
90
90
|
*/
|
package/dist/database/model.d.ts
CHANGED
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
* 🆕 NEW: $dirty tracking (know exactly what changed)
|
|
11
11
|
* 🆕 NEW: $original + isDirty(field) helpers
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
* -
|
|
15
|
-
* -
|
|
16
|
-
* -
|
|
17
|
-
* - @beforeCreate() → generate
|
|
18
|
-
* - @beforeDelete() →
|
|
13
|
+
* Examples:
|
|
14
|
+
* - User ↔ Role (manyToMany via user_roles)
|
|
15
|
+
* - Country → Users → Posts (hasManyThrough)
|
|
16
|
+
* - User.query().active().verified().byRole('admin').paginate(1, 20)
|
|
17
|
+
* - @beforeCreate() → generate UUID or reference code
|
|
18
|
+
* - @beforeDelete() → enforce audit retention policy
|
|
19
19
|
*/
|
|
20
20
|
import { type DatabaseAdapter } from './connection.js';
|
|
21
21
|
export interface RelationDefinition {
|
|
@@ -71,13 +71,7 @@ export declare class Relation implements PromiseLike<any> {
|
|
|
71
71
|
* Computed properties are derived from other attributes (not stored in DB).
|
|
72
72
|
*
|
|
73
73
|
* @example
|
|
74
|
-
* class
|
|
75
|
-
* @computed()
|
|
76
|
-
* get age(): number {
|
|
77
|
-
* const dob = new Date(this.date_of_birth);
|
|
78
|
-
* return Math.floor((Date.now() - dob.getTime()) / (365.25 * 24 * 3600 * 1000));
|
|
79
|
-
* }
|
|
80
|
-
*
|
|
74
|
+
* class User extends Model {
|
|
81
75
|
* @computed()
|
|
82
76
|
* get fullName(): string {
|
|
83
77
|
* return `${this.first_name} ${this.last_name}`;
|
|
@@ -90,7 +84,7 @@ export declare function computed(): PropertyDecorator;
|
|
|
90
84
|
* The attribute is stored encrypted in the database, but read and manipulated as plaintext in application code.
|
|
91
85
|
*
|
|
92
86
|
* @example
|
|
93
|
-
* class
|
|
87
|
+
* class AccountRecord extends Model {
|
|
94
88
|
* @encrypted()
|
|
95
89
|
* public ssn!: string;
|
|
96
90
|
* }
|
|
@@ -118,8 +112,8 @@ export declare class Model {
|
|
|
118
112
|
* Global query scopes automatically applied to every query.
|
|
119
113
|
*
|
|
120
114
|
* @example
|
|
121
|
-
* class
|
|
122
|
-
* public static override globalScopes = [
|
|
115
|
+
* class User extends Model {
|
|
116
|
+
* public static override globalScopes = [TenantScope, ActiveScope];
|
|
123
117
|
* }
|
|
124
118
|
*/
|
|
125
119
|
static globalScopes: Array<(qb: any, ctx?: any) => void>;
|
|
@@ -147,32 +141,22 @@ export declare class Model {
|
|
|
147
141
|
* ManyToMany Relationship via a pivot table.
|
|
148
142
|
*
|
|
149
143
|
* @example
|
|
150
|
-
* //
|
|
151
|
-
* public
|
|
152
|
-
* return this.manyToMany(
|
|
153
|
-
* pivotTable: '
|
|
154
|
-
* pivotForeignKey: '
|
|
155
|
-
* pivotRelatedKey: '
|
|
156
|
-
* pivotColumns: ['
|
|
157
|
-
* });
|
|
158
|
-
* }
|
|
159
|
-
*
|
|
160
|
-
* // Patient ↔ ICD-11 Diagnosis (pivot: patient_diagnoses)
|
|
161
|
-
* public diagnoses() {
|
|
162
|
-
* return this.manyToMany(Diagnosis, {
|
|
163
|
-
* pivotTable: 'patient_diagnoses',
|
|
164
|
-
* pivotForeignKey: 'patient_id',
|
|
165
|
-
* pivotRelatedKey: 'diagnosis_code',
|
|
144
|
+
* // User ↔ Role (pivot: user_roles)
|
|
145
|
+
* public roles() {
|
|
146
|
+
* return this.manyToMany(Role, {
|
|
147
|
+
* pivotTable: 'user_roles',
|
|
148
|
+
* pivotForeignKey: 'user_id',
|
|
149
|
+
* pivotRelatedKey: 'role_id',
|
|
150
|
+
* pivotColumns: ['assigned_at'], // extra pivot columns
|
|
166
151
|
* });
|
|
167
152
|
* }
|
|
168
153
|
*
|
|
169
|
-
* //
|
|
170
|
-
* public
|
|
171
|
-
* return this.manyToMany(
|
|
172
|
-
* pivotTable: '
|
|
173
|
-
* pivotForeignKey: '
|
|
174
|
-
* pivotRelatedKey: '
|
|
175
|
-
* pivotColumns: ['role'], // primary_surgeon, assistant, anesthesiologist
|
|
154
|
+
* // Article ↔ Tag (pivot: article_tags)
|
|
155
|
+
* public tags() {
|
|
156
|
+
* return this.manyToMany(Tag, {
|
|
157
|
+
* pivotTable: 'article_tags',
|
|
158
|
+
* pivotForeignKey: 'article_id',
|
|
159
|
+
* pivotRelatedKey: 'tag_id',
|
|
176
160
|
* });
|
|
177
161
|
* }
|
|
178
162
|
*/
|
|
@@ -181,19 +165,19 @@ export declare class Model {
|
|
|
181
165
|
* HasManyThrough Relationship.
|
|
182
166
|
*
|
|
183
167
|
* @example
|
|
184
|
-
* //
|
|
185
|
-
* public
|
|
186
|
-
* return this.hasManyThrough(
|
|
187
|
-
* foreignKey: '
|
|
188
|
-
* throughForeignKey: '
|
|
168
|
+
* // Country has many Posts through Users
|
|
169
|
+
* public posts() {
|
|
170
|
+
* return this.hasManyThrough(Post, User, {
|
|
171
|
+
* foreignKey: 'country_id', // FK on User pointing to Country
|
|
172
|
+
* throughForeignKey: 'user_id', // FK on Post pointing to User
|
|
189
173
|
* });
|
|
190
174
|
* }
|
|
191
175
|
*
|
|
192
|
-
* //
|
|
193
|
-
* public
|
|
194
|
-
* return this.hasManyThrough(
|
|
195
|
-
* foreignKey: '
|
|
196
|
-
* throughForeignKey: '
|
|
176
|
+
* // Organization has many Tasks through Projects
|
|
177
|
+
* public tasks() {
|
|
178
|
+
* return this.hasManyThrough(Task, Project, {
|
|
179
|
+
* foreignKey: 'organization_id',
|
|
180
|
+
* throughForeignKey: 'project_id',
|
|
197
181
|
* });
|
|
198
182
|
* }
|
|
199
183
|
*/
|
|
@@ -202,27 +186,27 @@ export declare class Model {
|
|
|
202
186
|
* Attach related records to the ManyToMany pivot table.
|
|
203
187
|
*
|
|
204
188
|
* @example
|
|
205
|
-
* // Attach
|
|
206
|
-
* await
|
|
189
|
+
* // Attach roles to user
|
|
190
|
+
* await user.attach('roles', [1, 3, 5]);
|
|
207
191
|
*
|
|
208
|
-
* // Attach with pivot data (e.g.
|
|
209
|
-
* await
|
|
192
|
+
* // Attach with pivot data (e.g. assigned_at date)
|
|
193
|
+
* await user.attach('roles', { 1: { assigned_at: '2024-01-01' } });
|
|
210
194
|
*/
|
|
211
195
|
attach(relationName: string, idsOrMap: number[] | string[] | Record<string | number, Record<string, any>>, connectionOrAdapter?: string | DatabaseAdapter): Promise<void>;
|
|
212
196
|
/**
|
|
213
197
|
* Detach related records from the ManyToMany pivot table.
|
|
214
198
|
*
|
|
215
199
|
* @example
|
|
216
|
-
* await
|
|
217
|
-
* await
|
|
200
|
+
* await user.detach('roles', [3]); // detach specific
|
|
201
|
+
* await user.detach('roles'); // detach all
|
|
218
202
|
*/
|
|
219
203
|
detach(relationName: string, ids?: number[] | string[], connectionOrAdapter?: string | DatabaseAdapter): Promise<void>;
|
|
220
204
|
/**
|
|
221
205
|
* Sync pivot table — detach all then re-attach.
|
|
222
206
|
*
|
|
223
207
|
* @example
|
|
224
|
-
* // Sync
|
|
225
|
-
* await
|
|
208
|
+
* // Sync user's roles (replaces all existing)
|
|
209
|
+
* await user.sync('roles', [1, 3, 5]);
|
|
226
210
|
*/
|
|
227
211
|
sync(relationName: string, idsOrMap: number[] | string[] | Record<string | number, Record<string, any>>, connectionOrAdapter?: string | DatabaseAdapter): Promise<void>;
|
|
228
212
|
/**
|
|
@@ -263,8 +247,8 @@ export declare class Model {
|
|
|
263
247
|
* Update or create a record.
|
|
264
248
|
*
|
|
265
249
|
* @example
|
|
266
|
-
* await
|
|
267
|
-
* {
|
|
250
|
+
* await User.updateOrCreate(
|
|
251
|
+
* { email: 'user@example.com' },
|
|
268
252
|
* { name: 'Rahim', phone: '01700000000' }
|
|
269
253
|
* );
|
|
270
254
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/database/model.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAA8B,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAQnF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,WAAW,GAAG,YAAY,GAAG,gBAAgB,CAAC;IAC3E,YAAY,EAAE,OAAO,KAAK,GAAG,GAAG,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,KAAK,CAAC;IAEtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB,YAAY,CAAC,EAAE,OAAO,KAAK,GAAG,GAAG,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAID,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAID,MAAM,WAAW,qBAAqB;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAID,qBAAa,QAAS,YAAW,WAAW,CAAC,GAAG,CAAC;IACxC,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACjC,YAAY,EAAE,OAAO,KAAK,GAAG,GAAG,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,KAAK,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,KAAK,GAAG,GAAG,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;gBAEpB,GAAG,EAAE,kBAAkB;IAetB,IAAI,CAAC,QAAQ,GAAG,GAAG,EAAE,QAAQ,GAAG,KAAK,EAChD,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EACvE,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,GACtE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAUlB,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC;YA8BvB,kBAAkB;YA0ClB,sBAAsB;CA0BrC;AAID
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/database/model.ts"],"names":[],"mappings":"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"}
|
package/dist/database/model.js
CHANGED
|
@@ -11,12 +11,12 @@ import { TenancyContext } from '../tenancy/tenant.js';
|
|
|
11
11
|
* 🆕 NEW: $dirty tracking (know exactly what changed)
|
|
12
12
|
* 🆕 NEW: $original + isDirty(field) helpers
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
* -
|
|
16
|
-
* -
|
|
17
|
-
* -
|
|
18
|
-
* - @beforeCreate() → generate
|
|
19
|
-
* - @beforeDelete() →
|
|
14
|
+
* Examples:
|
|
15
|
+
* - User ↔ Role (manyToMany via user_roles)
|
|
16
|
+
* - Country → Users → Posts (hasManyThrough)
|
|
17
|
+
* - User.query().active().verified().byRole('admin').paginate(1, 20)
|
|
18
|
+
* - @beforeCreate() → generate UUID or reference code
|
|
19
|
+
* - @beforeDelete() → enforce audit retention policy
|
|
20
20
|
*/
|
|
21
21
|
import { Database } from './connection.js';
|
|
22
22
|
import { QueryBuilder } from './query-builder.js';
|
|
@@ -162,13 +162,7 @@ export class Relation {
|
|
|
162
162
|
* Computed properties are derived from other attributes (not stored in DB).
|
|
163
163
|
*
|
|
164
164
|
* @example
|
|
165
|
-
* class
|
|
166
|
-
* @computed()
|
|
167
|
-
* get age(): number {
|
|
168
|
-
* const dob = new Date(this.date_of_birth);
|
|
169
|
-
* return Math.floor((Date.now() - dob.getTime()) / (365.25 * 24 * 3600 * 1000));
|
|
170
|
-
* }
|
|
171
|
-
*
|
|
165
|
+
* class User extends Model {
|
|
172
166
|
* @computed()
|
|
173
167
|
* get fullName(): string {
|
|
174
168
|
* return `${this.first_name} ${this.last_name}`;
|
|
@@ -189,7 +183,7 @@ export function computed() {
|
|
|
189
183
|
* The attribute is stored encrypted in the database, but read and manipulated as plaintext in application code.
|
|
190
184
|
*
|
|
191
185
|
* @example
|
|
192
|
-
* class
|
|
186
|
+
* class AccountRecord extends Model {
|
|
193
187
|
* @encrypted()
|
|
194
188
|
* public ssn!: string;
|
|
195
189
|
* }
|
|
@@ -261,8 +255,8 @@ export class Model {
|
|
|
261
255
|
* Global query scopes automatically applied to every query.
|
|
262
256
|
*
|
|
263
257
|
* @example
|
|
264
|
-
* class
|
|
265
|
-
* public static override globalScopes = [
|
|
258
|
+
* class User extends Model {
|
|
259
|
+
* public static override globalScopes = [TenantScope, ActiveScope];
|
|
266
260
|
* }
|
|
267
261
|
*/
|
|
268
262
|
static globalScopes = [];
|
|
@@ -395,32 +389,22 @@ export class Model {
|
|
|
395
389
|
* ManyToMany Relationship via a pivot table.
|
|
396
390
|
*
|
|
397
391
|
* @example
|
|
398
|
-
* //
|
|
399
|
-
* public
|
|
400
|
-
* return this.manyToMany(
|
|
401
|
-
* pivotTable: '
|
|
402
|
-
* pivotForeignKey: '
|
|
403
|
-
* pivotRelatedKey: '
|
|
404
|
-
* pivotColumns: ['
|
|
405
|
-
* });
|
|
406
|
-
* }
|
|
407
|
-
*
|
|
408
|
-
* // Patient ↔ ICD-11 Diagnosis (pivot: patient_diagnoses)
|
|
409
|
-
* public diagnoses() {
|
|
410
|
-
* return this.manyToMany(Diagnosis, {
|
|
411
|
-
* pivotTable: 'patient_diagnoses',
|
|
412
|
-
* pivotForeignKey: 'patient_id',
|
|
413
|
-
* pivotRelatedKey: 'diagnosis_code',
|
|
392
|
+
* // User ↔ Role (pivot: user_roles)
|
|
393
|
+
* public roles() {
|
|
394
|
+
* return this.manyToMany(Role, {
|
|
395
|
+
* pivotTable: 'user_roles',
|
|
396
|
+
* pivotForeignKey: 'user_id',
|
|
397
|
+
* pivotRelatedKey: 'role_id',
|
|
398
|
+
* pivotColumns: ['assigned_at'], // extra pivot columns
|
|
414
399
|
* });
|
|
415
400
|
* }
|
|
416
401
|
*
|
|
417
|
-
* //
|
|
418
|
-
* public
|
|
419
|
-
* return this.manyToMany(
|
|
420
|
-
* pivotTable: '
|
|
421
|
-
* pivotForeignKey: '
|
|
422
|
-
* pivotRelatedKey: '
|
|
423
|
-
* pivotColumns: ['role'], // primary_surgeon, assistant, anesthesiologist
|
|
402
|
+
* // Article ↔ Tag (pivot: article_tags)
|
|
403
|
+
* public tags() {
|
|
404
|
+
* return this.manyToMany(Tag, {
|
|
405
|
+
* pivotTable: 'article_tags',
|
|
406
|
+
* pivotForeignKey: 'article_id',
|
|
407
|
+
* pivotRelatedKey: 'tag_id',
|
|
424
408
|
* });
|
|
425
409
|
* }
|
|
426
410
|
*/
|
|
@@ -446,19 +430,19 @@ export class Model {
|
|
|
446
430
|
* HasManyThrough Relationship.
|
|
447
431
|
*
|
|
448
432
|
* @example
|
|
449
|
-
* //
|
|
450
|
-
* public
|
|
451
|
-
* return this.hasManyThrough(
|
|
452
|
-
* foreignKey: '
|
|
453
|
-
* throughForeignKey: '
|
|
433
|
+
* // Country has many Posts through Users
|
|
434
|
+
* public posts() {
|
|
435
|
+
* return this.hasManyThrough(Post, User, {
|
|
436
|
+
* foreignKey: 'country_id', // FK on User pointing to Country
|
|
437
|
+
* throughForeignKey: 'user_id', // FK on Post pointing to User
|
|
454
438
|
* });
|
|
455
439
|
* }
|
|
456
440
|
*
|
|
457
|
-
* //
|
|
458
|
-
* public
|
|
459
|
-
* return this.hasManyThrough(
|
|
460
|
-
* foreignKey: '
|
|
461
|
-
* throughForeignKey: '
|
|
441
|
+
* // Organization has many Tasks through Projects
|
|
442
|
+
* public tasks() {
|
|
443
|
+
* return this.hasManyThrough(Task, Project, {
|
|
444
|
+
* foreignKey: 'organization_id',
|
|
445
|
+
* throughForeignKey: 'project_id',
|
|
462
446
|
* });
|
|
463
447
|
* }
|
|
464
448
|
*/
|
|
@@ -482,11 +466,11 @@ export class Model {
|
|
|
482
466
|
* Attach related records to the ManyToMany pivot table.
|
|
483
467
|
*
|
|
484
468
|
* @example
|
|
485
|
-
* // Attach
|
|
486
|
-
* await
|
|
469
|
+
* // Attach roles to user
|
|
470
|
+
* await user.attach('roles', [1, 3, 5]);
|
|
487
471
|
*
|
|
488
|
-
* // Attach with pivot data (e.g.
|
|
489
|
-
* await
|
|
472
|
+
* // Attach with pivot data (e.g. assigned_at date)
|
|
473
|
+
* await user.attach('roles', { 1: { assigned_at: '2024-01-01' } });
|
|
490
474
|
*/
|
|
491
475
|
async attach(relationName, idsOrMap, connectionOrAdapter) {
|
|
492
476
|
const rel = this[relationName]();
|
|
@@ -515,8 +499,8 @@ export class Model {
|
|
|
515
499
|
* Detach related records from the ManyToMany pivot table.
|
|
516
500
|
*
|
|
517
501
|
* @example
|
|
518
|
-
* await
|
|
519
|
-
* await
|
|
502
|
+
* await user.detach('roles', [3]); // detach specific
|
|
503
|
+
* await user.detach('roles'); // detach all
|
|
520
504
|
*/
|
|
521
505
|
async detach(relationName, ids, connectionOrAdapter) {
|
|
522
506
|
const rel = this[relationName]();
|
|
@@ -535,8 +519,8 @@ export class Model {
|
|
|
535
519
|
* Sync pivot table — detach all then re-attach.
|
|
536
520
|
*
|
|
537
521
|
* @example
|
|
538
|
-
* // Sync
|
|
539
|
-
* await
|
|
522
|
+
* // Sync user's roles (replaces all existing)
|
|
523
|
+
* await user.sync('roles', [1, 3, 5]);
|
|
540
524
|
*/
|
|
541
525
|
async sync(relationName, idsOrMap, connectionOrAdapter) {
|
|
542
526
|
await this.detach(relationName, undefined, connectionOrAdapter);
|
|
@@ -862,8 +846,8 @@ export class Model {
|
|
|
862
846
|
* Update or create a record.
|
|
863
847
|
*
|
|
864
848
|
* @example
|
|
865
|
-
* await
|
|
866
|
-
* {
|
|
849
|
+
* await User.updateOrCreate(
|
|
850
|
+
* { email: 'user@example.com' },
|
|
867
851
|
* { name: 'Rahim', phone: '01700000000' }
|
|
868
852
|
* );
|
|
869
853
|
*/
|