mirror of
https://github.com/bknd-io/bknd/
synced 2026-08-03 08:36:01 +00:00
Merge remote-tracking branch 'origin/main' into feat/jsonv-refactor
# Conflicts: # bun.lock
This commit is contained in:
+1
-1
@@ -3,7 +3,7 @@
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
"bin": "./dist/cli/index.js",
|
||||
"version": "0.15.0-rc.8",
|
||||
"version": "0.15.0",
|
||||
"description": "Lightweight Firebase/Supabase alternative built to run anywhere — incl. Next.js, React Router, Astro, Cloudflare, Bun, Node, AWS Lambda & more.",
|
||||
"homepage": "https://bknd.io",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Connection } from "bknd/data";
|
||||
import { bunSqlite } from "../bun/connection/BunSqliteConnection";
|
||||
|
||||
export function sqlite(config: { url: string }): Connection {
|
||||
export function sqlite(config?: { url: string }): Connection {
|
||||
return bunSqlite(config);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Connection } from "bknd/data";
|
||||
import { nodeSqlite } from "../node/connection/NodeSqliteConnection";
|
||||
|
||||
export function sqlite(config: { url: string }): Connection {
|
||||
export function sqlite(config?: { url: string }): Connection {
|
||||
return nodeSqlite(config);
|
||||
}
|
||||
|
||||
@@ -334,9 +334,9 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
||||
await setSignedCookie(c, "auth", token, secret, this.cookieOptions);
|
||||
}
|
||||
|
||||
private async deleteAuthCookie(c: Context) {
|
||||
private deleteAuthCookie(c: Context) {
|
||||
$console.debug("deleting auth cookie");
|
||||
await deleteCookie(c, "auth", this.cookieOptions);
|
||||
deleteCookie(c, "auth", this.cookieOptions);
|
||||
}
|
||||
|
||||
async logout(c: Context<ServerEnv>) {
|
||||
@@ -345,9 +345,13 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
||||
|
||||
const cookie = await this.getAuthCookie(c);
|
||||
if (cookie) {
|
||||
await this.deleteAuthCookie(c);
|
||||
await addFlashMessage(c, "Signed out", "info");
|
||||
addFlashMessage(c, "Signed out", "info");
|
||||
}
|
||||
|
||||
// on waku, only one cookie setting is performed
|
||||
// therefore adding deleting cookie at the end
|
||||
// as the flash isn't that important
|
||||
this.deleteAuthCookie(c);
|
||||
}
|
||||
|
||||
// @todo: move this to a server helper
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Client, Config, ResultSet } from "@libsql/client";
|
||||
import type { Client, Config, InStatement, ResultSet, TransactionMode } from "@libsql/client";
|
||||
import { createClient } from "libsql-stateless-easy";
|
||||
import { FilterNumericKeysPlugin } from "data/plugins/FilterNumericKeysPlugin";
|
||||
import {
|
||||
@@ -10,7 +10,12 @@ import type { QueryResult } from "kysely";
|
||||
export type LibsqlConnection = GenericSqliteConnection<Client>;
|
||||
export type LibSqlCredentials = Config;
|
||||
|
||||
function getClient(clientOrCredentials: Client | LibSqlCredentials): Client {
|
||||
export type LibsqlClientFns = {
|
||||
execute: (statement: InStatement) => Promise<ResultSet>;
|
||||
batch: (statements: InStatement[], mode?: TransactionMode) => Promise<ResultSet[]>;
|
||||
};
|
||||
|
||||
function getClient(clientOrCredentials: Client | LibSqlCredentials | LibsqlClientFns): Client {
|
||||
if (clientOrCredentials && "url" in clientOrCredentials) {
|
||||
const { url, authToken } = clientOrCredentials;
|
||||
return createClient({ url, authToken });
|
||||
@@ -19,7 +24,7 @@ function getClient(clientOrCredentials: Client | LibSqlCredentials): Client {
|
||||
return clientOrCredentials as Client;
|
||||
}
|
||||
|
||||
export function libsql(config: LibSqlCredentials | Client) {
|
||||
export function libsql(config: LibSqlCredentials | Client | LibsqlClientFns) {
|
||||
const db = getClient(config);
|
||||
|
||||
return genericSqlite(
|
||||
|
||||
@@ -51,7 +51,7 @@ export class AdminController extends Controller {
|
||||
basepath: this._options.basepath ?? "/",
|
||||
adminBasepath: this._options.adminBasepath ?? "",
|
||||
assetsPath: this._options.assetsPath ?? config.server.assets_path,
|
||||
theme: this._options.theme ?? "system",
|
||||
//theme: this._options.theme ?? "system",
|
||||
logo_return_path: this._options.logoReturnPath ?? "/",
|
||||
};
|
||||
}
|
||||
@@ -195,7 +195,7 @@ export class AdminController extends Controller {
|
||||
if (isProd) {
|
||||
let manifest: any;
|
||||
if (this.options.assetsPath.startsWith("http")) {
|
||||
manifest = await fetch(this.options.assetsPath + "manifest.json", {
|
||||
manifest = await fetch(this.options.assetsPath + ".vite/manifest.json", {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
|
||||
@@ -55,7 +55,7 @@ export default function Admin({
|
||||
|
||||
const Skeleton = ({ theme }: { theme?: any }) => {
|
||||
const t = useTheme();
|
||||
const actualTheme = theme ?? t.theme;
|
||||
const actualTheme = theme && ["dark", "light"].includes(theme) ? theme : t.theme;
|
||||
|
||||
return (
|
||||
<div id="bknd-admin" className={actualTheme + " antialiased"}>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Link, useLocation } from "wouter";
|
||||
import { IconButton } from "../../components/buttons/IconButton";
|
||||
import { Dropdown } from "../../components/overlay/Dropdown";
|
||||
import { useEvent } from "../../hooks/use-event";
|
||||
import { useNavigate } from "ui/lib/routes";
|
||||
|
||||
type Breadcrumb = {
|
||||
label: string | Element;
|
||||
@@ -17,26 +18,11 @@ export type Breadcrumbs2Props = {
|
||||
};
|
||||
|
||||
export const Breadcrumbs2 = ({ path: _path, backTo, onBack }: Breadcrumbs2Props) => {
|
||||
const [_, navigate] = useLocation();
|
||||
const location = window.location.pathname;
|
||||
const [, , _goBack] = useNavigate();
|
||||
const path = Array.isArray(_path) ? _path : [_path];
|
||||
const loc = location.split("/").filter((v) => v !== "");
|
||||
const hasBack = path.length > 1;
|
||||
|
||||
const goBack = onBack
|
||||
? onBack
|
||||
: useEvent(() => {
|
||||
if (backTo) {
|
||||
navigate(backTo, { replace: true });
|
||||
return;
|
||||
} else if (_path.length > 0 && _path[0]?.href) {
|
||||
navigate(_path[0].href, { replace: true });
|
||||
return;
|
||||
}
|
||||
|
||||
const href = loc.slice(0, path.length + 1).join("/");
|
||||
navigate(`~/${href}`, { replace: true });
|
||||
});
|
||||
const goBack = onBack ? onBack : () => _goBack({ fallback: backTo });
|
||||
|
||||
const crumbs = useMemo(
|
||||
() =>
|
||||
|
||||
@@ -185,9 +185,7 @@ function UserMenu() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.theme) {
|
||||
items.push(() => <UserMenuThemeToggler />);
|
||||
}
|
||||
items.push(() => <UserMenuThemeToggler />);
|
||||
items.push(() => (
|
||||
<div className="font-mono leading-none text-xs text-primary/50 text-center pb-1 pt-2 mt-1 border-t border-primary/5">
|
||||
{getVersion()}
|
||||
|
||||
@@ -102,13 +102,29 @@ export function useNavigate() {
|
||||
}
|
||||
|
||||
const _url = options?.absolute ? `~/${basepath}${url}`.replace(/\/+/g, "/") : url;
|
||||
const state = {
|
||||
...options?.state,
|
||||
referrer: location,
|
||||
};
|
||||
|
||||
navigate(options?.query ? withQuery(_url, options?.query) : _url, {
|
||||
replace: options?.replace,
|
||||
state: options?.state,
|
||||
state,
|
||||
});
|
||||
});
|
||||
},
|
||||
location,
|
||||
(opts?: { fallback?: string }) => {
|
||||
const state = window.history.state;
|
||||
if (state?.referrer) {
|
||||
//window.history.replaceState(state, "", state.referrer);
|
||||
navigate(state.referrer, { replace: true });
|
||||
} else if (opts?.fallback) {
|
||||
navigate(opts.fallback, { replace: true });
|
||||
} else {
|
||||
window.history.back();
|
||||
}
|
||||
},
|
||||
] as const;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ function DataEntityUpdateImpl({ params }) {
|
||||
|
||||
const entityId = params.id as PrimaryFieldType;
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [navigate] = useNavigate();
|
||||
const [navigate, _, _goBack] = useNavigate();
|
||||
useBrowserTitle(["Data", entity.label, `#${entityId}`]);
|
||||
const targetRelations = relations.listableRelationsOf(entity);
|
||||
|
||||
@@ -52,9 +52,8 @@ function DataEntityUpdateImpl({ params }) {
|
||||
},
|
||||
);
|
||||
|
||||
function goBack() {
|
||||
window.history.go(-1);
|
||||
}
|
||||
const backHref = routes.data.entity.list(entity.name);
|
||||
const goBack = () => _goBack({ fallback: backHref });
|
||||
|
||||
async function onSubmitted(changeSet?: EntityData) {
|
||||
//return;
|
||||
@@ -162,10 +161,8 @@ function DataEntityUpdateImpl({ params }) {
|
||||
className="pl-3"
|
||||
>
|
||||
<Breadcrumbs2
|
||||
path={[
|
||||
{ label: entity.label, href: routes.data.entity.list(entity.name) },
|
||||
{ label: `Edit #${entityId}` },
|
||||
]}
|
||||
backTo={backHref}
|
||||
path={[{ label: entity.label, href: backHref }, { label: `Edit #${entityId}` }]}
|
||||
/>
|
||||
</AppShell.SectionHeader>
|
||||
{$q.isLoading ? (
|
||||
|
||||
@@ -8,13 +8,14 @@ import { useBrowserTitle } from "ui/hooks/use-browser-title";
|
||||
import { useSearch } from "ui/hooks/use-search";
|
||||
import * as AppShell from "ui/layouts/AppShell/AppShell";
|
||||
import { Breadcrumbs2 } from "ui/layouts/AppShell/Breadcrumbs2";
|
||||
import { routes } from "ui/lib/routes";
|
||||
import { routes, useNavigate } from "ui/lib/routes";
|
||||
import { EntityForm } from "ui/modules/data/components/EntityForm";
|
||||
import { useEntityForm } from "ui/modules/data/hooks/useEntityForm";
|
||||
import { s } from "core/object/schema";
|
||||
|
||||
export function DataEntityCreate({ params }) {
|
||||
const { $data } = useBkndData();
|
||||
const [navigate, _, _goBack] = useNavigate();
|
||||
const entity = $data.entity(params.entity as string);
|
||||
if (!entity) {
|
||||
return <Message.NotFound description={`Entity "${params.entity}" doesn't exist.`} />;
|
||||
@@ -30,9 +31,8 @@ export function DataEntityCreate({ params }) {
|
||||
// @todo: use entity schema for prefilling
|
||||
const search = useSearch(s.object({}), {});
|
||||
|
||||
function goBack() {
|
||||
window.history.go(-1);
|
||||
}
|
||||
const backHref = routes.data.entity.list(entity.name);
|
||||
const goBack = () => _goBack({ fallback: backHref });
|
||||
|
||||
async function onSubmitted(changeSet?: EntityData) {
|
||||
console.log("create:changeSet", changeSet);
|
||||
@@ -80,12 +80,7 @@ export function DataEntityCreate({ params }) {
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Breadcrumbs2
|
||||
path={[
|
||||
{ label: entity.label, href: routes.data.entity.list(entity.name) },
|
||||
{ label: "Create" },
|
||||
]}
|
||||
/>
|
||||
<Breadcrumbs2 backTo={backHref} path={[{ label: entity.label }, { label: "Create" }]} />
|
||||
</AppShell.SectionHeader>
|
||||
<AppShell.Scrollable key={entity.name}>
|
||||
{error && (
|
||||
|
||||
Reference in New Issue
Block a user