@ampsec/platform-client 47.3.0 → 47.4.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/build/src/dto/assetKeys.d.ts +2 -0
- package/build/src/dto/entityIdSummaries.dto.d.ts +22 -0
- package/build/src/dto/entityIdSummaries.dto.js +3 -0
- package/build/src/dto/entityIdSummaries.dto.js.map +1 -0
- package/build/src/dto/enums/globalUser.type.d.ts +1 -0
- package/build/src/dto/enums/globalUser.type.js +1 -0
- package/build/src/dto/enums/globalUser.type.js.map +1 -1
- package/build/src/dto/extKeyMap.dto.d.ts +2 -0
- package/build/src/dto/index.d.ts +1 -0
- package/build/src/dto/index.js +1 -0
- package/build/src/dto/index.js.map +1 -1
- package/build/src/services/AmpSdk.d.ts +8 -7
- package/build/src/services/AmpSdk.js +9 -8
- package/build/src/services/AmpSdk.js.map +1 -1
- package/build/src/services/entity.service.d.ts +12 -10
- package/build/src/services/entity.service.js +81 -16
- package/build/src/services/entity.service.js.map +1 -1
- package/build/src/services/index.d.ts +3 -0
- package/build/src/services/index.js +3 -0
- package/build/src/services/index.js.map +1 -1
- package/build/src/services/lookup.service.d.ts +55 -0
- package/build/src/services/lookup.service.js +173 -0
- package/build/src/services/lookup.service.js.map +1 -0
- package/build/src/services/saasEntity.service.d.ts +32 -0
- package/build/src/services/saasEntity.service.js +154 -0
- package/build/src/services/saasEntity.service.js.map +1 -0
- package/build/src/services/utils.d.ts +1 -0
- package/build/src/services/utils.js +15 -0
- package/build/src/services/utils.js.map +1 -0
- package/package.json +1 -1
- package/src/dto/assetKeys.ts +2 -0
- package/src/dto/entityIdSummaries.dto.ts +27 -0
- package/src/dto/enums/globalUser.type.ts +1 -0
- package/src/dto/extKeyMap.dto.ts +2 -0
- package/src/dto/index.ts +1 -0
- package/src/services/AmpSdk.ts +12 -29
- package/src/services/entity.service.ts +87 -24
- package/src/services/index.ts +3 -0
- package/src/services/lookup.service.ts +176 -0
- package/src/services/saasEntity.service.ts +181 -0
- package/src/services/utils.ts +8 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import {AssetIdDto, AssetKeys, RawUserIds, SaasComponentIdDto, UserIdDto} from '../dto';
|
|
3
|
+
import {formatMacAddress} from './utils';
|
|
4
|
+
|
|
5
|
+
export class UserLookupService {
|
|
6
|
+
private readonly emailLookupMap = new Map<string, UserIdDto>();
|
|
7
|
+
private readonly extIdLookupMap = new Map<string, UserIdDto>();
|
|
8
|
+
private lastUpdated = new Date('2023-04-17T13:00:00.000Z');
|
|
9
|
+
|
|
10
|
+
getLastUpdated(): string {
|
|
11
|
+
return this.lastUpdated.toISOString();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// TODO throw errors if conflicts are found
|
|
15
|
+
/**
|
|
16
|
+
* Emails are normalized to lower case but external IDs are case sensitive
|
|
17
|
+
*/
|
|
18
|
+
add(user: UserIdDto) {
|
|
19
|
+
user.emails.forEach(email => this.emailLookupMap.set(email.toLowerCase(), user));
|
|
20
|
+
if (user.extId) {
|
|
21
|
+
this.extIdLookupMap.set(user.extId, user);
|
|
22
|
+
}
|
|
23
|
+
this.lastUpdated = new Date();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// TODO throw errors if conflicts are found
|
|
27
|
+
/**
|
|
28
|
+
* Calls through to `byEmails` and `byExtId`
|
|
29
|
+
*/
|
|
30
|
+
lookup(userIds?: RawUserIds): UserIdDto[] {
|
|
31
|
+
if (!userIds) {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
const matches = [] as UserIdDto[];
|
|
35
|
+
const emails = [];
|
|
36
|
+
if (userIds.primaryEmail) {
|
|
37
|
+
emails.push(userIds.primaryEmail);
|
|
38
|
+
}
|
|
39
|
+
if (Array.isArray(userIds.emails)) {
|
|
40
|
+
emails.push(...userIds.emails);
|
|
41
|
+
}
|
|
42
|
+
matches.push(...this.byEmails(emails));
|
|
43
|
+
if (userIds.extId) {
|
|
44
|
+
const match = this.byExtId(userIds.extId);
|
|
45
|
+
if (match) {
|
|
46
|
+
matches.push(match);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return _.uniqBy(matches, 'id');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Emails are normalized to lower case
|
|
54
|
+
*/
|
|
55
|
+
byEmails(emails: string[]): UserIdDto[] {
|
|
56
|
+
const matches = [] as UserIdDto[];
|
|
57
|
+
if (!Array.isArray(emails)) {
|
|
58
|
+
emails = [emails];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
emails = _.uniq(emails);
|
|
62
|
+
|
|
63
|
+
for (const email of emails) {
|
|
64
|
+
const match = this.emailLookupMap.get(email.toLocaleLowerCase());
|
|
65
|
+
if (match) {
|
|
66
|
+
matches.push(match);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return _.uniqBy(matches, 'id');
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Emails are normalized to lower case
|
|
73
|
+
*/
|
|
74
|
+
byEmail(email: string): UserIdDto | undefined {
|
|
75
|
+
return this.emailLookupMap.get(email.toLocaleLowerCase());
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* External IDs are case sensitive
|
|
80
|
+
*/
|
|
81
|
+
byExtId(extId: string): UserIdDto | undefined {
|
|
82
|
+
return this.extIdLookupMap.get(extId);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export class AssetLookupService {
|
|
87
|
+
private readonly macsLookupMap = new Map<string, AssetIdDto>();
|
|
88
|
+
private readonly snLookupMap = new Map<string, AssetIdDto>();
|
|
89
|
+
private readonly extIdLookupMap = new Map<string, AssetIdDto>();
|
|
90
|
+
private lastUpdated = new Date('2023-04-17T13:00:00.000Z');
|
|
91
|
+
|
|
92
|
+
getLastUpdated(): string {
|
|
93
|
+
return this.lastUpdated.toISOString();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// TODO throw errors if conflicts are found
|
|
97
|
+
/**
|
|
98
|
+
* Macs are normalized to standard format using `formatMacAddress` but serial numbers and external IDs are case sensitive
|
|
99
|
+
*/
|
|
100
|
+
add(asset: AssetIdDto) {
|
|
101
|
+
asset.macs?.forEach(mac => this.macsLookupMap.set(formatMacAddress(mac), asset));
|
|
102
|
+
if (asset.sn) {
|
|
103
|
+
this.snLookupMap.set(asset.sn, asset);
|
|
104
|
+
}
|
|
105
|
+
if (asset.extId) {
|
|
106
|
+
this.extIdLookupMap.set(asset.extId, asset);
|
|
107
|
+
}
|
|
108
|
+
this.lastUpdated = new Date();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// TODO throw errors if conflicts are found
|
|
112
|
+
lookup(keys: AssetKeys): AssetIdDto[] {
|
|
113
|
+
const matches = [] as AssetIdDto[];
|
|
114
|
+
matches.push(...this.byMacs(keys.macs));
|
|
115
|
+
if (keys.sn) {
|
|
116
|
+
const ids = this.bySn(keys.sn);
|
|
117
|
+
if (ids) {
|
|
118
|
+
matches.push(ids);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (keys.extId) {
|
|
122
|
+
const match = this.byExtId(keys.extId);
|
|
123
|
+
if (match) {
|
|
124
|
+
matches.push(match);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return _.uniqBy(matches, 'id');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Macs are normalized to standard format using `formatMacAddress`
|
|
132
|
+
*/
|
|
133
|
+
byMacs(macs: string | string[]): AssetIdDto[] {
|
|
134
|
+
const matches = [] as AssetIdDto[];
|
|
135
|
+
if (!Array.isArray(macs)) {
|
|
136
|
+
macs = [macs];
|
|
137
|
+
}
|
|
138
|
+
for (const mac of macs) {
|
|
139
|
+
const match = this.macsLookupMap.get(formatMacAddress(mac));
|
|
140
|
+
if (match) {
|
|
141
|
+
matches.push(match);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return _.uniqBy(matches, 'id');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
bySn(sn?: string): AssetIdDto | undefined {
|
|
148
|
+
return sn ? this.snLookupMap.get(sn) : undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* External IDs are case sensitive
|
|
153
|
+
*/
|
|
154
|
+
byExtId(extId: string): AssetIdDto | undefined {
|
|
155
|
+
return this.extIdLookupMap.get(extId);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export class SaasComponentLookupService {
|
|
160
|
+
private readonly extIdLookupMap = new Map<string, SaasComponentIdDto>();
|
|
161
|
+
private lastUpdated = new Date('2023-04-17T13:00:00.000Z');
|
|
162
|
+
|
|
163
|
+
getLastUpdated(): string {
|
|
164
|
+
return this.lastUpdated.toISOString();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// TODO throw errors if conflicts are found
|
|
168
|
+
add(sc: SaasComponentIdDto) {
|
|
169
|
+
this.extIdLookupMap.set(sc.extId, sc);
|
|
170
|
+
this.lastUpdated = new Date();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
byExtId(extId: string): SaasComponentIdDto | undefined {
|
|
174
|
+
return this.extIdLookupMap.get(extId);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import {
|
|
3
|
+
AssetIdDto,
|
|
4
|
+
BaseDto,
|
|
5
|
+
BaseUpsertDto,
|
|
6
|
+
ExtKeyMap,
|
|
7
|
+
Page,
|
|
8
|
+
PlatformSaasAssetDto,
|
|
9
|
+
PlatformSaasAssetUpsertDto,
|
|
10
|
+
PlatformSaasComponentDto,
|
|
11
|
+
PlatformSaasComponentUpsertDto,
|
|
12
|
+
PlatformSaasUserDto,
|
|
13
|
+
PlatformSaasUserUpsertDto,
|
|
14
|
+
SaasComponentIdDto,
|
|
15
|
+
UserIdDto,
|
|
16
|
+
} from '../dto';
|
|
17
|
+
import {TargetApi, TARGET_API_AGENT, ErrorHandler, KIND} from './constants';
|
|
18
|
+
import {AmpDataService} from './data.service';
|
|
19
|
+
import {RestClient, RestRequest} from './rest';
|
|
20
|
+
import {QueryMap} from './rest/utils';
|
|
21
|
+
import {AssetLookupService, SaasComponentLookupService, UserLookupService} from './lookup.service';
|
|
22
|
+
import {AmpEntityServiceImpl, EntityCallOptions} from './entity.service';
|
|
23
|
+
|
|
24
|
+
const LOOKUP_ID_PAGE_SIZE = 50;
|
|
25
|
+
|
|
26
|
+
export interface AmpSaaSEntityService<WriteT extends BaseUpsertDto, ReadT extends BaseDto> extends AmpDataService<ReadT> {
|
|
27
|
+
create(_model: WriteT | WriteT[], _options?: EntityCallOptions): Promise<Page<ReadT>>;
|
|
28
|
+
update(_model: WriteT | WriteT[], _options?: EntityCallOptions): Promise<Page<ReadT>>;
|
|
29
|
+
delete(_id: string, _options?: EntityCallOptions): Promise<Page<ReadT>>;
|
|
30
|
+
getLookupIds(_cid: string, _options?: EntityCallOptions): Promise<ExtKeyMap>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const extIdMapErrorHandler: ErrorHandler<ExtKeyMap> = (error: unknown) => {
|
|
34
|
+
if (error instanceof Error) {
|
|
35
|
+
console.error(error.message);
|
|
36
|
+
}
|
|
37
|
+
return {};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export class AmpSaaSEntityServiceImpl<WriteT extends BaseUpsertDto, ReadT extends BaseDto>
|
|
41
|
+
extends AmpEntityServiceImpl<WriteT, ReadT>
|
|
42
|
+
implements AmpSaaSEntityService<WriteT, ReadT>
|
|
43
|
+
{
|
|
44
|
+
constructor(rest: RestClient, kind: string, targetApi: TargetApi = TARGET_API_AGENT) {
|
|
45
|
+
super(rest, kind, targetApi);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** @deprecated */
|
|
49
|
+
getLookupIds = (cid: string, options?: EntityCallOptions): Promise<ExtKeyMap> => {
|
|
50
|
+
const req: RestRequest = {
|
|
51
|
+
url: `/${this.targetApi}/v1/${this.kind}/ext_key_map`,
|
|
52
|
+
method: 'GET',
|
|
53
|
+
params: {
|
|
54
|
+
...((options?.params as QueryMap) ?? {}),
|
|
55
|
+
cid,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
return this.call(req, extIdMapErrorHandler);
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const errorHandler = (error: unknown) => {
|
|
63
|
+
if (error instanceof Error) {
|
|
64
|
+
console.error(error.message);
|
|
65
|
+
}
|
|
66
|
+
throw error;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export class AmpSdkSaasUserService extends AmpSaaSEntityServiceImpl<PlatformSaasUserUpsertDto, PlatformSaasUserDto> {
|
|
70
|
+
constructor(rest: RestClient, targetApi: TargetApi = TARGET_API_AGENT) {
|
|
71
|
+
super(rest, KIND.SAAS_USERS, targetApi);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getLookup = async (cid: string, options?: EntityCallOptions): Promise<UserLookupService> => {
|
|
75
|
+
const lookup = new UserLookupService();
|
|
76
|
+
return this.refreshLookup(lookup, cid, options);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
refreshLookup = async (lookup: UserLookupService, cid: string, options?: EntityCallOptions): Promise<UserLookupService> => {
|
|
80
|
+
const limit = LOOKUP_ID_PAGE_SIZE;
|
|
81
|
+
let offset = 0;
|
|
82
|
+
let hasMore = true;
|
|
83
|
+
if (!options) {
|
|
84
|
+
options = {params: {}};
|
|
85
|
+
}
|
|
86
|
+
_.set(options, 'params.updatedAt', {$gt: lookup.getLastUpdated()});
|
|
87
|
+
while (hasMore) {
|
|
88
|
+
const req: RestRequest = {
|
|
89
|
+
url: `/${this.targetApi}/v1/${this.kind}/id_summary`,
|
|
90
|
+
method: 'GET',
|
|
91
|
+
params: {
|
|
92
|
+
...((options?.params as QueryMap) ?? {}),
|
|
93
|
+
cid,
|
|
94
|
+
limit,
|
|
95
|
+
offset,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
const page = await this.call(req, errorHandler as ErrorHandler<Page<UserIdDto>>);
|
|
99
|
+
page.data.forEach(ids => lookup.add(ids));
|
|
100
|
+
offset = (page.hints.offset ?? offset) + limit;
|
|
101
|
+
hasMore = page.hints.hasMore ?? false;
|
|
102
|
+
}
|
|
103
|
+
return lookup;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export class AmpSdkSaasAssetService extends AmpSaaSEntityServiceImpl<PlatformSaasAssetUpsertDto, PlatformSaasAssetDto> {
|
|
108
|
+
constructor(rest: RestClient, targetApi: TargetApi = TARGET_API_AGENT) {
|
|
109
|
+
super(rest, KIND.SAAS_ASSETS, targetApi);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
getLookup = async (cid: string, options?: EntityCallOptions): Promise<AssetLookupService> => {
|
|
113
|
+
const lookup = new AssetLookupService();
|
|
114
|
+
return this.refreshLookup(lookup, cid, options);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
refreshLookup = async (lookup: AssetLookupService, cid: string, options?: EntityCallOptions): Promise<AssetLookupService> => {
|
|
118
|
+
const limit = LOOKUP_ID_PAGE_SIZE;
|
|
119
|
+
let offset = 0;
|
|
120
|
+
let hasMore = true;
|
|
121
|
+
if (!options) {
|
|
122
|
+
options = {params: {}};
|
|
123
|
+
}
|
|
124
|
+
_.set(options, 'params.updatedAt', {$gt: lookup.getLastUpdated()});
|
|
125
|
+
while (hasMore) {
|
|
126
|
+
const req: RestRequest = {
|
|
127
|
+
url: `/${this.targetApi}/v1/${this.kind}/id_summary`,
|
|
128
|
+
method: 'GET',
|
|
129
|
+
params: {
|
|
130
|
+
...((options?.params as QueryMap) ?? {}),
|
|
131
|
+
cid,
|
|
132
|
+
limit,
|
|
133
|
+
offset,
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
const page = await this.call(req, errorHandler as ErrorHandler<Page<AssetIdDto>>);
|
|
137
|
+
page.data.forEach(ids => lookup.add(ids));
|
|
138
|
+
offset = (page.hints.offset ?? offset) + limit;
|
|
139
|
+
hasMore = page.hints.hasMore ?? false;
|
|
140
|
+
}
|
|
141
|
+
return lookup;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export class AmpSdkSaasComponentService extends AmpSaaSEntityServiceImpl<PlatformSaasComponentUpsertDto, PlatformSaasComponentDto> {
|
|
146
|
+
constructor(rest: RestClient, targetApi: TargetApi = TARGET_API_AGENT) {
|
|
147
|
+
super(rest, KIND.SAAS_COMPONENTS, targetApi);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
getLookup = async (cid: string, options?: EntityCallOptions): Promise<SaasComponentLookupService> => {
|
|
151
|
+
const lookup = new SaasComponentLookupService();
|
|
152
|
+
return this.refreshLookup(lookup, cid, options);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
refreshLookup = async (lookup: SaasComponentLookupService, cid: string, options?: EntityCallOptions): Promise<SaasComponentLookupService> => {
|
|
156
|
+
const limit = LOOKUP_ID_PAGE_SIZE;
|
|
157
|
+
let offset = 0;
|
|
158
|
+
let hasMore = true;
|
|
159
|
+
if (!options) {
|
|
160
|
+
options = {params: {}};
|
|
161
|
+
}
|
|
162
|
+
_.set(options, 'params.updatedAt', {$gt: lookup.getLastUpdated()});
|
|
163
|
+
while (hasMore) {
|
|
164
|
+
const req: RestRequest = {
|
|
165
|
+
url: `/${this.targetApi}/v1/${this.kind}/id_summary`,
|
|
166
|
+
method: 'GET',
|
|
167
|
+
params: {
|
|
168
|
+
...((options?.params as QueryMap) ?? {}),
|
|
169
|
+
cid,
|
|
170
|
+
limit,
|
|
171
|
+
offset,
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
const page = await this.call(req, errorHandler as ErrorHandler<Page<SaasComponentIdDto>>);
|
|
175
|
+
page.data.forEach(ids => lookup.add(ids));
|
|
176
|
+
offset = (page.hints.offset ?? offset) + limit;
|
|
177
|
+
hasMore = page.hints.hasMore ?? false;
|
|
178
|
+
}
|
|
179
|
+
return lookup;
|
|
180
|
+
};
|
|
181
|
+
}
|