@mbc-cqrs-serverless/core 1.1.6 → 1.2.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.
Files changed (53) hide show
  1. package/dist/commands/command.module.js +3 -0
  2. package/dist/commands/command.module.js.map +1 -1
  3. package/dist/commands/command.service.d.ts +9 -1
  4. package/dist/commands/command.service.js +33 -2
  5. package/dist/commands/command.service.js.map +1 -1
  6. package/dist/commands/data.service.js +3 -26
  7. package/dist/commands/data.service.js.map +1 -1
  8. package/dist/commands/index.d.ts +1 -0
  9. package/dist/commands/index.js +1 -0
  10. package/dist/commands/index.js.map +1 -1
  11. package/dist/commands/repository.d.ts +102 -0
  12. package/dist/commands/repository.js +280 -0
  13. package/dist/commands/repository.js.map +1 -0
  14. package/dist/data-store/data-store.module.js +3 -2
  15. package/dist/data-store/data-store.module.js.map +1 -1
  16. package/dist/data-store/index.d.ts +2 -0
  17. package/dist/data-store/index.js +2 -0
  18. package/dist/data-store/index.js.map +1 -1
  19. package/dist/data-store/session.interface.d.ts +10 -0
  20. package/dist/data-store/session.interface.js +3 -0
  21. package/dist/data-store/session.interface.js.map +1 -0
  22. package/dist/data-store/session.service.d.ts +52 -0
  23. package/dist/data-store/session.service.js +128 -0
  24. package/dist/data-store/session.service.js.map +1 -0
  25. package/dist/env.validation.d.ts +1 -0
  26. package/dist/env.validation.js +5 -0
  27. package/dist/env.validation.js.map +1 -1
  28. package/dist/helpers/index.d.ts +1 -0
  29. package/dist/helpers/index.js +1 -0
  30. package/dist/helpers/index.js.map +1 -1
  31. package/dist/helpers/key.d.ts +13 -0
  32. package/dist/helpers/key.js +26 -0
  33. package/dist/helpers/key.js.map +1 -1
  34. package/dist/helpers/transform.d.ts +7 -0
  35. package/dist/helpers/transform.js +36 -0
  36. package/dist/helpers/transform.js.map +1 -0
  37. package/dist/queue/index.d.ts +1 -0
  38. package/dist/queue/index.js +1 -0
  39. package/dist/queue/index.js.map +1 -1
  40. package/dist/queue/queue.module.js +4 -2
  41. package/dist/queue/queue.module.js.map +1 -1
  42. package/dist/queue/sns-client-factory.d.ts +2 -2
  43. package/dist/queue/sns-client-factory.js +4 -6
  44. package/dist/queue/sns-client-factory.js.map +1 -1
  45. package/dist/queue/sns.service.js +1 -1
  46. package/dist/queue/sns.service.js.map +1 -1
  47. package/dist/queue/sqs-client-factory.d.ts +8 -0
  48. package/dist/queue/sqs-client-factory.js +35 -0
  49. package/dist/queue/sqs-client-factory.js.map +1 -0
  50. package/dist/queue/sqs.service.d.ts +28 -0
  51. package/dist/queue/sqs.service.js +89 -0
  52. package/dist/queue/sqs.service.js.map +1 -0
  53. package/package.json +2 -2
