@adminide-stack/marketplace-module-server 12.0.4-alpha.41 → 12.0.4-alpha.412

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 (185) hide show
  1. package/Readme.md +321 -0
  2. package/lib/containers/module.d.ts +8 -0
  3. package/lib/containers/module.d.ts.map +1 -1
  4. package/lib/containers/module.js +15 -5
  5. package/lib/containers/module.js.map +1 -1
  6. package/lib/dataloaders/index.d.ts +1 -0
  7. package/lib/dataloaders/index.d.ts.map +1 -0
  8. package/lib/demo/test-graphql-examples.d.ts +73 -0
  9. package/lib/demo/test-graphql-examples.d.ts.map +1 -0
  10. package/lib/graphql/resolvers/form-templates-resolver.d.ts +220 -0
  11. package/lib/graphql/resolvers/form-templates-resolver.d.ts.map +1 -0
  12. package/lib/graphql/resolvers/form-templates-resolver.js +170 -0
  13. package/lib/graphql/resolvers/form-templates-resolver.js.map +1 -0
  14. package/lib/graphql/resolvers/gallery-resolver.d.ts +15 -0
  15. package/lib/graphql/resolvers/gallery-resolver.d.ts.map +1 -0
  16. package/lib/graphql/resolvers/gallery-resolver.js +35 -0
  17. package/lib/graphql/resolvers/gallery-resolver.js.map +1 -0
  18. package/lib/graphql/resolvers/index.d.ts +247 -1
  19. package/lib/graphql/resolvers/index.d.ts.map +1 -1
  20. package/lib/graphql/resolvers/index.js +1 -0
  21. package/lib/graphql/resolvers/index.js.map +1 -0
  22. package/lib/graphql/resolvers/installed-extension-resolver.d.ts +5 -0
  23. package/lib/graphql/resolvers/installed-extension-resolver.d.ts.map +1 -0
  24. package/lib/graphql/resolvers/installed-extension-resolver.js +289 -0
  25. package/lib/graphql/resolvers/installed-extension-resolver.js.map +1 -0
  26. package/lib/graphql/resolvers/marketplace-form-resolver.d.ts +13 -0
  27. package/lib/graphql/resolvers/marketplace-form-resolver.d.ts.map +1 -0
  28. package/lib/graphql/resolvers/marketplace-form-resolver.js +90 -0
  29. package/lib/graphql/resolvers/marketplace-form-resolver.js.map +1 -0
  30. package/lib/graphql/resolvers/publisher-analytics-resolver.d.ts +14 -0
  31. package/lib/graphql/resolvers/publisher-analytics-resolver.d.ts.map +1 -0
  32. package/lib/graphql/resolvers/publisher-analytics-resolver.js +221 -0
  33. package/lib/graphql/resolvers/publisher-analytics-resolver.js.map +1 -0
  34. package/lib/graphql/resolvers/publisher-resolver.d.ts +5 -0
  35. package/lib/graphql/resolvers/publisher-resolver.d.ts.map +1 -0
  36. package/lib/graphql/resolvers/publisher-resolver.js +176 -0
  37. package/lib/graphql/resolvers/publisher-resolver.js.map +1 -0
  38. package/lib/graphql/resolvers/registry-extension-resolver.d.ts +5 -0
  39. package/lib/graphql/resolvers/registry-extension-resolver.d.ts.map +1 -0
  40. package/lib/graphql/resolvers/registry-extension-resolver.js +46 -0
  41. package/lib/graphql/resolvers/registry-extension-resolver.js.map +1 -0
  42. package/lib/graphql/schemas/extension-pricing.graphql +546 -0
  43. package/lib/graphql/schemas/extension-pricing.graphql.js +1 -0
  44. package/lib/graphql/schemas/extension-pricing.graphql.js.map +1 -0
  45. package/lib/graphql/schemas/extension-registry.graphql +107 -0
  46. package/lib/graphql/schemas/extension-registry.graphql.js +1 -0
  47. package/lib/graphql/schemas/extension-registry.graphql.js.map +1 -0
  48. package/lib/graphql/schemas/form-templates.graphql +269 -0
  49. package/lib/graphql/schemas/form-templates.graphql.js +1 -0
  50. package/lib/graphql/schemas/form-templates.graphql.js.map +1 -0
  51. package/lib/graphql/schemas/gallery-schema.graphql +247 -0
  52. package/lib/graphql/schemas/gallery-schema.graphql.js +1 -0
  53. package/lib/graphql/schemas/gallery-schema.graphql.js.map +1 -0
  54. package/lib/graphql/schemas/index.d.ts.map +1 -1
  55. package/lib/graphql/schemas/index.js +3 -4
  56. package/lib/graphql/schemas/index.js.map +1 -1
  57. package/lib/graphql/schemas/installed-extension.graphql +309 -0
  58. package/lib/graphql/schemas/installed-extension.graphql.js +1 -0
  59. package/lib/graphql/schemas/installed-extension.graphql.js.map +1 -0
  60. package/lib/graphql/schemas/publisher-analytics.graphql +305 -0
  61. package/lib/graphql/schemas/publisher-analytics.graphql.js +1 -0
  62. package/lib/graphql/schemas/publisher-analytics.graphql.js.map +1 -0
  63. package/lib/graphql/schemas/publisher.graphql +376 -0
  64. package/lib/graphql/schemas/publisher.graphql.js +1 -0
  65. package/lib/graphql/schemas/publisher.graphql.js.map +1 -0
  66. package/lib/graphql/schemas/service.graphql +196 -0
  67. package/lib/index.d.ts +3 -1
  68. package/lib/index.d.ts.map +1 -1
  69. package/lib/index.js +1 -1
  70. package/lib/index.js.map +1 -1
  71. package/lib/module.d.ts +1 -1
  72. package/lib/module.d.ts.map +1 -1
  73. package/lib/module.js +10 -23
  74. package/lib/module.js.map +1 -1
  75. package/lib/plugins/extension-moleculer-service.d.ts +86 -0
  76. package/lib/plugins/extension-moleculer-service.d.ts.map +1 -0
  77. package/lib/plugins/index.d.ts +2 -0
  78. package/lib/plugins/index.d.ts.map +1 -0
  79. package/lib/services/extension-gallery-repository.d.ts +17 -0
  80. package/lib/services/extension-gallery-repository.d.ts.map +1 -0
  81. package/lib/services/extension-gallery-repository.js +192 -0
  82. package/lib/services/extension-gallery-repository.js.map +1 -0
  83. package/lib/services/extension-gallery-service-new.d.ts +39 -0
  84. package/lib/services/extension-gallery-service-new.d.ts.map +1 -0
  85. package/lib/services/extension-gallery-service.d.ts +30 -0
  86. package/lib/services/extension-gallery-service.d.ts.map +1 -0
  87. package/lib/services/extension-gallery-service.js +311 -0
  88. package/lib/services/extension-gallery-service.js.map +1 -0
  89. package/lib/services/index.d.ts +6 -1
  90. package/lib/services/index.d.ts.map +1 -1
  91. package/lib/services/installed-extension-service-ext.d.ts +16 -0
  92. package/lib/services/installed-extension-service-ext.d.ts.map +1 -0
  93. package/lib/services/installed-extension-service-ext.js +485 -0
  94. package/lib/services/installed-extension-service-ext.js.map +1 -0
  95. package/lib/services/installed-extension-service.d.ts +96 -0
  96. package/lib/services/installed-extension-service.d.ts.map +1 -0
  97. package/lib/services/installed-extension-service.js +521 -0
  98. package/lib/services/installed-extension-service.js.map +1 -0
  99. package/lib/services/installed-extension-service.test.d.ts +1 -0
  100. package/lib/services/installed-extension-service.test.d.ts.map +1 -0
  101. package/lib/services/publisher-analytics-service.d.ts +128 -0
  102. package/lib/services/publisher-analytics-service.d.ts.map +1 -0
  103. package/lib/services/publisher-event-service.d.ts +48 -0
  104. package/lib/services/publisher-event-service.d.ts.map +1 -0
  105. package/lib/services/publisher-event-service.js +296 -0
  106. package/lib/services/publisher-event-service.js.map +1 -0
  107. package/lib/services/publisher-service-context.d.ts +1 -0
  108. package/lib/services/publisher-service-context.d.ts.map +1 -0
  109. package/lib/services/publisher-service.d.ts +60 -0
  110. package/lib/services/publisher-service.d.ts.map +1 -0
  111. package/lib/services/publisher-service.js +134 -0
  112. package/lib/services/publisher-service.js.map +1 -0
  113. package/lib/store/index.d.ts +1 -1
  114. package/lib/store/index.d.ts.map +1 -1
  115. package/lib/store/models/index.d.ts +2 -1
  116. package/lib/store/models/index.d.ts.map +1 -1
  117. package/lib/store/models/installed-extension-model.d.ts +4 -0
  118. package/lib/store/models/installed-extension-model.d.ts.map +1 -0
  119. package/lib/store/models/installed-extension-model.js +269 -0
  120. package/lib/store/models/installed-extension-model.js.map +1 -0
  121. package/lib/store/models/publisher-event-model.d.ts +11 -0
  122. package/lib/store/models/publisher-event-model.d.ts.map +1 -0
  123. package/lib/store/models/publisher-model.d.ts +5 -0
  124. package/lib/store/models/publisher-model.d.ts.map +1 -0
  125. package/lib/store/models/publisher-model.js +103 -0
  126. package/lib/store/models/publisher-model.js.map +1 -0
  127. package/lib/store/models/publisher-stats-model.d.ts +1 -0
  128. package/lib/store/models/publisher-stats-model.d.ts.map +1 -0
  129. package/lib/store/repositories/index.d.ts +3 -0
  130. package/lib/store/repositories/index.d.ts.map +1 -0
  131. package/lib/store/repositories/installed-extension-repository.d.ts +73 -0
  132. package/lib/store/repositories/installed-extension-repository.d.ts.map +1 -0
  133. package/lib/store/repositories/installed-extension-repository.js +442 -0
  134. package/lib/store/repositories/installed-extension-repository.js.map +1 -0
  135. package/lib/store/repositories/publisher-analytics-repository.d.ts +1 -0
  136. package/lib/store/repositories/publisher-analytics-repository.d.ts.map +1 -0
  137. package/lib/store/repositories/publisher-repository.d.ts +19 -0
  138. package/lib/store/repositories/publisher-repository.d.ts.map +1 -0
  139. package/lib/store/repositories/publisher-repository.js +87 -0
  140. package/lib/store/repositories/publisher-repository.js.map +1 -0
  141. package/lib/templates/constants/DB_COLL_NAMES.ts.template +5 -0
  142. package/lib/templates/constants/SERVER_TYPES.ts.template +10 -4
  143. package/lib/templates/repositories/ExtensionGalleryRepository.ts.template +44 -0
  144. package/lib/templates/repositories/InstalledExtensionRepository.ts.template +94 -0
  145. package/lib/templates/repositories/MarketplacePublisherRepository.ts.template +24 -0
  146. package/lib/templates/repositories/RegistryExtensionRepository.ts.template +10 -15
  147. package/lib/templates/services/ExtensionGalleryDataLoader.ts.template +2 -0
  148. package/lib/templates/services/ExtensionGalleryService.ts.template +79 -0
  149. package/lib/templates/services/InstalledExtensionDataLoader.ts.template +2 -0
  150. package/lib/templates/services/InstalledExtensionService.ts.template +181 -0
  151. package/lib/templates/services/MarketplacePublisherService.ts.template +49 -0
  152. package/lib/templates/services/PublisherEventService.ts.template +56 -0
  153. package/lib/templates/services/RegistryExtensionService.ts.template +62 -18
  154. package/lib/tests/extension-integration.test.d.ts +1 -0
  155. package/lib/tests/extension-integration.test.d.ts.map +1 -0
  156. package/lib/tests/install-extension-graphql.test.d.ts +2 -0
  157. package/lib/tests/install-extension-graphql.test.d.ts.map +1 -0
  158. package/lib/tests/test-extension-services.d.ts +1 -0
  159. package/lib/tests/test-extension-services.d.ts.map +1 -0
  160. package/lib/utils/publisherValidation.d.ts +23 -0
  161. package/lib/utils/publisherValidation.d.ts.map +1 -0
  162. package/lib/utils/publisherValidation.js +144 -0
  163. package/lib/utils/publisherValidation.js.map +1 -0
  164. package/package.json +15 -7
  165. package/lib/graphql/resolvers/resolvers.d.ts +0 -2
  166. package/lib/graphql/resolvers/resolvers.d.ts.map +0 -1
  167. package/lib/graphql/resolvers/resolvers.js +0 -167
  168. package/lib/graphql/resolvers/resolvers.js.map +0 -1
  169. package/lib/graphql/schemas/extension.graphql +0 -57
  170. package/lib/graphql/schemas/extension.graphql.js +0 -1
  171. package/lib/graphql/schemas/extension.graphql.js.map +0 -1
  172. package/lib/services/extension-service.d.ts +0 -54
  173. package/lib/services/extension-service.d.ts.map +0 -1
  174. package/lib/services/extension-service.js +0 -42
  175. package/lib/services/extension-service.js.map +0 -1
  176. package/lib/store/models/registry-extension-model.d.ts +0 -10
  177. package/lib/store/models/registry-extension-model.d.ts.map +0 -1
  178. package/lib/store/models/registry-extension-model.js +0 -62
  179. package/lib/store/models/registry-extension-model.js.map +0 -1
  180. package/lib/store/repository/index.d.ts +0 -2
  181. package/lib/store/repository/index.d.ts.map +0 -1
  182. package/lib/store/repository/registry-extension-repository.d.ts +0 -31
  183. package/lib/store/repository/registry-extension-repository.d.ts.map +0 -1
  184. package/lib/store/repository/registry-extension-repository.js +0 -135
  185. package/lib/store/repository/registry-extension-repository.js.map +0 -1
