@solidxai/core 0.1.10-beta.15 → 0.1.10-beta.21

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 (116) hide show
  1. package/dist/commands/test-data.command.d.ts +2 -0
  2. package/dist/commands/test-data.command.d.ts.map +1 -1
  3. package/dist/commands/test-data.command.js +32 -6
  4. package/dist/commands/test-data.command.js.map +1 -1
  5. package/dist/controllers/chatter-message.controller.d.ts +2 -0
  6. package/dist/controllers/chatter-message.controller.d.ts.map +1 -1
  7. package/dist/controllers/chatter-message.controller.js +17 -0
  8. package/dist/controllers/chatter-message.controller.js.map +1 -1
  9. package/dist/controllers/gupshup-webhook.controller.d.ts +11 -0
  10. package/dist/controllers/gupshup-webhook.controller.d.ts.map +1 -0
  11. package/dist/controllers/gupshup-webhook.controller.js +87 -0
  12. package/dist/controllers/gupshup-webhook.controller.js.map +1 -0
  13. package/dist/controllers/meta-cloud-whatsapp-webhook.controller.d.ts +16 -0
  14. package/dist/controllers/meta-cloud-whatsapp-webhook.controller.d.ts.map +1 -0
  15. package/dist/controllers/meta-cloud-whatsapp-webhook.controller.js +133 -0
  16. package/dist/controllers/meta-cloud-whatsapp-webhook.controller.js.map +1 -0
  17. package/dist/dtos/update-chatter-note-message.dto.d.ts +5 -0
  18. package/dist/dtos/update-chatter-note-message.dto.d.ts.map +1 -0
  19. package/dist/dtos/update-chatter-note-message.dto.js +34 -0
  20. package/dist/dtos/update-chatter-note-message.dto.js.map +1 -0
  21. package/dist/factories/whatsapp.factory.d.ts.map +1 -1
  22. package/dist/factories/whatsapp.factory.js +13 -11
  23. package/dist/factories/whatsapp.factory.js.map +1 -1
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -0
  27. package/dist/index.js.map +1 -1
  28. package/dist/interfaces.d.ts +1 -0
  29. package/dist/interfaces.d.ts.map +1 -1
  30. package/dist/interfaces.js.map +1 -1
  31. package/dist/listeners/user-registration.listener.d.ts +5 -2
  32. package/dist/listeners/user-registration.listener.d.ts.map +1 -1
  33. package/dist/listeners/user-registration.listener.js +37 -4
  34. package/dist/listeners/user-registration.listener.js.map +1 -1
  35. package/dist/seeders/module-test-data.service.d.ts +2 -0
  36. package/dist/seeders/module-test-data.service.d.ts.map +1 -1
  37. package/dist/seeders/module-test-data.service.js +61 -0
  38. package/dist/seeders/module-test-data.service.js.map +1 -1
  39. package/dist/seeders/seed-data/solid-core-metadata.json +1 -0
  40. package/dist/services/authentication.service.d.ts +6 -1
  41. package/dist/services/authentication.service.d.ts.map +1 -1
  42. package/dist/services/authentication.service.js +144 -14
  43. package/dist/services/authentication.service.js.map +1 -1
  44. package/dist/services/chatter-message.service.d.ts +7 -1
  45. package/dist/services/chatter-message.service.d.ts.map +1 -1
  46. package/dist/services/chatter-message.service.js +94 -2
  47. package/dist/services/chatter-message.service.js.map +1 -1
  48. package/dist/services/mediaStorageProviders/file-s3-storage-provider.d.ts +1 -0
  49. package/dist/services/mediaStorageProviders/file-s3-storage-provider.d.ts.map +1 -1
  50. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js +11 -0
  51. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
  52. package/dist/services/mediaStorageProviders/file-storage-provider.d.ts +1 -0
  53. package/dist/services/mediaStorageProviders/file-storage-provider.d.ts.map +1 -1
  54. package/dist/services/mediaStorageProviders/file-storage-provider.js +6 -0
  55. package/dist/services/mediaStorageProviders/file-storage-provider.js.map +1 -1
  56. package/dist/services/settings/default-settings-provider.service.d.ts +174 -0
  57. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  58. package/dist/services/settings/default-settings-provider.service.js +98 -0
  59. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  60. package/dist/services/user.service.js +1 -1
  61. package/dist/services/user.service.js.map +1 -1
  62. package/dist/services/whatsapp/GupshupOtpWhatsappService.d.ts +11 -0
  63. package/dist/services/whatsapp/GupshupOtpWhatsappService.d.ts.map +1 -0
  64. package/dist/services/whatsapp/GupshupOtpWhatsappService.js +127 -0
  65. package/dist/services/whatsapp/GupshupOtpWhatsappService.js.map +1 -0
  66. package/dist/services/whatsapp/MetaCloudWhatsappService.d.ts +17 -0
  67. package/dist/services/whatsapp/MetaCloudWhatsappService.d.ts.map +1 -0
  68. package/dist/services/whatsapp/MetaCloudWhatsappService.js +209 -0
  69. package/dist/services/whatsapp/MetaCloudWhatsappService.js.map +1 -0
  70. package/dist/solid-core.module.d.ts +2 -2
  71. package/dist/solid-core.module.d.ts.map +1 -1
  72. package/dist/solid-core.module.js +14 -6
  73. package/dist/solid-core.module.js.map +1 -1
  74. package/dist-tests/api/authenticate.spec.js +119 -0
  75. package/dist-tests/api/authenticate.spec.js.map +1 -0
  76. package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +97 -0
  77. package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +1 -0
  78. package/dist-tests/api/ping.spec.js +21 -0
  79. package/dist-tests/api/ping.spec.js.map +1 -0
  80. package/dist-tests/helpers/auth.js +41 -0
  81. package/dist-tests/helpers/auth.js.map +1 -0
  82. package/dist-tests/helpers/env.js +11 -0
  83. package/dist-tests/helpers/env.js.map +1 -0
  84. package/docs/grouping-enhancements.md +89 -0
  85. package/docs/java-spring/README.md +3 -0
  86. package/docs/java-spring/solid-core-module-deep-dive-report.md +1317 -0
  87. package/docs/seed-changes.md +65 -0
  88. package/docs/test-data-workflow.md +200 -0
  89. package/docs/type-declaration-import-issue.md +24 -0
  90. package/package.json +1 -1
  91. package/src/commands/test-data.command.ts +29 -6
  92. package/src/controllers/chatter-message.controller.ts +12 -0
  93. package/src/controllers/gupshup-webhook.controller.ts +91 -0
  94. package/src/controllers/meta-cloud-whatsapp-webhook.controller.ts +155 -0
  95. package/src/dtos/update-chatter-note-message.dto.ts +14 -0
  96. package/src/factories/whatsapp.factory.ts +33 -32
  97. package/src/helpers/field-crud-managers/field-quality-check-fixes.md +178 -0
  98. package/src/index.ts +2 -0
  99. package/src/interfaces.ts +1 -1
  100. package/src/listeners/user-registration.listener.ts +49 -6
  101. package/src/seeders/module-test-data.service.ts +79 -2
  102. package/src/seeders/seed-data/solid-core-metadata.json +1 -0
  103. package/src/services/authentication.service.ts +281 -46
  104. package/src/services/chatter-message.service.ts +112 -2
  105. package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +12 -0
  106. package/src/services/mediaStorageProviders/file-storage-provider.ts +8 -1
  107. package/src/services/settings/default-settings-provider.service.ts +98 -0
  108. package/src/services/user.service.ts +1 -1
  109. package/src/services/whatsapp/GupshupOtpWhatsappService.ts +174 -0
  110. package/src/services/whatsapp/MetaCloudWhatsappService.ts +253 -0
  111. package/src/solid-core.module.ts +205 -196
  112. package/src/testing/README.md +15 -0
  113. package/.claude/settings.local.json +0 -15
  114. package/CLAUDE.md +0 -18
  115. package/CURRENT_PROMPT +0 -6
  116. package/src/services/1.js +0 -6
