@dx-do/client 6.4.0 → 7.0.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/dist/index.cjs.js CHANGED
@@ -64831,6 +64831,23 @@ class AuthorizationService {
64831
64831
  }
64832
64832
  return raw;
64833
64833
  }
64834
+ /**
64835
+ * Returns true if a user with the given identifier exists on the tenant.
64836
+ * Matches case-insensitively against each account's `userId` (the login
64837
+ * principal — usually the upper-cased email) and any of its `emailIds`.
64838
+ *
64839
+ * @remarks Fetches the user list via {@link getUsersV2} (a single page, up
64840
+ * to 5000 accounts). A tenant with more users than that could yield a false
64841
+ * negative for an account beyond the page.
64842
+ */
64843
+ async userExists(userIdentifier) {
64844
+ const needle = userIdentifier.trim().toUpperCase();
64845
+ if (needle.length === 0)
64846
+ return false;
64847
+ const response = await this.getUsersV2(1, 5000);
64848
+ return response.users.some((user) => (user.userId ?? '').toUpperCase() === needle ||
64849
+ (user.emailIds ?? []).some((email) => (email.emailAddr ?? '').toUpperCase() === needle));
64850
+ }
64834
64851
  /** Reformats a cohort id to upper-cased, dashed GUID form (`8-4-4-4-12`). */
