@vyckr/tachyon 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.example ADDED
@@ -0,0 +1,24 @@
1
+ # Tachyon environment variables
2
+ PORT=8000
3
+ ALLOW_HEADERS=*
4
+ ALLOW_ORGINS=*
5
+ ALLOW_CREDENTIALS=true|false
6
+ ALLOW_EXPOSE_HEADERS=*
7
+ ALLOW_MAX_AGE=3600
8
+ ALLOW_METHODS=GET,POST,PUT,DELETE,PATCH
9
+ PRODUCTION=true|false
10
+ SAVE_LOGS=true|false
11
+ SAVE_STATS=true|false
12
+ SAVE_REQUESTS=true|false
13
+ SAVE_ERRORS=true|false
14
+
15
+ # BYOS environment variables
16
+ DB_DIR=/path/to/disk/database
17
+ SCHEMA=LOOSE|STRICT
18
+ LOGGING=true|false
19
+ SCHEMA_PATH=/path/to/schema/directory
20
+ MEM_DR=/path/to/memory/database
21
+ S3_REGION=region
22
+ S3_INDEX_BUCKET=bucket
23
+ S3_DATA_BUCKET=bucket
24
+ S3_ENDPOINT=https//example.com
package/Dockerfile ADDED
@@ -0,0 +1,43 @@
1
+ FROM oven/bun:latest AS build
2
+
3
+ RUN apt-get update && apt-get install -y unzip git
4
+
5
+ WORKDIR /app
6
+
7
+ RUN git clone https://github.com/oven-sh/bun.git
8
+
9
+ WORKDIR /app/bun/packages/bun-lambda
10
+
11
+ RUN bun install
12
+
13
+ RUN bun run build-layer
14
+
15
+ RUN unzip bun-lambda-layer.zip -d /tmp
16
+
17
+ WORKDIR /tmp
18
+
19
+ COPY ./src/Tach.ts .
20
+
21
+ COPY package.json .
22
+
23
+ RUN bun install
24
+
25
+ RUN bun build --target=bun Tach.ts --outfile lambda
26
+
27
+ FROM public.ecr.aws/lambda/provided:al2
28
+
29
+ COPY --from=build /tmp/lambda ${LAMBDA_TASK_ROOT}
30
+
31
+ COPY --from=build /tmp/bootstrap ${LAMBDA_RUNTIME_DIR}
32
+
33
+ COPY --from=build /tmp/bun /opt
34
+
35
+ COPY ./src/runtime.ts /opt
36
+
37
+ RUN chmod 777 /opt/bun
38
+
39
+ RUN chmod 777 ${LAMBDA_TASK_ROOT}/lambda
40
+
41
+ RUN chmod 777 ${LAMBDA_RUNTIME_DIR}/bootstrap
42
+
43
+ CMD ["lambda.fetch"]
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # Tachyon
2
+
3
+ Tachyon is a simple to use API framework built with TypeScript (Bun), which was inspired by Fastly and FastAPI (Python). Tachyon aim to provide a simple and intuitive API framework for building serverless applications and abstracts away the complexity of configuations, letting you focus on building your application.
4
+
5
+ ## Features
6
+
7
+ - Has BYOS [(Bring Your Own Storage)](https://github.com/Chidelma/BYOS) integration
8
+ - Use of decorators for routes
9
+ - Customizable methods for routes
10
+ - AWS Lambda support [(Docker)](https://hub.docker.com/repository/docker/iyormobi/tachyon/general)
11
+ - Use of file-system based routing
12
+ - Hot reloading of routes in development mode
13
+ - Supports dynamic routes
14
+ - Supports Async Iterators (Streaming)
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ bun add @vyckr/tachyon
20
+ ```
21
+
22
+ ## Configuration
23
+
24
+ The .env file should be in the root directory of your project. The following environment variables:
25
+ ```
26
+ # Tachyon environment variables
27
+ PORT=8000 (optional)
28
+ ALLOW_HEADERS=* (optional)
29
+ ALLOW_ORGINS=* (optional)
30
+ ALLOW_CREDENTIALS=true|false (optional)
31
+ ALLOW_EXPOSE_HEADERS=* (optional)
32
+ ALLOW_MAX_AGE=3600 (optional)
33
+ ALLOW_METHODS=GET,POST,PUT,DELETE,PATCH (optional)
34
+ PRODUCTION=true|false (optional)
35
+ SAVE_LOGS=true|false (optional)
36
+ SAVE_STATS=true|false (optional)
37
+ SAVE_REQUESTS=true|false (optional)
38
+ SAVE_ERRORS=true|false (optional)
39
+
40
+ # BYOS environment variables
41
+ DB_DIR=/path/to/disk/database (required)
42
+ SCHEMA=LOOSE|STRICT (optional)
43
+ LOGGING=true|false (optional)
44
+ SCHEMA_PATH=/path/to/schema/directory (required if SCHEMA is set to STRICT)
45
+ MEM_DR=/path/to/memory/database (optional)
46
+ S3_REGION=region (optional)
47
+ S3_INDEX_BUCKET=bucket (required)
48
+ S3_DATA_BUCKET=bucket (required)
49
+ S3_ENDPOINT=https//example.com (optional)
50
+ ```
51
+
52
+ ## Usage/Example
53
+
54
+ Make sure you have set the 'SCHEMA_PATH' if 'SCHEMA' is set to 'STRICT'. The schema path should be a directory containing the declaration files. for example:
55
+
56
+ ```
57
+ /path/to/schema/directory
58
+ /users.d.ts
59
+ ```
60
+ ### Requirements
61
+ - Make sure to have a 'routes' directory in the root of your project
62
+ - Dynamic routes should be enclosed in square brackets
63
+ - The first parameter should NOT be a dynamic route (e.g. /[version]/doc.ts)
64
+ - All dynamic routes should be within odd indexes (e.g. /v1/[path]/login/[id]/name.ts)
65
+ - The last parameter in the route should not be a dynamic route (e.g. /v1/[path]/login/[id]/name.ts)
66
+
67
+ ```typescript
68
+ // routes/v1/[collection]/doc.ts
69
+ import Silo from "@vyckr/byos"
70
+ imoprt { VALIDATE } from "../utils/decorators"
71
+
72
+ export default class Users {
73
+
74
+ static collection = "[collection]"
75
+
76
+ @VALIDATE
77
+ async GET({ slugs }) {
78
+ return await Silo.findDocs(slugs.get(this.collection), { $limit: 10 })
79
+ }
80
+
81
+ @VALIDATE
82
+ async POST(user: _user, { slugs }) {
83
+ return await Silo.putData(slugs.get(this.collection), { name: user.name, age: user.age })
84
+ }
85
+
86
+ @VALIDATE
87
+ async PATCH(user: _user, { slugs }) {
88
+ return await Silo.patchDoc(slugs.get(this.collection), { $set: { name: user.name, age: user.age } })
89
+ }
90
+
91
+ @VALIDATE
92
+ async DELETE(id: string, { slugs }) {
93
+ await Silo.delDoc(slugs.get(this.collection), id)
94
+ }
95
+ }
96
+ ```
97
+
98
+ To run the application, you can use the following command:
99
+
100
+ ```bash
101
+ bun tach
102
+ ```
103
+
104
+ To invoke the API endpoints, you can use the following commands:
105
+
106
+ ```bash
107
+ curl -X GET http://localhost:8000/v1/users/doc
108
+ ```
109
+
110
+ ```bash
111
+ curl -X POST http://localhost:8000/v1/users/doc -d '{"name": "John Doe", "age": 30}'
112
+ ```
113
+
114
+ ```bash
115
+ curl -X PATCH http://localhost:8000/v1/users/doc -d '{"name": "Jane Doe", "age": 31}'
116
+ ```
117
+
118
+ ```bash
119
+ curl -X DELETE http://localhost:8000/v1/users/doc/5e8b0a9c-c0d1-4d3b-a0b1-e2d8e0e9a1c0
120
+ ```
121
+
122
+ # License
123
+
124
+ Tachyon is licensed under the MIT License.
package/bun.lockb ADDED
Binary file
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@vyckr/tachyon",
3
+ "version": "0.1.0",
4
+ "devDependencies": {
5
+ "@types/node": "^20.4.2",
6
+ "bun-types": "^1.1.21"
7
+ },
8
+ "dependencies": {
9
+ "@vyckr/byos": "^0.1.0"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./types/index.d.ts"
14
+ }
15
+ },
16
+ "bin": {
17
+ "tach": "./src/Yon.ts"
18
+ },
19
+ "type": "module",
20
+ "license": "MIT",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/Chidelma/Tachyon.git"
24
+ },
25
+ "keywords": [
26
+ "tachyon",
27
+ "api",
28
+ "framework",
29
+ "typescript",
30
+ "bun"
31
+ ],
32
+ "author": "Chidelma",
33
+ "bugs": {
34
+ "url": "https://github.com/Chidelma/Tachyon/issues"
35
+ }
36
+ }
@@ -0,0 +1,36 @@
1
+ export const VALIDATE = (input: any[]) => (cls: Object, funcName: string, propDesc: PropertyDescriptor) => {
2
+
3
+ const originalFunc: Function = propDesc.value
4
+
5
+ propDesc.value = async function(...args: any[]) {
6
+
7
+ const params = [...input]
8
+
9
+ if(params.length !== args.length) {
10
+
11
+ do {
12
+
13
+ const idx = params.findLastIndex(x => x.default !== undefined)
14
+
15
+ if(idx === -1) break
16
+
17
+ const [ param ] = params.splice(idx, 1)
18
+
19
+ args.unshift(param.default)
20
+
21
+ } while(true)
22
+
23
+ if(input.length !== args.length) throw new Error(`Invalid number of arguments for ${funcName}`)
24
+ }
25
+
26
+ for(let i = 0; i < input.length; i++) {
27
+
28
+ if(typeof args[i] !== input[i].type) {
29
+
30
+ throw new Error(`Invalid argument type for ${funcName}`)
31
+ }
32
+ }
33
+
34
+ return originalFunc.apply(this, args)
35
+ }
36
+ }
@@ -0,0 +1,28 @@
1
+ import { VALIDATE } from "../../_utils/validation.js";
2
+
3
+ export default class Doc {
4
+
5
+ @VALIDATE([{ type: "object" }])
6
+ static async GET({ request }: _HTTPContext) {
7
+
8
+ console.log(request.url)
9
+ }
10
+
11
+ @VALIDATE([{ type: "object" }, { type: "object" }])
12
+ static async POST({ request }: _HTTPContext) {
13
+
14
+ console.log(request.url)
15
+ }
16
+
17
+ @VALIDATE([{ type: "object" }, { type: "object" }])
18
+ static async PATCH({ request }: _HTTPContext) {
19
+
20
+ console.log(request.url)
21
+ }
22
+
23
+ @VALIDATE([{ type: "string" }, { type: "object" }])
24
+ static async DELETE({ request }: _HTTPContext) {
25
+
26
+ console.log(request.url)
27
+ }
28
+ }
@@ -0,0 +1,28 @@
1
+ import { VALIDATE } from "../../_utils/validation.js";
2
+
3
+ export default class Docs {
4
+
5
+ @VALIDATE([{ type: "object" }])
6
+ static async GET({ request }: _HTTPContext) {
7
+
8
+ console.log(request.url)
9
+ }
10
+
11
+ @VALIDATE([{ type: "object" }])
12
+ static async POST({ request }: _HTTPContext) {
13
+
14
+ console.log(request.url)
15
+ }
16
+
17
+ @VALIDATE([{ type: "object" }])
18
+ static async PATCH({ request }: _HTTPContext) {
19
+
20
+ console.log(request.url)
21
+ }
22
+
23
+ @VALIDATE([{ type: "object" }])
24
+ static async DELETE({ request }: _HTTPContext) {
25
+
26
+ console.log(request.url)
27
+ }
28
+ }
@@ -0,0 +1,10 @@
1
+ import { VALIDATE } from "../../../../_utils/validation.js";
2
+
3
+ export default class Docs {
4
+
5
+ @VALIDATE([{ type: "object" }])
6
+ static async GET({ slugs }: _HTTPContext) {
7
+
8
+ console.info(slugs)
9
+ }
10
+ }
@@ -0,0 +1,17 @@
1
+ export default class Schema {
2
+
3
+ static async POST({ request }: _HTTPContext) {
4
+
5
+ console.log(request.url)
6
+ }
7
+
8
+ static async PATCH({ request }: _HTTPContext) {
9
+
10
+ console.log(request.url)
11
+ }
12
+
13
+ static DELETE({ request }: _HTTPContext) {
14
+
15
+ console.log(request.url)
16
+ }
17
+ }
@@ -0,0 +1,28 @@
1
+ import { VALIDATE } from "../../../_utils/validation.js";
2
+
3
+ export default class {
4
+
5
+ @VALIDATE([{ type: "object" }])
6
+ static GET({ request }: _HTTPContext) {
7
+
8
+ return {
9
+
10
+ async *[Symbol.asyncIterator]() {
11
+
12
+ yield request.url
13
+ }
14
+ }
15
+ }
16
+
17
+ @VALIDATE([{ type: "object" }])
18
+ static DELETE({ request }: _HTTPContext) {
19
+
20
+ return {
21
+
22
+ async *[Symbol.asyncIterator]() {
23
+
24
+ yield request.url
25
+ }
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,28 @@
1
+ import { VALIDATE } from "../../../_utils/validation.js";
2
+
3
+ export default class {
4
+
5
+ @VALIDATE([{ type: "object" }])
6
+ static GET({ request }: _HTTPContext) {
7
+
8
+ return {
9
+
10
+ async *[Symbol.asyncIterator]() {
11
+
12
+ yield request.url
13
+ }
14
+ }
15
+ }
16
+
17
+ @VALIDATE([{ type: "object", default: {} }, { type: "object" }])
18
+ static DELETE({ request }: _HTTPContext) {
19
+
20
+ return {
21
+
22
+ async *[Symbol.asyncIterator]() {
23
+
24
+ yield request.url
25
+ }
26
+ }
27
+ }
28
+ }