mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
fix cli for cloudflare proxy and plugins
- proper cli exists required for cloudflare proxy to dispose - updated cloudflare proxy to allow proxy options (e.g. remote) - updated config command to include proper required structure for the export on code mode
This commit is contained in:
76
app/__test__/app/plugins/sync-config.test.ts
Normal file
76
app/__test__/app/plugins/sync-config.test.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { describe, it, expect, mock } from "bun:test";
|
||||
import { createApp } from "core/test/utils";
|
||||
import { syncConfig } from "plugins/dev/sync-config.plugin";
|
||||
|
||||
describe("syncConfig", () => {
|
||||
it("should only sync if enabled", async () => {
|
||||
const called = mock(() => null);
|
||||
const app = createApp();
|
||||
await app.build();
|
||||
|
||||
await syncConfig({
|
||||
write: () => {
|
||||
called();
|
||||
},
|
||||
enabled: false,
|
||||
includeFirstBoot: false,
|
||||
})(app).onBuilt?.();
|
||||
expect(called).not.toHaveBeenCalled();
|
||||
|
||||
await syncConfig({
|
||||
write: () => {
|
||||
called();
|
||||
},
|
||||
enabled: false,
|
||||
includeFirstBoot: true,
|
||||
})(app).onBuilt?.();
|
||||
expect(called).not.toHaveBeenCalled();
|
||||
|
||||
await syncConfig({
|
||||
write: () => {
|
||||
called();
|
||||
},
|
||||
enabled: true,
|
||||
includeFirstBoot: true,
|
||||
})(app).onBuilt?.();
|
||||
expect(called).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should respect secrets", async () => {
|
||||
const called = mock(() => null);
|
||||
const app = createApp({
|
||||
config: {
|
||||
auth: {
|
||||
enabled: true,
|
||||
jwt: {
|
||||
secret: "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
await app.build();
|
||||
|
||||
await syncConfig({
|
||||
write: async (config) => {
|
||||
called();
|
||||
expect(config.auth.jwt.secret).toBe("test");
|
||||
},
|
||||
enabled: true,
|
||||
includeSecrets: true,
|
||||
includeFirstBoot: true,
|
||||
})(app).onBuilt?.();
|
||||
|
||||
await syncConfig({
|
||||
write: async (config) => {
|
||||
called();
|
||||
// it's an important test, because the `jwt` part is omitted if secrets=false in general app.toJSON()
|
||||
// but it's required to get the app running
|
||||
expect(config.auth.jwt.secret).toBe("");
|
||||
},
|
||||
enabled: true,
|
||||
includeSecrets: false,
|
||||
includeFirstBoot: true,
|
||||
})(app).onBuilt?.();
|
||||
expect(called).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
@@ -130,7 +130,8 @@
|
||||
"vite-plugin-circular-dependency": "^0.5.0",
|
||||
"vite-tsconfig-paths": "^5.1.4",
|
||||
"vitest": "^3.0.9",
|
||||
"wouter": "^3.6.0"
|
||||
"wouter": "^3.6.0",
|
||||
"wrangler": "^4.37.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@hono/node-server": "^1.14.3"
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
type CloudflareBkndConfig,
|
||||
type CloudflareEnv,
|
||||
} from "bknd/adapter/cloudflare";
|
||||
import type { PlatformProxy } from "wrangler";
|
||||
import type { GetPlatformProxyOptions, PlatformProxy } from "wrangler";
|
||||
import process from "node:process";
|
||||
|
||||
export type WithPlatformProxyOptions = {
|
||||
@@ -14,10 +14,11 @@ export type WithPlatformProxyOptions = {
|
||||
* You can override/force this by setting this option.
|
||||
*/
|
||||
useProxy?: boolean;
|
||||
proxyOptions?: GetPlatformProxyOptions;
|
||||
};
|
||||
|
||||
export function withPlatformProxy<Env extends CloudflareEnv>(
|
||||
config?: CloudflareBkndConfig<Env>,
|
||||
config: CloudflareBkndConfig<Env> = {},
|
||||
opts?: WithPlatformProxyOptions,
|
||||
) {
|
||||
const use_proxy =
|
||||
@@ -28,8 +29,10 @@ export function withPlatformProxy<Env extends CloudflareEnv>(
|
||||
if (use_proxy) {
|
||||
if (!proxy) {
|
||||
const getPlatformProxy = await import("wrangler").then((mod) => mod.getPlatformProxy);
|
||||
proxy = await getPlatformProxy();
|
||||
setTimeout(proxy?.dispose, 1000);
|
||||
proxy = await getPlatformProxy(opts?.proxyOptions);
|
||||
process.on("exit", () => {
|
||||
proxy?.dispose();
|
||||
});
|
||||
}
|
||||
return proxy.env as unknown as Env;
|
||||
}
|
||||
|
||||
@@ -39,5 +39,7 @@ export const config: CliCommand = (program) => {
|
||||
} else {
|
||||
console.info(JSON.parse(config));
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -34,4 +34,5 @@ async function action(options: { out?: string; clean?: boolean }) {
|
||||
|
||||
// biome-ignore lint/suspicious/noConsoleLog:
|
||||
console.log(c.green(`Assets copied to: ${c.bold(out)}`));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,9 @@ const subjects = {
|
||||
async function action(subject: string) {
|
||||
if (subject in subjects) {
|
||||
await subjects[subject]();
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.error("Invalid subject: ", subject);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ export const schema: CliCommand = (program) => {
|
||||
.option("--pretty", "pretty print")
|
||||
.action((options) => {
|
||||
const schema = getDefaultSchema();
|
||||
// biome-ignore lint/suspicious/noConsoleLog:
|
||||
console.log(options.pretty ? JSON.stringify(schema, null, 2) : JSON.stringify(schema));
|
||||
console.info(options.pretty ? JSON.stringify(schema, null, 2) : JSON.stringify(schema));
|
||||
process.exit(0);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -53,6 +53,7 @@ export const secrets: CliCommand = (program) => {
|
||||
}
|
||||
}
|
||||
console.info("");
|
||||
process.exit(0);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -7,13 +7,14 @@ import { withConfigOptions } from "cli/utils/options";
|
||||
export const sync: CliCommand = (program) => {
|
||||
withConfigOptions(program.command("sync"))
|
||||
.description("sync database")
|
||||
.option("--dump", "dump operations to console instead of executing them")
|
||||
.option("--force", "perform database syncing operations")
|
||||
.option("--drop", "include destructive DDL operations")
|
||||
.option("--out <file>", "output file")
|
||||
.option("--sql", "use sql output")
|
||||
.action(async (options) => {
|
||||
const app = await makeAppFromEnv(options);
|
||||
const schema = app.em.schema();
|
||||
console.info(c.dim("Checking database state..."));
|
||||
const stmts = await schema.sync({ drop: options.drop });
|
||||
|
||||
console.info("");
|
||||
@@ -24,22 +25,27 @@ export const sync: CliCommand = (program) => {
|
||||
// @todo: currently assuming parameters aren't used
|
||||
const sql = stmts.map((d) => d.sql).join(";\n") + ";";
|
||||
|
||||
if (options.dump) {
|
||||
if (options.force) {
|
||||
console.info(c.dim("Executing:") + "\n" + c.cyan(sql));
|
||||
await schema.sync({ force: true, drop: options.drop });
|
||||
|
||||
console.info(`\n${c.gray(`Executed ${c.cyan(stmts.length)} statement(s)`)}`);
|
||||
console.info(`${c.green("Database synced")}`);
|
||||
} else {
|
||||
if (options.out) {
|
||||
const output = options.sql ? sql : JSON.stringify(stmts, null, 2);
|
||||
await writeFile(options.out, output);
|
||||
console.info(`SQL written to ${c.cyan(options.out)}`);
|
||||
} else {
|
||||
console.info(options.sql ? c.cyan(sql) : stmts);
|
||||
console.info(c.dim("DDL to execute:") + "\n" + c.cyan(sql));
|
||||
|
||||
console.info(
|
||||
c.yellow(
|
||||
"\nNo statements have been executed. Use --force to perform database syncing operations",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
await schema.sync({ force: true, drop: options.drop });
|
||||
console.info(c.cyan(sql));
|
||||
|
||||
console.info(`${c.gray(`Executed ${c.cyan(stmts.length)} statement(s)`)}`);
|
||||
console.info(`${c.green("Database synced")}`);
|
||||
process.exit(0);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -78,9 +78,11 @@ async function create(app: App, options: any) {
|
||||
password: await strategy.hash(password as string),
|
||||
});
|
||||
$log.success(`Created user: ${c.cyan(created.email)}`);
|
||||
process.exit(0);
|
||||
} catch (e) {
|
||||
$log.error("Error creating user");
|
||||
$console.error(e);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,8 +123,10 @@ async function update(app: App, options: any) {
|
||||
|
||||
if (await app.module.auth.changePassword(user.id, password)) {
|
||||
$log.success(`Updated user: ${c.cyan(user.email)}`);
|
||||
process.exit(0);
|
||||
} else {
|
||||
$log.error("Error updating user");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,4 +162,5 @@ async function token(app: App, options: any) {
|
||||
console.log(
|
||||
`\n${c.dim("Token:")}\n${c.yellow(await app.module.auth.authenticator.jwt(user))}\n`,
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { App, type AppConfig, type AppPlugin } from "bknd";
|
||||
import { App, type AppConfig, type AppPlugin, type MaybePromise, type ModuleConfigs } from "bknd";
|
||||
|
||||
export type SyncConfigOptions = {
|
||||
enabled?: boolean;
|
||||
includeSecrets?: boolean;
|
||||
includeFirstBoot?: boolean;
|
||||
write: (config: AppConfig) => Promise<void>;
|
||||
write: (config: ModuleConfigs) => MaybePromise<void>;
|
||||
};
|
||||
|
||||
export function syncConfig({
|
||||
@@ -14,6 +14,14 @@ export function syncConfig({
|
||||
write,
|
||||
}: SyncConfigOptions): AppPlugin {
|
||||
let firstBoot = true;
|
||||
|
||||
const getConfigs = (app: App, secrets = false) => {
|
||||
if (secrets) {
|
||||
return app.toJSON(true);
|
||||
}
|
||||
return app.modules.extractSecrets().configs;
|
||||
};
|
||||
|
||||
return (app: App) => ({
|
||||
name: "bknd-sync-config",
|
||||
onBuilt: async () => {
|
||||
@@ -21,7 +29,7 @@ export function syncConfig({
|
||||
app.emgr.onEvent(
|
||||
App.Events.AppConfigUpdatedEvent,
|
||||
async () => {
|
||||
await write?.(app.toJSON(includeSecrets));
|
||||
await write?.(getConfigs(app, includeSecrets));
|
||||
},
|
||||
{
|
||||
id: "sync-config",
|
||||
@@ -30,7 +38,7 @@ export function syncConfig({
|
||||
|
||||
if (firstBoot && includeFirstBoot) {
|
||||
firstBoot = false;
|
||||
await write?.(app.toJSON(includeSecrets));
|
||||
await write?.(getConfigs(app, includeSecrets));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user