aws-service-stack 0.18.372 → 0.18.374

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 (64) hide show
  1. package/README.md +150 -0
  2. package/dist/_examples/controller/property/property-crud.d.ts +4 -0
  3. package/dist/_examples/controller/property/property-crud.js +58 -0
  4. package/dist/_examples/controller/property/property-crud.js.map +1 -0
  5. package/dist/_examples/controller/property/property.config.d.ts +10 -0
  6. package/dist/_examples/controller/property/property.config.js +53 -0
  7. package/dist/_examples/controller/property/property.config.js.map +1 -0
  8. package/dist/_examples/controller/property/property.controller.d.ts +14 -0
  9. package/dist/_examples/controller/property/property.controller.js +72 -0
  10. package/dist/_examples/controller/property/property.controller.js.map +1 -0
  11. package/dist/_examples/controller/property/property.permissions.d.ts +2 -0
  12. package/dist/_examples/controller/property/property.permissions.js +19 -0
  13. package/dist/_examples/controller/property/property.permissions.js.map +1 -0
  14. package/dist/controller/controller-api.d.ts +5 -0
  15. package/dist/controller/controller-api.js +29 -1
  16. package/dist/controller/controller-api.js.map +1 -1
  17. package/dist/controller/controller-role.d.ts +53 -0
  18. package/dist/controller/controller-role.js +216 -0
  19. package/dist/controller/controller-role.js.map +1 -0
  20. package/dist/controller/index.d.ts +1 -0
  21. package/dist/controller/index.js +1 -0
  22. package/dist/controller/index.js.map +1 -1
  23. package/dist/function/cognito/cognito.function.d.ts +15 -0
  24. package/dist/function/cognito/cognito.function.js +45 -0
  25. package/dist/function/cognito/cognito.function.js.map +1 -1
  26. package/dist/function/cognito/index.d.ts +5 -1
  27. package/dist/function/cognito/index.js +4 -0
  28. package/dist/function/cognito/index.js.map +1 -1
  29. package/dist/function/index.d.ts +4 -0
  30. package/dist/model/base.config.d.ts +5 -1
  31. package/dist/model/base.config.js +7 -0
  32. package/dist/model/base.config.js.map +1 -1
  33. package/dist/model/base.model.d.ts +15 -0
  34. package/dist/model/base.model.js +4 -1
  35. package/dist/model/base.model.js.map +1 -1
  36. package/dist/model/index.d.ts +1 -0
  37. package/dist/model/index.js.map +1 -1
  38. package/dist/model/role.model.d.ts +20 -0
  39. package/dist/model/role.model.js +12 -0
  40. package/dist/model/role.model.js.map +1 -0
  41. package/dist/model/validation.model.d.ts +1 -1
  42. package/dist/model/validation.model.js.map +1 -1
  43. package/dist/service/index.d.ts +3 -0
  44. package/dist/service/index.js +3 -0
  45. package/dist/service/index.js.map +1 -1
  46. package/dist/service/permission.cache.d.ts +24 -0
  47. package/dist/service/permission.cache.js +61 -0
  48. package/dist/service/permission.cache.js.map +1 -0
  49. package/dist/service/permission.repo.d.ts +16 -0
  50. package/dist/service/permission.repo.js +63 -0
  51. package/dist/service/permission.repo.js.map +1 -0
  52. package/dist/service/permission.service.d.ts +39 -0
  53. package/dist/service/permission.service.js +151 -0
  54. package/dist/service/permission.service.js.map +1 -0
  55. package/dist/utils/date.util.d.ts +0 -13
  56. package/dist/utils/date.util.js +0 -35
  57. package/dist/utils/date.util.js.map +1 -1
  58. package/dist/utils/index.d.ts +0 -1
  59. package/dist/utils/index.js +0 -1
  60. package/dist/utils/index.js.map +1 -1
  61. package/package.json +31 -31
  62. package/dist/utils/data.util.d.ts +0 -20
  63. package/dist/utils/data.util.js +0 -73
  64. package/dist/utils/data.util.js.map +0 -1
