@stndrds/schema 1.0.0-alpha.76 → 1.0.0-alpha.78

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.
@@ -2,16 +2,20 @@
2
2
  var SYSTEM_RESOURCES = {
3
3
  /** User profiles, invitations, roles and permissions management */
4
4
  PEOPLE: "people",
5
- /** Object definitions, attributes, tenant settings and audit logs */
6
- WORKSPACE: "workspace"
5
+ /** Tenant settings, audit logs, workflow execution, document generation */
6
+ WORKSPACE: "workspace",
7
+ /** Object definitions, attributes, views, workflow definitions */
8
+ ARCHITECT: "architect"
7
9
  };
8
10
  var ALL_SYSTEM_RESOURCES = [
9
11
  SYSTEM_RESOURCES.PEOPLE,
10
- SYSTEM_RESOURCES.WORKSPACE
12
+ SYSTEM_RESOURCES.WORKSPACE,
13
+ SYSTEM_RESOURCES.ARCHITECT
11
14
  ];
12
15
  var SYSTEM_RESOURCE_LABELS = {
13
16
  people: "People",
14
- workspace: "Workspace"
17
+ workspace: "Workspace",
18
+ architect: "Architect"
15
19
  };
16
20
  var DEFAULT_ROLES = {
17
21
  /** Full platform access - can manage everything */
@@ -34,16 +38,17 @@ var DEFAULT_ROLE_PERMISSIONS = {
34
38
  object: [{ target: "*", actions: ALL_ACTIONS }]
35
39
  },
36
40
  member: {
37
- system: [{ target: "people", actions: ["read"] }],
41
+ system: [
42
+ { target: "people", actions: ["read"] },
43
+ { target: "workspace", actions: ["read"] }
44
+ ],
38
45
  object: [{ target: "*", actions: ALL_ACTIONS }]
39
46
  }
40
47
  };
48
+ var DEFAULT_ROLE_FOR_NEW_USERS = "member";
41
49
  function isDefaultRole(roleName) {
42
50
  return Object.values(DEFAULT_ROLES).includes(roleName);
43
51
  }
44
- function isAdminRole(roleName) {
45
- return roleName === DEFAULT_ROLES.OWNER;
46
- }
47
52
 
48
53
 
49
54
 
