@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 +24 -0
- package/Dockerfile +43 -0
- package/README.md +124 -0
- package/bun.lockb +0 -0
- package/package.json +36 -0
- package/routes/_utils/validation.ts +36 -0
- package/routes/byos/[primary]/doc.ts +28 -0
- package/routes/byos/[primary]/docs.ts +28 -0
- package/routes/byos/[primary]/join/[secondary]/docs.ts +10 -0
- package/routes/byos/[primary]/schema.ts +17 -0
- package/routes/byos/[primary]/stream/doc.ts +28 -0
- package/routes/byos/[primary]/stream/docs.ts +28 -0
- package/src/Tach.ts +602 -0
- package/src/Yon.ts +25 -0
- package/src/runtime.ts +822 -0
- package/tsconfig.json +17 -0
- package/types/index.d.ts +13 -0
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,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
|
+
}
|