@stndrds/schema 1.0.0-alpha.77 → 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";
@@ -4590,8 +4587,6 @@ function createMockPermissionsRepository(stores) {
4590
4587
  getEffectivePermissions(userProfileId) {
4591
4588
  const tenantId = getTenantId();
4592
4589
  const userRoleIds = Array.from(stores.userRoles.values()).filter((ur) => ur.userProfileId === userProfileId && ur.tenantId === tenantId).map((ur) => ur.roleId);
4593
- const userRoles = Array.from(stores.roles.values()).filter((r) => userRoleIds.includes(r.id));
4594
- const hasAdmin = userRoles.some((r) => isAdminRole(r.name));
4595
4590
  const userPermissions = Array.from(stores.permissions.values()).filter(
4596
4591
  (p) => userRoleIds.includes(p.roleId)
4597
4592
  );
@@ -4618,7 +4613,7 @@ function createMockPermissionsRepository(stores) {
4618
4613
  }
4619
4614
  }
4620
4615
  }
4621
- return Promise.resolve({ isAdmin: hasAdmin, objectPermissions, systemPermissions });
4616
+ return Promise.resolve({ objectPermissions, systemPermissions });
4622
4617
  },
4623
4618
  countUsersWithRole(roleName) {
4624
4619
  const tenantId = getTenantId();
@@ -9867,15 +9862,31 @@ var AuditService = class extends BaseService {
9867
9862
  if (!this.adapter.audit) {
9868
9863
  return;
9869
9864
  }
9865
+ const resolved = await this.resolveActorEmail(entry);
9870
9866
  if (this.options?.async) {
9871
- this.buffer.push(entry);
9867
+ this.buffer.push(resolved);
9872
9868
  const batchSize = this.options.batchSize ?? 10;
9873
9869
  if (this.buffer.length >= batchSize) {
9874
9870
  await this.flush();
9875
9871
  }
9876
9872
  } else {
9877
- 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
+ }
9878
9888
  }
9889
+ return entry;
9879
9890
  }
9880
9891
  /**
9881
9892
  * Start the flush timer for async mode
@@ -15123,6 +15134,74 @@ var UserProfileService = class extends BaseService {
15123
15134
  await this.invalidateCache(cacheKeys.userProfileByEmail(this.tenantId, email));
15124
15135
  }
15125
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
+ // ============================================================================
15126
15205
  /**
15127
15206
  * Create a new user profile (typically after first auth).
15128
15207
  * Automatically uses tenant context from AsyncLocalStorage.
@@ -15163,18 +15242,19 @@ var UserProfileService = class extends BaseService {
15163
15242
  targetUserEmail: profile.email
15164
15243
  });
15165
15244
  }
15166
- return profile;
15245
+ return this.resolveAvatarUrl(profile);
15167
15246
  }
15168
15247
  /**
15169
15248
  * Get user profile by ID.
15170
15249
  * Results are cached if a CacheAdapter is configured.
15171
15250
  */
