@ezcoder.dev/sdk 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/DatabaseProvider-DalP-KHC.d.ts +167 -0
  2. package/dist/analytics/index.d.ts +22 -1
  3. package/dist/analytics/index.js +79 -4
  4. package/dist/analytics/index.js.map +1 -1
  5. package/dist/animation/index.js.map +1 -1
  6. package/dist/auth/index.d.ts +2 -1
  7. package/dist/auth/index.js +25 -6
  8. package/dist/auth/index.js.map +1 -1
  9. package/dist/chunk-CQKYANAW.js +44 -0
  10. package/dist/chunk-CQKYANAW.js.map +1 -0
  11. package/dist/{chunk-5XIZHBKE.js → chunk-HJ2EIZ4S.js} +23 -6
  12. package/dist/chunk-HJ2EIZ4S.js.map +1 -0
  13. package/dist/{chunk-G7XDUN3Z.js → chunk-I2YGB7Z6.js} +24 -44
  14. package/dist/chunk-I2YGB7Z6.js.map +1 -0
  15. package/dist/chunk-LIUE7M7K.js +72 -0
  16. package/dist/chunk-LIUE7M7K.js.map +1 -0
  17. package/dist/{chunk-YNDCD53D.js → chunk-QHB7LGCA.js} +123 -16
  18. package/dist/chunk-QHB7LGCA.js.map +1 -0
  19. package/dist/chunk-R4MDAYFO.js +642 -0
  20. package/dist/chunk-R4MDAYFO.js.map +1 -0
  21. package/dist/cms/index.js +4 -2
  22. package/dist/cms/index.js.map +1 -1
  23. package/dist/cron/index.d.ts +32 -0
  24. package/dist/cron/index.js +63 -0
  25. package/dist/cron/index.js.map +1 -0
  26. package/dist/database/index.d.ts +37 -0
  27. package/dist/database/index.js +32 -0
  28. package/dist/database/index.js.map +1 -0
  29. package/dist/email/index.d.ts +29 -0
  30. package/dist/email/index.js +60 -0
  31. package/dist/email/index.js.map +1 -0
  32. package/dist/errors/index.js.map +1 -1
  33. package/dist/index.d.ts +176 -3
  34. package/dist/index.js +270 -6
  35. package/dist/index.js.map +1 -1
  36. package/dist/notifications/index.d.ts +35 -1
  37. package/dist/notifications/index.js +61 -4
  38. package/dist/notifications/index.js.map +1 -1
  39. package/dist/payments/index.d.ts +11 -3
  40. package/dist/payments/index.js +101 -7
  41. package/dist/payments/index.js.map +1 -1
  42. package/dist/roles/index.js +6 -4
  43. package/dist/roles/index.js.map +1 -1
  44. package/dist/seo/index.js.map +1 -1
  45. package/dist/server/index.js.map +1 -1
  46. package/dist/storage/index.d.ts +1 -1
  47. package/dist/storage/index.js +18 -9
  48. package/dist/storage/index.js.map +1 -1
  49. package/dist/{types-DtY5lp3P.d.ts → types-1uP3V_pe.d.ts} +5 -0
  50. package/package.json +120 -105
  51. package/dist/chunk-5XIZHBKE.js.map +0 -1
  52. package/dist/chunk-G7XDUN3Z.js.map +0 -1
  53. package/dist/chunk-YNDCD53D.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/database/DatabaseProvider.tsx","../src/database/errors.ts","../src/database/QueryBuilder.ts","../src/database/DatabaseClient.ts","../src/database/useRealtime.ts"],"sourcesContent":["import { createContext, useContext, useMemo, type ReactNode } from 'react';\r\nimport { supabase, isSupabaseConfigured } from '../core/supabase';\r\nimport { env } from '../core/config';\r\nimport { DatabaseClient } from './DatabaseClient';\r\n\r\ninterface DatabaseContextValue {\r\n db: DatabaseClient | null;\r\n isConfigured: boolean;\r\n}\r\n\r\nconst DatabaseContext = createContext<DatabaseContextValue>({\r\n db: null,\r\n isConfigured: false,\r\n});\r\n\r\ninterface DatabaseProviderProps {\r\n children: ReactNode;\r\n projectId?: string;\r\n}\r\n\r\nexport function DatabaseProvider({ children, projectId }: DatabaseProviderProps) {\r\n const resolvedProjectId = projectId || env.EZC_PROJECT_ID;\r\n const configured = isSupabaseConfigured && Boolean(resolvedProjectId);\r\n\r\n const db = useMemo(\r\n () => (configured ? new DatabaseClient(supabase, resolvedProjectId) : null),\r\n [configured, resolvedProjectId],\r\n );\r\n\r\n const value = useMemo(() => ({ db, isConfigured: configured }), [db, configured]);\r\n\r\n return <DatabaseContext.Provider value={value}>{children}</DatabaseContext.Provider>;\r\n}\r\n\r\nexport function useDatabase(): DatabaseClient {\r\n const { db } = useContext(DatabaseContext);\r\n if (!db) {\r\n throw new Error(\r\n 'useDatabase() must be used within <DatabaseProvider>. ' +\r\n 'Ensure EZC_PROJECT_ID and Supabase credentials are configured.',\r\n );\r\n }\r\n return db;\r\n}\r\n\r\nexport function useDatabaseOptional(): DatabaseClient | null {\r\n const { db } = useContext(DatabaseContext);\r\n return db;\r\n}\r\n\r\nexport function useIsDatabaseConfigured(): boolean {\r\n const { isConfigured } = useContext(DatabaseContext);\r\n return isConfigured;\r\n}\r\n","export class DatabaseError extends Error {\r\n readonly code: string;\r\n readonly statusCode: number;\r\n\r\n constructor(message: string, code = 'DATABASE_ERROR', statusCode = 500) {\r\n super(message);\r\n this.name = 'DatabaseError';\r\n this.code = code;\r\n this.statusCode = statusCode;\r\n }\r\n}\r\n\r\nexport class QueryError extends DatabaseError {\r\n readonly sql?: string;\r\n\r\n constructor(message: string, sql?: string) {\r\n super(message, 'QUERY_ERROR', 400);\r\n this.name = 'QueryError';\r\n this.sql = sql;\r\n }\r\n}\r\n\r\nexport class ValidationError extends DatabaseError {\r\n constructor(message: string) {\r\n super(message, 'VALIDATION_ERROR', 422);\r\n this.name = 'ValidationError';\r\n }\r\n}\r\n\r\nexport class ConnectionError extends DatabaseError {\r\n constructor(message: string) {\r\n super(message, 'CONNECTION_ERROR', 503);\r\n this.name = 'ConnectionError';\r\n }\r\n}\r\n\r\nexport class NotFoundError extends DatabaseError {\r\n constructor(message = 'Record not found') {\r\n super(message, 'NOT_FOUND', 404);\r\n this.name = 'NotFoundError';\r\n }\r\n}\r\n\r\nexport function mapRpcError(rpcResult: { success: boolean; error?: string; code?: string }): DatabaseError | null {\r\n if (rpcResult.success) return null;\r\n const msg = rpcResult.error || 'Unknown database error';\r\n if (msg.includes('No database schema exists')) return new NotFoundError(msg);\r\n if (msg.includes('Authentication required')) return new ConnectionError(msg);\r\n if (msg.includes('blocked') || msg.includes('forbidden')) return new ValidationError(msg);\r\n return new QueryError(msg);\r\n}\r\n","import type { SupabaseClient } from '@supabase/supabase-js';\r\nimport type { DatabaseResult, SingleResult, MutationResult, FilterValue, OrderOption } from './types';\r\nimport { QueryError, ValidationError, mapRpcError } from './errors';\r\n\r\nfunction escapeSqlValue(value: FilterValue): string {\r\n if (value === null) return 'NULL';\r\n if (typeof value === 'boolean') return value ? 'TRUE' : 'FALSE';\r\n if (typeof value === 'number') {\r\n if (!Number.isFinite(value)) throw new ValidationError('Non-finite numbers are not allowed');\r\n return String(value);\r\n }\r\n return `'${String(value).replace(/'/g, \"''\")}'`;\r\n}\r\n\r\nfunction escapeIdentifier(name: string): string {\r\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\r\n throw new ValidationError(`Invalid identifier: ${name}`);\r\n }\r\n return `\"${name}\"`;\r\n}\r\n\r\ntype Operation = 'select' | 'insert' | 'update' | 'delete' | 'count' | 'upsert';\r\n\r\ninterface Filter {\r\n column: string;\r\n op: string;\r\n value: FilterValue | FilterValue[];\r\n}\r\n\r\nexport interface ServerProxy {\r\n serverQuery: (sql: string) => Promise<{ success: boolean; data?: unknown[]; rowCount?: number; error?: string; schema?: string }>;\r\n serverExec: (sql: string) => Promise<{ success: boolean; data?: unknown[]; rowCount?: number; error?: string; schema?: string }>;\r\n}\r\n\r\nexport class QueryBuilder<T = Record<string, unknown>> {\r\n private readonly supabase: SupabaseClient;\r\n private readonly projectId: string;\r\n private readonly table: string;\r\n private readonly serverProxy?: ServerProxy;\r\n\r\n private operation: Operation = 'select';\r\n private selectColumns = '*';\r\n private filters: Filter[] = [];\r\n private orderClauses: string[] = [];\r\n private limitValue: number | null = null;\r\n private offsetValue: number | null = null;\r\n private insertData: Record<string, FilterValue>[] | null = null;\r\n private updateData: Record<string, FilterValue> | null = null;\r\n private upsertConflict: string | null = null;\r\n private singleMode = false;\r\n private maybeSingleMode = false;\r\n\r\n constructor(supabase: SupabaseClient, projectId: string, table: string, serverProxy?: ServerProxy) {\r\n this.supabase = supabase;\r\n this.projectId = projectId;\r\n this.table = table;\r\n this.serverProxy = serverProxy;\r\n }\r\n\r\n select(columns = '*'): this {\r\n this.operation = 'select';\r\n this.selectColumns = columns;\r\n return this;\r\n }\r\n\r\n // --- Filters ---\r\n\r\n eq(column: string, value: FilterValue): this {\r\n this.filters.push({ column, op: '=', value });\r\n return this;\r\n }\r\n\r\n neq(column: string, value: FilterValue): this {\r\n this.filters.push({ column, op: '!=', value });\r\n return this;\r\n }\r\n\r\n gt(column: string, value: FilterValue): this {\r\n this.filters.push({ column, op: '>', value });\r\n return this;\r\n }\r\n\r\n lt(column: string, value: FilterValue): this {\r\n this.filters.push({ column, op: '<', value });\r\n return this;\r\n }\r\n\r\n gte(column: string, value: FilterValue): this {\r\n this.filters.push({ column, op: '>=', value });\r\n return this;\r\n }\r\n\r\n lte(column: string, value: FilterValue): this {\r\n this.filters.push({ column, op: '<=', value });\r\n return this;\r\n }\r\n\r\n like(column: string, pattern: string): this {\r\n this.filters.push({ column, op: 'LIKE', value: pattern });\r\n return this;\r\n }\r\n\r\n ilike(column: string, pattern: string): this {\r\n this.filters.push({ column, op: 'ILIKE', value: pattern });\r\n return this;\r\n }\r\n\r\n in(column: string, values: FilterValue[]): this {\r\n this.filters.push({ column, op: 'IN', value: values });\r\n return this;\r\n }\r\n\r\n is(column: string, value: null | boolean): this {\r\n this.filters.push({ column, op: 'IS', value });\r\n return this;\r\n }\r\n\r\n // --- Ordering & Pagination ---\r\n\r\n order(column: string, options: OrderOption = {}): this {\r\n const dir = options.ascending === false ? 'DESC' : 'ASC';\r\n const nulls = options.nullsFirst ? 'NULLS FIRST' : 'NULLS LAST';\r\n this.orderClauses.push(`${escapeIdentifier(column)} ${dir} ${nulls}`);\r\n return this;\r\n }\r\n\r\n limit(count: number): this {\r\n this.limitValue = count;\r\n return this;\r\n }\r\n\r\n offset(count: number): this {\r\n this.offsetValue = count;\r\n return this;\r\n }\r\n\r\n // --- Mutations ---\r\n\r\n insert(records: Record<string, FilterValue> | Record<string, FilterValue>[]): this {\r\n this.operation = 'insert';\r\n this.insertData = Array.isArray(records) ? records : [records];\r\n return this;\r\n }\r\n\r\n update(values: Record<string, FilterValue>): this {\r\n this.operation = 'update';\r\n this.updateData = values;\r\n return this;\r\n }\r\n\r\n delete(): this {\r\n this.operation = 'delete';\r\n return this;\r\n }\r\n\r\n upsert(records: Record<string, FilterValue> | Record<string, FilterValue>[], options?: { onConflict?: string }): this {\r\n this.operation = 'upsert';\r\n this.insertData = Array.isArray(records) ? records : [records];\r\n this.upsertConflict = options?.onConflict || null;\r\n return this;\r\n }\r\n\r\n // --- Result Helpers ---\r\n\r\n count(): QueryBuilder<{ count: number }> {\r\n this.operation = 'count';\r\n return this as unknown as QueryBuilder<{ count: number }>;\r\n }\r\n\r\n single(): QueryBuilder<T> {\r\n this.singleMode = true;\r\n this.limitValue = 1;\r\n return this;\r\n }\r\n\r\n maybeSingle(): QueryBuilder<T> {\r\n this.maybeSingleMode = true;\r\n this.limitValue = 1;\r\n return this;\r\n }\r\n\r\n // --- SQL Building ---\r\n\r\n private buildWhereClause(): string {\r\n if (this.filters.length === 0) return '';\r\n const conditions = this.filters.map((f) => {\r\n const col = escapeIdentifier(f.column);\r\n if (f.op === 'IS') {\r\n const val = f.value === null ? 'NULL' : f.value ? 'TRUE' : 'FALSE';\r\n return `${col} IS ${val}`;\r\n }\r\n if (f.op === 'IN') {\r\n const vals = (f.value as FilterValue[]).map(escapeSqlValue).join(', ');\r\n return `${col} IN (${vals})`;\r\n }\r\n return `${col} ${f.op} ${escapeSqlValue(f.value as FilterValue)}`;\r\n });\r\n return ` WHERE ${conditions.join(' AND ')}`;\r\n }\r\n\r\n private buildSelectSql(): string {\r\n let sql = `SELECT ${this.selectColumns} FROM \"${this.table}\"`;\r\n sql += this.buildWhereClause();\r\n if (this.orderClauses.length > 0) sql += ` ORDER BY ${this.orderClauses.join(', ')}`;\r\n if (this.limitValue !== null) sql += ` LIMIT ${this.limitValue}`;\r\n if (this.offsetValue !== null && this.offsetValue > 0) sql += ` OFFSET ${this.offsetValue}`;\r\n return sql;\r\n }\r\n\r\n private buildCountSql(): string {\r\n let sql = `SELECT COUNT(*) as count FROM \"${this.table}\"`;\r\n sql += this.buildWhereClause();\r\n return sql;\r\n }\r\n\r\n private buildInsertSql(): string {\r\n if (!this.insertData || this.insertData.length === 0) {\r\n throw new ValidationError('No data provided for insert');\r\n }\r\n const columns = Object.keys(this.insertData[0]);\r\n const colList = columns.map(escapeIdentifier).join(', ');\r\n const rows = this.insertData.map(\r\n (row) => `(${columns.map((c) => escapeSqlValue(row[c] ?? null)).join(', ')})`\r\n );\r\n return `INSERT INTO \"${this.table}\" (${colList}) VALUES ${rows.join(', ')}`;\r\n }\r\n\r\n private buildUpsertSql(): string {\r\n let sql = this.buildInsertSql();\r\n const conflict = this.upsertConflict || 'id';\r\n const columns = Object.keys(this.insertData![0]);\r\n const updateCols = columns\r\n .filter((c) => c !== conflict)\r\n .map((c) => `${escapeIdentifier(c)} = EXCLUDED.${escapeIdentifier(c)}`)\r\n .join(', ');\r\n sql += ` ON CONFLICT (${escapeIdentifier(conflict)}) DO UPDATE SET ${updateCols}`;\r\n return sql;\r\n }\r\n\r\n private buildUpdateSql(): string {\r\n if (!this.updateData || Object.keys(this.updateData).length === 0) {\r\n throw new ValidationError('No data provided for update');\r\n }\r\n if (this.filters.length === 0) {\r\n throw new ValidationError('UPDATE without filters is not allowed — add .eq() or other filters');\r\n }\r\n const setClauses = Object.entries(this.updateData)\r\n .map(([col, val]) => `${escapeIdentifier(col)} = ${escapeSqlValue(val)}`)\r\n .join(', ');\r\n return `UPDATE \"${this.table}\" SET ${setClauses}${this.buildWhereClause()}`;\r\n }\r\n\r\n private buildDeleteSql(): string {\r\n if (this.filters.length === 0) {\r\n throw new ValidationError('DELETE without filters is not allowed — add .eq() or other filters');\r\n }\r\n return `DELETE FROM \"${this.table}\"${this.buildWhereClause()}`;\r\n }\r\n\r\n // --- Execution ---\r\n\r\n private async executeQuery(): Promise<DatabaseResult<T>> {\r\n const isRead = this.operation === 'select' || this.operation === 'count';\r\n\r\n let sql: string;\r\n switch (this.operation) {\r\n case 'select': sql = this.buildSelectSql(); break;\r\n case 'count': sql = this.buildCountSql(); break;\r\n case 'insert': sql = this.buildInsertSql(); break;\r\n case 'upsert': sql = this.buildUpsertSql(); break;\r\n case 'update': sql = this.buildUpdateSql(); break;\r\n case 'delete': sql = this.buildDeleteSql(); break;\r\n default: throw new QueryError(`Unknown operation: ${this.operation}`);\r\n }\r\n\r\n if (this.serverProxy) {\r\n const fn = isRead ? this.serverProxy.serverQuery : this.serverProxy.serverExec;\r\n const data = await fn(sql);\r\n if (!data.success) {\r\n const dbError = mapRpcError(data);\r\n if (dbError) throw dbError;\r\n throw new QueryError(data.error || 'Query failed', sql);\r\n }\r\n return {\r\n success: true,\r\n data: (isRead ? data.data || [] : []) as T[],\r\n rowCount: data.rowCount ?? (isRead ? (data.data?.length || 0) : 0),\r\n schema: data.schema,\r\n };\r\n }\r\n\r\n const rpcName = isRead ? 'sdk_query_project' : 'sdk_exec_project';\r\n const { data, error } = await this.supabase.rpc(rpcName, {\r\n p_project_id: this.projectId,\r\n p_sql: sql,\r\n });\r\n\r\n if (error) {\r\n throw new QueryError(error.message, sql);\r\n }\r\n\r\n if (!data.success) {\r\n const dbError = mapRpcError(data);\r\n if (dbError) throw dbError;\r\n throw new QueryError(data.error || 'Query failed', sql);\r\n }\r\n\r\n if (isRead) {\r\n return {\r\n success: true,\r\n data: data.data || [],\r\n rowCount: data.rowCount ?? (data.data?.length || 0),\r\n schema: data.schema,\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n data: [],\r\n rowCount: data.rowCount ?? 0,\r\n schema: data.schema,\r\n };\r\n }\r\n\r\n then<TResult1 = DatabaseResult<T> | SingleResult<T>, TResult2 = never>(\r\n onfulfilled?: ((value: DatabaseResult<T> | SingleResult<T>) => TResult1 | PromiseLike<TResult1>) | null,\r\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\r\n ): Promise<TResult1 | TResult2> {\r\n const promise = this.executeQuery().then((result) => {\r\n if (this.singleMode) {\r\n if (result.data.length === 0) {\r\n throw new QueryError('Expected exactly one row, got 0');\r\n }\r\n return { success: true, data: result.data[0], error: undefined } as SingleResult<T>;\r\n }\r\n if (this.maybeSingleMode) {\r\n return {\r\n success: true,\r\n data: result.data.length > 0 ? result.data[0] : null,\r\n error: undefined,\r\n } as SingleResult<T>;\r\n }\r\n return result;\r\n });\r\n return promise.then(onfulfilled, onrejected);\r\n }\r\n}\r\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type { DatabaseResult, MutationResult, SchemaInfo } from './types';\nimport { QueryBuilder, type ServerProxy } from './QueryBuilder';\nimport { QueryError, ConnectionError } from './errors';\nimport { ezcoder } from '../core/platform';\nimport { features } from '../core/config';\n\nfunction trackDbEvent(event: string, props: Record<string, unknown>) {\n if (!features.analytics) return;\n try { ezcoder.analytics.track(event, props); } catch { /* non-critical */ }\n}\n\ninterface ServerProxyResult {\n success: boolean;\n data?: unknown[];\n rowCount?: number;\n error?: string;\n schema?: string;\n exists?: boolean;\n tables?: unknown[];\n tablesCount?: number;\n createdAt?: string;\n lastAccessedAt?: string;\n executed_sql?: string;\n}\n\nconst MAX_RETRIES = 3;\nconst SERVER_TIMEOUT_MS = 5000;\n\nexport class DatabaseClient {\n private readonly supabase: SupabaseClient | null;\n private readonly projectId: string;\n private apiKey?: string;\n private platformUrl?: string;\n private serverMode: boolean = false;\n\n constructor(supabase: SupabaseClient | null, projectId: string) {\n this.supabase = supabase;\n this.projectId = projectId;\n }\n\n static createServerClient(\n projectId: string,\n apiKey: string,\n platformUrl?: string\n ): DatabaseClient {\n const client = new DatabaseClient(null, projectId);\n client.apiKey = apiKey;\n client.platformUrl = platformUrl\n || (typeof process !== 'undefined' && process.env?.EZCODER_API_URL)\n || 'https://ezcoder.app';\n client.serverMode = true;\n return client;\n }\n\n from<T = Record<string, unknown>>(table: string): QueryBuilder<T> {\n if (this.serverMode) {\n return new QueryBuilder<T>(null as unknown as SupabaseClient, this.projectId, table, {\n serverQuery: (sql: string) => this._serverRequest('/query', sql),\n serverExec: (sql: string) => this._serverRequest('/execute', sql),\n });\n }\n return new QueryBuilder<T>(this.supabase!, this.projectId, table);\n }\n\n async sql<T = Record<string, unknown>>(query: string): Promise<DatabaseResult<T>> {\n const trimmed = query.trim().toLowerCase();\n if (!trimmed.startsWith('select')) {\n throw new QueryError('sql() is for read-only queries. Use execute() for mutations.');\n }\n\n if (this.serverMode) {\n return this._serverQuery<T>(query);\n }\n\n const start = Date.now();\n const { data, error } = await this.supabase!.rpc('sdk_query_project', {\n p_project_id: this.projectId,\n p_sql: query,\n });\n const latencyMs = Date.now() - start;\n\n if (error) {\n trackDbEvent('db_query', { projectId: this.projectId, latencyMs, success: false, error: error.message });\n throw new QueryError(error.message, query);\n }\n if (!data.success) {\n trackDbEvent('db_query', { projectId: this.projectId, latencyMs, success: false, error: data.error });\n throw new QueryError(data.error || 'Query failed', query);\n }\n\n trackDbEvent('db_query', { projectId: this.projectId, latencyMs, success: true, rowCount: data.rowCount ?? 0 });\n\n return {\n success: true,\n data: data.data || [],\n rowCount: data.rowCount ?? (data.data?.length || 0),\n schema: data.schema,\n };\n }\n\n async execute(sql: string): Promise<MutationResult> {\n if (this.serverMode) {\n return this._serverExecute(sql);\n }\n\n const start = Date.now();\n const { data, error } = await this.supabase!.rpc('sdk_exec_project', {\n p_project_id: this.projectId,\n p_sql: sql,\n });\n const latencyMs = Date.now() - start;\n\n if (error) {\n trackDbEvent('db_mutation', { projectId: this.projectId, latencyMs, success: false, error: error.message });\n throw new QueryError(error.message, sql);\n }\n if (!data.success) {\n trackDbEvent('db_mutation', { projectId: this.projectId, latencyMs, success: false, error: data.error });\n throw new QueryError(data.error || 'Execution failed', sql);\n }\n\n trackDbEvent('db_mutation', { projectId: this.projectId, latencyMs, success: true, rowCount: data.rowCount ?? 0 });\n\n return {\n success: true,\n rowCount: data.rowCount ?? 0,\n schema: data.schema,\n executed_sql: data.executed_sql,\n };\n }\n\n async getSchema(): Promise<SchemaInfo> {\n if (this.serverMode) {\n return this._serverGetSchema();\n }\n\n const { data, error } = await this.supabase!.rpc('sdk_get_schema_info', {\n p_project_id: this.projectId,\n });\n\n if (error) throw new ConnectionError(error.message);\n\n return {\n exists: data.exists ?? false,\n schema: data.schema,\n tables: data.tables || [],\n tablesCount: data.tablesCount ?? 0,\n createdAt: data.createdAt,\n lastAccessedAt: data.lastAccessedAt,\n };\n }\n\n private async _serverRequest(endpoint: string, sql: string): Promise<ServerProxyResult> {\n const url = `${this.platformUrl}/api/platform/db/${this.projectId}${endpoint}`;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ sql }),\n signal: AbortSignal.timeout(SERVER_TIMEOUT_MS),\n });\n\n if (res.status === 429) {\n const retryAfter = parseInt(res.headers.get('retry-after') || '60', 10);\n await new Promise(r => setTimeout(r, retryAfter * 1000));\n continue;\n }\n if (res.status === 503) {\n await new Promise(r => setTimeout(r, (attempt + 1) * 2000));\n continue;\n }\n\n return await res.json() as ServerProxyResult;\n } catch (e) {\n lastError = e instanceof Error ? e : new Error(String(e));\n }\n }\n\n return { success: false, error: lastError?.message || 'Request failed after retries' };\n }\n\n private async _serverQuery<T>(query: string): Promise<DatabaseResult<T>> {\n const start = Date.now();\n const result = await this._serverRequest('/query', query);\n const latencyMs = Date.now() - start;\n\n if (!result.success) {\n trackDbEvent('db_query', { projectId: this.projectId, latencyMs, success: false, error: result.error, serverMode: true });\n throw new QueryError(result.error || 'Query failed', query);\n }\n\n trackDbEvent('db_query', { projectId: this.projectId, latencyMs, success: true, rowCount: result.rowCount ?? 0, serverMode: true });\n\n return {\n success: true,\n data: (result.data || []) as T[],\n rowCount: result.rowCount ?? ((result.data as unknown[])?.length || 0),\n schema: result.schema,\n };\n }\n\n private async _serverExecute(sql: string): Promise<MutationResult> {\n const start = Date.now();\n const result = await this._serverRequest('/execute', sql);\n const latencyMs = Date.now() - start;\n\n if (!result.success) {\n trackDbEvent('db_mutation', { projectId: this.projectId, latencyMs, success: false, error: result.error, serverMode: true });\n throw new QueryError(result.error || 'Execution failed', sql);\n }\n\n trackDbEvent('db_mutation', { projectId: this.projectId, latencyMs, success: true, rowCount: result.rowCount ?? 0, serverMode: true });\n\n return {\n success: true,\n rowCount: result.rowCount ?? 0,\n schema: result.schema,\n executed_sql: result.executed_sql,\n };\n }\n\n private async _serverGetSchema(): Promise<SchemaInfo> {\n const url = `${this.platformUrl}/api/platform/db/${this.projectId}/schema`;\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n const res = await fetch(url, {\n method: 'GET',\n headers: { 'Authorization': `Bearer ${this.apiKey}` },\n signal: AbortSignal.timeout(SERVER_TIMEOUT_MS),\n });\n\n if (res.status === 503) {\n await new Promise(r => setTimeout(r, (attempt + 1) * 2000));\n continue;\n }\n\n const data = await res.json() as ServerProxyResult;\n if (!data.success) throw new ConnectionError(data.error || 'Schema fetch failed');\n\n return {\n exists: data.exists ?? false,\n schema: data.schema,\n tables: (data.tables || []) as SchemaInfo['tables'],\n tablesCount: data.tablesCount ?? 0,\n createdAt: data.createdAt,\n lastAccessedAt: data.lastAccessedAt,\n };\n } catch (e) {\n lastError = e instanceof Error ? e : new Error(String(e));\n }\n }\n\n throw new ConnectionError(lastError?.message || 'Schema request failed after retries');\n }\n}\n","import { useEffect, useState, useRef } from 'react';\r\nimport { supabase, isSupabaseConfigured } from '../core/supabase';\r\nimport { env } from '../core/config';\r\n\r\ntype RealtimeEvent = 'INSERT' | 'UPDATE' | 'DELETE' | '*';\r\n\r\ninterface RealtimeOptions {\r\n event?: RealtimeEvent;\r\n filter?: string;\r\n}\r\n\r\ninterface UseRealtimeReturn<T> {\r\n data: T[];\r\n status: 'connecting' | 'connected' | 'error' | 'disabled';\r\n setData: React.Dispatch<React.SetStateAction<T[]>>;\r\n}\r\n\r\nexport function useRealtime<T extends Record<string, unknown> = Record<string, unknown>>(\r\n table: string,\r\n options: RealtimeOptions = {},\r\n): UseRealtimeReturn<T> {\r\n const [data, setData] = useState<T[]>([]);\r\n const [status, setStatus] = useState<UseRealtimeReturn<T>['status']>('connecting');\r\n const optionsRef = useRef(options);\r\n optionsRef.current = options;\r\n\r\n const projectId = env.EZC_PROJECT_ID;\r\n\r\n useEffect(() => {\r\n if (!isSupabaseConfigured || !projectId) {\r\n setStatus('disabled');\r\n return;\r\n }\r\n\r\n const schemaName = `proj_${projectId.replace(/-/g, '_')}`;\r\n const channelName = `${schemaName}_${table}_${optionsRef.current.event || 'all'}`;\r\n\r\n const channel = supabase\r\n .channel(channelName)\r\n .on(\r\n 'postgres_changes' as never,\r\n {\r\n event: optionsRef.current.event || '*',\r\n schema: schemaName,\r\n table,\r\n filter: optionsRef.current.filter,\r\n } as never,\r\n (payload: { eventType: string; new: Record<string, unknown>; old: Record<string, unknown> }) => {\r\n if (payload.eventType === 'INSERT') {\r\n setData((prev) => [...prev, payload.new as T]);\r\n } else if (payload.eventType === 'UPDATE') {\r\n setData((prev) =>\r\n prev.map((item) =>\r\n (item as Record<string, unknown>).id === (payload.new as Record<string, unknown>).id\r\n ? (payload.new as T)\r\n : item,\r\n ),\r\n );\r\n } else if (payload.eventType === 'DELETE') {\r\n setData((prev) =>\r\n prev.filter(\r\n (item) =>\r\n (item as Record<string, unknown>).id !== (payload.old as Record<string, unknown>).id,\r\n ),\r\n );\r\n }\r\n },\r\n )\r\n .subscribe((subStatus: string) => {\r\n setStatus(subStatus === 'SUBSCRIBED' ? 'connected' : 'connecting');\r\n });\r\n\r\n return () => {\r\n supabase.removeChannel(channel);\r\n };\r\n }, [projectId, table]);\r\n\r\n return { data, status, setData };\r\n}\r\n"],"mappings":"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","names":["supabase","data","supabase"]}
package/dist/cms/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import {
2
- features,
3
2
  supabase
4
- } from "../chunk-G7XDUN3Z.js";
3
+ } from "../chunk-I2YGB7Z6.js";
4
+ import {
5
+ features
6
+ } from "../chunk-LIUE7M7K.js";
5
7
 
