@econneq/auth-cli 1.0.1 → 1.0.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.
package/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # @econneq/auth-cli
2
+
3
+ Interactive scaffolder for new Econneq Auth integrations. One command, a few prompts, a working `auth/` folder.
4
+
5
+ ## Position in the install order
6
+
7
+ ```
8
+ auth-cli (independent — no SDK packages required to run it)
9
+ ```
10
+
11
+ The CLI is standalone. You **don't** need `auth-core`, `auth-react`, or anything else installed to run it — it just *generates* files that depend on those packages. You'll install those after the CLI scaffolds your config.
12
+
13
+ ## Use without installing
14
+
15
+ ```bash
16
+ npx @econneq/auth-cli init
17
+ # or, after global install:
18
+ npm install -g @econneq/auth-cli
19
+ econneq-auth init
20
+ ```
21
+
22
+ The single command available today is `init`.
23
+
24
+ ## What `init` asks
25
+
26
+ | Prompt | Notes |
27
+ |---|---|
28
+ | Application name | Free text — used in generated comments |
29
+ | Auth API base URL | e.g. `https://auth.example.com` |
30
+ | Enable multi-tenant mode? | yes/no |
31
+ | Framework | Next.js, Remix, Vite, … |
32
+ | Token storage strategy | cookie / localStorage / memory |
33
+ | Auth methods | password, otp, oauth, … (multi-select) |
34
+
35
+ ## What `init` creates
36
+
37
+ ```
38
+ src/auth/auth.config.ts # defineAuthConfig(...) populated from your answers
39
+ src/auth/provider.tsx # <AuthProvider> wrapper ready to mount
40
+ proxy.ts # Next.js middleware (only when Next.js was picked)
41
+ ```
42
+
43
+ After the CLI finishes, install the SDK packages it referenced:
44
+
45
+ ```bash
46
+ npm install @econneq/auth-core @econneq/auth-react
47
+ # Next.js apps:
48
+ npm install @econneq/auth-nextjs
49
+ # If you want the hosted UI screens:
50
+ npm install @econneq/auth-ui
51
+ ```
52
+
53
+ Then mount the generated `Providers` component in your root layout and you're done.
54
+
55
+ ## Build
56
+
57
+ ```bash
58
+ npm run build # tsup → dist/bin.js (and dist/index.js)
59
+ npm run typecheck
60
+ npm run dev # tsup --watch
61
+ ```
62
+
63
+ ## Notes
64
+
65
+ - `bin` is set to `dist/bin.js`, so `npx @econneq/auth-cli` and a global `econneq-auth` shim both work after publish.
66
+ - The generator is template-based — edit `src/templates/` to change the scaffolded output.
67
+ - Runs on Node — no React or browser globals required.
package/dist/bin.js ADDED
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env node
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+
25
+ // src/commands/init.ts
26
+ var import_prompts = __toESM(require("prompts"));
27
+ var import_chalk = __toESM(require("chalk"));
28
+ var import_ora = __toESM(require("ora"));
29
+ var import_fs_extra = __toESM(require("fs-extra"));
30
+ var import_path = __toESM(require("path"));
31
+
32
+ // src/templates/auth.config.template.ts
33
+ function generateAuthConfig(a) {
34
+ const methods = a.authMethods.map((m) => `'${m}'`).join(", ");
35
+ return `import { defineAuthConfig } from '@econneq/auth-react'
36
+
37
+ export const authConfig = defineAuthConfig({
38
+ appName: '${a.appName}',
39
+ apiBaseUrl: process.env.NEXT_PUBLIC_AUTH_API_URL ?? '${a.apiBaseUrl}',
40
+ tenantMode: ${a.tenantMode},
41
+
42
+ routing: {
43
+ strategy: 'subdomain',
44
+ },
45
+
46
+ auth: {
47
+ methods: [${methods}],
48
+ mfa: false,
49
+ rememberSession: true,
50
+ },
51
+
52
+ storage: {
53
+ strategy: '${a.storage}',
54
+ },
55
+
56
+ tokens: {
57
+ autoRefresh: true,
58
+ accessTokenExpiry: 900,
59
+ refreshTokenExpiry: 604800,
60
+ },
61
+
62
+ security: {
63
+ csrf: true,
64
+ sameSite: 'lax',
65
+ rotateRefreshTokens: true,
66
+ },
67
+
68
+ ui: {
69
+ hostedPages: true,
70
+ darkMode: false,
71
+ },
72
+ })
73
+ `;
74
+ }
75
+
76
+ // src/templates/provider.template.ts
77
+ function generateProviderFile(a) {
78
+ const pkg = a.framework === "nextjs" ? "@econneq/auth-react" : "@econneq/auth-react";
79
+ return `'use client'
80
+ import { AuthProvider } from '${pkg}'
81
+ import { authConfig } from './auth.config'
82
+ import type { ReactNode } from 'react'
83
+
84
+ export function AppAuthProvider({ children }: { children: ReactNode }) {
85
+ return (
86
+ <AuthProvider config={authConfig}>
87
+ {children}
88
+ </AuthProvider>
89
+ )
90
+ }
91
+ `;
92
+ }
93
+
94
+ // src/templates/proxy.template.ts
95
+ function generateProxyFile(_a) {
96
+ return `/**
97
+ * proxy.ts \u2014 Econneq Auth Middleware
98
+ * Generated by: npx econneq-auth init
99
+ */
100
+ import { createAuthMiddleware } from '@econneq/auth-react/middleware'
101
+ import { authConfig } from './src/auth/auth.config'
102
+
103
+ export default createAuthMiddleware(authConfig, {
104
+ protectedRoutes: ['/dashboard', '/app', '/admin'],
105
+ publicRoutes: ['/auth/login', '/auth/register', '/auth/select-tenant'],
106
+ loginUrl: '/auth/login',
107
+ tenantSelectUrl: '/auth/select-tenant',
108
+ })
109
+
110
+ export const config = {
111
+ matcher: ['/((?!_next/static|_next/image|favicon\\.ico|.*\\.[a-zA-Z]{2,5}$).*)'],
112
+ }
113
+ `;
114
+ }
115
+
116
+ // src/templates/env.template.ts
117
+ function generateEnvFile(a) {
118
+ return `# @econneq-auth \u2014 generated by npx econneq-auth init
119
+ NEXT_PUBLIC_AUTH_API_URL=${a.apiBaseUrl}
120
+ NEXT_PUBLIC_ROOT_DOMAIN=yourdomain.com
121
+
122
+ # Optional: set these server-side only (not NEXT_PUBLIC_)
123
+ # AUTH_SECRET=your-jwt-secret
124
+ # AUTH_CSRF_SECRET=your-csrf-secret
125
+ `;
126
+ }
127
+
128
+ // src/commands/init.ts
129
+ async function initCommand() {
130
+ console.log("\n" + import_chalk.default.bold.cyan("\u{1F510} @econneq-auth init") + "\n");
131
+ const answers = await (0, import_prompts.default)([
132
+ {
133
+ type: "text",
134
+ name: "appName",
135
+ message: "Application name?",
136
+ initial: "My Enterprise App"
137
+ },
138
+ {
139
+ type: "text",
140
+ name: "apiBaseUrl",
141
+ message: "Auth API base URL?",
142
+ initial: "https://api.yourdomain.com"
143
+ },
144
+ {
145
+ type: "confirm",
146
+ name: "tenantMode",
147
+ message: "Enable multi-tenant mode?",
148
+ initial: true
149
+ },
150
+ {
151
+ type: "select",
152
+ name: "framework",
153
+ message: "Framework?",
154
+ choices: [
155
+ { title: "Next.js (App Router)", value: "nextjs" },
156
+ { title: "React (Vite/CRA)", value: "react" }
157
+ ]
158
+ },
159
+ {
160
+ type: "select",
161
+ name: "storage",
162
+ message: "Token storage strategy?",
163
+ choices: [
164
+ { title: "Cookies (recommended for SSR)", value: "cookies" },
165
+ { title: "localStorage", value: "localStorage" },
166
+ { title: "Memory", value: "memory" }
167
+ ]
168
+ },
169
+ {
170
+ type: "multiselect",
171
+ name: "authMethods",
172
+ message: "Auth methods to enable?",
173
+ choices: [
174
+ { title: "Password", value: "password", selected: true },
175
+ { title: "OTP", value: "otp", selected: false },
176
+ { title: "Google", value: "google", selected: false },
177
+ { title: "Magic Link", value: "magic-link", selected: false }
178
+ ]
179
+ }
180
+ ]);
181
+ if (!answers.appName) {
182
+ console.log(import_chalk.default.red("\nAborted."));
183
+ process.exit(1);
184
+ }
185
+ const spinner = (0, import_ora.default)("Generating auth files\u2026").start();
186
+ try {
187
+ const srcDir = import_path.default.join(process.cwd(), "src");
188
+ await import_fs_extra.default.outputFile(
189
+ import_path.default.join(srcDir, "auth", "auth.config.ts"),
190
+ generateAuthConfig(answers)
191
+ );
192
+ await import_fs_extra.default.outputFile(
193
+ import_path.default.join(srcDir, "auth", "provider.tsx"),
194
+ generateProviderFile(answers)
195
+ );
196
+ if (answers.framework === "nextjs") {
197
+ await import_fs_extra.default.outputFile(
198
+ import_path.default.join(process.cwd(), "proxy.ts"),
199
+ generateProxyFile(answers)
200
+ );
201
+ }
202
+ await import_fs_extra.default.outputFile(
203
+ import_path.default.join(process.cwd(), ".env.local"),
204
+ generateEnvFile(answers)
205
+ );
206
+ spinner.succeed("Auth files generated!");
207
+ console.log("\n" + import_chalk.default.bold("Files created:"));
208
+ console.log(" " + import_chalk.default.green("src/auth/auth.config.ts"));
209
+ console.log(" " + import_chalk.default.green("src/auth/provider.tsx"));
210
+ if (answers.framework === "nextjs") {
211
+ console.log(" " + import_chalk.default.green("proxy.ts"));
212
+ }
213
+ console.log(" " + import_chalk.default.green(".env.local"));
214
+ console.log("\n" + import_chalk.default.bold("Next steps:"));
215
+ if (answers.framework === "nextjs") {
216
+ console.log(` 1. npm install @econneq/auth-react @econneq/auth-ui`);
217
+ console.log(` 2. Wrap your root layout with <AuthProvider config={authConfig}>`);
218
+ console.log(` 3. Ensure proxy.ts is at your project root`);
219
+ } else {
220
+ console.log(` 1. npm install @econneq/auth-react @econneq/auth-ui`);
221
+ console.log(` 2. Wrap your App with <AuthProvider config={authConfig}>`);
222
+ }
223
+ console.log(` 4. Set your API URL in .env.local`);
224
+ console.log("\n" + import_chalk.default.cyan("Docs: https://github.com/econneq/econneq-auth") + "\n");
225
+ } catch (err) {
226
+ spinner.fail("Generation failed");
227
+ console.error(err);
228
+ process.exit(1);
229
+ }
230
+ }
231
+
232
+ // src/index.ts
233
+ async function run() {
234
+ const [, , cmd = "init"] = process.argv;
235
+ switch (cmd) {
236
+ case "init":
237
+ await initCommand();
238
+ break;
239
+ default:
240
+ console.log("Unknown command. Available: init");
241
+ process.exit(1);
242
+ }
243
+ }
244
+
245
+ // src/bin.ts
246
+ run();
package/dist/index.js ADDED
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/env node
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ run: () => run
34
+ });
35
+ module.exports = __toCommonJS(src_exports);
36
+
37
+ // src/commands/init.ts
38
+ var import_prompts = __toESM(require("prompts"));
39
+ var import_chalk = __toESM(require("chalk"));
40
+ var import_ora = __toESM(require("ora"));
41
+ var import_fs_extra = __toESM(require("fs-extra"));
42
+ var import_path = __toESM(require("path"));
43
+
44
+ // src/templates/auth.config.template.ts
45
+ function generateAuthConfig(a) {
46
+ const methods = a.authMethods.map((m) => `'${m}'`).join(", ");
47
+ return `import { defineAuthConfig } from '@econneq/auth-react'
48
+
49
+ export const authConfig = defineAuthConfig({
50
+ appName: '${a.appName}',
51
+ apiBaseUrl: process.env.NEXT_PUBLIC_AUTH_API_URL ?? '${a.apiBaseUrl}',
52
+ tenantMode: ${a.tenantMode},
53
+
54
+ routing: {
55
+ strategy: 'subdomain',
56
+ },
57
+
58
+ auth: {
59
+ methods: [${methods}],
60
+ mfa: false,
61
+ rememberSession: true,
62
+ },
63
+
64
+ storage: {
65
+ strategy: '${a.storage}',
66
+ },
67
+
68
+ tokens: {
69
+ autoRefresh: true,
70
+ accessTokenExpiry: 900,
71
+ refreshTokenExpiry: 604800,
72
+ },
73
+
74
+ security: {
75
+ csrf: true,
76
+ sameSite: 'lax',
77
+ rotateRefreshTokens: true,
78
+ },
79
+
80
+ ui: {
81
+ hostedPages: true,
82
+ darkMode: false,
83
+ },
84
+ })
85
+ `;
86
+ }
87
+
88
+ // src/templates/provider.template.ts
89
+ function generateProviderFile(a) {
90
+ const pkg = a.framework === "nextjs" ? "@econneq/auth-react" : "@econneq/auth-react";
91
+ return `'use client'
92
+ import { AuthProvider } from '${pkg}'
93
+ import { authConfig } from './auth.config'
94
+ import type { ReactNode } from 'react'
95
+
96
+ export function AppAuthProvider({ children }: { children: ReactNode }) {
97
+ return (
98
+ <AuthProvider config={authConfig}>
99
+ {children}
100
+ </AuthProvider>
101
+ )
102
+ }
103
+ `;
104
+ }
105
+
106
+ // src/templates/proxy.template.ts
107
+ function generateProxyFile(_a) {
108
+ return `/**
109
+ * proxy.ts \u2014 Econneq Auth Middleware
110
+ * Generated by: npx econneq-auth init
111
+ */
112
+ import { createAuthMiddleware } from '@econneq/auth-react/middleware'
113
+ import { authConfig } from './src/auth/auth.config'
114
+
115
+ export default createAuthMiddleware(authConfig, {
116
+ protectedRoutes: ['/dashboard', '/app', '/admin'],
117
+ publicRoutes: ['/auth/login', '/auth/register', '/auth/select-tenant'],
118
+ loginUrl: '/auth/login',
119
+ tenantSelectUrl: '/auth/select-tenant',
120
+ })
121
+
122
+ export const config = {
123
+ matcher: ['/((?!_next/static|_next/image|favicon\\.ico|.*\\.[a-zA-Z]{2,5}$).*)'],
124
+ }
125
+ `;
126
+ }
127
+
128
+ // src/templates/env.template.ts
129
+ function generateEnvFile(a) {
130
+ return `# @econneq-auth \u2014 generated by npx econneq-auth init
131
+ NEXT_PUBLIC_AUTH_API_URL=${a.apiBaseUrl}
132
+ NEXT_PUBLIC_ROOT_DOMAIN=yourdomain.com
133
+
134
+ # Optional: set these server-side only (not NEXT_PUBLIC_)
135
+ # AUTH_SECRET=your-jwt-secret
136
+ # AUTH_CSRF_SECRET=your-csrf-secret
137
+ `;
138
+ }
139
+
140
+ // src/commands/init.ts
141
+ async function initCommand() {
142
+ console.log("\n" + import_chalk.default.bold.cyan("\u{1F510} @econneq-auth init") + "\n");
143
+ const answers = await (0, import_prompts.default)([
144
+ {
145
+ type: "text",
146
+ name: "appName",
147
+ message: "Application name?",
148
+ initial: "My Enterprise App"
149
+ },
150
+ {
151
+ type: "text",
152
+ name: "apiBaseUrl",
153
+ message: "Auth API base URL?",
154
+ initial: "https://api.yourdomain.com"
155
+ },
156
+ {
157
+ type: "confirm",
158
+ name: "tenantMode",
159
+ message: "Enable multi-tenant mode?",
160
+ initial: true
161
+ },
162
+ {
163
+ type: "select",
164
+ name: "framework",
165
+ message: "Framework?",
166
+ choices: [
167
+ { title: "Next.js (App Router)", value: "nextjs" },
168
+ { title: "React (Vite/CRA)", value: "react" }
169
+ ]
170
+ },
171
+ {
172
+ type: "select",
173
+ name: "storage",
174
+ message: "Token storage strategy?",
175
+ choices: [
176
+ { title: "Cookies (recommended for SSR)", value: "cookies" },
177
+ { title: "localStorage", value: "localStorage" },
178
+ { title: "Memory", value: "memory" }
179
+ ]
180
+ },
181
+ {
182
+ type: "multiselect",
183
+ name: "authMethods",
184
+ message: "Auth methods to enable?",
185
+ choices: [
186
+ { title: "Password", value: "password", selected: true },
187
+ { title: "OTP", value: "otp", selected: false },
188
+ { title: "Google", value: "google", selected: false },
189
+ { title: "Magic Link", value: "magic-link", selected: false }
190
+ ]
191
+ }
192
+ ]);
193
+ if (!answers.appName) {
194
+ console.log(import_chalk.default.red("\nAborted."));
195
+ process.exit(1);
196
+ }
197
+ const spinner = (0, import_ora.default)("Generating auth files\u2026").start();
198
+ try {
199
+ const srcDir = import_path.default.join(process.cwd(), "src");
200
+ await import_fs_extra.default.outputFile(
201
+ import_path.default.join(srcDir, "auth", "auth.config.ts"),
202
+ generateAuthConfig(answers)
203
+ );
204
+ await import_fs_extra.default.outputFile(
205
+ import_path.default.join(srcDir, "auth", "provider.tsx"),
206
+ generateProviderFile(answers)
207
+ );
208
+ if (answers.framework === "nextjs") {
209
+ await import_fs_extra.default.outputFile(
210
+ import_path.default.join(process.cwd(), "proxy.ts"),
211
+ generateProxyFile(answers)
212
+ );
213
+ }
214
+ await import_fs_extra.default.outputFile(
215
+ import_path.default.join(process.cwd(), ".env.local"),
216
+ generateEnvFile(answers)
217
+ );
218
+ spinner.succeed("Auth files generated!");
219
+ console.log("\n" + import_chalk.default.bold("Files created:"));
220
+ console.log(" " + import_chalk.default.green("src/auth/auth.config.ts"));
221
+ console.log(" " + import_chalk.default.green("src/auth/provider.tsx"));
222
+ if (answers.framework === "nextjs") {
223
+ console.log(" " + import_chalk.default.green("proxy.ts"));
224
+ }
225
+ console.log(" " + import_chalk.default.green(".env.local"));
226
+ console.log("\n" + import_chalk.default.bold("Next steps:"));
227
+ if (answers.framework === "nextjs") {
228
+ console.log(` 1. npm install @econneq/auth-react @econneq/auth-ui`);
229
+ console.log(` 2. Wrap your root layout with <AuthProvider config={authConfig}>`);
230
+ console.log(` 3. Ensure proxy.ts is at your project root`);
231
+ } else {
232
+ console.log(` 1. npm install @econneq/auth-react @econneq/auth-ui`);
233
+ console.log(` 2. Wrap your App with <AuthProvider config={authConfig}>`);
234
+ }
235
+ console.log(` 4. Set your API URL in .env.local`);
236
+ console.log("\n" + import_chalk.default.cyan("Docs: https://github.com/econneq/econneq-auth") + "\n");
237
+ } catch (err) {
238
+ spinner.fail("Generation failed");
239
+ console.error(err);
240
+ process.exit(1);
241
+ }
242
+ }
243
+
244
+ // src/index.ts
245
+ async function run() {
246
+ const [, , cmd = "init"] = process.argv;
247
+ switch (cmd) {
248
+ case "init":
249
+ await initCommand();
250
+ break;
251
+ default:
252
+ console.log("Unknown command. Available: init");
253
+ process.exit(1);
254
+ }
255
+ }
256
+ // Annotate the CommonJS export names for ESM import in node:
257
+ 0 && (module.exports = {
258
+ run
259
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@econneq/auth-cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "CLI — npx econneq-auth init",
5
5
  "author": "Econneq",
6
6
  "license": "MIT",