@adminide-stack/marketplace-module-server 12.0.4-alpha.95 → 13.0.1-alpha.0

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 (175) hide show
  1. package/lib/containers/module.d.ts +4 -4
  2. package/lib/containers/module.d.ts.map +1 -1
  3. package/lib/containers/module.js +12 -7
  4. package/lib/containers/module.js.map +1 -1
  5. package/lib/dataloaders/index.d.ts +1 -1
  6. package/lib/dataloaders/index.d.ts.map +1 -1
  7. package/lib/dataloaders/publisher-data-loader.d.ts +6 -0
  8. package/lib/dataloaders/publisher-data-loader.d.ts.map +1 -0
  9. package/lib/demo/test-graphql-examples.d.ts +73 -0
  10. package/lib/demo/test-graphql-examples.d.ts.map +1 -0
  11. package/lib/graphql/resolvers/form-templates-resolver.d.ts +220 -0
  12. package/lib/graphql/resolvers/form-templates-resolver.d.ts.map +1 -0
  13. package/lib/graphql/resolvers/form-templates-resolver.js +170 -0
  14. package/lib/graphql/resolvers/form-templates-resolver.js.map +1 -0
  15. package/lib/graphql/resolvers/gallery-resolver.d.ts +15 -0
  16. package/lib/graphql/resolvers/gallery-resolver.d.ts.map +1 -0
  17. package/lib/graphql/resolvers/gallery-resolver.js +35 -0
  18. package/lib/graphql/resolvers/gallery-resolver.js.map +1 -0
  19. package/lib/graphql/resolvers/index.d.ts +247 -1
  20. package/lib/graphql/resolvers/index.d.ts.map +1 -1
  21. package/lib/graphql/resolvers/index.js +1 -1
  22. package/lib/graphql/resolvers/installed-extension-resolver.d.ts.map +1 -1
  23. package/lib/graphql/resolvers/installed-extension-resolver.js +161 -35
  24. package/lib/graphql/resolvers/installed-extension-resolver.js.map +1 -1
  25. package/lib/graphql/resolvers/marketplace-form-resolver.d.ts +13 -0
  26. package/lib/graphql/resolvers/marketplace-form-resolver.d.ts.map +1 -0
  27. package/lib/graphql/resolvers/marketplace-form-resolver.js +90 -0
  28. package/lib/graphql/resolvers/marketplace-form-resolver.js.map +1 -0
  29. package/lib/graphql/resolvers/publisher-analytics-resolver.d.ts +14 -0
  30. package/lib/graphql/resolvers/publisher-analytics-resolver.d.ts.map +1 -0
  31. package/lib/graphql/resolvers/publisher-analytics-resolver.js +221 -0
  32. package/lib/graphql/resolvers/publisher-analytics-resolver.js.map +1 -0
  33. package/lib/graphql/resolvers/publisher-resolver.d.ts +5 -0
  34. package/lib/graphql/resolvers/publisher-resolver.d.ts.map +1 -0
  35. package/lib/graphql/resolvers/publisher-resolver.js +183 -0
  36. package/lib/graphql/resolvers/publisher-resolver.js.map +1 -0
  37. package/lib/graphql/resolvers/registry-extension-resolver.d.ts.map +1 -1
  38. package/lib/graphql/resolvers/registry-extension-resolver.js +34 -167
  39. package/lib/graphql/resolvers/registry-extension-resolver.js.map +1 -1
  40. package/lib/graphql/schemas/extension-pricing.graphql +546 -0
  41. package/lib/graphql/schemas/extension-pricing.graphql.js +1 -0
  42. package/lib/graphql/schemas/extension-pricing.graphql.js.map +1 -0
  43. package/lib/graphql/schemas/extension-registry.graphql +91 -58
  44. package/lib/graphql/schemas/extension-registry.graphql.js +1 -1
  45. package/lib/graphql/schemas/form-templates.graphql +269 -0
  46. package/lib/graphql/schemas/form-templates.graphql.js +1 -0
  47. package/lib/graphql/schemas/form-templates.graphql.js.map +1 -0
  48. package/lib/graphql/schemas/gallery-schema.graphql +247 -0
  49. package/lib/graphql/schemas/gallery-schema.graphql.js +1 -0
  50. package/lib/graphql/schemas/gallery-schema.graphql.js.map +1 -0
  51. package/lib/graphql/schemas/index.d.ts.map +1 -1
  52. package/lib/graphql/schemas/index.js +3 -1
  53. package/lib/graphql/schemas/index.js.map +1 -1
  54. package/lib/graphql/schemas/installed-extension.graphql +37 -7
  55. package/lib/graphql/schemas/installed-extension.graphql.js +1 -1
  56. package/lib/graphql/schemas/publisher-analytics.graphql +305 -0
  57. package/lib/graphql/schemas/publisher-analytics.graphql.js +1 -0
  58. package/lib/graphql/schemas/publisher-analytics.graphql.js.map +1 -0
  59. package/lib/graphql/schemas/publisher.graphql +584 -0
  60. package/lib/graphql/schemas/publisher.graphql.js +1 -0
  61. package/lib/graphql/schemas/publisher.graphql.js.map +1 -0
  62. package/lib/graphql/schemas/service.graphql +15 -0
  63. package/lib/index.d.ts +1 -1
  64. package/lib/index.js +1 -1
  65. package/lib/index.js.map +1 -1
  66. package/lib/migrations/dbMigrations/DropOldPublisherIndexMigration.d.ts +20 -0
  67. package/lib/migrations/dbMigrations/DropOldPublisherIndexMigration.d.ts.map +1 -0
  68. package/lib/migrations/dbMigrations/DropOldPublisherIndexMigration.js +61 -0
  69. package/lib/migrations/dbMigrations/DropOldPublisherIndexMigration.js.map +1 -0
  70. package/lib/migrations/index.d.ts +2 -0
  71. package/lib/migrations/index.d.ts.map +1 -0
  72. package/lib/module.d.ts +1 -1
  73. package/lib/module.d.ts.map +1 -1
  74. package/lib/module.js +11 -26
  75. package/lib/module.js.map +1 -1
  76. package/lib/services/extension-gallery-repository.d.ts +17 -0
  77. package/lib/services/extension-gallery-repository.d.ts.map +1 -0
  78. package/lib/services/extension-gallery-repository.js +192 -0
  79. package/lib/services/extension-gallery-repository.js.map +1 -0
  80. package/lib/services/extension-gallery-service-new.d.ts +39 -0
  81. package/lib/services/extension-gallery-service-new.d.ts.map +1 -0
  82. package/lib/services/extension-gallery-service.d.ts +30 -0
  83. package/lib/services/extension-gallery-service.d.ts.map +1 -0
  84. package/lib/services/extension-gallery-service.js +334 -0
  85. package/lib/services/extension-gallery-service.js.map +1 -0
  86. package/lib/services/index.d.ts +4 -1
  87. package/lib/services/index.d.ts.map +1 -1
  88. package/lib/services/installed-extension-service-ext.d.ts +5 -2
  89. package/lib/services/installed-extension-service-ext.d.ts.map +1 -1
  90. package/lib/services/installed-extension-service-ext.js +364 -117
  91. package/lib/services/installed-extension-service-ext.js.map +1 -1
  92. package/lib/services/installed-extension-service.d.ts +30 -13
  93. package/lib/services/installed-extension-service.d.ts.map +1 -1
  94. package/lib/services/installed-extension-service.js +301 -68
  95. package/lib/services/installed-extension-service.js.map +1 -1
  96. package/lib/services/installed-extension-service.test.d.ts +0 -1
  97. package/lib/services/publisher-analytics-service.d.ts +128 -0
  98. package/lib/services/publisher-analytics-service.d.ts.map +1 -0
  99. package/lib/services/publisher-event-service.d.ts +48 -0
  100. package/lib/services/publisher-event-service.d.ts.map +1 -0
  101. package/lib/services/publisher-event-service.js +296 -0
  102. package/lib/services/publisher-event-service.js.map +1 -0
  103. package/lib/services/publisher-service-context.d.ts +1 -0
  104. package/lib/services/publisher-service-context.d.ts.map +1 -0
  105. package/lib/services/publisher-service.d.ts +62 -0
  106. package/lib/services/publisher-service.d.ts.map +1 -0
  107. package/lib/services/publisher-service.js +135 -0
  108. package/lib/services/publisher-service.js.map +1 -0
  109. package/lib/store/models/index.d.ts +1 -1
  110. package/lib/store/models/index.d.ts.map +1 -1
  111. package/lib/store/models/installed-extension-model.d.ts.map +1 -1
  112. package/lib/store/models/installed-extension-model.js +17 -45
  113. package/lib/store/models/installed-extension-model.js.map +1 -1
  114. package/lib/store/models/publisher-event-model.d.ts +11 -0
  115. package/lib/store/models/publisher-event-model.d.ts.map +1 -0
  116. package/lib/store/models/publisher-model.d.ts +5 -0
  117. package/lib/store/models/publisher-model.d.ts.map +1 -0
  118. package/lib/store/models/publisher-model.js +117 -0
  119. package/lib/store/models/publisher-model.js.map +1 -0
  120. package/lib/store/models/publisher-stats-model.d.ts +1 -0
  121. package/lib/store/models/publisher-stats-model.d.ts.map +1 -0
  122. package/lib/store/repositories/index.d.ts +1 -1
  123. package/lib/store/repositories/index.d.ts.map +1 -1
  124. package/lib/store/repositories/installed-extension-repository.d.ts +17 -11
  125. package/lib/store/repositories/installed-extension-repository.d.ts.map +1 -1
  126. package/lib/store/repositories/installed-extension-repository.js +123 -75
  127. package/lib/store/repositories/installed-extension-repository.js.map +1 -1
  128. package/lib/store/repositories/publisher-analytics-repository.d.ts +1 -0
  129. package/lib/store/repositories/publisher-analytics-repository.d.ts.map +1 -0
  130. package/lib/store/repositories/publisher-repository.d.ts +19 -0
  131. package/lib/store/repositories/publisher-repository.d.ts.map +1 -0
  132. package/lib/store/repositories/publisher-repository.js +87 -0
  133. package/lib/store/repositories/publisher-repository.js.map +1 -0
  134. package/lib/templates/constants/DB_COLL_NAMES.ts.template +1 -1
  135. package/lib/templates/constants/SERVER_TYPES.ts.template +8 -5
  136. package/lib/templates/repositories/ExtensionGalleryRepository.ts.template +44 -0
  137. package/lib/templates/repositories/InstalledExtensionRepository.ts.template +19 -14
  138. package/lib/templates/repositories/MarketplacePublisherRepository.ts.template +24 -0
  139. package/lib/templates/repositories/RegistryExtensionRepository.ts.template +2 -2
  140. package/lib/templates/services/ExtensionGalleryDataLoader.ts.template +2 -0
  141. package/lib/templates/services/ExtensionGalleryService.ts.template +79 -0
  142. package/lib/templates/services/InstalledExtensionService.ts.template +63 -32
  143. package/lib/templates/services/MarketplacePublisherService.ts.template +51 -0
  144. package/lib/templates/services/PublisherDataLoader.ts.template +3 -0
  145. package/lib/templates/services/PublisherEventService.ts.template +56 -0
  146. package/lib/templates/services/RegistryExtensionService.ts.template +46 -2
  147. package/lib/tests/extension-integration.test.d.ts +0 -1
  148. package/lib/tests/install-extension-graphql.test.d.ts +2 -0
  149. package/lib/tests/install-extension-graphql.test.d.ts.map +1 -0
  150. package/lib/utils/publisherValidation.d.ts +23 -0
  151. package/lib/utils/publisherValidation.d.ts.map +1 -0
  152. package/lib/utils/publisherValidation.js +144 -0
  153. package/lib/utils/publisherValidation.js.map +1 -0
  154. package/package.json +13 -9
  155. package/lib/constants/extension-events.d.ts +0 -136
  156. package/lib/constants/extension-events.d.ts.map +0 -1
  157. package/lib/dataloaders/registry-extension-data-loader.d.ts +0 -6
  158. package/lib/dataloaders/registry-extension-data-loader.d.ts.map +0 -1
  159. package/lib/dataloaders/registry-extension-data-loader.js +0 -6
  160. package/lib/dataloaders/registry-extension-data-loader.js.map +0 -1
  161. package/lib/graphql/schemas/service.graphql.js +0 -1
  162. package/lib/graphql/schemas/service.graphql.js.map +0 -1
  163. package/lib/services/extension-service.d.ts +0 -42
  164. package/lib/services/extension-service.d.ts.map +0 -1
  165. package/lib/services/extension-service.js +0 -60
  166. package/lib/services/extension-service.js.map +0 -1
  167. package/lib/store/models/registry-extension-model.d.ts +0 -5
  168. package/lib/store/models/registry-extension-model.d.ts.map +0 -1
  169. package/lib/store/models/registry-extension-model.js +0 -83
  170. package/lib/store/models/registry-extension-model.js.map +0 -1
  171. package/lib/store/repositories/registry-extension-repository.d.ts +0 -54
  172. package/lib/store/repositories/registry-extension-repository.d.ts.map +0 -1
  173. package/lib/store/repositories/registry-extension-repository.js +0 -137
  174. package/lib/store/repositories/registry-extension-repository.js.map +0 -1
  175. package/lib/templates/services/RegistryExtensionDataLoader.ts.template +0 -2