@@ -0,0 +1,280 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var Repository_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.Repository = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const constants_1 = require("../constants");
19
+ const user_1 = require("../context/user");
20
+ const session_service_1 = require("../data-store/session.service");
21
+ const key_1 = require("../helpers/key");
22
+ const transform_1 = require("../helpers/transform");
23
+ const interfaces_1 = require("../interfaces");
24
+ const command_module_definition_1 = require("./command.module-definition");
25
+ const command_service_1 = require("./command.service");
26
+ const data_service_1 = require("./data.service");
27
+ let Repository = Repository_1 = class Repository {
28
+ constructor(options, dataService, commandService, sessionService) {
29
+ this.options = options;
30
+ this.dataService = dataService;
31
+ this.commandService = commandService;
32
+ this.sessionService = sessionService;
33
+ this.logger = new common_1.Logger(Repository_1.name);
34
+ this.moduleTableName = this.options.tableName;
35
+ }
36
+ /**
37
+ * Get a single data item, merging a pending async command when a session exists.
38
+ */
39
+ async getItem(key, options) {
40
+ const userContext = (0, user_1.getUserContext)(options.invokeContext);
41
+ const userId = userContext?.userId;
42
+ const tenantCode = (0, key_1.getTenantCode)(key.pk);
43
+ if (userId && tenantCode) {
44
+ const itemId = (0, key_1.generateId)(key.pk, key.sk);
45
+ const session = await this.sessionService.get(userId, tenantCode, this.moduleTableName, itemId);
46
+ if (session) {
47
+ this.logger.debug(`getItem session merge — version ${session.version}`, key);
48
+ const cmd = await this.commandService.getItem({
49
+ pk: key.pk,
50
+ sk: (0, key_1.addSortKeyVersion)(key.sk, session.version),
51
+ });
52
+ if (cmd) {
53
+ const existing = await this.dataService.getItem(key);
54
+ return (0, transform_1.transformCommandToData)(cmd, existing);
55
+ }
56
+ }
57
+ }
58
+ return this.dataService.getItem(key);
59
+ }
60
+ /**
61
+ * List items from the DynamoDB data table with an optional merge of pending async commands.
62
+ *
63
+ * When `mergeOptions.latestFlg` is true, the result is augmented with any
64
+ * pending writes the current user has not yet seen reflected in the data table:
65
+ *
66
+ * - **update** — the existing item is replaced in-place, preserving its
67
+ * position in the list.
68
+ * - **delete** — the item is removed from the result.
69
+ * - **create-new** — the item is prepended to the top of the list, sorted by
70
+ * `updatedAt` descending when there are multiple pending creates.
71
+ *
72
+ * > **Sort-order note**: Prepended create-new items are not integrated into
73
+ * > the caller's sort order (e.g. by `name` or `code`). They will appear
74
+ * > at the top of the result until the async DynamoDB Stream sync completes and
75
+ * > the next read returns fully sorted data. This is intentional — the
76
+ * > guarantee is visibility, not sort position.
77
+ */
78
+ async listItemsByPk(pk, opts, mergeOptions, options) {
79
+ const baseResult = await this.dataService.listItemsByPk(pk, opts);
80
+ if (!mergeOptions?.latestFlg || !options) {
81
+ return baseResult;
82
+ }
83
+ const userContext = (0, user_1.getUserContext)(options.invokeContext);
84
+ const userId = userContext?.userId;
85
+ if (!userId)
86
+ return baseResult;
87
+ const tenantCode = (0, key_1.getTenantCode)(pk);
88
+ if (!tenantCode) {
89
+ return baseResult;
90
+ }
91
+ const sessions = await this.sessionService.listByUser(userId, tenantCode, this.moduleTableName);
92
+ if (!sessions.length)
93
+ return baseResult;
94
+ this.logger.debug(`listItemsByPk merge — ${sessions.length} sessions`, {
95
+ pk,
96
+ });
97
+ // Map preserves insertion order for existing items
98
+ const itemMap = new Map(baseResult.items.map((item) => [item.id, item]));
99
+ // Separate array to collect newly created items so they can be prepended
100
+ const newItems = [];
101
+ const skPrefix = `${this.moduleTableName}${constants_1.KEY_SEPARATOR}`;
102
+ for (const session of sessions) {
103
+ if (!session.sk.startsWith(skPrefix)) {
104
+ continue;
105
+ }
106
+ const itemId = session.sk.slice(skPrefix.length);
107
+ const existing = itemMap.get(itemId);
108
+ const cmdPk = pk;
109
+ let skBase;
110
+ if (existing?.sk) {
111
+ skBase = (0, key_1.removeSortKeyVersion)(existing.sk);
112
+ }
113
+ else {
114
+ // Since we already know the exact PK from the method parameter,
115
+ // we can safely extract the skBase without strict 2-segment assumptions.
116
+ skBase = (0, key_1.sortKeyBaseFromId)(pk, itemId);
117
+ if (!skBase) {
118
+ continue;
119
+ }
120
+ }
121
+ const cmd = await this.commandService.getItem({
122
+ pk: cmdPk,
123
+ sk: (0, key_1.addSortKeyVersion)(skBase, session.version),
124
+ });
125
+ if (!cmd)
126
+ continue;
127
+ const transformed = (0, transform_1.transformCommandToData)(cmd, existing);
128
+ if (cmd.isDeleted) {
129
+ // Delete the item from the map
130
+ itemMap.delete(itemId);
131
+ }
132
+ else if (itemMap.has(itemId)) {
133
+ // Update: preserves the original sort order in the Map
134
+ itemMap.set(itemId, new interfaces_1.DataEntity(transformed));
135
+ }
136
+ else {
137
+ // Create-new: push to the newItems array
138
+ newItems.push(new interfaces_1.DataEntity(transformed));
139
+ }
140
+ }
141
+ // Sort newly created items by createdAt descending
142
+ if (newItems.length > 1) {
143
+ newItems.sort((a, b) => {
144
+ const timeA = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
145
+ const timeB = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
146
+ return timeB - timeA;
147
+ });
148
+ }
149
+ return new interfaces_1.DataListEntity({
150
+ lastSk: baseResult.lastSk,
151
+ // Prepend newly created items to the top of the list
152
+ items: [...newItems, ...itemMap.values()],
153
+ });
154
+ }
155
+ /**
156
+ * List items from an external source (e.g., RDS/Elasticsearch) with an
157
+ * optional merge of pending async commands.
158
+ *
159
+ * When `mergeOptions.latestFlg` is true, the result is augmented with any
160
+ * pending writes the current user has not yet seen reflected in the query
161
+ * source:
162
+ *
163
+ * - **update** — the existing item is replaced in-place via `transformCommand`,
164
+ * preserving its position. `existing` is passed to the transformer so join
165
+ * data (e.g. related RDS rows) can be carried over.
166
+ * - **delete** — the item is removed and `total` is decremented.
167
+ * - **create-new** — the item is transformed, optionally filtered by
168
+ * `matchesFilter`, and prepended to the top of the result sorted by
169
+ * `updatedAt` descending. `total` is incremented.
170
+ *
171
+ * > **Sort-order note**: Prepended create-new items are not integrated into
172
+ * > the caller's sort order (e.g. by `name` or `code`). They will appear
173
+ * > at the top of the result until the async Stream → RDS sync completes and
174
+ * > the next read returns fully sorted data. This is intentional — the
175
+ * > guarantee is visibility, not sort position.
176
+ *
177
+ * > **Pagination note**: `total` reflects the adjusted count after merge.
178
+ * > However, prepended items sit outside the RDS `LIMIT`/`OFFSET` window, so
179
+ * > on page 2+ the caller may see a one-item overlap or gap until sync
180
+ * > completes. For most UX patterns (redirect-after-write, optimistic UI)
181
+ * > this is not noticeable.
182
+ */
183
+ async listItems(query, mergeOptions, options) {
184
+ const baseResult = await query();
185
+ if (!mergeOptions?.latestFlg || !options) {
186
+ return baseResult;
187
+ }
188
+ const userContext = (0, user_1.getUserContext)(options.invokeContext);
189
+ const userId = userContext?.userId;
190
+ if (!userId)
191
+ return baseResult;
192
+ const tenantCode = userContext.tenantCode;
193
+ if (!tenantCode)
194
+ return baseResult;
195
+ const sessions = await this.sessionService.listByUser(userId, tenantCode, this.moduleTableName);
196
+ if (!sessions.length)
197
+ return baseResult;
198
+ this.logger.debug(`listItems merge — ${sessions.length} sessions`, {
199
+ tenantCode,
200
+ });
201
+ const itemMap = new Map(baseResult.items.map((item) => [item.id, item]));
202
+ const newItems = [];
203
+ let adjustedTotal = baseResult.total;
204
+ const skPrefix = `${this.moduleTableName}${constants_1.KEY_SEPARATOR}`;
205
+ for (const session of sessions) {
206
+ if (!session.sk.startsWith(skPrefix)) {
207
+ continue;
208
+ }
209
+ const itemId = session.sk.slice(skPrefix.length);
210
+ const existing = itemMap.get(itemId);
211
+ let cmdPk;
212
+ let skBase;
213
+ const existingSk = existing?.sk;
214
+ const existingPk = existing?.pk;
215
+ if (existing && existingSk && existingPk) {
216
+ cmdPk = existingPk;
217
+ skBase = (0, key_1.removeSortKeyVersion)(existingSk);
218
+ }
219
+ else {
220
+ // Fallback: Strictly parse the ID assuming a 2-segment PK format ({type}#{tenantCode})
221
+ const parsed = (0, key_1.parseTwoSegmentPkSkFromId)(itemId);
222
+ if (!parsed) {
223
+ continue;
224
+ }
225
+ cmdPk = parsed.pk;
226
+ skBase = parsed.skBase;
227
+ }
228
+ if (!cmdPk || !skBase) {
229
+ continue;
230
+ }
231
+ const cmd = await this.commandService.getItem({
232
+ pk: cmdPk,
233
+ sk: (0, key_1.addSortKeyVersion)(skBase, session.version),
234
+ });
235
+ if (!cmd)
236
+ continue;
237
+ const transformed = mergeOptions.transformCommand(cmd, existing);
238
+ if (cmd.isDeleted) {
239
+ // Delete the item from the map
240
+ if (itemMap.has(itemId)) {
241
+ itemMap.delete(itemId);
242
+ adjustedTotal--;
243
+ }
244
+ }
245
+ else if (itemMap.has(itemId)) {
246
+ // Update: preserves original position
247
+ itemMap.set(itemId, transformed);
248
+ }
249
+ else {
250
+ // Create-new: check if it satisfies the current query filters
251
+ if (!mergeOptions.matchesFilter ||
252
+ mergeOptions.matchesFilter(transformed)) {
253
+ newItems.push(transformed);
254
+ adjustedTotal++;
255
+ }
256
+ }
257
+ }
258
+ // Sort newly created items by createdAt descending (safely fallback to 0 if field is missing)
259
+ if (newItems.length > 1) {
260
+ newItems.sort((a, b) => {
261
+ const timeA = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
262
+ const timeB = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
263
+ return timeB - timeA;
264
+ });
265
+ }
266
+ return {
267
+ total: adjustedTotal,
268
+ items: [...newItems, ...itemMap.values()],
269
+ };
270
+ }
271
+ };
272
+ exports.Repository = Repository;
273
+ exports.Repository = Repository = Repository_1 = __decorate([
274
+ (0, common_1.Injectable)(),
275
+ __param(0, (0, common_1.Inject)(command_module_definition_1.MODULE_OPTIONS_TOKEN)),
276
+ __metadata("design:paramtypes", [Object, data_service_1.DataService,
277
+ command_service_1.CommandService,
278
+ session_service_1.SessionService])
279
+ ], Repository);
280
+ //# sourceMappingURL=repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/commands/repository.ts"],"names":[],"mappings":"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"}
@@ -10,14 +10,15 @@ exports.DataStoreModule = void 0;
10
10
  const common_1 = require("@nestjs/common");