6
8
  // src/cms/cmsClient.ts
7
9
  function slugify(text) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cms/cmsClient.ts","../../src/cms/useContent.ts"],"sourcesContent":["import { supabase } from '../core/supabase';\nimport { features } from '../core/config';\n\ninterface ContentItem {\n id: string;\n title: string;\n slug: string;\n content: string;\n type: string;\n status: string;\n author_id?: string;\n metadata?: Record<string, unknown>;\n published_at?: string;\n created_at: string;\n updated_at: string;\n}\n\ninterface ContentListOptions {\n type?: string;\n status?: string;\n limit?: number;\n}\n\nfunction slugify(text: string): string {\n return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');\n}\n\nexport const cmsClient = {\n async list(options: ContentListOptions = {}): Promise<ContentItem[]> {\n if (!features.database) return [];\n\n let query = supabase.from('cms_content').select('*');\n if (options.type) query = query.eq('type', options.type);\n if (options.status) query = query.eq('status', options.status);\n query = query.order('created_at', { ascending: false });\n if (options.limit) query = query.limit(options.limit);\n\n const { data, error } = await query;\n if (error) throw error;\n return (data as ContentItem[]) || [];\n },\n\n async getBySlug(slug: string): Promise<ContentItem | null> {\n if (!features.database) return null;\n\n const { data, error } = await supabase\n .from('cms_content')\n .select('*')\n .eq('slug', slug)\n .single();\n\n if (error) return null;\n return data as ContentItem;\n },\n\n async getById(id: string): Promise<ContentItem | null> {\n if (!features.database) return null;\n\n const { data, error } = await supabase\n .from('cms_content')\n .select('*')\n .eq('id', id)\n .single();\n\n if (error) return null;\n return data as ContentItem;\n },\n\n async create(item: Partial<ContentItem>): Promise<ContentItem> {\n if (!features.database) throw new Error('Database not configured');\n\n const slug = item.slug || slugify(item.title || '');\n const { data, error } = await supabase\n .from('cms_content')\n .insert({ ...item, slug, status: item.status || 'draft' })\n .select()\n .single();\n\n if (error) throw error;\n return data as ContentItem;\n },\n\n async update(id: string, updates: Partial<ContentItem>): Promise<ContentItem> {\n if (!features.database) throw new Error('Database not configured');\n\n const { data, error } = await supabase\n .from('cms_content')\n .update({ ...updates, updated_at: new Date().toISOString() })\n .eq('id', id)\n .select()\n .single();\n\n if (error) throw error;\n return data as ContentItem;\n },\n\n async delete(id: string): Promise<void> {\n if (!features.database) throw new Error('Database not configured');\n const { error } = await supabase.from('cms_content').delete().eq('id', id);\n if (error) throw error;\n },\n\n async publish(id: string): Promise<ContentItem> {\n return cmsClient.update(id, { status: 'published', published_at: new Date().toISOString() });\n },\n\n async unpublish(id: string): Promise<ContentItem> {\n return cmsClient.update(id, { status: 'draft' });\n },\n};\n\nexport type { ContentItem, ContentListOptions };\n","import { useState, useEffect, useCallback } from 'react';\nimport { cmsClient } from './cmsClient';\nimport type { ContentItem, ContentListOptions } from './cmsClient';\n\ninterface UseContentListReturn {\n content: ContentItem[];\n loading: boolean;\n error: string | null;\n refetch: () => Promise<void>;\n}\n\ninterface UseContentReturn {\n content: ContentItem | null;\n loading: boolean;\n error: string | null;\n}\n\nexport function useContentList(options: ContentListOptions = {}): UseContentListReturn {\n const [content, setContent] = useState<ContentItem[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const fetch = useCallback(async () => {\n try {\n setLoading(true);\n const data = await cmsClient.list(options);\n setContent(data);\n setError(null);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : 'Failed to fetch content');\n } finally {\n setLoading(false);\n }\n }, [options.type, options.status, options.limit]);\n\n useEffect(() => {\n fetch();\n }, [fetch]);\n\n return { content, loading, error, refetch: fetch };\n}\n\nexport function useContent(slug: string): UseContentReturn {\n const [content, setContent] = useState<ContentItem | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!slug) {\n setLoading(false);\n return;\n }\n\n cmsClient.getBySlug(slug)\n .then((data) => {\n setContent(data);\n setError(null);\n })\n .catch((err: unknown) => {\n setError(err instanceof Error ? err.message : 'Failed to fetch content');\n })\n .finally(() => setLoading(false));\n }, [slug]);\n\n return { content, loading, error };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/cms/cmsClient.ts","../../src/cms/useContent.ts"],"sourcesContent":["import { supabase } from '../core/supabase';\r\nimport { features } from '../core/config';\r\n\r\ninterface ContentItem {\r\n id: string;\r\n title: string;\r\n slug: string;\r\n content: string;\r\n type: string;\r\n status: string;\r\n author_id?: string;\r\n metadata?: Record<string, unknown>;\r\n published_at?: string;\r\n created_at: string;\r\n updated_at: string;\r\n}\r\n\r\ninterface ContentListOptions {\r\n type?: string;\r\n status?: string;\r\n limit?: number;\r\n}\r\n\r\nfunction slugify(text: string): string {\r\n return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');\r\n}\r\n\r\nexport const cmsClient = {\r\n async list(options: ContentListOptions = {}): Promise<ContentItem[]> {\r\n if (!features.database) return [];\r\n\r\n let query = supabase.from('cms_content').select('*');\r\n if (options.type) query = query.eq('type', options.type);\r\n if (options.status) query = query.eq('status', options.status);\r\n query = query.order('created_at', { ascending: false });\r\n if (options.limit) query = query.limit(options.limit);\r\n\r\n const { data, error } = await query;\r\n if (error) throw error;\r\n return (data as ContentItem[]) || [];\r\n },\r\n\r\n async getBySlug(slug: string): Promise<ContentItem | null> {\r\n if (!features.database) return null;\r\n\r\n const { data, error } = await supabase\r\n .from('cms_content')\r\n .select('*')\r\n .eq('slug', slug)\r\n .single();\r\n\r\n if (error) return null;\r\n return data as ContentItem;\r\n },\r\n\r\n async getById(id: string): Promise<ContentItem | null> {\r\n if (!features.database) return null;\r\n\r\n const { data, error } = await supabase\r\n .from('cms_content')\r\n .select('*')\r\n .eq('id', id)\r\n .single();\r\n\r\n if (error) return null;\r\n return data as ContentItem;\r\n },\r\n\r\n async create(item: Partial<ContentItem>): Promise<ContentItem> {\r\n if (!features.database) throw new Error('Database not configured');\r\n\r\n const slug = item.slug || slugify(item.title || '');\r\n const { data, error } = await supabase\r\n .from('cms_content')\r\n .insert({ ...item, slug, status: item.status || 'draft' })\r\n .select()\r\n .single();\r\n\r\n if (error) throw error;\r\n return data as ContentItem;\r\n },\r\n\r\n async update(id: string, updates: Partial<ContentItem>): Promise<ContentItem> {\r\n if (!features.database) throw new Error('Database not configured');\r\n\r\n const { data, error } = await supabase\r\n .from('cms_content')\r\n .update({ ...updates, updated_at: new Date().toISOString() })\r\n .eq('id', id)\r\n .select()\r\n .single();\r\n\r\n if (error) throw error;\r\n return data as ContentItem;\r\n },\r\n\r\n async delete(id: string): Promise<void> {\r\n if (!features.database) throw new Error('Database not configured');\r\n const { error } = await supabase.from('cms_content').delete().eq('id', id);\r\n if (error) throw error;\r\n },\r\n\r\n async publish(id: string): Promise<ContentItem> {\r\n return cmsClient.update(id, { status: 'published', published_at: new Date().toISOString() });\r\n },\r\n\r\n async unpublish(id: string): Promise<ContentItem> {\r\n return cmsClient.update(id, { status: 'draft' });\r\n },\r\n};\r\n\r\nexport type { ContentItem, ContentListOptions };\r\n","import { useState, useEffect, useCallback } from 'react';\r\nimport { cmsClient } from './cmsClient';\r\nimport type { ContentItem, ContentListOptions } from './cmsClient';\r\n\r\ninterface UseContentListReturn {\r\n content: ContentItem[];\r\n loading: boolean;\r\n error: string | null;\r\n refetch: () => Promise<void>;\r\n}\r\n\r\ninterface UseContentReturn {\r\n content: ContentItem | null;\r\n loading: boolean;\r\n error: string | null;\r\n}\r\n\r\nexport function useContentList(options: ContentListOptions = {}): UseContentListReturn {\r\n const [content, setContent] = useState<ContentItem[]>([]);\r\n const [loading, setLoading] = useState(true);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const fetch = useCallback(async () => {\r\n try {\r\n setLoading(true);\r\n const data = await cmsClient.list(options);\r\n setContent(data);\r\n setError(null);\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : 'Failed to fetch content');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [options.type, options.status, options.limit]);\r\n\r\n useEffect(() => {\r\n fetch();\r\n }, [fetch]);\r\n\r\n return { content, loading, error, refetch: fetch };\r\n}\r\n\r\nexport function useContent(slug: string): UseContentReturn {\r\n const [content, setContent] = useState<ContentItem | null>(null);\r\n const [loading, setLoading] = useState(true);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n useEffect(() => {\r\n if (!slug) {\r\n setLoading(false);\r\n return;\r\n }\r\n\r\n cmsClient.getBySlug(slug)\r\n .then((data) => {\r\n setContent(data);\r\n setError(null);\r\n })\r\n .catch((err: unknown) => {\r\n setError(err instanceof Error ? err.message : 'Failed to fetch content');\r\n })\r\n .finally(() => setLoading(false));\r\n }, [slug]);\r\n\r\n return { content, loading, error };\r\n}\r\n"],"mappings":"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","names":[]}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * SDK registerCronJob (B1).
3
+ *
4
+ * Routes to /api/project-cron/register using the SERVER-class project token.
5
+ *
6
+ * BEFORE B1, this function read the Supabase auth session and sent the
7
+ * resulting JWT as `Authorization: Bearer`. The server endpoint expected
8
+ * a NextAuth session — they never matched, so every register returned 401.
9
+ *
10
+ * AFTER B1:
11
+ * - Reads EZC_PROJECT_TOKEN_SERVER from server-side env.
12
+ * - Sends via `X-EzCoder-Server-Token` header.
13
+ * - Refuses to run from browser bundles with a clear, actionable error.
14
+ * - The server endpoint now uses verifyProjectServerToken (project-scoped
15
+ * auth) instead of NextAuth getServerSession (user-scoped auth).
16
+ */
17
+ interface RegisterJobOptions {
18
+ httpMethod?: string;
19
+ headers?: Record<string, string>;
20
+ body?: Record<string, unknown>;
21
+ timezone?: string;
22
+ timeoutSeconds?: number;
23
+ }
24
+ interface RegisterJobResult {
25
+ success: boolean;
26
+ job?: Record<string, unknown>;
27
+ error?: string;
28
+ code?: string;
29
+ }
30
+ declare function registerCronJob(name: string, cronExpression: string, endpointUrl: string, options?: RegisterJobOptions): Promise<RegisterJobResult>;
31
+
32
+ export { registerCronJob };
@@ -0,0 +1,63 @@
1
+ import {
2
+ resolveServerToken
3
+ } from "../chunk-CQKYANAW.js";
4
+ import {
5
+ env
6
+ } from "../chunk-LIUE7M7K.js";
7
+
8
+ // src/cron/registerJob.ts
9
+ async function registerCronJob(name, cronExpression, endpointUrl, options = {}) {
10
+ const apiUrl = env.EZCODER_API_URL;
11
+ const projectId = env.EZC_PROJECT_ID;
12
+ if (!apiUrl || !projectId) {
13
+ return {
14
+ success: false,
15
+ error: "EZCODER_API_URL and EZC_PROJECT_ID are required",
16
+ code: "sdk_misconfigured"
17
+ };
18
+ }
19
+ const tokenResolution = resolveServerToken();
20
+ if (!tokenResolution.ok) {
21
+ return { success: false, error: tokenResolution.reason, code: "no_server_token" };
22
+ }
23
+ try {
24
+ const res = await fetch(`${apiUrl}/api/project-cron/register`, {
25
+ method: "POST",
26
+ headers: {
27
+ "Content-Type": "application/json",
28
+ "X-EzCoder-Server-Token": tokenResolution.token
29
+ },
30
+ body: JSON.stringify({
31
+ projectId,
32
+ name,
33
+ cronExpression,
34
+ endpointUrl,
35
+ httpMethod: options.httpMethod || "POST",
36
+ headers: options.headers,
37
+ body: options.body,
38
+ timezone: options.timezone,
39
+ timeoutSeconds: options.timeoutSeconds
40
+ })
41
+ });
42
+ const raw = await res.json().catch(() => ({}));
43
+ const data = raw && typeof raw === "object" ? raw : {};
44
+ if (!res.ok) {
45
+ return {
46
+ success: false,
47
+ error: data.error ?? `HTTP ${res.status}`,
48
+ code: data.code
49
+ };
50
+ }
51
+ return { success: true, job: data.job };
52
+ } catch (err) {
53
+ return {
54
+ success: false,
55
+ error: err instanceof Error ? err.message : "Network error",
56
+ code: "network_error"
57
+ };
58
+ }
59
+ }
60
+ export {
61
+ registerCronJob
62
+ };
63
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cron/registerJob.ts"],"sourcesContent":["/**\r\n * SDK registerCronJob (B1).\r\n *\r\n * Routes to /api/project-cron/register using the SERVER-class project token.\r\n *\r\n * BEFORE B1, this function read the Supabase auth session and sent the\r\n * resulting JWT as `Authorization: Bearer`. The server endpoint expected\r\n * a NextAuth session — they never matched, so every register returned 401.\r\n *\r\n * AFTER B1:\r\n * - Reads EZC_PROJECT_TOKEN_SERVER from server-side env.\r\n * - Sends via `X-EzCoder-Server-Token` header.\r\n * - Refuses to run from browser bundles with a clear, actionable error.\r\n * - The server endpoint now uses verifyProjectServerToken (project-scoped\r\n * auth) instead of NextAuth getServerSession (user-scoped auth).\r\n */\r\n\r\nimport { env } from '../core/config';\r\nimport { resolveServerToken } from '../core/projectToken';\r\n\r\ninterface RegisterJobOptions {\r\n httpMethod?: string;\r\n headers?: Record<string, string>;\r\n body?: Record<string, unknown>;\r\n timezone?: string;\r\n timeoutSeconds?: number;\r\n}\r\n\r\ninterface RegisterJobResult {\r\n success: boolean;\r\n job?: Record<string, unknown>;\r\n error?: string;\r\n code?: string;\r\n}\r\n\r\nexport async function registerCronJob(\r\n name: string,\r\n cronExpression: string,\r\n endpointUrl: string,\r\n options: RegisterJobOptions = {},\r\n): Promise<RegisterJobResult> {\r\n const apiUrl = env.EZCODER_API_URL;\r\n const projectId = env.EZC_PROJECT_ID;\r\n\r\n if (!apiUrl || !projectId) {\r\n return {\r\n success: false,\r\n error: 'EZCODER_API_URL and EZC_PROJECT_ID are required',\r\n code: 'sdk_misconfigured',\r\n };\r\n }\r\n\r\n const tokenResolution = resolveServerToken();\r\n if (!tokenResolution.ok) {\r\n return { success: false, error: tokenResolution.reason, code: 'no_server_token' };\r\n }\r\n\r\n try {\r\n const res = await fetch(`${apiUrl}/api/project-cron/register`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'X-EzCoder-Server-Token': tokenResolution.token,\r\n },\r\n body: JSON.stringify({\r\n projectId,\r\n name,\r\n cronExpression,\r\n endpointUrl,\r\n httpMethod: options.httpMethod || 'POST',\r\n headers: options.headers,\r\n body: options.body,\r\n timezone: options.timezone,\r\n timeoutSeconds: options.timeoutSeconds,\r\n }),\r\n });\r\n\r\n const raw: unknown = await res.json().catch(() => ({}));\r\n const data = (raw && typeof raw === 'object' ? raw : {}) as {\r\n job?: Record<string, unknown>;\r\n error?: string;\r\n code?: string;\r\n };\r\n\r\n if (!res.ok) {\r\n return {\r\n success: false,\r\n error: data.error ?? `HTTP ${res.status}`,\r\n code: data.code,\r\n };\r\n }\r\n\r\n return { success: true, job: data.job };\r\n } catch (err: unknown) {\r\n return {\r\n success: false,\r\n error: err instanceof Error ? err.message : 'Network error',\r\n code: 'network_error',\r\n };\r\n }\r\n}\r\n"],"mappings":";;;;;;;;AAmCA,eAAsB,gBACpB,MACA,gBACA,aACA,UAA8B,CAAC,GACH;AAC5B,QAAM,SAAS,IAAI;AACnB,QAAM,YAAY,IAAI;AAEtB,MAAI,CAAC,UAAU,CAAC,WAAW;AACzB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,kBAAkB,mBAAmB;AAC3C,MAAI,CAAC,gBAAgB,IAAI;AACvB,WAAO,EAAE,SAAS,OAAO,OAAO,gBAAgB,QAAQ,MAAM,kBAAkB;AAAA,EAClF;AAEA,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,GAAG,MAAM,8BAA8B;AAAA,MAC7D,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,0BAA0B,gBAAgB;AAAA,MAC5C;AAAA,MACA,MAAM,KAAK,UAAU;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,QAAQ,cAAc;AAAA,QAClC,SAAS,QAAQ;AAAA,QACjB,MAAM,QAAQ;AAAA,QACd,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,MAC1B,CAAC;AAAA,IACH,CAAC;AAED,UAAM,MAAe,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACtD,UAAM,OAAQ,OAAO,OAAO,QAAQ,WAAW,MAAM,CAAC;AAMtD,QAAI,CAAC,IAAI,IAAI;AACX,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,KAAK,SAAS,QAAQ,IAAI,MAAM;AAAA,QACvC,MAAM,KAAK;AAAA,MACb;AAAA,IACF;AAEA,WAAO,EAAE,SAAS,MAAM,KAAK,KAAK,IAAI;AAAA,EACxC,SAAS,KAAc;AACrB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,eAAe,QAAQ,IAAI,UAAU;AAAA,MAC5C,MAAM;AAAA,IACR;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,37 @@
1
+ export { C as ColumnInfo, D as DatabaseClient, a as DatabaseProvider, b as DatabaseResult, F as FilterValue, c as ForeignKeyInfo, I as IndexInfo, M as MutationResult, O as OrderOption, P as PolicyInfo, Q as QueryBuilder, S as SchemaInfo, d as SingleResult, T as TableInfo, u as useDatabase, e as useDatabaseOptional, f as useIsDatabaseConfigured } from '../DatabaseProvider-DalP-KHC.js';
2
+ import 'react/jsx-runtime';
3
+ import 'react';
4
+ import '@supabase/supabase-js';
5
+
6
+ type RealtimeEvent = 'INSERT' | 'UPDATE' | 'DELETE' | '*';
7
+ interface RealtimeOptions {
8
+ event?: RealtimeEvent;
9
+ filter?: string;
10
+ }
11
+ interface UseRealtimeReturn<T> {
12
+ data: T[];
13
+ status: 'connecting' | 'connected' | 'error' | 'disabled';
14
+ setData: React.Dispatch<React.SetStateAction<T[]>>;
15
+ }
16
+ declare function useRealtime<T extends Record<string, unknown> = Record<string, unknown>>(table: string, options?: RealtimeOptions): UseRealtimeReturn<T>;
17
+
18
+ declare class DatabaseError extends Error {
19
+ readonly code: string;
20
+ readonly statusCode: number;
21
+ constructor(message: string, code?: string, statusCode?: number);
22
+ }
23
+ declare class QueryError extends DatabaseError {
24
+ readonly sql?: string;
25
+ constructor(message: string, sql?: string);
26
+ }
27
+ declare class ValidationError extends DatabaseError {
28
+ constructor(message: string);
29
+ }
30
+ declare class ConnectionError extends DatabaseError {
31
+ constructor(message: string);
32
+ }
33
+ declare class NotFoundError extends DatabaseError {
34
+ constructor(message?: string);
35
+ }
36
+
37
+ export { ConnectionError, DatabaseError, NotFoundError, QueryError, ValidationError, useRealtime };
@@ -0,0 +1,32 @@
1
+ import {
2
+ ConnectionError,
3
+ DatabaseClient,
4
+ DatabaseError,
5
+ DatabaseProvider,
6
+ NotFoundError,
7
+ QueryBuilder,
8
+ QueryError,
9
+ ValidationError,
10
+ useDatabase,
11
+ useDatabaseOptional,
12
+ useIsDatabaseConfigured,
13
+ useRealtime
14
+ } from "../chunk-R4MDAYFO.js";
15
+ import "../chunk-HJ2EIZ4S.js";
16
+ import "../chunk-I2YGB7Z6.js";
17
+ import "../chunk-LIUE7M7K.js";
18
+ export {
19
+ ConnectionError,
20
+ DatabaseClient,
21
+ DatabaseError,
22
+ DatabaseProvider,
23
+ NotFoundError,
24
+ QueryBuilder,
25
+ QueryError,
26
+ ValidationError,
27
+ useDatabase,
28
+ useDatabaseOptional,
29
+ useIsDatabaseConfigured,
30
+ useRealtime
31
+ };
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * SDK sendEmail (B1).
3
+ *
4
+ * Routes to /api/project-email/send using the SERVER-class project token.
5
+ *
6
+ * BEFORE B1, this function read the Supabase auth session and sent the
7
+ * resulting JWT as `Authorization: Bearer`. The server endpoint expected
8
+ * the project token (ezc_) — they never matched, so every send returned 401.
9
+ *
10
+ * AFTER B1:
11
+ * - Reads EZC_PROJECT_TOKEN_SERVER from server-side env.
12
+ * - Sends via `X-EzCoder-Server-Token` header.
13
+ * - Refuses to run from browser bundles with a clear, actionable error.
14
+ * - Falls back to the legacy single-class token through Phase 1, with a
15
+ * one-shot deprecation warning.
16
+ */
17
+ interface SendEmailOptions {
18
+ from?: string;
19
+ text?: string;
20
+ }
21
+ interface SendEmailResult {
22
+ success: boolean;
23
+ id?: string;
24
+ error?: string;
25
+ code?: string;
26
+ }
27
+ declare function sendEmail(to: string, subject: string, html: string, options?: SendEmailOptions): Promise<SendEmailResult>;
28
+
29
+ export { sendEmail };
@@ -0,0 +1,60 @@
1
+ import {
2
+ resolveServerToken
3
+ } from "../chunk-CQKYANAW.js";
4
+ import {
5
+ env
6
+ } from "../chunk-LIUE7M7K.js";
7
+
8
+ // src/email/sendEmail.ts
9
+ async function sendEmail(to, subject, html, options = {}) {
10
+ const apiUrl = env.EZCODER_API_URL;
11
+ const projectId = env.EZC_PROJECT_ID;
12
+ if (!apiUrl || !projectId) {
13
+ return {
14
+ success: false,
15
+ error: "EZCODER_API_URL and EZC_PROJECT_ID are required",
16
+ code: "sdk_misconfigured"
17
+ };
18
+ }
19
+ const tokenResolution = resolveServerToken();
20
+ if (!tokenResolution.ok) {
21
+ return { success: false, error: tokenResolution.reason, code: "no_server_token" };
22
+ }
23
+ try {
24
+ const res = await fetch(`${apiUrl}/api/project-email/send`, {
25
+ method: "POST",
26
+ headers: {
27
+ "Content-Type": "application/json",
28
+ "X-EzCoder-Server-Token": tokenResolution.token
29
+ },
30
+ body: JSON.stringify({
31
+ projectId,
32
+ to,
33
+ subject,
34
+ html,
35
+ text: options.text,
36
+ from: options.from
37
+ })
38
+ });
39
+ const raw = await res.json().catch(() => ({}));
40
+ const data = raw && typeof raw === "object" ? raw : {};
41
+ if (!res.ok) {
42
+ return {
43
+ success: false,
44
+ error: data.error ?? `HTTP ${res.status}`,
45
+ code: data.code
46
+ };
47
+ }
48
+ return { success: true, id: data.id };
49
+ } catch (err) {
50
+ return {
51
+ success: false,
52
+ error: err instanceof Error ? err.message : "Network error",
53
+ code: "network_error"
54
+ };
55
+ }
56
+ }
57
+ export {
58
+ sendEmail
59
+ };
60
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/email/sendEmail.ts"],"sourcesContent":["/**\r\n * SDK sendEmail (B1).\r\n *\r\n * Routes to /api/project-email/send using the SERVER-class project token.\r\n *\r\n * BEFORE B1, this function read the Supabase auth session and sent the\r\n * resulting JWT as `Authorization: Bearer`. The server endpoint expected\r\n * the project token (ezc_) — they never matched, so every send returned 401.\r\n *\r\n * AFTER B1:\r\n * - Reads EZC_PROJECT_TOKEN_SERVER from server-side env.\r\n * - Sends via `X-EzCoder-Server-Token` header.\r\n * - Refuses to run from browser bundles with a clear, actionable error.\r\n * - Falls back to the legacy single-class token through Phase 1, with a\r\n * one-shot deprecation warning.\r\n */\r\n\r\nimport { env } from '../core/config';\r\nimport { resolveServerToken } from '../core/projectToken';\r\n\r\ninterface SendEmailOptions {\r\n from?: string;\r\n text?: string;\r\n}\r\n\r\ninterface SendEmailResult {\r\n success: boolean;\r\n id?: string;\r\n error?: string;\r\n code?: string;\r\n}\r\n\r\nexport async function sendEmail(\r\n to: string,\r\n subject: string,\r\n html: string,\r\n options: SendEmailOptions = {},\r\n): Promise<SendEmailResult> {\r\n const apiUrl = env.EZCODER_API_URL;\r\n const projectId = env.EZC_PROJECT_ID;\r\n\r\n if (!apiUrl || !projectId) {\r\n return {\r\n success: false,\r\n error: 'EZCODER_API_URL and EZC_PROJECT_ID are required',\r\n code: 'sdk_misconfigured',\r\n };\r\n }\r\n\r\n const tokenResolution = resolveServerToken();\r\n if (!tokenResolution.ok) {\r\n return { success: false, error: tokenResolution.reason, code: 'no_server_token' };\r\n }\r\n\r\n try {\r\n const res = await fetch(`${apiUrl}/api/project-email/send`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'X-EzCoder-Server-Token': tokenResolution.token,\r\n },\r\n body: JSON.stringify({\r\n projectId,\r\n to,\r\n subject,\r\n html,\r\n text: options.text,\r\n from: options.from,\r\n }),\r\n });\r\n\r\n const raw: unknown = await res.json().catch(() => ({}));\r\n const data = (raw && typeof raw === 'object' ? raw : {}) as {\r\n id?: string;\r\n error?: string;\r\n code?: string;\r\n };\r\n\r\n if (!res.ok) {\r\n return {\r\n success: false,\r\n error: data.error ?? `HTTP ${res.status}`,\r\n code: data.code,\r\n };\r\n }\r\n\r\n return { success: true, id: data.id };\r\n } catch (err: unknown) {\r\n return {\r\n success: false,\r\n error: err instanceof Error ? err.message : 'Network error',\r\n code: 'network_error',\r\n };\r\n }\r\n}\r\n"],"mappings":";;;;;;;;AAgCA,eAAsB,UACpB,IACA,SACA,MACA,UAA4B,CAAC,GACH;AAC1B,QAAM,SAAS,IAAI;AACnB,QAAM,YAAY,IAAI;AAEtB,MAAI,CAAC,UAAU,CAAC,WAAW;AACzB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,kBAAkB,mBAAmB;AAC3C,MAAI,CAAC,gBAAgB,IAAI;AACvB,WAAO,EAAE,SAAS,OAAO,OAAO,gBAAgB,QAAQ,MAAM,kBAAkB;AAAA,EAClF;AAEA,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,GAAG,MAAM,2BAA2B;AAAA,MAC1D,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,0BAA0B,gBAAgB;AAAA,MAC5C;AAAA,MACA,MAAM,KAAK,UAAU;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM,QAAQ;AAAA,QACd,MAAM,QAAQ;AAAA,MAChB,CAAC;AAAA,IACH,CAAC;AAED,UAAM,MAAe,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACtD,UAAM,OAAQ,OAAO,OAAO,QAAQ,WAAW,MAAM,CAAC;AAMtD,QAAI,CAAC,IAAI,IAAI;AACX,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,KAAK,SAAS,QAAQ,IAAI,MAAM;AAAA,QACvC,MAAM,KAAK;AAAA,MACb;AAAA,IACF;AAEA,WAAO,EAAE,SAAS,MAAM,IAAI,KAAK,GAAG;AAAA,EACtC,SAAS,KAAc;AACrB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,eAAe,QAAQ,IAAI,UAAU;AAAA,MAC5C,MAAM;AAAA,IACR;AAAA,EACF;AACF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/errors/ErrorBoundary.tsx"],"sourcesContent":["import { Component } from 'react';\nimport type { ErrorInfo, ReactNode } from 'react';\n\ninterface ErrorBoundaryProps {\n children: ReactNode;\n fallback?: ReactNode | ((error: Error) => ReactNode);\n}\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n}\n\nexport class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false, error: null };\n }\n\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: ErrorInfo): void {\n void errorInfo;\n void error;\n }\n\n render() {\n if (this.state.hasError && this.state.error) {\n if (typeof this.props.fallback === 'function') {\n return this.props.fallback(this.state.error);\n }\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n return (\n <div style={{ padding: '40px', textAlign: 'center' }}>\n <h2 style={{ fontSize: '1.5rem', fontWeight: 600, color: '#dc2626', marginBottom: '8px' }}>\n Something went wrong\n </h2>\n <p style={{ color: '#6b7280', marginBottom: '16px' }}>\n {this.state.error.message}\n </p>\n <button\n onClick={() => this.setState({ hasError: false, error: null })}\n style={{\n padding: '8px 16px', backgroundColor: '#3b82f6', color: 'white',\n border: 'none', borderRadius: '6px', cursor: 'pointer', marginRight: '8px',\n }}\n >\n Try Again\n </button>\n <a href=\"/\" style={{ padding: '8px 16px', color: '#3b82f6', textDecoration: 'none' }}>\n Go Home\n </a>\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n\nexport function NotFoundPage() {\n return (\n <div style={{ textAlign: 'center', padding: '80px 20px' }}>\n <h1 style={{ fontSize: '4rem', fontWeight: 700, color: '#d1d5db', marginBottom: '8px' }}>404</h1>\n <h2 style={{ fontSize: '1.5rem', fontWeight: 600, marginBottom: '8px' }}>Page Not Found</h2>\n <p style={{ color: '#6b7280', marginBottom: '24px' }}>The page you&apos;re looking for doesn&apos;t exist.</p>\n <a href=\"/\" style={{ color: '#3b82f6', textDecoration: 'none', fontWeight: 500 }}>Go Home</a>\n </div>\n );\n}\n"],"mappings":";AAAA,SAAS,iBAAiB;AAsClB,SACE,KADF;AAzBD,IAAM,gBAAN,cAA4B,UAAkD;AAAA,EACnF,YAAY,OAA2B;AACrC,UAAM,KAAK;AACX,SAAK,QAAQ,EAAE,UAAU,OAAO,OAAO,KAAK;AAAA,EAC9C;AAAA,EAEA,OAAO,yBAAyB,OAAkC;AAChE,WAAO,EAAE,UAAU,MAAM,MAAM;AAAA,EACjC;AAAA,EAEA,kBAAkB,OAAc,WAA4B;AAC1D,SAAK;AACL,SAAK;AAAA,EACP;AAAA,EAEA,SAAS;AACP,QAAI,KAAK,MAAM,YAAY,KAAK,MAAM,OAAO;AAC3C,UAAI,OAAO,KAAK,MAAM,aAAa,YAAY;AAC7C,eAAO,KAAK,MAAM,SAAS,KAAK,MAAM,KAAK;AAAA,MAC7C;AACA,UAAI,KAAK,MAAM,UAAU;AACvB,eAAO,KAAK,MAAM;AAAA,MACpB;AAEA,aACE,qBAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,WAAW,SAAS,GACjD;AAAA,4BAAC,QAAG,OAAO,EAAE,UAAU,UAAU,YAAY,KAAK,OAAO,WAAW,cAAc,MAAM,GAAG,kCAE3F;AAAA,QACA,oBAAC,OAAE,OAAO,EAAE,OAAO,WAAW,cAAc,OAAO,GAChD,eAAK,MAAM,MAAM,SACpB;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,MAAM,KAAK,SAAS,EAAE,UAAU,OAAO,OAAO,KAAK,CAAC;AAAA,YAC7D,OAAO;AAAA,cACL,SAAS;AAAA,cAAY,iBAAiB;AAAA,cAAW,OAAO;AAAA,cACxD,QAAQ;AAAA,cAAQ,cAAc;AAAA,cAAO,QAAQ;AAAA,cAAW,aAAa;AAAA,YACvE;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QACA,oBAAC,OAAE,MAAK,KAAI,OAAO,EAAE,SAAS,YAAY,OAAO,WAAW,gBAAgB,OAAO,GAAG,qBAEtF;AAAA,SACF;AAAA,IAEJ;AAEA,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;AAEO,SAAS,eAAe;AAC7B,SACE,qBAAC,SAAI,OAAO,EAAE,WAAW,UAAU,SAAS,YAAY,GACtD;AAAA,wBAAC,QAAG,OAAO,EAAE,UAAU,QAAQ,YAAY,KAAK,OAAO,WAAW,cAAc,MAAM,GAAG,iBAAG;AAAA,IAC5F,oBAAC,QAAG,OAAO,EAAE,UAAU,UAAU,YAAY,KAAK,cAAc,MAAM,GAAG,4BAAc;AAAA,IACvF,oBAAC,OAAE,OAAO,EAAE,OAAO,WAAW,cAAc,OAAO,GAAG,wDAAoD;AAAA,IAC1G,oBAAC,OAAE,MAAK,KAAI,OAAO,EAAE,OAAO,WAAW,gBAAgB,QAAQ,YAAY,IAAI,GAAG,qBAAO;AAAA,KAC3F;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/errors/ErrorBoundary.tsx"],"sourcesContent":["import { Component } from 'react';\r\nimport type { ErrorInfo, ReactNode } from 'react';\r\n\r\ninterface ErrorBoundaryProps {\r\n children: ReactNode;\r\n fallback?: ReactNode | ((error: Error) => ReactNode);\r\n}\r\n\r\ninterface ErrorBoundaryState {\r\n hasError: boolean;\r\n error: Error | null;\r\n}\r\n\r\nexport class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\r\n constructor(props: ErrorBoundaryProps) {\r\n super(props);\r\n this.state = { hasError: false, error: null };\r\n }\r\n\r\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\r\n return { hasError: true, error };\r\n }\r\n\r\n componentDidCatch(error: Error, errorInfo: ErrorInfo): void {\r\n void errorInfo;\r\n void error;\r\n }\r\n\r\n render() {\r\n if (this.state.hasError && this.state.error) {\r\n if (typeof this.props.fallback === 'function') {\r\n return this.props.fallback(this.state.error);\r\n }\r\n if (this.props.fallback) {\r\n return this.props.fallback;\r\n }\r\n\r\n return (\r\n <div style={{ padding: '40px', textAlign: 'center' }}>\r\n <h2 style={{ fontSize: '1.5rem', fontWeight: 600, color: '#dc2626', marginBottom: '8px' }}>\r\n Something went wrong\r\n </h2>\r\n <p style={{ color: '#6b7280', marginBottom: '16px' }}>\r\n {this.state.error.message}\r\n </p>\r\n <button\r\n onClick={() => this.setState({ hasError: false, error: null })}\r\n style={{\r\n padding: '8px 16px', backgroundColor: '#3b82f6', color: 'white',\r\n border: 'none', borderRadius: '6px', cursor: 'pointer', marginRight: '8px',\r\n }}\r\n >\r\n Try Again\r\n </button>\r\n <a href=\"/\" style={{ padding: '8px 16px', color: '#3b82f6', textDecoration: 'none' }}>\r\n Go Home\r\n </a>\r\n </div>\r\n );\r\n }\r\n\r\n return this.props.children;\r\n }\r\n}\r\n\r\nexport function NotFoundPage() {\r\n return (\r\n <div style={{ textAlign: 'center', padding: '80px 20px' }}>\r\n <h1 style={{ fontSize: '4rem', fontWeight: 700, color: '#d1d5db', marginBottom: '8px' }}>404</h1>\r\n <h2 style={{ fontSize: '1.5rem', fontWeight: 600, marginBottom: '8px' }}>Page Not Found</h2>\r\n <p style={{ color: '#6b7280', marginBottom: '24px' }}>The page you&apos;re looking for doesn&apos;t exist.</p>\r\n <a href=\"/\" style={{ color: '#3b82f6', textDecoration: 'none', fontWeight: 500 }}>Go Home</a>\r\n </div>\r\n );\r\n}\r\n"],"mappings":";AAAA,SAAS,iBAAiB;AAsClB,SACE,KADF;AAzBD,IAAM,gBAAN,cAA4B,UAAkD;AAAA,EACnF,YAAY,OAA2B;AACrC,UAAM,KAAK;AACX,SAAK,QAAQ,EAAE,UAAU,OAAO,OAAO,KAAK;AAAA,EAC9C;AAAA,EAEA,OAAO,yBAAyB,OAAkC;AAChE,WAAO,EAAE,UAAU,MAAM,MAAM;AAAA,EACjC;AAAA,EAEA,kBAAkB,OAAc,WAA4B;AAC1D,SAAK;AACL,SAAK;AAAA,EACP;AAAA,EAEA,SAAS;AACP,QAAI,KAAK,MAAM,YAAY,KAAK,MAAM,OAAO;AAC3C,UAAI,OAAO,KAAK,MAAM,aAAa,YAAY;AAC7C,eAAO,KAAK,MAAM,SAAS,KAAK,MAAM,KAAK;AAAA,MAC7C;AACA,UAAI,KAAK,MAAM,UAAU;AACvB,eAAO,KAAK,MAAM;AAAA,MACpB;AAEA,aACE,qBAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,WAAW,SAAS,GACjD;AAAA,4BAAC,QAAG,OAAO,EAAE,UAAU,UAAU,YAAY,KAAK,OAAO,WAAW,cAAc,MAAM,GAAG,kCAE3F;AAAA,QACA,oBAAC,OAAE,OAAO,EAAE,OAAO,WAAW,cAAc,OAAO,GAChD,eAAK,MAAM,MAAM,SACpB;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,MAAM,KAAK,SAAS,EAAE,UAAU,OAAO,OAAO,KAAK,CAAC;AAAA,YAC7D,OAAO;AAAA,cACL,SAAS;AAAA,cAAY,iBAAiB;AAAA,cAAW,OAAO;AAAA,cACxD,QAAQ;AAAA,cAAQ,cAAc;AAAA,cAAO,QAAQ;AAAA,cAAW,aAAa;AAAA,YACvE;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QACA,oBAAC,OAAE,MAAK,KAAI,OAAO,EAAE,SAAS,YAAY,OAAO,WAAW,gBAAgB,OAAO,GAAG,qBAEtF;AAAA,SACF;AAAA,IAEJ;AAEA,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;AAEO,SAAS,eAAe;AAC7B,SACE,qBAAC,SAAI,OAAO,EAAE,WAAW,UAAU,SAAS,YAAY,GACtD;AAAA,wBAAC,QAAG,OAAO,EAAE,UAAU,QAAQ,YAAY,KAAK,OAAO,WAAW,cAAc,MAAM,GAAG,iBAAG;AAAA,IAC5F,oBAAC,QAAG,OAAO,EAAE,UAAU,UAAU,YAAY,KAAK,cAAc,MAAM,GAAG,4BAAc;AAAA,IACvF,oBAAC,OAAE,OAAO,EAAE,OAAO,WAAW,cAAc,OAAO,GAAG,wDAAoD;AAAA,IAC1G,oBAAC,OAAE,MAAK,KAAI,OAAO,EAAE,OAAO,WAAW,gBAAgB,QAAQ,YAAY,IAAI,GAAG,qBAAO;AAAA,KAC3F;AAEJ;","names":[]}