@@ -0,0 +1,24 @@
1
+ import { IBaseMongoRepository, IMarketplacePublisherModel, AsDomainType } from 'common/server';
2
+
3
+ export interface IMarketplacePublisherRepository extends IBaseMongoRepository<IMarketplacePublisherModel> {
4
+ findByPublisherName(publisherName: string): Promise<AsDomainType<IMarketplacePublisherModel> | null>;
5
+ findPublishers(
6
+ search?: string,
7
+ orderBy?: string,
8
+ orderDirection?: 'ASC' | 'DESC',
9
+ limit?: number,
10
+ offset?: number,
11
+ ): Promise<{
12
+ publishers: AsDomainType<IMarketplacePublisherModel>[];
13
+ totalCount: number;
14
+ }>;
15
+ updatePublisherStats(
16
+ publisherId: string,
17
+ stats: {
18
+ extensionCount?: number;
19
+ totalInstalls?: number;
20
+ averageRating?: number;
21
+ },
22
+ ): Promise<AsDomainType<IMarketplacePublisherModel> | null>;
23
+ verifyPublisher(publisherId: string): Promise<AsDomainType<IMarketplacePublisherModel> | null>;
24
+ }
@@ -1,4 +1,4 @@
1
- import { IPublishRequest, IExtensionRelease, IBaseMongoRepository, IRegistryExtensionModel, IExtensionReleaseModel, AsDomainType } from 'common/server';
1
+ import { IMarketplacePublishExtensionInput, IExtensionRelease, IBaseMongoRepository, IRegistryExtensionModel, IExtensionReleaseModel, AsDomainType } from 'common/server';
2
2
 
