@nextsparkjs/core 0.1.0-beta.97 → 0.1.0-beta.99

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 (80) hide show
  1. package/dist/components/media/MediaCard.d.ts +2 -1
  2. package/dist/components/media/MediaCard.d.ts.map +1 -1
  3. package/dist/components/media/MediaCard.js +13 -9
  4. package/dist/components/media/MediaDetailPanel.d.ts +2 -1
  5. package/dist/components/media/MediaDetailPanel.d.ts.map +1 -1
  6. package/dist/components/media/MediaDetailPanel.js +22 -10
  7. package/dist/components/media/MediaGrid.d.ts +3 -2
  8. package/dist/components/media/MediaGrid.d.ts.map +1 -1
  9. package/dist/components/media/MediaGrid.js +3 -1
  10. package/dist/components/media/MediaList.d.ts +3 -2
  11. package/dist/components/media/MediaList.d.ts.map +1 -1
  12. package/dist/components/media/MediaList.js +10 -6
  13. package/dist/contexts/TeamContext.d.ts.map +1 -1
  14. package/dist/contexts/TeamContext.js +9 -5
  15. package/dist/hooks/useMedia.d.ts.map +1 -1
  16. package/dist/hooks/useMedia.js +20 -14
  17. package/dist/lib/api/api-error.d.ts +41 -0
  18. package/dist/lib/api/api-error.d.ts.map +1 -0
  19. package/dist/lib/api/api-error.js +61 -0
  20. package/dist/lib/api/auth/dual-auth.d.ts +15 -0
  21. package/dist/lib/api/auth/dual-auth.d.ts.map +1 -1
  22. package/dist/lib/api/auth/dual-auth.js +21 -1
  23. package/dist/lib/api/index.d.ts +2 -0
  24. package/dist/lib/api/index.d.ts.map +1 -1
  25. package/dist/lib/api/index.js +5 -0
  26. package/dist/lib/api/permission-middleware.d.ts.map +1 -1
  27. package/dist/lib/api/permission-middleware.js +2 -1
  28. package/dist/lib/services/media.service.d.ts +30 -56
  29. package/dist/lib/services/media.service.d.ts.map +1 -1
  30. package/dist/lib/services/media.service.js +63 -77
  31. package/dist/lib/teams/schema.d.ts +6 -34
  32. package/dist/lib/teams/schema.d.ts.map +1 -1
  33. package/dist/lib/teams/schema.js +14 -7
  34. package/dist/messages/de/index.d.ts +2 -0
  35. package/dist/messages/de/index.d.ts.map +1 -1
  36. package/dist/messages/de/permissions.json +2 -0
  37. package/dist/messages/en/index.d.ts +3 -0
  38. package/dist/messages/en/index.d.ts.map +1 -1
  39. package/dist/messages/en/media.json +1 -0
  40. package/dist/messages/en/permissions.json +2 -0
  41. package/dist/messages/es/index.d.ts +3 -0
  42. package/dist/messages/es/index.d.ts.map +1 -1
  43. package/dist/messages/es/media.json +1 -0
  44. package/dist/messages/es/permissions.json +2 -0
  45. package/dist/messages/fr/index.d.ts +2 -0
  46. package/dist/messages/fr/index.d.ts.map +1 -1
  47. package/dist/messages/fr/permissions.json +2 -0
  48. package/dist/messages/it/index.d.ts +2 -0
  49. package/dist/messages/it/index.d.ts.map +1 -1
  50. package/dist/messages/it/permissions.json +2 -0
  51. package/dist/messages/pt/index.d.ts +2 -0
  52. package/dist/messages/pt/index.d.ts.map +1 -1
  53. package/dist/messages/pt/permissions.json +2 -0
  54. package/dist/migrations/021_media.sql +53 -0
  55. package/dist/providers/query-provider.d.ts +0 -1
  56. package/dist/providers/query-provider.d.ts.map +1 -1
  57. package/dist/providers/query-provider.js +26 -3
  58. package/dist/styles/classes.json +2 -3
  59. package/dist/templates/app/api/csp-report/route.ts +1 -0
  60. package/dist/templates/app/api/v1/media/[id]/route.ts +50 -14
  61. package/dist/templates/app/api/v1/media/[id]/tags/route.ts +75 -9
  62. package/dist/templates/app/api/v1/media/check-duplicates/route.ts +14 -2
  63. package/dist/templates/app/api/v1/media/route.ts +17 -5
  64. package/dist/templates/app/api/v1/media/upload/route.ts +22 -10
  65. package/dist/templates/app/api/v1/media-tags/route.ts +27 -7
  66. package/dist/templates/app/dashboard/(main)/media/page.tsx +35 -23
  67. package/dist/templates/instrumentation.ts +18 -12
  68. package/migrations/021_media.sql +53 -0
  69. package/package.json +15 -15
  70. package/scripts/build/registry/discovery/permissions.mjs +79 -2
  71. package/templates/app/api/csp-report/route.ts +1 -0
  72. package/templates/app/api/v1/media/[id]/route.ts +50 -14
  73. package/templates/app/api/v1/media/[id]/tags/route.ts +75 -9
  74. package/templates/app/api/v1/media/check-duplicates/route.ts +14 -2
  75. package/templates/app/api/v1/media/route.ts +17 -5
  76. package/templates/app/api/v1/media/upload/route.ts +22 -10
  77. package/templates/app/api/v1/media-tags/route.ts +27 -7
  78. package/templates/app/dashboard/(main)/media/page.tsx +35 -23
  79. package/templates/instrumentation.ts +18 -12
  80. package/tests/jest/__mocks__/@nextsparkjs/registries/permissions-registry.ts +28 -17
