@ampsec/platform-client 47.2.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.
Files changed (51) hide show
  1. package/build/src/dto/assetKeys.d.ts +2 -0
  2. package/build/src/dto/entityIdSummaries.dto.d.ts +22 -0
  3. package/build/src/dto/entityIdSummaries.dto.js +3 -0
  4. package/build/src/dto/entityIdSummaries.dto.js.map +1 -0
  5. package/build/src/dto/enums/globalUser.type.d.ts +1 -0
  6. package/build/src/dto/enums/globalUser.type.js +1 -0
  7. package/build/src/dto/enums/globalUser.type.js.map +1 -1
  8. package/build/src/dto/enums/index.d.ts +1 -0
  9. package/build/src/dto/enums/index.js +1 -0
  10. package/build/src/dto/enums/index.js.map +1 -1
  11. package/build/src/dto/enums/supportedMessageChannelKind.enum.d.ts +5 -0
  12. package/build/src/dto/enums/supportedMessageChannelKind.enum.js +21 -0
  13. package/build/src/dto/enums/supportedMessageChannelKind.enum.js.map +1 -0
  14. package/build/src/dto/extKeyMap.dto.d.ts +2 -0
  15. package/build/src/dto/index.d.ts +1 -0
  16. package/build/src/dto/index.js +1 -0
  17. package/build/src/dto/index.js.map +1 -1
  18. package/build/src/dto/notification.dto.d.ts +6 -1
  19. package/build/src/services/AmpSdk.d.ts +8 -7
  20. package/build/src/services/AmpSdk.js +9 -8
  21. package/build/src/services/AmpSdk.js.map +1 -1
  22. package/build/src/services/entity.service.d.ts +12 -10
  23. package/build/src/services/entity.service.js +81 -16
  24. package/build/src/services/entity.service.js.map +1 -1
  25. package/build/src/services/index.d.ts +3 -0
  26. package/build/src/services/index.js +3 -0
  27. package/build/src/services/index.js.map +1 -1
  28. package/build/src/services/lookup.service.d.ts +55 -0
  29. package/build/src/services/lookup.service.js +173 -0
  30. package/build/src/services/lookup.service.js.map +1 -0
  31. package/build/src/services/saasEntity.service.d.ts +32 -0
  32. package/build/src/services/saasEntity.service.js +154 -0
  33. package/build/src/services/saasEntity.service.js.map +1 -0
  34. package/build/src/services/utils.d.ts +1 -0
  35. package/build/src/services/utils.js +15 -0
  36. package/build/src/services/utils.js.map +1 -0
  37. package/package.json +1 -1
  38. package/src/dto/assetKeys.ts +2 -0
  39. package/src/dto/entityIdSummaries.dto.ts +27 -0
  40. package/src/dto/enums/globalUser.type.ts +1 -0
  41. package/src/dto/enums/index.ts +1 -0
  42. package/src/dto/enums/supportedMessageChannelKind.enum.ts +17 -0
  43. package/src/dto/extKeyMap.dto.ts +2 -0
  44. package/src/dto/index.ts +1 -0
  45. package/src/dto/notification.dto.ts +7 -1
  46. package/src/services/AmpSdk.ts +12 -29
  47. package/src/services/entity.service.ts +87 -24
  48. package/src/services/index.ts +3 -0
  49. package/src/services/lookup.service.ts +176 -0
  50. package/src/services/saasEntity.service.ts +181 -0
  51. package/src/services/utils.ts +8 -0
@@ -1,9 +1,12 @@
1
1
  import _ from 'lodash';
2
- import {BaseDto, BaseUpsertDto, ExtKeyMap, Page} from '../dto';
3
- import {TargetApi, TARGET_API_AGENT, ErrorHandler} from './constants';
2
+ import {AssetIdDto, BaseDto, BaseUpsertDto, ExtKeyMap, Page, PlatformAssetDto, PlatformAssetUpsertDto, PlatformUserDto, PlatformUserUpsertDto, UserIdDto} from '../dto';
3
+ import {TargetApi, TARGET_API_AGENT, ErrorHandler, KIND} from './constants';
4
4
  import {AmpDataService, AmpDataServiceImpl} from './data.service';
5
5
  import {RestClient, RestRequest} from './rest';