@@ -0,0 +1,39 @@
1
+ import { Permission } from "../model/role.model";
2
+ /**
3
+ * PermissionService — cache + orchestration layer for Permission entities.
4
+ *
5
+ * Design decisions:
6
+ * - Read-through cache via PermissionCache (in-flight dedup, TTL).
7
+ * - Repository handles only DB I/O.
8
+ * - Cache invalidation on every mutation.
9
+ * - ~100 roles total, read-heavy → caching makes sense.
10
+ * - Cache keyed by `perm:{permissionKey}` for deterministic, namespaced lookup.
11
+ */
12
+ export declare class PermissionService {
13
+ private readonly repo;
14
+ private readonly cache;
15
+ constructor(tableName: string, cacheTtlMs?: number);
16
+ /** Fetch Permission by composite key (role#resource#scope). Read-through cached. */
17
+ getPermissionByKey(permissionKey: string): Promise<Permission | null>;
18
+ /** Fetch Permission by id. Read-through cached. */
19
+ getPermissionById(id: string): Promise<Permission | null>;
20
+ /**
21
+ * Check if the given role+resource+scope has a specific HTTP method allowed.
22
+ *
23
+ * Builds the permissionKey `role#resource#scope`, fetches the Permission,
24
+ * and checks the method map.
25
+ *
26
+ * @returns `true` if allowed, `false` otherwise.
27
+ */
28
+ hasPermission(role: string, resource: string, scope: string, method: string): Promise<boolean>;
29
+ createPermission(input: {
30
+ role: string;
31
+ resource: string;
32
+ scope: string;
33
+ method: Permission["method"];
34
+ }): Promise<Permission>;
35
+ updatePermission(id: string, updates: Partial<Pick<Permission, "role" | "resource" | "scope" | "method">>): Promise<Permission>;
36
+ deletePermission(id: string): Promise<boolean>;
37
+ listPermissions(): Promise<Permission[]>;
38
+ clearCache(): void;
39
+ }
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PermissionService = void 0;
4
+ const exception_1 = require("../exception");
5
+ const permission_cache_1 = require("./permission.cache");
6
+ const permission_repo_1 = require("./permission.repo");
7
+ /**
8
+ * PermissionService — cache + orchestration layer for Permission entities.
9
+ *
10
+ * Design decisions:
11
+ * - Read-through cache via PermissionCache (in-flight dedup, TTL).
12
+ * - Repository handles only DB I/O.
13
+ * - Cache invalidation on every mutation.
14
+ * - ~100 roles total, read-heavy → caching makes sense.
15
+ * - Cache keyed by `perm:{permissionKey}` for deterministic, namespaced lookup.
16
+ */
17
+ class PermissionService {
18
+ repo;
19
+ cache;
20
+ constructor(tableName, cacheTtlMs) {
21
+ this.repo = new permission_repo_1.PermissionRepo(tableName);
22
+ this.cache = new permission_cache_1.PermissionCache(cacheTtlMs);
23
+ }
24
+ // ---------------------------------------------------------------------------
25
+ // Core lookup
26
+ // ---------------------------------------------------------------------------
27
+ /** Fetch Permission by composite key (role#resource#scope). Read-through cached. */
28
+ async getPermissionByKey(permissionKey) {
29
+ if (!permissionKey)
30
+ return null;
31
+ return this.cache.getOrFetch(`perm:${permissionKey}`, () => this.repo.findByPermissionKey(permissionKey));
32
+ }
33
+ /** Fetch Permission by id. Read-through cached. */
34
+ async getPermissionById(id) {
35
+ if (!id)
36
+ return null;
37
+ return this.cache.getOrFetch(`id:${id}`, () => this.repo.findById(id));
38
+ }
39
+ // ---------------------------------------------------------------------------
40
+ // Permission check
41
+ // ---------------------------------------------------------------------------
42
+ /**
43
+ * Check if the given role+resource+scope has a specific HTTP method allowed.
44
+ *
45
+ * Builds the permissionKey `role#resource#scope`, fetches the Permission,
46
+ * and checks the method map.
47
+ *
48
+ * @returns `true` if allowed, `false` otherwise.
49
+ */
50
+ async hasPermission(role, resource, scope, method) {
51
+ if (!role || !resource || !scope || !method)
52
+ return false;
53
+ const permissionKey = `${role}#${resource}#${scope}`;
54
+ const permission = await this.getPermissionByKey(permissionKey);
55
+ if (!permission?.method)
56
+ return false;
57
+ const methodLower = method.toUpperCase();
58
+ return permission.method[methodLower] === true;
59
+ }
60
+ // ---------------------------------------------------------------------------
61
+ // CRUD — create
62
+ // ---------------------------------------------------------------------------
63
+ async createPermission(input) {
64
+ if (!input.role?.trim()) {
65
+ throw new exception_1.ErrorHttp({ code: 400, error: "BadRequest" }, "Role is required");
66
+ }
67
+ if (!input.resource?.trim()) {
68
+ throw new exception_1.ErrorHttp({ code: 400, error: "BadRequest" }, "Resource is required");
69
+ }
70
+ if (!input.scope?.trim()) {
71
+ throw new exception_1.ErrorHttp({ code: 400, error: "BadRequest" }, "Scope is required");
72
+ }
73
+ // Duplicate check
74
+ const permissionKey = `${input.role}#${input.resource}#${input.scope}`;
75
+ const existing = await this.repo.findByPermissionKey(permissionKey);
76
+ if (existing) {
77
+ throw new exception_1.ErrorHttp({ code: 409, error: "Conflict" }, `Permission "${permissionKey}" already exists`);
78
+ }
79
+ const saved = await this.repo.save({
80
+ role: input.role.trim(),
81
+ resource: input.resource.trim(),
82
+ scope: input.scope.trim(),
83
+ method: input.method ?? {},
84
+ permissionKey,
85
+ });
86
+ this.cache.clear();
87
+ return saved;
88
+ }
89
+ // ---------------------------------------------------------------------------
90
+ // CRUD — update
91
+ // ---------------------------------------------------------------------------
92
+ async updatePermission(id, updates) {
93
+ if (!id)
94
+ throw new exception_1.ErrorHttp({ code: 400, error: "BadRequest" }, "Permission id is required");
95
+ const existing = await this.repo.findById(id);
96
+ if (!existing)
97
+ throw new exception_1.ErrorHttp({ code: 404, error: "NotFound" }, `Permission "${id}" not found`);
98
+ const data = { id };
99
+ if (updates.role !== undefined)
100
+ data.role = updates.role.trim();
101
+ if (updates.resource !== undefined)
102
+ data.resource = updates.resource.trim();
103
+ if (updates.scope !== undefined)
104
+ data.scope = updates.scope.trim();
105
+ if (updates.method !== undefined)
106
+ data.method = updates.method;
107
+ // Rebuild key if any key component changed
108
+ const role = data.role ?? existing.role;
109
+ const resource = data.resource ?? existing.resource;
110
+ const scope = data.scope ?? existing.scope;
111
+ data.permissionKey = `${role}#${resource}#${scope}`;
112
+ // Check for duplicate key if components changed
113
+ if (data.permissionKey !== existing.permissionKey) {
114
+ const conflict = await this.repo.findByPermissionKey(data.permissionKey);
115
+ if (conflict) {
116
+ throw new exception_1.ErrorHttp({ code: 409, error: "Conflict" }, `Permission "${data.permissionKey}" already exists`);
117
+ }
118
+ }
119
+ const updated = await this.repo.update(data);
120
+ this.cache.clear();
121
+ return updated;
122
+ }
123
+ // ---------------------------------------------------------------------------
124
+ // CRUD — delete
125
+ // ---------------------------------------------------------------------------
126
+ async deletePermission(id) {
127
+ if (!id)
128
+ throw new exception_1.ErrorHttp({ code: 400, error: "BadRequest" }, "Permission id is required");
129
+ const existing = await this.repo.findById(id);
130
+ if (!existing)
131
+ throw new exception_1.ErrorHttp({ code: 404, error: "NotFound" }, `Permission "${id}" not found`);
132
+ const result = await this.repo.delete(id);
133
+ this.cache.clear();
134
+ return result;
135
+ }
136
+ // ---------------------------------------------------------------------------
137
+ // CRUD — list
138
+ // ---------------------------------------------------------------------------
139
+ async listPermissions() {
140
+ const result = await this.repo.scan();
141
+ return (result.items ?? []);
142
+ }
143
+ // ---------------------------------------------------------------------------
144
+ // Cache control (for testing)
145
+ // ---------------------------------------------------------------------------
146
+ clearCache() {
147
+ this.cache.clear();
148
+ }
149
+ }
150
+ exports.PermissionService = PermissionService;
151
+ //# sourceMappingURL=permission.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission.service.js","sourceRoot":"","sources":["../../src/service/permission.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Permission } from \"../model/role.model\";\nimport { ErrorHttp } from \"../exception\";\nimport { PermissionCache } from \"./permission.cache\";\nimport { PermissionRepo } from \"./permission.repo\";\n\n/**\n * PermissionService — cache + orchestration layer for Permission entities.\n *\n * Design decisions:\n * - Read-through cache via PermissionCache (in-flight dedup, TTL).\n * - Repository handles only DB I/O.\n * - Cache invalidation on every mutation.\n * - ~100 roles total, read-heavy → caching makes sense.\n * - Cache keyed by `perm:{permissionKey}` for deterministic, namespaced lookup.\n */\nexport class PermissionService {\n private readonly repo: PermissionRepo;\n private readonly cache: PermissionCache;\n\n constructor(tableName: string, cacheTtlMs?: number) {\n this.repo = new PermissionRepo(tableName);\n this.cache = new PermissionCache(cacheTtlMs);\n }\n\n // ---------------------------------------------------------------------------\n // Core lookup\n // ---------------------------------------------------------------------------\n\n /** Fetch Permission by composite key (role#resource#scope). Read-through cached. */\n async getPermissionByKey(permissionKey: string): Promise<Permission | null> {\n if (!permissionKey) return null;\n\n return this.cache.getOrFetch(`perm:${permissionKey}`, () => this.repo.findByPermissionKey(permissionKey));\n }\n\n /** Fetch Permission by id. Read-through cached. */\n async getPermissionById(id: string): Promise<Permission | null> {\n if (!id) return null;\n\n return this.cache.getOrFetch(`id:${id}`, () => this.repo.findById(id));\n }\n\n // ---------------------------------------------------------------------------\n // Permission check\n // ---------------------------------------------------------------------------\n\n /**\n * Check if the given role+resource+scope has a specific HTTP method allowed.\n *\n * Builds the permissionKey `role#resource#scope`, fetches the Permission,\n * and checks the method map.\n *\n * @returns `true` if allowed, `false` otherwise.\n */\n async hasPermission(role: string, resource: string, scope: string, method: string): Promise<boolean> {\n if (!role || !resource || !scope || !method) return false;\n\n const permissionKey = `${role}#${resource}#${scope}`;\n const permission = await this.getPermissionByKey(permissionKey);\n if (!permission?.method) return false;\n\n const methodLower = method.toUpperCase() as keyof Permission[\"method\"];\n\n return permission.method[methodLower] === true;\n }\n\n // ---------------------------------------------------------------------------\n // CRUD — create\n // ---------------------------------------------------------------------------\n\n async createPermission(input: {\n role: string;\n resource: string;\n scope: string;\n method: Permission[\"method\"];\n }): Promise<Permission> {\n if (!input.role?.trim()) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Role is required\");\n }\n if (!input.resource?.trim()) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Resource is required\");\n }\n if (!input.scope?.trim()) {\n throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Scope is required\");\n }\n\n // Duplicate check\n const permissionKey = `${input.role}#${input.resource}#${input.scope}`;\n const existing = await this.repo.findByPermissionKey(permissionKey);\n if (existing) {\n throw new ErrorHttp({ code: 409, error: \"Conflict\" }, `Permission \"${permissionKey}\" already exists`);\n }\n\n const saved = await this.repo.save({\n role: input.role.trim(),\n resource: input.resource.trim(),\n scope: input.scope.trim(),\n method: input.method ?? {},\n permissionKey,\n });\n\n this.cache.clear();\n return saved;\n }\n\n // ---------------------------------------------------------------------------\n // CRUD — update\n // ---------------------------------------------------------------------------\n\n async updatePermission(\n id: string,\n updates: Partial<Pick<Permission, \"role\" | \"resource\" | \"scope\" | \"method\">>,\n ): Promise<Permission> {\n if (!id) throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Permission id is required\");\n\n const existing = await this.repo.findById(id);\n if (!existing) throw new ErrorHttp({ code: 404, error: \"NotFound\" }, `Permission \"${id}\" not found`);\n\n const data: Partial<Permission> = { id };\n if (updates.role !== undefined) data.role = updates.role.trim();\n if (updates.resource !== undefined) data.resource = updates.resource.trim();\n if (updates.scope !== undefined) data.scope = updates.scope.trim();\n if (updates.method !== undefined) data.method = updates.method;\n\n // Rebuild key if any key component changed\n const role = data.role ?? existing.role;\n const resource = data.resource ?? existing.resource;\n const scope = data.scope ?? existing.scope;\n data.permissionKey = `${role}#${resource}#${scope}`;\n\n // Check for duplicate key if components changed\n if (data.permissionKey !== existing.permissionKey) {\n const conflict = await this.repo.findByPermissionKey(data.permissionKey);\n if (conflict) {\n throw new ErrorHttp({ code: 409, error: \"Conflict\" }, `Permission \"${data.permissionKey}\" already exists`);\n }\n }\n\n const updated = await this.repo.update(data);\n\n this.cache.clear();\n return updated;\n }\n\n // ---------------------------------------------------------------------------\n // CRUD — delete\n // ---------------------------------------------------------------------------\n\n async deletePermission(id: string): Promise<boolean> {\n if (!id) throw new ErrorHttp({ code: 400, error: \"BadRequest\" }, \"Permission id is required\");\n\n const existing = await this.repo.findById(id);\n if (!existing) throw new ErrorHttp({ code: 404, error: \"NotFound\" }, `Permission \"${id}\" not found`);\n\n const result = await this.repo.delete(id);\n\n this.cache.clear();\n return result;\n }\n\n // ---------------------------------------------------------------------------\n // CRUD — list\n // ---------------------------------------------------------------------------\n\n async listPermissions(): Promise<Permission[]> {\n const result = await this.repo.scan();\n return (result.items ?? []) as Permission[];\n }\n\n // ---------------------------------------------------------------------------\n // Cache control (for testing)\n // ---------------------------------------------------------------------------\n\n clearCache(): void {\n this.cache.clear();\n }\n}\n"]}
@@ -3,16 +3,3 @@ export declare function isValidDate(dateStr: string): boolean;
3
3
  export declare function isSameYearMonth(date1: string | Date | Dayjs, date2: string | Date | Dayjs): boolean;