@@ -11,6 +11,8 @@ export * from './helpers';
11
11
  export * from './rate-limit';
12
12
  export * from './cache';
13
13
  export * from './distributed-cache';
14
+ export * from './api-error';
14
15
  export type { ApiKeyAuth, ApiKeyValidationResult } from './auth';
15
16
  export type { ApiScope } from './keys';
17
+ export { ApiError } from './api-error';
16
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/api/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,QAAQ,CAAC;AACvB,cAAc,kBAAkB,CAAC;AACjC,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,qBAAqB,CAAC;AAGpC,YAAY,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AACjE,YAAY,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/api/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,QAAQ,CAAC;AACvB,cAAc,kBAAkB,CAAC;AACjC,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAG5B,YAAY,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AACjE,YAAY,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC"}
@@ -5,3 +5,8 @@ export * from "./helpers.js";
5
5
  export * from "./rate-limit.js";
6
6
  export * from "./cache.js";
7
7
  export * from "./distributed-cache.js";
8
+ export * from "./api-error.js";
9
+ import { ApiError } from "./api-error.js";
10
+ export {
11
+ ApiError
12
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"permission-middleware.d.ts","sourceRoot":"","sources":["../../../src/lib/api/permission-middleware.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAa1C;;GAEG;AACH,eAAO,MAAM,WAAW,SAAS,CAAA;AAEjC;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAElF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,MAAM,CAOjF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC,CAkCtE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,GACpB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAK9B"}
1
+ {"version":3,"file":"permission-middleware.d.ts","sourceRoot":"","sources":["../../../src/lib/api/permission-middleware.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAc1C;;GAEG;AACH,eAAO,MAAM,WAAW,SAAS,CAAA;AAEjC;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAElF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,MAAM,CAOjF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC,CAkCtE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,GACpB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAK9B"}
@@ -1,5 +1,6 @@
1
1
  import { checkPermission } from "../permissions/check.js";
2
2
  import { NextResponse } from "next/server";
3
+ import { API_ERROR_CODES } from "./api-error.js";
3
4
  const HTTP_TO_ACTION = {
4
5
  "GET": "read",
5
6
  // Single entity retrieval
@@ -31,7 +32,7 @@ async function checkEntityPermission(userId, teamId, entitySlug, action) {
31
32
  success: false,
32
33
  error: {
33
34
  message: `Permission denied: You do not have permission to ${action} ${entitySlug}`,
34
- code: "PERMISSION_DENIED",
35
+ code: API_ERROR_CODES.PERMISSION_DENIED,
35
36
  details: {
36
37
  requiredPermission: permission,
37
38
  entity: entitySlug,
@@ -2,50 +2,40 @@
2
2
  * Media Service
3
3
  *
4
4
  * Provides CRUD operations for media library entries.
5
- * Supports team isolation via RLS, search, filtering by type.
5
+ * ALL methods require teamId for strict team isolation.
6
6
  *
7
7
  * @module MediaService
8
8
  */
9
9
  import type { Media, CreateMediaInput, UpdateMediaInput, MediaListOptions, MediaListResult, MediaTag } from '../media/types';
10
10
  export declare class MediaService {
11
11
  /**
12
- * Get media item by ID
12
+ * Get media item by ID (team-scoped)
13
13
  *
14
14
  * @param id - Media ID
15
15
  * @param userId - User ID for RLS context
16
+ * @param teamId - Team ID for isolation
16
17
  * @returns Media or null if not found
17
- *
18
- * @example
19
- * const media = await MediaService.getById('media-123', 'user-456')
20
18
  */
21
- static getById(id: string, userId: string): Promise<Media | null>;
19
+ static getById(id: string, userId: string, teamId: string): Promise<Media | null>;
22
20
  /**
23
- * List media with pagination, filtering, and search
21
+ * List media with pagination, filtering, and search (team-scoped)
24
22
  *
25
23
  * @param userId - User ID for RLS context
24
+ * @param teamId - Team ID for isolation
26
25
  * @param options - List options (pagination, filtering, search, sort)
27
26
  * @returns Paginated media list result
28
- *
29
- * @example
30
- * const result = await MediaService.list('user-123', {
31
- * limit: 20,
32
- * offset: 0,
33
- * type: 'image',
34
- * search: 'logo',
35
- * orderBy: 'createdAt',
36
- * orderDir: 'desc'
37
- * })
38
27
  */
39
- static list(userId: string, options?: MediaListOptions): Promise<MediaListResult>;
28
+ static list(userId: string, teamId: string, options?: MediaListOptions): Promise<MediaListResult>;
40
29
  /**
41
- * Find existing media by filename and fileSize (duplicate detection)
30
+ * Find existing media by filename and fileSize (duplicate detection, team-scoped)
42
31
  *
43
32
  * @param userId - User ID for RLS context
33
+ * @param teamId - Team ID for isolation
44
34
  * @param filename - Original filename
45
35
  * @param fileSize - File size in bytes
46
36
  * @returns Matching media items (same name+size = likely duplicate)
47
37
  */
48
- static findDuplicates(userId: string, filename: string, fileSize: number): Promise<Media[]>;
38
+ static findDuplicates(userId: string, teamId: string, filename: string, fileSize: number): Promise<Media[]>;
49
39
  /**
50
40
  * Create a new media record
51
41
  *
@@ -53,59 +43,44 @@ export declare class MediaService {
53
43
  * @param teamId - Team ID for isolation
54
44
  * @param data - Media data
55
45
  * @returns Created media record
56
- *
57
- * @example
58
- * const media = await MediaService.create('user-123', 'team-456', {
59
- * url: 'https://example.com/image.jpg',
60
- * filename: 'image.jpg',
61
- * fileSize: 150000,
62
- * mimeType: 'image/jpeg',
63
- * width: 1920,
64
- * height: 1080
65
- * })
66
46
  */
67
47
  static create(userId: string, teamId: string, data: CreateMediaInput): Promise<Media>;
68
48
  /**
69
- * Update media metadata (title, alt, caption - file properties are immutable)
49
+ * Update media metadata (team-scoped)
70
50
  *
71
51
  * @param id - Media ID
72
52
  * @param userId - User ID for RLS context
73
- * @param data - Update data (alt, caption)
74
- * @returns Updated media record
75
- *
76
- * @example
77
- * const media = await MediaService.update('media-123', 'user-456', {
78
- * alt: 'Company logo',
79
- * caption: 'Our brand logo in high resolution'
80
- * })
53
+ * @param data - Update data (title, alt, caption)
54
+ * @param teamId - Team ID for isolation
55
+ * @returns Updated media record or null if not found
81
56
  */
82
- static update(id: string, userId: string, data: UpdateMediaInput): Promise<Media>;
57
+ static update(id: string, userId: string, data: UpdateMediaInput, teamId: string): Promise<Media | null>;
83
58
  /**
84
- * Soft delete a media record (sets status to 'deleted')
59
+ * Soft delete a media record (team-scoped)
85
60
  *
86
61
  * @param id - Media ID
87
62
  * @param userId - User ID for RLS context
63
+ * @param teamId - Team ID for isolation
88
64
  * @returns True if deleted successfully
89
- *
90
- * @example
91
- * const deleted = await MediaService.softDelete('media-123', 'user-456')
92
65
  */
93
- static softDelete(id: string, userId: string): Promise<boolean>;
66
+ static softDelete(id: string, userId: string, teamId: string): Promise<boolean>;
94
67
  /**
95
- * Get all media tags
68
+ * Get all media tags for a team
96
69
  *
97
70
  * @param userId - User ID for RLS context
98
- * @returns Array of media tags
71
+ * @param teamId - Team ID for isolation
72
+ * @returns Array of media tags scoped to the team
99
73
  */
100
- static getTags(userId: string): Promise<MediaTag[]>;
74
+ static getTags(userId: string, teamId: string): Promise<MediaTag[]>;
101
75
  /**
102
76
  * Get tags for a specific media item
103
77
  *
104
78
  * @param mediaId - Media item ID
105
79
  * @param userId - User ID for RLS context
80
+ * @param teamId - Team ID for isolation (media ownership verified before calling)
106
81
  * @returns Array of tags assigned to the media
107
82
  */
108
- static getMediaTags(mediaId: string, userId: string): Promise<MediaTag[]>;
83
+ static getMediaTags(mediaId: string, userId: string, teamId: string): Promise<MediaTag[]>;
109
84
  /**
110
85
  * Add a tag to a media item
111
86
  *
@@ -133,24 +108,23 @@ export declare class MediaService {
133
108
  */
134
109
  static setTags(mediaId: string, tagIds: string[], userId: string): Promise<void>;
135
110
  /**
136
- * Create a new media tag (taxonomy of type 'media_tag')
111
+ * Create a new media tag (team-scoped)
137
112
  *
138
113
  * @param name - Tag display name
139
114
  * @param userId - User ID for RLS context
115
+ * @param teamId - Team ID for isolation
140
116
  * @returns The created tag
141
117
  */
142
- static createTag(name: string, userId: string): Promise<MediaTag>;
118
+ static createTag(name: string, userId: string, teamId: string): Promise<MediaTag>;
143
119
  /**
144
- * Count media items
120
+ * Count media items (team-scoped)
145
121
  *
146
122
  * @param userId - User ID for RLS context
123
+ * @param teamId - Team ID for isolation
147
124
  * @param options - Count options (type filter, status filter)
148
125
  * @returns Total count
149
- *
150
- * @example
151
- * const imageCount = await MediaService.count('user-123', { type: 'image' })
152
126
  */
153
- static count(userId: string, options?: {
127
+ static count(userId: string, teamId: string, options?: {
154
128
  type?: 'image' | 'video' | 'all';
155
129
  status?: string;
156
130
  }): Promise<number>;
@@ -1 +1 @@
1
- {"version":3,"file":"media.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/media.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,KAAK,EACL,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACT,MAAM,gBAAgB,CAAA;AAEvB,qBAAa,YAAY;IAKvB;;;;;;;;;OASG;WACU,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAWvE;;;;;;;;;;;;;;;;OAgBG;WACU,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC;IA8F3F;;;;;;;OAOG;WACU,cAAc,CACzB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,KAAK,EAAE,CAAC;IAiBnB;;;;;;;;;;;;;;;;;OAiBG;WACU,MAAM,CACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,KAAK,CAAC;IAsBjB;;;;;;;;;;;;;OAaG;WACU,MAAM,CACjB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,KAAK,CAAC;IAuCjB;;;;;;;;;OASG;WACU,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkBrE;;;;;OAKG;WACU,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAazD;;;;;;OAMG;WACU,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAgB/E;;;;;;;OAOG;WACU,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBrF;;;;;;;OAOG;WACU,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAexF;;;;;;OAMG;WACU,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBtF;;;;;;OAMG;WACU,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAkBvE;;;;;;;;;OASG;WACU,KAAK,CAChB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAClE,OAAO,CAAC,MAAM,CAAC;CAkBnB"}
1
+ {"version":3,"file":"media.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/media.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,KAAK,EACL,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACT,MAAM,gBAAgB,CAAA;AAEvB,qBAAa,YAAY;IAKvB;;;;;;;OAOG;WACU,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAYvF;;;;;;;OAOG;WACU,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC;IA+F3G;;;;;;;;OAQG;WACU,cAAc,CACzB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,KAAK,EAAE,CAAC;IAkBnB;;;;;;;OAOG;WACU,MAAM,CACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,KAAK,CAAC;IAsBjB;;;;;;;;OAQG;WACU,MAAM,CACjB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,gBAAgB,EACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAyCxB;;;;;;;OAOG;WACU,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkBrF;;;;;;OAMG;WACU,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAczE;;;;;;;OAOG;WACU,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAkB/F;;;;;;;OAOG;WACU,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBrF;;;;;;;OAOG;WACU,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAexF;;;;;;OAMG;WACU,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBtF;;;;;;;OAOG;WACU,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAoBvF;;;;;;;OAOG;WACU,KAAK,CAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAClE,OAAO,CAAC,MAAM,CAAC;CAmBnB"}
@@ -4,44 +4,35 @@ class MediaService {
4
4
  // QUERIES
5
5
  // ============================================
6
6
  /**
7
- * Get media item by ID
7
+ * Get media item by ID (team-scoped)
8
8
  *
9
9
  * @param id - Media ID
10
10
  * @param userId - User ID for RLS context
11
+ * @param teamId - Team ID for isolation
11
12
  * @returns Media or null if not found
12
- *
13
- * @example
14
- * const media = await MediaService.getById('media-123', 'user-456')
15
13
  */
16
- static async getById(id, userId) {
14
+ static async getById(id, userId, teamId) {
17
15
  if (!(id == null ? void 0 : id.trim())) throw new Error("Media ID is required");
18
16
  if (!(userId == null ? void 0 : userId.trim())) throw new Error("User ID is required");
17
+ if (!(teamId == null ? void 0 : teamId.trim())) throw new Error("Team ID is required");
19
18
  return queryOneWithRLS(
20
- `SELECT * FROM "media" WHERE id = $1 AND status = 'active'`,
21
- [id],
19
+ `SELECT * FROM "media" WHERE id = $1 AND "teamId" = $2 AND status = 'active'`,
20
+ [id, teamId],
22
21
  userId
23
22
  );
24
23
  }
25
24
  /**
26
- * List media with pagination, filtering, and search
25
+ * List media with pagination, filtering, and search (team-scoped)
27
26
  *
28
27
  * @param userId - User ID for RLS context
28
+ * @param teamId - Team ID for isolation
29
29
  * @param options - List options (pagination, filtering, search, sort)
30
30
  * @returns Paginated media list result
31
- *
32
- * @example
33
- * const result = await MediaService.list('user-123', {
34
- * limit: 20,
35
- * offset: 0,
36
- * type: 'image',
37
- * search: 'logo',
38
- * orderBy: 'createdAt',
39
- * orderDir: 'desc'
40
- * })
41
31
  */
42
- static async list(userId, options = {}) {
32
+ static async list(userId, teamId, options = {}) {
43
33
  var _a;
44
34
  if (!(userId == null ? void 0 : userId.trim())) throw new Error("User ID is required");
35
+ if (!(teamId == null ? void 0 : teamId.trim())) throw new Error("Team ID is required");
45
36
  const {
46
37
  limit = 20,
47
38
  offset = 0,
@@ -53,9 +44,9 @@ class MediaService {
53
44
  tagIds,
54
45
  tagSlugs
55
46
  } = options;
56
- const conditions = ["m.status = $1"];
57
- const params = [status];
58
- let paramIndex = 2;
47
+ const conditions = ["m.status = $1", 'm."teamId" = $2'];
48
+ const params = [status, teamId];
49
+ let paramIndex = 3;
59
50
  if (type === "image") {
60
51
  conditions.push(`m."mimeType" LIKE 'image/%'`);
61
52
  } else if (type === "video") {
@@ -116,21 +107,23 @@ class MediaService {
116
107
  return { data, total, limit, offset };
117
108
  }
118
109
  /**
119
- * Find existing media by filename and fileSize (duplicate detection)
110
+ * Find existing media by filename and fileSize (duplicate detection, team-scoped)
120
111
  *
121
112
  * @param userId - User ID for RLS context
113
+ * @param teamId - Team ID for isolation
122
114
  * @param filename - Original filename
123
115
  * @param fileSize - File size in bytes
124
116
  * @returns Matching media items (same name+size = likely duplicate)
125
117
  */
126
- static async findDuplicates(userId, filename, fileSize) {
118
+ static async findDuplicates(userId, teamId, filename, fileSize) {
127
119
  if (!(userId == null ? void 0 : userId.trim())) throw new Error("User ID is required");
120
+ if (!(teamId == null ? void 0 : teamId.trim())) throw new Error("Team ID is required");
128
121
  return queryWithRLS(
129
122
  `SELECT * FROM "media"
130
- WHERE filename = $1 AND "fileSize" = $2 AND status = 'active'
123
+ WHERE filename = $1 AND "fileSize" = $2 AND "teamId" = $3 AND status = 'active'
131
124
  ORDER BY "createdAt" DESC
132
125
  LIMIT 5`,
133
- [filename, fileSize],
126
+ [filename, fileSize, teamId],
134
127
  userId
135
128
  );
136
129
  }
@@ -144,16 +137,6 @@ class MediaService {
144
137
  * @param teamId - Team ID for isolation
145
138
  * @param data - Media data
146
139
  * @returns Created media record
147
- *
148
- * @example
149
- * const media = await MediaService.create('user-123', 'team-456', {
150
- * url: 'https://example.com/image.jpg',
151
- * filename: 'image.jpg',
152
- * fileSize: 150000,
153
- * mimeType: 'image/jpeg',
154
- * width: 1920,
155
- * height: 1080
156
- * })
157
140
  */
158
141
  static async create(userId, teamId, data) {
159
142
  if (!(userId == null ? void 0 : userId.trim())) throw new Error("User ID is required");
@@ -183,22 +166,18 @@ class MediaService {
183
166
  return result.rows[0];
184
167
  }
185
168
  /**
186
- * Update media metadata (title, alt, caption - file properties are immutable)
169
+ * Update media metadata (team-scoped)
187
170
  *
188
171
  * @param id - Media ID
189
172
  * @param userId - User ID for RLS context
190
- * @param data - Update data (alt, caption)
191
- * @returns Updated media record
192
- *
193
- * @example
194
- * const media = await MediaService.update('media-123', 'user-456', {
195
- * alt: 'Company logo',
196
- * caption: 'Our brand logo in high resolution'
197
- * })
173
+ * @param data - Update data (title, alt, caption)
174
+ * @param teamId - Team ID for isolation
175
+ * @returns Updated media record or null if not found
198
176
  */
199
- static async update(id, userId, data) {
177
+ static async update(id, userId, data, teamId) {
200
178
  if (!(id == null ? void 0 : id.trim())) throw new Error("Media ID is required");
201
179
  if (!(userId == null ? void 0 : userId.trim())) throw new Error("User ID is required");
180
+ if (!(teamId == null ? void 0 : teamId.trim())) throw new Error("Team ID is required");
202
181
  const setClauses = [];
203
182
  const params = [];
204
183
  let paramIndex = 1;
@@ -217,55 +196,57 @@ class MediaService {
217
196
  if (setClauses.length === 0) throw new Error("No fields to update");
218
197
  setClauses.push(`"updatedAt" = NOW()`);
219
198
  params.push(id);
199
+ paramIndex++;
200
+ params.push(teamId);
220
201
  const result = await mutateWithRLS(
221
202
  `UPDATE "media"
222
203
  SET ${setClauses.join(", ")}
223
- WHERE id = $${paramIndex} AND status = 'active'
204
+ WHERE id = $${paramIndex - 1} AND status = 'active' AND "teamId" = $${paramIndex}
224
205
  RETURNING *`,
225
206
  params,
226
207
  userId
227
208
  );
228
- if (!result.rows[0]) throw new Error("Media not found or not authorized");
229
- return result.rows[0];
209
+ return result.rows[0] || null;
230
210
  }
231
211
  /**
232
- * Soft delete a media record (sets status to 'deleted')
212
+ * Soft delete a media record (team-scoped)
233
213
  *
234
214
  * @param id - Media ID
235
215
  * @param userId - User ID for RLS context
216
+ * @param teamId - Team ID for isolation
236
217
  * @returns True if deleted successfully
237
- *
238
- * @example
239
- * const deleted = await MediaService.softDelete('media-123', 'user-456')
240
218
  */
241
- static async softDelete(id, userId) {
219
+ static async softDelete(id, userId, teamId) {
242
220
  if (!(id == null ? void 0 : id.trim())) throw new Error("Media ID is required");
243
221
  if (!(userId == null ? void 0 : userId.trim())) throw new Error("User ID is required");
222
+ if (!(teamId == null ? void 0 : teamId.trim())) throw new Error("Team ID is required");
244
223
  const result = await mutateWithRLS(
245
224
  `UPDATE "media" SET status = 'deleted', "updatedAt" = NOW()
246
- WHERE id = $1 AND status = 'active'`,
247
- [id],
225
+ WHERE id = $1 AND "teamId" = $2 AND status = 'active'`,
226
+ [id, teamId],
248
227
  userId
249
228
  );
250
229
  return result.rowCount > 0;
251
230
  }
252
231
  // ============================================
253
- // TAG OPERATIONS
232
+ // TAG OPERATIONS (team-scoped)
254
233
  // ============================================
255
234
  /**
256
- * Get all media tags
235
+ * Get all media tags for a team
257
236
  *
258
237
  * @param userId - User ID for RLS context
259
- * @returns Array of media tags
238
+ * @param teamId - Team ID for isolation
239
+ * @returns Array of media tags scoped to the team
260
240
  */
261
- static async getTags(userId) {
241
+ static async getTags(userId, teamId) {
262
242
  if (!(userId == null ? void 0 : userId.trim())) throw new Error("User ID is required");
243
+ if (!(teamId == null ? void 0 : teamId.trim())) throw new Error("Team ID is required");
263
244
  return queryWithRLS(
264
245
  `SELECT id, type, slug, name, description, icon, color, "order", "isActive", "createdAt", "updatedAt"
265
246
  FROM "taxonomies"
266
- WHERE type = 'media_tag' AND "isActive" = true AND "deletedAt" IS NULL
247
+ WHERE type = 'media_tag' AND "teamId" = $1 AND "isActive" = true AND "deletedAt" IS NULL
267
248
  ORDER BY "order" ASC, name ASC`,
268
- [],
249
+ [teamId],
269
250
  userId
270
251
  );
271
252
  }
@@ -274,19 +255,22 @@ class MediaService {
274
255
  *
275
256
  * @param mediaId - Media item ID
276
257
  * @param userId - User ID for RLS context
258
+ * @param teamId - Team ID for isolation (media ownership verified before calling)
277
259
  * @returns Array of tags assigned to the media
278
260
  */
279
- static async getMediaTags(mediaId, userId) {
261
+ static async getMediaTags(mediaId, userId, teamId) {
280
262
  if (!(mediaId == null ? void 0 : mediaId.trim())) throw new Error("Media ID is required");
281
263
  if (!(userId == null ? void 0 : userId.trim())) throw new Error("User ID is required");
264
+ if (!(teamId == null ? void 0 : teamId.trim())) throw new Error("Team ID is required");
282
265
  return queryWithRLS(
283
266
  `SELECT t.id, t.type, t.slug, t.name, t.description, t.icon, t.color, t."order", t."isActive", t."createdAt", t."updatedAt"
284
267
  FROM "taxonomies" t
285
268
  JOIN "entity_taxonomy_relations" etr ON etr."taxonomyId" = t.id
286
269
  WHERE etr."entityType" = 'media' AND etr."entityId" = $1
270
+ AND t."teamId" = $2
287
271
  AND t."isActive" = true AND t."deletedAt" IS NULL
288
272
  ORDER BY t."order" ASC, t.name ASC`,
289
- [mediaId],
273
+ [mediaId, teamId],
290
274
  userId
291
275
  );
292
276
  }
@@ -359,42 +343,44 @@ class MediaService {
359
343
  }
360
344
  }
361
345
  /**
362
- * Create a new media tag (taxonomy of type 'media_tag')
346
+ * Create a new media tag (team-scoped)
363
347
  *
364
348
  * @param name - Tag display name
365
349
  * @param userId - User ID for RLS context
350
+ * @param teamId - Team ID for isolation
366
351
  * @returns The created tag
367
352
  */
368
- static async createTag(name, userId) {
353
+ static async createTag(name, userId, teamId) {
369
354
  if (!(name == null ? void 0 : name.trim())) throw new Error("Tag name is required");
370
355
  if (!(userId == null ? void 0 : userId.trim())) throw new Error("User ID is required");
356
+ if (!(teamId == null ? void 0 : teamId.trim())) throw new Error("Team ID is required");
371
357
  const slug = name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
372
358
  const result = await mutateWithRLS(
373
- `INSERT INTO "taxonomies" (type, slug, name, "isActive")
374
- VALUES ('media_tag', $1, $2, true)
375
- ON CONFLICT (type, slug) DO UPDATE SET name = EXCLUDED.name
359
+ `INSERT INTO "taxonomies" (type, slug, name, "teamId", "isActive")
360
+ VALUES ('media_tag', $1, $2, $3, true)
361
+ ON CONFLICT (type, slug, "teamId") WHERE "teamId" IS NOT NULL
362
+ DO UPDATE SET name = EXCLUDED.name
376
363
  RETURNING id, slug, name, color, icon, "order", "isActive"`,
377
- [slug, name.trim()],
364
+ [slug, name.trim(), teamId],
378
365
  userId
379
366
  );
380
367
  return result.rows[0];
381
368
  }
382
369
  /**
383
- * Count media items
370
+ * Count media items (team-scoped)
384
371
  *
385
372
  * @param userId - User ID for RLS context
373
+ * @param teamId - Team ID for isolation
386
374
  * @param options - Count options (type filter, status filter)
387
375
  * @returns Total count
388
- *
389
- * @example
390
- * const imageCount = await MediaService.count('user-123', { type: 'image' })
391
376
  */
392
- static async count(userId, options = {}) {
377
+ static async count(userId, teamId, options = {}) {
393
378
  var _a;
394
379
  if (!(userId == null ? void 0 : userId.trim())) throw new Error("User ID is required");
380
+ if (!(teamId == null ? void 0 : teamId.trim())) throw new Error("Team ID is required");
395
381
  const { type = "all", status = "active" } = options;
396
- const conditions = ["status = $1"];
397
- const params = [status];
382
+ const conditions = ["status = $1", '"teamId" = $2'];
383
+ const params = [status, teamId];
398
384
  if (type === "image") conditions.push(`"mimeType" LIKE 'image/%'`);
399
385
  else if (type === "video") conditions.push(`"mimeType" LIKE 'video/%'`);
400
386
  const result = await queryWithRLS(
@@ -7,12 +7,7 @@
7
7
  * @module core/lib/teams/schema
8
8
  */
9
9
  import { z } from 'zod';
10
- export declare const teamRoleSchema: z.ZodEnum<{
11
- member: "member";
12
- owner: "owner";
13
- admin: "admin";
14
- viewer: "viewer";
15
- }>;
10
+ export declare const teamRoleSchema: z.ZodString;
16
11
  export declare const invitationStatusSchema: z.ZodEnum<{
17
12
  expired: "expired";
18
13
  pending: "pending";
@@ -34,12 +29,7 @@ export declare const teamMemberSchema: z.ZodObject<{
34
29
  id: z.ZodString;
35
30
  teamId: z.ZodString;
36
31
  userId: z.ZodString;
37
- role: z.ZodEnum<{
38
- member: "member";
39
- owner: "owner";
40
- admin: "admin";
41
- viewer: "viewer";
42
- }>;
32
+ role: z.ZodString;
43
33
  invitedBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
44
34
  joinedAt: z.ZodString;
45
35
  createdAt: z.ZodString;
@@ -49,12 +39,7 @@ export declare const teamInvitationSchema: z.ZodObject<{
49
39
  id: z.ZodString;
50
40
  teamId: z.ZodString;
51
41
  email: z.ZodString;
52
- role: z.ZodEnum<{
53
- member: "member";
54
- owner: "owner";
55
- admin: "admin";
56
- viewer: "viewer";
57
- }>;
42
+ role: z.ZodString;
58
43
  status: z.ZodEnum<{
59
44
  expired: "expired";
60
45
  pending: "pending";
@@ -116,18 +101,10 @@ export declare const updateTeamSchema: z.ZodObject<{
116
101
  }, z.core.$strip>;
117
102
  export declare const inviteMemberSchema: z.ZodObject<{
118
103
  email: z.ZodString;
119
- role: z.ZodEnum<{
120
- member: "member";
121
- admin: "admin";
122
- viewer: "viewer";
123
- }>;
104
+ role: z.ZodString;
124
105
  }, z.core.$strip>;
125
106
  export declare const updateMemberRoleSchema: z.ZodObject<{
126
- role: z.ZodEnum<{
127
- member: "member";
128
- admin: "admin";
129
- viewer: "viewer";
130
- }>;
107
+ role: z.ZodString;
131
108
  }, z.core.$strip>;
132
109
  export declare const paginationSchema: z.ZodObject<{
133
110
  page: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
@@ -154,12 +131,7 @@ export declare const teamListQuerySchema: z.ZodObject<{
154
131
  export declare const memberListQuerySchema: z.ZodObject<{
155
132
  page: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
156
133
  limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
157
- role: z.ZodOptional<z.ZodEnum<{
158
- member: "member";
159
- owner: "owner";
160
- admin: "admin";
161
- viewer: "viewer";
162
- }>>;
134
+ role: z.ZodOptional<z.ZodString>;
163
135
  search: z.ZodOptional<z.ZodString>;
164
136
  }, z.core.$strip>;
165
137
  export declare const invitationListQuerySchema: z.ZodObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/lib/teams/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,cAAc;;;;;EAAiD,CAAA;AAC5E,eAAO,MAAM,sBAAsB;;;;;EAAyD,CAAA;AAG5F,eAAO,MAAM,UAAU;;;;;;;;;;iBAerB,CAAA;AAGF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;iBAS3B,CAAA;AAGF,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;iBAa/B,CAAA;AAGF,eAAO,MAAM,gBAAgB;;;;iBAI3B,CAAA;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB;;;iBAOhC,CAAA;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB;;;;iBAIhC,CAAA;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB;;;;;;iBAAqD,CAAA;AAElF,eAAO,MAAM,kBAAkB;;;;;;;iBAK7B,CAAA;AAEF,eAAO,MAAM,sBAAsB;;;;;;iBAIjC,CAAA;AAGF,eAAO,MAAM,gBAAgB;;;iBAG3B,CAAA;AAGF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;iBAK9B,CAAA;AAEF,eAAO,MAAM,qBAAqB;;;;;;;;;;iBAGhC,CAAA;AAEF,eAAO,MAAM,yBAAyB;;;;;;;;;iBAEpC,CAAA;AAGF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA;AACnD,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAC/D,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA;AACvE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAC/D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAC/D,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AACzE,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AACzE,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AACnE,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAC3E,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AACrE,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AACzE,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/lib/teams/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAKvB,eAAO,MAAM,cAAc,aAG1B,CAAA;AACD,eAAO,MAAM,sBAAsB;;;;;EAAyD,CAAA;AAG5F,eAAO,MAAM,UAAU;;;;;;;;;;iBAerB,CAAA;AAGF,eAAO,MAAM,gBAAgB;;;;;;;;;iBAS3B,CAAA;AAGF,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;iBAa/B,CAAA;AAGF,eAAO,MAAM,gBAAgB;;;;iBAI3B,CAAA;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB;;;iBAOhC,CAAA;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB;;;;iBAIhC,CAAA;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB;;;;;;iBAAqD,CAAA;AAElF,eAAO,MAAM,kBAAkB;;;iBAM7B,CAAA;AAEF,eAAO,MAAM,sBAAsB;;iBAKjC,CAAA;AAGF,eAAO,MAAM,gBAAgB;;;iBAG3B,CAAA;AAGF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;iBAK9B,CAAA;AAEF,eAAO,MAAM,qBAAqB;;;;;iBAGhC,CAAA;AAEF,eAAO,MAAM,yBAAyB;;;;;;;;;iBAEpC,CAAA;AAGF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA;AACnD,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAC/D,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA;AACvE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAC/D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAC/D,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AACzE,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AACzE,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AACnE,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAC3E,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AACrE,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AACzE,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA"}
@@ -1,5 +1,10 @@
1
1
  import { z } from "zod";
2
- const teamRoleSchema = z.enum(["owner", "admin", "member", "viewer"]);
2
+ import { AVAILABLE_ROLES } from "@nextsparkjs/registries/permissions-registry";
3
+ import { getInvitableRoles } from "./permissions.js";
4
+ const teamRoleSchema = z.string().refine(
5
+ (role) => AVAILABLE_ROLES.includes(role),
6
+ (role) => ({ message: `Invalid team role: ${role}. Must be one of: ${[...AVAILABLE_ROLES].join(", ")}` })
7
+ );
3
8
  const invitationStatusSchema = z.enum(["pending", "accepted", "declined", "expired"]);
4
9
  const teamSchema = z.object({
5
10
  id: z.string().uuid(),
@@ -58,15 +63,17 @@ const adminUpdateTeamSchema = z.object({
58
63
  const updateTeamSchema = ownerUpdateTeamSchema.merge(adminUpdateTeamSchema);
59
64
  const inviteMemberSchema = z.object({
60
65
  email: z.string().email("Invalid email address"),
61
- role: z.enum(["admin", "member", "viewer"], {
62
- message: "Role must be admin, member, or viewer"
63
- })
66
+ role: z.string().refine(
67
+ (role) => getInvitableRoles().includes(role),
68
+ (role) => ({ message: `Role must be one of: ${getInvitableRoles().join(", ")}` })
69
+ )
64
70
  // Cannot invite as owner
65
71
  });
66
72
  const updateMemberRoleSchema = z.object({
67
- role: z.enum(["admin", "member", "viewer"], {
68
- message: "Role must be admin, member, or viewer"
69
- })
73
+ role: z.string().refine(
74
+ (role) => getInvitableRoles().includes(role),
75
+ (role) => ({ message: `Role must be one of: ${getInvitableRoles().join(", ")}` })
76
+ )
70
77
  // Cannot promote to owner
71
78
  });
72
79
  const paginationSchema = z.object({
@@ -1248,6 +1248,8 @@ declare const _default: {
1248
1248
  allPermissions: string;
1249
1249
  permission: string;
1250
1250
  dangerousAction: string;
1251
+ roleChanged: string;
1252
+ roleChangedDescription: string;
1251
1253
  roles: {
1252
1254
  owner: {
1253
1255
  title: string;