@adaas/a-server 0.0.29 → 0.0.31

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 (84) hide show
  1. package/dist/browser/index.d.mts +123 -69
  2. package/dist/browser/index.mjs +211 -69
  3. package/dist/browser/index.mjs.map +1 -1
  4. package/dist/node/controllers/A-EntityController/A-EntityController.component.d.mts +2 -5
  5. package/dist/node/controllers/A-EntityController/A-EntityController.component.d.ts +2 -5
  6. package/dist/node/controllers/A-EntityController/A-EntityController.component.js +66 -88
  7. package/dist/node/controllers/A-EntityController/A-EntityController.component.js.map +1 -1
  8. package/dist/node/controllers/A-EntityController/A-EntityController.component.mjs +67 -89
  9. package/dist/node/controllers/A-EntityController/A-EntityController.component.mjs.map +1 -1
  10. package/dist/node/controllers/A-ListingController/A-ListingController.component.js +20 -18
  11. package/dist/node/controllers/A-ListingController/A-ListingController.component.js.map +1 -1
  12. package/dist/node/controllers/A-ListingController/A-ListingController.component.mjs +20 -18
  13. package/dist/node/controllers/A-ListingController/A-ListingController.component.mjs.map +1 -1
  14. package/dist/node/controllers/A-ServerHealthMonitor/A-ServerHealthMonitor.component.d.mts +0 -2
  15. package/dist/node/controllers/A-ServerHealthMonitor/A-ServerHealthMonitor.component.d.ts +0 -2
  16. package/dist/node/controllers/A-ServerHealthMonitor/A-ServerHealthMonitor.component.js +10 -1
  17. package/dist/node/controllers/A-ServerHealthMonitor/A-ServerHealthMonitor.component.js.map +1 -1
  18. package/dist/node/controllers/A-ServerHealthMonitor/A-ServerHealthMonitor.component.mjs +10 -1
  19. package/dist/node/controllers/A-ServerHealthMonitor/A-ServerHealthMonitor.component.mjs.map +1 -1
  20. package/dist/node/index.d.mts +3 -1
  21. package/dist/node/index.d.ts +3 -1
  22. package/dist/node/index.js +14 -0
  23. package/dist/node/index.mjs +2 -0
  24. package/dist/node/lib/A-Server/A-HttpServer.container.d.mts +4 -6
  25. package/dist/node/lib/A-Server/A-HttpServer.container.d.ts +4 -6
  26. package/dist/node/lib/A-ServerController/A-ServerController.component.js +17 -4
  27. package/dist/node/lib/A-ServerController/A-ServerController.component.js.map +1 -1
  28. package/dist/node/lib/A-ServerController/A-ServerController.component.mjs +17 -4
  29. package/dist/node/lib/A-ServerController/A-ServerController.component.mjs.map +1 -1
  30. package/dist/node/lib/A-ServerEntityList/A-EntityList.entity.d.mts +52 -28
  31. package/dist/node/lib/A-ServerEntityList/A-EntityList.entity.d.ts +52 -28
  32. package/dist/node/lib/A-ServerEntityList/A-EntityList.entity.js +117 -44
  33. package/dist/node/lib/A-ServerEntityList/A-EntityList.entity.js.map +1 -1
  34. package/dist/node/lib/A-ServerEntityList/A-EntityList.entity.mjs +118 -45
  35. package/dist/node/lib/A-ServerEntityList/A-EntityList.entity.mjs.map +1 -1
  36. package/dist/node/lib/A-ServerEntityList/A-EntityList.types.d.mts +14 -6
  37. package/dist/node/lib/A-ServerEntityList/A-EntityList.types.d.ts +14 -6
  38. package/dist/node/lib/A-ServerEntityList/A-EntityList.types.js.map +1 -1
  39. package/dist/node/lib/A-ServerEntityList/A-EntityList.types.mjs.map +1 -1
  40. package/dist/node/lib/A-ServerEntityList/A-EntityListCacheState.context.d.mts +12 -0
  41. package/dist/node/lib/A-ServerEntityList/A-EntityListCacheState.context.d.ts +12 -0
  42. package/dist/node/lib/A-ServerEntityList/A-EntityListCacheState.context.js +25 -0
  43. package/dist/node/lib/A-ServerEntityList/A-EntityListCacheState.context.js.map +1 -0
  44. package/dist/node/lib/A-ServerEntityList/A-EntityListCacheState.context.mjs +24 -0
  45. package/dist/node/lib/A-ServerEntityList/A-EntityListCacheState.context.mjs.map +1 -0
  46. package/dist/node/lib/A-ServerEntityList/A-EntityListPagination.context.d.mts +18 -0
  47. package/dist/node/lib/A-ServerEntityList/A-EntityListPagination.context.d.ts +18 -0
  48. package/dist/node/lib/A-ServerEntityList/A-EntityListPagination.context.js +48 -0
  49. package/dist/node/lib/A-ServerEntityList/A-EntityListPagination.context.js.map +1 -0
  50. package/dist/node/lib/A-ServerEntityList/A-EntityListPagination.context.mjs +47 -0
  51. package/dist/node/lib/A-ServerEntityList/A-EntityListPagination.context.mjs.map +1 -0
  52. package/dist/node/lib/A-ServerLogger/A-ServerLogger.component.d.mts +6 -8
  53. package/dist/node/lib/A-ServerLogger/A-ServerLogger.component.d.ts +6 -8
  54. package/dist/node/lib/A-ServerLogger/A-ServerLogger.component.js +3 -4
  55. package/dist/node/lib/A-ServerLogger/A-ServerLogger.component.js.map +1 -1
  56. package/dist/node/lib/A-ServerLogger/A-ServerLogger.component.mjs +4 -5
  57. package/dist/node/lib/A-ServerLogger/A-ServerLogger.component.mjs.map +1 -1
  58. package/dist/node/lib/A-ServerRouter/A-ServerRouter.component.d.mts +0 -2
  59. package/dist/node/lib/A-ServerRouter/A-ServerRouter.component.d.ts +0 -2
  60. package/dist/node/middlewares/A-ServerCORS/A_ServerCORS.component.js +1 -1
  61. package/dist/node/middlewares/A-ServerCORS/A_ServerCORS.component.js.map +1 -1
  62. package/dist/node/middlewares/A-ServerCORS/A_ServerCORS.component.mjs +1 -1
  63. package/dist/node/middlewares/A-ServerCORS/A_ServerCORS.component.mjs.map +1 -1
  64. package/dist/node/repositories/A-EntityRepository/A-EntityRepository.component.d.mts +1 -0
  65. package/dist/node/repositories/A-EntityRepository/A-EntityRepository.component.d.ts +1 -0
  66. package/examples/simple-server/components/Users.repository.ts +2 -2
  67. package/jest.config.ts +1 -0
  68. package/package.json +5 -5
  69. package/src/controllers/A-EntityController/A-EntityController.component.ts +69 -109
  70. package/src/controllers/A-ListingController/A-ListingController.component.ts +22 -20
  71. package/src/controllers/A-ServerHealthMonitor/A-ServerHealthMonitor.component.ts +11 -1
  72. package/src/index.ts +2 -0
  73. package/src/lib/A-ServerController/A-ServerController.component.ts +17 -8
  74. package/src/lib/A-ServerEntityList/A-EntityList.entity.ts +159 -55
  75. package/src/lib/A-ServerEntityList/A-EntityList.types.ts +17 -7
  76. package/src/lib/A-ServerEntityList/A-EntityListCacheState.context.ts +27 -0
  77. package/src/lib/A-ServerEntityList/A-EntityListPagination.context.ts +48 -0
  78. package/src/lib/A-ServerLogger/A-ServerLogger.component.ts +3 -4
  79. package/src/middlewares/A-ServerCORS/A_ServerCORS.component.ts +1 -1
  80. package/tests/A-Server-CORS.test.ts +542 -0
  81. package/tests/A-Server-Entity.test.ts +205 -0
  82. package/tests/A-Server-Health.test.ts +89 -0
  83. package/tests/A-Server-Routes.test.ts +113 -0
  84. package/tests/A-ServerEntityList.test.ts +416 -0
@@ -1,48 +1,72 @@
1
- import { A_Entity } from '@adaas/a-concept';
1
+ import { A_Entity, A_TYPES__Entity_Constructor, A_Scope } from '@adaas/a-concept';
2
2
  import { A_SERVER_TYPES__A_EntityListConstructor, A_SERVER_TYPES__A_EntityListSerialized, A_SERVER_TYPES__A_EntityListPagination } from './A-EntityList.types.js';
