flarecms 0.1.0 → 0.1.2

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.
Files changed (113) hide show
  1. package/LICENSE +21 -0
  2. package/dist/auth/index.js +201 -1
  3. package/dist/cli/commands.js +5554 -55
  4. package/dist/cli/index.js +5554 -55
  5. package/dist/cli/mcp.js +30 -0
  6. package/dist/client/index.js +23576 -0
  7. package/dist/db/index.js +10392 -25
  8. package/dist/index.js +56776 -7582
  9. package/dist/server/index.js +43280 -0
  10. package/dist/style.css +5536 -0
  11. package/package.json +33 -30
  12. package/scripts/fix-api-paths.mjs +0 -32
  13. package/scripts/fix-imports.mjs +0 -38
  14. package/scripts/prefix-css.mjs +0 -45
  15. package/src/api/lib/cache.ts +0 -45
  16. package/src/api/lib/response.ts +0 -40
  17. package/src/api/middlewares/auth.ts +0 -186
  18. package/src/api/middlewares/cors.ts +0 -10
  19. package/src/api/middlewares/rbac.ts +0 -85
  20. package/src/api/routes/auth.ts +0 -377
  21. package/src/api/routes/collections.ts +0 -205
  22. package/src/api/routes/content.ts +0 -175
  23. package/src/api/routes/device.ts +0 -160
  24. package/src/api/routes/magic.ts +0 -150
  25. package/src/api/routes/mcp.ts +0 -273
  26. package/src/api/routes/oauth.ts +0 -160
  27. package/src/api/routes/settings.ts +0 -43
  28. package/src/api/routes/setup.ts +0 -307
  29. package/src/api/routes/tokens.ts +0 -80
  30. package/src/api/schemas/auth.ts +0 -15
  31. package/src/api/schemas/index.ts +0 -51
  32. package/src/api/schemas/tokens.ts +0 -24
  33. package/src/auth/index.ts +0 -28
  34. package/src/cli/commands.ts +0 -217
  35. package/src/cli/index.ts +0 -21
  36. package/src/cli/mcp.ts +0 -210
  37. package/src/cli/tests/cli.test.ts +0 -40
  38. package/src/cli/tests/create.test.ts +0 -87
  39. package/src/client/FlareAdminRouter.tsx +0 -47
  40. package/src/client/app.tsx +0 -175
  41. package/src/client/components/app-sidebar.tsx +0 -227
  42. package/src/client/components/collection-modal.tsx +0 -215
  43. package/src/client/components/content-list.tsx +0 -247
  44. package/src/client/components/dynamic-form.tsx +0 -190
  45. package/src/client/components/field-modal.tsx +0 -221
  46. package/src/client/components/settings/api-token-section.tsx +0 -400
  47. package/src/client/components/settings/general-section.tsx +0 -224
  48. package/src/client/components/settings/security-section.tsx +0 -154
  49. package/src/client/components/settings/seo-section.tsx +0 -200
  50. package/src/client/components/settings/signup-section.tsx +0 -257
  51. package/src/client/components/ui/accordion.tsx +0 -78
  52. package/src/client/components/ui/avatar.tsx +0 -107
  53. package/src/client/components/ui/badge.tsx +0 -52
  54. package/src/client/components/ui/button.tsx +0 -60
  55. package/src/client/components/ui/card.tsx +0 -103
  56. package/src/client/components/ui/checkbox.tsx +0 -27
  57. package/src/client/components/ui/collapsible.tsx +0 -19
  58. package/src/client/components/ui/dialog.tsx +0 -162
  59. package/src/client/components/ui/icon-picker.tsx +0 -485
  60. package/src/client/components/ui/icons-data.ts +0 -8476
  61. package/src/client/components/ui/input.tsx +0 -20
  62. package/src/client/components/ui/label.tsx +0 -20
  63. package/src/client/components/ui/popover.tsx +0 -91
  64. package/src/client/components/ui/select.tsx +0 -204
  65. package/src/client/components/ui/separator.tsx +0 -23
  66. package/src/client/components/ui/sheet.tsx +0 -141
  67. package/src/client/components/ui/sidebar.tsx +0 -722
  68. package/src/client/components/ui/skeleton.tsx +0 -13
  69. package/src/client/components/ui/sonner.tsx +0 -47
  70. package/src/client/components/ui/switch.tsx +0 -30
  71. package/src/client/components/ui/table.tsx +0 -116
  72. package/src/client/components/ui/tabs.tsx +0 -80
  73. package/src/client/components/ui/textarea.tsx +0 -18
  74. package/src/client/components/ui/tooltip.tsx +0 -68
  75. package/src/client/hooks/use-mobile.ts +0 -19
  76. package/src/client/index.css +0 -149
  77. package/src/client/index.ts +0 -7
  78. package/src/client/layouts/admin-layout.tsx +0 -93
  79. package/src/client/layouts/settings-layout.tsx +0 -104
  80. package/src/client/lib/api.ts +0 -72
  81. package/src/client/lib/utils.ts +0 -6
  82. package/src/client/main.tsx +0 -10
  83. package/src/client/pages/collection-detail.tsx +0 -634
  84. package/src/client/pages/collections.tsx +0 -180
  85. package/src/client/pages/dashboard.tsx +0 -133
  86. package/src/client/pages/device.tsx +0 -66
  87. package/src/client/pages/document-detail-page.tsx +0 -139
  88. package/src/client/pages/documents-page.tsx +0 -103
  89. package/src/client/pages/login.tsx +0 -345
  90. package/src/client/pages/settings.tsx +0 -65
  91. package/src/client/pages/setup.tsx +0 -129
  92. package/src/client/pages/signup.tsx +0 -188
  93. package/src/client/store/auth.ts +0 -30
  94. package/src/client/store/collections.ts +0 -13
  95. package/src/client/store/config.ts +0 -12
  96. package/src/client/store/fetcher.ts +0 -30
  97. package/src/client/store/router.ts +0 -95
  98. package/src/client/store/schema.ts +0 -39
  99. package/src/client/store/settings.ts +0 -31
  100. package/src/client/types.ts +0 -34
  101. package/src/db/dynamic.ts +0 -70
  102. package/src/db/index.ts +0 -16
  103. package/src/db/migrations/001_initial_schema.ts +0 -57
  104. package/src/db/migrations/002_auth_tables.ts +0 -84
  105. package/src/db/migrator.ts +0 -61
  106. package/src/db/schema.ts +0 -142
  107. package/src/index.ts +0 -12
  108. package/src/server/index.ts +0 -66
  109. package/src/types.ts +0 -20
  110. package/tests/css.test.ts +0 -21
  111. package/tests/modular.test.ts +0 -29
  112. package/tsconfig.json +0 -10
  113. /package/{style.css.d.ts → dist/style.css.d.ts} +0 -0