15172
15251
  async getProfile(profileId) {
15173
- return this.cachedBy(
15252
+ const profile = await this.cachedBy(
15174
15253
  "userProfileById",
15175
15254
  profileId,
15176
15255
  () => this.adapter.userProfiles.findById(profileId)
15177
15256
  );
15257
+ return profile ? this.resolveAvatarUrl(profile) : null;
15178
15258
  }
15179
15259
  /**
15180
15260
  * Get user profile by ID or throw
@@ -15196,11 +15276,12 @@ var UserProfileService = class extends BaseService {
15196
15276
  * @returns User profile or null
15197
15277
  */
15198
15278
  async getProfileByAuthId(authId) {
15199
- return this.cachedBy(
15279
+ const profile = await this.cachedBy(
15200
15280
  "userProfileByAuthId",
15201
15281
  authId,
15202
15282
  () => this.adapter.userProfiles.findByAuthId(authId)
15203
15283
  );
15284
+ return profile ? this.resolveAvatarUrl(profile) : null;
15204
15285
  }
15205
15286
  /**
15206
15287
  * Get or create user profile (idempotent operation)
@@ -15239,11 +15320,11 @@ var UserProfileService = class extends BaseService {
15239
15320
  const updated = await this.adapter.userProfiles.update(profileId, data);
15240
15321
  await this.invalidateProfileCache(updated.id, updated.authId, updated.email);
15241
15322
  if (this.auditService && this.userId) {
15242
- const changes = buildAuditChanges(existing, data, [
15243
- "firstName",
15244
- "lastName",
15245
- "status"
15246
- ]);
15323
+ const changes = buildAuditChanges(
15324
+ existing,
15325
+ data,
15326
+ ["firstName", "lastName", "status"]
15327
+ );
15247
15328
  if (changes.length > 0) {
15248
15329
  await this.auditService.logUserAction({
15249
15330
  action: "user.updated",
@@ -15254,7 +15335,7 @@ var UserProfileService = class extends BaseService {
15254
15335
  });
15255
15336
  }
15256
15337
  }
15257
- return updated;
15338
+ return this.resolveAvatarUrl(updated);
15258
15339
  }
15259
15340
  /**
15260
15341
  * Delete user profile.
@@ -15291,7 +15372,8 @@ var UserProfileService = class extends BaseService {
15291
15372
  * Automatically uses tenant context from AsyncLocalStorage.
15292
15373
  */
15293
15374
  async listProfiles(options) {
15294
- return await this.adapter.userProfiles.list(options);
15375
+ const profiles = await this.adapter.userProfiles.list(options);
15376
+ return this.resolveAvatarUrls(profiles);
15295
15377
  }
15296
15378
  /**
15297
15379
  * Update last login timestamp
@@ -15322,11 +15404,12 @@ var UserProfileService = class extends BaseService {
15322
15404
  * Automatically uses tenant context from AsyncLocalStorage.
15323
15405
  */
15324
15406
  async getProfileByEmail(email) {
15325
- return this.cachedBy(
15407
+ const profile = await this.cachedBy(
15326
15408
  "userProfileByEmail",
15327
15409
  email,
15328
15410
  () => this.adapter.userProfiles.findByEmail(email)
15329
15411
  );
15412
+ return profile ? this.resolveAvatarUrl(profile) : null;
15330
15413
  }
15331
15414
  /**
15332
15415
  * Invite a new user by email.
@@ -15359,6 +15442,21 @@ var UserProfileService = class extends BaseService {
15359
15442
  throw new Error(`User with email "${data.email}" already exists in this tenant`);
15360
15443
  }
15361
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
+ }
15362
15460
  await this.invalidateProfileCache(profile.id, profile.authId, profile.email);
15363
15461
  if (this.auditService && this.userId) {
15364
15462
  await this.auditService.logUserAction({
@@ -15368,7 +15466,7 @@ var UserProfileService = class extends BaseService {
15368
15466
  targetUserEmail: profile.email
15369
15467
  });
15370
15468
  }
15371
- return profile;
15469
+ return this.resolveAvatarUrl(profile);
15372
15470
  }
15373
15471
  };
15374
15472
 
@@ -17041,14 +17139,11 @@ var FileService = class extends BaseService {
17041
17139
  * @param userId - User ID to check
17042
17140
  * @returns true if user can access the file
17043
17141
  */
17044
- async checkAccess(fileId, userId, options) {
17142
+ async checkAccess(fileId, userId) {
17045
17143
  const file2 = await this.getFile(fileId);
17046
17144
  if (!file2) {
17047
17145
  return false;
17048
17146
  }
17049
- if (options?.isAdmin) {
17050
- return true;
17051
- }
17052
17147
  if (file2.visibility === "public") {
17053
17148
  return true;
17054
17149
  }
@@ -17332,9 +17427,6 @@ var PermissionService = class extends BaseService {
17332
17427
  */
17333
17428
  async canAccessObject(userProfileId, objectName, action) {
17334
17429
  const permissions = await this.getEffectivePermissions(userProfileId);
17335
- if (permissions.isAdmin) {
17336
- return true;
17337
- }
17338
17430
  const wildcardPerms = permissions.objectPermissions["*"];
17339
17431
  if (wildcardPerms?.includes(action)) {
17340
17432
  return true;
@@ -17366,9 +17458,6 @@ var PermissionService = class extends BaseService {
17366
17458
  */
17367
17459
  async getObjectPermissions(userProfileId, objectName) {
17368
17460
  const permissions = await this.getEffectivePermissions(userProfileId);
17369
- if (permissions.isAdmin) {
17370
- return { canRead: true, canCreate: true, canUpdate: true, canDelete: true };
17371
- }
17372
17461
  const wildcardPerms = permissions.objectPermissions["*"] ?? [];
17373
17462
  const objectPerms = permissions.objectPermissions[objectName] ?? [];
17374
17463
  const allPerms = /* @__PURE__ */ new Set([...wildcardPerms, ...objectPerms]);
@@ -17392,9 +17481,6 @@ var PermissionService = class extends BaseService {
17392
17481
  */
17393
17482
  async canAccessSystem(userProfileId, resource, action) {
17394
17483
  const permissions = await this.getEffectivePermissions(userProfileId);
17395
- if (permissions.isAdmin) {
17396
- return true;
17397
- }
17398
17484
  const wildcardPerms = permissions.systemPermissions?.["*"];
17399
17485
  if (wildcardPerms?.includes(action)) {
17400
17486
  return true;
@@ -17426,9 +17512,6 @@ var PermissionService = class extends BaseService {
17426
17512
  */
17427
17513
  async getSystemPermissions(userProfileId, resource) {
17428
17514
  const permissions = await this.getEffectivePermissions(userProfileId);
17429
- if (permissions.isAdmin) {
17430
- return { canRead: true, canCreate: true, canUpdate: true, canDelete: true };
17431
- }
17432
17515
  const wildcardPerms = permissions.systemPermissions?.["*"] ?? [];
17433
17516
  const resourcePerms = permissions.systemPermissions?.[resource] ?? [];
17434
17517
  const allPerms = /* @__PURE__ */ new Set([...wildcardPerms, ...resourcePerms]);
@@ -17633,9 +17716,8 @@ var PermissionService = class extends BaseService {
17633
17716
  * Initialize default roles for the tenant if they don't exist.
17634
17717
  *
17635
17718
  * Creates the following roles with their default permissions:
17636
- * - **admin**: Full access to all system resources and objects
17637
- * - **member**: No system access, can read/create/update objects (no delete)
17638
- * - **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)
17639
17721
  *
17640
17722
  * This method is idempotent - it only creates roles that don't already exist.
17641
17723
  * Should be called during tenant bootstrap or on first admin login.
@@ -17652,7 +17734,7 @@ var PermissionService = class extends BaseService {
17652
17734
  DEFAULT_ROLE_LABELS,
17653
17735
  DEFAULT_ROLE_DESCRIPTIONS,
17654
17736
  DEFAULT_ROLE_PERMISSIONS
17655
- } = await import("./default-roles-OAMHLOCS.mjs");
17737
+ } = await import("./default-roles-6D3HQ3DQ.mjs");
17656
17738
  const existingRoles = await this.getRoles();
17657
17739
  const existingRoleNames = existingRoles.reduce((set, r) => set.add(r.name), /* @__PURE__ */ new Set());
17658
17740
  for (const roleName of Object.values(DEFAULT_ROLES)) {
@@ -18591,9 +18673,7 @@ async function cleanupOrphanObjects(adapter, nativeObjects, result, options) {
18591
18673
  const registryNames = nativeObjects.map((obj) => obj.name);
18592
18674
  if (options.dryRun) {
18593
18675
  const allObjects = await adapter.objects.list();
18594
- const orphans = allObjects.filter(
18595
- (obj) => obj.system && !registryNames.includes(obj.name)
18596
- );
18676
+ const orphans = allObjects.filter((obj) => obj.system && !registryNames.includes(obj.name));
18597
18677
  result.objectsDeleted += orphans.length;
18598
18678
  if (options.verbose && orphans.length > 0) {
18599
18679
  console.info(