@darco2903/cdn-api 1.0.7-beta.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/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # CDN API
2
+
3
+ ## Description
4
+
5
+ This API is a TypeScript client for the Darco2903 CDN service.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install cdn-api-<version>.tgz
11
+ npm install @ts-rest/core zod@3.22.3
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ Create an instance of the API
17
+
18
+ ```ts
19
+ import { initClient } from "@ts-rest/core";
20
+ import { contract } from "cdn-api";
21
+
22
+ const api = initClient(contract, {
23
+ baseUrl: "https://api.example.com",
24
+ });
25
+ ```
package/TODO.md ADDED
File without changes
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@darco2903/cdn-api",
3
+ "version": "1.0.7-beta.0",
4
+ "description": "",
5
+ "main": "./dist/index.js",
6
+ "type": "module",
7
+ "keywords": [],
8
+ "author": "",
9
+ "license": "ISC",
10
+ "repository": {
11
+ "url": "https://github.com/Darco2903/cdn-api.git"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "exports": {
17
+ ".": "./dist/index.js",
18
+ "./client": "./dist/client.js",
19
+ "./server": "./dist/server.js"
20
+ },
21
+ "dependencies": {
22
+ "@darco2903/auth-api": "2.0.3-pre.0",
23
+ "@ts-rest/core": "^3.52.1",
24
+ "@ts-rest/open-api": "^3.52.1",
25
+ "axios": "^1.12.2",
26
+ "jsonwebtoken": "^9.0.3",
27
+ "neverthrow": "^8.2.0",
28
+ "socket.io-client": "^4.8.1",
29
+ "zod": "^3.25.76"
30
+ },
31
+ "peerDependencies": {
32
+ "@darco2903/secondthought": "^1.1.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/jsonwebtoken": "^9.0.10",
36
+ "@types/node": "^25.4.0",
37
+ "prettier": "^3.8.1",
38
+ "rimraf": "^6.1.3",
39
+ "tsx": "^4.21.0",
40
+ "typescript": "^5.9.3",
41
+ "vitest": "^4.0.18"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc",
45
+ "test": "vitest",
46
+ "clean": "rimraf -g dist darco2903-cdn-api-*.tgz openapi.json",
47
+ "generate:openapi": "tsx tools/generate-openapi.ts"
48
+ }
49
+ }
@@ -0,0 +1,24 @@
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/client.ts ADDED
@@ -0,0 +1,18 @@
1
+ export * from "./common.js";
2
+ import io from "socket.io-client";
3
+ import { initClient } from "@ts-rest/core";
4
+ import contract from "./contract/index.js";
5
+ import type { CdnClientSocket } from "./socket/index.js";
6
+
7
+ export function createClient(origin: string) {
8
+ return initClient(contract, {
9
+ baseUrl: origin,
10
+ credentials: "include",
11
+ });
12
+ }
13
+
14
+ export function createSocket(origin: string): CdnClientSocket {
15
+ return io(origin, {
16
+ autoConnect: true,
17
+ });
18
+ }
package/src/common.ts ADDED
@@ -0,0 +1,4 @@
1
+ export { default as contract } from "./contract/index.js";
2
+ export * from "./socket/index.js";
3
+ export * from "./types/index.js";
4
+ export * from "./consts.js";
package/src/consts.ts ADDED
@@ -0,0 +1,8 @@
1
+ import type { Algorithm } from "jsonwebtoken";
2
+
3
+ export const API_VERSION = "v2";
4
+ export const API_PATH_PREFIX = `/api/${API_VERSION}`;
5
+
6
+ export const JWT_ALGORITHM: Algorithm = "ES256";
7
+
8
+ export const STORAGE_PUBLIC_ID_LENGTH = 8;
@@ -0,0 +1,22 @@
1
+ import { initContract } from "@ts-rest/core";
2
+ import z from "zod";
3
+ import { authHeaderSchema } from "@darco2903/auth-api/client";
4
+ import { apiError, apiSuccess } from "../types.js";
5
+
6
+ const c = initContract();
7
+
8
+ export default c.router({
9
+ access: {
10
+ method: "GET",
11
+ path: "/auth/access",
12
+ headers: authHeaderSchema,
13
+ responses: {
14
+ 200: apiSuccess(
15
+ z.object({
16
+ access: z.boolean(),
17
+ })
18
+ ),
19
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
20
+ },
21
+ },
22
+ });
@@ -0,0 +1,53 @@
1
+ import { initContract, ZodErrorSchema } from "@ts-rest/core";
2
+ import z from "zod";
3
+ import { authHeaderSchema } from "@darco2903/auth-api/client";
4
+ import { apiError, apiSuccess } from "../types.js";
5
+ import { endpointPathSchema } from "../types/index.js";
6
+
7
+ const c = initContract();
8
+
9
+ export default c.router({
10
+ create: {
11
+ method: "POST",
12
+ path: "/endpoint",
13
+ headers: authHeaderSchema,
14
+ body: z.object({
15
+ storage_id: z.string().nonempty(),
16
+ endpoint: endpointPathSchema,
17
+ }),
18
+ responses: {
19
+ 200: apiSuccess(z.null()),
20
+ 400: ZodErrorSchema,
21
+ 401: apiError(z.literal("UNAUTHORIZED"), z.literal("Unauthorized")),
22
+ 403: apiError(z.literal("FORBIDDEN"), z.literal("Forbidden")),
23
+ 404: apiError(
24
+ z.literal("NOT_FOUND"),
25
+ z.literal("Record not found")
26
+ ),
27
+ 409: apiError(
28
+ z.literal("CONFLICT"),
29
+ z.literal("Endpoint already exists")
30
+ ),
31
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
32
+ },
33
+ },
34
+ delete: {
35
+ method: "DELETE",
36
+ path: "/endpoint",
37
+ headers: authHeaderSchema,
38
+ body: z.object({
39
+ endpoint: endpointPathSchema,
40
+ }),
41
+ responses: {
42
+ 200: apiSuccess(z.null()),
43
+ 400: ZodErrorSchema,
44
+ 401: apiError(z.literal("UNAUTHORIZED"), z.literal("Unauthorized")),
45
+ 403: apiError(z.literal("FORBIDDEN"), z.literal("Forbidden")),
46
+ 404: apiError(
47
+ z.literal("NOT_FOUND"),
48
+ z.literal("Endpoint not found")
49
+ ),
50
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
51
+ },
52
+ },
53
+ });
@@ -0,0 +1,27 @@
1
+ import { initContract } from "@ts-rest/core";
2
+ import auth from "./auth.js";
3
+ import endpoint from "./endpoint.js";
4
+ import key from "./key.js";
5
+ import list from "./list.js";
6
+ import record from "./record.js";
7
+ import service from "./service.js";
8
+ import stats from "./stats.js";
9
+ import upload from "./upload.js";
10
+
11
+ const c = initContract();
12
+
13
+ export default c.router(
14
+ {
15
+ auth,
16
+ endpoint,
17
+ ...key,
18
+ list,
19
+ record,
20
+ service,
21
+ stats,
22
+ upload,
23
+ },
24
+ {
25
+ pathPrefix: "/api/v2",
26
+ }
27
+ );
@@ -0,0 +1,19 @@
1
+ import { initContract } from "@ts-rest/core";
2
+ import z from "zod";
3
+ import { apiSuccess } from "../types.js";
4
+
5
+ const c = initContract();
6
+
7
+ export default c.router({
8
+ publicKey: {
9
+ method: "GET",
10
+ path: "/public-key",
11
+ responses: {
12
+ 200: apiSuccess(
13
+ z.object({
14
+ publicKey: z.string(),
15
+ })
16
+ ),
17
+ },
18
+ },
19
+ });
@@ -0,0 +1,30 @@
1
+ import { initContract } from "@ts-rest/core";
2
+ import z from "zod";
3
+ import { authHeaderSchema } from "@darco2903/auth-api/client";
4
+ import { apiError, apiSuccess } from "../types.js";
5
+ import { recordSchema, recordPublicSchema } from "../types/index.js";
6
+
7
+ const c = initContract();
8
+
9
+ export default c.router({
10
+ public: {
11
+ method: "GET",
12
+ path: "/list",
13
+ headers: authHeaderSchema,
14
+ responses: {
15
+ 200: apiSuccess(z.array(recordPublicSchema)),
16
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
17
+ },
18
+ },
19
+ admin: {
20
+ method: "GET",
21
+ path: "/list/admin",
22
+ headers: authHeaderSchema,
23
+ responses: {
24
+ 200: apiSuccess(z.array(recordSchema)),
25
+ 401: apiError(z.literal("UNAUTHORIZED"), z.literal("Unauthorized")),
26
+ 403: apiError(z.literal("FORBIDDEN"), z.literal("Forbidden")),
27
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
28
+ },
29
+ },
30
+ });
@@ -0,0 +1,82 @@
1
+ import { initContract, ZodErrorSchema } from "@ts-rest/core";
2
+ import z from "zod";
3
+ import { authHeaderSchema } from "@darco2903/auth-api/client";
4
+ import { apiError, apiSuccess } from "../types.js";
5
+ import { recordSchema } from "../types/index.js";
6
+
7
+ const c = initContract();
8
+
9
+ export default c.router({
10
+ get: {
11
+ method: "GET",
12
+ path: "/record/:storage_id",
13
+ headers: authHeaderSchema,
14
+ responses: {
15
+ 200: apiSuccess(recordSchema),
16
+ 401: apiError(z.literal("UNAUTHORIZED"), z.literal("Unauthorized")),
17
+ 403: apiError(z.literal("FORBIDDEN"), z.literal("Forbidden")),
18
+ 404: apiError(
19
+ z.literal("NOT_FOUND"),
20
+ z.literal("Record not found")
21
+ ),
22
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
23
+ },
24
+ },
25
+ update: {
26
+ method: "POST",
27
+ path: "/record/:storage_id",
28
+ headers: authHeaderSchema,
29
+ body: z.union([
30
+ z.object({
31
+ filename: z.string().max(128),
32
+ role: z.number().gte(0).optional(),
33
+ active: z.boolean().optional(),
34
+ visible: z.boolean().optional(),
35
+ }),
36
+ z.object({
37
+ filename: z.string().max(128).optional(),
38
+ role: z.number().gte(0),
39
+ active: z.boolean().optional(),
40
+ visible: z.boolean().optional(),
41
+ }),
42
+ z.object({
43
+ filename: z.string().max(128).optional(),
44
+ role: z.number().gte(0).optional(),
45
+ active: z.boolean(),
46
+ visible: z.boolean().optional(),
47
+ }),
48
+ z.object({
49
+ filename: z.string().max(128).optional(),
50
+ role: z.number().gte(0).optional(),
51
+ active: z.boolean().optional(),
52
+ visible: z.boolean(),
53
+ }),
54
+ ]),
55
+ responses: {
56
+ 200: apiSuccess(z.null()),
57
+ 400: ZodErrorSchema,
58
+ 401: apiError(z.literal("UNAUTHORIZED"), z.literal("Unauthorized")),
59
+ 403: apiError(z.literal("FORBIDDEN"), z.literal("Forbidden")),
60
+ 404: apiError(
61
+ z.literal("NOT_FOUND"),
62
+ z.literal("Record not found")
63
+ ),
64
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
65
+ },
66
+ },
67
+ delete: {
68
+ method: "DELETE",
69
+ path: "/record/:storage_id",
70
+ headers: authHeaderSchema,
71
+ responses: {
72
+ 200: apiSuccess(z.null()),
73
+ 401: apiError(z.literal("UNAUTHORIZED"), z.literal("Unauthorized")),
74
+ 403: apiError(z.literal("FORBIDDEN"), z.literal("Forbidden")),
75
+ 404: apiError(
76
+ z.literal("NOT_FOUND"),
77
+ z.literal("Record not found")
78
+ ),
79
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
80
+ },
81
+ },
82
+ });
@@ -0,0 +1,44 @@
1
+ import { initContract, ZodErrorSchema } from "@ts-rest/core";
2
+ import z from "zod";
3
+ import { apiError, apiSuccess } from "../types.js";
4
+ import { cdnHeaderSchema } from "../types/index.js";
5
+
6
+ const c = initContract();
7
+
8
+ export default c.router({
9
+ update: {
10
+ method: "POST",
11
+ path: "/service/asset",
12
+ headers: cdnHeaderSchema,
13
+ contentType: "multipart/form-data",
14
+ body: z.object({}),
15
+ responses: {
16
+ 200: apiSuccess(z.null()),
17
+ 400: apiError(z.literal("BAD_REQUEST"), z.string()),
18
+ 401: apiError(
19
+ z.literal("UNAUTHORIZED"),
20
+ z.literal("Invalid CDN token")
21
+ ),
22
+ 429: apiError(z.literal("TOO_MANY_REQUESTS"), z.string()),
23
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
24
+ },
25
+ },
26
+ delete: {
27
+ method: "DELETE",
28
+ path: "/service/asset",
29
+ headers: cdnHeaderSchema,
30
+ responses: {
31
+ 200: apiSuccess(z.null()),
32
+ 400: ZodErrorSchema,
33
+ 401: apiError(
34
+ z.literal("UNAUTHORIZED"),
35
+ z.literal("Invalid CDN token")
36
+ ),
37
+ 404: apiError(
38
+ z.literal("NOT_FOUND"),
39
+ z.literal("Service asset not found")
40
+ ),
41
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
42
+ },
43
+ },
44
+ });
@@ -0,0 +1,36 @@
1
+ import { initContract } from "@ts-rest/core";
2
+ import z from "zod";
3
+ import { apiError, apiSuccess } from "../types.js";
4
+ import { statsGlobalSchema } from "../types/index.js";
5
+
6
+ const c = initContract();
7
+
8
+ export default c.router({
9
+ global: {
10
+ method: "GET",
11
+ path: "/stats",
12
+ responses: {
13
+ 200: apiSuccess(statsGlobalSchema),
14
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
15
+ },
16
+ },
17
+ // globalAdmin: {
18
+ // method: "GET",
19
+ // path: "/stats/admin",
20
+ // responses: {
21
+ // 200: apiSuccess(statsGlobalSchema),
22
+ // 401: apiError(z.literal("UNAUTHORIZED"), z.literal("Unauthorized")),
23
+ // 403: apiError(z.literal("FORBIDDEN"), z.literal("Forbidden")),
24
+ // 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
25
+ // },
26
+ // },
27
+ // user: {
28
+ // method: "GET",
29
+ // path: "/stats/:public_id",
30
+ // headers: authHeaderSchema,
31
+ // responses: {
32
+ // 200: apiSuccess(statsGlobalSchema),
33
+ // 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
34
+ // },
35
+ // },
36
+ });
@@ -0,0 +1,82 @@
1
+ import { initContract, ZodErrorSchema } from "@ts-rest/core";
2
+ import z from "zod";
3
+ import { authHeaderSchema } from "@darco2903/auth-api/client";
4
+ import { apiError, apiSuccess, jsonStringAs } from "../types.js";
5
+ import { uploadDataSchema, uploadInitSchema } from "../types/index.js";
6
+
7
+ const c = initContract();
8
+
9
+ export default c.router({
10
+ upload: {
11
+ method: "POST",
12
+ path: "/upload",
13
+ headers: authHeaderSchema,
14
+ contentType: "multipart/form-data",
15
+ body: z.object({
16
+ file: z.any(),
17
+ data: jsonStringAs(uploadDataSchema),
18
+ }),
19
+ responses: {
20
+ 200: apiSuccess(z.null()),
21
+ 400: z.union([
22
+ ZodErrorSchema,
23
+ apiError(z.literal("BAD_REQUEST"), z.string()),
24
+ ]),
25
+ 401: apiError(z.literal("UNAUTHORIZED"), z.literal("Unauthorized")),
26
+ 403: apiError(z.literal("FORBIDDEN"), z.literal("Forbidden")),
27
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
28
+ },
29
+ },
30
+ uploadInit: {
31
+ method: "POST",
32
+ path: "/upload/init",
33
+ body: uploadInitSchema,
34
+ responses: {
35
+ 200: apiSuccess(
36
+ z.object({
37
+ uploadId: z.string(),
38
+ })
39
+ ),
40
+ 400: z.union([
41
+ ZodErrorSchema,
42
+ apiError(z.literal("BAD_REQUEST"), z.string()),
43
+ ]),
44
+ 401: apiError(z.literal("UNAUTHORIZED"), z.literal("Unauthorized")),
45
+ 403: apiError(z.literal("FORBIDDEN"), z.literal("Forbidden")),
46
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
47
+ },
48
+ },
49
+ uploadPart: {
50
+ method: "POST",
51
+ path: "/upload/part/:upload_id/:part",
52
+ contentType: "multipart/form-data",
53
+ body: z.object({
54
+ file: z.any(),
55
+ }),
56
+ responses: {
57
+ 200: apiSuccess(z.null()),
58
+ 400: z.union([
59
+ ZodErrorSchema,
60
+ apiError(z.literal("BAD_REQUEST"), z.string()),
61
+ ]),
62
+ 401: apiError(z.literal("UNAUTHORIZED"), z.literal("Unauthorized")),
63
+ 403: apiError(z.literal("FORBIDDEN"), z.literal("Forbidden")),
64
+ 404: apiError(z.literal("NOT_FOUND"), z.string()),
65
+ 409: apiError(z.literal("CONFLICT"), z.string()),
66
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
67
+ },
68
+ },
69
+ uploadEnd: {
70
+ method: "POST",
71
+ path: "/upload/end/:upload_id",
72
+ body: z.undefined(),
73
+ responses: {
74
+ 200: apiSuccess(z.null()),
75
+ 400: ZodErrorSchema,
76
+ 401: apiError(z.literal("UNAUTHORIZED"), z.literal("Unauthorized")),
77
+ 403: apiError(z.literal("FORBIDDEN"), z.literal("Forbidden")),
78
+ 404: apiError(z.literal("NOT_FOUND"), z.string()),
79
+ 500: apiError(z.literal("INTERNAL_SERVER_ERROR"), z.string()),
80
+ },
81
+ },
82
+ });
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./client.js";
2
+ export * from "./server.js";
package/src/server.ts ADDED
@@ -0,0 +1,89 @@
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
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./interface/index.js";
2
+ export * from "./types.js";
@@ -0,0 +1,12 @@
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 {}
@@ -0,0 +1,7 @@
1
+ export interface SocketClientToServerTemplate {
2
+ ping: (message: string, callback: (message: string) => void) => void;
3
+ }
4
+
5
+ export interface SocketServerToClientTemplate {
6
+ pong: (message: string) => void;
7
+ }
@@ -0,0 +1,7 @@
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>;
@@ -0,0 +1,7 @@
1
+ import z from "zod";
2
+
3
+ const jwtSchema = z.string().startsWith("Bearer ");
4
+
5
+ export const cdnHeaderSchema = z.object({
6
+ authorization: jwtSchema,
7
+ });