6
6
  import {QueryMap} from './rest/utils';
7
+ import {AssetLookupService, UserLookupService} from './lookup.service';
8
+
9
+ const LOOKUP_ID_PAGE_SIZE = 50;
7
10
 
8
11
  export type EntityCallOptions = {
9
12
  params: unknown;
@@ -20,18 +23,13 @@ export interface AmpSdkTenantService<WriteT extends BaseUpsertDto, ReadT extends
20
23
  update(_model: WriteT | WriteT[], _options?: EntityCallOptions): Promise<Page<ReadT>>;
21
24
  delete(_id: string, _options?: EntityCallOptions): Promise<Page<ReadT>>;
22
25
  }
26
+
23
27
  export interface AmpGlobalEntityService<WriteT extends BaseUpsertDto, ReadT extends BaseDto> extends AmpDataService<ReadT> {
24
28
  create(_model: WriteT | WriteT[], _options?: EntityCallOptions): Promise<Page<ReadT>>;
25
29
  update(_model: WriteT | WriteT[], _options?: EntityCallOptions): Promise<Page<ReadT>>;
26
30
  delete(_id: string, _options?: EntityCallOptions): Promise<Page<ReadT>>;
27
31
  getLookupIds(_tid: string, _options?: EntityCallOptions): Promise<ExtKeyMap>;
28
32
  }
29
- export interface AmpSaaSEntityService<WriteT extends BaseUpsertDto, ReadT extends BaseDto> extends AmpDataService<ReadT> {
30
- create(_model: WriteT | WriteT[], _options?: EntityCallOptions): Promise<Page<ReadT>>;
31
- update(_model: WriteT | WriteT[], _options?: EntityCallOptions): Promise<Page<ReadT>>;
32
- delete(_id: string, _options?: EntityCallOptions): Promise<Page<ReadT>>;
33
- getLookupIds(_cid: string, _options?: EntityCallOptions): Promise<ExtKeyMap>;
34
- }
35
33
 
