create-z3 0.0.55 → 0.0.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +208 -0
- package/package.json +1 -1
- package/templates/nextjs/convex/auth/index.ts +2 -2
- package/templates/nextjs/convex/auth/plugins/index.ts +7 -4
- package/templates/nextjs/convex/http.ts +16 -3
- package/templates/nextjs/convex/schema.ts +13 -2
- package/templates/nextjs/src/db/constants/auth.ts +2 -0
- package/templates/nextjs/src/db/constants/index.ts +2 -0
- package/templates/nextjs/src/db/types.ts +2 -0
- package/templates/tanstack-start/convex/auth/index.ts +2 -2
- package/templates/tanstack-start/convex/auth/plugins/index.ts +7 -4
- package/templates/tanstack-start/convex/http.ts +11 -0
- package/templates/tanstack-start/convex/schema.ts +5 -1
- package/templates/tanstack-start/src/db/constants/auth.ts +2 -0
- package/templates/tanstack-start/src/db/constants/index.ts +2 -0
- package/templates/tanstack-start/src/db/types.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -1817,6 +1817,75 @@ async function replacePlaceholder(filePath, placeholder, content, options) {
|
|
|
1817
1817
|
}
|
|
1818
1818
|
await fs3.writeFile(filePath, updatedLines.join("\n"), "utf-8");
|
|
1819
1819
|
}
|
|
1820
|
+
function generateOrganizationsPlugin() {
|
|
1821
|
+
return `organization({
|
|
1822
|
+
roles: {
|
|
1823
|
+
admin: {
|
|
1824
|
+
permissions: ["organization:read", "organization:write", "member:write"]
|
|
1825
|
+
},
|
|
1826
|
+
member: {
|
|
1827
|
+
permissions: ["organization:read"]
|
|
1828
|
+
}
|
|
1829
|
+
},
|
|
1830
|
+
adminRole: "admin"
|
|
1831
|
+
}),`;
|
|
1832
|
+
}
|
|
1833
|
+
function generateOrganizationsSchema() {
|
|
1834
|
+
return `// Organization tables
|
|
1835
|
+
[TABLE_SLUG_ORGANIZATIONS]: defineTable({
|
|
1836
|
+
name: v.string(),
|
|
1837
|
+
slug: v.string(),
|
|
1838
|
+
metadata: v.optional(v.any()),
|
|
1839
|
+
logo: v.optional(v.string()),
|
|
1840
|
+
createdAt: v.number(),
|
|
1841
|
+
updatedAt: v.number(),
|
|
1842
|
+
})
|
|
1843
|
+
.index("by_slug", ["slug"]),
|
|
1844
|
+
|
|
1845
|
+
[TABLE_SLUG_ORGANIZATION_MEMBERS]: defineTable({
|
|
1846
|
+
userId: v.id(TABLE_SLUG_USERS),
|
|
1847
|
+
organizationId: v.id(TABLE_SLUG_ORGANIZATIONS),
|
|
1848
|
+
role: v.string(),
|
|
1849
|
+
createdAt: v.number(),
|
|
1850
|
+
updatedAt: v.number(),
|
|
1851
|
+
})
|
|
1852
|
+
.index("by_user", ["userId"])
|
|
1853
|
+
.index("by_organization", ["organizationId"])
|
|
1854
|
+
.index("by_user_organization", ["userId", "organizationId"]),`;
|
|
1855
|
+
}
|
|
1856
|
+
function generateUserOrganizationFields() {
|
|
1857
|
+
return `activeOrganizationId: v.optional(v.id(TABLE_SLUG_ORGANIZATIONS)),`;
|
|
1858
|
+
}
|
|
1859
|
+
function generateOrganizationRoles() {
|
|
1860
|
+
return `
|
|
1861
|
+
export const ORGANIZATION_ROLES = {
|
|
1862
|
+
admin: "admin",
|
|
1863
|
+
member: "member",
|
|
1864
|
+
} as const;
|
|
1865
|
+
export type OrganizationRole = (typeof ORGANIZATION_ROLES)[keyof typeof ORGANIZATION_ROLES];`;
|
|
1866
|
+
}
|
|
1867
|
+
function generateOrganizationTableConstants() {
|
|
1868
|
+
return `export const TABLE_SLUG_ORGANIZATIONS = "organization" as const;
|
|
1869
|
+
export const TABLE_SLUG_ORGANIZATION_MEMBERS = "organization_member" as const;`;
|
|
1870
|
+
}
|
|
1871
|
+
function generateOrganizationTableImports() {
|
|
1872
|
+
return `,
|
|
1873
|
+
TABLE_SLUG_ORGANIZATIONS,
|
|
1874
|
+
TABLE_SLUG_ORGANIZATION_MEMBERS`;
|
|
1875
|
+
}
|
|
1876
|
+
function generateUserWithOrganizationType() {
|
|
1877
|
+
return `import { OrganizationRole } from './constants/auth';
|
|
1878
|
+
|
|
1879
|
+
export type UserWithOrganization = User & {
|
|
1880
|
+
organization?: {
|
|
1881
|
+
id: string;
|
|
1882
|
+
name: string;
|
|
1883
|
+
slug: string;
|
|
1884
|
+
role: OrganizationRole;
|
|
1885
|
+
metadata?: any;
|
|
1886
|
+
} | null;
|
|
1887
|
+
};`;
|
|
1888
|
+
}
|
|
1820
1889
|
function generateCredentialsValue(enabled) {
|
|
1821
1890
|
return `credentials={${enabled}}`;
|
|
1822
1891
|
}
|
|
@@ -2196,6 +2265,18 @@ Make sure you are authenticated with GitHub CLI (run "gh auth login")`
|
|
|
2196
2265
|
oauthUISpinner.fail("Failed to configure OAuth UI");
|
|
2197
2266
|
throw error;
|
|
2198
2267
|
}
|
|
2268
|
+
const multitenancySpinner = ora("Configuring multitenancy...").start();
|
|
2269
|
+
try {
|
|
2270
|
+
await this.updateMultitenancyConfig(options.multitenancy);
|
|
2271
|
+
if (options.multitenancy) {
|
|
2272
|
+
multitenancySpinner.succeed("Multitenancy configuration updated");
|
|
2273
|
+
} else {
|
|
2274
|
+
multitenancySpinner.succeed("Multitenancy placeholders cleaned up");
|
|
2275
|
+
}
|
|
2276
|
+
} catch (error) {
|
|
2277
|
+
multitenancySpinner.fail("Failed to configure multitenancy");
|
|
2278
|
+
throw error;
|
|
2279
|
+
}
|
|
2199
2280
|
const envSpinner = ora("Updating .env.example...").start();
|
|
2200
2281
|
try {
|
|
2201
2282
|
await this.updateEnvExample(options.oauthProviders);
|
|
@@ -2389,6 +2470,59 @@ var TanStackInstaller = class extends FrameworkInstaller {
|
|
|
2389
2470
|
runtimeMapping
|
|
2390
2471
|
);
|
|
2391
2472
|
}
|
|
2473
|
+
/**
|
|
2474
|
+
* Configure multitenancy with organizations
|
|
2475
|
+
* Updates auth plugins, schema, and user types for organization support
|
|
2476
|
+
* Target files:
|
|
2477
|
+
* - convex/auth/plugins/index.ts - Add organization plugin
|
|
2478
|
+
* - convex/schema.ts - Add organization and membership tables
|
|
2479
|
+
* - src/db/constants/auth.ts - Add organization roles
|
|
2480
|
+
* - src/db/types.ts - Update user type with organization
|
|
2481
|
+
*
|
|
2482
|
+
* @param enabled - Whether multitenancy is enabled
|
|
2483
|
+
*/
|
|
2484
|
+
async updateMultitenancyConfig(enabled) {
|
|
2485
|
+
const pluginsFilePath = join2(this.targetPath, "convex/auth/plugins/index.ts");
|
|
2486
|
+
await replacePlaceholder(
|
|
2487
|
+
pluginsFilePath,
|
|
2488
|
+
"// {{ORGANIZATIONS_PLUGIN}}",
|
|
2489
|
+
enabled ? generateOrganizationsPlugin() : ""
|
|
2490
|
+
);
|
|
2491
|
+
const schemaFilePath = join2(this.targetPath, "convex/schema.ts");
|
|
2492
|
+
await replacePlaceholder(
|
|
2493
|
+
schemaFilePath,
|
|
2494
|
+
"// {{ORGANIZATION_TABLE_IMPORTS}}",
|
|
2495
|
+
enabled ? generateOrganizationTableImports() : ""
|
|
2496
|
+
);
|
|
2497
|
+
await replacePlaceholder(
|
|
2498
|
+
schemaFilePath,
|
|
2499
|
+
"// {{ORGANIZATIONS_SCHEMA}}",
|
|
2500
|
+
enabled ? generateOrganizationsSchema() : ""
|
|
2501
|
+
);
|
|
2502
|
+
await replacePlaceholder(
|
|
2503
|
+
schemaFilePath,
|
|
2504
|
+
"// {{USER_ORGANIZATION_FIELDS}}",
|
|
2505
|
+
enabled ? generateUserOrganizationFields() : ""
|
|
2506
|
+
);
|
|
2507
|
+
const constantsFilePath = join2(this.targetPath, "src/db/constants/auth.ts");
|
|
2508
|
+
await replacePlaceholder(
|
|
2509
|
+
constantsFilePath,
|
|
2510
|
+
"// {{ORGANIZATION_ROLES}}",
|
|
2511
|
+
enabled ? generateOrganizationRoles() : ""
|
|
2512
|
+
);
|
|
2513
|
+
const constantsIndexFilePath = join2(this.targetPath, "src/db/constants/index.ts");
|
|
2514
|
+
await replacePlaceholder(
|
|
2515
|
+
constantsIndexFilePath,
|
|
2516
|
+
"// {{ORGANIZATION_TABLES}}",
|
|
2517
|
+
enabled ? generateOrganizationTableConstants() : ""
|
|
2518
|
+
);
|
|
2519
|
+
const typesFilePath = join2(this.targetPath, "src/db/types.ts");
|
|
2520
|
+
await replacePlaceholder(
|
|
2521
|
+
typesFilePath,
|
|
2522
|
+
"// {{USER_WITH_ORGANIZATION_TYPE}}",
|
|
2523
|
+
enabled ? generateUserWithOrganizationType() : ""
|
|
2524
|
+
);
|
|
2525
|
+
}
|
|
2392
2526
|
};
|
|
2393
2527
|
|
|
2394
2528
|
// src/installers/nextjs.ts
|
|
@@ -2522,6 +2656,59 @@ var NextJSInstaller = class extends FrameworkInstaller {
|
|
|
2522
2656
|
runtimeMapping
|
|
2523
2657
|
);
|
|
2524
2658
|
}
|
|
2659
|
+
/**
|
|
2660
|
+
* Configure multitenancy with organizations
|
|
2661
|
+
* Updates auth plugins, schema, and user types for organization support
|
|
2662
|
+
* Target files:
|
|
2663
|
+
* - convex/auth/plugins/index.ts - Add organization plugin
|
|
2664
|
+
* - convex/schema.ts - Add organization and membership tables
|
|
2665
|
+
* - src/db/constants/auth.ts - Add organization roles
|
|
2666
|
+
* - src/db/types.ts - Update user type with organization
|
|
2667
|
+
*
|
|
2668
|
+
* @param enabled - Whether multitenancy is enabled
|
|
2669
|
+
*/
|
|
2670
|
+
async updateMultitenancyConfig(enabled) {
|
|
2671
|
+
const pluginsFilePath = join3(this.targetPath, "convex/auth/plugins/index.ts");
|
|
2672
|
+
await replacePlaceholder(
|
|
2673
|
+
pluginsFilePath,
|
|
2674
|
+
"// {{ORGANIZATIONS_PLUGIN}}",
|
|
2675
|
+
enabled ? generateOrganizationsPlugin() : ""
|
|
2676
|
+
);
|
|
2677
|
+
const schemaFilePath = join3(this.targetPath, "convex/schema.ts");
|
|
2678
|
+
await replacePlaceholder(
|
|
2679
|
+
schemaFilePath,
|
|
2680
|
+
"// {{ORGANIZATION_TABLE_IMPORTS}}",
|
|
2681
|
+
enabled ? generateOrganizationTableImports() : ""
|
|
2682
|
+
);
|
|
2683
|
+
await replacePlaceholder(
|
|
2684
|
+
schemaFilePath,
|
|
2685
|
+
"// {{ORGANIZATIONS_SCHEMA}}",
|
|
2686
|
+
enabled ? generateOrganizationsSchema() : ""
|
|
2687
|
+
);
|
|
2688
|
+
await replacePlaceholder(
|
|
2689
|
+
schemaFilePath,
|
|
2690
|
+
"// {{USER_ORGANIZATION_FIELDS}}",
|
|
2691
|
+
enabled ? generateUserOrganizationFields() : ""
|
|
2692
|
+
);
|
|
2693
|
+
const constantsFilePath = join3(this.targetPath, "src/db/constants/auth.ts");
|
|
2694
|
+
await replacePlaceholder(
|
|
2695
|
+
constantsFilePath,
|
|
2696
|
+
"// {{ORGANIZATION_ROLES}}",
|
|
2697
|
+
enabled ? generateOrganizationRoles() : ""
|
|
2698
|
+
);
|
|
2699
|
+
const constantsIndexFilePath = join3(this.targetPath, "src/db/constants/index.ts");
|
|
2700
|
+
await replacePlaceholder(
|
|
2701
|
+
constantsIndexFilePath,
|
|
2702
|
+
"// {{ORGANIZATION_TABLES}}",
|
|
2703
|
+
enabled ? generateOrganizationTableConstants() : ""
|
|
2704
|
+
);
|
|
2705
|
+
const typesFilePath = join3(this.targetPath, "src/db/types.ts");
|
|
2706
|
+
await replacePlaceholder(
|
|
2707
|
+
typesFilePath,
|
|
2708
|
+
"// {{USER_WITH_ORGANIZATION_TYPE}}",
|
|
2709
|
+
enabled ? generateUserWithOrganizationType() : ""
|
|
2710
|
+
);
|
|
2711
|
+
}
|
|
2525
2712
|
};
|
|
2526
2713
|
|
|
2527
2714
|
// src/index.ts
|
|
@@ -2645,6 +2832,21 @@ program.name("create-z3").version(packageJson.version).description("CLI for scaf
|
|
|
2645
2832
|
console.log(chalk2.yellow(" Your app will have no user authentication."));
|
|
2646
2833
|
console.log();
|
|
2647
2834
|
}
|
|
2835
|
+
let multitenancy = false;
|
|
2836
|
+
if (emailPassword || oauthProviders.length > 0) {
|
|
2837
|
+
multitenancy = await confirm({
|
|
2838
|
+
message: "Enable multitenancy with organizations?",
|
|
2839
|
+
default: false
|
|
2840
|
+
});
|
|
2841
|
+
if (multitenancy) {
|
|
2842
|
+
console.log();
|
|
2843
|
+
console.log(chalk2.cyan("\u{1F3E2} Organizations enabled:"));
|
|
2844
|
+
console.log(chalk2.dim(" \u2022 Users can belong to multiple organizations"));
|
|
2845
|
+
console.log(chalk2.dim(" \u2022 Role-based permissions per organization"));
|
|
2846
|
+
console.log(chalk2.dim(" \u2022 Admin users can manage organization members"));
|
|
2847
|
+
console.log();
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2648
2850
|
console.log();
|
|
2649
2851
|
console.log(chalk2.dim("\u{1F4A1} TweakCN themes: Visit https://tweakcn.com/themes/[theme-id]"));
|
|
2650
2852
|
console.log(chalk2.dim(' Click "Code" button and copy the CSS.'));
|
|
@@ -2688,6 +2890,7 @@ program.name("create-z3").version(packageJson.version).description("CLI for scaf
|
|
|
2688
2890
|
framework,
|
|
2689
2891
|
emailPasswordAuth: emailPassword,
|
|
2690
2892
|
oauthProviders,
|
|
2893
|
+
multitenancy,
|
|
2691
2894
|
tweakcnTheme,
|
|
2692
2895
|
initGit,
|
|
2693
2896
|
installDependencies
|
|
@@ -2733,6 +2936,11 @@ program.name("create-z3").version(packageJson.version).description("CLI for scaf
|
|
|
2733
2936
|
} else {
|
|
2734
2937
|
console.log(chalk2.dim("Authentication: None selected"));
|
|
2735
2938
|
}
|
|
2939
|
+
if (multitenancy) {
|
|
2940
|
+
console.log("Organizations: Enabled");
|
|
2941
|
+
} else {
|
|
2942
|
+
console.log("Organizations: Disabled");
|
|
2943
|
+
}
|
|
2736
2944
|
if (tweakcnTheme) {
|
|
2737
2945
|
console.log("Theme: Custom TweakCN theme");
|
|
2738
2946
|
} else {
|
package/package.json
CHANGED
|
@@ -14,7 +14,7 @@ import type { DataModel } from "../_generated/dataModel"
|
|
|
14
14
|
|
|
15
15
|
import schema from "../schema"
|
|
16
16
|
import { convexAdapter } from "./adapter"
|
|
17
|
-
import
|
|
17
|
+
import { createPlugins } from "./plugins"
|
|
18
18
|
|
|
19
19
|
export const createAuth = (
|
|
20
20
|
ctx: GenericActionCtx<DataModel>,
|
|
@@ -31,7 +31,7 @@ export const createAuth = (
|
|
|
31
31
|
logger: {
|
|
32
32
|
disabled: optionsOnly
|
|
33
33
|
},
|
|
34
|
-
plugins:
|
|
34
|
+
plugins: createPlugins(),
|
|
35
35
|
secret: process.env.BETTER_AUTH_SECRET,
|
|
36
36
|
session: {
|
|
37
37
|
modelName: TABLE_SLUG_SESSIONS
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { nextCookies } from "better-auth/next-js"
|
|
2
|
-
import { admin } from "better-auth/plugins"
|
|
2
|
+
import { admin, organization } from "better-auth/plugins"
|
|
3
3
|
import { apiKey } from "@better-auth/api-key"
|
|
4
4
|
import { convex } from "@convex-dev/better-auth/plugins"
|
|
5
5
|
import { USER_ROLES } from "~/db/constants"
|
|
6
6
|
import authConfig from "@convex/auth.config"
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
// Return a new array each call so plugin initialization (including the convex()
|
|
9
|
+
// factory which internally calls the deprecated oidc-provider plugin) runs inside
|
|
10
|
+
// createAuth() rather than at module-eval time. This lets the console.warn filter
|
|
11
|
+
// in http.ts suppress the deprecation noise before it fires.
|
|
12
|
+
export const createPlugins = () => [
|
|
9
13
|
admin({
|
|
10
14
|
adminRoles: [USER_ROLES.admin],
|
|
11
15
|
defaultRole: USER_ROLES.user,
|
|
12
16
|
}),
|
|
17
|
+
// {{ORGANIZATIONS_PLUGIN}}
|
|
13
18
|
apiKey(),
|
|
14
19
|
nextCookies(),
|
|
15
20
|
convex({ authConfig }),
|
|
16
21
|
]
|
|
17
|
-
|
|
18
|
-
export default plugins
|
|
@@ -7,9 +7,22 @@ const http = httpRouter();
|
|
|
7
7
|
|
|
8
8
|
// Auth request handler - basePath hardcoded to /api/auth for now
|
|
9
9
|
const authRequestHandler = httpAction(async (ctx, request) => {
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
// Suppress the oidc-provider deprecation warning spammed by @convex-dev/better-auth
|
|
11
|
+
// on every request. Convex wraps console.warn per-invocation, so this must run
|
|
12
|
+
// inside the handler (not at module level) to intercept after Convex's wrapper is set.
|
|
13
|
+
// Remove once @convex-dev/better-auth migrates to @better-auth/oauth-provider.
|
|
14
|
+
const _warn = console.warn;
|
|
15
|
+
console.warn = (...args: unknown[]) => {
|
|
16
|
+
if (typeof args[0] === "string" && args[0].includes("oidc-provider")) return;
|
|
17
|
+
_warn(...args);
|
|
18
|
+
};
|
|
19
|
+
try {
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
21
|
+
const auth = createAuth(ctx);
|
|
22
|
+
return await auth.handler(request);
|
|
23
|
+
} finally {
|
|
24
|
+
console.warn = _warn;
|
|
25
|
+
}
|
|
13
26
|
});
|
|
14
27
|
|
|
15
28
|
// Register auth routes for GET and POST
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { defineSchema, defineTable } from "convex/server";
|
|
2
2
|
import { v } from "convex/values"
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
TABLE_SLUG_ACCOUNTS,
|
|
6
|
+
TABLE_SLUG_API_KEYS,
|
|
7
|
+
TABLE_SLUG_JWKS,
|
|
8
|
+
TABLE_SLUG_SESSIONS,
|
|
9
|
+
TABLE_SLUG_USERS,
|
|
10
|
+
TABLE_SLUG_VERIFICATIONS
|
|
11
|
+
// {{ORGANIZATION_TABLE_IMPORTS}}
|
|
12
|
+
} from "~/db/constants";
|
|
5
13
|
|
|
6
14
|
export default defineSchema({
|
|
7
15
|
// Better Auth component tables (type definitions only - actual tables are in component)
|
|
@@ -23,7 +31,8 @@ export default defineSchema({
|
|
|
23
31
|
roles: v.array(v.string()), // our multi-role field via additionalFields
|
|
24
32
|
twoFactorEnabled: v.optional(v.union(v.null(), v.boolean())),
|
|
25
33
|
updatedAt: v.number(),
|
|
26
|
-
userId: v.optional(v.union(v.null(), v.string()))
|
|
34
|
+
userId: v.optional(v.union(v.null(), v.string())),
|
|
35
|
+
// {{USER_ORGANIZATION_FIELDS}}
|
|
27
36
|
})
|
|
28
37
|
.index("by_email", ["email"]),
|
|
29
38
|
|
|
@@ -98,4 +107,6 @@ export default defineSchema({
|
|
|
98
107
|
})
|
|
99
108
|
.index("by_referenceId", ["referenceId"])
|
|
100
109
|
.index("by_key", ["key"]),
|
|
110
|
+
|
|
111
|
+
// {{ORGANIZATIONS_SCHEMA}}
|
|
101
112
|
})
|
|
@@ -8,6 +8,8 @@ export const TABLE_SLUG_VERIFICATIONS = "verification" as const;
|
|
|
8
8
|
export const TABLE_SLUG_JWKS = "jwks" as const;
|
|
9
9
|
export const TABLE_SLUG_API_KEYS = "apikey" as const;
|
|
10
10
|
|
|
11
|
+
// {{ORGANIZATION_TABLES}}
|
|
12
|
+
|
|
11
13
|
export const COLLECTION_SLUG_MEDIA = "media" as const;
|
|
12
14
|
|
|
13
15
|
export const AUTH_PROVIDERS = {
|
|
@@ -14,7 +14,7 @@ import type { DataModel } from "../_generated/dataModel"
|
|
|
14
14
|
|
|
15
15
|
import schema from "../schema"
|
|
16
16
|
import { convexAdapter } from "./adapter"
|
|
17
|
-
import
|
|
17
|
+
import { createPlugins } from "./plugins"
|
|
18
18
|
|
|
19
19
|
export const createAuth = (
|
|
20
20
|
ctx: GenericActionCtx<DataModel>,
|
|
@@ -31,7 +31,7 @@ export const createAuth = (
|
|
|
31
31
|
logger: {
|
|
32
32
|
disabled: optionsOnly
|
|
33
33
|
},
|
|
34
|
-
plugins:
|
|
34
|
+
plugins: createPlugins(),
|
|
35
35
|
secret: process.env.BETTER_AUTH_SECRET,
|
|
36
36
|
session: {
|
|
37
37
|
modelName: TABLE_SLUG_SESSIONS
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
import { admin } from "better-auth/plugins"
|
|
1
|
+
import { admin, organization } from "better-auth/plugins"
|
|
2
2
|
import { apiKey } from "@better-auth/api-key"
|
|
3
3
|
import { convex } from "@convex-dev/better-auth/plugins"
|
|
4
4
|
import authConfig from "@convex/auth.config"
|
|
5
5
|
import { USER_ROLES } from "~/db/constants"
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
// Return a new array each call so plugin initialization (including the convex()
|
|
8
|
+
// factory which internally calls the deprecated oidc-provider plugin) runs inside
|
|
9
|
+
// createAuth() rather than at module-eval time. This lets the console.warn filter
|
|
10
|
+
// in http.ts suppress the deprecation noise before it fires.
|
|
11
|
+
export const createPlugins = () => [
|
|
8
12
|
admin({
|
|
9
13
|
adminRoles: [USER_ROLES.admin],
|
|
10
14
|
defaultRole: USER_ROLES.user
|
|
11
15
|
}),
|
|
16
|
+
// {{ORGANIZATIONS_PLUGIN}}
|
|
12
17
|
apiKey(),
|
|
13
18
|
convex({ authConfig }),
|
|
14
19
|
]
|
|
15
|
-
|
|
16
|
-
export default plugins
|
|
@@ -8,6 +8,15 @@ const http = httpRouter()
|
|
|
8
8
|
* Auth handler - handles Better Auth requests with custom adapter
|
|
9
9
|
*/
|
|
10
10
|
const authRequestHandler = httpAction(async (ctx, request) => {
|
|
11
|
+
// Suppress the oidc-provider deprecation warning spammed by @convex-dev/better-auth
|
|
12
|
+
// on every request. Convex wraps console.warn per-invocation, so this must run
|
|
13
|
+
// inside the handler (not at module level) to intercept after Convex's wrapper is set.
|
|
14
|
+
// Remove once @convex-dev/better-auth migrates to @better-auth/oauth-provider.
|
|
15
|
+
const _warn = console.warn
|
|
16
|
+
console.warn = (...args: unknown[]) => {
|
|
17
|
+
if (typeof args[0] === "string" && args[0].includes("oidc-provider")) return
|
|
18
|
+
_warn(...args)
|
|
19
|
+
}
|
|
11
20
|
try {
|
|
12
21
|
const auth = createAuth(ctx)
|
|
13
22
|
const response = await auth.handler(request)
|
|
@@ -15,6 +24,8 @@ const authRequestHandler = httpAction(async (ctx, request) => {
|
|
|
15
24
|
} catch (error) {
|
|
16
25
|
console.error("❌ Auth error:", error)
|
|
17
26
|
return new Response("Auth error", { status: 500 })
|
|
27
|
+
} finally {
|
|
28
|
+
console.warn = _warn
|
|
18
29
|
}
|
|
19
30
|
})
|
|
20
31
|
|
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
TABLE_SLUG_JWKS,
|
|
8
8
|
TABLE_SLUG_SESSIONS,
|
|
9
9
|
TABLE_SLUG_USERS,
|
|
10
|
-
TABLE_SLUG_VERIFICATIONS
|
|
10
|
+
TABLE_SLUG_VERIFICATIONS
|
|
11
|
+
// {{ORGANIZATION_TABLE_IMPORTS}}
|
|
11
12
|
} from "~/db/constants";
|
|
12
13
|
|
|
13
14
|
export default defineSchema({
|
|
@@ -31,6 +32,7 @@ export default defineSchema({
|
|
|
31
32
|
banReason: v.optional(v.string()), // admin plugin
|
|
32
33
|
role: v.optional(v.string()), // admin plugin — single string in BA 1.5
|
|
33
34
|
roles: v.array(v.string()), // our multi-role field via additionalFields
|
|
35
|
+
// {{USER_ORGANIZATION_FIELDS}}
|
|
34
36
|
})
|
|
35
37
|
.index("by_email", ["email"]),
|
|
36
38
|
|
|
@@ -105,4 +107,6 @@ export default defineSchema({
|
|
|
105
107
|
})
|
|
106
108
|
.index("by_referenceId", ["referenceId"])
|
|
107
109
|
.index("by_key", ["key"]),
|
|
110
|
+
|
|
111
|
+
// {{ORGANIZATIONS_SCHEMA}}
|
|
108
112
|
})
|