@nextblock-cms/db 0.14.5 → 0.14.6
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.
package/lib/supabase/server.d.ts
CHANGED
|
@@ -725,6 +725,45 @@ export declare const getServiceRoleSupabaseClient: () => import('@supabase/supab
|
|
|
725
725
|
referencedColumns: ["id"];
|
|
726
726
|
}];
|
|
727
727
|
};
|
|
728
|
+
mcp_access_tokens: {
|
|
729
|
+
Row: {
|
|
730
|
+
created_at: string;
|
|
731
|
+
created_by: string | null;
|
|
732
|
+
expires_at: string | null;
|
|
733
|
+
id: string;
|
|
734
|
+
last_used_at: string | null;
|
|
735
|
+
name: string;
|
|
736
|
+
revoked_at: string | null;
|
|
737
|
+
scopes: string[];
|
|
738
|
+
token_hash: string;
|
|
739
|
+
token_prefix: string;
|
|
740
|
+
};
|
|
741
|
+
Insert: {
|
|
742
|
+
created_at?: string;
|
|
743
|
+
created_by?: string | null;
|
|
744
|
+
expires_at?: string | null;
|
|
745
|
+
id?: string;
|
|
746
|
+
last_used_at?: string | null;
|
|
747
|
+
name: string;
|
|
748
|
+
revoked_at?: string | null;
|
|
749
|
+
scopes?: string[];
|
|
750
|
+
token_hash: string;
|
|
751
|
+
token_prefix: string;
|
|
752
|
+
};
|
|
753
|
+
Update: {
|
|
754
|
+
created_at?: string;
|
|
755
|
+
created_by?: string | null;
|
|
756
|
+
expires_at?: string | null;
|
|
757
|
+
id?: string;
|
|
758
|
+
last_used_at?: string | null;
|
|
759
|
+
name?: string;
|
|
760
|
+
revoked_at?: string | null;
|
|
761
|
+
scopes?: string[];
|
|
762
|
+
token_hash?: string;
|
|
763
|
+
token_prefix?: string;
|
|
764
|
+
};
|
|
765
|
+
Relationships: [];
|
|
766
|
+
};
|
|
728
767
|
media: {
|
|
729
768
|
Row: {
|
|
730
769
|
blur_data_url: string | null;
|
|
@@ -1523,6 +1562,48 @@ export declare const getServiceRoleSupabaseClient: () => import('@supabase/supab
|
|
|
1523
1562
|
referencedColumns: ["id"];
|
|
1524
1563
|
}];
|
|
1525
1564
|
};
|
|
1565
|
+
product_revisions: {
|
|
1566
|
+
Row: {
|
|
1567
|
+
author_id: string | null;
|
|
1568
|
+
content: import('./types').Json;
|
|
1569
|
+
created_at: string;
|
|
1570
|
+
id: number;
|
|
1571
|
+
product_id: string;
|
|
1572
|
+
revision_type: Database["public"]["Enums"]["revision_type"];
|
|
1573
|
+
version: number;
|
|
1574
|
+
};
|
|
1575
|
+
Insert: {
|
|
1576
|
+
author_id?: string | null;
|
|
1577
|
+
content: import('./types').Json;
|
|
1578
|
+
created_at?: string;
|
|
1579
|
+
id?: number;
|
|
1580
|
+
product_id: string;
|
|
1581
|
+
revision_type: Database["public"]["Enums"]["revision_type"];
|
|
1582
|
+
version: number;
|
|
1583
|
+
};
|
|
1584
|
+
Update: {
|
|
1585
|
+
author_id?: string | null;
|
|
1586
|
+
content?: import('./types').Json;
|
|
1587
|
+
created_at?: string;
|
|
1588
|
+
id?: number;
|
|
1589
|
+
product_id?: string;
|
|
1590
|
+
revision_type?: Database["public"]["Enums"]["revision_type"];
|
|
1591
|
+
version?: number;
|
|
1592
|
+
};
|
|
1593
|
+
Relationships: [{
|
|
1594
|
+
foreignKeyName: "product_revisions_author_id_fkey";
|
|
1595
|
+
columns: ["author_id"];
|
|
1596
|
+
isOneToOne: false;
|
|
1597
|
+
referencedRelation: "profiles";
|
|
1598
|
+
referencedColumns: ["id"];
|
|
1599
|
+
}, {
|
|
1600
|
+
foreignKeyName: "product_revisions_product_id_fkey";
|
|
1601
|
+
columns: ["product_id"];
|
|
1602
|
+
isOneToOne: false;
|
|
1603
|
+
referencedRelation: "products";
|
|
1604
|
+
referencedColumns: ["id"];
|
|
1605
|
+
}];
|
|
1606
|
+
};
|
|
1526
1607
|
product_variants: {
|
|
1527
1608
|
Row: {
|
|
1528
1609
|
created_at: string | null;
|
|
@@ -1636,6 +1717,7 @@ export declare const getServiceRoleSupabaseClient: () => import('@supabase/supab
|
|
|
1636
1717
|
trial_requires_payment_method: boolean;
|
|
1637
1718
|
upc: string | null;
|
|
1638
1719
|
updated_at: string | null;
|
|
1720
|
+
version: number;
|
|
1639
1721
|
};
|
|
1640
1722
|
Insert: {
|
|
1641
1723
|
average_rating?: number;
|
|
@@ -1674,6 +1756,7 @@ export declare const getServiceRoleSupabaseClient: () => import('@supabase/supab
|
|
|
1674
1756
|
trial_requires_payment_method?: boolean;
|
|
1675
1757
|
upc?: string | null;
|
|
1676
1758
|
updated_at?: string | null;
|
|
1759
|
+
version?: number;
|
|
1677
1760
|
};
|
|
1678
1761
|
Update: {
|
|
1679
1762
|
average_rating?: number;
|
|
@@ -1712,6 +1795,7 @@ export declare const getServiceRoleSupabaseClient: () => import('@supabase/supab
|
|
|
1712
1795
|
trial_requires_payment_method?: boolean;
|
|
1713
1796
|
upc?: string | null;
|
|
1714
1797
|
updated_at?: string | null;
|
|
1798
|
+
version?: number;
|
|
1715
1799
|
};
|
|
1716
1800
|
Relationships: [{
|
|
1717
1801
|
foreignKeyName: "products_language_id_fkey";
|
package/lib/supabase/types.d.ts
CHANGED
|
@@ -749,6 +749,45 @@ export type Database = {
|
|
|
749
749
|
}
|
|
750
750
|
];
|
|
751
751
|
};
|
|
752
|
+
mcp_access_tokens: {
|
|
753
|
+
Row: {
|
|
754
|
+
created_at: string;
|
|
755
|
+
created_by: string | null;
|
|
756
|
+
expires_at: string | null;
|
|
757
|
+
id: string;
|
|
758
|
+
last_used_at: string | null;
|
|
759
|
+
name: string;
|
|
760
|
+
revoked_at: string | null;
|
|
761
|
+
scopes: string[];
|
|
762
|
+
token_hash: string;
|
|
763
|
+
token_prefix: string;
|
|
764
|
+
};
|
|
765
|
+
Insert: {
|
|
766
|
+
created_at?: string;
|
|
767
|
+
created_by?: string | null;
|
|
768
|
+
expires_at?: string | null;
|
|
769
|
+
id?: string;
|
|
770
|
+
last_used_at?: string | null;
|
|
771
|
+
name: string;
|
|
772
|
+
revoked_at?: string | null;
|
|
773
|
+
scopes?: string[];
|
|
774
|
+
token_hash: string;
|
|
775
|
+
token_prefix: string;
|
|
776
|
+
};
|
|
777
|
+
Update: {
|
|
778
|
+
created_at?: string;
|
|
779
|
+
created_by?: string | null;
|
|
780
|
+
expires_at?: string | null;
|
|
781
|
+
id?: string;
|
|
782
|
+
last_used_at?: string | null;
|
|
783
|
+
name?: string;
|
|
784
|
+
revoked_at?: string | null;
|
|
785
|
+
scopes?: string[];
|
|
786
|
+
token_hash?: string;
|
|
787
|
+
token_prefix?: string;
|
|
788
|
+
};
|
|
789
|
+
Relationships: [];
|
|
790
|
+
};
|
|
752
791
|
media: {
|
|
753
792
|
Row: {
|
|
754
793
|
blur_data_url: string | null;
|
|
@@ -1586,6 +1625,51 @@ export type Database = {
|
|
|
1586
1625
|
}
|
|
1587
1626
|
];
|
|
1588
1627
|
};
|
|
1628
|
+
product_revisions: {
|
|
1629
|
+
Row: {
|
|
1630
|
+
author_id: string | null;
|
|
1631
|
+
content: Json;
|
|
1632
|
+
created_at: string;
|
|
1633
|
+
id: number;
|
|
1634
|
+
product_id: string;
|
|
1635
|
+
revision_type: Database["public"]["Enums"]["revision_type"];
|
|
1636
|
+
version: number;
|
|
1637
|
+
};
|
|
1638
|
+
Insert: {
|
|
1639
|
+
author_id?: string | null;
|
|
1640
|
+
content: Json;
|
|
1641
|
+
created_at?: string;
|
|
1642
|
+
id?: number;
|
|
1643
|
+
product_id: string;
|
|
1644
|
+
revision_type: Database["public"]["Enums"]["revision_type"];
|
|
1645
|
+
version: number;
|
|
1646
|
+
};
|
|
1647
|
+
Update: {
|
|
1648
|
+
author_id?: string | null;
|
|
1649
|
+
content?: Json;
|
|
1650
|
+
created_at?: string;
|
|
1651
|
+
id?: number;
|
|
1652
|
+
product_id?: string;
|
|
1653
|
+
revision_type?: Database["public"]["Enums"]["revision_type"];
|
|
1654
|
+
version?: number;
|
|
1655
|
+
};
|
|
1656
|
+
Relationships: [
|
|
1657
|
+
{
|
|
1658
|
+
foreignKeyName: "product_revisions_author_id_fkey";
|
|
1659
|
+
columns: ["author_id"];
|
|
1660
|
+
isOneToOne: false;
|
|
1661
|
+
referencedRelation: "profiles";
|
|
1662
|
+
referencedColumns: ["id"];
|
|
1663
|
+
},
|
|
1664
|
+
{
|
|
1665
|
+
foreignKeyName: "product_revisions_product_id_fkey";
|
|
1666
|
+
columns: ["product_id"];
|
|
1667
|
+
isOneToOne: false;
|
|
1668
|
+
referencedRelation: "products";
|
|
1669
|
+
referencedColumns: ["id"];
|
|
1670
|
+
}
|
|
1671
|
+
];
|
|
1672
|
+
};
|
|
1589
1673
|
product_variants: {
|
|
1590
1674
|
Row: {
|
|
1591
1675
|
created_at: string | null;
|
|
@@ -1702,6 +1786,7 @@ export type Database = {
|
|
|
1702
1786
|
trial_requires_payment_method: boolean;
|
|
1703
1787
|
upc: string | null;
|
|
1704
1788
|
updated_at: string | null;
|
|
1789
|
+
version: number;
|
|
1705
1790
|
};
|
|
1706
1791
|
Insert: {
|
|
1707
1792
|
average_rating?: number;
|
|
@@ -1740,6 +1825,7 @@ export type Database = {
|
|
|
1740
1825
|
trial_requires_payment_method?: boolean;
|
|
1741
1826
|
upc?: string | null;
|
|
1742
1827
|
updated_at?: string | null;
|
|
1828
|
+
version?: number;
|
|
1743
1829
|
};
|
|
1744
1830
|
Update: {
|
|
1745
1831
|
average_rating?: number;
|
|
@@ -1778,6 +1864,7 @@ export type Database = {
|
|
|
1778
1864
|
trial_requires_payment_method?: boolean;
|
|
1779
1865
|
upc?: string | null;
|
|
1780
1866
|
updated_at?: string | null;
|
|
1867
|
+
version?: number;
|
|
1781
1868
|
};
|
|
1782
1869
|
Relationships: [
|
|
1783
1870
|
{
|
package/package.json
CHANGED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
-- Cortex AI MCP (Model Context Protocol) server access.
|
|
2
|
+
--
|
|
3
|
+
-- Adds the bearer-token store that gates /api/mcp, the endpoint that exposes the
|
|
4
|
+
-- Cortex AI tool registry to external MCP clients (Claude Code, Claude Desktop,
|
|
5
|
+
-- Cursor, VS Code). Two pieces:
|
|
6
|
+
--
|
|
7
|
+
-- 1. public.mcp_access_tokens — one row per issued token. We store ONLY the
|
|
8
|
+
-- SHA-256 hash of the token, never the token itself: the plaintext is shown
|
|
9
|
+
-- to the admin exactly once at mint time and is unrecoverable afterwards, so
|
|
10
|
+
-- a database leak cannot be replayed against the MCP endpoint. `token_prefix`
|
|
11
|
+
-- is the non-secret leading fragment kept purely so the UI can tell two tokens
|
|
12
|
+
-- apart in a list.
|
|
13
|
+
--
|
|
14
|
+
-- 2. cortex_ai_mcp_settings — a non-secret JSON site_settings row holding the
|
|
15
|
+
-- server on/off switch and the localhost-trust flag. It is added to all four
|
|
16
|
+
-- site_settings policies so only authenticated ADMINs can read or write it;
|
|
17
|
+
-- the MCP route itself reads it through the service-role client, which
|
|
18
|
+
-- bypasses RLS.
|
|
19
|
+
--
|
|
20
|
+
-- Forward-only. Recreates the four site_settings policies idempotently, preserving
|
|
21
|
+
-- every key already in each policy's sensitive array (note that
|
|
22
|
+
-- language_detection_settings stays anon-READABLE and so is absent from the SELECT
|
|
23
|
+
-- policy, exactly as migration 00000000000012 left it).
|
|
24
|
+
|
|
25
|
+
CREATE TABLE IF NOT EXISTS public.mcp_access_tokens (
|
|
26
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
27
|
+
name text NOT NULL,
|
|
28
|
+
-- Lowercase hex SHA-256 of the plaintext token. Unique so a lookup is a single
|
|
29
|
+
-- indexed equality probe and duplicate mints are impossible.
|
|
30
|
+
token_hash text NOT NULL UNIQUE,
|
|
31
|
+
-- Non-secret display fragment, e.g. "nbmcp_a1b2c3d4". Never enough to authenticate.
|
|
32
|
+
token_prefix text NOT NULL,
|
|
33
|
+
-- 'read' grants the read-only tools; 'write' additionally grants the mutating ones.
|
|
34
|
+
scopes text[] NOT NULL DEFAULT ARRAY['read', 'write']::text[],
|
|
35
|
+
created_by uuid REFERENCES auth.users (id) ON DELETE SET NULL,
|
|
36
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
37
|
+
last_used_at timestamptz,
|
|
38
|
+
expires_at timestamptz,
|
|
39
|
+
revoked_at timestamptz
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
COMMENT ON TABLE public.mcp_access_tokens IS
|
|
43
|
+
'Bearer tokens for the Cortex AI MCP server at /api/mcp. Stores SHA-256 hashes only; plaintext is displayed once at mint time.';
|
|
44
|
+
|
|
45
|
+
CREATE INDEX IF NOT EXISTS mcp_access_tokens_token_hash_idx
|
|
46
|
+
ON public.mcp_access_tokens (token_hash);
|
|
47
|
+
|
|
48
|
+
-- Orders the admin token list newest-first without a sort.
|
|
49
|
+
CREATE INDEX IF NOT EXISTS mcp_access_tokens_created_at_idx
|
|
50
|
+
ON public.mcp_access_tokens (created_at DESC);
|
|
51
|
+
|
|
52
|
+
ALTER TABLE public.mcp_access_tokens ENABLE ROW LEVEL SECURITY;
|
|
53
|
+
|
|
54
|
+
-- Tokens are credentials: admin-only, with no anon or WRITER access at all. The
|
|
55
|
+
-- MCP route verifies them with the service-role client, which bypasses RLS.
|
|
56
|
+
DROP POLICY IF EXISTS mcp_access_tokens_admin_select ON public.mcp_access_tokens;
|
|
57
|
+
CREATE POLICY mcp_access_tokens_admin_select ON public.mcp_access_tokens
|
|
58
|
+
FOR SELECT TO authenticated
|
|
59
|
+
USING ((SELECT public.get_current_user_role()) = 'ADMIN'::public.user_role);
|
|
60
|
+
|
|
61
|
+
DROP POLICY IF EXISTS mcp_access_tokens_admin_insert ON public.mcp_access_tokens;
|
|
62
|
+
CREATE POLICY mcp_access_tokens_admin_insert ON public.mcp_access_tokens
|
|
63
|
+
FOR INSERT TO authenticated
|
|
64
|
+
WITH CHECK ((SELECT public.get_current_user_role()) = 'ADMIN'::public.user_role);
|
|
65
|
+
|
|
66
|
+
DROP POLICY IF EXISTS mcp_access_tokens_admin_update ON public.mcp_access_tokens;
|
|
67
|
+
CREATE POLICY mcp_access_tokens_admin_update ON public.mcp_access_tokens
|
|
68
|
+
FOR UPDATE TO authenticated
|
|
69
|
+
USING ((SELECT public.get_current_user_role()) = 'ADMIN'::public.user_role)
|
|
70
|
+
WITH CHECK ((SELECT public.get_current_user_role()) = 'ADMIN'::public.user_role);
|
|
71
|
+
|
|
72
|
+
DROP POLICY IF EXISTS mcp_access_tokens_admin_delete ON public.mcp_access_tokens;
|
|
73
|
+
CREATE POLICY mcp_access_tokens_admin_delete ON public.mcp_access_tokens
|
|
74
|
+
FOR DELETE TO authenticated
|
|
75
|
+
USING ((SELECT public.get_current_user_role()) = 'ADMIN'::public.user_role);
|
|
76
|
+
|
|
77
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON public.mcp_access_tokens TO authenticated;
|
|
78
|
+
GRANT ALL ON public.mcp_access_tokens TO service_role;
|
|
79
|
+
|
|
80
|
+
-- Add cortex_ai_mcp_settings to the admin-only site_settings group (all four policies).
|
|
81
|
+
DROP POLICY IF EXISTS site_settings_read_policy ON public.site_settings;
|
|
82
|
+
CREATE POLICY site_settings_read_policy ON public.site_settings FOR SELECT USING (((key <> ALL (ARRAY['cortex_ai_openrouter_api_key'::text, 'bot_protection_secret'::text, 'email_secret'::text, 'payment_secret'::text, 'cortex_ai_pexels_api_key'::text, 'cortex_ai_unsplash_access_key'::text, 'cortex_ai_mcp_settings'::text])) OR ((key = ANY (ARRAY['cortex_ai_openrouter_api_key'::text, 'bot_protection_secret'::text, 'email_secret'::text, 'payment_secret'::text, 'cortex_ai_pexels_api_key'::text, 'cortex_ai_unsplash_access_key'::text, 'cortex_ai_mcp_settings'::text])) AND (( SELECT auth.role() AS role) = 'authenticated'::text) AND (( SELECT public.get_current_user_role() AS get_current_user_role) = 'ADMIN'::public.user_role))));
|
|
83
|
+
|
|
84
|
+
DROP POLICY IF EXISTS site_settings_insert_policy ON public.site_settings;
|
|
85
|
+
CREATE POLICY site_settings_insert_policy ON public.site_settings FOR INSERT TO authenticated WITH CHECK ((((key <> ALL (ARRAY['cortex_ai_openrouter_api_key'::text, 'bot_protection_secret'::text, 'email_secret'::text, 'payment_secret'::text, 'language_detection_settings'::text, 'cortex_ai_pexels_api_key'::text, 'cortex_ai_unsplash_access_key'::text, 'cortex_ai_mcp_settings'::text])) AND (( SELECT public.get_current_user_role() AS get_current_user_role) = ANY (ARRAY['ADMIN'::public.user_role, 'WRITER'::public.user_role]))) OR ((key = ANY (ARRAY['cortex_ai_openrouter_api_key'::text, 'bot_protection_secret'::text, 'email_secret'::text, 'payment_secret'::text, 'language_detection_settings'::text, 'cortex_ai_pexels_api_key'::text, 'cortex_ai_unsplash_access_key'::text, 'cortex_ai_mcp_settings'::text])) AND (( SELECT public.get_current_user_role() AS get_current_user_role) = 'ADMIN'::public.user_role))));
|
|
86
|
+
|
|
87
|
+
DROP POLICY IF EXISTS site_settings_update_policy ON public.site_settings;
|
|
88
|
+
CREATE POLICY site_settings_update_policy ON public.site_settings FOR UPDATE TO authenticated USING ((((key <> ALL (ARRAY['cortex_ai_openrouter_api_key'::text, 'bot_protection_secret'::text, 'email_secret'::text, 'payment_secret'::text, 'language_detection_settings'::text, 'cortex_ai_pexels_api_key'::text, 'cortex_ai_unsplash_access_key'::text, 'cortex_ai_mcp_settings'::text])) AND (( SELECT public.get_current_user_role() AS get_current_user_role) = ANY (ARRAY['ADMIN'::public.user_role, 'WRITER'::public.user_role]))) OR ((key = ANY (ARRAY['cortex_ai_openrouter_api_key'::text, 'bot_protection_secret'::text, 'email_secret'::text, 'payment_secret'::text, 'language_detection_settings'::text, 'cortex_ai_pexels_api_key'::text, 'cortex_ai_unsplash_access_key'::text, 'cortex_ai_mcp_settings'::text])) AND (( SELECT public.get_current_user_role() AS get_current_user_role) = 'ADMIN'::public.user_role)))) WITH CHECK ((((key <> ALL (ARRAY['cortex_ai_openrouter_api_key'::text, 'bot_protection_secret'::text, 'email_secret'::text, 'payment_secret'::text, 'language_detection_settings'::text, 'cortex_ai_pexels_api_key'::text, 'cortex_ai_unsplash_access_key'::text, 'cortex_ai_mcp_settings'::text])) AND (( SELECT public.get_current_user_role() AS get_current_user_role) = ANY (ARRAY['ADMIN'::public.user_role, 'WRITER'::public.user_role]))) OR ((key = ANY (ARRAY['cortex_ai_openrouter_api_key'::text, 'bot_protection_secret'::text, 'email_secret'::text, 'payment_secret'::text, 'language_detection_settings'::text, 'cortex_ai_pexels_api_key'::text, 'cortex_ai_unsplash_access_key'::text, 'cortex_ai_mcp_settings'::text])) AND (( SELECT public.get_current_user_role() AS get_current_user_role) = 'ADMIN'::public.user_role))));
|
|
89
|
+
|
|
90
|
+
DROP POLICY IF EXISTS site_settings_delete_policy ON public.site_settings;
|
|
91
|
+
CREATE POLICY site_settings_delete_policy ON public.site_settings FOR DELETE TO authenticated USING ((((key <> ALL (ARRAY['cortex_ai_openrouter_api_key'::text, 'bot_protection_secret'::text, 'email_secret'::text, 'payment_secret'::text, 'language_detection_settings'::text, 'cortex_ai_pexels_api_key'::text, 'cortex_ai_unsplash_access_key'::text, 'cortex_ai_mcp_settings'::text])) AND (( SELECT public.get_current_user_role() AS get_current_user_role) = ANY (ARRAY['ADMIN'::public.user_role, 'WRITER'::public.user_role]))) OR ((key = ANY (ARRAY['cortex_ai_openrouter_api_key'::text, 'bot_protection_secret'::text, 'email_secret'::text, 'payment_secret'::text, 'language_detection_settings'::text, 'cortex_ai_pexels_api_key'::text, 'cortex_ai_unsplash_access_key'::text, 'cortex_ai_mcp_settings'::text])) AND (( SELECT public.get_current_user_role() AS get_current_user_role) = 'ADMIN'::public.user_role))));
|