4
4
  export declare function isCurrentMonth(date: string | Date | Dayjs): boolean;
5
5
  export declare function isFutureMonth(date: string): boolean;
6
- export declare function addSecondToDate(date: string | Date | Dayjs): Dayjs;
7
- /**
8
- * Returns the oldest date string from a list of date strings.
9
- * @param dateStrList List of date strings (ISO or other formats supported by dayjs).
10
- * @returns The oldest date string, or an empty string if the list is empty.
11
- */
12
- export declare function minDateStr(dateStrList: any[]): string;
13
- /**
14
- * Returns the newest date string from a list of date strings.
15
- * @param dateStrList List of date strings (ISO or other formats supported by dayjs).
16
- * @returns The newest date string, or an empty string if the list is empty.
17
- */
18
- export declare function maxDateStr(dateStrList: any[]): string;
@@ -7,9 +7,6 @@ exports.isValidDate = isValidDate;
7
7
  exports.isSameYearMonth = isSameYearMonth;
8
8
  exports.isCurrentMonth = isCurrentMonth;
9
9
  exports.isFutureMonth = isFutureMonth;
10
- exports.addSecondToDate = addSecondToDate;
11
- exports.minDateStr = minDateStr;
12
- exports.maxDateStr = maxDateStr;
13
10
  const dayjs_1 = __importDefault(require("dayjs"));
