@wecode-team/cms-supabase-api 0.1.29

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.
@@ -0,0 +1,39 @@
1
+ import { CmsModelAttributes, CmsModelCreationAttributes } from "../types";
2
+ declare class CmsModelService {
3
+ private supabase;
4
+ private tableName;
5
+ constructor();
6
+ /**
7
+ * 创建新的CMS模型
8
+ */
9
+ create(data: CmsModelCreationAttributes): Promise<CmsModelAttributes>;
10
+ /**
11
+ * 根据ID获取模型
12
+ */
13
+ findById(id: number): Promise<CmsModelAttributes | null>;
14
+ /**
15
+ * 根据表名获取模型
16
+ */
17
+ findByTableName(tableName: string): Promise<CmsModelAttributes | null>;
18
+ /**
19
+ * 获取所有模型
20
+ */
21
+ findAll(): Promise<CmsModelAttributes[]>;
22
+ /**
23
+ * 更新模型
24
+ */
25
+ update(id: number, data: Partial<CmsModelCreationAttributes>): Promise<CmsModelAttributes>;
26
+ /**
27
+ * 删除模型
28
+ */
29
+ delete(id: number): Promise<boolean>;
30
+ }
31
+ /**
32
+ * 获取CMS模型服务实例
33
+ */
34
+ export declare function getCmsModelService(): CmsModelService;
35
+ /**
36
+ * 初始化 CMS 模型表
37
+ */
38
+ export declare function initializeCmsModel(): Promise<boolean>;
39
+ export default CmsModelService;
@@ -0,0 +1,80 @@
1
+ export interface User {
2
+ id: number;
3
+ username: string;
4
+ password_hash: string;
5
+ role: string;
6
+ created_at: string;
7
+ updated_at: string;
8
+ }
9
+ export interface UserInfo {
10
+ id: number;
11
+ username: string;
12
+ role: string;
13
+ created_at: string;
14
+ updated_at: string;
15
+ }
16
+ export declare class AuthService {
17
+ private supabase;
18
+ private defaultTableName;
19
+ constructor();
20
+ /**
21
+ * 根据用户名查询用户
22
+ */
23
+ findUserByUsername(username: string, tableName?: string): Promise<User | null>;
24
+ /**
25
+ * 根据用户ID查询用户信息(不包含密码)
26
+ */
27
+ findUserById(userId: number, tableName?: string): Promise<UserInfo | null>;
28
+ /**
29
+ * 检查用户名是否存在
30
+ */
31
+ checkUsernameExists(username: string, tableName?: string): Promise<boolean>;
32
+ /**
33
+ * 创建新用户
34
+ */
35
+ createUser(userData: {
36
+ tableName?: string;
37
+ username: string;
38
+ password_hash: string;
39
+ role?: string;
40
+ }): Promise<UserInfo>;
41
+ /**
42
+ * 更新用户信息
43
+ */
44
+ updateUser(userId: number, updateData?: {
45
+ username?: string;
46
+ password_hash?: string;
47
+ role?: string;
48
+ tableName?: string;
49
+ }): Promise<UserInfo>;
50
+ /**
51
+ * 删除用户
52
+ */
53
+ deleteUser(userId: number, tableName?: string): Promise<boolean>;
54
+ /**
55
+ * 获取所有用户列表(分页)
56
+ */
57
+ getUserList(page?: number, limit?: number, tableName?: string): Promise<{
58
+ data: UserInfo[];
59
+ total: number;
60
+ page: number;
61
+ limit: number;
62
+ totalPages: number;
63
+ }>;
64
+ /**
65
+ * 搜索用户(按用户名)
66
+ */
67
+ searchUsers(searchValue: string, page?: number, limit?: number, tableName?: string): Promise<{
68
+ data: UserInfo[];
69
+ total: number;
70
+ page: number;
71
+ limit: number;
72
+ totalPages: number;
73
+ }>;
74
+ /**
75
+ * 更新用户最后登录时间(如果需要记录的话)
76
+ */
77
+ updateLastLogin(userId: number, tableName?: string): Promise<void>;
78
+ }
79
+ export declare function getAuthService(): AuthService;
80
+ export default AuthService;
@@ -0,0 +1,92 @@
1
+ import { JsonSchema, PaginatedResponse, SchemaField, RelationOption, GetRelationOptionsParams, SupabaseFilter } from "../types";
2
+ export declare class DynamicTableService {
3
+ private supabase;
4
+ constructor();
5
+ private applySupabaseFilters;
6
+ /**
7
+ * 从完整表名中提取前缀
8
+ * 例如: "jjj231122a342_posts" -> "jjj231122a342_"
9
+ * 例如: "posts" -> ""
10
+ */
11
+ private extractTablePrefix;
12
+ /**
13
+ * 根据 JSON 模式创建数据表
14
+ * @param tableName 完整表名(可能包含前缀,如 "jjj231122a342_posts")
15
+ * @param schema JSON Schema
16
+ * @param baseTableName 可选,基础表名(不含前缀,如 "posts"),用于计算前缀
17
+ */
18
+ createTable(tableName: string, schema: JsonSchema, baseTableName?: string): Promise<boolean>;
19
+ /**
20
+ * 删除数据表
21
+ */
22
+ dropTable(tableName: string): Promise<boolean>;
23
+ /**
24
+ * 删除表的所有外键约束
25
+ * 用于解决外键约束引用错误表的问题
26
+ */
27
+ dropAllForeignKeys(tableName: string): Promise<boolean>;
28
+ /**
29
+ * 根据约束名直接删除外键约束
30
+ */
31
+ dropForeignKeyByName(tableName: string, constraintName: string): Promise<boolean>;
32
+ /**
33
+ * 删除指定的外键约束
34
+ */
35
+ dropForeignKey(tableName: string, constraintName: string): Promise<boolean>;
36
+ /**
37
+ * 检查表是否存在
38
+ */
39
+ tableExists(tableName: string): Promise<boolean>;
40
+ /**
41
+ * 获取表结构
42
+ */
43
+ getTableStructure(tableName: string): Promise<any>;
44
+ /**
45
+ * 执行原生 SQL 查询
46
+ */
47
+ executeQuery(sql: string, values?: any[]): Promise<any>;
48
+ /**
49
+ * 获取表数据(分页)
50
+ */
51
+ getTableData(tableName: string, page?: number, limit?: number, where?: string, filters?: SupabaseFilter[]): Promise<PaginatedResponse>;
52
+ /**
53
+ * 获取表数据(分页,带搜索)
54
+ */
55
+ getTableDataWithSearch(tableName: string, page: number | undefined, limit: number | undefined, searchableFields: string[], searchValue: string, filters?: SupabaseFilter[]): Promise<PaginatedResponse>;
56
+ /**
57
+ * 插入数据
58
+ */
59
+ insertData(tableName: string, data: Record<string, any>, autoFixForeignKey?: boolean): Promise<Record<string, any>>;
60
+ /**
61
+ * 更新数据
62
+ * @param id 支持整数和 UUID 字符串
63
+ */
64
+ updateData(tableName: string, id: number | string, data: Record<string, any>, autoFixForeignKey?: boolean): Promise<Record<string, any>>;
65
+ /**
66
+ * 删除数据
67
+ * @param id 支持整数和 UUID 字符串
68
+ */
69
+ deleteData(tableName: string, id: number | string): Promise<any>;
70
+ /**
71
+ * 根据 ID 获取单条数据
72
+ * @param id 支持整数和 UUID 字符串
73
+ */
74
+ getDataById(tableName: string, id: number | string): Promise<any>;
75
+ /**
76
+ * 获取关联表选项列表 (用于下拉选择)
77
+ * @param params 查询参数
78
+ * @returns 选项列表
79
+ */
80
+ getRelationOptions(params: GetRelationOptionsParams): Promise<RelationOption[]>;
81
+ /**
82
+ * 获取表数据(带关联数据)
83
+ * @param tableName 表名
84
+ * @param schema JSON Schema (包含关系定义)
85
+ * @param page 页码
86
+ * @param limit 每页数量
87
+ * @returns 分页数据(包含关联数据)
88
+ */
89
+ getTableDataWithRelations(tableName: string, schema: SchemaField[], page?: number, limit?: number): Promise<PaginatedResponse>;
90
+ }
91
+ export declare function getDynamicTableService(): DynamicTableService;
92
+ export default DynamicTableService;
@@ -0,0 +1,127 @@
1
+ export type RelationType = 'belongsTo' | 'hasMany' | 'belongsToMany';
2
+ export interface RelationConfig {
3
+ /**
4
+ * 关系类型
5
+ * - belongsTo: 多对一,当前表存储外键 (如:文章表的 author_id 关联作者表)
6
+ * - hasMany: 一对多,目标表存储外键 (如:作者表关联多篇文章)
7
+ * - belongsToMany: 多对多,需要中间表 (如:文章和标签)
8
+ */
9
+ type: RelationType;
10
+ /**
11
+ * 目标表名
12
+ */
13
+ target: string;
14
+ /**
15
+ * 外键字段名
16
+ * - belongsTo: 当前表中的外键字段,默认为 ${target}_id
17
+ * - hasMany: 目标表中的外键字段,默认为 ${currentTable}_id
18
+ */
19
+ foreignKey?: string;
20
+ /**
21
+ * 目标表的主键字段,默认为 'id'
22
+ */
23
+ targetKey?: string;
24
+ /**
25
+ * 多对多关系的中间表名 (仅 belongsToMany 需要)
26
+ */
27
+ through?: string;
28
+ /**
29
+ * 用于下拉选项显示的字段名,默认为 'name' 或 'title'
30
+ */
31
+ displayField?: string;
32
+ /**
33
+ * 是否在列表中显示关联数据
34
+ */
35
+ showInList?: boolean;
36
+ }
37
+ export interface SchemaField {
38
+ name: string;
39
+ /**
40
+ * 字段类型
41
+ * - 基础类型: string, text, integer, float, boolean, date, datetime, json, jsonb, email
42
+ * - 关系类型: relation (需要配置 relation 属性)
43
+ */
44
+ type: string;
45
+ required?: boolean;
46
+ unique?: boolean;
47
+ maxLength?: number;
48
+ defaultValue?: any;
49
+ comment?: string;
50
+ /**
51
+ * 关系配置 (当 type 为 'relation' 时必填)
52
+ */
53
+ relation?: RelationConfig;
54
+ }
55
+ export interface JsonSchema {
56
+ fields: SchemaField[];
57
+ }
58
+ export interface CmsModelAttributes {
59
+ id: number;
60
+ name: string;
61
+ table_name: string;
62
+ json_schema: JsonSchema;
63
+ created_at: Date;
64
+ updated_at: Date;
65
+ }
66
+ export interface CmsModelCreationAttributes {
67
+ name: string;
68
+ table_name: string;
69
+ json_schema: JsonSchema;
70
+ }
71
+ export interface ApiResponse<T = any> {
72
+ success: boolean;
73
+ message?: string;
74
+ data?: T;
75
+ error?: string;
76
+ }
77
+ export interface PaginatedResponse<T = any> {
78
+ data: T[];
79
+ total: number;
80
+ page: number;
81
+ limit: number;
82
+ totalPages: number;
83
+ }
84
+ export interface SupabaseConfig {
85
+ url: string;
86
+ key: string;
87
+ schema?: string;
88
+ }
89
+ export interface DatabaseConfig extends SupabaseConfig {
90
+ }
91
+ export interface TableDataOptions {
92
+ page?: number;
93
+ limit?: number;
94
+ search?: string;
95
+ where?: string;
96
+ orderBy?: string;
97
+ ascending?: boolean;
98
+ }
99
+ export interface SupabaseFilter {
100
+ column: string;
101
+ operator: "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "like" | "ilike" | "in" | "is";
102
+ value: any;
103
+ }
104
+ export interface FieldTypeMapping {
105
+ string: "text";
106
+ text: "text";
107
+ integer: "int4";
108
+ float: "float8";
109
+ boolean: "bool";
110
+ date: "date";
111
+ datetime: "timestamptz";
112
+ json: "jsonb";
113
+ jsonb: "jsonb";
114
+ email: "text";
115
+ relation: "int4";
116
+ }
117
+ export interface RelationOption {
118
+ id: number | string;
119
+ label: string;
120
+ [key: string]: any;
121
+ }
122
+ export interface GetRelationOptionsParams {
123
+ tableName: string;
124
+ displayField?: string;
125
+ limit?: number;
126
+ search?: string;
127
+ }
@@ -0,0 +1,14 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ export declare function normalizeSessionId(sessionId: string | null | undefined): string;
3
+ /**
4
+ * 从前端传来的 auth tableName 中提取 session_id
5
+ * 约定:auth tableName 形如 `${sessionId}_cms_users`;无前缀则为 `cms_users`
6
+ */
7
+ export declare function extractSessionIdFromAuthTableName(tableName: string): string;
8
+ export declare function ensureAdminRegistryTable(supabase: SupabaseClient): Promise<boolean>;
9
+ export declare function getSessionAdminRow(supabase: SupabaseClient, sessionId: string): Promise<{
10
+ session_id: string;
11
+ user_id: string;
12
+ email?: string | null;
13
+ } | null>;
14
+ export declare function isUserSessionAdmin(supabase: SupabaseClient, sessionId: string, userId: string): Promise<boolean>;
@@ -0,0 +1,56 @@
1
+ import { UserInfo } from "../services/auth.service";
2
+ /**
3
+ * 认证工具类 - 处理JWT、密码验证等通用逻辑
4
+ */
5
+ export declare class AuthUtils {
6
+ /**
7
+ * 生成JWT token
8
+ */
9
+ static generateToken(user: UserInfo): string;
10
+ /**
11
+ * 验证JWT token
12
+ */
13
+ static verifyToken(token: string): any;
14
+ /**
15
+ * 验证密码
16
+ */
17
+ static validatePassword(plainPassword: string, hashedPassword: string): Promise<boolean>;
18
+ /**
19
+ * 加密密码
20
+ */
21
+ static hashPassword(password: string): Promise<string>;
22
+ /**
23
+ * 从请求头中提取和验证token
24
+ */
25
+ static extractTokenFromHeader(authHeader: string | null): string | null;
26
+ /**
27
+ * 获取AuthService实例
28
+ */
29
+ static getAuthService(): import("../services/auth.service").AuthService;
30
+ /**
31
+ * 验证用户登录
32
+ */
33
+ static authenticateUser(username: string, password: string, tableName: string): Promise<{
34
+ success: boolean;
35
+ message: string;
36
+ user?: undefined;
37
+ } | {
38
+ success: boolean;
39
+ user: UserInfo;
40
+ message?: undefined;
41
+ }>;
42
+ /**
43
+ * 验证并获取用户信息
44
+ */
45
+ static verifyTokenAndGetUser(token: string, tableName: string): Promise<{
46
+ success: boolean;
47
+ message: string;
48
+ user?: undefined;
49
+ decoded?: undefined;
50
+ } | {
51
+ success: boolean;
52
+ user: UserInfo;
53
+ decoded: any;
54
+ message?: undefined;
55
+ }>;
56
+ }
@@ -0,0 +1,7 @@
1
+ import { Hono } from "hono";
2
+ export declare function createModelRoute(app: Hono): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ export declare function createDataRoute(app: Hono, tableName: string): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
4
+ export declare function createDynamicDataRoute(app: Hono): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
5
+ export declare function createDynamicAuthRoute(app: Hono): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
6
+ export declare function createAuthRoute(app: Hono, tableName: string): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
7
+ export declare function createCmsRoutes(app: Hono): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
@@ -0,0 +1,7 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ export declare function ensureUserRegistryTable(supabase: SupabaseClient): Promise<boolean>;
3
+ export declare function isUsernameTaken(supabase: SupabaseClient, sessionId: string, username: string): Promise<boolean>;
4
+ export declare function registerUsername(supabase: SupabaseClient, sessionId: string, username: string, userId: string): Promise<{
5
+ ok: boolean;
6
+ conflict?: boolean;
7
+ }>;
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@wecode-team/cms-supabase-api",
3
+ "version": "0.1.29",
4
+ "description": "A CMS API package using Hono framework with Supabase and dynamic table management",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.esm.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "require": "./dist/index.js",
12
+ "import": "./dist/index.esm.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "supabase-setup.sql",
18
+ "README.md",
19
+ "USAGE_EXAMPLE.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "rollup -c --bundleConfigAsCjs",
23
+ "prepublishOnly": "npm run build",
24
+ "dev": "tsx server.ts",
25
+ "start": "node --loader tsx server.ts",
26
+ "dev:all": "./start-dev.sh",
27
+ "publish:public": "npm run build && npm publish --registry https://registry.npmjs.org/ --access public --ignore-scripts",
28
+ "publish:private": "npm run build && npm publish --registry https://packages.aliyun.com/691ae90ae6c3e0425dbdc56f/npm/npm-registry/ --access public --ignore-scripts",
29
+ "publish:all": "npm run build && npm publish --registry https://registry.npmjs.org/ --access public --ignore-scripts && npm publish --registry https://packages.aliyun.com/691ae90ae6c3e0425dbdc56f/npm/npm-registry/ --access public --ignore-scripts",
30
+ "test": "echo \"Error: no test specified\" && exit 1"
31
+ },
32
+ "keywords": [
33
+ "cms",
34
+ "api",
35
+ "hono",
36
+ "supabase",
37
+ "postgresql",
38
+ "dynamic-table"
39
+ ],
40
+ "author": "wecode-team",
41
+ "license": "MIT",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "https://github.com/wecode-team/wequicksandbox.git",
45
+ "directory": "packages/cms-supabase-api"
46
+ },
47
+ "publishConfig": {
48
+ "access": "public",
49
+ "registry": "https://registry.npmjs.org/"
50
+ },
51
+ "dependencies": {
52
+ "@babel/runtime": "^7.22.5",
53
+ "jsonwebtoken": "^9.0.2",
54
+ "bcryptjs": "^2.4.3"
55
+ },
56
+ "peerDependencies": {
57
+ "@supabase/supabase-js": "^2.0.0",
58
+ "hono": "^4.0.0"
59
+ },
60
+ "devDependencies": {
61
+ "@babel/core": "^7.22.5",
62
+ "@babel/plugin-transform-runtime": "^7.22.5",
63
+ "@babel/preset-env": "^7.22.5",
64
+ "@babel/preset-typescript": "^7.22.5",
65
+ "@hono/node-server": "^1.12.0",
66
+ "@rollup/plugin-babel": "^6.0.3",
67
+ "@rollup/plugin-commonjs": "^25.0.0",
68
+ "@rollup/plugin-json": "^6.1.0",
69
+ "@rollup/plugin-node-resolve": "^15.1.0",
70
+ "@rollup/plugin-typescript": "^11.1.1",
71
+ "@supabase/supabase-js": "^2.52.1",
72
+ "@types/bcryptjs": "^2.4.6",
73
+ "@types/jsonwebtoken": "^9.0.5",
74
+ "@types/node": "^20.0.0",
75
+ "hono": "^4.0.0",
76
+ "rollup": "^3.25.1",
77
+ "tsx": "^4.21.0",
78
+ "typescript": "^5.1.3"
79
+ }
80
+ }
@@ -0,0 +1,151 @@
1
+ -- Supabase Setup SQL for we0-cms-supabase-hono-api
2
+ -- Execute this SQL in your Supabase SQL Editor to set up the required functions
3
+
4
+ -- Function to execute SQL queries
5
+ CREATE OR REPLACE FUNCTION execute_sql(sql_query text)
6
+ RETURNS json
7
+ LANGUAGE plpgsql
8
+ SECURITY DEFINER
9
+ AS $$
10
+ DECLARE
11
+ result json;
12
+ row_count integer;
13
+ BEGIN
14
+ EXECUTE sql_query;
15
+ GET DIAGNOSTICS row_count = ROW_COUNT;
16
+ RETURN json_build_object('success', true, 'rows_affected', row_count);
17
+ EXCEPTION
18
+ WHEN OTHERS THEN
19
+ RETURN json_build_object('success', false, 'error', SQLERRM);
20
+ END;
21
+ $$;
22
+
23
+ -- Function to execute SQL with parameters (simplified version)
24
+ CREATE OR REPLACE FUNCTION execute_sql_with_params(sql_query text, params json)
25
+ RETURNS json
26
+ LANGUAGE plpgsql
27
+ SECURITY DEFINER
28
+ AS $$
29
+ DECLARE
30
+ result json;
31
+ row_count integer;
32
+ BEGIN
33
+ -- Note: This is a simplified version for basic use cases
34
+ -- In production, you might want more sophisticated parameter binding
35
+ EXECUTE sql_query;
36
+ GET DIAGNOSTICS row_count = ROW_COUNT;
37
+ RETURN json_build_object('success', true, 'rows_affected', row_count);
38
+ EXCEPTION
39
+ WHEN OTHERS THEN
40
+ RETURN json_build_object('success', false, 'error', SQLERRM);
41
+ END;
42
+ $$;
43
+
44
+ -- Function to check if table exists
45
+ CREATE OR REPLACE FUNCTION check_table_exists(input_table_name text)
46
+ RETURNS boolean
47
+ LANGUAGE plpgsql
48
+ SECURITY DEFINER
49
+ AS $$
50
+ BEGIN
51
+ RETURN EXISTS (
52
+ SELECT 1 FROM information_schema.tables
53
+ WHERE table_schema = 'public'
54
+ AND table_name = input_table_name
55
+ );
56
+ END;
57
+ $$;
58
+
59
+ -- Function to get table structure
60
+ CREATE OR REPLACE FUNCTION get_table_structure(table_name text)
61
+ RETURNS json
62
+ LANGUAGE plpgsql
63
+ SECURITY DEFINER
64
+ AS $$
65
+ DECLARE
66
+ result json;
67
+ BEGIN
68
+ SELECT json_agg(
69
+ json_build_object(
70
+ 'column_name', column_name,
71
+ 'data_type', data_type,
72
+ 'is_nullable', is_nullable,
73
+ 'column_default', column_default,
74
+ 'character_maximum_length', character_maximum_length
75
+ )
76
+ ) INTO result
77
+ FROM information_schema.columns
78
+ WHERE table_schema = 'public' AND table_name = $1
79
+ ORDER BY ordinal_position;
80
+
81
+ RETURN COALESCE(result, '[]'::json);
82
+ END;
83
+ $$;
84
+
85
+ -- Function to create CMS models table if not exists
86
+ CREATE OR REPLACE FUNCTION create_cms_models_table_if_not_exists()
87
+ RETURNS json
88
+ LANGUAGE plpgsql
89
+ SECURITY DEFINER
90
+ AS $$
91
+ BEGIN
92
+ -- Create the CMS models table
93
+ CREATE TABLE IF NOT EXISTS "_cms_models" (
94
+ id SERIAL PRIMARY KEY,
95
+ name VARCHAR(100) NOT NULL,
96
+ table_name VARCHAR(100) NOT NULL UNIQUE,
97
+ json_schema JSONB NOT NULL,
98
+ created_at TIMESTAMPTZ DEFAULT NOW(),
99
+ updated_at TIMESTAMPTZ DEFAULT NOW()
100
+ );
101
+
102
+ -- Create or replace the trigger function for updating timestamps
103
+ CREATE OR REPLACE FUNCTION update_updated_at_column()
104
+ RETURNS TRIGGER AS $trigger$
105
+ BEGIN
106
+ NEW.updated_at = NOW();
107
+ RETURN NEW;
108
+ END;
109
+ $trigger$ language 'plpgsql';
110
+
111
+ -- Drop existing trigger if it exists and create new one
112
+ DROP TRIGGER IF EXISTS update_cms_models_updated_at ON "_cms_models";
113
+ CREATE TRIGGER update_cms_models_updated_at
114
+ BEFORE UPDATE ON "_cms_models"
115
+ FOR EACH ROW
116
+ EXECUTE FUNCTION update_updated_at_column();
117
+
118
+ RETURN json_build_object('success', true, 'message', 'CMS models table created successfully');
119
+ EXCEPTION
120
+ WHEN OTHERS THEN
121
+ RETURN json_build_object('success', false, 'error', SQLERRM);
122
+ END;
123
+ $$;
124
+
125
+ -- Initialize the CMS models table
126
+ SELECT create_cms_models_table_if_not_exists ();
127
+
128
+ -- Grant necessary permissions (adjust as needed for your security requirements)
129
+ -- Note: Be careful with these permissions in production
130
+ GRANT USAGE ON SCHEMA public TO anon, authenticated;
131
+
132
+ GRANT ALL ON ALL TABLES IN SCHEMA public TO anon, authenticated;
133
+
134
+ GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO anon, authenticated;
135
+
136
+ GRANT ALL ON ALL FUNCTIONS IN SCHEMA public TO anon, authenticated;
137
+
138
+ -- Create RLS policies for the CMS models table (optional, adjust as needed)
139
+ ALTER TABLE "_cms_models" ENABLE ROW LEVEL SECURITY;
140
+
141
+ -- Allow all operations for all users (development environment)
142
+ CREATE POLICY "Allow all operations" ON "_cms_models" FOR ALL USING (true);
143
+
144
+ COMMENT ON
145
+ TABLE "_cms_models" IS 'CMS models configuration table for we0-cms-supabase-hono-api';
146
+
147
+ COMMENT ON FUNCTION execute_sql (text) IS 'Execute SQL queries for dynamic table management';
148
+
149
+ COMMENT ON FUNCTION check_table_exists (text) IS 'Check if a table exists in the public schema';
150
+
151
+ COMMENT ON FUNCTION get_table_structure (text) IS 'Get the structure of a table';