@hobenakicoffee/libraries 8.1.0 → 8.3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hobenakicoffee/libraries",
3
- "version": "8.1.0",
3
+ "version": "8.3.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "types": "src/index.ts",
package/src/App.tsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import { useState } from "react";
2
2
  import { productInfo } from "@/constants/legal";
3
+ import SchemaViewer from "@/SchemaViewer";
3
4
  import logoSvg from "/favicon.svg";
4
5
 
5
6
  declare const __LATEST_VERSION__: string;
@@ -39,7 +40,10 @@ const EXPORTS = [
39
40
  { path: "/docs", name: "docs", desc: "Documentation & guides" },
40
41
  ];
41
42
 
43
+ type Page = "home" | "schema";
44
+
42
45
  const App = () => {
46
+ const [page, setPage] = useState<Page>("home");
43
47
  const [copied, setCopied] = useState(false);
44
48
 
45
49
  const handleCopy = () => {
@@ -48,6 +52,10 @@ const App = () => {
48
52
  setTimeout(() => setCopied(false), 2000);
49
53
  };
50
54
 
55
+ if (page === "schema") {
56
+ return <SchemaViewer onBack={() => setPage("home")} />;
57
+ }
58
+
51
59
  return (
52
60
  <div className="min-dvh relative flex flex-col overflow-hidden bg-[#0a0c10] text-slate-200">
53
61
  <div className="pointer-events-none absolute inset-0 overflow-hidden">
@@ -76,9 +84,18 @@ const App = () => {
76
84
  </p>
77
85
  </div>
78
86
  </div>
79
- <div className="flex items-center gap-2 rounded-md border border-slate-800 bg-slate-900/50 px-2 py-1 font-mono text-slate-400 text-xs">
80
- <span className="h-2 w-2 rounded-full bg-green-500" />
81
- TypeScript
87
+ <div className="flex items-center gap-3">
88
+ <button
89
+ className="cursor-pointer rounded-md border border-slate-700 bg-slate-900/50 px-3 py-1.5 font-mono text-slate-400 text-xs transition-colors hover:border-slate-500 hover:text-slate-200"
90
+ onClick={() => setPage("schema")}
91
+ type="button"
92
+ >
93
+ schema
94
+ </button>
95
+ <div className="flex items-center gap-2 rounded-md border border-slate-800 bg-slate-900/50 px-2 py-1 font-mono text-slate-400 text-xs">
96
+ <span className="h-2 w-2 rounded-full bg-green-500" />
97
+ TypeScript
98
+ </div>
82
99
  </div>
83
100
  </header>
84
101
 
@@ -0,0 +1,616 @@
1
+ import { schema } from "virtual:supabase-schema";
2
+ import { useMemo, useState } from "react";
3
+
4
+ type SelectedItem =
5
+ | { type: "table"; name: string }
6
+ | { type: "view"; name: string }
7
+ | { type: "enum"; name: string };
8
+
9
+ const tableNames = Object.keys(schema.tables);
10
+ const viewNames = Object.keys(schema.views);
11
+ const enumNames = Object.keys(schema.enums);
12
+
13
+ const SectionIcon = ({ label }: { label: string }) => {
14
+ if (label === "Tables") return <span className="text-blue-400">&#9654;</span>;
15
+ if (label === "Views")
16
+ return <span className="text-emerald-400">&#9654;</span>;
17
+ if (label === "Enums") return <span className="text-amber-400">&#9654;</span>;
18
+ return null;
19
+ };
20
+
21
+ const EnumBadge = ({ values }: { values: string[] }) => (
22
+ <span
23
+ className="cursor-help rounded border border-amber-700/40 bg-amber-950/40 px-1.5 py-0.5 font-mono text-[10px] text-amber-300"
24
+ title={values.join(", ")}
25
+ >
26
+ enum
27
+ </span>
28
+ );
29
+
30
+ const SerialBadge = () => (
31
+ <span className="rounded border border-purple-700/40 bg-purple-950/40 px-1.5 py-0.5 font-mono text-[10px] text-purple-300">
32
+ serial
33
+ </span>
34
+ );
35
+
36
+ const NullableBadge = () => (
37
+ <span className="rounded border border-slate-600/40 bg-slate-800/40 px-1.5 py-0.5 font-mono text-[10px] text-slate-400">
38
+ null
39
+ </span>
40
+ );
41
+
42
+ const BackButton = ({ onClick }: { onClick: () => void }) => (
43
+ <button
44
+ className="flex cursor-pointer items-center gap-1.5 rounded-lg border border-slate-700 bg-slate-900 px-3 py-1.5 font-mono text-slate-400 text-xs transition-colors hover:border-slate-500 hover:text-slate-200"
45
+ onClick={onClick}
46
+ type="button"
47
+ >
48
+ <span>&larr;</span>
49
+ <span>Back</span>
50
+ </button>
51
+ );
52
+
53
+ const SchemaViewer = ({ onBack }: { onBack: () => void }) => {
54
+ const [selected, setSelected] = useState<SelectedItem | null>(null);
55
+ const [search, setSearch] = useState("");
56
+ const [collapsed, setCollapsed] = useState<Record<string, boolean>>({
57
+ Tables: false,
58
+ Views: false,
59
+ Enums: false,
60
+ });
61
+ const [sidebarOpen, setSidebarOpen] = useState(false);
62
+
63
+ const query = search.toLowerCase();
64
+
65
+ const filteredTables = useMemo(
66
+ () => tableNames.filter((n) => n.includes(query)),
67
+ [query]
68
+ );
69
+ const filteredViews = useMemo(
70
+ () => viewNames.filter((n) => n.includes(query)),
71
+ [query]
72
+ );
73
+ const filteredEnums = useMemo(
74
+ () => enumNames.filter((n) => n.includes(query)),
75
+ [query]
76
+ );
77
+
78
+ const hasTables = filteredTables.length > 0;
79
+ const hasViews = filteredViews.length > 0;
80
+ const hasEnums = filteredEnums.length > 0;
81
+
82
+ const toggleSection = (section: string) => {
83
+ setCollapsed((prev) => ({ ...prev, [section]: !prev[section] }));
84
+ };
85
+
86
+ const handleSelect = (item: SelectedItem) => {
87
+ setSelected(item);
88
+ setSidebarOpen(false);
89
+ };
90
+
91
+ const handleFKClick = (tableName: string) => {
92
+ setSelected({ type: "table", name: tableName });
93
+ };
94
+
95
+ const sel = selected;
96
+ const selectedTable =
97
+ sel !== null && sel.type === "table" ? schema.tables[sel.name] : undefined;
98
+ const selectedView =
99
+ sel !== null && sel.type === "view" ? schema.views[sel.name] : undefined;
100
+ const selectedEnum =
101
+ sel !== null && sel.type === "enum"
102
+ ? { name: sel.name, values: schema.enums[sel.name] ?? [] }
103
+ : undefined;
104
+
105
+ const getEnumValues = (enumName: string): string[] | undefined =>
106
+ schema.enums[enumName];
107
+
108
+ return (
109
+ <div className="flex h-dvh flex-col bg-[#0a0c10] text-slate-200">
110
+ <header className="flex shrink-0 items-center justify-between border-slate-800 border-b px-6 py-3">
111
+ <div className="flex items-center gap-4">
112
+ <BackButton onClick={onBack} />
113
+ <h1 className="font-mono font-semibold text-sm">
114
+ <span className="text-brand">$</span> supabase schema
115
+ </h1>
116
+ </div>
117
+ <div className="flex items-center gap-3">
118
+ {selected && (
119
+ <span className="hidden font-mono text-slate-500 text-xs sm:inline">
120
+ {selected.type} / {selected.name}
121
+ </span>
122
+ )}
123
+ <button
124
+ className="flex cursor-pointer items-center gap-1.5 rounded-lg border border-slate-700 bg-slate-900 px-3 py-1.5 font-mono text-slate-400 text-xs transition-colors hover:border-slate-500 hover:text-slate-200 lg:hidden"
125
+ onClick={() => setSidebarOpen(true)}
126
+ type="button"
127
+ >
128
+ <svg
129
+ aria-label="Menu"
130
+ className="h-4 w-4"
131
+ fill="none"
132
+ role="img"
133
+ stroke="currentColor"
134
+ strokeWidth="2"
135
+ viewBox="0 0 24 24"
136
+ >
137
+ <title>Open sidebar</title>
138
+ <path d="M4 6h16M4 12h16M4 18h16" strokeLinecap="round" />
139
+ </svg>
140
+ <span>Tables</span>
141
+ </button>
142
+ </div>
143
+ </header>
144
+
145
+ <div className="flex min-h-0 flex-1">
146
+ {sidebarOpen && (
147
+ <button
148
+ aria-label="Close sidebar"
149
+ className="fixed inset-0 z-30 cursor-default bg-black/60 lg:hidden"
150
+ onClick={() => setSidebarOpen(false)}
151
+ type="button"
152
+ />
153
+ )}
154
+
155
+ <aside
156
+ className={`w-72 shrink-0 overflow-y-auto border-slate-800 border-r bg-slate-950 p-4 ${
157
+ sidebarOpen
158
+ ? "fixed inset-y-0 left-0 z-40 block"
159
+ : "hidden lg:block"
160
+ }`}
161
+ >
162
+ <SidebarContent
163
+ collapsed={collapsed}
164
+ filteredEnums={filteredEnums}
165
+ filteredTables={filteredTables}
166
+ filteredViews={filteredViews}
167
+ handleSelect={handleSelect}
168
+ hasEnums={hasEnums}
169
+ hasTables={hasTables}
170
+ hasViews={hasViews}
171
+ search={search}
172
+ selected={selected}
173
+ setSearch={setSearch}
174
+ toggleSection={toggleSection}
175
+ />
176
+ </aside>
177
+
178
+ <main className="flex-1 overflow-y-auto p-6">
179
+ {!selected && (
180
+ <div className="flex items-center justify-center pt-24">
181
+ <div className="text-center">
182
+ <div className="mb-4 font-mono text-4xl text-slate-600">
183
+ {"{ : }"}
184
+ </div>
185
+ <p className="font-mono text-slate-500 text-sm">
186
+ select a table, view, or enum from the sidebar
187
+ </p>
188
+ </div>
189
+ </div>
190
+ )}
191
+
192
+ {selectedTable && sel && (
193
+ <TableDetail
194
+ enumValues={getEnumValues}
195
+ onFKClick={handleFKClick}
196
+ relationships={selectedTable.relationships}
197
+ tableName={sel.name}
198
+ >
199
+ <ColumnsTable
200
+ columns={selectedTable.columns}
201
+ enumValues={getEnumValues}
202
+ />
203
+ </TableDetail>
204
+ )}
205
+
206
+ {selectedView && sel && (
207
+ <ViewDetail viewName={sel.name}>
208
+ <ColumnsTable
209
+ columns={selectedView.columns}
210
+ enumValues={getEnumValues}
211
+ />
212
+ </ViewDetail>
213
+ )}
214
+
215
+ {selectedEnum && (
216
+ <EnumDetail name={selectedEnum.name} values={selectedEnum.values} />
217
+ )}
218
+ </main>
219
+ </div>
220
+ </div>
221
+ );
222
+ };
223
+
224
+ const SidebarSection = ({
225
+ children,
226
+ collapsed,
227
+ count,
228
+ label,
229
+ onToggle,
230
+ }: {
231
+ children: React.ReactNode;
232
+ collapsed: boolean;
233
+ count: number;
234
+ label: string;
235
+ onToggle: () => void;
236
+ }) => (
237
+ <div className="mb-3">
238
+ <button
239
+ className="flex w-full cursor-pointer items-center gap-2 rounded px-1 py-1.5 font-mono text-slate-400 text-xs transition-colors hover:text-slate-200"
240
+ onClick={onToggle}
241
+ type="button"
242
+ >
243
+ <span className={`transition-transform ${collapsed ? "-rotate-90" : ""}`}>
244
+ <SectionIcon label={label} />
245
+ </span>
246
+ <span>{label}</span>
247
+ <span className="ml-auto rounded bg-slate-800 px-1.5 py-0.5 text-slate-500">
248
+ {count}
249
+ </span>
250
+ </button>
251
+ {!collapsed && <div className="mt-1 ml-2 space-y-0.5">{children}</div>}
252
+ </div>
253
+ );
254
+
255
+ const SidebarItem = ({
256
+ isActive,
257
+ label,
258
+ onClick,
259
+ }: {
260
+ isActive: boolean;
261
+ label: string;
262
+ onClick: () => void;
263
+ }) => (
264
+ <button
265
+ className={`w-full cursor-pointer rounded px-3 py-1.5 text-left font-mono text-xs transition-colors ${
266
+ isActive
267
+ ? "bg-brand/10 text-brand"
268
+ : "text-slate-400 hover:bg-slate-800/50 hover:text-slate-200"
269
+ }`}
270
+ onClick={onClick}
271
+ type="button"
272
+ >
273
+ {label}
274
+ </button>
275
+ );
276
+
277
+ const SidebarContent = ({
278
+ collapsed,
279
+ filteredEnums,
280
+ filteredTables,
281
+ filteredViews,
282
+ handleSelect,
283
+ hasEnums,
284
+ hasTables,
285
+ hasViews,
286
+ search,
287
+ selected,
288
+ setSearch,
289
+ toggleSection,
290
+ }: {
291
+ collapsed: Record<string, boolean>;
292
+ filteredEnums: string[];
293
+ filteredTables: string[];
294
+ filteredViews: string[];
295
+ handleSelect: (item: SelectedItem) => void;
296
+ hasEnums: boolean;
297
+ hasTables: boolean;
298
+ hasViews: boolean;
299
+ search: string;
300
+ selected: SelectedItem | null;
301
+ setSearch: (v: string) => void;
302
+ toggleSection: (section: string) => void;
303
+ }) => (
304
+ <>
305
+ <input
306
+ className="mb-4 w-full rounded-lg border border-slate-700 bg-slate-900 px-3 py-2 font-mono text-slate-200 text-xs placeholder-slate-500 outline-none focus:border-brand/50"
307
+ onChange={(e) => setSearch(e.target.value)}
308
+ placeholder="filter tables, views, enums..."
309
+ type="text"
310
+ value={search}
311
+ />
312
+
313
+ {!(hasTables || hasViews || hasEnums) && (
314
+ <p className="font-mono text-slate-500 text-xs">no results</p>
315
+ )}
316
+
317
+ {hasTables && (
318
+ <SidebarSection
319
+ collapsed={collapsed.Tables ?? false}
320
+ count={filteredTables.length}
321
+ label="Tables"
322
+ onToggle={() => toggleSection("Tables")}
323
+ >
324
+ {filteredTables.map((name) => (
325
+ <SidebarItem
326
+ isActive={selected?.type === "table" && selected.name === name}
327
+ key={name}
328
+ label={name}
329
+ onClick={() => handleSelect({ type: "table", name })}
330
+ />
331
+ ))}
332
+ </SidebarSection>
333
+ )}
334
+
335
+ {hasViews && (
336
+ <SidebarSection
337
+ collapsed={collapsed.Views ?? false}
338
+ count={filteredViews.length}
339
+ label="Views"
340
+ onToggle={() => toggleSection("Views")}
341
+ >
342
+ {filteredViews.map((name) => (
343
+ <SidebarItem
344
+ isActive={selected?.type === "view" && selected.name === name}
345
+ key={name}
346
+ label={name}
347
+ onClick={() => handleSelect({ type: "view", name })}
348
+ />
349
+ ))}
350
+ </SidebarSection>
351
+ )}
352
+
353
+ {hasEnums && (
354
+ <SidebarSection
355
+ collapsed={collapsed.Enums ?? false}
356
+ count={filteredEnums.length}
357
+ label="Enums"
358
+ onToggle={() => toggleSection("Enums")}
359
+ >
360
+ {filteredEnums.map((name) => (
361
+ <SidebarItem
362
+ isActive={selected?.type === "enum" && selected.name === name}
363
+ key={name}
364
+ label={name}
365
+ onClick={() => handleSelect({ type: "enum", name })}
366
+ />
367
+ ))}
368
+ </SidebarSection>
369
+ )}
370
+ </>
371
+ );
372
+
373
+ const ColumnsTable = ({
374
+ columns,
375
+ enumValues,
376
+ }: {
377
+ columns: {
378
+ name: string;
379
+ type: string;
380
+ rawType: string;
381
+ nullable: boolean;
382
+ enumName: string | null;
383
+ }[];
384
+ enumValues: (name: string) => string[] | undefined;
385
+ }) => {
386
+ if (columns.length === 0) {
387
+ return (
388
+ <p className="py-4 font-mono text-slate-500 text-xs">
389
+ no columns defined
390
+ </p>
391
+ );
392
+ }
393
+
394
+ return (
395
+ <div className="overflow-x-auto rounded-lg border border-slate-800">
396
+ <table className="w-full border-collapse font-mono text-xs">
397
+ <thead>
398
+ <tr className="border-slate-800 border-b bg-slate-900/80">
399
+ <Th>Column</Th>
400
+ <Th>Type</Th>
401
+ <Th>Attributes</Th>
402
+ </tr>
403
+ </thead>
404
+ <tbody>
405
+ {columns.map((col) => {
406
+ const enumName: string | null = col.enumName;
407
+ const isEnum = enumName !== null;
408
+ const isSerial = col.rawType === "never";
409
+ const hasEnumValues = isEnum
410
+ ? (enumValues(enumName) ?? [])
411
+ : undefined;
412
+
413
+ return (
414
+ <tr
415
+ className="border-slate-800/50 border-b transition-colors hover:bg-slate-800/30"
416
+ key={col.name}
417
+ >
418
+ <Td>{col.name}</Td>
419
+ <Td>
420
+ <span
421
+ className={
422
+ isEnum
423
+ ? "text-amber-300"
424
+ : isSerial
425
+ ? "text-purple-300"
426
+ : "text-cyan-300"
427
+ }
428
+ title={col.rawType}
429
+ >
430
+ {col.type}
431
+ </span>
432
+ </Td>
433
+ <Td>
434
+ <div className="flex flex-wrap gap-1">
435
+ {isSerial && <SerialBadge />}
436
+ {col.nullable && <NullableBadge />}
437
+ {isEnum && <EnumBadge values={hasEnumValues ?? []} />}
438
+ </div>
439
+ </Td>
440
+ </tr>
441
+ );
442
+ })}
443
+ </tbody>
444
+ </table>
445
+ </div>
446
+ );
447
+ };
448
+
449
+ const Th = ({ children }: { children: React.ReactNode }) => (
450
+ <th className="px-4 py-2.5 text-left font-semibold text-slate-400">
451
+ {children}
452
+ </th>
453
+ );
454
+
455
+ const Td = ({ children }: { children: React.ReactNode }) => (
456
+ <td className="px-4 py-2.5 text-slate-300">{children}</td>
457
+ );
458
+
459
+ const TableDetail = ({
460
+ children,
461
+ enumValues,
462
+ onFKClick,
463
+ relationships,
464
+ tableName,
465
+ }: {
466
+ children: React.ReactNode;
467
+ enumValues: (name: string) => string[] | undefined;
468
+ onFKClick: (tableName: string) => void;
469
+ relationships: {
470
+ column: string;
471
+ referencedTable: string;
472
+ referencedColumn: string;
473
+ foreignKeyName: string;
474
+ isOneToOne: boolean;
475
+ }[];
476
+ tableName: string;
477
+ }) => (
478
+ <div>
479
+ <div className="mb-6">
480
+ <h2 className="font-mono font-semibold text-lg text-slate-100">
481
+ {tableName}
482
+ </h2>
483
+ <p className="font-mono text-slate-500 text-xs">table</p>
484
+ </div>
485
+
486
+ <div className="mb-8">
487
+ <h3 className="mb-3 font-mono text-slate-500 text-xs uppercase tracking-wider">
488
+ Columns
489
+ </h3>
490
+ {children}
491
+ </div>
492
+
493
+ {relationships.length > 0 && (
494
+ <div>
495
+ <h3 className="mb-3 font-mono text-slate-500 text-xs uppercase tracking-wider">
496
+ Relationships
497
+ </h3>
498
+ <div className="space-y-1.5">
499
+ {relationships.map((rel) => (
500
+ <RelationshipRow
501
+ enumValues={enumValues}
502
+ isOneToOne={rel.isOneToOne}
503
+ key={rel.foreignKeyName}
504
+ onTableClick={onFKClick}
505
+ rel={rel}
506
+ />
507
+ ))}
508
+ </div>
509
+ </div>
510
+ )}
511
+ </div>
512
+ );
513
+
514
+ const RelationshipRow = ({
515
+ enumValues,
516
+ isOneToOne,
517
+ onTableClick,
518
+ rel,
519
+ }: {
520
+ enumValues: (name: string) => string[] | undefined;
521
+ isOneToOne: boolean;
522
+ onTableClick: (tableName: string) => void;
523
+ rel: {
524
+ column: string;
525
+ referencedTable: string;
526
+ referencedColumn: string;
527
+ foreignKeyName: string;
528
+ isOneToOne: boolean;
529
+ };
530
+ }) => {
531
+ const hasEnumOnRef = enumValues(rel.referencedTable) !== undefined;
532
+ return (
533
+ <div
534
+ className="group rounded-lg border border-slate-800 bg-slate-900/30 p-3 transition-colors hover:border-slate-700"
535
+ key={rel.foreignKeyName}
536
+ >
537
+ <div className="mb-1 flex items-center gap-2 font-mono text-xs">
538
+ <code className="text-cyan-300">{rel.column}</code>
539
+ <span className="text-slate-600">
540
+ {isOneToOne ? "\u2192" : "\u2192\u2192"}
541
+ </span>
542
+ <button
543
+ className="cursor-pointer text-brand transition-colors hover:text-brand/80"
544
+ onClick={() => onTableClick(rel.referencedTable)}
545
+ title={`Jump to ${rel.referencedTable}`}
546
+ type="button"
547
+ >
548
+ {rel.referencedTable}
549
+ </button>
550
+ <code className="text-slate-500">.{rel.referencedColumn}</code>
551
+ {isOneToOne && (
552
+ <span className="rounded border border-purple-700/30 bg-purple-950/30 px-1.5 py-0.5 text-[10px] text-purple-300">
553
+ 1:1
554
+ </span>
555
+ )}
556
+ {hasEnumOnRef && (
557
+ <EnumBadge values={enumValues(rel.referencedTable) ?? []} />
558
+ )}
559
+ </div>
560
+ <div className="font-mono text-[10px] text-slate-600">
561
+ {rel.foreignKeyName.replace(/_fkey$/, "")}
562
+ </div>
563
+ </div>
564
+ );
565
+ };
566
+
567
+ const ViewDetail = ({
568
+ children,
569
+ viewName,
570
+ }: {
571
+ children: React.ReactNode;
572
+ viewName: string;
573
+ }) => (
574
+ <div>
575
+ <div className="mb-6">
576
+ <h2 className="font-mono font-semibold text-lg text-slate-100">
577
+ {viewName}
578
+ </h2>
579
+ <p className="font-mono text-slate-500 text-xs">view</p>
580
+ </div>
581
+
582
+ <div className="mb-8">
583
+ <h3 className="mb-3 font-mono text-slate-500 text-xs uppercase tracking-wider">
584
+ Columns
585
+ </h3>
586
+ {children}
587
+ </div>
588
+ </div>
589
+ );
590
+
591
+ const EnumDetail = ({ name, values }: { name: string; values: string[] }) => (
592
+ <div>
593
+ <div className="mb-6">
594
+ <h2 className="font-mono font-semibold text-lg text-slate-100">{name}</h2>
595
+ <p className="font-mono text-slate-500 text-xs">enum</p>
596
+ </div>
597
+
598
+ <div className="mb-8">
599
+ <h3 className="mb-3 font-mono text-slate-500 text-xs uppercase tracking-wider">
600
+ Values
601
+ </h3>
602
+ <div className="flex flex-wrap gap-2">
603
+ {values.map((v) => (
604
+ <span
605
+ className="rounded-lg border border-slate-700 bg-slate-900 px-3 py-1.5 font-mono text-slate-300 text-xs"
606
+ key={v}
607
+ >
608
+ {v}
609
+ </span>
610
+ ))}
611
+ </div>
612
+ </div>
613
+ </div>
614
+ );
615
+
616
+ export default SchemaViewer;
@@ -1333,7 +1333,7 @@ export type Database = {
1333
1333
  },
1334
1334
  ];
1335
1335
  };
1336
- messages_2026_05: {
1336
+ messages_2026_06: {
1337
1337
  Row: {
1338
1338
  content: string;
1339
1339
  conversation_id: string;
@@ -1357,7 +1357,7 @@ export type Database = {
1357
1357
  };
1358
1358
  Relationships: [];
1359
1359
  };
1360
- messages_2026_06: {
1360
+ messages_2026_08: {
1361
1361
  Row: {
1362
1362
  content: string;
1363
1363
  conversation_id: string;
@@ -1818,6 +1818,95 @@ export type Database = {
1818
1818
  },
1819
1819
  ];
1820
1820
  };
1821
+ payment_sessions: {
1822
+ Row: {
1823
+ amount: number;
1824
+ bank_tran_id: string | null;
1825
+ created_at: string;
1826
+ creator_profile_id: string | null;
1827
+ currency: string;
1828
+ error: string | null;
1829
+ expires_at: string;
1830
+ gateway_response: Json | null;
1831
+ id: string;
1832
+ payload: Json;
1833
+ rpc_result: Json | null;
1834
+ service_type: string;
1835
+ status: Database["public"]["Enums"]["payment_session_status_enum"];
1836
+ supporter_profile_id: string | null;
1837
+ tran_id: string;
1838
+ updated_at: string;
1839
+ val_id: string | null;
1840
+ };
1841
+ Insert: {
1842
+ amount: number;
1843
+ bank_tran_id?: string | null;
1844
+ created_at?: string;
1845
+ creator_profile_id?: string | null;
1846
+ currency?: string;
1847
+ error?: string | null;
1848
+ expires_at?: string;
1849
+ gateway_response?: Json | null;
1850
+ id?: string;
1851
+ payload: Json;
1852
+ rpc_result?: Json | null;
1853
+ service_type: string;
1854
+ status?: Database["public"]["Enums"]["payment_session_status_enum"];
1855
+ supporter_profile_id?: string | null;
1856
+ tran_id: string;
1857
+ updated_at?: string;
1858
+ val_id?: string | null;
1859
+ };
1860
+ Update: {
1861
+ amount?: number;
1862
+ bank_tran_id?: string | null;
1863
+ created_at?: string;
1864
+ creator_profile_id?: string | null;
1865
+ currency?: string;
1866
+ error?: string | null;
1867
+ expires_at?: string;
1868
+ gateway_response?: Json | null;
1869
+ id?: string;
1870
+ payload?: Json;
1871
+ rpc_result?: Json | null;
1872
+ service_type?: string;
1873
+ status?: Database["public"]["Enums"]["payment_session_status_enum"];
1874
+ supporter_profile_id?: string | null;
1875
+ tran_id?: string;
1876
+ updated_at?: string;
1877
+ val_id?: string | null;
1878
+ };
1879
+ Relationships: [
1880
+ {
1881
+ foreignKeyName: "payment_sessions_creator_profile_id_fkey";
1882
+ columns: ["creator_profile_id"];
1883
+ isOneToOne: false;
1884
+ referencedRelation: "profiles";
1885
+ referencedColumns: ["id"];
1886
+ },
1887
+ {
1888
+ foreignKeyName: "payment_sessions_creator_profile_id_fkey";
1889
+ columns: ["creator_profile_id"];
1890
+ isOneToOne: false;
1891
+ referencedRelation: "public_profiles";
1892
+ referencedColumns: ["id"];
1893
+ },
1894
+ {
1895
+ foreignKeyName: "payment_sessions_supporter_profile_id_fkey";
1896
+ columns: ["supporter_profile_id"];
1897
+ isOneToOne: false;
1898
+ referencedRelation: "profiles";
1899
+ referencedColumns: ["id"];
1900
+ },
1901
+ {
1902
+ foreignKeyName: "payment_sessions_supporter_profile_id_fkey";
1903
+ columns: ["supporter_profile_id"];
1904
+ isOneToOne: false;
1905
+ referencedRelation: "public_profiles";
1906
+ referencedColumns: ["id"];
1907
+ },
1908
+ ];
1909
+ };
1821
1910
  payout_methods: {
1822
1911
  Row: {
1823
1912
  created_at: string;
@@ -4184,6 +4273,7 @@ export type Database = {
4184
4273
  dismiss_all_activities: { Args: never; Returns: undefined };
4185
4274
  dispatch_pending_email_notifications: { Args: never; Returns: undefined };
4186
4275
  drop_old_partitions: { Args: never; Returns: undefined };
4276
+ expire_stale_payment_sessions: { Args: never; Returns: number };
4187
4277
  flag_transaction_disputed: {
4188
4278
  Args: { p_is_disputed?: boolean; p_transaction_id: string };
4189
4279
  Returns: Json;
@@ -4418,6 +4508,15 @@ export type Database = {
4418
4508
  Args: never;
4419
4509
  Returns: Database["public"]["Enums"]["user_role"];
4420
4510
  };
4511
+ get_payment_session_status: {
4512
+ Args: { p_tran_id: string };
4513
+ Returns: {
4514
+ amount: number;
4515
+ error: string;
4516
+ service_type: string;
4517
+ status: Database["public"]["Enums"]["payment_session_status_enum"];
4518
+ }[];
4519
+ };
4421
4520
  get_platform_setting: { Args: { p_key: string }; Returns: number };
4422
4521
  get_platform_setting_jsonb: { Args: { p_key: string }; Returns: Json };
4423
4522
  get_popular_content: {
@@ -5218,6 +5317,12 @@ export type Database = {
5218
5317
  | "expired"
5219
5318
  | "paused"
5220
5319
  | "past_due";
5320
+ payment_session_status_enum:
5321
+ | "pending"
5322
+ | "completed"
5323
+ | "failed"
5324
+ | "cancelled"
5325
+ | "expired";
5221
5326
  payment_status_enum:
5222
5327
  | "pending"
5223
5328
  | "processing"
@@ -5512,6 +5617,13 @@ export const Constants = {
5512
5617
  "paused",
5513
5618
  "past_due",
5514
5619
  ],
5620
+ payment_session_status_enum: [
5621
+ "pending",
5622
+ "completed",
5623
+ "failed",
5624
+ "cancelled",
5625
+ "expired",
5626
+ ],
5515
5627
  payment_status_enum: [
5516
5628
  "pending",
5517
5629
  "processing",
package/src/vite-env.d.ts CHANGED
@@ -1 +1,36 @@
1
1
  /// <reference types="vite/client" />
2
+
3
+ declare module "virtual:supabase-schema" {
4
+ export type ColumnInfo = {
5
+ name: string;
6
+ type: string;
7
+ rawType: string;
8
+ nullable: boolean;
9
+ enumName: string | null;
10
+ };
11
+
12
+ export type RelationshipInfo = {
13
+ foreignKeyName: string;
14
+ column: string;
15
+ referencedTable: string;
16
+ referencedColumn: string;
17
+ isOneToOne: boolean;
18
+ };
19
+
20
+ export type TableInfo = {
21
+ columns: ColumnInfo[];
22
+ relationships: RelationshipInfo[];
23
+ };
24
+
25
+ export type ViewInfo = {
26
+ columns: ColumnInfo[];
27
+ };
28
+
29
+ export type Schema = {
30
+ tables: Record<string, TableInfo>;
31
+ views: Record<string, ViewInfo>;
32
+ enums: Record<string, string[]>;
33
+ };
34
+
35
+ export const schema: Schema;
36
+ }