create-tezx-app 2.0.6 → 2.0.8
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/bin +590 -52
- package/package.json +1 -1
package/bin
CHANGED
|
@@ -1,5 +1,97 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{execSync as
|
|
2
|
+
import{execSync as K}from"node:child_process";import{mkdirSync as j,writeFileSync as Y}from"node:fs";import E,{join as q,resolve as Q}from"node:path";import P from"node:readline";var p=(n,s)=>({version:s,npm:["npm install",n],bun:["bun add",n],yarn:["yarn add",n],pnpm:["pnpm add",n]});var I={readme:`
|
|
3
|
+
# \u{1F510} GitHub OAuth2 Example for TezX
|
|
4
|
+
|
|
5
|
+
This example demonstrates how to implement GitHub OAuth2 login using \`@tezx/github-oauth2\`.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## \u{1F680} Features
|
|
10
|
+
|
|
11
|
+
- \u{1F510} Redirects users to GitHub for login
|
|
12
|
+
- \u{1F4E5} Handles GitHub's OAuth2 callback
|
|
13
|
+
- \u{1F9D1} Retrieves user profile and creates session
|
|
14
|
+
- \u2699\uFE0F Easy to integrate with any TezX backend
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## \u{1F527} Setup
|
|
19
|
+
|
|
20
|
+
### 1. Install the required package
|
|
21
|
+
|
|
22
|
+
\`\`\`bash
|
|
23
|
+
${Object.values(p("@tezx/github-oauth2","^1.0.3"))?.filter(n=>typeof n!="string")?.join(`
|
|
24
|
+
#or
|
|
25
|
+
`)}
|
|
26
|
+
\`\`\`
|
|
27
|
+
|
|
28
|
+
### 2. Add environment variables
|
|
29
|
+
|
|
30
|
+
Create a \`.env\` file:
|
|
31
|
+
|
|
32
|
+
\`\`\`env
|
|
33
|
+
GITHUB_CLIENT_ID=your_client_id
|
|
34
|
+
GITHUB_CLIENT_SECRET=your_client_secret
|
|
35
|
+
\`\`\`
|
|
36
|
+
|
|
37
|
+
Make sure you register your OAuth app at:
|
|
38
|
+
> https://github.com/settings/developers
|
|
39
|
+
|
|
40
|
+
Use callback URL:
|
|
41
|
+
\`http://localhost:3000/github/callback\`
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## \u{1F9EA} Example Flow
|
|
46
|
+
|
|
47
|
+
### Step 1: Redirect to GitHub login
|
|
48
|
+
|
|
49
|
+
\`\`\`ts
|
|
50
|
+
app.get('/github', getGithubOAuthURL({
|
|
51
|
+
authClient: client,
|
|
52
|
+
}), (ctx) => {
|
|
53
|
+
return ctx.redirect(ctx.state.get('github_oauth_url'));
|
|
54
|
+
});
|
|
55
|
+
\`\`\`
|
|
56
|
+
|
|
57
|
+
### Step 2: GitHub redirects back \u2192 create session
|
|
58
|
+
|
|
59
|
+
\`\`\`ts
|
|
60
|
+
app.get('/github/callback', verifyGithubToken({
|
|
61
|
+
authClient: client,
|
|
62
|
+
Callbacks: (ctx) => ({
|
|
63
|
+
session: async (session, user) => {
|
|
64
|
+
console.log("Session:", session);
|
|
65
|
+
console.log("User:", user);
|
|
66
|
+
return session;
|
|
67
|
+
}
|
|
68
|
+
}),
|
|
69
|
+
}), async (ctx) => {
|
|
70
|
+
return ctx.json({ success: true });
|
|
71
|
+
});
|
|
72
|
+
\`\`\`
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## \u{1F4C1} File Structure
|
|
77
|
+
|
|
78
|
+
\`\`\`
|
|
79
|
+
.
|
|
80
|
+
\u251C\u2500\u2500 .env
|
|
81
|
+
\u251C\u2500\u2500 server.ts
|
|
82
|
+
\`\`\`
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## \u{1F4DA} References
|
|
87
|
+
|
|
88
|
+
- GitHub OAuth Docs: https://docs.github.com/en/developers/apps/building-oauth-apps
|
|
89
|
+
- TezX GitHub OAuth: https://www.npmjs.com/package/@tezx/github-oauth2
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
Login securely and build smarter auth with TezX! \u{1F680}
|
|
94
|
+
`.trim(),content:`
|
|
3
95
|
// 1. Initialize OAuth2 client
|
|
4
96
|
const client = GitHubOauthClient({
|
|
5
97
|
clientId: process.env.GITHUB_CLIENT_ID,
|
|
@@ -29,47 +121,87 @@ app.get('/github/callback', verifyGithubToken({
|
|
|
29
121
|
}), async (ctx) => {
|
|
30
122
|
return ctx.json({ success: true });
|
|
31
123
|
});
|
|
32
|
-
|
|
33
|
-
GITHUB_CLIENT_SECRET=234234
|
|
34
|
-
|
|
35
|
-
// 1. Initialize OAuth2 client
|
|
36
|
-
const client = GoogleOauthClient({
|
|
37
|
-
clientId: process.env.GOOGLE_CLIENT_ID,
|
|
38
|
-
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
|
39
|
-
redirectUri: 'http://localhost:3000/auth/callback',
|
|
40
|
-
});
|
|
124
|
+
`.trim(),files:[{content:`GITHUB_CLIENT_ID=12323
|
|
125
|
+
GITHUB_CLIENT_SECRET=234234`,path:".env"}],import:["import { GitHubOauthClient, getGithubOAuthURL, verifyGithubToken } from '@tezx/github-oauth2';"],package:[p("@tezx/github-oauth2","^1.0.3")]};var G={readme:`
|
|
126
|
+
# \u{1F510} Google OAuth2 Example for TezX
|
|
41
127
|
|
|
42
|
-
|
|
128
|
+
This example demonstrates how to use \`@tezx/google-oauth2\` to implement Google OAuth2 login in your TezX app.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## \u{1F680} Features
|
|
133
|
+
|
|
134
|
+
- Redirects users to Google Sign-In
|
|
135
|
+
- Verifies ID token and fetches user profile
|
|
136
|
+
- Allows role control via email domain or claims
|
|
137
|
+
- Persists session with custom user structure
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## \u{1F527} Setup Instructions
|
|
142
|
+
|
|
143
|
+
### 1. Install Required Packages
|
|
144
|
+
|
|
145
|
+
Choose your package manager and install:
|
|
146
|
+
|
|
147
|
+
\`\`\`bash
|
|
148
|
+
${Object.values(p("@tezx/google-oauth2","^1.0.9")).filter(n=>typeof n!="string").join(`
|
|
149
|
+
# or
|
|
150
|
+
`)}
|
|
151
|
+
|
|
152
|
+
# Plus Google OAuth SDK
|
|
153
|
+
${Object.values(p("@googleapis/oauth2","^2.0.1")).filter(n=>typeof n!="string").join(`
|
|
154
|
+
# or
|
|
155
|
+
`)}
|
|
156
|
+
\`\`\`
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
### 2. Setup \`.env\`
|
|
161
|
+
|
|
162
|
+
\`\`\`env
|
|
163
|
+
GOOGLE_CLIENT_ID=your-google-client-id
|
|
164
|
+
GOOGLE_CLIENT_SECRET=your-google-client-secret
|
|
165
|
+
\`\`\`
|
|
166
|
+
|
|
167
|
+
> Register your app here: https://console.cloud.google.com/apis/credentials
|
|
168
|
+
> Redirect URI: \`http://localhost:3000/auth/callback\`
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## \u{1F9EA} Example Route Flow
|
|
173
|
+
|
|
174
|
+
### \u{1F517} Step 1: Start Google OAuth
|
|
175
|
+
|
|
176
|
+
\`\`\`ts
|
|
43
177
|
app.get('/auth/google', getGoogleOAuthURL({
|
|
44
178
|
authClient: client,
|
|
45
|
-
scopes: ['openid','email','profile'],
|
|
179
|
+
scopes: ['openid', 'email', 'profile'],
|
|
46
180
|
}), (ctx) => {
|
|
47
181
|
return ctx.redirect(ctx.state.get('google_oauth_url'));
|
|
48
182
|
});
|
|
183
|
+
\`\`\`
|
|
49
184
|
|
|
50
|
-
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
### \u2705 Step 2: Callback \u2014 Verify & Create Session
|
|
188
|
+
|
|
189
|
+
\`\`\`ts
|
|
51
190
|
app.get('/auth/callback', verifyGoogleToken({
|
|
52
191
|
authClient: client,
|
|
53
192
|
onError: (err) => {
|
|
54
193
|
console.error('OAuth Error:', err);
|
|
55
|
-
// handle error or redirect
|
|
56
194
|
},
|
|
57
195
|
onSuccess: (tokens) => {
|
|
58
196
|
console.log('Tokens:', tokens);
|
|
59
197
|
},
|
|
60
|
-
Callbacks: (ctx)=> {
|
|
61
|
-
|
|
62
|
-
signIn: async (user) => {
|
|
63
|
-
// e.g. allow only users from a domain
|
|
64
|
-
return user.email.endsWith('@yourcompany.com');
|
|
65
|
-
},
|
|
198
|
+
Callbacks: (ctx) => ({
|
|
199
|
+
signIn: async (user) => user.email.endsWith('@yourcompany.com'),
|
|
66
200
|
jwt: async (token, user) => {
|
|
67
|
-
// attach roles or custom claims
|
|
68
201
|
token.role = user.email_verified ? 'member' : 'guest';
|
|
69
202
|
return token;
|
|
70
203
|
},
|
|
71
204
|
session: async (session, user) => {
|
|
72
|
-
// persist user profile in session
|
|
73
205
|
session.user = {
|
|
74
206
|
id: user.sub,
|
|
75
207
|
email: user.email,
|
|
@@ -78,15 +210,154 @@ app.get('/auth/callback', verifyGoogleToken({
|
|
|
78
210
|
};
|
|
79
211
|
return session;
|
|
80
212
|
}
|
|
81
|
-
}
|
|
213
|
+
})
|
|
214
|
+
}), async (ctx) => {
|
|
215
|
+
return ctx.json({ success: true });
|
|
216
|
+
});
|
|
217
|
+
\`\`\`
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## \u{1F4C1} File Structure
|
|
222
|
+
|
|
223
|
+
\`\`\`
|
|
224
|
+
.
|
|
225
|
+
\u251C\u2500\u2500 .env
|
|
226
|
+
\u2514\u2500\u2500 server.ts
|
|
227
|
+
\`\`\`
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
> \u{1F4A1} Note: TezX OAuth2 uses stateful sessions or JWTs depending on your setup. It supports advanced callback hooks for full control.
|
|
232
|
+
|
|
233
|
+
Secure your apps with Google the easy way \u{1F512}
|
|
234
|
+
`.trim(),content:`
|
|
235
|
+
// 1. Initialize OAuth2 client
|
|
236
|
+
const client = GoogleOauthClient({
|
|
237
|
+
clientId: process.env.GOOGLE_CLIENT_ID,
|
|
238
|
+
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
|
239
|
+
redirectUri: 'http://localhost:3000/auth/callback',
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// 2. Route to start Google login
|
|
243
|
+
app.get('/auth/google', getGoogleOAuthURL({
|
|
244
|
+
authClient: client,
|
|
245
|
+
scopes: ['openid','email','profile'],
|
|
246
|
+
}), (ctx) => {
|
|
247
|
+
return ctx.redirect(ctx.state.get('google_oauth_url'));
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// 3. Callback route, verify token and establish session
|
|
251
|
+
app.get('/auth/callback', verifyGoogleToken({
|
|
252
|
+
authClient: client,
|
|
253
|
+
onError: (err) => {
|
|
254
|
+
console.error('OAuth Error:', err);
|
|
255
|
+
},
|
|
256
|
+
onSuccess: (tokens) => {
|
|
257
|
+
console.log('Tokens:', tokens);
|
|
258
|
+
},
|
|
259
|
+
Callbacks: (ctx)=> {
|
|
260
|
+
return {
|
|
261
|
+
signIn: async (user) => {
|
|
262
|
+
return user.email.endsWith('@yourcompany.com');
|
|
263
|
+
},
|
|
264
|
+
jwt: async (token, user) => {
|
|
265
|
+
token.role = user.email_verified ? 'member' : 'guest';
|
|
266
|
+
return token;
|
|
267
|
+
},
|
|
268
|
+
session: async (session, user) => {
|
|
269
|
+
session.user = {
|
|
270
|
+
id: user.sub,
|
|
271
|
+
email: user.email,
|
|
272
|
+
name: user.name,
|
|
273
|
+
picture: user.picture
|
|
274
|
+
};
|
|
275
|
+
return session;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
82
278
|
}
|
|
83
279
|
}), async (ctx) => {
|
|
84
|
-
// Now ctx.session is populated
|
|
85
280
|
return ctx.json({ success: true });
|
|
86
281
|
});
|
|
87
|
-
|
|
282
|
+
`.trim(),files:[{content:`GOOGLE_CLIENT_ID=12323
|
|
88
283
|
GOOGLE_CLIENT_SECRET=234234
|
|
89
|
-
`,path:".env"}],import:['import { GoogleOauthClient, getGoogleOAuthURL, verifyGoogleToken } from "@tezx/google-oauth2";'],package:[
|
|
284
|
+
`,path:".env"}],import:['import { GoogleOauthClient, getGoogleOAuthURL, verifyGoogleToken } from "@tezx/google-oauth2";'],package:[p("@tezx/google-oauth2","^1.0.9"),p("@googleapis/oauth2","^2.0.1")]};var R={readme:`
|
|
285
|
+
# TezX View Engine Example
|
|
286
|
+
|
|
287
|
+
This example demonstrates how to use the \`@tezx/view-engine\` package to render server-side views using template engines such as **EJS**, **Pug**, **Handlebars**, **Mustache**, or **Nunjucks**.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## \u{1F680} How it works
|
|
292
|
+
|
|
293
|
+
The \`ViewEngine\` class handles:
|
|
294
|
+
|
|
295
|
+
- Compiling templates at runtime
|
|
296
|
+
- Injecting dynamic data into views
|
|
297
|
+
- Supporting multiple template engines with the same API
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## \u{1F4C1} File structure
|
|
302
|
+
|
|
303
|
+
\`\`\`bash
|
|
304
|
+
.src
|
|
305
|
+
\u251C\u2500\u2500 views/
|
|
306
|
+
\u2502 \u2514\u2500\u2500 home.ejs
|
|
307
|
+
\u2514\u2500\u2500 index.ts
|
|
308
|
+
\`\`\`
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## \u{1F9EA} Example Usage
|
|
313
|
+
|
|
314
|
+
\`\`\`ts
|
|
315
|
+
import { ViewEngine } from "@tezx/view-engine";
|
|
316
|
+
|
|
317
|
+
const views = new ViewEngine("ejs", "./views");
|
|
318
|
+
|
|
319
|
+
app.get("engine", async (ctx) => {
|
|
320
|
+
const html = await views.render("home", {
|
|
321
|
+
title: "TezX SSR Page",
|
|
322
|
+
user: ctx.user || { name: "Guest" },
|
|
323
|
+
});
|
|
324
|
+
return ctx.html(html);
|
|
325
|
+
});
|
|
326
|
+
\`\`\`
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## \u{1F4A1} Notes
|
|
331
|
+
|
|
332
|
+
- The \`ViewEngine\` class auto-caches template files unless disabled.
|
|
333
|
+
- You can switch engines by passing a different type like \`"pug"\`, \`"hbs"\`, etc.
|
|
334
|
+
- All rendering is asynchronous.
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
Happy TezX templating! \u{1F389}
|
|
339
|
+
`.trim(),content:`
|
|
340
|
+
const views = new ViewEngine("ejs", "./views");
|
|
341
|
+
|
|
342
|
+
app.get("engine", async (ctx) => {
|
|
343
|
+
const html = await views.render("home", {
|
|
344
|
+
title: "TezX SSR Page",
|
|
345
|
+
user: ctx.user || { name: "Guest" },
|
|
346
|
+
});
|
|
347
|
+
return ctx.html(html);
|
|
348
|
+
});
|
|
349
|
+
`.trim(),files:[{content:`
|
|
350
|
+
<html lang="en">
|
|
351
|
+
<head>
|
|
352
|
+
<meta charset="UTF-8">
|
|
353
|
+
<title><%= title %></title>
|
|
354
|
+
</head>
|
|
355
|
+
<body>
|
|
356
|
+
<h1>Welcome to TezX SSR!</h1>
|
|
357
|
+
<p>Hello, <%= user.name %> \u{1F44B}</p>
|
|
358
|
+
</body>
|
|
359
|
+
</html>
|
|
360
|
+
`.trim(),path:"views/home.ejs"}],import:['import { ViewEngine } from "@tezx/view-engine";'],package:[p("@tezx/view-engine","^1.0.3"),p("ejs","^3.1.10")]};var F=`
|
|
90
361
|
<!DOCTYPE html>
|
|
91
362
|
<html lang="en">
|
|
92
363
|
<head>
|
|
@@ -254,28 +525,107 @@ GOOGLE_CLIENT_SECRET=234234
|
|
|
254
525
|
</script>
|
|
255
526
|
</body>
|
|
256
527
|
</html>
|
|
257
|
-
`,
|
|
528
|
+
`,_={readme:`
|
|
529
|
+
# \u{1F50C} TezX WebSocket Example
|
|
530
|
+
|
|
531
|
+
This example demonstrates how to set up a WebSocket server using \`upgradeWebSocket\` from \`tezx/ws\`.
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
## \u{1F680} Features
|
|
536
|
+
|
|
537
|
+
- Upgrade HTTP requests to WebSocket connections
|
|
538
|
+
- Handle events: \`open\`, \`message\`, and \`close\`
|
|
539
|
+
- Respond to \`ping\` with \`pong\`
|
|
540
|
+
- Echo received messages back to the client
|
|
541
|
+
- Works with Node.js and Bun
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## \u{1F527} Setup
|
|
546
|
+
|
|
547
|
+
### 1. Install required package (if needed)
|
|
548
|
+
|
|
549
|
+
TezX WebSocket support is built-in with \`tezx/ws\`. If your setup doesn't include it:
|
|
550
|
+
|
|
551
|
+
\`\`\`bash
|
|
552
|
+
npm install tezx
|
|
553
|
+
# or
|
|
554
|
+
bun add tezx
|
|
555
|
+
\`\`\`
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
### 2. How it works
|
|
560
|
+
|
|
561
|
+
- Connect to \`/ws\` via a browser or WebSocket client
|
|
562
|
+
- On connect: sends a welcome message
|
|
563
|
+
- On message: replies with either \`pong\` or echoes back the message
|
|
564
|
+
- Logs disconnection reason
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## \u{1F9EA} Client Test File
|
|
569
|
+
|
|
570
|
+
A simple HTML file is included in \`public/ws.html\`:
|
|
571
|
+
|
|
572
|
+
\`\`\`html
|
|
573
|
+
<script>
|
|
574
|
+
const ws = new WebSocket("ws://localhost:3000/ws");
|
|
575
|
+
|
|
576
|
+
ws.onopen = () => {
|
|
577
|
+
console.log("Connected to WebSocket!");
|
|
578
|
+
ws.send("ping");
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
ws.onmessage = (event) => {
|
|
582
|
+
console.log("Message:", event.data);
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
ws.onclose = () => {
|
|
586
|
+
console.log("Disconnected.");
|
|
587
|
+
};
|
|
588
|
+
</script>
|
|
589
|
+
\`\`\`
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
## \u{1F4C1} File Structure
|
|
594
|
+
|
|
595
|
+
\`\`\`
|
|
596
|
+
.
|
|
597
|
+
\u251C\u2500\u2500 public/
|
|
598
|
+
\u2502 \u2514\u2500\u2500 ws.html
|
|
599
|
+
\u2514\u2500\u2500 src
|
|
600
|
+
\u2514\u2500\u2500 index.ts
|
|
601
|
+
\`\`\`
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
Enjoy real-time power with TezX! \u26A1\uFE0F
|
|
606
|
+
`.trim(),content:`
|
|
258
607
|
const socket = [];
|
|
608
|
+
|
|
259
609
|
app.get(
|
|
260
610
|
"/ws",
|
|
261
611
|
upgradeWebSocket(
|
|
262
612
|
(ctx) => {
|
|
263
613
|
return {
|
|
264
|
-
//
|
|
614
|
+
// \u2705 Node.js-compatible WebSocket handler
|
|
265
615
|
open: (ws) => {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
616
|
+
socket.push(ws);
|
|
617
|
+
console.log("WebSocket connected");
|
|
618
|
+
ws.send("\u{1F44B} Welcome to TezX WebSocket!");
|
|
269
619
|
},
|
|
270
620
|
message: (ws, msg) => {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
621
|
+
if (typeof msg === "string" && msg === "ping") {
|
|
622
|
+
ws.send("pong \u{1F3D3}");
|
|
623
|
+
} else if (msg !== undefined) {
|
|
624
|
+
ws.send("Echo: " + msg);
|
|
625
|
+
}
|
|
276
626
|
},
|
|
277
627
|
close: (ws, data) => {
|
|
278
|
-
|
|
628
|
+
console.log(\`WebSocket closed: \${data?.reason ?? "No reason provided"}\`);
|
|
279
629
|
},
|
|
280
630
|
};
|
|
281
631
|
},
|
|
@@ -290,12 +640,130 @@ app.get(
|
|
|
290
640
|
return ctx.sendFile("public/ws.html");
|
|
291
641
|
},
|
|
292
642
|
);
|
|
293
|
-
|
|
294
|
-
`),t.forEach((l,i)=>{console.log(`${i===o?"\u{1F449}":" "} ${i===o?"\x1B[36m":"\x1B[0m"}${l}\x1B[0m`)})},c=(l,i)=>{if(i.name==="up")o=(o-1+t.length)%t.length,a();else if(i.name==="down")o=(o+1)%t.length,a();else if(i.name==="return")return r(t[o])};a(),process.stdin.on("keypress",c)})}var
|
|
643
|
+
`.trim(),files:[{content:F,path:"public/ws.html"}],import:['import { upgradeWebSocket } from "tezx/ws";']};var C={minimal:{readme:"",content:"",files:[],import:[],package:[]},ws:_,"github-oauth2":I,"google-oauth2":G,"view-engine":R};import B from"node:readline";async function z(n,s,t){return new Promise(r=>{let o=0;B.emitKeypressEvents(process.stdin,n),process.stdin.isTTY&&process.stdin.setRawMode(!0);let a=()=>{process.stdout.write("\x1B[2J\x1B[0f"),console.log(s+` (Use \u2191 \u2193 arrows, Enter to confirm)
|
|
644
|
+
`),t.forEach((l,i)=>{console.log(`${i===o?"\u{1F449}":" "} ${i===o?"\x1B[36m":"\x1B[0m"}${l}\x1B[0m`)})},c=(l,i)=>{if(i.name==="up")o=(o-1+t.length)%t.length,a();else if(i.name==="down")o=(o+1)%t.length,a();else if(i.name==="return")return r(t[o])};a(),process.stdin.on("keypress",c)})}var A={reset:"\x1B[0m",bold:"\x1B[1m",underline:"\x1B[4m",gray:"\x1B[90m",white:"\x1B[97m",black:"\x1B[30m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",cyan:"\x1B[36m",bgRed:"\x1B[41m",bgGreen:"\x1B[42m",bgYellow:"\x1B[43m",bgBlue:"\x1B[44m",bgMagenta:"\x1B[45m",bgCyan:"\x1B[46m",bgWhite:"\x1B[47m",orange:"\x1B[38;2;255;88;30m",bgOrange:"\x1B[48;2;255;88;30m"};function e(n,s){return`${A[s]}${n}${A.reset}`}import{mkdirSync as V,writeFileSync as b}from"node:fs";import{join as g}from"node:path";var S="2.0.8";var J=`
|
|
645
|
+
# \u{1F680} TezX Starter Template
|
|
646
|
+
|
|
647
|
+
Welcome to the **TezX Starter Template** \u2014 a blazing-fast, full-featured backend template built on [TezX](https://github.com/tezxjs/tezx), the lightweight web framework inspired by the best of Express, Hono, and Bun.
|
|
648
|
+
|
|
649
|
+
This starter is designed to help you spin up production-ready APIs or SSR apps in seconds.
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## \u2728 Features
|
|
654
|
+
|
|
655
|
+
- \u26A1\uFE0F Ultra-fast routing & middleware
|
|
656
|
+
- \u{1F512} Built-in WebSocket & OAuth2-ready
|
|
657
|
+
- \u{1F527} Plug-and-play \`ViewEngine\` for SSR
|
|
658
|
+
- \u{1F331} Environment-based config support
|
|
659
|
+
- \u{1F9EA} Minimal, testable, and extendable codebase
|
|
660
|
+
|
|
661
|
+
---
|
|
662
|
+
|
|
663
|
+
## \u{1F4E6} Tech Stack
|
|
664
|
+
|
|
665
|
+
- **Framework:** [TezX](https://github.com/tezxjs/tezx)
|
|
666
|
+
- **Language:** TypeScript / JavaScript
|
|
667
|
+
- **Template Engine (optional):** \`ejs\`, \`pug\`, \`hbs\`, \`mustache\`, or \`nunjucks\`
|
|
668
|
+
- **Runtime Support:** Node.js, Bun, Deno (via compatibility)
|
|
669
|
+
|
|
670
|
+
---
|
|
671
|
+
|
|
672
|
+
## \u{1F6E0}\uFE0F Getting Started
|
|
673
|
+
|
|
674
|
+
### 1. Install Dependencies
|
|
675
|
+
|
|
676
|
+
\`\`\`bash
|
|
677
|
+
npm install
|
|
678
|
+
# or
|
|
679
|
+
bun install
|
|
680
|
+
\`\`\`\`
|
|
681
|
+
|
|
682
|
+
### 2. Start Development Server
|
|
683
|
+
|
|
684
|
+
\`\`\`bash
|
|
685
|
+
npm run dev
|
|
686
|
+
# or
|
|
687
|
+
bun run dev
|
|
688
|
+
\`\`\`
|
|
689
|
+
|
|
690
|
+
### 3. Open in Browser
|
|
691
|
+
|
|
692
|
+
\`\`\`bash
|
|
693
|
+
http://localhost:3000
|
|
694
|
+
\`\`\`
|
|
695
|
+
|
|
696
|
+
---
|
|
697
|
+
|
|
698
|
+
## \u{1F510} Environment Variables
|
|
699
|
+
|
|
700
|
+
Create a \`.env\` file at the project root:
|
|
701
|
+
|
|
702
|
+
\`\`\`bash
|
|
703
|
+
PORT=3000
|
|
704
|
+
NODE_ENV=development
|
|
705
|
+
|
|
706
|
+
# For OAuth2 templates
|
|
707
|
+
GOOGLE_CLIENT_ID=your-client-id
|
|
708
|
+
GOOGLE_CLIENT_SECRET=your-secret
|
|
709
|
+
\`\`\`
|
|
710
|
+
|
|
711
|
+
---
|
|
712
|
+
|
|
713
|
+
## \u{1F4C1} Project Structure
|
|
714
|
+
|
|
715
|
+
\`\`\`
|
|
716
|
+
.
|
|
717
|
+
\u251C\u2500\u2500 public/ # Static files (images, js, css)
|
|
718
|
+
\u251C\u2500\u2500 views/ # SSR templates (optional)
|
|
719
|
+
\u251C\u2500\u2500 src/
|
|
720
|
+
\u2502 \u251C\u2500\u2500 index.ts # Entry point
|
|
721
|
+
\u2502 \u2514\u2500\u2500 routes/ # Route modules
|
|
722
|
+
\u251C\u2500\u2500 .env
|
|
723
|
+
\u251C\u2500\u2500 .gitignore
|
|
724
|
+
\u2514\u2500\u2500 package.json
|
|
725
|
+
\`\`\`
|
|
726
|
+
|
|
727
|
+
---
|
|
728
|
+
|
|
729
|
+
## \u{1F9EA} Example Commands
|
|
730
|
+
|
|
731
|
+
\`\`\`bash
|
|
732
|
+
# Build the app
|
|
733
|
+
bun run build
|
|
734
|
+
|
|
735
|
+
# Start the server in production
|
|
736
|
+
bun start
|
|
737
|
+
|
|
738
|
+
# Run a TezX test (if added)
|
|
739
|
+
bun test
|
|
740
|
+
\`\`\`
|
|
741
|
+
|
|
742
|
+
---
|
|
743
|
+
|
|
744
|
+
## \u{1F91D} Contributing
|
|
745
|
+
|
|
746
|
+
Pull requests are welcome! For major changes, please open an issue first to discuss what you would like to change.
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
## \u{1F4C4} License
|
|
751
|
+
|
|
752
|
+
MIT \xA9 [SRAKIB17](https://github.com/SRAKIB17)
|
|
753
|
+
|
|
754
|
+
---
|
|
755
|
+
|
|
756
|
+
## \u{1F49A} Powered by
|
|
757
|
+
|
|
758
|
+
[TezX Framework](https://github.com/tezxjs/TezX) \xB7 Made with performance in mind
|
|
759
|
+
|
|
760
|
+
---
|
|
761
|
+
|
|
762
|
+
`,L=({ts:n,template:s,root:t,env:r,useStatic:o=!1,staticFolder:a})=>{let c=g(t,n?"src/index.ts":"src/index.js");V(g(t,"src"),{recursive:!0});let l=`
|
|
295
763
|
import { TezX } from "tezx";
|
|
296
764
|
import { ${r}Adapter ,loadEnv} from "tezx/${r}";
|
|
297
765
|
import { logger } from "tezx/middleware";
|
|
298
|
-
${
|
|
766
|
+
${s?.import?.join(`
|
|
299
767
|
`)}
|
|
300
768
|
const app = new TezX({
|
|
301
769
|
env: loadEnv(),
|
|
@@ -307,13 +775,13 @@ app.use([logger()]);
|
|
|
307
775
|
app.get("/", (ctx) => ctx.text("Hello from TezX (${r})"));
|
|
308
776
|
|
|
309
777
|
${o?`app.static("${a||"public"}");`:""}
|
|
310
|
-
${
|
|
311
|
-
${
|
|
778
|
+
${s?.content?`
|
|
779
|
+
${s?.content?.trim()}
|
|
312
780
|
`:""}
|
|
313
781
|
${r}Adapter(app).listen(3000, () => {
|
|
314
782
|
console.log("\u{1F680} TezX running on http://localhost:3000");
|
|
315
783
|
});
|
|
316
|
-
`;if(
|
|
784
|
+
`;if(n){let i=`
|
|
317
785
|
{
|
|
318
786
|
"compilerOptions": {
|
|
319
787
|
"outDir": "./dist",
|
|
@@ -335,7 +803,7 @@ ${r}Adapter(app).listen(3000, () => {
|
|
|
335
803
|
"tests"
|
|
336
804
|
]
|
|
337
805
|
}
|
|
338
|
-
`.trim();
|
|
806
|
+
`.trim();b(g(t,"tsconfig.json"),i)}b(c,l.trim())},N=({template:n,root:s,projectName:t,env:r,ts:o,useWS:a,choiceStep:c})=>{let l=[];Array.isArray(n?.package)&&n?.package?.forEach(m=>{let{version:w,npm:v}=m||{};l.push(`"${v?.[1]}": "${w}"`)});let i={bun:{start:"bun dist/index.js",dev:"bun run --hot --watch src/index.ts"},deno:{start:"deno run --allow-all dist/index.js",dev:"deno run --watch --allow-all --unstable-sloppy-imports src/index.ts"},node:{start:"node dist/index.js",dev:"tsx watch src/index.ts"}},u=`
|
|
339
807
|
{
|
|
340
808
|
"name": "${t||"tezx-app-example"}",
|
|
341
809
|
"version": "1.0.0",
|
|
@@ -361,7 +829,7 @@ ${r}Adapter(app).listen(3000, () => {
|
|
|
361
829
|
"homepage": "https://github.com/tezxjs/tezx-app-example",
|
|
362
830
|
"dependencies": {
|
|
363
831
|
${o?'"typescript": "^5.8.2",':""}
|
|
364
|
-
"tezx": "^${
|
|
832
|
+
"tezx": "^${S}"${r=="node"?`,
|
|
365
833
|
"tsx": "^4.19.2"`:""}${a&&r=="node"?`,
|
|
366
834
|
"ws": "^8.18.1"`:""}${l.length?`,
|
|
367
835
|
${l?.join(`,
|
|
@@ -370,15 +838,85 @@ ${r}Adapter(app).listen(3000, () => {
|
|
|
370
838
|
"devDependencies": {
|
|
371
839
|
"@types/node": "^22.13.14"
|
|
372
840
|
}
|
|
373
|
-
}`.trim();
|
|
374
|
-
|
|
841
|
+
}`.trim();b(g(s,"package.json"),u)},D=({root:n})=>{let s=`
|
|
842
|
+
# Node dependencies
|
|
843
|
+
node_modules/
|
|
844
|
+
.env
|
|
845
|
+
.env.local
|
|
846
|
+
.env.*.local
|
|
847
|
+
|
|
848
|
+
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
849
|
+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
850
|
+
|
|
851
|
+
# Logs
|
|
852
|
+
logs
|
|
853
|
+
*.log
|
|
854
|
+
npm-debug.log*
|
|
855
|
+
yarn-debug.log*
|
|
856
|
+
yarn-error.log*
|
|
857
|
+
lerna-debug.log*
|
|
858
|
+
.pnpm-debug.log*
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
# Runtime data
|
|
862
|
+
pids
|
|
863
|
+
*.pid
|
|
864
|
+
*.seed
|
|
865
|
+
*.pid.lock
|
|
866
|
+
|
|
867
|
+
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
868
|
+
lib-cov
|
|
869
|
+
|
|
870
|
+
# Dependency directories
|
|
871
|
+
node_modules/
|
|
872
|
+
package/example-ts/node_modules/
|
|
873
|
+
package/example-commonjs/node_modules/
|
|
874
|
+
package/example-js-module/node_modules/
|
|
875
|
+
package-lock.json
|
|
876
|
+
bun.lock
|
|
877
|
+
|
|
878
|
+
# Stores VSCode versions used for testing VSCode extensions
|
|
879
|
+
.vscode-test
|
|
880
|
+
|
|
881
|
+
# yarn v2
|
|
882
|
+
.yarn/cache
|
|
883
|
+
.yarn/unplugged
|
|
884
|
+
.yarn/build-state.yml
|
|
885
|
+
.yarn/install-state.gz
|
|
886
|
+
.pnp.*
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
# Build outputs
|
|
890
|
+
dist/
|
|
891
|
+
build/
|
|
892
|
+
.cache/
|
|
893
|
+
.tezx/
|
|
894
|
+
out/
|
|
895
|
+
|
|
896
|
+
# System files
|
|
897
|
+
.DS_Store
|
|
898
|
+
Thumbs.db
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
# Output of 'npm pack'
|
|
902
|
+
*.tgz
|
|
903
|
+
|
|
904
|
+
# Yarn Integrity file
|
|
905
|
+
.yarn-integrity
|
|
906
|
+
|
|
907
|
+
# Editor settings
|
|
908
|
+
.vscode/
|
|
909
|
+
.idea/
|
|
910
|
+
*.swp
|
|
911
|
+
`.trim();b(g(n,".gitignore"),s,{encoding:"utf8"})},M=({root:n,readme:s})=>{let t=typeof s=="string"?s?.trim():J.trim();b(g(n,"README.md"),t,{encoding:"utf8"})};var f=["npm","bun","yarn","pnpm"],x=["node","bun","deno"];function Z(n){let s=0,t=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],r=setInterval(()=>{process.stdout.write(`\r${t[s=++s%t.length]} ${n}`)},80);return()=>{clearInterval(r),process.stdout.write(`\r\u2705 Done!
|
|
912
|
+
`)}}var $=P.createInterface({input:process.stdin,output:process.stdout});P.emitKeypressEvents(process.stdin);process.stdin.isTTY&&process.stdin.setRawMode(!0);var y=(n,s="")=>new Promise(t=>{$.question(s?`${n} (${s}): `:n,r=>{t(r.trim()||s)})});async function W(n){let s=n?.directory,t=n?.options;console.log(e(`
|
|
375
913
|
\u26A1 TezX App Creator (no dependencies CLI)
|
|
376
|
-
`,"orange")),
|
|
914
|
+
`,"orange")),s||(s=await y(e("\u{1F4E6} Project name: ","magenta")),s||(console.log(e("\u274C Project name required.","red")),process.exit(0)));let r=E.basename(s),o=Q(process.cwd(),s),a=!!t?.ts,c=t?.env||t?.runtime,l=x?.includes(c)?c:await z($,"\u{1F4BB} Runtime?",x),i=t?.staticFolder||"public",u=!0,m={content:"",import:[],readme:"",files:[]};if(t?.t||t?.template){let d=t.t||t.template,k=C?.[d];k||(console.error(`\u274C Unknown template: "${d}"`),console.error(`\u2139\uFE0F Available templates: ${Object.keys(C).join(", ")}`),process.exit(0)),m=k}else a=!!(t?.ts||(await y("\u{1F7E6} Use TypeScript? (y/N): ")).toLowerCase()==="y"),u=!!t?.useStatic||(await y("\u{1F4C1} Use static folder? (y/N): ")).toLowerCase()==="y",i=u?t?.staticFolder||await y("\u{1F4C2} Static folder name? (default: public): "):"";let w=t?.pm||t?.p,v=f?.includes(w)?w:await z($,"\u{1F4E6} Choose your package manager",f),T=t?.i==="true"||t?.install==="true"||(await y("\u{1F4E5} Install dependencies now? (y/N): ")).toLowerCase()==="y";console.log(`
|
|
377
915
|
\u{1F4C1} Creating project: ${r}...
|
|
378
|
-
`);let U=
|
|
916
|
+
`);let U=Z("Creating Project");if(j(o,{recursive:!0}),u){let d=q(o,i||"public");j(d,{recursive:!0})}let h={bun:{cd:"cd "+s,install:"bun install",dev:"bun dev",build:"bun build:esm && bun build:dts"},npm:{cd:"cd "+s,install:"npm install",dev:"npm run dev",build:"npm run build:esm && npm run build:dts"},yarn:{cd:"cd "+s,install:"yarn",dev:"yarn dev",build:"yarn build:esm && yarn build:dts"},pnpm:{cd:"cd "+s,install:"pnpm install",dev:"pnpm run dev",build:"pnpm run build:esm && pnpm run build:dts"}}[v];L({template:m,root:o,ts:!!a,env:l,staticFolder:i,useStatic:u}),N({projectName:r,env:l,root:o,ts:!!a,template:m,choiceStep:h}),D({root:o}),M({root:o,readme:m?.readme}),$.close(),m?.files?.forEach(d=>{let k=E.join(o,E.dirname(d?.path));j(k,{recursive:!0}),Y(E.join(o,d?.path),d?.content)}),T&&K(h?.install,{cwd:o,stdio:"inherit"}),console.log(e(`
|
|
379
917
|
\u2705 TezX project "${r}" is ready!
|
|
380
|
-
`,"green")),console.log(e("\u{1F9F0} Summary of your configuration:","cyan")),console.log(`\u{1F4C1} Project Name: ${e(r,"yellow")}`);let
|
|
381
|
-
`),console.log(e("\u{1F449} Next Steps:","cyan")),console.log(e(` ${
|
|
918
|
+
`,"green")),console.log(e("\u{1F9F0} Summary of your configuration:","cyan")),console.log(`\u{1F4C1} Project Name: ${e(r,"yellow")}`);let O=t?.t||t?.template;O&&console.log(`\u{1F4C1} Template Name: ${e(O,"orange")}`),console.log(`\u{1F7E6} TypeScript: ${e(a?"Yes":"No",a?"green":"gray")}`),console.log(`\u{1F4BB} Runtime: ${e(l,"blue")}`),console.log(`\u{1F4C1} Static Folder: ${e(u?i||"public":"Not Used",u?"green":"gray")}`),console.log(`\u{1F4E6} Package Manager: ${e(v,"magenta")}`),console.log(`\u{1F4E5} Dependencies Installed: ${e(T?"Yes":"No",T?"green":"red")}
|
|
919
|
+
`),console.log(e("\u{1F449} Next Steps:","cyan")),console.log(e(` ${h?.cd}`,"white")),T||console.log(e(` ${h?.install}`,"white")),console.log(e(` ${h?.dev}`,"white")),console.log(""),U(),process.exit(0)}function X(){console.log(`
|
|
382
920
|
${e("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E","gray")}
|
|
383
921
|
${e("\u2502","gray")} ${e("\u26A1 Create TezX","yellow")} - Scaffold your next backend app ${e("\u2502","gray")}
|
|
384
922
|
${e("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F","gray")}
|
|
@@ -418,4 +956,4 @@ ${r}Adapter(app).listen(3000, () => {
|
|
|
418
956
|
${e("https://github.com/tezxjs/tezx","underline")}
|
|
419
957
|
|
|
420
958
|
${e("\u{1F9D1}\u200D\u{1F4BB} Author:","cyan")}
|
|
421
|
-
Rakibul Islam ${e("<https://github.com/srakib17>","blue")}`),process.exit(0)}function
|
|
959
|
+
Rakibul Islam ${e("<https://github.com/srakib17>","blue")}`),process.exit(0)}function H(){console.log(`TezX CLI v${S}`),process.exit(0)}(async()=>{let n=(a,c)=>{c.name==="c"&&c.ctrl&&(process.stdin.off("keypress",n),process.stdin.isTTY&&process.stdin.setRawMode(!1),process.exit(0))};process.stdin.on("keypress",n);let s=process.argv.slice(2),t={},r;for(let a=0;a<s.length;a++){let c=s[a];if(c.startsWith("--")){let l=c.slice(2),i=s[a+1];i&&!i.startsWith("-")?(t[l]=i,a++):t[l]="true"}else if(c.startsWith("-")){let l=c.slice(1),i=s[a+1];i&&!i.startsWith("-")?(t[l]=i,a++):t[l]="true"}else r||(r=c)}let o={directory:r,options:t};if((t.y==="true"||t.yes==="true")&&(o.options.ts="true",o.options.useStatic="true",o.options.staticFolder="public",o.options.pm=f?.includes(o.options?.p||o?.options?.pm)?o.options?.p||o?.options?.pm:"npm",o.options.p=f?.includes(o.options?.p||o?.options?.pm)?o.options?.p||o?.options?.pm:"npm",o.options.env=x?.includes(o.options?.env||o?.options?.runtime)?o.options?.env||o?.options?.runtime:"node",o.options.runtime=x?.includes(o.options?.env||o?.options?.runtime)?o.options?.env||o?.options?.runtime:"node",o.options.install="true"),t.help||t.h){X();return}if(t.v||t.version){H();return}W(o)})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-tezx-app",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "TezX is a high-performance, lightweight JavaScript framework designed for speed, scalability, and flexibility. It enables efficient routing, middleware management, and static file serving with minimal configuration. Fully compatible with Node.js, Deno, and Bun.",
|
|
6
6
|
"bin": "./bin",
|