11
11
  const dynamodb_service_1 = require("./dynamodb.service");
12
12
  const s3_service_1 = require("./s3.service");
13
+ const session_service_1 = require("./session.service");
13
14
  let DataStoreModule = class DataStoreModule {
14
15
  };
15
16
  exports.DataStoreModule = DataStoreModule;
16
17
  exports.DataStoreModule = DataStoreModule = __decorate([
17
18
  (0, common_1.Global)(),
18
19
  (0, common_1.Module)({
19
- providers: [dynamodb_service_1.DynamoDbService, s3_service_1.S3Service],
20
- exports: [dynamodb_service_1.DynamoDbService, s3_service_1.S3Service],
20
+ providers: [dynamodb_service_1.DynamoDbService, s3_service_1.S3Service, session_service_1.SessionService],
21
+ exports: [dynamodb_service_1.DynamoDbService, s3_service_1.S3Service, session_service_1.SessionService],
21
22
  })
22
23
  ], DataStoreModule);
23
24
  //# sourceMappingURL=data-store.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-store.module.js","sourceRoot":"","sources":["../../src/data-store/data-store.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA+C;AAE/C,yDAAoD;AACpD,6CAAwC;AAOjC,IAAM,eAAe,GAArB,MAAM,eAAe;CAAG,CAAA;AAAlB,0CAAe;0BAAf,eAAe;IAL3B,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,SAAS,EAAE,CAAC,kCAAe,EAAE,sBAAS,CAAC;QACvC,OAAO,EAAE,CAAC,kCAAe,EAAE,sBAAS,CAAC;KACtC,CAAC;GACW,eAAe,CAAG"}