3
3
  export interface IRegistryExtensionRepository extends IBaseMongoRepository<IRegistryExtensionModel> {
4
4
  extensionReleases(extensionSlug: string): Promise<AsDomainType<IExtensionReleaseModel>[]>;
@@ -11,7 +11,7 @@ export interface IRegistryExtensionRepository extends IBaseMongoRepository<IRegi
11
11
 
12
12
  deleteExtension(extensionSlug: string): boolean | Promise<boolean>;
13
13
 
14
- publishExtension(request: IPublishRequest): Promise<AsDomainType<IRegistryExtensionModel>>;
14
+ publishExtension(request: IMarketplacePublishExtensionInput): Promise<AsDomainType<IRegistryExtensionModel>>;
15
15
 
16
16
  findExtensions(first: number, query: string, local?: boolean, remote?: boolean, prioritizeExtensionIDs?: string[]): Promise<AsDomainType<IRegistryExtensionModel>[]>;
17
17
 
@@ -0,0 +1,2 @@
1
+ import { IGalleryExtension, IDataLoader } from 'common/server';
2
+ export type IExtensionGalleryDataLoader = IDataLoader<IGalleryExtension>;
@@ -0,0 +1,79 @@
1
+ // from package: marketplace-server
2
+ import {
3
+ IGalleryExtension,
4
+ IExtensionIdentifier,
5
+ IExtensionManifest,
6
+ IGalleryPager,
7
+ AsDomainType,
8
+ IRegistryExtensionModel,
9
+ } from 'common/server';
10
+
11
+ /**
12
+ * Query options interface for gallery searches
13
+ */
14
+ export interface IQueryOptions {
15
+ text?: string;
16
+ pageSize?: number;
17
+ }
18
+
19
+ /**
20
+ * Service interface for managing extension gallery
21
+ * IMPORTANT: All service methods that return domain entities MUST use AsDomainType<IEntityModel>
22
+ * This ensures proper type compatibility between MongoDB models and GraphQL domain types
23
+ */
24
+ export interface IExtensionGalleryService {
25
+ /**
26
+ * Check if gallery service is enabled
27
+ */
28
+ isEnabled(): boolean;
29
+
30
+ /**
31
+ * Query extensions in gallery
32
+ */
33
+ query(options?: IQueryOptions): Promise<IGalleryPager>;
34
+
35
+ /**
36
+ * Get a specific extension by identifier
37
+ */
38
+ getExtension(identifier: IExtensionIdentifier | string): Promise<IGalleryExtension | null>;
39
+
40
+ /**
41
+ * Download an extension
42
+ */
43
+ download(extension: IGalleryExtension): Promise<string>;
44
+
45
+ /**
46
+ * Get extension README content
47
+ */
48
+ getReadme(extension: IGalleryExtension): Promise<string>;
49
+
50
+ /**
51
+ * Get extension manifest
52
+ */
53
+ getManifest(extension: IGalleryExtension): Promise<IExtensionManifest | null>;
54
+
55
+ /**
56
+ * Get extension changelog
57
+ */
58
+ getChangelog(extension: IGalleryExtension): Promise<string>;
59
+
60
+ /**
61
+ * Get extension license
62
+ */
63
+ getLicense(extension: IGalleryExtension): Promise<string>;
64
+
65
+ /**
66
+ * Load compatible version of extension
67
+ */
68
+ loadCompatibleVersion(extension: IGalleryExtension): Promise<IGalleryExtension>;
69
+ }
70
+
71
+ /**
72
+ * This file augments the ServerContext interface from the central apollo-context.
73
+ * Through declaration merging, the extensionGalleryService will be added to the ServerContext.
74
+ */
75
+ declare module '../apollo-context' {
76
+ export interface ServerContext {
77
+ extensionGalleryService: IExtensionGalleryService;
78
+ }
79
+ }
@@ -11,8 +11,8 @@ import {
11
11
  * Input type for creating installed extensions with additional server-side fields
12
12
  */
13
13
  export interface ICreateInstalledExtensionInput extends IInstallExtensionInput {
14
- extensionId: string;
15
- tenantId: string;
14
+ extensionId: string; // ObjectId reference to extension registry
15
+ orgId: string; // Organization ID
16
16
  installedVersion: string;
17
17
  installedBy: string; // User ObjectId as string
18
18
  }
@@ -54,14 +54,13 @@ export interface IUpdateInstalledExtensionInput {
54
54
  * Filter input for querying installed extensions
55
55
  */
56
56
  export interface IInstalledExtensionFilter {
57
- tenantId?: string;
58
- extensionSlug?: string; // From GraphQL: extensionSlug field
59
- extension?: string; // ObjectId as string reference
57
+ accountId?: string; // Account ID for filtering extensions by account
58
+ orgId?: string; // Organization ID for filtering extensions by organization
59
+ extension?: string; // ObjectId as string reference to extension registry
60
60
  status?: string[];
61
- registryStatus?: string[];
62
- isOrphaned?: boolean;
63
- userEnabled?: boolean;
64
- systemEnabled?: boolean;
61
+ 'lifecycle.registryStatus'?: string[];
62
+ 'lifecycle.isOrphaned'?: boolean;
63
+ 'settings.effectiveEnabled'?: boolean;
65
64
  installedBy?: string;
66
65
  }
67
66
 
@@ -73,60 +72,78 @@ export interface IInstalledExtensionService extends IBaseService<IInstalledExten
73
72
  /**
74
73
  * Install a new extension from the registry
75
74
  */
76
- installExtension(input: ICreateInstalledExtensionInput): Promise<AsDomainType<IInstalledExtensionModel>>;
75
+ installExtension(input: ICreateInstalledExtensionInput, tenantId: string): Promise<AsDomainType<IInstalledExtensionModel>>;
77
76
 
78
77
  /**
79
- * Uninstall an extension
78
+ * Uninstall an extension - now supports accountId and orgId based filtering
80
79
  */
81
- uninstallExtension(tenantId: string, extensionSlug: string, uninstalledBy: string): Promise<boolean>;
80
+ uninstallExtension(
81
+ orgId: string,
82
+ extensionSlug: string,
83
+ uninstalledBy: string,
84
+ tenantId: string
85
+ ): Promise<boolean>;
82
86
 
83
87
  /**
84
- * Update an installed extension's configuration or status
88
+ * Update an installed extension's configuration or status - now supports accountId and orgId based filtering
85
89
  */
86
90
  updateInstalledExtension(
87
- tenantId: string,
91
+ orgId: string,
88
92
  extensionSlug: string,
89
93
  update: IUpdateInstalledExtensionInput,
94
+ tenantId: string,
90
95
  ): Promise<AsDomainType<IInstalledExtensionModel>>;
91
96
 
92
97
  /**
93
- * Get a specific installed extension
98
+ * Get a specific installed extension - now supports accountId and orgId based filtering
94
99
  */
95
- getInstalledExtension(tenantId: string, extensionSlug: string): Promise<AsDomainType<IInstalledExtensionModel> | null>;
100
+ getInstalledExtension(
101
+ orgId: string,
102
+ extensionSlug: string,
103
+ ): Promise<AsDomainType<IInstalledExtensionModel> | null>;
96
104
 
97
105
  /**
98
- * Get all installed extensions for a tenant with optional filtering
106
+ * Get all installed extensions with optional filtering - now supports accountId and orgId based filtering
99
107
  */
100
108
  getInstalledExtensions(filter: IInstalledExtensionFilter): Promise<AsDomainType<IInstalledExtensionModel>[]>;
101
109
 
102
110
  /**
103
- * Enable/disable an installed extension
111
+ * Get all installed extensions for a specific extension by extensionSlug
112
+ * Useful for finding all organizations that have installed a specific extension
113
+ */
114
+ getInstalledExtensionsBySlug(extensionSlug: string): Promise<AsDomainType<IInstalledExtensionModel>[]>;
115
+
116
+ /**
117
+ * Enable/disable an installed extension - now supports accountId and orgId based filtering
104
118
  */
105
119
  toggleExtension(
106
- tenantId: string,
120
+ orgId: string,
107
121
  extensionSlug: string,
108
122
  enabled: boolean,
109
123
  toggledBy: string,
124
+ tenantId: string,
110
125
  ): Promise<AsDomainType<IInstalledExtensionModel>>;
111
126
 
112
127
  /**
113
- * Update extension settings/configuration
128
+ * Update extension settings/configuration - now supports accountId and orgId based filtering
114
129
  */
115
130
  updateExtensionSettings(
116
- tenantId: string,
131
+ orgId: string,
117
132
  extensionSlug: string,
118
133
  userConfig: Record<string, unknown>,
119
134
  updatedBy: string,
135
+ tenantId: string,
120
136
  ): Promise<AsDomainType<IInstalledExtensionModel>>;
121
137
 
122
138
  /**
123
- * Check for extension updates and return available updates
139
+ * Check for extension updates and return available updates - now supports accountId and orgId based filtering
124
140
  */
125
141
  checkForUpdates(
126
- tenantId: string,
142
+ orgId: string,
127
143
  extensionSlug?: string,
128
144
  ): Promise<
129
145
  Array<{
146
+ extensionId: string;
130
147
  extensionSlug: string;
131
148
  currentVersion: string;
132
149
  availableVersion: string;
@@ -135,34 +152,48 @@ export interface IInstalledExtensionService extends IBaseService<IInstalledExten
135
152
  >;
136
153
 
137
154
  /**
138
- * Update an extension to a newer version
155
+ * Update an extension to a newer version - now supports accountId and orgId based filtering
139
156
  */
140
157
  updateExtensionVersion(
141
- tenantId: string,
158
+ orgId: string,
142
159
  extensionSlug: string,
143
160
  targetVersion: string,
144
161
  updatedBy: string,
162
+ tenantId: string
145
163
  ): Promise<AsDomainType<IInstalledExtensionModel>>;
146
164
 
147
165
  /**
148
- * Sync installed extensions with registry status (for orphaned, deprecated, etc.)
166
+ * Sync installed extensions with registry status (for orphaned, deprecated, etc.) - now supports accountId and orgId based filtering
149
167
  */
150
- syncWithRegistry(tenantId: string): Promise<void>;
168
+ syncWithRegistry(orgId: string, tenantId: string): Promise<void>;
151
169
 
152
170
  /**
153
- * Get extensions that need attention (deprecated, orphaned, security updates, etc.)
171
+ * Get extensions that need attention (deprecated, orphaned, security updates, etc.) - now supports accountId and orgId based filtering
154
172
  */
155
- getExtensionsNeedingAttention(tenantId: string): Promise<AsDomainType<IInstalledExtensionModel>[]>;
173
+ getExtensionsNeedingAttention(orgId: string): Promise<AsDomainType<IInstalledExtensionModel>[]>;
156
174
 
157
175
  /**
158
- * Clean up deprecated or removed extensions based on policies
176
+ * Clean up deprecated or removed extensions based on policies - now supports accountId and orgId based filtering
159
177
  */
160
178
  cleanupExtensions(
179
+ orgId: string,
180
+ tenantId: string,
181
+ dryRun?: boolean,
182
+ ): Promise<{
183
+ removed: string[]; // Array of extension ObjectIds
184
+ deprecated: string[]; // Array of extension ObjectIds
185
+ warnings: string[];
186
+ }>;
187
+
188
+ /**
189
+ * Clean up orphaned extensions that exist in installed_extensions but not in system_extension registry
190
+ */
191
+ cleanupOrphanedExtensions(
192
+ orgId: string,
161
193
  tenantId: string,
162
194
  dryRun?: boolean,
163
195
  ): Promise<{
164
- removed: string[];
165
- deprecated: string[];
196
+ removed: string[]; // Array of extension slugs
166
197
  warnings: string[];
167
198
  }>;
168
199
  }
@@ -0,0 +1,51 @@
1
+ import { IBaseService, IMarketplacePublisherModel, AsDomainType } from 'common/server';
2
+
3
+ export interface IMarketplacePublisherService extends IBaseService<IMarketplacePublisherModel> {
4
+ findById(id: string): Promise<AsDomainType<IMarketplacePublisherModel> | null>;
5
+ findByPublisherName(publisherName: string): Promise<AsDomainType<IMarketplacePublisherModel> | null>;
6
+ findPublishers(
7
+ search?: string,
8
+ orderBy?: string,
9
+ orderDirection?: 'ASC' | 'DESC',
10
+ first?: number,
11
+ after?: number,
12
+ ): Promise<{
13
+ publishers: AsDomainType<IMarketplacePublisherModel>[];
14
+ totalCount: number;
15
+ }>;
16
+ createPublisher(data: {
17
+ displayName: string;
18
+ publisherName: string;
19
+ description?: string;
20
+ website?: string;
21
+ domain?: string;
22
+ tenant?: string;
23
+ }): Promise<AsDomainType<IMarketplacePublisherModel>>;
24
+ updatePublisher(
25
+ publisherId: string,
26
+ data: {
27
+ displayName?: string;
28
+ description?: string;
29
+ website?: string;
30
+ avatarUrl?: string;
31
+ tenant?: string;
32
+ },
33
+ ): Promise<AsDomainType<IMarketplacePublisherModel> | null>;
34
+ updatePublisherStats(
35
+ publisherId: string,
36
+ stats: {
37
+ extensionCount?: number;
38
+ totalInstalls?: number;
39
+ averageRating?: number;
40
+ },
41
+ ): Promise<AsDomainType<IMarketplacePublisherModel> | null>;
42
+ verifyPublisher(publisherId: string): Promise<AsDomainType<IMarketplacePublisherModel> | null>;
43
+ getPublisherStats(publisherId: string): Promise<{
44
+ totalExtensions: number;
45
+ totalDownloads: number;
46
+ totalInstallations: number;
47
+ averageRating: number;
48
+ verifiedCount: number;
49
+ topExtension?: unknown; // TODO: Should be IRegistryExtension when available
50
+ } | null>;
51
+ }
@@ -0,0 +1,3 @@
1
+ import { IMarketplacePublisherModel, IDataLoader } from 'common/server';
2
+
3
+ export type IPublisherDataLoader = IDataLoader<IMarketplacePublisherModel>;
@@ -0,0 +1,56 @@
1
+ // from package: marketplace-server
2
+
3
+ /**
4
+ * Service interface for managing publisher analytics events
5
+ */
6
+ export interface IPublisherEventService {
7
+ recordEvent(event: {
8
+ publisherId: string;
9
+ extensionId?: string;
10
+ eventType: 'download' | 'install' | 'view' | 'rating';
11
+ value?: number;
12
+ metadata?: Record<string, unknown>;
13
+ }): Promise<void>;
14
+
15
+ getPublisherStats(publisherId: string): Promise<{
16
+ totalDownloads: number;
17
+ totalInstalls: number;
18
+ totalViews: number;
19
+ totalRatings: number;
20
+ averageRating: number;
21
+ extensionCount: number;
22
+ lastUpdated: Date;
23
+ }>;
24
+
25
+ getPublisherAnalytics(
26
+ publisherId: string,
27
+ startDate: Date,
28
+ endDate: Date,
29
+ granularity: string,
30
+ ): Promise<
31
+ Array<{
32
+ date: Date;
33
+ downloads: number;
34
+ installs: number;
35
+ views: number;
36
+ ratings: number;
37
+ averageRating: number;
38
+ uniqueUsers: number;
39
+ }>
40
+ >;
41
+
42
+ getPublisherTrends(
43
+ publisherId: string,
44
+ days: number,
45
+ ): Promise<{
46
+ downloadTrend: string;
47
+ downloadChange: number;
48
+ installTrend: string;
49
+ installChange: number;
50
+ viewTrend: string;
51
+ viewChange: number;
52
+ ratingTrend: string;
53
+ ratingChange: number;
54
+ trendScore: number;
55
+ }>;
56
+ }
@@ -1,4 +1,4 @@
1
- import { IPublishRequest, IExtensionRelease, IBaseService, IRegistryExtensionModel, AsDomainType } from 'common/server';
1
+ import { IMarketplacePublishExtensionInput, IExtensionRelease, IBaseService, IRegistryExtensionModel, AsDomainType } from 'common/server';
2
2
 
3
3
  export interface IRegistryExtensionService extends IBaseService<AsDomainType<IRegistryExtensionModel>> {
4
4
  extensionReleases(extensionSlug: string): Promise<IExtensionRelease[]>;
@@ -11,9 +11,53 @@ export interface IRegistryExtensionService extends IBaseService<AsDomainType<IRe
11
11
 
12
12
  deleteExtension(extensionSlug: string): boolean | Promise<boolean>;
13
13
 
14
- publishExtension(request: IPublishRequest): Promise<AsDomainType<IRegistryExtensionModel>>;
14
+ publishExtension(request: IMarketplacePublishExtensionInput): Promise<AsDomainType<IRegistryExtensionModel>>;
15
15
 
16
16
  findExtensions(first: number, query: string, local?: boolean, remote?: boolean, prioritizeExtensionIDs?: string[]): Promise<AsDomainType<IRegistryExtensionModel>[]>;
17
17
 
18
18
  findExtension(extensionSlug: string): Promise<AsDomainType<IRegistryExtensionModel>>;
19
+
20
+ // Enhanced marketplace features
21
+ formSubmission(input: {
22
+ extensionSlug: string;
23
+ formData: string;
24
+ submissionType: string;
25
+ metadata?: string;
26
+ }): Promise<{
27
+ success: boolean;
28
+ message?: string;
29
+ errors?: string[];
30
+ submissionId?: string;
31
+ data?: string;
32
+ }>;
33
+
34
+ validateExtension(input: {
35
+ manifest: string;
36
+ bundle?: string;
37
+ sourceMap?: string;
38
+ extensionSlug?: string;
39
+ version?: string;
40
+ }): Promise<{
41
+ isValid: boolean;
42
+ errors: Array<{ field: string; message: string; code?: string }>;
43
+ warnings: Array<{ field: string; message: string; code?: string }>;
44
+ metadata?: string;
45
+ }>;
46
+
47
+ publishExtensionEnhanced(input: {
48
+ extensionSlug: string;
49
+ manifest: string;
50
+ bundle: string;
51
+ sourceMap?: string;
52
+ version: string;
53
+ releaseNotes?: string;
54
+ force?: boolean;
55
+ preRelease?: boolean;
56
+ }): Promise<{
57
+ success: boolean;
58
+ extension?: AsDomainType<IRegistryExtensionModel>;
59
+ message?: string;
60
+ errors?: string[];
61
+ releaseId?: string;
62
+ }>;
19
63
  }
@@ -1,2 +1 @@
1
- export {};
2
1
  //# sourceMappingURL=extension-integration.test.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=install-extension-graphql.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-extension-graphql.test.d.ts","sourceRoot":"","sources":["../../src/tests/install-extension-graphql.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Backend validation utilities for publisher data
3
+ */
4
+ export interface ValidationResult {
5
+ valid: boolean;
6
+ error?: string;
7
+ }
8
+ /**
9
+ * Validates a publisher name on the backend
10
+ * Ensures it doesn't contain characters that would break URL routing or extension slug parsing
11
+ */
12
+ export declare function validatePublisherName(publisherName: string): ValidationResult;
13
+ /**
14
+ * Validates publisher data for creation or update
15
+ */
16
+ export declare function validatePublisherData(data: {
17
+ publisherName: string;
18
+ displayName: string;
19
+ email?: string;
20
+ website?: string;
21
+ description?: string;
22
+ }): ValidationResult;
23
+ //# sourceMappingURL=publisherValidation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publisherValidation.d.ts","sourceRoot":"","sources":["../../src/utils/publisherValidation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,gBAAgB;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM,GAAG,gBAAgB,CA4E7E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,gBAAgB,CA2CnB"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Backend validation utilities for publisher data
3
+ */
4
+ /**
5
+ * Validates a publisher name on the backend
6
+ * Ensures it doesn't contain characters that would break URL routing or extension slug parsing
7
+ */
8
+ function validatePublisherName(publisherName) {
9
+ if (!publisherName || publisherName.trim().length === 0) {
10
+ return {
11
+ valid: false,
12
+ error: 'Publisher name is required'
13
+ };
14
+ }
15
+ const trimmed = publisherName.trim();
16
+ // Check minimum length
17
+ if (trimmed.length < 2) {
18
+ return {
19
+ valid: false,
20
+ error: 'Publisher name must be at least 2 characters long'
21
+ };
22
+ }
23
+ // Check maximum length
24
+ if (trimmed.length > 50) {
25
+ return {
26
+ valid: false,
27
+ error: 'Publisher name must be less than 50 characters'
28
+ };
29
+ }
30
+ // Check for invalid characters that would break routing or parsing
31
+ if (trimmed.includes('/')) {
32
+ return {
33
+ valid: false,
34
+ error: 'Publisher name cannot contain forward slashes (/)'
35
+ };
36
+ }
37
+ if (trimmed.includes('.')) {
38
+ return {
39
+ valid: false,
40
+ error: 'Publisher name cannot contain dots (.)'
41
+ };
42
+ }
43
+ if (trimmed.includes('\\')) {
44
+ return {
45
+ valid: false,
46
+ error: 'Publisher name cannot contain backslashes (\\)'
47
+ };
48
+ }
49
+ // Check for other URL-unsafe characters
50
+ const urlUnsafeChars = ['?', '#', '&', '%', '+', '=', '<', '>', '"', '`', '{', '}', '|', '^', '[', ']', '@', ':', ';', ',', ' '];
51
+ for (const char of urlUnsafeChars) {
52
+ if (trimmed.includes(char)) {
53
+ return {
54
+ valid: false,
55
+ error: `Publisher name cannot contain the character: ${char}`
56
+ };
57
+ }
58
+ }
59
+ // Check if it starts or ends with special characters
60
+ if (trimmed.startsWith('-') || trimmed.endsWith('-')) {
61
+ return {
62
+ valid: false,
63
+ error: 'Publisher name cannot start or end with hyphens'
64
+ };
65
+ }
66
+ if (trimmed.startsWith('_') || trimmed.endsWith('_')) {
67
+ return {
68
+ valid: false,
69
+ error: 'Publisher name cannot start or end with underscores'
70
+ };
71
+ }
72
+ // Only allow alphanumeric characters, hyphens, and underscores
73
+ const validPattern = /^[a-zA-Z0-9]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;
74
+ if (!validPattern.test(trimmed)) {
75
+ return {
76
+ valid: false,
77
+ error: 'Publisher name can only contain letters, numbers, hyphens, and underscores'
78
+ };
79
+ }
80
+ return {
81
+ valid: true
82
+ };
83
+ }
84
+ /**
85
+ * Validates publisher data for creation or update
86
+ */
87
+ function validatePublisherData(data) {
88
+ // Validate publisher name
89
+ const nameValidation = validatePublisherName(data.publisherName);
90
+ if (!nameValidation.valid) {
91
+ return nameValidation;
92
+ }
93
+ // Validate display name
94
+ if (!data.displayName || data.displayName.trim().length === 0) {
95
+ return {
96
+ valid: false,
97
+ error: 'Display name is required'
98
+ };
99
+ }
100
+ if (data.displayName.trim().length > 100) {
101
+ return {
102
+ valid: false,
103
+ error: 'Display name must be less than 100 characters'
104
+ };
105
+ }
106
+ // Validate email if provided
107
+ if (data.email && data.email.trim().length > 0) {
108
+ const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
109
+ if (!emailPattern.test(data.email)) {
110
+ return {
111
+ valid: false,
112
+ error: 'Please provide a valid email address'
113
+ };
114
+ }
115
+ }
116
+ // Validate website if provided
117
+ if (data.website && data.website.trim().length > 0) {
118
+ try {
119
+ const url = new URL(data.website);
120
+ // URL constructor validates the URL format
121
+ if (!url.protocol.startsWith('http')) {
122
+ return {
123
+ valid: false,
124
+ error: 'Website must use http or https protocol'
125
+ };
126
+ }
127
+ } catch {
128
+ return {
129
+ valid: false,
130
+ error: 'Website must be a valid URL'
131
+ };
132
+ }
133
+ }
134
+ // Validate description length if provided
135
+ if (data.description && data.description.length > 1000) {
136
+ return {
137
+ valid: false,
138
+ error: 'Description must be less than 1000 characters'
139
+ };
140
+ }
141
+ return {
142
+ valid: true
143
+ };
144
+ }export{validatePublisherData,validatePublisherName};//# sourceMappingURL=publisherValidation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publisherValidation.js","sources":["../../src/utils/publisherValidation.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;;AAEG;AAEH;;;AAGC;AAED,SAAA,qBAAA,CAAA,aAAA,EAAA;;;AAGG,MAAA,KAAA,EAAA,KAAA;AACH,MAAA,KAAA,EAAA;AA8EA,KAAA;;AAEG,EAAA,MAAA,OAAA,GAAA,aAAA,CAAA,IAAA,EAAA;AACH;MACI,OAAA,CAAA,YAAsB;IACtB,OAAA;MACA,KAAM,EAAE,KAAM;MACd,KAAO,EAAC;KACR;AACH,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}