@darco2903/cdn-api 1.0.7-beta.0 → 1.0.7-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -9
- package/dist/client.d.ts +1039 -0
- package/{src/client.ts → dist/client.js} +15 -18
- package/{src/common.ts → dist/common.d.ts} +4 -4
- package/dist/common.js +4 -0
- package/dist/consts.d.ts +5 -0
- package/{src/consts.ts → dist/consts.js} +4 -8
- package/dist/contract/auth.d.ts +35 -0
- package/{src/contract/auth.ts → dist/contract/auth.js} +18 -22
- package/dist/contract/endpoint.d.ts +396 -0
- package/{src/contract/endpoint.ts → dist/contract/endpoint.js} +42 -53
- package/dist/contract/index.d.ts +2039 -0
- package/{src/contract/index.ts → dist/contract/index.js} +22 -27
- package/dist/contract/key.d.ts +15 -0
- package/{src/contract/key.ts → dist/contract/key.js} +15 -19
- package/dist/contract/list.d.ts +134 -0
- package/{src/contract/list.ts → dist/contract/list.js} +28 -30
- package/dist/contract/record.d.ts +412 -0
- package/{src/contract/record.ts → dist/contract/record.js} +71 -82
- package/dist/contract/service.d.ts +240 -0
- package/{src/contract/service.ts → dist/contract/service.js} +33 -44
- package/dist/contract/stats.d.ts +32 -0
- package/{src/contract/stats.ts → dist/contract/stats.js} +34 -36
- package/dist/contract/upload.d.ts +790 -0
- package/{src/contract/upload.ts → dist/contract/upload.js} +78 -82
- package/{src/index.ts → dist/index.d.ts} +2 -2
- package/dist/index.js +2 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.js +58 -0
- package/{src/socket/index.ts → dist/socket/index.d.ts} +2 -2
- package/dist/socket/index.js +2 -0
- package/dist/socket/interface/index.d.ts +5 -0
- package/dist/socket/interface/index.js +1 -0
- package/{src/socket/interface/template.ts → dist/socket/interface/template.d.ts} +6 -7
- package/dist/socket/interface/template.js +1 -0
- package/dist/socket/types.d.ts +3 -0
- package/dist/socket/types.js +1 -0
- package/dist/types/creds.d.ts +8 -0
- package/{src/types/creds.ts → dist/types/creds.js} +5 -7
- package/dist/types/endpoint.d.ts +25 -0
- package/{src/types/endpoint.ts → dist/types/endpoint.js} +12 -19
- package/{src/types/index.ts → dist/types/index.d.ts} +6 -6
- package/dist/types/index.js +6 -0
- package/dist/types/jwt.d.ts +128 -0
- package/dist/types/jwt.js +33 -0
- package/dist/types/record.d.ts +97 -0
- package/{src/types/record.ts → dist/types/record.js} +25 -35
- package/dist/types/stats.d.ts +15 -0
- package/{src/types/stats.ts → dist/types/stats.js} +6 -9
- package/dist/types/upload.d.ts +45 -0
- package/{src/types/upload.ts → dist/types/upload.js} +12 -18
- package/dist/types.d.ts +32 -0
- package/dist/types.js +27 -0
- package/dist/uploader.d.ts +1044 -0
- package/{src/uploader.ts → dist/uploader.js} +72 -99
- package/package.json +2 -2
- package/.gitattributes +0 -2
- package/.github/workflows/release.yml +0 -116
- package/TODO.md +0 -0
- package/prettier.config.js +0 -24
- package/src/server.ts +0 -89
- package/src/socket/interface/index.ts +0 -12
- package/src/socket/types.ts +0 -7
- package/src/types/jwt.ts +0 -78
- package/src/types.ts +0 -38
- package/tests/keys/private.pem +0 -5
- package/tests/keys/public.pem +0 -4
- package/tests/keys.ts +0 -11
- package/tests/tsconfig.json +0 -12
- package/tests/vitest/jwt.test.ts +0 -38
- package/tsconfig.json +0 -14
|
@@ -1,99 +1,72 @@
|
|
|
1
|
-
import axios
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const formData = new FormData();
|
|
74
|
-
formData.append("file", file.slice(start, end));
|
|
75
|
-
|
|
76
|
-
const res = await this.ax.post(
|
|
77
|
-
this.getPartEndpoint(uploadId, part + 1),
|
|
78
|
-
formData,
|
|
79
|
-
{
|
|
80
|
-
onUploadProgress(e) {
|
|
81
|
-
//
|
|
82
|
-
},
|
|
83
|
-
}
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
if (res.status !== 200) {
|
|
87
|
-
throw new Error("Failed to upload part " + (part + 1));
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const res = await this.client.upload.uploadEnd({
|
|
92
|
-
params: { upload_id: uploadId },
|
|
93
|
-
});
|
|
94
|
-
if (res.status !== 200) {
|
|
95
|
-
throw new Error("Failed to finalize upload");
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { createClient } from "./client.js";
|
|
3
|
+
class Uploader {
|
|
4
|
+
constructor(origin) {
|
|
5
|
+
this.ax = axios.create({
|
|
6
|
+
baseURL: origin,
|
|
7
|
+
withCredentials: true,
|
|
8
|
+
});
|
|
9
|
+
this.client = createClient(origin);
|
|
10
|
+
}
|
|
11
|
+
getPartEndpoint(uploadId, part) {
|
|
12
|
+
return `/upload/part/${uploadId}/${part}`;
|
|
13
|
+
}
|
|
14
|
+
async upload(file, role, visible, active) {
|
|
15
|
+
if (file.size < Uploader.MAX_SINGLE_UPLOAD_SIZE) {
|
|
16
|
+
const formData = new FormData();
|
|
17
|
+
const data = {
|
|
18
|
+
filename: file.name,
|
|
19
|
+
role,
|
|
20
|
+
visible,
|
|
21
|
+
active,
|
|
22
|
+
};
|
|
23
|
+
formData.append("data", JSON.stringify(data));
|
|
24
|
+
formData.append("file", file);
|
|
25
|
+
const res = await this.ax.post("/upload", formData, {
|
|
26
|
+
onUploadProgress(e) {
|
|
27
|
+
//
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const parts = Math.ceil(file.size / Uploader.MAX_SINGLE_UPLOAD_SIZE);
|
|
33
|
+
const resInit = await this.client.upload.uploadInit({
|
|
34
|
+
body: {
|
|
35
|
+
filename: file.name,
|
|
36
|
+
role,
|
|
37
|
+
visible,
|
|
38
|
+
active,
|
|
39
|
+
size: file.size,
|
|
40
|
+
mimeType: file.type,
|
|
41
|
+
parts,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
if (resInit.status !== 200) {
|
|
45
|
+
throw new Error("Failed to initialize upload");
|
|
46
|
+
}
|
|
47
|
+
const uploadId = resInit.body.uploadId;
|
|
48
|
+
for (let part = 0; part < parts; part++) {
|
|
49
|
+
const start = part * Uploader.MAX_SINGLE_UPLOAD_SIZE;
|
|
50
|
+
const end = Math.min(start + Uploader.MAX_SINGLE_UPLOAD_SIZE, file.size);
|
|
51
|
+
const formData = new FormData();
|
|
52
|
+
formData.append("file", file.slice(start, end));
|
|
53
|
+
const res = await this.ax.post(this.getPartEndpoint(uploadId, part + 1), formData, {
|
|
54
|
+
onUploadProgress(e) {
|
|
55
|
+
//
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
if (res.status !== 200) {
|
|
59
|
+
throw new Error("Failed to upload part " + (part + 1));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const res = await this.client.upload.uploadEnd({
|
|
63
|
+
params: { upload_id: uploadId },
|
|
64
|
+
});
|
|
65
|
+
if (res.status !== 200) {
|
|
66
|
+
throw new Error("Failed to finalize upload");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
Uploader.MAX_SINGLE_UPLOAD_SIZE = 100000000; // 100MB
|
|
72
|
+
export default Uploader;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@darco2903/cdn-api",
|
|
3
|
-
"version": "1.0.7-beta.
|
|
3
|
+
"version": "1.0.7-beta.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"./server": "./dist/server.js"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@darco2903/auth-api": "2.
|
|
22
|
+
"@darco2903/auth-api": "2.1.0",
|
|
23
23
|
"@ts-rest/core": "^3.52.1",
|
|
24
24
|
"@ts-rest/open-api": "^3.52.1",
|
|
25
25
|
"axios": "^1.12.2",
|
package/.gitattributes
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
name: Release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- "v*" # Trigger on version tags
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
id-token: write
|
|
10
|
-
contents: write
|
|
11
|
-
|
|
12
|
-
env:
|
|
13
|
-
PNPM_VERSION: "10.32.0"
|
|
14
|
-
TARBALL_NAME: "darco2903-cdn-api"
|
|
15
|
-
|
|
16
|
-
jobs:
|
|
17
|
-
check:
|
|
18
|
-
runs-on: ubuntu-latest
|
|
19
|
-
|
|
20
|
-
steps:
|
|
21
|
-
- name: Checkout code
|
|
22
|
-
uses: actions/checkout@v5
|
|
23
|
-
|
|
24
|
-
- name: Check tag matches package.json version
|
|
25
|
-
run: |
|
|
26
|
-
TAG_VERSION="${GITHUB_REF_NAME#v}"
|
|
27
|
-
PKG_VERSION=$(node -p "require('./package.json').version")
|
|
28
|
-
PNPM_VERSION=$(node -p "require('./package.json').packageManager.split('@')[1]")
|
|
29
|
-
|
|
30
|
-
echo "Tag version: $TAG_VERSION"
|
|
31
|
-
echo "Package version: $PKG_VERSION"
|
|
32
|
-
|
|
33
|
-
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
|
|
34
|
-
echo "❌ Tag version does not match package.json version"
|
|
35
|
-
exit 1
|
|
36
|
-
fi
|
|
37
|
-
|
|
38
|
-
if [ "$PNPM_VERSION" != "${{ env.PNPM_VERSION }}" ]; then
|
|
39
|
-
echo "❌ package.json specifies pnpm version $PNPM_VERSION, expected ${{ env.PNPM_VERSION }}"
|
|
40
|
-
exit 1
|
|
41
|
-
fi
|
|
42
|
-
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
test:
|
|
46
|
-
needs: check
|
|
47
|
-
runs-on: ${{ matrix.os }}
|
|
48
|
-
|
|
49
|
-
strategy:
|
|
50
|
-
matrix:
|
|
51
|
-
os: [ubuntu-latest]
|
|
52
|
-
node-version: [24]
|
|
53
|
-
|
|
54
|
-
steps:
|
|
55
|
-
- name: Checkout code
|
|
56
|
-
uses: actions/checkout@v5
|
|
57
|
-
|
|
58
|
-
- name: Install pnpm
|
|
59
|
-
uses: pnpm/action-setup@v4
|
|
60
|
-
with:
|
|
61
|
-
version: "${{ env.PNPM_VERSION }}"
|
|
62
|
-
|
|
63
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
64
|
-
uses: actions/setup-node@v4
|
|
65
|
-
with:
|
|
66
|
-
node-version: ${{ matrix.node-version }}
|
|
67
|
-
cache: "pnpm"
|
|
68
|
-
|
|
69
|
-
- name: Install dependencies
|
|
70
|
-
run: pnpm install --frozen-lockfile
|
|
71
|
-
|
|
72
|
-
- name: Run tests
|
|
73
|
-
run: pnpm test
|
|
74
|
-
|
|
75
|
-
#
|
|
76
|
-
|
|
77
|
-
release:
|
|
78
|
-
needs: [check, test]
|
|
79
|
-
runs-on: ubuntu-latest
|
|
80
|
-
|
|
81
|
-
strategy:
|
|
82
|
-
matrix:
|
|
83
|
-
node-version: [24]
|
|
84
|
-
|
|
85
|
-
steps:
|
|
86
|
-
- name: Checkout code
|
|
87
|
-
uses: actions/checkout@v5
|
|
88
|
-
|
|
89
|
-
- name: Install pnpm
|
|
90
|
-
uses: pnpm/action-setup@v4
|
|
91
|
-
with:
|
|
92
|
-
version: "${{ env.PNPM_VERSION }}"
|
|
93
|
-
|
|
94
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
95
|
-
uses: actions/setup-node@v4
|
|
96
|
-
with:
|
|
97
|
-
node-version: ${{ matrix.node-version }}
|
|
98
|
-
cache: "pnpm"
|
|
99
|
-
|
|
100
|
-
- name: Install dependencies
|
|
101
|
-
run: pnpm install --frozen-lockfile
|
|
102
|
-
|
|
103
|
-
- name: Pack project
|
|
104
|
-
run: pnpm pack
|
|
105
|
-
|
|
106
|
-
- name: Upload release asset
|
|
107
|
-
uses: softprops/action-gh-release@v2
|
|
108
|
-
with:
|
|
109
|
-
files: "${{ env.TARBALL_NAME }}-*.tgz"
|
|
110
|
-
generate_release_notes: true
|
|
111
|
-
env:
|
|
112
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
113
|
-
|
|
114
|
-
- name: Publish to NPM
|
|
115
|
-
shell: bash
|
|
116
|
-
run: pnpm publish --access public --no-git-checks
|
package/TODO.md
DELETED
|
File without changes
|
package/prettier.config.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @see https://prettier.io/docs/configuration
|
|
3
|
-
* @type {import("prettier").Config}
|
|
4
|
-
*/
|
|
5
|
-
const config = {
|
|
6
|
-
trailingComma: "es5",
|
|
7
|
-
tabWidth: 4,
|
|
8
|
-
semi: true,
|
|
9
|
-
singleQuote: false,
|
|
10
|
-
bracketSpacing: true,
|
|
11
|
-
printWidth: 80,
|
|
12
|
-
arrowParens: "always",
|
|
13
|
-
endOfLine: "lf",
|
|
14
|
-
useTabs: false,
|
|
15
|
-
proseWrap: "preserve",
|
|
16
|
-
quoteProps: "as-needed",
|
|
17
|
-
htmlWhitespaceSensitivity: "css",
|
|
18
|
-
bracketSameLine: false,
|
|
19
|
-
experimentalOperatorPosition: "start",
|
|
20
|
-
experimentalTernaries: true,
|
|
21
|
-
objectWrap: "preserve",
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export default config;
|
package/src/server.ts
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
export * from "./common.js";
|
|
2
|
-
import jwt from "jsonwebtoken";
|
|
3
|
-
import { ResultAsync } from "neverthrow";
|
|
4
|
-
import type { Time } from "@darco2903/secondthought";
|
|
5
|
-
import {
|
|
6
|
-
cdnAssetTokenDataDecodedSchema,
|
|
7
|
-
type JWTVerifyError,
|
|
8
|
-
type CdnFeedbackTokenData,
|
|
9
|
-
type CdnAssetTokenDataDecoded,
|
|
10
|
-
type JWTSignError,
|
|
11
|
-
} from "./common.js";
|
|
12
|
-
import { JWT_ALGORITHM } from "./consts.js";
|
|
13
|
-
|
|
14
|
-
export function JWTVerify(
|
|
15
|
-
token: string,
|
|
16
|
-
pubKey: string
|
|
17
|
-
): ResultAsync<CdnAssetTokenDataDecoded, JWTVerifyError> {
|
|
18
|
-
return ResultAsync.fromPromise(
|
|
19
|
-
new Promise((resolve, reject) => {
|
|
20
|
-
jwt.verify(
|
|
21
|
-
token,
|
|
22
|
-
pubKey,
|
|
23
|
-
{ algorithms: [JWT_ALGORITHM] },
|
|
24
|
-
(e, decoded) => {
|
|
25
|
-
if (e) {
|
|
26
|
-
reject({
|
|
27
|
-
name: e.name as JWTVerifyError["name"],
|
|
28
|
-
message: e.message,
|
|
29
|
-
} satisfies JWTVerifyError);
|
|
30
|
-
} else if (decoded === undefined) {
|
|
31
|
-
reject({
|
|
32
|
-
name: "InvalidToken",
|
|
33
|
-
message: "Token is undefined",
|
|
34
|
-
} satisfies JWTVerifyError);
|
|
35
|
-
} else {
|
|
36
|
-
const res =
|
|
37
|
-
cdnAssetTokenDataDecodedSchema.safeParse(decoded);
|
|
38
|
-
if (res.success) {
|
|
39
|
-
resolve(res.data);
|
|
40
|
-
} else {
|
|
41
|
-
reject({
|
|
42
|
-
name: "InvalidTokenData",
|
|
43
|
-
message: "Invalid token data",
|
|
44
|
-
} satisfies JWTVerifyError);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
);
|
|
49
|
-
}),
|
|
50
|
-
(e) => e as JWTVerifyError
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Sign a JWT token with the given payload and private key, with the specified expiration time.
|
|
56
|
-
* @param expiresIn Expiration time in seconds or a Time object.
|
|
57
|
-
*/
|
|
58
|
-
export function JWTSign(
|
|
59
|
-
payload: CdnFeedbackTokenData,
|
|
60
|
-
privKey: string,
|
|
61
|
-
expiresIn: number | Time
|
|
62
|
-
): ResultAsync<string, JWTSignError> {
|
|
63
|
-
const expiresInSec =
|
|
64
|
-
typeof expiresIn === "number" ? expiresIn : expiresIn.toSecond().time;
|
|
65
|
-
|
|
66
|
-
return ResultAsync.fromPromise(
|
|
67
|
-
new Promise((resolve, reject) => {
|
|
68
|
-
jwt.sign(
|
|
69
|
-
payload,
|
|
70
|
-
privKey,
|
|
71
|
-
{
|
|
72
|
-
algorithm: JWT_ALGORITHM,
|
|
73
|
-
expiresIn: expiresInSec,
|
|
74
|
-
},
|
|
75
|
-
(e, token) => {
|
|
76
|
-
if (e || token === undefined) {
|
|
77
|
-
reject({
|
|
78
|
-
name: "JsonWebTokenError",
|
|
79
|
-
message: e?.message ?? "Failed to sign token",
|
|
80
|
-
} satisfies JWTSignError);
|
|
81
|
-
} else {
|
|
82
|
-
resolve(token);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
);
|
|
86
|
-
}),
|
|
87
|
-
(e) => e as JWTSignError
|
|
88
|
-
);
|
|
89
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
SocketClientToServerTemplate,
|
|
3
|
-
SocketServerToClientTemplate,
|
|
4
|
-
} from "./template.js";
|
|
5
|
-
|
|
6
|
-
export interface CdnClientToServerEvents
|
|
7
|
-
//
|
|
8
|
-
extends SocketClientToServerTemplate {}
|
|
9
|
-
|
|
10
|
-
export interface CdnServerToClientEvents
|
|
11
|
-
//
|
|
12
|
-
extends SocketServerToClientTemplate {}
|
package/src/socket/types.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Socket as ClientSocket } from "socket.io-client";
|
|
2
|
-
import {
|
|
3
|
-
CdnClientToServerEvents as ClientToServer,
|
|
4
|
-
CdnServerToClientEvents as ServerToClient,
|
|
5
|
-
} from "./interface/index.js";
|
|
6
|
-
|
|
7
|
-
export type CdnClientSocket = ClientSocket<ServerToClient, ClientToServer>;
|
package/src/types/jwt.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import z from "zod";
|
|
2
|
-
import {
|
|
3
|
-
authAssetTypeSchema,
|
|
4
|
-
authServiceSchema,
|
|
5
|
-
userPublicIdSchema,
|
|
6
|
-
} from "@darco2903/auth-api/client";
|
|
7
|
-
import { endpointPathSchema } from "./endpoint.js";
|
|
8
|
-
|
|
9
|
-
export type JWTVerifyError = {
|
|
10
|
-
name:
|
|
11
|
-
| "TokenExpiredError"
|
|
12
|
-
| "JsonWebTokenError"
|
|
13
|
-
| "NotBeforeError"
|
|
14
|
-
| "InvalidToken"
|
|
15
|
-
| "InvalidTokenData";
|
|
16
|
-
message: string;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type JWTSignError = {
|
|
20
|
-
name: "InvalidTokenData" | "JsonWebTokenError";
|
|
21
|
-
message: string;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const JWTData = z.object({
|
|
25
|
-
iat: z.number(),
|
|
26
|
-
exp: z.number(),
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
export const jwtSchema = z.string().startsWith("Bearer ");
|
|
30
|
-
|
|
31
|
-
///////////////////////////////////
|
|
32
|
-
|
|
33
|
-
export const cdnAssetHeaderSchema = z.object({
|
|
34
|
-
"x-cdn-asset": jwtSchema.optional(),
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
export const cdnAssetTokenDataSchema = z.object({
|
|
38
|
-
service: authServiceSchema,
|
|
39
|
-
type: z.literal("avatar"),
|
|
40
|
-
endpoint: endpointPathSchema,
|
|
41
|
-
user_public_id: userPublicIdSchema,
|
|
42
|
-
file_size_max: z.number().min(0).optional(),
|
|
43
|
-
allowed_file_types: z.array(z.string()).optional(),
|
|
44
|
-
callback_url: z.string().url().optional(),
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
export const cdnAssetTokenDataDecodedSchema = z.intersection(
|
|
48
|
-
cdnAssetTokenDataSchema,
|
|
49
|
-
JWTData
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
export type CdnAssetTokenData = z.infer<typeof cdnAssetTokenDataSchema>;
|
|
53
|
-
export type CdnAssetTokenDataDecoded = z.infer<
|
|
54
|
-
typeof cdnAssetTokenDataDecodedSchema
|
|
55
|
-
>;
|
|
56
|
-
|
|
57
|
-
///////////////////////////////////
|
|
58
|
-
|
|
59
|
-
export const cdnFeedbackHeaderSchema = z.object({
|
|
60
|
-
authorization: jwtSchema.optional(),
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
export const cdnFeedbackTokenDataSchema = z.object({
|
|
64
|
-
service: authServiceSchema,
|
|
65
|
-
type: authAssetTypeSchema,
|
|
66
|
-
endpoint: endpointPathSchema,
|
|
67
|
-
user_public_id: userPublicIdSchema,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
export const cdnFeedbackTokenDecodedSchema = z.intersection(
|
|
71
|
-
cdnFeedbackTokenDataSchema,
|
|
72
|
-
JWTData
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
export type CdnFeedbackTokenData = z.infer<typeof cdnFeedbackTokenDataSchema>;
|
|
76
|
-
export type CdnFeedbackTokenDataDecoded = z.infer<
|
|
77
|
-
typeof cdnFeedbackTokenDecodedSchema
|
|
78
|
-
>;
|
package/src/types.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { z, type ZodType } from "zod";
|
|
2
|
-
|
|
3
|
-
export const apiSuccess = <T>(schema: ZodType<T>) => schema;
|
|
4
|
-
|
|
5
|
-
export const apiError = <T, U>(code: ZodType<T>, error: ZodType<U>) =>
|
|
6
|
-
z.object({
|
|
7
|
-
code,
|
|
8
|
-
error,
|
|
9
|
-
name: z.literal("APIError"),
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
export const apiErrorData = <T, U, V>(
|
|
13
|
-
code: ZodType<T>,
|
|
14
|
-
error: ZodType<U>,
|
|
15
|
-
data: ZodType<V>
|
|
16
|
-
) =>
|
|
17
|
-
z.object({
|
|
18
|
-
code,
|
|
19
|
-
error,
|
|
20
|
-
name: z.literal("APIError"),
|
|
21
|
-
data,
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
export function jsonStringAs<T extends z.ZodTypeAny>(
|
|
25
|
-
schema: T
|
|
26
|
-
): z.ZodEffects<z.ZodString, z.infer<T>> {
|
|
27
|
-
return z.string().transform((str, ctx) => {
|
|
28
|
-
try {
|
|
29
|
-
return schema.parse(JSON.parse(str));
|
|
30
|
-
} catch {
|
|
31
|
-
ctx.addIssue({
|
|
32
|
-
code: z.ZodIssueCode.custom,
|
|
33
|
-
message: "Invalid JSON",
|
|
34
|
-
});
|
|
35
|
-
return z.NEVER;
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
}
|
package/tests/keys/private.pem
DELETED
package/tests/keys/public.pem
DELETED
package/tests/keys.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
|
|
4
|
-
export const PRIVATE_KEY = fs.readFileSync(
|
|
5
|
-
path.join(import.meta.dirname, "keys/private.pem"),
|
|
6
|
-
"utf-8"
|
|
7
|
-
);
|
|
8
|
-
export const PUBLIC_KEY = fs.readFileSync(
|
|
9
|
-
path.join(import.meta.dirname, "keys/public.pem"),
|
|
10
|
-
"utf-8"
|
|
11
|
-
);
|
package/tests/tsconfig.json
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"noEmit": true,
|
|
5
|
-
"rootDir": "..",
|
|
6
|
-
"types": ["node"],
|
|
7
|
-
"module": "nodenext",
|
|
8
|
-
"moduleResolution": "nodenext"
|
|
9
|
-
},
|
|
10
|
-
"include": ["**/*.ts", "../src/**/*.ts"],
|
|
11
|
-
"exclude": ["../dist", "../node_modules"]
|
|
12
|
-
}
|
package/tests/vitest/jwt.test.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
type CdnFeedbackTokenData,
|
|
4
|
-
JWTSign,
|
|
5
|
-
JWTVerify,
|
|
6
|
-
} from "../../src/index.js";
|
|
7
|
-
import { Hour } from "@darco2903/secondthought";
|
|
8
|
-
import { PRIVATE_KEY, PUBLIC_KEY } from "../keys.js";
|
|
9
|
-
|
|
10
|
-
//////////////////////////
|
|
11
|
-
// Tests for JWT Sign & Verify
|
|
12
|
-
|
|
13
|
-
describe("JWT Sign & Verify", () => {
|
|
14
|
-
it("should resolve after the specified time", async () => {
|
|
15
|
-
const data: CdnFeedbackTokenData = {
|
|
16
|
-
user_public_id: "abcdefgh",
|
|
17
|
-
endpoint: "/test",
|
|
18
|
-
service: "auth",
|
|
19
|
-
type: "avatar",
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const res = await JWTSign(data, PRIVATE_KEY, new Hour(1));
|
|
23
|
-
expect(res.isOk()).toBeTruthy();
|
|
24
|
-
|
|
25
|
-
const signedToken = res._unsafeUnwrap();
|
|
26
|
-
expect(signedToken).toBeTypeOf("string");
|
|
27
|
-
|
|
28
|
-
const verifyRes = await JWTVerify(signedToken, PUBLIC_KEY);
|
|
29
|
-
expect(verifyRes.isOk()).toBeTruthy();
|
|
30
|
-
|
|
31
|
-
const decodedData = verifyRes._unsafeUnwrap();
|
|
32
|
-
expect(decodedData).toMatchObject({
|
|
33
|
-
...data,
|
|
34
|
-
iat: expect.any(Number),
|
|
35
|
-
exp: expect.any(Number),
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
});
|
package/tsconfig.json
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"declaration": true,
|
|
4
|
-
"target": "ES2020",
|
|
5
|
-
"module": "nodenext",
|
|
6
|
-
"outDir": "dist",
|
|
7
|
-
"rootDir": "src",
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"strict": true,
|
|
10
|
-
"moduleResolution": "node16",
|
|
11
|
-
"resolveJsonModule": true
|
|
12
|
-
},
|
|
13
|
-
"include": ["src"]
|
|
14
|
-
}
|