Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0454f82d6 | ||
|
|
dfa37b5244 | ||
|
|
8263db505e | ||
|
|
37bdd6f203 | ||
|
|
0bfcb5ad71 | ||
|
|
05e0086fcd | ||
|
|
282c9f6054 | ||
|
|
b294ee68ac | ||
|
|
e8a256af2a | ||
|
|
4709fec45c | ||
|
|
da80e91074 | ||
|
|
3ad9fd01e1 | ||
|
|
89d7e4ea2b | ||
|
|
6e3b7515d5 | ||
|
|
62d3a9c4f4 | ||
|
|
919d9f15d1 | ||
|
|
e68d29760a | ||
|
|
eba2f8a535 | ||
|
|
6cfdb77ba0 | ||
|
|
8c596781ff | ||
|
|
b2315ed012 | ||
|
|
9e5c77db79 | ||
|
|
5892b898bf | ||
|
|
fc83a593a0 | ||
|
|
8d37f9df3f | ||
|
|
43cbdb3010 | ||
|
|
b3c9f258de | ||
|
|
5c3d3d763e | ||
|
|
407d103a5f | ||
|
|
2fd8b9f9a0 | ||
|
|
e81636ea95 | ||
|
|
37c36e5d07 |
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"bknd": {
|
||||
"userbase": {
|
||||
"url": "http://localhost:28623/api/system/mcp"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ jobs:
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_DB: bknd
|
||||
ports:
|
||||
- 5430:5432
|
||||
POSTGRES_DB: userbase
|
||||
# ports:
|
||||
# - 5430:5432
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
@@ -25,15 +25,15 @@ jobs:
|
||||
--health-retries 5
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "22.x"
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: "1.3.3"
|
||||
|
||||
|
||||
Vendored
+8
-5
@@ -1,19 +1,22 @@
|
||||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"js/ts.tsdk.path": "node_modules/typescript/lib",
|
||||
"biome.enabled": true,
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.codeActionsOnSave": {
|
||||
//"source.organizeImports.biome": "explicit",
|
||||
"source.fixAll.biome": "explicit"
|
||||
},
|
||||
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||
"typescript.preferences.autoImportFileExcludePatterns": [
|
||||
"js/ts.preferences.importModuleSpecifier": "non-relative",
|
||||
"js/ts.preferences.autoImportFileExcludePatterns": [
|
||||
"**/dist/**",
|
||||
"**/node_modules/**/dist/**",
|
||||
"**/node_modules/**/!(src|lib|esm)/**" // optional, stricter
|
||||
],
|
||||
"typescript.preferences.includePackageJsonAutoImports": "on",
|
||||
"typescript.tsserver.watchOptions": {
|
||||
"js/ts.preferences.includePackageJsonAutoImports": "on",
|
||||
"js/ts.tsserver.watchOptions": {
|
||||
"excludeDirectories": ["**/dist", "**/node_modules/**/dist"]
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
}
|
||||
}
|
||||
|
||||
+24
-24
@@ -1,6 +1,6 @@
|
||||
# Contributing to bknd
|
||||
# Contributing to userbase
|
||||
|
||||
Thank you for your interest in contributing to bknd. This guide will help you get started, understand the codebase, and submit contributions that align with the project's direction.
|
||||
Thank you for your interest in contributing to userbase. This guide will help you get started, understand the codebase, and submit contributions that align with the project's direction.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -23,7 +23,7 @@ Thank you for your interest in contributing to bknd. This guide will help you ge
|
||||
|
||||
**Open a GitHub Issue before writing code.** This is the preferred way to propose any change. It lets maintainers and the community align on the approach before time is spent on implementation. If you have discussed a contribution in the [Discord server](https://discord.com/invite/952SFk8Tb8) instead, include a link to the relevant Discord thread in your pull request. Pull requests submitted without a corresponding issue or Discord discussion may be closed.
|
||||
|
||||
**Unsolicited architectural changes will be closed.** The internal architecture of bknd is intentional. Refactors, restructuring, or changes to core patterns must be discussed and approved before any code is written.
|
||||
**Unsolicited architectural changes will be closed.** The internal architecture of userbase is intentional. Refactors, restructuring, or changes to core patterns must be discussed and approved before any code is written.
|
||||
|
||||
Contributions that are generally welcome (after opening an issue):
|
||||
|
||||
@@ -33,12 +33,12 @@ Contributions that are generally welcome (after opening an issue):
|
||||
- New examples
|
||||
- Test coverage improvements
|
||||
|
||||
**A note on versioning**: bknd is pre-1.0 and under active development. Full backward compatibility is not guaranteed before v1.0.0. Contributors should be aware that APIs and internal interfaces may change between releases.
|
||||
**A note on versioning**: userbase is pre-1.0 and under active development. Full backward compatibility is not guaranteed before v1.0.0. Contributors should be aware that APIs and internal interfaces may change between releases.
|
||||
|
||||
## Important Resources
|
||||
|
||||
- **Documentation**: https://docs.bknd.io
|
||||
- **Issue Tracker**: https://github.com/bknd-io/bknd/issues
|
||||
- **Documentation**: https://docs.userbase.io
|
||||
- **Issue Tracker**: https://github.com/userbase-io/userbase/issues
|
||||
- **Discord**: https://discord.com/invite/952SFk8Tb8
|
||||
- **FAQ / Search**: https://www.answeroverflow.com/c/1308395750564302952
|
||||
|
||||
@@ -86,8 +86,8 @@ Contributions that are generally welcome (after opening an issue):
|
||||
This is a Bun monorepo using workspaces. The vast majority of the code lives in `app/`.
|
||||
|
||||
```
|
||||
bknd/
|
||||
app/ # Main "bknd" npm package (this is where most work happens)
|
||||
userbase/
|
||||
app/ # Main "userbase" npm package (this is where most work happens)
|
||||
src/
|
||||
adapter/ # Runtime/framework adapters (node, bun, cloudflare, nextjs, astro, etc.)
|
||||
auth/ # Authentication module (strategies, sessions, user pool)
|
||||
@@ -100,21 +100,21 @@ bknd/
|
||||
modules/ # Module system, MCP server, permissions framework
|
||||
plugins/ # Built-in plugins (auth, data, cloudflare, dev)
|
||||
ui/ # All frontend code
|
||||
client/ # TypeScript SDK and React hooks (exported as bknd/client)
|
||||
elements/ # React components for auth/media (exported as bknd/elements)
|
||||
(everything else) # Admin UI (exported as bknd/ui)
|
||||
client/ # TypeScript SDK and React hooks (exported as userbase/client)
|
||||
elements/ # React components for auth/media (exported as userbase/elements)
|
||||
(everything else) # Admin UI (exported as userbase/ui)
|
||||
App.ts # Central application orchestrator
|
||||
index.ts # Main package exports
|
||||
__test__/ # Unit tests (mirrors src/ structure)
|
||||
e2e/ # End-to-end tests (Playwright)
|
||||
build.ts # Build script (tsdown/rolldown)
|
||||
build.ts # Build script (tsup/esbuild)
|
||||
build.cli.ts # CLI build script
|
||||
packages/ # Small satellite packages
|
||||
cli/ # Standalone CLI package (bknd-cli)
|
||||
cli/ # Standalone CLI package (userbase-cli)
|
||||
plasmic/ # Plasmic integration
|
||||
postgres/ # Postgres helper
|
||||
sqlocal/ # SQLocal helper
|
||||
docs/ # Documentation site (Next.js + Fumadocs, deployed to docs.bknd.io)
|
||||
docs/ # Documentation site (Next.js + Fumadocs, deployed to docs.userbase.io)
|
||||
examples/ # Example projects across runtimes and frameworks
|
||||
docker/ # Docker configuration
|
||||
```
|
||||
@@ -127,7 +127,7 @@ The project uses TypeScript path aliases defined in `app/tsconfig.json`. Imports
|
||||
|
||||
### Module System
|
||||
|
||||
bknd is built around four core modules, each with its own schema, API routes, and permissions:
|
||||
userbase is built around four core modules, each with its own schema, API routes, and permissions:
|
||||
|
||||
- **Data** -- entity definitions, field types, relations, queries (backed by Kysely)
|
||||
- **Auth** -- authentication strategies, sessions, user management
|
||||
@@ -138,7 +138,7 @@ These modules are managed by the `ModuleManager` (in `app/src/modules/`), which
|
||||
|
||||
### Adapter Pattern
|
||||
|
||||
Adapters in `app/src/adapter/` allow bknd to run on different runtimes and frameworks. Each adapter provides the glue between bknd's Hono-based server and a specific environment (Node, Bun, Cloudflare Workers, Next.js, Astro, etc.).
|
||||
Adapters in `app/src/adapter/` allow userbase to run on different runtimes and frameworks. Each adapter provides the glue between userbase's Hono-based server and a specific environment (Node, Bun, Cloudflare Workers, Next.js, Astro, etc.).
|
||||
|
||||
### Plugin System
|
||||
|
||||
@@ -146,7 +146,7 @@ Plugins (in `app/src/plugins/`) hook into the app lifecycle via callbacks like `
|
||||
|
||||
### Build System
|
||||
|
||||
The build is handled by a custom `app/build.ts` script using tsdown (rolldown under the hood). It builds four targets in parallel:
|
||||
The build is handled by a custom `app/build.ts` script using tsup (esbuild under the hood). It builds four targets in parallel:
|
||||
|
||||
- **API** -- the core backend
|
||||
- **UI** -- the admin interface
|
||||
@@ -242,26 +242,26 @@ Open a GitHub Issue with:
|
||||
- A clear title describing the problem.
|
||||
- Steps to reproduce the bug.
|
||||
- Expected behavior vs. actual behavior.
|
||||
- Your environment (runtime, database, adapter, bknd version).
|
||||
- Your environment (runtime, database, adapter, userbase version).
|
||||
- Any relevant error messages or logs.
|
||||
|
||||
## Getting Help
|
||||
|
||||
- **Discord**: https://discord.com/invite/952SFk8Tb8
|
||||
- **FAQ / Search**: https://www.answeroverflow.com/c/1308395750564302952
|
||||
- **GitHub Issues**: https://github.com/bknd-io/bknd/issues
|
||||
- **GitHub Issues**: https://github.com/userbase-io/userbase/issues
|
||||
|
||||
## Contributors
|
||||
|
||||
Thank you to everyone who has contributed to bknd.
|
||||
Thank you to everyone who has contributed to userbase.
|
||||
|
||||
<a href="https://github.com/bknd-io/bknd/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=bknd-io/bknd" />
|
||||
<a href="https://github.com/userbase-io/userbase/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=userbase-io/userbase" />
|
||||
</a>
|
||||
|
||||
Made with [contrib.rocks](https://contrib.rocks).
|
||||
|
||||
## Maintainers
|
||||
|
||||
- **Dennis** ([@dswbx](https://github.com/dswbx)) -- Creator and maintainer of bknd
|
||||
- **Cameron Pak** ([@cameronapak](https://github.com/cameronapak)) -- Maintainer of bknd docs
|
||||
- **Dennis** ([@dswbx](https://github.com/dswbx)) -- Creator and maintainer of userbase
|
||||
- **Cameron Pak** ([@cameronapak](https://github.com/cameronapak)) -- Maintainer of userbase docs
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
This is an independently maintained fork of [bknd](https://github.com/bknd-io/bknd) which is a drop in replacement for the original package. It is intended to be used in projects that require a more up-to-date version of bknd, or that need to use features that are not available in the original package.
|
||||
|
||||
[](https://npmjs.org/package/bknd)
|
||||
|
||||

|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
playwright-report
|
||||
test-results
|
||||
bknd.config.*
|
||||
userbase.config.*
|
||||
__test__/helper.d.ts
|
||||
.env.local
|
||||
@@ -4,73 +4,72 @@ import { disableConsoleLog, enableConsoleLog, omitKeys } from "core/utils";
|
||||
import { adapterTestSuite } from "adapter/adapter-test-suite";
|
||||
import { bunTestRunner } from "adapter/bun/test";
|
||||
|
||||
const stripConnection = <T extends Record<string, any>>(cfg: T) =>
|
||||
omitKeys(cfg, ["connection"]);
|
||||
const stripConnection = <T extends Record<string, any>>(cfg: T) => omitKeys(cfg, ["connection"]);
|
||||
|
||||
beforeAll(disableConsoleLog);
|
||||
afterAll(enableConsoleLog);
|
||||
|
||||
describe("adapter", () => {
|
||||
describe("makeConfig", () => {
|
||||
it("returns empty config for empty inputs", async () => {
|
||||
const cases: Array<Parameters<typeof adapter.makeConfig>> = [
|
||||
[{}],
|
||||
[{}, { env: { TEST: "test" } }],
|
||||
];
|
||||
describe("makeConfig", () => {
|
||||
it("returns empty config for empty inputs", async () => {
|
||||
const cases: Array<Parameters<typeof adapter.makeConfig>> = [
|
||||
[{}],
|
||||
[{}, { env: { TEST: "test" } }],
|
||||
];
|
||||
|
||||
for (const args of cases) {
|
||||
const cfg = await adapter.makeConfig(...(args as any));
|
||||
expect(stripConnection(cfg)).toEqual({});
|
||||
}
|
||||
});
|
||||
|
||||
it("merges app output into config", async () => {
|
||||
const cfg = await adapter.makeConfig(
|
||||
{ app: (a) => ({ config: { server: { cors: { origin: a.env.TEST } } } }) },
|
||||
{ env: { TEST: "test" } },
|
||||
);
|
||||
|
||||
expect(stripConnection(cfg)).toEqual({
|
||||
config: { server: { cors: { origin: "test" } } },
|
||||
for (const args of cases) {
|
||||
const cfg = await adapter.makeConfig(...(args as any));
|
||||
expect(stripConnection(cfg)).toEqual({});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("allows all properties in app() result", async () => {
|
||||
const called = mock(() => null);
|
||||
it("merges app output into config", async () => {
|
||||
const cfg = await adapter.makeConfig(
|
||||
{ app: (a) => ({ config: { server: { cors: { origin: a.env.TEST } } } }) },
|
||||
{ env: { TEST: "test" } },
|
||||
);
|
||||
|
||||
const cfg = await adapter.makeConfig(
|
||||
{
|
||||
app: (env) => ({
|
||||
connection: { url: "test" },
|
||||
expect(stripConnection(cfg)).toEqual({
|
||||
config: { server: { cors: { origin: "test" } } },
|
||||
options: { mode: "db" as const },
|
||||
onBuilt: () => {
|
||||
called();
|
||||
expect(env).toEqual({ foo: "bar" });
|
||||
});
|
||||
});
|
||||
|
||||
it("allows all properties in app() result", async () => {
|
||||
const called = mock(() => null);
|
||||
|
||||
const cfg = await adapter.makeConfig(
|
||||
{
|
||||
app: (env) => ({
|
||||
connection: { url: "test" },
|
||||
config: { server: { cors: { origin: "test" } } },
|
||||
options: { mode: "db" as const },
|
||||
onBuilt: () => {
|
||||
called();
|
||||
expect(env).toEqual({ foo: "bar" });
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
},
|
||||
{ foo: "bar" },
|
||||
);
|
||||
{ foo: "bar" },
|
||||
);
|
||||
|
||||
expect(cfg.connection).toEqual({ url: "test" });
|
||||
expect(cfg.config).toEqual({ server: { cors: { origin: "test" } } });
|
||||
expect(cfg.options).toEqual({ mode: "db" });
|
||||
expect(cfg.connection).toEqual({ url: "test" });
|
||||
expect(cfg.config).toEqual({ server: { cors: { origin: "test" } } });
|
||||
expect(cfg.options).toEqual({ mode: "db" });
|
||||
|
||||
await cfg.onBuilt?.({} as any);
|
||||
expect(called).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
await cfg.onBuilt?.({} as any);
|
||||
expect(called).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("adapter test suites", () => {
|
||||
adapterTestSuite(bunTestRunner, {
|
||||
makeApp: adapter.createFrameworkApp,
|
||||
label: "framework app",
|
||||
});
|
||||
describe("adapter test suites", () => {
|
||||
adapterTestSuite(bunTestRunner, {
|
||||
makeApp: adapter.createFrameworkApp,
|
||||
label: "framework app",
|
||||
});
|
||||
|
||||
adapterTestSuite(bunTestRunner, {
|
||||
makeApp: adapter.createRuntimeApp,
|
||||
label: "runtime app",
|
||||
});
|
||||
});
|
||||
adapterTestSuite(bunTestRunner, {
|
||||
makeApp: adapter.createRuntimeApp,
|
||||
label: "runtime app",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,7 +73,13 @@ describe("Api", async () => {
|
||||
|
||||
it("should extract tokens case insensitive", async () => {
|
||||
const token = await sign({ sub: "test" }, "1234");
|
||||
expect(new Api({ headers: new Headers({ Authorization: `Bearer ${token}` }) }).getAuthState().token).toBe(token);
|
||||
expect(new Api({ headers: new Headers({ Authorization: `bearer ${token}` }) }).getAuthState().token).toBe(token);
|
||||
})
|
||||
expect(
|
||||
new Api({ headers: new Headers({ Authorization: `Bearer ${token}` }) }).getAuthState()
|
||||
.token,
|
||||
).toBe(token);
|
||||
expect(
|
||||
new Api({ headers: new Headers({ Authorization: `bearer ${token}` }) }).getAuthState()
|
||||
.token,
|
||||
).toBe(token);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, mock, test, beforeAll, afterAll } from "bun:test";
|
||||
import { createApp as internalCreateApp, type CreateAppConfig } from "bknd";
|
||||
import { createApp as internalCreateApp, type CreateAppConfig } from "userbase";
|
||||
import { getDummyConnection } from "../../__test__/helper";
|
||||
import { ModuleManager } from "modules/ModuleManager";
|
||||
import { em, entity, text } from "data/prototype";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, test, expect, beforeEach, beforeAll, afterAll } from "bun:test";
|
||||
import { type App, createApp, createMcpToolCaller } from "core/test/utils";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
||||
import type { McpServer } from "bknd/utils";
|
||||
import type { McpServer } from "userbase/utils";
|
||||
|
||||
beforeAll(disableConsoleLog);
|
||||
afterAll(enableConsoleLog);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { describe, test, expect, beforeEach, beforeAll, afterAll } from "bun:test";
|
||||
import { type App, createApp, createMcpToolCaller } from "core/test/utils";
|
||||
import { getSystemMcp } from "modules/mcp/system-mcp";
|
||||
import { pickKeys, type McpServer } from "bknd/utils";
|
||||
import { entity, text } from "bknd";
|
||||
import { pickKeys, type McpServer } from "userbase/utils";
|
||||
import { entity, text } from "userbase";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
||||
|
||||
beforeAll(disableConsoleLog);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { getSystemMcp } from "modules/mcp/system-mcp";
|
||||
import { registries } from "index";
|
||||
import { StorageLocalAdapter } from "adapter/node/storage/StorageLocalAdapter";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
||||
import type { McpServer } from "bknd/utils";
|
||||
import type { McpServer } from "userbase/utils";
|
||||
|
||||
beforeAll(disableConsoleLog);
|
||||
afterAll(enableConsoleLog);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, test, expect, beforeAll, afterAll } from "bun:test";
|
||||
import { type App, createApp, createMcpToolCaller } from "core/test/utils";
|
||||
import type { McpServer } from "bknd/utils";
|
||||
import type { McpServer } from "userbase/utils";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils/test";
|
||||
|
||||
beforeAll(() => disableConsoleLog());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AppEvents } from "App";
|
||||
import { describe, test, expect, beforeAll, mock, afterAll } from "bun:test";
|
||||
import { type App, createApp, createMcpToolCaller } from "core/test/utils";
|
||||
import type { McpServer } from "bknd/utils";
|
||||
import type { McpServer } from "userbase/utils";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils/test";
|
||||
|
||||
beforeAll(disableConsoleLog);
|
||||
|
||||
@@ -51,14 +51,18 @@ describe("Authenticator", async () => {
|
||||
});
|
||||
const token = await auth.jwt({ sub: "test" });
|
||||
|
||||
const res = await auth.resolveAuthFromRequest(new Headers({
|
||||
Authorization: `Bearer ${token}`,
|
||||
}));
|
||||
expect((res as any).sub).toBe("test")
|
||||
const res = await auth.resolveAuthFromRequest(
|
||||
new Headers({
|
||||
Authorization: `Bearer ${token}`,
|
||||
}),
|
||||
);
|
||||
expect((res as any).sub).toBe("test");
|
||||
|
||||
const res2 = await auth.resolveAuthFromRequest(new Headers({
|
||||
Authorization: `bearer ${token}`,
|
||||
}));
|
||||
expect((res2 as any).sub).toBe("test")
|
||||
})
|
||||
const res2 = await auth.resolveAuthFromRequest(
|
||||
new Headers({
|
||||
Authorization: `bearer ${token}`,
|
||||
}),
|
||||
);
|
||||
expect((res2 as any).sub).toBe("test");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, expect, test, beforeAll, afterAll } from "bun:test";
|
||||
import { Guard, type GuardConfig } from "auth/authorize/Guard";
|
||||
import { Permission } from "auth/authorize/Permission";
|
||||
import { Role, type RoleSchema } from "auth/authorize/Role";
|
||||
import { objectTransform, s } from "bknd/utils";
|
||||
import { objectTransform, s } from "userbase/utils";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils/test";
|
||||
|
||||
beforeAll(disableConsoleLog);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { createApp } from "core/test/utils";
|
||||
import type { CreateAppConfig } from "App";
|
||||
import * as proto from "data/prototype";
|
||||
import { mergeObject } from "core/utils/objects";
|
||||
import type { App, DB } from "bknd";
|
||||
import type { App, DB } from "userbase";
|
||||
import type { CreateUserPayload } from "auth/AppAuth";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils/test";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect } from "bun:test";
|
||||
import { s } from "bknd/utils";
|
||||
import { s } from "userbase/utils";
|
||||
import { Permission } from "auth/authorize/Permission";
|
||||
import { Policy } from "auth/authorize/Policy";
|
||||
import { Hono } from "hono";
|
||||
@@ -7,7 +7,7 @@ import { getPermissionRoutes, permission } from "auth/middlewares/permission.mid
|
||||
import { auth } from "auth/middlewares/auth.middleware";
|
||||
import { Guard, mergeFilters, type GuardConfig } from "auth/authorize/Guard";
|
||||
import { Role, RolePermission } from "auth/authorize/Role";
|
||||
import { Exception } from "bknd";
|
||||
import { Exception } from "userbase";
|
||||
import { convert } from "core/object/query/object-query";
|
||||
|
||||
describe("Permission", () => {
|
||||
@@ -421,7 +421,7 @@ describe("permission middleware", () => {
|
||||
);
|
||||
|
||||
const res = await hono.request("/test");
|
||||
// expecting 500 because bknd should have handled it correctly
|
||||
// expecting 500 because userbase should have handled it correctly
|
||||
expect(res.status).toBe(500);
|
||||
});
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ describe("Polymorphic", async () => {
|
||||
target: "media",
|
||||
config: {
|
||||
mappedBy: "image",
|
||||
on_delete: "set null",
|
||||
},
|
||||
});
|
||||
// media should not see categories
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import { describe, beforeAll, afterAll, test } from "bun:test";
|
||||
import type { PostgresConnection } from "data/connection/postgres/PostgresConnection";
|
||||
import { pg, postgresJs } from "bknd";
|
||||
import { pg, postgresJs } from "userbase";
|
||||
import { Pool } from "pg";
|
||||
import postgres from "postgres";
|
||||
import { disableConsoleLog, enableConsoleLog, $waitUntil } from "bknd/utils";
|
||||
import { disableConsoleLog, enableConsoleLog, $waitUntil } from "userbase/utils";
|
||||
import { $ } from "bun";
|
||||
import { connectionTestSuite } from "data/connection/connection-test-suite";
|
||||
import { bunTestRunner } from "adapter/bun/test";
|
||||
|
||||
const isCI = !!(process.env.GITEA_ACTIONS || process.env.GITHUB_ACTIONS);
|
||||
|
||||
const credentials = {
|
||||
host: "localhost",
|
||||
port: 5430,
|
||||
host: isCI ? "postgres" : "localhost",
|
||||
port: 5432,
|
||||
user: "postgres",
|
||||
password: "postgres",
|
||||
database: "bknd",
|
||||
database: "userbase",
|
||||
};
|
||||
|
||||
async function cleanDatabase(connection: InstanceType<typeof PostgresConnection>) {
|
||||
@@ -39,8 +41,13 @@ async function isPostgresRunning() {
|
||||
|
||||
describe("postgres", () => {
|
||||
beforeAll(async () => {
|
||||
if (process.env.GITEA_ACTIONS || process.env.GITHUB_ACTIONS) {
|
||||
console.log("Running in CI: Skipping manual docker run");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(await isPostgresRunning())) {
|
||||
await $`docker run --rm --name bknd-test-postgres -d -e POSTGRES_PASSWORD=${credentials.password} -e POSTGRES_USER=${credentials.user} -e POSTGRES_DB=${credentials.database} -p ${credentials.port}:5432 postgres:17`;
|
||||
await $`docker run --rm --name userbase-test-postgres -d -e POSTGRES_PASSWORD=${credentials.password} -e POSTGRES_USER=${credentials.user} -e POSTGRES_DB=${credentials.database} -p ${credentials.port}:5432 postgres:17`;
|
||||
await $waitUntil("Postgres is running", isPostgresRunning, 500, 20);
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
}
|
||||
@@ -50,7 +57,7 @@ describe("postgres", () => {
|
||||
afterAll(async () => {
|
||||
if (await isPostgresRunning()) {
|
||||
try {
|
||||
await $`docker stop bknd-test-postgres`;
|
||||
await $`docker stop userbase-test-postgres`;
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { describe, it, expect } from "bun:test";
|
||||
import * as sDirect from "jsonv-ts";
|
||||
import { s as sFromBknd } from "bknd/utils";
|
||||
import { s as sFromUserbase } from "userbase/utils";
|
||||
|
||||
describe("jsonv-ts resolution", () => {
|
||||
it("should resolve to a single instance", () => {
|
||||
const sameNamespace = sDirect === (sFromBknd as unknown as typeof sDirect);
|
||||
const sameNamespace = sDirect === (sFromUserbase as unknown as typeof sDirect);
|
||||
// If this fails, two instances are being loaded via different specifiers/paths
|
||||
expect(sameNamespace).toBe(true);
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import { format as sqlFormat } from "sql-formatter";
|
||||
import type { em as protoEm } from "../src/data/prototype";
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { slugify } from "bknd/utils";
|
||||
import { slugify } from "userbase/utils";
|
||||
import { type Connection, SqliteLocalConnection } from "data/connection";
|
||||
import { EntityManager } from "data/entities/EntityManager";
|
||||
|
||||
|
||||
@@ -57,11 +57,11 @@ const configs = {
|
||||
},
|
||||
users: {
|
||||
normal: {
|
||||
email: "normal@bknd.io",
|
||||
email: "normal@userbase.io",
|
||||
password: "12345678",
|
||||
},
|
||||
admin: {
|
||||
email: "admin@bknd.io",
|
||||
email: "admin@userbase.io",
|
||||
password: "12345678",
|
||||
role: "admin",
|
||||
},
|
||||
@@ -271,7 +271,7 @@ describe("integration auth", () => {
|
||||
expect(
|
||||
await app
|
||||
.createUser({
|
||||
email: "test@bknd.io",
|
||||
email: "test@userbase.io",
|
||||
password: "12345678",
|
||||
})
|
||||
.then((r) => r.role),
|
||||
@@ -280,7 +280,7 @@ describe("integration auth", () => {
|
||||
// throws error if role doesn't exist
|
||||
expect(
|
||||
app.createUser({
|
||||
email: "test@bknd.io",
|
||||
email: "test@userbase.io",
|
||||
password: "12345678",
|
||||
role: "doesnt exist",
|
||||
}),
|
||||
@@ -290,7 +290,7 @@ describe("integration auth", () => {
|
||||
expect(
|
||||
await app
|
||||
.createUser({
|
||||
email: "test2@bknd.io",
|
||||
email: "test2@userbase.io",
|
||||
password: "12345678",
|
||||
role: "admin",
|
||||
})
|
||||
@@ -301,7 +301,7 @@ describe("integration auth", () => {
|
||||
expect(
|
||||
await $fns
|
||||
.register({
|
||||
email: "test3@bknd.io",
|
||||
email: "test3@userbase.io",
|
||||
password: "12345678",
|
||||
role: "admin",
|
||||
})
|
||||
@@ -312,7 +312,7 @@ describe("integration auth", () => {
|
||||
expect(
|
||||
await $fns
|
||||
.register({
|
||||
email: "test3@bknd.io",
|
||||
email: "test3@userbase.io",
|
||||
password: "12345678",
|
||||
})
|
||||
.then((r) => r.data.user.role),
|
||||
|
||||
@@ -136,7 +136,7 @@ describe("AppAuth", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("registers auth middleware for bknd routes only", async () => {
|
||||
test("registers auth middleware for userbase routes only", async () => {
|
||||
const app = createApp({
|
||||
config: {
|
||||
auth: {
|
||||
|
||||
@@ -7,7 +7,9 @@ import v7 from "./samples/v7.json";
|
||||
import v8 from "./samples/v8.json";
|
||||
import v8_2 from "./samples/v8-2.json";
|
||||
import v9 from "./samples/v9.json";
|
||||
import v10 from "./samples/v10.json";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils/test";
|
||||
import { CURRENT_VERSION } from "modules/db/migrations";
|
||||
|
||||
beforeAll(() => disableConsoleLog());
|
||||
afterAll(enableConsoleLog);
|
||||
@@ -23,7 +25,7 @@ async function createVersionedApp(
|
||||
const { version, ...rest } = config;
|
||||
|
||||
const db = dummyConnection.kysely as Kysely<any>;
|
||||
await sql`CREATE TABLE "__bknd" (
|
||||
await sql`CREATE TABLE "__userbase" (
|
||||
"id" integer not null primary key autoincrement,
|
||||
"version" integer,
|
||||
"type" text,
|
||||
@@ -33,7 +35,7 @@ async function createVersionedApp(
|
||||
)`.execute(db);
|
||||
|
||||
await db
|
||||
.insertInto("__bknd")
|
||||
.insertInto("__userbase")
|
||||
.values({
|
||||
version,
|
||||
type: "config",
|
||||
@@ -59,9 +61,9 @@ async function getRawConfig(
|
||||
) {
|
||||
const db = app.em.connection.kysely;
|
||||
return await db
|
||||
.selectFrom("__bknd")
|
||||
.selectFrom("__userbase")
|
||||
.selectAll()
|
||||
.$if(!!opts?.version, (qb) => qb.where("version", "=", opts?.version))
|
||||
.where("version", "=", opts?.version ?? CURRENT_VERSION)
|
||||
.$if((opts?.types?.length ?? 0) > 0, (qb) => qb.where("type", "in", opts?.types))
|
||||
.execute();
|
||||
}
|
||||
@@ -115,7 +117,6 @@ describe("Migrations", () => {
|
||||
"^^s3.secret_access_key^^",
|
||||
);
|
||||
const [config, secrets] = (await getRawConfig(app, {
|
||||
version: 10,
|
||||
types: ["config", "secrets"],
|
||||
})) as any;
|
||||
|
||||
@@ -129,4 +130,15 @@ describe("Migrations", () => {
|
||||
"^^s3.secret_access_key^^",
|
||||
);
|
||||
});
|
||||
|
||||
test("migration from 10 to 11", async () => {
|
||||
expect(v10.version).toBe(10);
|
||||
expect(v10.data.entities.test.fields.title.config.fillable).toEqual(["read", "update"]);
|
||||
|
||||
const app = await createVersionedApp(v10);
|
||||
|
||||
expect(app.version()).toBeGreaterThan(10);
|
||||
const [config] = (await getRawConfig(app, { types: ["config"] })) as any;
|
||||
expect(config.json.data.entities.test.fields.title.config.fillable).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
{
|
||||
"version": 10,
|
||||
"server": {
|
||||
"cors": {
|
||||
"origin": "*",
|
||||
"allow_methods": ["GET", "POST", "PATCH", "PUT", "DELETE"],
|
||||
"allow_headers": [
|
||||
"Content-Type",
|
||||
"Content-Length",
|
||||
"Authorization",
|
||||
"Accept"
|
||||
],
|
||||
"allow_credentials": true
|
||||
},
|
||||
"mcp": {
|
||||
"enabled": true,
|
||||
"path": "/api/system/mcp",
|
||||
"logLevel": "warning"
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"basepath": "/api/data",
|
||||
"default_primary_format": "integer",
|
||||
"entities": {
|
||||
"test": {
|
||||
"type": "regular",
|
||||
"fields": {
|
||||
"id": {
|
||||
"type": "primary",
|
||||
"config": {
|
||||
"format": "integer",
|
||||
"fillable": false,
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"type": "text",
|
||||
"config": {
|
||||
"required": false,
|
||||
"fillable": ["read", "update"]
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"type": "enum",
|
||||
"config": {
|
||||
"default_value": "INACTIVE",
|
||||
"options": {
|
||||
"type": "strings",
|
||||
"values": ["INACTIVE", "SUBSCRIBED", "UNSUBSCRIBED"]
|
||||
},
|
||||
"required": true,
|
||||
"fillable": true
|
||||
}
|
||||
},
|
||||
"created_at": {
|
||||
"type": "date",
|
||||
"config": {
|
||||
"type": "datetime",
|
||||
"required": true,
|
||||
"fillable": true
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"type": "jsonschema",
|
||||
"config": {
|
||||
"default_from_schema": true,
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"one": {
|
||||
"type": "number",
|
||||
"default": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true,
|
||||
"fillable": true
|
||||
}
|
||||
},
|
||||
"text": {
|
||||
"type": "text",
|
||||
"config": {
|
||||
"required": false,
|
||||
"fillable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort_field": "id",
|
||||
"sort_dir": "asc"
|
||||
}
|
||||
},
|
||||
"items": {
|
||||
"type": "regular",
|
||||
"fields": {
|
||||
"id": {
|
||||
"type": "primary",
|
||||
"config": {
|
||||
"format": "integer",
|
||||
"fillable": false,
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"type": "text",
|
||||
"config": {
|
||||
"required": false,
|
||||
"fillable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort_field": "id",
|
||||
"sort_dir": "asc"
|
||||
}
|
||||
},
|
||||
"media": {
|
||||
"type": "system",
|
||||
"fields": {
|
||||
"id": {
|
||||
"type": "primary",
|
||||
"config": {
|
||||
"format": "integer",
|
||||
"fillable": false,
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"path": {
|
||||
"type": "text",
|
||||
"config": {
|
||||
"required": true,
|
||||
"fillable": true
|
||||
}
|
||||
},
|
||||
"folder": {
|
||||
"type": "boolean",
|
||||
"config": {
|
||||
"default_value": false,
|
||||
"hidden": true,
|
||||
"fillable": ["create"],
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"mime_type": {
|
||||
"type": "text",
|
||||
"config": {
|
||||
"required": false,
|
||||
"fillable": true
|
||||
}
|
||||
},
|
||||
"size": {
|
||||
"type": "number",
|
||||
"config": {
|
||||
"required": false,
|
||||
"fillable": true
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"type": "text",
|
||||
"config": {
|
||||
"hidden": true,
|
||||
"fillable": ["create"],
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"etag": {
|
||||
"type": "text",
|
||||
"config": {
|
||||
"required": false,
|
||||
"fillable": true
|
||||
}
|
||||
},
|
||||
"modified_at": {
|
||||
"type": "date",
|
||||
"config": {
|
||||
"type": "datetime",
|
||||
"required": false,
|
||||
"fillable": true
|
||||
}
|
||||
},
|
||||
"reference": {
|
||||
"type": "text",
|
||||
"config": {
|
||||
"required": false,
|
||||
"fillable": true
|
||||
}
|
||||
},
|
||||
"entity_id": {
|
||||
"type": "text",
|
||||
"config": {
|
||||
"required": false,
|
||||
"fillable": true
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"type": "json",
|
||||
"config": {
|
||||
"required": false,
|
||||
"fillable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort_field": "id",
|
||||
"sort_dir": "asc"
|
||||
}
|
||||
}
|
||||
},
|
||||
"relations": {},
|
||||
"indices": {
|
||||
"idx_unique_media_path": {
|
||||
"entity": "media",
|
||||
"fields": ["path"],
|
||||
"unique": true
|
||||
},
|
||||
"idx_media_reference": {
|
||||
"entity": "media",
|
||||
"fields": ["reference"],
|
||||
"unique": false
|
||||
},
|
||||
"idx_media_entity_id": {
|
||||
"entity": "media",
|
||||
"fields": ["entity_id"],
|
||||
"unique": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"enabled": false,
|
||||
"basepath": "/api/auth",
|
||||
"entity_name": "users",
|
||||
"allow_register": true,
|
||||
"jwt": {
|
||||
"secret": "",
|
||||
"alg": "HS256",
|
||||
"fields": ["id", "email", "role"]
|
||||
},
|
||||
"cookie": {
|
||||
"path": "/",
|
||||
"sameSite": "lax",
|
||||
"secure": true,
|
||||
"httpOnly": true,
|
||||
"expires": 604800,
|
||||
"partitioned": false,
|
||||
"renew": true,
|
||||
"pathSuccess": "/",
|
||||
"pathLoggedOut": "/"
|
||||
},
|
||||
"strategies": {
|
||||
"password": {
|
||||
"type": "password",
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"hashing": "sha256"
|
||||
}
|
||||
}
|
||||
},
|
||||
"guard": {
|
||||
"enabled": false
|
||||
},
|
||||
"roles": {}
|
||||
},
|
||||
"media": {
|
||||
"enabled": false
|
||||
},
|
||||
"flows": {
|
||||
"basepath": "/api/flows",
|
||||
"flows": {}
|
||||
}
|
||||
}
|
||||
@@ -546,7 +546,7 @@
|
||||
"config": {
|
||||
"access_key": "123",
|
||||
"secret_access_key": "123",
|
||||
"url": "https://123.r2.cloudflarestorage.com/bknd-123"
|
||||
"url": "https://123.r2.cloudflarestorage.com/userbase-123"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@ import { EntityManager } from "data/entities/EntityManager";
|
||||
import { Module, type ModuleBuildContext } from "modules/Module";
|
||||
import { getDummyConnection } from "../helper";
|
||||
import { ModuleHelper } from "modules/ModuleHelper";
|
||||
import { DebugLogger, McpServer } from "bknd/utils";
|
||||
import { DebugLogger, McpServer } from "userbase/utils";
|
||||
|
||||
export function makeCtx(overrides?: Partial<ModuleBuildContext>): ModuleBuildContext {
|
||||
const { dummyConnection } = getDummyConnection();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, it, expect, beforeEach } from "vitest";
|
||||
import { AppReduced, type AppType } from "ui/client/utils/AppReduced";
|
||||
import type { BkndAdminProps } from "ui/Admin";
|
||||
import type { UserbaseAdminProps } from "ui/Admin";
|
||||
|
||||
// Import the normalizeAdminPath function for testing
|
||||
// Note: This assumes the function is exported or we need to test it indirectly through public methods
|
||||
@@ -24,7 +24,7 @@ describe("AppReduced", () => {
|
||||
|
||||
describe("getSettingsPath", () => {
|
||||
it("should return settings path with basepath", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "/admin",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -36,7 +36,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should return settings path with empty basepath", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -48,7 +48,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should append additional path segments", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "/admin",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -60,7 +60,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should normalize multiple slashes", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "//admin//",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -72,7 +72,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should handle basepath without leading slash", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "admin",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -86,7 +86,7 @@ describe("AppReduced", () => {
|
||||
|
||||
describe("getAbsolutePath", () => {
|
||||
it("should return absolute path with basepath", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "/admin",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -98,7 +98,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should return base path when no path provided", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "/admin",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -110,7 +110,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should normalize paths correctly", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "//admin//",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -124,7 +124,7 @@ describe("AppReduced", () => {
|
||||
|
||||
describe("options getter", () => {
|
||||
it("should return merged options with defaults", () => {
|
||||
const customOptions: BkndAdminProps["config"] = {
|
||||
const customOptions: UserbaseAdminProps["config"] = {
|
||||
basepath: "/custom-admin",
|
||||
logo_return_path: "/custom-home",
|
||||
};
|
||||
@@ -139,7 +139,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should use default logo_return_path when not provided", () => {
|
||||
const customOptions: BkndAdminProps["config"] = {
|
||||
const customOptions: UserbaseAdminProps["config"] = {
|
||||
basepath: "/admin",
|
||||
};
|
||||
|
||||
@@ -153,7 +153,7 @@ describe("AppReduced", () => {
|
||||
|
||||
describe("path normalization behavior", () => {
|
||||
it("should normalize duplicate slashes in settings path", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "/admin",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -165,7 +165,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should handle root path normalization", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "/",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -179,7 +179,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should preserve entity paths ending with slash", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "/admin",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -191,7 +191,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should remove trailing slashes from non-entity paths", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "/admin",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -205,7 +205,7 @@ describe("AppReduced", () => {
|
||||
|
||||
describe("withBasePath - double slash fix (admin_basepath with trailing slash)", () => {
|
||||
it("should not produce double slashes when admin_basepath has trailing slash", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "/admin",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -218,7 +218,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should work correctly when admin_basepath has no trailing slash", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "/admin",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -230,7 +230,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should handle absolute paths with admin_basepath trailing slash", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "/admin",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -243,7 +243,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should handle settings path with admin_basepath trailing slash", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "/admin",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
@@ -258,7 +258,7 @@ describe("AppReduced", () => {
|
||||
|
||||
describe("edge cases", () => {
|
||||
it("should handle undefined basepath", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
logo_return_path: "/",
|
||||
};
|
||||
|
||||
@@ -270,7 +270,7 @@ describe("AppReduced", () => {
|
||||
});
|
||||
|
||||
it("should handle null path segments", () => {
|
||||
const options: BkndAdminProps["config"] = {
|
||||
const options: UserbaseAdminProps["config"] = {
|
||||
basepath: "/admin",
|
||||
logo_return_path: "/",
|
||||
};
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
import pkg from "./package.json" with { type: "json" };
|
||||
import c from "picocolors";
|
||||
import { formatNumber } from "bknd/utils";
|
||||
import { formatNumber } from "userbase/utils";
|
||||
|
||||
const deps = Object.keys(pkg.dependencies);
|
||||
const external = ["jsonv-ts/*", "wrangler", "bknd", "bknd/*", ...deps];
|
||||
const external = ["jsonv-ts/*", "wrangler", "userbase", "userbase/*", ...deps];
|
||||
|
||||
const result = await Bun.build({
|
||||
entrypoints: ["./src/cli/index.ts"],
|
||||
|
||||
+171
-207
@@ -1,9 +1,9 @@
|
||||
import { build, type UserConfig } from "tsdown";
|
||||
import { $ } from "bun";
|
||||
import * as tsup from "tsup";
|
||||
import pkg from "./package.json" with { type: "json" };
|
||||
import c from "picocolors";
|
||||
import { watch as fsWatch, readdirSync, rmSync } from "node:fs";
|
||||
import { join, resolve } from "node:path";
|
||||
import { buildTypes as runTypesBuild } from "./build.types";
|
||||
import { join } from "node:path";
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const watch = args.includes("--watch");
|
||||
@@ -11,15 +11,14 @@ const minify = args.includes("--minify");
|
||||
const types = args.includes("--types");
|
||||
const sourcemap = args.includes("--sourcemap");
|
||||
const clean = args.includes("--clean");
|
||||
const dev = args.includes("--dev");
|
||||
|
||||
// silence tsdown
|
||||
// silence tsup
|
||||
const oldConsole = {
|
||||
log: console.log,
|
||||
warn: console.warn,
|
||||
};
|
||||
console.log = () => { };
|
||||
console.warn = () => { };
|
||||
console.log = () => {};
|
||||
console.warn = () => {};
|
||||
|
||||
const define = {
|
||||
__isDev: "0",
|
||||
@@ -37,48 +36,55 @@ if (clean) {
|
||||
const entryPath = join(distPath, entry);
|
||||
rmSync(entryPath, { recursive: true, force: true });
|
||||
}
|
||||
} catch {
|
||||
} catch (e) {
|
||||
// dist may not exist yet, ignore
|
||||
}
|
||||
}
|
||||
|
||||
let types_running = false;
|
||||
async function buildTypes() {
|
||||
function buildTypes() {
|
||||
if (types_running || !types) return;
|
||||
types_running = true;
|
||||
|
||||
try {
|
||||
await runTypesBuild();
|
||||
oldConsole.log(c.cyan("[Types]"), c.green("built"));
|
||||
} finally {
|
||||
types_running = false;
|
||||
}
|
||||
Bun.spawn(["bun", "build:types"], {
|
||||
stdout: "inherit",
|
||||
onExit: () => {
|
||||
oldConsole.log(c.cyan("[Types]"), c.green("built"));
|
||||
Bun.spawn(["bun", "tsc-alias"], {
|
||||
stdout: "inherit",
|
||||
onExit: () => {
|
||||
oldConsole.log(c.cyan("[Types]"), c.green("aliased"));
|
||||
types_running = false;
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (types && !watch) {
|
||||
buildTypes();
|
||||
}
|
||||
|
||||
let watcher_timeout: any;
|
||||
function delayTypes(delayTime = 1000) {
|
||||
function delayTypes() {
|
||||
if (!watch || !types) return;
|
||||
if (watcher_timeout) {
|
||||
clearTimeout(watcher_timeout);
|
||||
}
|
||||
watcher_timeout = setTimeout(() => {
|
||||
void buildTypes().catch((error) => {
|
||||
oldConsole.warn(c.cyan("[Types]"), c.red("build failed"), error);
|
||||
});
|
||||
}, delayTime);
|
||||
watcher_timeout = setTimeout(buildTypes, 1000);
|
||||
}
|
||||
|
||||
const dependencies = Object.keys(pkg.dependencies);
|
||||
|
||||
// collection of always-neverBundle packages
|
||||
const neverBundle = [
|
||||
// collection of always-external packages
|
||||
const external = [
|
||||
...dependencies,
|
||||
"bun:test",
|
||||
"node:test",
|
||||
"node:assert/strict",
|
||||
"@libsql/client",
|
||||
"bknd",
|
||||
/^bknd\/.*/,
|
||||
"userbase",
|
||||
/^userbase\/.*/,
|
||||
"jsonv-ts",
|
||||
/^jsonv-ts\/.*/,
|
||||
] as const;
|
||||
@@ -87,14 +93,11 @@ const neverBundle = [
|
||||
* Building backend and general API
|
||||
*/
|
||||
async function buildApi() {
|
||||
await build({
|
||||
await tsup.build({
|
||||
minify,
|
||||
sourcemap,
|
||||
// don't use tsdown's broken watch, we'll handle it ourselves
|
||||
// don't use tsup's broken watch, we'll handle it ourselves
|
||||
watch: false,
|
||||
// cleaning is handled manually (--clean) to preserve dist/static
|
||||
clean: false,
|
||||
dts: false,
|
||||
define,
|
||||
entry: [
|
||||
"src/index.ts",
|
||||
@@ -102,19 +105,14 @@ async function buildApi() {
|
||||
"src/plugins/index.ts",
|
||||
"src/modes/index.ts",
|
||||
],
|
||||
unbundle: false,
|
||||
outDir: "dist",
|
||||
deps: {
|
||||
neverBundle: [
|
||||
...neverBundle
|
||||
],
|
||||
},
|
||||
|
||||
external: [...external],
|
||||
metafile: true,
|
||||
target: "esnext",
|
||||
platform: "browser",
|
||||
nodeProtocol: true,
|
||||
format: "esm",
|
||||
|
||||
removeNodeProtocol: false,
|
||||
format: ["esm"],
|
||||
splitting: false,
|
||||
loader: {
|
||||
".svg": "dataurl",
|
||||
},
|
||||
@@ -127,7 +125,7 @@ async function buildApi() {
|
||||
|
||||
async function rewriteClient(path: string) {
|
||||
const bundle = await Bun.file(path).text();
|
||||
await Bun.write(path, '"use client";\n' + bundle.replaceAll("ui/client", "bknd/client"));
|
||||
await Bun.write(path, '"use client";\n' + bundle.replaceAll("ui/client", "userbase/client"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,109 +136,94 @@ async function buildUi() {
|
||||
minify,
|
||||
sourcemap,
|
||||
watch: false,
|
||||
// cleaning is handled manually (--clean) to preserve dist/static
|
||||
clean: false,
|
||||
dts: false,
|
||||
define,
|
||||
css: {
|
||||
transformer: "postcss",
|
||||
postcss: "postcss.config.js",
|
||||
minify: true,
|
||||
splitting: false
|
||||
},
|
||||
deps: {
|
||||
neverBundle: [
|
||||
...neverBundle,
|
||||
"react",
|
||||
"react-dom",
|
||||
"react/jsx-runtime",
|
||||
"react/jsx-dev-runtime",
|
||||
"use-sync-external-store",
|
||||
/codemirror/,
|
||||
"@xyflow/react",
|
||||
"@mantine/core",
|
||||
],
|
||||
},
|
||||
devtools: dev,
|
||||
external: [
|
||||
...external,
|
||||
"react",
|
||||
"react-dom",
|
||||
"react/jsx-runtime",
|
||||
"react/jsx-dev-runtime",
|
||||
"use-sync-external-store",
|
||||
/codemirror/,
|
||||
"@xyflow/react",
|
||||
"@mantine/core",
|
||||
],
|
||||
metafile: true,
|
||||
platform: "browser",
|
||||
format: "esm",
|
||||
unbundle: false,
|
||||
treeshake: true,
|
||||
loader: {
|
||||
".svg": "dataurl",
|
||||
},
|
||||
|
||||
logLevel: "silent",
|
||||
} satisfies UserConfig;
|
||||
|
||||
|
||||
|
||||
await Promise.all([
|
||||
build({
|
||||
...base,
|
||||
entry: ["src/ui/index.ts", "src/ui/main.css", "src/ui/styles.css"],
|
||||
outDir: "dist/ui",
|
||||
onSuccess: async () => {
|
||||
await rewriteClient("./dist/ui/index.js");
|
||||
delayTypes();
|
||||
oldConsole.log(c.cyan("[UI]"), c.green("built"));
|
||||
},
|
||||
}),
|
||||
|
||||
build({
|
||||
...base,
|
||||
entry: ["src/ui/client/index.ts"],
|
||||
outDir: "dist/ui/client",
|
||||
onSuccess: async () => {
|
||||
await rewriteClient("./dist/ui/client/index.js");
|
||||
delayTypes();
|
||||
oldConsole.log(c.cyan("[UI]"), "Client", c.green("built"));
|
||||
},
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Building UI Elements
|
||||
* - tailwind-merge is mocked, no exclude
|
||||
* - ui/client is external, and after built replaced with "bknd/client"
|
||||
*/
|
||||
async function buildUiElements() {
|
||||
await build({
|
||||
minify,
|
||||
sourcemap,
|
||||
watch: false,
|
||||
// cleaning is handled manually (--clean) to preserve dist/static
|
||||
clean: false,
|
||||
dts: false,
|
||||
define,
|
||||
entry: ["src/ui/elements/index.ts"],
|
||||
outDir: "dist/ui/elements",
|
||||
deps: {
|
||||
neverBundle: [
|
||||
"ui/client",
|
||||
"bknd",
|
||||
/^bknd\/.*/,
|
||||
"wouter",
|
||||
"react",
|
||||
"react-dom",
|
||||
"react/jsx-runtime",
|
||||
"react/jsx-dev-runtime",
|
||||
"use-sync-external-store",
|
||||
],
|
||||
},
|
||||
platform: "browser",
|
||||
format: "esm",
|
||||
format: ["esm"],
|
||||
splitting: false,
|
||||
bundle: true,
|
||||
treeshake: true,
|
||||
loader: {
|
||||
".svg": "dataurl",
|
||||
},
|
||||
alias: {
|
||||
// not important for elements, mock to reduce bundle
|
||||
"tailwind-merge": resolve(import.meta.dir, "src/ui/elements/mocks/tailwind-merge.ts"),
|
||||
esbuildOptions: (options) => {
|
||||
options.logLevel = "silent";
|
||||
},
|
||||
} satisfies tsup.Options;
|
||||
|
||||
await tsup.build({
|
||||
...base,
|
||||
entry: ["src/ui/index.ts", "src/ui/main.css", "src/ui/styles.css"],
|
||||
outDir: "dist/ui",
|
||||
onSuccess: async () => {
|
||||
await rewriteClient("./dist/ui/index.js");
|
||||
delayTypes();
|
||||
oldConsole.log(c.cyan("[UI]"), c.green("built"));
|
||||
},
|
||||
});
|
||||
|
||||
await tsup.build({
|
||||
...base,
|
||||
entry: ["src/ui/client/index.ts"],
|
||||
outDir: "dist/ui/client",
|
||||
onSuccess: async () => {
|
||||
await rewriteClient("./dist/ui/client/index.js");
|
||||
delayTypes();
|
||||
oldConsole.log(c.cyan("[UI]"), "Client", c.green("built"));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Building UI Elements
|
||||
* - tailwind-merge is mocked, no exclude
|
||||
* - ui/client is external, and after built replaced with "userbase/client"
|
||||
*/
|
||||
async function buildUiElements() {
|
||||
await tsup.build({
|
||||
minify,
|
||||
sourcemap,
|
||||
watch: false,
|
||||
define,
|
||||
entry: ["src/ui/elements/index.ts"],
|
||||
outDir: "dist/ui/elements",
|
||||
external: [
|
||||
"ui/client",
|
||||
"userbase",
|
||||
/^userbase\/.*/,
|
||||
"wouter",
|
||||
"react",
|
||||
"react-dom",
|
||||
"react/jsx-runtime",
|
||||
"react/jsx-dev-runtime",
|
||||
"use-sync-external-store",
|
||||
],
|
||||
metafile: true,
|
||||
platform: "browser",
|
||||
format: ["esm"],
|
||||
splitting: false,
|
||||
bundle: true,
|
||||
treeshake: true,
|
||||
loader: {
|
||||
".svg": "dataurl",
|
||||
},
|
||||
esbuildOptions: (options) => {
|
||||
options.alias = {
|
||||
// not important for elements, mock to reduce bundle
|
||||
"tailwind-merge": "./src/ui/elements/mocks/tailwind-merge.ts",
|
||||
};
|
||||
},
|
||||
onSuccess: async () => {
|
||||
await rewriteClient("./dist/ui/elements/index.js");
|
||||
delayTypes();
|
||||
@@ -252,20 +235,18 @@ async function buildUiElements() {
|
||||
/**
|
||||
* Building adapters
|
||||
*/
|
||||
function baseConfig(adapter: string, overrides: Partial<UserConfig> = {}): UserConfig {
|
||||
function baseConfig(adapter: string, overrides: Partial<tsup.Options> = {}): tsup.Options {
|
||||
return {
|
||||
minify,
|
||||
sourcemap,
|
||||
watch: false,
|
||||
// cleaning is handled manually (--clean) to preserve dist/static
|
||||
clean: false,
|
||||
dts: false,
|
||||
entry: [`src/adapter/${adapter}/index.ts`],
|
||||
format: "esm",
|
||||
format: ["esm"],
|
||||
platform: "neutral",
|
||||
outDir: `dist/adapter/${adapter}`,
|
||||
devtools: dev,
|
||||
nodeProtocol: true,
|
||||
metafile: true,
|
||||
splitting: false,
|
||||
removeNodeProtocol: false,
|
||||
onSuccess: async () => {
|
||||
delayTypes();
|
||||
oldConsole.log(c.cyan("[Adapter]"), adapter || "base", c.green("built"));
|
||||
@@ -275,23 +256,21 @@ function baseConfig(adapter: string, overrides: Partial<UserConfig> = {}): UserC
|
||||
...define,
|
||||
...overrides.define,
|
||||
},
|
||||
deps: {
|
||||
neverBundle: [
|
||||
/^cloudflare*/,
|
||||
/^@?hono.*?/,
|
||||
/^(bknd|react|next|node).*?/,
|
||||
/.*\.(html)$/,
|
||||
...neverBundle,
|
||||
...(Array.isArray(overrides.deps?.neverBundle) ? overrides.deps.neverBundle : []),
|
||||
],
|
||||
},
|
||||
external: [
|
||||
/^cloudflare*/,
|
||||
/^@?hono.*?/,
|
||||
/^(userbase|react|next|node).*?/,
|
||||
/.*\.(html)$/,
|
||||
...external,
|
||||
...(Array.isArray(overrides.external) ? overrides.external : []),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
async function buildAdapters() {
|
||||
await Promise.all([
|
||||
// base adapter handles
|
||||
build({
|
||||
tsup.build({
|
||||
...baseConfig(""),
|
||||
target: "esnext",
|
||||
platform: "neutral",
|
||||
@@ -299,120 +278,105 @@ async function buildAdapters() {
|
||||
outDir: "dist/adapter",
|
||||
// only way to keep @vite-ignore comments
|
||||
minify: false,
|
||||
dts: false,
|
||||
}),
|
||||
|
||||
// specific adapters
|
||||
build(baseConfig("react-router")),
|
||||
build(
|
||||
// specific adatpers
|
||||
tsup.build(baseConfig("react-router")),
|
||||
tsup.build(
|
||||
baseConfig("browser", {
|
||||
deps: {
|
||||
neverBundle: [/^sqlocal\/?.*?/, "wouter"],
|
||||
},
|
||||
external: [/^sqlocal\/?.*?/, "wouter"],
|
||||
}),
|
||||
),
|
||||
build(
|
||||
tsup.build(
|
||||
baseConfig("bun", {
|
||||
deps: {
|
||||
neverBundle: [/^bun:.*/],
|
||||
},
|
||||
external: [/^bun\:.*/],
|
||||
}),
|
||||
),
|
||||
build(baseConfig("astro")),
|
||||
build(baseConfig("aws")),
|
||||
build(
|
||||
tsup.build(baseConfig("astro")),
|
||||
tsup.build(baseConfig("aws")),
|
||||
tsup.build(
|
||||
baseConfig("cloudflare", {
|
||||
deps: {
|
||||
neverBundle: ["wrangler", "node:process", "miniflare"],
|
||||
},
|
||||
external: ["wrangler", "node:process"],
|
||||
}),
|
||||
),
|
||||
build(
|
||||
tsup.build(
|
||||
baseConfig("cloudflare/proxy", {
|
||||
target: "esnext",
|
||||
entry: ["src/adapter/cloudflare/proxy.ts"],
|
||||
outDir: "dist/adapter/cloudflare",
|
||||
devtools: false,
|
||||
deps: {
|
||||
neverBundle: [/bknd/, "wrangler", "node:process", "miniflare"],
|
||||
},
|
||||
metafile: false,
|
||||
external: [/userbase/, "wrangler", "node:process"],
|
||||
}),
|
||||
),
|
||||
|
||||
build({
|
||||
tsup.build({
|
||||
...baseConfig("vite"),
|
||||
platform: "node",
|
||||
}),
|
||||
|
||||
build({
|
||||
tsup.build({
|
||||
...baseConfig("nextjs"),
|
||||
platform: "node",
|
||||
}),
|
||||
|
||||
build({
|
||||
tsup.build({
|
||||
...baseConfig("tanstack-start"),
|
||||
platform: "node",
|
||||
}),
|
||||
|
||||
build({
|
||||
tsup.build({
|
||||
...baseConfig("sveltekit"),
|
||||
platform: "node",
|
||||
}),
|
||||
|
||||
build({
|
||||
tsup.build({
|
||||
...baseConfig("nuxt"),
|
||||
platform: "node",
|
||||
}),
|
||||
|
||||
build({
|
||||
tsup.build({
|
||||
...baseConfig("node"),
|
||||
platform: "node",
|
||||
}),
|
||||
|
||||
build({
|
||||
tsup.build({
|
||||
...baseConfig("solid-start"),
|
||||
platform: "node",
|
||||
}),
|
||||
|
||||
tsup.build({
|
||||
...baseConfig("sqlite/edge"),
|
||||
entry: ["src/adapter/sqlite/edge.ts"],
|
||||
outDir: "dist/adapter/sqlite",
|
||||
devtools: false,
|
||||
metafile: false,
|
||||
}),
|
||||
|
||||
build({
|
||||
tsup.build({
|
||||
...baseConfig("sqlite/node"),
|
||||
entry: ["src/adapter/sqlite/node.ts"],
|
||||
outDir: "dist/adapter/sqlite",
|
||||
platform: "node",
|
||||
devtools: false,
|
||||
metafile: false,
|
||||
}),
|
||||
|
||||
build(
|
||||
baseConfig("sqlite/bun", {
|
||||
entry: ["src/adapter/sqlite/bun.ts"],
|
||||
outDir: "dist/adapter/sqlite",
|
||||
devtools: false,
|
||||
deps: {
|
||||
neverBundle: [/^bun:.*/],
|
||||
},
|
||||
}),
|
||||
),
|
||||
tsup.build({
|
||||
...baseConfig("sqlite/bun"),
|
||||
entry: ["src/adapter/sqlite/bun.ts"],
|
||||
outDir: "dist/adapter/sqlite",
|
||||
metafile: false,
|
||||
external: [/^bun\:.*/],
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
const buildPipeline = [buildApi, buildUi, buildUiElements, buildAdapters];
|
||||
|
||||
// Run type generation in parallel, since it can be slow and doesn't block the main build
|
||||
if (types) {
|
||||
buildPipeline.push(async () => await buildTypes());
|
||||
async function buildAll() {
|
||||
await Promise.all([buildApi(), buildUi(), buildUiElements(), buildAdapters()]);
|
||||
}
|
||||
|
||||
// initial build
|
||||
await buildAll();
|
||||
|
||||
async function buildAll() {
|
||||
await Promise.all(buildPipeline.map(fn => fn()));
|
||||
}
|
||||
|
||||
|
||||
// custom watcher since tsdown's watch is broken in v0.21.7
|
||||
// custom watcher since tsup's watch is broken in 8.3.5+
|
||||
if (watch) {
|
||||
oldConsole.log(c.cyan("[Watch]"), "watching for changes in src/...");
|
||||
|
||||
@@ -448,5 +412,5 @@ if (watch) {
|
||||
});
|
||||
|
||||
// keep process alive
|
||||
await new Promise(() => { });
|
||||
await new Promise(() => {});
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { build } from "tsdown";
|
||||
import c from "picocolors";
|
||||
|
||||
export async function buildTypes() {
|
||||
await build({
|
||||
tsconfig: "tsconfig.build.json",
|
||||
watch: false,
|
||||
clean: true,
|
||||
logLevel: "silent",
|
||||
unbundle: true,
|
||||
root: "src",
|
||||
outDir: "dist/types",
|
||||
entry: ["./src/**/*.ts", "./src/**/*.tsx"],
|
||||
format: "esm",
|
||||
dts: {
|
||||
emitDtsOnly: true,
|
||||
resolver: "oxc",
|
||||
eager: true,
|
||||
incremental: true,
|
||||
},
|
||||
deps: {
|
||||
skipNodeModulesBundle: true
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
try {
|
||||
await buildTypes();
|
||||
console.log(c.cyan("[Types]"), c.green("built"));
|
||||
} catch (error) {
|
||||
console.error(c.cyan("[Types]"), c.red("build failed"), error);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -3,7 +3,10 @@ import path from "node:path";
|
||||
import c from "picocolors";
|
||||
|
||||
const basePath = new URL(import.meta.resolve("../../")).pathname.slice(0, -1);
|
||||
type RunOptions = Omit<Bun.SpawnOptions.SpawnOptions<"ignore", "pipe", "pipe">, "stdout" | "stderr">;
|
||||
type RunOptions = Omit<
|
||||
Bun.SpawnOptions.SpawnOptions<"ignore", "pipe", "pipe">,
|
||||
"stdout" | "stderr"
|
||||
>;
|
||||
|
||||
async function run(
|
||||
cmd: string[] | string,
|
||||
|
||||
+42
-39
@@ -1,50 +1,53 @@
|
||||
const adapter = process.env.TEST_ADAPTER;
|
||||
|
||||
const default_config = {
|
||||
media_adapter: "local",
|
||||
base_path: "",
|
||||
media_adapter: "local",
|
||||
base_path: "",
|
||||
} as const;
|
||||
|
||||
const configs = {
|
||||
cloudflare: {
|
||||
media_adapter: "r2",
|
||||
},
|
||||
"react-router": {
|
||||
base_path: "/admin",
|
||||
},
|
||||
nextjs: {
|
||||
base_path: "/admin",
|
||||
},
|
||||
nuxt: {
|
||||
base_path: "/admin",
|
||||
},
|
||||
astro: {
|
||||
base_path: "/admin",
|
||||
},
|
||||
node: {
|
||||
base_path: "",
|
||||
},
|
||||
bun: {
|
||||
base_path: "",
|
||||
},
|
||||
"tanstack-start": {
|
||||
base_path: "/admin",
|
||||
},
|
||||
cloudflare: {
|
||||
media_adapter: "r2",
|
||||
},
|
||||
"react-router": {
|
||||
base_path: "/admin",
|
||||
},
|
||||
nextjs: {
|
||||
base_path: "/admin",
|
||||
},
|
||||
nuxt: {
|
||||
base_path: "/admin",
|
||||
},
|
||||
"solid-start": {
|
||||
base_path: "/admin",
|
||||
},
|
||||
astro: {
|
||||
base_path: "/admin",
|
||||
},
|
||||
node: {
|
||||
base_path: "",
|
||||
},
|
||||
bun: {
|
||||
base_path: "",
|
||||
},
|
||||
"tanstack-start": {
|
||||
base_path: "/admin",
|
||||
},
|
||||
};
|
||||
|
||||
export function getAdapterConfig(): typeof default_config {
|
||||
if (adapter) {
|
||||
if (!configs[adapter]) {
|
||||
console.warn(
|
||||
`Adapter "${adapter}" not found. Available adapters: ${Object.keys(configs).join(", ")}`,
|
||||
);
|
||||
} else {
|
||||
return {
|
||||
...default_config,
|
||||
...configs[adapter],
|
||||
};
|
||||
}
|
||||
}
|
||||
if (adapter) {
|
||||
if (!configs[adapter]) {
|
||||
console.warn(
|
||||
`Adapter "${adapter}" not found. Available adapters: ${Object.keys(configs).join(", ")}`,
|
||||
);
|
||||
} else {
|
||||
return {
|
||||
...default_config,
|
||||
...configs[adapter],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return default_config;
|
||||
return default_config;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createApp } from "bknd/adapter/bun";
|
||||
import { createApp } from "userbase/adapter/bun";
|
||||
|
||||
async function generate() {
|
||||
console.info("Generating MCP documentation...");
|
||||
|
||||
+93
-115
@@ -1,34 +1,33 @@
|
||||
{
|
||||
"name": "bknd",
|
||||
"name": "userbase",
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
"bin": "./dist/cli/index.js",
|
||||
"version": "0.21.0-rc.1",
|
||||
"version": "0.0.2",
|
||||
"description": "Lightweight Firebase/Supabase alternative built to run anywhere — incl. Next.js, React Router, Astro, Cloudflare, Bun, Node, AWS Lambda & more.",
|
||||
"homepage": "https://bknd.io",
|
||||
"homepage": "https://gitea.bsws.in/shishantbiswas/userbase",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bknd-io/bknd.git"
|
||||
"url": "https://gitea.bsws.in/shishantbiswas/userbase.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/bknd-io/bknd/issues"
|
||||
"url": "https://gitea.bsws.in/shishantbiswas/userbase/issues"
|
||||
},
|
||||
"packageManager": "bun@1.3.3",
|
||||
"engines": {
|
||||
"node": ">=22.18.0",
|
||||
"bun": ">=1.3.3"
|
||||
"node": ">=22.13"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "BKND_CLI_LOG_LEVEL=debug vite",
|
||||
"dev": "USERBASE_CLI_LOG_LEVEL=debug vite",
|
||||
"build": "NODE_ENV=production bun run build.ts --minify --types",
|
||||
"build:all": "rm -rf dist && bun run build:static && NODE_ENV=production bun run build.ts --minify --types --clean && bun run build:cli",
|
||||
"build:ci": "mkdir -p dist/static/.vite && echo '{}' > dist/static/.vite/manifest.json && NODE_ENV=production bun run build.ts",
|
||||
"build:cli": "bun run build.cli.ts",
|
||||
"build:types": "bun run build.types.ts",
|
||||
"build:static": "vite build",
|
||||
"watch": "bun run build.ts --types --watch",
|
||||
"types": "bun tsc -p tsconfig.build.json --noEmit",
|
||||
"clean:types": "find ./dist -name '*.d.ts' -delete && rm -f ./dist/tsconfig.tsbuildinfo",
|
||||
"build:types": "tsc -p tsconfig.build.json --emitDeclarationOnly && tsc-alias",
|
||||
"updater": "bun x npm-check-updates -ui",
|
||||
"cli": "LOCAL=1 bun src/cli/index.ts",
|
||||
"prepublishOnly": "bun run types && bun run test && bun run test:node && NODE_NO_WARNINGS=1 VITE_DB_URL=:memory: bun run test:e2e && bun run build:all && cp ../README.md ./",
|
||||
@@ -89,23 +88,22 @@
|
||||
"@libsql/client": "^0.15.15",
|
||||
"@mantine/modals": "^7.17.1",
|
||||
"@mantine/notifications": "^7.17.1",
|
||||
"@playwright/test": "^1.56.1",
|
||||
"@playwright/test": "^1.63.0",
|
||||
"@rjsf/core": "5.22.2",
|
||||
"@rjsf/utils": "5.22.0",
|
||||
"@standard-schema/spec": "^1.0.0",
|
||||
"@tabler/icons-react": "3.35.0",
|
||||
"@tailwindcss/postcss": "^4.2.2",
|
||||
"@tailwindcss/vite": "^4.2.4",
|
||||
"@tailwindcss/postcss": "^4.1.16",
|
||||
"@tailwindcss/vite": "^4.1.16",
|
||||
"@tanstack/react-store": "^0.8.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.2.0",
|
||||
"@tsdown/css": "^0.22.14",
|
||||
"@types/node": "^24.13.3",
|
||||
"@types/node": "^24.10.0",
|
||||
"@types/pg": "^8.15.6",
|
||||
"@types/react": "^19.2.16",
|
||||
"@types/react": "^19.0.10",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@vitejs/plugin-react": "^6.0.2",
|
||||
"@vitest/coverage-v8": "4.1.10",
|
||||
"@vitejs/plugin-react": "^5.1.0",
|
||||
"@vitest/coverage-v8": "3.0.9",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"clsx": "^2.1.1",
|
||||
"commander": "^14.0.2",
|
||||
@@ -116,87 +114,89 @@
|
||||
"kysely-postgres-js": "^2.0.0",
|
||||
"libsql": "^0.5.22",
|
||||
"libsql-stateless-easy": "^1.8.0",
|
||||
"miniflare": "^4.20260317.3",
|
||||
"miniflare": "^4.20251011.2",
|
||||
"open": "^10.2.0",
|
||||
"openapi-types": "^12.1.3",
|
||||
"pg": "^8.16.3",
|
||||
"postcss": "^8.5.26",
|
||||
"postcss-import": "^16.1.1",
|
||||
"postcss": "^8.5.3",
|
||||
"postcss-preset-mantine": "^1.18.0",
|
||||
"postcss-simple-vars": "^7.0.1",
|
||||
"postgres": "^3.4.7",
|
||||
"posthog-js-lite": "^3.6.0",
|
||||
"react": "^19.2.7",
|
||||
"react-dom": "^19.2.7",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-hook-form": "^7.66.0",
|
||||
"react-icons": "5.5.0",
|
||||
"react-json-view-lite": "^2.5.0",
|
||||
"sql-formatter": "^15.6.10",
|
||||
"sqlocal": "^0.16.0",
|
||||
"tailwind-merge": "^3.0.2",
|
||||
"tailwindcss": "^4.3.3",
|
||||
"tailwindcss": "^4.1.16",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"tsdown": "^0.22.14",
|
||||
"tsc-alias": "^1.8.16",
|
||||
"tsup": "^8.5.0",
|
||||
"tsx": "^4.20.6",
|
||||
"uuid": "^13.0.0",
|
||||
"vite": "^8.0.16",
|
||||
"vite-plugin-circular-dependency": "^0.6.0",
|
||||
"vitest": "4.1.10",
|
||||
"vite": "^7.1.12",
|
||||
"vite-plugin-circular-dependency": "^0.5.0",
|
||||
"vite-tsconfig-paths": "^5.1.4",
|
||||
"vitest": "3.0.9",
|
||||
"wouter": "^3.7.1",
|
||||
"wrangler": "^4.78.0"
|
||||
"wrangler": "^4.45.4"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@hono/node-server": "^1.19.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=19.2.6",
|
||||
"react-dom": ">=19.2.6"
|
||||
"react": ">=19",
|
||||
"react-dom": ">=19"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/types/index.d.mts",
|
||||
"types": "./dist/types/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/types/index.d.mts",
|
||||
"types": "./dist/types/index.d.ts",
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.js"
|
||||
},
|
||||
"./ui": {
|
||||
"types": "./dist/types/ui/index.d.mts",
|
||||
"types": "./dist/types/ui/index.d.ts",
|
||||
"import": "./dist/ui/index.js",
|
||||
"require": "./dist/ui/index.js"
|
||||
},
|
||||
"./elements": {
|
||||
"types": "./dist/types/ui/elements/index.d.mts",
|
||||
"types": "./dist/types/ui/elements/index.d.ts",
|
||||
"import": "./dist/ui/elements/index.js",
|
||||
"require": "./dist/ui/elements/index.js"
|
||||
},
|
||||
"./client": {
|
||||
"types": "./dist/types/ui/client/index.d.mts",
|
||||
"types": "./dist/types/ui/client/index.d.ts",
|
||||
"import": "./dist/ui/client/index.js",
|
||||
"require": "./dist/ui/client/index.js"
|
||||
},
|
||||
"./utils": {
|
||||
"types": "./dist/types/core/utils/index.d.mts",
|
||||
"types": "./dist/types/core/utils/index.d.ts",
|
||||
"import": "./dist/core/utils/index.js",
|
||||
"require": "./dist/core/utils/index.js"
|
||||
},
|
||||
"./cli": {
|
||||
"types": "./dist/types/cli/index.d.mts",
|
||||
"types": "./dist/types/cli/index.d.ts",
|
||||
"import": "./dist/cli/index.js",
|
||||
"require": "./dist/cli/index.js"
|
||||
},
|
||||
"./plugins": {
|
||||
"types": "./dist/types/plugins/index.d.mts",
|
||||
"types": "./dist/types/plugins/index.d.ts",
|
||||
"import": "./dist/plugins/index.js",
|
||||
"require": "./dist/plugins/index.js"
|
||||
},
|
||||
"./modes": {
|
||||
"types": "./dist/types/modes/index.d.mts",
|
||||
"types": "./dist/types/modes/index.d.ts",
|
||||
"import": "./dist/modes/index.js",
|
||||
"require": "./dist/modes/index.js"
|
||||
},
|
||||
"./adapter/sqlite": {
|
||||
"types": "./dist/types/adapter/sqlite/edge.d.mts",
|
||||
"types": "./dist/types/adapter/sqlite/edge.d.ts",
|
||||
"import": {
|
||||
"workerd": "./dist/adapter/sqlite/edge.js",
|
||||
"edge-light": "./dist/adapter/sqlite/edge.js",
|
||||
@@ -204,130 +204,107 @@
|
||||
"vercel": "./dist/adapter/sqlite/edge.js",
|
||||
"browser": "./dist/adapter/sqlite/edge.js",
|
||||
"bun": "./dist/adapter/sqlite/bun.js",
|
||||
"node": "./dist/adapter/sqlite/node.mjs",
|
||||
"default": "./dist/adapter/sqlite/node.mjs"
|
||||
"node": "./dist/adapter/sqlite/node.js",
|
||||
"default": "./dist/adapter/sqlite/node.js"
|
||||
},
|
||||
"require": "./dist/adapter/sqlite/node.mjs"
|
||||
"require": "./dist/adapter/sqlite/node.js"
|
||||
},
|
||||
"./adapter/cloudflare": {
|
||||
"types": "./dist/types/adapter/cloudflare/index.d.mts",
|
||||
"types": "./dist/types/adapter/cloudflare/index.d.ts",
|
||||
"import": "./dist/adapter/cloudflare/index.js",
|
||||
"require": "./dist/adapter/cloudflare/index.js"
|
||||
},
|
||||
"./adapter/cloudflare/proxy": {
|
||||
"types": "./dist/types/adapter/cloudflare/proxy.d.mts",
|
||||
"types": "./dist/types/adapter/cloudflare/proxy.d.ts",
|
||||
"import": "./dist/adapter/cloudflare/proxy.js",
|
||||
"require": "./dist/adapter/cloudflare/proxy.js"
|
||||
},
|
||||
"./adapter": {
|
||||
"types": "./dist/types/adapter/index.d.mts",
|
||||
"types": "./dist/types/adapter/index.d.ts",
|
||||
"import": "./dist/adapter/index.js"
|
||||
},
|
||||
"./adapter/vite": {
|
||||
"types": "./dist/types/adapter/vite/index.d.mts",
|
||||
"import": "./dist/adapter/vite/index.mjs",
|
||||
"require": "./dist/adapter/vite/index.mjs"
|
||||
"types": "./dist/types/adapter/vite/index.d.ts",
|
||||
"import": "./dist/adapter/vite/index.js",
|
||||
"require": "./dist/adapter/vite/index.js"
|
||||
},
|
||||
"./adapter/nextjs": {
|
||||
"types": "./dist/types/adapter/nextjs/index.d.mts",
|
||||
"import": "./dist/adapter/nextjs/index.mjs",
|
||||
"require": "./dist/adapter/nextjs/index.mjs"
|
||||
"types": "./dist/types/adapter/nextjs/index.d.ts",
|
||||
"import": "./dist/adapter/nextjs/index.js",
|
||||
"require": "./dist/adapter/nextjs/index.js"
|
||||
},
|
||||
"./adapter/nuxt": {
|
||||
"types": "./dist/types/adapter/nuxt/index.d.mts",
|
||||
"import": "./dist/adapter/nuxt/index.mjs",
|
||||
"require": "./dist/adapter/nuxt/index.mjs"
|
||||
"types": "./dist/types/adapter/nuxt/index.d.ts",
|
||||
"import": "./dist/adapter/nuxt/index.js",
|
||||
"require": "./dist/adapter/nuxt/index.js"
|
||||
},
|
||||
"./adapter/react-router": {
|
||||
"types": "./dist/types/adapter/react-router/index.d.mts",
|
||||
"types": "./dist/types/adapter/react-router/index.d.ts",
|
||||
"import": "./dist/adapter/react-router/index.js",
|
||||
"require": "./dist/adapter/react-router/index.js"
|
||||
},
|
||||
"./adapter/bun": {
|
||||
"types": "./dist/types/adapter/bun/index.d.mts",
|
||||
"types": "./dist/types/adapter/bun/index.d.ts",
|
||||
"import": "./dist/adapter/bun/index.js",
|
||||
"require": "./dist/adapter/bun/index.js"
|
||||
},
|
||||
"./adapter/node": {
|
||||
"types": "./dist/types/adapter/node/index.d.mts",
|
||||
"import": "./dist/adapter/node/index.mjs",
|
||||
"require": "./dist/adapter/node/index.mjs"
|
||||
"types": "./dist/types/adapter/node/index.d.ts",
|
||||
"import": "./dist/adapter/node/index.js",
|
||||
"require": "./dist/adapter/node/index.js"
|
||||
},
|
||||
"./adapter/astro": {
|
||||
"types": "./dist/types/adapter/astro/index.d.mts",
|
||||
"types": "./dist/types/adapter/astro/index.d.ts",
|
||||
"import": "./dist/adapter/astro/index.js",
|
||||
"require": "./dist/adapter/astro/index.js"
|
||||
},
|
||||
"./adapter/sveltekit": {
|
||||
"types": "./dist/types/adapter/sveltekit/index.d.mts",
|
||||
"import": "./dist/adapter/sveltekit/index.mjs",
|
||||
"require": "./dist/adapter/sveltekit/index.mjs"
|
||||
"types": "./dist/types/adapter/sveltekit/index.d.ts",
|
||||
"import": "./dist/adapter/sveltekit/index.js",
|
||||
"require": "./dist/adapter/sveltekit/index.js"
|
||||
},
|
||||
"./adapter/solid-start": {
|
||||
"types": "./dist/types/adapter/solid-start/index.d.ts",
|
||||
"import": "./dist/adapter/solid-start/index.js",
|
||||
"require": "./dist/adapter/solid-start/index.js"
|
||||
},
|
||||
"./adapter/aws": {
|
||||
"types": "./dist/types/adapter/aws/index.d.mts",
|
||||
"types": "./dist/types/adapter/aws/index.d.ts",
|
||||
"import": "./dist/adapter/aws/index.js",
|
||||
"require": "./dist/adapter/aws/index.js"
|
||||
},
|
||||
"./adapter/browser": {
|
||||
"types": "./dist/types/adapter/browser/index.d.mts",
|
||||
"types": "./dist/types/adapter/browser/index.d.ts",
|
||||
"import": "./dist/adapter/browser/index.js",
|
||||
"require": "./dist/adapter/browser/index.js"
|
||||
},
|
||||
"./adapter/tanstack-start": {
|
||||
"types": "./dist/types/adapter/tanstack-start/index.d.mts",
|
||||
"import": "./dist/adapter/tanstack-start/index.mjs",
|
||||
"require": "./dist/adapter/tanstack-start/index.mjs"
|
||||
"types": "./dist/types/adapter/tanstack-start/index.d.ts",
|
||||
"import": "./dist/adapter/tanstack-start/index.js",
|
||||
"require": "./dist/adapter/tanstack-start/index.js"
|
||||
},
|
||||
"./dist/main.css": "./dist/ui/style.css",
|
||||
"./dist/styles.css": "./dist/ui/style.css",
|
||||
"./dist/style.css": "./dist/ui/style.css",
|
||||
"./dist/main.css": "./dist/ui/main.css",
|
||||
"./dist/styles.css": "./dist/ui/styles.css",
|
||||
"./dist/manifest.json": "./dist/static/.vite/manifest.json",
|
||||
"./static/*": "./dist/static/*"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"utils": [
|
||||
"./dist/types/core/utils/index.d.mts"
|
||||
],
|
||||
"cli": [
|
||||
"./dist/types/cli/index.d.mts"
|
||||
],
|
||||
"plugins": [
|
||||
"./dist/types/plugins/index.d.mts"
|
||||
],
|
||||
"adapter": [
|
||||
"./dist/types/adapter/index.d.mts"
|
||||
],
|
||||
"adapter/cloudflare": [
|
||||
"./dist/types/adapter/cloudflare/index.d.mts"
|
||||
],
|
||||
"adapter/vite": [
|
||||
"./dist/types/adapter/vite/index.d.mts"
|
||||
],
|
||||
"adapter/nextjs": [
|
||||
"./dist/types/adapter/nextjs/index.d.mts"
|
||||
],
|
||||
"adapter/nuxt": [
|
||||
"./dist/types/adapter/nuxt/index.d.mts"
|
||||
],
|
||||
"adapter/react-router": [
|
||||
"./dist/types/adapter/react-router/index.d.mts"
|
||||
],
|
||||
"adapter/bun": [
|
||||
"./dist/types/adapter/bun/index.d.mts"
|
||||
],
|
||||
"adapter/node": [
|
||||
"./dist/types/adapter/node/index.d.mts"
|
||||
],
|
||||
"adapter/sveltekit": [
|
||||
"./dist/types/adapter/sveltekit/index.d.mts"
|
||||
],
|
||||
"adapter/tanstack-start": [
|
||||
"./dist/types/adapter/tanstack-start/index.d.mts"
|
||||
],
|
||||
"adapter/sqlite": [
|
||||
"./dist/types/adapter/sqlite/edge.d.mts"
|
||||
]
|
||||
"utils": ["./dist/types/core/utils/index.d.ts"],
|
||||
"cli": ["./dist/types/cli/index.d.ts"],
|
||||
"plugins": ["./dist/types/plugins/index.d.ts"],
|
||||
"adapter": ["./dist/types/adapter/index.d.ts"],
|
||||
"adapter/cloudflare": ["./dist/types/adapter/cloudflare/index.d.ts"],
|
||||
"adapter/vite": ["./dist/types/adapter/vite/index.d.ts"],
|
||||
"adapter/nextjs": ["./dist/types/adapter/nextjs/index.d.ts"],
|
||||
"adapter/nuxt": ["./dist/types/adapter/nuxt/index.d.ts"],
|
||||
"adapter/react-router": ["./dist/types/adapter/react-router/index.d.ts"],
|
||||
"adapter/bun": ["./dist/types/adapter/bun/index.d.ts"],
|
||||
"adapter/node": ["./dist/types/adapter/node/index.d.ts"],
|
||||
"adapter/sveltekit": ["./dist/types/adapter/sveltekit/index.d.ts"],
|
||||
"adapter/tanstack-start": ["./dist/types/adapter/tanstack-start/index.d.ts"],
|
||||
"adapter/solid-start": ["./dist/types/adapter/solid-start/index.d.ts"],
|
||||
"adapter/sqlite": ["./dist/types/adapter/sqlite/edge.d.ts"]
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
@@ -360,6 +337,7 @@
|
||||
"sveltekit",
|
||||
"svelte",
|
||||
"bun",
|
||||
"node"
|
||||
"node",
|
||||
"solid-start"
|
||||
]
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import type { SafeUser } from "bknd";
|
||||
import type { SafeUser } from "userbase";
|
||||
import { AuthApi, type AuthApiOptions } from "auth/api/AuthApi";
|
||||
import { DataApi, type DataApiOptions } from "data/api/DataApi";
|
||||
import { decode } from "hono/jwt";
|
||||
import { MediaApi, type MediaApiOptions } from "media/api/MediaApi";
|
||||
import { SystemApi } from "modules/SystemApi";
|
||||
import { omitKeys } from "bknd/utils";
|
||||
import { omitKeys } from "userbase/utils";
|
||||
import type { BaseModuleApiOptions } from "modules";
|
||||
|
||||
export type TApiUser = SafeUser;
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import type { CreateUserPayload } from "auth/AppAuth";
|
||||
import { $console, McpClient } from "bknd/utils";
|
||||
import { $console, McpClient } from "userbase/utils";
|
||||
import { Event } from "core/events";
|
||||
import type { em as prototypeEm } from "data/prototype";
|
||||
import { Connection } from "data/connection/Connection";
|
||||
@@ -346,7 +346,7 @@ export class App<
|
||||
|
||||
try {
|
||||
// gracefully add the app id
|
||||
c.res.headers.set("X-bknd-id", this._id);
|
||||
c.res.headers.set("X-userbase-id", this._id);
|
||||
} catch (e) {}
|
||||
|
||||
await this.emgr.emit(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { TestRunner } from "core/test";
|
||||
import type { BkndConfig, DefaultArgs } from "./index";
|
||||
import type { UserbaseConfig, DefaultArgs } from "./index";
|
||||
import type { App } from "App";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils/test";
|
||||
|
||||
export function adapterTestSuite<
|
||||
Config extends BkndConfig = BkndConfig,
|
||||
Config extends UserbaseConfig = UserbaseConfig,
|
||||
Args extends DefaultArgs = DefaultArgs,
|
||||
>(
|
||||
testRunner: TestRunner,
|
||||
@@ -39,7 +39,7 @@ export function adapterTestSuite<
|
||||
}),
|
||||
beforeBuild,
|
||||
onBuilt,
|
||||
} as const satisfies BkndConfig;
|
||||
} as const satisfies UserbaseConfig;
|
||||
|
||||
const app = await makeApp(
|
||||
config as any,
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { type FrameworkBkndConfig, createFrameworkApp } from "bknd/adapter";
|
||||
import { type FrameworkUserbaseConfig, createFrameworkApp } from "userbase/adapter";
|
||||
|
||||
type AstroEnv = NodeJS.ProcessEnv;
|
||||
type TAstro = {
|
||||
request: Request;
|
||||
};
|
||||
export type AstroBkndConfig<Env = AstroEnv> = FrameworkBkndConfig<Env>;
|
||||
export type AstroUserbaseConfig<Env = AstroEnv> = FrameworkUserbaseConfig<Env>;
|
||||
|
||||
export async function getApp<Env = AstroEnv>(
|
||||
config: AstroBkndConfig<Env> = {},
|
||||
config: AstroUserbaseConfig<Env> = {},
|
||||
args: Env = import.meta.env as Env,
|
||||
) {
|
||||
return await createFrameworkApp(config, args);
|
||||
}
|
||||
|
||||
export function serve<Env = AstroEnv>(
|
||||
config: AstroBkndConfig<Env> = {},
|
||||
config: AstroUserbaseConfig<Env> = {},
|
||||
args: Env = import.meta.env as Env,
|
||||
) {
|
||||
return async (fnArgs: TAstro) => {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { App } from "bknd";
|
||||
import type { App } from "userbase";
|
||||
import { handle } from "hono/aws-lambda";
|
||||
import { serveStatic } from "@hono/node-server/serve-static";
|
||||
import { type RuntimeBkndConfig, createRuntimeApp } from "bknd/adapter";
|
||||
import { type RuntimeUserbaseConfig, createRuntimeApp } from "userbase/adapter";
|
||||
|
||||
type AwsLambdaEnv = object;
|
||||
export type AwsLambdaBkndConfig<Env extends AwsLambdaEnv = AwsLambdaEnv> =
|
||||
RuntimeBkndConfig<Env> & {
|
||||
export type AwsLambdaUserbaseConfig<Env extends AwsLambdaEnv = AwsLambdaEnv> =
|
||||
RuntimeUserbaseConfig<Env> & {
|
||||
assets?:
|
||||
| {
|
||||
mode: "local";
|
||||
@@ -18,10 +18,10 @@ export type AwsLambdaBkndConfig<Env extends AwsLambdaEnv = AwsLambdaEnv> =
|
||||
};
|
||||
|
||||
export async function createApp<Env extends AwsLambdaEnv = AwsLambdaEnv>(
|
||||
{ adminOptions = false, assets, ...config }: AwsLambdaBkndConfig<Env> = {},
|
||||
{ adminOptions = false, assets, ...config }: AwsLambdaUserbaseConfig<Env> = {},
|
||||
args: Env = {} as Env,
|
||||
): Promise<App> {
|
||||
let additional: Partial<RuntimeBkndConfig> = {
|
||||
let additional: Partial<RuntimeUserbaseConfig> = {
|
||||
adminOptions,
|
||||
};
|
||||
|
||||
@@ -60,7 +60,7 @@ export async function createApp<Env extends AwsLambdaEnv = AwsLambdaEnv>(
|
||||
}
|
||||
|
||||
export function serve<Env extends AwsLambdaEnv = AwsLambdaEnv>(
|
||||
config: AwsLambdaBkndConfig<Env> = {},
|
||||
config: AwsLambdaUserbaseConfig<Env> = {},
|
||||
args: Env = {} as Env,
|
||||
) {
|
||||
return async (event) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { FileBody, FileListObject, FileMeta, FileUploadPayload } from "bknd";
|
||||
import { StorageAdapter, guessMimeType } from "bknd";
|
||||
import { parse, s, isFile, isBlob } from "bknd/utils";
|
||||
import type { FileBody, FileListObject, FileMeta, FileUploadPayload } from "userbase";
|
||||
import { StorageAdapter, guessMimeType } from "userbase";
|
||||
import { parse, s, isFile, isBlob } from "userbase/utils";
|
||||
|
||||
export const opfsAdapterConfig = s.object(
|
||||
{
|
||||
|
||||
+19
-19
@@ -7,20 +7,20 @@ import {
|
||||
useState,
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
import { checksum } from "bknd/utils";
|
||||
import { App, registries, sqlocal, type BkndConfig } from "bknd";
|
||||
import { checksum } from "userbase/utils";
|
||||
import { App, registries, sqlocal, type UserbaseConfig } from "userbase";
|
||||
import { Route, Router, Switch } from "wouter";
|
||||
import { ClientProvider } from "bknd/client";
|
||||
import { ClientProvider } from "userbase/client";
|
||||
import { SQLocalKysely } from "sqlocal/kysely";
|
||||
import type { ClientConfig, DatabasePath } from "sqlocal";
|
||||
import { OpfsStorageAdapter } from "bknd/adapter/browser";
|
||||
import type { BkndAdminConfig } from "bknd/ui";
|
||||
import { OpfsStorageAdapter } from "userbase/adapter/browser";
|
||||
import type { UserbaseAdminConfig } from "userbase/ui";
|
||||
|
||||
const Admin = lazy(() =>
|
||||
Promise.all([
|
||||
import("bknd/ui"),
|
||||
import("userbase/ui"),
|
||||
// @ts-ignore
|
||||
import("bknd/dist/styles.css"),
|
||||
import("userbase/dist/styles.css"),
|
||||
]).then(([mod]) => ({
|
||||
default: mod.Admin,
|
||||
})),
|
||||
@@ -34,34 +34,34 @@ function safeViewTransition(fn: () => void) {
|
||||
}
|
||||
}
|
||||
|
||||
export type BrowserBkndConfig<Args = ImportMetaEnv> = Omit<
|
||||
BkndConfig<Args>,
|
||||
export type BrowserUserbaseConfig<Args = ImportMetaEnv> = Omit<
|
||||
UserbaseConfig<Args>,
|
||||
"connection" | "app"
|
||||
> & {
|
||||
adminConfig?: BkndAdminConfig;
|
||||
adminConfig?: UserbaseAdminConfig;
|
||||
connection?: ClientConfig | DatabasePath;
|
||||
};
|
||||
|
||||
export type BkndBrowserAppProps = {
|
||||
export type UserbaseBrowserAppProps = {
|
||||
children: ReactNode;
|
||||
header?: ReactNode;
|
||||
loading?: ReactNode;
|
||||
notFound?: ReactNode;
|
||||
} & BrowserBkndConfig;
|
||||
} & BrowserUserbaseConfig;
|
||||
|
||||
const BkndBrowserAppContext = createContext<{
|
||||
const UserbaseBrowserAppContext = createContext<{
|
||||
app: App;
|
||||
hash: string;
|
||||
}>(undefined!);
|
||||
|
||||
export function BkndBrowserApp({
|
||||
export function UserbaseBrowserApp({
|
||||
children,
|
||||
adminConfig,
|
||||
header,
|
||||
loading,
|
||||
notFound,
|
||||
...config
|
||||
}: BkndBrowserAppProps) {
|
||||
}: UserbaseBrowserAppProps) {
|
||||
const [app, setApp] = useState<App | undefined>(undefined);
|
||||
const [hash, setHash] = useState<string>("");
|
||||
const adminRoutePath = (adminConfig?.basepath ?? "") + "/*?";
|
||||
@@ -90,7 +90,7 @@ export function BkndBrowserApp({
|
||||
}
|
||||
|
||||
return (
|
||||
<BkndBrowserAppContext.Provider value={{ app, hash }}>
|
||||
<UserbaseBrowserAppContext.Provider value={{ app, hash }}>
|
||||
<ClientProvider storage={window.localStorage} fetcher={app.server.request}>
|
||||
{header}
|
||||
<Router key={hash}>
|
||||
@@ -110,12 +110,12 @@ export function BkndBrowserApp({
|
||||
</Switch>
|
||||
</Router>
|
||||
</ClientProvider>
|
||||
</BkndBrowserAppContext.Provider>
|
||||
</UserbaseBrowserAppContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useApp() {
|
||||
return useContext(BkndBrowserAppContext);
|
||||
return useContext(UserbaseBrowserAppContext);
|
||||
}
|
||||
|
||||
const Center = (props: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
@@ -133,7 +133,7 @@ const Center = (props: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
);
|
||||
|
||||
let initialized = false;
|
||||
async function setup(config: BrowserBkndConfig = {}) {
|
||||
async function setup(config: BrowserUserbaseConfig = {}) {
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export * from "./OpfsStorageAdapter";
|
||||
export * from "./BkndBrowserApp";
|
||||
export * from "./UserbaseBrowserApp";
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import path from "node:path";
|
||||
import { type RuntimeBkndConfig, createRuntimeApp } from "bknd/adapter";
|
||||
import { type RuntimeUserbaseConfig, createRuntimeApp } from "userbase/adapter";
|
||||
import { registerLocalMediaAdapter } from ".";
|
||||
import { config, type App } from "bknd";
|
||||
import { config, type App } from "userbase";
|
||||
import { serveStatic } from "hono/bun";
|
||||
|
||||
type BunEnv = Bun.Env;
|
||||
export type BunBkndConfig<Env = BunEnv> = RuntimeBkndConfig<Env> &
|
||||
export type BunUserbaseConfig<Env = BunEnv> = RuntimeUserbaseConfig<Env> &
|
||||
Omit<Bun.Serve.Options<undefined, string>, "fetch">;
|
||||
|
||||
export async function createApp<Env = BunEnv>(
|
||||
{ distPath, serveStatic: _serveStatic, ...config }: BunBkndConfig<Env> = {},
|
||||
{ distPath, serveStatic: _serveStatic, ...config }: BunUserbaseConfig<Env> = {},
|
||||
args: Env = Bun.env as Env,
|
||||
) {
|
||||
const root = path.resolve(distPath ?? "./node_modules/bknd/dist", "static");
|
||||
const root = path.resolve(distPath ?? "./node_modules/userbase/dist", "static");
|
||||
registerLocalMediaAdapter();
|
||||
|
||||
return await createRuntimeApp(
|
||||
@@ -29,7 +29,7 @@ export async function createApp<Env = BunEnv>(
|
||||
}
|
||||
|
||||
export function createHandler<Env = BunEnv>(
|
||||
config: BunBkndConfig<Env> = {},
|
||||
config: BunUserbaseConfig<Env> = {},
|
||||
args: Env = Bun.env as Env,
|
||||
) {
|
||||
let app: App | undefined;
|
||||
@@ -55,7 +55,7 @@ export function serve<Env = BunEnv>(
|
||||
serveStatic,
|
||||
beforeBuild,
|
||||
...serveOptions
|
||||
}: BunBkndConfig<Env> = {},
|
||||
}: BunUserbaseConfig<Env> = {},
|
||||
args: Env = Bun.env as Env,
|
||||
) {
|
||||
Bun.serve({
|
||||
|
||||
@@ -3,8 +3,8 @@ import {
|
||||
genericSqlite,
|
||||
type GenericSqliteConnection,
|
||||
type GenericSqliteConnectionConfig,
|
||||
} from "bknd";
|
||||
import { omitKeys } from "bknd/utils";
|
||||
} from "userbase";
|
||||
import { omitKeys } from "userbase/utils";
|
||||
|
||||
export type BunSqliteConnection = GenericSqliteConnection<Database>;
|
||||
export type BunSqliteConnectionConfig = Omit<
|
||||
|
||||
@@ -3,7 +3,7 @@ import { makeConfig, type CloudflareContext } from "./config";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
||||
import { adapterTestSuite } from "adapter/adapter-test-suite";
|
||||
import { bunTestRunner } from "adapter/bun/test";
|
||||
import { type CloudflareBkndConfig, createApp } from "./cloudflare-workers.adapter";
|
||||
import { type CloudflareUserbaseConfig, createApp } from "./cloudflare-workers.adapter";
|
||||
|
||||
beforeAll(disableConsoleLog);
|
||||
afterAll(enableConsoleLog);
|
||||
@@ -40,7 +40,7 @@ describe("cf adapter", () => {
|
||||
expect(dynamicConfig.connection).toBeDefined();
|
||||
});
|
||||
|
||||
adapterTestSuite<CloudflareBkndConfig, CloudflareContext<any>>(bunTestRunner, {
|
||||
adapterTestSuite<CloudflareUserbaseConfig, CloudflareContext<any>>(bunTestRunner, {
|
||||
makeApp: async (c, a) => {
|
||||
return await createApp(c, { env: a } as any);
|
||||
},
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
/// <reference types="@cloudflare/workers-types" />
|
||||
|
||||
import type { RuntimeBkndConfig } from "bknd/adapter";
|
||||
import type { RuntimeUserbaseConfig } from "userbase/adapter";
|
||||
import { Hono } from "hono";
|
||||
import { serveStatic } from "hono/cloudflare-workers";
|
||||
import type { App, MaybePromise } from "bknd";
|
||||
import { $console } from "bknd/utils";
|
||||
import { createRuntimeApp } from "bknd/adapter";
|
||||
import type { App, MaybePromise } from "userbase";
|
||||
import { $console } from "userbase/utils";
|
||||
import { createRuntimeApp } from "userbase/adapter";
|
||||
import { registerAsyncsExecutionContext, makeConfig, type CloudflareContext } from "./config";
|
||||
|
||||
// Statically import the admin UI build manifest so the bundler (wrangler/esbuild)
|
||||
// resolves and bundles it at build time, rather than leaving a runtime dynamic
|
||||
// import that workerd cannot resolve via package.json exports maps.
|
||||
// @ts-ignore
|
||||
import adminUiManifest from "bknd/dist/manifest.json";
|
||||
|
||||
declare global {
|
||||
namespace Cloudflare {
|
||||
interface Env {}
|
||||
@@ -21,7 +15,7 @@ declare global {
|
||||
}
|
||||
|
||||
export type CloudflareEnv = Cloudflare.Env;
|
||||
export type CloudflareBkndConfig<Env = CloudflareEnv> = RuntimeBkndConfig<Env> & {
|
||||
export type CloudflareUserbaseConfig<Env = CloudflareEnv> = RuntimeUserbaseConfig<Env> & {
|
||||
bindings?: (args: Env) => MaybePromise<{
|
||||
kv?: KVNamespace;
|
||||
db?: D1Database;
|
||||
@@ -40,23 +34,10 @@ export type CloudflareBkndConfig<Env = CloudflareEnv> = RuntimeBkndConfig<Env> &
|
||||
};
|
||||
|
||||
export async function createApp<Env extends CloudflareEnv = CloudflareEnv>(
|
||||
config: CloudflareBkndConfig<Env> = {},
|
||||
config: CloudflareUserbaseConfig<Env> = {},
|
||||
ctx: Partial<CloudflareContext<Env>> = {},
|
||||
) {
|
||||
const appConfig = await makeConfig(config, ctx);
|
||||
|
||||
// The AdminController can't dynamically import "bknd/dist/manifest.json"
|
||||
// at runtime in the Workers runtime (workerd ignores package.json exports
|
||||
// for runtime imports). Statically import it here so esbuild bundles the
|
||||
// manifest into the Worker and pass it as the admin controller's manifest
|
||||
// unless the caller explicitly provides one (or disables the admin).
|
||||
if (appConfig.adminOptions !== false && !(appConfig.adminOptions as any)?.manifest) {
|
||||
appConfig.adminOptions = {
|
||||
...(appConfig.adminOptions as any),
|
||||
manifest: adminUiManifest,
|
||||
};
|
||||
}
|
||||
|
||||
return await createRuntimeApp<Env>(
|
||||
{
|
||||
...appConfig,
|
||||
@@ -76,7 +57,7 @@ export const getFresh = createApp;
|
||||
|
||||
let app: App | undefined;
|
||||
export function serve<Env extends CloudflareEnv = CloudflareEnv>(
|
||||
config: CloudflareBkndConfig<Env> = {},
|
||||
config: CloudflareUserbaseConfig<Env> = {},
|
||||
serveOptions?: (args: Env) => {
|
||||
warm?: boolean;
|
||||
},
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
|
||||
/// <reference types="@cloudflare/workers-types" />
|
||||
|
||||
import { Connection } from "bknd";
|
||||
import { sqlite } from "bknd/adapter/sqlite";
|
||||
import { makeConfig as makeAdapterConfig } from "bknd/adapter";
|
||||
import { Connection } from "userbase";
|
||||
import { sqlite } from "userbase/adapter/sqlite";
|
||||
import { makeConfig as makeAdapterConfig } from "userbase/adapter";
|
||||
import { registerMedia } from "./storage/StorageR2Adapter";
|
||||
import { getBinding } from "./bindings";
|
||||
import { d1Sqlite } from "./connection/D1Connection";
|
||||
import type { CloudflareBkndConfig, CloudflareEnv } from ".";
|
||||
import { App } from "bknd";
|
||||
import type { CloudflareUserbaseConfig, CloudflareEnv } from ".";
|
||||
import { App } from "userbase";
|
||||
import type { Context as HonoContext, ExecutionContext } from "hono";
|
||||
import { $console } from "bknd/utils";
|
||||
import { $console } from "userbase/utils";
|
||||
import { setCookie } from "hono/cookie";
|
||||
|
||||
export const constants = {
|
||||
exec_async_event_id: "cf_register_waituntil",
|
||||
cache_endpoint: "/__bknd/cache",
|
||||
do_endpoint: "/__bknd/do",
|
||||
cache_endpoint: "/__userbase/cache",
|
||||
do_endpoint: "/__userbase/do",
|
||||
d1_session: {
|
||||
cookie: "cf_d1_session",
|
||||
header: "x-cf-d1-session",
|
||||
@@ -40,7 +41,7 @@ function getCookieValue(cookies: string | null, name: string) {
|
||||
return null;
|
||||
}
|
||||
|
||||
export function d1SessionHelper(config: CloudflareBkndConfig<any>) {
|
||||
export function d1SessionHelper(config: CloudflareUserbaseConfig<any>) {
|
||||
const headerKey = constants.d1_session.header;
|
||||
const cookieKey = constants.d1_session.cookie;
|
||||
const transport = config.d1?.transport;
|
||||
@@ -90,7 +91,7 @@ export function d1SessionHelper(config: CloudflareBkndConfig<any>) {
|
||||
|
||||
let media_registered: boolean = false;
|
||||
export async function makeConfig<Env extends CloudflareEnv = CloudflareEnv>(
|
||||
config: CloudflareBkndConfig<Env>,
|
||||
config: CloudflareUserbaseConfig<Env>,
|
||||
args?: Partial<CloudflareContext<Env>>,
|
||||
) {
|
||||
if (!media_registered && config.registerMedia !== false) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/// <reference types="@cloudflare/workers-types" />
|
||||
|
||||
import { genericSqlite, type GenericSqliteConnection } from "bknd";
|
||||
import { genericSqlite, type GenericSqliteConnection } from "userbase";
|
||||
import type { QueryResult } from "kysely";
|
||||
|
||||
export type D1SqliteConnection = GenericSqliteConnection<D1Database>;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/// <reference types="@cloudflare/workers-types" />
|
||||
|
||||
import { genericSqlite, type GenericSqliteConnection } from "bknd";
|
||||
import { genericSqlite, type GenericSqliteConnection } from "userbase";
|
||||
import type { QueryResult } from "kysely";
|
||||
|
||||
export type DoSqliteConnection = GenericSqliteConnection<DurableObjectState["storage"]["sql"]>;
|
||||
|
||||
@@ -5,7 +5,7 @@ export {
|
||||
createApp,
|
||||
serve,
|
||||
type CloudflareEnv,
|
||||
type CloudflareBkndConfig,
|
||||
type CloudflareUserbaseConfig,
|
||||
} from "./cloudflare-workers.adapter";
|
||||
export { d1Sqlite, type D1ConnectionConfig };
|
||||
export { doSqlite, type DoConnectionConfig } from "./connection/DoConnection";
|
||||
@@ -18,7 +18,7 @@ export {
|
||||
} from "./bindings";
|
||||
export { constants, makeConfig, type CloudflareContext } from "./config";
|
||||
export { StorageR2Adapter, registerMedia } from "./storage/StorageR2Adapter";
|
||||
export { registries } from "bknd";
|
||||
export { registries } from "userbase";
|
||||
export { devFsVitePlugin, devFsWrite } from "./vite";
|
||||
|
||||
// for compatibility with old code
|
||||
|
||||
@@ -2,12 +2,12 @@ import {
|
||||
d1Sqlite,
|
||||
getBinding,
|
||||
registerMedia,
|
||||
type CloudflareBkndConfig,
|
||||
type CloudflareUserbaseConfig,
|
||||
type CloudflareEnv,
|
||||
} from "bknd/adapter/cloudflare";
|
||||
} from "userbase/adapter/cloudflare";
|
||||
import type { GetPlatformProxyOptions, PlatformProxy } from "wrangler";
|
||||
import process from "node:process";
|
||||
import { $console } from "bknd/utils";
|
||||
import { $console } from "userbase/utils";
|
||||
|
||||
export type WithPlatformProxyOptions = {
|
||||
/**
|
||||
@@ -42,7 +42,7 @@ async function getPlatformProxy(opts?: GetPlatformProxyOptions) {
|
||||
}
|
||||
|
||||
export function withPlatformProxy<Env extends CloudflareEnv>(
|
||||
config: CloudflareBkndConfig<Env> = {},
|
||||
config: CloudflareUserbaseConfig<Env> = {},
|
||||
opts?: WithPlatformProxyOptions,
|
||||
) {
|
||||
const use_proxy =
|
||||
@@ -91,5 +91,5 @@ export function withPlatformProxy<Env extends CloudflareEnv>(
|
||||
connection,
|
||||
};
|
||||
},
|
||||
} satisfies CloudflareBkndConfig<Env>;
|
||||
} satisfies CloudflareUserbaseConfig<Env>;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { registries as $registries, isDebug, guessMimeType } from "bknd";
|
||||
import { registries as $registries, isDebug, guessMimeType } from "userbase";
|
||||
import { getBindings } from "../bindings";
|
||||
import { s } from "bknd/utils";
|
||||
import { StorageAdapter, type FileBody } from "bknd";
|
||||
import { s } from "userbase/utils";
|
||||
import { StorageAdapter, type FileBody } from "userbase";
|
||||
|
||||
export function makeSchema(bindings: string[] = []) {
|
||||
return s.object(
|
||||
|
||||
@@ -8,7 +8,7 @@ import { resolve } from "node:path";
|
||||
*/
|
||||
export function devFsVitePlugin({
|
||||
verbose = false,
|
||||
configFile = "bknd.config.ts",
|
||||
configFile = "userbase.config.ts",
|
||||
}: {
|
||||
verbose?: boolean;
|
||||
configFile?: string;
|
||||
@@ -195,7 +195,7 @@ export function devFsVitePlugin({
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is the bknd config file
|
||||
// Check if this is the userbase config file
|
||||
if (id.includes(configFile)) {
|
||||
if (verbose) {
|
||||
console.debug("[dev-fs-plugin] Transforming", configFile);
|
||||
|
||||
+16
-16
@@ -7,27 +7,27 @@ import {
|
||||
type MaybePromise,
|
||||
registries as $registries,
|
||||
type Merge,
|
||||
} from "bknd";
|
||||
import { $console } from "bknd/utils";
|
||||
} from "userbase";
|
||||
import { $console } from "userbase/utils";
|
||||
import type { Context, MiddlewareHandler, Next } from "hono";
|
||||
import type { AdminControllerOptions } from "modules/server/AdminController";
|
||||
import type { Manifest } from "vite";
|
||||
|
||||
export type BkndConfig<Args = any, Additional = {}> = Merge<
|
||||
export type UserbaseConfig<Args = any, Additional = {}> = Merge<
|
||||
CreateAppConfig &
|
||||
Omit<Additional, "app"> & {
|
||||
app?:
|
||||
| Omit<BkndConfig<Args, Additional>, "app">
|
||||
| ((args: Args) => MaybePromise<Omit<BkndConfig<Args, Additional>, "app">>);
|
||||
| Omit<UserbaseConfig<Args, Additional>, "app">
|
||||
| ((args: Args) => MaybePromise<Omit<UserbaseConfig<Args, Additional>, "app">>);
|
||||
onBuilt?: (app: App) => MaybePromise<void>;
|
||||
beforeBuild?: (app?: App, registries?: typeof $registries) => MaybePromise<void>;
|
||||
buildConfig?: Parameters<App["build"]>[0];
|
||||
}
|
||||
>;
|
||||
|
||||
export type FrameworkBkndConfig<Args = any> = BkndConfig<Args>;
|
||||
export type FrameworkUserbaseConfig<Args = any> = UserbaseConfig<Args>;
|
||||
|
||||
export type RuntimeBkndConfig<Args = any> = BkndConfig<Args> & {
|
||||
export type RuntimeUserbaseConfig<Args = any> = UserbaseConfig<Args> & {
|
||||
distPath?: string;
|
||||
serveStatic?: MiddlewareHandler | [string, MiddlewareHandler];
|
||||
adminOptions?: AdminControllerOptions | false;
|
||||
@@ -38,9 +38,9 @@ export type DefaultArgs = {
|
||||
};
|
||||
|
||||
export async function makeConfig<Args = DefaultArgs>(
|
||||
config: BkndConfig<Args>,
|
||||
config: UserbaseConfig<Args>,
|
||||
args?: Args,
|
||||
): Promise<Omit<BkndConfig<Args>, "app">> {
|
||||
): Promise<Omit<UserbaseConfig<Args>, "app">> {
|
||||
let additionalConfig: CreateAppConfig = {};
|
||||
const { app, ...rest } = config;
|
||||
if (app) {
|
||||
@@ -57,10 +57,10 @@ export async function makeConfig<Args = DefaultArgs>(
|
||||
return { ...rest, ...additionalConfig };
|
||||
}
|
||||
|
||||
export async function createAdapterApp<Config extends BkndConfig = BkndConfig, Args = DefaultArgs>(
|
||||
export async function createAdapterApp<Config extends UserbaseConfig = UserbaseConfig, Args = DefaultArgs>(
|
||||
config: Config = {} as Config,
|
||||
args?: Args,
|
||||
): Promise<{ app: App; config: BkndConfig<Args> }> {
|
||||
): Promise<{ app: App; config: UserbaseConfig<Args> }> {
|
||||
await config.beforeBuild?.(undefined, $registries);
|
||||
|
||||
const appConfig = await makeConfig(config, args);
|
||||
@@ -69,7 +69,7 @@ export async function createAdapterApp<Config extends BkndConfig = BkndConfig, A
|
||||
if (Connection.isConnection(config.connection)) {
|
||||
connection = config.connection;
|
||||
} else {
|
||||
const sqlite = (await import("bknd/adapter/sqlite")).sqlite;
|
||||
const sqlite = (await import("userbase/adapter/sqlite")).sqlite;
|
||||
const conf = appConfig.connection ?? { url: "file:data.db" };
|
||||
connection = sqlite(conf) as any;
|
||||
$console.info(`Using ${connection!.name} connection`, conf.url);
|
||||
@@ -84,7 +84,7 @@ export async function createAdapterApp<Config extends BkndConfig = BkndConfig, A
|
||||
}
|
||||
|
||||
export async function createFrameworkApp<Args = DefaultArgs>(
|
||||
config: FrameworkBkndConfig = {},
|
||||
config: FrameworkUserbaseConfig = {},
|
||||
args?: Args,
|
||||
): Promise<App> {
|
||||
const { app, config: appConfig } = await createAdapterApp(config, args);
|
||||
@@ -108,7 +108,7 @@ export async function createFrameworkApp<Args = DefaultArgs>(
|
||||
}
|
||||
|
||||
export async function createRuntimeApp<Args = DefaultArgs>(
|
||||
{ serveStatic, adminOptions, ...config }: RuntimeBkndConfig<Args> = {},
|
||||
{ serveStatic, adminOptions, ...config }: RuntimeUserbaseConfig<Args> = {},
|
||||
args?: Args,
|
||||
): Promise<App> {
|
||||
const { app, config: appConfig } = await createAdapterApp(config, args);
|
||||
@@ -148,7 +148,7 @@ export async function createRuntimeApp<Args = DefaultArgs>(
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { serveStaticViaImport } from "bknd/adapter";
|
||||
* import { serveStaticViaImport } from "userbase/adapter";
|
||||
*
|
||||
* serve({
|
||||
* serveStatic: serveStaticViaImport(),
|
||||
@@ -161,7 +161,7 @@ export function serveStaticViaImport(opts?: {
|
||||
package?: string;
|
||||
}) {
|
||||
let files: string[] | undefined;
|
||||
const pkg = opts?.package ?? "bknd";
|
||||
const pkg = opts?.package ?? "userbase";
|
||||
|
||||
// @ts-ignore
|
||||
return async (c: Context, next: Next) => {
|
||||
|
||||
@@ -3,13 +3,13 @@ import * as nextjs from "./nextjs.adapter";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
||||
import { adapterTestSuite } from "adapter/adapter-test-suite";
|
||||
import { bunTestRunner } from "adapter/bun/test";
|
||||
import type { NextjsBkndConfig } from "./nextjs.adapter";
|
||||
import type { NextjsUserbaseConfig } from "./nextjs.adapter";
|
||||
|
||||
beforeAll(disableConsoleLog);
|
||||
afterAll(enableConsoleLog);
|
||||
|
||||
describe("nextjs adapter", () => {
|
||||
adapterTestSuite<NextjsBkndConfig>(bunTestRunner, {
|
||||
adapterTestSuite<NextjsUserbaseConfig>(bunTestRunner, {
|
||||
makeApp: nextjs.getApp,
|
||||
makeHandler: nextjs.serve,
|
||||
});
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import { createFrameworkApp, type FrameworkBkndConfig } from "bknd/adapter";
|
||||
import { isNode } from "bknd/utils";
|
||||
import { createFrameworkApp, type FrameworkUserbaseConfig } from "userbase/adapter";
|
||||
import { isNode } from "userbase/utils";
|
||||
// @ts-expect-error next is not installed
|
||||
import type { NextApiRequest } from "next";
|
||||
|
||||
type NextjsEnv = NextApiRequest["env"];
|
||||
export type NextjsBkndConfig<Env = NextjsEnv> = FrameworkBkndConfig<Env> & {
|
||||
export type NextjsUserbaseConfig<Env = NextjsEnv> = FrameworkUserbaseConfig<Env> & {
|
||||
cleanRequest?: { searchParams?: string[] };
|
||||
};
|
||||
|
||||
export async function getApp<Env = NextjsEnv>(
|
||||
config: NextjsBkndConfig<Env>,
|
||||
config: NextjsUserbaseConfig<Env>,
|
||||
args: Env = process.env as Env,
|
||||
) {
|
||||
return await createFrameworkApp(config, args);
|
||||
}
|
||||
|
||||
function getCleanRequest(req: Request, cleanRequest: NextjsBkndConfig["cleanRequest"]) {
|
||||
function getCleanRequest(req: Request, cleanRequest: NextjsUserbaseConfig["cleanRequest"]) {
|
||||
if (!cleanRequest) return req;
|
||||
|
||||
const url = new URL(req.url);
|
||||
@@ -41,7 +41,7 @@ function getCleanRequest(req: Request, cleanRequest: NextjsBkndConfig["cleanRequ
|
||||
}
|
||||
|
||||
export function serve<Env = NextjsEnv>(
|
||||
{ cleanRequest, ...config }: NextjsBkndConfig<Env> = {},
|
||||
{ cleanRequest, ...config }: NextjsUserbaseConfig<Env> = {},
|
||||
args: Env = process.env as Env,
|
||||
) {
|
||||
return async (req: Request) => {
|
||||
|
||||
@@ -2,9 +2,9 @@ import {
|
||||
genericSqlite,
|
||||
type GenericSqliteConnection,
|
||||
type GenericSqliteConnectionConfig,
|
||||
} from "bknd";
|
||||
} from "userbase";
|
||||
import { DatabaseSync } from "node:sqlite";
|
||||
import { omitKeys } from "bknd/utils";
|
||||
import { omitKeys } from "userbase/utils";
|
||||
|
||||
export type NodeSqliteConnection = GenericSqliteConnection<DatabaseSync>;
|
||||
export type NodeSqliteConnectionConfig = Omit<
|
||||
|
||||
@@ -2,12 +2,12 @@ import path from "node:path";
|
||||
import { serve as honoServe } from "@hono/node-server";
|
||||
import { serveStatic } from "@hono/node-server/serve-static";
|
||||
import { registerLocalMediaAdapter } from "adapter/node/storage";
|
||||
import { type RuntimeBkndConfig, createRuntimeApp } from "bknd/adapter";
|
||||
import { config as $config, type App } from "bknd";
|
||||
import { $console } from "bknd/utils";
|
||||
import { type RuntimeUserbaseConfig, createRuntimeApp } from "userbase/adapter";
|
||||
import { config as $config, type App } from "userbase";
|
||||
import { $console } from "userbase/utils";
|
||||
|
||||
type NodeEnv = NodeJS.ProcessEnv;
|
||||
export type NodeBkndConfig<Env = NodeEnv> = RuntimeBkndConfig<Env> & {
|
||||
export type NodeUserbaseConfig<Env = NodeEnv> = RuntimeUserbaseConfig<Env> & {
|
||||
port?: number;
|
||||
hostname?: string;
|
||||
listener?: Parameters<typeof honoServe>[1];
|
||||
@@ -16,12 +16,12 @@ export type NodeBkndConfig<Env = NodeEnv> = RuntimeBkndConfig<Env> & {
|
||||
};
|
||||
|
||||
export async function createApp<Env = NodeEnv>(
|
||||
{ distPath, relativeDistPath, ...config }: NodeBkndConfig<Env> = {},
|
||||
{ distPath, relativeDistPath, ...config }: NodeUserbaseConfig<Env> = {},
|
||||
args: Env = process.env as Env,
|
||||
) {
|
||||
const root = path.relative(
|
||||
process.cwd(),
|
||||
path.resolve(distPath ?? relativeDistPath ?? "./node_modules/bknd/dist", "static"),
|
||||
path.resolve(distPath ?? relativeDistPath ?? "./node_modules/userbase/dist", "static"),
|
||||
);
|
||||
if (relativeDistPath) {
|
||||
$console.warn("relativeDistPath is deprecated, please use distPath instead");
|
||||
@@ -38,7 +38,7 @@ export async function createApp<Env = NodeEnv>(
|
||||
}
|
||||
|
||||
export function createHandler<Env = NodeEnv>(
|
||||
config: NodeBkndConfig<Env> = {},
|
||||
config: NodeUserbaseConfig<Env> = {},
|
||||
args: Env = process.env as Env,
|
||||
) {
|
||||
let app: App | undefined;
|
||||
@@ -51,7 +51,7 @@ export function createHandler<Env = NodeEnv>(
|
||||
}
|
||||
|
||||
export function serve<Env = NodeEnv>(
|
||||
{ port = $config.server.default_port, hostname, listener, ...config }: NodeBkndConfig<Env> = {},
|
||||
{ port = $config.server.default_port, hostname, listener, ...config }: NodeUserbaseConfig<Env> = {},
|
||||
args: Env = process.env as Env,
|
||||
) {
|
||||
honoServe(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { readFile, readdir, stat, unlink, writeFile } from "node:fs/promises";
|
||||
import type { FileBody, FileListObject, FileMeta, FileUploadPayload } from "bknd";
|
||||
import { StorageAdapter, guessMimeType } from "bknd";
|
||||
import { parse, s, isFile } from "bknd/utils";
|
||||
import type { FileBody, FileListObject, FileMeta, FileUploadPayload } from "userbase";
|
||||
import { StorageAdapter, guessMimeType } from "userbase";
|
||||
import { parse, s, isFile } from "userbase/utils";
|
||||
|
||||
export const localAdapterConfig = s.object(
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { registries } from "bknd";
|
||||
import { registries } from "userbase";
|
||||
import { type LocalAdapterConfig, StorageLocalAdapter } from "./StorageLocalAdapter";
|
||||
|
||||
export * from "./StorageLocalAdapter";
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { createRuntimeApp, type RuntimeBkndConfig } from "bknd/adapter";
|
||||
import { createRuntimeApp, type RuntimeUserbaseConfig } from "userbase/adapter";
|
||||
|
||||
export type NuxtEnv = NodeJS.ProcessEnv;
|
||||
export type NuxtBkndConfig<Env = NuxtEnv> = RuntimeBkndConfig<Env>;
|
||||
export type NuxtUserbaseConfig<Env = NuxtEnv> = RuntimeUserbaseConfig<Env>;
|
||||
|
||||
/**
|
||||
* Get bknd app instance
|
||||
* @param config - bknd configuration
|
||||
* Get userbase app instance
|
||||
* @param config - userbase configuration
|
||||
* @param args - environment variables
|
||||
*/
|
||||
export async function getApp<Env>(
|
||||
config: NuxtBkndConfig<Env> = {} as NuxtBkndConfig<Env>,
|
||||
config: NuxtUserbaseConfig<Env> = {} as NuxtUserbaseConfig<Env>,
|
||||
args: Env,
|
||||
) {
|
||||
return await createRuntimeApp(config, args);
|
||||
@@ -17,13 +17,10 @@ export async function getApp<Env>(
|
||||
|
||||
/**
|
||||
* Create middleware handler for Nuxt
|
||||
* @param config - bknd configuration
|
||||
* @param config - userbase configuration
|
||||
* @param args - environment variables
|
||||
*/
|
||||
export function serve<Env>(
|
||||
config: NuxtBkndConfig<Env> = {} as NuxtBkndConfig<Env>,
|
||||
args: Env,
|
||||
) {
|
||||
export function serve<Env>(config: NuxtUserbaseConfig<Env> = {} as NuxtUserbaseConfig<Env>, args: Env) {
|
||||
return async (request: Request) => {
|
||||
return (await getApp(config, args)).fetch(request);
|
||||
};
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { type FrameworkBkndConfig, createFrameworkApp } from "bknd/adapter";
|
||||
import { type FrameworkUserbaseConfig, createFrameworkApp } from "userbase/adapter";
|
||||
|
||||
type ReactRouterEnv = NodeJS.ProcessEnv;
|
||||
type ReactRouterFunctionArgs = {
|
||||
request: Request;
|
||||
};
|
||||
export type ReactRouterBkndConfig<Env = ReactRouterEnv> = FrameworkBkndConfig<Env>;
|
||||
export type ReactRouterUserbaseConfig<Env = ReactRouterEnv> = FrameworkUserbaseConfig<Env>;
|
||||
|
||||
export async function getApp<Env = ReactRouterEnv>(
|
||||
config: ReactRouterBkndConfig<Env>,
|
||||
config: ReactRouterUserbaseConfig<Env>,
|
||||
args: Env = process.env as Env,
|
||||
) {
|
||||
return await createFrameworkApp(config, args);
|
||||
}
|
||||
|
||||
export function serve<Env = ReactRouterEnv>(
|
||||
config: ReactRouterBkndConfig<Env> = {},
|
||||
config: ReactRouterUserbaseConfig<Env> = {},
|
||||
args: Env = process.env as Env,
|
||||
) {
|
||||
return async (fnArgs: ReactRouterFunctionArgs) => {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./solid-start.adapter";
|
||||
@@ -0,0 +1,16 @@
|
||||
import { afterAll, beforeAll, describe } from "bun:test";
|
||||
import * as solidStart from "./solid-start.adapter";
|
||||
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
||||
import { adapterTestSuite } from "adapter/adapter-test-suite";
|
||||
import { bunTestRunner } from "adapter/bun/test";
|
||||
import type { SolidStartUserbaseConfig } from "./solid-start.adapter";
|
||||
|
||||
beforeAll(disableConsoleLog);
|
||||
afterAll(enableConsoleLog);
|
||||
|
||||
describe("solid-start adapter", () => {
|
||||
adapterTestSuite<SolidStartUserbaseConfig>(bunTestRunner, {
|
||||
makeApp: solidStart.getApp,
|
||||
makeHandler: solidStart.serve,
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
import { createRuntimeApp, type RuntimeUserbaseConfig } from "userbase/adapter";
|
||||
|
||||
export type SolidStartEnv = NodeJS.ProcessEnv;
|
||||
export type SolidStartUserbaseConfig<Env = SolidStartEnv> = RuntimeUserbaseConfig<Env>;
|
||||
|
||||
/**
|
||||
* Get userbase app instance
|
||||
* @param config - userbase configuration
|
||||
* @param args - environment variables
|
||||
*/
|
||||
export async function getApp<Env = SolidStartEnv>(
|
||||
config: SolidStartUserbaseConfig<Env>,
|
||||
args: Env = process.env as Env,
|
||||
) {
|
||||
return await createRuntimeApp(config, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create middleware handler for Solid Start
|
||||
* @param config - userbase configuration
|
||||
* @param args - environment variables
|
||||
*/
|
||||
export function serve<Env = SolidStartEnv>(
|
||||
config: SolidStartUserbaseConfig<Env> = {},
|
||||
args: Env = process.env as Env,
|
||||
) {
|
||||
return async (req: Request) => {
|
||||
const app = await getApp(config, args);
|
||||
return app.fetch(req);
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Connection } from "bknd";
|
||||
import type { Connection } from "userbase";
|
||||
import { bunSqlite } from "../bun/connection/BunSqliteConnection";
|
||||
|
||||
export function sqlite(config?: { url: string }): Connection {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type Connection, libsql } from "bknd";
|
||||
import { type Connection, libsql } from "userbase";
|
||||
|
||||
export function sqlite(config: { url: string }): Connection {
|
||||
return libsql(config);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Connection } from "bknd";
|
||||
import type { Connection } from "userbase";
|
||||
import { nodeSqlite } from "../node/connection/NodeSqliteConnection";
|
||||
|
||||
export function sqlite(config?: { url: string }): Connection {
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { createRuntimeApp, type RuntimeBkndConfig } from "bknd/adapter";
|
||||
import { createRuntimeApp, type RuntimeUserbaseConfig } from "userbase/adapter";
|
||||
|
||||
type TSvelteKit = {
|
||||
request: Request;
|
||||
};
|
||||
|
||||
export type SvelteKitBkndConfig<Env> = Pick<RuntimeBkndConfig<Env>, "adminOptions">;
|
||||
export type SvelteKitUserbaseConfig<Env> = Pick<RuntimeUserbaseConfig<Env>, "adminOptions">;
|
||||
|
||||
/**
|
||||
* Get bknd app instance
|
||||
* @param config - bknd configuration
|
||||
* Get userbase app instance
|
||||
* @param config - userbase configuration
|
||||
* @param args - environment variables (use $env/dynamic/private for universal runtime support)
|
||||
*/
|
||||
export async function getApp<Env>(
|
||||
config: SvelteKitBkndConfig<Env> = {} as SvelteKitBkndConfig<Env>,
|
||||
config: SvelteKitUserbaseConfig<Env> = {} as SvelteKitUserbaseConfig<Env>,
|
||||
args: Env,
|
||||
) {
|
||||
return await createRuntimeApp(config, args);
|
||||
@@ -20,11 +20,11 @@ export async function getApp<Env>(
|
||||
|
||||
/**
|
||||
* Create request handler for hooks.server.ts
|
||||
* @param config - bknd configuration
|
||||
* @param config - userbase configuration
|
||||
* @param args - environment variables (use $env/dynamic/private for universal runtime support)
|
||||
*/
|
||||
export function serve<Env>(
|
||||
config: SvelteKitBkndConfig<Env> = {} as SvelteKitBkndConfig<Env>,
|
||||
config: SvelteKitUserbaseConfig<Env> = {} as SvelteKitUserbaseConfig<Env>,
|
||||
args: Env,
|
||||
) {
|
||||
return async (fnArgs: TSvelteKit) => {
|
||||
|
||||
@@ -1,33 +1,32 @@
|
||||
import { createFrameworkApp, type FrameworkBkndConfig } from "bknd/adapter";
|
||||
import { createFrameworkApp, type FrameworkUserbaseConfig } from "userbase/adapter";
|
||||
|
||||
export type TanstackStartEnv = NodeJS.ProcessEnv;
|
||||
|
||||
export type TanstackStartConfig<Env = TanstackStartEnv> =
|
||||
FrameworkBkndConfig<Env>;
|
||||
export type TanstackStartConfig<Env = TanstackStartEnv> = FrameworkUserbaseConfig<Env>;
|
||||
|
||||
/**
|
||||
* Get bknd app instance
|
||||
* @param config - bknd configuration
|
||||
* Get userbase app instance
|
||||
* @param config - userbase configuration
|
||||
* @param args - environment variables
|
||||
*/
|
||||
export async function getApp<Env = TanstackStartEnv>(
|
||||
config: TanstackStartConfig<Env> = {},
|
||||
args: Env = process.env as Env,
|
||||
config: TanstackStartConfig<Env> = {},
|
||||
args: Env = process.env as Env,
|
||||
) {
|
||||
return await createFrameworkApp(config, args);
|
||||
return await createFrameworkApp(config, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create request handler for src/routes/api.$.ts
|
||||
* @param config - bknd configuration
|
||||
* @param config - userbase configuration
|
||||
* @param args - environment variables
|
||||
*/
|
||||
export function serve<Env = TanstackStartEnv>(
|
||||
config: TanstackStartConfig<Env> = {},
|
||||
args: Env = process.env as Env,
|
||||
config: TanstackStartConfig<Env> = {},
|
||||
args: Env = process.env as Env,
|
||||
) {
|
||||
return async (request: Request) => {
|
||||
const app = await getApp(config, args);
|
||||
return app.fetch(request);
|
||||
};
|
||||
return async (request: Request) => {
|
||||
const app = await getApp(config, args);
|
||||
return app.fetch(request);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { serveStatic } from "@hono/node-server/serve-static";
|
||||
import { type DevServerOptions, default as honoViteDevServer } from "@hono/vite-dev-server";
|
||||
import type { App } from "bknd";
|
||||
import { type RuntimeBkndConfig, createRuntimeApp } from "bknd/adapter";
|
||||
import { registerLocalMediaAdapter } from "bknd/adapter/node";
|
||||
import type { App } from "userbase";
|
||||
import { type RuntimeUserbaseConfig, createRuntimeApp } from "userbase/adapter";
|
||||
import { registerLocalMediaAdapter } from "userbase/adapter/node";
|
||||
import { devServerConfig } from "./dev-server-config";
|
||||
import type { MiddlewareHandler } from "hono";
|
||||
|
||||
export type ViteEnv = NodeJS.ProcessEnv;
|
||||
export type ViteBkndConfig<Env = ViteEnv> = RuntimeBkndConfig<Env> & {
|
||||
export type ViteUserbaseConfig<Env = ViteEnv> = RuntimeUserbaseConfig<Env> & {
|
||||
serveStatic?: false | MiddlewareHandler;
|
||||
};
|
||||
|
||||
export function addViteScript(html: string, addBkndContext: boolean = true) {
|
||||
export function addViteScript(html: string, addUserbaseContext: boolean = true) {
|
||||
return html.replace(
|
||||
"</head>",
|
||||
`<script type="module">
|
||||
@@ -22,13 +22,13 @@ window.$RefreshSig$ = () => (type) => type
|
||||
window.__vite_plugin_react_preamble_installed__ = true
|
||||
</script>
|
||||
<script type="module" src="/@vite/client"></script>
|
||||
${addBkndContext ? "<!-- BKND_CONTEXT -->" : ""}
|
||||
${addUserbaseContext ? "<!-- BKND_CONTEXT -->" : ""}
|
||||
</head>`,
|
||||
);
|
||||
}
|
||||
|
||||
async function createApp<ViteEnv>(
|
||||
config: ViteBkndConfig<ViteEnv> = {},
|
||||
config: ViteUserbaseConfig<ViteEnv> = {},
|
||||
env: ViteEnv = {} as ViteEnv,
|
||||
): Promise<App> {
|
||||
registerLocalMediaAdapter();
|
||||
@@ -49,7 +49,7 @@ async function createApp<ViteEnv>(
|
||||
);
|
||||
}
|
||||
|
||||
export function serve<ViteEnv>(config: ViteBkndConfig<ViteEnv> = {}, args?: ViteEnv) {
|
||||
export function serve<ViteEnv>(config: ViteUserbaseConfig<ViteEnv> = {}, args?: ViteEnv) {
|
||||
return {
|
||||
async fetch(request: Request, env: any, ctx: ExecutionContext) {
|
||||
const app = await createApp(config, env);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { DB, PrimaryFieldType } from "bknd";
|
||||
import type { DB, PrimaryFieldType } from "userbase";
|
||||
import * as AuthPermissions from "auth/auth-permissions";
|
||||
import type { AuthStrategy } from "auth/authenticate/strategies/Strategy";
|
||||
import type { PasswordStrategy } from "auth/authenticate/strategies/PasswordStrategy";
|
||||
import { $console, secureRandomString, transformObject, pickKeys } from "bknd/utils";
|
||||
import { $console, secureRandomString, transformObject, pickKeys } from "userbase/utils";
|
||||
import type { Entity, EntityManager } from "data/entities";
|
||||
import { em, entity, enumm, type FieldSchema } from "data/prototype";
|
||||
import { Module } from "modules/Module";
|
||||
@@ -16,7 +16,7 @@ import { Role } from "./authorize/Role";
|
||||
|
||||
export type UsersFields = typeof AppAuth.usersFields;
|
||||
export type UserFieldSchema = FieldSchema<typeof AppAuth.usersFields>;
|
||||
declare module "bknd" {
|
||||
declare module "userbase" {
|
||||
interface Users extends AppEntity, UserFieldSchema {}
|
||||
interface DB {
|
||||
users: Users;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AppAuth } from "auth/AppAuth";
|
||||
import type { CreateUser, SafeUser, User, UserPool } from "auth/authenticate/Authenticator";
|
||||
import { $console } from "bknd/utils";
|
||||
import { $console } from "userbase/utils";
|
||||
import { pick } from "lodash-es";
|
||||
import {
|
||||
InvalidConditionsException,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { AuthActionResponse } from "auth/api/AuthController";
|
||||
import type { AppAuthSchema } from "auth/auth-schema";
|
||||
import type { AuthResponse, SafeUser, AuthStrategy } from "bknd";
|
||||
import type { AuthResponse, SafeUser, AuthStrategy } from "userbase";
|
||||
import { type BaseModuleApiOptions, ModuleApi } from "modules/ModuleApi";
|
||||
|
||||
export type AuthApiOptions = BaseModuleApiOptions & {
|
||||
@@ -69,7 +69,7 @@ export class AuthApi extends ModuleApi<AuthApiOptions> {
|
||||
async logout() {
|
||||
return this.get(["logout"], undefined, {
|
||||
headers: {
|
||||
// this way bknd detects a json request and doesn't redirect back
|
||||
// this way userbase detects a json request and doesn't redirect back
|
||||
Accept: "application/json",
|
||||
},
|
||||
}).then(() => this.options.onTokenUpdate?.(undefined, true));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DB, SafeUser } from "bknd";
|
||||
import type { DB, SafeUser } from "userbase";
|
||||
import type { AuthStrategy } from "auth/authenticate/strategies/Strategy";
|
||||
import type { AppAuth } from "auth/AppAuth";
|
||||
import * as AuthPermissions from "auth/auth-permissions";
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
transformObject,
|
||||
mcpTool,
|
||||
$console,
|
||||
} from "bknd/utils";
|
||||
} from "userbase/utils";
|
||||
import type { PasswordStrategy } from "auth/authenticate/strategies";
|
||||
|
||||
export type AuthActionResponse = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { cookieConfig, jwtConfig } from "auth/authenticate/Authenticator";
|
||||
import { CustomOAuthStrategy, OAuthStrategy, PasswordStrategy } from "auth/authenticate/strategies";
|
||||
import { roleSchema } from "auth/authorize/Role";
|
||||
import { objectTransform, omitKeys, pick, s } from "bknd/utils";
|
||||
import { objectTransform, omitKeys, pick, s } from "userbase/utils";
|
||||
import { $object, $record } from "modules/mcp";
|
||||
|
||||
export const Strategies = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DB } from "bknd";
|
||||
import type { DB } from "userbase";
|
||||
import { Exception } from "core/errors";
|
||||
import { addFlashMessage } from "core/server/flash";
|
||||
import type { Context } from "hono";
|
||||
@@ -7,7 +7,7 @@ import { sign, verify } from "hono/jwt";
|
||||
import { type CookieOptions, serializeSigned } from "hono/utils/cookie";
|
||||
import type { ServerEnv } from "modules/Controller";
|
||||
import { InvalidConditionsException } from "auth/errors";
|
||||
import { s, parse, secret, runtimeSupports, truncate, $console, pickKeys } from "bknd/utils";
|
||||
import { s, parse, secret, runtimeSupports, truncate, $console, pickKeys } from "userbase/utils";
|
||||
import type { AuthStrategy } from "./strategies/Strategy";
|
||||
|
||||
type Input = any; // workaround
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { User } from "bknd";
|
||||
import type { User } from "userbase";
|
||||
import type { Authenticator } from "auth/authenticate/Authenticator";
|
||||
import { InvalidCredentialsException } from "auth/errors";
|
||||
import { hash, $console, s, parse, jsc, describeRoute } from "bknd/utils";
|
||||
import { hash, $console, s, parse, jsc, describeRoute } from "userbase/utils";
|
||||
import { Hono } from "hono";
|
||||
import { compare as bcryptCompare, genSalt as bcryptGenSalt, hash as bcryptHash } from "bcryptjs";
|
||||
import { AuthStrategy } from "./Strategy";
|
||||
|
||||
@@ -5,7 +5,7 @@ import type {
|
||||
StrategyActions,
|
||||
} from "../Authenticator";
|
||||
import type { Hono } from "hono";
|
||||
import { type s, parse } from "bknd/utils";
|
||||
import { type s, parse } from "userbase/utils";
|
||||
|
||||
export type StrategyMode = "form" | "external";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type * as oauth from "oauth4webapi";
|
||||
import { OAuthStrategy } from "./OAuthStrategy";
|
||||
import { s } from "bknd/utils";
|
||||
import { s } from "userbase/utils";
|
||||
|
||||
type SupportedTypes = "oauth2" | "oidc";
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { type Context, Hono } from "hono";
|
||||
import { getSignedCookie, setSignedCookie } from "hono/cookie";
|
||||
import * as oauth from "oauth4webapi";
|
||||
import * as issuers from "./issuers";
|
||||
import { s, filterKeys } from "bknd/utils";
|
||||
import { s, filterKeys } from "userbase/utils";
|
||||
import { Exception } from "core/errors";
|
||||
import { isDebug } from "core/env";
|
||||
import { AuthStrategy } from "../Strategy";
|
||||
|
||||
@@ -37,7 +37,7 @@ export const github: IssuerConfig<GithubUserInfo> = {
|
||||
try {
|
||||
const res = await fetch("https://api.github.com/user/emails", {
|
||||
headers: {
|
||||
"User-Agent": "bknd", // this is mandatory... *smh*
|
||||
"User-Agent": "userbase", // this is mandatory... *smh*
|
||||
Accept: "application/json",
|
||||
Authorization: `Bearer ${tokenResponse.access_token}`,
|
||||
},
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Exception } from "core/errors";
|
||||
import { $console, mergeObject, type s } from "bknd/utils";
|
||||
import { $console, mergeObject, type s } from "userbase/utils";
|
||||
import type { Permission, PermissionContext } from "auth/authorize/Permission";
|
||||
import type { Context } from "hono";
|
||||
import type { ServerEnv } from "modules/Controller";
|
||||
import type { Role } from "./Role";
|
||||
import { HttpStatus } from "bknd/utils";
|
||||
import { HttpStatus } from "userbase/utils";
|
||||
import type { Policy, PolicySchema } from "./Policy";
|
||||
import { convert, type ObjectQuery } from "core/object/query/object-query";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { s, type ParseOptions, parse, InvalidSchemaError, HttpStatus } from "bknd/utils";
|
||||
import { s, type ParseOptions, parse, InvalidSchemaError, HttpStatus } from "userbase/utils";
|
||||
|
||||
export const permissionOptionsSchema = s
|
||||
.strictObject({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { s, parse, recursivelyReplacePlaceholders } from "bknd/utils";
|
||||
import { s, parse, recursivelyReplacePlaceholders } from "userbase/utils";
|
||||
import * as query from "core/object/query/object-query";
|
||||
|
||||
export const policySchema = s
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { s } from "bknd/utils";
|
||||
import { s } from "userbase/utils";
|
||||
import { Permission } from "./Permission";
|
||||
import { Policy, policySchema } from "./Policy";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Exception } from "core/errors";
|
||||
import { isDebug } from "core/env";
|
||||
import { HttpStatus } from "bknd/utils";
|
||||
import { HttpStatus } from "userbase/utils";
|
||||
|
||||
export class AuthException extends Exception {
|
||||
getSafeErrorAndCode() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { $console, patternMatch } from "bknd/utils";
|
||||
import { $console, patternMatch } from "userbase/utils";
|
||||
import type { Context } from "hono";
|
||||
import { createMiddleware } from "hono/factory";
|
||||
import type { ServerEnv } from "modules/Controller";
|
||||
@@ -26,9 +26,7 @@ export function shouldSkip(c: Context<ServerEnv>, skip?: (string | RegExp)[]) {
|
||||
return result;
|
||||
}
|
||||
|
||||
export const auth = (options?: {
|
||||
skip?: (string | RegExp)[];
|
||||
}) =>
|
||||
export const auth = (options?: { skip?: (string | RegExp)[] }) =>
|
||||
createMiddleware<ServerEnv>(async (c, next) => {
|
||||
if (!c.get("auth")) {
|
||||
c.set("auth", {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Permission, PermissionContext } from "auth/authorize/Permission";
|
||||
import { $console, threw } from "bknd/utils";
|
||||
import { $console, threw } from "userbase/utils";
|
||||
import type { Context, Hono } from "hono";
|
||||
import type { RouterRoute } from "hono/types";
|
||||
import { createMiddleware } from "hono/factory";
|
||||
|
||||
@@ -4,7 +4,7 @@ import { makeAppFromEnv } from "cli/commands/run";
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import c from "picocolors";
|
||||
import { withConfigOptions } from "cli/utils/options";
|
||||
import { $console } from "bknd/utils";
|
||||
import { $console } from "userbase/utils";
|
||||
|
||||
export const config: CliCommand = (program) => {
|
||||
withConfigOptions(program.command("config"))
|
||||
|
||||
@@ -5,9 +5,9 @@ import type { CliCommand } from "cli/types";
|
||||
import { typewriter, wait } from "cli/utils/cli";
|
||||
import { execAsync, getVersion } from "cli/utils/sys";
|
||||
import { Option } from "commander";
|
||||
import { env } from "bknd";
|
||||
import { env } from "userbase";
|
||||
import color from "picocolors";
|
||||
import { overridePackageJson, updateBkndPackages } from "./npm";
|
||||
import { overridePackageJson, updateUserbasePackages } from "./npm";
|
||||
import { type Template, templates, type TemplateSetupCtx } from "./templates";
|
||||
import { createScoped, flush } from "cli/utils/telemetry";
|
||||
import path from "node:path";
|
||||
@@ -48,7 +48,7 @@ function errorOutro() {
|
||||
// biome-ignore lint/suspicious/noConsoleLog:
|
||||
console.log(
|
||||
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/userbase-io/userbase/issues"),
|
||||
);
|
||||
// biome-ignore lint/suspicious/noConsoleLog:
|
||||
console.log("");
|
||||
@@ -80,12 +80,12 @@ async function action(options: {
|
||||
|
||||
const version = await getVersion();
|
||||
$p.intro(
|
||||
`👋 Welcome to the ${color.bold(color.cyan("bknd"))} create cli ${color.bold(`v${version}`)}`,
|
||||
`👋 Welcome to the ${color.bold(color.cyan("userbase"))} create cli ${color.bold(`v${version}`)}`,
|
||||
);
|
||||
|
||||
await $p.stream.message(
|
||||
(async function* () {
|
||||
yield* typewriter("Thanks for choosing to create a new project with bknd!", color.dim);
|
||||
yield* typewriter("Thanks for choosing to create a new project with userbase!", color.dim);
|
||||
await wait();
|
||||
})(),
|
||||
);
|
||||
@@ -127,7 +127,7 @@ async function action(options: {
|
||||
? downloadOpts.dir.split("/").pop()
|
||||
: downloadOpts.dir.replace(/[./]/g, "");
|
||||
|
||||
if (!name || name.length === 0) name = "bknd";
|
||||
if (!name || name.length === 0) name = "userbase";
|
||||
|
||||
let template: Template | undefined;
|
||||
|
||||
@@ -254,7 +254,7 @@ async function action(options: {
|
||||
}
|
||||
|
||||
s.stop("Template downloaded.");
|
||||
await updateBkndPackages(ctx.dir);
|
||||
await updateUserbasePackages(ctx.dir);
|
||||
|
||||
if (template.preinstall) {
|
||||
await template.preinstall(ctx);
|
||||
@@ -335,7 +335,7 @@ async function action(options: {
|
||||
yield "\n\n";
|
||||
yield* typewriter(
|
||||
`Enter your project's directory using ${color.cyan("cd " + ctx.dir)}
|
||||
If you need help, check ${color.cyan("https://docs.bknd.io")} or join our Discord!`,
|
||||
If you need help, check ${color.cyan("https://docs.userbase.io")} or join our Discord!`,
|
||||
);
|
||||
await wait(2);
|
||||
})(),
|
||||
|
||||
@@ -92,10 +92,10 @@ export async function replacePackageJsonVersions(
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateBkndPackages(dir?: string, map?: Record<string, string>) {
|
||||
export async function updateUserbasePackages(dir?: string, map?: Record<string, string>) {
|
||||
try {
|
||||
const versions = {
|
||||
bknd: await sysGetVersion(),
|
||||
userbase: await sysGetVersion(),
|
||||
...(map ?? {}),
|
||||
};
|
||||
await replacePackageJsonVersions(
|
||||
|
||||
@@ -9,8 +9,8 @@ export const aws = {
|
||||
key: "aws",
|
||||
title: "AWS Lambda Basic",
|
||||
integration: "aws",
|
||||
description: "A basic bknd AWS Lambda starter",
|
||||
path: "gh:bknd-io/bknd/examples/aws-lambda",
|
||||
description: "A basic userbase AWS Lambda starter",
|
||||
path: "gh:userbase-io/userbase/examples/aws-lambda",
|
||||
ref: true,
|
||||
setup: async (ctx) => {
|
||||
await $p.stream.info(
|
||||
|
||||
@@ -11,8 +11,8 @@ export const cloudflare = {
|
||||
key: "cloudflare",
|
||||
title: "Cloudflare Basic",
|
||||
integration: "cloudflare",
|
||||
description: "A basic bknd Cloudflare worker",
|
||||
path: "gh:bknd-io/bknd/examples/cloudflare-worker",
|
||||
description: "A basic userbase Cloudflare worker",
|
||||
path: "gh:userbase-io/userbase/examples/cloudflare-worker",
|
||||
ref: true,
|
||||
setup: async (ctx) => {
|
||||
// overwrite assets directory & name
|
||||
@@ -22,7 +22,7 @@ export const cloudflare = {
|
||||
...json,
|
||||
name: ctx.name,
|
||||
assets: {
|
||||
directory: "node_modules/bknd/dist/static",
|
||||
directory: "node_modules/userbase/dist/static",
|
||||
},
|
||||
}),
|
||||
{ dir: ctx.dir },
|
||||
|
||||
@@ -6,15 +6,15 @@ export const deno = {
|
||||
key: "deno",
|
||||
title: "Deno Basic",
|
||||
integration: "deno",
|
||||
description: "A basic bknd Deno server with static assets",
|
||||
path: "gh:bknd-io/bknd/examples/deno",
|
||||
description: "A basic userbase Deno server with static assets",
|
||||
path: "gh:userbase-io/userbase/examples/deno",
|
||||
installDeps: false,
|
||||
ref: true,
|
||||
setup: async (ctx) => {
|
||||
const version = await getVersion();
|
||||
await overrideJson(
|
||||
"deno.json",
|
||||
(json) => ({ ...json, links: undefined, imports: { bknd: `npm:bknd@${version}` } }),
|
||||
(json) => ({ ...json, links: undefined, imports: { userbase: `npm:userbase@${version}` } }),
|
||||
{ dir: ctx.dir },
|
||||
);
|
||||
},
|
||||
|
||||
@@ -33,7 +33,7 @@ export type Template = {
|
||||
description?: string;
|
||||
path: string;
|
||||
/**
|
||||
* adds a ref "#{ref}" to the path. If "true", adds the current version of bknd
|
||||
* adds a ref "#{ref}" to the path. If "true", adds the current version of userbase
|
||||
*/
|
||||
ref?: true | string;
|
||||
/**
|
||||
@@ -53,48 +53,48 @@ export const templates: Template[] = [
|
||||
key: "node",
|
||||
title: "Node.js Basic",
|
||||
integration: "node",
|
||||
description: "A basic bknd Node.js server",
|
||||
path: "gh:bknd-io/bknd/examples/node",
|
||||
description: "A basic userbase Node.js server",
|
||||
path: "gh:userbase-io/userbase/examples/node",
|
||||
ref: true,
|
||||
},
|
||||
{
|
||||
key: "bun",
|
||||
title: "Bun Basic",
|
||||
integration: "bun",
|
||||
description: "A basic bknd Bun server",
|
||||
path: "gh:bknd-io/bknd/examples/bun",
|
||||
description: "A basic userbase Bun server",
|
||||
path: "gh:userbase-io/userbase/examples/bun",
|
||||
ref: true,
|
||||
},
|
||||
{
|
||||
key: "nextjs",
|
||||
title: "Next.js Basic",
|
||||
integration: "nextjs",
|
||||
description: "A basic bknd Next.js starter",
|
||||
path: "gh:bknd-io/bknd/examples/nextjs",
|
||||
description: "A basic userbase Next.js starter",
|
||||
path: "gh:userbase-io/userbase/examples/nextjs",
|
||||
ref: true,
|
||||
},
|
||||
{
|
||||
key: "astro",
|
||||
title: "Astro Basic",
|
||||
integration: "astro",
|
||||
description: "A basic bknd Astro starter",
|
||||
path: "gh:bknd-io/bknd/examples/astro",
|
||||
description: "A basic userbase Astro starter",
|
||||
path: "gh:userbase-io/userbase/examples/astro",
|
||||
ref: true,
|
||||
},
|
||||
{
|
||||
key: "react-router",
|
||||
title: "React Router Basic",
|
||||
integration: "react-router",
|
||||
description: "A basic bknd React Router starter",
|
||||
path: "gh:bknd-io/bknd/examples/react-router",
|
||||
description: "A basic userbase React Router starter",
|
||||
path: "gh:userbase-io/userbase/examples/react-router",
|
||||
ref: true,
|
||||
},
|
||||
{
|
||||
key: "aws",
|
||||
title: "AWS Lambda Basic",
|
||||
integration: "aws",
|
||||
description: "A basic bknd AWS Lambda starter",
|
||||
path: "gh:bknd-io/bknd/examples/aws-lambda",
|
||||
description: "A basic userbase AWS Lambda starter",
|
||||
path: "gh:userbase-io/userbase/examples/aws-lambda",
|
||||
ref: true,
|
||||
},
|
||||
deno,
|
||||
|
||||
@@ -10,7 +10,7 @@ import type { CliCommand } from "../types";
|
||||
export const debug: CliCommand = (program) => {
|
||||
program
|
||||
.command("debug")
|
||||
.description("debug bknd")
|
||||
.description("debug userbase")
|
||||
.addArgument(new Argument("<subject>", "subject to debug").choices(Object.keys(subjects)))
|
||||
.action(action);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { CliCommand } from "cli/types";
|
||||
import { makeAppFromEnv } from "../run";
|
||||
import { getSystemMcp } from "modules/mcp/system-mcp";
|
||||
import { $console, stdioTransport } from "bknd/utils";
|
||||
import { $console, stdioTransport } from "userbase/utils";
|
||||
import { withConfigOptions, type WithConfigOptions } from "cli/utils/options";
|
||||
|
||||
export const mcp: CliCommand = (program) =>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user