64835
64852
  toGuidCohortId(cohortId) {
64836
64853
  const hex = cohortId.replace(/-/g, '').toLowerCase();
@@ -67460,46 +67477,55 @@ const coerce$1 = (version, options) => {
67460
67477
  };
67461
67478
  var coerce_1 = coerce$1;
67462
67479
 
67463
- class LRUCache {
67464
- constructor () {
67465
- this.max = 1000;
67466
- this.map = new Map();
67467
- }
67480
+ var lrucache;
67481
+ var hasRequiredLrucache;
67468
67482
 
67469
- get (key) {
67470
- const value = this.map.get(key);
67471
- if (value === undefined) {
67472
- return undefined
67473
- } else {
67474
- // Remove the key from the map and add it to the end
67475
- this.map.delete(key);
67476
- this.map.set(key, value);
67477
- return value
67478
- }
67479
- }
67483
+ function requireLrucache () {
67484
+ if (hasRequiredLrucache) return lrucache;
67485
+ hasRequiredLrucache = 1;
67480
67486
 
67481
- delete (key) {
67482
- return this.map.delete(key)
67483
- }
67487
+ class LRUCache {
67488
+ constructor () {
67489
+ this.max = 1000;
67490
+ this.map = new Map();
67491
+ }
67484
67492
 
67485
- set (key, value) {
67486
- const deleted = this.delete(key);
67493
+ get (key) {
67494
+ const value = this.map.get(key);
67495
+ if (value === undefined) {
67496
+ return undefined
67497
+ } else {
67498
+ // Remove the key from the map and add it to the end
67499
+ this.map.delete(key);
67500
+ this.map.set(key, value);
67501
+ return value
67502
+ }
67503
+ }
67487
67504
 
67488
- if (!deleted && value !== undefined) {
67489
- // If cache is full, delete the least recently used item
67490
- if (this.map.size >= this.max) {
67491
- const firstKey = this.map.keys().next().value;
67492
- this.delete(firstKey);
67493
- }
67505
+ delete (key) {
67506
+ return this.map.delete(key)
67507
+ }
67494
67508
 
67495
- this.map.set(key, value);
67496
- }
67509
+ set (key, value) {
67510
+ const deleted = this.delete(key);
67497
67511
 
67498
- return this
67499
- }
67500
- }
67512
+ if (!deleted && value !== undefined) {
67513
+ // If cache is full, delete the least recently used item
67514
+ if (this.map.size >= this.max) {
67515
+ const firstKey = this.map.keys().next().value;
67516
+ this.delete(firstKey);
67517
+ }
67518
+
67519
+ this.map.set(key, value);
67520
+ }
67501
67521
 
67502
- var lrucache = LRUCache;
67522
+ return this
67523
+ }
67524
+ }
67525
+
67526
+ lrucache = LRUCache;
67527
+ return lrucache;
67528
+ }
67503
67529
 
67504
67530
  var range;
67505
67531
  var hasRequiredRange;
@@ -67722,7 +67748,7 @@ function requireRange () {
67722
67748
 
67723
67749
  range = Range;
67724
67750
 
67725
- const LRU = lrucache;
67751
+ const LRU = requireLrucache();
67726
67752
  const cache = new LRU();
67727
67753
 
67728
67754
  const parseOptions = parseOptions_1;
@@ -78831,6 +78857,419 @@ class DataStoreNASSService {
78831
78857
  }
78832
78858
  }
78833
78859
 
78860
+ /**
78861
+ * Service Universe models — an **OI-owned universe (view) scoped to a curated
78862
+ * list of services**, managed through the tenant `views/*` API. The wire shape
78863
+ * here matches the real server payload (verified against a live tenant): `views`
78864
+ * is an **array** of typed sub-views and access grants carry a `permissions`
78865
+ * array. (This is deliberately distinct from the object-shaped `ViewBodySchema`
78866
+ * in `./query`, which models a different, unused surface.)
78867
+ */
78868
+ /** Access permission granted on a service universe. */
78869
+ const ServiceUniversePermissionSchema = v4.z
78870
+ .enum(['READ', 'WRITE'])
78871
+ .describe('Permission granted on the universe');
78872
+ /** A single user or group access grant on a service universe. */
78873
+ const ServiceUniverseAccessEntrySchema = v4.z.looseObject({
78874
+ name: v4.z.string().describe('User email or group name being granted access'),
78875
+ permissions: v4.z
78876
+ .array(ServiceUniversePermissionSchema)
78877
+ .optional()
78878
+ .describe('Permissions granted to this principal (READ and/or WRITE)'),
78879
+ canManage: v4.z
78880
+ .boolean()
78881
+ .optional()
78882
+ .describe('Whether the principal may manage (re-share) the universe'),
78883
+ attributeInclude: v4.z
78884
+ .array(v4.z.unknown())
78885
+ .optional()
78886
+ .describe('Attribute-based include scoping for this grant'),
78887
+ attributeExclude: v4.z
78888
+ .array(v4.z.unknown())
78889
+ .optional()
78890
+ .describe('Attribute-based exclude scoping for this grant'),
78891
+ isValid: v4.z
78892
+ .array(v4.z.string())
78893
+ .optional()
78894
+ .describe('Server-side validation hints for the principal (UI-supplied)'),
78895
+ });
78896
+ /** Access policy for a service universe (per-user and per-group grants). */
78897
+ const ServiceUniverseAccessSchema = v4.z.looseObject({
78898
+ users: v4.z
78899
+ .array(ServiceUniverseAccessEntrySchema)
78900
+ .optional()
78901
+ .describe('Per-user access grants'),
78902
+ groups: v4.z
78903
+ .array(ServiceUniverseAccessEntrySchema)
78904
+ .optional()
78905
+ .describe('Per-group access grants'),
78906
+ });
78907
+ /** The TAS scoping of a service universe — its inner filter selects the services. */
78908
+ const ServiceUniverseTasSpecSchema = v4.z.looseObject({
78909
+ filter: TasFilterSchema.optional().describe('TAS filter selecting the topology; for a service universe this is a SERVICE-op filter over the chosen service names'),
78910
+ includeMetricFilter: v4.z
78911
+ .boolean()
78912
+ .optional()
78913
+ .describe('Whether a metric filter is applied; defaults to false'),
78914
+ projection: v4.z
78915
+ .string()
78916
+ .optional()
78917
+ .describe("Projection mode, e.g. 'NO_TYPE'"),
78918
+ projectionFilter: v4.z
78919
+ .looseObject({
78920
+ attributes: v4.z
78921
+ .array(v4.z.string())
78922
+ .optional()
78923
+ .describe('Attributes to project, e.g. ["name"]'),
78924
+ })
78925
+ .optional()
78926
+ .describe('Which vertex attributes to project'),
78927
+ });
78928
+ /** A TAS sub-view of a service universe. */
78929
+ const ServiceUniverseTasViewSchema = v4.z.looseObject({
78930
+ type: v4.z.literal('tas').describe('Discriminator: topology (TAS) sub-view'),
78931
+ filter: ServiceUniverseTasSpecSchema.describe('TAS scoping for this sub-view'),
78932
+ permissions: v4.z
78933
+ .array(ServiceUniversePermissionSchema)
78934
+ .optional()
78935
+ .describe('Permissions on this sub-view'),
78936
+ });
78937
+ /** A NASS (metrics) sub-view of a service universe. */
78938
+ const ServiceUniverseNassViewSchema = v4.z.looseObject({
78939
+ type: v4.z.literal('nass').describe('Discriminator: metrics (NASS) sub-view'),
78940
+ filter: v4.z
78941
+ .looseObject({
78942
+ filter: v4.z
78943
+ .looseObject({ op: v4.z.string().describe('Filter op, e.g. "ALL"') })
78944
+ .optional()
78945
+ .describe('NASS filter tree'),
78946
+ serviceFilter: v4.z
78947
+ .unknown()
78948
+ .optional()
78949
+ .describe('Optional service-scoped NASS filter'),
78950
+ })
78951
+ .optional()
78952
+ .describe('NASS scoping for this sub-view'),
78953
+ permissions: v4.z
78954
+ .array(ServiceUniversePermissionSchema)
78955
+ .optional()
78956
+ .describe('Permissions on this sub-view'),
78957
+ });
78958
+ /** A service universe sub-view: TAS (service-scoped topology) or NASS (metrics). */
78959
+ const ServiceUniverseViewSchema = v4.z
78960
+ .discriminatedUnion('type', [
78961
+ ServiceUniverseTasViewSchema,
78962
+ ServiceUniverseNassViewSchema,
78963
+ ])
78964
+ .describe('A TAS or NASS sub-view of the universe');
78965
+ /** Metadata for a service universe. */
78966
+ const ServiceUniverseAttributesSchema = v4.z.looseObject({
78967
+ owner: v4.z
78968
+ .string()
78969
+ .optional()
78970
+ .describe("Owning product; service universes are 'OI'"),
78971
+ label: v4.z.string().describe('Human-readable universe name'),
78972
+ description: v4.z.string().optional().describe('Universe description'),
78973
+ });
78974
+ /**
78975
+ * The create/update request body for a service universe
78976
+ * (`POST/PUT views/view`).
78977
+ */
78978
+ const ServiceUniverseBodySchema = v4.z.looseObject({
78979
+ inactive: v4.z
78980
+ .boolean()
78981
+ .optional()
78982
+ .describe('Whether the universe is inactive (hidden from active use)'),
78983
+ attributes: ServiceUniverseAttributesSchema.describe('Universe metadata (owner, label, description)'),
78984
+ access: ServiceUniverseAccessSchema.optional().describe('Access policy (users/groups)'),
78985
+ views: v4.z
78986
+ .array(ServiceUniverseViewSchema)
78987
+ .describe('The TAS + NASS sub-views defining the universe scope'),
78988
+ });
78989
+ /**
78990
+ * A summary row from `GET oi/v2/universe/getAllUniverseList`.
78991
+ */
78992
+ const ServiceUniverseListItemSchema = v4.z.looseObject({
78993
+ id: v4.z.string().describe('Universe (view) id, e.g. "VIEW1821"'),
78994
+ name: v4.z.string().optional().describe('Universe label'),
78995
+ description: v4.z.string().optional().describe('Universe description'),
78996
+ owner: v4.z
78997
+ .string()
78998
+ .optional()
78999
+ .describe("Owning product; service universes are 'OI'"),
79000
+ inactive: v4.z.boolean().optional().describe('Whether the universe is inactive'),
79001
+ });
79002
+ const ServiceUniverseListResponseSchema = v4.z
79003
+ .array(ServiceUniverseListItemSchema)
79004
+ .describe('All universes returned by getAllUniverseList');
79005
+ /**
79006
+ * A full service universe as returned by `POST views/queryView` (op:ID).
79007
+ * Loosely modeled — the detail response echoes the body plus server-resolved
79008
+ * fields (viewId, resolved access).
79009
+ */
79010
+ const ServiceUniverseSchema = v4.z.looseObject({
79011
+ viewId: v4.z.string().optional().describe('Server-assigned view id'),
79012
+ inactive: v4.z.boolean().optional().describe('Whether the universe is inactive'),
79013
+ attributes: ServiceUniverseAttributesSchema.optional().describe('Universe metadata'),
79014
+ access: ServiceUniverseAccessSchema.optional().describe('Access policy'),
79015
+ views: v4.z
79016
+ .array(v4.z.unknown())
79017
+ .optional()
79018
+ .describe('The universe sub-views (TAS/NASS)'),
79019
+ });
79020
+ /** Response wrapper for `POST views/queryView`. */
79021
+ const ServiceUniverseQueryResponseSchema = v4.z.looseObject({
79022
+ views: v4.z
79023
+ .array(ServiceUniverseSchema)
79024
+ .optional()
79025
+ .describe('Universes matching the query filter'),
79026
+ });
79027
+
79028
+ /**
79029
+ * Service for **Service Universes** — OI-owned universes (views) scoped to a
79030
+ * curated list of services, managed via the tenant `views/*` API plus the OI
79031
+ * universe-list endpoint. The "View sample" preview runs the SERVICE-op filter
79032
+ * as a TAS graph query.
79033
+ *
79034
+ * @example
79035
+ * ```ts
79036
+ * const svc = new ServiceUniverseService(dxSaasService, log);
79037
+ * const body = ServiceUniverseService.buildBody({ label: 'IoT', serviceNames: ['IoT RDS'] });
79038
+ * await svc.createServiceUniverse(body);
79039
+ * ```
79040
+ */
79041
+ class ServiceUniverseService {
79042
+ dxSaasService;
79043
+ log;
79044
+ constructor(dxSaasService, log) {
79045
+ this.dxSaasService = dxSaasService;
79046
+ this.log = log;
79047
+ }
79048
+ /**
79049
+ * Lists service universes (OI-owned) via
79050
+ * `GET oi/v2/universe/getAllUniverseList` (VIEWALL).
79051
+ *
79052
+ * @remarks Response-validated (mismatch → `log.warn`, raw still returned).
79053
+ */
79054
+ async listServiceUniverses() {
79055
+ const raw = await this.dxSaasService.oiGet('oi/v2/universe/getAllUniverseList');
79056
+ const result = ServiceUniverseListResponseSchema.safeParse(raw);
79057
+ if (!result.success) {
79058
+ this.log.warn('ServiceUniverseListResponse validation warning:', result.error.message);
79059
+ }
79060
+ const all = raw ?? [];
79061
+ return all.filter((u) => (u.owner ?? '').toUpperCase() === 'OI');
79062
+ }
79063
+ /**
79064
+ * Returns a single service universe by its view id via
79065
+ * `POST views/queryView` (op:ID). Throws if not exactly one match.
79066
+ */
79067
+ async getServiceUniverse(viewId) {
79068
+ const raw = await this.dxSaasService.tenantPost('views/queryView', {
79069
+ filter: { op: 'ID', ids: [viewId], input: { op: 'ALL' } },
79070
+ includeInactive: true,
79071
+ });
79072
+ const result = ServiceUniverseQueryResponseSchema.safeParse(raw);
79073
+ if (!result.success) {
79074
+ this.log.warn('ServiceUniverseQueryResponse validation warning:', result.error.message);
79075
+ }
79076
+ const views = raw.views ?? [];
79077
+ if (views.length !== 1) {
79078
+ throw new Error(`Expected exactly one universe with viewId '${viewId}', found ${views.length}.`);
79079
+ }
79080
+ return views[0];
79081
+ }
79082
+ /**
79083
+ * Creates a service universe via `POST views/view`.
79084
+ *
79085
+ * @throws ZodError if the body fails schema validation.
79086
+ */
79087
+ async createServiceUniverse(body) {
79088
+ ServiceUniverseBodySchema.parse(body);
79089
+ return this.dxSaasService.tenantPost('views/view', body);
79090
+ }
79091
+ /**
79092
+ * Updates a service universe via `PUT views/view/{viewId}`.
79093
+ *
79094
+ * @throws ZodError if the body fails schema validation.
79095
+ */
79096
+ async updateServiceUniverse(viewId, body) {
79097
+ ServiceUniverseBodySchema.parse(body);
79098
+ return this.dxSaasService.tenantPut(`views/view/${encodeURIComponent(viewId)}`, body);
79099
+ }
79100
+ /**
79101
+ * PUTs a full universe body to `views/view/{viewId}` **without** re-validating
79102
+ * it against the client schema. Used by the access commands, which round-trip
79103
+ * the universe's existing views verbatim (a UI-created universe may carry view
79104
+ * shapes our builder wouldn't reconstruct); only the `access` policy changes.
79105
+ */
79106
+ async putServiceUniverse(viewId, body) {
79107
+ return this.dxSaasService.tenantPut(`views/view/${encodeURIComponent(viewId)}`, body);
79108
+ }
79109
+ /** Deletes a service universe via `DELETE views/view/{viewId}`. */
79110
+ async deleteServiceUniverse(viewId) {
79111
+ return this.dxSaasService.tenantDelete(`views/view/${encodeURIComponent(viewId)}`);
79112
+ }
79113
+ /**
79114
+ * Checks which of the given service names actually exist on the tenant, via
79115
+ * `GET oi/v2/sa/services/{name}` per name. A 404 means the service does not
79116
+ * exist; any other error is re-thrown (so a transient failure is never
79117
+ * silently reported as "missing").
79118
+ *
79119
+ * @throws Error if any name could not be verified for a non-404 reason.
79120
+ */
79121
+ async resolveServiceNames(serviceNames) {
79122
+ const existing = [];
79123
+ const missing = [];
79124
+ const errored = [];
79125
+ await dist$1.PromisePool.for(serviceNames)
79126
+ .withConcurrency(5)
79127
+ .process(async (name) => {
79128
+ try {
79129
+ await this.dxSaasService.oiGet(`oi/v2/sa/services/${encodeURIComponent(name)}`, { subservices: false });
79130
+ existing.push(name);
79131
+ }
79132
+ catch (err) {
79133
+ if (err.httpCode === 404) {
79134
+ missing.push(name);
79135
+ }
79136
+ else {
79137
+ errored.push({ name, error: err });
79138
+ }
79139
+ }
79140
+ });
79141
+ if (errored.length > 0) {
79142
+ const first = errored[0].error;
79143
+ const reason = first instanceof Error ? first.message : String(first);
79144
+ throw new Error(`Could not verify ${errored.length} service name(s) (${errored
79145
+ .map((e) => e.name)
79146
+ .join(', ')}): ${reason}`);
79147
+ }
79148
+ return { existing, missing };
79149
+ }
79150
+ /**
79151
+ * "View sample": runs the SERVICE-scoped filter as a TAS graph query
79152
+ * (`POST tas/graph/query`) and returns the matching entities — the dry-run
79153
+ * preview of what a universe over `serviceNames` would contain.
79154
+ *
79155
+ * @remarks Response-validated (mismatch → `log.warn`, raw still returned).
79156
+ */
79157
+ async sampleServices(serviceNames, options = {}) {
79158
+ const query = {
79159
+ filter: {
79160
+ op: 'OR',
79161
+ input: [
79162
+ {
79163
+ op: 'SERVICE',
79164
+ values: serviceNames,
79165
+ includeServiceHierarchy: options.includeServiceHierarchy ?? true,
79166
+ excludeSubServices: options.excludeSubServices ?? false,
79167
+ },
79168
+ ],
79169
+ },
79170
+ authorizationView: 'VIEWALL',
79171
+ schema: 'SA',
79172
+ limit: options.limit ?? 200,
79173
+ };
79174
+ TasQuerySchema.parse(query);
79175
+ const raw = await this.dxSaasService.tenantPost('tas/graph/query', query);
79176
+ const result = TasGraphSchema.safeParse(raw);
79177
+ if (!result.success) {
79178
+ this.log.warn('ServiceUniverse sample (TasGraph) validation warning:', result.error.message);
79179
+ }
79180
+ return raw;
79181
+ }
79182
+ /**
79183
+ * Builds a service universe request body: a SERVICE-scoped TAS sub-view over
79184
+ * `serviceNames` (or an ALL view when empty) plus an ALL NASS sub-view. Mirrors
79185
+ * the shape the DXO2 Service Universe UI submits.
79186
+ */
79187
+ /** A user/group access grant: READ+WRITE, no attribute scoping (per current UX). */
79188
+ static accessEntry(name, canManage) {
79189
+ return {
79190
+ name,
79191
+ permissions: ['READ', 'WRITE'],
79192
+ canManage,
79193
+ attributeInclude: [],
79194
+ attributeExclude: [],
79195
+ };
79196
+ }
79197
+ /**
79198
+ * Returns a copy of `existing` with a user/group access grant added (or
79199
+ * updated in place if the principal already has a grant). Preserves the
79200
+ * universe's server-managed fields and views verbatim — only `access`
79201
+ * changes. Pass exactly one of `user` / `group`.
79202
+ */
79203
+ static withAccessEntry(existing, target) {
79204
+ const isGroup = !!target.group;
79205
+ const name = (target.user ?? target.group);
79206
+ const users = [...(existing.access?.users ?? [])];
79207
+ const groups = [...(existing.access?.groups ?? [])];
79208
+ const list = isGroup ? groups : users;
79209
+ const next = list.filter((e) => e.name !== name);
79210
+ next.push(this.accessEntry(name, target.canManage));
79211
+ const access = isGroup
79212
+ ? { users, groups: next }
79213
+ : { users: next, groups };
79214
+ return {
79215
+ ...existing,
79216
+ access,
79217
+ };
79218
+ }
79219
+ /**
79220
+ * Returns a copy of `existing` with a user/group access grant removed.
79221
+ * Preserves everything else verbatim. Pass exactly one of `user` / `group`.
79222
+ */
79223
+ static withoutAccessEntry(existing, target) {
79224
+ const isGroup = !!target.group;
79225
+ const name = (target.user ?? target.group);
79226
+ const users = (existing.access?.users ?? []).filter((e) => isGroup || e.name !== name);
79227
+ const groups = (existing.access?.groups ?? []).filter((e) => !isGroup || e.name !== name);
79228
+ return {
79229
+ ...existing,
79230
+ access: { users, groups },
79231
+ };
79232
+ }
79233
+ static buildBody(input) {
79234
+ const { label, description, serviceNames, inactive, includeServiceHierarchy, excludeSubServices, access, } = input;
79235
+ const tasFilter = serviceNames.length === 0
79236
+ ? { op: 'ALL' }
79237
+ : {
79238
+ op: 'SERVICE',
79239
+ values: serviceNames,
79240
+ includeServiceHierarchy: includeServiceHierarchy ?? true,
79241
+ excludeSubServices: excludeSubServices ?? false,
79242
+ };
79243
+ return {
79244
+ inactive: inactive ?? false,
79245
+ attributes: { owner: 'OI', label, description: description ?? '' },
79246
+ access: access ?? { groups: [], users: [] },
79247
+ views: [
79248
+ {
79249
+ type: 'tas',
79250
+ filter: {
79251
+ filter: tasFilter,
79252
+ includeMetricFilter: false,
79253
+ projection: 'NO_TYPE',
79254
+ projectionFilter: { attributes: ['name'] },
79255
+ },
79256
+ permissions: ['READ', 'WRITE'],
79257
+ },
79258
+ {
79259
+ type: 'nass',
79260
+ filter: {
79261
+ filter: { op: 'ALL' },
79262
+ serviceFilter: serviceNames.length === 0
79263
+ ? undefined
79264
+ : { op: 'SERVICE', values: serviceNames },
79265
+ },
79266
+ permissions: ['READ', 'WRITE'],
79267
+ },
79268
+ ],
79269
+ };
79270
+ }
79271
+ }
79272
+
78834
79273
  var NullSimpleLog = Logging.NullSimpleLog;
78835
79274
  /**
78836
79275
  * Creates and returns a container of all DX client services (ACC, alerts, alarms,
@@ -78865,6 +79304,7 @@ function createServiceMonolith(dxDoConfiguration, log = new NullSimpleLog()) {
78865
79304
  dxDataStoreNASSService: new DataStoreNASSService(dxSaaSService, log),
78866
79305
  dxDataStoreNASSQLService: new DataStoreNASSQLService(dxSaaSService, log),
78867
79306
  dxDataStoreTASService: new DataStoreTASService(dxSaaSService, log),
79307
+ dxServiceUniverseService: new ServiceUniverseService(dxSaaSService, log),
78868
79308
  dxEventService: new EventService(dxSaaSService, log),
78869
79309
  dxExperienceService: new ExperienceService(dxSaaSService, log),
78870
79310
  dxFeaturesService: new DataStoreFeaturesService(dxSaaSService, log),
@@ -79069,6 +79509,7 @@ exports.SLIService = SLIService;
79069
79509
  exports.SQLService = SQLService;
79070
79510
  exports.ServiceFilterSpecifierSchema = ServiceFilterSpecifierSchema;
79071
79511
  exports.ServiceService = ServiceService;
79512
+ exports.ServiceUniverseService = ServiceUniverseService;
79072
79513
  exports.SessionService = SessionService;
79073
79514
  exports.SimpleHTTPError = SimpleHTTPError;
79074
79515
  exports.SituationService = SituationService;