@econneq/auth-cli 1.0.1 → 1.0.3
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 +75 -0
- package/dist/bin.js +246 -0
- package/dist/bin.mjs +1 -1
- package/dist/{chunk-2DIZS5TH.mjs → chunk-R677WW5L.mjs} +4 -4
- package/dist/index.js +259 -0
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
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
|
+
cd project root
|
|
17
|
+
pnpm add -D @econneq/auth-cli
|
|
18
|
+
pnpm exec econneq-auth init
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
or
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx @econneq/auth-cli init
|
|
25
|
+
# or, after global install:
|
|
26
|
+
npm install -g @econneq/auth-cli
|
|
27
|
+
econneq-auth init
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The single command available today is `init`.
|
|
31
|
+
|
|
32
|
+
## What `init` asks
|
|
33
|
+
|
|
34
|
+
| Prompt | Notes |
|
|
35
|
+
|---|---|
|
|
36
|
+
| Application name | Free text — used in generated comments |
|
|
37
|
+
| Auth API base URL | e.g. `https://auth.example.com` |
|
|
38
|
+
| Enable multi-tenant mode? | yes/no |
|
|
39
|
+
| Framework | Next.js, Remix, Vite, … |
|
|
40
|
+
| Token storage strategy | cookie / localStorage / memory |
|
|
41
|
+
| Auth methods | password, otp, oauth, … (multi-select) |
|
|
42
|
+
|
|
43
|
+
## What `init` creates
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
src/auth/auth.config.ts # defineAuthConfig(...) populated from your answers
|
|
47
|
+
src/auth/provider.tsx # <AuthProvider> wrapper ready to mount
|
|
48
|
+
proxy.ts # Next.js middleware (only when Next.js was picked)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
After the CLI finishes, install the SDK packages it referenced:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install @econneq/auth-core @econneq/auth-react
|
|
55
|
+
# Next.js apps:
|
|
56
|
+
npm install @econneq/auth-nextjs
|
|
57
|
+
# If you want the hosted UI screens:
|
|
58
|
+
npm install @econneq/auth-ui
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Then mount the generated `Providers` component in your root layout and you're done.
|
|
62
|
+
|
|
63
|
+
## Build
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm run build # tsup → dist/bin.js (and dist/index.js)
|
|
67
|
+
npm run typecheck
|
|
68
|
+
npm run dev # tsup --watch
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Notes
|
|
72
|
+
|
|
73
|
+
- `bin` is set to `dist/bin.js`, so `npx @econneq/auth-cli` and a global `econneq-auth` shim both work after publish.
|
|
74
|
+
- The generator is template-based — edit `src/templates/` to change the scaffolded output.
|
|
75
|
+
- 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_BACKEND_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.e-conneq.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-core @econneq/auth-react @econneq/auth-nextjs`);
|
|
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-core @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/bin.mjs
CHANGED
|
@@ -14,7 +14,7 @@ function generateAuthConfig(a) {
|
|
|
14
14
|
|
|
15
15
|
export const authConfig = defineAuthConfig({
|
|
16
16
|
appName: '${a.appName}',
|
|
17
|
-
apiBaseUrl: process.env.
|
|
17
|
+
apiBaseUrl: process.env.NEXT_PUBLIC_BACKEND_URL ?? '${a.apiBaseUrl}',
|
|
18
18
|
tenantMode: ${a.tenantMode},
|
|
19
19
|
|
|
20
20
|
routing: {
|
|
@@ -117,7 +117,7 @@ async function initCommand() {
|
|
|
117
117
|
type: "text",
|
|
118
118
|
name: "apiBaseUrl",
|
|
119
119
|
message: "Auth API base URL?",
|
|
120
|
-
initial: "https://api.
|
|
120
|
+
initial: "https://api.e-conneq.com"
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
type: "confirm",
|
|
@@ -191,11 +191,11 @@ async function initCommand() {
|
|
|
191
191
|
console.log(" " + chalk.green(".env.local"));
|
|
192
192
|
console.log("\n" + chalk.bold("Next steps:"));
|
|
193
193
|
if (answers.framework === "nextjs") {
|
|
194
|
-
console.log(` 1. npm install @econneq/auth-react @econneq/auth-
|
|
194
|
+
console.log(` 1. npm install @econneq/auth-core @econneq/auth-react @econneq/auth-nextjs`);
|
|
195
195
|
console.log(` 2. Wrap your root layout with <AuthProvider config={authConfig}>`);
|
|
196
196
|
console.log(` 3. Ensure proxy.ts is at your project root`);
|
|
197
197
|
} else {
|
|
198
|
-
console.log(` 1. npm install @econneq/auth-react @econneq/auth-ui`);
|
|
198
|
+
console.log(` 1. npm install @econneq/auth-core @econneq/auth-react @econneq/auth-ui`);
|
|
199
199
|
console.log(` 2. Wrap your App with <AuthProvider config={authConfig}>`);
|
|
200
200
|
}
|
|
201
201
|
console.log(` 4. Set your API URL in .env.local`);
|
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_BACKEND_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.e-conneq.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-core @econneq/auth-react @econneq/auth-nextjs`);
|
|
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-core @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/dist/index.mjs
CHANGED