@@ -55,4 +60,4 @@ function isAdminRole(roleName) {
55
60
 
56
61
 
57
62
 
58
- exports.SYSTEM_RESOURCES = SYSTEM_RESOURCES; exports.ALL_SYSTEM_RESOURCES = ALL_SYSTEM_RESOURCES; exports.SYSTEM_RESOURCE_LABELS = SYSTEM_RESOURCE_LABELS; exports.DEFAULT_ROLES = DEFAULT_ROLES; exports.DEFAULT_ROLE_LABELS = DEFAULT_ROLE_LABELS; exports.DEFAULT_ROLE_DESCRIPTIONS = DEFAULT_ROLE_DESCRIPTIONS; exports.DEFAULT_ROLE_PERMISSIONS = DEFAULT_ROLE_PERMISSIONS; exports.isDefaultRole = isDefaultRole; exports.isAdminRole = isAdminRole;
63
+ exports.SYSTEM_RESOURCES = SYSTEM_RESOURCES; exports.ALL_SYSTEM_RESOURCES = ALL_SYSTEM_RESOURCES; exports.SYSTEM_RESOURCE_LABELS = SYSTEM_RESOURCE_LABELS; exports.DEFAULT_ROLES = DEFAULT_ROLES; exports.DEFAULT_ROLE_LABELS = DEFAULT_ROLE_LABELS; exports.DEFAULT_ROLE_DESCRIPTIONS = DEFAULT_ROLE_DESCRIPTIONS; exports.DEFAULT_ROLE_PERMISSIONS = DEFAULT_ROLE_PERMISSIONS; exports.DEFAULT_ROLE_FOR_NEW_USERS = DEFAULT_ROLE_FOR_NEW_USERS; exports.isDefaultRole = isDefaultRole;
@@ -2,16 +2,20 @@
2
2
  var SYSTEM_RESOURCES = {
3
3
  /** User profiles, invitations, roles and permissions management */
4
4
  PEOPLE: "people",
5
- /** Object definitions, attributes, tenant settings and audit logs */
6
- WORKSPACE: "workspace"
5
+ /** Tenant settings, audit logs, workflow execution, document generation */
6
+ WORKSPACE: "workspace",
7
+ /** Object definitions, attributes, views, workflow definitions */
8
+ ARCHITECT: "architect"
7
9
  };
8
10
  var ALL_SYSTEM_RESOURCES = [
9
11
  SYSTEM_RESOURCES.PEOPLE,
10
- SYSTEM_RESOURCES.WORKSPACE
12
+ SYSTEM_RESOURCES.WORKSPACE,
13
+ SYSTEM_RESOURCES.ARCHITECT
11
14
  ];
12
15
  var SYSTEM_RESOURCE_LABELS = {
13
16
  people: "People",
14
- workspace: "Workspace"
17
+ workspace: "Workspace",
18
+ architect: "Architect"
15
19
  };
16
20
  var DEFAULT_ROLES = {
17
21
  /** Full platform access - can manage everything */
@@ -34,16 +38,17 @@ var DEFAULT_ROLE_PERMISSIONS = {
34
38
  object: [{ target: "*", actions: ALL_ACTIONS }]
35
39
  },
36
40
  member: {
37
- system: [{ target: "people", actions: ["read"] }],
41
+ system: [
42
+ { target: "people", actions: ["read"] },
43
+ { target: "workspace", actions: ["read"] }
44
+ ],
38
45
  object: [{ target: "*", actions: ALL_ACTIONS }]
39
46
  }
40
47
  };
48
+ var DEFAULT_ROLE_FOR_NEW_USERS = "member";
41
49
  function isDefaultRole(roleName) {
42
50
  return Object.values(DEFAULT_ROLES).includes(roleName);
43
51
  }
44
- function isAdminRole(roleName) {
45
- return roleName === DEFAULT_ROLES.OWNER;
46
- }
47
52
 
48
53
  export {
49
54
  SYSTEM_RESOURCES,
@@ -53,6 +58,6 @@ export {
53
58
  DEFAULT_ROLE_LABELS,
54
59
  DEFAULT_ROLE_DESCRIPTIONS,
55
60
  DEFAULT_ROLE_PERMISSIONS,
56
- isDefaultRole,
57
- isAdminRole
61
+ DEFAULT_ROLE_FOR_NEW_USERS,
62
+ isDefaultRole
58
63
  };
@@ -13,9 +13,6 @@ import {
13
13
  validateObject,
14
14
  validateObjectOrThrow
15
15
  } from "./chunk-5SZ5OISG.mjs";
16
- import {
17
- isAdminRole
18
- } from "./chunk-6P3NPTYV.mjs";
19
16
  import {
20
17
  __require
21
18
  } from "./chunk-Y6FXYEAI.mjs";
@@ -3210,6 +3207,17 @@ function createMockObjectsRepository(stores) {
3210
3207
  );
3211
3208
  return Promise.resolve(results);
3212
3209
  },
3210
+ deleteSystemNotInNames(excludeNames) {
3211
+ const tenantId = getTenantId();
3212
+ let count = 0;
3213
+ for (const [id, obj] of stores.objects.entries()) {
3214
+ if (obj.tenantId === tenantId && obj.system && !excludeNames.includes(obj.name)) {
3215
+ stores.objects.delete(id);
3216
+ count++;
3217
+ }
3218
+ }
3219
+ return Promise.resolve(count);
3220
+ },
3213
3221
  upsert(data) {
3214
3222
  const tenantId = getTenantId();
3215
3223
  for (const obj of stores.objects.values()) {
@@ -4579,8 +4587,6 @@ function createMockPermissionsRepository(stores) {
4579
4587
  getEffectivePermissions(userProfileId) {
4580
4588
  const tenantId = getTenantId();
4581
4589
  const userRoleIds = Array.from(stores.userRoles.values()).filter((ur) => ur.userProfileId === userProfileId && ur.tenantId === tenantId).map((ur) => ur.roleId);
4582
- const userRoles = Array.from(stores.roles.values()).filter((r) => userRoleIds.includes(r.id));
4583
- const hasAdmin = userRoles.some((r) => isAdminRole(r.name));
4584
4590
  const userPermissions = Array.from(stores.permissions.values()).filter(
4585
4591
  (p) => userRoleIds.includes(p.roleId)
4586
4592
  );
@@ -4607,7 +4613,7 @@ function createMockPermissionsRepository(stores) {
4607
4613
  }
4608
4614
  }
4609
4615
  }
4610
- return Promise.resolve({ isAdmin: hasAdmin, objectPermissions, systemPermissions });
4616
+ return Promise.resolve({ objectPermissions, systemPermissions });
4611
4617
  },
4612
4618
  countUsersWithRole(roleName) {
4613
4619
  const tenantId = getTenantId();
@@ -9856,15 +9862,31 @@ var AuditService = class extends BaseService {
9856
9862
  if (!this.adapter.audit) {
9857
9863
  return;
9858
9864
  }
9865
+ const resolved = await this.resolveActorEmail(entry);
9859
9866
  if (this.options?.async) {
9860
- this.buffer.push(entry);
9867
+ this.buffer.push(resolved);
9861
9868
  const batchSize = this.options.batchSize ?? 10;
9862
9869
  if (this.buffer.length >= batchSize) {
9863
9870
  await this.flush();
9864
9871
  }
9865
9872
  } else {
9866
- await this.adapter.audit.create(entry);
9873
+ await this.adapter.audit.create(resolved);
9874
+ }
9875
+ }
9876
+ /**
9877
+ * Resolve actorEmail from user profiles if not already set
9878
+ */
9879
+ async resolveActorEmail(entry) {
9880
+ if (!entry.actorEmail && entry.actorId) {
9881
+ try {
9882
+ const profile = await this.adapter.userProfiles.findById(entry.actorId);
9883
+ if (profile?.email) {
9884
+ return { ...entry, actorEmail: profile.email };
9885
+ }
9886
+ } catch {
9887
+ }
9867
9888
  }
9889
+ return entry;
9868
9890
  }
9869
9891
  /**
9870
9892
  * Start the flush timer for async mode
@@ -15112,6 +15134,74 @@ var UserProfileService = class extends BaseService {
15112
15134
  await this.invalidateCache(cacheKeys.userProfileByEmail(this.tenantId, email));
15113
15135
  }
15114
15136
  }
15137
+ // ============================================================================
15138
+ // AVATAR URL RESOLUTION
15139
+ // ============================================================================
15140
+ /**
15141
+ * Resolve avatar storage path to a signed URL.
15142
+ * External URLs (https://) pass through unchanged.
15143
+ * Storage paths are resolved to fresh signed URLs (1h expiry).
15144
+ */
15145
+ async resolveAvatarUrl(profile) {
15146
+ if (!profile.avatarUrl || profile.avatarUrl.startsWith("https://")) {
15147
+ return profile;
15148
+ }
15149
+ if (!this.adapter.storage) return profile;
15150
+ try {
15151
+ const signedUrl = await this.adapter.storage.getSignedUrl(profile.avatarUrl, {
15152
+ expiresIn: 3600
15153
+ });
15154
+ return { ...profile, avatarUrl: signedUrl };
15155
+ } catch {
15156
+ return profile;
15157
+ }
15158
+ }
15159
+ async resolveAvatarUrls(profiles) {
15160
+ return Promise.all(profiles.map((p) => this.resolveAvatarUrl(p)));
15161
+ }
15162
+ // ============================================================================
15163
+ // AVATAR MANAGEMENT
15164
+ // ============================================================================
15165
+ /**
15166
+ * Upload a new avatar for the user.
15167
+ * Deletes previous avatar from storage if it was an internal upload.
15168
+ * Stores the storagePath — resolved to signed URL at read time.
15169
+ */
15170
+ async uploadAvatar(profileId, input) {
15171
+ if (!this.adapter.storage) {
15172
+ throw new Error("StorageAdapter is not configured.");
15173
+ }
15174
+ if (!input.mimeType.startsWith("image/")) {
15175
+ throw new Error("Only image files are allowed for avatars.");
15176
+ }
15177
+ const profile = await this.getProfileOrThrow(profileId);
15178
+ if (profile.avatarUrl && !profile.avatarUrl.startsWith("https://")) {
15179
+ await this.adapter.storage.delete(profile.avatarUrl).catch(() => void 0);
15180
+ }
15181
+ const result = await this.adapter.storage.upload({
15182
+ content: input.content,
15183
+ fileName: input.fileName,
15184
+ mimeType: input.mimeType,
15185
+ size: input.size,
15186
+ tenantId: this.tenantId,
15187
+ folderPath: "avatars"
15188
+ });
15189
+ return await this.updateProfile(profileId, { avatarUrl: result.storagePath });
15190
+ }
15191
+ /**
15192
+ * Delete the user's avatar.
15193
+ * Removes file from storage if it was an internal upload, then clears avatarUrl.
15194
+ */
15195
+ async deleteAvatar(profileId) {
15196
+ const profile = await this.getProfileOrThrow(profileId);
15197
+ if (profile.avatarUrl && !profile.avatarUrl.startsWith("https://")) {
15198
+ await this.adapter.storage?.delete(profile.avatarUrl).catch(() => void 0);
15199
+ }
15200
+ return await this.updateProfile(profileId, { avatarUrl: null });
15201
+ }
15202
+ // ============================================================================
15203
+ // CREATE
15204
+ // ============================================================================
15115
15205
  /**
15116
15206
  * Create a new user profile (typically after first auth).
15117
15207
  * Automatically uses tenant context from AsyncLocalStorage.
@@ -15152,18 +15242,19 @@ var UserProfileService = class extends BaseService {
15152
15242
  targetUserEmail: profile.email
15153
15243
  });
15154
15244
  }
15155
- return profile;
15245
+ return this.resolveAvatarUrl(profile);
15156
15246
  }
15157
15247
  /**
15158
15248
  * Get user profile by ID.
15159
15249
  * Results are cached if a CacheAdapter is configured.
15160
15250
  */
15161
15251
  async getProfile(profileId) {
15162
- return this.cachedBy(
15252
+ const profile = await this.cachedBy(
15163
15253
  "userProfileById",
15164
15254
  profileId,
15165
15255
  () => this.adapter.userProfiles.findById(profileId)
15166
15256
  );
15257
+ return profile ? this.resolveAvatarUrl(profile) : null;
15167
15258
  }
15168
15259
  /**
15169
15260
  * Get user profile by ID or throw
@@ -15185,11 +15276,12 @@ var UserProfileService = class extends BaseService {
15185
15276
  * @returns User profile or null
15186
15277
  */
15187
15278
  async getProfileByAuthId(authId) {
15188
- return this.cachedBy(
15279
+ const profile = await this.cachedBy(
15189
15280
  "userProfileByAuthId",
15190
15281
  authId,
15191
15282
  () => this.adapter.userProfiles.findByAuthId(authId)
15192
15283
  );
15284
+ return profile ? this.resolveAvatarUrl(profile) : null;
15193
15285
  }
15194
15286
  /**
15195
15287
  * Get or create user profile (idempotent operation)
@@ -15228,11 +15320,11 @@ var UserProfileService = class extends BaseService {
15228
15320
  const updated = await this.adapter.userProfiles.update(profileId, data);
15229
15321
  await this.invalidateProfileCache(updated.id, updated.authId, updated.email);
15230
15322
  if (this.auditService && this.userId) {
15231
- const changes = buildAuditChanges(existing, data, [
15232
- "firstName",
15233
- "lastName",
15234
- "status"
15235
- ]);
15323
+ const changes = buildAuditChanges(
15324
+ existing,
15325
+ data,
15326
+ ["firstName", "lastName", "status"]
15327
+ );
15236
15328
  if (changes.length > 0) {
15237
15329
  await this.auditService.logUserAction({
15238
15330
  action: "user.updated",
@@ -15243,7 +15335,7 @@ var UserProfileService = class extends BaseService {
15243
15335
  });
15244
15336
  }
15245
15337
  }
15246
- return updated;
15338
+ return this.resolveAvatarUrl(updated);
15247
15339
  }
15248
15340
  /**
15249
15341
  * Delete user profile.
@@ -15280,7 +15372,8 @@ var UserProfileService = class extends BaseService {
15280
15372
  * Automatically uses tenant context from AsyncLocalStorage.
15281
15373
  */
15282
15374
  async listProfiles(options) {
15283
- return await this.adapter.userProfiles.list(options);
15375
+ const profiles = await this.adapter.userProfiles.list(options);
15376
+ return this.resolveAvatarUrls(profiles);
15284
15377
  }
15285
15378
  /**
15286
15379
  * Update last login timestamp
@@ -15311,11 +15404,12 @@ var UserProfileService = class extends BaseService {
15311
15404
  * Automatically uses tenant context from AsyncLocalStorage.
15312
15405
  */
15313
15406
  async getProfileByEmail(email) {
15314
- return this.cachedBy(
15407
+ const profile = await this.cachedBy(
15315
15408
  "userProfileByEmail",
15316
15409
  email,
15317
15410
  () => this.adapter.userProfiles.findByEmail(email)
15318
15411
  );
15412
+ return profile ? this.resolveAvatarUrl(profile) : null;
15319
15413
  }
15320
15414
  /**
15321
15415
  * Invite a new user by email.
@@ -15348,6 +15442,21 @@ var UserProfileService = class extends BaseService {
15348
15442
  throw new Error(`User with email "${data.email}" already exists in this tenant`);
15349
15443
  }
15350
15444
  const profile = await this.adapter.userProfiles.invite(data);
15445
+ if (this.adapter.permissions) {
15446
+ try {
15447
+ const roles = await this.adapter.permissions.getRoles();
15448
+ const defaultRole = roles.find((r) => r.name === "member" && r.system);
15449
+ if (defaultRole) {
15450
+ await this.adapter.permissions.assignRole({
15451
+ userProfileId: profile.id,
15452
+ roleId: defaultRole.id,
15453
+ tenantId: this.tenantId,
15454
+ assignedBy: this.userId ?? void 0
15455
+ });
15456
+ }
15457
+ } catch {
15458
+ }
15459
+ }
15351
15460
  await this.invalidateProfileCache(profile.id, profile.authId, profile.email);
15352
15461
  if (this.auditService && this.userId) {
15353
15462
  await this.auditService.logUserAction({
@@ -15357,7 +15466,7 @@ var UserProfileService = class extends BaseService {
15357
15466
  targetUserEmail: profile.email
15358
15467
  });
15359
15468
  }
15360
- return profile;
15469
+ return this.resolveAvatarUrl(profile);
15361
15470
  }
15362
15471
  };
15363
15472
 
@@ -17030,14 +17139,11 @@ var FileService = class extends BaseService {
17030
17139
  * @param userId - User ID to check
17031
17140
  * @returns true if user can access the file
17032
17141
  */
17033
- async checkAccess(fileId, userId, options) {
17142
+ async checkAccess(fileId, userId) {
17034
17143
  const file2 = await this.getFile(fileId);
17035
17144
  if (!file2) {
17036
17145
  return false;
17037
17146
  }
17038
- if (options?.isAdmin) {
17039
- return true;
17040
- }
17041
17147
  if (file2.visibility === "public") {
17042
17148
  return true;
17043
17149
  }
@@ -17321,9 +17427,6 @@ var PermissionService = class extends BaseService {
17321
17427
  */
17322
17428
  async canAccessObject(userProfileId, objectName, action) {
17323
17429
  const permissions = await this.getEffectivePermissions(userProfileId);
17324
- if (permissions.isAdmin) {
17325
- return true;
17326
- }
17327
17430
  const wildcardPerms = permissions.objectPermissions["*"];
17328
17431
  if (wildcardPerms?.includes(action)) {
17329
17432
  return true;
@@ -17355,9 +17458,6 @@ var PermissionService = class extends BaseService {
17355
17458
  */
17356
17459
  async getObjectPermissions(userProfileId, objectName) {
17357
17460
  const permissions = await this.getEffectivePermissions(userProfileId);
17358
- if (permissions.isAdmin) {
17359
- return { canRead: true, canCreate: true, canUpdate: true, canDelete: true };
17360
- }
17361
17461
  const wildcardPerms = permissions.objectPermissions["*"] ?? [];
17362
17462
  const objectPerms = permissions.objectPermissions[objectName] ?? [];
17363
17463
  const allPerms = /* @__PURE__ */ new Set([...wildcardPerms, ...objectPerms]);
@@ -17381,9 +17481,6 @@ var PermissionService = class extends BaseService {
17381
17481
  */
17382
17482
  async canAccessSystem(userProfileId, resource, action) {
17383
17483
  const permissions = await this.getEffectivePermissions(userProfileId);
17384
- if (permissions.isAdmin) {
17385
- return true;
17386
- }
17387
17484
  const wildcardPerms = permissions.systemPermissions?.["*"];
17388
17485
  if (wildcardPerms?.includes(action)) {
17389
17486
  return true;
@@ -17415,9 +17512,6 @@ var PermissionService = class extends BaseService {
17415
17512
  */
17416
17513
  async getSystemPermissions(userProfileId, resource) {
17417
17514
  const permissions = await this.getEffectivePermissions(userProfileId);
17418
- if (permissions.isAdmin) {
17419
- return { canRead: true, canCreate: true, canUpdate: true, canDelete: true };
17420
- }
17421
17515
  const wildcardPerms = permissions.systemPermissions?.["*"] ?? [];
17422
17516
  const resourcePerms = permissions.systemPermissions?.[resource] ?? [];
17423
17517
  const allPerms = /* @__PURE__ */ new Set([...wildcardPerms, ...resourcePerms]);
@@ -17622,9 +17716,8 @@ var PermissionService = class extends BaseService {
17622
17716
  * Initialize default roles for the tenant if they don't exist.
17623
17717
  *
17624
17718
  * Creates the following roles with their default permissions:
17625
- * - **admin**: Full access to all system resources and objects
17626
- * - **member**: No system access, can read/create/update objects (no delete)
17627
- * - **guest**: No system access, read-only access to objects
17719
+ * - **owner**: Full access to all system resources and objects
17720
+ * - **member**: Full CRUD on business data, read-only on system resources (people, workspace)
17628
17721
  *
17629
17722
  * This method is idempotent - it only creates roles that don't already exist.
17630
17723
  * Should be called during tenant bootstrap or on first admin login.
@@ -17641,7 +17734,7 @@ var PermissionService = class extends BaseService {
17641
17734
  DEFAULT_ROLE_LABELS,
17642
17735
  DEFAULT_ROLE_DESCRIPTIONS,
17643
17736
  DEFAULT_ROLE_PERMISSIONS
17644
- } = await import("./default-roles-OAMHLOCS.mjs");
17737
+ } = await import("./default-roles-6D3HQ3DQ.mjs");
17645
17738
  const existingRoles = await this.getRoles();
17646
17739
  const existingRoleNames = existingRoles.reduce((set, r) => set.add(r.name), /* @__PURE__ */ new Set());
17647
17740
  for (const roleName of Object.values(DEFAULT_ROLES)) {
@@ -18426,6 +18519,7 @@ async function syncNativeObjects(adapter, nativeRegistry, options = {}) {
18426
18519
  const result = {
18427
18520
  success: true,
18428
18521
  objectsSynced: 0,
18522
+ objectsDeleted: 0,
18429
18523
  attributesSynced: 0,
18430
18524
  objectsCreated: 0,
18431
18525
  objectsUpdated: 0,
@@ -18451,6 +18545,7 @@ async function syncNativeObjects(adapter, nativeRegistry, options = {}) {
18451
18545
  });
18452
18546
  }
18453
18547
  }
18548
+ await cleanupOrphanObjects(tx, nativeObjects, result, options);
18454
18549
  });
18455
18550
  } catch (error2) {
18456
18551
  result.success = false;
@@ -18462,7 +18557,7 @@ async function syncNativeObjects(adapter, nativeRegistry, options = {}) {
18462
18557
  if (options.verbose) {
18463
18558
  console.info(
18464
18559
  `[SyncService] ${result.success ? "\u2713" : "\u2717"} Sync complete:
18465
- Objects: ${result.objectsCreated} created, ${result.objectsUpdated} updated
18560
+ Objects: ${result.objectsCreated} created, ${result.objectsUpdated} updated, ${result.objectsDeleted} deleted
18466
18561
  Attributes: ${result.attributesCreated} created, ${result.attributesUpdated} updated, ${result.attributesDeleted} deleted
18467
18562
  Errors: ${result.errors.length}`
18468
18563
  );
@@ -18574,6 +18669,25 @@ async function cleanupAttributes(adapter, objectId, nativeObject, result) {
18574
18669
  const deletedCount = await adapter.attributes.deleteSystemByNames(objectId, attributeNames);
18575
18670
  result.attributesDeleted += deletedCount;
18576
18671
  }
18672
+ async function cleanupOrphanObjects(adapter, nativeObjects, result, options) {
18673
+ const registryNames = nativeObjects.map((obj) => obj.name);
18674
+ if (options.dryRun) {
18675
+ const allObjects = await adapter.objects.list();
18676
+ const orphans = allObjects.filter((obj) => obj.system && !registryNames.includes(obj.name));
18677
+ result.objectsDeleted += orphans.length;
18678
+ if (options.verbose && orphans.length > 0) {
18679
+ console.info(
18680
+ `[SyncService] Would delete ${orphans.length} orphan system object(s): ${orphans.map((o) => o.name).join(", ")}`
18681
+ );
18682
+ }
18683
+ return;
18684
+ }
18685
+ const deletedCount = await adapter.objects.deleteSystemNotInNames(registryNames);
18686
+ result.objectsDeleted += deletedCount;
18687
+ if (options.verbose && deletedCount > 0) {
18688
+ console.info(`[SyncService] Deleted ${deletedCount} orphan system object(s)`);
18689
+ }
18690
+ }
18577
18691
  function logSyncSuccess(nativeObject, options) {
18578
18692
  if (options.verbose) {
18579
18693
  console.info(