@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.
- package/lib/containers/module.d.ts +4 -4
- package/lib/containers/module.d.ts.map +1 -1
- package/lib/containers/module.js +12 -7
- package/lib/containers/module.js.map +1 -1
- package/lib/dataloaders/index.d.ts +1 -1
- package/lib/dataloaders/index.d.ts.map +1 -1
- package/lib/dataloaders/publisher-data-loader.d.ts +6 -0
- package/lib/dataloaders/publisher-data-loader.d.ts.map +1 -0
- package/lib/demo/test-graphql-examples.d.ts +73 -0
- package/lib/demo/test-graphql-examples.d.ts.map +1 -0
- package/lib/graphql/resolvers/form-templates-resolver.d.ts +220 -0
- package/lib/graphql/resolvers/form-templates-resolver.d.ts.map +1 -0
- package/lib/graphql/resolvers/form-templates-resolver.js +170 -0
- package/lib/graphql/resolvers/form-templates-resolver.js.map +1 -0
- package/lib/graphql/resolvers/gallery-resolver.d.ts +15 -0
- package/lib/graphql/resolvers/gallery-resolver.d.ts.map +1 -0
- package/lib/graphql/resolvers/gallery-resolver.js +35 -0
- package/lib/graphql/resolvers/gallery-resolver.js.map +1 -0
- package/lib/graphql/resolvers/index.d.ts +247 -1
- package/lib/graphql/resolvers/index.d.ts.map +1 -1
- package/lib/graphql/resolvers/index.js +1 -1
- package/lib/graphql/resolvers/installed-extension-resolver.d.ts.map +1 -1
- package/lib/graphql/resolvers/installed-extension-resolver.js +161 -35
- package/lib/graphql/resolvers/installed-extension-resolver.js.map +1 -1
- package/lib/graphql/resolvers/marketplace-form-resolver.d.ts +13 -0
- package/lib/graphql/resolvers/marketplace-form-resolver.d.ts.map +1 -0
- package/lib/graphql/resolvers/marketplace-form-resolver.js +90 -0
- package/lib/graphql/resolvers/marketplace-form-resolver.js.map +1 -0
- package/lib/graphql/resolvers/publisher-analytics-resolver.d.ts +14 -0
- package/lib/graphql/resolvers/publisher-analytics-resolver.d.ts.map +1 -0
- package/lib/graphql/resolvers/publisher-analytics-resolver.js +221 -0
- package/lib/graphql/resolvers/publisher-analytics-resolver.js.map +1 -0
- package/lib/graphql/resolvers/publisher-resolver.d.ts +5 -0
- package/lib/graphql/resolvers/publisher-resolver.d.ts.map +1 -0
- package/lib/graphql/resolvers/publisher-resolver.js +183 -0
- package/lib/graphql/resolvers/publisher-resolver.js.map +1 -0
- package/lib/graphql/resolvers/registry-extension-resolver.d.ts.map +1 -1
- package/lib/graphql/resolvers/registry-extension-resolver.js +34 -167
- package/lib/graphql/resolvers/registry-extension-resolver.js.map +1 -1
- package/lib/graphql/schemas/extension-pricing.graphql +546 -0
- package/lib/graphql/schemas/extension-pricing.graphql.js +1 -0
- package/lib/graphql/schemas/extension-pricing.graphql.js.map +1 -0
- package/lib/graphql/schemas/extension-registry.graphql +91 -58
- package/lib/graphql/schemas/extension-registry.graphql.js +1 -1
- package/lib/graphql/schemas/form-templates.graphql +269 -0
- package/lib/graphql/schemas/form-templates.graphql.js +1 -0
- package/lib/graphql/schemas/form-templates.graphql.js.map +1 -0
- package/lib/graphql/schemas/gallery-schema.graphql +247 -0
- package/lib/graphql/schemas/gallery-schema.graphql.js +1 -0
- package/lib/graphql/schemas/gallery-schema.graphql.js.map +1 -0
- package/lib/graphql/schemas/index.d.ts.map +1 -1
- package/lib/graphql/schemas/index.js +3 -1
- package/lib/graphql/schemas/index.js.map +1 -1
- package/lib/graphql/schemas/installed-extension.graphql +37 -7
- package/lib/graphql/schemas/installed-extension.graphql.js +1 -1
- package/lib/graphql/schemas/publisher-analytics.graphql +305 -0
- package/lib/graphql/schemas/publisher-analytics.graphql.js +1 -0
- package/lib/graphql/schemas/publisher-analytics.graphql.js.map +1 -0
- package/lib/graphql/schemas/publisher.graphql +584 -0
- package/lib/graphql/schemas/publisher.graphql.js +1 -0
- package/lib/graphql/schemas/publisher.graphql.js.map +1 -0
- package/lib/graphql/schemas/service.graphql +15 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/migrations/dbMigrations/DropOldPublisherIndexMigration.d.ts +20 -0
- package/lib/migrations/dbMigrations/DropOldPublisherIndexMigration.d.ts.map +1 -0
- package/lib/migrations/dbMigrations/DropOldPublisherIndexMigration.js +61 -0
- package/lib/migrations/dbMigrations/DropOldPublisherIndexMigration.js.map +1 -0
- package/lib/migrations/index.d.ts +2 -0
- package/lib/migrations/index.d.ts.map +1 -0
- package/lib/module.d.ts +1 -1
- package/lib/module.d.ts.map +1 -1
- package/lib/module.js +11 -26
- package/lib/module.js.map +1 -1
- package/lib/services/extension-gallery-repository.d.ts +17 -0
- package/lib/services/extension-gallery-repository.d.ts.map +1 -0
- package/lib/services/extension-gallery-repository.js +192 -0
- package/lib/services/extension-gallery-repository.js.map +1 -0
- package/lib/services/extension-gallery-service-new.d.ts +39 -0
- package/lib/services/extension-gallery-service-new.d.ts.map +1 -0
- package/lib/services/extension-gallery-service.d.ts +30 -0
- package/lib/services/extension-gallery-service.d.ts.map +1 -0
- package/lib/services/extension-gallery-service.js +334 -0
- package/lib/services/extension-gallery-service.js.map +1 -0
- package/lib/services/index.d.ts +4 -1
- package/lib/services/index.d.ts.map +1 -1
- package/lib/services/installed-extension-service-ext.d.ts +5 -2
- package/lib/services/installed-extension-service-ext.d.ts.map +1 -1
- package/lib/services/installed-extension-service-ext.js +364 -117
- package/lib/services/installed-extension-service-ext.js.map +1 -1
- package/lib/services/installed-extension-service.d.ts +30 -13
- package/lib/services/installed-extension-service.d.ts.map +1 -1
- package/lib/services/installed-extension-service.js +301 -68
- package/lib/services/installed-extension-service.js.map +1 -1
- package/lib/services/installed-extension-service.test.d.ts +0 -1
- package/lib/services/publisher-analytics-service.d.ts +128 -0
- package/lib/services/publisher-analytics-service.d.ts.map +1 -0
- package/lib/services/publisher-event-service.d.ts +48 -0
- package/lib/services/publisher-event-service.d.ts.map +1 -0
- package/lib/services/publisher-event-service.js +296 -0
- package/lib/services/publisher-event-service.js.map +1 -0
- package/lib/services/publisher-service-context.d.ts +1 -0
- package/lib/services/publisher-service-context.d.ts.map +1 -0
- package/lib/services/publisher-service.d.ts +62 -0
- package/lib/services/publisher-service.d.ts.map +1 -0
- package/lib/services/publisher-service.js +135 -0
- package/lib/services/publisher-service.js.map +1 -0
- package/lib/store/models/index.d.ts +1 -1
- package/lib/store/models/index.d.ts.map +1 -1
- package/lib/store/models/installed-extension-model.d.ts.map +1 -1
- package/lib/store/models/installed-extension-model.js +17 -45
- package/lib/store/models/installed-extension-model.js.map +1 -1
- package/lib/store/models/publisher-event-model.d.ts +11 -0
- package/lib/store/models/publisher-event-model.d.ts.map +1 -0
- package/lib/store/models/publisher-model.d.ts +5 -0
- package/lib/store/models/publisher-model.d.ts.map +1 -0
- package/lib/store/models/publisher-model.js +117 -0
- package/lib/store/models/publisher-model.js.map +1 -0
- package/lib/store/models/publisher-stats-model.d.ts +1 -0
- package/lib/store/models/publisher-stats-model.d.ts.map +1 -0
- package/lib/store/repositories/index.d.ts +1 -1
- package/lib/store/repositories/index.d.ts.map +1 -1
- package/lib/store/repositories/installed-extension-repository.d.ts +17 -11
- package/lib/store/repositories/installed-extension-repository.d.ts.map +1 -1
- package/lib/store/repositories/installed-extension-repository.js +123 -75
- package/lib/store/repositories/installed-extension-repository.js.map +1 -1
- package/lib/store/repositories/publisher-analytics-repository.d.ts +1 -0
- package/lib/store/repositories/publisher-analytics-repository.d.ts.map +1 -0
- package/lib/store/repositories/publisher-repository.d.ts +19 -0
- package/lib/store/repositories/publisher-repository.d.ts.map +1 -0
- package/lib/store/repositories/publisher-repository.js +87 -0
- package/lib/store/repositories/publisher-repository.js.map +1 -0
- package/lib/templates/constants/DB_COLL_NAMES.ts.template +1 -1
- package/lib/templates/constants/SERVER_TYPES.ts.template +8 -5
- package/lib/templates/repositories/ExtensionGalleryRepository.ts.template +44 -0
- package/lib/templates/repositories/InstalledExtensionRepository.ts.template +19 -14
- package/lib/templates/repositories/MarketplacePublisherRepository.ts.template +24 -0
- package/lib/templates/repositories/RegistryExtensionRepository.ts.template +2 -2
- package/lib/templates/services/ExtensionGalleryDataLoader.ts.template +2 -0
- package/lib/templates/services/ExtensionGalleryService.ts.template +79 -0
- package/lib/templates/services/InstalledExtensionService.ts.template +63 -32
- package/lib/templates/services/MarketplacePublisherService.ts.template +51 -0
- package/lib/templates/services/PublisherDataLoader.ts.template +3 -0
- package/lib/templates/services/PublisherEventService.ts.template +56 -0
- package/lib/templates/services/RegistryExtensionService.ts.template +46 -2
- package/lib/tests/extension-integration.test.d.ts +0 -1
- package/lib/tests/install-extension-graphql.test.d.ts +2 -0
- package/lib/tests/install-extension-graphql.test.d.ts.map +1 -0
- package/lib/utils/publisherValidation.d.ts +23 -0
- package/lib/utils/publisherValidation.d.ts.map +1 -0
- package/lib/utils/publisherValidation.js +144 -0
- package/lib/utils/publisherValidation.js.map +1 -0
- package/package.json +13 -9
- package/lib/constants/extension-events.d.ts +0 -136
- package/lib/constants/extension-events.d.ts.map +0 -1
- package/lib/dataloaders/registry-extension-data-loader.d.ts +0 -6
- package/lib/dataloaders/registry-extension-data-loader.d.ts.map +0 -1
- package/lib/dataloaders/registry-extension-data-loader.js +0 -6
- package/lib/dataloaders/registry-extension-data-loader.js.map +0 -1
- package/lib/graphql/schemas/service.graphql.js +0 -1
- package/lib/graphql/schemas/service.graphql.js.map +0 -1
- package/lib/services/extension-service.d.ts +0 -42
- package/lib/services/extension-service.d.ts.map +0 -1
- package/lib/services/extension-service.js +0 -60
- package/lib/services/extension-service.js.map +0 -1
- package/lib/store/models/registry-extension-model.d.ts +0 -5
- package/lib/store/models/registry-extension-model.d.ts.map +0 -1
- package/lib/store/models/registry-extension-model.js +0 -83
- package/lib/store/models/registry-extension-model.js.map +0 -1
- package/lib/store/repositories/registry-extension-repository.d.ts +0 -54
- package/lib/store/repositories/registry-extension-repository.d.ts.map +0 -1
- package/lib/store/repositories/registry-extension-repository.js +0 -137
- package/lib/store/repositories/registry-extension-repository.js.map +0 -1
- 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 {
|
|
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:
|
|
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,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
|
-
|
|
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
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
100
|
+
getInstalledExtension(
|
|
101
|
+
orgId: string,
|
|
102
|
+
extensionSlug: string,
|
|
103
|
+
): Promise<AsDomainType<IInstalledExtensionModel> | null>;
|
|
96
104
|
|
|
97
105
|
/**
|
|
98
|
-
* Get all installed extensions
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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,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 {
|
|
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:
|
|
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
|
}
|
|
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|