@@ -1,42 +1,43 @@
1
- import { Inject, Injectable, Logger } from "@nestjs/common";
2
- import { ConfigType } from "@nestjs/config";
1
+ import { Injectable, Logger } from "@nestjs/common";
3
2
  import { ModuleRef } from "@nestjs/core";
4
3
  import { SolidRegistry } from "src/helpers/solid-registry";
5
4
  import { IWhatsAppTransport } from "src/interfaces";
6
5
  import { SettingService } from "src/services/setting.service";
7
6
  import type { SolidCoreSetting } from "src/services/settings/default-settings-provider.service";
8
7
 
9
- function norm(s?: string) {
10
- return s?.trim().toLowerCase();
11
- }
12
-
13
- // This factory will be use to return a mail service instance, using the configured environment variables
14
8
  @Injectable()
15
9
  export class WhatsAppFactory {
16
- private readonly logger = new Logger(this.constructor.name);
17
- constructor(
18
- private readonly moduleRef: ModuleRef, // Use the module ref to dynamically resolve the mail service
19
- private readonly solidRegistry: SolidRegistry,
20
- private readonly settingService: SettingService,
21
- ) { }
22
-
23
- getWhatsappService(name: string = null): IWhatsAppTransport {
24
- // This is the default provider
25
- const whatsappServiceName = name || this.settingService.getConfigValue<SolidCoreSetting>("whatsappProvider");
26
- if (!whatsappServiceName) {
27
- throw new Error("Unable to resolve whatsapp provider")
28
- }
29
- const whatsappProviders = this.solidRegistry.getWhatsappProviders();
30
-
31
- // Return the instance which matches the whatsappServiceName
32
- if (!whatsappProviders.length) {
33
- // throw new Error("No mail providers are registered.");
34
- this.logger.error("No whatsapp providers are registered.");
35
- }
36
-
37
- const whatsappServiceProvider = whatsappProviders.find(provider => provider.name === whatsappServiceName);
38
-
39
- return whatsappServiceProvider.instance as IWhatsAppTransport;
10
+ private readonly logger = new Logger(WhatsAppFactory.name);
11
+
12
+ constructor(
13
+ private readonly moduleRef: ModuleRef,
14
+ private readonly solidRegistry: SolidRegistry,
15
+ private readonly settingService: SettingService,
16
+ ) {}
17
+
18
+ getWhatsappService(name?: string): IWhatsAppTransport {
19
+ const providerKey =
20
+ name ||
21
+ this.settingService.getConfigValue<SolidCoreSetting>("whatsappProvider");
22
+
23
+ if (!providerKey) {
24
+ throw new Error("Unable to resolve whatsapp provider");
25
+ }
26
+
27
+ const whatsappProviders = this.solidRegistry.getWhatsappProviders();
28
+
29
+ if (!whatsappProviders.length) {
30
+ throw new Error("No whatsapp providers are registered.");
31
+ }
32
+
33
+ const whatsappServiceProvider = whatsappProviders.find((provider) =>
34
+ provider.name?.toLowerCase().includes(providerKey.toLowerCase()),
35
+ );
36
+
37
+ if (!whatsappServiceProvider) {
38
+ throw new Error(`WhatsApp provider '${providerKey}' not found`);
40
39
  }
41
40
 
42
- }
41
+ return whatsappServiceProvider.instance as IWhatsAppTransport;
42
+ }
43
+ }
@@ -0,0 +1,178 @@
1
+ # Field Quality Checks And Fixes
2
+
3
+ This checklist tracks backend issues and logical enhancements for each field type in `solid-core-module`.
4
+
5
+ Use it for backend concerns only:
6
+
7
+ - CRUD validation
8
+ - transformation and normalization
9
+ - persistence behavior
10
+ - relation semantics
11
+ - field-level correctness and consistency
12
+
13
+ Frontend widget and rendering concerns belong in `solid-core-ui`.
14
+
15
+ ## `shortText`
16
+
17
+ - [ ] Resolve the `length` versus `max` contract for `shortText` and document one clear meaning for each attribute.
18
+ - [ ] Decide whether backend validation should also enforce `min`, so `shortText` constraints remain consistent even outside generated form flows.
19
+ - [ ] Return the configured regex mismatch message when `regexPatternNotMatchingErrorMsg` is present instead of always using a generic regex error.
20
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits a `shortText` field.
21
+ - [ ] Decide whether `shortText` should support optional normalization such as trimming or whitespace collapsing, and keep that decision consistent across comparable text field types.
22
+ - [ ] Review whether uniqueness should receive any pre-save validation support at the CRUD layer or continue to rely entirely on persistence-layer constraints.
23
+ - [ ] Add targeted coverage for partial update behavior, empty string versus null handling, regex validation, and max-length enforcement.
24
+ - [ ] Review whether the text-oriented managers share enough behavior to justify a common validation utility or base manager without weakening field-specific semantics.
25
+
26
+ ## `longText`
27
+
28
+ - [ ] Decide whether backend validation should also enforce `min` and `max`, so `longText` constraints remain consistent outside generated form flows.
29
+ - [ ] Return the configured regex mismatch message when `regexPatternNotMatchingErrorMsg` is present instead of always using a generic regex error.
30
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits a `longText` field.
31
+ - [ ] Decide whether `longText` should support optional normalization such as trimming trailing whitespace while preserving intentional line breaks.
32
+ - [ ] Review whether uniqueness should receive any pre-save validation support at the CRUD layer or continue to rely entirely on persistence-layer constraints.
33
+ - [ ] Add targeted coverage for multiline content, regex validation, partial updates, and empty string versus null handling.
34
+ - [ ] Review whether the text-oriented managers share enough behavior to justify a common validation utility or base manager without weakening field-specific semantics.
35
+
36
+ ## `richText`
37
+
38
+ - [ ] Decide whether backend validation should also enforce `min` and `max`, so `richText` constraints remain consistent outside generated form flows.
39
+ - [ ] Return the configured regex mismatch message when `regexPatternNotMatchingErrorMsg` is present instead of always using a generic regex error.
40
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits a `richText` field.
41
+ - [ ] Decide whether `richText` should support optional normalization or sanitization at save time, and define that behavior explicitly.
42
+ - [ ] Review whether uniqueness should receive any pre-save validation support at the CRUD layer or continue to rely entirely on persistence-layer constraints.
43
+ - [ ] Add targeted coverage for rich HTML-like content, regex validation, partial updates, and empty string versus null handling.
44
+ - [ ] Review whether the text-oriented managers share enough behavior to justify a common validation utility or base manager without weakening field-specific semantics.
45
+
46
+ ## `json`
47
+
48
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits a `json` field.
49
+ - [ ] Decide whether backend validation should accept only stringified JSON or also handle already-parsed object and array payloads more explicitly.
50
+ - [ ] Review whether the current JSON validation error should distinguish between invalid JSON syntax and unsupported runtime value shapes.
51
+ - [ ] Decide whether normalization or canonical stringification should happen before persistence for comparable JSON values.
52
+ - [ ] Review whether uniqueness should receive any pre-save validation support at the CRUD layer or continue to rely entirely on persistence-layer constraints.
53
+ - [ ] Add targeted coverage for object payloads, array payloads, stringified JSON payloads, invalid JSON, partial updates, and empty string versus null handling.
54
+
55
+ ## `int`
56
+
57
+ - [ ] Fix the current min/max activation rule, because backend validation only applies numeric bounds when the configured value is greater than `0`, which skips valid `0` and negative thresholds.
58
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits an `int` field.
59
+ - [ ] Decide whether the CRUD layer should normalize numeric strings into integers more explicitly before validation and persistence.
60
+ - [ ] Review whether integer fields should reject decimal-shaped inputs more clearly when values arrive from metadata-driven clients as strings.
61
+ - [ ] Review whether uniqueness should receive any pre-save validation support at the CRUD layer or continue to rely entirely on persistence-layer constraints.
62
+ - [ ] Add targeted coverage for `0`, negative values, numeric strings, invalid decimal-like input, min/max bounds, and partial update behavior.
63
+
64
+
65
+ ## `bigint`
66
+
67
+ - [ ] Clarify the authored support surface for `bigint`, because the CRUD manager contains numeric bound logic while the authored field surface does not currently present `min` and `max` in the same way as `int` and `decimal`.
68
+ - [ ] Fix or clarify the current numeric-bound activation rule if bigint bounds are intended to be supported, since the logic only applies bounds when the configured value is greater than `0`.
69
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits a `bigint` field.
70
+ - [ ] Decide what the canonical runtime contract should be for bigint inputs: native `bigint`, numeric strings, or finite JavaScript numbers.
71
+ - [ ] Review whether accepting finite JavaScript numbers for bigint validation is sufficient when exact large-integer fidelity matters.
72
+ - [ ] Review whether uniqueness should receive any pre-save validation support at the CRUD layer or continue to rely entirely on persistence-layer constraints.
73
+ - [ ] Add targeted coverage for numeric strings, very large values, invalid numeric input, bound handling, null handling, and partial update behavior.
74
+
75
+
76
+ ## `decimal`
77
+
78
+ - [ ] Fix the current min/max activation rule, because backend validation only applies numeric bounds when the configured value is greater than `0`, which skips valid `0` and negative thresholds.
79
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits a `decimal` field.
80
+ - [ ] Decide whether the CRUD layer should normalize numeric strings into decimal numbers more explicitly before validation and persistence.
81
+ - [ ] Review whether decimal fields need an explicit precision-and-scale contract instead of relying entirely on the persistence-layer `ormType`.
82
+ - [ ] Review whether uniqueness should receive any pre-save validation support at the CRUD layer or continue to rely entirely on persistence-layer constraints.
83
+ - [ ] Add targeted coverage for `0`, negative values, fractional values, numeric strings, invalid numeric input, min/max bounds, and partial update behavior.
84
+
85
+
86
+ ## `boolean`
87
+
88
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits a `boolean` field.
89
+ - [ ] Decide whether boolean CRUD validation should accept only runtime booleans or also normalize `"true"` and `"false"` string payloads when they arrive from metadata-driven clients.
90
+ - [ ] Review whether the required validation path should distinguish more clearly between an omitted value and an explicit `false` value, especially for partial updates.
91
+ - [ ] Review whether uniqueness should receive any pre-save validation support at the CRUD layer or continue to rely entirely on persistence-layer constraints.
92
+ - [ ] Add targeted coverage for `true`, `false`, null, empty string, string booleans, and partial update behavior.
93
+
94
+ ## `date`
95
+
96
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits a `date` field.
97
+ - [ ] Review whether the CRUD layer should accept only runtime `Date` objects or also normalize common serialized date inputs more explicitly before validation.
98
+ - [ ] Decide whether `date` and `datetime` should continue to share the same backend validation path or receive more distinct normalization and validation behavior.
99
+ - [ ] Review whether uniqueness should receive any pre-save validation support at the CRUD layer or continue to rely entirely on persistence-layer constraints.
100
+ - [ ] Add targeted coverage for `Date` objects, serialized date strings, null handling, invalid date inputs, and partial update behavior.
101
+
102
+ ## `datetime`
103
+
104
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits a `datetime` field.
105
+ - [ ] Review whether the CRUD layer should accept only runtime `Date` objects or also normalize common serialized datetime inputs more explicitly before validation.
106
+ - [ ] Decide whether `date` and `datetime` should continue to share the same backend validation path or receive more distinct normalization and validation behavior.
107
+ - [ ] Review whether timezone normalization rules should be documented and enforced more explicitly at save time.
108
+ - [ ] Review whether uniqueness should receive any pre-save validation support at the CRUD layer or continue to rely entirely on persistence-layer constraints.
109
+ - [ ] Add targeted coverage for `Date` objects, serialized datetime strings, null handling, timezone-sensitive values, invalid datetime inputs, and partial update behavior.
110
+
111
+ ## `time`
112
+
113
+ - [ ] Add an explicit CRUD-manager path for `SolidFieldType.time`, since the field currently has core UI support but is not routed through a dedicated backend field manager.
114
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits a `time` field.
115
+ - [ ] Decide what canonical persisted shape `time` should use: pure time string, database-native time value, or a normalized timestamp-derived representation.
116
+ - [ ] Review whether the CRUD layer should normalize common time inputs such as `HH:mm:ss`, ISO timestamps, and UI-submitted values more explicitly before validation and persistence.
117
+ - [ ] Review whether uniqueness should receive any pre-save validation support at the CRUD layer or continue to rely entirely on persistence-layer constraints.
118
+ - [ ] Add targeted coverage for `HH:mm:ss` inputs, ISO-style inputs, invalid time values, null handling, and partial update behavior.
119
+
120
+ ## `email`
121
+
122
+ - [ ] Decide whether backend validation should also enforce `min`, so email constraints remain consistent outside generated form flows.
123
+ - [ ] Return the configured regex mismatch message when `regexPatternNotMatchingErrorMsg` is present instead of always using a generic regex error.
124
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits an `email` field.
125
+ - [ ] Decide whether email values should support optional normalization such as trimming and lowercasing before persistence.
126
+ - [ ] Review whether uniqueness should receive any pre-save validation support at the CRUD layer or continue to rely entirely on persistence-layer constraints.
127
+ - [ ] Add targeted coverage for max-length enforcement, regex overrides, invalid email formats, null handling, and partial update behavior.
128
+
129
+ ## `password`
130
+
131
+ - [ ] Return the configured regex mismatch message when `regexPatternNotMatchingErrorMsg` is present instead of always using a generic password-regex error.
132
+ - [ ] Review whether password validation should produce clearer error messages for min, max, regex, and confirm-password mismatch failures.
133
+ - [ ] Clarify and implement the expected behavior for `defaultValue` on password fields, including whether it should be ignored entirely for secure create flows.
134
+ - [ ] Review whether password hashing and password-update flows should share a more explicit single contract across create and update operations.
135
+ - [ ] Decide whether password normalization should include trimming or whether exact raw user input should always be preserved before hashing.
136
+ - [ ] Add targeted coverage for create-required behavior, update-optional behavior, confirm-password mismatch, hashing behavior, regex fallback behavior, and partial update behavior.
137
+
138
+ ## `selectionStatic`
139
+
140
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits a `selectionStatic` field, especially for multi-select fields.
141
+ - [ ] Decide whether the CRUD layer should normalize single-select and multi-select payloads into one consistent stored shape before persistence.
142
+ - [ ] Review whether the current `selectionStaticValues` parsing should validate malformed `value:label` entries more explicitly instead of assuming a valid authored format.
143
+ - [ ] Add clearer error messaging when the submitted value has the wrong type versus when it is simply not part of the authored option set.
144
+ - [ ] Review whether numeric selection values need more explicit normalization, especially when values can arrive as strings from metadata-driven clients.
145
+ - [ ] Add targeted coverage for single-select string values, single-select numeric values, JSON-stringified multi-select arrays, invalid option tokens, malformed arrays, and partial update behavior.
146
+
147
+ ## `selectionDynamic`
148
+
149
+ - [ ] Clarify and implement the expected behavior for `defaultValue` when a create payload omits a `selectionDynamic` field, especially for multi-select fields.
150
+ - [ ] Review whether the CRUD layer should normalize single-select and multi-select payloads into one consistent stored shape before persistence.
151
+ - [ ] Add clearer error messaging when the submitted value has the wrong type, when the provider rejects the value, and when the provider itself cannot be resolved.
152
+ - [ ] Review whether numeric selection values need more explicit normalization, especially when values can arrive as strings from metadata-driven clients.
153
+ - [ ] Clarify how `validateOnSave` in `selectionDynamicProviderCtxt` should be treated as part of the supported field contract and whether more provider-context keys should be validated.
154
+ - [ ] Add targeted coverage for provider-backed single-select values, JSON-stringified multi-select arrays, invalid provider names, `validateOnSave: false`, invalid option values, and partial update behavior.
155
+
156
+ ## `many-to-one`
157
+
158
+ - [ ] Review pending.
159
+
160
+ ## `one-to-many`
161
+
162
+ - [ ] Review pending.
163
+
164
+ ## `many-to-many`
165
+
166
+ - [ ] Review pending.
167
+
168
+ ## `mediaSingle`
169
+
170
+ - [ ] Review pending.
171
+
172
+ ## `mediaMultiple`
173
+
174
+ - [ ] Review pending.
175
+
176
+ ## `computed`
177
+
178
+ - [ ] Review pending.
package/src/index.ts CHANGED
@@ -29,6 +29,7 @@ export * from './decorators/settings-provider.decorator'
29
29
  export * from './decorators/extension-user-creation-provider.decorator'
