@contentgrowth/content-auth 0.0.1

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.
@@ -0,0 +1,9 @@
1
+ import {
2
+ authClient,
3
+ createClient
4
+ } from "../chunk-NKDKDBM2.js";
5
+ import "../chunk-R5U7XKVJ.js";
6
+ export {
7
+ authClient,
8
+ createClient
9
+ };
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { authClient } from './client.js';
3
+ export { createClient } from './client.js';
4
+ import 'nanostores';
5
+ import '@better-fetch/fetch';
6
+ import 'better-auth';
7
+ import 'better-auth/plugins';
8
+
9
+ interface AuthFormProps {
10
+ view?: 'signin' | 'signup';
11
+ client?: typeof authClient;
12
+ onSuccess?: () => void;
13
+ className?: string;
14
+ socialProviders?: string[];
15
+ socialLayout?: 'row' | 'column';
16
+ title?: React.ReactNode;
17
+ width?: 'default' | 'compact' | 'wide';
18
+ layout?: 'default' | 'split';
19
+ socialPosition?: 'top' | 'bottom';
20
+ onSwitchMode?: () => void;
21
+ }
22
+ declare const AuthForm: React.FC<AuthFormProps>;
23
+
24
+ interface BaseOrgProps {
25
+ client?: typeof authClient;
26
+ className?: string;
27
+ onSuccess?: (data?: any) => void;
28
+ onError?: (error: string) => void;
29
+ }
30
+ declare const CreateOrganizationForm: React.FC<BaseOrgProps>;
31
+ declare const OrganizationSwitcher: React.FC<BaseOrgProps & {
32
+ currentOrgId?: string;
33
+ }>;
34
+ declare const InviteMemberForm: React.FC<BaseOrgProps & {
35
+ organizationId?: string;
36
+ }>;
37
+
38
+ export { AuthForm, CreateOrganizationForm, InviteMemberForm, OrganizationSwitcher, authClient };
@@ -0,0 +1,19 @@
1
+ import {
2
+ AuthForm,
3
+ CreateOrganizationForm,
4
+ InviteMemberForm,
5
+ OrganizationSwitcher
6
+ } from "../chunk-VX6RJ5XJ.js";
7
+ import {
8
+ authClient,
9
+ createClient
10
+ } from "../chunk-NKDKDBM2.js";
11
+ import "../chunk-R5U7XKVJ.js";
12
+ export {
13
+ AuthForm,
14
+ CreateOrganizationForm,
15
+ InviteMemberForm,
16
+ OrganizationSwitcher,
17
+ authClient,
18
+ createClient
19
+ };
@@ -0,0 +1,12 @@
1
+ export { AuthConfig, authMiddleware, createAuth, createAuthApp, schema } from './backend/index.js';
2
+ export { AuthForm, CreateOrganizationForm, InviteMemberForm, OrganizationSwitcher } from './frontend/index.js';
3
+ export { authClient, createClient } from './frontend/client.js';
4
+ export * from 'better-auth';
5
+ export { Hono } from 'hono';
6
+ import 'hono/types';
7
+ import '@cloudflare/workers-types';
8
+ import 'drizzle-orm/sqlite-core';
9
+ import 'react';
10
+ import 'nanostores';
11
+ import '@better-fetch/fetch';
12
+ import 'better-auth/plugins';
package/dist/index.js ADDED
@@ -0,0 +1,31 @@
1
+ import {
2
+ Hono,
3
+ authMiddleware,
4
+ createAuth,
5
+ createAuthApp,
6
+ schema_exports
7
+ } from "./chunk-526JE62U.js";
8
+ import {
9
+ AuthForm,
10
+ CreateOrganizationForm,
11
+ InviteMemberForm,
12
+ OrganizationSwitcher
13
+ } from "./chunk-VX6RJ5XJ.js";
14
+ import {
15
+ authClient,
16
+ createClient
17
+ } from "./chunk-NKDKDBM2.js";
18
+ import "./chunk-R5U7XKVJ.js";
19
+ export {
20
+ AuthForm,
21
+ CreateOrganizationForm,
22
+ Hono,
23
+ InviteMemberForm,
24
+ OrganizationSwitcher,
25
+ authClient,
26
+ authMiddleware,
27
+ createAuth,
28
+ createAuthApp,
29
+ createClient,
30
+ schema_exports as schema
31
+ };
@@ -0,0 +1,264 @@
1
+ .ca-container {
2
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
3
+ width: 100%;
4
+ max-width: 420px;
5
+ margin: 0 auto;
6
+ padding: 2.5rem;
7
+ border-radius: 16px;
8
+ box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
9
+ background-color: white;
10
+ border: 1px solid #f3f4f6;
11
+ }
12
+
13
+ .ca-title {
14
+ font-size: 1.75rem;
15
+ font-weight: 700;
16
+ text-align: center;
17
+ margin-bottom: 2rem;
18
+ color: #111827;
19
+ letter-spacing: -0.025em;
20
+ }
21
+
22
+ .ca-form {
23
+ display: flex;
24
+ flex-direction: column;
25
+ gap: 1.25rem;
26
+ }
27
+
28
+ .ca-input-group {
29
+ display: flex;
30
+ flex-direction: column;
31
+ gap: 0.5rem;
32
+ }
33
+
34
+ .ca-label {
35
+ font-size: 0.875rem;
36
+ font-weight: 500;
37
+ color: #374151;
38
+ }
39
+
40
+ .ca-input {
41
+ padding: 0.75rem 1rem;
42
+ border-radius: 8px;
43
+ border: 1px solid #e5e7eb;
44
+ font-size: 0.95rem;
45
+ transition: all 0.2s ease;
46
+ background-color: #f9fafb;
47
+ }
48
+
49
+ .ca-input:focus {
50
+ outline: none;
51
+ border-color: #3b82f6;
52
+ background-color: white;
53
+ box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1);
54
+ }
55
+
56
+ .ca-button {
57
+ display: inline-flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ padding: 0.75rem 1.5rem;
61
+ border-radius: 8px;
62
+ border: 1px solid transparent;
63
+ font-weight: 500;
64
+ font-size: 0.95rem;
65
+ cursor: pointer;
66
+ transition: all 0.2s ease;
67
+ gap: 0.5rem;
68
+ }
69
+
70
+ .ca-button-primary,
71
+ button[type="submit"] {
72
+ background-color: #111827;
73
+ color: white;
74
+ border: 1px solid #111827;
75
+ }
76
+
77
+ button[type="submit"]:hover {
78
+ background-color: #1f2937;
79
+ border-color: #1f2937;
80
+ transform: translateY(-1px);
81
+ }
82
+
83
+ .ca-button-submit:disabled,
84
+ button[type="submit"]:disabled {
85
+ background-color: #9ca3af;
86
+ border-color: #9ca3af;
87
+ cursor: not-allowed;
88
+ transform: none;
89
+ }
90
+
91
+ /* Social Buttons */
92
+ .ca-social-grid {
93
+ display: grid;
94
+ grid-template-columns: 1fr 1fr;
95
+ gap: 1rem;
96
+ margin-bottom: 1.5rem;
97
+ }
98
+
99
+ .ca-button-social {
100
+ background-color: white;
101
+ color: #374151;
102
+ border: 1px solid #e5e7eb;
103
+ padding: 0.625rem 1rem;
104
+ font-weight: 500;
105
+ }
106
+
107
+ .ca-button-social:hover {
108
+ background-color: #f9fafb;
109
+ border-color: #d1d5db;
110
+ }
111
+
112
+ .ca-icon {
113
+ flex-shrink: 0;
114
+ }
115
+
116
+ /* Divider */
117
+ .ca-divider {
118
+ position: relative;
119
+ text-align: center;
120
+ margin: 1.5rem 0;
121
+ }
122
+
123
+ .ca-divider::before {
124
+ content: "";
125
+ position: absolute;
126
+ top: 50%;
127
+ left: 0;
128
+ right: 0;
129
+ height: 1px;
130
+ background-color: #e5e7eb;
131
+ }
132
+
133
+ .ca-divider-text {
134
+ position: relative;
135
+ background-color: white;
136
+ padding: 0 0.75rem;
137
+ color: #6b7280;
138
+ font-size: 0.875rem;
139
+ font-weight: 400;
140
+ }
141
+
142
+ .ca-social-header {
143
+ font-size: 0.875rem;
144
+ font-weight: 500;
145
+ color: #374151;
146
+ text-align: center;
147
+ margin-bottom: 1rem;
148
+ }
149
+
150
+ .ca-footer {
151
+ margin-top: 2rem;
152
+ text-align: center;
153
+ font-size: 0.875rem;
154
+ color: #6b7280;
155
+ }
156
+
157
+ .ca-link {
158
+ color: #2563eb;
159
+ text-decoration: none;
160
+ cursor: pointer;
161
+ background: none;
162
+ border: none;
163
+ padding: 0;
164
+ font: inherit;
165
+ font-weight: 500;
166
+ }
167
+
168
+ .ca-link:hover {
169
+ text-decoration: underline;
170
+ color: #1d4ed8;
171
+ }
172
+
173
+ .ca-error {
174
+ background-color: #fef2f2;
175
+ color: #ef4444;
176
+ font-size: 0.875rem;
177
+ padding: 0.75rem;
178
+ border-radius: 6px;
179
+ border: 1px solid #fee2e2;
180
+ text-align: center;
181
+ }
182
+
183
+ /* New Layout Classes */
184
+ .ca-social-column {
185
+ display: flex;
186
+ flex-direction: column;
187
+ gap: 0.75rem;
188
+ margin-bottom: 1.5rem;
189
+ }
190
+
191
+ .ca-container-wide {
192
+ max-width: 600px;
193
+ }
194
+
195
+ /* Split Layout */
196
+ .ca-split-body {
197
+ display: flex;
198
+ flex-direction: column;
199
+ gap: 1.5rem;
200
+ }
201
+
202
+ @media (min-width: 640px) {
203
+ .ca-layout-split .ca-split-body {
204
+ flex-direction: row;
205
+ align-items: stretch;
206
+ }
207
+
208
+ .ca-layout-split.ca-container {
209
+ /* base styles, width controlled by utility classes */
210
+ }
211
+
212
+ /* Width Variants */
213
+ .ca-layout-split.ca-width-compact {
214
+ max-width: 640px !important;
215
+ }
216
+
217
+ .ca-layout-split.ca-width-default {
218
+ max-width: 768px !important;
219
+ }
220
+
221
+ .ca-layout-split.ca-width-wide {
222
+ max-width: 1000px !important;
223
+ }
224
+
225
+ .ca-split-main {
226
+ flex: 2;
227
+ min-width: 0;
228
+ }
229
+
230
+ .ca-split-divider {
231
+ display: flex;
232
+ flex-direction: column;
233
+ align-items: center;
234
+ justify-content: center;
235
+ padding: 0 1.5rem;
236
+ position: relative;
237
+ }
238
+
239
+ .ca-split-divider::before {
240
+ content: "";
241
+ position: absolute;
242
+ top: 10%;
243
+ bottom: 10%;
244
+ left: 50%;
245
+ width: 1px;
246
+ background-color: #e5e7eb;
247
+ }
248
+
249
+ .ca-split-divider-text {
250
+ background-color: white;
251
+ padding: 0.5rem 0;
252
+ color: #6b7280;
253
+ font-size: 0.875rem;
254
+ z-index: 1;
255
+ }
256
+
257
+ .ca-split-social {
258
+ flex: 1;
259
+ flex-shrink: 0;
260
+ display: flex;
261
+ flex-direction: column;
262
+ justify-content: center;
263
+ }
264
+ }
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@contentgrowth/content-auth",
3
+ "version": "0.0.1",
4
+ "description": "Better Auth wrapper with UI components for Cloudflare Workers & Pages",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "content-auth": "./dist/cli.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ },
17
+ "./backend": {
18
+ "types": "./dist/backend/index.d.ts",
19
+ "import": "./dist/backend/index.js"
20
+ },
21
+ "./frontend": {
22
+ "types": "./dist/frontend/index.d.ts",
23
+ "import": "./dist/frontend/index.js"
24
+ },
25
+ "./client": {
26
+ "types": "./dist/frontend/client.d.ts",
27
+ "import": "./dist/frontend/client.js"
28
+ },
29
+ "./styles.css": "./dist/styles.css"
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "schema",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
37
+ "scripts": {
38
+ "build": "tsup && cp src/styles.css dist/styles.css",
39
+ "dev": "tsup --watch",
40
+ "prepublishOnly": "npm run build"
41
+ },
42
+ "keywords": [
43
+ "auth",
44
+ "better-auth",
45
+ "cloudflare",
46
+ "workers",
47
+ "pages",
48
+ "react"
49
+ ],
50
+ "author": "Content Growth",
51
+ "license": "MIT",
52
+ "peerDependencies": {
53
+ "react": "^18.0.0",
54
+ "react-dom": "^18.0.0"
55
+ },
56
+ "dependencies": {
57
+ "better-auth": "^1.0.0",
58
+ "cac": "^6.0.0",
59
+ "drizzle-orm": "^0.45.0",
60
+ "hono": "^4.0.0"
61
+ },
62
+ "devDependencies": {
63
+ "@cloudflare/workers-types": "^4.20240101.0",
64
+ "@types/node": "^20.0.0",
65
+ "@types/react": "^18.0.0",
66
+ "@types/react-dom": "^18.0.0",
67
+ "react": "^18.0.0",
68
+ "react-dom": "^18.0.0",
69
+ "tsup": "^8.0.0",
70
+ "typescript": "^5.0.0"
71
+ }
72
+ }
@@ -0,0 +1,115 @@
1
+ -- ============================================
2
+ -- @contentgrowth/content-auth - Database Schema Template
3
+ -- ============================================
4
+ --
5
+ -- USAGE:
6
+ -- 1. Copy this file to your project's migrations folder
7
+ -- 2. Add your application-specific tables after the auth tables
8
+ -- 3. Run migrations (e.g., wrangler d1 migrations apply DB --local)
9
+ --
10
+ -- EXTENDING TABLES:
11
+ -- You can add extra columns to any table for your business needs.
12
+ -- Just ensure you keep ALL the columns defined here - they are required
13
+ -- by Better Auth to function correctly.
14
+ --
15
+ -- ============================================
16
+
17
+ -- ==========================================
18
+ -- Core Authentication Tables
19
+ -- ==========================================
20
+
21
+ -- Users
22
+ CREATE TABLE IF NOT EXISTS user (
23
+ id TEXT PRIMARY KEY,
24
+ name TEXT NOT NULL,
25
+ email TEXT NOT NULL UNIQUE,
26
+ emailVerified BOOLEAN NOT NULL,
27
+ image TEXT,
28
+ createdAt TIMESTAMP NOT NULL,
29
+ updatedAt TIMESTAMP NOT NULL
30
+ );
31
+
32
+ -- Sessions
33
+ CREATE TABLE IF NOT EXISTS session (
34
+ id TEXT PRIMARY KEY,
35
+ expiresAt TIMESTAMP NOT NULL,
36
+ token TEXT NOT NULL UNIQUE,
37
+ createdAt TIMESTAMP NOT NULL,
38
+ updatedAt TIMESTAMP NOT NULL,
39
+ ipAddress TEXT,
40
+ userAgent TEXT,
41
+ userId TEXT NOT NULL REFERENCES user(id) ON DELETE CASCADE
42
+ );
43
+
44
+ -- OAuth/Credential Accounts
45
+ CREATE TABLE IF NOT EXISTS account (
46
+ id TEXT PRIMARY KEY,
47
+ accountId TEXT NOT NULL,
48
+ providerId TEXT NOT NULL,
49
+ userId TEXT NOT NULL REFERENCES user(id) ON DELETE CASCADE,
50
+ accessToken TEXT,
51
+ refreshToken TEXT,
52
+ idToken TEXT,
53
+ accessTokenExpiresAt TIMESTAMP,
54
+ refreshTokenExpiresAt TIMESTAMP,
55
+ scope TEXT,
56
+ password TEXT,
57
+ createdAt TIMESTAMP NOT NULL,
58
+ updatedAt TIMESTAMP NOT NULL
59
+ );
60
+
61
+ -- Email/Token Verification
62
+ CREATE TABLE IF NOT EXISTS verification (
63
+ id TEXT PRIMARY KEY,
64
+ identifier TEXT NOT NULL,
65
+ value TEXT NOT NULL,
66
+ expiresAt TIMESTAMP NOT NULL,
67
+ createdAt TIMESTAMP,
68
+ updatedAt TIMESTAMP
69
+ );
70
+
71
+ -- ==========================================
72
+ -- Organization Plugin Tables
73
+ -- ==========================================
74
+
75
+ -- Organizations
76
+ CREATE TABLE IF NOT EXISTS organization (
77
+ id TEXT PRIMARY KEY,
78
+ name TEXT NOT NULL,
79
+ slug TEXT UNIQUE,
80
+ logo TEXT,
81
+ createdAt TIMESTAMP NOT NULL,
82
+ metadata TEXT -- JSON: Use for custom org data (e.g., billing, verification status)
83
+ );
84
+
85
+ -- Organization Members
86
+ CREATE TABLE IF NOT EXISTS member (
87
+ id TEXT PRIMARY KEY,
88
+ organizationId TEXT NOT NULL REFERENCES organization(id) ON DELETE CASCADE,
89
+ userId TEXT NOT NULL REFERENCES user(id) ON DELETE CASCADE,
90
+ role TEXT NOT NULL, -- 'owner', 'admin', 'member'
91
+ createdAt TIMESTAMP NOT NULL
92
+ );
93
+
94
+ -- Organization Invitations
95
+ CREATE TABLE IF NOT EXISTS invitation (
96
+ id TEXT PRIMARY KEY,
97
+ organizationId TEXT NOT NULL REFERENCES organization(id) ON DELETE CASCADE,
98
+ email TEXT NOT NULL,
99
+ role TEXT,
100
+ status TEXT NOT NULL, -- 'pending', 'accepted', 'rejected', 'expired'
101
+ expiresAt TIMESTAMP NOT NULL,
102
+ inviterId TEXT NOT NULL REFERENCES user(id) ON DELETE CASCADE
103
+ );
104
+
105
+ -- ==========================================
106
+ -- YOUR APPLICATION TABLES GO BELOW
107
+ -- ==========================================
108
+ -- Example:
109
+ --
110
+ -- CREATE TABLE IF NOT EXISTS my_entity (
111
+ -- id TEXT PRIMARY KEY,
112
+ -- org_id TEXT NOT NULL, -- References organization.id
113
+ -- name TEXT NOT NULL,
114
+ -- created_at INTEGER
115
+ -- );