@structcms/api 0.1.0 → 0.1.1

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.
@@ -1,4 +1,4 @@
1
- import { S as StorageAdapter, M as MediaAdapter, A as AuthAdapter } from '../types-Zi0Iyow1.cjs';
1
+ import { S as StorageAdapter, M as MediaAdapter, A as AuthAdapter } from '../types-Cdui_Ets.cjs';
2
2
 
3
3
  interface SupabaseAdapterFactoryStorageConfig {
4
4
  bucket?: string;
@@ -1,4 +1,4 @@
1
- import { S as StorageAdapter, M as MediaAdapter, A as AuthAdapter } from '../types-Zi0Iyow1.js';
1
+ import { S as StorageAdapter, M as MediaAdapter, A as AuthAdapter } from '../types-Cdui_Ets.js';
2
2
 
3
3
  interface SupabaseAdapterFactoryStorageConfig {
4
4
  bucket?: string;
@@ -109,7 +109,38 @@ function createAuthAdapter(config) {
109
109
  return new SupabaseAuthAdapter(config);
110
110
  }
111
111
 
112
+ // src/media/types.ts
113
+ var MAX_FILE_SIZE = 50 * 1024 * 1024;
114
+ var ALLOWED_MIME_TYPES = [
115
+ "image/jpeg",
116
+ "image/png",
117
+ "image/gif",
118
+ "image/webp",
119
+ "image/svg+xml"
120
+ ];
121
+ var ALLOWED_DOCUMENT_MIME_TYPES = [
122
+ "application/pdf",
123
+ "application/msword",
124
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
125
+ "application/vnd.ms-excel",
126
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
127
+ "application/vnd.ms-powerpoint",
128
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
129
+ "text/plain",
130
+ "text/csv",
131
+ "application/zip",
132
+ "application/gzip"
133
+ ];
134
+ var ALL_ALLOWED_MIME_TYPES = [
135
+ ...ALLOWED_MIME_TYPES,
136
+ ...ALLOWED_DOCUMENT_MIME_TYPES
137
+ ];
138
+
112
139
  // src/media/supabase-adapter.ts
140
+ function deriveCategory(mimeType) {
141
+ const imageMimes = ALLOWED_MIME_TYPES;
142
+ return imageMimes.includes(mimeType) ? "image" : "document";
143
+ }
113
144
  var MediaError = class extends Error {
114
145
  constructor(message, code, details) {
115
146
  super(message);
@@ -151,6 +182,7 @@ var SupabaseMediaAdapter = class {
151
182
  url: this.getPublicUrl(row.storage_path),
152
183
  mimeType: row.mime_type,
153
184
  size: row.size,
185
+ category: row.category,
154
186
  createdAt: new Date(row.created_at)
155
187
  };
156
188
  }
@@ -171,7 +203,8 @@ var SupabaseMediaAdapter = class {
171
203
  filename: input.filename,
172
204
  storage_path: storagePath,
173
205
  mime_type: input.mimeType,
174
- size: input.size
206
+ size: input.size,
207
+ category: deriveCategory(input.mimeType)
175
208
  }).select().single();
176
209
  if (dbError) {
177
210
  await this.client.storage.from(this.bucketName).remove([storagePath]);
@@ -198,6 +231,9 @@ var SupabaseMediaAdapter = class {
198
231
  if (filter?.mimeType) {
199
232
  query = query.eq("mime_type", filter.mimeType);
200
233
  }
234
+ if (filter?.category) {
235
+ query = query.eq("category", filter.category);
236
+ }
201
237
  query = query.order("created_at", { ascending: false });
202
238
  if (filter?.limit) {
203
239
  query = query.limit(filter.limit);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/supabase/factory.ts","../../src/auth/supabase-adapter.ts","../../src/media/supabase-adapter.ts","../../src/storage/supabase-adapter.ts"],"sourcesContent":["import { createClient } from '@supabase/supabase-js';\nimport { createAuthAdapter } from '../auth';\nimport type { AuthAdapter } from '../auth';\nimport { createMediaAdapter } from '../media';\nimport type { MediaAdapter } from '../media';\nimport { createStorageAdapter } from '../storage';\nimport type { StorageAdapter } from '../storage';\n\nexport interface SupabaseAdapterFactoryStorageConfig {\n bucket?: string;\n}\n\nexport interface SupabaseAdapterFactoryConfig {\n url?: string;\n key?: string;\n storage?: SupabaseAdapterFactoryStorageConfig;\n}\n\nexport interface SupabaseAdapters {\n storageAdapter: StorageAdapter;\n mediaAdapter: MediaAdapter;\n authAdapter: AuthAdapter;\n}\n\ninterface ProcessLike {\n env: Record<string, string | undefined>;\n}\n\nfunction readEnv(name: string): string | undefined {\n const processLike = (globalThis as typeof globalThis & { process?: ProcessLike }).process;\n return processLike?.env[name];\n}\n\nfunction resolveRequiredConfig(\n explicitValue: string | undefined,\n envName: 'SUPABASE_URL' | 'SUPABASE_SECRET_KEY'\n): string {\n const explicit = explicitValue?.trim();\n if (explicit) {\n return explicit;\n }\n\n const fromEnv = readEnv(envName)?.trim();\n if (fromEnv) {\n return fromEnv;\n }\n\n throw new Error(\n `Missing Supabase configuration: provide ${envName} in factory config or environment variable`\n );\n}\n\nfunction resolveBucketName(config: SupabaseAdapterFactoryConfig): string {\n const explicitBucket = config.storage?.bucket?.trim();\n if (explicitBucket) {\n return explicitBucket;\n }\n\n const envBucket = readEnv('SUPABASE_STORAGE_BUCKET')?.trim();\n if (envBucket) {\n return envBucket;\n }\n\n return 'media';\n}\n\nexport function createSupabaseAdapters(\n config: SupabaseAdapterFactoryConfig = {}\n): SupabaseAdapters {\n const url = resolveRequiredConfig(config.url, 'SUPABASE_URL');\n const key = resolveRequiredConfig(config.key, 'SUPABASE_SECRET_KEY');\n const bucketName = resolveBucketName(config);\n\n const client = createClient(url, key);\n\n return {\n storageAdapter: createStorageAdapter({ client }),\n mediaAdapter: createMediaAdapter({ client, bucketName }),\n authAdapter: createAuthAdapter({ client }),\n };\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type {\n AuthAdapter,\n AuthSession,\n AuthUser,\n OAuthResponse,\n SignInWithOAuthInput,\n SignInWithPasswordInput,\n VerifySessionInput,\n} from './types';\n\nexport class AuthError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly details?: string\n ) {\n super(message);\n this.name = 'AuthError';\n }\n}\n\nexport interface SupabaseAuthAdapterConfig {\n client: SupabaseClient;\n}\n\nexport class SupabaseAuthAdapter implements AuthAdapter {\n private client: SupabaseClient;\n\n constructor(config: SupabaseAuthAdapterConfig) {\n this.client = config.client;\n }\n\n private mapSupabaseUser(user: {\n id: string;\n email?: string;\n user_metadata?: Record<string, unknown>;\n }): AuthUser {\n if (!user.email) {\n throw new AuthError('User email is required', 'INVALID_USER');\n }\n\n return {\n id: user.id,\n email: user.email,\n metadata: user.user_metadata,\n };\n }\n\n async signInWithOAuth(input: SignInWithOAuthInput): Promise<OAuthResponse> {\n const { data, error } = await this.client.auth.signInWithOAuth({\n provider: input.provider,\n options: {\n redirectTo: input.redirectTo,\n },\n });\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n\n if (!data.url) {\n throw new AuthError('OAuth URL not provided', 'OAUTH_URL_MISSING');\n }\n\n return {\n url: data.url,\n provider: input.provider,\n };\n }\n\n async signInWithPassword(input: SignInWithPasswordInput): Promise<AuthSession> {\n const { data, error } = await this.client.auth.signInWithPassword({\n email: input.email,\n password: input.password,\n });\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n\n if (!data.session || !data.user) {\n throw new AuthError('Session or user not returned', 'AUTH_FAILED');\n }\n\n return {\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at ? new Date(data.session.expires_at * 1000) : undefined,\n user: this.mapSupabaseUser(data.user),\n };\n }\n\n async signOut(_accessToken: string): Promise<void> {\n const { error } = await this.client.auth.signOut();\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n }\n\n async verifySession(input: VerifySessionInput): Promise<AuthUser | null> {\n const { data, error } = await this.client.auth.getUser(input.accessToken);\n\n if (error) {\n return null;\n }\n\n if (!data.user) {\n return null;\n }\n\n return this.mapSupabaseUser(data.user);\n }\n\n async refreshSession(refreshToken: string): Promise<AuthSession> {\n const { data, error } = await this.client.auth.refreshSession({\n refresh_token: refreshToken,\n });\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n\n if (!data.session || !data.user) {\n throw new AuthError('Session refresh failed', 'REFRESH_FAILED');\n }\n\n return {\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at ? new Date(data.session.expires_at * 1000) : undefined,\n user: this.mapSupabaseUser(data.user),\n };\n }\n\n async getCurrentUser(accessToken: string): Promise<AuthUser | null> {\n const { data, error } = await this.client.auth.getUser(accessToken);\n\n if (error) {\n return null;\n }\n\n if (!data.user) {\n return null;\n }\n\n return this.mapSupabaseUser(data.user);\n }\n}\n\nexport function createAuthAdapter(config: SupabaseAuthAdapterConfig): AuthAdapter {\n return new SupabaseAuthAdapter(config);\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type { MediaAdapter, MediaFile, MediaFilter, UploadMediaInput } from './types';\n\n/**\n * Database row type for media (snake_case)\n */\ninterface MediaRow {\n id: string;\n filename: string;\n storage_path: string;\n mime_type: string;\n size: number;\n created_at: string;\n updated_at: string;\n}\n\n/**\n * Media adapter error with additional context\n */\nexport class MediaError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly details?: string\n ) {\n super(message);\n this.name = 'MediaError';\n }\n}\n\n/**\n * Configuration for creating a Supabase media adapter\n */\nexport interface SupabaseMediaAdapterConfig {\n client: SupabaseClient;\n bucketName?: string;\n}\n\n/**\n * Supabase implementation of the MediaAdapter interface\n */\nexport class SupabaseMediaAdapter implements MediaAdapter {\n private client: SupabaseClient;\n private bucketName: string;\n\n constructor(config: SupabaseMediaAdapterConfig) {\n this.client = config.client;\n this.bucketName = config.bucketName ?? 'media';\n }\n\n /**\n * Generates a unique storage path for a file\n */\n private generateStoragePath(filename: string): string {\n const timestamp = Date.now();\n const randomSuffix = Math.random().toString(36).substring(2, 8);\n const sanitizedFilename = filename.replace(/[^a-zA-Z0-9.-]/g, '_');\n return `${timestamp}-${randomSuffix}-${sanitizedFilename}`;\n }\n\n /**\n * Constructs the public URL for a stored file\n */\n private getPublicUrl(storagePath: string): string {\n const { data } = this.client.storage.from(this.bucketName).getPublicUrl(storagePath);\n return data.publicUrl;\n }\n\n /**\n * Maps a database row to MediaFile\n */\n private mapRowToMediaFile(row: MediaRow): MediaFile {\n return {\n id: row.id,\n filename: row.filename,\n url: this.getPublicUrl(row.storage_path),\n mimeType: row.mime_type,\n size: row.size,\n createdAt: new Date(row.created_at),\n };\n }\n\n async upload(input: UploadMediaInput): Promise<MediaFile> {\n const storagePath = this.generateStoragePath(input.filename);\n\n // Upload file to Supabase Storage\n const { error: uploadError } = await this.client.storage\n .from(this.bucketName)\n .upload(storagePath, input.data, {\n contentType: input.mimeType,\n upsert: false,\n });\n\n if (uploadError) {\n throw new MediaError(\n `Failed to upload file: ${uploadError.message}`,\n 'UPLOAD_FAILED',\n uploadError.message\n );\n }\n\n // Create database record\n const { data, error: dbError } = await this.client\n .from('media')\n .insert({\n filename: input.filename,\n storage_path: storagePath,\n mime_type: input.mimeType,\n size: input.size,\n })\n .select()\n .single();\n\n if (dbError) {\n // Cleanup: delete uploaded file if DB insert fails\n await this.client.storage.from(this.bucketName).remove([storagePath]);\n throw new MediaError(\n `Failed to create media record: ${dbError.message}`,\n dbError.code,\n dbError.details\n );\n }\n\n return this.mapRowToMediaFile(data as MediaRow);\n }\n\n async getMedia(id: string): Promise<MediaFile | null> {\n const { data, error } = await this.client.from('media').select('*').eq('id', id).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new MediaError(error.message, error.code, error.details);\n }\n\n return this.mapRowToMediaFile(data as MediaRow);\n }\n\n async listMedia(filter?: MediaFilter): Promise<MediaFile[]> {\n let query = this.client.from('media').select('*');\n\n if (filter?.mimeType) {\n query = query.eq('mime_type', filter.mimeType);\n }\n\n query = query.order('created_at', { ascending: false });\n\n if (filter?.limit) {\n query = query.limit(filter.limit);\n }\n\n if (filter?.offset) {\n query = query.range(filter.offset, filter.offset + (filter.limit ?? 100) - 1);\n }\n\n const { data, error } = await query;\n\n if (error) {\n throw new MediaError(error.message, error.code, error.details);\n }\n\n return (data as MediaRow[]).map((row) => this.mapRowToMediaFile(row));\n }\n\n async deleteMedia(id: string): Promise<void> {\n // First get the media record to find the storage path\n const { data: mediaRecord, error: fetchError } = await this.client\n .from('media')\n .select('storage_path')\n .eq('id', id)\n .single();\n\n if (fetchError) {\n if (fetchError.code === 'PGRST116') {\n throw new MediaError(`Media not found: ${id}`, 'NOT_FOUND');\n }\n throw new MediaError(fetchError.message, fetchError.code, fetchError.details);\n }\n\n const storagePath = (mediaRecord as { storage_path: string }).storage_path;\n\n // Delete from storage\n const { error: storageError } = await this.client.storage\n .from(this.bucketName)\n .remove([storagePath]);\n\n if (storageError) {\n throw new MediaError(\n `Failed to delete file from storage: ${storageError.message}`,\n 'STORAGE_DELETE_FAILED',\n storageError.message\n );\n }\n\n // Delete database record\n const { error: dbError } = await this.client.from('media').delete().eq('id', id);\n\n if (dbError) {\n throw new MediaError(dbError.message, dbError.code, dbError.details);\n }\n }\n}\n\n/**\n * Creates a media adapter using Supabase\n */\nexport function createMediaAdapter(config: SupabaseMediaAdapterConfig): MediaAdapter {\n return new SupabaseMediaAdapter(config);\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type {\n CreateNavigationInput,\n CreatePageInput,\n Navigation,\n NavigationItem,\n Page,\n PageFilter,\n PageSection,\n StorageAdapter,\n UpdateNavigationInput,\n UpdatePageInput,\n} from './types';\n\n/**\n * Database row types (snake_case)\n */\ninterface PageRow {\n id: string;\n slug: string;\n page_type: string;\n title: string;\n sections: PageSection[];\n created_at: string;\n updated_at: string;\n}\n\ninterface NavigationRow {\n id: string;\n name: string;\n items: NavigationItem[];\n created_at: string;\n updated_at: string;\n}\n\n/**\n * Maps a database page row to the Page type\n */\nfunction mapPageRowToPage(row: PageRow): Page {\n return {\n id: row.id,\n slug: row.slug,\n pageType: row.page_type,\n title: row.title,\n sections: row.sections,\n createdAt: new Date(row.created_at),\n updatedAt: new Date(row.updated_at),\n };\n}\n\n/**\n * Maps a database navigation row to the Navigation type\n */\nfunction mapNavigationRowToNavigation(row: NavigationRow): Navigation {\n return {\n id: row.id,\n name: row.name,\n items: row.items,\n updatedAt: new Date(row.updated_at),\n };\n}\n\n/**\n * Storage adapter error with additional context\n */\nexport class StorageError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly details?: string\n ) {\n super(message);\n this.name = 'StorageError';\n }\n}\n\n/**\n * Configuration for creating a Supabase storage adapter\n */\nexport interface SupabaseStorageAdapterConfig {\n client: SupabaseClient;\n}\n\n/**\n * Supabase implementation of the StorageAdapter interface\n */\nexport class SupabaseStorageAdapter implements StorageAdapter {\n private client: SupabaseClient;\n\n constructor(config: SupabaseStorageAdapterConfig) {\n this.client = config.client;\n }\n\n async getPage(slug: string): Promise<Page | null> {\n const { data, error } = await this.client.from('pages').select('*').eq('slug', slug).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async getPageById(id: string): Promise<Page | null> {\n const { data, error } = await this.client.from('pages').select('*').eq('id', id).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async createPage(input: CreatePageInput): Promise<Page> {\n const { data, error } = await this.client\n .from('pages')\n .insert({\n slug: input.slug,\n page_type: input.pageType,\n title: input.title,\n sections: input.sections ?? [],\n })\n .select()\n .single();\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async updatePage(input: UpdatePageInput): Promise<Page> {\n const updateData: Record<string, unknown> = {};\n\n if (input.slug !== undefined) {\n updateData.slug = input.slug;\n }\n if (input.pageType !== undefined) {\n updateData.page_type = input.pageType;\n }\n if (input.title !== undefined) {\n updateData.title = input.title;\n }\n if (input.sections !== undefined) {\n updateData.sections = input.sections;\n }\n\n const { data, error } = await this.client\n .from('pages')\n .update(updateData)\n .eq('id', input.id)\n .select()\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n throw new StorageError(`Page not found: ${input.id}`, 'NOT_FOUND');\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async deletePage(id: string): Promise<void> {\n const { error } = await this.client.from('pages').delete().eq('id', id);\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n }\n\n async listPages(filter?: PageFilter): Promise<Page[]> {\n let query = this.client.from('pages').select('*');\n\n if (filter?.pageType) {\n query = query.eq('page_type', filter.pageType);\n }\n\n query = query.order('created_at', { ascending: false });\n\n if (filter?.limit) {\n query = query.limit(filter.limit);\n }\n\n if (filter?.offset) {\n query = query.range(filter.offset, filter.offset + (filter.limit ?? 100) - 1);\n }\n\n const { data, error } = await query;\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return (data as PageRow[]).map(mapPageRowToPage);\n }\n\n async getNavigation(name: string): Promise<Navigation | null> {\n const { data, error } = await this.client\n .from('navigation')\n .select('*')\n .eq('name', name)\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async getNavigationById(id: string): Promise<Navigation | null> {\n const { data, error } = await this.client.from('navigation').select('*').eq('id', id).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async createNavigation(input: CreateNavigationInput): Promise<Navigation> {\n const { data, error } = await this.client\n .from('navigation')\n .insert({\n name: input.name,\n items: input.items,\n })\n .select()\n .single();\n\n if (error) {\n if (error.code === '23505') {\n throw new StorageError(\n `Navigation with name \"${input.name}\" already exists`,\n 'DUPLICATE_NAME'\n );\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async updateNavigation(input: UpdateNavigationInput): Promise<Navigation> {\n const updateData: Record<string, unknown> = {};\n\n if (input.name !== undefined) {\n updateData.name = input.name;\n }\n if (input.items !== undefined) {\n updateData.items = input.items;\n }\n\n const { data, error } = await this.client\n .from('navigation')\n .update(updateData)\n .eq('id', input.id)\n .select()\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n throw new StorageError(`Navigation not found: ${input.id}`, 'NOT_FOUND');\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async deleteNavigation(id: string): Promise<void> {\n const { error } = await this.client.from('navigation').delete().eq('id', id);\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n }\n\n async listNavigations(): Promise<Navigation[]> {\n const { data, error } = await this.client\n .from('navigation')\n .select('*')\n .order('name', { ascending: true });\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return (data as NavigationRow[]).map(mapNavigationRowToNavigation);\n }\n}\n\n/**\n * Creates a storage adapter using Supabase\n */\nexport function createStorageAdapter(config: SupabaseStorageAdapterConfig): StorageAdapter {\n return new SupabaseStorageAdapter(config);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/supabase/factory.ts","../../src/auth/supabase-adapter.ts","../../src/media/types.ts","../../src/media/supabase-adapter.ts","../../src/storage/supabase-adapter.ts"],"sourcesContent":["import { createClient } from '@supabase/supabase-js';\nimport { createAuthAdapter } from '../auth';\nimport type { AuthAdapter } from '../auth';\nimport { createMediaAdapter } from '../media';\nimport type { MediaAdapter } from '../media';\nimport { createStorageAdapter } from '../storage';\nimport type { StorageAdapter } from '../storage';\n\nexport interface SupabaseAdapterFactoryStorageConfig {\n bucket?: string;\n}\n\nexport interface SupabaseAdapterFactoryConfig {\n url?: string;\n key?: string;\n storage?: SupabaseAdapterFactoryStorageConfig;\n}\n\nexport interface SupabaseAdapters {\n storageAdapter: StorageAdapter;\n mediaAdapter: MediaAdapter;\n authAdapter: AuthAdapter;\n}\n\ninterface ProcessLike {\n env: Record<string, string | undefined>;\n}\n\nfunction readEnv(name: string): string | undefined {\n const processLike = (globalThis as typeof globalThis & { process?: ProcessLike }).process;\n return processLike?.env[name];\n}\n\nfunction resolveRequiredConfig(\n explicitValue: string | undefined,\n envName: 'SUPABASE_URL' | 'SUPABASE_SECRET_KEY'\n): string {\n const explicit = explicitValue?.trim();\n if (explicit) {\n return explicit;\n }\n\n const fromEnv = readEnv(envName)?.trim();\n if (fromEnv) {\n return fromEnv;\n }\n\n throw new Error(\n `Missing Supabase configuration: provide ${envName} in factory config or environment variable`\n );\n}\n\nfunction resolveBucketName(config: SupabaseAdapterFactoryConfig): string {\n const explicitBucket = config.storage?.bucket?.trim();\n if (explicitBucket) {\n return explicitBucket;\n }\n\n const envBucket = readEnv('SUPABASE_STORAGE_BUCKET')?.trim();\n if (envBucket) {\n return envBucket;\n }\n\n return 'media';\n}\n\nexport function createSupabaseAdapters(\n config: SupabaseAdapterFactoryConfig = {}\n): SupabaseAdapters {\n const url = resolveRequiredConfig(config.url, 'SUPABASE_URL');\n const key = resolveRequiredConfig(config.key, 'SUPABASE_SECRET_KEY');\n const bucketName = resolveBucketName(config);\n\n const client = createClient(url, key);\n\n return {\n storageAdapter: createStorageAdapter({ client }),\n mediaAdapter: createMediaAdapter({ client, bucketName }),\n authAdapter: createAuthAdapter({ client }),\n };\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type {\n AuthAdapter,\n AuthSession,\n AuthUser,\n OAuthResponse,\n SignInWithOAuthInput,\n SignInWithPasswordInput,\n VerifySessionInput,\n} from './types';\n\nexport class AuthError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly details?: string\n ) {\n super(message);\n this.name = 'AuthError';\n }\n}\n\nexport interface SupabaseAuthAdapterConfig {\n client: SupabaseClient;\n}\n\nexport class SupabaseAuthAdapter implements AuthAdapter {\n private client: SupabaseClient;\n\n constructor(config: SupabaseAuthAdapterConfig) {\n this.client = config.client;\n }\n\n private mapSupabaseUser(user: {\n id: string;\n email?: string;\n user_metadata?: Record<string, unknown>;\n }): AuthUser {\n if (!user.email) {\n throw new AuthError('User email is required', 'INVALID_USER');\n }\n\n return {\n id: user.id,\n email: user.email,\n metadata: user.user_metadata,\n };\n }\n\n async signInWithOAuth(input: SignInWithOAuthInput): Promise<OAuthResponse> {\n const { data, error } = await this.client.auth.signInWithOAuth({\n provider: input.provider,\n options: {\n redirectTo: input.redirectTo,\n },\n });\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n\n if (!data.url) {\n throw new AuthError('OAuth URL not provided', 'OAUTH_URL_MISSING');\n }\n\n return {\n url: data.url,\n provider: input.provider,\n };\n }\n\n async signInWithPassword(input: SignInWithPasswordInput): Promise<AuthSession> {\n const { data, error } = await this.client.auth.signInWithPassword({\n email: input.email,\n password: input.password,\n });\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n\n if (!data.session || !data.user) {\n throw new AuthError('Session or user not returned', 'AUTH_FAILED');\n }\n\n return {\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at ? new Date(data.session.expires_at * 1000) : undefined,\n user: this.mapSupabaseUser(data.user),\n };\n }\n\n async signOut(_accessToken: string): Promise<void> {\n const { error } = await this.client.auth.signOut();\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n }\n\n async verifySession(input: VerifySessionInput): Promise<AuthUser | null> {\n const { data, error } = await this.client.auth.getUser(input.accessToken);\n\n if (error) {\n return null;\n }\n\n if (!data.user) {\n return null;\n }\n\n return this.mapSupabaseUser(data.user);\n }\n\n async refreshSession(refreshToken: string): Promise<AuthSession> {\n const { data, error } = await this.client.auth.refreshSession({\n refresh_token: refreshToken,\n });\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n\n if (!data.session || !data.user) {\n throw new AuthError('Session refresh failed', 'REFRESH_FAILED');\n }\n\n return {\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at ? new Date(data.session.expires_at * 1000) : undefined,\n user: this.mapSupabaseUser(data.user),\n };\n }\n\n async getCurrentUser(accessToken: string): Promise<AuthUser | null> {\n const { data, error } = await this.client.auth.getUser(accessToken);\n\n if (error) {\n return null;\n }\n\n if (!data.user) {\n return null;\n }\n\n return this.mapSupabaseUser(data.user);\n }\n}\n\nexport function createAuthAdapter(config: SupabaseAuthAdapterConfig): AuthAdapter {\n return new SupabaseAuthAdapter(config);\n}\n","/**\n * Maximum file size: 50MB\n */\nexport const MAX_FILE_SIZE = 50 * 1024 * 1024;\n\n/**\n * Allowed MIME types for image uploads\n */\nexport const ALLOWED_MIME_TYPES = [\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n 'image/svg+xml',\n] as const;\n\nexport type AllowedMimeType = (typeof ALLOWED_MIME_TYPES)[number];\n\n/**\n * Allowed MIME types for document uploads\n */\nexport const ALLOWED_DOCUMENT_MIME_TYPES = [\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n 'application/vnd.ms-excel',\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'application/vnd.ms-powerpoint',\n 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n 'text/plain',\n 'text/csv',\n 'application/zip',\n 'application/gzip',\n] as const;\n\nexport type AllowedDocumentMimeType = (typeof ALLOWED_DOCUMENT_MIME_TYPES)[number];\n\n/**\n * All allowed MIME types (images + documents)\n */\nexport const ALL_ALLOWED_MIME_TYPES = [\n ...ALLOWED_MIME_TYPES,\n ...ALLOWED_DOCUMENT_MIME_TYPES,\n] as const;\n\n/**\n * Media category discriminator\n */\nexport type MediaCategory = 'image' | 'document';\n\n/**\n * Represents a media file stored in the CMS\n */\nexport interface MediaFile {\n id: string;\n filename: string;\n url: string;\n mimeType: string;\n size: number;\n category: MediaCategory;\n createdAt: Date;\n}\n\n/**\n * Input for uploading a media file\n * data accepts ArrayBuffer for platform-agnostic binary data\n */\nexport interface UploadMediaInput {\n filename: string;\n mimeType: string;\n size: number;\n data: ArrayBuffer | Uint8Array;\n}\n\n/**\n * Filter options for listing media files\n */\nexport interface MediaFilter {\n limit?: number;\n offset?: number;\n mimeType?: string;\n category?: MediaCategory;\n}\n\n/**\n * Media adapter interface for file storage operations.\n * This interface is Supabase-agnostic to allow future portability.\n */\nexport interface MediaAdapter {\n /**\n * Upload a media file\n */\n upload(input: UploadMediaInput): Promise<MediaFile>;\n\n /**\n * Get a media file by ID\n */\n getMedia(id: string): Promise<MediaFile | null>;\n\n /**\n * List media files with optional filtering and pagination\n */\n listMedia(filter?: MediaFilter): Promise<MediaFile[]>;\n\n /**\n * Delete a media file by ID\n */\n deleteMedia(id: string): Promise<void>;\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type {\n MediaAdapter,\n MediaCategory,\n MediaFile,\n MediaFilter,\n UploadMediaInput,\n} from './types';\nimport { ALLOWED_MIME_TYPES } from './types';\n\n/**\n * Database row type for media (snake_case)\n */\ninterface MediaRow {\n id: string;\n filename: string;\n storage_path: string;\n mime_type: string;\n size: number;\n category: string;\n created_at: string;\n updated_at: string;\n}\n\n/**\n * Derives the media category from a MIME type.\n * Image MIME types map to 'image', everything else to 'document'.\n */\nfunction deriveCategory(mimeType: string): MediaCategory {\n const imageMimes = ALLOWED_MIME_TYPES as readonly string[];\n return imageMimes.includes(mimeType) ? 'image' : 'document';\n}\n\n/**\n * Media adapter error with additional context\n */\nexport class MediaError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly details?: string\n ) {\n super(message);\n this.name = 'MediaError';\n }\n}\n\n/**\n * Configuration for creating a Supabase media adapter\n */\nexport interface SupabaseMediaAdapterConfig {\n client: SupabaseClient;\n bucketName?: string;\n}\n\n/**\n * Supabase implementation of the MediaAdapter interface\n */\nexport class SupabaseMediaAdapter implements MediaAdapter {\n private client: SupabaseClient;\n private bucketName: string;\n\n constructor(config: SupabaseMediaAdapterConfig) {\n this.client = config.client;\n this.bucketName = config.bucketName ?? 'media';\n }\n\n /**\n * Generates a unique storage path for a file\n */\n private generateStoragePath(filename: string): string {\n const timestamp = Date.now();\n const randomSuffix = Math.random().toString(36).substring(2, 8);\n const sanitizedFilename = filename.replace(/[^a-zA-Z0-9.-]/g, '_');\n return `${timestamp}-${randomSuffix}-${sanitizedFilename}`;\n }\n\n /**\n * Constructs the public URL for a stored file\n */\n private getPublicUrl(storagePath: string): string {\n const { data } = this.client.storage.from(this.bucketName).getPublicUrl(storagePath);\n return data.publicUrl;\n }\n\n /**\n * Maps a database row to MediaFile\n */\n private mapRowToMediaFile(row: MediaRow): MediaFile {\n return {\n id: row.id,\n filename: row.filename,\n url: this.getPublicUrl(row.storage_path),\n mimeType: row.mime_type,\n size: row.size,\n category: row.category as MediaCategory,\n createdAt: new Date(row.created_at),\n };\n }\n\n async upload(input: UploadMediaInput): Promise<MediaFile> {\n const storagePath = this.generateStoragePath(input.filename);\n\n // Upload file to Supabase Storage\n const { error: uploadError } = await this.client.storage\n .from(this.bucketName)\n .upload(storagePath, input.data, {\n contentType: input.mimeType,\n upsert: false,\n });\n\n if (uploadError) {\n throw new MediaError(\n `Failed to upload file: ${uploadError.message}`,\n 'UPLOAD_FAILED',\n uploadError.message\n );\n }\n\n // Create database record\n const { data, error: dbError } = await this.client\n .from('media')\n .insert({\n filename: input.filename,\n storage_path: storagePath,\n mime_type: input.mimeType,\n size: input.size,\n category: deriveCategory(input.mimeType),\n })\n .select()\n .single();\n\n if (dbError) {\n // Cleanup: delete uploaded file if DB insert fails\n await this.client.storage.from(this.bucketName).remove([storagePath]);\n throw new MediaError(\n `Failed to create media record: ${dbError.message}`,\n dbError.code,\n dbError.details\n );\n }\n\n return this.mapRowToMediaFile(data as MediaRow);\n }\n\n async getMedia(id: string): Promise<MediaFile | null> {\n const { data, error } = await this.client.from('media').select('*').eq('id', id).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new MediaError(error.message, error.code, error.details);\n }\n\n return this.mapRowToMediaFile(data as MediaRow);\n }\n\n async listMedia(filter?: MediaFilter): Promise<MediaFile[]> {\n let query = this.client.from('media').select('*');\n\n if (filter?.mimeType) {\n query = query.eq('mime_type', filter.mimeType);\n }\n\n if (filter?.category) {\n query = query.eq('category', filter.category);\n }\n\n query = query.order('created_at', { ascending: false });\n\n if (filter?.limit) {\n query = query.limit(filter.limit);\n }\n\n if (filter?.offset) {\n query = query.range(filter.offset, filter.offset + (filter.limit ?? 100) - 1);\n }\n\n const { data, error } = await query;\n\n if (error) {\n throw new MediaError(error.message, error.code, error.details);\n }\n\n return (data as MediaRow[]).map((row) => this.mapRowToMediaFile(row));\n }\n\n async deleteMedia(id: string): Promise<void> {\n // First get the media record to find the storage path\n const { data: mediaRecord, error: fetchError } = await this.client\n .from('media')\n .select('storage_path')\n .eq('id', id)\n .single();\n\n if (fetchError) {\n if (fetchError.code === 'PGRST116') {\n throw new MediaError(`Media not found: ${id}`, 'NOT_FOUND');\n }\n throw new MediaError(fetchError.message, fetchError.code, fetchError.details);\n }\n\n const storagePath = (mediaRecord as { storage_path: string }).storage_path;\n\n // Delete from storage\n const { error: storageError } = await this.client.storage\n .from(this.bucketName)\n .remove([storagePath]);\n\n if (storageError) {\n throw new MediaError(\n `Failed to delete file from storage: ${storageError.message}`,\n 'STORAGE_DELETE_FAILED',\n storageError.message\n );\n }\n\n // Delete database record\n const { error: dbError } = await this.client.from('media').delete().eq('id', id);\n\n if (dbError) {\n throw new MediaError(dbError.message, dbError.code, dbError.details);\n }\n }\n}\n\n/**\n * Creates a media adapter using Supabase\n */\nexport function createMediaAdapter(config: SupabaseMediaAdapterConfig): MediaAdapter {\n return new SupabaseMediaAdapter(config);\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type {\n CreateNavigationInput,\n CreatePageInput,\n Navigation,\n NavigationItem,\n Page,\n PageFilter,\n PageSection,\n StorageAdapter,\n UpdateNavigationInput,\n UpdatePageInput,\n} from './types';\n\n/**\n * Database row types (snake_case)\n */\ninterface PageRow {\n id: string;\n slug: string;\n page_type: string;\n title: string;\n sections: PageSection[];\n created_at: string;\n updated_at: string;\n}\n\ninterface NavigationRow {\n id: string;\n name: string;\n items: NavigationItem[];\n created_at: string;\n updated_at: string;\n}\n\n/**\n * Maps a database page row to the Page type\n */\nfunction mapPageRowToPage(row: PageRow): Page {\n return {\n id: row.id,\n slug: row.slug,\n pageType: row.page_type,\n title: row.title,\n sections: row.sections,\n createdAt: new Date(row.created_at),\n updatedAt: new Date(row.updated_at),\n };\n}\n\n/**\n * Maps a database navigation row to the Navigation type\n */\nfunction mapNavigationRowToNavigation(row: NavigationRow): Navigation {\n return {\n id: row.id,\n name: row.name,\n items: row.items,\n updatedAt: new Date(row.updated_at),\n };\n}\n\n/**\n * Storage adapter error with additional context\n */\nexport class StorageError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly details?: string\n ) {\n super(message);\n this.name = 'StorageError';\n }\n}\n\n/**\n * Configuration for creating a Supabase storage adapter\n */\nexport interface SupabaseStorageAdapterConfig {\n client: SupabaseClient;\n}\n\n/**\n * Supabase implementation of the StorageAdapter interface\n */\nexport class SupabaseStorageAdapter implements StorageAdapter {\n private client: SupabaseClient;\n\n constructor(config: SupabaseStorageAdapterConfig) {\n this.client = config.client;\n }\n\n async getPage(slug: string): Promise<Page | null> {\n const { data, error } = await this.client.from('pages').select('*').eq('slug', slug).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async getPageById(id: string): Promise<Page | null> {\n const { data, error } = await this.client.from('pages').select('*').eq('id', id).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async createPage(input: CreatePageInput): Promise<Page> {\n const { data, error } = await this.client\n .from('pages')\n .insert({\n slug: input.slug,\n page_type: input.pageType,\n title: input.title,\n sections: input.sections ?? [],\n })\n .select()\n .single();\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async updatePage(input: UpdatePageInput): Promise<Page> {\n const updateData: Record<string, unknown> = {};\n\n if (input.slug !== undefined) {\n updateData.slug = input.slug;\n }\n if (input.pageType !== undefined) {\n updateData.page_type = input.pageType;\n }\n if (input.title !== undefined) {\n updateData.title = input.title;\n }\n if (input.sections !== undefined) {\n updateData.sections = input.sections;\n }\n\n const { data, error } = await this.client\n .from('pages')\n .update(updateData)\n .eq('id', input.id)\n .select()\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n throw new StorageError(`Page not found: ${input.id}`, 'NOT_FOUND');\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async deletePage(id: string): Promise<void> {\n const { error } = await this.client.from('pages').delete().eq('id', id);\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n }\n\n async listPages(filter?: PageFilter): Promise<Page[]> {\n let query = this.client.from('pages').select('*');\n\n if (filter?.pageType) {\n query = query.eq('page_type', filter.pageType);\n }\n\n query = query.order('created_at', { ascending: false });\n\n if (filter?.limit) {\n query = query.limit(filter.limit);\n }\n\n if (filter?.offset) {\n query = query.range(filter.offset, filter.offset + (filter.limit ?? 100) - 1);\n }\n\n const { data, error } = await query;\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return (data as PageRow[]).map(mapPageRowToPage);\n }\n\n async getNavigation(name: string): Promise<Navigation | null> {\n const { data, error } = await this.client\n .from('navigation')\n .select('*')\n .eq('name', name)\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async getNavigationById(id: string): Promise<Navigation | null> {\n const { data, error } = await this.client.from('navigation').select('*').eq('id', id).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async createNavigation(input: CreateNavigationInput): Promise<Navigation> {\n const { data, error } = await this.client\n .from('navigation')\n .insert({\n name: input.name,\n items: input.items,\n })\n .select()\n .single();\n\n if (error) {\n if (error.code === '23505') {\n throw new StorageError(\n `Navigation with name \"${input.name}\" already exists`,\n 'DUPLICATE_NAME'\n );\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async updateNavigation(input: UpdateNavigationInput): Promise<Navigation> {\n const updateData: Record<string, unknown> = {};\n\n if (input.name !== undefined) {\n updateData.name = input.name;\n }\n if (input.items !== undefined) {\n updateData.items = input.items;\n }\n\n const { data, error } = await this.client\n .from('navigation')\n .update(updateData)\n .eq('id', input.id)\n .select()\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n throw new StorageError(`Navigation not found: ${input.id}`, 'NOT_FOUND');\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async deleteNavigation(id: string): Promise<void> {\n const { error } = await this.client.from('navigation').delete().eq('id', id);\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n }\n\n async listNavigations(): Promise<Navigation[]> {\n const { data, error } = await this.client\n .from('navigation')\n .select('*')\n .order('name', { ascending: true });\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return (data as NavigationRow[]).map(mapNavigationRowToNavigation);\n }\n}\n\n/**\n * Creates a storage adapter using Supabase\n */\nexport function createStorageAdapter(config: SupabaseStorageAdapterConfig): StorageAdapter {\n return new SupabaseStorageAdapter(config);\n}\n"],"mappings":"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","names":[]}
@@ -109,10 +109,27 @@ interface StorageAdapter {
109
109
  }
110
110
 
111
111
  /**
112
- * Allowed MIME types for media uploads
112
+ * Maximum file size: 50MB
113
+ */
114
+ declare const MAX_FILE_SIZE: number;
115
+ /**
116
+ * Allowed MIME types for image uploads
113
117
  */
114
118
  declare const ALLOWED_MIME_TYPES: readonly ["image/jpeg", "image/png", "image/gif", "image/webp", "image/svg+xml"];
115
119
  type AllowedMimeType = (typeof ALLOWED_MIME_TYPES)[number];
120
+ /**
121
+ * Allowed MIME types for document uploads
122
+ */
123
+ declare const ALLOWED_DOCUMENT_MIME_TYPES: readonly ["application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "text/plain", "text/csv", "application/zip", "application/gzip"];
124
+ type AllowedDocumentMimeType = (typeof ALLOWED_DOCUMENT_MIME_TYPES)[number];
125
+ /**
126
+ * All allowed MIME types (images + documents)
127
+ */
128
+ declare const ALL_ALLOWED_MIME_TYPES: readonly ["image/jpeg", "image/png", "image/gif", "image/webp", "image/svg+xml", "application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "text/plain", "text/csv", "application/zip", "application/gzip"];
129
+ /**
130
+ * Media category discriminator
131
+ */
132
+ type MediaCategory = 'image' | 'document';
116
133
  /**
117
134
  * Represents a media file stored in the CMS
118
135
  */
@@ -122,6 +139,7 @@ interface MediaFile {
122
139
  url: string;
123
140
  mimeType: string;
124
141
  size: number;
142
+ category: MediaCategory;
125
143
  createdAt: Date;
126
144
  }
127
145
  /**
@@ -141,6 +159,7 @@ interface MediaFilter {
141
159
  limit?: number;
142
160
  offset?: number;
143
161
  mimeType?: string;
162
+ category?: MediaCategory;
144
163
  }
145
164
  /**
146
165
  * Media adapter interface for file storage operations.
@@ -201,4 +220,4 @@ interface AuthAdapter {
201
220
  getCurrentUser(accessToken: string): Promise<AuthUser | null>;
202
221
  }
203
222
 
204
- export { type AuthAdapter as A, type CreatePageInput as C, type MediaAdapter as M, type Navigation as N, type OAuthResponse as O, type Page as P, type StorageAdapter as S, type UpdatePageInput as U, type VerifySessionInput as V, type PageFilter as a, type CreateNavigationInput as b, type UpdateNavigationInput as c, type NavigationItem as d, type PageSection as e, type UploadMediaInput as f, type MediaFile as g, type MediaFilter as h, type SignInWithOAuthInput as i, type SignInWithPasswordInput as j, type AuthSession as k, type AuthUser as l, ALLOWED_MIME_TYPES as m, type AllowedMimeType as n };
223
+ export { type AuthAdapter as A, type CreatePageInput as C, type MediaAdapter as M, type Navigation as N, type OAuthResponse as O, type Page as P, type StorageAdapter as S, type UpdatePageInput as U, type VerifySessionInput as V, type PageFilter as a, type CreateNavigationInput as b, type UpdateNavigationInput as c, type NavigationItem as d, type PageSection as e, type UploadMediaInput as f, type MediaFile as g, type MediaFilter as h, type SignInWithOAuthInput as i, type SignInWithPasswordInput as j, type AuthSession as k, type AuthUser as l, ALLOWED_DOCUMENT_MIME_TYPES as m, ALLOWED_MIME_TYPES as n, ALL_ALLOWED_MIME_TYPES as o, type AllowedDocumentMimeType as p, type AllowedMimeType as q, MAX_FILE_SIZE as r, type MediaCategory as s };
@@ -109,10 +109,27 @@ interface StorageAdapter {
109
109
  }
110
110
 
111
111
  /**
112
- * Allowed MIME types for media uploads
112
+ * Maximum file size: 50MB
113
+ */
114
+ declare const MAX_FILE_SIZE: number;
115
+ /**
116
+ * Allowed MIME types for image uploads
113
117
  */
114
118
  declare const ALLOWED_MIME_TYPES: readonly ["image/jpeg", "image/png", "image/gif", "image/webp", "image/svg+xml"];
115
119
  type AllowedMimeType = (typeof ALLOWED_MIME_TYPES)[number];
120
+ /**
121
+ * Allowed MIME types for document uploads
122
+ */
123
+ declare const ALLOWED_DOCUMENT_MIME_TYPES: readonly ["application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "text/plain", "text/csv", "application/zip", "application/gzip"];
124
+ type AllowedDocumentMimeType = (typeof ALLOWED_DOCUMENT_MIME_TYPES)[number];
125
+ /**
126
+ * All allowed MIME types (images + documents)
127
+ */
128
+ declare const ALL_ALLOWED_MIME_TYPES: readonly ["image/jpeg", "image/png", "image/gif", "image/webp", "image/svg+xml", "application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "text/plain", "text/csv", "application/zip", "application/gzip"];
129
+ /**
130
+ * Media category discriminator
131
+ */
132
+ type MediaCategory = 'image' | 'document';
116
133
  /**
117
134
  * Represents a media file stored in the CMS
118
135
  */
@@ -122,6 +139,7 @@ interface MediaFile {
122
139
  url: string;
123
140
  mimeType: string;
124
141
  size: number;
142
+ category: MediaCategory;
125
143
  createdAt: Date;
126
144
  }
127
145
  /**
@@ -141,6 +159,7 @@ interface MediaFilter {
141
159
  limit?: number;
142
160
  offset?: number;
143
161
  mimeType?: string;
162
+ category?: MediaCategory;
144
163
  }
145
164
  /**
146
165
  * Media adapter interface for file storage operations.
@@ -201,4 +220,4 @@ interface AuthAdapter {
201
220
  getCurrentUser(accessToken: string): Promise<AuthUser | null>;
202
221
  }
203
222
 
204
- export { type AuthAdapter as A, type CreatePageInput as C, type MediaAdapter as M, type Navigation as N, type OAuthResponse as O, type Page as P, type StorageAdapter as S, type UpdatePageInput as U, type VerifySessionInput as V, type PageFilter as a, type CreateNavigationInput as b, type UpdateNavigationInput as c, type NavigationItem as d, type PageSection as e, type UploadMediaInput as f, type MediaFile as g, type MediaFilter as h, type SignInWithOAuthInput as i, type SignInWithPasswordInput as j, type AuthSession as k, type AuthUser as l, ALLOWED_MIME_TYPES as m, type AllowedMimeType as n };
223
+ export { type AuthAdapter as A, type CreatePageInput as C, type MediaAdapter as M, type Navigation as N, type OAuthResponse as O, type Page as P, type StorageAdapter as S, type UpdatePageInput as U, type VerifySessionInput as V, type PageFilter as a, type CreateNavigationInput as b, type UpdateNavigationInput as c, type NavigationItem as d, type PageSection as e, type UploadMediaInput as f, type MediaFile as g, type MediaFilter as h, type SignInWithOAuthInput as i, type SignInWithPasswordInput as j, type AuthSession as k, type AuthUser as l, ALLOWED_DOCUMENT_MIME_TYPES as m, ALLOWED_MIME_TYPES as n, ALL_ALLOWED_MIME_TYPES as o, type AllowedDocumentMimeType as p, type AllowedMimeType as q, MAX_FILE_SIZE as r, type MediaCategory as s };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@structcms/api",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Storage, domain API, and delivery API for StructCMS",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -49,7 +49,8 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "@supabase/supabase-js": "^2.45.0",
52
- "sanitize-html": "^2.17.0"
52
+ "sanitize-html": "^2.17.0",
53
+ "zod": "^3.23.0"
53
54
  },
54
55
  "devDependencies": {
55
56
  "@types/sanitize-html": "^2.16.0",