@fluixi/cli 0.1.0-alpha.82 → 0.1.0-alpha.83
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/README.md +21 -3
- package/dist/add.cjs +590 -0
- package/dist/add.d.ts +10 -0
- package/dist/add.d.ts.map +1 -0
- package/dist/add.js +107 -0
- package/dist/add.mjs +562 -0
- package/dist/check.cjs +102 -0
- package/dist/check.d.ts +13 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +88 -0
- package/dist/check.mjs +76 -0
- package/dist/cli.cjs +977 -78
- package/dist/cli.js +44 -2
- package/dist/cli.mjs +976 -77
- package/dist/doctor.cjs +119 -0
- package/dist/doctor.d.ts +13 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +114 -0
- package/dist/doctor.mjs +92 -0
- package/dist/generate.cjs +614 -65
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +118 -48
- package/dist/generate.mjs +619 -64
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/report.cjs +54 -0
- package/dist/report.d.ts +5 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +31 -0
- package/dist/report.mjs +28 -0
- package/dist/scaffold/auth.cjs +422 -0
- package/dist/scaffold/auth.d.ts +39 -0
- package/dist/scaffold/auth.d.ts.map +1 -0
- package/dist/scaffold/auth.js +137 -0
- package/dist/scaffold/auth.mjs +389 -0
- package/dist/scaffold/edit.cjs +153 -0
- package/dist/scaffold/edit.d.ts +35 -0
- package/dist/scaffold/edit.d.ts.map +1 -0
- package/dist/scaffold/edit.js +140 -0
- package/dist/scaffold/edit.mjs +124 -0
- package/dist/scaffold/index.cjs +610 -0
- package/dist/scaffold/index.d.ts +10 -0
- package/dist/scaffold/index.d.ts.map +1 -0
- package/dist/scaffold/index.js +9 -0
- package/dist/scaffold/index.mjs +569 -0
- package/dist/scaffold/prompt.cjs +108 -0
- package/dist/scaffold/prompt.d.ts +9 -0
- package/dist/scaffold/prompt.d.ts.map +1 -0
- package/dist/scaffold/prompt.js +95 -0
- package/dist/scaffold/prompt.mjs +81 -0
- package/dist/scaffold/templates.cjs +274 -0
- package/dist/scaffold/templates.d.ts +26 -0
- package/dist/scaffold/templates.d.ts.map +1 -0
- package/dist/scaffold/templates.js +216 -0
- package/dist/scaffold/templates.mjs +229 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +19 -3
package/dist/generate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AA8MA,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAgGjF"}
|
package/dist/generate.js
CHANGED
|
@@ -4,18 +4,32 @@
|
|
|
4
4
|
* fluixi g route about → src/routes/about.tsx (a file route)
|
|
5
5
|
* fluixi g route blog/[id] → src/routes/blog/[id].tsx
|
|
6
6
|
* fluixi g middleware → src/middleware.ts
|
|
7
|
+
* fluixi g service Orders → src/services/orders.ts, listed in src/app.config.ts
|
|
8
|
+
* fluixi g auth oauth2 → env config, auth service, callback and login routes
|
|
7
9
|
*/
|
|
8
10
|
import { writeFileSync, readFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
9
11
|
import { resolve, dirname, relative, basename } from 'node:path';
|
|
10
12
|
import { c } from '@fluixi/start/ui';
|
|
11
|
-
|
|
13
|
+
import { envPublicNames, ensureAuthEnv, registerModule, ScaffoldError, setupBetterAuth, setupOAuth2, templates as t, writeOnce as writeOnceTo, importPath, } from './scaffold/index.js';
|
|
14
|
+
import { report, reportAuth } from './report.js';
|
|
15
|
+
const GEN_USAGE = `Usage: fluixi generate <kind> [name] [options]
|
|
12
16
|
|
|
13
17
|
Kinds:
|
|
14
|
-
component <Name>
|
|
15
|
-
route <path>
|
|
16
|
-
middleware
|
|
17
|
-
|
|
18
|
+
component <Name> a reusable component → src/components/<Name>.{tsx,ts}
|
|
19
|
+
route <path> a file-based route page → src/routes/<path>.{tsx,ts}
|
|
20
|
+
middleware the request middleware file → src/middleware.ts
|
|
21
|
+
env typed config from env.public → src/config/env.ts
|
|
22
|
+
module <name> an app module → src/services/<name>/<name>.module.ts
|
|
23
|
+
service <Name> [--server] a service, token and module → src/services/<name>.ts (.server.ts)
|
|
24
|
+
api <path> [--role <role>] an API route, guarded by role → src/api/<path>.ts
|
|
25
|
+
server-fn <name> a "use server" function → src/server/<name>.ts
|
|
26
|
+
auth oauth2 [--provider <p>] [--tokens browser|server]
|
|
27
|
+
@fluixi/oauth2 wiring: env config, service, routes, .env.example
|
|
28
|
+
(fluixi add auth does the same, asks, and installs)
|
|
29
|
+
auth better-auth @fluixi/auth wiring → auth.config + auth.client + middleware + /api/auth
|
|
18
30
|
|
|
31
|
+
Modules and services are listed in src/app.config.ts, or app.config.server.ts for --server,
|
|
32
|
+
which is created when missing. Providers: ${t.PROVIDERS.join(', ')}.
|
|
19
33
|
Component/route syntax follows the project (JSX → .tsx, html\`\` → .ts); override with --jsx / --html.
|
|
20
34
|
`;
|
|
21
35
|
/**
|
|
@@ -76,6 +90,27 @@ function resolveHint(Name, ext) {
|
|
|
76
90
|
console.log(` ${c.gray(`resolve: [{ match: /^([A-Z]\\w+)$/, module: '/src/components/$1.${ext}' }]`)}`);
|
|
77
91
|
console.log(` ${c.gray('one pattern covers the whole folder. Importing it works too — including with')} ${c.cyan('load:')}`);
|
|
78
92
|
}
|
|
93
|
+
/** The value of `--name value` or `--name=value`. */
|
|
94
|
+
function option(name) {
|
|
95
|
+
const args = process.argv;
|
|
96
|
+
const i = args.indexOf(`--${name}`);
|
|
97
|
+
if (i !== -1 && args[i + 1] && !args[i + 1].startsWith('--'))
|
|
98
|
+
return args[i + 1];
|
|
99
|
+
return args.find((a) => a.startsWith(`--${name}=`))?.slice(name.length + 3);
|
|
100
|
+
}
|
|
101
|
+
const kebab = (s) => s.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
|
102
|
+
/** Write a file the app may already have, keeping theirs. Returns whether it wrote. */
|
|
103
|
+
function writeOnce(file, content) {
|
|
104
|
+
const steps = [];
|
|
105
|
+
const wrote = writeOnceTo(steps, file, content);
|
|
106
|
+
report(steps);
|
|
107
|
+
return wrote;
|
|
108
|
+
}
|
|
109
|
+
function registerIn(server, file, name, entry = name) {
|
|
110
|
+
const steps = [];
|
|
111
|
+
registerModule(steps, process.cwd(), server, file, name, entry);
|
|
112
|
+
report(steps);
|
|
113
|
+
}
|
|
79
114
|
function write(file, content) {
|
|
80
115
|
const rel = relative(process.cwd(), file);
|
|
81
116
|
if (existsSync(file)) {
|
|
@@ -140,44 +175,6 @@ export default defineMiddleware([
|
|
|
140
175
|
},
|
|
141
176
|
]);
|
|
142
177
|
`;
|
|
143
|
-
const authConfig = () => `import { betterAuth } from 'better-auth';
|
|
144
|
-
import { defineAuth } from '@fluixi/auth/server';
|
|
145
|
-
|
|
146
|
-
export type AppUser = { id: string; email: string; name?: string; role?: string };
|
|
147
|
-
|
|
148
|
-
// Better Auth owns the audited primitives; defineAuth registers it with @fluixi/auth.
|
|
149
|
-
export const auth = defineAuth<AppUser>(
|
|
150
|
-
betterAuth({
|
|
151
|
-
// database: <your adapter>,
|
|
152
|
-
emailAndPassword: { enabled: true },
|
|
153
|
-
// socialProviders: { google: { … }, github: { … } },
|
|
154
|
-
} as Parameters<typeof betterAuth>[0]),
|
|
155
|
-
);
|
|
156
|
-
`;
|
|
157
|
-
const authClient = () => `import { createAuthClient } from 'better-auth/client';
|
|
158
|
-
import { createAuthHooks } from '@fluixi/auth/client';
|
|
159
|
-
import type { AppUser } from './auth.config.js';
|
|
160
|
-
|
|
161
|
-
const client = createAuthClient({ baseURL: '/api/auth' });
|
|
162
|
-
|
|
163
|
-
// Or, to reuse an existing reactive session: createAuthHooks({ session: yourSessionStore }).
|
|
164
|
-
export const { useUser, useSession, useAuth, useSignIn, useSignOut, protectedRoute } =
|
|
165
|
-
createAuthHooks<AppUser>({ client, loginPath: '/login' });
|
|
166
|
-
`;
|
|
167
|
-
const authMiddleware = () => `import { defineMiddleware } from '@fluixi/start';
|
|
168
|
-
import { authMiddleware } from '@fluixi/auth/server';
|
|
169
|
-
import './auth.config.js';
|
|
170
|
-
|
|
171
|
-
export default defineMiddleware([authMiddleware()]);
|
|
172
|
-
`;
|
|
173
|
-
const authRoute = () => `import { mountAuthRoutes } from '@fluixi/auth/server';
|
|
174
|
-
import '../../../auth.config.js';
|
|
175
|
-
|
|
176
|
-
const handler = mountAuthRoutes();
|
|
177
|
-
export const GET = handler;
|
|
178
|
-
export const POST = handler;
|
|
179
|
-
export default handler;
|
|
180
|
-
`;
|
|
181
178
|
export function generate(kind, name) {
|
|
182
179
|
switch (kind) {
|
|
183
180
|
case 'component':
|
|
@@ -204,18 +201,91 @@ export function generate(kind, name) {
|
|
|
204
201
|
case 'm':
|
|
205
202
|
write(resolve('src/middleware.ts'), middleware());
|
|
206
203
|
break;
|
|
204
|
+
case 'env': {
|
|
205
|
+
const names = (envPublicNames(resolve('fluixi.config.ts')) ?? []).filter((n) => !n.startsWith('AUTH_'));
|
|
206
|
+
write(resolve('src/config/env.ts'), t.envConfig(names));
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
case 'module': {
|
|
210
|
+
if (!name)
|
|
211
|
+
return fail('module name required, e.g. `fluixi g module billing`');
|
|
212
|
+
const slug = kebab(name);
|
|
213
|
+
const file = resolve('src/services', slug, `${slug}.module.ts`);
|
|
214
|
+
write(file, t.moduleFile(pascal(name), slug));
|
|
215
|
+
registerIn(false, file, `${pascal(name)}Module`);
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
case 'service':
|
|
219
|
+
case 's': {
|
|
220
|
+
if (!name)
|
|
221
|
+
return fail('service name required, e.g. `fluixi g service Orders`');
|
|
222
|
+
const Name = pascal(name).replace(/Service$/, '') || 'App';
|
|
223
|
+
const server = process.argv.includes('--server');
|
|
224
|
+
const file = resolve('src/services', `${kebab(Name)}${server ? '.server' : ''}.ts`);
|
|
225
|
+
write(file, t.serviceFile(Name, kebab(Name), server));
|
|
226
|
+
registerIn(server, file, `${Name}Module`);
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
case 'api': {
|
|
230
|
+
if (!name)
|
|
231
|
+
return fail('api path required, e.g. `fluixi g api users/[id]`');
|
|
232
|
+
const file = resolve('src/api', `${name.replace(/\.ts$/, '')}.ts`);
|
|
233
|
+
const role = option('role');
|
|
234
|
+
if (!role) {
|
|
235
|
+
write(file, t.apiRoute());
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
const verify = resolve('src/services/verify.server.ts');
|
|
239
|
+
write(file, t.guardedApiRoute(importPath(file, verify), role));
|
|
240
|
+
writeOnce(verify, t.verifyServer());
|
|
241
|
+
{
|
|
242
|
+
const steps = [];
|
|
243
|
+
ensureAuthEnv(steps, process.cwd());
|
|
244
|
+
report(steps);
|
|
245
|
+
}
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
case 'server-fn': {
|
|
249
|
+
if (!name)
|
|
250
|
+
return fail('function name required, e.g. `fluixi g server-fn getUser`');
|
|
251
|
+
const fn = name.replace(/[^a-zA-Z0-9]+(.)/g, (_, ch) => ch.toUpperCase());
|
|
252
|
+
write(resolve('src/server', `${fn}.ts`), t.serverFn(fn));
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
207
255
|
case 'auth':
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
256
|
+
try {
|
|
257
|
+
if (name === 'oauth2') {
|
|
258
|
+
reportAuth(setupOAuth2(process.cwd(), {
|
|
259
|
+
provider: option('provider'),
|
|
260
|
+
tokens: tokensOption(),
|
|
261
|
+
format: detectFormat(),
|
|
262
|
+
}), 'install @fluixi/oauth2');
|
|
263
|
+
}
|
|
264
|
+
else if (!name || name === 'better-auth') {
|
|
265
|
+
reportAuth(setupBetterAuth(process.cwd()), 'install @fluixi/auth and better-auth');
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
return fail(`unknown auth kind ${name}: oauth2 or better-auth`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
if (error instanceof ScaffoldError)
|
|
273
|
+
return fail(error.message);
|
|
274
|
+
throw error;
|
|
275
|
+
}
|
|
213
276
|
break;
|
|
214
277
|
default:
|
|
215
278
|
console.error(GEN_USAGE);
|
|
216
279
|
process.exit(1);
|
|
217
280
|
}
|
|
218
281
|
}
|
|
282
|
+
function tokensOption() {
|
|
283
|
+
const tokens = option('tokens');
|
|
284
|
+
if (tokens !== undefined && tokens !== 'browser' && tokens !== 'server') {
|
|
285
|
+
fail('--tokens is browser or server');
|
|
286
|
+
}
|
|
287
|
+
return tokens;
|
|
288
|
+
}
|
|
219
289
|
function fail(msg) {
|
|
220
290
|
console.error(` ${c.red('✗')} ${msg}`);
|
|
221
291
|
process.exit(1);
|