14
11
  function isValidDate(dateStr) {
15
12
  const d = new Date(dateStr);
@@ -34,36 +31,4 @@ function isFutureMonth(date) {
34
31
  // Compare year-month
35
32
  return inputYear > currentYear || (inputYear === currentYear && inputMonth > currentMonth);
36
33
  }
37
- function addSecondToDate(date) {
38
- return (0, dayjs_1.default)(date).add(1, "second");
39
- }
40
- /**
41
- * Returns the oldest date string from a list of date strings.
42
- * @param dateStrList List of date strings (ISO or other formats supported by dayjs).
43
- * @returns The oldest date string, or an empty string if the list is empty.
44
- */
45
- function minDateStr(dateStrList) {
46
- return minMaxDateStr(dateStrList, false);
47
- }
48
- /**
49
- * Returns the newest date string from a list of date strings.
50
- * @param dateStrList List of date strings (ISO or other formats supported by dayjs).
51
- * @returns The newest date string, or an empty string if the list is empty.
52
- */
53
- function maxDateStr(dateStrList) {
54
- return minMaxDateStr(dateStrList, true);
55
- }
56
- function minMaxDateStr(dateStrList, isMax) {
57
- if (!dateStrList || dateStrList.length === 0)
58
- return "";
59
- const filtered = dateStrList.filter((d) => !!d);
60
- if (filtered.length === 0)
61
- return "";
62
- return filtered.reduce((newestDate, current) => {
63
- if (isMax)
64
- return (0, dayjs_1.default)(current).isAfter((0, dayjs_1.default)(newestDate)) ? current : newestDate;
65
- else
66
- return (0, dayjs_1.default)(current).isBefore((0, dayjs_1.default)(newestDate)) ? newestDate : current;
67
- });
68
- }
69
34
  //# sourceMappingURL=date.util.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"date.util.js","sourceRoot":"","sources":["../../src/utils/date.util.ts"],"names":[],"mappings":";;;;;AAEA,kCAGC;AAED,0CAIC;AAED,wCAEC;AAED,sCAYC;AAED,0CAEC;AAMD,gCAEC;AAOD,gCAEC;AAlDD,kDAAqC;AAErC,SAAgB,WAAW,CAAC,OAAe;IACzC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AACpC,CAAC;AAED,SAAgB,eAAe,CAAC,KAA4B,EAAE,KAA4B;IACxF,MAAM,EAAE,GAAG,IAAA,eAAK,EAAC,KAAK,CAAC,CAAC;IACxB,MAAM,EAAE,GAAG,IAAA,eAAK,EAAC,KAAK,CAAC,CAAC;IACxB,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;AACzD,CAAC;AAED,SAAgB,cAAc,CAAC,IAA2B;IACxD,OAAO,eAAe,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,SAAgB,aAAa,CAAC,IAAY;IACxC,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC;IAEzB,yBAAyB;IACzB,MAAM,SAAS,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IAC1C,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC,oBAAoB;IAC7D,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IACxC,MAAM,YAAY,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;IAEtC,qBAAqB;IACrB,OAAO,SAAS,GAAG,WAAW,IAAI,CAAC,SAAS,KAAK,WAAW,IAAI,UAAU,GAAG,YAAY,CAAC,CAAC;AAC7F,CAAC;AAED,SAAgB,eAAe,CAAC,IAA2B;IACzD,OAAO,IAAA,eAAK,EAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC;AACD;;;;GAIG;AACH,SAAgB,UAAU,CAAC,WAAkB;IAC3C,OAAO,aAAa,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;AAC3C,CAAC;AAED;;;;GAIG;AACH,SAAgB,UAAU,CAAC,WAAkB;IAC3C,OAAO,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,aAAa,CAAC,WAAkB,EAAE,KAAc;IACvD,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAExD,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,OAAO,EAAE,EAAE;QAC7C,IAAI,KAAK;YAAE,OAAO,IAAA,eAAK,EAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAA,eAAK,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;;YAC9E,OAAO,IAAA,eAAK,EAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAA,eAAK,EAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;IAChF,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import dayjs, { Dayjs } from \"dayjs\";\n\nexport function isValidDate(dateStr: string): boolean {\n const d = new Date(dateStr);\n return !Number.isNaN(d.getTime());\n}\n\nexport function isSameYearMonth(date1: string | Date | Dayjs, date2: string | Date | Dayjs): boolean {\n const d1 = dayjs(date1);\n const d2 = dayjs(date2);\n return d1.isSame(d2, \"month\") && d1.isSame(d2, \"year\");\n}\n\nexport function isCurrentMonth(date: string | Date | Dayjs): boolean {\n return isSameYearMonth(date, new Date());\n}\n\nexport function isFutureMonth(date: string): boolean {\n const inputDate = new Date(date);\n const today = new Date();\n\n // Extract year and month\n const inputYear = inputDate.getFullYear();\n const inputMonth = inputDate.getMonth(); // 0-based (0 = Jan)\n const currentYear = today.getFullYear();\n const currentMonth = today.getMonth();\n\n // Compare year-month\n return inputYear > currentYear || (inputYear === currentYear && inputMonth > currentMonth);\n}\n\nexport function addSecondToDate(date: string | Date | Dayjs): Dayjs {\n return dayjs(date).add(1, \"second\");\n}\n/**\n * Returns the oldest date string from a list of date strings.\n * @param dateStrList List of date strings (ISO or other formats supported by dayjs).\n * @returns The oldest date string, or an empty string if the list is empty.\n */\nexport function minDateStr(dateStrList: any[]): string {\n return minMaxDateStr(dateStrList, false);\n}\n\n/**\n * Returns the newest date string from a list of date strings.\n * @param dateStrList List of date strings (ISO or other formats supported by dayjs).\n * @returns The newest date string, or an empty string if the list is empty.\n */\nexport function maxDateStr(dateStrList: any[]): string {\n return minMaxDateStr(dateStrList, true);\n}\n\nfunction minMaxDateStr(dateStrList: any[], isMax: boolean): string {\n if (!dateStrList || dateStrList.length === 0) return \"\";\n\n const filtered = dateStrList.filter((d) => !!d);\n if (filtered.length === 0) return \"\";\n\n return filtered.reduce((newestDate, current) => {\n if (isMax) return dayjs(current).isAfter(dayjs(newestDate)) ? current : newestDate;\n else return dayjs(current).isBefore(dayjs(newestDate)) ? newestDate : current;\n });\n}\n"]}
1
+ {"version":3,"file":"date.util.js","sourceRoot":"","sources":["../../src/utils/date.util.ts"],"names":[],"mappings":";;;;;AACA,kCAGC;AAED,0CAIC;AAED,wCAEC;AAED,sCAYC;AA5BD,kDAAqC;AACrC,SAAgB,WAAW,CAAC,OAAe;IACzC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AACpC,CAAC;AAED,SAAgB,eAAe,CAAC,KAA4B,EAAE,KAA4B;IACxF,MAAM,EAAE,GAAG,IAAA,eAAK,EAAC,KAAK,CAAC,CAAC;IACxB,MAAM,EAAE,GAAG,IAAA,eAAK,EAAC,KAAK,CAAC,CAAC;IACxB,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;AACzD,CAAC;AAED,SAAgB,cAAc,CAAC,IAA2B;IACxD,OAAO,eAAe,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,SAAgB,aAAa,CAAC,IAAY;IACxC,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC;IAEzB,yBAAyB;IACzB,MAAM,SAAS,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IAC1C,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC,oBAAoB;IAC7D,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IACxC,MAAM,YAAY,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;IAEtC,qBAAqB;IACrB,OAAO,SAAS,GAAG,WAAW,IAAI,CAAC,SAAS,KAAK,WAAW,IAAI,UAAU,GAAG,YAAY,CAAC,CAAC;AAC7F,CAAC","sourcesContent":["import dayjs, { Dayjs } from \"dayjs\";\nexport function isValidDate(dateStr: string): boolean {\n const d = new Date(dateStr);\n return !Number.isNaN(d.getTime());\n}\n\nexport function isSameYearMonth(date1: string | Date | Dayjs, date2: string | Date | Dayjs): boolean {\n const d1 = dayjs(date1);\n const d2 = dayjs(date2);\n return d1.isSame(d2, \"month\") && d1.isSame(d2, \"year\");\n}\n\nexport function isCurrentMonth(date: string | Date | Dayjs): boolean {\n return isSameYearMonth(date, new Date());\n}\n\nexport function isFutureMonth(date: string): boolean {\n const inputDate = new Date(date);\n const today = new Date();\n\n // Extract year and month\n const inputYear = inputDate.getFullYear();\n const inputMonth = inputDate.getMonth(); // 0-based (0 = Jan)\n const currentYear = today.getFullYear();\n const currentMonth = today.getMonth();\n\n // Compare year-month\n return inputYear > currentYear || (inputYear === currentYear && inputMonth > currentMonth);\n}\n"]}
@@ -12,5 +12,4 @@ export * from "./reflection.util";
12
12
  export * from "./validation.util";
13
13
  export * from "./opensearch/opensearch.parser";
14
14
  export * from "./opensearch/opensearch.transform";
15
- export * from "./data.util";
16
15
  export * from "../function/logger";
@@ -28,6 +28,5 @@ __exportStar(require("./reflection.util"), exports);
28
28
  __exportStar(require("./validation.util"), exports);
29
29
  __exportStar(require("./opensearch/opensearch.parser"), exports);
30
30
  __exportStar(require("./opensearch/opensearch.transform"), exports);
31
- __exportStar(require("./data.util"), exports);
32
31
  __exportStar(require("../function/logger"), exports);
33
32
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mDAAiC;AACjC,sDAAoC;AACpC,+CAA6B;AAC7B,8CAA4B;AAC5B,8CAA4B;AAC5B,mDAAiC;AACjC,6CAA2B;AAC3B,+CAA6B;AAC7B,8CAA4B;AAC5B,qDAAmC;AACnC,oDAAkC;AAClC,oDAAkC;AAClC,iEAA+C;AAC/C,oEAAkD;AAClD,8CAA4B;AAE5B,qDAAmC","sourcesContent":["export * from \"./http/http.util\";\nexport * from \"./http/http-request\";\nexport * from \"./array.util\";\nexport * from \"./auth.util\";\nexport * from \"./date.util\";\nexport * from \"./dynamodb.utils\";\nexport * from \"./env.util\";\nexport * from \"./error.util\";\nexport * from \"./json.util\";\nexport * from \"./opensearch.utils\";\nexport * from \"./reflection.util\";\nexport * from \"./validation.util\";\nexport * from \"./opensearch/opensearch.parser\";\nexport * from \"./opensearch/opensearch.transform\";\nexport * from \"./data.util\";\n\nexport * from \"../function/logger\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mDAAiC;AACjC,sDAAoC;AACpC,+CAA6B;AAC7B,8CAA4B;AAC5B,8CAA4B;AAC5B,mDAAiC;AACjC,6CAA2B;AAC3B,+CAA6B;AAC7B,8CAA4B;AAC5B,qDAAmC;AACnC,oDAAkC;AAClC,oDAAkC;AAClC,iEAA+C;AAC/C,oEAAkD;AAElD,qDAAmC","sourcesContent":["export * from \"./http/http.util\";\nexport * from \"./http/http-request\";\nexport * from \"./array.util\";\nexport * from \"./auth.util\";\nexport * from \"./date.util\";\nexport * from \"./dynamodb.utils\";\nexport * from \"./env.util\";\nexport * from \"./error.util\";\nexport * from \"./json.util\";\nexport * from \"./opensearch.utils\";\nexport * from \"./reflection.util\";\nexport * from \"./validation.util\";\nexport * from \"./opensearch/opensearch.parser\";\nexport * from \"./opensearch/opensearch.transform\";\n\nexport * from \"../function/logger\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aws-service-stack",
3
- "version": "0.18.372",
3
+ "version": "0.18.374",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "author": "chinggis.systems",
@@ -23,45 +23,45 @@
23
23
  "tslib": "^2.8.1"
24
24
  },
25
25
  "peerDependencies": {
26
- "@aws-sdk/client-api-gateway": "^3.999.0",
27
- "@aws-sdk/client-apigatewaymanagementapi": "^3.999.0",
28
- "@aws-sdk/client-cognito-identity-provider": "^3.999.0",
29
- "@aws-sdk/client-dynamodb": "^3.999.0",
30
- "@aws-sdk/client-lambda": "^3.999.0",
31
- "@aws-sdk/client-pinpoint": "^3.999.0",
32
- "@aws-sdk/client-secrets-manager": "^3.999.0",
33
- "@aws-sdk/client-sqs": "^3.999.0",
34
- "@aws-sdk/credential-provider-node": "^3.972.14",
35
- "@aws-sdk/lib-dynamodb": "^3.999.0",
36
- "@aws-sdk/s3-request-presigner": "^3.999.0",
37
- "@aws-sdk/util-dynamodb": "^3.996.1",
26
+ "@aws-sdk/client-api-gateway": "^3.907.0",
27
+ "@aws-sdk/client-apigatewaymanagementapi": "^3.907.0",
28
+ "@aws-sdk/client-cognito-identity-provider": "^3.907.0",
29
+ "@aws-sdk/client-dynamodb": "^3.907.0",
30
+ "@aws-sdk/client-lambda": "^3.907.0",
31
+ "@aws-sdk/client-pinpoint": "^3.907.0",
32
+ "@aws-sdk/client-secrets-manager": "^3.907.0",
33
+ "@aws-sdk/client-sqs": "^3.907.0",
34
+ "@aws-sdk/credential-provider-node": "^3.907.0",
35
+ "@aws-sdk/lib-dynamodb": "^3.907.0",
36
+ "@aws-sdk/s3-request-presigner": "^3.907.0",
37
+ "@aws-sdk/util-dynamodb": "^3.907.0",
38
38
  "@opensearch-project/opensearch": "^3.5.1",
39
- "axios": "^1.13.5",
40
- "dayjs": "^1.11.19",
41
- "elastic-builder": "^4.1.0",
39
+ "axios": "^1.12.2",
40
+ "dayjs": "^1.11.10",
41
+ "elastic-builder": "^3.4.0",
42
42
  "lodash.truncate": "^4.4.2",
43
- "nodemailer": "^8.0.1",
43
+ "nodemailer": "^6.9.11",
44
44
  "numeral": "^2.0.6",
45
45
  "typedi": "0.10.0",
46
46
  "yup": "^1.7.1",
47
- "zod": "^4.3.6"
47
+ "zod": "^4.1.12"
48
48
  },
49
49
  "devDependencies": {
50
- "@types/aws-lambda": "^8.10.161",
51
- "@types/jest": "^30.0.0",
52
- "eslint": "^10.0.2",
53
- "@typescript-eslint/eslint-plugin": "^8.56.1",
54
- "@typescript-eslint/parser": "^8.56.1",
55
- "jest": "^30.2.0",
50
+ "@types/aws-lambda": "^8.10.149",
51
+ "@types/jest": "^29.5.14",
52
+ "eslint": "^8.56.0",
53
+ "@typescript-eslint/eslint-plugin": "^6.19.1",
54
+ "@typescript-eslint/parser": "^6.19.1",
55
+ "jest": "^29.7.0",
56
56
  "jest-transform-stub": "^2.0.0",
57
- "jsonc-eslint-parser": "^3.1.0",
58
- "serverless-offline": "^14.5.0",
57
+ "jsonc-eslint-parser": "^2.4.0",
58
+ "serverless-offline": "^14.4.0",
59
59
  "serverless-stage-manager": "^1.0.5",
60
- "ts-jest": "^29.4.6",
60
+ "ts-jest": "^29.3.1",
61
61
  "ts-node": "^10.9.2",
62
- "tsc-alias": "^1.8.16",
63
- "typescript": "^5.9.3",
64
- "prettier": "^3.8.1",
65
- "typescript-transform-paths": "^3.5.6"
62
+ "tsc-alias": "^1.8.11",
63
+ "typescript": "^5.8.3",
64
+ "prettier": "^3.6.2",
65
+ "typescript-transform-paths": "^3.5.3"
66
66
  }
67
67
  }
