@rebasepro/studio 0.8.0 → 0.9.1-canary.09aaf62
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/README.md +4 -4
- package/dist/{ApiExplorer-CdIwR9Ga.js → ApiExplorer-B9M9-uy_.js} +3 -3
- package/dist/ApiExplorer-B9M9-uy_.js.map +1 -0
- package/dist/{ApiKeysView-D-_FSlNL.js → ApiKeysView-vQKqt2wl.js} +45 -3
- package/dist/ApiKeysView-vQKqt2wl.js.map +1 -0
- package/dist/{AuthSimulationSelector-iEZ-Or_1.js → AuthSimulationSelector-Bougd521.js} +2 -2
- package/dist/AuthSimulationSelector-Bougd521.js.map +1 -0
- package/dist/BackupsView-DNS6LdVg.js +227 -0
- package/dist/BackupsView-DNS6LdVg.js.map +1 -0
- package/dist/{BranchesView-Dlg78EQ8.js → BranchesView-DH0qnU9J.js} +2 -2
- package/dist/BranchesView-DH0qnU9J.js.map +1 -0
- package/dist/{CronJobsView-4gdtJvoe.js → CronJobsView-B59i3Mis.js} +2 -2
- package/dist/CronJobsView-B59i3Mis.js.map +1 -0
- package/dist/{JSEditor-Ca4XYGRp.js → JSEditor-BeHHuxhA.js} +28 -32
- package/dist/JSEditor-BeHHuxhA.js.map +1 -0
- package/dist/LogsExplorer-BCXoGREr.js +298 -0
- package/dist/LogsExplorer-BCXoGREr.js.map +1 -0
- package/dist/{MonacoEditor-COZqrIJ1.js → MonacoEditor-D0_QljcX.js} +2 -2
- package/dist/MonacoEditor-D0_QljcX.js.map +1 -0
- package/dist/{RLSEditor-BM64laoW.js → RLSEditor-D6adwB6e.js} +38 -34
- package/dist/RLSEditor-D6adwB6e.js.map +1 -0
- package/dist/{SQLEditor-CuAhR-zr.js → SQLEditor-_dCqVAN_.js} +8 -8
- package/dist/SQLEditor-_dCqVAN_.js.map +1 -0
- package/dist/{SchemaVisualizer-OibKoD3g.js → SchemaVisualizer-C_ErehfH.js} +11 -11
- package/dist/SchemaVisualizer-C_ErehfH.js.map +1 -0
- package/dist/{StorageView-BMhD29YO.js → StorageView-UvyM2xdW.js} +2 -2
- package/dist/StorageView-UvyM2xdW.js.map +1 -0
- package/dist/components/AuthSimulationSelector.d.ts +1 -1
- package/dist/components/Backups/BackupsView.d.ts +2 -0
- package/dist/components/SchemaVisualizer/useSchemaGraph.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.es.js +74 -111
- package/dist/index.es.js.map +1 -1
- package/dist/utils/pgColumnToProperty.d.ts +3 -3
- package/dist/utils/sql_utils.d.ts +3 -3
- package/package.json +11 -12
- package/src/components/ApiExplorer/ApiExplorer.tsx +1 -1
- package/src/components/ApiExplorer/TryItPanel.tsx +1 -1
- package/src/components/ApiKeys/ApiKeysView.tsx +43 -3
- package/src/components/AuthSimulationSelector.tsx +1 -1
- package/src/components/Backups/BackupsView.tsx +185 -0
- package/src/components/Branches/BranchesView.tsx +1 -1
- package/src/components/CronJobs/CronJobsView.tsx +1 -1
- package/src/components/JSEditor/JSEditor.tsx +12 -12
- package/src/components/JSEditor/JSMonacoEditor.tsx +21 -25
- package/src/components/LogsExplorer/LogsExplorer.tsx +168 -46
- package/src/components/RLSEditor/PolicyEditor.tsx +5 -3
- package/src/components/RLSEditor/RLSEditor.tsx +51 -34
- package/src/components/RebaseStudio.tsx +12 -3
- package/src/components/SQLEditor/MonacoEditor.tsx +1 -1
- package/src/components/SQLEditor/SQLEditor.tsx +6 -6
- package/src/components/SQLEditor/SQLEditorSidebar.tsx +1 -1
- package/src/components/SQLEditor/SchemaBrowser.tsx +3 -3
- package/src/components/SchemaVisualizer/SchemaVisualizer.tsx +10 -9
- package/src/components/SchemaVisualizer/TableNode.tsx +1 -1
- package/src/components/SchemaVisualizer/useSchemaGraph.ts +11 -11
- package/src/components/StorageView/StorageView.tsx +1 -1
- package/src/components/StudioHomePage.tsx +62 -87
- package/src/index.ts +4 -4
- package/src/utils/pgColumnToProperty.ts +3 -3
- package/src/utils/sql_utils.test.ts +6 -6
- package/src/utils/sql_utils.ts +3 -3
- package/dist/ApiExplorer-CdIwR9Ga.js.map +0 -1
- package/dist/ApiKeysView-D-_FSlNL.js.map +0 -1
- package/dist/AuthSimulationSelector-iEZ-Or_1.js.map +0 -1
- package/dist/BranchesView-Dlg78EQ8.js.map +0 -1
- package/dist/CronJobsView-4gdtJvoe.js.map +0 -1
- package/dist/JSEditor-Ca4XYGRp.js.map +0 -1
- package/dist/LogsExplorer-J4xfsuv3.js +0 -206
- package/dist/LogsExplorer-J4xfsuv3.js.map +0 -1
- package/dist/MonacoEditor-COZqrIJ1.js.map +0 -1
- package/dist/RLSEditor-BM64laoW.js.map +0 -1
- package/dist/SQLEditor-CuAhR-zr.js.map +0 -1
- package/dist/SchemaVisualizer-OibKoD3g.js.map +0 -1
- package/dist/StorageView-BMhD29YO.js.map +0 -1
- package/dist/index.umd.js +0 -11491
- package/dist/index.umd.js.map +0 -1
- package/src/vite-env.d.ts +0 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef, useCallback } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Alert,
|
|
4
|
+
Button,
|
|
5
|
+
Chip,
|
|
6
|
+
CircularProgress,
|
|
7
|
+
cls,
|
|
8
|
+
DatabaseIcon,
|
|
9
|
+
defaultBorderMixin,
|
|
10
|
+
DownloadIcon,
|
|
11
|
+
iconSize,
|
|
12
|
+
IconButton,
|
|
13
|
+
RefreshCwIcon,
|
|
14
|
+
Typography
|
|
15
|
+
} from "@rebasepro/ui";
|
|
16
|
+
import { useRebaseClient, useSnackbarController } from "@rebasepro/app";
|
|
17
|
+
import type { BackupInfo, RebaseClient } from "@rebasepro/types";
|
|
18
|
+
|
|
19
|
+
function formatSize(bytes: number | undefined): string {
|
|
20
|
+
if (bytes === undefined || bytes === null) return "—";
|
|
21
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
22
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
23
|
+
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
24
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function formatDate(iso: string | undefined): string {
|
|
28
|
+
if (!iso) return "—";
|
|
29
|
+
const d = new Date(iso);
|
|
30
|
+
if (isNaN(d.getTime())) return "—";
|
|
31
|
+
return d.toLocaleString();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function BackupsView() {
|
|
35
|
+
const client = useRebaseClient<RebaseClient>();
|
|
36
|
+
const snackbar = useSnackbarController();
|
|
37
|
+
|
|
38
|
+
const [backups, setBackups] = useState<BackupInfo[]>([]);
|
|
39
|
+
const [destinationKind, setDestinationKind] = useState<string>("local");
|
|
40
|
+
const [configured, setConfigured] = useState(true);
|
|
41
|
+
const [loading, setLoading] = useState(true);
|
|
42
|
+
const [downloading, setDownloading] = useState<string | null>(null);
|
|
43
|
+
|
|
44
|
+
const clientRef = useRef(client);
|
|
45
|
+
clientRef.current = client;
|
|
46
|
+
const snackbarRef = useRef(snackbar);
|
|
47
|
+
snackbarRef.current = snackbar;
|
|
48
|
+
|
|
49
|
+
const load = useCallback(async () => {
|
|
50
|
+
const c = clientRef.current;
|
|
51
|
+
if (!c?.backups) {
|
|
52
|
+
setLoading(false);
|
|
53
|
+
setConfigured(false);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const res = await c.backups.list();
|
|
58
|
+
setBackups(res.backups);
|
|
59
|
+
setDestinationKind(res.destinationKind);
|
|
60
|
+
setConfigured(res.configured);
|
|
61
|
+
} catch (e: unknown) {
|
|
62
|
+
snackbarRef.current.open({
|
|
63
|
+
type: "error",
|
|
64
|
+
message: e instanceof Error ? e.message : String(e)
|
|
65
|
+
});
|
|
66
|
+
} finally {
|
|
67
|
+
setLoading(false);
|
|
68
|
+
}
|
|
69
|
+
}, []);
|
|
70
|
+
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
load();
|
|
73
|
+
}, [load]);
|
|
74
|
+
|
|
75
|
+
const handleDownload = async (backup: BackupInfo) => {
|
|
76
|
+
const c = clientRef.current;
|
|
77
|
+
if (!c?.backups) return;
|
|
78
|
+
setDownloading(backup.key);
|
|
79
|
+
try {
|
|
80
|
+
const blob = await c.backups.download(backup.key);
|
|
81
|
+
const url = URL.createObjectURL(blob);
|
|
82
|
+
const a = document.createElement("a");
|
|
83
|
+
a.href = url;
|
|
84
|
+
a.download = backup.name;
|
|
85
|
+
document.body.appendChild(a);
|
|
86
|
+
a.click();
|
|
87
|
+
a.remove();
|
|
88
|
+
URL.revokeObjectURL(url);
|
|
89
|
+
} catch (e: unknown) {
|
|
90
|
+
snackbarRef.current.open({
|
|
91
|
+
type: "error",
|
|
92
|
+
message: e instanceof Error ? e.message : String(e)
|
|
93
|
+
});
|
|
94
|
+
} finally {
|
|
95
|
+
setDownloading(null);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Backups API not available on this client (e.g. non-Postgres backend).
|
|
100
|
+
if (!client?.backups) {
|
|
101
|
+
return (
|
|
102
|
+
<div className="flex flex-col items-center justify-center h-full gap-4 text-center p-8">
|
|
103
|
+
<DatabaseIcon size={iconSize.large} className="text-surface-300 dark:text-surface-600"/>
|
|
104
|
+
<Typography variant="h6" color="secondary">Backups Not Available</Typography>
|
|
105
|
+
<Typography variant="body2" color="disabled" className="max-w-md">
|
|
106
|
+
The backups API is not exposed by this backend.
|
|
107
|
+
</Typography>
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (loading) {
|
|
113
|
+
return (
|
|
114
|
+
<div className="flex items-center justify-center h-full">
|
|
115
|
+
<CircularProgress/>
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<div className="flex flex-col h-full w-full overflow-hidden bg-white dark:bg-surface-950">
|
|
122
|
+
{/* Header */}
|
|
123
|
+
<div className={cls("flex items-center justify-between px-5 py-2.5 border-b bg-surface-50 dark:bg-surface-900 min-h-[48px]", defaultBorderMixin)}>
|
|
124
|
+
<div className="flex items-center gap-2">
|
|
125
|
+
<DatabaseIcon size={iconSize.small} className="text-primary"/>
|
|
126
|
+
<Typography variant="subtitle2" className="font-semibold">Backups</Typography>
|
|
127
|
+
<Chip size="smallest" className="bg-surface-200 dark:bg-surface-700 text-surface-600 dark:text-surface-300">{backups.length}</Chip>
|
|
128
|
+
<Chip size="smallest" className="bg-surface-100 dark:bg-surface-800 text-surface-500 dark:text-surface-400 uppercase font-mono text-[10px]">{destinationKind}</Chip>
|
|
129
|
+
</div>
|
|
130
|
+
<IconButton size="small" onClick={load} title="Refresh">
|
|
131
|
+
<RefreshCwIcon size={iconSize.smallest}/>
|
|
132
|
+
</IconButton>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
<div className="flex-1 overflow-y-auto p-5">
|
|
136
|
+
{!configured ? (
|
|
137
|
+
<Alert color="info">
|
|
138
|
+
<Typography variant="body2" className="text-[13px]">
|
|
139
|
+
<strong>Backups are not configured.</strong> Set
|
|
140
|
+
<code className="mx-1 px-1.5 py-0.5 rounded bg-surface-100 dark:bg-surface-950 font-mono text-[12px]">BACKUP_DESTINATION</code>
|
|
141
|
+
(a local path or an <code className="font-mono text-[12px]">s3://</code> / <code className="font-mono text-[12px]">gs://</code> URL) and create backups with
|
|
142
|
+
<code className="mx-1 px-1.5 py-0.5 rounded bg-surface-100 dark:bg-surface-950 font-mono text-[12px]">rebase db backup</code>
|
|
143
|
+
or a scheduled cron. See docs/backups.md.
|
|
144
|
+
</Typography>
|
|
145
|
+
</Alert>
|
|
146
|
+
) : backups.length === 0 ? (
|
|
147
|
+
<div className="flex flex-col items-center justify-center h-full gap-3 text-center">
|
|
148
|
+
<DatabaseIcon size={iconSize.large} className="text-surface-200 dark:text-surface-700"/>
|
|
149
|
+
<Typography variant="body2" color="disabled">
|
|
150
|
+
No backups found yet. Run <code className="font-mono text-[12px]">rebase db backup</code> or wait for the next scheduled run.
|
|
151
|
+
</Typography>
|
|
152
|
+
</div>
|
|
153
|
+
) : (
|
|
154
|
+
<div className="space-y-2 max-w-3xl">
|
|
155
|
+
{backups.map(backup => (
|
|
156
|
+
<div
|
|
157
|
+
key={backup.key}
|
|
158
|
+
className={cls("flex items-center gap-3 px-4 py-3 rounded-lg border bg-white dark:bg-surface-900", defaultBorderMixin)}
|
|
159
|
+
>
|
|
160
|
+
<DatabaseIcon size={iconSize.small} className="text-surface-400 shrink-0"/>
|
|
161
|
+
<div className="flex-1 min-w-0">
|
|
162
|
+
<Typography variant="body2" className="truncate font-medium font-mono text-[12px]">{backup.name}</Typography>
|
|
163
|
+
<Typography variant="caption" color="secondary" className="text-[11px]">
|
|
164
|
+
{formatDate(backup.createdAt)} · {formatSize(backup.sizeBytes)}
|
|
165
|
+
</Typography>
|
|
166
|
+
</div>
|
|
167
|
+
<Button
|
|
168
|
+
size="small"
|
|
169
|
+
variant="outlined"
|
|
170
|
+
onClick={() => handleDownload(backup)}
|
|
171
|
+
disabled={downloading === backup.key}
|
|
172
|
+
startIcon={downloading === backup.key
|
|
173
|
+
? <CircularProgress size="smallest"/>
|
|
174
|
+
: <DownloadIcon size={iconSize.smallest}/>}
|
|
175
|
+
>
|
|
176
|
+
{downloading === backup.key ? "Downloading…" : "Download"}
|
|
177
|
+
</Button>
|
|
178
|
+
</div>
|
|
179
|
+
))}
|
|
180
|
+
</div>
|
|
181
|
+
)}
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
Trash2Icon,
|
|
25
25
|
Typography
|
|
26
26
|
} from "@rebasepro/ui";
|
|
27
|
-
import { useRebaseContext, useSnackbarController, ConfirmationDialog } from "@rebasepro/
|
|
27
|
+
import { useRebaseContext, useSnackbarController, ConfirmationDialog } from "@rebasepro/app";
|
|
28
28
|
import { isBranchAdmin } from "@rebasepro/types";
|
|
29
29
|
import type { BranchInfo } from "@rebasepro/types";
|
|
30
30
|
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
RefreshCwIcon,
|
|
20
20
|
Typography
|
|
21
21
|
} from "@rebasepro/ui";
|
|
22
|
-
import { useRebaseClient, useSnackbarController } from "@rebasepro/
|
|
22
|
+
import { useRebaseClient, useSnackbarController } from "@rebasepro/app";
|
|
23
23
|
import type { CronJobStatus, CronJobLogEntry } from "@rebasepro/types";
|
|
24
24
|
import type { RebaseClient } from "@rebasepro/types";
|
|
25
25
|
|
|
@@ -35,9 +35,9 @@ import {
|
|
|
35
35
|
VirtualTableColumn,
|
|
36
36
|
XIcon
|
|
37
37
|
} from "@rebasepro/ui";
|
|
38
|
-
import { useStudioUrlController, useStudioCollectionRegistry,
|
|
39
|
-
import { useRebaseContext, useRebaseClient, useSnackbarController, useApiConfig, useTranslation, useModeController, ErrorView, SelectableUser, IconForView } from "@rebasepro/
|
|
40
|
-
import {
|
|
38
|
+
import { useStudioUrlController, useStudioCollectionRegistry, useStudioSidePanelController } from "@rebasepro/app";
|
|
39
|
+
import { useRebaseContext, useRebaseClient, useSnackbarController, useApiConfig, useTranslation, useModeController, ErrorView, SelectableUser, IconForView } from "@rebasepro/app";
|
|
40
|
+
import { CollectionConfig } from "@rebasepro/types";
|
|
41
41
|
import { createRebaseClient } from "@rebasepro/client";
|
|
42
42
|
import { JSMonacoEditor } from "./JSMonacoEditor";
|
|
43
43
|
import { JSEditorSidebar, JSSnippet } from "./JSEditorSidebar";
|
|
@@ -65,7 +65,7 @@ interface EditorTab {
|
|
|
65
65
|
code: string;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
// SelectedUser is now SelectableUser from @rebasepro/
|
|
68
|
+
// SelectedUser is now SelectableUser from @rebasepro/app
|
|
69
69
|
|
|
70
70
|
// ─── Constants ───────────────────────────────────────────────────────
|
|
71
71
|
|
|
@@ -113,7 +113,7 @@ function formatJSON(value: unknown): string {
|
|
|
113
113
|
|
|
114
114
|
interface MatchedJSCollection {
|
|
115
115
|
collectionSlug: string;
|
|
116
|
-
collection:
|
|
116
|
+
collection: CollectionConfig;
|
|
117
117
|
pkColumn: string;
|
|
118
118
|
}
|
|
119
119
|
|
|
@@ -126,7 +126,7 @@ interface MatchedJSCollection {
|
|
|
126
126
|
function detectCollectionsInResult(
|
|
127
127
|
code: string,
|
|
128
128
|
resultValue: unknown,
|
|
129
|
-
collections:
|
|
129
|
+
collections: CollectionConfig[]
|
|
130
130
|
): MatchedJSCollection[] {
|
|
131
131
|
if (!resultValue || !collections?.length) return [];
|
|
132
132
|
|
|
@@ -190,7 +190,7 @@ export function JSEditor() {
|
|
|
190
190
|
const apiConfig = useApiConfig();
|
|
191
191
|
const snackbar = useSnackbarController();
|
|
192
192
|
const collectionRegistry = useStudioCollectionRegistry();
|
|
193
|
-
const
|
|
193
|
+
const sidePanelController = useStudioSidePanelController();
|
|
194
194
|
const { t } = useTranslation();
|
|
195
195
|
|
|
196
196
|
// User management for the "Run as" picker
|
|
@@ -670,7 +670,7 @@ message: t("studio_sql_markdown_copy_failed") });
|
|
|
670
670
|
</div>
|
|
671
671
|
</div>
|
|
672
672
|
<div className="flex shrink-0 items-center justify-end gap-1.5">
|
|
673
|
-
<Tooltip title="
|
|
673
|
+
<Tooltip title="Save as snippet">
|
|
674
674
|
<IconButton
|
|
675
675
|
size="small"
|
|
676
676
|
onClick={() => {
|
|
@@ -854,7 +854,7 @@ id: String(ra.entityId) })}>
|
|
|
854
854
|
className="text-surface-400 dark:text-surface-500 hover:text-surface-600 dark:hover:text-surface-300"
|
|
855
855
|
onClick={(e) => {
|
|
856
856
|
e.stopPropagation();
|
|
857
|
-
|
|
857
|
+
sidePanelController.open({
|
|
858
858
|
path: ra.collection.collectionSlug,
|
|
859
859
|
entityId: ra.entityId,
|
|
860
860
|
collection: ra.collection.collection,
|
|
@@ -887,7 +887,7 @@ id: String(ra.entityId) })}>
|
|
|
887
887
|
key={ra.collection.collectionSlug}
|
|
888
888
|
dense
|
|
889
889
|
onClick={() => {
|
|
890
|
-
|
|
890
|
+
sidePanelController.open({
|
|
891
891
|
path: ra.collection.collectionSlug,
|
|
892
892
|
entityId: ra.entityId,
|
|
893
893
|
collection: ra.collection.collection,
|
|
@@ -1009,9 +1009,9 @@ id: String(ra.entityId) })}
|
|
|
1009
1009
|
/>
|
|
1010
1010
|
</div>
|
|
1011
1011
|
|
|
1012
|
-
{/*
|
|
1012
|
+
{/* Save snippet dialog */}
|
|
1013
1013
|
<Dialog open={showSaveDialog} onOpenChange={setShowSaveDialog}>
|
|
1014
|
-
<DialogTitle>
|
|
1014
|
+
<DialogTitle>Save Snippet</DialogTitle>
|
|
1015
1015
|
<DialogContent>
|
|
1016
1016
|
<TextField
|
|
1017
1017
|
label="Snippet name"
|
|
@@ -3,7 +3,7 @@ import React, { useRef, useEffect } from "react";
|
|
|
3
3
|
import Editor, { Monaco, OnMount } from "@monaco-editor/react";
|
|
4
4
|
import type { editor } from "monaco-editor";
|
|
5
5
|
import { cls, defaultBorderMixin, FileIcon } from "@rebasepro/ui";
|
|
6
|
-
import { useModeController } from "@rebasepro/
|
|
6
|
+
import { useModeController } from "@rebasepro/app";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Shape of `monaco.languages.typescript` at runtime.
|
|
@@ -23,11 +23,7 @@ interface MonacoTypeScriptApi {
|
|
|
23
23
|
const REBASE_CLIENT_TYPES = `
|
|
24
24
|
// ─── Rebase Client SDK Type Definitions ─────────────────────────────
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
id: string | number;
|
|
28
|
-
path: string;
|
|
29
|
-
values: M;
|
|
30
|
-
}
|
|
26
|
+
/** A flat database row with the id merged at the top level. */
|
|
31
27
|
|
|
32
28
|
interface FindParams {
|
|
33
29
|
limit?: number;
|
|
@@ -39,8 +35,8 @@ interface FindParams {
|
|
|
39
35
|
searchString?: string;
|
|
40
36
|
}
|
|
41
37
|
|
|
42
|
-
interface
|
|
43
|
-
data:
|
|
38
|
+
interface FindResult<M extends Record<string, any> = any> {
|
|
39
|
+
data: M[];
|
|
44
40
|
meta: {
|
|
45
41
|
total: number;
|
|
46
42
|
limit: number;
|
|
@@ -57,55 +53,55 @@ interface QueryBuilder<M extends Record<string, any> = any> {
|
|
|
57
53
|
limit(count: number): QueryBuilder<M>;
|
|
58
54
|
offset(count: number): QueryBuilder<M>;
|
|
59
55
|
search(searchString: string): QueryBuilder<M>;
|
|
60
|
-
find(): Promise<
|
|
61
|
-
findOne(): Promise<Entity<M> | undefined>;
|
|
56
|
+
find(): Promise<FindResult<M>>;
|
|
62
57
|
count(): Promise<number>;
|
|
63
58
|
}
|
|
64
59
|
|
|
65
60
|
interface CollectionClient<M extends Record<string, any> = any> {
|
|
66
|
-
find(params?: FindParams): Promise<
|
|
67
|
-
findById(id: string | number): Promise<
|
|
68
|
-
create(data: Partial<M>, id?: string | number): Promise<
|
|
69
|
-
update(id: string | number, data: Partial<M>): Promise<
|
|
61
|
+
find(params?: FindParams): Promise<FindResult<M>>;
|
|
62
|
+
findById(id: string | number): Promise<M | undefined>;
|
|
63
|
+
create(data: Partial<M>, id?: string | number): Promise<M>;
|
|
64
|
+
update(id: string | number, data: Partial<M>): Promise<M>;
|
|
70
65
|
delete(id: string | number): Promise<void>;
|
|
71
66
|
where(column: keyof M & string, operator: WhereFilterOp, value: any): QueryBuilder<M>;
|
|
72
67
|
orderBy(column: keyof M & string, direction?: "asc" | "desc"): QueryBuilder<M>;
|
|
73
68
|
limit(count: number): QueryBuilder<M>;
|
|
74
69
|
offset(count: number): QueryBuilder<M>;
|
|
75
70
|
search(searchString: string): QueryBuilder<M>;
|
|
76
|
-
listen?(params: FindParams | undefined, onUpdate: (response:
|
|
77
|
-
listenById?(id: string | number, onUpdate: (
|
|
71
|
+
listen?(params: FindParams | undefined, onUpdate: (response: FindResult<M>) => void, onError?: (error: Error) => void): () => void;
|
|
72
|
+
listenById?(id: string | number, onUpdate: (row: M | undefined) => void, onError?: (error: Error) => void): () => void;
|
|
78
73
|
count?(params?: FindParams): Promise<number>;
|
|
79
74
|
}
|
|
80
75
|
|
|
81
|
-
interface
|
|
76
|
+
interface User {
|
|
82
77
|
uid: string;
|
|
83
78
|
email: string | null;
|
|
84
79
|
displayName: string | null;
|
|
85
80
|
photoURL: string | null;
|
|
86
|
-
emailVerified?: boolean;
|
|
87
|
-
roles?: string[];
|
|
88
81
|
providerId: string;
|
|
89
82
|
isAnonymous: boolean;
|
|
83
|
+
emailVerified?: boolean;
|
|
84
|
+
roles?: string[];
|
|
85
|
+
metadata?: Record<string, unknown>;
|
|
90
86
|
}
|
|
91
87
|
|
|
92
88
|
interface RebaseSession {
|
|
93
89
|
accessToken: string;
|
|
94
90
|
refreshToken: string;
|
|
95
91
|
expiresAt: number;
|
|
96
|
-
user:
|
|
92
|
+
user: User;
|
|
97
93
|
}
|
|
98
94
|
|
|
99
95
|
type AuthChangeEvent = 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED';
|
|
100
96
|
|
|
101
97
|
interface RebaseAuth {
|
|
102
|
-
signInWithEmail(email: string, password: string): Promise<{ user:
|
|
103
|
-
signUp(email: string, password: string, displayName?: string): Promise<{ user:
|
|
104
|
-
signInWithGoogle(idToken: string): Promise<{ user:
|
|
98
|
+
signInWithEmail(email: string, password: string): Promise<{ user: User; accessToken: string; refreshToken: string }>;
|
|
99
|
+
signUp(email: string, password: string, displayName?: string): Promise<{ user: User; accessToken: string; refreshToken: string }>;
|
|
100
|
+
signInWithGoogle(idToken: string): Promise<{ user: User; accessToken: string; refreshToken: string }>;
|
|
105
101
|
signOut(): Promise<void>;
|
|
106
102
|
refreshSession(): Promise<RebaseSession>;
|
|
107
|
-
getUser(): Promise<
|
|
108
|
-
updateUser(updates: { displayName?: string; photoURL?: string }): Promise<
|
|
103
|
+
getUser(): Promise<User>;
|
|
104
|
+
updateUser(updates: { displayName?: string; photoURL?: string }): Promise<User>;
|
|
109
105
|
resetPasswordForEmail(email: string): Promise<{ success: boolean; message: string }>;
|
|
110
106
|
resetPassword(token: string, password: string): Promise<{ success: boolean; message: string }>;
|
|
111
107
|
changePassword(oldPassword: string, newPassword: string): Promise<{ success: boolean; message: string }>;
|