@@ -0,0 +1,521 @@
1
+ import {__decorate,__param,__metadata}from'tslib';import {injectable,inject}from'inversify';import'@cdm-logger/core';import {ServiceBroker}from'moleculer';import {CommonType}from'@common-stack/core';import {Emitter,DisposableCollection}from'@adminide-stack/core';import {BaseService2}from'@common-stack/store-mongo';import {SERVER_TYPES,DB_COLL_NAMES,ExtensionActivationState}from'common/server';var InstalledExtensionService_1;
2
+ let InstalledExtensionService = InstalledExtensionService_1 = class InstalledExtensionService extends BaseService2 {
3
+ installedExtensionRepository;
4
+ registryExtensionService;
5
+ slugService;
6
+ broker;
7
+ onExtensionInstalled = new Emitter();
8
+ onExtensionUninstalled = new Emitter();
9
+ onExtensionEnabled = new Emitter();
10
+ onExtensionDisabled = new Emitter();
11
+ onExtensionUpdated = new Emitter();
12
+ onExtensionVersionUpdated = new Emitter();
13
+ onExtensionConfigurationUpdated = new Emitter();
14
+ onExtensionSyncCompleted = new Emitter();
15
+ onExtensionCleanupCompleted = new Emitter();
16
+ onExtensionStatusChanged = new Emitter();
17
+ onExtensionActivationFailed = new Emitter();
18
+ onExtensionDeprecated = new Emitter();
19
+ onExtensionOrphaned = new Emitter();
20
+ toDispose = new DisposableCollection(this.onExtensionInstalled, this.onExtensionUninstalled, this.onExtensionEnabled, this.onExtensionDisabled, this.onExtensionUpdated, this.onExtensionVersionUpdated, this.onExtensionConfigurationUpdated, this.onExtensionSyncCompleted, this.onExtensionCleanupCompleted, this.onExtensionStatusChanged, this.onExtensionActivationFailed, this.onExtensionDeprecated, this.onExtensionOrphaned);
21
+ logger;
22
+ constructor(installedExtensionRepository, registryExtensionService, slugService, broker, logger) {
23
+ super(installedExtensionRepository);
24
+ this.installedExtensionRepository = installedExtensionRepository;
25
+ this.registryExtensionService = registryExtensionService;
26
+ this.slugService = slugService;
27
+ this.broker = broker;
28
+ this.logger = logger.child({
29
+ className: InstalledExtensionService_1.name
30
+ });
31
+ }
32
+ dispose() {
33
+ this.toDispose.dispose();
34
+ }
35
+ resolveExtensionSlug(extensionSlug) {
36
+ return this.slugService.resolveSlugWithProvider(DB_COLL_NAMES.ExtensionRegistries, 'extensionSlug', extensionSlug);
37
+ }
38
+ /**
39
+ * Install a new extension from the registry
40
+ */
41
+ async installExtension(input, tenantId) {
42
+ this.logger.debug('Installing extension [%s] for organization [%s] with input [%j]', input.extensionSlug, input.orgId, input);
43
+ if (!input.orgId) {
44
+ this.logger.error('Organization ID missing for extension installation [%s]', input.extensionSlug);
45
+ throw new Error('Organization ID (orgId) is required for extension installation');
46
+ }
47
+ this.logger.info('Installing extension [%s] for organization [%s]', input.extensionSlug, input.orgId);
48
+ // Check if extension already exists for this organization
49
+ this.logger.debug('Resolving extension slug [%s] to extension ID', input.extensionSlug);
50
+ const extensionId = await this.resolveExtensionSlug(input.extensionSlug);
51
+ this.logger.debug('Extension slug [%s] resolved to ID [%s]', input.extensionSlug, extensionId);
52
+ this.logger.debug('Checking if extension [%s] already exists for organization [%s]', extensionId, input.orgId);
53
+ const existing = await this.installedExtensionRepository.exists(input.orgId, extensionId);
54
+ if (existing) {
55
+ this.logger.warn('Extension [%s] already installed for organization [%s]', input.extensionSlug, input.orgId);
56
+ throw new Error(`Extension ${input.extensionSlug} is already installed for organization ${input.orgId}`);
57
+ }
58
+ // Get extension from registry to validate
59
+ this.logger.debug('Fetching extension [%s] from registry', input.extensionSlug);
60
+ const registryExtension = await this.registryExtensionService.findExtension(input.extensionSlug);
61
+ if (!registryExtension) {
62
+ this.logger.error('Extension [%s] not found in registry', input.extensionSlug);
63
+ throw new Error(`Extension ${input.extensionSlug} not found in registry`);
64
+ }
65
+ this.logger.debug('Registry extension found [%j]', {
66
+ id: registryExtension.id,
67
+ version: registryExtension.version,
68
+ name: registryExtension.name
69
+ });
70
+ // Delegate to the internal install method (validation already done)
71
+ this.logger.debug('Delegating to doInstallExtension for [%s]', input.extensionSlug);
72
+ return this.doInstallExtension(input, registryExtension, tenantId);
73
+ }
74
+ /**
75
+ * Internal method to perform the actual installation after validation
76
+ */
77
+ async doInstallExtension(input, registryExtension, tenantId) {
78
+ this.logger.debug('doInstallExtension input [%j]', input);
79
+ this.logger.debug('doInstallExtension registryExtension [%j]', {
80
+ id: registryExtension.id,
81
+ version: registryExtension.version,
82
+ name: registryExtension.name
83
+ });
84
+ const versionToUse = input.version || registryExtension.version;
85
+ this.logger.debug('Version resolution: input.version=[%s], registryExtension.version=[%s], using=[%s]', input.version, registryExtension.version, versionToUse);
86
+ // Create the installed extension record with proper defaults
87
+ const installedExtension = await this.installedExtensionRepository.create({
88
+ organization: input.orgId,
89
+ extensionSlug: input.extensionSlug,
90
+ extension: registryExtension.id,
91
+ version: versionToUse,
92
+ installedVersion: registryExtension.version,
93
+ installedBy: input.installedBy,
94
+ policies: {
95
+ allowOrphanedExecution: false,
96
+ requireSecurityUpdates: true,
97
+ autoRemoveDeprecated: false,
98
+ deprecationGracePeriod: 30,
99
+ ...input.policies
100
+ },
101
+ settings: {
102
+ userEnabled: true,
103
+ systemEnabled: true,
104
+ ...input.settings
105
+ }
106
+ });
107
+ // Fire installation event
108
+ const event = {
109
+ extensionSlug: input.extensionSlug,
110
+ installedBy: input.installedBy,
111
+ installedVersion: installedExtension.installedVersion,
112
+ registryRef: registryExtension.id,
113
+ installedAt: new Date().toISOString(),
114
+ policies: input.policies,
115
+ settings: input.settings,
116
+ tenantId
117
+ };
118
+ this.onExtensionInstalled.fire(event);
119
+ this.logger.info(`Successfully installed extension ${input.extensionSlug}`);
120
+ return installedExtension;
121
+ }
122
+ /**
123
+ * Uninstall an extension
124
+ */
125
+ async uninstallExtension(orgId, extensionSlug, uninstalledBy, tenantId) {
126
+ this.logger.debug('Uninstalling extension [%s] for org [%s] by user [%s] with tenantId [%s]', extensionSlug, orgId, uninstalledBy, tenantId);
127
+ this.logger.info('Uninstalling extension [%s] in org [%s]', extensionSlug, orgId);
128
+ this.logger.debug('Resolving extension slug [%s] to extension ID', extensionSlug);
129
+ const extensionId = await this.resolveExtensionSlug(extensionSlug);
130
+ this.logger.debug('Extension slug [%s] resolved to ID [%s]', extensionSlug, extensionId);
131
+ if (!extensionId) {
132
+ this.logger.error('Failed to resolve extension slug [%s] - not found in registry', extensionSlug);
133
+ throw new Error(`Extension ${extensionSlug} not found in registry`);
134
+ }
135
+ let extension = null;
136
+ if (extensionId) {
137
+ this.logger.debug('Finding extension by org [%s] and extension ID [%s]', orgId, extensionId);
138
+ // Try to find by extension ID first
139
+ extension = await this.installedExtensionRepository.findByOrgAndExtensionId(orgId, extensionId);
140
+ this.logger.debug('Extension found by ID lookup: [%s]', !!extension);
141
+ }
142
+ // If not found by extension ID, try alternative methods
143
+ if (!extension) {
144
+ this.logger.debug('Extension not found by ID, trying alternative lookup methods');
145
+ // Instead of complex lookups, let's search all installed extensions
146
+ // and match by checking if the registry extension has the matching slug
147
+ const allInstalled = await this.getInstalledExtensions({
148
+ orgId
149
+ });
150
+ this.logger.debug('Found [%d] installed extensions for org [%s]', allInstalled.length, orgId);
151
+ // For each installed extension, check if it matches our slug
152
+ for (const installed of allInstalled) {
153
+ this.logger.debug('Checking installed extension [%j]', {
154
+ id: installed.id,
155
+ extensionId: installed.extension
156
+ });
157
+ // Since we can't easily look up registry by ID, let's try a different approach
158
+ // Use the slug service to find if this matches
159
+ try {
160
+ // Get the extension slug from the registry extension directly if possible
161
+ if (installed.extension) {
162
+ // Try to resolve the extension ID back to slug for comparison
163
+ const extensionIdString = String(installed.extension);
164
+ // Check if this extension ID matches what we'd expect for this slug
165
+ const resolvedExtensionId = await this.resolveExtensionSlug(extensionSlug);
166
+ this.logger.debug('Comparing extension IDs: installed [%s] vs resolved [%s]', extensionIdString, resolvedExtensionId);
167
+ if (resolvedExtensionId && resolvedExtensionId === extensionIdString) {
168
+ this.logger.debug('Found matching extension via alternative lookup');
169
+ extension = installed;
170
+ break;
171
+ }
172
+ }
173
+ } catch (error) {
174
+ this.logger.warn('Error in alternative lookup for extension [%s]: [%s]', installed.id, error.message);
175
+ }
176
+ }
177
+ }
178
+ if (!extension) {
179
+ this.logger.error('Extension [%s] not found in org [%s] after all lookup attempts', extensionSlug, orgId);
180
+ throw new Error(`Extension ${extensionSlug} not found in org ${orgId}`);
181
+ }
182
+ this.logger.debug('Found extension to uninstall [%j]', {
183
+ id: extension.id,
184
+ extensionId: extension.extension,
185
+ slug: extension.extensionSlug
186
+ });
187
+ // Use the extension ID from the found extension record
188
+ const actualExtensionId = String(extension.extension);
189
+ this.logger.debug('Using actual extension ID [%s] for uninstall operations', actualExtensionId);
190
+ // Check dependencies - prevent uninstalling if other extensions depend on this
191
+ this.logger.debug('Checking dependency graph for org [%s]', orgId);
192
+ const dependencyGraph = await this.installedExtensionRepository.getDependencyGraph(orgId);
193
+ const extensionDeps = dependencyGraph.dependencies.find(dep => dep.extensionId === actualExtensionId);
194
+ if (extensionDeps && extensionDeps.dependents.length > 0) {
195
+ this.logger.warn('Cannot uninstall extension [%s]: required by dependents [%j]', extensionSlug, extensionDeps.dependents);
196
+ throw new Error(`Cannot uninstall ${extensionSlug}: Required by ${extensionDeps.dependents.join(', ')}`);
197
+ }
198
+ // Delete the extension using the installed extension's ID
199
+ this.logger.debug('Attempting to delete extension [%s] from org [%s]', actualExtensionId, orgId);
200
+ const deleted = await this.installedExtensionRepository.deleteExtension(orgId, actualExtensionId);
201
+ this.logger.debug('Extension deletion result: [%s]', deleted);
202
+ if (deleted) {
203
+ this.logger.debug('Creating uninstall event for extension [%s]', extensionSlug);
204
+ // Fire uninstallation event
205
+ const event = {
206
+ extensionSlug,
207
+ tenantId,
208
+ // Using accountId as tenantId for backward compatibility in events
209
+ uninstalledBy,
210
+ uninstalledAt: new Date().toISOString(),
211
+ wasEnabled: extension.settings?.userEnabled || false,
212
+ dependencies: extension.dependencies || []
213
+ };
214
+ this.logger.debug('Firing uninstall event [%j]', event);
215
+ this.onExtensionUninstalled.fire(event);
216
+ this.logger.info('Successfully uninstalled extension [%s] ([%s])', extensionSlug, actualExtensionId);
217
+ } else {
218
+ this.logger.error('Failed to delete extension [%s] from database', actualExtensionId);
219
+ }
220
+ return deleted;
221
+ }
222
+ /**
223
+ * Update an installed extension's configuration or status
224
+ */
225
+ async updateInstalledExtension(orgId, extensionSlug, update, tenantId) {
226
+ // For now, use orgId as tenantId for backward compatibility until repository is updated
227
+ this.logger.info(`Updating installed extension ${extensionSlug} for org ${orgId}`);
228
+ const extensionId = await this.resolveExtensionSlug(extensionSlug);
229
+ const updatedExtension = await this.installedExtensionRepository.updateExtension(orgId, extensionId, {
230
+ ...update,
231
+ lastUpdatedBy: update.lastUpdatedBy
232
+ });
233
+ if (!updatedExtension) {
234
+ throw new Error(`Extension ${extensionId} not found for org ${orgId}`);
235
+ }
236
+ // Fire update event if status changed
237
+ if (update.status || update.settings) {
238
+ const event = {
239
+ extensionSlug,
240
+ tenantId,
241
+ updatedBy: update.lastUpdatedBy || 'system',
242
+ updatedAt: new Date().toISOString(),
243
+ changes: update
244
+ };
245
+ this.onExtensionUpdated.fire(event);
246
+ }
247
+ return updatedExtension;
248
+ }
249
+ /**
250
+ * Get a specific installed extension
251
+ */
252
+ async getInstalledExtension(orgId, extensionSlug) {
253
+ // For now, use accountId as tenantId for backward compatibility until repository is updated
254
+ const extensionId = await this.resolveExtensionSlug(extensionSlug);
255
+ const result = await this.installedExtensionRepository.findByOrgAndExtensionId(orgId, extensionId);
256
+ return result ? result : null;
257
+ }
258
+ /**
259
+ * Get all installed extensions for a tenant with optional filtering
260
+ */
261
+ async getInstalledExtensions(filter) {
262
+ const results = await this.installedExtensionRepository.findExtensions(filter);
263
+ return results;
264
+ }
265
+ /**
266
+ * Enable/disable an installed extension
267
+ */
268
+ async toggleExtension(orgId, extensionSlug, enabled, toggledBy, tenantId) {
269
+ const activationState = enabled ? ExtensionActivationState.Enabled : ExtensionActivationState.DisabledByUser;
270
+ const updatedExtension = await this.updateInstalledExtension(orgId, extensionSlug, {
271
+ settings: {
272
+ userEnabled: enabled
273
+ },
274
+ runtime: {
275
+ activationState,
276
+ ...(enabled ? {
277
+ lastActivated: new Date()
278
+ } : {
279
+ lastDeactivated: new Date()
280
+ })
281
+ },
282
+ lastUpdatedBy: toggledBy
283
+ }, tenantId);
284
+ // Fire toggle event
285
+ const event = enabled ? {
286
+ extensionSlug,
287
+ tenantId,
288
+ enabledBy: toggledBy,
289
+ enabledAt: new Date().toISOString(),
290
+ previousState: updatedExtension.runtime.activationState
291
+ } : {
292
+ extensionSlug,
293
+ tenantId,
294
+ disabledBy: toggledBy,
295
+ disabledAt: new Date().toISOString(),
296
+ reason: 'user'
297
+ };
298
+ // Fire status change event
299
+ if (enabled) {
300
+ this.onExtensionEnabled.fire(event);
301
+ } else {
302
+ this.onExtensionDisabled.fire(event);
303
+ }
304
+ return updatedExtension;
305
+ }
306
+ /**
307
+ * Update extension settings/configuration
308
+ */
309
+ async updateExtensionSettings(orgId, extensionSlug, userConfig, updatedBy, tenantId) {
310
+ const updatedExtension = await this.updateInstalledExtension(orgId, extensionSlug, {
311
+ settings: {
312
+ userConfig
313
+ },
314
+ lastUpdatedBy: updatedBy
315
+ }, tenantId);
316
+ // Fire configuration update event
317
+ const event = {
318
+ extensionSlug,
319
+ tenantId,
320
+ updatedBy,
321
+ updatedAt: new Date().toISOString(),
322
+ configType: 'user',
323
+ newConfig: userConfig
324
+ // configurationChanges: userConfig,
325
+ // previousConfiguration: updatedExtension.settings.userConfig,
326
+ };
327
+ // Fire configuration update event
328
+ this.onExtensionConfigurationUpdated.fire(event);
329
+ return updatedExtension;
330
+ }
331
+ /**
332
+ * Check for extension updates and return available updates
333
+ */
334
+ async checkForUpdates(orgId, extensionSlug) {
335
+ const query = {
336
+ orgId
337
+ };
338
+ if (extensionSlug) {
339
+ const extensionId = await this.resolveExtensionSlug(extensionSlug);
340
+ query.extension = extensionId;
341
+ }
342
+ const installedExtensions = await this.installedExtensionRepository.findExtensions(query);
343
+ const updates = [];
344
+ for (const installed of installedExtensions) {
345
+ const registryExtension = await this.registryExtensionService.findExtension(installed.extension?.toString());
346
+ if (registryExtension && registryExtension.version !== installed.installedVersion) {
347
+ updates.push({
348
+ extensionId: installed.extension?.toString(),
349
+ extensionSlug,
350
+ currentVersion: installed.installedVersion,
351
+ availableVersion: registryExtension.version,
352
+ isSecurityUpdate: this.isSecurityUpdate(installed.installedVersion, registryExtension.version)
353
+ });
354
+ }
355
+ }
356
+ return updates;
357
+ }
358
+ /**
359
+ * Update an extension to a newer version
360
+ */
361
+ async updateExtensionVersion(orgId, extensionSlug, targetVersion, updatedBy, tenantId) {
362
+ const extension = await this.getInstalledExtension(orgId, extensionSlug);
363
+ if (!extension) {
364
+ throw new Error(`Extension ${extensionSlug} not found for organization ${orgId}`);
365
+ }
366
+ // Validate target version exists in registry
367
+ const registryExtension = await this.registryExtensionService.findExtension(extensionSlug);
368
+ if (!registryExtension) {
369
+ throw new Error(`Extension ${extensionSlug} not found in registry`);
370
+ }
371
+ const updatedExtension = await this.updateInstalledExtension(orgId, extensionSlug, {
372
+ lastUpdatedBy: updatedBy
373
+ // Note: Version update should be handled at the model level, not through update input
374
+ }, tenantId);
375
+ // Fire version update event
376
+ const event = {
377
+ extensionSlug,
378
+ updatedBy,
379
+ fromVersion: extension.installedVersion,
380
+ toVersion: targetVersion,
381
+ updatedAt: new Date().toISOString(),
382
+ isSecurityUpdate: this.isSecurityUpdate(extension.installedVersion, targetVersion),
383
+ tenantId
384
+ };
385
+ // Fire version update event
386
+ this.onExtensionVersionUpdated.fire(event);
387
+ return updatedExtension;
388
+ }
389
+ /**
390
+ * Sync installed extensions with registry status
391
+ */
392
+ async syncWithRegistry(orgId, tenantId) {
393
+ this.logger.info(`Syncing installed extensions with registry for organization ${orgId}`);
394
+ const installedExtensions = await this.installedExtensionRepository.findExtensions({
395
+ orgId
396
+ });
397
+ const syncUpdates = [];
398
+ for (const installed of installedExtensions) {
399
+ const registryExtension = await this.registryExtensionService.findExtension(installed.extension?.toString());
400
+ if (!registryExtension) {
401
+ // Extension removed from registry
402
+ syncUpdates.push({
403
+ orgId,
404
+ extensionId: installed.extension?.toString(),
405
+ registryStatus: 'removed',
406
+ isOrphaned: true
407
+ });
408
+ } else {
409
+ syncUpdates.push({
410
+ extensionId: installed.extension?.toString(),
411
+ registryStatus: registryExtension.status || 'active',
412
+ latestVersion: registryExtension.version,
413
+ isOrphaned: false,
414
+ orgId
415
+ });
416
+ }
417
+ }
418
+ // For now, map to old format for repository compatibility
419
+ const repoCompatibleUpdates = syncUpdates.map(update => ({
420
+ orgId: update.orgId,
421
+ // Use orgId as tenantId for backward compatibility
422
+ extensionId: update.extensionId,
423
+ registryStatus: update.registryStatus,
424
+ latestVersion: update.latestVersion,
425
+ isOrphaned: update.isOrphaned
426
+ }));
427
+ await this.installedExtensionRepository.syncRegistryStatus(repoCompatibleUpdates);
428
+ // Fire sync completion event
429
+ const orphanedUpdates = syncUpdates.filter(u => u.isOrphaned);
430
+ syncUpdates.filter(u => u.registryStatus === 'deprecated');
431
+ const versionsUpdates = syncUpdates.filter(u => u.latestVersion);
432
+ const event = {
433
+ syncedAt: new Date().toISOString(),
434
+ extensionsChecked: syncUpdates.length,
435
+ // syncedExtensions: versionsUpdates.length,
436
+ extensionsOrphaned: orphanedUpdates.length,
437
+ extensionsUpdated: versionsUpdates.length,
438
+ tenantId,
439
+ errors: []
440
+ // orphanedExtensions: orphanedUpdates.map((u) => u.extensionId),
441
+ // deprecatedExtensions: deprecatedUpdates.map((u) => u.extensionId),
442
+ // updatedExtensions: versionsUpdates.map((u) => u.extensionId),
443
+ };
444
+ // Fire sync completed event
445
+ this.onExtensionSyncCompleted.fire(event);
446
+ this.logger.info(`Synced ${syncUpdates.length} extensions with registry`);
447
+ }
448
+ /**
449
+ * Get extensions that need attention
450
+ */
451
+ async getExtensionsNeedingAttention(orgId) {
452
+ const extensions = await this.getInstalledExtensions({
453
+ orgId
454
+ });
455
+ const filtered = extensions.filter(ext => {
456
+ // Check for conditions that need attention
457
+ const isOrphaned = ext.lifecycle?.isOrphaned;
458
+ const isDeprecated = ext.lifecycle?.registryStatus === 'deprecated';
459
+ const hasUpdates = ext.availableVersion && ext.availableVersion !== ext.installedVersion;
460
+ return isOrphaned || isDeprecated || hasUpdates;
461
+ });
462
+ return filtered;
463
+ }
464
+ /**
465
+ * Clean up deprecated or removed extensions based on policies
466
+ */
467
+ async cleanupExtensions(orgId, tenantId, dryRun) {
468
+ // For now, use accountId as tenantId for backward compatibility until repository is updated
469
+ const result = {
470
+ removed: [],
471
+ deprecated: [],
472
+ warnings: []
473
+ };
474
+ const extensions = await this.installedExtensionRepository.findExtensions({
475
+ orgId
476
+ });
477
+ for (const extension of extensions) {
478
+ const gracePeriodExpired = extension.policies.deprecationGracePeriod > 0 && extension.lifecycle.lastRegistryCheck && Date.now() - new Date(extension.lifecycle.lastRegistryCheck).getTime() > extension.policies.deprecationGracePeriod * 24 * 60 * 60 * 1000;
479
+ // Remove orphaned extensions
480
+ if (extension.lifecycle.isOrphaned && !extension.policies.allowOrphanedExecution) {
481
+ if (!dryRun) {
482
+ await this.uninstallExtension(orgId, extension.extension?.toString(), 'system-cleanup', tenantId);
483
+ }
484
+ result.removed.push(extension.extension?.toString());
485
+ }
486
+ // Remove deprecated extensions if auto-remove is enabled and grace period expired
487
+ else if (extension.lifecycle.registryStatus === 'deprecated' && extension.policies.autoRemoveDeprecated && gracePeriodExpired) {
488
+ if (!dryRun) {
489
+ await this.uninstallExtension(orgId, extension.extension?.toString(), 'system-cleanup', tenantId);
490
+ }
491
+ result.deprecated.push(extension.extension?.toString());
492
+ }
493
+ // Add warnings for extensions that need attention
494
+ else if (extension.lifecycle.registryStatus === 'deprecated' || extension.lifecycle.isOrphaned) {
495
+ result.warnings.push(extension.extension?.toString());
496
+ }
497
+ }
498
+ // Fire cleanup completion event
499
+ const event = {
500
+ tenantId,
501
+ cleanedAt: new Date().toISOString(),
502
+ // cleanupAt: new Date().toISOString(),
503
+ warnings: result.warnings,
504
+ dryRun: false,
505
+ extensionsDeprecated: result.deprecated,
506
+ extensionsRemoved: result.removed
507
+ };
508
+ // Fire cleanup completed event
509
+ this.onExtensionCleanupCompleted.fire(event);
510
+ return result;
511
+ }
512
+ /**
513
+ * Check if update is a security update (simplified logic)
514
+ */
515
+ isSecurityUpdate(_currentVersion, _targetVersion) {
516
+ // Simple heuristic - in a real implementation, this would check
517
+ // security advisories or version metadata
518
+ return false;
519
+ }
520
+ };
521
+ InstalledExtensionService = InstalledExtensionService_1 = __decorate([injectable(), __param(0, inject(SERVER_TYPES.IInstalledExtensionRepository)), __param(1, inject(SERVER_TYPES.IRegistryExtensionService)), __param(2, inject(SERVER_TYPES.SlugService)), __param(3, inject(CommonType.MOLECULER_BROKER)), __param(4, inject(CommonType.LOGGER)), __metadata("design:paramtypes", [Object, Object, Object, ServiceBroker, Object])], InstalledExtensionService);export{InstalledExtensionService};//# sourceMappingURL=installed-extension-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installed-extension-service.js","sources":["../../src/services/installed-extension-service.ts"],"sourcesContent":[null],"names":[],"mappings":"4YAEA,IAAA;AAwCI,IAAA,yBAAmB,GAAA,2BAAoB,GAAA,MAAA,yBAA2C,SAAA,YAAA,CAAA;AAElF,EAAA,4BAAmB;AAEnB,EAAA,wBAAmB;AAEnB,EAAA,WAAS;AAET,EAAA,MAAA;AAEA,EAAA,oBAAkB,GAAC,IAAA,OAAA,EAAA;AAEnB,EAAA,sBAAmB,GAAA,IAAA,OAAA,EAAA;AAEnB,EAAA,kBAAU,GAAS,IAAA,OAAA,EAAA;AAEnB,EAAA,mBAAU,GAAS,IAAA,OAAA,EAAA;AAEnB,EAAA,kBAAU,GAAS,IAAA,OAAA,EAAA;AAEnB,EAAA,yBAAmB,GAAA,IAAA,OAAA,EAAA;AAEnB,EAAA,+BAAmB,GAAA,IAAA,OAAqB,EAAA;AAExC,EAAA,wBAAmB,GAAA,IAAA,OAAA,EAAmB;AAEtC,EAAA,2BAAmB,GAAS,IAAA,OAAA,EAAA;0BAgBM,GAAA,IAAA,OAAA,EAAA;AAItB,EAAA,2BAAA,GAAA,IAAA,OAAA;AAkBL,EAAA,qBAAe,GAAA,IAAA,OAAA,EAAA;AAItB,EAAA,mBAAQ,GAAA,IAAA,OAAoB,EAAA;AAQ5B,EAAA,SAAA,GAAA,IAAA,oBAAA,CAAA,IAAA,CAAA,oBAAA,EAAA,IAAA,CAAA,sBAAA,EAAA,IAAA,CAAA,kBAAA,EAAA,IAAA,CAAA,mBAAA,EAAA,IAAA,CAAA,kBAAA,EAAA,IAAA,CAAA,yBAAA,EAAA,IAAA,CAAA,+BAAA,EAAA,IAAA,CAAA,wBAAA,EAAA,IAAA,CAAA,2BAAA,EAAA,IAAA,CAAA,wBAAA,EAAA,IAAA,CAAA,2BAAA,EAAA,IAAA,CAAA,qBAAA,EAAA,IAAA,CAAA,mBAAA,CAAA;;AAEG,EAAA,WAAA,CAAA,4BAAA,EAAA,wBAAA,EAAA,WAAA,EAAA,MAAA,EAAA,MAAA,EAAA;AACU,IAAA,KAAA,CAAA,4BACF,CAAA;AAmDX,IAAA,IAAA,CAAA,4BAAA,GAAA,4BAAA;;AAEG,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;eACW,GAAA,MAAA;AA4Dd,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA,KAAA,CAAA;;AAEG,KAAA,CAAA;AACU,EAAA;AA0Ib,EAAA,OAAA,GAAA;;AAEG,EAAA;sBACU,CAAA,aACF,EAAA;AAkCX,IAAA,OAAA,IAAA,CAAA,WAAA,CAAA,uBAAA,CAAA,aAAA,CAAA,mBAAA,EAAA,eAAA,EAAA,aAAA,CAAA;;AAEG;AACU;AAWb;;AAEG,IAAA,IAAA,CAAA,MAAA,CAAA,KAAA,CAAA,iEAAA,EAAA,KAAA,CAAA,aAAA,EAAA,KAAA,CAAA,KAAA,EAAA,KAAA,CAAA;AACU,IAAA,IAAA,CAAA,KAAA,CAAA,KAAA,EAAA;AAOb,MAAA,IAAA,CAAA,MAAA,CAAA,KAAA,CAAA,yDAAA,EAAA,KAAA,CAAA,aAAA,CAAA;;AAEG,IAAA;IACU,IAAA,CAAA,MAAA,CAAA,IACT,CAAA,iDAES,EAAA,KACT,CAAA,aAAW,EAAM,KACjB,CAAA,KAAQ,CAAE;AAiDd;;AAEG,IAAA,MAAA,WAAA,GAAA,MAAA,IAAA,CAAA,oBAAA,CAAA,KAAA,CAAA,aAAA,CAAA;AACU,IAAA,IAAA,CAAA,MAAA,CAAA,KAAA,CAAA,yCAEM,EAAM,KACrB,CAAA,aAAkB,aAAS,CAAA;AAkC/B,IAAA,IAAA,CAAA,MAAA,CAAA,KAAA,CAAA,iEAAA,EAAA,WAAA,EAAA,KAAA,CAAA,KAAA,CAAA;;AAEG,IAAA,IAAA,QAAA,EAAA;AACU,MAAA,IAAA,CAAA,MAAA,CAAA,IACT,CAAA,wDAGM,EAAA,KAAA,CAAA,aAAA,EAAA,KAAA,CAAA,KAAA,CAAA;YACF,IAAA,KAAa,YAAO,EAAA,KAAA,CAAA,aAAA,CAAA,uCAAA,EAAA,KAAA,CAAA,KAAA,CAAA,CAAA,CAAA;;;QAGpB,CAAA,MAAA,CAAA,KAAA,CAAA,uCAAyB,EAAA,KAAA,CAAA,aAAA,CAAA;UACzB,0BAA0B,IAAA,CAAA,wBAAA,CAAA,aAAA,CAAA,KAAA,CAAA,aAAA,CAAA;AAC7B,IAAA,IACJ,CAAA,iBAAA,EAAA;AAmCD,MAAA,IAAA,CAAA,MAAA,CAAA,KAAA,CAAA,sCAAA,EAAA,KAAA,CAAA,aAAA,CAAA;;AAEG,IAAA;IACU,IAAA,CAAA,MAAA,CAAA,KAAA,CAAA,+BAET,EAAa;AA2CjB,MAAA,EAAA,EAAA,iBAAA,CAAA,EAAA;;AAEG,MAAA,IAAA,EAAA,iBAAA,CAAA;AACU,KAAA,CAAA;AAsEb;;AAEG,IAAA,OAAA,IAAA,CAAA,kBAAA,CAAA,KAAA,EAAA,iBAAA,EAAA,QAAA,CAAA;AACU,EAAA;AAeb;;AAEG;AACU,EAAA,MAAA,kBACT,CAAK,KAAE,EAAA,iBACG,EAAM,QACV,EAAC;QAEP,CAAA,MAAO,CAAA,KAAE,CAAA,+BAAS,EAAA,KAAA,CAAA;QAClB,CAAA,MAAA,CAAA,KAAY,CAAA,2CAAS,EAAA;QACrB,EAAA,iBAAmB,CAAA,EAAA;MACrB,OAAA,EAAA,iBAAA,CAAA,OAAA;AA0DF,MAAA,IAAA,EAAA,iBAAA,CAAA;;AAEG,IAAA,MAAA,YAAA,GAAA,KAAA,CAAA,OAAA,IAAA,iBAAA,CAAA,OAAA;AACH,IAAA,IAAA,CAAA,MAAQ,CAAA,KAAA,CAAA,oFAAgB,EAAA,KAAA,CAAA,OAAA,EAAA,iBAAA,CAAA,OAAA,EAAA,YAAA,CAAA;AAK3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=installed-extension-service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installed-extension-service.test.d.ts","sourceRoot":"","sources":["../../src/services/installed-extension-service.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,128 @@
1
+ import { CdmLogger } from '@cdm-logger/core';
2
+ import { BaseService2 } from '@common-stack/store-mongo';
3
+ import { Disposable, DisposableCollection, Emitter } from '@adminide-stack/core';
4
+ import { IRegistryExtensionRepository, IRegistryExtensionModel } from 'common/server';
5
+ export interface AnalyticsEvent {
6
+ eventType: string;
7
+ extensionSlug: string;
8
+ publisherId: string;
9
+ timestamp: string;
10
+ metadata?: string;
11
+ region?: string;
12
+ version?: string;
13
+ }
14
+ export interface AnalyticsDataPoint {
15
+ timestamp: string;
16
+ value: number;
17
+ secondaryValue?: number;
18
+ }
19
+ export interface VersionMetrics {
20
+ version: string;
21
+ downloads: number;
22
+ installations: number;
23
+ releasedAt: string;
24
+ adoptionRate: number;
25
+ }
26
+ export interface ExtensionMetrics {
27
+ extensionSlug: string;
28
+ name: string;
29
+ version?: string;
30
+ downloads: number;
31
+ installations: number;
32
+ rating?: number;
33
+ reviewCount: number;
34
+ revenue?: number;
35
+ lastUpdated?: string;
36
+ versionMetrics: VersionMetrics[];
37
+ }
38
+ export interface RegionMetrics {
39
+ region: string;
40
+ regionName: string;
41
+ downloads: number;
42
+ installations: number;
43
+ percentage: number;
44
+ }
45
+ export interface PublisherAnalyticsInput {
46
+ publisherId: string;
47
+ period: string;
48
+ extensionSlugs?: string[];
49
+ includeRevenue?: boolean;
50
+ includeRegions?: boolean;
51
+ }
52
+ export interface PublisherAnalyticsResult {
53
+ publisherId: string;
54
+ totalExtensions: number;
55
+ totalDownloads: number;
56
+ totalInstallations: number;
57
+ averageRating?: number;
58
+ period: string;
59
+ extensions: ExtensionMetrics[];
60
+ downloadTrend: AnalyticsDataPoint[];
61
+ installationTrend: AnalyticsDataPoint[];
62
+ popularRegions: RegionMetrics[];
63
+ }
64
+ export interface RevenueDataPoint {
65
+ timestamp: string;
66
+ revenue: number;
67
+ transactions: number;
68
+ }
69
+ export interface ExtensionRevenue {
70
+ extensionSlug: string;
71
+ name: string;
72
+ revenue: number;
73
+ paidInstallations: number;
74
+ arpu: number;
75
+ }
76
+ export interface PublisherRevenueAnalyticsInput {
77
+ publisherId: string;
78
+ period: string;
79
+ currency?: string;
80
+ }
81
+ export interface PublisherRevenueAnalyticsResult {
82
+ publisherId: string;
83
+ totalRevenue: number;
84
+ currency: string;
85
+ extensionRevenue: ExtensionRevenue[];
86
+ revenueTrend: RevenueDataPoint[];
87
+ topEarningExtensions: ExtensionRevenue[];
88
+ }
89
+ export interface TrackAnalyticsEventInput {
90
+ eventType: string;
91
+ extensionSlug: string;
92
+ userId?: string;
93
+ metadata?: string;
94
+ region?: string;
95
+ version?: string;
96
+ }
97
+ export interface TrackAnalyticsEventResult {
98
+ success: boolean;
99
+ message?: string;
100
+ eventId?: string;
101
+ }
102
+ export interface IPublisherAnalyticsService {
103
+ getPublisherAnalytics(input: PublisherAnalyticsInput): Promise<PublisherAnalyticsResult>;
104
+ getPublisherRevenueAnalytics(input: PublisherRevenueAnalyticsInput): Promise<PublisherRevenueAnalyticsResult>;
105
+ trackAnalyticsEvent(input: TrackAnalyticsEventInput): Promise<TrackAnalyticsEventResult>;
106
+ getRecentAnalyticsEvents(publisherId: string, limit?: number): Promise<AnalyticsEvent[]>;
107
+ }
108
+ export declare class PublisherAnalyticsService extends BaseService2<IRegistryExtensionModel> implements IPublisherAnalyticsService, Disposable {
109
+ private extensionRepository;
110
+ protected readonly onAnalyticsEvent: Emitter<AnalyticsEvent>;
111
+ protected readonly onDownloadEvent: Emitter<AnalyticsEvent>;
112
+ protected readonly onInstallationEvent: Emitter<AnalyticsEvent>;
113
+ protected readonly toDispose: DisposableCollection;
114
+ private logger;
115
+ constructor(extensionRepository: IRegistryExtensionRepository, logger: CdmLogger.ILogger);
116
+ dispose(): void;
117
+ getPublisherAnalytics(input: PublisherAnalyticsInput): Promise<PublisherAnalyticsResult>;
118
+ getPublisherRevenueAnalytics(input: PublisherRevenueAnalyticsInput): Promise<PublisherRevenueAnalyticsResult>;
119
+ trackAnalyticsEvent(input: TrackAnalyticsEventInput): Promise<TrackAnalyticsEventResult>;
120
+ getRecentAnalyticsEvents(publisherId: string, limit?: number): Promise<AnalyticsEvent[]>;
121
+ get analyticsEvents(): import("@adminide-stack/core").Event<AnalyticsEvent>;
122
+ get downloadEvents(): import("@adminide-stack/core").Event<AnalyticsEvent>;
123
+ get installationEvents(): import("@adminide-stack/core").Event<AnalyticsEvent>;
124
+ private generateTrendData;
125
+ private generateRegionData;
126
+ private generateRevenueTrend;
127
+ }
128
+ //# sourceMappingURL=publisher-analytics-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publisher-analytics-service.d.ts","sourceRoot":"","sources":["../../src/services/publisher-analytics-service.ts"],"names":[],"mappings":"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"}