3
+ import { A_ServerEntityListPagination } from './A-EntityListPagination.context.js';
3
4
 
4
5
  /**
5
6
  * A-EntityList
6
7
  *
7
- * Entity that represents a list of entities with pagination of particular type
8
+ * Typed, paginated list of A-Concept entities.
9
+ *
10
+ * Construction (user-facing):
11
+ * new A_ServerEntityList<User>({ entity: User, pagination: { page: 1, pageSize: 20 } })
12
+ *
13
+ * Construction (controller-internal, backward-compat):
14
+ * new A_ServerEntityList({ name: 'user', scope: 'my-scope', constructor: User })
8
15
  */
9
- declare class A_ServerEntityList<EntityType extends A_Entity = A_Entity> extends A_Entity<A_SERVER_TYPES__A_EntityListConstructor, A_SERVER_TYPES__A_EntityListSerialized> {
16
+ declare class A_ServerEntityList<EntityType extends A_Entity = A_Entity> extends A_Entity<A_SERVER_TYPES__A_EntityListConstructor<EntityType>, A_SERVER_TYPES__A_EntityListSerialized<EntityType>> {
10
17
  static get scope(): string;
11
- protected _entityConstructor: new (...args: ConstructorParameters<typeof A_Entity>) => EntityType;
12
- protected _items: Array<EntityType>;
13
- protected _pagination: A_SERVER_TYPES__A_EntityListPagination;
18
+ protected _entityConstructor: A_TYPES__Entity_Constructor<EntityType>;
14
19
  /**
15
- * Returns the entity constructor used for the list
20
+ * Ordered item references for O(1) positional access.
21
+ * The list's own scope is the authoritative store (enables @A_Inject and
22
+ * feature chains on items); this array mirrors the same items in order.
16
23
  */
17
- get entityConstructor(): new (...args: ConstructorParameters<typeof A_Entity>) => EntityType;
24
+ protected _items: Array<EntityType>;
25
+ /** Lazily allocated private scope — pagination and cache state live here. */
26
+ private _ownScope?;
18
27
  /**
19
- * Returns the list of items contained in the entity list
28
+ * The list's own scope, created on first access and bound to this entity
29
+ * via A_Context.allocate. Items, pagination and cache state are registered
30
+ * here so they participate in feature chains and @A_Inject resolution.
20
31
  */
32
+ get ownScope(): A_Scope;
33
+ get entityConstructor(): A_TYPES__Entity_Constructor<EntityType>;
21
34
  get items(): Array<EntityType>;
35
+ /** Pagination state — lives as a Fragment in the list's own scope. */
36
+ get pagination(): A_ServerEntityListPagination;
37
+ private get cacheState();
38
+ /** Total number of items currently held in memory. */
39
+ get length(): number;
40
+ fromNew(newEntity: A_SERVER_TYPES__A_EntityListConstructor<EntityType>): void;
22
41
  /**
23
- * Returns pagination information about the entity list
24
- */
25
- get pagination(): A_SERVER_TYPES__A_EntityListPagination;
26
- /**
27
- * Creates a new instance of A_EntityList
28
- *
29
- * @param newEntity
30
- */
31
- fromNew(newEntity: A_SERVER_TYPES__A_EntityListConstructor): void;
32
- /**
33
- * Allows to convert Repository Response data to EntityList instance
34
- *
35
- * [!] This method does not load the data from the repository, it only converts the data to the EntityList instance
36
- *
37
- * @param items
38
- * @param pagination
42
+ * Populate the list from raw repository data.
43
+ * Items are registered in the list's own scope so they participate in
44
+ * feature chains and @A_Inject resolution.
39
45
  */
40
46
  fromList(items: Array<EntityType> | Array<ReturnType<EntityType['toJSON']>>, pagination?: A_SERVER_TYPES__A_EntityListPagination): void;
47
+ /** Return the item at `index`, or `undefined` if out of range. */
48
+ at(index: number): EntityType | undefined;
49
+ /** Replace the item at `index` in place. Accepts a live entity or a plain serialised object. */
50
+ replace(index: number, item: EntityType | ReturnType<EntityType['toJSON']>): this;
51
+ /** Append an item to the end of the list. */
52
+ push(item: EntityType | ReturnType<EntityType['toJSON']>): this;
53
+ /** Prepend an item to the beginning of the list. */
54
+ unshift(item: EntityType | ReturnType<EntityType['toJSON']>): this;
55
+ /** Remove the item at `index` from the list. */
56
+ remove(index: number): this;
57
+ /** Return the first item that satisfies `predicate`, or `undefined`. */
58
+ find(predicate: (item: EntityType, index: number) => boolean): EntityType | undefined;
59
+ /** Return all items that satisfy `predicate` without mutating the list. */
60
+ filter(predicate: (item: EntityType, index: number) => boolean): EntityType[];
41
61
  /**
42
- * Serializes the EntityList to a JSON object
43
- *
44
- * @returns
62
+ * Mark this list as cached for `ttlMs` milliseconds from now.
63
+ * Callers can check `isCached()` to decide whether to skip `load()`.
45
64
  */
65
+ setCache(ttlMs: number): this;
66
+ /** Returns `true` if the cache is still valid. */
67
+ isCached(): boolean;
68
+ /** Invalidate the cache so the next `load()` call fetches fresh data. */
69
+ invalidateCache(): this;
46
70
  toJSON(): A_SERVER_TYPES__A_EntityListSerialized<EntityType>;
47
71
  }
48
72
 
@@ -1,87 +1,160 @@
1
1
  'use strict';
2
2
 
3
3
  var aConcept = require('@adaas/a-concept');
4
+ var AEntityListPagination_context = require('./A-EntityListPagination.context');
5
+ var AEntityListCacheState_context = require('./A-EntityListCacheState.context');
4
6
 
5
7
  class A_ServerEntityList extends aConcept.A_Entity {
6
8
  constructor() {
7
9
  super(...arguments);
10
+ /**
11
+ * Ordered item references for O(1) positional access.
12
+ * The list's own scope is the authoritative store (enables @A_Inject and
13
+ * feature chains on items); this array mirrors the same items in order.
14
+ */
8
15
  this._items = [];
9
- this._pagination = {
10
- total: 0,
11
- page: 1,
12
- pageSize: 10
13
- };
14
16
  }
15
17
  static get scope() {
16
18
  return "a-server";
17
19
  }
20
+ // ── Getters ──────────────────────────────────────────────────────────────
18
21
  /**
19
- * Returns the entity constructor used for the list
22
+ * The list's own scope, created on first access and bound to this entity
23
+ * via A_Context.allocate. Items, pagination and cache state are registered
24
+ * here so they participate in feature chains and @A_Inject resolution.
20
25
  */
26
+ get ownScope() {
27
+ if (!this._ownScope) {
28
+ this._ownScope = aConcept.A_Context.allocate(
29
+ this,
30
+ new aConcept.A_Scope({ name: `${this.aseid.id}-scope` })
31
+ );
32
+ }
33
+ return this._ownScope;
34
+ }
21
35
  get entityConstructor() {
22
36
  return this._entityConstructor;
23
37
  }
24
- /**
25
- * Returns the list of items contained in the entity list
26
- */
27
38
  get items() {
28
39
  return this._items;
29
40
  }
30
- /**
31
- * Returns pagination information about the entity list
32
- */
41
+ /** Pagination state — lives as a Fragment in the list's own scope. */
33
42
  get pagination() {
34
- return this._pagination;
43
+ return this.ownScope.resolveFlatOnce(AEntityListPagination_context.A_ServerEntityListPagination);
35
44
  }
36
- /**
37
- * Creates a new instance of A_EntityList
38
- *
39
- * @param newEntity
40
- */
45
+ get cacheState() {
46
+ return this.ownScope.resolveFlatOnce(AEntityListCacheState_context.A_ServerEntityListCacheState);
47
+ }
48
+ /** Total number of items currently held in memory. */
49
+ get length() {
50
+ return this._items.length;
51
+ }
52
+ // ── Initialisation ───────────────────────────────────────────────────────
41
53
  fromNew(newEntity) {
42
- this.aseid = new aConcept.ASEID({
54
+ this.aseid = this.generateASEID({
43
55
  concept: aConcept.A_Context.root.name,
44
- scope: "default",
45
- entity: "a-list" + (newEntity.name ? `.${newEntity.name}` : ""),
46
- id: (/* @__PURE__ */ new Date()).getTime().toString()
56
+ entity: "a-list." + newEntity.entity.name
47
57
  });
48
- this._entityConstructor = newEntity.constructor;
58
+ this._entityConstructor = newEntity.entity;
59
+ this.ownScope.register(new AEntityListPagination_context.A_ServerEntityListPagination(newEntity.pagination));
60
+ this.ownScope.register(new AEntityListCacheState_context.A_ServerEntityListCacheState());
49
61
  }
50
62
  /**
51
- * Allows to convert Repository Response data to EntityList instance
52
- *
53
- * [!] This method does not load the data from the repository, it only converts the data to the EntityList instance
54
- *
55
- * @param items
56
- * @param pagination
63
+ * Populate the list from raw repository data.
64
+ * Items are registered in the list's own scope so they participate in
65
+ * feature chains and @A_Inject resolution.
57
66
  */
58
67
  fromList(items, pagination) {
59
- this._items = items.map((item) => {
60
- if (item instanceof aConcept.A_Entity) {
61
- return item;
62
- } else {
63
- const entity = new this._entityConstructor(item);
64
- return entity;
68
+ this._items.forEach((item) => {
69
+ try {
70
+ this.ownScope.deregister(item);
71
+ } catch {
65
72
  }
66
73
  });
74
+ this._items = items.map((item) => {
75
+ const entity = item instanceof aConcept.A_Entity ? item : new this._entityConstructor(item);
76
+ this.ownScope.register(entity);
77
+ return entity;
78
+ });
67
79
  if (pagination) {
68
- this._pagination = {
69
- total: pagination.total,
70
- page: pagination.page,
71
- pageSize: pagination.pageSize
72
- };
80
+ this.pagination.update(pagination);
73
81
  }
74
82
  }
83
+ // ── Collection access ────────────────────────────────────────────────────
84
+ /** Return the item at `index`, or `undefined` if out of range. */
85
+ at(index) {
86
+ return this._items[index];
87
+ }
88
+ /** Replace the item at `index` in place. Accepts a live entity or a plain serialised object. */
89
+ replace(index, item) {
90
+ const next = item instanceof aConcept.A_Entity ? item : new this._entityConstructor(item);
91
+ try {
92
+ this.ownScope.deregister(this._items[index]);
93
+ } catch {
94
+ }
95
+ this.ownScope.register(next);
96
+ this._items[index] = next;
97
+ return this;
98
+ }
99
+ /** Append an item to the end of the list. */
100
+ push(item) {
101
+ const next = item instanceof aConcept.A_Entity ? item : new this._entityConstructor(item);
102
+ this.ownScope.register(next);
103
+ this._items.push(next);
104
+ return this;
105
+ }
106
+ /** Prepend an item to the beginning of the list. */
107
+ unshift(item) {
108
+ const next = item instanceof aConcept.A_Entity ? item : new this._entityConstructor(item);
109
+ this.ownScope.register(next);
110
+ this._items.unshift(next);
111
+ return this;
112
+ }
113
+ /** Remove the item at `index` from the list. */
114
+ remove(index) {
115
+ const [removed] = this._items.splice(index, 1);
116
+ if (removed) {
117
+ try {
118
+ this.ownScope.deregister(removed);
119
+ } catch {
120
+ }
121
+ }
122
+ return this;
123
+ }
124
+ /** Return the first item that satisfies `predicate`, or `undefined`. */
125
+ find(predicate) {
126
+ return this._items.find(predicate);
127
+ }
128
+ /** Return all items that satisfy `predicate` without mutating the list. */
129
+ filter(predicate) {
130
+ return this._items.filter(predicate);
131
+ }
132
+ // ── Caching ──────────────────────────────────────────────────────────────
75
133
  /**
76
- * Serializes the EntityList to a JSON object
77
- *
78
- * @returns
134
+ * Mark this list as cached for `ttlMs` milliseconds from now.
135
+ * Callers can check `isCached()` to decide whether to skip `load()`.
79
136
  */
137
+ setCache(ttlMs) {
138
+ this.cacheState.set(ttlMs);
139
+ return this;
140
+ }
141
+ /** Returns `true` if the cache is still valid. */
142
+ isCached() {
143
+ return this.cacheState.isValid();
144
+ }
145
+ /** Invalidate the cache so the next `load()` call fetches fresh data. */
146
+ invalidateCache() {
147
+ this.cacheState.invalidate();
148
+ return this;
149
+ }
150
+ // ── Serialisation ────────────────────────────────────────────────────────
80
151
  toJSON() {
152
+ const { total, page, pageSize } = this.pagination;
81
153
  return {
82
154
  ...super.toJSON(),
83
155
  items: this._items.map((i) => i.toJSON()),
84
- pagination: this._pagination
156
+ type: this._entityConstructor.entity ?? "unknown",
157
+ pagination: { total, page, pageSize }
85
158
  };
86
159
  }
87
160
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/A-ServerEntityList/A-EntityList.entity.ts"],"names":["A_Entity","ASEID","A_Context"],"mappings":";;;;AAiBO,MAAM,2BAEHA,iBAAA,CAGR;AAAA,EALK,WAAA,GAAA;AAAA,IAAA,KAAA,CAAA,GAAA,SAAA,CAAA;AAYH,IAAA,IAAA,CAAU,SAA4B,EAAC;AACvC,IAAA,IAAA,CAAU,WAAA,GAAsD;AAAA,MAC5D,KAAA,EAAO,CAAA;AAAA,MACP,IAAA,EAAM,CAAA;AAAA,MACN,QAAA,EAAU;AAAA,KACd;AAAA,EAAA;AAAA,EAVA,WAAW,KAAA,GAAgB;AACvB,IAAA,OAAO,UAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAcA,IAAI,iBAAA,GAAyF;AACzF,IAAA,OAAO,IAAA,CAAK,kBAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,KAAA,GAA2B;AAC3B,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,UAAA,GAAqD;AACrD,IAAA,OAAO,IAAA,CAAK,WAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,QAAQ,SAAA,EAA0D;AAC9D,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAIC,cAAA,CAAM;AAAA,MACnB,OAAA,EAASC,mBAAU,IAAA,CAAK,IAAA;AAAA,MACxB,KAAA,EAAO,SAAA;AAAA,MACP,QAAQ,QAAA,IAAY,SAAA,CAAU,OAAO,CAAA,CAAA,EAAI,SAAA,CAAU,IAAI,CAAA,CAAA,GAAK,EAAA,CAAA;AAAA,MAC5D,qBAAK,IAAI,IAAA,EAAK,EAAG,OAAA,GAAU,QAAA;AAAS,KACvC,CAAA;AAED,IAAA,IAAA,CAAK,qBAAqB,SAAA,CAAU,WAAA;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,QAAA,CACI,OACA,UAAA,EACF;AACE,IAAA,IAAA,CAAK,MAAA,GAAS,KAAA,CAAM,GAAA,CAAI,CAAA,IAAA,KAAQ;AAC5B,MAAA,IAAI,gBAAgBF,iBAAA,EAAU;AAC1B,QAAA,OAAO,IAAA;AAAA,MACX,CAAA,MAAO;AACH,QAAA,MAAM,MAAA,GAAS,IAAI,IAAA,CAAK,kBAAA,CAAmB,IAAI,CAAA;AAC/C,QAAA,OAAO,MAAA;AAAA,MACX;AAAA,IACJ,CAAC,CAAA;AAED,IAAA,IAAI,UAAA,EAAY;AACZ,MAAA,IAAA,CAAK,WAAA,GAAc;AAAA,QACf,OAAO,UAAA,CAAW,KAAA;AAAA,QAClB,MAAM,UAAA,CAAW,IAAA;AAAA,QACjB,UAAU,UAAA,CAAW;AAAA,OACzB;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAA,GAA6D;AACzD,IAAA,OAAO;AAAA,MACH,GAAG,MAAM,MAAA,EAAO;AAAA,MAChB,OAAO,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,QAAQ,CAAA;AAAA,MACtC,YAAY,IAAA,CAAK;AAAA,KACrB;AAAA,EACJ;AACJ","file":"A-EntityList.entity.js","sourcesContent":["import {\n A_Context, A_Entity,\n ASEID,\n} from \"@adaas/a-concept\";\nimport {\n A_SERVER_TYPES__A_EntityListConstructor,\n A_SERVER_TYPES__A_EntityListPagination,\n A_SERVER_TYPES__A_EntityListSerialized\n} from \"./A-EntityList.types\";\n\n\n\n/**\n * A-EntityList\n * \n * Entity that represents a list of entities with pagination of particular type\n */\nexport class A_ServerEntityList<\n EntityType extends A_Entity = A_Entity,\n> extends A_Entity<\n A_SERVER_TYPES__A_EntityListConstructor,\n A_SERVER_TYPES__A_EntityListSerialized\n> {\n\n static get scope(): string {\n return 'a-server';\n }\n\n protected _entityConstructor!: new (...args: ConstructorParameters<typeof A_Entity>) => EntityType;\n protected _items: Array<EntityType> = [];\n protected _pagination: A_SERVER_TYPES__A_EntityListPagination = {\n total: 0,\n page: 1,\n pageSize: 10\n };\n\n\n /**\n * Returns the entity constructor used for the list\n */\n get entityConstructor(): new (...args: ConstructorParameters<typeof A_Entity>) => EntityType {\n return this._entityConstructor;\n }\n\n /**\n * Returns the list of items contained in the entity list\n */\n get items(): Array<EntityType> {\n return this._items;\n }\n\n /**\n * Returns pagination information about the entity list\n */\n get pagination(): A_SERVER_TYPES__A_EntityListPagination {\n return this._pagination;\n }\n\n\n\n\n /**\n * Creates a new instance of A_EntityList\n * \n * @param newEntity \n */\n fromNew(newEntity: A_SERVER_TYPES__A_EntityListConstructor): void {\n this.aseid = new ASEID({\n concept: A_Context.root.name,\n scope: 'default',\n entity: 'a-list' + (newEntity.name ? `.${newEntity.name}` : ''),\n id: (new Date()).getTime().toString(),\n });\n\n this._entityConstructor = newEntity.constructor as new (...args: any[]) => EntityType;\n }\n\n\n\n /**\n * Allows to convert Repository Response data to EntityList instance\n * \n * [!] This method does not load the data from the repository, it only converts the data to the EntityList instance\n * \n * @param items \n * @param pagination \n */\n fromList(\n items: Array<EntityType> | Array<ReturnType<EntityType['toJSON']>>,\n pagination?: A_SERVER_TYPES__A_EntityListPagination\n ) {\n this._items = items.map(item => {\n if (item instanceof A_Entity) {\n return item as EntityType;\n } else {\n const entity = new this._entityConstructor(item);\n return entity;\n }\n });\n\n if (pagination) {\n this._pagination = {\n total: pagination.total,\n page: pagination.page,\n pageSize: pagination.pageSize\n }\n }\n }\n\n\n\n /**\n * Serializes the EntityList to a JSON object\n * \n * @returns \n */\n toJSON(): A_SERVER_TYPES__A_EntityListSerialized<EntityType> {\n return {\n ...super.toJSON(),\n items: this._items.map(i => i.toJSON()) as ReturnType<EntityType['toJSON']>[],\n pagination: this._pagination\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../../../../src/lib/A-ServerEntityList/A-EntityList.entity.ts"],"names":["A_Entity","A_Context","A_Scope","A_ServerEntityListPagination","A_ServerEntityListCacheState"],"mappings":"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","file":"A-EntityList.entity.js","sourcesContent":["import {\n A_Context, A_Entity, A_Scope,\n A_TYPES__Entity_Constructor,\n ASEID,\n} from \"@adaas/a-concept\";\nimport {\n A_SERVER_TYPES__A_EntityListConstructor,\n A_SERVER_TYPES__A_EntityListPagination,\n A_SERVER_TYPES__A_EntityListSerialized\n} from \"./A-EntityList.types\";\nimport { A_ServerEntityListPagination } from \"./A-EntityListPagination.context\";\nimport { A_ServerEntityListCacheState } from \"./A-EntityListCacheState.context\";\n\n\n\n/**\n * A-EntityList\n *\n * Typed, paginated list of A-Concept entities.\n *\n * Construction (user-facing):\n * new A_ServerEntityList<User>({ entity: User, pagination: { page: 1, pageSize: 20 } })\n *\n * Construction (controller-internal, backward-compat):\n * new A_ServerEntityList({ name: 'user', scope: 'my-scope', constructor: User })\n */\nexport class A_ServerEntityList<\n EntityType extends A_Entity = A_Entity,\n> extends A_Entity<\n A_SERVER_TYPES__A_EntityListConstructor<EntityType>,\n A_SERVER_TYPES__A_EntityListSerialized<EntityType>\n> {\n\n static get scope(): string {\n return 'a-server';\n }\n\n protected _entityConstructor!: A_TYPES__Entity_Constructor<EntityType>;\n\n /**\n * Ordered item references for O(1) positional access.\n * The list's own scope is the authoritative store (enables @A_Inject and\n * feature chains on items); this array mirrors the same items in order.\n */\n protected _items: Array<EntityType> = [];\n\n /** Lazily allocated private scope — pagination and cache state live here. */\n private _ownScope?: A_Scope;\n\n\n // ── Getters ──────────────────────────────────────────────────────────────\n\n /**\n * The list's own scope, created on first access and bound to this entity\n * via A_Context.allocate. Items, pagination and cache state are registered\n * here so they participate in feature chains and @A_Inject resolution.\n */\n get ownScope(): A_Scope {\n if (!this._ownScope) {\n this._ownScope = A_Context.allocate(\n this,\n new A_Scope({ name: `${this.aseid.id}-scope` })\n );\n }\n return this._ownScope;\n }\n\n get entityConstructor(): A_TYPES__Entity_Constructor<EntityType> {\n return this._entityConstructor;\n }\n\n get items(): Array<EntityType> {\n return this._items;\n }\n\n /** Pagination state — lives as a Fragment in the list's own scope. */\n get pagination(): A_ServerEntityListPagination {\n return this.ownScope.resolveFlatOnce(A_ServerEntityListPagination)!;\n }\n\n private get cacheState(): A_ServerEntityListCacheState {\n return this.ownScope.resolveFlatOnce(A_ServerEntityListCacheState)!;\n }\n\n /** Total number of items currently held in memory. */\n get length(): number {\n return this._items.length;\n }\n\n\n // ── Initialisation ───────────────────────────────────────────────────────\n\n fromNew(newEntity: A_SERVER_TYPES__A_EntityListConstructor<EntityType>): void {\n this.aseid = this.generateASEID({\n concept: A_Context.root.name,\n entity: 'a-list.' + newEntity.entity.name,\n });\n\n this._entityConstructor = newEntity.entity;\n\n // Initialise state Fragments in the list's own scope\n this.ownScope.register(new A_ServerEntityListPagination(newEntity.pagination));\n this.ownScope.register(new A_ServerEntityListCacheState());\n }\n\n\n /**\n * Populate the list from raw repository data.\n * Items are registered in the list's own scope so they participate in\n * feature chains and @A_Inject resolution.\n */\n fromList(\n items: Array<EntityType> | Array<ReturnType<EntityType['toJSON']>>,\n pagination?: A_SERVER_TYPES__A_EntityListPagination\n ) {\n // Deregister previous items from own scope\n this._items.forEach(item => {\n try { this.ownScope.deregister(item); } catch { /* already gone */ }\n });\n\n this._items = items.map(item => {\n const entity = item instanceof A_Entity\n ? item as EntityType\n : new this._entityConstructor(item as any);\n this.ownScope.register(entity);\n return entity;\n });\n\n if (pagination) {\n this.pagination.update(pagination);\n }\n }\n\n\n // ── Collection access ────────────────────────────────────────────────────\n\n /** Return the item at `index`, or `undefined` if out of range. */\n at(index: number): EntityType | undefined {\n return this._items[index];\n }\n\n /** Replace the item at `index` in place. Accepts a live entity or a plain serialised object. */\n replace(index: number, item: EntityType | ReturnType<EntityType['toJSON']>): this {\n const next = item instanceof A_Entity\n ? item as EntityType\n : new this._entityConstructor(item as any);\n try { this.ownScope.deregister(this._items[index]); } catch { /* ok */ }\n this.ownScope.register(next);\n this._items[index] = next;\n return this;\n }\n\n /** Append an item to the end of the list. */\n push(item: EntityType | ReturnType<EntityType['toJSON']>): this {\n const next = item instanceof A_Entity\n ? item as EntityType\n : new this._entityConstructor(item as any);\n this.ownScope.register(next);\n this._items.push(next);\n return this;\n }\n\n /** Prepend an item to the beginning of the list. */\n unshift(item: EntityType | ReturnType<EntityType['toJSON']>): this {\n const next = item instanceof A_Entity\n ? item as EntityType\n : new this._entityConstructor(item as any);\n this.ownScope.register(next);\n this._items.unshift(next);\n return this;\n }\n\n /** Remove the item at `index` from the list. */\n remove(index: number): this {\n const [removed] = this._items.splice(index, 1);\n if (removed) {\n try { this.ownScope.deregister(removed); } catch { /* ok */ }\n }\n return this;\n }\n\n /** Return the first item that satisfies `predicate`, or `undefined`. */\n find(predicate: (item: EntityType, index: number) => boolean): EntityType | undefined {\n return this._items.find(predicate);\n }\n\n /** Return all items that satisfy `predicate` without mutating the list. */\n filter(predicate: (item: EntityType, index: number) => boolean): EntityType[] {\n return this._items.filter(predicate);\n }\n\n\n // ── Caching ──────────────────────────────────────────────────────────────\n\n /**\n * Mark this list as cached for `ttlMs` milliseconds from now.\n * Callers can check `isCached()` to decide whether to skip `load()`.\n */\n setCache(ttlMs: number): this {\n this.cacheState.set(ttlMs);\n return this;\n }\n\n /** Returns `true` if the cache is still valid. */\n isCached(): boolean {\n return this.cacheState.isValid();\n }\n\n /** Invalidate the cache so the next `load()` call fetches fresh data. */\n invalidateCache(): this {\n this.cacheState.invalidate();\n return this;\n }\n\n\n // ── Serialisation ────────────────────────────────────────────────────────\n\n toJSON(): A_SERVER_TYPES__A_EntityListSerialized<EntityType> {\n const { total, page, pageSize } = this.pagination;\n return {\n ...super.toJSON(),\n items: this._items.map(i => i.toJSON()) as ReturnType<EntityType['toJSON']>[],\n type: (this._entityConstructor as any).entity ?? 'unknown',\n pagination: { total, page, pageSize },\n };\n }\n}\n\n"]}
@@ -1,86 +1,159 @@
1
1
  import '../../chunk-EQQGB2QZ.mjs';
2
- import { A_Entity, ASEID, A_Context } from '@adaas/a-concept';
2
+ import { A_Entity, A_Context, A_Scope } from '@adaas/a-concept';
3
+ import { A_ServerEntityListPagination } from './A-EntityListPagination.context';
4
+ import { A_ServerEntityListCacheState } from './A-EntityListCacheState.context';
3
5
 
4
6
  class A_ServerEntityList extends A_Entity {
5
7
  constructor() {
6
8
  super(...arguments);
9
+ /**
10
+ * Ordered item references for O(1) positional access.
11
+ * The list's own scope is the authoritative store (enables @A_Inject and
12
+ * feature chains on items); this array mirrors the same items in order.
13
+ */
7
14
  this._items = [];
8
- this._pagination = {
9
- total: 0,
10
- page: 1,
11
- pageSize: 10
12
- };
13
15
  }
14
16
  static get scope() {
15
17
  return "a-server";
16
18
  }
19
+ // ── Getters ──────────────────────────────────────────────────────────────
17
20
  /**
18
- * Returns the entity constructor used for the list
21
+ * The list's own scope, created on first access and bound to this entity
22
+ * via A_Context.allocate. Items, pagination and cache state are registered
23
+ * here so they participate in feature chains and @A_Inject resolution.
19
24
  */
25
+ get ownScope() {
26
+ if (!this._ownScope) {
27
+ this._ownScope = A_Context.allocate(
28
+ this,
29
+ new A_Scope({ name: `${this.aseid.id}-scope` })
30
+ );
31
+ }
32
+ return this._ownScope;
33
+ }
20
34
  get entityConstructor() {
21
35
  return this._entityConstructor;
22
36
  }
23
- /**
24
- * Returns the list of items contained in the entity list
25
- */
26
37
  get items() {
27
38
  return this._items;
28
39
  }
29
- /**
30
- * Returns pagination information about the entity list
31
- */
40
+ /** Pagination state — lives as a Fragment in the list's own scope. */
32
41
  get pagination() {
33
- return this._pagination;
42
+ return this.ownScope.resolveFlatOnce(A_ServerEntityListPagination);
34
43
  }
35
- /**
36
- * Creates a new instance of A_EntityList
37
- *
38
- * @param newEntity
39
- */
44
+ get cacheState() {
45
+ return this.ownScope.resolveFlatOnce(A_ServerEntityListCacheState);
46
+ }
47
+ /** Total number of items currently held in memory. */
48
+ get length() {
49
+ return this._items.length;
50
+ }
51
+ // ── Initialisation ───────────────────────────────────────────────────────
40
52
  fromNew(newEntity) {
41
- this.aseid = new ASEID({
53
+ this.aseid = this.generateASEID({
42
54
  concept: A_Context.root.name,
43
- scope: "default",
44
- entity: "a-list" + (newEntity.name ? `.${newEntity.name}` : ""),
45
- id: (/* @__PURE__ */ new Date()).getTime().toString()
55
+ entity: "a-list." + newEntity.entity.name
46
56
  });
47
- this._entityConstructor = newEntity.constructor;
57
+ this._entityConstructor = newEntity.entity;
58
+ this.ownScope.register(new A_ServerEntityListPagination(newEntity.pagination));
59
+ this.ownScope.register(new A_ServerEntityListCacheState());
48
60
  }
49
61
  /**
50
- * Allows to convert Repository Response data to EntityList instance
51
- *
52
- * [!] This method does not load the data from the repository, it only converts the data to the EntityList instance
53
- *
54
- * @param items
55
- * @param pagination
62
+ * Populate the list from raw repository data.
63
+ * Items are registered in the list's own scope so they participate in
64
+ * feature chains and @A_Inject resolution.
56
65
  */
57
66
  fromList(items, pagination) {
58
- this._items = items.map((item) => {
59
- if (item instanceof A_Entity) {
60
- return item;
61
- } else {
62
- const entity = new this._entityConstructor(item);
63
- return entity;
67
+ this._items.forEach((item) => {
68
+ try {
69
+ this.ownScope.deregister(item);
70
+ } catch {
64
71
  }
65
72
  });
73
+ this._items = items.map((item) => {
74
+ const entity = item instanceof A_Entity ? item : new this._entityConstructor(item);
75
+ this.ownScope.register(entity);
76
+ return entity;
77
+ });
66
78
  if (pagination) {
67
- this._pagination = {
68
- total: pagination.total,
69
- page: pagination.page,
70
- pageSize: pagination.pageSize
71
- };
79
+ this.pagination.update(pagination);
72
80
  }
73
81
  }
82
+ // ── Collection access ────────────────────────────────────────────────────
83
+ /** Return the item at `index`, or `undefined` if out of range. */
84
+ at(index) {
85
+ return this._items[index];
86
+ }
87
+ /** Replace the item at `index` in place. Accepts a live entity or a plain serialised object. */
88
+ replace(index, item) {
89
+ const next = item instanceof A_Entity ? item : new this._entityConstructor(item);
90
+ try {
91
+ this.ownScope.deregister(this._items[index]);
92
+ } catch {
93
+ }
94
+ this.ownScope.register(next);
95
+ this._items[index] = next;
96
+ return this;
97
+ }
98
+ /** Append an item to the end of the list. */
99
+ push(item) {
100
+ const next = item instanceof A_Entity ? item : new this._entityConstructor(item);
101
+ this.ownScope.register(next);
102
+ this._items.push(next);
103
+ return this;
104
+ }
105
+ /** Prepend an item to the beginning of the list. */
106
+ unshift(item) {
107
+ const next = item instanceof A_Entity ? item : new this._entityConstructor(item);
108
+ this.ownScope.register(next);
109
+ this._items.unshift(next);
110
+ return this;
111
+ }
112
+ /** Remove the item at `index` from the list. */
113
+ remove(index) {
114
+ const [removed] = this._items.splice(index, 1);
115
+ if (removed) {
116
+ try {
117
+ this.ownScope.deregister(removed);
118
+ } catch {
119
+ }
120
+ }
121
+ return this;
122
+ }
123
+ /** Return the first item that satisfies `predicate`, or `undefined`. */
124
+ find(predicate) {
125
+ return this._items.find(predicate);
126
+ }
127
+ /** Return all items that satisfy `predicate` without mutating the list. */
128
+ filter(predicate) {
129
+ return this._items.filter(predicate);
130
+ }
131
+ // ── Caching ──────────────────────────────────────────────────────────────
74
132
  /**
75
- * Serializes the EntityList to a JSON object
76
- *
77
- * @returns
133
+ * Mark this list as cached for `ttlMs` milliseconds from now.
134
+ * Callers can check `isCached()` to decide whether to skip `load()`.
78
135
  */
136
+ setCache(ttlMs) {
137
+ this.cacheState.set(ttlMs);
138
+ return this;
139
+ }
140
+ /** Returns `true` if the cache is still valid. */
141
+ isCached() {
142
+ return this.cacheState.isValid();
143
+ }
144
+ /** Invalidate the cache so the next `load()` call fetches fresh data. */
145
+ invalidateCache() {
146
+ this.cacheState.invalidate();
147
+ return this;
148
+ }
149
+ // ── Serialisation ────────────────────────────────────────────────────────
79
150
  toJSON() {
151
+ const { total, page, pageSize } = this.pagination;
80
152
  return {
81
153
  ...super.toJSON(),
82
154
  items: this._items.map((i) => i.toJSON()),
83
- pagination: this._pagination
155
+ type: this._entityConstructor.entity ?? "unknown",
156
+ pagination: { total, page, pageSize }
84
157
  };
85
158
  }
86
159
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/lib/A-ServerEntityList/A-EntityList.entity.ts"],"names":[],"mappings":";;;AAiBO,MAAM,2BAEH,QAAA,CAGR;AAAA,EALK,WAAA,GAAA;AAAA,IAAA,KAAA,CAAA,GAAA,SAAA,CAAA;AAYH,IAAA,IAAA,CAAU,SAA4B,EAAC;AACvC,IAAA,IAAA,CAAU,WAAA,GAAsD;AAAA,MAC5D,KAAA,EAAO,CAAA;AAAA,MACP,IAAA,EAAM,CAAA;AAAA,MACN,QAAA,EAAU;AAAA,KACd;AAAA,EAAA;AAAA,EAVA,WAAW,KAAA,GAAgB;AACvB,IAAA,OAAO,UAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAcA,IAAI,iBAAA,GAAyF;AACzF,IAAA,OAAO,IAAA,CAAK,kBAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,KAAA,GAA2B;AAC3B,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,UAAA,GAAqD;AACrD,IAAA,OAAO,IAAA,CAAK,WAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,QAAQ,SAAA,EAA0D;AAC9D,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAI,KAAA,CAAM;AAAA,MACnB,OAAA,EAAS,UAAU,IAAA,CAAK,IAAA;AAAA,MACxB,KAAA,EAAO,SAAA;AAAA,MACP,QAAQ,QAAA,IAAY,SAAA,CAAU,OAAO,CAAA,CAAA,EAAI,SAAA,CAAU,IAAI,CAAA,CAAA,GAAK,EAAA,CAAA;AAAA,MAC5D,qBAAK,IAAI,IAAA,EAAK,EAAG,OAAA,GAAU,QAAA;AAAS,KACvC,CAAA;AAED,IAAA,IAAA,CAAK,qBAAqB,SAAA,CAAU,WAAA;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,QAAA,CACI,OACA,UAAA,EACF;AACE,IAAA,IAAA,CAAK,MAAA,GAAS,KAAA,CAAM,GAAA,CAAI,CAAA,IAAA,KAAQ;AAC5B,MAAA,IAAI,gBAAgB,QAAA,EAAU;AAC1B,QAAA,OAAO,IAAA;AAAA,MACX,CAAA,MAAO;AACH,QAAA,MAAM,MAAA,GAAS,IAAI,IAAA,CAAK,kBAAA,CAAmB,IAAI,CAAA;AAC/C,QAAA,OAAO,MAAA;AAAA,MACX;AAAA,IACJ,CAAC,CAAA;AAED,IAAA,IAAI,UAAA,EAAY;AACZ,MAAA,IAAA,CAAK,WAAA,GAAc;AAAA,QACf,OAAO,UAAA,CAAW,KAAA;AAAA,QAClB,MAAM,UAAA,CAAW,IAAA;AAAA,QACjB,UAAU,UAAA,CAAW;AAAA,OACzB;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAA,GAA6D;AACzD,IAAA,OAAO;AAAA,MACH,GAAG,MAAM,MAAA,EAAO;AAAA,MAChB,OAAO,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,QAAQ,CAAA;AAAA,MACtC,YAAY,IAAA,CAAK;AAAA,KACrB;AAAA,EACJ;AACJ","file":"A-EntityList.entity.mjs","sourcesContent":["import {\n A_Context, A_Entity,\n ASEID,\n} from \"@adaas/a-concept\";\nimport {\n A_SERVER_TYPES__A_EntityListConstructor,\n A_SERVER_TYPES__A_EntityListPagination,\n A_SERVER_TYPES__A_EntityListSerialized\n} from \"./A-EntityList.types\";\n\n\n\n/**\n * A-EntityList\n * \n * Entity that represents a list of entities with pagination of particular type\n */\nexport class A_ServerEntityList<\n EntityType extends A_Entity = A_Entity,\n> extends A_Entity<\n A_SERVER_TYPES__A_EntityListConstructor,\n A_SERVER_TYPES__A_EntityListSerialized\n> {\n\n static get scope(): string {\n return 'a-server';\n }\n\n protected _entityConstructor!: new (...args: ConstructorParameters<typeof A_Entity>) => EntityType;\n protected _items: Array<EntityType> = [];\n protected _pagination: A_SERVER_TYPES__A_EntityListPagination = {\n total: 0,\n page: 1,\n pageSize: 10\n };\n\n\n /**\n * Returns the entity constructor used for the list\n */\n get entityConstructor(): new (...args: ConstructorParameters<typeof A_Entity>) => EntityType {\n return this._entityConstructor;\n }\n\n /**\n * Returns the list of items contained in the entity list\n */\n get items(): Array<EntityType> {\n return this._items;\n }\n\n /**\n * Returns pagination information about the entity list\n */\n get pagination(): A_SERVER_TYPES__A_EntityListPagination {\n return this._pagination;\n }\n\n\n\n\n /**\n * Creates a new instance of A_EntityList\n * \n * @param newEntity \n */\n fromNew(newEntity: A_SERVER_TYPES__A_EntityListConstructor): void {\n this.aseid = new ASEID({\n concept: A_Context.root.name,\n scope: 'default',\n entity: 'a-list' + (newEntity.name ? `.${newEntity.name}` : ''),\n id: (new Date()).getTime().toString(),\n });\n\n this._entityConstructor = newEntity.constructor as new (...args: any[]) => EntityType;\n }\n\n\n\n /**\n * Allows to convert Repository Response data to EntityList instance\n * \n * [!] This method does not load the data from the repository, it only converts the data to the EntityList instance\n * \n * @param items \n * @param pagination \n */\n fromList(\n items: Array<EntityType> | Array<ReturnType<EntityType['toJSON']>>,\n pagination?: A_SERVER_TYPES__A_EntityListPagination\n ) {\n this._items = items.map(item => {\n if (item instanceof A_Entity) {\n return item as EntityType;\n } else {\n const entity = new this._entityConstructor(item);\n return entity;\n }\n });\n\n if (pagination) {\n this._pagination = {\n total: pagination.total,\n page: pagination.page,\n pageSize: pagination.pageSize\n }\n }\n }\n\n\n\n /**\n * Serializes the EntityList to a JSON object\n * \n * @returns \n */\n toJSON(): A_SERVER_TYPES__A_EntityListSerialized<EntityType> {\n return {\n ...super.toJSON(),\n items: this._items.map(i => i.toJSON()) as ReturnType<EntityType['toJSON']>[],\n pagination: this._pagination\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../../../../src/lib/A-ServerEntityList/A-EntityList.entity.ts"],"names":[],"mappings":";;;;;AA0BO,MAAM,2BAEH,QAAA,CAGR;AAAA,EALK,WAAA,GAAA;AAAA,IAAA,KAAA,CAAA,GAAA,SAAA,CAAA;AAkBH;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,IAAA,CAAU,SAA4B,EAAC;AAAA,EAAA;AAAA,EAXvC,WAAW,KAAA,GAAgB;AACvB,IAAA,OAAO,UAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,IAAI,QAAA,GAAoB;AACpB,IAAA,IAAI,CAAC,KAAK,SAAA,EAAW;AACjB,MAAA,IAAA,CAAK,YAAY,SAAA,CAAU,QAAA;AAAA,QACvB,IAAA;AAAA,QACA,IAAI,QAAQ,EAAE,IAAA,EAAM,GAAG,IAAA,CAAK,KAAA,CAAM,EAAE,CAAA,MAAA,CAAA,EAAU;AAAA,OAClD;AAAA,IACJ;AACA,IAAA,OAAO,IAAA,CAAK,SAAA;AAAA,EAChB;AAAA,EAEA,IAAI,iBAAA,GAA6D;AAC7D,IAAA,OAAO,IAAA,CAAK,kBAAA;AAAA,EAChB;AAAA,EAEA,IAAI,KAAA,GAA2B;AAC3B,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,UAAA,GAA2C;AAC3C,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,eAAA,CAAgB,4BAA4B,CAAA;AAAA,EACrE;AAAA,EAEA,IAAY,UAAA,GAA2C;AACnD,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,eAAA,CAAgB,4BAA4B,CAAA;AAAA,EACrE;AAAA;AAAA,EAGA,IAAI,MAAA,GAAiB;AACjB,IAAA,OAAO,KAAK,MAAA,CAAO,MAAA;AAAA,EACvB;AAAA;AAAA,EAKA,QAAQ,SAAA,EAAsE;AAC1E,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAK,aAAA,CAAc;AAAA,MAC5B,OAAA,EAAS,UAAU,IAAA,CAAK,IAAA;AAAA,MACxB,MAAA,EAAQ,SAAA,GAAY,SAAA,CAAU,MAAA,CAAO;AAAA,KACxC,CAAA;AAED,IAAA,IAAA,CAAK,qBAAqB,SAAA,CAAU,MAAA;AAGpC,IAAA,IAAA,CAAK,SAAS,QAAA,CAAS,IAAI,4BAAA,CAA6B,SAAA,CAAU,UAAU,CAAC,CAAA;AAC7E,IAAA,IAAA,CAAK,QAAA,CAAS,QAAA,CAAS,IAAI,4BAAA,EAA8B,CAAA;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAA,CACI,OACA,UAAA,EACF;AAEE,IAAA,IAAA,CAAK,MAAA,CAAO,QAAQ,CAAA,IAAA,KAAQ;AACxB,MAAA,IAAI;AAAE,QAAA,IAAA,CAAK,QAAA,CAAS,WAAW,IAAI,CAAA;AAAA,MAAG,CAAA,CAAA,MAAQ;AAAA,MAAqB;AAAA,IACvE,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,MAAA,GAAS,KAAA,CAAM,GAAA,CAAI,CAAA,IAAA,KAAQ;AAC5B,MAAA,MAAM,SAAS,IAAA,YAAgB,QAAA,GACzB,OACA,IAAI,IAAA,CAAK,mBAAmB,IAAW,CAAA;AAC7C,MAAA,IAAA,CAAK,QAAA,CAAS,SAAS,MAAM,CAAA;AAC7B,MAAA,OAAO,MAAA;AAAA,IACX,CAAC,CAAA;AAED,IAAA,IAAI,UAAA,EAAY;AACZ,MAAA,IAAA,CAAK,UAAA,CAAW,OAAO,UAAU,CAAA;AAAA,IACrC;AAAA,EACJ;AAAA;AAAA;AAAA,EAMA,GAAG,KAAA,EAAuC;AACtC,IAAA,OAAO,IAAA,CAAK,OAAO,KAAK,CAAA;AAAA,EAC5B;AAAA;AAAA,EAGA,OAAA,CAAQ,OAAe,IAAA,EAA2D;AAC9E,IAAA,MAAM,OAAO,IAAA,YAAgB,QAAA,GACvB,OACA,IAAI,IAAA,CAAK,mBAAmB,IAAW,CAAA;AAC7C,IAAA,IAAI;AAAE,MAAA,IAAA,CAAK,QAAA,CAAS,UAAA,CAAW,IAAA,CAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,IAAG,CAAA,CAAA,MAAQ;AAAA,IAAW;AACvE,IAAA,IAAA,CAAK,QAAA,CAAS,SAAS,IAAI,CAAA;AAC3B,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA,GAAI,IAAA;AACrB,IAAA,OAAO,IAAA;AAAA,EACX;AAAA;AAAA,EAGA,KAAK,IAAA,EAA2D;AAC5D,IAAA,MAAM,OAAO,IAAA,YAAgB,QAAA,GACvB,OACA,IAAI,IAAA,CAAK,mBAAmB,IAAW,CAAA;AAC7C,IAAA,IAAA,CAAK,QAAA,CAAS,SAAS,IAAI,CAAA;AAC3B,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,IAAI,CAAA;AACrB,IAAA,OAAO,IAAA;AAAA,EACX;AAAA;AAAA,EAGA,QAAQ,IAAA,EAA2D;AAC/D,IAAA,MAAM,OAAO,IAAA,YAAgB,QAAA,GACvB,OACA,IAAI,IAAA,CAAK,mBAAmB,IAAW,CAAA;AAC7C,IAAA,IAAA,CAAK,QAAA,CAAS,SAAS,IAAI,CAAA;AAC3B,IAAA,IAAA,CAAK,MAAA,CAAO,QAAQ,IAAI,CAAA;AACxB,IAAA,OAAO,IAAA;AAAA,EACX;AAAA;AAAA,EAGA,OAAO,KAAA,EAAqB;AACxB,IAAA,MAAM,CAAC,OAAO,CAAA,GAAI,KAAK,MAAA,CAAO,MAAA,CAAO,OAAO,CAAC,CAAA;AAC7C,IAAA,IAAI,OAAA,EAAS;AACT,MAAA,IAAI;AAAE,QAAA,IAAA,CAAK,QAAA,CAAS,WAAW,OAAO,CAAA;AAAA,MAAG,CAAA,CAAA,MAAQ;AAAA,MAAW;AAAA,IAChE;AACA,IAAA,OAAO,IAAA;AAAA,EACX;AAAA;AAAA,EAGA,KAAK,SAAA,EAAiF;AAClF,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA;AAAA,EACrC;AAAA;AAAA,EAGA,OAAO,SAAA,EAAuE;AAC1E,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,SAAS,CAAA;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,SAAS,KAAA,EAAqB;AAC1B,IAAA,IAAA,CAAK,UAAA,CAAW,IAAI,KAAK,CAAA;AACzB,IAAA,OAAO,IAAA;AAAA,EACX;AAAA;AAAA,EAGA,QAAA,GAAoB;AAChB,IAAA,OAAO,IAAA,CAAK,WAAW,OAAA,EAAQ;AAAA,EACnC;AAAA;AAAA,EAGA,eAAA,GAAwB;AACpB,IAAA,IAAA,CAAK,WAAW,UAAA,EAAW;AAC3B,IAAA,OAAO,IAAA;AAAA,EACX;AAAA;AAAA,EAKA,MAAA,GAA6D;AACzD,IAAA,MAAM,EAAE,KAAA,EAAO,IAAA,EAAM,QAAA,KAAa,IAAA,CAAK,UAAA;AACvC,IAAA,OAAO;AAAA,MACH,GAAG,MAAM,MAAA,EAAO;AAAA,MAChB,OAAO,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,QAAQ,CAAA;AAAA,MACtC,IAAA,EAAO,IAAA,CAAK,kBAAA,CAA2B,MAAA,IAAU,SAAA;AAAA,MACjD,UAAA,EAAY,EAAE,KAAA,EAAO,IAAA,EAAM,QAAA;AAAS,KACxC;AAAA,EACJ;AACJ","file":"A-EntityList.entity.mjs","sourcesContent":["import {\n A_Context, A_Entity, A_Scope,\n A_TYPES__Entity_Constructor,\n ASEID,\n} from \"@adaas/a-concept\";\nimport {\n A_SERVER_TYPES__A_EntityListConstructor,\n A_SERVER_TYPES__A_EntityListPagination,\n A_SERVER_TYPES__A_EntityListSerialized\n} from \"./A-EntityList.types\";\nimport { A_ServerEntityListPagination } from \"./A-EntityListPagination.context\";\nimport { A_ServerEntityListCacheState } from \"./A-EntityListCacheState.context\";\n\n\n\n/**\n * A-EntityList\n *\n * Typed, paginated list of A-Concept entities.\n *\n * Construction (user-facing):\n * new A_ServerEntityList<User>({ entity: User, pagination: { page: 1, pageSize: 20 } })\n *\n * Construction (controller-internal, backward-compat):\n * new A_ServerEntityList({ name: 'user', scope: 'my-scope', constructor: User })\n */\nexport class A_ServerEntityList<\n EntityType extends A_Entity = A_Entity,\n> extends A_Entity<\n A_SERVER_TYPES__A_EntityListConstructor<EntityType>,\n A_SERVER_TYPES__A_EntityListSerialized<EntityType>\n> {\n\n static get scope(): string {\n return 'a-server';\n }\n\n protected _entityConstructor!: A_TYPES__Entity_Constructor<EntityType>;\n\n /**\n * Ordered item references for O(1) positional access.\n * The list's own scope is the authoritative store (enables @A_Inject and\n * feature chains on items); this array mirrors the same items in order.\n */\n protected _items: Array<EntityType> = [];\n\n /** Lazily allocated private scope — pagination and cache state live here. */\n private _ownScope?: A_Scope;\n\n\n // ── Getters ──────────────────────────────────────────────────────────────\n\n /**\n * The list's own scope, created on first access and bound to this entity\n * via A_Context.allocate. Items, pagination and cache state are registered\n * here so they participate in feature chains and @A_Inject resolution.\n */\n get ownScope(): A_Scope {\n if (!this._ownScope) {\n this._ownScope = A_Context.allocate(\n this,\n new A_Scope({ name: `${this.aseid.id}-scope` })\n );\n }\n return this._ownScope;\n }\n\n get entityConstructor(): A_TYPES__Entity_Constructor<EntityType> {\n return this._entityConstructor;\n }\n\n get items(): Array<EntityType> {\n return this._items;\n }\n\n /** Pagination state — lives as a Fragment in the list's own scope. */\n get pagination(): A_ServerEntityListPagination {\n return this.ownScope.resolveFlatOnce(A_ServerEntityListPagination)!;\n }\n\n private get cacheState(): A_ServerEntityListCacheState {\n return this.ownScope.resolveFlatOnce(A_ServerEntityListCacheState)!;\n }\n\n /** Total number of items currently held in memory. */\n get length(): number {\n return this._items.length;\n }\n\n\n // ── Initialisation ───────────────────────────────────────────────────────\n\n fromNew(newEntity: A_SERVER_TYPES__A_EntityListConstructor<EntityType>): void {\n this.aseid = this.generateASEID({\n concept: A_Context.root.name,\n entity: 'a-list.' + newEntity.entity.name,\n });\n\n this._entityConstructor = newEntity.entity;\n\n // Initialise state Fragments in the list's own scope\n this.ownScope.register(new A_ServerEntityListPagination(newEntity.pagination));\n this.ownScope.register(new A_ServerEntityListCacheState());\n }\n\n\n /**\n * Populate the list from raw repository data.\n * Items are registered in the list's own scope so they participate in\n * feature chains and @A_Inject resolution.\n */\n fromList(\n items: Array<EntityType> | Array<ReturnType<EntityType['toJSON']>>,\n pagination?: A_SERVER_TYPES__A_EntityListPagination\n ) {\n // Deregister previous items from own scope\n this._items.forEach(item => {\n try { this.ownScope.deregister(item); } catch { /* already gone */ }\n });\n\n this._items = items.map(item => {\n const entity = item instanceof A_Entity\n ? item as EntityType\n : new this._entityConstructor(item as any);\n this.ownScope.register(entity);\n return entity;\n });\n\n if (pagination) {\n this.pagination.update(pagination);\n }\n }\n\n\n // ── Collection access ────────────────────────────────────────────────────\n\n /** Return the item at `index`, or `undefined` if out of range. */\n at(index: number): EntityType | undefined {\n return this._items[index];\n }\n\n /** Replace the item at `index` in place. Accepts a live entity or a plain serialised object. */\n replace(index: number, item: EntityType | ReturnType<EntityType['toJSON']>): this {\n const next = item instanceof A_Entity\n ? item as EntityType\n : new this._entityConstructor(item as any);\n try { this.ownScope.deregister(this._items[index]); } catch { /* ok */ }\n this.ownScope.register(next);\n this._items[index] = next;\n return this;\n }\n\n /** Append an item to the end of the list. */\n push(item: EntityType | ReturnType<EntityType['toJSON']>): this {\n const next = item instanceof A_Entity\n ? item as EntityType\n : new this._entityConstructor(item as any);\n this.ownScope.register(next);\n this._items.push(next);\n return this;\n }\n\n /** Prepend an item to the beginning of the list. */\n unshift(item: EntityType | ReturnType<EntityType['toJSON']>): this {\n const next = item instanceof A_Entity\n ? item as EntityType\n : new this._entityConstructor(item as any);\n this.ownScope.register(next);\n this._items.unshift(next);\n return this;\n }\n\n /** Remove the item at `index` from the list. */\n remove(index: number): this {\n const [removed] = this._items.splice(index, 1);\n if (removed) {\n try { this.ownScope.deregister(removed); } catch { /* ok */ }\n }\n return this;\n }\n\n /** Return the first item that satisfies `predicate`, or `undefined`. */\n find(predicate: (item: EntityType, index: number) => boolean): EntityType | undefined {\n return this._items.find(predicate);\n }\n\n /** Return all items that satisfy `predicate` without mutating the list. */\n filter(predicate: (item: EntityType, index: number) => boolean): EntityType[] {\n return this._items.filter(predicate);\n }\n\n\n // ── Caching ──────────────────────────────────────────────────────────────\n\n /**\n * Mark this list as cached for `ttlMs` milliseconds from now.\n * Callers can check `isCached()` to decide whether to skip `load()`.\n */\n setCache(ttlMs: number): this {\n this.cacheState.set(ttlMs);\n return this;\n }\n\n /** Returns `true` if the cache is still valid. */\n isCached(): boolean {\n return this.cacheState.isValid();\n }\n\n /** Invalidate the cache so the next `load()` call fetches fresh data. */\n invalidateCache(): this {\n this.cacheState.invalidate();\n return this;\n }\n\n\n // ── Serialisation ────────────────────────────────────────────────────────\n\n toJSON(): A_SERVER_TYPES__A_EntityListSerialized<EntityType> {\n const { total, page, pageSize } = this.pagination;\n return {\n ...super.toJSON(),\n items: this._items.map(i => i.toJSON()) as ReturnType<EntityType['toJSON']>[],\n type: (this._entityConstructor as any).entity ?? 'unknown',\n pagination: { total, page, pageSize },\n };\n }\n}\n\n"]}
@@ -1,9 +1,13 @@
1
- import { A_TYPES__Entity_Constructor, A_Entity, A_TYPES__Entity_Serialized } from '@adaas/a-concept';
1
+ import { A_Entity, A_TYPES__Entity_Constructor, A_TYPES__Entity_Serialized } from '@adaas/a-concept';
2
2
 
3
- type A_SERVER_TYPES__A_EntityListConstructor = {
4
- name: string;
5
- scope: string;
6
- constructor: A_TYPES__Entity_Constructor;
3
+ type A_SERVER_TYPES__A_EntityListConstructor<T extends A_Entity = A_Entity> = {
4
+ /** User-facing: the entity class (e.g. `User`). Name and scope are derived from its statics. */
5
+ entity: A_TYPES__Entity_Constructor<T>;
6
+ /** Initial pagination request parameters. Defaults to page 1, pageSize 10. */
7
+ pagination?: {
8
+ page?: number;
9
+ pageSize?: number;
10
+ };
7
11
  };
8
12
  declare enum A_SERVER_TYPES__A_EntityListEvent {
9
13
  Load = "load"
@@ -18,5 +22,9 @@ type A_SERVER_TYPES__A_EntityListPagination = {
18
22
  page: number;
19
23
  pageSize: number;
20
24
  };
25
+ type A_SERVER_TYPES__A_EntityListCacheEntry = {
26
+ timestamp: number;
27
+ ttl: number;
28
+ };
21
29
 
22
- export { type A_SERVER_TYPES__A_EntityListConstructor, A_SERVER_TYPES__A_EntityListEvent, type A_SERVER_TYPES__A_EntityListPagination, type A_SERVER_TYPES__A_EntityListSerialized };
30
+ export { type A_SERVER_TYPES__A_EntityListCacheEntry, type A_SERVER_TYPES__A_EntityListConstructor, A_SERVER_TYPES__A_EntityListEvent, type A_SERVER_TYPES__A_EntityListPagination, type A_SERVER_TYPES__A_EntityListSerialized };