├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .prettierrc.js
├── LICENSE
├── README.md
├── SECURITY.md
├── bundle.ts
├── code-of-conduct.md
├── contributing.md
├── deno.json
├── docs
├── assets
│ ├── Request-Lifecycle.svg
│ ├── custom-typography.css
│ ├── favicon.ico
│ ├── home.png
│ ├── icon-transparent.webp
│ ├── icon.webp
│ ├── index.css
│ ├── index.html
│ ├── prism.css
│ └── prism.js
├── discord
│ └── index.html
├── docs
│ ├── credits.md
│ ├── docs
│ │ ├── context.md
│ │ ├── deployment.md
│ │ ├── error-handling.md
│ │ ├── installation.md
│ │ ├── introduction.md
│ │ ├── middleware.md
│ │ ├── plugin.md
│ │ ├── plugins.md
│ │ ├── quickstart.md
│ │ ├── request-lifecycle.md
│ │ ├── resources
│ │ │ └── resources.md
│ │ └── routing.md
│ └── home-links
│ │ └── tutorial.md
└── fragments
│ ├── docs.html
│ └── other.html
├── example
├── README.md
├── app.jet.ts
├── chat.html
├── data
│ └── models.ts
├── definitions.ts
├── index.jet.ts
├── middleware
│ └── global.ts
├── plugins
│ ├── auth.ts
│ └── logging.ts
├── routes
│ ├── auth.jet.ts
│ ├── live.jet.ts
│ ├── pets.jet.ts
│ ├── reviews.jet.ts
│ └── utils.jet.ts
├── types.ts
└── websockets-usage.md
├── icon-transparent.png
├── icon.png
├── pack
├── package-lock.json
├── package.json
├── repository-open-graph-template.png
├── src
├── assets
│ ├── api-doc.html
│ └── bundle.ts
├── cli.ts
├── extracts
│ └── mimejs-extract.ts
├── index.ts
└── primitives
│ ├── classes.ts
│ ├── functions.ts
│ └── types.ts
├── tsconfig.d.json
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | insert_final_newline = true
9 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | docs/build
2 | example
3 | bundle.ts
4 | dist
5 | definitions.jet.ts
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/gts/"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | ./lib
3 | **.tgz
4 | jetpath-**.tgz
5 | jetpath-**
6 | .history
7 | api-doc.http
8 | dist
9 | ./dist
10 | .vscode
11 | official-plugins
12 | security-audits
13 | formdata-psrser.ts
14 | tests/uploads
15 | docmach
16 | ccokies.ts
17 | repository-open-graph-template.png
18 | repository-open-graph-template.xcf
19 | example/uploads
20 | example/petshop-api-log.log
21 | example/val.ts
22 | example/ws.jet.ts
23 | tbench.ts
24 | trie.ts
25 | audit-server
26 | apis-types.d.ts
27 | NEXT-FEATURES.md
28 | example/pet-shop-api-log.log
29 | src/assets/bundle.js
30 | bench.sh
31 | **.log
32 | docs/build
33 | definitions.jet.ts
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | export default {
2 | ...require('node_modules/gts/.prettierrc.json')
3 | }
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | Copyright 2023 friday candour
179 |
180 | Licensed under the Apache License, Version 2.0 (the "License");
181 | you may not use this file except in compliance with the License.
182 | You may obtain a copy of the License at
183 |
184 | http://www.apache.org/licenses/LICENSE-2.0
185 |
186 | Unless required by applicable law or agreed to in writing, software
187 | distributed under the License is distributed on an "AS IS" BASIS,
188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189 | See the License for the specific language governing permissions and
190 | limitations under the License.
191 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
35 |
36 | ## Why Engineers Choose Jetpath
37 |
38 | Every framework promises to be fast and easy. Jetpath got built because most of them aren't.
39 |
40 | ```ts
41 | // This is a complete API endpoint in Jetpath
42 | export const GET_users_$id: JetRoute = async function (ctx) {
43 | const { id } = ctx.params;
44 | const user = await db.users.findUnique({ where: { id } });
45 | return ctx.send(user);
46 | };
47 | ```
48 |
49 | Jetpath eliminates the cognitive overhead that slows down development. No more router configuration, middleware chains, or callback hell. Just pure functions that map directly to HTTP endpoints through a clean, predictable naming convention.
50 |
51 | **The tech stack you already trust, but faster:**
52 | - Write APIs in TypeScript/JavaScript across Node.js, Deno, or Bun
53 | - ~50% less code than Express with stronger type safety
54 | - [Benchmarks](https://github.com/CodeDynasty-dev/jetpath-benchmark) show massive throughput compared to Elysia.js.
55 |
56 | ## Core Design Principles
57 |
58 | Jetpath is built with strong opinions on what matters most:
59 |
60 | 1. **Zero config by default** - Convention eliminates boilerplate
61 | 2. **Runtime agnostic** - True support for Node.js, Deno, and Bun (not just compatibility layers)
62 | 3. **Type safety** - Full TypeScript support that doesn't get in your way
63 | 4. **Predictable routing** - Routes derived from function names (GET_users_$id → GET /users/:id)
64 | 5. **Built for production** - Security, validation, and error handling baked in
65 |
66 | ## In Production
67 |
68 | I am using Jetpath in production and here are the results.
69 | - 40% reduction in API codebase size
70 | - Simplified onboarding for new team members
71 | - Faster iterations on API endpoints
72 |
73 | ## Quick Start
74 |
75 | ```bash
76 | # Create new project
77 | npx jetpath new-project
78 |
79 | # Navigate and start the dev server
80 | cd new-project && npm install && npm run dev
81 | ```
82 |
83 | ## API Design That Gets Out of Your Way
84 |
85 | ```ts
86 | import { type JetRoute, Jetpath, use } from "jetpath";
87 |
88 | const app = new Jetpath();
89 | app.listen(3000);
90 |
91 | // GET /products
92 | export const GET_products: JetRoute = async (ctx) => {
93 | const products = await db.products.findMany();
94 | ctx.send({ products });
95 | };
96 |
97 | // POST /products with validation
98 | export const POST_products: JetRoute = async (ctx) => {
99 | const data = await ctx.parse();
100 | const product = await db.products.create({ data });
101 | ctx.send({ product }, 201);
102 | };
103 |
104 | // Add validation and docs in one step
105 | use(POST_products)
106 | .title("Create a new product")
107 | .body((t) => ({
108 | name: t.string().required().min(3),
109 | price: t.number().required().min(0),
110 | description: t.string()
111 | }));
112 |
113 | // Maps to ws://your-host/live
114 | export const GET_live: JetRoute = (ctx) => {
115 | ctx.upgrade();
116 | const conn = ctx.connection!;
117 | conn.addEventListener("open", (socket) => { /* ... */ });
118 | conn.addEventListener("message", (socket, event) => { /* ... */ });
119 | };
120 | ```
121 |
122 | ## Key Features
123 |
124 | - **Unified dev experience** across Node.js, Deno, and Bun
125 | - **Auto-generated API documentation** with interactive UI
126 | - **First-class WebSocket support**
127 | - **Plugin system** for extending functionality
128 | - **Schema validation** that is part of api documentation
129 | - **Request parsing** that just works (JSON, forms, multipart)
130 | - **Performance-optimized** routing and middleware execution
131 | - **Security** good defaults
132 |
133 | ## Real Performance
134 |
135 | It's not just a claim how fast - measure it. In the [benchmark suite](hhttps://github.com/CodeDynasty-dev/jetpath-benchmark), Jetpath consistently perform close to raw Bunjs performance matches elysia.js on common API workloads:
136 |
137 | | Framework | Requests/sec | Latency (avg)
138 | |-----------|-------------|---------------|
139 | | Bun | ~40,890 | 12.2ms |
140 | | Elysia | ~33,383 | 13.2ms |
141 | | Jetpath | ~32,339 | 13.7ms |
142 |
143 | *4-core CPU, 1000 concurrent connections and 1,000,000 requests, simple JSON response*
144 |
145 | Bunjs being amongst the fastest http runtime.
146 |
147 | ## Installation
148 |
149 | For existing projects:
150 |
151 | ```bash
152 | npm install jetpath --save
153 | ```
154 |
155 | ## Community & Support
156 |
157 | - [Documentation](https://jetpath.codedynasty.dev) - In-depth guides and API reference
158 | - [Discord Community](https://discord.gg/faqydQASTy) - Get help from the team and other users
159 | - [GitHub Issues](https://github.com/codedynasty-dev/jetpath/issues) - Report bugs or request features
160 |
161 | ## License
162 |
163 | Apache 2.0 - Open source and built for the community.
164 |
165 | ### Contributing
166 |
167 | We welcome contributions! See our [contributing guide](https://github.com/CodeDynasty-dev/Jetpath/blob/main/contributing.md) for details on how to get involved.
168 |
169 | By contributing, you agree to license your code under the Apache 2.0 license and confirm that all contributions are your original work.
170 |
171 | ### Support or Sponsor the Project
172 |
173 | If Jetpath helps you or your team ship faster and more understandable codebase, consider supporting its development through [GitHub Sponsors](https://github.com/sponsors/CodeDynasty-dev).
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | ## Reporting a Vulnerability
2 |
3 | Please report security vulnerabilities to fridaycandours@gmail.com.
4 |
--------------------------------------------------------------------------------
/bundle.ts:
--------------------------------------------------------------------------------
1 | import { readFile, writeFile } from "fs/promises";
2 | // ? This file does a lot of in just few lines thanks to bunjs
3 | console.log("Jetpath: compiling...");
4 | const html = await readFile("src/assets/api-doc.html", {
5 | encoding: "utf-8",
6 | });
7 | const code = await readFile("dist/index.js", {
8 | encoding: "utf-8",
9 | });
10 | await Bun.build({
11 | entrypoints: ["src/assets/bundle.ts"],
12 | outdir: "src/assets",
13 | minify: true,
14 | // additional config
15 | });
16 | const html_script_code = await readFile("src/assets/bundle.js", {
17 | encoding: "utf-8",
18 | });
19 | const view = html.replaceAll(/(\n|\r|\s{2,})/g, "").replace(
20 | "{JETPATH-DOC-SCRIPT}",
21 | html_script_code,
22 | ).replaceAll(/`/g, "\\`")
23 | .replaceAll(/\${/g, "\\${");
24 | await writeFile("dist/index.js", code.replace("{{view}}", view));
25 | console.log("Jetpath: compiled!");
26 |
27 | // [X] npm pack will call npm run prepare which will run this file
28 |
--------------------------------------------------------------------------------
/code-of-conduct.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | As a member of the JetPath project, JetPath has adopted the
4 | [Contributor Covenant 2.0][cc-20-doc].
5 |
6 | If an issue arises and you cannot resolve it directly with the parties
7 | involved, you can report it to the JetPath project technical committee through the following
8 | email: {}
9 |
10 |
11 | ## Our Pledge
12 |
13 | We as members, contributors, and leaders pledge to make participation in our
14 | community a harassment-free experience for everyone, regardless of age, body
15 | size, visible or invisible disability, ethnicity, sex characteristics, gender
16 | identity and expression, level of experience, education, socio-economic status,
17 | nationality, personal appearance, race, religion, or sexual identity and
18 | orientation.
19 |
20 | We pledge to act and interact in ways that contribute to an open, welcoming,
21 | diverse, inclusive, and healthy community.
22 |
23 | ## Our Standards
24 |
25 | Examples of behavior that contributes to a positive environment for our
26 | community include:
27 |
28 | * Demonstrating empathy and kindness toward other people
29 | * Being respectful of differing opinions, viewpoints, and experiences
30 | * Giving and gracefully accepting constructive feedback
31 | * Accepting responsibility and apologizing to those affected by our mistakes,
32 | and learning from the experience
33 | * Focusing on what is best not just for us as individuals, but for the overall
34 | community
35 |
36 | Examples of unacceptable behavior include:
37 |
38 | * The use of sexualized language or imagery, and sexual attention or advances
39 | of any kind
40 | * Trolling, insulting or derogatory comments, and personal or political attacks
41 | * Public or private harassment
42 | * Publishing others' private information, such as a physical or email address,
43 | without their explicit permission
44 | * Other conduct which could reasonably be considered inappropriate in a
45 | professional setting
46 |
47 | ## Enforcement Responsibilities
48 |
49 | The project team are responsible for clarifying and enforcing our standards of
50 | acceptable behavior and will take appropriate and fair corrective action in
51 | response to any behavior that they deem inappropriate, threatening, offensive,
52 | or harmful.
53 |
54 | The project team have the right and responsibility to remove, edit, or reject
55 | comments, commits, code, wiki edits, issues, and other contributions that are
56 | not aligned to this Code of Conduct, and will communicate reasons for
57 | moderation decisions when appropriate.
58 |
59 | ## Scope
60 |
61 | This Code of Conduct applies within the community, and also applies when
62 | an individual is officially representing the community in public spaces.
63 | Examples of representing our community include using an official e-mail
64 | address, posting via an official social media account, or acting as an
65 | appointed representative at an online or offline event.
66 |
67 | ## Enforcement
68 |
69 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
70 | reported to the project team responsible for enforcement at
71 | {} All complaints will be reviewed and
72 | investigated promptly and fairly.
73 |
74 | All project team are obligated to respect the privacy and security of the
75 | reporter of any incident.
76 |
77 | ## Enforcement Guidelines
78 |
79 | The project team will follow these Community Impact Guidelines in determining
80 | the consequences for any action they deem in violation of this Code of Conduct:
81 |
82 | ### 1. Correction
83 |
84 | **Community Impact**: Use of inappropriate language or other behavior deemed
85 | unprofessional or unwelcome in the community.
86 |
87 | **Consequence**: A private, written warning from the project team, providing
88 | clarity around the nature of the violation and an explanation of why the
89 | behavior was inappropriate. A public apology may be requested.
90 |
91 | ### 2. Warning
92 |
93 | **Community Impact**: A violation through a single incident or series of
94 | actions.
95 |
96 | **Consequence**: A warning with consequences for continued behavior. No
97 | interaction with the people involved, including unsolicited interaction with
98 | those enforcing the Code of Conduct, for a specified period of time. This
99 | includes avoiding interactions in community spaces as well as external channels
100 | like social media. Violating these terms may lead to a temporary or permanent
101 | ban.
102 |
103 | ### 3. Temporary Ban
104 |
105 | **Community Impact**: A serious violation of community standards, including
106 | sustained inappropriate behavior.
107 |
108 | **Consequence**: A temporary ban from any sort of interaction or public
109 | communication with the community for a specified period of time. No public or
110 | private interaction with the people involved, including unsolicited
111 | interaction with those enforcing the Code of Conduct, is allowed during this
112 | period. Violating these terms may lead to a permanent ban.
113 |
114 | ### 4. Permanent Ban
115 |
116 | **Community Impact**: Demonstrating a pattern of violation of community
117 | standards, including sustained inappropriate behavior, harassment of an
118 | individual, or aggression toward or disparagement of classes of individuals.
119 |
120 | **Consequence**: A permanent ban from any sort of public interaction within the
121 | project community.
122 |
123 | ## Attribution
124 |
125 | This Code of Conduct is adapted from the [Contributor Covenant, version 2.0][cc-20-doc].
126 |
127 | Community Impact Guidelines were inspired by
128 | [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
129 |
130 | [cc-20-doc]: https://www.contributor-covenant.org/version/2/0/code_of_conduct/
131 |
132 | For answers to common questions about this code of conduct, see the FAQ at
133 | https://www.contributor-covenant.org/faq. Translations are available at
134 | https://www.contributor-covenant.org/translations.
--------------------------------------------------------------------------------
/contributing.md:
--------------------------------------------------------------------------------
1 |
2 | # JetPath Contributing Guide
3 |
4 |
5 | Welcome to the JetPath Contributing Guide, and thank you for your interest.
6 |
7 | If you would like to contribute to a specific part of the project, check out the following list of contributions that we accept and their corresponding sections that are within this guide:
8 |
9 | * Documentation
10 | * Go to the `docs` dir
11 | * Bug Fixes
12 | * Go to source code dir at `src`
13 | * New Features
14 | * Create a sample of the new feature, and start a discussion in the community forum.
15 |
16 | However, at this time, we do not accept the following contributions:
17 |
18 | * Maintenance
19 |
20 | ## JetPath overview
21 |
22 | The purpose of the JetPath is to streamline your development process while offering flexibility in your choice of runtime environment
23 |
24 | ## Ground rules
25 |
26 | Before contributing, read our [Code of Conduct](https://github.com/CodeDynasty-dev/Jetpath?tab=coc-ov-file) to learn more about our community guidelines and expectations.
27 |
28 | ## Community engagement
29 |
30 | Refer to the following channels to connect with fellow contributors or to stay up-to-date with news about JetPath:
31 |
32 | * Join our project contributors on {name and link to online chat}.Discord
33 | * Participate in our project meetings on {specify the day of the week and cadence} at {specify time and timezone}, where you can provide a status update or raise questions and concerns about your contributions. Use the following link to join: {link to online meeting space}
34 | 2-3 meetings monthly, Fridays
35 |
36 | ## Before you start
37 |
38 | Before you start contributing, ensure you have the following:
39 | * For developers: The latest version of [Node.js](https://nodejs.org/en/download), [Bon.js](https://bun.sh/), [Deno.js](https://deno.com/).
40 | * For writers: The lastest version of [Node.js](https://nodejs.org/en/download).
41 |
42 |
43 | ## Environment setup
44 |
45 | To set up your environment, perform the following actions:
46 |
47 | ### Developer
48 |
49 | 1. Fork the Repository: Click the **Fork** button at the top right of the repository page to create a copy under your GitHub account.
50 |
51 | 2. Clone your forked repository to your computer using the command below. Replace `yourusername` with your GitHub username:
52 |
53 | ```bash
54 | git clone https://github.com//JetPath.git
55 | ```
56 | 3. Navigate to the Project Directory: Change into the project folder using the command below.
57 |
58 | ```bash
59 | cd JetPath
60 | ```
61 | 4. Install Dependencies: Install all necessary packages with npm:
62 |
63 | ```bash
64 | npm install
65 |
66 | ```
67 | This will download and set up all libraries the project depends on.
68 |
69 | 5. Create a new branch for your feature or fix
70 | ```bash
71 | git checkout -b your-feature-branch
72 | ```
73 | 6. Run the Development Server: Start the local server to preview your changes
74 |
75 | ```bash
76 | npm run dev
77 | ```
78 | Open your browser and click the URL shown in the terminal (usually http://localhost:4000).
79 |
80 | 7. Compile the Project: Run the following command to build the project for production
81 |
82 | ```bash
83 | npm run compile
84 | ```
85 | 8. Push your branch to your fork and open a Pull Request to the main repository.
86 | Feel free to ask questions or open an issue if you need help!
87 |
88 |
89 | ### Writers
90 |
91 |
92 | 1. Fork the Repository: Click the **Fork** button at the top right of the repository page to create a copy under your GitHub account.
93 |
94 | 2. Clone your forked repository to your computer using the command below. Replace with your GitHub username:
95 |
96 | ```bash
97 | git clone https://github.com//JetPath.git
98 | ```
99 | 3. Navigate to the Project Directory: Change into the project folder using the command below.
100 |
101 | ```bash
102 | cd JetPath
103 | ```
104 | 4. Install Dependencies
105 | ```bash
106 | npm install
107 |
108 | ```
109 |
110 | 5. Create a new branch
111 |
112 | ```bash
113 | git checkout -b your-feature-branch
114 | ```
115 | 6. Preview your changes with this command below
116 |
117 | ```bash
118 | npx docmach
119 | ```
120 |
121 | 7. Push your branch to your fork and open a Pull Request to the main repository.
122 |
123 | Open your browser and click the URL shown in the terminal (usually http://localhost:4000).
124 |
125 |
126 |
127 | ### Troubleshoot
128 |
129 | If you encounter issues as you set up your environment,
130 | reach out to the team @fridaycandour for development and @NickyShe for documentation.
131 |
132 |
133 | ## Best practices
134 |
135 | Our project uses the [Google Typescript coding style guide](https://github.com/google/gts) as our parent guide for best practices. Reference the guide to familiarize yourself with the best practices we want contributors to follow
136 | ### Developers
137 |
138 | * Organize your code properly
139 | * Always run your test before pushing any code
140 |
141 | ### Writers
142 |
143 | Read the [Google developers documentation writing style guide](https://developers.google.com/style) to understand the guidelines for writing and formatting documents. The purpose of the style guide is to ensure consistency in the tone, voice, and structure of our documentation.
144 |
145 | ## Contribution workflow
146 |
147 | ### Report issues and bugs
148 |
149 | To help us improve JetPath, please report any issues or bugs you encounter. Here’s how you can do it:
150 |
151 | 1. **Check existing issues**: Before creating a new issue, search the issue tracker to see if someone else has already reported the problem.
152 | 2. **Create a new issue**: If you can’t find an existing issue, click the **New issue** button and fill out the template provided. Make sure to include:
153 | * Summarize the issue in a few words.
154 | * Explain the problem, including any error messages or unexpected behavior.
155 | * List the steps you took that led to the issue.
156 | * Describe what you expected to happen and what actually happened.
157 | * Attach any relevant screenshots or log files if applicable.
158 |
159 | 3. **Provide context**: If relevant, mention your environment for example, operating system, browser, version of JetPath.
160 |
161 | 4. **Use Labels**: Apply labels to categorize issues by type for eexample,bug, feature request, documentation.
162 | 5. **Prioritize**: Use priority labels for example, high, medium, low to indicate the urgency of the issue.
163 |
164 | 6. **Comment and discuss**: Use the issue comments to discuss the problem and potential solutions with other contributors.
165 |
166 | By following these steps, we can efficiently track and resolve issues, ensuring JetPath continues to improve for everyone.
167 |
168 | ### Commit messages
169 | Here are the types and description of commit messages
170 |
171 | | Type | Description |
172 | |----------|------------ |
173 | | feat | New feature |
174 | | fix | Bug fix |
175 | | docs | Documentation changes |
176 | | chore | Maintenance / build tasks |
177 | | refactor | Code refactoring without feature change |
178 |
179 | Example Commit message
180 |
181 | ```bash
182 | feat: add support for Deno.js runtime environment detection
183 |
184 | fix: resolve issue with npm run compile failing on Windows
185 |
186 | docs: update contributing guide with branch naming conventions
187 |
188 | chore: upgrade dependencies to latest stable versions
189 |
190 | refactor: reorganize src/utils for better modularity
191 |
192 | ```
193 |
194 | ### Branch creation
195 |
196 | To keep our repository organized and make collaboration easier, please follow these guidelines when creating and naming branches:
197 |
198 | Use a consistent prefix to indicate the type of work:
199 |
200 | * feature/ for new features
201 |
202 | * bugfix/ for bug fixes
203 |
204 | * hotfix/ for urgent or critical fixes
205 |
206 | * release/ for release preparation
207 |
208 | * docs/ for documentation updates
209 |
210 | Example:
211 | ```bash
212 | git checkout -b feature/add-user-authentication
213 | git checkout -b bugfix/fix-login-error
214 | git checkout -b docs/update-contributing-guide
215 | git checkout -b release/1.0.0
216 |
217 | ```
218 | Sticking to these conventions helps everyone quickly understand the purpose of each branch and keeps our workflow efficient
219 |
220 | ### Pull requests
221 |
222 | When your changes are ready, submit a pull request (PR) to propose merging your branch into the main repository. Please follow these steps:
223 |
224 | 1. Push your branch to your forked repository:
225 |
226 | ```bash
227 | git push -u origin your-branch-name
228 | ```
229 | 2. Open a pull request on GitHub:
230 |
231 | * Navigate to the main repository on GitHub.
232 |
233 | * Click "Compare & pull request" next to your branch.
234 |
235 | * Ensure the base branch is main (or the appropriate target branch).
236 |
237 | 3. Fill out the pull request template:
238 |
239 | * Provide a clear title and description.
240 |
241 | * List the main changes and the motivation behind them.
242 |
243 | * Reference any related issues by number (e.g., fixes #42).
244 |
245 | Pull Request Template Example:
246 | ```
247 | ## Description
248 | Briefly describe the purpose of this pull request.
249 |
250 | ## Changes
251 | - List key changes here
252 |
253 | ## Additional Information
254 | Add any extra context, screenshots, or testing instructions.
255 |
256 | ## Checklist
257 | - [ ] Tests passed
258 | - [ ] Documentation updated
259 | ```
260 |
261 | ### Releases
262 |
263 | {Provide a description of the release process and cadence for the project, such as the source code.}
264 |
265 |
266 | ---
267 |
--------------------------------------------------------------------------------
/deno.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@codedynasty/jetpath",
3 | "version": "1.4.17",
4 | "exports": "./dist/index.js",
5 | "ustable": [
6 | "byonm"
7 | ]
8 | }
--------------------------------------------------------------------------------
/docs/assets/custom-typography.css:
--------------------------------------------------------------------------------
1 | /* Custom Typography Styles */
2 | :root {
3 | --font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
4 |
5 | /* Font Sizes */
6 | --font-size-xs: 0.75rem;
7 | --font-size-sm: 0.875rem;
8 | --font-size-base: 1rem;
9 | --font-size-lg: 1.125rem;
10 | --font-size-xl: 1.25rem;
11 | --font-size-2xl: 1.5rem;
12 | --font-size-3xl: 1.875rem;
13 | --font-size-4xl: 2.25rem;
14 | --font-size-5xl: 3rem;
15 | --font-size-6xl: 4rem;
16 |
17 | /* Line Heights */
18 | --line-height-tight: 1.25;
19 | --line-height-normal: 1.5;
20 | --line-height-relaxed: 1.75;
21 | --line-height-loose: 2;
22 | }
23 |
24 | /* Base Typography */
25 | body {
26 | font-family: var(--font-family);
27 | line-height: var(--line-height-normal);
28 | }
29 |
30 | /* Headings */
31 | h1, h2, h3, h4, h5, h6 {
32 | font-weight: 600;
33 | line-height: var(--line-height-tight);
34 | margin-bottom: 1rem;
35 | }
36 |
37 | h1 {
38 | font-size: var(--font-size-4xl);
39 | color: var(--text);
40 | }
41 |
42 | h2 {
43 | font-size: var(--font-size-3xl);
44 | color: var(--text);
45 | border-bottom: 1px solid var(--border);
46 | padding-bottom: 0.5rem;
47 | }
48 |
49 | h3 {
50 | font-size: var(--font-size-2xl);
51 | color: var(--text);
52 | }
53 |
54 | h4 {
55 | font-size: var(--font-size-xl);
56 | color: var(--text-light);
57 | }
58 |
59 | h5 {
60 | font-size: var(--font-size-lg);
61 | color: var(--text-light);
62 | }
63 |
64 | h6 {
65 | font-size: var(--font-size-base);
66 | color: var(--text-light);
67 | }
68 |
69 | /* Paragraphs */
70 | p {
71 | font-size: var(--font-size-base);
72 | color: var(--text-light);
73 | margin-bottom: 1.5rem;
74 | }
75 |
76 | /* Lists */
77 | ul, ol {
78 | margin-bottom: 1.5rem;
79 | padding-left: 1.5rem;
80 | }
81 |
82 | li {
83 | margin-bottom: 0.5rem;
84 | }
85 |
86 | /* Code Blocks */
87 | pre {
88 | font-family: 'JetBrains Mono', monospace;
89 | font-size: 0.875rem;
90 | background: rgba(16, 16, 16, 0.9);
91 | padding: 1.5rem;
92 | border-radius: 0.5rem;
93 | overflow-x: auto;
94 | margin-bottom: 1.5rem;
95 | }
96 |
97 | code {
98 | font-family: 'JetBrains Mono', monospace;
99 | font-size: 0.875rem;
100 | background: rgba(16, 16, 16, 0.9);
101 | padding: 0.25rem 0.5rem;
102 | border-radius: 0.25rem;
103 | color: #7f99ff;
104 | }
105 |
106 | /* Blockquotes */
107 | blockquote {
108 | border-left: 3px solid var(--primary);
109 | padding: 1rem 1.5rem;
110 | margin: 1.5rem 0;
111 | background: rgba(16, 16, 16, 0.9);
112 | color: var(--text-light);
113 | }
114 |
115 | /* Tables */
116 | table {
117 | width: 100%;
118 | border-collapse: collapse;
119 | margin-bottom: 1.5rem;
120 | }
121 |
122 | th, td {
123 | padding: 0.75rem;
124 | text-align: left;
125 | border-bottom: 1px solid var(--border);
126 | }
127 |
128 | th {
129 | font-weight: 600;
130 | background: rgba(16, 16, 16, 0.9);
131 | }
132 |
133 | /* Links */
134 | a {
135 | color: var(--primary);
136 | text-decoration: none;
137 | transition: color 0.2s ease;
138 | }
139 |
140 | a:hover {
141 | color: var(--primary-dark);
142 | }
143 |
144 | /* Emphasis */
145 | strong {
146 | color: var(--text);
147 | }
148 |
149 | em {
150 | color: var(--text-light);
151 | }
152 |
153 | /* Horizontal Rules */
154 | hr {
155 | border: none;
156 | border-top: 1px solid var(--border);
157 | margin: 2rem 0;
158 | }
159 |
160 | /* Responsive Typography */
161 | @media (max-width: 768px) {
162 | h1 {
163 | font-size: var(--font-size-3xl);
164 | }
165 |
166 | h2 {
167 | font-size: var(--font-size-2xl);
168 | }
169 |
170 | h3 {
171 | font-size: var(--font-size-xl);
172 | }
173 |
174 | h4 {
175 | font-size: var(--font-size-lg);
176 | }
177 |
178 | pre {
179 | font-size: 0.8125rem;
180 | }
181 | }
182 |
183 |
184 | .token.string {
185 | color: gold !important;
186 | text-shadow: 0px 0px 12px gold !important;
187 | }
188 |
189 | .prose a, .prose strong, .prose em {
190 | color: var(--secondary);
191 | text-decoration: none;
192 | transition: color 0.2s ease;
193 | }
194 |
195 | /* mobile styles */
196 | @media (max-width: 768px) {
197 | .prose {
198 | font-size: var(--font-size-base);
199 | }
200 |
201 | .prose h1 {
202 | font-size: var(--font-size-2xl);
203 | }
204 |
205 | .prose h2 {
206 | font-size: var(--font-size-xl);
207 | }
208 |
209 | .prose h3 {
210 | font-size: var(--font-size-lg);
211 | }
212 |
213 | .prose h4 {
214 | font-size: var(--font-size-base);
215 | }
216 |
217 | .header {
218 | padding: 0;
219 | }
220 | }
--------------------------------------------------------------------------------
/docs/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeDynasty-dev/Jetpath/ec22ef8a7e056071590def7c0be943ed464398e7/docs/assets/favicon.ico
--------------------------------------------------------------------------------
/docs/assets/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeDynasty-dev/Jetpath/ec22ef8a7e056071590def7c0be943ed464398e7/docs/assets/home.png
--------------------------------------------------------------------------------
/docs/assets/icon-transparent.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeDynasty-dev/Jetpath/ec22ef8a7e056071590def7c0be943ed464398e7/docs/assets/icon-transparent.webp
--------------------------------------------------------------------------------
/docs/assets/icon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeDynasty-dev/Jetpath/ec22ef8a7e056071590def7c0be943ed464398e7/docs/assets/icon.webp
--------------------------------------------------------------------------------
/docs/assets/index.css:
--------------------------------------------------------------------------------
1 | :root{--primary:#fff;--primary-dark:#6769a9;--secondary:#3B82F6;--secondary-dark:#2563EB;--dark:#0A0A0A;--dark-light:#121212;--dark-lighter:#1A1A1A;--text:#F9FAFB;--text-light:#D1D5DB;--text-lighter:#9CA3AF;--border-color:rgba(255,255,255,0.1);--border-light:rgba(255,255,255,0.05)}body{background-color:var(--dark);color:var(--text);font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;overflow-x:hidden;line-height:1.6}a{color:inherit;text-decoration:none}.container{width:100%;max-width:1200px;margin:0 auto;padding:0 1.5rem}.header{position:fixed;top:0;left:0;right:0;z-index:100;background:rgba(10,10,10,0.8);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border-bottom:1px solid rgba(255,255,255,0.1);padding:1rem 0;transition:all 0.3s ease}.header-scrolled{background:rgba(10,10,10,0.95);box-shadow:0 4px 20px rgba(0,0,0,0.3)}.header-container{display:flex;justify-content:space-between;align-items:center}.logo{display:flex;align-items:center;font-weight:700;font-size:1.5rem}.logo-text{background:linear-gradient(90deg,var(--primary),var(--secondary));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;color:transparent}.nav{display:flex;align-items:center;gap:2rem}.nav-link{font-weight:500;transition:color 0.2s ease;position:relative}.nav-link::after{content:'';position:absolute;bottom:-4px;left:0;width:0;height:2px;background:linear-gradient(90deg,var(--primary),var(--secondary));transition:width 0.3s ease}.nav-link:hover::after{width:100%}.nav-link:hover{color:var(--primary)}.btn{display:inline-block;padding:0.75rem 1.5rem;border-radius:0.5rem;font-weight:600;transition:all 0.3s ease;cursor:pointer}.btn-primary{background:linear-gradient(135deg,var(--primary),var(--secondary));color:var(--dark);border:none;box-shadow:0 4px 14px rgba(59,130,246,0.3)}.btn-primary:hover{transform:translateY(-2px);box-shadow:0 6px 20px rgba(59,130,246,0.4)}.btn-outline{background:transparent;color:var(--text);border:1px solid rgba(255,255,255,0.1)}.btn-outline:hover{border-color:var(--primary);color:var(--primary)}.mobile-menu-btn{background:transparent none;font-size:1.5rem;display:none;padding:0.5rem;border:none;background:transparent;cursor:pointer;z-index:100}.hero{padding-top:15rem;padding-bottom:6rem;position:relative;overflow:hidden}.hero::before{content:'';position:absolute;top:0;left:0;right:0;bottom:0;background-image:radial-gradient(circle at 20% 30%,rgb(59 130 246) 0%,transparent 50%),radial-gradient(circle at 80% 70%,rgb(37 99 235) 0%,transparent 50%);z-index:-1}.hero-grid{position:absolute;top:0;left:0;right:0;bottom:0;background-image:linear-gradient(rgba(255,255,255,0.02) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,0.02) 1px,transparent 1px);background-size:30px 30px;z-index:-1}.hero-content{display:flex;flex-direction:column;align-items:center;text-align:center;max-width:900px;margin:0 auto}.hero-badge{background:#2563eb;border:1px solid rgba(110,231,183,0.2);color:var(--primary);font-size:0.875rem;font-weight:500;padding:0.5rem 1rem;border-radius:2rem;margin-bottom:1.5rem}.hero-title{font-size:3.5rem;font-weight:800;line-height:1.2;margin-bottom:1.5rem;background:linear-gradient(to right,var(--primary),var(--secondary));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;color:transparent}.hero-subtitle{font-size:1.25rem;color:var(--text-light);max-width:700px;margin-bottom:2.5rem}.hero-cta{display:flex;gap:1rem;margin-bottom:4rem}.code-demo{width:100%;max-width:800px;margin:0 auto;border-radius:0.75rem;overflow:hidden;box-shadow:0 20px 50px rgba(0,0,0,0.5);transform:translateY(0);transition:transform 0.3s ease}.code-demo:hover{transform:translateY(-5px)}.code-header{display:flex;align-items:center;background:#1E1E1E;padding:0.75rem 1rem;border-bottom:1px solid rgba(255,255,255,0.1)}.code-dots{display:flex;gap:0.375rem;margin-right:1rem}.code-dot{width:0.75rem;height:0.75rem;border-radius:50%}.code-dot.red{background-color:#FF5F56}.code-dot.yellow{background-color:#FFBD2E}.code-dot.green{background-color:#27C93F}.code-tabs{display:flex;gap:1rem}.code-tab{font-size:0.875rem;color:var(--text-lighter);cursor:pointer;padding-bottom:0.25rem;border-bottom:2px solid transparent;transition:all 0.2s ease}.code-tab.active{color:var(--primary);border-bottom-color:var(--primary)}.code-content{background:#1E1E1E;position:relative}.code-wrapper{display:none}.code-wrapper.active{display:block}.copy-btn{position:absolute;top:1rem;right:1rem;background:rgba(255,255,255,0.1);border:none;color:var(--text-lighter);padding:0.375rem 0.75rem;border-radius:0.25rem;font-size:0.75rem;cursor:pointer;transition:all 0.2s ease;z-index:2}.copy-btn:hover{background:rgba(255,255,255,0.2);color:var(--text)}pre{margin:0 0!important;padding:1.5rem 1.5rem!important;font-size:0.9rem;line-height:1.6;border-radius:0}code{font-family:'Menlo','Monaco','Consolas',monospace}.section{padding:6rem 0}.section-title{text-align:center;margin-bottom:1rem;text-align:center;font-size:2.25rem;text-align:center;margin-bottom:3rem}.section-title span{background:linear-gradient(to right,var(--primary),var(--secondary));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;color:transparent}.section-subtitle{font-size:1.125rem;color:var(--text-light);text-align:center;max-width:700px;margin:0 auto 3rem}.features-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:2rem}.feature-card{background:var(--dark-lighter);border:1px solid rgba(255,255,255,0.1);border-radius:1rem;padding:2rem;transition:all 0.3s ease;height:100%;display:flex;flex-direction:column}.feature-card:hover{transform:translateY(-5px);box-shadow:0 10px 30px rgba(0,0,0,0.2);border-color:rgb(37 99 235 / 57%)}.feature-icon{width:3rem;height:3rem;background:linear-gradient(135deg,#2563eb,rgba(59,130,246,0.2));border-radius:0.75rem;display:flex;align-items:center;justify-content:center;margin-bottom:1.5rem}.feature-icon svg{width:1.5rem;height:1.5rem;color:var(--primary)}.feature-title{font-size:1.25rem;font-weight:600;margin-bottom:0.75rem}.feature-description{color:var(--text-light);font-size:1rem;line-height:1.6;flex-grow:1}.why-jetpath{background:linear-gradient(to bottom,var(--dark),var(--dark-light))}.comparison-table{width:100%;background:var(--dark-lighter);border-radius:1rem;overflow:hidden;border:1px solid rgba(255,255,255,0.1);margin-top:2rem;box-shadow:0 10px 30px rgba(0,0,0,0.2)}.comparison-table thead{background:#2563eb}.comparison-table th,.comparison-table td{padding:1rem 1.5rem;text-align:left;border-bottom:1px solid rgba(255,255,255,0.1)}.comparison-table th{font-weight:600;color:var(--text)}.comparison-table td{color:var(--text-light)}.comparison-table tr:last-child td{border-bottom:0}.highlight-cell{color:var(--primary)!important}.performance{background:var(--dark);position:relative;overflow:hidden}.performance::before{content:'';position:absolute;top:0;left:0;right:0;bottom:0;background:radial-gradient(circle at 10% 90%,rgba(110,231,183,0.08) 0%,transparent 50%);z-index:-1}.benchmark-container{background:var(--dark-lighter);border:1px solid rgba(255,255,255,0.1);border-radius:1rem;padding:2rem;margin-top:3rem;box-shadow:0 10px 30px rgba(0,0,0,0.2)}.benchmark-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:2rem;margin-top:2rem}.benchmark-card{text-align:center}.benchmark-value{font-size:2.5rem;font-weight:700;background:linear-gradient(to right,var(--primary),var(--secondary));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;color:transparent;margin-bottom:0.5rem}.benchmark-label{color:var(--text-light);font-size:0.875rem}.ecosystem{background:linear-gradient(to bottom,var(--dark-light),var(--dark))}.ecosystem-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:2rem}.ecosystem-card{background:var(--dark-lighter);border:1px solid rgba(255,255,255,0.1);border-radius:1rem;padding:2rem;transition:all 0.3s ease;text-align:center}.ecosystem-card:hover{transform:translateY(-5px);box-shadow:0 10px 30px rgba(0,0,0,0.2);border-color:rgba(59,130,246,0.3)}.ecosystem-icon{width:3.5rem;height:3.5rem;margin:0 auto 1.5rem;background:linear-gradient(135deg,#2563eb,rgba(10,10,10,0.95));border-radius:50%;display:flex;align-items:center;justify-content:center}.ecosystem-icon svg{width:1.75rem;height:1.75rem;color:var(--secondary)}.ecosystem-title{font-size:1.25rem;font-weight:600;margin-bottom:0.75rem}.ecosystem-description{color:var(--text-light);font-size:1rem}.cta{background:linear-gradient(to bottom right,var(--dark-light),#0B1120);padding:6rem 0;position:relative;overflow:hidden}.cta::before{content:'';position:absolute;top:0;left:0;right:0;bottom:0;background:radial-gradient(circle at 80% 20%,rgba(59,130,246,0.15) 0%,transparent 50%),radial-gradient(circle at 20% 80%,rgba(110,231,183,0.15) 0%,transparent 50%);z-index:-1}.cta-content{max-width:600px;margin:0 auto;text-align:center}.cta-title{font-size:2.5rem;font-weight:800;margin-bottom:1.5rem}.cta-description{color:var(--text-light);font-size:1.125rem;margin-bottom:2.5rem}.cta-buttons{display:flex;justify-content:center;gap:1rem}.footer{background:var(--dark);padding:4rem 0 2rem;border-top:1px solid rgba(255,255,255,0.1)}.footer-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:3rem;margin-bottom:3rem}.footer-brand{grid-column:1 / -1}@media (min-width:768px){.footer-brand{grid-column:auto}}.footer-logo{font-size:1.5rem;font-weight:700;margin-bottom:1rem;background:linear-gradient(90deg,var(--primary),var(--secondary));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;color:transparent}.footer-tagline{color:var(--text-light);font-size:0.875rem;margin-bottom:1.5rem}.footer-social{display:flex;gap:1rem}.footer-social-link{width:2rem;height:2rem;background:rgba(255,255,255,0.05);border-radius:50%;display:flex;align-items:center;justify-content:center;color:var(--text-light);transition:all 0.2s ease}.footer-social-link:hover{background:#2563eb;color:var(--primary);transform:translateY(-3px)}.footer-heading{font-size:1rem;font-weight:600;margin-bottom:1.25rem}.footer-links{list-style:none}.footer-link{margin-bottom:0.75rem}.footer-link a{color:var(--text-light);font-size:0.9rem;transition:color 0.2s ease}.footer-link a:hover{color:var(--primary)}.footer-bottom{border-top:1px solid rgba(255,255,255,0.1);padding-top:2rem;text-align:center;color:var(--text-lighter);font-size:0.875rem}@keyframes float{0%,100%{transform:translateY(0)}50%{transform:translateY(-15px)}}.float-animation{animation:float 6s ease-in-out infinite}@media (max-width:768px){.nav{display:none;position:absolute;top:100%;left:0;right:0;flex-direction:column;align-items:center;gap:1rem;padding:1.5rem;background:rgba(10,10,10,0.95);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border-bottom:1px solid rgba(255,255,255,0.1)}.nav.active{display:flex}.mobile-menu-btn{display:block}.hero-title{font-size:2.5rem}.hero-cta{flex-direction:column}.code-demo{border-radius:0.5rem}.section-title{font-size:2rem}.cta-title{font-size:2rem}.cta-buttons{flex-direction:column}}.custom-shape{position:absolute;width:500px;height:500px;filter:blur(100px);opacity:0.15;z-index:-1}.shape-1{background:var(--primary);top:10%;right:-200px;border-radius:100% 0 0 100%}.shape-2{background:var(--secondary);bottom:-200px;left:-100px;border-radius:100%}.interactive-features{display:flex;flex-wrap:wrap;justify-content:center;gap:1rem;margin-bottom:3rem}.feature-btn{background:var(--dark-lighter);border:1px solid rgba(255,255,255,0.1);color:var(--text-light);padding:0.75rem 1.5rem;border-radius:0.5rem;font-weight:500;cursor:pointer;transition:all 0.3s ease}.feature-btn:hover,.feature-btn.active{background:linear-gradient(135deg,#2563eb,rgba(59,130,246,0.1));border-color:rgb(37 99 235 / 57%);color:var(--primary);transform:translateY(-3px)}.terminal{position:relative;width:100%;max-width:800px;margin:3rem auto 0;border-radius:0.75rem;overflow:hidden;box-shadow:0 20px 50px rgba(0,0,0,0.5)}.terminal-header{display:flex;align-items:center;background:#1E1E1E;padding:0.75rem 1rem;border-bottom:1px solid rgba(255,255,255,0.1)}.terminal-title{margin-left:1rem;font-size:0.875rem;color:var(--text-lighter)}.terminal-body{background:#0D1017;padding:1.5rem;font:0.875rem/1.7 'Menlo','Monaco','Consolas',monospace;color:var(--text-light)}.terminal-line{display:flex;margin-bottom:0.5rem}.terminal-prompt{color:var(--primary);margin-right:0.75rem;user-select:none}.terminal-output{opacity:0;animation:fadeIn 0.5s ease forwards}@keyframes fadeIn{from{opacity:0}to{opacity:1}}.terminal-cursor{display:inline-block;width:0.5rem;height:1.2rem;background:var(--primary);margin-left:2px;animation:blink 1s infinite}@keyframes blink{0%,100%{opacity:1}50%{opacity:0}}.terminal-typing{position:relative}.terminal-typing::after{content:'|';position:absolute;right:-10px;animation:blink 1s infinite}.cursor-highlight{position:fixed;width:300px;height:300px;border-radius:50%;pointer-events:none;background:radial-gradient(circle,#2563eb 0%,rgba(110,231,183,0) 70%);transform:translate(-50%,-50%);z-index:-1;opacity:0;transition:opacity 0.3s ease-out}.section-padding{padding:5rem 1.5rem}@media (min-width:768px){.section-padding{padding-left:3rem;padding-right:3rem}}@media (min-width:1024px){.section-padding{padding-left:6rem;padding-right:6rem}}@media (min-width:768px){.section-title{font-size:2.75rem;margin-bottom:4rem}}.glassmorphism{background:rgba(16,16,16,0.7);border-radius:16px;box-shadow:0 4px 30px rgba(0,0,0,0.2);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,0.15);padding:8px;margin-top:1rem}.red{border:1px red solid}.red-a *{border:1px red solid}.logo-container{display:flex;align-items:center;gap:1rem}.search-bar-container{width:100%;flex-grow:1;max-width:400px}.search-bar{position:relative;display:flex;align-items:center;background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.1);border-radius:0.5rem;padding:0.5rem 1rem;transition:all 0.3s ease;width:100%;max-width:100%}.search-bar:focus-within{border-color:var(--primary);box-shadow:0 0 0 2px rgba(110,231,183,0.2)}.search-input{background:transparent;border:none;color:var(--text);font-size:1rem;width:100%;outline:0}.search-bar svg{margin-right:0.5rem}@media (max-width:768px){.header-container{display:grid;grid-template-rows:1fr 1fr}.shape-1,.shape-2{display:none}.header-container.container{width:100%;padding:12px;display:flex;justify-content:center;align-items:center;flex-direction:column}.search-bar-container{flex-basis:100%;max-width:100%;margin-bottom:0.5rem}.header-container .flex.w-full.justify-between{min-width:80vw;margin:0 auto}.search-bar{max-width:100%}}:not(pre)>code[class*=language-],pre[class*=language-]{background-color:#000523!important}.mobile-menu-btn svg{width:24px;height:24px}.mobile-overlay{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:85}@media (max-width:1024px){.mobile-menu-btn{display:block}#doc-side-bar{position:fixed;top:0;left:-256px;width:256px;min-height:100vh;height:100%;background:rgba(10,10,10,0.8);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border-right:1px solid rgba(255,255,255,0.1);z-index:90;padding:2rem 1rem;transition:left 0.3s ease}#doc-side-bar.active{left:0;display:block}.mobile-overlay.active{display:block}.main-content{margin-left:0;padding:4rem 1.5rem 1.5rem}}@media (min-width:768px){.footer-brand{grid-column:auto}}@keyframes float{0%,100%{transform:translateY(0)}50%{transform:translateY(-15px)}}@media (max-width:768px){.nav{display:none;position:absolute;top:100%;left:0;right:0;flex-direction:column;align-items:center;gap:1rem;padding:1.5rem;background:rgba(10,10,10,0.95);backdrop-filter:blur(10px);-webkit-backpack-filter:blur(10px);border-bottom:1px solid rgba(255,255,255,0.1)}.nav.active{display:flex}.mobile-menu-btn{display:block}.hero-title{font-size:2.5rem}.hero-cta{flex-direction:column}.code-demo{border-radius:0.5rem}.section-title{font-size:2rem}.cta-title{font-size:2rem}.cta-buttons{flex-direction:column}}@keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes blink{0%,100%{opacity:1}50%{opacity:0}}@media (min-width:768px){.section-padding{padding-left:3rem;padding-right:3rem}}@media (min-width:1024px){.section-padding{padding-left:6rem;padding-right:6rem}}@media (min-width:768px){.section-title{font-size:2.75rem;margin-bottom:4rem}}@media (max-width:768px){.header-container{display:grid;grid-template-rows:1fr 1fr}.shape-1,.shape-2{display:none}.header-container.container{width:100%;padding:0px;display:flex;justify-content:center;align-items:center;flex-direction:column}.search-bar-container{flex-basis:100%;max-width:100%;margin-bottom:0.5rem}.header-container .flex.w-full.justify-between{min-width:80vw;margin:0 auto}.search-bar{max-width:100%}}#doc-side-bar{position:fixed;top:0;left:0;width:256px;height:100vh;background:rgba(10,10,10,0.8);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border-right:1px solid rgba(255,255,255,0.1);z-index:90;}.main-content{margin-left:256px;padding:4rem 1.5rem 1.5rem}@media (max-width:1024px){#doc-side-bar{display:none}.main-content{margin-left:0;padding:4rem 1.5rem 1.5rem}}
--------------------------------------------------------------------------------
/docs/assets/prism.css:
--------------------------------------------------------------------------------
1 | /* PrismJS 1.30.0
2 | https://prismjs.com/download#themes=prism-okaidia&languages=markup+css+clike+javascript+http+typescript */
3 | code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#272822}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8292a2}.token.punctuation{color:#f8f8f2}.token.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#a6e22e}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.important,.token.regex{color:#fd971f}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
4 |
--------------------------------------------------------------------------------
/docs/discord/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | CodeDynasty.dev on Discord
7 |
12 |
13 |
14 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/docs/docs/credits.md:
--------------------------------------------------------------------------------
1 | # Hello world
--------------------------------------------------------------------------------
/docs/docs/docs/deployment.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Deployment
4 |
5 | Deploying your Jetpath application involves packaging your code and dependencies, choosing a hosting environment, and running the application server so it's accessible to users. Jetpath's flexibility allows you to deploy it across various platforms using Node.js, Deno, or Bun as the runtime.
6 |
7 | ---
8 |
9 | ## General Considerations Before Deployment
10 |
11 | Regardless of your target platform, consider these points:
12 |
13 | 1. **Build Step (TypeScript Compilation):**
14 | * Jetpath applications are typically written in TypeScript (`.jet.ts`, `.ts`).
15 | * **Node.js/Bun (often):** You'll usually need to compile your TypeScript code to JavaScript using `tsc` (based on your `tsconfig.json`) or Bun's built-in bundler/transpiler before deployment. Your `server.ts` entry point will then run the compiled JavaScript output (e.g., `node dist/server.js`).
16 | * **Deno:** Deno can run TypeScript directly. You might still have a build step for bundling or type checking (`deno check server.ts`), but compilation to JS isn't strictly necessary for running.
17 | * Ensure your build output includes all necessary JavaScript files.
18 |
19 | 2. **Dependencies:**
20 | * **Node.js/Bun:** Your `node_modules` directory (containing dependencies listed in `package.json`) must be included in the deployment or installed on the target server using `npm install --production`, `yarn install --production`, or `bun install --production`.
21 | * **Deno:** Dependencies are typically cached based on imports. Ensure the deployment environment has network access to download dependencies on first run, or use `deno vendor` to vendor dependencies locally before deployment.
22 |
23 | 3. **Runtime Choice:**
24 | * Ensure the exact runtime (Node.js, Deno, or Bun) and version you developed with is installed and available in your deployment environment (VM, container image, PaaS setting).
25 |
26 | 4. **Environment Variables:**
27 | * **Never hardcode secrets** (API keys, database passwords, JWT secrets) in your code.
28 | * Use environment variables (`process.env.VARIABLE_NAME`) to manage configuration.
29 | * Most hosting platforms provide a way to securely set environment variables for your application. Consult your platform's documentation.
30 |
31 | 5. **Port Binding:**
32 | * Your Jetpath application listens on a port specified in the `Jetpath` constructor (`port: 3000`) or potentially via an environment variable (e.g., `process.env.PORT`).
33 | * Most hosting platforms (PaaS, Containers) automatically route external traffic (on port 80/443) to the port your application listens on internally. Ensure your application respects the `PORT` environment variable if provided by the platform.
34 |
35 | 6. **Static Files:**
36 | * If your application serves static files (CSS, JS, images) using Jetpath's `static` option, ensure these files are included in your deployment package and the paths are configured correctly. Often, it's more performant to serve static files directly via a reverse proxy (like Nginx) or a CDN.
37 |
38 | ---
39 |
40 | ## Common Deployment Strategies
41 |
42 | Here are outlines for common deployment approaches:
43 |
44 | ### 1. Virtual Machines (VMs) / Bare Metal
45 |
46 | * **Concept:** You manage the operating system, runtime installation, and application deployment manually or via configuration management tools.
47 | * **Steps:**
48 | 1. Provision a VM (e.g., AWS EC2, Google Compute Engine, DigitalOcean Droplet) or prepare a physical server.
49 | 2. Install your chosen runtime (Node.js, Deno, or Bun).
50 | 3. Install necessary tools (Git, potentially a process manager like PM2).
51 | 4. Clone your application repository or copy your built application code (including `node_modules` or vendor directory).
52 | 5. Install production dependencies if needed.
53 | 6. Set environment variables (e.g., using `.env` files with `dotenv` or system environment variables).
54 | 7. Start your application server (e.g., `node dist/server.js`, `deno run --allow-net server.ts`, `bun run server.ts`).
55 | 8. **(Recommended)** Use a process manager (like PM2 for Node.js/Bun, or systemd for any runtime) to automatically restart your app if it crashes and manage logs.
56 | 9. **(Recommended)** Set up a reverse proxy (like Nginx or Caddy) in front of your Jetpath app to handle TLS/SSL termination (HTTPS), load balancing (if running multiple instances), basic caching, and potentially serving static files directly.
57 |
58 | ### 2. Containers (Docker)
59 |
60 | * **Concept:** Package your application, its runtime, and dependencies into a standardized container image. Deploy this image using container orchestration platforms.
61 | * **Steps:**
62 | 1. **Create a `Dockerfile`:**
63 | * Start with a base image for your chosen runtime (e.g., `node:18-alpine`, `denoland/deno:latest`, `oven/bun:latest`).
64 | * Set the working directory (e.g., `/app`).
65 | * Copy `package.json`, `*.lockb`, `deno.json` etc. and install dependencies (`npm install --production`, `deno cache`, `bun install --production`). Use multi-stage builds to keep the final image small.
66 | * Copy your application source code.
67 | * Perform the build step if necessary (`RUN tsc` or `RUN bun build`).
68 | * Expose the port your Jetpath application listens on (`EXPOSE 3000`).
69 | * Set the command to run your application (`CMD ["node", "dist/server.js"]` or `CMD ["deno", "run", "--allow-net", "server.ts"]` or `CMD ["bun", "run", "server.ts"]`).
70 | 2. **Build the Docker Image:** `docker build -t my-jetpath-app .`
71 | 3. **Run the Container:** `docker run -p 3000:3000 -e "NODE_ENV=production" -e "DATABASE_URL=..." my-jetpath-app` (Map port, pass environment variables).
72 | 4. **Deploy:** Push the image to a registry (Docker Hub, AWS ECR, Google Artifact Registry) and deploy it using platforms like Kubernetes, AWS ECS, Google Cloud Run, Docker Swarm, etc. These platforms handle scaling, networking, and health checks.
73 |
74 | ### 3. Platform-as-a-Service (PaaS)
75 |
76 | * **Concept:** Abstract away server management. You push your code, and the platform handles building, deploying, scaling, and routing.
77 | * **Platforms:** Heroku, Render, Fly.io, Railway, Vercel (Node.js focus), Deno Deploy (Deno focus).
78 | * **Steps:**
79 | 1. Choose a PaaS provider that supports your chosen runtime (Node.js, Deno, or Bun).
80 | 2. Configure your project according to the platform's requirements:
81 | * **Procfile (Heroku, others):** Define how to start your web process (e.g., `web: node dist/server.js`).
82 | * **Build Scripts (`package.json`):** Define `build` and `start` scripts.
83 | * **Runtime Configuration:** Specify the runtime version (e.g., `engines` in `package.json`, `deno.json`, platform-specific config files).
84 | * **Environment Variables:** Configure secrets and settings through the platform's dashboard or CLI.
85 | 3. Connect your Git repository to the platform.
86 | 4. Push your code. The platform will detect your project type, install dependencies, run your build script, and deploy your application.
87 |
88 | ### 4. Serverless Functions
89 |
90 | * **Concept:** Run your code in response to events (like HTTP requests) without managing servers. Pay per execution.
91 | * **Platforms:** AWS Lambda, Google Cloud Functions, Azure Functions, Cloudflare Workers.
92 | * **Steps:**
93 | 1. **Adapter/Wrapper:** This is often the trickiest part. Serverless platforms have specific event formats. You typically need an **adapter** layer to translate the platform's event into a standard `Request` object that Jetpath can understand and convert Jetpath's response back into the format the platform expects. Look for official or community-provided adapters for running generic web frameworks (or specifically Jetpath, if available) on your target serverless platform. Without an adapter, significant manual integration is required.
94 | 2. **Packaging:** Bundle your Jetpath application code, dependencies (including the adapter), and any build output into a deployment package (e.g., a zip file).
95 | 3. **Configuration:** Define the function handler (pointing to the adapter's entry point), memory allocation, timeout, and environment variables.
96 | 4. **API Gateway:** Configure an API Gateway service (like AWS API Gateway or Google Cloud API Gateway) to create an HTTP endpoint that triggers your serverless function.
97 |
98 | ---
99 |
100 | ## Jetpath Specifics & Recommendations
101 |
102 | * **Cross-Runtime:** The main advantage is choosing the best platform *and* runtime combination for your needs. Docker and VMs offer the most flexibility here. PaaS support might vary depending on how well they support Deno and Bun compared to Node.js. Serverless often requires runtime-specific adapters.
103 | * **Configuration:** Rely heavily on environment variables for configuration across all deployment types.
104 | * **Build Output:** Ensure your deployment process correctly includes the compiled JavaScript output (`dist` folder or similar) if applicable for your runtime choice.
105 | * **Process Management:** For VM/Bare Metal, always use a process manager (PM2, systemd) to ensure your app restarts on failure. Containers and PaaS handle this automatically.
106 | * **Logging:** Configure structured logging (e.g., JSON format) that can be easily ingested by your chosen platform's logging service (CloudWatch, Google Cloud Logging, Datadog, etc.).
107 |
108 | ---
109 |
110 | ## Next Steps
111 |
112 | * Consult the documentation for your chosen **hosting platform** and **runtime** for detailed, platform-specific instructions.
113 | * Review Jetpath's [**Configuration**](./configuration.md) options.
114 | * Implement robust [**Logging**](#observability) for monitoring your deployed application. *(Assuming an Observability page exists)*
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/docs/docs/docs/error-handling.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Error Handling
4 |
5 | Robust error handling is essential for creating reliable APIs. Jetpath centralizes error handling in middleware for consistent error management.
6 |
7 | ## Philosophy
8 |
9 | Instead of scattered `try...catch` blocks, Jetpath's approach relies on:
10 |
11 | 1. **Signaling Errors:** Using `throw new Error()`
12 | 2. **Centralized Catching:** Intercepting errors in middleware
13 | 3. **Standardized Responses:** Sending consistent error responses
14 |
15 | ## Throwing Errors
16 |
17 | When processing cannot continue normally, signal an error using `ctx.send(error, )`.
18 |
19 | ### Using `ctx.send(error, )`
20 |
21 | - **Common Status Codes:**
22 | - `400 Bad Request`: Validation errors
23 | - `401 Unauthorized`: Authentication issues
24 | - `403 Forbidden`: Permission denied
25 | - `404 Not Found`: Resource not found
26 | - `500 Internal Server Error`: Unexpected issues
27 |
28 | - **Examples:**
29 | ```typescript
30 | // Resource Not Found
31 | if (!pet) {
32 | ctx.send(`Pet ${ctx.params.id} not found`, 404);
33 | }
34 |
35 | // Unauthorized Access
36 | if (!ctx.plugins.verifyAuth(ctx).authenticated) {
37 | ctx.set("WWW-Authenticate", "Bearer realm=\"protected\"");
38 | ctx.send("Authentication required", 401);
39 | }
40 |
41 | // Forbidden Action
42 | if (ctx.app.user?.role !== 'admin') {
43 | ctx.send("Admin privileges required", 403);
44 | }
45 |
46 | // Validation Error
47 | try {
48 | const data = ctx.validate(RequestSchema);
49 | } catch (err) {
50 | ctx.send(err.message, 400);
51 | }
52 |
53 | // Simple Not Found
54 | ctx.send("",404);
55 | ```
56 |
57 | ### Using `throw new Error()`
58 |
59 | For unexpected internal errors:
60 |
61 | ```typescript
62 | try {
63 | const result = await riskyOperation();
64 | } catch (error) {
65 | console.error("Internal error:", error);
66 | throw new Error("Internal processing error");
67 | }
68 | ```
69 |
70 | ## Middleware Error Handling
71 |
72 | The post-handler function in middleware handles errors from route handlers and validation.
73 |
74 | ### Error Handling Structure
75 |
76 | ```typescript
77 | return (ctx, err?: Error) => {
78 | if (err) {
79 | // 1. Log error
80 | console.error({
81 | message: `Request Error: ${err.message}`,
82 | stack: err.stack,
83 | requestId: ctx.get("X-Request-ID"),
84 | url: ctx.request.url,
85 | method: ctx.request.method,
86 | });
87 | // 2. Set status code
88 | ctx.code = ctx.code >= 400 ? ctx.code : 500;
89 | // 3. Format response
90 | const errorMessage = (ctx.code >= 500 && process.env.NODE_ENV === 'production')
91 | ? "Internal Server Error"
92 | : err.message || "An unexpected error occurred";
93 | const errorResponse = {
94 | error: {
95 | message: errorMessage,
96 | code: ctx.code,
97 | requestId: ctx.get("X-Request-ID"),
98 | },
99 | timestamp: new Date().toISOString(),
100 | };
101 | // 4. Send response
102 | ctx.set("Content-Type", "application/json");
103 | ctx.send(errorResponse);
104 | // 5. Stop processing
105 | return;
106 | }
107 | // Handle successful responses
108 | };
109 | ```
110 |
111 | ## Error Cases
112 |
113 | - **404 Not Found:** Send 404 response if no error and no response was sent
114 | - **400 Bad Request:** Use `ctx.send(, 400)` for validation errors
115 | - **401 Unauthorized:** Use `ctx.send(, 401)` with `WWW-Authenticate` header
116 | - **403 Forbidden:** Use `ctx.send(, 403)` for permission issues
117 | - **500 Internal Error:** Handle unexpected errors with generic messages
118 |
119 | ## Best Practices
120 |
121 | - **Centralize:** Implement error handling in global middleware
122 | - **Standardize:** Use consistent JSON structure for error responses
123 | - **Log Effectively:** Include request context in error logs
124 | - **Secure:** Never leak sensitive information in production
125 | - **Use `ctx.send(error, )`:** Prefer it for HTTP-specific errors
126 |
127 | ## Next Steps
128 |
129 | - Review the [Middleware](./middleware.html) documentation
130 | - Learn about the [Context (`ctx`) Object](./context.html) methods
131 |
132 |
133 |
--------------------------------------------------------------------------------
/docs/docs/docs/installation.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # Installation
5 |
6 | Hello welcome to jetpath.
7 |
8 |
9 | Get ready to build universal JavaScript backends! Installing Jetpath is straightforward and adapts to your preferred runtime environment: Node.js, Deno, or Bun.
10 |
11 | ---
12 |
13 | ## Prerequisites
14 |
15 | Before you begin, ensure you have the following installed:
16 |
17 | 1.**A JavaScript Runtime:**
18 |
19 | **Node.js:** Version 18.x or later recommended. ([Download Node.js](https://nodejs.org/))
20 |
21 | **Deno:** Version 1.30 or later recommended. ([Install Deno](https://deno.land/manual/getting_started/installation))
22 |
23 | **Bun:** Version 1.0 or later recommended. ([Install Bun](https://bun.sh/docs/installation))
24 |
25 | 2.**TypeScript:** Jetpath is built with TypeScript and provides first-class typing support. While you can use it with JavaScript,
26 |
27 | TypeScript is highly recommended for the best experience.
28 |
29 | ```bash
30 | npm install -g typescript
31 | ```
32 |
33 | ---
34 |
35 | ## Installing Jetpath:
36 |
37 | ```bash
38 | # Create your project folder
39 | mkdir my-api
40 |
41 | # Navigate to your project folder
42 | cd my-api
43 |
44 | # Initialize a new Node.js project
45 | npm init -y
46 |
47 |
48 |
49 |
50 | # Choose the installation method corresponding to your primary development runtime.
51 |
52 | # Using npm
53 | npm install jetpath
54 |
55 | # Using yarn
56 | yarn add jetpath
57 |
58 | # Using pnpm
59 | pnpm add jetpath
60 | ````
61 |
62 |
63 | -----
64 |
65 | ## Project Setup
66 |
67 | Regardless of the runtime, a basic project structure and TypeScript configuration are recommended.
68 |
69 | **1. Folder Structure:**
70 |
71 | A common structure looks like this:
72 |
73 | ```
74 | your-project/
75 | ├── src/ # Your Jetpath route handlers (.jet.ts files)
76 | │ └── users.jet.ts # where you defined functions for users
77 | │ └── products.jet.ts # where you defined functions for products
78 | │ └── auth.jet.ts # where you defined functions for authentication
79 | │ └── carts.jet.ts # where you defined functions for carts
80 | │ └── users.jet.ts # where you defined functions for users
81 | ├── server.jet.ts # Your main server entry point (initializes Jetpath)
82 | ├── node_modules/ # (Node.js/Bun)
83 | ├── package.json # (Node.js/Bun)
84 | └── tsconfig.json # TypeScript configuration
85 | ```
86 |
87 |
88 |
89 | ## Next Steps
90 |
91 | * Quick Start: Build your first simple API following the [**Quick Start**](./quickstart.html) guide.
92 | * Core Concepts: Dive deeper into how Jetpath works by reading the [**Core Concepts**](./routing.html).
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/docs/docs/docs/introduction.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Introduction to Jetpath
4 |
5 | **Write Once, Run Cross-runtime**
6 |
7 | Welcome to Jetpath! 🚀 If you're a JavaScript/TypeScript developer looking to build modern APIs, you're in for a treat. Jetpath is more than just another framework - it's your new best friend in backend development, designed to make your life easier while giving you unprecedented flexibility.
8 |
9 | ## What Makes Jetpath Special?
10 |
11 | Jetpath isn't just another framework - it's a new way of thinking about backend development. Here's why developers love it:
12 |
13 | - **Write Once, Run Cross-runtime:** Your code runs seamlessly on Node.js, Deno, or Bun. No more worrying about runtime lock-in!
14 | - **Zero-Config Magic:** Create endpoints by simply writing functions. No need to wrestle with complex configuration files.
15 | - **TypeScript First:** Built with TypeScript from the ground up, giving you the best of both worlds: type safety and JavaScript flexibility.
16 | - **Joy:** We've eliminated all the boring parts of backend development so you can focus on what matters - building amazing features.
17 |
18 | ## How It Works
19 |
20 | Jetpath uses smart conventions and naming-based routing. Instead of writing route definitions, you just:
21 |
22 | 1\. Create `.jet.ts` or `.jet.js` files in your `src` directory
23 |
24 | 2\. Export functions with intuitive names like `METHOD_optionalPathSegment`
25 |
26 | 3\. Let Jetpath handle the rest
27 |
28 | For example, create `src/users.jet.ts` with:
29 | ```typescript
30 | // This becomes GET /users
31 | export const GET_users: JetRoute = (ctx) => {
32 | ctx.send({ message: "I am super fast and runs on any runtime!" });
33 | };
34 | ```
35 |
36 | It's that simple!
37 |
38 | ## Why Developers Love Jetpath
39 |
40 | Here's what makes Jetpath stand out:
41 |
42 | - 🚀 **Blazing Fast Development:** No more configuration files or complex setup. Just write your code and let Jetpath handle the rest.
43 | - 📚 **Automatic API Docs:** Define your validation schemas once, and get beautiful, interactive API documentation that stays in sync with your code.
44 | - 🔒 **Type Safety:** Built with TypeScript first, giving you the best of both worlds: type safety and JavaScript flexibility.
45 | - 🧩 **Unlimited Extensibility:** Extend Jetpath with official plugins or create your own. The framework is designed to grow with your needs.
46 | - 💡 **Smart Conventions:** Instead of fighting with the framework, Jetpath works the way you think. Function naming conventions means your code structure matches your API structure.
47 |
48 | ## Jetpath is perfect for:
49 |
50 | - **Every Developer & Teams:** Build projects faster without sacrificing quality
51 | - **Startups:** Rapidly iterate on your API while maintaining type safety
52 | - **Enterprise Teams:** Build maintainable, scalable APIs that work across multiple runtimes
53 | - **Full-Stack Developers:** Finally have a backend framework that matches the joy of frontend development
54 | - **Anyone Who Hates Boilerplate:** Jetpath handles the boring stuff so you can focus on what matters
55 | - **Anyone Who Loves:** Developer experience, code maintainability, and runtime flexibility
56 |
57 | ## Ready to Get Started?
58 |
59 | Dive into Jetpath and experience the joy of modern backend development:
60 |
61 | - **Quick Start:** Follow our [Quick Start](./quickstart.html) guide to build your first API in minutes
62 | - **Core Concepts:** Explore the [Core Concepts](./routing.html) to understand how everything works together
63 |
64 | Join the [Discord community](https://discord.codedynasty.dev),
65 |
66 |
67 | ## Who is Jetpath For?
68 |
69 | Jetpath is an excellent choice for:
70 |
71 | - **Startups and Teams:** Needing to build and iterate quickly without sacrificing structure or type safety
72 | - **Multi-Platform Deployments:** Developers targeting or potentially migrating between Node.js, Deno, and Bun environments
73 | - **API-First Development:** Projects where clear, automatically generated API documentation is essential
74 | - **Full-Stack Developers:** Looking for a productive and modern JavaScript/TypeScript backend framework
75 | - **Anyone valuing:** Developer experience, code maintainability, and runtime flexibility
76 |
77 | ## Discord?
78 |
79 | Join the growing [community of developers](https://discord.codedynasty.dev) who've discovered that building APIs can be both powerful and fun! 🚀
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/docs/docs/docs/middleware.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Middleware
4 |
5 | Middleware functions are a fundamental part of building applications with Jetpath. They allow you to implement cross-cutting concerns like logging, authentication, and error handling in a clean, reusable way.
6 |
7 | ## What is Middleware?
8 |
9 | Middleware are functions that sit in the middle of the request-response cycle. They can:
10 |
11 | - Execute any code
12 | - Modify request and response objects (`ctx`)
13 | - End the request-response cycle early
14 | - Handle errors
15 | - Process responses after route handlers
16 |
17 | ## Defining Middleware
18 |
19 | In Jetpath, middleware is defined by exporting a special function named `MIDDLEWARE_` from a `.jet.ts` file.
20 |
21 | ```typescript
22 |
23 | import { type JetMiddleware } from "jetpath";
24 |
25 | export const MIDDLEWARE_: JetMiddleware = (ctx) => {
26 | // Pre-handler: Initial request processing
27 | console.log("Start: ", ctx.request.url);
28 | const startTime = Date.now();
29 | // Post-handler: Response processing
30 | return (ctx, err) => {
31 | const duration = Date.now() - startTime;
32 | // Error handling
33 | if (err) {
34 | ctx.code = ctx.code >= 400 ? ctx.code : 500;
35 | ctx.send({
36 | error: {
37 | message: ctx.code < 500 ? err.message : "Internal Server Error",
38 | code: ctx.code,
39 | },
40 | });
41 | return;
42 | }
43 | console.log("End: ", ctx.request.url, duration + "ms");
44 | };
45 | };
46 |
47 | ```
48 |
49 | ### Key Concepts
50 |
51 | 1. **Middleware Structure**
52 | - Pre-handler: Runs before route handler
53 | - Post-handler: Runs after route handler
54 | - Error handling: Built into post-handler
55 | - Response handling: Required for all cases
56 |
57 | 2. **Execution Flow**
58 | - Request → Pre-handler → Route Handler → Post-handler
59 | - Multiple middleware: Pre-handler → Pre-handler → ... → Route Handler → ... → Post-handler → Post-handler
60 |
61 | 3. **Response Handling**
62 | - Always handle responses in post-handler
63 | - Handle errors and 404s appropriately
64 |
65 | 4. **Error Handling**
66 | - Use `err` parameter in post-handler
67 | - Set appropriate status codes
68 | - Send standardized error responses
69 | - Return after sending response
70 |
71 | ## Scoping Middleware
72 |
73 | Middleware can be scoped to apply globally or to specific parts of your API:
74 |
75 | ## Common Use Cases
76 |
77 | - **Logging:** Request/response logging
78 | - **Authentication:** Token verification
79 | - **Authorization:** Role-based access control
80 | - **Response Formatting:** Standard headers and response structure
81 | - **Error Handling:** Centralized error management
82 | - **Rate Limiting:** Request rate control
83 |
84 | ## Error Handling
85 |
86 | Best practices for error handling in middleware:
87 |
88 | 1. Check for errors in the `err` parameter
89 | 2. Log error details
90 | 3. Set appropriate HTTP status code
91 | 4. Send standardized error response
92 | 5. Return after sending response
93 |
94 | ## Best Practices
95 |
96 | - Keep middleware focused on single concerns
97 | - Be mindful of execution order
98 | - Handle errors properly
99 | - Avoid heavy computations in global middleware
100 |
101 | ## Next Steps
102 |
103 | - Learn about the [Context (`ctx`) Object](./context.html)
104 | - Understand the complete [Request Lifecycle](./request-lifecycle.html)
105 | - Review [Error Handling](./error-handling.html) strategies
106 |
107 |
108 |
--------------------------------------------------------------------------------
/docs/docs/docs/plugin.md:
--------------------------------------------------------------------------------
1 |
2 | ## jetpath plugins
3 |
4 | Jetpath plugins are a way to extend the functionalities of Jetpath.
5 | They can be used to add new features to Jetpath or to modify existing ones.
6 |
7 | Plugins can be used to add new routes, middleware, or to modify the request
8 | and response objects or even convert to serverless runtime.
9 |
10 | ### Creating a plugin
11 |
12 | ```ts
13 | import { JetPlugin } from "jetpath";
14 |
15 | export const plugin = new JetPlugin{
16 | name: "plugin",
17 | version: "1.0.0",
18 | executor({ config }) {
19 | return {
20 | greet_world() {
21 | return {
22 | body: "Hello world",
23 | };
24 | },
25 | };
26 | },
27 | });
28 |
29 | ```
--------------------------------------------------------------------------------
/docs/docs/docs/plugins.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Extending Jetpath: Plugins
4 |
5 | Plugins are the primary way to extend Jetpath's core functionality, promote code reuse, and encapsulate complex or shared logic, such as authentication, database interactions, file handling, logging, or connections to third-party services.
6 |
7 | ---
8 |
9 | ## What are Plugins?
10 |
11 | Think of plugins as self-contained modules that can:
12 |
13 | 1. **Initialize Resources:** Set up database connections, configure API clients, read configuration, etc., when the application starts.
14 | 2. **Expose Functionality:** Add new methods and properties to the `ctx.plugins` object, making them easily accessible within your middleware and route handlers.
15 | 3. **Manage Dependencies:** Encapsulate dependencies needed by the plugin's functionality (as discussed in [Dependency Injection](./dependency-injection.md)).
16 |
17 | ---
18 |
19 | ## Using Plugins
20 |
21 | Integrating existing plugins (whether official Jetpath plugins or community-created ones) is straightforward.
22 |
23 | ### 1. Installation
24 |
25 | Install the plugin package using your preferred package manager:
26 |
27 | ```bash
28 | # Example installing an official file upload plugin
29 | npm install @jetpath/plugin-busboy
30 | # or
31 | bun add @jetpath/plugin-busboy
32 | # or add via import map/URL for Deno
33 | ````
34 |
35 | ### 2\. Registration
36 |
37 | Instantiate the plugin (if necessary, passing configuration options) and register it with your Jetpath application instance using `app.use()`. Registration typically happens in your main server file (`server.ts`).
38 |
39 | ```typescript
40 | // server.ts
41 | import { Jetpath } from "jetpath";
42 | // Assuming jetbusboy is the exported plugin factory/instance
43 | import { jetbusboy } from "@jetpath/plugin-busboy";
44 | import { createAuthPlugin } from "./plugins/authPlugin"; // Your custom auth plugin
45 |
46 | const app = new Jetpath({ source: "./src" });
47 |
48 | // Instantiate and register plugins
49 | // Official plugin for multipart/form-data handling
50 | app.use(jetbusboy);
51 |
52 | // Custom authentication plugin (example)
53 | const authPlugin = createAuthPlugin({ /* options like JWT secret */ });
54 | app.use(authPlugin);
55 |
56 | app.listen();
57 | ```
58 |
59 | *[cite: Registration pattern shown in tests/app.jet.ts]*
60 |
61 | **Important:** Plugins are generally executed/initialized in the order they are registered with `app.use()`.
62 |
63 | ### 3\. Accessing Plugin Functionality
64 |
65 | Once registered, the methods and properties returned by the plugin's `executor` function become available on the `ctx.plugins` object within middleware and route handlers.
66 |
67 | ```typescript
68 | // In a route handler or middleware
69 | import type { JetRoute, JetMiddleware } from "jetpath";
70 | // Import types exposed by plugins if available
71 | import type { JetBusBoyType } from "@jetpath/plugin-busboy";
72 | import type { AuthPluginAPI } from "./plugins/authPlugin";
73 |
74 | // Use generics to type ctx.plugins
75 | type HandlerPlugins = [JetBusBoyType, AuthPluginAPI];
76 |
77 | export const POST_upload: JetRoute<{}, HandlerPlugins> = async (ctx) => {
78 | // Access file upload functionality from jetbusboy plugin
79 | const formData = await ctx.plugins.formData(ctx);
80 | const image = formData.image;
81 | // ... process image ...
82 |
83 | ctx.send({ message: "Upload processed" });
84 | };
85 |
86 | export const GET_profile: JetRoute<{}, HandlerPlugins> = (ctx) => {
87 | // Access auth functionality from authPlugin
88 | const authResult = ctx.plugins.verifyAuth(ctx); // Example method name
89 | if (!authResult.authenticated) {
90 | ctx.send("Not authenticated", 402);
91 | }
92 | ctx.send({ user: authResult.user });
93 | };
94 | ```
95 |
96 | *[cite: Usage pattern `ctx.plugins.methodName()` shown in tests/app.jet.ts]*
97 |
98 | -----
99 |
100 | ## Creating Plugins
101 |
102 | Creating your own plugins allows you to structure reusable logic cleanly.
103 |
104 | ### The `executor` Function
105 |
106 | * **Purpose:** This function is the core of your plugin. It's executed when `app.use(yourPluginInstance)` is called.
107 | * **Initialization:** Use the `executor` to perform any setup required by your plugin (e.g., establish database connections, initialize SDKs, read configuration). It can be `async` if needed.
108 | * **Return Value:** The `executor` **must return an object**. The properties and methods of this returned object are merged into the `ctx.plugins` object, forming the public API of your plugin.
109 | * **Dependency Scope:** Variables defined *outside* the returned object but *within* the `executor`'s scope (or the factory function's scope, like `prefix` and `dbClient` in the examples) act as private state or encapsulated dependencies for your plugin's public methods.
110 |
111 | ### Example: Simplified Auth Plugin Structure
112 |
113 | This mirrors the `authPlugin` structure seen in `tests/app.jet.ts`.
114 |
115 | ```typescript
116 | import { JetPlugin } from "jetpath";
117 | import type { JetContext } from "jetpath";
118 |
119 | // Define the API exposed by this plugin
120 | export interface AuthPluginAPI {
121 | verifyAuth: (ctx: JetContext) => { authenticated: boolean; user?: any; message?: string };
122 | isAdmin: (ctx: JetContext) => boolean;
123 | }
124 |
125 | // Define configuration options
126 | interface AuthPluginOptions {
127 | jwtSecret: string;
128 | adminApiKey: string;
129 | }
130 |
131 | export function createAuthPlugin(options: AuthPluginOptions): JetPlugin {
132 | // Dependencies are configured here and accessible within the executor's returned methods
133 | const JWT_SECRET = options.jwtSecret;
134 | const ADMIN_API_KEY = options.adminApiKey;
135 | // In-memory store or DB connection could be initialized here
136 |
137 | return ({
138 | executor(): AuthPluginAPI {
139 | // Return the methods that handlers will call via ctx.plugins
140 | return {
141 |
142 |
143 | verifyAuth(this: JetContext) {
144 | // ? the this here is the ctx of the api request, hence you have access to the entire context;
145 | const authHeader = this.get("authorization");
146 | // ... logic to validate token using JWT_SECRET ...
147 | if (/* valid token */) {
148 | // const user = findUserFromToken(...);
149 | return { authenticated: true, user: { id: '...', role: '...' } };
150 | }
151 | return { authenticated: false, message: "Invalid token" };
152 | },
153 |
154 | isAdmin(this: JetContext) {
155 | if (this.get("x-admin-key") === ADMIN_API_KEY) {
156 | return true;
157 | }
158 | const auth = this.verifyAuth(ctx); // Can call other plugin methods
159 | return auth.authenticated && auth.user?.role === "admin";
160 | }
161 | };
162 | }
163 | });
164 | }
165 | ```
166 |
167 | *[cite: Based on `authPlugin` structure in tests/app.jet.ts]*
168 |
169 | -----
170 |
171 | ## Plugin Lifecycle
172 |
173 | * **Instantiation:** You create an instance of your plugin, potentially passing configuration options.
174 | * **Registration:** You call `app.use(pluginInstance)`.
175 | * **Execution:** The plugin's `executor` function runs during the `app.use()` call. Any asynchronous operations within the `executor` should complete before the server starts fully listening or handling requests (depending on Jetpath's internal handling, usually `app.listen` awaits plugin initialization implicitly or explicitly).
176 | * **Runtime:** The methods returned by the `executor` are available on `ctx.plugins` for every incoming request handled after the plugin was registered.
177 |
178 | -----
179 |
180 | ## Best Practices
181 |
182 | * **Single Responsibility:** Design plugins to handle a specific concern (authentication, database access, specific API client).
183 | * **Clear API:** Define a clear and well-typed interface for the functionality your plugin exposes.
184 | * **Configuration:** Allow configuration via options passed during instantiation rather than relying solely on global environment variables within the plugin.
185 | * **Asynchronous Initialization:** Handle connections and other async setup correctly within the `executor` using `async/await`.
186 | * **Documentation:** Document your plugin's configuration options and the methods it provides on `ctx.plugins`.
187 |
188 | -----
189 |
190 | ## Next Steps
191 |
192 | * Understand how plugin methods are accessed via the [**Context (`ctx`) Object**](./context.html).
193 |
194 |
195 |
196 |
197 |
198 |
199 |
--------------------------------------------------------------------------------
/docs/docs/docs/quickstart.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # Quick Start Guide
5 |
6 | Let's build your first Jetpath application! This guide will walk you through creating a simple API server that returns a welcome message.
7 |
8 | ## Prerequisites
9 |
10 | Before you start, make sure you have:
11 |
12 | - A compatible JavaScript runtime (Node.js v18+, Deno v1.30+, or Bun v1.0+)
13 |
14 | ## Create a New Project
15 |
16 | ```bash
17 | npx jetpath my-api
18 | ```
19 |
20 | Your project structure will look like this:
21 |
22 | ```
23 | my-api/
24 | ├── src/
25 | │ ├── app/
26 | │ │ ├── auth.jet.ts
27 | │ │ ├── carts.jet.ts
28 | │ │ ├── products.jet.ts
29 | │ │ └── users.jet.ts
30 | │ ├── db/
31 | │ │ ├── schema.ts
32 | │ │ ├── interfaces.ts
33 | │ │ └── index.ts
34 | │ └── site/
35 | │ ├── index.html
36 | │ ├── about.html
37 | │ └── contact.html
38 | ├── package.json
39 | ├── .dockerignore
40 | ├── .gitignore
41 | ├── Dockerfile
42 | ├── README.md
43 | ├── fly.toml
44 | └── tsconfig.json
45 | ```
46 |
47 | ## Install Dependencies
48 |
49 | ```bash
50 | cd my-api
51 | npm install # or yarn install or pnpm install or bun install
52 | ```
53 |
54 | ## Create Your First Route
55 |
56 | Create a file named `users.jet.ts` in the `src` directory:
57 |
58 | ```typescript
59 | // src/users.jet.ts
60 | import { type JetRoute, use } from "jetpath";
61 |
62 | /**
63 | * Handles GET requests to the root path ('/')
64 | */
65 | export const GET_users: JetRoute = (ctx) => {
66 | ctx.send({
67 | message: "Welcome to your first Jetpath API!",
68 | status: "ok"
69 | });
70 | };
71 |
72 | use(GET_users).title("Returns a welcome message and API status.");
73 | ```
74 |
75 | ## Create the Server Entry Point
76 |
77 | Create a file named `server.ts` in your project root:
78 |
79 | ```typescript
80 | // server.ts
81 | import { Jetpath } from "jetpath";
82 |
83 | const app = new Jetpath({
84 | source: "./src",
85 | port: 3000,
86 | apiDoc: {
87 | name: "My First Jetpath API",
88 | info: "This is the documentation for the Quick Start API.",
89 | color: "#7e57c2",
90 | display: "UI"
91 | }
92 | });
93 |
94 | app.listen();
95 | ```
96 |
97 | ## Run Your Server
98 |
99 | ```bash
100 | npx run dev
101 | ```
102 |
103 | ## Verify It Works
104 |
105 | 1. Open your browser and navigate to `http://localhost:3000` to see the JSON response
106 | 2. Visit `http://localhost:3000/api-docs` to explore the interactive API documentation
107 |
108 | **Congratulations! You've successfully created and run your first Jetpath application!**
109 |
110 | ## Next Steps
111 |
112 | - Learn about [Routing](./routing.md), the [Context Object](./context.md), [Validation](./validation.md), and [Middleware](./middleware.md)
113 | - Build more complex features by following the practical [Guides](./guides/crud-api.md)
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/docs/docs/docs/request-lifecycle.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Request Lifecycle
4 |
5 | Understanding Jetpath's request lifecycle is essential for building efficient and maintainable applications. This document outlines the complete journey of a request from request to response.
6 |
7 |
8 |
9 | ## 1. Request
10 |
11 | When a request is received:
12 |
13 | - The request path is matched against registered routes
14 | - A `Context` instance is retrieved from the pool for the request
15 | - Request metadata is extracted (method, headers, path)
16 | - Query parameters are normalized
17 |
18 | ## 2. Pre-Handler Middleware
19 |
20 | Before reaching the route handler, the request passes through pre-handler middleware:
21 |
22 | - Executed before the route handler
23 | - Can modify the request or response
24 | - Used for authentication, validation, rate limiting, and logging
25 |
26 | ## 3. Route Handler Execution
27 |
28 | Once the request reaches the handler:
29 |
30 | - The handler executes the business logic
31 | - Processes request data
32 | - Generates the response
33 |
34 | ## 4. Post-Processing
35 |
36 | ### Post-Handler Middleware
37 |
38 | After the handler executes, the response passes through post-handler middleware:
39 |
40 | - Modifies the response as needed
41 | - Performs final processing
42 | - Sends the response to the client
43 |
44 | ## Error Handling
45 |
46 | Error handling is integrated throughout the lifecycle:
47 | - Catches and handles errors at each stage
48 | - Ensures consistent error responses
49 | - Provides error recovery mechanisms
50 |
--------------------------------------------------------------------------------
/docs/docs/docs/resources/resources.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Resources
4 |
5 | ### Application Types
6 |
7 | For detailed information, see:
8 | - [Context API Reference](/docs/context.html)
9 | - [Plugin Documentation](/docs/plugins.html)
10 | - [Routing Guide](/docs/routing.html)
11 | - [Middleware Guide](/docs/middleware.html)
12 |
13 |
--------------------------------------------------------------------------------
/docs/docs/docs/routing.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # Core Concepts 1: Routing
5 |
6 | Routing in Jetpath is designed to be intuitive, relying on **convention over configuration** through a **function naming convention**. Your exported function names directly determine your API endpoints.
7 |
8 | ## Key Concepts
9 |
10 | ### 1. Source Directory
11 |
12 | When you initialize Jetpath, specify a `source` directory for your `.jet.ts` route handler files:
13 |
14 | ```typescript
15 | // index.jet.ts
16 | import { Jetpath } from "jetpath";
17 |
18 | const app = new Jetpath({
19 | source: "./src"
20 | });
21 |
22 | app.listen();
23 | ```
24 |
25 | ### 2. Handler Files (`.jet.ts`)
26 |
27 | Files ending with `.jet.ts` are scanned for exported functions that define route handlers. Other `.ts` or `.js` files are ignored for routing but can be imported by your handlers.
28 |
29 | ### 3. Export Naming Convention
30 |
31 | The core convention lies in the names of the exported functions:
32 |
33 | - **Format:** `METHOD_optionalPathSegment`
34 | - **`METHOD`:** HTTP method prefix (uppercase only):
35 | - `GET_`
36 | - `POST_`
37 | - `PUT_`
38 | - `DELETE_`
39 | - `PATCH_`
40 | - `HEAD_`
41 |
42 | **Examples: In `src/pets.jet.ts`:**
43 |
44 | ```typescript
45 | // GET /pets
46 | export const GET_pets: JetRoute = (ctx) => { ... }
47 |
48 | // POST /pets
49 | export const POST_pets: JetRoute = async (ctx) => { ... }
50 |
51 | // GET /pets/search
52 |
53 | export const GET_pets_search: JetRoute = (ctx) => { ... }
54 | ```
55 |
56 | ### 4. Path Parameters (`$paramName`)
57 |
58 | Capture dynamic segments using a `$` prefix in filenames or export names:
59 |
60 | ```typescript
61 | // Maps to: GET /pets/by/:id
62 | export const GET_pets_by$id: JetRoute = (ctx) => {
63 | const petId = ctx.params.id;
64 | // ...
65 | };
66 |
67 |
68 | // Maps to: GET /pets/petBy/:id/:slug
69 | export const GET_pets_petBy$id$slug: JetRoute = (ctx) => {
70 | const petId = ctx.params.id;
71 | const slug = ctx.params.slug;
72 | // ...
73 | };
74 | ```
75 |
76 | ### 5. Catch-all Routes (`$0`)
77 |
78 | Match multiple path segments using `$0
79 | `:
80 |
81 | ```typescript
82 | // Maps to GET /*
83 | export const GET_$0: JetRoute = (ctx) => {
84 | const filePath = ctx.params.$0; // e.g., "file.txt" from
85 | ctx.sendStream(filePath, {
86 | folder: "./files",
87 | });
88 | };
89 |
90 |
91 | ```
92 |
93 | ### 6. WebSocket Routes (`WS`) via `ctx.upgrade()`
94 |
95 | ```typescript
96 | // Maps to ws://your-host/live
97 | export const GET_live: JetRoute = (ctx) => {
98 | ctx.upgrade();
99 | const conn = ctx.connection!;
100 | conn.addEventListener("open", (socket) => { /* ... */ });
101 | conn.addEventListener("message", (socket, event) => { /* ... */ });
102 | // ...
103 | };
104 | ```
105 |
106 | ## Route Precedence
107 |
108 | Jetpath follows standard routing precedence:
109 | Static routes (e.g., `/pets/search`) are matched before dynamic routes (`/pets/:id`)
110 |
111 | ## Next Steps
112 |
113 | - Learn how the [Context (`ctx`) Object](./context.html) provides access to request/response data
114 | - Understand the full [Request Lifecycle](./request-lifecycle.html), including middleware execution
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/docs/docs/home-links/tutorial.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Building APIs with Jetpath: A Framework Creator's Perspective
4 |
5 | As the creator of Jetpath, I'm excited to share the story behind this framework and how it can revolutionize the way you build APIs. Jetpath was born from my frustration with existing frameworks and a vision for a simpler, more declarative approach to API development.
6 |
7 | ## The Journey to Jetpath
8 |
9 | Before creating Jetpath, I spent years working with various frameworks, each with their own set of challenges:
10 |
11 | - Too much boilerplate code
12 | - Complex configuration
13 | - Manual type definitions
14 | - Tedious documentation maintenance
15 | - Runtime-specific limitations
16 |
17 | I wanted to create something different - a framework that would make API development enjoyable again.
18 |
19 | ## The Vision Behind Jetpath
20 |
21 | When I designed Jetpath, I had several key principles in mind:
22 |
23 | 1. **Simplicity First** - No configuration needed to get started
24 | 2. **Type Safety** - Built-in TypeScript support with zero configuration
25 | 3. **Declarative Approach** - Routes as simple exports instead of complex registrations
26 | 4. **Developer Experience** - Automatic documentation and intuitive API design
27 | 5. **Cross-Platform** - Works seamlessly across Node.js, Deno, and Bun
28 |
29 | ## Building the Pet Shop API
30 |
31 | To demonstrate Jetpath's capabilities, let's build a simple pet shop API. This example showcases the core principles that guided Jetpath's development.
32 |
33 | ### Step 1: Setting Up the Project
34 |
35 | First, I created a new directory and initialized the project:
36 |
37 | ```bash
38 | mkdir petshop-api
39 | cd petshop-api
40 | npm init -y
41 | npm install jetpath
42 | ```
43 |
44 | ### Step 2: Creating the Application
45 |
46 | I started with a simple `app.jet.ts`:
47 |
48 | ```typescript
49 | import { Jetpath } from 'jetpath';
50 |
51 | // Initialize Jetpath with configuration
52 | const app = new Jetpath({
53 | port: 3000,
54 | apiDoc: {
55 | display: "UI",
56 | name: "Pet Shop API",
57 | color: "#7e57c2"
58 | }
59 | });
60 |
61 | // Start the server
62 | app.listen();
63 | ```
64 |
65 | ### Step 3: Real-World Challenges
66 |
67 | As the API grew, I encountered some common challenges:
68 |
69 | 1. **Type Safety** - Ensuring consistent data types across endpoints
70 | 2. **Error Handling** - Managing different types of errors gracefully
71 | 3. **Documentation** - Keeping API docs up to date
72 |
73 | Jetpath solved these problems beautifully. The type inference system made it easy to maintain consistency, and the automatic documentation saved me hours of work.
74 |
75 | ### Step 4: Building the Pet Management System
76 |
77 | Here's how I implemented the core functionality:
78 |
79 | ```typescript
80 | // In-memory storage for our pets
81 | const pets: Record = {};
82 | let nextId = 1;
83 |
84 | // Get all pets
85 | export const GET_pets = (ctx) => {
86 | // Tip: Use ctx.query to handle pagination
87 | const page = ctx.query.page || 1;
88 | const limit = ctx.query.limit || 10;
89 |
90 | const petsList = Object.values(pets);
91 | const startIndex = (page - 1) * limit;
92 | const endIndex = startIndex + limit;
93 |
94 | ctx.send({
95 | pets: petsList.slice(startIndex, endIndex),
96 | total: petsList.length,
97 | page,
98 | limit
99 | });
100 | };
101 |
102 | // Create a new pet with validation
103 | export const POST_pets: JetRoute<
104 | { body: { name: string; species: string; age: number } }
105 | > = async (ctx) => {
106 | await ctx.parse();
107 | const { name, species, age } = ctx.body;
108 |
109 | // Create the pet
110 | const pet = {
111 | id: nextId++,
112 | name,
113 | species,
114 | age
115 | };
116 |
117 | // Save to our in-memory storage
118 | pets[pet.id] = pet;
119 |
120 | // Send success response
121 | ctx.send(pet, 201);
122 | };
123 |
124 | // Define our pet schema
125 | use(POST_pets).body((t)=>{
126 | return {
127 | name: t.string().min(1).max(50),
128 | species: t.string().min(1).max(50),
129 | age: t.number().min(0).max(30)
130 | }
131 | });
132 | ```
133 |
134 | ## Advanced Features I Love
135 |
136 | ### 1. Validation Made Easy
137 |
138 | The validation system in Jetpath is a game-changer. Here's how I use it:
139 |
140 | ```typescript
141 | // Define our pet schema
142 | use(POST_pets).body((t)=>{
143 | // Real-world validation rules
144 | return {
145 | name: t.string().min(1).max(50)
146 | .withMessage('Name must be between 1 and 50 characters'),
147 | species: t.string().min(1).max(50)
148 | .withMessage('Species must be between 1 and 50 characters'),
149 | age: t.number().min(0).max(30)
150 | .withMessage('Age must be between 0 and 30')
151 | }
152 | });
153 | ```
154 |
155 | ### 2. Middleware for Cross-Cutting Concerns
156 |
157 | I implemented middleware to handle logging and error handling:
158 |
159 | ```typescript
160 | export const MIDDLEWARE_ = (ctx) => {
161 | // Log every request with detailed information
162 | console.log(`[${new Date().toISOString()}] ${ctx.request.method} ${ctx.request.url} - ${ctx.request.headers['user-agent']}`);
163 |
164 | // Add useful headers to responses
165 | ctx.set('X-Request-ID', Date.now().toString());
166 | ctx.set('X-Response-Time', `${Date.now() - ctx.request.time}ms`);
167 |
168 | // Handle errors with proper logging
169 | return (ctx, err) => {
170 | if (err) {
171 | console.error('Error:', {
172 | timestamp: new Date().toISOString(),
173 | method: ctx.request.method,
174 | url: ctx.request.url,
175 | error: err.message,
176 | stack: err.stack
177 | });
178 | return ctx.send('Internal server error');
179 | }
180 | };
181 | };
182 | ```
183 |
184 | ## Best Practices I've Learned
185 |
186 | Here are some practical tips I've picked up along the way:
187 |
188 | 1. **Start Simple**
189 | - Begin with basic CRUD operations
190 | - Add complexity gradually
191 | - Keep your code DRY (Don't Repeat Yourself)
192 |
193 | 2. **Validation Tips**
194 | - Always validate input data
195 | - Use descriptive error messages
196 | - Consider edge cases (like empty strings or null values)
197 |
198 | 3. **Error Handling**
199 | - Use `ctx.send(msg, code)` and return;
200 | - Implement global error handling
201 | - Log errors with context
202 |
203 | ## Real-World Use Cases
204 |
205 | I've used Jetpath for several projects:
206 |
207 | 1. **Microservices** - Building small, focused services
208 | 2. **API Gateways** - Routing and transforming requests
209 | 3. **Internal Tools** - Creating admin interfaces and dashboards
210 |
211 | ## Next Steps for Your API
212 |
213 | Now that you've built a basic API, here are some practical suggestions:
214 |
215 | 1. **Add Authentication**
216 | - Implement JWT tokens
217 | - Add role-based access control
218 | - Secure sensitive endpoints
219 |
220 | 2. **Performance Optimization**
221 | - Add caching layers
222 | - Implement rate limiting
223 | - Optimize database queries
224 |
225 | 3. **Monitoring and Logging**
226 | - Add error tracking
227 | - Monitor API performance
228 | - Set up alerting
229 |
230 | 4. **Testing**
231 | - Write unit tests
232 | - Add integration tests
233 | - Implement end-to-end tests
234 |
235 | ## Conclusion
236 |
237 | Jetpath has transformed the way I build APIs. The declarative approach makes development faster, more reliable, and more enjoyable. Whether you're building a small microservice or a large-scale application, Jetpath provides the tools you need to succeed.
238 |
239 | I hope this journey through Jetpath has been helpful. Remember, the key to success is starting simple and building incrementally. Happy coding!
240 |
241 |
242 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 |
2 | # PetShop API Sample
3 |
4 | The goal is to make the codebase clearer for beginners by splitting the original monolithic file into logical modules, while preserving all the features and conventions demonstrated in the original sample.
5 |
6 | This structure helps beginners understand how to build a Jetpath application by separating concerns into different files:
7 |
8 | - **Framework Initialization and Configuration:** How the app is set up.
9 | - **Global Middleware:** Logic applied to all requests (logging, error handling).
10 | - **Data Models and Storage:** Where data structures and in-memory data reside.
11 | - **API Routes:** Grouping related API endpoints together.
12 | - **Utilities/Miscellaneous Routes:** Other supporting endpoints.
13 | - **WebSockets:** Handling real-time communication.
14 | - **Plugins:** External functionalities integrated into the framework.
15 |
16 | All features from the original `app.jet.ts` sample are included in this version, including:
17 |
18 | - Convention-over-configuration routing (using exported function names like `GET_pets`, `POST_auth_login`).
19 | - Global middleware (`MIDDLEWARE_`) for logging and error handling.
20 | - In-memory data storage (arrays of pet and review objects).
21 | - Authentication and Authorization checks (using a mock plugin).
22 | - Logging (using a mock plugin).
23 | - Input validation using `use().body()` (including objects, arrays, files).
24 | - Handling various HTTP methods (GET, POST, PUT, DELETE).
25 | - Dynamic routing with path parameters (e.g., `/petBy/:id`).
26 | - Query parameter parsing for filtering, sorting, and pagination.
27 | - **File uploads** (handling multipart/form-data).
28 | - **WebSocket communication** for real-time updates.
29 | - Automatic API Documentation UI (Swagger UI).
30 | - API Documentation Export (JSON, YAML, Markdown).
31 | - Error Handling and Testing routes (`/error`).
32 | - Health Check route (`/health`).
33 | - Serving static/uploaded files (`/serve/*`, `/static/*`).
34 |
35 | ## Code Structure
36 |
37 | The original `app.jet.ts` file has been split into the following directories and files within the `src` folder:
38 |
39 | ```
40 |
41 | petshop-api/
42 | ├── src/
43 | │ ├── data/
44 | │ │ └── models.ts \# Defines data types and in-memory data arrays (pets, reviews).
45 | │ ├── middleware/
46 | │ │ └── global.ts \# Contains the global middleware (MIDDLEWARE\_) for logging and error handling.
47 | │ ├── plugins/ \# Directory for external plugins (mock examples)
48 | │ │ ├── auth.ts \# Mock authentication plugin (authenticate, verify, isAdmin).
49 | │ │ └── logging.ts \# Mock logging plugin (info, warn, error).
50 | │ ├── routes/
51 | │ │ ├── auth.ts \# Authentication routes (e.g., POST /auth/login).
52 | │ │ ├── live.ts \# WebSocket route (GET /live) and broadcasting logic.
53 | │ │ ├── pets.ts \# Pet management routes (CRUD, search, image upload, gallery).
54 | │ │ ├── reviews.ts \# Review management routes (GET, POST, DELETE reviews for pets).
55 | │ │ └── utils.ts \# Utility and miscellaneous routes (/, /stats, /error, /health, /export/docs, /upload, /serve, /static).
56 | │ ├── types.ts \# Defines TypeScript types used across the application (PetType, ReviewType).
57 | │ └── index.ts \# Main application entry point: Jetpath app initialization, configuration, plugin registration, imports.
58 | ├── package.json \# Project dependencies and scripts.
59 | ├── README.md \# This file.
60 | └── pet-shop-api-log.log \# Log file generated by the logger plugin (created on first run).
61 | └── uploads/ \# Directory for uploaded files (create this manually)
62 | ├── pet-images/ \# Directory for uploaded pet images (create this manually)
63 | └── general-files/ \# Directory for general file uploads (create this manually)
64 | └── served-content/ \# Directory for files served via /serve/\* (create this manually)
65 | └── public/ \# Directory for static files served via /static/\* (create this manually)
66 | └── static/ \# Subdirectory for static files (create this manually)
67 |
68 | ````
69 |
70 | ## Explanation of the Structure
71 |
72 | - **`src/index.ts`**: This is the application's bootstrapper. It sets up the core Jetpath application instance with global configurations (`apiDoc`, `globalHeaders`, `port`, `upgrade`). It initializes the database (in this case, conceptually preparing the in-memory data). It registers external plugins using `app.addPlugin()`. Crucially, it **imports** the other route and middleware files. Jetpath then automatically discovers and registers the exported route handlers (like `GET_pets`, `POST_auth_login`) and global middleware (`MIDDLEWARE_`) based on their naming conventions in these imported files.
73 | - **`src/types.ts`**: Centralizes the TypeScript interface/type definitions (`PetType`, `ReviewType`), promoting code consistency and clarity.
74 | - **`src/data/models.ts`**: Holds the application's data structures (the `PetType` and `ReviewType` definitions again for clarity, although imported from `types.ts`) and the in-memory data arrays (`pets`, `reviews`). In a real-world application, this layer would contain database connection logic and functions to interact with the database, abstracting data access away from the route handlers.
75 | - **`src/middleware/global.ts`**: Contains the single exported `MIDDLEWARE_` function. This function defines logic that runs for **every** incoming request (the pre-handler) and after the request is processed (the post-handler), handling cross-cutting concerns like logging, authentication checks, and error handling as demonstrated in the original sample. Jetpath automatically applies this global middleware due to its name.
76 | - **`src/plugins/`**: This directory represents external plugins. The original sample referenced `auth.ts` and `logging.ts`. These are included here as mock examples showing the expected structure (exporting plugin instances with specific methods like `authenticateUser`, `info`, `error`) that Jetpath's `app.addPlugin()` expects. The actual implementation details of these plugins would be more complex.
77 | - **`src/routes/`**: This directory contains files that group API endpoint handlers by functionality (auth, pets, reviews, live, utils). Each file exports functions following Jetpath's `METHOD_path$param` naming convention (e.g., `GET_pets`, `POST_auth_login`, `PUT_petBy$id`, `GET_live`).
78 | - `use(functionName).body(...)` is chained directly after the function definition to specify input validation for the request body.
79 | - `use(functionName).info(...)` is chained (often after `use().body()`) to provide documentation details for that specific endpoint, which Jetpath uses to generate the API documentation UI and export.
80 | - Route handlers access the request context (`ctx`) to get parameters, body, plugins, state, and send responses. They interact with the data layer (`../../data/models`).
81 | - **File System Directories**: `uploads/pet-images`, `uploads/general-files`, `served-content`, and `public/static` are directories used by the file upload and serving routes. You need to create these manually for those features to work correctly.
82 |
83 | This structure is designed to be easier for a beginner to navigate, understand the separation of concerns, and see how different parts of a Jetpath application fit together while still preserving the framework's unique conventions.
84 |
85 | ## Prerequisites
86 |
87 | * **Node.js** (v18 or higher recommended) or **Bun** (v1.0 or higher recommended). Ensure your chosen runtime is installed and accessible from your terminal.
88 | * A basic understanding of JavaScript or TypeScript.
89 | * Familiarity with fundamental backend and RESTful API concepts.
90 | * The **Jetpath framework** source code or package installed/accessible. You **must** update the `jetpath` dependency path in `package.json` to point to the correct location or package name of the Jetpath framework.
91 |
92 | ## Setup
93 |
94 | 1. **Obtain the Code:** Create the directory structure (`src`, `src/data`, `src/middleware`, `src/plugins`, `src/routes`, `src/routes/data`, `src/routes/middleware`, `src/routes/plugins`, `src/routes/routes`, `src/routes/types`) and files listed above, or clone the repository if this code is hosted in a Git repository:
95 | ```bash
96 | # If cloning from a repo
97 | git clone
98 | cd petshop-api
99 | ```
100 | *(Replace `` with the actual URL if applicable)*
101 |
102 | 2. **Create Necessary Directories:** Manually create the file system directories used by the file handling routes:
103 | ```bash
104 | mkdir -p uploads/pet-images
105 | mkdir -p uploads/general-files
106 | mkdir -p served-content
107 | mkdir -p public/static
108 | ```
109 |
110 | 3. **Update the `jetpath` dependency:**
111 | Open the `package.json` file and change the line `"jetpath": "file:../path/to/your/jetpath/dist"` to the correct path relative to your project's root directory where the Jetpath framework's `dist` directory is located, or replace it with the package name if Jetpath is published to an npm registry.
112 |
113 | 4. **Install dependencies:**
114 | Open your terminal in the project's root directory and run the appropriate command for your chosen runtime:
115 |
116 | * **If you will primarily use Node.js:**
117 | ```bash
118 | npm install
119 | ```
120 | This will install `better-sqlite3` (if needed for SQLite, although this sample uses in-memory arrays), `ts-node` (which allows Node.js to run TypeScript files directly), and `typescript`, plus any other dependencies defined in `package.json` (like placeholders for plugins).
121 |
122 | * **If you will primarily use Bun:**
123 | ```bash
124 | bun install
125 | ```
126 | Bun will handle the dependencies listed in `package.json`. Bun runs TypeScript files directly, so `ts-node` is not needed.
127 |
128 | ## Running the API
129 |
130 | You can run the API using either Node.js or Bun. The in-memory data will reset each time the server restarts.
131 |
132 | * **Using Node.js:**
133 | ```bash
134 | npm run start:node
135 | ```
136 | This script uses `ts-node` to execute the `src/index.ts` file with Node.js.
137 |
138 | * **Using Bun:**
139 | ```bash
140 | bun run src/index.ts
141 | # Alternatively, use the npm script alias:
142 | bun run start:bun
143 | ```
144 | Bun runs the `src/index.ts` file directly, using its native TypeScript capabilities.
145 |
146 | Once running, the server will print messages to the console indicating which port it's listening on (defaulting to 9000, as in the original sample) and the URL where you can access the API documentation.
147 |
148 | ## API Documentation (Swagger UI)
149 |
150 | An interactive API documentation interface (Swagger UI) is automatically generated and available while the server is running. Open your web browser and go to:
151 |
152 | `http://localhost:9000/api-doc`
153 |
154 | *(Note the port 9000 as configured in `src/index.ts`)*. This documentation is created by Jetpath based on the `apiDoc` configuration in `src/index.ts` and the `.info` properties you've added to the route handlers. It provides a convenient way to explore the API's endpoints and their expected parameters and responses. The documentation itself is secured with basic auth (admin/1234) as in the original sample.
155 |
156 | ## Example API Calls and Features
157 |
158 | You can interact with the API using command-line tools like `curl` or graphical clients like Postman or Insomnia. Since the original sample used in-memory data and mock plugins, you'll need to authenticate first to access protected routes (admin/1234).
159 |
160 | **1. Get API Status (GET /):**
161 |
162 | ```bash
163 | curl http://localhost:9000/
164 | ````
165 |
166 | *Expect basic API information.*
167 |
168 | **2. Authenticate (POST /auth/login):**
169 |
170 | ```bash
171 | curl -X POST http://localhost:9000/auth/login \
172 | -H "Content-Type: application/json" \
173 | -d '{"username": "admin", "password": "1234"}'
174 | ```
175 |
176 | *Expect a token in the response. You will need this token in the `Authorization: Bearer ` header for protected routes.*
177 |
178 | **3. Get all pets (GET /pets):**
179 |
180 | ```bash
181 | curl http://localhost:9000/pets
182 | # With pagination/filtering example:
183 | # curl "http://localhost:9000/pets?limit=5&species=dog&search=friendly"
184 | ```
185 |
186 | *Expect a list of pets.*
187 |
188 | **4. Add a new pet (POST /pets - requires Authentication and Admin role):**
189 |
190 | ```bash
191 | curl -X POST http://localhost:9000/pets \
192 | -H "Content-Type: application/json" \
193 | -H "Authorization: Bearer " \
194 | -d '{
195 | "name": "Buddy",
196 | "species": "Dog",
197 | "breed": "Beagle",
198 | "age": 2,
199 | "gender": "Male",
200 | "color": "Brown and White",
201 | "description": "Energetic and playful Beagle",
202 | "price": 300,
203 | "available": true,
204 | "tags": ["playful", "loyal"]
205 | }'
206 | ```
207 |
208 | *Replace `` with the token from the login response.*
209 |
210 | **5. Upload a pet image (POST /petImage/:id - requires Authentication and Admin role):**
211 |
212 | ```bash
213 | curl -X POST http://localhost:9000/petImage/pet-1 \
214 | -H "Authorization: Bearer " \
215 | -F "image=@/path/to/your/image.jpg" \
216 | -H "Content-Type: multipart/form-data"
217 | ```
218 |
219 | *Replace `pet-1` with a pet ID and `/path/to/your/image.jpg` with an image file path.*
220 |
221 | **6. Connect to WebSocket for live updates (GET /live):**
222 |
223 | Use a WebSocket client to connect to `ws://localhost:9000/live`. You should receive messages for certain events (like pet additions, though this might require adding broadcast calls in the route handlers).
224 |
225 | **7. Export API Documentation (GET /export/docs/:format):**
226 |
227 | ```bash
228 | curl http://localhost:9000/export/docs/json
229 | # or yaml, or markdown
230 | ```
231 |
232 | By exploring these modular files, you should gain a clearer understanding of how the different features of Jetpath demonstrated in the original sample can be organized into a more maintainable structure.
233 |
234 | ## Mock Plugins
235 |
236 | The sample relies on `authPlugin` and `jetLogger`. Simple mock versions are provided in `src/plugins/` to allow the code to run. In a real application, you would use actual plugin implementations.
237 |
--------------------------------------------------------------------------------
/example/chat.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Modern WebSocket Chat
7 |
8 |
9 |
10 |
248 |
249 |
250 |
251 |
252 |
Jetpath WS Chat
253 |
254 |
255 | Disconnected
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
273 |
274 |
275 |
276 |
392 |
393 |
394 |
--------------------------------------------------------------------------------
/example/data/models.ts:
--------------------------------------------------------------------------------
1 | import type { PetType, ReviewType } from "../types.js"; // Import types
2 |
3 | /**
4 | * In-memory pet database
5 | * In a production application, this would be replaced with a real database
6 | * Exported for use in route handlers.
7 | */
8 | export const pets: PetType[] = [
9 | {
10 | id: "pet-1",
11 | name: "Max",
12 | species: "Dog",
13 | breed: "Golden Retriever",
14 | age: 3,
15 | gender: "Male",
16 | color: "Golden",
17 | description: "Friendly and energetic golden retriever, great with children",
18 | image: "/assets/images/max.jpg",
19 | price: 500,
20 | available: true,
21 | createdAt: "2023-06-15T10:30:00Z",
22 | updatedAt: "2023-06-15T10:30:00Z",
23 | tags: ["friendly", "energetic", "family-friendly"],
24 | health: {
25 | vaccinated: true,
26 | neutered: true,
27 | medicalHistory: ["Regular checkup - 2023-05-01"],
28 | },
29 | },
30 | {
31 | id: "pet-2",
32 | name: "Luna",
33 | species: "Cat",
34 | breed: "Siamese",
35 | age: 2,
36 | gender: "Female",
37 | color: "Cream with brown points",
38 | description:
39 | "Elegant Siamese cat with striking blue eyes and a playful personality",
40 | image: "/assets/images/luna.jpg",
41 | price: 350,
42 | available: true,
43 | createdAt: "2023-07-10T14:15:00Z",
44 | updatedAt: "2023-07-10T14:15:00Z",
45 | tags: ["elegant", "vocal", "playful"],
46 | health: {
47 | vaccinated: true,
48 | neutered: true,
49 | medicalHistory: ["Regular checkup - 2023-06-15"],
50 | },
51 | },
52 | ];
53 |
54 | /**
55 | * In-memory reviews database
56 | * Exported for use in route handlers.
57 | */
58 | export const reviews: ReviewType[] = [
59 | {
60 | id: "review-1",
61 | petId: "pet-1",
62 | userId: "2",
63 | username: "user",
64 | rating: 5,
65 | comment: "Max is such a wonderful companion! Highly recommend this breed.",
66 | createdAt: "2023-08-20T09:45:00Z",
67 | },
68 | ];
69 |
--------------------------------------------------------------------------------
/example/definitions.ts:
--------------------------------------------------------------------------------
1 | export const routes = {
2 | GET_live: {
3 | path: "/live",
4 | method: "get",
5 | title: "WebSocket endpoint for real-time pet updates.",
6 | },
7 | GET_petBy$id_reviews: {
8 | path: "/petBy/:id/reviews",
9 | method: "get",
10 | query: { "sort": "string" },
11 | title: "Get all reviews for a specific pet",
12 | },
13 | GET_: {
14 | path: "/",
15 | method: "get",
16 | title: "Returns API information and status",
17 | },
18 | GET_error: {
19 | path: "/error",
20 | method: "get",
21 | title:
22 | "Route that intentionally throws an error (for testing global error handling)",
23 | },
24 | GET_export_docs$format: {
25 | path: "/export/docs/:format",
26 | method: "get",
27 | title:
28 | "Export API documentation in different formats (json, yaml, markdown)",
29 | },
30 | GET_health: {
31 | path: "/health",
32 | method: "get",
33 | title: "API health check endpoint",
34 | },
35 | GET_serve$0: {
36 | path: "/serve/*",
37 | method: "get",
38 | title: "Serve files from the file system based on wildcard path parameter.",
39 | },
40 | GET_static$0: {
41 | path: "/static/*",
42 | method: "get",
43 | title: "Serve static files for download or in-browser display.",
44 | },
45 | GET_stats: {
46 | path: "/stats",
47 | method: "get",
48 | title: "Get shop statistics (admin only)",
49 | },
50 | GET_petBy$id: {
51 | path: "/petBy/:id",
52 | method: "get",
53 | title: "Retrieve detailed information about a specific pet by ID",
54 | },
55 | GET_petBy$id_gallery: {
56 | path: "/petBy/:id/gallery",
57 | method: "get",
58 | title:
59 | "Get images for a specific pet (returns main image URL in this sample)",
60 | },
61 | GET_pets: {
62 | path: "/pets",
63 | method: "get",
64 | title: "Retrieves a list of pets with filtering and pagination options",
65 | },
66 | GET_pets_search: {
67 | path: "/pets/search",
68 | method: "get",
69 | title: "Advanced search for pets by various criteria",
70 | },
71 | POST_auth_login: {
72 | path: "/auth/login",
73 | method: "post",
74 | body: { "username": "string", "password": "string" },
75 | title: "Authenticate a user and receive an access token",
76 | },
77 | POST_petBy$id_reviews: {
78 | path: "/petBy/:id/reviews",
79 | method: "post",
80 | body: { "rating": 1, "comment": "string" },
81 | title: "Add a review for a specific pet (authenticated users only)",
82 | },
83 | POST_upload: {
84 | path: "/upload",
85 | method: "post",
86 | body: {
87 | "image": "file",
88 | "document": "file",
89 | "title": "string",
90 | "description": "string",
91 | "tags": "string",
92 | },
93 | title:
94 | "Upload files with metadata (admin only) - expects multipart/form-data",
95 | },
96 | POST_pets: {
97 | path: "/pets",
98 | method: "post",
99 | body: {
100 | "name": "string",
101 | "species": "string",
102 | "breed": "string",
103 | "age": 1,
104 | "gender": "string",
105 | "color": "string",
106 | "description": "string",
107 | "image": "file",
108 | "price": 1,
109 | "available": true,
110 | "tags": [],
111 | "health": {},
112 | },
113 | title: "Add a new pet to the inventory (admin only)",
114 | },
115 | POST_recipes$id_image: {
116 | path: "/recipes/:id/image",
117 | method: "post",
118 | body: { "image": "file" },
119 | title: "Upload an image for a specific pet (admin only)",
120 | },
121 | PUT_petBy$id: {
122 | path: "/petBy/:id",
123 | method: "put",
124 | body: {
125 | "name": "string",
126 | "species": "string",
127 | "breed": "string",
128 | "age": 1,
129 | "gender": "string",
130 | "color": "string",
131 | "description": "string",
132 | "image": "file",
133 | "price": 1,
134 | "available": true,
135 | "tags": [],
136 | "health": {},
137 | },
138 | title: "Update an existing pet's information (admin only)",
139 | },
140 | DELETE_reviews$reviewId: {
141 | path: "/reviews/:reviewId",
142 | method: "delete",
143 | title: "Delete a review (admin or review owner only)",
144 | },
145 | DELETE_petBy$id: {
146 | path: "/petBy/:id",
147 | method: "delete",
148 | title: "Remove a pet from the inventory (admin only)",
149 | },
150 | } as const;
151 |
--------------------------------------------------------------------------------
/example/index.jet.ts:
--------------------------------------------------------------------------------
1 | // src/index.ts
2 |
3 | import { Jetpath } from "../dist/index.js";
4 | // Create mock plugin files in src/plugins if you don't have real ones.
5 | import { authPlugin } from "./plugins/auth.js";
6 | import { jetLogger } from "./plugins/logging.js";
7 | // --- Application Initialization ---
8 |
9 | // Create a new Jetpath application instance with configuration.
10 | // Route handlers and global middleware are automatically detected
11 | // by Jetpath based on their exported names from imported modules.
12 | const app = new Jetpath({
13 | // Strict mode can enforce certain behaviors (e.g., strict content type checking).
14 | strictMode: "ON", // Example from app.jet.ts
15 | generatedRoutesFilePath: "./example/definitions.ts",
16 | // Configure API documentation (Swagger UI).
17 | // This makes it easy to visualize and test the API endpoints.
18 | apiDoc: {
19 | display: "UI", // Set to "UI" to enable the Swagger UI
20 | name: "PetShop API", // Using PetShop name from original sample
21 | // Use Markdown for a rich description in the documentation.
22 | // This info can be more general, as route-specific info comes from .info() calls.
23 | info: `
24 | #### PetShop API Documentation
25 |
26 | This is an API for managing a pet shop inventory, built with the **Jetpath** cross-runtime framework.
27 |
28 | It demonstrates various Jetpath features including:
29 | - Convention-over-configuration for routing and middleware.
30 | - Modular project structure.
31 | - Cross-runtime capabilities.
32 | - Authentication and authorization (via plugin).
33 | - Comprehensive logging (via plugin).
34 | - Robust error handling (via global middleware)
35 |
36 | [check our docs for more info](https://jetpath.codedynasty.dev)
37 | `,
38 |
39 | color: "#7e57c2", // Using the color from the original sample
40 | // Optional: Secure the documentation UI itself with basic authentication (example from sample).
41 | username: "admin", // Default username from sample
42 | password: "1234", // Default password from sample **WARNING:** Do not use simple passwords in production. Use environment variables.
43 | },
44 | source: "./example",
45 | // Configure global headers to be sent with all responses.
46 | globalHeaders: {
47 | "X-Pet-API-Version": "1.0.0", // Example custom header from sample
48 | "Access-Control-Allow-Origin": "*", // **WARNING:** In production, replace "*" with the specific origin(s) of your frontend application(s) for security.
49 | "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
50 | "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Request-ID", // Include Authorization and X-Request-ID headers
51 | "Content-Type": "application/json", // Default response content type
52 | },
53 |
54 | // Configure the port for the server to listen on.
55 | port: process.env.PORT ? parseInt(process.env.PORT, 10) : 9000, // Using sample's port
56 |
57 | // Enable WebSocket upgrades. This is required for the /live WebSocket endpoint to work.
58 | upgrade: true,
59 | // Optional: Configure a directory for serving static files automatically (alternative to GET_static$0 route)
60 | // static: "./public", // Example
61 | });
62 |
63 | // --- Add Plugins ---
64 | // Add plugin instances to the application. Plugins provide extended functionality.
65 | // Access plugins via ctx.plugins in middleware and route handlers.
66 |
67 | // Add the logger plugin
68 | // Configure the logger plugin first if needed, then add it.
69 | jetLogger.config = {
70 | level: process.env.NODE_ENV === "production" ? "info" : "debug",
71 | format: "json", // Log format (json or text)
72 | filename: "./pet-shop-api-log.log", // Log file path relative to project root
73 | };
74 |
75 | app.derivePlugins(jetLogger, authPlugin);
76 |
77 | app.listen();
78 |
--------------------------------------------------------------------------------
/example/middleware/global.ts:
--------------------------------------------------------------------------------
1 | // src/middleware/global.ts
2 |
3 | import { JetMiddleware } from "../../dist";
4 | // Assuming AuthPluginType and jetLoggerType are defined or imported from plugin types
5 | import { type AuthPluginType } from "../plugins/auth"; // Assuming auth plugin types are here
6 | import { type jetLoggerType } from "../plugins/logging"; // Assuming logger plugin types are here
7 |
8 | /**
9 | * Global middleware for request processing and error handling
10 | * This middleware runs for all routes and handles:
11 | * - Request logging
12 | * - Authentication verification (when needed)
13 | * - Error processing
14 | * - Response formatting
15 | *
16 | * It is automatically applied by Jetpath because of its exported name `MIDDLEWARE_`.
17 | *
18 | * @param {Object} ctx - The request context (pre-handler)
19 | * @returns {Function} The post-handler middleware function
20 | */
21 | export const MIDDLEWARE_: JetMiddleware<{}, [AuthPluginType, jetLoggerType]> = (
22 | ctx,
23 | ) => {
24 | // --- Pre-handler Logic (runs before the route handler) ---
25 | const startTime = Date.now();
26 | // Generate a unique request ID (example from app.jet.ts)
27 | const requestId = `req-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
28 | ctx.set("X-Request-ID", requestId); // Add request ID to response headers
29 |
30 | // Log initial request info using the logger plugin (if available)
31 | // Use optional chaining in case plugins aren't correctly loaded/typed
32 | ctx.plugins?.info(
33 | ctx,
34 | "Request received",
35 | );
36 |
37 | // Authentication verification (example from app.jet.ts)
38 | // Skip auth check for public routes
39 | const isPublicRoute = ctx.request.url.includes("/auth/login") ||
40 | ctx.request.url.includes("/api-doc") || // api-doc is public
41 | ctx.request.url.includes("/export/docs") || // documentation export is public
42 | ctx.request.url.includes("/health") || // health check is public
43 | ctx.request.url === "/" || // root is public
44 | ctx.request.url.startsWith("/static/") || // static files are public (based on GET_static$0)
45 | ctx.request.url.startsWith("/serve/"); // served files are public (based on GET_serve$0)
46 | // Note: Pet list and detail (GET /pets, GET /petBy/:id) were public in the sample,
47 | // while POST/PUT/DELETE pets and others were protected.
48 | // We'll leave the authentication check logic as it was in the sample for now.
49 |
50 | // Verify authentication for protected routes
51 | // The original sample checked auth for any non-public route unless it was the root GET.
52 | // Let's refine this check slightly for clarity, assuming auth is needed *unless* it's explicitly public.
53 | const requiresAuth = !isPublicRoute &&
54 | !ctx.request.url.startsWith("/pets") && // Assuming GET /pets and /petBy/:id are public
55 | !ctx.request.url.startsWith("/petBy/") && // GET pet details are public
56 | !ctx.request.url.startsWith("/reviews"); // Assuming GET reviews are public
57 |
58 | if (requiresAuth) { // Only run auth check if the route is not public
59 | const auth = ctx.plugins?.auth?.verifyAuth(ctx); // Use optional chaining for safety
60 | if (!auth?.authenticated) {
61 | ctx.code = 401; // Unauthorized
62 | ctx.set("WWW-Authenticate", "Bearer"); // Suggest Bearer auth
63 | ctx.plugins?.warn(
64 | ctx,
65 | "Authentication failed",
66 | );
67 | // We don't ctx.throw here; the post-handler will process the 401 code.
68 | } else {
69 | // Attach user info to context state for use in route handlers
70 | ctx.state["user"] = auth.user;
71 | }
72 | }
73 |
74 | // --- Post-handler Logic (runs after the route handler, or if an error occurs) ---
75 | // This function is returned by the pre-handler and receives the context and potential error.
76 | return (ctx, err: any) => {
77 | const duration = Date.now() - startTime; // Calculate total request duration.
78 |
79 | // Add standard response header
80 | ctx.set("X-Response-Time", `${duration}ms`);
81 |
82 | // --- Error Handling ---
83 | if (err) {
84 | // An error occurred. Log it using the logger plugin.
85 | ctx.plugins?.error(
86 | ctx,
87 | "Request failed due to error",
88 | );
89 |
90 | // Determine the status code for the error response.
91 | ctx.code = ctx.code >= 400
92 | ? ctx.code
93 | : (err.statusCode && err.statusCode >= 400 ? err.statusCode : 500);
94 |
95 | // Send a standardized JSON error response.
96 | ctx.send({
97 | status: "error",
98 | message: ctx.code === 500 && process.env.NODE_ENV === "production"
99 | ? "An internal server error occurred."
100 | : err.message || "Internal server error", // Use error message in dev or for client errors
101 | requestId,
102 | timestamp: new Date().toISOString(),
103 | // Include stack trace in non-production environments
104 | ...(process.env.NODE_ENV !== "production" && err instanceof Error &&
105 | err.stack && { stack: err.stack.split("\n") }),
106 | });
107 |
108 | // Return to stop further processing of this error by Jetpath.
109 | return;
110 | }
111 |
112 | // --- 404 Handling ---
113 | // If no route matched, Jetpath sets ctx.code to 404. Handle this specifically.
114 | if (ctx.code === 404) {
115 | ctx.plugins?.warn(
116 | ctx,
117 | "Resource not found (404)",
118 | );
119 |
120 | ctx.send({
121 | status: "error",
122 | message: "The requested resource was not found",
123 | requestId,
124 | timestamp: new Date().toISOString(),
125 | });
126 | return; // Return to stop further processing
127 | }
128 |
129 | // --- Successful Response Logging ---
130 | // If no error and code is not 404, it's a successful response.
131 | ctx.plugins?.info(
132 | ctx,
133 | "Request completed successfully",
134 | );
135 |
136 | // If the post-handler doesn't return anything (or returns undefined),
137 | // Jetpath continues with the response process.
138 | };
139 | };
140 |
--------------------------------------------------------------------------------
/example/plugins/auth.ts:
--------------------------------------------------------------------------------
1 | // =============================================================================
2 | // PLUGINS CONFIGURATION
3 | // =============================================================================
4 |
5 | import { type JetContext } from "../../dist/index.js";
6 |
7 | /**
8 | * Auth Plugin - Provides authentication and authorization functionality
9 | *
10 | * This plugin adds methods for token generation, validation, and user
11 | * authentication that can be used across routes.
12 | */
13 | export const authPlugin = {
14 | name: "authPlugin",
15 | executor() {
16 | // In a real application, use a secure secret management solution
17 | const ADMIN_API_KEY = process.env["ADMIN_API_KEY"] || "admin-secret-key";
18 |
19 | // Simple in-memory user store (use a database in production)
20 | const users = [
21 | { id: "1", username: "admin", password: "admin123", role: "admin" },
22 | { id: "2", username: "user", password: "user123", role: "customer" },
23 | ];
24 |
25 | return {
26 | /**
27 | * Validates user credentials and returns a token
28 | */
29 | authenticateUser(username: string, password: string) {
30 | const user = users.find((u) =>
31 | u.username === username && u.password === password
32 | );
33 | if (!user) {
34 | return { authenticated: false, message: "Invalid credentials" };
35 | }
36 |
37 | // In production, use proper JWT library
38 | const token = `token-${user.id}-${Date.now()}`;
39 | return {
40 | authenticated: true,
41 | token,
42 | user: { id: user.id, username: user.username, role: user.role },
43 | };
44 | },
45 |
46 | /**
47 | * Verifies if a request has valid authentication
48 | */
49 | verifyAuth(ctx: JetContext) {
50 | const authHeader = ctx.get("authorization");
51 |
52 | if (!authHeader || !authHeader.startsWith("Bearer ")) {
53 | return { authenticated: false, message: "Missing or invalid token" };
54 | }
55 |
56 | const token = authHeader.split(" ")[1];
57 | // In production, implement proper token validation
58 | const userId = token.split("-")[1];
59 | const user = users.find((u) => u.id === userId);
60 |
61 | if (!user) {
62 | return { authenticated: false, message: "Invalid token" };
63 | }
64 |
65 | return {
66 | authenticated: true,
67 | user: { id: user.id, username: user.username, role: user.role },
68 | };
69 | },
70 |
71 | /**
72 | * Verifies if the request is from an admin
73 | */
74 | isAdmin(ctx: JetContext): boolean {
75 | // Check for admin API key
76 | if (ctx.get("x-admin-Key") === ADMIN_API_KEY) {
77 | return true;
78 | }
79 |
80 | // Alternatively check user role
81 | const auth = this["verifyAuth"](ctx);
82 | // @ts-ignore
83 | return auth.authenticated && auth.user.role === "admin";
84 | },
85 | };
86 | },
87 | };
88 |
89 | export type AuthPluginType = ReturnType;
90 |
--------------------------------------------------------------------------------
/example/plugins/logging.ts:
--------------------------------------------------------------------------------
1 | import { appendFileSync } from "node:fs";
2 | import { resolve } from "node:path";
3 | import { config } from "node:process";
4 |
5 | /**
6 | * Supported log levels
7 | */
8 | export type LogLevel = "trace" | "debug" | "info" | "warn" | "error";
9 | const levelRank: Record = {
10 | trace: 10,
11 | debug: 20,
12 | info: 30,
13 | warn: 40,
14 | error: 50,
15 | };
16 |
17 | /**
18 | * Configuration options for the logging plugin
19 | */
20 | interface LoggingConfig {
21 | level?: LogLevel; // minimum level to emit
22 | format?: "json" | "text"; // format of log entries
23 | filename?: string; // file to write logs to
24 | getRequestId?: (req: Request) => string; // extract or generate a request ID
25 | transports?: Transport[]; // custom transports (overrides filename/format defaults)
26 | }
27 |
28 | /**
29 | * Structure of a log entry
30 | */
31 | interface LogEntry {
32 | timestamp: string;
33 | level: LogLevel;
34 | message?: string;
35 | method: string;
36 | url: string;
37 | requestId?: string;
38 | meta?: Record;
39 | }
40 |
41 | /** Transport interface for log targets */
42 | interface Transport {
43 | log(entry: LogEntry): Promise | void;
44 | }
45 |
46 | /** Default console transport, respects JSON or text */
47 | class ConsoleTransport implements Transport {
48 | private format: "json" | "text" = "json";
49 | constructor(format: "json" | "text" = "json") {
50 | this.format = format;
51 | }
52 | log(entry: LogEntry) {
53 | const line = this.format === "json"
54 | ? JSON.stringify(entry)
55 | : `${entry.timestamp} [${entry.level.toUpperCase()}] ${entry.method} ${entry.url} - ${entry.message}${
56 | Object.keys(entry.meta || {}).length
57 | ? " " + JSON.stringify(entry.meta)
58 | : ""
59 | }`;
60 | console.log(line);
61 | }
62 | }
63 |
64 | /** File transport for Node/Bun/Deno, appends to given filename */
65 | class FileTransport implements Transport {
66 | private filename: string;
67 | private format: "json" | "text" = "json";
68 | constructor(
69 | filename: string,
70 | format: "json" | "text" = "json",
71 | ) {
72 | this.filename = filename;
73 | this.format = format;
74 | }
75 | log(entry: LogEntry) {
76 | const line = this.format === "json"
77 | ? JSON.stringify(entry)
78 | : `${entry.timestamp} [${entry.level.toUpperCase()}] ${entry.method} ${entry.url} - ${entry.message}${
79 | Object.keys(entry.meta || {}).length
80 | ? " " + JSON.stringify(entry.meta)
81 | : ""
82 | }`;
83 | // Cross-runtime append
84 | appendFileSync(resolve(this.filename), line + "\n");
85 | }
86 | }
87 |
88 | /**
89 | * Creates a JetPlugin with structured logging capabilities
90 | */
91 | export const jetLogger = {
92 | name: "jetLogger",
93 | /**
94 | * Creates a logging plugin instance
95 | * @param config Configuration options for the logger
96 | */
97 | config: {
98 | level: "info",
99 | format: "json",
100 | filename: undefined,
101 | transports: undefined,
102 | } as LoggingConfig,
103 | executor() {
104 | const {
105 | level = "info",
106 | format = "json",
107 | filename,
108 | getRequestId,
109 | transports: customTransports,
110 | } = this.config;
111 | // Determine transports: custom, or build from filename/console defaults
112 | const transports: Transport[] = customTransports
113 | ? customTransports
114 | : filename
115 | ? [new FileTransport(filename, format)]
116 | : [new ConsoleTransport(format)];
117 | // Send entry to all configured transports
118 | async function emit(entry: LogEntry) {
119 | for (const t of transports) {
120 | try {
121 | await t.log(entry);
122 | } catch (err) {
123 | console.error("Logging transport error:", err);
124 | }
125 | }
126 | }
127 |
128 | // Level filtering
129 | function shouldLog(entryLevel: LogLevel) {
130 | return levelRank[entryLevel] >= levelRank[level];
131 | }
132 |
133 | // Build the entry object
134 | function buildEntry(
135 | entryLevel: LogLevel,
136 | ctx: { request: Request },
137 | message?: string,
138 | meta?: Record,
139 | ): LogEntry {
140 | const { request } = ctx;
141 | return {
142 | timestamp: new Date().toISOString(),
143 | level: entryLevel,
144 | message: typeof message === "string"
145 | ? message
146 | : JSON.stringify(message),
147 | method: request.method,
148 | url: request.url,
149 | requestId: getRequestId?.(request),
150 | meta,
151 | };
152 | }
153 |
154 | // Exposed log methods
155 | return {
156 | trace(
157 | ctx: { request: Request },
158 | message: any,
159 | meta?: Record,
160 | ) {
161 | if (!shouldLog("trace")) return;
162 | emit(buildEntry("trace", ctx, message, meta));
163 | },
164 | debug(
165 | ctx: { request: Request },
166 | message: any,
167 | meta?: Record,
168 | ) {
169 | if (!shouldLog("debug")) return;
170 | emit(buildEntry("debug", ctx, message, meta));
171 | },
172 | info(
173 | ctx: { request: Request },
174 | message?: any,
175 | meta?: Record,
176 | ) {
177 | if (!shouldLog("info")) return;
178 | emit(buildEntry("info", ctx, message, meta));
179 | },
180 | warn(
181 | ctx: { request: Request },
182 | message: any,
183 | meta?: Record,
184 | ) {
185 | if (!shouldLog("warn")) return;
186 | emit(buildEntry("warn", ctx, message, meta));
187 | },
188 | error(
189 | ctx: { request: Request },
190 | message: any,
191 | meta?: Record,
192 | ) {
193 | if (!shouldLog("error")) return;
194 | emit(buildEntry("error", ctx, message, meta));
195 | },
196 | };
197 | },
198 | };
199 |
200 | export type jetLoggerType = ReturnType;
201 |
--------------------------------------------------------------------------------
/example/routes/auth.jet.ts:
--------------------------------------------------------------------------------
1 | // src/routes/auth.ts
2 |
3 | import { type JetRoute, use } from "../../dist/index.js";
4 | import { type AuthPluginType } from "../plugins/auth.js"; // Import AuthPluginType
5 |
6 | // --- Authentication Route ---
7 |
8 | /**
9 | * Authentication endpoint - Login with username and password
10 | * @route POST /auth/login
11 | * @access Public
12 | * Demonstrates: POST request, body parsing, plugin usage (auth), sending token.
13 | */
14 | export const POST_auth_login: JetRoute<
15 | { body: { username: string; password: string } },
16 | [AuthPluginType]
17 | > = async function (ctx) {
18 | // Parse the request body. Jetpath handles this.
19 | await ctx.parse();
20 | const { username, password } = ctx.body;
21 |
22 | // Use the auth plugin to authenticate the user.
23 | // Access plugins via ctx.plugins, assuming the plugin was added with app.addPlugin(authPlugin) in index.ts.
24 | const authResult = ctx.plugins.authenticateUser(username, password);
25 |
26 | // Check authentication result.
27 | if (!authResult.authenticated) {
28 | ctx.code = 401; // Unauthorized status code.
29 | ctx.send({ status: "error", message: authResult.message }); // Send error response.
30 | return; // Stop further processing.
31 | }
32 |
33 | // If authentication is successful, send success response with token and user info.
34 | ctx.send({
35 | status: "success",
36 | message: "Authentication successful",
37 | token: authResult.token, // Send the generated token.
38 | user: { // Send basic user info.
39 | id: authResult.user?.id,
40 | username: authResult.user?.username,
41 | role: authResult.user?.role,
42 | },
43 | });
44 | };
45 |
46 | // Apply body validation and .info() for documentation using use() chained after the function definition.
47 | use(POST_auth_login).body((t) => {
48 | // Define the expected request body structure and validation rules.
49 | return {
50 | username: t.string({
51 | err: "Username is required",
52 | inputDefaultValue: "admin",
53 | }).required(), // Username must be a required string.
54 | password: t.string({
55 | err: "Password is required",
56 | inputDefaultValue: "admin123",
57 | }).required(), // Password must be a required string.
58 | };
59 | }).title("Authenticate a user and receive an access token") // Add info for documentation.
60 | .description(`
61 | ### ok here
62 | `);
63 |
--------------------------------------------------------------------------------
/example/routes/live.jet.ts:
--------------------------------------------------------------------------------
1 | // src/routes/live.ts
2 |
3 | import { type JetRoute, use } from "../../dist/index.js";
4 | // Import types if needed, e.g., for initial stats message
5 | import { pets } from "../data/models.js"; // Import pets data for initial stats message
6 |
7 | // --- WebSocket Server ---
8 | // This route handles WebSocket connections for real-time updates.
9 |
10 | // Keep track of connected WebSocket clients using a Set.
11 | const connectedSockets = new Set();
12 |
13 | // --- WebSocket Broadcasting ---
14 | // Function to broadcast messages to all connected clients.
15 | const broadcastMessage = (message: string) => {
16 | // Iterate over all connected sockets.
17 | const messageJson = JSON.stringify({
18 | type: "update",
19 | message,
20 | timestamp: new Date().toISOString(),
21 | }); // Format message as JSON
22 |
23 | connectedSockets.forEach((socket) => {
24 | // Check if the socket connection is open before sending.
25 | if (socket.readyState === WebSocket.OPEN) {
26 | socket.send(messageJson); // Send the message to the client.
27 | }
28 | });
29 | console.log(
30 | `Broadcasted message to ${connectedSockets.size} clients: "${message}"`,
31 | );
32 | };
33 |
34 | // Export the broadcast function so other modules (like recipes) can use it.
35 | export { broadcastMessage };
36 |
37 | /**
38 | * WebSocket Endpoint for real-time updates.
39 | * @route GET /live
40 | * @access Public
41 | * Demonstrates: Handling WebSocket connections, sending/receiving messages, broadcasting.
42 | */
43 | export const GET_live: JetRoute = (ctx) => {
44 | // Initiate the WebSocket upgrade handshake.
45 | // This tells Jetpath to switch from HTTP to WebSocket protocol for this connection.
46 | ctx.upgrade();
47 |
48 | // After a successful upgrade, ctx.connection or a similar property holds the WebSocket object.
49 | // The exact way to access the WebSocket object might depend on the Jetpath version/adapter.
50 | // The original sample uses `const conn = ctx.connection!`. Let's stick to that assumption.
51 | const ws = ctx.connection; // Assuming ctx.connection is the WebSocket or similar
52 |
53 | // If the upgrade fails, handle the error (though the middleware might catch it).
54 | if (!ws) {
55 | ctx.code = 500;
56 | ctx.send({ status: "error", message: "Failed to upgrade to WebSocket." });
57 | console.error("WebSocket upgrade failed for request:", ctx.request.url);
58 | return; // Stop processing if no WebSocket connection was established.
59 | }
60 |
61 | // --- WebSocket Event Listeners ---
62 | // Attach event listeners to the WebSocket object to handle connection events and messages.
63 |
64 | // When the WebSocket connection is opened successfully.
65 | ws.addEventListener("open", (socket) => {
66 | console.log("WebSocket client connected.");
67 | connectedSockets.add(socket); // Add the new socket to our set of connected clients.
68 |
69 | // Send a welcome message to the new client.
70 | // You could include initial data like current stats.
71 | const availablePets = pets.filter((pet) => pet.available).length;
72 | socket.send(JSON.stringify({
73 | type: "info",
74 | message: "Connected to PetShop live updates.",
75 | currentStats: {
76 | totalPets: pets.length,
77 | availablePets: availablePets,
78 | },
79 | timestamp: new Date().toISOString(),
80 | }));
81 |
82 | // Inform other clients about the new connection (optional).
83 | broadcastMessage(
84 | `A new client connected (Total active connections: ${connectedSockets.size}).`,
85 | );
86 | });
87 |
88 | // When a message is received from a client.
89 | ws.addEventListener("message", (socket, event) => {
90 | const message = event.data; // The data received from the client.
91 | console.log("WebSocket message received:", message);
92 | // Handle incoming messages from clients if needed.
93 | // For this simple sample, we'll respond to a 'ping' message.
94 | try {
95 | const parsedMessage = typeof message === "string"
96 | ? JSON.parse(message)
97 | : message;
98 | if (parsedMessage.type === "ping") {
99 | // Respond with a pong message for health checks.
100 | socket.send(
101 | JSON.stringify({ type: "pong", timestamp: new Date().toISOString() }),
102 | );
103 | } else {
104 | // If the message is not recognized, you could broadcast it or handle it differently.
105 | // For this sample, we'll just log and ignore other messages.
106 | broadcastMessage(message);
107 | }
108 | // You could add more complex command handling here based on message.type or content.
109 | } catch (e) {
110 | console.error("Failed to parse or handle WebSocket message:", e);
111 | socket.send(
112 | JSON.stringify({
113 | type: "error",
114 | message: "Invalid message format (expected JSON)",
115 | }),
116 | );
117 | }
118 | });
119 |
120 | // When the WebSocket connection is closed by either the client or server.
121 | ws.addEventListener("close", (socket, event) => {
122 | console.log(
123 | `WebSocket client disconnected (Code: ${event.code}, Reason: ${
124 | event.reason || "No reason"
125 | }).`,
126 | );
127 | connectedSockets.delete(socket); // Remove the closed socket from the set.
128 | // Inform other clients about the disconnection (optional).
129 | broadcastMessage(
130 | `A client disconnected (Total active connections: ${connectedSockets.size}).`,
131 | );
132 | });
133 |
134 | // The initial HTTP request handler does not send a response after calling ctx.upgrade().
135 | // The connection is now managed by the WebSocket event listeners and the server's WebSocket handling.
136 | };
137 |
138 | // Apply .info() for documentation.
139 | // This describes the GET request that initiates the WebSocket handshake.
140 | use(GET_live).title("WebSocket endpoint for real-time pet updates."); // Adjusted info message
141 |
142 | // Export the route handler.
143 |
--------------------------------------------------------------------------------
/example/routes/reviews.jet.ts:
--------------------------------------------------------------------------------
1 | // src/routes/reviews.ts
2 |
3 | import { type JetRoute, use } from "../../dist/index.js";
4 | // Import AuthPluginType if authentication checks are done within route handlers
5 | import { type AuthPluginType } from "../plugins/auth.js";
6 | // Import data models and in-memory data arrays
7 | import { pets, reviews } from "../data/models.js";
8 | import { type ReviewType } from "../types.js"; // Import ReviewType
9 |
10 | // --- Reviews Management Routes ---
11 |
12 | /**
13 | * Get all reviews for a pet
14 | * @route GET /petBy/:id/reviews
15 | * @access Public
16 | * Demonstrates: Dynamic GET route ($id), path parameter, filtering related data, sorting, calculating aggregates (average rating).
17 | */
18 | export const GET_petBy$id_reviews: JetRoute<{
19 | params: { id: string }; // Pet ID from path
20 | query: { sort?: string }; // Optional sort query parameter
21 | }> = function (ctx) {
22 | const petId = ctx.params.id; // Access pet ID from path.
23 | const sort = ctx.query.sort || "-createdAt"; // Access sort query param, default to newest first.
24 |
25 | // Find the pet to ensure it exists.
26 | const pet = pets.find((p) => p.id === petId);
27 |
28 | if (!pet) {
29 | ctx.code = 404; // Not Found
30 | ctx.send({
31 | status: "error",
32 | message: `Pet with ID ${petId} not found.`,
33 | });
34 | return;
35 | }
36 |
37 | // Filter reviews to get only those for the specified pet.
38 | let petReviews = reviews.filter((review) => review.petId === petId);
39 |
40 | // Sort the filtered reviews based on the sort query parameter.
41 | const sortField = sort.startsWith("-") ? sort.substring(1) : sort; // Get field name (remove leading '-')
42 | const sortDirection = sort.startsWith("-") ? -1 : 1; // Determine sort direction (1 for asc, -1 for desc)
43 |
44 | // Sort the array. Using `any` for simplicity due to dynamic sortField access.
45 | petReviews.sort((a: any, b: any) => {
46 | const valueA = a[sortField];
47 | const valueB = b[sortField];
48 |
49 | if (valueA < valueB) return -1 * sortDirection;
50 | if (valueA > valueB) return 1 * sortDirection;
51 | return 0; // Values are equal
52 | });
53 |
54 | // Calculate aggregate statistics for the reviews (e.g., average rating).
55 | const totalRating = petReviews.reduce(
56 | (sum, review) => sum + review.rating,
57 | 0,
58 | ); // Sum of all ratings
59 | const averageRating = petReviews.length > 0
60 | ? totalRating / petReviews.length
61 | : 0; // Calculate average, handle division by zero.
62 |
63 | // Send the response with the filtered, sorted reviews and statistics.
64 | ctx.send({
65 | status: "success",
66 | petId: petId,
67 | petName: pet.name,
68 | stats: { // Include review statistics
69 | count: petReviews.length,
70 | averageRating: averageRating,
71 | },
72 | reviews: petReviews, // Include the list of reviews
73 | });
74 | };
75 |
76 | // Apply .info() for documentation.
77 | use(GET_petBy$id_reviews).title("Get all reviews for a specific pet").query(
78 | (t) => {
79 | // Define the expected query parameters and validation rules.
80 | return {
81 | // Optional sort parameter, default to '-createdAt' (newest first).
82 | sort: t.string({
83 | err: "Sort parameter must be a string",
84 | }).default("-createdAt"),
85 | };
86 | },
87 | );
88 |
89 | /**
90 | * Add a review for a pet
91 | * @route POST /petBy/:id/reviews
92 | * @access Authenticated (Based on sample's middleware check)
93 | * Demonstrates: POST request, dynamic routing ($id), body parsing, input validation (use().body()), data insertion.
94 | */
95 | export const POST_petBy$id_reviews: JetRoute<{
96 | params: { id: string }; // Pet ID from path
97 | body: { // Expected request body structure
98 | rating: number;
99 | comment: string;
100 | };
101 | }, [AuthPluginType]> = async function (ctx) {
102 | // Check if user is authenticated (access user and authenticated status from ctx.state/plugins)
103 | // The global middleware sets ctx.state.user if authenticated.
104 | const user = ctx.state["user"];
105 | if (!user) {
106 | ctx.code = 401; // Unauthorized
107 | ctx.send({
108 | status: "error",
109 | message: "Authentication required to post reviews",
110 | });
111 | return;
112 | }
113 |
114 | const petId = ctx.params.id; // Access pet ID from path.
115 |
116 | // Find the pet to ensure it exists before adding a review.
117 | const pet = pets.find((p) => p.id === petId);
118 |
119 | if (!pet) {
120 | ctx.code = 404; // Not Found
121 | ctx.send({
122 | status: "error",
123 | message: `Pet with ID ${petId} not found.`,
124 | });
125 | return;
126 | }
127 |
128 | // Parse and validate the request body. Jetpath handles this via use().body().
129 | await ctx.parse(); // Ensure body is parsed
130 | const { rating, comment } = ctx.body; // Access the validated body
131 |
132 | // Create a new review object with a unique ID and current timestamp.
133 | const newReview: ReviewType = {
134 | id: `review-${Date.now()}-${Math.random().toString(36).substring(2, 15)}`, // Generate unique ID
135 | petId: petId, // Link to the pet
136 | userId: user.id, // Link to the authenticated user's ID
137 | username: user.username, // Store the reviewer's username
138 | rating: rating, // Rating from the request body
139 | comment: comment, // Comment from the request body
140 | createdAt: new Date().toISOString(), // Set creation timestamp
141 | };
142 |
143 | // Add the new review to the in-memory database array.
144 | reviews.push(newReview);
145 |
146 | // Log the review creation action.
147 | // Log the review creation action.
148 | ctx.plugins?.["info"]({
149 | action: "create_review",
150 | reviewId: newReview.id,
151 | petId: newReview.petId,
152 | userId: newReview.userId,
153 | message: `User ${newReview.username} added review for pet ${pet.name}`,
154 | });
155 |
156 | // Send a 201 Created response with the newly created review details.
157 | ctx.code = 201; // Created status code.
158 | ctx.send({
159 | status: "success",
160 | message: "Review added successfully",
161 | review: newReview,
162 | });
163 | };
164 |
165 | // Apply body validation and .info() for documentation using use() chained after the function definition.
166 | use(POST_petBy$id_reviews).body((t) => {
167 | // Define the expected request body structure and validation rules.
168 | return {
169 | // Validate rating as a required number.
170 | rating: t.number({
171 | err: "Rating is required (1-5)",
172 | }).required(),
173 | // Validate comment as a required string.
174 | comment: t.string({ err: "Review comment is required" }).required(),
175 | };
176 | }).title("Add a review for a specific pet (authenticated users only)");
177 |
178 | /**
179 | * Delete a review
180 | * @route DELETE /reviews/:reviewId
181 | * @access Authenticated (Review owner or Admin - Based on sample logic)
182 | * Demonstrates: DELETE request, dynamic routing ($reviewId), path parameter, data deletion, authorization check (owner or admin).
183 | */
184 | export const DELETE_reviews$reviewId: JetRoute<{
185 | params: { reviewId: string }; // Review ID from path
186 | }, [AuthPluginType]> = function (ctx) {
187 | // Check if user is authenticated.
188 | const user = ctx.state["user"];
189 | if (!user) {
190 | ctx.code = 401; // Unauthorized
191 | ctx.send({
192 | status: "error",
193 | message: "Authentication required to delete reviews",
194 | });
195 | return;
196 | }
197 |
198 | const reviewId = ctx.params.reviewId; // Access review ID from path.
199 |
200 | // Find index of the review by ID.
201 | const reviewIndex = reviews.findIndex((r) => r.id === reviewId);
202 |
203 | // If review is not found, set 404 status and send error response.
204 | if (reviewIndex === -1) {
205 | ctx.code = 404; // Not Found
206 | ctx.send({
207 | status: "error",
208 | message: `Review with ID ${reviewId} not found.`,
209 | });
210 | return;
211 | }
212 |
213 | const review = reviews[reviewIndex]; // Get the review object.
214 |
215 | // Authorization Check: Check if the authenticated user is the owner of the review OR an admin.
216 | const isOwner = review.userId === user.id;
217 | const isAdmin = user.role === "admin";
218 |
219 | if (!isOwner && !isAdmin) {
220 | ctx.code = 403; // Forbidden
221 | ctx.send({
222 | status: "error",
223 | message: "You don't have permission to delete this review",
224 | });
225 | return;
226 | }
227 |
228 | // Remove the review from the in-memory array using splice().
229 | const deletedReview = reviews.splice(reviewIndex, 1)[0];
230 |
231 | // Log the deletion action.
232 | ctx.plugins?.["info"]({
233 | action: "delete_review",
234 | reviewId: deletedReview.id,
235 | petId: deletedReview.petId,
236 | userId: user.id,
237 | message: `User ${user.username} deleted review ${deletedReview.id}`,
238 | });
239 |
240 | // Send a success response with details of the deleted review.
241 | ctx.send({
242 | status: "success",
243 | message: `Review with ID ${reviewId} deleted successfully`,
244 | review: deletedReview,
245 | });
246 | };
247 |
248 | // Apply .info() for documentation.
249 | use(DELETE_reviews$reviewId).title(
250 | "Delete a review (admin or review owner only)",
251 | );
252 |
253 | // Export route handlers so Jetpath can discover and register them based on naming convention.
254 |
--------------------------------------------------------------------------------
/example/types.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Pet data model (Based on app.jet.ts typedef comment)
3 | */
4 | export type PetType = {
5 | id?: string;
6 | name: string;
7 | species: string;
8 | breed: string;
9 | age: number;
10 | gender: string;
11 | color: string;
12 | description: string;
13 | image?: string;
14 | price: number;
15 | available: boolean;
16 | createdAt?: string;
17 | updatedAt?: string;
18 | tags?: string[];
19 | health?: {
20 | vaccinated?: boolean;
21 | neutered?: boolean;
22 | medicalHistory?: string[];
23 | };
24 | };
25 |
26 | /**
27 | * User review data model (Based on app.jet.ts typedef comment)
28 | */
29 | export type ReviewType = {
30 | id: string;
31 | petId: string;
32 | userId: string;
33 | username: string;
34 | rating: number;
35 | comment: string;
36 | createdAt: string;
37 | };
38 |
--------------------------------------------------------------------------------
/example/websockets-usage.md:
--------------------------------------------------------------------------------
1 | # Using websockets in jetpath
2 |
3 | ## Deno & Bunjs
4 |
5 | ```js
6 | // usage go to ws://localhost:8000/sockets
7 |
8 | // for deno and bun only
9 | export const GET_sockets: JetRoute = (ctx) => {
10 | ctx.upgrade();
11 | const conn = ctx.connection!;
12 | try {
13 | conn.addEventListener("open", (socket) => {
14 | console.log("a client connected!");
15 | socket.send("😎 Welcome to jet chat");
16 | });
17 | conn.addEventListener("message", (socket,event) => {
18 | if (event.data === "ping") {
19 | socket.send("pong");
20 | } else {
21 | socket.send("all your " + event.data + " are belong to us!");
22 | }
23 | });
24 | } catch (error) {
25 | console.log(error);
26 | }
27 | };
28 |
29 | ```
30 |
31 | ## Node
32 |
33 | ```js
34 | // install
35 |
36 | // npm i ws
37 |
38 | // usage
39 | import { WebSocketServer } from "ws";
40 | import http from "node:http";
41 | import { Jetpath } from "jetpath";
42 | const app = new Jetpath({ source: "tests" });
43 |
44 | // Spinning the HTTP server and the WebSocket server.
45 | const server = app.server;
46 | const wsServer = new WebSocketServer({ server });
47 | const port = 8000;
48 | server.listen(port, () => {
49 | console.log(`WebSocket server is running on port ${port}`);
50 | });
51 |
52 | //? listen for server upgrade via ctx.request
53 | ```
--------------------------------------------------------------------------------
/icon-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeDynasty-dev/Jetpath/ec22ef8a7e056071590def7c0be943ed464398e7/icon-transparent.png
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeDynasty-dev/Jetpath/ec22ef8a7e056071590def7c0be943ed464398e7/icon.png
--------------------------------------------------------------------------------
/pack:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | #!/bin/bash
3 |
4 | echo " Packing ...."
5 | tsc
6 | bun bundle
7 | npm pack --ignore-scripts # how to avoid running npm prepare here?
8 | mv **.tgz ~/zips && echo "Packed successfully"
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jetpath",
3 | "version": "1.8.6",
4 | "description": "Jetpath - A fast, seamless and minimalist framework for Node, Deno and Bun.js. Embrace the speed and elegance of the next-gen server-side experience.",
5 | "main": "dist/index.js",
6 | "type": "module",
7 | "files": [
8 | "dist/index.d.ts",
9 | "dist/primitives",
10 | "dist/extracts",
11 | "dist/index.js"
12 | ],
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/codedynasty-dev/jetpath.git"
16 | },
17 | "bin": {
18 | "jetpath": "dist/cli.js"
19 | },
20 | "keywords": [
21 | "web",
22 | "framework",
23 | "fast",
24 | "simple",
25 | "bunjs",
26 | "nodejs",
27 | "denojs",
28 | "expressive",
29 | "server",
30 | "http",
31 | "convention"
32 | ],
33 | "author": "friday candour fridaycandours@gmail.com",
34 | "license": "Apache",
35 | "bugs": {
36 | "url": "https://github.com/codedynasty-dev/jetpath/issues"
37 | },
38 | "homepage": "https://jetpath.codedynasty.dev",
39 | "scripts": {
40 | "compile": "./pack",
41 | "deno": "deno run --allow-all tests/app.jet.ts",
42 | "bun": "bun --watch tests/app.jet.ts",
43 | "dev": "node --watch --experimental-strip-types example/index.jet.ts",
44 | "node": "node --watch --experimental-strip-types example/index.jet.ts",
45 | "watch": "tsc tests/*.ts --target esnext --watch",
46 | "watch:docs": "docmach",
47 | "build": "npx docmach build",
48 | "lint": "gts lint",
49 | "clean": "gts clean",
50 | "fix": "gts fix",
51 | "prepare": "tsc --project tsconfig.d.json && tsc --project tsconfig.json && bun bundle.ts && npm run build",
52 | "pretest": "npm run build",
53 | "build:css": " css-purge -i docs/fragments/index.css -o docs/assets/index.css",
54 | "posttest": "npm run lint",
55 | "bench": "./bench.sh"
56 | },
57 | "engines": {
58 | "node": ">=14.0.0",
59 | "bun": ">=0.1.0"
60 | },
61 | "private": false,
62 | "devDependencies": {
63 | "@types/bun": "^1.1.8",
64 | "@types/node": "^22.7.5",
65 | "docmach": "^1.0.16",
66 | "gts": "^6.0.2",
67 | "mitata": "^1.0.34",
68 | "typescript": "^5.6.3"
69 | },
70 | "docmach": {
71 | "docs-directory": "docs/docs",
72 | "assets-folder": "docs/assets",
73 | "build-directory": "docs/build"
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/repository-open-graph-template.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeDynasty-dev/Jetpath/ec22ef8a7e056071590def7c0be943ed464398e7/repository-open-graph-template.png
--------------------------------------------------------------------------------
/src/assets/api-doc.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {NAME} API
8 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
414 |
415 |
416 |
417 |
418 |