36
34
  export class AmpEntityServiceImpl<WriteT extends BaseUpsertDto, ReadT extends BaseDto> extends AmpDataServiceImpl<ReadT> implements AmpEntityService<WriteT, ReadT> {
37
35
  constructor(rest: RestClient, kind: string, targetApi: TargetApi = TARGET_API_AGENT) {
@@ -93,6 +91,8 @@ export class AmpGlobalEntityServiceImpl<WriteT extends BaseUpsertDto, ReadT exte
93
91
  constructor(rest: RestClient, kind: string, targetApi: TargetApi = TARGET_API_AGENT) {
94
92
  super(rest, kind, targetApi);
95
93
  }
94
+
95
+ /** @deprecated */
96
96
  getLookupIds = (tid: string, options?: EntityCallOptions): Promise<ExtKeyMap> => {
97
97
  const req: RestRequest = {
98
98
  url: `/${this.targetApi}/v1/${this.kind}/ext_key_map`,
@@ -106,22 +106,85 @@ export class AmpGlobalEntityServiceImpl<WriteT extends BaseUpsertDto, ReadT exte
106
106
  };
107
107
  }
108
108
 
109
- export class AmpSaaSEntityServiceImpl<WriteT extends BaseUpsertDto, ReadT extends BaseDto>
110
- extends AmpEntityServiceImpl<WriteT, ReadT>
111
- implements AmpSaaSEntityService<WriteT, ReadT>
112
- {
113
- constructor(rest: RestClient, kind: string, targetApi: TargetApi = TARGET_API_AGENT) {
114
- super(rest, kind, targetApi);
109
+ const errorHandler = (error: unknown) => {
110
+ if (error instanceof Error) {
111
+ console.error(error.message);
115
112
  }
116
- getLookupIds = (cid: string, options?: EntityCallOptions): Promise<ExtKeyMap> => {
117
- const req: RestRequest = {
118
- url: `/${this.targetApi}/v1/${this.kind}/ext_key_map`,
119
- method: 'GET',
120
- params: {
121
- ...((options?.params as QueryMap) ?? {}),
122
- cid,
123
- },
124
- };
125
- return this.call(req, extIdMapErrorHandler);
113
+ throw error;
114
+ };
115
+
116
+ export class AmpSdkUserService extends AmpGlobalEntityServiceImpl<PlatformUserUpsertDto, PlatformUserDto> {
117
+ constructor(rest: RestClient, targetApi: TargetApi = TARGET_API_AGENT) {
118
+ super(rest, KIND.USERS, targetApi);
119
+ }
120
+
121
+ getLookup = async (tid: string, options?: EntityCallOptions): Promise<UserLookupService> => {
122
+ const lookup = new UserLookupService();
123
+ return this.refreshLookup(lookup, tid, options);
124
+ };
125
+
126
+ refreshLookup = async (lookup: UserLookupService, tid: string, options?: EntityCallOptions): Promise<UserLookupService> => {
127
+ const limit = LOOKUP_ID_PAGE_SIZE;
128
+ let offset = 0;
129
+ let hasMore = true;
130
+ if (!options) {
131
+ options = {params: {}};
132
+ }
133
+ _.set(options, 'params.updatedAt', {$gt: lookup.getLastUpdated()});
134
+ while (hasMore) {
135
+ const req: RestRequest = {
136
+ url: `/${this.targetApi}/v1/${this.kind}/id_summary`,
137
+ method: 'GET',
138
+ params: {
139
+ ...((options?.params as QueryMap) ?? {}),
140
+ tid,
141
+ limit,
142
+ offset,
143
+ },
144
+ };
145
+ const page = await this.call(req, errorHandler as ErrorHandler<Page<UserIdDto>>);
146
+ page.data.forEach(ids => lookup.add(ids));
147
+ offset = (page.hints.offset ?? offset) + limit;
148
+ hasMore = page.hints.hasMore ?? false;
149
+ }
150
+ return lookup;
151
+ };
152
+ }
153
+
154
+ export class AmpSdkAssetService extends AmpGlobalEntityServiceImpl<PlatformAssetUpsertDto, PlatformAssetDto> {
155
+ constructor(rest: RestClient, targetApi: TargetApi = TARGET_API_AGENT) {
156
+ super(rest, KIND.ASSETS, targetApi);
157
+ }
158
+
159
+ getLookup = async (tid: string, options?: EntityCallOptions): Promise<AssetLookupService> => {
160
+ const lookup = new AssetLookupService();
161
+ return this.refreshLookup(lookup, tid, options);
162
+ };
163
+
164
+ refreshLookup = async (lookup: AssetLookupService, tid: string, options?: EntityCallOptions): Promise<AssetLookupService> => {
165
+ const limit = LOOKUP_ID_PAGE_SIZE;
166
+ let offset = 0;
167
+ let hasMore = true;
168
+ if (!options) {
169
+ options = {params: {}};
170
+ }
171
+ _.set(options, 'params.updatedAt', {$gt: lookup.getLastUpdated()});
172
+ while (hasMore) {
173
+ const req: RestRequest = {
174
+ url: `/${this.targetApi}/v1/${this.kind}/id_summary`,
175
+ method: 'GET',
176
+ params: {
177
+ ...((options?.params as QueryMap) ?? {}),
178
+ tid,
179
+ limit,
180
+ offset,
181
+ },
182
+ };
183
+ const page = await this.call(req, errorHandler as ErrorHandler<Page<AssetIdDto>>);
184
+ page.data.forEach(ids => lookup.add(ids));
185
+ offset = (page.hints.offset ?? offset) + limit;
186
+ hasMore = page.hints.hasMore ?? false;
187
+ }
188
+ return lookup;
126
189
  };
127
190
  }
@@ -5,5 +5,8 @@ export * from './constants';
5
5
  export * from './data.service';
6
6
  export * from './entity.service';
7
7
  export * from './findings.service';
8
+ export * from './lookup.service';
8
9
  export * from './rest';
10
+ export * from './saasEntity.service';
9
11
  export * from './settings.service';
12
+ export * from './utils';
@@ -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
+ }
@@ -0,0 +1,8 @@
1
+ import _ from 'lodash';
2
+
3
+ export function formatMacAddress(raw: string): string {
4
+ const lower = raw.toLowerCase().replace(/[^a-f0-9]/g, '');
5
+ return _.chunk(lower.split(''), 2)
6
+ .map(chunk => chunk.join(''))
7
+ .join(':');
8
+ }