@@ -1,20 +0,0 @@
1
- import { z, ZodType } from "zod";
2
- type InvalidConfig = boolean | string[];
3
- /**
4
- * EntityBuilder generates mock objects from a Zod schema.
5
- * - Can produce fully valid objects
6
- * - Can produce random invalid objects (at least one field invalid)
7
- * - Can produce targeted invalid objects (specific fields)
8
- * - Arrays are autofilled with multiple elements if `arrayLength` > 1
9
- */
10
- export declare class EntityBuilder<T extends ZodType<any, any, any>> {
11
- private readonly schema;
12
- private readonly invalid;
13
- private readonly arrayLength;
14
- private seed;
15
- constructor(schema: T, invalid?: InvalidConfig, arrayLength?: number);
16
- build(): z.infer<T>;
17
- private buildFromZod;
18
- private shouldInvalidate;
19
- }
20
- export {};
@@ -1,73 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EntityBuilder = void 0;
4
- const zod_1 = require("zod");
5
- /**
6
- * EntityBuilder generates mock objects from a Zod schema.
7
- * - Can produce fully valid objects
8
- * - Can produce random invalid objects (at least one field invalid)
9
- * - Can produce targeted invalid objects (specific fields)
10
- * - Arrays are autofilled with multiple elements if `arrayLength` > 1
11
- */
12
- class EntityBuilder {
13
- schema;
14
- invalid;
15
- arrayLength;
16
- seed = 1;
17
- constructor(schema, invalid = true, arrayLength = 1) {
18
- this.schema = schema;
19
- this.invalid = invalid;
20
- this.arrayLength = arrayLength;
21
- }
22
- build() {
23
- return this.buildFromZod(this.schema, this.invalid);
24
- }
25
- buildFromZod(schema, invalidConfig, path = []) {
26
- // Optional / Nullable unwrap
27
- if (schema instanceof zod_1.ZodOptional || schema instanceof zod_1.ZodNullable) {
28
- const inner = schema._def.innerType;
29
- return this.buildFromZod(inner, invalidConfig, path);
30
- }
31
- if (schema instanceof zod_1.ZodString) {
32
- return this.shouldInvalidate(path, invalidConfig) ? "INVALID" : `valid_${path.join("_")}`;
33
- }
34
- if (schema instanceof zod_1.ZodNumber) {
35
- return this.shouldInvalidate(path, invalidConfig) ? -1 : 1;
36
- }
37
- if (schema instanceof zod_1.ZodBoolean) {
38
- return !this.shouldInvalidate(path, invalidConfig);
39
- }
40
- if (schema instanceof zod_1.ZodArray) {
41
- const elementSchema = schema.element;
42
- const arr = [];
43
- for (let i = 0; i < this.arrayLength; i++) {
44
- arr.push(this.buildFromZod(elementSchema, invalidConfig, path.concat([String(i)])));
45
- }
46
- return arr;
47
- }
48
- if (schema instanceof zod_1.ZodObject) {
49
- const obj = {};
50
- const shape = schema.shape;
51
- for (const key in shape) {
52
- obj[key] = this.buildFromZod(shape[key], invalidConfig, path.concat([key]));
53
- }
54
- return obj;
55
- }
56
- // fallback for unsupported types
57
- return null;
58
- }
59
- shouldInvalidate(path, invalidConfig) {
60
- if (invalidConfig === false) {
61
- // random invalid
62
- const x = Math.sin(this.seed++) * 10000;
63
- return x - Math.floor(x) > 0.5;
64
- }
65
- if (Array.isArray(invalidConfig)) {
66
- // targeted invalid
67
- return invalidConfig.includes(path.join("."));
68
- }
69
- return false; // valid by default
70
- }
71
- }
72
- exports.EntityBuilder = EntityBuilder;
73
- //# sourceMappingURL=data.util.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"data.util.js","sourceRoot":"","sources":["../../src/utils/data.util.ts"],"names":[],"mappings":"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","sourcesContent":["import { z, ZodArray, ZodBoolean, ZodNullable, ZodNumber, ZodObject, ZodOptional, ZodString, ZodType } from \"zod\";\n\ntype InvalidConfig = boolean | string[];\n\n/**\n * EntityBuilder generates mock objects from a Zod schema.\n * - Can produce fully valid objects\n * - Can produce random invalid objects (at least one field invalid)\n * - Can produce targeted invalid objects (specific fields)\n * - Arrays are autofilled with multiple elements if `arrayLength` > 1\n */\nexport class EntityBuilder<T extends ZodType<any, any, any>> {\n private seed = 1;\n\n constructor(\n private readonly schema: T,\n private readonly invalid: InvalidConfig = true,\n private readonly arrayLength: number = 1, // default number of elements in arrays\n ) {}\n\n build(): z.infer<T> {\n return this.buildFromZod(this.schema, this.invalid) as z.infer<T>;\n }\n\n private buildFromZod(schema: ZodType<any, any, any>, invalidConfig: InvalidConfig, path: string[] = []): any {\n // Optional / Nullable unwrap\n if (schema instanceof ZodOptional || schema instanceof ZodNullable) {\n const inner = (schema as any)._def.innerType as ZodType<any, any, any>;\n return this.buildFromZod(inner, invalidConfig, path);\n }\n\n if (schema instanceof ZodString) {\n return this.shouldInvalidate(path, invalidConfig) ? \"INVALID\" : `valid_${path.join(\"_\")}`;\n }\n\n if (schema instanceof ZodNumber) {\n return this.shouldInvalidate(path, invalidConfig) ? -1 : 1;\n }\n\n if (schema instanceof ZodBoolean) {\n return !this.shouldInvalidate(path, invalidConfig);\n }\n\n if (schema instanceof ZodArray) {\n const elementSchema = (schema as ZodArray<any>).element as ZodType<any, any, any>;\n const arr = [];\n for (let i = 0; i < this.arrayLength; i++) {\n arr.push(this.buildFromZod(elementSchema, invalidConfig, path.concat([String(i)])));\n }\n return arr;\n }\n\n if (schema instanceof ZodObject) {\n const obj: any = {};\n const shape = (schema as ZodObject<any>).shape;\n for (const key in shape) {\n obj[key] = this.buildFromZod(shape[key], invalidConfig, path.concat([key]));\n }\n return obj;\n }\n\n // fallback for unsupported types\n return null;\n }\n\n private shouldInvalidate(path: string[], invalidConfig: InvalidConfig): boolean {\n if (invalidConfig === false) {\n // random invalid\n const x = Math.sin(this.seed++) * 10000;\n return x - Math.floor(x) > 0.5;\n }\n if (Array.isArray(invalidConfig)) {\n // targeted invalid\n return invalidConfig.includes(path.join(\".\"));\n }\n return false; // valid by default\n }\n}\n"]}