30
30
 
31
31
  export * from './dtos/post-chatter-message.dto'
32
+ export * from './dtos/update-chatter-note-message.dto'
32
33
  export * from './dtos/security-rule-config.dto'
33
34
  export * from './dtos/basic-filters.dto'
34
35
  export * from './dtos/solid-request-context.dto'
@@ -322,6 +323,7 @@ export * from './services/solid-introspect.service'
322
323
  export * from './services/user.service'
323
324
  export * from './services/view-metadata.service'
324
325
  export * from './services/whatsapp/Msg91WhatsappService' //rename
326
+ export * from './services/whatsapp/GupshupOtpWhatsappService'
325
327
  export * from './services/setting.service'
326
328
  export * from './services/encryption.service'
327
329
  export * from './services/info.service'
package/src/interfaces.ts CHANGED
@@ -42,6 +42,7 @@ export interface ValidationError {
42
42
  export interface MediaStorageProvider<T> {
43
43
  store(files: Express.Multer.File[], entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]>;
44
44
  delete(entity: T, mediaFieldMetadata: FieldMetadata): Promise<void>;
45
+ deleteByMediaRecord(media: Media): Promise<void>;
45
46
  retrieve(entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]>;
46
47
  storeStreams(streamPairs: [Readable, string][], entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]>;
47
48
  // delete(file: string): Promise<void>;
@@ -448,4 +449,3 @@ export interface AuditQueuePayload {
448
449
  updatedColumnNames?: string[];
449
450
  userId?: number | null;
450
451
  }
451
-
@@ -1,14 +1,57 @@
1
-
2
1
  import { User } from "../entities/user.entity";
3
2
  import { OnEvent } from "@nestjs/event-emitter";
4
3
  import { Injectable, Logger } from "@nestjs/common";
5
4
  import { EventDetails, EventType } from "../interfaces";
5
+ import { WhatsAppFactory } from "src/factories/whatsapp.factory";
6
6
 
7
7
  @Injectable()
8
8
  export class UserRegistrationListener {
9
- private logger = new Logger(UserRegistrationListener.name);
10
- @OnEvent(EventType.USER_REGISTERED)
11
- handleUserRegistration(event: EventDetails<User>) {
12
- this.logger.log(`User registered with details: ${JSON.stringify(event.payload)}`);
9
+ private readonly logger = new Logger(UserRegistrationListener.name);
10
+
11
+ constructor(private readonly whatsAppFactory: WhatsAppFactory) {}
12
+
13
+ @OnEvent(EventType.USER_REGISTERED)
14
+ async handleUserRegistration(event: EventDetails<User>) {
15
+ this.logger.log(`User registered with details: ${JSON.stringify(event.payload)}`);
16
+
17
+ const notifyTo = process.env.WHATSAPP_EVENT_NOTIFY_TO;
18
+ if (!notifyTo) {
19
+ this.logger.debug("WHATSAPP_EVENT_NOTIFY_TO not set. Skipping registration WhatsApp notification.");
20
+ return;
21
+ }
22
+
23
+ try {
24
+ const whatsappService = this.whatsAppFactory.getWhatsappService();
25
+ const username = event.payload?.username || "User";
26
+ const userId = event.payload?.id || "N/A";
27
+
28
+ await whatsappService.sendWhatsAppMessage(
29
+ notifyTo,
30
+ "registration_event",
31
+ {
32
+ payload: {
33
+ channel: "whatsapp",
34
+ source: process.env.COMMON_GUPSHUP_WHATSAPP_SOURCE,
35
+ destination: notifyTo,
36
+ "src.name": process.env.COMMON_GUPSHUP_APP_NAME || "solidx",
37
+ message: {
38
+ type: "text",
39
+ text: `New user registered: ${username} (id: ${userId})`,
40
+ },
41
+ },
42
+ },
43
+ );
44
+
45
+ this.logger.log(`Sent registration WhatsApp notification to ${notifyTo}`);
46
+ } catch (error: any) {
47
+ const status = error?.response?.status;
48
+ const responseData = error?.response?.data;
49
+ const errorMessage = error?.message;
50
+ const stack = error?.stack;
51
+
52
+ this.logger.error(
53
+ `Failed to send registration WhatsApp notification to ${notifyTo}. status=${status ?? "unknown"}, response=${typeof responseData === "object" ? JSON.stringify(responseData) : responseData}, message=${errorMessage}, stack=${stack}`,
54
+ );
13
55
  }
14
- }
56
+ }
57
+ }
@@ -19,7 +19,7 @@ import { ModelMetadataService } from 'src/services/model-metadata.service';
19
19
  import { RoleMetadataService } from 'src/services/role-metadata.service';
20
20
  import { UserService } from 'src/services/user.service';
21
21
  import { getMediaStorageProvider } from 'src/services/mediaStorageProviders';
22
- import { TestingRoleSpec, TestingUserSpec } from 'src/testing/contracts/testing-metadata.types';
22
+ import { TestingDataRecord, TestingRoleSpec, TestingUserSpec } from 'src/testing/contracts/testing-metadata.types';
23
23
 
24
24
  @Injectable()
25
25
  export class ModuleTestDataService {
@@ -51,6 +51,25 @@ export class ModuleTestDataService {
51
51
  }
52
52
  }
53
53
 
54
+ async removeTestData(modulesToTest?: string[]): Promise<void> {
55
+ const testDataFiles = this.testDataFiles;
56
+ const filteredFiles = modulesToTest?.length ? testDataFiles.filter((file) => modulesToTest.includes(file.moduleMetadata?.name)) : testDataFiles;
57
+
58
+ if (filteredFiles.length === 0) {
59
+ this.logger.warn('No modules matched the provided modulesToTest list.');
60
+ console.log('No modules matched the provided modulesToTest list.');
61
+ return;
62
+ }
63
+
64
+ for (const overallMetadata of filteredFiles) {
65
+ const moduleName = overallMetadata?.moduleMetadata?.name ?? 'unknown';
66
+ this.logger.log(`Removing test data for module: ${moduleName}`);
67
+ console.log(`Removing test data for module: ${moduleName}`);
68
+ await this.unlinkTestData(overallMetadata);
69
+ console.log(`✔ Test data unlink complete for module: ${moduleName}`);
70
+ }
71
+ }
72
+
54
73
  async createTestDatasources(): Promise<void> {
55
74
  const manifestPath = path.join(process.cwd(), '.solidx-test-manifest');
56
75
  if (fs.existsSync(manifestPath)) {
@@ -199,7 +218,7 @@ export class ModuleTestDataService {
199
218
 
200
219
  const testingRoles: TestingRoleSpec[] = overallMetadata?.testing?.roles ?? [];
201
220
  const testingUsers: TestingUserSpec[] = overallMetadata?.testing?.users ?? [];
202
- const testingData: Array<{ modelUserKey: string; data: Record<string, any> }> = overallMetadata?.testing?.data ?? [];
221
+ const testingData: TestingDataRecord[] = overallMetadata?.testing?.data ?? [];
203
222
 
204
223
  if (testingRoles.length > 0) {
205
224
  await this.seedTestRoles(testingRoles);
@@ -290,16 +309,21 @@ export class ModuleTestDataService {
290
309
  // Upsert entity, capturing the saved result for post-save steps
291
310
  let savedEntity: any;
292
311
  const userKeyField = modelDef.userKeyFieldUserKey;
312
+ const recordUserKeyValue = entry.recUserKeyValue ?? payload[userKeyField];
313
+ const recordLabel = `${modelUserKey}.${userKeyField}=${recordUserKeyValue}`;
293
314
  if (userKeyField && payload[userKeyField] !== undefined) {
294
315
  const existing = await entityRepo.findOne({
295
316
  where: { [userKeyField]: payload[userKeyField] },
296
317
  });
297
318
  if (existing) {
319
+ console.log(`Updating test data record: ${recordLabel}`);
298
320
  savedEntity = await entityRepo.save(entityRepo.merge(existing, payload));
299
321
  } else {
322
+ console.log(`Creating test data record: ${recordLabel}`);
300
323
  savedEntity = await entityRepo.save(entityRepo.create(payload));
301
324
  }
302
325
  } else {
326
+ console.log(`Creating test data record without user key lookup: ${modelUserKey}`);
303
327
  savedEntity = await entityRepo.save(entityRepo.create(payload));
304
328
  }
305
329
 
@@ -313,6 +337,59 @@ export class ModuleTestDataService {
313
337
  }
314
338
  }
315
339
 
340
+ private async unlinkTestData(overallMetadata: any): Promise<void> {
341
+ const moduleMetadata: CreateModuleMetadataDto = overallMetadata.moduleMetadata;
342
+ if (!moduleMetadata) {
343
+ throw new Error('Module metadata missing from test data payload.');
344
+ }
345
+
346
+ const testingData: TestingDataRecord[] = overallMetadata?.testing?.data ?? [];
347
+ if (testingData.length === 0) {
348
+ this.logger.debug(`No test data found for ${moduleMetadata.name}`);
349
+ return;
350
+ }
351
+
352
+ const modelsByName = new Map<string, CreateModelMetadataDto>(
353
+ (moduleMetadata.models ?? []).map((m) => [m.singularName, m]),
354
+ );
355
+
356
+ for (const entry of [...testingData].reverse()) {
357
+ const modelUserKey = entry.modelUserKey;
358
+ const modelDef = modelsByName.get(modelUserKey);
359
+ if (!modelDef) {
360
+ throw new Error(`Test data modelUserKey not found in metadata: ${modelUserKey}`);
361
+ }
362
+
363
+ const userKeyField = modelDef.userKeyFieldUserKey;
364
+ if (!userKeyField) {
365
+ throw new Error(`Cannot unlink test data for model ${modelUserKey} because userKeyFieldUserKey is not configured.`);
366
+ }
367
+
368
+ const userKeyValue = entry.data?.[userKeyField];
369
+ if (userKeyValue === undefined || userKeyValue === null || userKeyValue === '') {
370
+ throw new Error(
371
+ `Cannot unlink test data for model ${modelUserKey} because testing.data entry is missing the actual user key field "${userKeyField}" in data.`,
372
+ );
373
+ }
374
+ const recordLabel = `${modelUserKey}.${userKeyField}=${userKeyValue}`;
375
+
376
+ const entityRepo = this.resolveRepository(modelUserKey);
377
+ const existing = typeof entityRepo.findOneByUserKey === 'function'
378
+ ? await entityRepo.findOneByUserKey(userKeyValue)
379
+ : await entityRepo.findOne({ where: { [userKeyField]: userKeyValue } });
380
+
381
+ if (!existing) {
382
+ console.log(`Skipping unlink; test data record not found: ${recordLabel}`);
383
+ this.logger.debug(`Test data record not found for unlink: ${modelUserKey}.${userKeyField}=${userKeyValue}`);
384
+ continue;
385
+ }
386
+
387
+ console.log(`Deleting test data record: ${recordLabel}`);
388
+ await entityRepo.remove(existing);
389
+ this.logger.debug(`Removed test data record: ${modelUserKey}.${userKeyField}=${userKeyValue}`);
390
+ }
391
+ }
392
+
316
393
  private async seedTestRoles(roles: TestingRoleSpec[]): Promise<void> {
317
394
  const roleService = this.moduleRef.get(RoleMetadataService, { strict: false });
318
395
  if (!roleService) {
@@ -6191,6 +6191,7 @@
6191
6191
  "ChatterMessageController.postMessage",
6192
6192
  "ChatterMessageController.findMany",
6193
6193
  "ChatterMessageController.markCompleted",
6194
+ "ChatterMessageController.updateCustomNoteMessage",
6194
6195
  "ImportTransactionController.getImportTemplate",
6195
6196
  "ImportTransactionController.getImportInstructions",
6196
6197
  "ImportTransactionController.getImportMappingInfo",