mirror of
https://github.com/bknd-io/bknd/
synced 2026-08-02 08:06:00 +00:00
cleanup: replace console.log/warn with $console, remove commented-out code
Removed various commented-out code and replaced direct `console.log` and `console.warn` usage across the codebase with `$console` from "core" for standardized logging. Also adjusted linting rules in biome.json to enable warnings for `console.log` usage.
This commit is contained in:
@@ -117,8 +117,6 @@ export class Api {
|
|||||||
this.updateToken(token);
|
this.updateToken(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.warn("Couldn't extract token");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateToken(token?: string, rebuild?: boolean) {
|
updateToken(token?: string, rebuild?: boolean) {
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ import * as SystemPermissions from "modules/permissions";
|
|||||||
import { AdminController, type AdminControllerOptions } from "modules/server/AdminController";
|
import { AdminController, type AdminControllerOptions } from "modules/server/AdminController";
|
||||||
import { SystemController } from "modules/server/SystemController";
|
import { SystemController } from "modules/server/SystemController";
|
||||||
|
|
||||||
// biome-ignore format: must be there
|
// biome-ignore format: must be here
|
||||||
import { Api, type ApiOptions } from "Api";
|
import { Api, type ApiOptions } from "Api";
|
||||||
import type { ServerEnv } from "modules/Controller";
|
import type { ServerEnv } from "modules/Controller";
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { getFresh } from "./modes/fresh";
|
|||||||
import { getCached } from "./modes/cached";
|
import { getCached } from "./modes/cached";
|
||||||
import { getDurable } from "./modes/durable";
|
import { getDurable } from "./modes/durable";
|
||||||
import type { App } from "bknd";
|
import type { App } from "bknd";
|
||||||
|
import { $console } from "core";
|
||||||
|
|
||||||
export type CloudflareEnv = object;
|
export type CloudflareEnv = object;
|
||||||
export type CloudflareBkndConfig<Env = CloudflareEnv> = RuntimeBkndConfig<Env> & {
|
export type CloudflareBkndConfig<Env = CloudflareEnv> = RuntimeBkndConfig<Env> & {
|
||||||
@@ -37,7 +38,7 @@ export function serve<Env extends CloudflareEnv = CloudflareEnv>(
|
|||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
|
|
||||||
if (config.manifest && config.static === "assets") {
|
if (config.manifest && config.static === "assets") {
|
||||||
console.warn("manifest is not useful with static 'assets'");
|
$console.warn("manifest is not useful with static 'assets'");
|
||||||
} else if (!config.manifest && config.static === "kv") {
|
} else if (!config.manifest && config.static === "kv") {
|
||||||
throw new Error("manifest is required with static 'kv'");
|
throw new Error("manifest is required with static 'kv'");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import type { CloudflareBkndConfig, CloudflareEnv } from ".";
|
|||||||
import { App } from "bknd";
|
import { App } from "bknd";
|
||||||
import { makeConfig as makeAdapterConfig } from "bknd/adapter";
|
import { makeConfig as makeAdapterConfig } from "bknd/adapter";
|
||||||
import type { ExecutionContext } from "hono";
|
import type { ExecutionContext } from "hono";
|
||||||
|
import { $console } from "core";
|
||||||
|
|
||||||
export const constants = {
|
export const constants = {
|
||||||
exec_async_event_id: "cf_register_waituntil",
|
exec_async_event_id: "cf_register_waituntil",
|
||||||
@@ -27,12 +28,12 @@ export function makeConfig<Env extends CloudflareEnv = CloudflareEnv>(
|
|||||||
if (!appConfig.connection) {
|
if (!appConfig.connection) {
|
||||||
let db: D1Database | undefined;
|
let db: D1Database | undefined;
|
||||||
if (bindings?.db) {
|
if (bindings?.db) {
|
||||||
console.log("Using database from bindings");
|
$console.log("Using database from bindings");
|
||||||
db = bindings.db;
|
db = bindings.db;
|
||||||
} else if (Object.keys(args).length > 0) {
|
} else if (Object.keys(args).length > 0) {
|
||||||
const binding = getBinding(args, "D1Database");
|
const binding = getBinding(args, "D1Database");
|
||||||
if (binding) {
|
if (binding) {
|
||||||
console.log(`Using database from env "${binding.key}"`);
|
$console.log(`Using database from env "${binding.key}"`);
|
||||||
db = binding.value;
|
db = binding.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { App, CreateAppConfig } from "bknd";
|
|||||||
import { createRuntimeApp, makeConfig } from "bknd/adapter";
|
import { createRuntimeApp, makeConfig } from "bknd/adapter";
|
||||||
import type { CloudflareBkndConfig, Context, CloudflareEnv } from "../index";
|
import type { CloudflareBkndConfig, Context, CloudflareEnv } from "../index";
|
||||||
import { constants, registerAsyncsExecutionContext } from "../config";
|
import { constants, registerAsyncsExecutionContext } from "../config";
|
||||||
|
import { $console } from "core";
|
||||||
|
|
||||||
export async function getDurable<Env extends CloudflareEnv = CloudflareEnv>(
|
export async function getDurable<Env extends CloudflareEnv = CloudflareEnv>(
|
||||||
config: CloudflareBkndConfig<Env>,
|
config: CloudflareBkndConfig<Env>,
|
||||||
@@ -13,7 +14,7 @@ export async function getDurable<Env extends CloudflareEnv = CloudflareEnv>(
|
|||||||
const key = config.key ?? "app";
|
const key = config.key ?? "app";
|
||||||
|
|
||||||
if ([config.onBuilt, config.beforeBuild].some((x) => x)) {
|
if ([config.onBuilt, config.beforeBuild].some((x) => x)) {
|
||||||
console.log("onBuilt and beforeBuild are not supported with DurableObject mode");
|
$console.warn("onBuilt and beforeBuild are not supported with DurableObject mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
|
|||||||
@@ -122,12 +122,10 @@ export class StorageR2Adapter extends StorageAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log("response headers:before", headersToObject(responseHeaders));
|
|
||||||
this.writeHttpMetadata(responseHeaders, object);
|
this.writeHttpMetadata(responseHeaders, object);
|
||||||
responseHeaders.set("etag", object.httpEtag);
|
responseHeaders.set("etag", object.httpEtag);
|
||||||
responseHeaders.set("Content-Length", String(object.size));
|
responseHeaders.set("Content-Length", String(object.size));
|
||||||
responseHeaders.set("Last-Modified", object.uploaded.toUTCString());
|
responseHeaders.set("Last-Modified", object.uploaded.toUTCString());
|
||||||
//console.log("response headers:after", headersToObject(responseHeaders));
|
|
||||||
|
|
||||||
return new Response(object.body, {
|
return new Response(object.body, {
|
||||||
status: object.range ? 206 : 200,
|
status: object.range ? 206 : 200,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { serveStatic } from "@hono/node-server/serve-static";
|
|||||||
import { registerLocalMediaAdapter } from "adapter/node/index";
|
import { registerLocalMediaAdapter } from "adapter/node/index";
|
||||||
import { type RuntimeBkndConfig, createRuntimeApp, type RuntimeOptions } from "bknd/adapter";
|
import { type RuntimeBkndConfig, createRuntimeApp, type RuntimeOptions } from "bknd/adapter";
|
||||||
import { config as $config } from "bknd/core";
|
import { config as $config } from "bknd/core";
|
||||||
|
import { $console } from "core";
|
||||||
|
|
||||||
type NodeEnv = NodeJS.ProcessEnv;
|
type NodeEnv = NodeJS.ProcessEnv;
|
||||||
export type NodeBkndConfig<Env = NodeEnv> = RuntimeBkndConfig<Env> & {
|
export type NodeBkndConfig<Env = NodeEnv> = RuntimeBkndConfig<Env> & {
|
||||||
@@ -62,7 +63,7 @@ export function serve<Env = NodeEnv>(
|
|||||||
fetch: createHandler(config, args, opts),
|
fetch: createHandler(config, args, opts),
|
||||||
},
|
},
|
||||||
(connInfo) => {
|
(connInfo) => {
|
||||||
console.log(`Server is running on http://localhost:${connInfo.port}`);
|
$console.log(`Server is running on http://localhost:${connInfo.port}`);
|
||||||
listener?.(connInfo);
|
listener?.(connInfo);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
|||||||
|
|
||||||
if (!from.enabled && to.enabled) {
|
if (!from.enabled && to.enabled) {
|
||||||
if (to.jwt.secret === defaultSecret) {
|
if (to.jwt.secret === defaultSecret) {
|
||||||
console.warn("No JWT secret provided, generating a random one");
|
$console.warn("No JWT secret provided, generating a random one");
|
||||||
to.jwt.secret = secureRandomString(64);
|
to.jwt.secret = secureRandomString(64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,6 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
|||||||
|
|
||||||
// compare strategy and identifier
|
// compare strategy and identifier
|
||||||
if (result.data.strategy !== strategy.getName()) {
|
if (result.data.strategy !== strategy.getName()) {
|
||||||
//console.log("!!! User registered with different strategy");
|
|
||||||
throw new Exception("User registered with different strategy");
|
throw new Exception("User registered with different strategy");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
import { type DB, Exception, type PrimaryFieldType } from "core";
|
import { $console, type DB, Exception, type PrimaryFieldType } from "core";
|
||||||
import { addFlashMessage } from "core/server/flash";
|
import { addFlashMessage } from "core/server/flash";
|
||||||
import {
|
import { parse, runtimeSupports, type Static, StringEnum, type TObject, Type } from "core/utils";
|
||||||
type Static,
|
|
||||||
StringEnum,
|
|
||||||
type TObject,
|
|
||||||
Type,
|
|
||||||
parse,
|
|
||||||
runtimeSupports,
|
|
||||||
transformObject,
|
|
||||||
} from "core/utils";
|
|
||||||
import type { Context, Hono } from "hono";
|
import type { Context, Hono } from "hono";
|
||||||
import { deleteCookie, getSignedCookie, setSignedCookie } from "hono/cookie";
|
import { deleteCookie, getSignedCookie, setSignedCookie } from "hono/cookie";
|
||||||
import { sign, verify } from "hono/jwt";
|
import { sign, verify } from "hono/jwt";
|
||||||
@@ -129,7 +121,6 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
|||||||
identifier: string,
|
identifier: string,
|
||||||
profile: ProfileExchange,
|
profile: ProfileExchange,
|
||||||
): Promise<AuthResponse> {
|
): Promise<AuthResponse> {
|
||||||
//console.log("resolve", { action, strategy: strategy.getName(), profile });
|
|
||||||
const user = await this.userResolver(action, strategy, identifier, profile);
|
const user = await this.userResolver(action, strategy, identifier, profile);
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
@@ -225,7 +216,7 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
|||||||
return token;
|
return token;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e instanceof Error) {
|
if (e instanceof Error) {
|
||||||
console.error("[Error:getAuthCookie]", e.message);
|
$console.error("[getAuthCookie]", e.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -262,7 +253,6 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
|||||||
|
|
||||||
// @todo: move this to a server helper
|
// @todo: move this to a server helper
|
||||||
isJsonRequest(c: Context): boolean {
|
isJsonRequest(c: Context): boolean {
|
||||||
//return c.req.header("Content-Type") === "application/x-www-form-urlencoded";
|
|
||||||
return c.req.header("Content-Type") === "application/json";
|
return c.req.header("Content-Type") === "application/json";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,7 +279,6 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
|||||||
async respond(c: Context, data: AuthResponse | Error | any, redirect?: string) {
|
async respond(c: Context, data: AuthResponse | Error | any, redirect?: string) {
|
||||||
const successUrl = this.getSafeUrl(c, redirect ?? this.config.cookie.pathSuccess ?? "/");
|
const successUrl = this.getSafeUrl(c, redirect ?? this.config.cookie.pathSuccess ?? "/");
|
||||||
const referer = redirect ?? c.req.header("Referer") ?? successUrl;
|
const referer = redirect ?? c.req.header("Referer") ?? successUrl;
|
||||||
//console.log("auth respond", { redirect, successUrl, successPath });
|
|
||||||
|
|
||||||
if ("token" in data) {
|
if ("token" in data) {
|
||||||
await this.setAuthCookie(c, data.token);
|
await this.setAuthCookie(c, data.token);
|
||||||
@@ -299,7 +288,6 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// can't navigate to "/" – doesn't work on nextjs
|
// can't navigate to "/" – doesn't work on nextjs
|
||||||
//console.log("auth success, redirecting to", successUrl);
|
|
||||||
return c.redirect(successUrl);
|
return c.redirect(successUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +301,6 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
|||||||
}
|
}
|
||||||
|
|
||||||
await addFlashMessage(c, message, "error");
|
await addFlashMessage(c, message, "error");
|
||||||
//console.log("auth failed, redirecting to", referer);
|
|
||||||
return c.redirect(referer);
|
return c.redirect(referer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
import type { Authenticator, Strategy } from "auth";
|
import type { Authenticator, Strategy } from "auth";
|
||||||
import { isDebug, tbValidator as tb } from "core";
|
import { tbValidator as tb } from "core";
|
||||||
import { type Static, StringEnum, Type, parse } from "core/utils";
|
import { hash, parse, type Static, StringEnum, Type } from "core/utils";
|
||||||
import { hash } from "core/utils";
|
import { Hono } from "hono";
|
||||||
import { type Context, Hono } from "hono";
|
import { createStrategyAction, type StrategyActions } from "../Authenticator";
|
||||||
import { type StrategyAction, type StrategyActions, createStrategyAction } from "../Authenticator";
|
|
||||||
|
|
||||||
type LoginSchema = { username: string; password: string } | { email: string; password: string };
|
type LoginSchema = { username: string; password: string } | { email: string; password: string };
|
||||||
type RegisterSchema = { email: string; password: string; [key: string]: any };
|
type RegisterSchema = { email: string; password: string; [key: string]: any };
|
||||||
|
|
||||||
const schema = Type.Object({
|
const schema = Type.Object({
|
||||||
hashing: StringEnum(["plain", "sha256" /*, "bcrypt"*/] as const, { default: "sha256" }),
|
hashing: StringEnum(["plain", "sha256"] as const, { default: "sha256" }),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type PasswordStrategyOptions = Static<typeof schema>;
|
export type PasswordStrategyOptions = Static<typeof schema>;
|
||||||
/*export type PasswordStrategyOptions2 = {
|
|
||||||
hashing?: "plain" | "bcrypt" | "sha256";
|
|
||||||
};*/
|
|
||||||
|
|
||||||
export class PasswordStrategy implements Strategy {
|
export class PasswordStrategy implements Strategy {
|
||||||
private options: PasswordStrategyOptions;
|
private options: PasswordStrategyOptions;
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { OAuthCallbackException, OAuthStrategy } from "./oauth/OAuthStrategy";
|
|||||||
export * as issuers from "./oauth/issuers";
|
export * as issuers from "./oauth/issuers";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
PasswordStrategy,
|
|
||||||
type PasswordStrategyOptions,
|
type PasswordStrategyOptions,
|
||||||
|
PasswordStrategy,
|
||||||
OAuthStrategy,
|
OAuthStrategy,
|
||||||
OAuthCallbackException,
|
OAuthCallbackException,
|
||||||
CustomOAuthStrategy,
|
CustomOAuthStrategy,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { AuthAction, Authenticator, Strategy } from "auth";
|
import type { AuthAction, Authenticator, Strategy } from "auth";
|
||||||
import { Exception, isDebug } from "core";
|
import { Exception, isDebug } from "core";
|
||||||
import { type Static, StringEnum, type TSchema, Type, filterKeys, parse } from "core/utils";
|
import { type Static, StringEnum, Type, filterKeys } from "core/utils";
|
||||||
import { type Context, Hono } from "hono";
|
import { type Context, Hono } from "hono";
|
||||||
import { getSignedCookie, setSignedCookie } from "hono/cookie";
|
import { getSignedCookie, setSignedCookie } from "hono/cookie";
|
||||||
import * as oauth from "oauth4webapi";
|
import * as oauth from "oauth4webapi";
|
||||||
@@ -13,7 +13,6 @@ type RequireKeys<T extends object, K extends keyof T> = Required<Pick<T, K>> & O
|
|||||||
|
|
||||||
const schemaProvided = Type.Object(
|
const schemaProvided = Type.Object(
|
||||||
{
|
{
|
||||||
//type: StringEnum(["oidc", "oauth2"] as const, { default: "oidc" }),
|
|
||||||
name: StringEnum(Object.keys(issuers) as ConfiguredIssuers[]),
|
name: StringEnum(Object.keys(issuers) as ConfiguredIssuers[]),
|
||||||
client: Type.Object(
|
client: Type.Object(
|
||||||
{
|
{
|
||||||
@@ -172,8 +171,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
) {
|
) {
|
||||||
const config = await this.getConfig();
|
const config = await this.getConfig();
|
||||||
const { client, as, type } = config;
|
const { client, as, type } = config;
|
||||||
//console.log("config", config);
|
|
||||||
console.log("callbackParams", callbackParams, options);
|
|
||||||
const parameters = oauth.validateAuthResponse(
|
const parameters = oauth.validateAuthResponse(
|
||||||
as,
|
as,
|
||||||
client, // no client_secret required
|
client, // no client_secret required
|
||||||
@@ -181,13 +179,9 @@ export class OAuthStrategy implements Strategy {
|
|||||||
oauth.expectNoState,
|
oauth.expectNoState,
|
||||||
);
|
);
|
||||||
if (oauth.isOAuth2Error(parameters)) {
|
if (oauth.isOAuth2Error(parameters)) {
|
||||||
//console.log("callback.error", parameters);
|
|
||||||
throw new OAuthCallbackException(parameters, "validateAuthResponse");
|
throw new OAuthCallbackException(parameters, "validateAuthResponse");
|
||||||
}
|
}
|
||||||
/*console.log(
|
|
||||||
"callback.parameters",
|
|
||||||
JSON.stringify(Object.fromEntries(parameters.entries()), null, 2),
|
|
||||||
);*/
|
|
||||||
const response = await oauth.authorizationCodeGrantRequest(
|
const response = await oauth.authorizationCodeGrantRequest(
|
||||||
as,
|
as,
|
||||||
client,
|
client,
|
||||||
@@ -195,13 +189,9 @@ export class OAuthStrategy implements Strategy {
|
|||||||
options.redirect_uri,
|
options.redirect_uri,
|
||||||
options.state,
|
options.state,
|
||||||
);
|
);
|
||||||
//console.log("callback.response", response);
|
|
||||||
|
|
||||||
const challenges = oauth.parseWwwAuthenticateChallenges(response);
|
const challenges = oauth.parseWwwAuthenticateChallenges(response);
|
||||||
if (challenges) {
|
if (challenges) {
|
||||||
for (const challenge of challenges) {
|
|
||||||
//console.log("callback.challenge", challenge);
|
|
||||||
}
|
|
||||||
// @todo: Handle www-authenticate challenges as needed
|
// @todo: Handle www-authenticate challenges as needed
|
||||||
throw new OAuthCallbackException(challenges, "www-authenticate");
|
throw new OAuthCallbackException(challenges, "www-authenticate");
|
||||||
}
|
}
|
||||||
@@ -216,20 +206,13 @@ export class OAuthStrategy implements Strategy {
|
|||||||
expectedNonce,
|
expectedNonce,
|
||||||
);
|
);
|
||||||
if (oauth.isOAuth2Error(result)) {
|
if (oauth.isOAuth2Error(result)) {
|
||||||
console.log("callback.error", result);
|
|
||||||
// @todo: Handle OAuth 2.0 response body error
|
// @todo: Handle OAuth 2.0 response body error
|
||||||
throw new OAuthCallbackException(result, "processAuthorizationCodeOpenIDResponse");
|
throw new OAuthCallbackException(result, "processAuthorizationCodeOpenIDResponse");
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log("callback.result", result);
|
|
||||||
|
|
||||||
const claims = oauth.getValidatedIdTokenClaims(result);
|
const claims = oauth.getValidatedIdTokenClaims(result);
|
||||||
//console.log("callback.IDTokenClaims", claims);
|
|
||||||
|
|
||||||
const infoRequest = await oauth.userInfoRequest(as, client, result.access_token!);
|
const infoRequest = await oauth.userInfoRequest(as, client, result.access_token!);
|
||||||
|
|
||||||
const resultUser = await oauth.processUserInfoResponse(as, client, claims.sub, infoRequest);
|
const resultUser = await oauth.processUserInfoResponse(as, client, claims.sub, infoRequest);
|
||||||
//console.log("callback.resultUser", resultUser);
|
|
||||||
|
|
||||||
return await config.profile(resultUser, config, claims); // @todo: check claims
|
return await config.profile(resultUser, config, claims); // @todo: check claims
|
||||||
}
|
}
|
||||||
@@ -240,8 +223,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
) {
|
) {
|
||||||
const config = await this.getConfig();
|
const config = await this.getConfig();
|
||||||
const { client, type, as, profile } = config;
|
const { client, type, as, profile } = config;
|
||||||
console.log("config", { client, as, type });
|
|
||||||
console.log("callbackParams", callbackParams, options);
|
|
||||||
const parameters = oauth.validateAuthResponse(
|
const parameters = oauth.validateAuthResponse(
|
||||||
as,
|
as,
|
||||||
client, // no client_secret required
|
client, // no client_secret required
|
||||||
@@ -249,13 +231,9 @@ export class OAuthStrategy implements Strategy {
|
|||||||
oauth.expectNoState,
|
oauth.expectNoState,
|
||||||
);
|
);
|
||||||
if (oauth.isOAuth2Error(parameters)) {
|
if (oauth.isOAuth2Error(parameters)) {
|
||||||
console.log("callback.error", parameters);
|
|
||||||
throw new OAuthCallbackException(parameters, "validateAuthResponse");
|
throw new OAuthCallbackException(parameters, "validateAuthResponse");
|
||||||
}
|
}
|
||||||
console.log(
|
|
||||||
"callback.parameters",
|
|
||||||
JSON.stringify(Object.fromEntries(parameters.entries()), null, 2),
|
|
||||||
);
|
|
||||||
const response = await oauth.authorizationCodeGrantRequest(
|
const response = await oauth.authorizationCodeGrantRequest(
|
||||||
as,
|
as,
|
||||||
client,
|
client,
|
||||||
@@ -266,9 +244,6 @@ export class OAuthStrategy implements Strategy {
|
|||||||
|
|
||||||
const challenges = oauth.parseWwwAuthenticateChallenges(response);
|
const challenges = oauth.parseWwwAuthenticateChallenges(response);
|
||||||
if (challenges) {
|
if (challenges) {
|
||||||
for (const challenge of challenges) {
|
|
||||||
//console.log("callback.challenge", challenge);
|
|
||||||
}
|
|
||||||
// @todo: Handle www-authenticate challenges as needed
|
// @todo: Handle www-authenticate challenges as needed
|
||||||
throw new OAuthCallbackException(challenges, "www-authenticate");
|
throw new OAuthCallbackException(challenges, "www-authenticate");
|
||||||
}
|
}
|
||||||
@@ -279,19 +254,15 @@ export class OAuthStrategy implements Strategy {
|
|||||||
try {
|
try {
|
||||||
result = await oauth.processAuthorizationCodeOAuth2Response(as, client, response);
|
result = await oauth.processAuthorizationCodeOAuth2Response(as, client, response);
|
||||||
if (oauth.isOAuth2Error(result)) {
|
if (oauth.isOAuth2Error(result)) {
|
||||||
console.log("error", result);
|
|
||||||
throw new Error(); // Handle OAuth 2.0 response body error
|
throw new Error(); // Handle OAuth 2.0 response body error
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
result = (await copy.json()) as any;
|
result = (await copy.json()) as any;
|
||||||
console.log("failed", result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const res2 = await oauth.userInfoRequest(as, client, result.access_token!);
|
const res2 = await oauth.userInfoRequest(as, client, result.access_token!);
|
||||||
const user = await res2.json();
|
const user = await res2.json();
|
||||||
console.log("res2", res2, user);
|
|
||||||
|
|
||||||
console.log("result", result);
|
|
||||||
return await config.profile(user, config, result);
|
return await config.profile(user, config, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,7 +272,6 @@ export class OAuthStrategy implements Strategy {
|
|||||||
): Promise<UserProfile> {
|
): Promise<UserProfile> {
|
||||||
const type = this.getIssuerConfig().type;
|
const type = this.getIssuerConfig().type;
|
||||||
|
|
||||||
console.log("type", type);
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "oidc":
|
case "oidc":
|
||||||
return await this.oidc(callbackParams, options);
|
return await this.oidc(callbackParams, options);
|
||||||
@@ -325,7 +295,6 @@ export class OAuthStrategy implements Strategy {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const setState = async (c: Context, config: TState): Promise<void> => {
|
const setState = async (c: Context, config: TState): Promise<void> => {
|
||||||
console.log("--- setting state", config);
|
|
||||||
await setSignedCookie(c, cookie_name, JSON.stringify(config), secret, {
|
await setSignedCookie(c, cookie_name, JSON.stringify(config), secret, {
|
||||||
secure: true,
|
secure: true,
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
@@ -356,7 +325,6 @@ export class OAuthStrategy implements Strategy {
|
|||||||
const params = new URLSearchParams(url.search);
|
const params = new URLSearchParams(url.search);
|
||||||
|
|
||||||
const state = await getState(c);
|
const state = await getState(c);
|
||||||
console.log("state", state);
|
|
||||||
|
|
||||||
// @todo: add config option to determine if state.action is allowed
|
// @todo: add config option to determine if state.action is allowed
|
||||||
const redirect_uri =
|
const redirect_uri =
|
||||||
@@ -371,7 +339,6 @@ export class OAuthStrategy implements Strategy {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await auth.resolve(state.action, this, profile.sub, profile);
|
const data = await auth.resolve(state.action, this, profile.sub, profile);
|
||||||
console.log("******** RESOLVED ********", data);
|
|
||||||
|
|
||||||
if (state.mode === "cookie") {
|
if (state.mode === "cookie") {
|
||||||
return await auth.respond(c, data, state.redirect);
|
return await auth.respond(c, data, state.redirect);
|
||||||
@@ -412,10 +379,8 @@ export class OAuthStrategy implements Strategy {
|
|||||||
redirect_uri,
|
redirect_uri,
|
||||||
state,
|
state,
|
||||||
});
|
});
|
||||||
//console.log("_state", state);
|
|
||||||
|
|
||||||
await setState(c, { state, action, redirect: referer.toString(), mode: "cookie" });
|
await setState(c, { state, action, redirect: referer.toString(), mode: "cookie" });
|
||||||
console.log("--redirecting to", response.url);
|
|
||||||
|
|
||||||
return c.redirect(response.url);
|
return c.redirect(response.url);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ export const github: IssuerConfig<GithubUserInfo> = {
|
|||||||
config: Omit<IssuerConfig, "profile">,
|
config: Omit<IssuerConfig, "profile">,
|
||||||
tokenResponse: any,
|
tokenResponse: any,
|
||||||
) => {
|
) => {
|
||||||
console.log("github info", info, config, tokenResponse);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch("https://api.github.com/user/emails", {
|
const res = await fetch("https://api.github.com/user/emails", {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -45,7 +43,6 @@ export const github: IssuerConfig<GithubUserInfo> = {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const data = (await res.json()) as GithubUserEmailResponse;
|
const data = (await res.json()) as GithubUserEmailResponse;
|
||||||
console.log("data", data);
|
|
||||||
const email = data.find((e: any) => e.primary)?.email;
|
const email = data.find((e: any) => e.primary)?.email;
|
||||||
if (!email) {
|
if (!email) {
|
||||||
throw new Error("No primary email found");
|
throw new Error("No primary email found");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Exception, Permission } from "core";
|
import { $console, Exception, Permission } from "core";
|
||||||
import { objectTransform } from "core/utils";
|
import { objectTransform } from "core/utils";
|
||||||
import type { Context } from "hono";
|
import type { Context } from "hono";
|
||||||
import type { ServerEnv } from "modules/Controller";
|
import type { ServerEnv } from "modules/Controller";
|
||||||
@@ -14,8 +14,6 @@ export type GuardConfig = {
|
|||||||
};
|
};
|
||||||
export type GuardContext = Context<ServerEnv> | GuardUserContext;
|
export type GuardContext = Context<ServerEnv> | GuardUserContext;
|
||||||
|
|
||||||
const debug = false;
|
|
||||||
|
|
||||||
export class Guard {
|
export class Guard {
|
||||||
permissions: Permission[];
|
permissions: Permission[];
|
||||||
roles?: Role[];
|
roles?: Role[];
|
||||||
@@ -95,16 +93,15 @@ export class Guard {
|
|||||||
if (user && typeof user.role === "string") {
|
if (user && typeof user.role === "string") {
|
||||||
const role = this.roles?.find((role) => role.name === user?.role);
|
const role = this.roles?.find((role) => role.name === user?.role);
|
||||||
if (role) {
|
if (role) {
|
||||||
debug && console.log("guard: role found", [user.role]);
|
$console.debug("guard: role found", [user.role]);
|
||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug &&
|
$console.debug("guard: role not found", {
|
||||||
console.log("guard: role not found", {
|
user: user,
|
||||||
user: user,
|
role: user?.role,
|
||||||
role: user?.role,
|
});
|
||||||
});
|
|
||||||
return this.getDefaultRole();
|
return this.getDefaultRole();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +117,6 @@ export class Guard {
|
|||||||
hasPermission(name: string, user?: GuardUserContext): boolean;
|
hasPermission(name: string, user?: GuardUserContext): boolean;
|
||||||
hasPermission(permissionOrName: Permission | string, user?: GuardUserContext): boolean {
|
hasPermission(permissionOrName: Permission | string, user?: GuardUserContext): boolean {
|
||||||
if (!this.isEnabled()) {
|
if (!this.isEnabled()) {
|
||||||
//console.log("guard not enabled, allowing");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,10 +129,10 @@ export class Guard {
|
|||||||
const role = this.getUserRole(user);
|
const role = this.getUserRole(user);
|
||||||
|
|
||||||
if (!role) {
|
if (!role) {
|
||||||
debug && console.log("guard: role not found, denying");
|
$console.debug("guard: role not found, denying");
|
||||||
return false;
|
return false;
|
||||||
} else if (role.implicit_allow === true) {
|
} else if (role.implicit_allow === true) {
|
||||||
debug && console.log("guard: role implicit allow, allowing");
|
$console.debug("guard: role implicit allow, allowing");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,12 +140,11 @@ export class Guard {
|
|||||||
(rolePermission) => rolePermission.permission.name === name,
|
(rolePermission) => rolePermission.permission.name === name,
|
||||||
);
|
);
|
||||||
|
|
||||||
debug &&
|
$console.debug("guard: rolePermission, allowing?", {
|
||||||
console.log("guard: rolePermission, allowing?", {
|
permission: name,
|
||||||
permission: name,
|
role: role.name,
|
||||||
role: role.name,
|
allowing: !!rolePermission,
|
||||||
allowing: !!rolePermission,
|
});
|
||||||
});
|
|
||||||
return !!rolePermission;
|
return !!rolePermission;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
export { UserExistsException, UserNotFoundException, InvalidCredentialsException } from "./errors";
|
export { UserExistsException, UserNotFoundException, InvalidCredentialsException } from "./errors";
|
||||||
export { sha256 } from "./utils/hash";
|
|
||||||
export {
|
export {
|
||||||
type ProfileExchange,
|
type ProfileExchange,
|
||||||
type Strategy,
|
type Strategy,
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
// @deprecated: moved to @bknd/core
|
|
||||||
export async function sha256(password: string, salt?: string) {
|
|
||||||
// 1. Convert password to Uint8Array
|
|
||||||
const encoder = new TextEncoder();
|
|
||||||
const data = encoder.encode((salt ?? "") + password);
|
|
||||||
|
|
||||||
// 2. Hash the data using SHA-256
|
|
||||||
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
||||||
|
|
||||||
// 3. Convert hash to hex string for easier display
|
|
||||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
||||||
return hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
||||||
}
|
|
||||||
@@ -8,6 +8,8 @@ export const config: CliCommand = (program) => {
|
|||||||
.option("--pretty", "pretty print")
|
.option("--pretty", "pretty print")
|
||||||
.action((options) => {
|
.action((options) => {
|
||||||
const config = getDefaultConfig();
|
const config = getDefaultConfig();
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noConsoleLog:
|
||||||
console.log(options.pretty ? JSON.stringify(config, null, 2) : JSON.stringify(config));
|
console.log(options.pretty ? JSON.stringify(config, null, 2) : JSON.stringify(config));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,5 +32,6 @@ async function action(options: { out?: string; clean?: boolean }) {
|
|||||||
// delete ".vite" directory in out
|
// delete ".vite" directory in out
|
||||||
await fs.rm(path.resolve(out, ".vite"), { recursive: true });
|
await fs.rm(path.resolve(out, ".vite"), { recursive: true });
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noConsoleLog:
|
||||||
console.log(c.green(`Assets copied to: ${c.bold(out)}`));
|
console.log(c.green(`Assets copied to: ${c.bold(out)}`));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,10 +43,12 @@ export const create: CliCommand = (program) => {
|
|||||||
|
|
||||||
function errorOutro() {
|
function errorOutro() {
|
||||||
$p.outro(color.red("Failed to create project."));
|
$p.outro(color.red("Failed to create project."));
|
||||||
|
// biome-ignore lint/suspicious/noConsoleLog:
|
||||||
console.log(
|
console.log(
|
||||||
color.yellow("Sorry that this happened. If you think this is a bug, please report it at: ") +
|
color.yellow("Sorry that this happened. If you think this is a bug, please report it at: ") +
|
||||||
color.cyan("https://github.com/bknd-io/bknd/issues"),
|
color.cyan("https://github.com/bknd-io/bknd/issues"),
|
||||||
);
|
);
|
||||||
|
// biome-ignore lint/suspicious/noConsoleLog:
|
||||||
console.log("");
|
console.log("");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
@@ -55,7 +57,14 @@ async function onExit() {
|
|||||||
await flush();
|
await flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function action(options: { template?: string; dir?: string; integration?: string, yes?: boolean, clean?: boolean }) {
|
async function action(options: {
|
||||||
|
template?: string;
|
||||||
|
dir?: string;
|
||||||
|
integration?: string;
|
||||||
|
yes?: boolean;
|
||||||
|
clean?: boolean;
|
||||||
|
}) {
|
||||||
|
// biome-ignore lint/suspicious/noConsoleLog:
|
||||||
console.log("");
|
console.log("");
|
||||||
const $t = createScoped("create");
|
const $t = createScoped("create");
|
||||||
$t.capture("start", {
|
$t.capture("start", {
|
||||||
@@ -96,10 +105,12 @@ async function action(options: { template?: string; dir?: string; integration?:
|
|||||||
|
|
||||||
$t.properties.at = "dir";
|
$t.properties.at = "dir";
|
||||||
if (fs.existsSync(downloadOpts.dir)) {
|
if (fs.existsSync(downloadOpts.dir)) {
|
||||||
const clean = options.clean ?? await $p.confirm({
|
const clean =
|
||||||
message: `Directory ${color.cyan(downloadOpts.dir)} exists. Clean it?`,
|
options.clean ??
|
||||||
initialValue: false,
|
(await $p.confirm({
|
||||||
});
|
message: `Directory ${color.cyan(downloadOpts.dir)} exists. Clean it?`,
|
||||||
|
initialValue: false,
|
||||||
|
}));
|
||||||
if ($p.isCancel(clean)) {
|
if ($p.isCancel(clean)) {
|
||||||
await onExit();
|
await onExit();
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@@ -174,8 +185,6 @@ async function action(options: { template?: string; dir?: string; integration?:
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log("integration", { type, integration });
|
|
||||||
|
|
||||||
const choices = templates.filter((t) => t.integration === integration);
|
const choices = templates.filter((t) => t.integration === integration);
|
||||||
if (choices.length === 0) {
|
if (choices.length === 0) {
|
||||||
await onExit();
|
await onExit();
|
||||||
@@ -261,9 +270,11 @@ async function action(options: { template?: string; dir?: string; integration?:
|
|||||||
$p.log.success(`Updated package name to ${color.cyan(ctx.name)}`);
|
$p.log.success(`Updated package name to ${color.cyan(ctx.name)}`);
|
||||||
|
|
||||||
{
|
{
|
||||||
const install = options.yes ?? await $p.confirm({
|
const install =
|
||||||
message: "Install dependencies?",
|
options.yes ??
|
||||||
});
|
(await $p.confirm({
|
||||||
|
message: "Install dependencies?",
|
||||||
|
}));
|
||||||
|
|
||||||
if ($p.isCancel(install)) {
|
if ($p.isCancel(install)) {
|
||||||
await onExit();
|
await onExit();
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export const debug: CliCommand = (program) => {
|
|||||||
|
|
||||||
const subjects = {
|
const subjects = {
|
||||||
paths: async () => {
|
paths: async () => {
|
||||||
|
// biome-ignore lint/suspicious/noConsoleLog:
|
||||||
console.log("[PATHS]", {
|
console.log("[PATHS]", {
|
||||||
rootpath: getRootPath(),
|
rootpath: getRootPath(),
|
||||||
distPath: getDistPath(),
|
distPath: getDistPath(),
|
||||||
@@ -27,6 +28,7 @@ const subjects = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
routes: async () => {
|
routes: async () => {
|
||||||
|
// biome-ignore lint/suspicious/noConsoleLog:
|
||||||
console.log("[APP ROUTES]");
|
console.log("[APP ROUTES]");
|
||||||
const credentials = getConnectionCredentialsFromEnv();
|
const credentials = getConnectionCredentialsFromEnv();
|
||||||
const app = createApp({ connection: credentials });
|
const app = createApp({ connection: credentials });
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import type { Config } from "@libsql/client/node";
|
import type { Config } from "@libsql/client/node";
|
||||||
import { config } from "core";
|
import { $console, config } from "core";
|
||||||
import type { MiddlewareHandler } from "hono";
|
import type { MiddlewareHandler } from "hono";
|
||||||
import open from "open";
|
import open from "open";
|
||||||
import { fileExists, getRelativeDistPath } from "../../utils/sys";
|
import { fileExists, getRelativeDistPath } from "../../utils/sys";
|
||||||
@@ -36,7 +36,7 @@ export async function startServer(
|
|||||||
options: { port: number; open?: boolean },
|
options: { port: number; open?: boolean },
|
||||||
) {
|
) {
|
||||||
const port = options.port;
|
const port = options.port;
|
||||||
console.log(`Using ${server} serve`);
|
$console.log(`Using ${server} serve`);
|
||||||
|
|
||||||
switch (server) {
|
switch (server) {
|
||||||
case "node": {
|
case "node": {
|
||||||
@@ -58,7 +58,8 @@ export async function startServer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const url = `http://localhost:${port}`;
|
const url = `http://localhost:${port}`;
|
||||||
console.info("Server listening on", url);
|
$console.info("Server listening on", url);
|
||||||
|
|
||||||
if (options.open) {
|
if (options.open) {
|
||||||
await open(url);
|
await open(url);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export const schema: CliCommand = (program) => {
|
|||||||
.option("--pretty", "pretty print")
|
.option("--pretty", "pretty print")
|
||||||
.action((options) => {
|
.action((options) => {
|
||||||
const schema = getDefaultSchema();
|
const schema = getDefaultSchema();
|
||||||
|
// biome-ignore lint/suspicious/noConsoleLog:
|
||||||
console.log(options.pretty ? JSON.stringify(schema, null, 2) : JSON.stringify(schema));
|
console.log(options.pretty ? JSON.stringify(schema, null, 2) : JSON.stringify(schema));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ async function token(app: App, options: any) {
|
|||||||
}
|
}
|
||||||
$log.info(`User found: ${c.cyan(user.email)}`);
|
$log.info(`User found: ${c.cyan(user.email)}`);
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noConsoleLog:
|
||||||
console.log(
|
console.log(
|
||||||
`\n${c.dim("Token:")}\n${c.yellow(await app.module.auth.authenticator.jwt(user))}\n`,
|
`\n${c.dim("Token:")}\n${c.yellow(await app.module.auth.authenticator.jwt(user))}\n`,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ export class AwsClient extends Aws4fetchClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getUrl(path: string = "/", searchParamsObj: Record<string, any> = {}): string {
|
getUrl(path: string = "/", searchParamsObj: Record<string, any> = {}): string {
|
||||||
//console.log("super:getUrl", path, searchParamsObj);
|
|
||||||
const url = new URL(path);
|
const url = new URL(path);
|
||||||
const converted = this.convertParams(searchParamsObj);
|
const converted = this.convertParams(searchParamsObj);
|
||||||
Object.entries(converted).forEach(([key, value]) => {
|
Object.entries(converted).forEach(([key, value]) => {
|
||||||
@@ -76,8 +75,6 @@ export class AwsClient extends Aws4fetchClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const raw = await response.text();
|
const raw = await response.text();
|
||||||
//console.log("raw", raw);
|
|
||||||
//console.log(JSON.stringify(xmlToObject(raw), null, 2));
|
|
||||||
return xmlToObject(raw) as T;
|
return xmlToObject(raw) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { type Event, type EventClass, InvalidEventReturn } from "./Event";
|
import { type Event, type EventClass, InvalidEventReturn } from "./Event";
|
||||||
import { EventListener, type ListenerHandler, type ListenerMode } from "./EventListener";
|
import { EventListener, type ListenerHandler, type ListenerMode } from "./EventListener";
|
||||||
|
import { $console } from "core";
|
||||||
|
|
||||||
export type RegisterListenerConfig =
|
export type RegisterListenerConfig =
|
||||||
| ListenerMode
|
| ListenerMode
|
||||||
@@ -83,10 +84,6 @@ export class EventManager<
|
|||||||
} else {
|
} else {
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
slug = eventOrSlug.constructor?.slug ?? eventOrSlug.slug;
|
slug = eventOrSlug.constructor?.slug ?? eventOrSlug.slug;
|
||||||
/*eventOrSlug instanceof Event
|
|
||||||
? // @ts-expect-error slug is static
|
|
||||||
eventOrSlug.constructor.slug
|
|
||||||
: eventOrSlug.slug;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!this.events.find((e) => slug === e.slug);
|
return !!this.events.find((e) => slug === e.slug);
|
||||||
@@ -128,8 +125,7 @@ export class EventManager<
|
|||||||
if (listener.id) {
|
if (listener.id) {
|
||||||
const existing = this.listeners.find((l) => l.id === listener.id);
|
const existing = this.listeners.find((l) => l.id === listener.id);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
// @todo: add a verbose option?
|
$console.debug(`Listener with id "${listener.id}" already exists.`);
|
||||||
//console.warn(`Listener with id "${listener.id}" already exists.`);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,7 +187,7 @@ export class EventManager<
|
|||||||
// @ts-expect-error slug is static
|
// @ts-expect-error slug is static
|
||||||
const slug = event.constructor.slug;
|
const slug = event.constructor.slug;
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
console.log("EventManager disabled, not emitting", slug);
|
$console.debug("EventManager disabled, not emitting", slug);
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +236,7 @@ export class EventManager<
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof InvalidEventReturn) {
|
if (e instanceof InvalidEventReturn) {
|
||||||
this.options?.onInvalidReturn?.(_event, e);
|
this.options?.onInvalidReturn?.(_event, e);
|
||||||
console.warn(`Invalid return of event listener for "${slug}": ${e.message}`);
|
$console.warn(`Invalid return of event listener for "${slug}": ${e.message}`);
|
||||||
} else if (this.options?.onError) {
|
} else if (this.options?.onError) {
|
||||||
this.options.onError(_event, e);
|
this.options.onError(_event, e);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ export class SchemaObject<Schema extends TObject> {
|
|||||||
forceParse: true,
|
forceParse: true,
|
||||||
skipMark: this.isForceParse(),
|
skipMark: this.isForceParse(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// regardless of "noEmit" – this should always be triggered
|
// regardless of "noEmit" – this should always be triggered
|
||||||
const updatedConfig = await this.onBeforeUpdate(this._config, valid);
|
const updatedConfig = await this.onBeforeUpdate(this._config, valid);
|
||||||
|
|
||||||
@@ -122,19 +123,15 @@ export class SchemaObject<Schema extends TObject> {
|
|||||||
const partial = path.length > 0 ? (set({}, path, value) as Partial<Static<Schema>>) : value;
|
const partial = path.length > 0 ? (set({}, path, value) as Partial<Static<Schema>>) : value;
|
||||||
|
|
||||||
this.throwIfRestricted(partial);
|
this.throwIfRestricted(partial);
|
||||||
//console.log(getFullPathKeys(value).map((k) => path + "." + k));
|
|
||||||
|
|
||||||
// overwrite arrays and primitives, only deep merge objects
|
// overwrite arrays and primitives, only deep merge objects
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
//console.log("---alt:new", _jsonp(mergeObject(current, partial)));
|
|
||||||
const config = mergeObjectWith(current, partial, (objValue, srcValue) => {
|
const config = mergeObjectWith(current, partial, (objValue, srcValue) => {
|
||||||
if (Array.isArray(objValue) && Array.isArray(srcValue)) {
|
if (Array.isArray(objValue) && Array.isArray(srcValue)) {
|
||||||
return srcValue;
|
return srcValue;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//console.log("---new", _jsonp(config));
|
|
||||||
|
|
||||||
//console.log("overwritePaths", this.options?.overwritePaths);
|
|
||||||
if (this.options?.overwritePaths) {
|
if (this.options?.overwritePaths) {
|
||||||
const keys = getFullPathKeys(value).map((k) => {
|
const keys = getFullPathKeys(value).map((k) => {
|
||||||
// only prepend path if given
|
// only prepend path if given
|
||||||
@@ -149,7 +146,6 @@ export class SchemaObject<Schema extends TObject> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
//console.log("overwritePaths", keys, overwritePaths);
|
|
||||||
|
|
||||||
if (overwritePaths.length > 0) {
|
if (overwritePaths.length > 0) {
|
||||||
// filter out less specific paths (but only if more than 1)
|
// filter out less specific paths (but only if more than 1)
|
||||||
@@ -157,12 +153,10 @@ export class SchemaObject<Schema extends TObject> {
|
|||||||
overwritePaths.length > 1
|
overwritePaths.length > 1
|
||||||
? overwritePaths.filter((k) =>
|
? overwritePaths.filter((k) =>
|
||||||
overwritePaths.some((k2) => {
|
overwritePaths.some((k2) => {
|
||||||
//console.log("keep?", { k, k2 }, k2 !== k && k2.startsWith(k));
|
|
||||||
return k2 !== k && k2.startsWith(k);
|
return k2 !== k && k2.startsWith(k);
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
: overwritePaths;
|
: overwritePaths;
|
||||||
//console.log("specific", specific);
|
|
||||||
|
|
||||||
for (const p of specific) {
|
for (const p of specific) {
|
||||||
set(config, p, get(partial, p));
|
set(config, p, get(partial, p));
|
||||||
@@ -170,8 +164,6 @@ export class SchemaObject<Schema extends TObject> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log("patch", _jsonp({ path, value, partial, config, current }));
|
|
||||||
|
|
||||||
const newConfig = await this.set(config);
|
const newConfig = await this.set(config);
|
||||||
return [partial, newConfig];
|
return [partial, newConfig];
|
||||||
}
|
}
|
||||||
@@ -181,14 +173,11 @@ export class SchemaObject<Schema extends TObject> {
|
|||||||
const partial = path.length > 0 ? (set({}, path, value) as Partial<Static<Schema>>) : value;
|
const partial = path.length > 0 ? (set({}, path, value) as Partial<Static<Schema>>) : value;
|
||||||
|
|
||||||
this.throwIfRestricted(partial);
|
this.throwIfRestricted(partial);
|
||||||
//console.log(getFullPathKeys(value).map((k) => path + "." + k));
|
|
||||||
|
|
||||||
// overwrite arrays and primitives, only deep merge objects
|
// overwrite arrays and primitives, only deep merge objects
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const config = set(current, path, value);
|
const config = set(current, path, value);
|
||||||
|
|
||||||
//console.log("overwrite", { path, value, partial, config, current });
|
|
||||||
|
|
||||||
const newConfig = await this.set(config);
|
const newConfig = await this.set(config);
|
||||||
return [partial, newConfig];
|
return [partial, newConfig];
|
||||||
}
|
}
|
||||||
@@ -198,7 +187,6 @@ export class SchemaObject<Schema extends TObject> {
|
|||||||
if (p.length > 1) {
|
if (p.length > 1) {
|
||||||
const parent = p.slice(0, -1).join(".");
|
const parent = p.slice(0, -1).join(".");
|
||||||
if (!has(this._config, parent)) {
|
if (!has(this._config, parent)) {
|
||||||
//console.log("parent", parent, JSON.stringify(this._config, null, 2));
|
|
||||||
throw new Error(`Parent path "${parent}" does not exist`);
|
throw new Error(`Parent path "${parent}" does not exist`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ export class SimpleRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static hasMarkup(template: string | object): boolean {
|
static hasMarkup(template: string | object): boolean {
|
||||||
//console.log("has markup?", template);
|
|
||||||
let flat: string = "";
|
let flat: string = "";
|
||||||
|
|
||||||
if (Array.isArray(template) || typeof template === "object") {
|
if (Array.isArray(template) || typeof template === "object") {
|
||||||
@@ -34,12 +33,8 @@ export class SimpleRenderer {
|
|||||||
flat = String(template);
|
flat = String(template);
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log("** flat", flat);
|
|
||||||
|
|
||||||
const checks = ["{{", "{%", "{#", "{:"];
|
const checks = ["{{", "{%", "{#", "{:"];
|
||||||
const hasMarkup = checks.some((check) => flat.includes(check));
|
return checks.some((check) => flat.includes(check));
|
||||||
//console.log("--has markup?", hasMarkup);
|
|
||||||
return hasMarkup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async render<Given extends TemplateTypes>(template: Given): Promise<Given> {
|
async render<Given extends TemplateTypes>(template: Given): Promise<Given> {
|
||||||
@@ -75,7 +70,6 @@ export class SimpleRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async renderString(template: string): Promise<string> {
|
async renderString(template: string): Promise<string> {
|
||||||
//console.log("*** renderString", template, this.variables);
|
|
||||||
return this.engine.parseAndRender(template, this.variables, this.options);
|
return this.engine.parseAndRender(template, this.variables, this.options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,11 @@ export class DebugLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
context(context: string) {
|
context(context: string) {
|
||||||
//console.log("[ settings context ]", context, this._context);
|
|
||||||
this._context.push(context);
|
this._context.push(context);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
//console.log("[ clear context ]", this._context.pop(), this._context);
|
|
||||||
this._context.pop();
|
this._context.pop();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -33,6 +31,8 @@ export class DebugLogger {
|
|||||||
const indents = " ".repeat(Math.max(this._context.length - 1, 0));
|
const indents = " ".repeat(Math.max(this._context.length - 1, 0));
|
||||||
const context =
|
const context =
|
||||||
this._context.length > 0 ? `[${this._context[this._context.length - 1]}]` : "";
|
this._context.length > 0 ? `[${this._context[this._context.length - 1]}]` : "";
|
||||||
|
|
||||||
|
// biome-ignore lint/suspicious/noConsoleLog: <explanation>
|
||||||
console.log(indents, context, time, ...args);
|
console.log(indents, context, time, ...args);
|
||||||
|
|
||||||
this.last = now;
|
this.last = now;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import weekOfYear from "dayjs/plugin/weekOfYear.js";
|
|||||||
declare module "dayjs" {
|
declare module "dayjs" {
|
||||||
interface Dayjs {
|
interface Dayjs {
|
||||||
week(): number;
|
week(): number;
|
||||||
|
|
||||||
week(value: number): dayjs.Dayjs;
|
week(value: number): dayjs.Dayjs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { extension, guess, isMimeType } from "media/storage/mime-types-tiny";
|
|||||||
import { randomString } from "core/utils/strings";
|
import { randomString } from "core/utils/strings";
|
||||||
import type { Context } from "hono";
|
import type { Context } from "hono";
|
||||||
import { invariant } from "core/utils/runtime";
|
import { invariant } from "core/utils/runtime";
|
||||||
|
import { $console } from "../console";
|
||||||
|
|
||||||
export function getContentName(request: Request): string | undefined;
|
export function getContentName(request: Request): string | undefined;
|
||||||
export function getContentName(contentDisposition: string): string | undefined;
|
export function getContentName(contentDisposition: string): string | undefined;
|
||||||
@@ -130,7 +131,7 @@ export async function getFileFromContext(c: Context<any>): Promise<File> {
|
|||||||
return await blobToFile(v);
|
return await blobToFile(v);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("Error parsing form data", e);
|
$console.warn("Error parsing form data", e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
@@ -141,7 +142,7 @@ export async function getFileFromContext(c: Context<any>): Promise<File> {
|
|||||||
return await blobToFile(blob, { name: getContentName(c.req.raw), type: contentType });
|
return await blobToFile(blob, { name: getContentName(c.req.raw), type: contentType });
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("Error parsing blob", e);
|
$console.warn("Error parsing blob", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
import { randomString } from "core/utils/strings";
|
|
||||||
import type { Context } from "hono";
|
|
||||||
import { extension, guess, isMimeType } from "media/storage/mime-types-tiny";
|
|
||||||
|
|
||||||
export function headersToObject(headers: Headers): Record<string, string> {
|
export function headersToObject(headers: Headers): Record<string, string> {
|
||||||
if (!headers) return {};
|
if (!headers) return {};
|
||||||
return { ...Object.fromEntries(headers.entries()) };
|
return { ...Object.fromEntries(headers.entries()) };
|
||||||
|
|||||||
@@ -114,7 +114,6 @@ export function parse<Schema extends TSchema = TSchema>(
|
|||||||
} else if (options?.onError) {
|
} else if (options?.onError) {
|
||||||
options.onError(Errors(schema, data));
|
options.onError(Errors(schema, data));
|
||||||
} else {
|
} else {
|
||||||
//console.warn("errors", JSON.stringify([...Errors(schema, data)], null, 2));
|
|
||||||
throw new TypeInvalidError(schema, data);
|
throw new TypeInvalidError(schema, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,13 +125,11 @@ export function parseDecode<Schema extends TSchema = TSchema>(
|
|||||||
schema: Schema,
|
schema: Schema,
|
||||||
data: RecursivePartial<StaticDecode<Schema>>,
|
data: RecursivePartial<StaticDecode<Schema>>,
|
||||||
): StaticDecode<Schema> {
|
): StaticDecode<Schema> {
|
||||||
//console.log("parseDecode", schema, data);
|
|
||||||
const parsed = Default(schema, data);
|
const parsed = Default(schema, data);
|
||||||
|
|
||||||
if (Check(schema, parsed)) {
|
if (Check(schema, parsed)) {
|
||||||
return parsed as StaticDecode<typeof schema>;
|
return parsed as StaticDecode<typeof schema>;
|
||||||
}
|
}
|
||||||
//console.log("errors", ...Errors(schema, data));
|
|
||||||
|
|
||||||
throw new TypeInvalidError(schema, data);
|
throw new TypeInvalidError(schema, data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { isDebug, tbValidator as tb } from "core";
|
import { $console, isDebug, tbValidator as tb } from "core";
|
||||||
import { StringEnum, Type } from "core/utils";
|
import { StringEnum, Type } from "core/utils";
|
||||||
import {
|
import {
|
||||||
DataPermissions,
|
DataPermissions,
|
||||||
@@ -45,7 +45,6 @@ export class DataController extends Controller {
|
|||||||
const template = { data: res.data, meta };
|
const template = { data: res.data, meta };
|
||||||
|
|
||||||
// @todo: this works but it breaks in FE (need to improve DataTable)
|
// @todo: this works but it breaks in FE (need to improve DataTable)
|
||||||
//return objectCleanEmpty(template) as any;
|
|
||||||
// filter empty
|
// filter empty
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
Object.entries(template).filter(([_, v]) => typeof v !== "undefined" && v !== null),
|
Object.entries(template).filter(([_, v]) => typeof v !== "undefined" && v !== null),
|
||||||
@@ -56,7 +55,6 @@ export class DataController extends Controller {
|
|||||||
const template = { data: res.data };
|
const template = { data: res.data };
|
||||||
|
|
||||||
// filter empty
|
// filter empty
|
||||||
//return objectCleanEmpty(template);
|
|
||||||
return Object.fromEntries(Object.entries(template).filter(([_, v]) => v !== undefined));
|
return Object.fromEntries(Object.entries(template).filter(([_, v]) => v !== undefined));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,11 +70,6 @@ export class DataController extends Controller {
|
|||||||
const { permission, auth } = this.middlewares;
|
const { permission, auth } = this.middlewares;
|
||||||
const hono = this.create().use(auth(), permission(SystemPermissions.accessApi));
|
const hono = this.create().use(auth(), permission(SystemPermissions.accessApi));
|
||||||
|
|
||||||
const definedEntities = this.em.entities.map((e) => e.name);
|
|
||||||
const tbNumber = Type.Transform(Type.String({ pattern: "^[1-9][0-9]{0,}$" }))
|
|
||||||
.Decode(Number.parseInt)
|
|
||||||
.Encode(String);
|
|
||||||
|
|
||||||
// @todo: sample implementation how to augment handler with additional info
|
// @todo: sample implementation how to augment handler with additional info
|
||||||
function handler<HH extends Handler>(name: string, h: HH): any {
|
function handler<HH extends Handler>(name: string, h: HH): any {
|
||||||
const func = h;
|
const func = h;
|
||||||
@@ -141,10 +134,8 @@ export class DataController extends Controller {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
//console.log("request", c.req.raw);
|
|
||||||
const { entity, context } = c.req.param();
|
const { entity, context } = c.req.param();
|
||||||
if (!this.entityExists(entity)) {
|
if (!this.entityExists(entity)) {
|
||||||
console.warn("not found:", entity, definedEntities);
|
|
||||||
return this.notFound(c);
|
return this.notFound(c);
|
||||||
}
|
}
|
||||||
const _entity = this.em.entity(entity);
|
const _entity = this.em.entity(entity);
|
||||||
@@ -254,7 +245,6 @@ export class DataController extends Controller {
|
|||||||
async (c) => {
|
async (c) => {
|
||||||
const { entity } = c.req.param();
|
const { entity } = c.req.param();
|
||||||
if (!this.entityExists(entity)) {
|
if (!this.entityExists(entity)) {
|
||||||
console.warn("not found:", entity, definedEntities);
|
|
||||||
return this.notFound(c);
|
return this.notFound(c);
|
||||||
}
|
}
|
||||||
const options = c.req.valid("query") as RepoQuery;
|
const options = c.req.valid("query") as RepoQuery;
|
||||||
@@ -328,7 +318,6 @@ export class DataController extends Controller {
|
|||||||
return this.notFound(c);
|
return this.notFound(c);
|
||||||
}
|
}
|
||||||
const options = (await c.req.valid("json")) as RepoQuery;
|
const options = (await c.req.valid("json")) as RepoQuery;
|
||||||
//console.log("options", options);
|
|
||||||
const result = await this.em.repository(entity).findMany(options);
|
const result = await this.em.repository(entity).findMany(options);
|
||||||
|
|
||||||
return c.json(this.repoResult(result), { status: result.data ? 200 : 404 });
|
return c.json(this.repoResult(result), { status: result.data ? 200 : 404 });
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export class LibsqlConnection extends SqliteConnection {
|
|||||||
if (clientOrCredentials && "url" in clientOrCredentials) {
|
if (clientOrCredentials && "url" in clientOrCredentials) {
|
||||||
let { url, authToken, protocol } = clientOrCredentials;
|
let { url, authToken, protocol } = clientOrCredentials;
|
||||||
if (protocol && LIBSQL_PROTOCOLS.includes(protocol)) {
|
if (protocol && LIBSQL_PROTOCOLS.includes(protocol)) {
|
||||||
console.log("changing protocol to", protocol);
|
$console.log("changing protocol to", protocol);
|
||||||
const [, rest] = url.split("://");
|
const [, rest] = url.split("://");
|
||||||
url = `${protocol}://${rest}`;
|
url = `${protocol}://${rest}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ export type TAppDataField = Static<typeof fieldsSchema>;
|
|||||||
export type TAppDataEntityFields = Static<typeof entityFields>;
|
export type TAppDataEntityFields = Static<typeof entityFields>;
|
||||||
|
|
||||||
export const entitiesSchema = Type.Object({
|
export const entitiesSchema = Type.Object({
|
||||||
//name: Type.String(),
|
|
||||||
type: Type.Optional(Type.String({ enum: entityTypes, default: "regular", readOnly: true })),
|
type: Type.Optional(Type.String({ enum: entityTypes, default: "regular", readOnly: true })),
|
||||||
config: Type.Optional(entityConfigSchema),
|
config: Type.Optional(entityConfigSchema),
|
||||||
fields: Type.Optional(entityFields),
|
fields: Type.Optional(entityFields),
|
||||||
@@ -60,7 +59,6 @@ export const indicesSchema = Type.Object(
|
|||||||
{
|
{
|
||||||
entity: Type.String(),
|
entity: Type.String(),
|
||||||
fields: Type.Array(Type.String(), { minItems: 1 }),
|
fields: Type.Array(Type.String(), { minItems: 1 }),
|
||||||
//name: Type.Optional(Type.String()),
|
|
||||||
unique: Type.Optional(Type.Boolean({ default: false })),
|
unique: Type.Optional(Type.Boolean({ default: false })),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { config } from "core";
|
import { $console, config } from "core";
|
||||||
import {
|
import {
|
||||||
type Static,
|
type Static,
|
||||||
StringEnum,
|
StringEnum,
|
||||||
@@ -183,9 +183,9 @@ export class Entity<
|
|||||||
if (existing) {
|
if (existing) {
|
||||||
// @todo: for now adding a graceful method
|
// @todo: for now adding a graceful method
|
||||||
if (JSON.stringify(existing) === JSON.stringify(field)) {
|
if (JSON.stringify(existing) === JSON.stringify(field)) {
|
||||||
/*console.warn(
|
$console.warn(
|
||||||
`Field "${field.name}" already exists on entity "${this.name}", but it's the same, so skipping.`,
|
`Field "${field.name}" already exists on entity "${this.name}", but it's the same, so skipping.`,
|
||||||
);*/
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +232,13 @@ export class Entity<
|
|||||||
|
|
||||||
for (const field of fields) {
|
for (const field of fields) {
|
||||||
if (!field.isValid(data[field.name], context)) {
|
if (!field.isValid(data[field.name], context)) {
|
||||||
console.log("Entity.isValidData:invalid", context, field.name, data[field.name]);
|
$console.warn(
|
||||||
|
"invalid data given for",
|
||||||
|
this.name,
|
||||||
|
context,
|
||||||
|
field.name,
|
||||||
|
data[field.name],
|
||||||
|
);
|
||||||
if (options?.explain) {
|
if (options?.explain) {
|
||||||
throw new Error(`Field "${field.name}" has invalid data: "${data[field.name]}"`);
|
throw new Error(`Field "${field.name}" has invalid data: "${data[field.name]}"`);
|
||||||
}
|
}
|
||||||
@@ -258,7 +264,6 @@ export class Entity<
|
|||||||
const _fields = Object.fromEntries(fields.map((field) => [field.name, field]));
|
const _fields = Object.fromEntries(fields.map((field) => [field.name, field]));
|
||||||
const schema = Type.Object(
|
const schema = Type.Object(
|
||||||
transformObject(_fields, (field) => {
|
transformObject(_fields, (field) => {
|
||||||
//const hidden = field.isHidden(options?.context);
|
|
||||||
const fillable = field.isFillable(options?.context);
|
const fillable = field.isFillable(options?.context);
|
||||||
return {
|
return {
|
||||||
title: field.config.label,
|
title: field.config.label,
|
||||||
@@ -276,9 +281,7 @@ export class Entity<
|
|||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
return {
|
return {
|
||||||
//name: this.name,
|
|
||||||
type: this.type,
|
type: this.type,
|
||||||
//fields: transformObject(this.fields, (field) => field.toJSON()),
|
|
||||||
fields: Object.fromEntries(this.fields.map((field) => [field.name, field.toJSON()])),
|
fields: Object.fromEntries(this.fields.map((field) => [field.name, field.toJSON()])),
|
||||||
config: this.config,
|
config: this.config,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { DB as DefaultDB } from "core";
|
import { $console, type DB as DefaultDB } from "core";
|
||||||
import { EventManager } from "core/events";
|
import { EventManager } from "core/events";
|
||||||
import { sql } from "kysely";
|
import { sql } from "kysely";
|
||||||
import { Connection } from "../connection/Connection";
|
import { Connection } from "../connection/Connection";
|
||||||
@@ -55,7 +55,6 @@ export class EntityManager<TBD extends object = DefaultDB> {
|
|||||||
|
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.emgr = emgr ?? new EventManager();
|
this.emgr = emgr ?? new EventManager();
|
||||||
//console.log("registering events", EntityManager.Events);
|
|
||||||
this.emgr.registerEvents(EntityManager.Events);
|
this.emgr.registerEvents(EntityManager.Events);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +89,9 @@ export class EntityManager<TBD extends object = DefaultDB> {
|
|||||||
if (existing) {
|
if (existing) {
|
||||||
// @todo: for now adding a graceful method
|
// @todo: for now adding a graceful method
|
||||||
if (JSON.stringify(existing) === JSON.stringify(entity)) {
|
if (JSON.stringify(existing) === JSON.stringify(entity)) {
|
||||||
//console.warn(`Entity "${entity.name}" already exists, but it's the same, so skipping.`);
|
$console.warn(
|
||||||
|
`Entity "${entity.name}" already exists, but it's the same, skipping adding it.`,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +109,6 @@ export class EntityManager<TBD extends object = DefaultDB> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._entities[entityIndex] = entity;
|
this._entities[entityIndex] = entity;
|
||||||
|
|
||||||
// caused issues because this.entity() was using a reference (for when initial config was given)
|
// caused issues because this.entity() was using a reference (for when initial config was given)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +295,6 @@ export class EntityManager<TBD extends object = DefaultDB> {
|
|||||||
return {
|
return {
|
||||||
entities: Object.fromEntries(this.entities.map((e) => [e.name, e.toJSON()])),
|
entities: Object.fromEntries(this.entities.map((e) => [e.name, e.toJSON()])),
|
||||||
relations: Object.fromEntries(this.relations.all.map((r) => [r.getName(), r.toJSON()])),
|
relations: Object.fromEntries(this.relations.all.map((r) => [r.getName(), r.toJSON()])),
|
||||||
//relations: this.relations.all.map((r) => r.toJSON()),
|
|
||||||
indices: Object.fromEntries(this.indices.map((i) => [i.name, i.toJSON()])),
|
indices: Object.fromEntries(this.indices.map((i) => [i.name, i.toJSON()])),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { DB as DefaultDB, PrimaryFieldType } from "core";
|
import { $console, type DB as DefaultDB, type PrimaryFieldType } from "core";
|
||||||
import { type EmitsEvents, EventManager } from "core/events";
|
import { type EmitsEvents, EventManager } from "core/events";
|
||||||
import type { DeleteQueryBuilder, InsertQueryBuilder, UpdateQueryBuilder } from "kysely";
|
import type { DeleteQueryBuilder, InsertQueryBuilder, UpdateQueryBuilder } from "kysely";
|
||||||
import { type TActionContext, WhereBuilder } from "..";
|
import { type TActionContext, WhereBuilder } from "..";
|
||||||
@@ -72,7 +72,6 @@ export class Mutator<
|
|||||||
|
|
||||||
// if relation field (include key and value in validatedData)
|
// if relation field (include key and value in validatedData)
|
||||||
if (Array.isArray(result)) {
|
if (Array.isArray(result)) {
|
||||||
//console.log("--- (instructions)", result);
|
|
||||||
const [relation_key, relation_value] = result;
|
const [relation_key, relation_value] = result;
|
||||||
validatedData[relation_key] = relation_value;
|
validatedData[relation_key] = relation_value;
|
||||||
}
|
}
|
||||||
@@ -122,7 +121,7 @@ export class Mutator<
|
|||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// @todo: redact
|
// @todo: redact
|
||||||
console.log("[Error in query]", sql);
|
$console.error("[Error in query]", sql);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ export class BooleanField<Required extends true | false = false> extends Field<
|
|||||||
}
|
}
|
||||||
|
|
||||||
override transformRetrieve(value: unknown): boolean | null {
|
override transformRetrieve(value: unknown): boolean | null {
|
||||||
//console.log("Boolean:transformRetrieve:value", value);
|
|
||||||
if (typeof value === "undefined" || value === null) {
|
if (typeof value === "undefined" || value === null) {
|
||||||
if (this.isRequired()) return false;
|
if (this.isRequired()) return false;
|
||||||
if (this.hasDefault()) return this.getDefault();
|
if (this.hasDefault()) return this.getDefault();
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { type Static, StringEnum, Type, dayjs } from "core/utils";
|
import { type Static, StringEnum, Type, dayjs } from "core/utils";
|
||||||
import type { EntityManager } from "../entities";
|
import type { EntityManager } from "../entities";
|
||||||
import { Field, type TActionContext, type TRenderContext, baseFieldConfigSchema } from "./Field";
|
import { Field, type TActionContext, type TRenderContext, baseFieldConfigSchema } from "./Field";
|
||||||
|
import { $console } from "core";
|
||||||
|
|
||||||
export const dateFieldConfigSchema = Type.Composite(
|
export const dateFieldConfigSchema = Type.Composite(
|
||||||
[
|
[
|
||||||
Type.Object({
|
Type.Object({
|
||||||
//default_value: Type.Optional(Type.Date()),
|
|
||||||
type: StringEnum(["date", "datetime", "week"] as const, { default: "date" }),
|
type: StringEnum(["date", "datetime", "week"] as const, { default: "date" }),
|
||||||
timezone: Type.Optional(Type.String()),
|
timezone: Type.Optional(Type.String()),
|
||||||
min_date: Type.Optional(Type.String()),
|
min_date: Type.Optional(Type.String()),
|
||||||
@@ -51,13 +51,11 @@ export class DateField<Required extends true | false = false> extends Field<
|
|||||||
}
|
}
|
||||||
|
|
||||||
private parseDateFromString(value: string): Date {
|
private parseDateFromString(value: string): Date {
|
||||||
//console.log("parseDateFromString", value);
|
|
||||||
if (this.config.type === "week" && value.includes("-W")) {
|
if (this.config.type === "week" && value.includes("-W")) {
|
||||||
const [year, week] = value.split("-W").map((n) => Number.parseInt(n, 10)) as [
|
const [year, week] = value.split("-W").map((n) => Number.parseInt(n, 10)) as [
|
||||||
number,
|
number,
|
||||||
number,
|
number,
|
||||||
];
|
];
|
||||||
//console.log({ year, week });
|
|
||||||
// @ts-ignore causes errors on build?
|
// @ts-ignore causes errors on build?
|
||||||
return dayjs().year(year).week(week).toDate();
|
return dayjs().year(year).week(week).toDate();
|
||||||
}
|
}
|
||||||
@@ -67,15 +65,12 @@ export class DateField<Required extends true | false = false> extends Field<
|
|||||||
|
|
||||||
override getValue(value: string, context?: TRenderContext): string | undefined {
|
override getValue(value: string, context?: TRenderContext): string | undefined {
|
||||||
if (value === null || !value) return;
|
if (value === null || !value) return;
|
||||||
//console.log("getValue", { value, context });
|
|
||||||
const date = this.parseDateFromString(value);
|
const date = this.parseDateFromString(value);
|
||||||
//console.log("getValue.date", date);
|
|
||||||
|
|
||||||
if (context === "submit") {
|
if (context === "submit") {
|
||||||
try {
|
try {
|
||||||
return date.toISOString();
|
return date.toISOString();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//console.warn("DateField.getValue:value/submit", value, e);
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,7 +79,7 @@ export class DateField<Required extends true | false = false> extends Field<
|
|||||||
try {
|
try {
|
||||||
return `${date.getFullYear()}-W${dayjs(date).week()}`;
|
return `${date.getFullYear()}-W${dayjs(date).week()}`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("error - DateField.getValue:week", value, e);
|
$console.warn("DateField.getValue:week error", value, String(e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,8 +92,7 @@ export class DateField<Required extends true | false = false> extends Field<
|
|||||||
|
|
||||||
return this.formatDate(local);
|
return this.formatDate(local);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("DateField.getValue:value", value);
|
$console.warn("DateField.getValue error", this.config.type, value, String(e));
|
||||||
console.warn("DateField.getValue:e", e);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +111,6 @@ export class DateField<Required extends true | false = false> extends Field<
|
|||||||
}
|
}
|
||||||
|
|
||||||
override transformRetrieve(_value: string): Date | null {
|
override transformRetrieve(_value: string): Date | null {
|
||||||
//console.log("transformRetrieve DateField", _value);
|
|
||||||
const value = super.transformRetrieve(_value);
|
const value = super.transformRetrieve(_value);
|
||||||
if (value === null) return null;
|
if (value === null) return null;
|
||||||
|
|
||||||
@@ -136,7 +129,6 @@ export class DateField<Required extends true | false = false> extends Field<
|
|||||||
const value = await super.transformPersist(_value, em, context);
|
const value = await super.transformPersist(_value, em, context);
|
||||||
if (this.nullish(value)) return value;
|
if (this.nullish(value)) return value;
|
||||||
|
|
||||||
//console.log("transformPersist DateField", value);
|
|
||||||
switch (this.config.type) {
|
switch (this.config.type) {
|
||||||
case "date":
|
case "date":
|
||||||
case "week":
|
case "week":
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Const, type Static, StringEnum, StringRecord, Type } from "core/utils";
|
import { Const, type Static, StringEnum, Type } from "core/utils";
|
||||||
import type { EntityManager } from "data";
|
import type { EntityManager } from "data";
|
||||||
import { TransformPersistFailedException } from "../errors";
|
import { TransformPersistFailedException } from "../errors";
|
||||||
import { Field, type TActionContext, type TRenderContext, baseFieldConfigSchema } from "./Field";
|
import { baseFieldConfigSchema, Field, type TActionContext, type TRenderContext } from "./Field";
|
||||||
|
|
||||||
export const enumFieldConfigSchema = Type.Composite(
|
export const enumFieldConfigSchema = Type.Composite(
|
||||||
[
|
[
|
||||||
@@ -53,10 +53,6 @@ export class EnumField<Required extends true | false = false, TypeOverride = str
|
|||||||
constructor(name: string, config: Partial<EnumFieldConfig>) {
|
constructor(name: string, config: Partial<EnumFieldConfig>) {
|
||||||
super(name, config);
|
super(name, config);
|
||||||
|
|
||||||
/*if (this.config.options.values.length === 0) {
|
|
||||||
throw new Error(`Enum field "${this.name}" requires at least one option`);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (this.config.default_value && !this.isValidValue(this.config.default_value)) {
|
if (this.config.default_value && !this.isValidValue(this.config.default_value)) {
|
||||||
throw new Error(`Default value "${this.config.default_value}" is not a valid option`);
|
throw new Error(`Default value "${this.config.default_value}" is not a valid option`);
|
||||||
}
|
}
|
||||||
@@ -69,10 +65,6 @@ export class EnumField<Required extends true | false = false, TypeOverride = str
|
|||||||
getOptions(): { label: string; value: string }[] {
|
getOptions(): { label: string; value: string }[] {
|
||||||
const options = this.config?.options ?? { type: "strings", values: [] };
|
const options = this.config?.options ?? { type: "strings", values: [] };
|
||||||
|
|
||||||
/*if (options.values?.length === 0) {
|
|
||||||
throw new Error(`Enum field "${this.name}" requires at least one option`);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (options.type === "strings") {
|
if (options.type === "strings") {
|
||||||
return options.values?.map((option) => ({ label: option, value: option }));
|
return options.values?.map((option) => ({ label: option, value: option }));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ export class JsonField<Required extends true | false = false, TypeOverride = obj
|
|||||||
context: TActionContext,
|
context: TActionContext,
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
const value = await super.transformPersist(_value, em, context);
|
const value = await super.transformPersist(_value, em, context);
|
||||||
//console.log("value", value);
|
|
||||||
if (this.nullish(value)) return value;
|
if (this.nullish(value)) return value;
|
||||||
|
|
||||||
if (!this.isSerializable(value)) {
|
if (!this.isSerializable(value)) {
|
||||||
|
|||||||
@@ -46,22 +46,16 @@ export class JsonSchemaField<
|
|||||||
|
|
||||||
override isValid(value: any, context: TActionContext = "update"): boolean {
|
override isValid(value: any, context: TActionContext = "update"): boolean {
|
||||||
const parentValid = super.isValid(value, context);
|
const parentValid = super.isValid(value, context);
|
||||||
//console.log("jsonSchemaField:isValid", this.getJsonSchema(), this.name, value, parentValid);
|
|
||||||
|
|
||||||
if (parentValid) {
|
if (parentValid) {
|
||||||
// already checked in parent
|
// already checked in parent
|
||||||
if (!this.isRequired() && (!value || typeof value !== "object")) {
|
if (!this.isRequired() && (!value || typeof value !== "object")) {
|
||||||
//console.log("jsonschema:valid: not checking", this.name, value, context);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = this.validator.validate(value);
|
const result = this.validator.validate(value);
|
||||||
//console.log("jsonschema:errors", this.name, result.errors);
|
|
||||||
return result.valid;
|
return result.valid;
|
||||||
} else {
|
|
||||||
//console.log("jsonschema:invalid", this.name, value, context);
|
|
||||||
}
|
}
|
||||||
//console.log("jsonschema:invalid:fromParent", this.name, value, context);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -89,7 +83,6 @@ export class JsonSchemaField<
|
|||||||
try {
|
try {
|
||||||
return Default(FromSchema(this.getJsonSchema()), {});
|
return Default(FromSchema(this.getJsonSchema()), {});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//console.error("jsonschema:transformRetrieve", e);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else if (this.hasDefault()) {
|
} else if (this.hasDefault()) {
|
||||||
@@ -107,13 +100,9 @@ export class JsonSchemaField<
|
|||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
const value = await super.transformPersist(_value, em, context);
|
const value = await super.transformPersist(_value, em, context);
|
||||||
if (this.nullish(value)) return value;
|
if (this.nullish(value)) return value;
|
||||||
//console.log("jsonschema:transformPersist", this.name, _value, context);
|
|
||||||
|
|
||||||
if (!this.isValid(value)) {
|
if (!this.isValid(value)) {
|
||||||
//console.error("jsonschema:transformPersist:invalid", this.name, value);
|
|
||||||
throw new TransformPersistFailedException(this.name, value);
|
throw new TransformPersistFailedException(this.name, value);
|
||||||
} else {
|
|
||||||
//console.log("jsonschema:transformPersist:valid", this.name, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!value || typeof value !== "object") return this.getDefault();
|
if (!value || typeof value !== "object") return this.getDefault();
|
||||||
|
|||||||
@@ -98,12 +98,9 @@ export function fieldTestSuite(
|
|||||||
test("toJSON", async () => {
|
test("toJSON", async () => {
|
||||||
const _config = {
|
const _config = {
|
||||||
..._requiredConfig,
|
..._requiredConfig,
|
||||||
//order: 1,
|
|
||||||
fillable: true,
|
fillable: true,
|
||||||
required: false,
|
required: false,
|
||||||
hidden: false,
|
hidden: false,
|
||||||
//virtual: false,
|
|
||||||
//default_value: undefined
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function fieldJson(field: Field) {
|
function fieldJson(field: Field) {
|
||||||
@@ -115,19 +112,16 @@ export function fieldTestSuite(
|
|||||||
}
|
}
|
||||||
|
|
||||||
expect(fieldJson(noConfigField)).toEqual({
|
expect(fieldJson(noConfigField)).toEqual({
|
||||||
//name: "no_config",
|
|
||||||
type: noConfigField.type,
|
type: noConfigField.type,
|
||||||
config: _config,
|
config: _config,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(fieldJson(fillable)).toEqual({
|
expect(fieldJson(fillable)).toEqual({
|
||||||
//name: "fillable",
|
|
||||||
type: noConfigField.type,
|
type: noConfigField.type,
|
||||||
config: _config,
|
config: _config,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(fieldJson(required)).toEqual({
|
expect(fieldJson(required)).toEqual({
|
||||||
//name: "required",
|
|
||||||
type: required.type,
|
type: required.type,
|
||||||
config: {
|
config: {
|
||||||
..._config,
|
..._config,
|
||||||
@@ -136,7 +130,6 @@ export function fieldTestSuite(
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(fieldJson(hidden)).toEqual({
|
expect(fieldJson(hidden)).toEqual({
|
||||||
//name: "hidden",
|
|
||||||
type: required.type,
|
type: required.type,
|
||||||
config: {
|
config: {
|
||||||
..._config,
|
..._config,
|
||||||
@@ -145,7 +138,6 @@ export function fieldTestSuite(
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(fieldJson(dflt)).toEqual({
|
expect(fieldJson(dflt)).toEqual({
|
||||||
//name: "dflt",
|
|
||||||
type: dflt.type,
|
type: dflt.type,
|
||||||
config: {
|
config: {
|
||||||
..._config,
|
..._config,
|
||||||
@@ -154,7 +146,6 @@ export function fieldTestSuite(
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(fieldJson(requiredAndDefault)).toEqual({
|
expect(fieldJson(requiredAndDefault)).toEqual({
|
||||||
//name: "full",
|
|
||||||
type: requiredAndDefault.type,
|
type: requiredAndDefault.type,
|
||||||
config: {
|
config: {
|
||||||
..._config,
|
..._config,
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ export class EntityIndex {
|
|||||||
return {
|
return {
|
||||||
entity: this.entity.name,
|
entity: this.entity.name,
|
||||||
fields: this.fields.map((f) => f.name),
|
fields: this.fields.map((f) => f.name),
|
||||||
//name: this.name,
|
|
||||||
unique: this.unique,
|
unique: this.unique,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ export function getChangeSet(
|
|||||||
data: EntityData,
|
data: EntityData,
|
||||||
fields: Field[],
|
fields: Field[],
|
||||||
): EntityData {
|
): EntityData {
|
||||||
//console.log("getChangeSet", formData, data);
|
|
||||||
return transform(
|
return transform(
|
||||||
formData,
|
formData,
|
||||||
(acc, _value, key) => {
|
(acc, _value, key) => {
|
||||||
@@ -32,17 +31,6 @@ export function getChangeSet(
|
|||||||
// @todo: add typing for "action"
|
// @todo: add typing for "action"
|
||||||
if (action === "create" || newValue !== data[key]) {
|
if (action === "create" || newValue !== data[key]) {
|
||||||
acc[key] = newValue;
|
acc[key] = newValue;
|
||||||
/*console.log("changed", {
|
|
||||||
key,
|
|
||||||
value,
|
|
||||||
valueType: typeof value,
|
|
||||||
prev: data[key],
|
|
||||||
newValue,
|
|
||||||
new: value,
|
|
||||||
sent: acc[key]
|
|
||||||
});*/
|
|
||||||
} else {
|
|
||||||
//console.log("no change", key, value, data[key]);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{} as typeof formData,
|
{} as typeof formData,
|
||||||
|
|||||||
@@ -12,15 +12,6 @@ import type { RelationType } from "./relation-types";
|
|||||||
export type KyselyJsonFrom = any;
|
export type KyselyJsonFrom = any;
|
||||||
export type KyselyQueryBuilder = SelectQueryBuilder<any, any, any>;
|
export type KyselyQueryBuilder = SelectQueryBuilder<any, any, any>;
|
||||||
|
|
||||||
/*export type RelationConfig = {
|
|
||||||
mappedBy?: string;
|
|
||||||
inversedBy?: string;
|
|
||||||
sourceCardinality?: number;
|
|
||||||
connectionTable?: string;
|
|
||||||
connectionTableMappedName?: string;
|
|
||||||
required?: boolean;
|
|
||||||
};*/
|
|
||||||
|
|
||||||
export type BaseRelationConfig = Static<typeof EntityRelation.schema>;
|
export type BaseRelationConfig = Static<typeof EntityRelation.schema>;
|
||||||
|
|
||||||
// @todo: add generic type for relation config
|
// @todo: add generic type for relation config
|
||||||
@@ -165,7 +156,6 @@ export abstract class EntityRelation<
|
|||||||
* @param entity
|
* @param entity
|
||||||
*/
|
*/
|
||||||
isListableFor(entity: Entity): boolean {
|
isListableFor(entity: Entity): boolean {
|
||||||
//console.log("isListableFor", entity.name, this.source.entity.name, this.target.entity.name);
|
|
||||||
return this.target.entity.name === entity.name;
|
return this.target.entity.name === entity.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { type Static, Type } from "core/utils";
|
import { type Static, Type } from "core/utils";
|
||||||
import type { ExpressionBuilder } from "kysely";
|
import type { ExpressionBuilder } from "kysely";
|
||||||
import { Entity, type EntityManager } from "../entities";
|
import { Entity, type EntityManager } from "../entities";
|
||||||
import { type Field, PrimaryField, VirtualField } from "../fields";
|
import { type Field, PrimaryField } from "../fields";
|
||||||
import type { RepoQuery } from "../server/data-query-impl";
|
import type { RepoQuery } from "../server/data-query-impl";
|
||||||
import { EntityRelation, type KyselyJsonFrom, type KyselyQueryBuilder } from "./EntityRelation";
|
import { EntityRelation, type KyselyQueryBuilder } from "./EntityRelation";
|
||||||
import { EntityRelationAnchor } from "./EntityRelationAnchor";
|
import { EntityRelationAnchor } from "./EntityRelationAnchor";
|
||||||
import { RelationField } from "./RelationField";
|
import { RelationField } from "./RelationField";
|
||||||
import { type RelationType, RelationTypes } from "./relation-types";
|
import { type RelationType, RelationTypes } from "./relation-types";
|
||||||
@@ -46,7 +46,6 @@ export class ManyToManyRelation extends EntityRelation<typeof ManyToManyRelation
|
|||||||
|
|
||||||
this.connectionTableMappedName = config?.connectionTableMappedName || connectionTable;
|
this.connectionTableMappedName = config?.connectionTableMappedName || connectionTable;
|
||||||
this.additionalFields = additionalFields || [];
|
this.additionalFields = additionalFields || [];
|
||||||
//this.connectionTable = connectionTable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultConnectionTable(source: Entity, target: Entity) {
|
static defaultConnectionTable(source: Entity, target: Entity) {
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import type { PrimaryFieldType } from "core";
|
import type { PrimaryFieldType } from "core";
|
||||||
import { snakeToPascalWithSpaces } from "core/utils";
|
import { snakeToPascalWithSpaces, type Static, Type } from "core/utils";
|
||||||
import { type Static, Type } from "core/utils";
|
|
||||||
import type { ExpressionBuilder } from "kysely";
|
import type { ExpressionBuilder } from "kysely";
|
||||||
import type { Entity, EntityManager } from "../entities";
|
import type { Entity, EntityManager } from "../entities";
|
||||||
import type { RepoQuery } from "../server/data-query-impl";
|
import type { RepoQuery } from "../server/data-query-impl";
|
||||||
import { EntityRelation, type KyselyJsonFrom, type KyselyQueryBuilder } from "./EntityRelation";
|
import { EntityRelation, type KyselyQueryBuilder } from "./EntityRelation";
|
||||||
import { EntityRelationAnchor } from "./EntityRelationAnchor";
|
import { EntityRelationAnchor } from "./EntityRelationAnchor";
|
||||||
import { RelationField, type RelationFieldBaseConfig } from "./RelationField";
|
import { RelationField, type RelationFieldBaseConfig } from "./RelationField";
|
||||||
import type { MutationInstructionResponse } from "./RelationMutator";
|
import type { MutationInstructionResponse } from "./RelationMutator";
|
||||||
@@ -125,7 +124,6 @@ export class ManyToOneRelation extends EntityRelation<typeof ManyToOneRelation.s
|
|||||||
}
|
}
|
||||||
|
|
||||||
const groupBy = `${entity.name}.${entity.getPrimaryField().name}`;
|
const groupBy = `${entity.name}.${entity.getPrimaryField().name}`;
|
||||||
//console.log("queryInfo", entity.name, { reference, side, relationRef, entityRef, otherRef });
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
other,
|
other,
|
||||||
|
|||||||
@@ -15,11 +15,6 @@ export const relationFieldConfigSchema = Type.Composite([
|
|||||||
on_delete: Type.Optional(StringEnum(CASCADES, { default: "set null" })),
|
on_delete: Type.Optional(StringEnum(CASCADES, { default: "set null" })),
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
/*export const relationFieldConfigSchema = baseFieldConfigSchema.extend({
|
|
||||||
reference: z.string(),
|
|
||||||
target: z.string(),
|
|
||||||
target_field: z.string().catch("id"),
|
|
||||||
});*/
|
|
||||||
|
|
||||||
export type RelationFieldConfig = Static<typeof relationFieldConfigSchema>;
|
export type RelationFieldConfig = Static<typeof relationFieldConfigSchema>;
|
||||||
export type RelationFieldBaseConfig = { label?: string };
|
export type RelationFieldBaseConfig = { label?: string };
|
||||||
@@ -31,16 +26,6 @@ export class RelationField extends Field<RelationFieldConfig> {
|
|||||||
return relationFieldConfigSchema;
|
return relationFieldConfigSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*constructor(name: string, config?: Partial<RelationFieldConfig>) {
|
|
||||||
//relation_name = relation_name || target.name;
|
|
||||||
//const name = [relation_name, target.getPrimaryField().name].join("_");
|
|
||||||
super(name, config);
|
|
||||||
|
|
||||||
//console.log(this.config);
|
|
||||||
//this.relation.target = target;
|
|
||||||
//this.relation.name = relation_name;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
static create(
|
static create(
|
||||||
relation: EntityRelation,
|
relation: EntityRelation,
|
||||||
target: EntityRelationAnchor,
|
target: EntityRelationAnchor,
|
||||||
@@ -50,7 +35,7 @@ export class RelationField extends Field<RelationFieldConfig> {
|
|||||||
target.reference ?? target.entity.name,
|
target.reference ?? target.entity.name,
|
||||||
target.entity.getPrimaryField().name,
|
target.entity.getPrimaryField().name,
|
||||||
].join("_");
|
].join("_");
|
||||||
//console.log('name', name);
|
|
||||||
return new RelationField(name, {
|
return new RelationField(name, {
|
||||||
...config,
|
...config,
|
||||||
required: relation.required,
|
required: relation.required,
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ export class RelationMutator {
|
|||||||
// make sure it's a primitive value
|
// make sure it's a primitive value
|
||||||
// @todo: this is not a good way of checking primitives. Null is also an object
|
// @todo: this is not a good way of checking primitives. Null is also an object
|
||||||
if (typeof value === "object") {
|
if (typeof value === "object") {
|
||||||
console.log("value", value);
|
|
||||||
throw new Error(`Invalid value for relation field "${key}" given, expected primitive.`);
|
throw new Error(`Invalid value for relation field "${key}" given, expected primitive.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
type Field<Type, Required extends true | false> = {
|
|
||||||
_type: Type;
|
|
||||||
_required: Required;
|
|
||||||
};
|
|
||||||
type TextField<Required extends true | false = false> = Field<string, Required> & {
|
|
||||||
_type: string;
|
|
||||||
required: () => TextField<true>;
|
|
||||||
};
|
|
||||||
type NumberField<Required extends true | false = false> = Field<number, Required> & {
|
|
||||||
_type: number;
|
|
||||||
required: () => NumberField<true>;
|
|
||||||
};
|
|
||||||
|
|
||||||
type Entity<Fields extends Record<string, Field<any, any>> = {}> = { name: string; fields: Fields };
|
|
||||||
|
|
||||||
function entity<Fields extends Record<string, Field<any, any>>>(
|
|
||||||
name: string,
|
|
||||||
fields: Fields,
|
|
||||||
): Entity<Fields> {
|
|
||||||
return { name, fields };
|
|
||||||
}
|
|
||||||
|
|
||||||
function text(): TextField<false> {
|
|
||||||
return {} as any;
|
|
||||||
}
|
|
||||||
function number(): NumberField<false> {
|
|
||||||
return {} as any;
|
|
||||||
}
|
|
||||||
|
|
||||||
const field1 = text();
|
|
||||||
const field1_req = text().required();
|
|
||||||
const field2 = number();
|
|
||||||
const user = entity("users", {
|
|
||||||
name: text().required(),
|
|
||||||
bio: text(),
|
|
||||||
age: number(),
|
|
||||||
some: number().required(),
|
|
||||||
});
|
|
||||||
|
|
||||||
type InferEntityFields<T> = T extends Entity<infer Fields>
|
|
||||||
? {
|
|
||||||
[K in keyof Fields]: Fields[K] extends { _type: infer Type; _required: infer Required }
|
|
||||||
? Required extends true
|
|
||||||
? Type
|
|
||||||
: Type | undefined
|
|
||||||
: never;
|
|
||||||
}
|
|
||||||
: never;
|
|
||||||
|
|
||||||
type Prettify<T> = {
|
|
||||||
[K in keyof T]: T[K];
|
|
||||||
};
|
|
||||||
export type Simplify<T> = { [KeyType in keyof T]: T[KeyType] } & {};
|
|
||||||
|
|
||||||
// from https://github.com/type-challenges/type-challenges/issues/28200
|
|
||||||
type Merge<T> = {
|
|
||||||
[K in keyof T]: T[K];
|
|
||||||
};
|
|
||||||
type OptionalUndefined<
|
|
||||||
T,
|
|
||||||
Props extends keyof T = keyof T,
|
|
||||||
OptionsProps extends keyof T = Props extends keyof T
|
|
||||||
? undefined extends T[Props]
|
|
||||||
? Props
|
|
||||||
: never
|
|
||||||
: never,
|
|
||||||
> = Merge<
|
|
||||||
{
|
|
||||||
[K in OptionsProps]?: T[K];
|
|
||||||
} & {
|
|
||||||
[K in Exclude<keyof T, OptionsProps>]: T[K];
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
|
|
||||||
type UserFields = InferEntityFields<typeof user>;
|
|
||||||
type UserFields2 = Simplify<OptionalUndefined<UserFields>>;
|
|
||||||
|
|
||||||
const obj: UserFields2 = { name: "h", age: 1, some: 1 };
|
|
||||||
@@ -25,7 +25,6 @@ export class AppFlows extends Module<typeof flowsConfigSchema> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override async build() {
|
override async build() {
|
||||||
//console.log("building flows", this.config);
|
|
||||||
const flows = transformObject(this.config.flows, (flowConfig, name) => {
|
const flows = transformObject(this.config.flows, (flowConfig, name) => {
|
||||||
return Flow.fromObject(name, flowConfig as any, TASKS);
|
return Flow.fromObject(name, flowConfig as any, TASKS);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Event, EventManager, type ListenerHandler } from "core/events";
|
|||||||
import type { EmitsEvents } from "core/events";
|
import type { EmitsEvents } from "core/events";
|
||||||
import type { Task, TaskResult } from "../tasks/Task";
|
import type { Task, TaskResult } from "../tasks/Task";
|
||||||
import type { Flow } from "./Flow";
|
import type { Flow } from "./Flow";
|
||||||
|
import { $console } from "core";
|
||||||
|
|
||||||
export type TaskLog = TaskResult & {
|
export type TaskLog = TaskResult & {
|
||||||
task: Task;
|
task: Task;
|
||||||
@@ -185,10 +186,9 @@ export class Execution implements EmitsEvents {
|
|||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
return this.run();
|
return this.run();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("RuntimeExecutor: error", e);
|
$console.error("RuntimeExecutor: error", e);
|
||||||
|
|
||||||
// for now just throw
|
// for now just throw
|
||||||
// biome-ignore lint/complexity/noUselessCatch: @todo: add error task on flow
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Condition, TaskConnection } from "../tasks/TaskConnection";
|
|||||||
import { Execution } from "./Execution";
|
import { Execution } from "./Execution";
|
||||||
import { FlowTaskConnector } from "./FlowTaskConnector";
|
import { FlowTaskConnector } from "./FlowTaskConnector";
|
||||||
import { Trigger } from "./triggers/Trigger";
|
import { Trigger } from "./triggers/Trigger";
|
||||||
|
import { $console } from "core";
|
||||||
|
|
||||||
type Jsoned<T extends { toJSON: () => object }> = ReturnType<T["toJSON"]>;
|
type Jsoned<T extends { toJSON: () => object }> = ReturnType<T["toJSON"]>;
|
||||||
|
|
||||||
@@ -53,8 +54,6 @@ export class Flow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSequence(sequence: Task[][] = []): Task[][] {
|
getSequence(sequence: Task[][] = []): Task[][] {
|
||||||
//console.log("queue", queue.map((step) => step.map((t) => t.name)));
|
|
||||||
|
|
||||||
// start task
|
// start task
|
||||||
if (sequence.length === 0) {
|
if (sequence.length === 0) {
|
||||||
sequence.push([this.startTask]);
|
sequence.push([this.startTask]);
|
||||||
@@ -69,7 +68,6 @@ export class Flow {
|
|||||||
// check if task already in one of queue steps
|
// check if task already in one of queue steps
|
||||||
// this is when we have a circle back
|
// this is when we have a circle back
|
||||||
if (sequence.some((step) => step.includes(outTask))) {
|
if (sequence.some((step) => step.includes(outTask))) {
|
||||||
//console.log("Task already in queue", outTask.name);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nextStep.push(outTask);
|
nextStep.push(outTask);
|
||||||
@@ -110,14 +108,6 @@ export class Flow {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*getResponse() {
|
|
||||||
if (!this.respondingTask) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.respondingTask.log.output;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// @todo: check for existence
|
// @todo: check for existence
|
||||||
addConnection(connection: TaskConnection) {
|
addConnection(connection: TaskConnection) {
|
||||||
// check if connection already exists
|
// check if connection already exists
|
||||||
@@ -179,7 +169,7 @@ export class Flow {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return new cls(name, obj.params);
|
return new cls(name, obj.params);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.log("Error creating task", name, obj.type, obj, taskClass);
|
$console.error("Error creating task", name, obj.type, obj, taskClass);
|
||||||
throw new Error(`Error creating task ${obj.type}: ${e.message}`);
|
throw new Error(`Error creating task ${obj.type}: ${e.message}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -31,37 +31,11 @@ export class FlowTaskConnector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*const targetDepth = this.task(target).getDepth();
|
|
||||||
console.log("depth", ownDepth, targetDepth);
|
|
||||||
|
|
||||||
// if target has a lower depth
|
|
||||||
if (targetDepth > 0 && ownDepth >= targetDepth) {
|
|
||||||
// check for unique out conditions
|
|
||||||
console.log(
|
|
||||||
"out conditions",
|
|
||||||
this.source.name,
|
|
||||||
this.getOutConnections().map((c) => [c.target.name, c.condition])
|
|
||||||
);
|
|
||||||
if (
|
|
||||||
this.getOutConnections().some(
|
|
||||||
(c) =>
|
|
||||||
c.condition[0] === condition[0] &&
|
|
||||||
c.condition[1] === condition[1]
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
"Task cannot be connected to a deeper task with the same condition"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
this.flow.addConnection(new TaskConnection(this.source, target, { condition, max_retries }));
|
this.flow.addConnection(new TaskConnection(this.source, target, { condition, max_retries }));
|
||||||
}
|
}
|
||||||
|
|
||||||
asOutputFor(target: Task, condition?: Condition) {
|
asOutputFor(target: Task, condition?: Condition) {
|
||||||
this.task(target).asInputFor(this.source, condition);
|
this.task(target).asInputFor(this.source, condition);
|
||||||
//new FlowTaskConnector(this.flow, target).asInputFor(this.source);
|
|
||||||
//this.flow.addConnection(new TaskConnection(target, this.source));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getNext() {
|
getNext() {
|
||||||
@@ -107,12 +81,4 @@ export class FlowTaskConnector {
|
|||||||
getOutTasks(result?: TaskResult): Task[] {
|
getOutTasks(result?: TaskResult): Task[] {
|
||||||
return this.getOutConnections(result).map((c) => c.target);
|
return this.getOutConnections(result).map((c) => c.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*getNextRunnableConnections() {
|
|
||||||
return this.getOutConnections().filter((c) => c.source.log.success);
|
|
||||||
}
|
|
||||||
|
|
||||||
getNextRunnableTasks() {
|
|
||||||
return this.getNextRunnableConnections().map((c) => c.target);
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { Task } from "../../tasks/Task";
|
import type { Task } from "../../tasks/Task";
|
||||||
|
import { $console } from "core";
|
||||||
|
|
||||||
export class RuntimeExecutor {
|
export class RuntimeExecutor {
|
||||||
async run(
|
async run(
|
||||||
@@ -10,7 +11,6 @@ export class RuntimeExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//const promises = tasks.map((t) => t.run());
|
|
||||||
const promises = tasks.map(async (t) => {
|
const promises = tasks.map(async (t) => {
|
||||||
const result = await t.run();
|
const result = await t.run();
|
||||||
onDone?.(t, result);
|
onDone?.(t, result);
|
||||||
@@ -20,7 +20,7 @@ export class RuntimeExecutor {
|
|||||||
try {
|
try {
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("RuntimeExecutor: error", e);
|
$console.error("RuntimeExecutor: error", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.run(nextTasks, onDone);
|
return this.run(nextTasks, onDone);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import type { EventManager } from "core/events";
|
|||||||
import { Type } from "core/utils";
|
import { Type } from "core/utils";
|
||||||
import type { Flow } from "../Flow";
|
import type { Flow } from "../Flow";
|
||||||
import { Trigger } from "./Trigger";
|
import { Trigger } from "./Trigger";
|
||||||
|
import { $console } from "core";
|
||||||
|
|
||||||
export class EventTrigger extends Trigger<typeof EventTrigger.schema> {
|
export class EventTrigger extends Trigger<typeof EventTrigger.schema> {
|
||||||
override type = "event";
|
override type = "event";
|
||||||
@@ -22,17 +23,13 @@ export class EventTrigger extends Trigger<typeof EventTrigger.schema> {
|
|||||||
emgr.on(
|
emgr.on(
|
||||||
this.config.event,
|
this.config.event,
|
||||||
async (event) => {
|
async (event) => {
|
||||||
console.log("event", event);
|
|
||||||
/*if (!this.match(event)) {
|
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
const execution = flow.createExecution();
|
const execution = flow.createExecution();
|
||||||
this.executions.push(execution);
|
this.executions.push(execution);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await execution.start(event.params);
|
await execution.start(event.params);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
$console.error(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
this.config.mode,
|
this.config.mode,
|
||||||
|
|||||||
@@ -10,14 +10,11 @@ export class HttpTrigger extends Trigger<typeof HttpTrigger.schema> {
|
|||||||
|
|
||||||
static override schema = Type.Composite([
|
static override schema = Type.Composite([
|
||||||
Trigger.schema,
|
Trigger.schema,
|
||||||
Type.Object(
|
Type.Object({
|
||||||
{
|
path: Type.String({ pattern: "^/.*$" }),
|
||||||
path: Type.String({ pattern: "^/.*$" }),
|
method: StringEnum(httpMethods, { default: "GET" }),
|
||||||
method: StringEnum(httpMethods, { default: "GET" }),
|
response_type: StringEnum(["json", "text", "html"], { default: "json" }),
|
||||||
response_type: StringEnum(["json", "text", "html"], { default: "json" }),
|
}),
|
||||||
},
|
|
||||||
//{ additionalProperties: false }
|
|
||||||
),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
override async register(flow: Flow, hono: Hono<any>) {
|
override async register(flow: Flow, hono: Hono<any>) {
|
||||||
@@ -43,7 +40,5 @@ export class HttpTrigger extends Trigger<typeof HttpTrigger.schema> {
|
|||||||
execution.start(params);
|
execution.start(params);
|
||||||
return c.json({ success: true });
|
return c.json({ success: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
//console.log("--registered flow", flow.name, "on", method, this.config.path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,9 @@ export class Trigger<Schema extends typeof Trigger.schema = typeof Trigger.schem
|
|||||||
type = "manual";
|
type = "manual";
|
||||||
config: Static<Schema>;
|
config: Static<Schema>;
|
||||||
|
|
||||||
static schema = Type.Object(
|
static schema = Type.Object({
|
||||||
{
|
mode: StringEnum(["sync", "async"], { default: "async" }),
|
||||||
mode: StringEnum(["sync", "async"], { default: "async" }),
|
});
|
||||||
},
|
|
||||||
//{ additionalProperties: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
constructor(config?: Partial<Static<Schema>>) {
|
constructor(config?: Partial<Static<Schema>>) {
|
||||||
const schema = (this.constructor as typeof Trigger).schema;
|
const schema = (this.constructor as typeof Trigger).schema;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { Trigger } from "./Trigger";
|
|||||||
|
|
||||||
export { Trigger, EventTrigger, HttpTrigger };
|
export { Trigger, EventTrigger, HttpTrigger };
|
||||||
|
|
||||||
//export type TriggerMapType = { [key: string]: { cls: typeof Trigger } };
|
|
||||||
export const TriggerMap = {
|
export const TriggerMap = {
|
||||||
manual: { cls: Trigger },
|
manual: { cls: Trigger },
|
||||||
event: { cls: EventTrigger },
|
event: { cls: EventTrigger },
|
||||||
|
|||||||
@@ -23,13 +23,9 @@ export {
|
|||||||
} from "./flows/triggers";
|
} from "./flows/triggers";
|
||||||
|
|
||||||
import { Task } from "./tasks/Task";
|
import { Task } from "./tasks/Task";
|
||||||
export { type TaskResult, type TaskRenderProps } from "./tasks/Task";
|
export type { TaskResult, TaskRenderProps } from "./tasks/Task";
|
||||||
export { TaskConnection, Condition } from "./tasks/TaskConnection";
|
export { TaskConnection, Condition } from "./tasks/TaskConnection";
|
||||||
|
|
||||||
// test
|
|
||||||
//export { simpleFetch } from "./examples/simple-fetch";
|
|
||||||
|
|
||||||
//export type TaskMapType = { [key: string]: { cls: typeof Task<any> } };
|
|
||||||
export const TaskMap = {
|
export const TaskMap = {
|
||||||
fetch: { cls: FetchTask },
|
fetch: { cls: FetchTask },
|
||||||
log: { cls: LogTask },
|
log: { cls: LogTask },
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import type { StaticDecode, TSchema } from "@sinclair/typebox";
|
import type { StaticDecode, TSchema } from "@sinclair/typebox";
|
||||||
import type { NodeProps } from "@xyflow/react";
|
|
||||||
import { BkndError, SimpleRenderer } from "core";
|
import { BkndError, SimpleRenderer } from "core";
|
||||||
import { type Static, type TObject, Type, Value, parse, ucFirst } from "core/utils";
|
import { parse, type Static, type TObject, Type, ucFirst, Value } from "core/utils";
|
||||||
import type { ExecutionEvent, InputsMap } from "../flows/Execution";
|
import type { InputsMap } from "../flows/Execution";
|
||||||
//type InstanceOf<T> = T extends new (...args: any) => infer R ? R : never;
|
|
||||||
|
|
||||||
export type TaskResult<Output = any> = {
|
export type TaskResult<Output = any> = {
|
||||||
start: Date;
|
start: Date;
|
||||||
@@ -13,10 +11,6 @@ export type TaskResult<Output = any> = {
|
|||||||
params: any;
|
params: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*export type TaskRenderProps<T extends Task = Task> = NodeProps<{
|
|
||||||
task: T;
|
|
||||||
state: { i: number; isStartTask: boolean; isRespondingTask; event: ExecutionEvent | undefined };
|
|
||||||
}>;*/
|
|
||||||
export type TaskRenderProps<T extends Task = Task> = any;
|
export type TaskRenderProps<T extends Task = Task> = any;
|
||||||
|
|
||||||
export function dynamic<Type extends TSchema>(
|
export function dynamic<Type extends TSchema>(
|
||||||
@@ -93,21 +87,6 @@ export abstract class Task<Params extends TObject = TObject, Output = unknown> {
|
|||||||
|
|
||||||
// @todo: string enums fail to validate
|
// @todo: string enums fail to validate
|
||||||
this._params = parse(schema, params || {});
|
this._params = parse(schema, params || {});
|
||||||
|
|
||||||
/*const validator = new Validator(schema as any);
|
|
||||||
const _params = Default(schema, params || {});
|
|
||||||
const result = validator.validate(_params);
|
|
||||||
if (!result.valid) {
|
|
||||||
//console.log("---errors", result, { params, _params });
|
|
||||||
const error = result.errors[0]!;
|
|
||||||
throw new Error(
|
|
||||||
`Invalid params for task "${name}.${error.keyword}": "${
|
|
||||||
error.error
|
|
||||||
}". Params given: ${JSON.stringify(params)}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._params = _params as Static<Params>;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get params() {
|
get params() {
|
||||||
@@ -126,11 +105,8 @@ export abstract class Task<Params extends TObject = TObject, Output = unknown> {
|
|||||||
const newParams: any = {};
|
const newParams: any = {};
|
||||||
const renderer = new SimpleRenderer(inputs, { strictVariables: true, renderKeys: true });
|
const renderer = new SimpleRenderer(inputs, { strictVariables: true, renderKeys: true });
|
||||||
|
|
||||||
//console.log("--resolveParams", params);
|
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(params)) {
|
for (const [key, value] of Object.entries(params)) {
|
||||||
if (value && SimpleRenderer.hasMarkup(value)) {
|
if (value && SimpleRenderer.hasMarkup(value)) {
|
||||||
//console.log("--- has markup", value);
|
|
||||||
try {
|
try {
|
||||||
newParams[key] = await renderer.render(value as string);
|
newParams[key] = await renderer.render(value as string);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
@@ -150,29 +126,21 @@ export abstract class Task<Params extends TObject = TObject, Output = unknown> {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
//console.log("-- no markup", key, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newParams[key] = value;
|
newParams[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log("--beforeDecode", newParams);
|
return Value.Decode(schema, newParams);
|
||||||
const v = Value.Decode(schema, newParams);
|
|
||||||
//console.log("--afterDecode", v);
|
|
||||||
//process.exit();
|
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async cloneWithResolvedParams(_inputs: Map<string, any>) {
|
private async cloneWithResolvedParams(_inputs: Map<string, any>) {
|
||||||
const inputs = Object.fromEntries(_inputs.entries());
|
const inputs = Object.fromEntries(_inputs.entries());
|
||||||
//console.log("--clone:inputs", inputs, this.params);
|
|
||||||
const newParams = await Task.resolveParams(
|
const newParams = await Task.resolveParams(
|
||||||
(this.constructor as any).schema,
|
(this.constructor as any).schema,
|
||||||
this._params,
|
this._params,
|
||||||
inputs,
|
inputs,
|
||||||
);
|
);
|
||||||
//console.log("--clone:newParams", this.name, newParams);
|
|
||||||
|
|
||||||
return this.clone(this.name, newParams as any);
|
return this.clone(this.name, newParams as any);
|
||||||
}
|
}
|
||||||
@@ -200,7 +168,6 @@ export abstract class Task<Params extends TObject = TObject, Output = unknown> {
|
|||||||
success = true;
|
success = true;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
success = false;
|
success = false;
|
||||||
//status.output = undefined;
|
|
||||||
|
|
||||||
if (e instanceof BkndError) {
|
if (e instanceof BkndError) {
|
||||||
error = e.toJSON();
|
error = e.toJSON();
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ export class Condition {
|
|||||||
return result.success === false;
|
return result.success === false;
|
||||||
case "matches":
|
case "matches":
|
||||||
return get(result.output, this.path) === this.value;
|
return get(result.output, this.path) === this.value;
|
||||||
//return this.value === output[this.path];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ export class FetchTask<Output extends Record<string, any>> extends Task<
|
|||||||
url: Type.String({
|
url: Type.String({
|
||||||
pattern: "^(http|https)://",
|
pattern: "^(http|https)://",
|
||||||
}),
|
}),
|
||||||
//method: Type.Optional(Type.Enum(FetchMethodsEnum)),
|
|
||||||
//method: Type.Optional(dynamic(Type.String({ enum: FetchMethods, default: "GET" }))),
|
|
||||||
method: Type.Optional(dynamic(StringEnum(FetchMethods, { default: "GET" }))),
|
method: Type.Optional(dynamic(StringEnum(FetchMethods, { default: "GET" }))),
|
||||||
headers: Type.Optional(
|
headers: Type.Optional(
|
||||||
dynamic(
|
dynamic(
|
||||||
@@ -42,7 +40,6 @@ export class FetchTask<Output extends Record<string, any>> extends Task<
|
|||||||
}
|
}
|
||||||
|
|
||||||
async execute() {
|
async execute() {
|
||||||
//console.log(`method: (${this.params.method})`);
|
|
||||||
if (!FetchMethods.includes(this.params.method ?? "GET")) {
|
if (!FetchMethods.includes(this.params.method ?? "GET")) {
|
||||||
throw this.error("Invalid method", {
|
throw this.error("Invalid method", {
|
||||||
given: this.params.method,
|
given: this.params.method,
|
||||||
@@ -53,19 +50,12 @@ export class FetchTask<Output extends Record<string, any>> extends Task<
|
|||||||
const body = this.getBody();
|
const body = this.getBody();
|
||||||
const headers = new Headers(this.params.headers?.map((h) => [h.key, h.value]));
|
const headers = new Headers(this.params.headers?.map((h) => [h.key, h.value]));
|
||||||
|
|
||||||
/*console.log("[FETCH]", {
|
|
||||||
url: this.params.url,
|
|
||||||
method: this.params.method ?? "GET",
|
|
||||||
headers,
|
|
||||||
body
|
|
||||||
});*/
|
|
||||||
const result = await fetch(this.params.url, {
|
const result = await fetch(this.params.url, {
|
||||||
method: this.params.method ?? "GET",
|
method: this.params.method ?? "GET",
|
||||||
headers,
|
headers,
|
||||||
body,
|
body,
|
||||||
});
|
});
|
||||||
|
|
||||||
//console.log("fetch:response", result);
|
|
||||||
if (!result.ok) {
|
if (!result.ok) {
|
||||||
throw this.error("Failed to fetch", {
|
throw this.error("Failed to fetch", {
|
||||||
status: result.status,
|
status: result.status,
|
||||||
@@ -74,8 +64,6 @@ export class FetchTask<Output extends Record<string, any>> extends Task<
|
|||||||
}
|
}
|
||||||
|
|
||||||
const data = (await result.json()) as Output;
|
const data = (await result.json()) as Output;
|
||||||
//console.log("fetch:response:data", data);
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Type } from "core/utils";
|
import { Type } from "core/utils";
|
||||||
import { Task } from "../Task";
|
import { Task } from "../Task";
|
||||||
|
import { $console } from "core";
|
||||||
|
|
||||||
export class LogTask extends Task<typeof LogTask.schema> {
|
export class LogTask extends Task<typeof LogTask.schema> {
|
||||||
type = "log";
|
type = "log";
|
||||||
@@ -10,7 +11,7 @@ export class LogTask extends Task<typeof LogTask.schema> {
|
|||||||
|
|
||||||
async execute() {
|
async execute() {
|
||||||
await new Promise((resolve) => setTimeout(resolve, this.params.delay));
|
await new Promise((resolve) => setTimeout(resolve, this.params.delay));
|
||||||
console.log(`[DONE] LogTask: ${this.name}`);
|
$console.log(`[DONE] LogTask: ${this.name}`);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { PrimaryFieldType } from "core";
|
import { $console, type PrimaryFieldType } from "core";
|
||||||
import { type Entity, EntityIndex, type EntityManager } from "data";
|
import { type Entity, type EntityManager } from "data";
|
||||||
import { type FileUploadedEventData, Storage, type StorageAdapter } from "media";
|
import { type FileUploadedEventData, Storage, type StorageAdapter } from "media";
|
||||||
import { Module } from "modules/Module";
|
import { Module } from "modules/Module";
|
||||||
import {
|
import {
|
||||||
@@ -145,11 +145,10 @@ export class AppMedia extends Module<typeof mediaConfigSchema> {
|
|||||||
// simple file deletion sync
|
// simple file deletion sync
|
||||||
const { data } = await em.repo(media).findOne({ path: e.params.name });
|
const { data } = await em.repo(media).findOne({ path: e.params.name });
|
||||||
if (data) {
|
if (data) {
|
||||||
console.log("item.data", data);
|
|
||||||
await em.mutator(media).deleteOne(data.id);
|
await em.mutator(media).deleteOne(data.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("App:storage:file deleted", e);
|
$console.log("App:storage:file deleted", e.params);
|
||||||
},
|
},
|
||||||
{ mode: "sync", id: "delete-data-media" },
|
{ mode: "sync", id: "delete-data-media" },
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { PrimaryFieldType } from "core";
|
import { $console, type PrimaryFieldType } from "core";
|
||||||
import { isDebug } from "core/env";
|
import { isDebug } from "core/env";
|
||||||
import { encodeSearch } from "core/utils/reqres";
|
import { encodeSearch } from "core/utils/reqres";
|
||||||
|
|
||||||
@@ -87,7 +87,6 @@ export abstract class ModuleApi<Options extends BaseModuleApiOptions = BaseModul
|
|||||||
|
|
||||||
// only add token if initial headers not provided
|
// only add token if initial headers not provided
|
||||||
if (this.options.token && this.options.token_transport === "header") {
|
if (this.options.token && this.options.token_transport === "header") {
|
||||||
//console.log("setting token", this.options.token);
|
|
||||||
headers.set("Authorization", `Bearer ${this.options.token}`);
|
headers.set("Authorization", `Bearer ${this.options.token}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +244,7 @@ export class FetchPromise<T = ApiResponse<any>> implements Promise<T> {
|
|||||||
|
|
||||||
const fetcher = this.options?.fetcher ?? fetch;
|
const fetcher = this.options?.fetcher ?? fetch;
|
||||||
if (this.verbose) {
|
if (this.verbose) {
|
||||||
console.log("[FetchPromise] Request", {
|
$console.debug("[FetchPromise] Request", {
|
||||||
method: this.request.method,
|
method: this.request.method,
|
||||||
url: this.request.url,
|
url: this.request.url,
|
||||||
});
|
});
|
||||||
@@ -253,7 +252,7 @@ export class FetchPromise<T = ApiResponse<any>> implements Promise<T> {
|
|||||||
|
|
||||||
const res = await fetcher(this.request);
|
const res = await fetcher(this.request);
|
||||||
if (this.verbose) {
|
if (this.verbose) {
|
||||||
console.log("[FetchPromise] Response", {
|
$console.debug("[FetchPromise] Response", {
|
||||||
res: res,
|
res: res,
|
||||||
ok: res.ok,
|
ok: res.ok,
|
||||||
status: res.status,
|
status: res.status,
|
||||||
|
|||||||
@@ -560,7 +560,7 @@ export class ModuleManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return async (...args) => {
|
return async (...args) => {
|
||||||
console.log("[Safe Mutate]", name);
|
$console.log("[Safe Mutate]", name);
|
||||||
try {
|
try {
|
||||||
// overwrite listener to run build inside this try/catch
|
// overwrite listener to run build inside this try/catch
|
||||||
module.setListener(async () => {
|
module.setListener(async () => {
|
||||||
@@ -582,12 +582,12 @@ export class ModuleManager {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[Safe Mutate] failed", e);
|
$console.error("[Safe Mutate] failed", e);
|
||||||
|
|
||||||
// revert to previous config & rebuild using original listener
|
// revert to previous config & rebuild using original listener
|
||||||
this.setConfigs(copy);
|
this.setConfigs(copy);
|
||||||
await this.onModuleConfigUpdated(name, module.config as any);
|
await this.onModuleConfigUpdated(name, module.config as any);
|
||||||
console.log("[Safe Mutate] reverted");
|
$console.warn("[Safe Mutate] reverted");
|
||||||
|
|
||||||
// make sure to throw the error
|
// make sure to throw the error
|
||||||
throw e;
|
throw e;
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export { auth, permission } from "auth/middlewares";
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import { _jsonp, transformObject } from "core/utils";
|
import { transformObject } from "core/utils";
|
||||||
import { type Kysely, sql } from "kysely";
|
import type { Kysely } from "kysely";
|
||||||
import { set } from "lodash-es";
|
import { set } from "lodash-es";
|
||||||
import type { InitialModuleConfigs } from "modules/ModuleManager";
|
|
||||||
|
|
||||||
export type MigrationContext = {
|
export type MigrationContext = {
|
||||||
db: Kysely<any>;
|
db: Kysely<any>;
|
||||||
@@ -17,7 +16,6 @@ export type Migration = {
|
|||||||
export const migrations: Migration[] = [
|
export const migrations: Migration[] = [
|
||||||
{
|
{
|
||||||
version: 1,
|
version: 1,
|
||||||
//schema: true,
|
|
||||||
up: async (config) => config,
|
up: async (config) => config,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -28,7 +26,6 @@ export const migrations: Migration[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
version: 3,
|
version: 3,
|
||||||
//schema: true,
|
|
||||||
up: async (config) => config,
|
up: async (config) => config,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -46,7 +43,6 @@ export const migrations: Migration[] = [
|
|||||||
{
|
{
|
||||||
version: 5,
|
version: 5,
|
||||||
up: async (config, { db }) => {
|
up: async (config, { db }) => {
|
||||||
//console.log("config", _jsonp(config));
|
|
||||||
const cors = config.server.cors?.allow_methods ?? [];
|
const cors = config.server.cors?.allow_methods ?? [];
|
||||||
set(config.server, "cors.allow_methods", [...new Set([...cors, "PATCH"])]);
|
set(config.server, "cors.allow_methods", [...new Set([...cors, "PATCH"])]);
|
||||||
return config;
|
return config;
|
||||||
@@ -114,15 +110,12 @@ export async function migrateTo(
|
|||||||
config: GenericConfigObject,
|
config: GenericConfigObject,
|
||||||
ctx: MigrationContext,
|
ctx: MigrationContext,
|
||||||
): Promise<[number, GenericConfigObject]> {
|
): Promise<[number, GenericConfigObject]> {
|
||||||
//console.log("migrating from", current, "to", CURRENT_VERSION, config);
|
|
||||||
const todo = migrations.filter((m) => m.version > current && m.version <= to);
|
const todo = migrations.filter((m) => m.version > current && m.version <= to);
|
||||||
//console.log("todo", todo.length);
|
|
||||||
let updated = Object.assign({}, config);
|
let updated = Object.assign({}, config);
|
||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let version = current;
|
let version = current;
|
||||||
for (const migration of todo) {
|
for (const migration of todo) {
|
||||||
//console.log("-- running migration", i + 1, "of", todo.length, { version: migration.version });
|
|
||||||
try {
|
try {
|
||||||
updated = await migration.up(updated, ctx);
|
updated = await migration.up(updated, ctx);
|
||||||
version = migration.version;
|
version = migration.version;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/** @jsxImportSource hono/jsx */
|
/** @jsxImportSource hono/jsx */
|
||||||
|
|
||||||
import type { App } from "App";
|
import type { App } from "App";
|
||||||
import { config, isDebug } from "core";
|
import { $console, config, isDebug } from "core";
|
||||||
import { addFlashMessage } from "core/server/flash";
|
import { addFlashMessage } from "core/server/flash";
|
||||||
import { html } from "hono/html";
|
import { html } from "hono/html";
|
||||||
import { Fragment } from "hono/jsx";
|
import { Fragment } from "hono/jsx";
|
||||||
@@ -99,7 +99,7 @@ export class AdminController extends Controller {
|
|||||||
onGranted: async (c) => {
|
onGranted: async (c) => {
|
||||||
// @todo: add strict test to permissions middleware?
|
// @todo: add strict test to permissions middleware?
|
||||||
if (c.get("auth")?.user) {
|
if (c.get("auth")?.user) {
|
||||||
console.log("redirecting to success");
|
$console.log("redirecting to success");
|
||||||
return c.redirect(authRoutes.success);
|
return c.redirect(authRoutes.success);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -122,7 +122,7 @@ export class AdminController extends Controller {
|
|||||||
onDenied: async (c) => {
|
onDenied: async (c) => {
|
||||||
addFlashMessage(c, "You are not authorized to access the Admin UI", "error");
|
addFlashMessage(c, "You are not authorized to access the Admin UI", "error");
|
||||||
|
|
||||||
console.log("redirecting");
|
$console.log("redirecting");
|
||||||
return c.redirect(authRoutes.login);
|
return c.redirect(authRoutes.login);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -150,7 +150,7 @@ export class AdminController extends Controller {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.warn(
|
$console.warn(
|
||||||
`Custom HTML needs to include '${htmlBkndContextReplace}' to inject BKND context`,
|
`Custom HTML needs to include '${htmlBkndContextReplace}' to inject BKND context`,
|
||||||
);
|
);
|
||||||
return this.options.html as string;
|
return this.options.html as string;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Exception, isDebug } from "core";
|
import { $console, Exception, isDebug } from "core";
|
||||||
import { type Static, StringEnum, Type } from "core/utils";
|
import { type Static, StringEnum, Type } from "core/utils";
|
||||||
import { cors } from "hono/cors";
|
import { cors } from "hono/cors";
|
||||||
import { Module } from "modules/Module";
|
import { Module } from "modules/Module";
|
||||||
@@ -29,8 +29,6 @@ export const serverConfigSchema = Type.Object(
|
|||||||
export type AppServerConfig = Static<typeof serverConfigSchema>;
|
export type AppServerConfig = Static<typeof serverConfigSchema>;
|
||||||
|
|
||||||
export class AppServer extends Module<typeof serverConfigSchema> {
|
export class AppServer extends Module<typeof serverConfigSchema> {
|
||||||
//private admin_html?: string;
|
|
||||||
|
|
||||||
override getRestrictedPaths() {
|
override getRestrictedPaths() {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -70,14 +68,13 @@ export class AppServer extends Module<typeof serverConfigSchema> {
|
|||||||
|
|
||||||
this.client.onError((err, c) => {
|
this.client.onError((err, c) => {
|
||||||
//throw err;
|
//throw err;
|
||||||
console.error(err);
|
$console.error(err);
|
||||||
|
|
||||||
if (err instanceof Response) {
|
if (err instanceof Response) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err instanceof Exception) {
|
if (err instanceof Exception) {
|
||||||
console.log("---is exception", err.code);
|
|
||||||
return c.json(err.toJSON(), err.code as any);
|
return c.json(err.toJSON(), err.code as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ export class SystemController extends Controller {
|
|||||||
try {
|
try {
|
||||||
return c.json(await cb(), { status: 202 });
|
return c.json(await cb(), { status: 202 });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
$console.error("config update error", e);
|
||||||
|
|
||||||
if (e instanceof TypeInvalidError) {
|
if (e instanceof TypeInvalidError) {
|
||||||
return c.json(
|
return c.json(
|
||||||
@@ -160,7 +160,6 @@ export class SystemController extends Controller {
|
|||||||
if (this.app.modules.get(module).schema().has(path)) {
|
if (this.app.modules.get(module).schema().has(path)) {
|
||||||
return c.json({ success: false, path, error: "Path already exists" }, { status: 400 });
|
return c.json({ success: false, path, error: "Path already exists" }, { status: 400 });
|
||||||
}
|
}
|
||||||
console.log("-- add", module, path, value);
|
|
||||||
|
|
||||||
return await handleConfigUpdateResponse(c, async () => {
|
return await handleConfigUpdateResponse(c, async () => {
|
||||||
await this.app.mutateConfig(module).patch(path, value);
|
await this.app.mutateConfig(module).patch(path, value);
|
||||||
|
|||||||
@@ -35,16 +35,14 @@ export function Panels({ children, ...props }: PanelsProps) {
|
|||||||
)}
|
)}
|
||||||
<Panel unstyled position="bottom-right">
|
<Panel unstyled position="bottom-right">
|
||||||
{props.zoom && (
|
{props.zoom && (
|
||||||
<>
|
<Panel.Wrapper className="px-1.5">
|
||||||
<Panel.Wrapper className="px-1.5">
|
<Panel.IconButton Icon={TbPlus} round onClick={handleZoomIn} />
|
||||||
<Panel.IconButton Icon={TbPlus} round onClick={handleZoomIn} />
|
<Panel.Text className="px-2" mono onClick={handleZoomReset}>
|
||||||
<Panel.Text className="px-2" mono onClick={handleZoomReset}>
|
{percent}%
|
||||||
{percent}%
|
</Panel.Text>
|
||||||
</Panel.Text>
|
<Panel.IconButton Icon={TbMinus} round onClick={handleZoomOut} />
|
||||||
<Panel.IconButton Icon={TbMinus} round onClick={handleZoomOut} />
|
<Panel.IconButton Icon={TbMaximize} round onClick={handleZoomReset} />
|
||||||
<Panel.IconButton Icon={TbMaximize} round onClick={handleZoomReset} />
|
</Panel.Wrapper>
|
||||||
</Panel.Wrapper>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
{props.minimap && (
|
{props.minimap && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export default function BaseInputTemplate<
|
|||||||
...getInputProps<T, S, F>(schema, type, options),
|
...getInputProps<T, S, F>(schema, type, options),
|
||||||
};
|
};
|
||||||
|
|
||||||
let inputValue;
|
let inputValue: any;
|
||||||
if (inputProps.type === "number" || inputProps.type === "integer") {
|
if (inputProps.type === "number" || inputProps.type === "integer") {
|
||||||
inputValue = value || value === 0 ? value : "";
|
inputValue = value || value === 0 ? value : "";
|
||||||
} else {
|
} else {
|
||||||
@@ -68,11 +68,11 @@ export default function BaseInputTemplate<
|
|||||||
[onChange, options],
|
[onChange, options],
|
||||||
);
|
);
|
||||||
const _onBlur = useCallback(
|
const _onBlur = useCallback(
|
||||||
({ target }: FocusEvent<HTMLInputElement>) => onBlur(id, target && target.value),
|
({ target }: FocusEvent<HTMLInputElement>) => onBlur(id, target?.value),
|
||||||
[onBlur, id],
|
[onBlur, id],
|
||||||
);
|
);
|
||||||
const _onFocus = useCallback(
|
const _onFocus = useCallback(
|
||||||
({ target }: FocusEvent<HTMLInputElement>) => onFocus(id, target && target.value),
|
({ target }: FocusEvent<HTMLInputElement>) => onFocus(id, target?.value),
|
||||||
[onFocus, id],
|
[onFocus, id],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Handle, type Node, type NodeProps, Position, useReactFlow } from "@xyflow/react";
|
import { Handle, type Node, type NodeProps, Position } from "@xyflow/react";
|
||||||
|
|
||||||
import type { TAppDataEntity } from "data/data-schema";
|
import type { TAppDataEntity } from "data/data-schema";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
@@ -24,8 +24,6 @@ function NodeComponent(props: NodeProps<Node<TAppDataEntity & { label: string }>
|
|||||||
const { data } = props;
|
const { data } = props;
|
||||||
const fields = props.data.fields ?? {};
|
const fields = props.data.fields ?? {};
|
||||||
const field_count = Object.keys(fields).length;
|
const field_count = Object.keys(fields).length;
|
||||||
//const flow = useReactFlow();
|
|
||||||
//const flow = useTestContext();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaultNode selected={props.selected}>
|
<DefaultNode selected={props.selected}>
|
||||||
@@ -92,15 +90,13 @@ const TableRow = ({
|
|||||||
<div className="flex opacity-60">{field.type}</div>
|
<div className="flex opacity-60">{field.type}</div>
|
||||||
|
|
||||||
{handles && (
|
{handles && (
|
||||||
<>
|
<Handle
|
||||||
<Handle
|
type="target"
|
||||||
type="target"
|
title={handleId}
|
||||||
title={handleId}
|
id={handleId}
|
||||||
id={handleId}
|
position={Position.Right}
|
||||||
position={Position.Right}
|
style={{ top: handleTop, right: -5, ...handleStyle }}
|
||||||
style={{ top: handleTop, right: -5, ...handleStyle }}
|
/>
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -73,18 +73,16 @@ export default function AppShellAccordionsTest() {
|
|||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full">
|
||||||
<AppShell.SectionHeader
|
<AppShell.SectionHeader
|
||||||
right={
|
right={
|
||||||
<>
|
<Dropdown
|
||||||
<Dropdown
|
items={[
|
||||||
items={[
|
{
|
||||||
{
|
label: "Settings",
|
||||||
label: "Settings",
|
},
|
||||||
},
|
]}
|
||||||
]}
|
position="bottom-end"
|
||||||
position="bottom-end"
|
>
|
||||||
>
|
<IconButton Icon={TbDots} />
|
||||||
<IconButton Icon={TbDots} />
|
</Dropdown>
|
||||||
</Dropdown>
|
|
||||||
</>
|
|
||||||
}
|
}
|
||||||
className="pl-3"
|
className="pl-3"
|
||||||
>
|
>
|
||||||
|
|||||||
+2
-1
@@ -69,7 +69,8 @@
|
|||||||
"noExplicitAny": "off",
|
"noExplicitAny": "off",
|
||||||
"noArrayIndexKey": "off",
|
"noArrayIndexKey": "off",
|
||||||
"noImplicitAnyLet": "warn",
|
"noImplicitAnyLet": "warn",
|
||||||
"noConfusingVoidType": "off"
|
"noConfusingVoidType": "off",
|
||||||
|
"noConsoleLog": "warn"
|
||||||
},
|
},
|
||||||
"security": {
|
"security": {
|
||||||
"noDangerouslySetInnerHtml": "off"
|
"noDangerouslySetInnerHtml": "off"
|
||||||
|
|||||||
Reference in New Issue
Block a user