@@ -1,84 +0,0 @@
1
- import { Kysely, sql } from 'kysely';
2
-
3
- export async function up(db: Kysely<any>): Promise<void> {
4
- // Core Sessions
5
- await db.schema
6
- .createTable('fc_sessions')
7
- .ifNotExists()
8
- .addColumn('id', 'text', (col) => col.primaryKey())
9
- .addColumn('user_id', 'text', (col) => col.notNull())
10
- .addColumn('expires_at', 'text', (col) => col.notNull())
11
- .execute();
12
-
13
- // Biometric Passkeys
14
- await db.schema
15
- .createTable('fc_passkeys')
16
- .ifNotExists()
17
- .addColumn('id', 'text', (col) => col.primaryKey())
18
- .addColumn('user_id', 'text', (col) => col.notNull())
19
- .addColumn('name', 'text')
20
- .addColumn('public_key', 'text', (col) => col.notNull())
21
- .addColumn('counter', 'integer', (col) => col.notNull())
22
- .addColumn('device_type', 'text', (col) => col.notNull())
23
- .addColumn('backed_up', 'integer', (col) => col.notNull())
24
- .addColumn('transports', 'text')
25
- .addColumn('created_at', 'text', (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`))
26
- .addColumn('last_used_at', 'text')
27
- .execute();
28
-
29
- // API Token Management
30
- await db.schema
31
- .createTable('fc_api_tokens')
32
- .ifNotExists()
33
- .addColumn('id', 'text', (col) => col.primaryKey())
34
- .addColumn('user_id', 'text', (col) => col.notNull())
35
- .addColumn('name', 'text', (col) => col.notNull())
36
- .addColumn('hash', 'text', (col) => col.notNull())
37
- .addColumn('scopes', 'text', (col) => col.notNull())
38
- .addColumn('expires_at', 'text')
39
- .addColumn('last_used_at', 'text')
40
- .addColumn('created_at', 'text', (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`))
41
- .execute();
42
-
43
- // OAuth Providers Linkage
44
- await db.schema
45
- .createTable('fc_oauth_accounts')
46
- .ifNotExists()
47
- .addColumn('provider_id', 'text', (col) => col.notNull())
48
- .addColumn('provider_user_id', 'text', (col) => col.notNull())
49
- .addColumn('user_id', 'text', (col) => col.notNull())
50
- .addPrimaryKeyConstraint('pk_oauth_accounts', ['provider_id', 'provider_user_id'])
51
- .execute();
52
-
53
- // Email/OTP Verification Tokens
54
- await db.schema
55
- .createTable('fc_verification_tokens')
56
- .ifNotExists()
57
- .addColumn('identifier', 'text', (col) => col.notNull())
58
- .addColumn('token', 'text', (col) => col.notNull())
59
- .addColumn('expires_at', 'text', (col) => col.notNull())
60
- .addPrimaryKeyConstraint('pk_verification_tokens', ['identifier', 'token'])
61
- .execute();
62
-
63
- // Device Code Authorization (IoT/TV flows)
64
- await db.schema
65
- .createTable('fc_device_codes')
66
- .ifNotExists()
67
- .addColumn('device_code', 'text', (col) => col.primaryKey())
68
- .addColumn('user_code', 'text', (col) => col.notNull().unique())
69
- .addColumn('client_id', 'text', (col) => col.notNull())
70
- .addColumn('user_id', 'text')
71
- .addColumn('scopes', 'text', (col) => col.notNull())
72
- .addColumn('expires_at', 'text', (col) => col.notNull())
73
- .addColumn('created_at', 'text', (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`))
74
- .execute();
75
- }
76
-
77
- export async function down(db: Kysely<any>): Promise<void> {
78
- await db.schema.dropTable('fc_sessions').ifExists().execute();
79
- await db.schema.dropTable('fc_passkeys').ifExists().execute();
80
- await db.schema.dropTable('fc_api_tokens').ifExists().execute();
81
- await db.schema.dropTable('fc_oauth_accounts').ifExists().execute();
82
- await db.schema.dropTable('fc_verification_tokens').ifExists().execute();
83
- await db.schema.dropTable('fc_device_codes').ifExists().execute();
84
- }
@@ -1,61 +0,0 @@
1
- import { sql, type Migration } from 'kysely';
2
- import type { FlareDb } from './index';
3
-
4
- import * as initialSchema from './migrations/001_initial_schema';
5
- import * as authTables from './migrations/002_auth_tables';
6
-
7
- const STATIC_MIGRATIONS: Record<string, any> = {
8
- '001_initial_schema': initialSchema,
9
- '002_auth_tables': authTables,
10
- };
11
-
12
- /**
13
- * Manual D1-safe migration runner.
14
- * We avoid Kysely's built-in Migrator because it uses introspection (sqlite_master)
15
- * which Cloudflare D1 restricts, causing SQLITE_AUTH errors.
16
- */
17
- export async function runMigrations(db: FlareDb) {
18
- // 1. Ensure migrations table exists
19
- await sql`
20
- CREATE TABLE IF NOT EXISTS _fc_migrations (
21
- name TEXT PRIMARY KEY,
22
- executed_at TEXT DEFAULT CURRENT_TIMESTAMP
23
- )
24
- `.execute(db);
25
-
26
- // 2. Get executed migrations
27
- const executed = await db
28
- .selectFrom('_fc_migrations' as any)
29
- .select('name')
30
- .execute();
31
- const executedNames = new Set(executed.map((m: any) => m.name));
32
-
33
- const results: { name: string; status: 'Success' | 'Skipped' | 'Error' }[] = [];
34
-
35
- // 3. Run missing migrations in order
36
- const migrationNames = Object.keys(STATIC_MIGRATIONS).sort();
37
-
38
- for (const name of migrationNames) {
39
- if (executedNames.has(name)) {
40
- results.push({ name, status: 'Skipped' });
41
- continue;
42
- }
43
-
44
- try {
45
- const migration = STATIC_MIGRATIONS[name];
46
- await migration.up(db);
47
-
48
- await db
49
- .insertInto('_fc_migrations' as any)
50
- .values({ name })
51
- .execute();
52
-
53
- results.push({ name, status: 'Success' });
54
- } catch (err) {
55
- console.error(`Migration ${name} failed:`, err);
56
- throw err;
57
- }
58
- }
59
-
60
- return results;
61
- }
package/src/db/schema.ts DELETED
@@ -1,142 +0,0 @@
1
- import type { ColumnType, Generated, Selectable, Insertable, Updateable } from 'kysely';
2
-
3
- export interface Database {
4
- options: OptionsTable;
5
- fc_collections: CollectionsTable;
6
- fc_fields: FieldsTable;
7
- fc_users: UsersTable;
8
- fc_passkeys: PasskeysTable;
9
- fc_sessions: SessionsTable;
10
- fc_api_tokens: ApiTokensTable;
11
- fc_oauth_accounts: OAuthAccountsTable;
12
- fc_verification_tokens: VerificationTokensTable;
13
- fc_device_codes: DeviceCodesTable;
14
- // This helps typescript understand that we can have arbitrary string tables for dynamic content
15
- [tableName: string]: any;
16
- }
17
-
18
- export interface OptionsTable {
19
- name: string;
20
- value: string;
21
- }
22
-
23
- export type Option = Selectable<OptionsTable>;
24
- export type NewOption = Insertable<OptionsTable>;
25
-
26
- export interface CollectionsTable {
27
- id: string;
28
- slug: string;
29
- label: string;
30
- label_singular: string | null;
31
- description: string | null;
32
- icon: string | null;
33
- is_public: ColumnType<number, number | undefined, number>;
34
- features: string | null; // JSON array of strings
35
- url_pattern: string | null;
36
- created_at: ColumnType<string, string | undefined, never>;
37
- updated_at: ColumnType<string, string | undefined, string>;
38
- }
39
-
40
- export type Collection = Selectable<CollectionsTable>;
41
- export type NewCollection = Insertable<CollectionsTable>;
42
- export type CollectionUpdate = Updateable<CollectionsTable>;
43
-
44
- export interface FieldsTable {
45
- id: string;
46
- collection_id: string;
47
- label: string;
48
- slug: string;
49
- type: string;
50
- required: ColumnType<number, number | undefined, number>; // sqlite boolean
51
- created_at: ColumnType<string, string | undefined, never>;
52
- }
53
-
54
- export type Field = Selectable<FieldsTable>;
55
- export type NewField = Insertable<FieldsTable>;
56
-
57
- export interface UsersTable {
58
- id: string;
59
- email: string;
60
- password: string | null; // Nullable if passkey only
61
- role: string;
62
- disabled: ColumnType<number, number | undefined, number>;
63
- created_at: ColumnType<string, string | undefined, never>;
64
- updated_at: ColumnType<string, string | undefined, string>;
65
- }
66
-
67
- export type User = Selectable<UsersTable>;
68
- export type NewUser = Insertable<UsersTable>;
69
- export type UserUpdate = Updateable<UsersTable>;
70
-
71
- export interface PasskeysTable {
72
- id: string; // credentialID base64url encoded
73
- user_id: string;
74
- name: string | null; // User-defined alias
75
- public_key: string; // base64url encoded
76
- counter: number;
77
- device_type: string;
78
- backed_up: number;
79
- transports: string | null;
80
- created_at: ColumnType<string, string | undefined, never>;
81
- last_used_at: string | null;
82
- }
83
-
84
- export type Passkey = Selectable<PasskeysTable>;
85
- export type NewPasskey = Insertable<PasskeysTable>;
86
- export type PasskeyUpdate = Updateable<PasskeysTable>;
87
-
88
- export interface SessionsTable {
89
- id: string;
90
- user_id: string;
91
- expires_at: string;
92
- }
93
-
94
- export type Session = Selectable<SessionsTable>;
95
- export type NewSession = Insertable<SessionsTable>;
96
- export type SessionUpdate = Updateable<SessionsTable>;
97
-
98
- export interface ApiTokensTable {
99
- id: string; // Token prefix (ec_pat_...)
100
- user_id: string;
101
- name: string;
102
- hash: string; // SHA-256 hashed secret
103
- scopes: string; // JSON string (array or structured object)
104
- expires_at: string | null;
105
- last_used_at: string | null;
106
- created_at: ColumnType<string, string | undefined, never>;
107
- }
108
-
109
- export type ApiToken = Selectable<ApiTokensTable>;
110
- export type NewApiToken = Insertable<ApiTokensTable>;
111
-
112
- export interface OAuthAccountsTable {
113
- provider_id: string;
114
- provider_user_id: string;
115
- user_id: string;
116
- }
117
-
118
- export type OAuthAccount = Selectable<OAuthAccountsTable>;
119
- export type NewOAuthAccount = Insertable<OAuthAccountsTable>;
120
-
121
- export interface VerificationTokensTable {
122
- identifier: string; // Email
123
- token: string; // Hashed token
124
- expires_at: string;
125
- }
126
-
127
- export type VerificationToken = Selectable<VerificationTokensTable>;
128
- export type NewVerificationToken = Insertable<VerificationTokensTable>;
129
-
130
- export interface DeviceCodesTable {
131
- device_code: string;
132
- user_code: string;
133
- client_id: string;
134
- user_id: string | null; // Null until user approves
135
- scopes: string; // JSON string array
136
- expires_at: string;
137
- created_at: ColumnType<string, string | undefined, never>;
138
- }
139
-
140
- export type DeviceCode = Selectable<DeviceCodesTable>;
141
- export type NewDeviceCode = Insertable<DeviceCodesTable>;
142
- export type DeviceCodeUpdate = Updateable<DeviceCodesTable>;
package/src/index.ts DELETED
@@ -1,12 +0,0 @@
1
- export * from './auth';
2
- export * from './db';
3
- export * from './server';
4
- export * from './client';
5
- export * from './types';
6
-
7
- import { createFlareAPI } from './server';
8
-
9
- /**
10
- * @deprecated Use createFlareAPI from 'flarecms/server' for better modularity.
11
- */
12
- export const flarecms = createFlareAPI;
@@ -1,66 +0,0 @@
1
- import { Hono } from 'hono';
2
- import { corsMiddleware } from '../api/middlewares/cors';
3
- import { setupMiddleware, authMiddleware } from '../api/middlewares/auth';
4
- import { authRoutes } from '../api/routes/auth';
5
- import { setupRoutes } from '../api/routes/setup';
6
- import { collectionsRoutes } from '../api/routes/collections';
7
- import { contentRoutes } from '../api/routes/content';
8
- import { tokenRoutes } from '../api/routes/tokens';
9
- import { deviceRoutes } from '../api/routes/device';
10
- import { magicRoutes } from '../api/routes/magic';
11
- import { oauthRoutes } from '../api/routes/oauth';
12
- import { settingsRoutes } from '../api/routes/settings';
13
- import { mcpRoutes } from '../api/routes/mcp';
14
- import { apiResponse } from '../api/lib/response';
15
- import type { Bindings, Variables } from '../types';
16
-
17
- /**
18
- * Creates the modular FlareCMS API router.
19
- * This can be mounted into any Hono application.
20
- *
21
- * @example
22
- * app.route('/api', createFlareAPI({ base: '/admin' }));
23
- */
24
- export function createFlareAPI(options: { base?: string } = {}) {
25
- const base = options.base || '/admin';
26
- const api = new Hono<{ Bindings: Bindings; Variables: Variables }>();
27
-
28
- // Middlewares
29
- api.use('*', corsMiddleware);
30
- api.use('*', async (c, next) => {
31
- // Collect reserved slugs from base and standard system paths
32
- const adminPrefix = base.replace(/^\//, '') || 'admin';
33
- c.set('reservedSlugs', [
34
- adminPrefix,
35
- 'api',
36
- 'setup',
37
- 'auth',
38
- 'login',
39
- 'signup',
40
- 'collections',
41
- 'users',
42
- 'settings',
43
- 'oauth',
44
- ]);
45
- await next();
46
- });
47
-
48
- api.use('/*', setupMiddleware);
49
- api.use('/*', authMiddleware);
50
-
51
- // Routes
52
- api.route('/auth', authRoutes);
53
- api.route('/setup', setupRoutes);
54
- api.route('/collections', collectionsRoutes);
55
- api.route('/content', contentRoutes);
56
- api.route('/tokens', tokenRoutes);
57
- api.route('/device', deviceRoutes);
58
- api.route('/magic', magicRoutes);
59
- api.route('/oauth', oauthRoutes);
60
- api.route('/settings', settingsRoutes);
61
- api.route('/mcp', mcpRoutes);
62
-
63
- api.get('/health', (c) => apiResponse.ok(c, { status: 'ok' }));
64
-
65
- return api;
66
- }
package/src/types.ts DELETED
@@ -1,20 +0,0 @@
1
- import {
2
- type D1Database,
3
- type KVNamespace,
4
- type Fetcher,
5
- } from '@cloudflare/workers-types';
6
-
7
- export type Bindings = {
8
- DB: D1Database;
9
- KV: KVNamespace;
10
- ASSETS: Fetcher;
11
- AUTH_SECRET: string;
12
- GITHUB_CLIENT_ID?: string;
13
- GITHUB_CLIENT_SECRET?: string;
14
- };
15
-
16
- export type Variables = {
17
- user: any;
18
- scopes: string[];
19
- reservedSlugs: string[];
20
- };
package/tests/css.test.ts DELETED
@@ -1,21 +0,0 @@
1
- import { expect, test, describe } from "bun:test";
2
- import fs from "node:fs";
3
-
4
- describe("CSS Modularization", () => {
5
- test("CSS is built with flare-cms prefix", () => {
6
- const css = fs.readFileSync("./dist/style.css", "utf8");
7
- // Verify prefix exists
8
- expect(css).toContain(".flare-cms");
9
- });
10
-
11
- test("Global tags are scoped under flare-cms", () => {
12
- const css = fs.readFileSync("./dist/style.css", "utf8");
13
-
14
- // html/body are converted to .flare-cms
15
- expect(css).toContain(".flare-cms {");
16
-
17
- // Verify that utility classes are prefixed with the scope
18
- // Example: .flare-cms .bg-background
19
- expect(css).toContain(".flare-cms .bg-background");
20
- });
21
- });
@@ -1,29 +0,0 @@
1
- import { expect, test, describe } from "bun:test";
2
- import { createFlareAPI } from "../src/server";
3
- import { Hono } from "hono";
4
-
5
- describe("Modular API", () => {
6
- test("createFlareAPI returns a Hono instance", () => {
7
- const api = createFlareAPI();
8
- expect(api).toBeInstanceOf(Hono);
9
- });
10
-
11
- test("API has health check route", async () => {
12
- const api = createFlareAPI();
13
- const res = await api.request("/health");
14
- expect(res.status).toBe(200);
15
- const data: any = await res.json();
16
- expect(data.data.status).toBe("ok");
17
- });
18
-
19
- test("API injects reservedSlugs middleware", async () => {
20
- const api = createFlareAPI({ base: '/custom-admin' });
21
- api.get('/test-context', (c) => {
22
- return c.json({ slugs: c.get('reservedSlugs') });
23
- });
24
- const res = await api.request("/test-context");
25
- const data: any = await res.json();
26
- expect(data.slugs).toContain('custom-admin');
27
- expect(data.slugs).toContain('api');
28
- });
29
- });
package/tsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "baseUrl": ".",
5
- "paths": {
6
- "@/*": ["./src/client/*"]
7
- }
8
- },
9
- "include": ["src"]
10
- }
File without changes