1
+ {"version":3,"file":"data-store.module.js","sourceRoot":"","sources":["../../src/data-store/data-store.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA+C;AAE/C,yDAAoD;AACpD,6CAAwC;AACxC,uDAAkD;AAO3C,IAAM,eAAe,GAArB,MAAM,eAAe;CAAG,CAAA;AAAlB,0CAAe;0BAAf,eAAe;IAL3B,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,SAAS,EAAE,CAAC,kCAAe,EAAE,sBAAS,EAAE,gCAAc,CAAC;QACvD,OAAO,EAAE,CAAC,kCAAe,EAAE,sBAAS,EAAE,gCAAc,CAAC;KACtD,CAAC;GACW,eAAe,CAAG"}
@@ -1,3 +1,5 @@
1
1
  export * from './data-store.module';
2
2
  export * from './dynamodb.service';
3
3
  export * from './s3.service';
4
+ export * from './session.interface';
5
+ export * from './session.service';
@@ -17,4 +17,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./data-store.module"), exports);
18
18
  __exportStar(require("./dynamodb.service"), exports);
19
19
  __exportStar(require("./s3.service"), exports);
20
+ __exportStar(require("./session.interface"), exports);
21
+ __exportStar(require("./session.service"), exports);
20
22
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/data-store/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAmC;AACnC,qDAAkC;AAClC,+CAA4B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/data-store/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAmC;AACnC,qDAAkC;AAClC,+CAA4B;AAC5B,sDAAmC;AACnC,oDAAiC"}
@@ -0,0 +1,10 @@
1
+ export interface SessionItem {
2
+ /** pk: {userId}#{tenantCode} */
3
+ pk: string;
4
+ /** sk: {moduleTableName}#{itemId} — module `tableName` from CommandModule */
5
+ sk: string;
6
+ /** Version of the command — used to fetch exact command record */
7
+ version: number;
8
+ /** Unix timestamp TTL — auto-expired by DynamoDB */
9
+ ttl: number;
10
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=session.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.interface.js","sourceRoot":"","sources":["../../src/data-store/session.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,52 @@
1
+ import { ConfigService } from '@nestjs/config';
2
+ import { DynamoDbService } from './dynamodb.service';
3
+ import { SessionItem } from './session.interface';
4
+ export declare class SessionService {
5
+ private readonly dynamoDbService;
6
+ private readonly config;
7
+ private readonly logger;
8
+ private readonly sessionTableName;
9
+ private readonly ttlSeconds;
10
+ /** When unset or invalid, session rows are not written (RYW read path still works on empty). */
11
+ private readonly sessionWritesEnabled;
12
+ constructor(dynamoDbService: DynamoDbService, config: ConfigService);
13
+ /**
14
+ * Build session pk: {userId}#{tenantCode}
15
+ */
16
+ private buildPk;
17
+ /**
18
+ * Build session sk: {moduleTableName}#{itemId}
19
+ */
20
+ private buildSk;
21
+ private calculateTtl;
22
+ /**
23
+ * Write a session entry after a successful async command publish.
24
+ * Called by CommandService after publishAsync only.
25
+ * No-ops when RYW session TTL is not configured (`sessionWritesEnabled` is false).
26
+ */
27
+ put(userId: string, tenantCode: string, moduleTableName: string, itemId: string, version: number): Promise<void>;
28
+ /**
29
+ * Get a single session entry for a specific item.
30
+ * Returns `null` without querying DynamoDB when session writes are disabled.
31
+ */
32
+ get(userId: string, tenantCode: string, moduleTableName: string, itemId: string): Promise<SessionItem | null>;
33
+ /**
34
+ * List session entries for a user scoped to a command module.
35
+ *
36
+ * Queries the session table by `{userId}#{tenantCode}` and filters to entries
37
+ * whose sort key begins with `{moduleTableName}#`, returning only sessions
38
+ * that belong to the given module.
39
+ *
40
+ * @param userId - The ID of the requesting user (from JWT `sub` claim).
41
+ * @param tenantCode - The tenant the user is operating under.
42
+ * @param moduleTableName - The `tableName` from `CommandModuleOptions` — used
43
+ * as the sort key prefix to scope results to a single command module.
44
+ * @param limit - Maximum number of session entries to fetch. Defaults to
45
+ * `MAX_SESSION_ENTRIES` to prevent silent truncation from the underlying
46
+ * DynamoDB query's default limit of 10. Callers should rarely need to
47
+ * override this.
48
+ * @returns The matching session entries, or an empty array if none exist or
49
+ * session writes are disabled.
50
+ */
51
+ listByUser(userId: string, tenantCode: string, moduleTableName: string, limit?: number): Promise<SessionItem[]>;
52
+ }
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var SessionService_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.SessionService = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const config_1 = require("@nestjs/config");
16
+ const constants_1 = require("../constants");
17
+ const dynamodb_service_1 = require("./dynamodb.service");
18
+ /**
19
+ * Upper-bound for session entries fetched per user/module in a single query.
20
+ * Sessions are short-lived (RYW_SESSION_TTL_MINUTES) so this stays cheap.
21
+ * Prevents silent truncation from DynamoDbService's default limit of 10.
22
+ */
23
+ const MAX_SESSION_ENTRIES = 1000;
24
+ const SESSION_TABLE_SUFFIX = 'session';
25
+ let SessionService = SessionService_1 = class SessionService {
26
+ constructor(dynamoDbService, config) {
27
+ this.dynamoDbService = dynamoDbService;
28
+ this.config = config;
29
+ this.logger = new common_1.Logger(SessionService_1.name);
30
+ const nodeEnv = this.config.get('NODE_ENV');
31
+ const appName = this.config.get('APP_NAME');
32
+ this.sessionTableName = `${nodeEnv}-${appName}-${SESSION_TABLE_SUFFIX}`;
33
+ const ttlMinutes = Number(this.config.get('RYW_SESSION_TTL_MINUTES'));
34
+ this.sessionWritesEnabled = !Number.isNaN(ttlMinutes) && ttlMinutes > 0;
35
+ this.ttlSeconds = this.sessionWritesEnabled ? ttlMinutes * 60 : 0;
36
+ if (this.sessionWritesEnabled) {
37
+ this.logger.log(`Session table: ${this.sessionTableName}, RYW TTL: ${ttlMinutes}m`);
38
+ }
39
+ else {
40
+ this.logger.log(`Session table: ${this.sessionTableName}, RYW session writes disabled (set RYW_SESSION_TTL_MINUTES to a positive number to enable)`);
41
+ }
42
+ }
43
+ /**
44
+ * Build session pk: {userId}#{tenantCode}
45
+ */
46
+ buildPk(userId, tenantCode) {
47
+ return `${userId}${constants_1.KEY_SEPARATOR}${tenantCode}`;
48
+ }
49
+ /**
50
+ * Build session sk: {moduleTableName}#{itemId}
51
+ */
52
+ buildSk(moduleTableName, itemId) {
53
+ return `${moduleTableName}${constants_1.KEY_SEPARATOR}${itemId}`;
54
+ }
55
+ calculateTtl() {
56
+ return Math.floor(Date.now() / 1000) + this.ttlSeconds;
57
+ }
58
+ /**
59
+ * Write a session entry after a successful async command publish.
60
+ * Called by CommandService after publishAsync only.
61
+ * No-ops when RYW session TTL is not configured (`sessionWritesEnabled` is false).
62
+ */
63
+ async put(userId, tenantCode, moduleTableName, itemId, version) {
64
+ if (!this.sessionWritesEnabled) {
65
+ this.logger.debug('session put skipped: RYW_SESSION_TTL_MINUTES not enabled');
66
+ return;
67
+ }
68
+ const item = {
69
+ pk: this.buildPk(userId, tenantCode),
70
+ sk: this.buildSk(moduleTableName, itemId),
71
+ version,
72
+ ttl: this.calculateTtl(),
73
+ };
74
+ this.logger.debug('session put::', item);
75
+ await this.dynamoDbService.putItem(this.sessionTableName, item);
76
+ }
77
+ /**
78
+ * Get a single session entry for a specific item.
79
+ * Returns `null` without querying DynamoDB when session writes are disabled.
80
+ */
81
+ async get(userId, tenantCode, moduleTableName, itemId) {
82
+ if (!this.sessionWritesEnabled) {
83
+ return null;
84
+ }
85
+ const result = await this.dynamoDbService.getItem(this.sessionTableName, {
86
+ pk: this.buildPk(userId, tenantCode),
87
+ sk: this.buildSk(moduleTableName, itemId),
88
+ });
89
+ return result ?? null;
90
+ }
91
+ /**
92
+ * List session entries for a user scoped to a command module.
93
+ *
94
+ * Queries the session table by `{userId}#{tenantCode}` and filters to entries
95
+ * whose sort key begins with `{moduleTableName}#`, returning only sessions
96
+ * that belong to the given module.
97
+ *
98
+ * @param userId - The ID of the requesting user (from JWT `sub` claim).
99
+ * @param tenantCode - The tenant the user is operating under.
100
+ * @param moduleTableName - The `tableName` from `CommandModuleOptions` — used
101
+ * as the sort key prefix to scope results to a single command module.
102
+ * @param limit - Maximum number of session entries to fetch. Defaults to
103
+ * `MAX_SESSION_ENTRIES` to prevent silent truncation from the underlying
104
+ * DynamoDB query's default limit of 10. Callers should rarely need to
105
+ * override this.
106
+ * @returns The matching session entries, or an empty array if none exist or
107
+ * session writes are disabled.
108
+ */
109
+ async listByUser(userId, tenantCode, moduleTableName, limit = MAX_SESSION_ENTRIES) {
110
+ if (!this.sessionWritesEnabled) {
111
+ return [];
112
+ }
113
+ const pk = this.buildPk(userId, tenantCode);
114
+ const skPrefix = `${moduleTableName}${constants_1.KEY_SEPARATOR}`;
115
+ const result = await this.dynamoDbService.listItemsByPk(this.sessionTableName, pk, {
116
+ skExpression: 'begins_with(sk, :skPrefix)',
117
+ skAttributeValues: { ':skPrefix': skPrefix },
118
+ }, undefined, limit);
119
+ return result?.items ?? [];
120
+ }
121
+ };
122
+ exports.SessionService = SessionService;
123
+ exports.SessionService = SessionService = SessionService_1 = __decorate([
124
+ (0, common_1.Injectable)(),
125
+ __metadata("design:paramtypes", [dynamodb_service_1.DynamoDbService,
126
+ config_1.ConfigService])
127
+ ], SessionService);
128
+ //# sourceMappingURL=session.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.service.js","sourceRoot":"","sources":["../../src/data-store/session.service.ts"],"names":[],"mappings":"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"}
@@ -27,5 +27,6 @@ export declare class EnvironmentVariables {
27
27
  SES_REGION: string;
28
28
  SES_FROM_EMAIL: string;
29
29
  REQUEST_BODY_SIZE_LIMIT: string;
30
+ RYW_SESSION_TTL_MINUTES: number;
30
31
  }
31
32
  export declare function getValidateConfig<T extends EnvironmentVariables>(cls?: ClassConstructor<T>): (config: Record<string, unknown>) => EnvironmentVariables;
@@ -120,6 +120,11 @@ __decorate([
120
120
  (0, class_validator_1.IsOptional)(),
121
121
  __metadata("design:type", String)
122
122
  ], EnvironmentVariables.prototype, "REQUEST_BODY_SIZE_LIMIT", void 0);
123
+ __decorate([
124
+ (0, class_validator_1.IsNumber)(),
125
+ (0, class_validator_1.IsOptional)(),
126
+ __metadata("design:type", Number)
127
+ ], EnvironmentVariables.prototype, "RYW_SESSION_TTL_MINUTES", void 0);
123
128
  function getValidateConfig(cls) {
124
129
  return function validate(config) {
125
130
  const validatedConfig = (0, class_transformer_1.plainToInstance)(cls || EnvironmentVariables, config, {
@@ -1 +1 @@
1
- {"version":3,"file":"env.validation.js","sourceRoot":"","sources":["../src/env.validation.ts"],"names":[],"mappings":";;;;;;;;;;;;AAqFA,8CAoBC;AAzGD,yDAAqE;AACrE,qDAQwB;AAExB,IAAY,WAKX;AALD,WAAY,WAAW;IACrB,8BAAe,CAAA;IACf,kCAAmB,CAAA;IACnB,kCAAmB,CAAA;IACnB,8BAAe,CAAA;AACjB,CAAC,EALW,WAAW,2BAAX,WAAW,QAKtB;AAED,MAAa,oBAAoB;CAiEhC;AAjED,oDAiEC;AA/DC;IADC,IAAA,wBAAM,EAAC,WAAW,CAAC;;sDACC;AAErB;IADC,IAAA,0BAAQ,GAAE;;sDACK;AAIhB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;sDACG;AAGhB;IADC,IAAA,2BAAS,GAAE;;mEACkB;AAG9B;IADC,IAAA,0BAAQ,GAAE;;uDACM;AAIjB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;+DACY;AAGzB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;6DACY;AAEvB;IADC,IAAA,4BAAU,GAAE;;kEACe;AAG5B;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;yDACM;AAGnB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;uDACI;AAEjB;IADC,IAAA,0BAAQ,GAAE;;4DACW;AAItB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;0DACO;AAGpB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;wDACK;AAElB;IADC,IAAA,0BAAQ,GAAE;;6DACY;AAIvB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;0DACO;AAGpB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;wDACK;AAIlB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;8DACW;AAIxB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;0DACO;AAGpB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;wDACK;AAElB;IADC,IAAA,0BAAQ,GAAE;;4DACW;AAItB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;qEACkB;AAGjC,SAAgB,iBAAiB,CAC/B,GAAyB;IAEzB,OAAO,SAAS,QAAQ,CAAC,MAA+B;QACtD,MAAM,eAAe,GAAG,IAAA,mCAAe,EACrC,GAAG,IAAI,oBAAoB,EAC3B,MAAM,EACN;YACE,wBAAwB,EAAE,IAAI;SAC/B,CACF,CAAA;QACD,MAAM,MAAM,GAAG,IAAA,8BAAY,EAAC,eAAe,EAAE;YAC3C,qBAAqB,EAAE,KAAK;SAC7B,CAAC,CAAA;QAEF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;QACpC,CAAC;QACD,OAAO,eAAe,CAAA;IACxB,CAAC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"env.validation.js","sourceRoot":"","sources":["../src/env.validation.ts"],"names":[],"mappings":";;;;;;;;;;;;AAyFA,8CAoBC;AA7GD,yDAAqE;AACrE,qDAQwB;AAExB,IAAY,WAKX;AALD,WAAY,WAAW;IACrB,8BAAe,CAAA;IACf,kCAAmB,CAAA;IACnB,kCAAmB,CAAA;IACnB,8BAAe,CAAA;AACjB,CAAC,EALW,WAAW,2BAAX,WAAW,QAKtB;AAED,MAAa,oBAAoB;CAqEhC;AArED,oDAqEC;AAnEC;IADC,IAAA,wBAAM,EAAC,WAAW,CAAC;;sDACC;AAErB;IADC,IAAA,0BAAQ,GAAE;;sDACK;AAIhB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;sDACG;AAGhB;IADC,IAAA,2BAAS,GAAE;;mEACkB;AAG9B;IADC,IAAA,0BAAQ,GAAE;;uDACM;AAIjB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;+DACY;AAGzB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;6DACY;AAEvB;IADC,IAAA,4BAAU,GAAE;;kEACe;AAG5B;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;yDACM;AAGnB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;uDACI;AAEjB;IADC,IAAA,0BAAQ,GAAE;;4DACW;AAItB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;0DACO;AAGpB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;wDACK;AAElB;IADC,IAAA,0BAAQ,GAAE;;6DACY;AAIvB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;0DACO;AAGpB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;wDACK;AAIlB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;8DACW;AAIxB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;0DACO;AAGpB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;wDACK;AAElB;IADC,IAAA,0BAAQ,GAAE;;4DACW;AAItB;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;qEACkB;AAI/B;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;qEACkB;AAGjC,SAAgB,iBAAiB,CAC/B,GAAyB;IAEzB,OAAO,SAAS,QAAQ,CAAC,MAA+B;QACtD,MAAM,eAAe,GAAG,IAAA,mCAAe,EACrC,GAAG,IAAI,oBAAoB,EAC3B,MAAM,EACN;YACE,wBAAwB,EAAE,IAAI;SAC/B,CACF,CAAA;QACD,MAAM,MAAM,GAAG,IAAA,8BAAY,EAAC,eAAe,EAAE;YAC3C,qBAAqB,EAAE,KAAK;SAC7B,CAAC,CAAA;QAEF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;QACpC,CAAC;QACD,OAAO,eAAe,CAAA;IACxB,CAAC,CAAA;AACH,CAAC"}
@@ -4,5 +4,6 @@ export * from './key';
4
4
  export * from './object';
5
5
  export * from './serializer';
6
6
  export * from './source';
7
+ export * from './transform';
7
8
  export { deserializeToInternal, serializeToExternal } from './serializer';
8
9
  export declare const IS_LAMBDA_RUNNING: boolean;
@@ -21,6 +21,7 @@ __exportStar(require("./key"), exports);
21
21
  __exportStar(require("./object"), exports);
22
22
  __exportStar(require("./serializer"), exports);
23
23
  __exportStar(require("./source"), exports);
24
+ __exportStar(require("./transform"), exports);
24
25
  // Re-export serialization helpers for convenience
25
26
  var serializer_1 = require("./serializer");
26
27
  Object.defineProperty(exports, "deserializeToInternal", { enumerable: true, get: function () { return serializer_1.deserializeToInternal; } });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,6CAA0B;AAC1B,+CAA4B;AAC5B,wCAAqB;AACrB,2CAAwB;AACxB,+CAA4B;AAC5B,2CAAwB;AAExB,kDAAkD;AAClD,2CAAyE;AAAhE,mHAAA,qBAAqB,OAAA;AAAE,iHAAA,mBAAmB,OAAA;AAEtC,QAAA,iBAAiB,GAC5B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB;IACtC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,2BAA2B;IACzC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,6CAA0B;AAC1B,+CAA4B;AAC5B,wCAAqB;AACrB,2CAAwB;AACxB,+CAA4B;AAC5B,2CAAwB;AACxB,8CAA2B;AAE3B,kDAAkD;AAClD,2CAAyE;AAAhE,mHAAA,qBAAqB,OAAA;AAAE,iHAAA,mBAAmB,OAAA;AAEtC,QAAA,iBAAiB,GAC5B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB;IACtC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,2BAA2B;IACzC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAA"}
@@ -2,6 +2,19 @@ export declare function addSortKeyVersion(sk: string, version: number): string;
2
2
  export declare function getSortKeyVersion(sk: string): number;
3
3
  export declare function removeSortKeyVersion(sk: string): string;
4
4
  export declare function generateId(pk: string, sk: string): string;
5
+ /**
6
+ * Inverse of {@link generateId}: extracts the base sort key from a composite id (`pk#skBase`).
7
+ */
8
+ export declare function sortKeyBaseFromId(pk: string, itemId: string): string | undefined;
9
+ /**
10
+ * Parses a composite {@link generateId} when partition key is always
11
+ * `{type}#{tenantCode}` (exactly two `#`-separated segments). The remainder of
12
+ * `itemId` after that prefix is `skBase` (may contain `#`).
13
+ */
14
+ export declare function parseTwoSegmentPkSkFromId(itemId: string): {
15
+ pk: string;
16
+ skBase: string;
17
+ } | undefined;
5
18
  export declare function getTenantCode(pk: string): string;
6
19
  export declare function isS3AttributeKey(attributes: any): boolean;
7
20
  export declare function toS3AttributeKey(bucket: string, key: string): string;