@wrytes/wrytes-api 0.0.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/package.json +122 -0
- package/pkg/index.d.ts +64 -0
- package/pkg/index.js +202 -0
package/package.json
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wrytes/wrytes-api",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"author": "Wrytes",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "pkg/index.js",
|
|
7
|
+
"types": "pkg/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"pkg"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://api.wrytes.io",
|
|
12
|
+
"repository": {
|
|
13
|
+
"url": "git+https://github.com/wrytes/wrytes-api.git"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "nest build",
|
|
17
|
+
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
18
|
+
"start": "nest start",
|
|
19
|
+
"dev": "nest start --watch",
|
|
20
|
+
"start:dev": "nest start --watch",
|
|
21
|
+
"start:debug": "nest start --debug --watch",
|
|
22
|
+
"start:prod": "node dist/main.js",
|
|
23
|
+
"lint": "eslint \"src/**/*.ts\" --fix",
|
|
24
|
+
"test": "jest",
|
|
25
|
+
"test:watch": "jest --watch",
|
|
26
|
+
"test:cov": "jest --coverage",
|
|
27
|
+
"test:e2e": "jest --config ./test/jest-e2e.json",
|
|
28
|
+
"infra:up": "docker stack deploy -c stack.testing.yml wrytes-api",
|
|
29
|
+
"infra:down": "docker stack remove wrytes-api",
|
|
30
|
+
"npm:build": "npx tsup",
|
|
31
|
+
"npm:publish": "npm publish --access public",
|
|
32
|
+
"db:generate": "prisma generate",
|
|
33
|
+
"db:push": "prisma db push",
|
|
34
|
+
"db:migrate": "prisma migrate dev",
|
|
35
|
+
"db:migrate:deploy": "prisma migrate deploy",
|
|
36
|
+
"db:studio": "prisma studio",
|
|
37
|
+
"db:reset": "prisma migrate reset",
|
|
38
|
+
"db:grant-admin": "ts-node --skip-project --compiler-options '{\"module\":\"commonjs\",\"moduleResolution\":\"node\",\"esModuleInterop\":true}' --transpile-only prisma/scripts/grant-admin.ts",
|
|
39
|
+
"db:list-users": "ts-node --skip-project --compiler-options '{\"module\":\"commonjs\",\"moduleResolution\":\"node\",\"esModuleInterop\":true}' --transpile-only prisma/scripts/list-users.ts",
|
|
40
|
+
"db:remove-user": "ts-node --skip-project --compiler-options '{\"module\":\"commonjs\",\"moduleResolution\":\"node\",\"esModuleInterop\":true}' --transpile-only prisma/scripts/remove-user.ts",
|
|
41
|
+
"script:deploy-safe": "ts-node --skip-project --compiler-options '{\"module\":\"commonjs\",\"moduleResolution\":\"node\",\"esModuleInterop\":true}' --transpile-only scripts/deploy-safe.ts"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@anthropic-ai/sdk": "^0.39.0",
|
|
45
|
+
"@nestjs/bullmq": "^11.0.4",
|
|
46
|
+
"@nestjs/common": "^10.0.0",
|
|
47
|
+
"@nestjs/config": "^3.2.3",
|
|
48
|
+
"@nestjs/core": "^10.0.0",
|
|
49
|
+
"@nestjs/event-emitter": "^2.0.0",
|
|
50
|
+
"@nestjs/platform-express": "^10.0.0",
|
|
51
|
+
"@nestjs/schedule": "^4.0.0",
|
|
52
|
+
"@nestjs/swagger": "^7.3.1",
|
|
53
|
+
"@nestjs/terminus": "^10.2.3",
|
|
54
|
+
"@nestjs/throttler": "^6.0.0",
|
|
55
|
+
"@prisma/client": "^6.13.0",
|
|
56
|
+
"@safe-global/protocol-kit": "^7.0.0",
|
|
57
|
+
"@wrytes/deribit-api-client": "^1.0.2",
|
|
58
|
+
"bcrypt": "^5.1.1",
|
|
59
|
+
"bullmq": "^5.73.0",
|
|
60
|
+
"class-transformer": "^0.5.1",
|
|
61
|
+
"class-validator": "^0.14.2",
|
|
62
|
+
"ioredis": "^5.4.1",
|
|
63
|
+
"joi": "^17.13.3",
|
|
64
|
+
"nanoid": "^3.3.7",
|
|
65
|
+
"nestjs-pino": "^4.1.0",
|
|
66
|
+
"nestjs-telegraf": "^2.4.0",
|
|
67
|
+
"openai": "^6.34.0",
|
|
68
|
+
"pdf-parse": "1.1.1",
|
|
69
|
+
"pino": "^10.3.1",
|
|
70
|
+
"pino-http": "^11.0.0",
|
|
71
|
+
"pino-pretty": "^13.0.0",
|
|
72
|
+
"prisma": "^6.13.0",
|
|
73
|
+
"reflect-metadata": "^0.2.0",
|
|
74
|
+
"rxjs": "^7.8.1",
|
|
75
|
+
"telegraf": "^4.16.3",
|
|
76
|
+
"viem": "^2.47.10"
|
|
77
|
+
},
|
|
78
|
+
"devDependencies": {
|
|
79
|
+
"@nestjs/cli": "^10.0.0",
|
|
80
|
+
"@nestjs/schematics": "^10.0.0",
|
|
81
|
+
"@nestjs/testing": "^10.0.0",
|
|
82
|
+
"@types/bcrypt": "^5.0.2",
|
|
83
|
+
"@types/express": "^4.17.17",
|
|
84
|
+
"@types/jest": "^29.5.2",
|
|
85
|
+
"@types/multer": "^2.1.0",
|
|
86
|
+
"@types/node": "^24.1.0",
|
|
87
|
+
"@types/pdf-parse": "^1.1.5",
|
|
88
|
+
"@types/supertest": "^6.0.0",
|
|
89
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
90
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
91
|
+
"eslint": "^8.42.0",
|
|
92
|
+
"eslint-config-prettier": "^9.0.0",
|
|
93
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
94
|
+
"jest": "^29.5.0",
|
|
95
|
+
"prettier": "^3.0.0",
|
|
96
|
+
"source-map-support": "^0.5.21",
|
|
97
|
+
"supertest": "^6.3.3",
|
|
98
|
+
"ts-jest": "^29.1.0",
|
|
99
|
+
"ts-loader": "^9.4.3",
|
|
100
|
+
"ts-node": "^10.9.1",
|
|
101
|
+
"tsconfig-paths": "^4.2.0",
|
|
102
|
+
"tsup": "^8.5.1",
|
|
103
|
+
"typescript": "^5.1.3"
|
|
104
|
+
},
|
|
105
|
+
"jest": {
|
|
106
|
+
"moduleFileExtensions": [
|
|
107
|
+
"js",
|
|
108
|
+
"json",
|
|
109
|
+
"ts"
|
|
110
|
+
],
|
|
111
|
+
"rootDir": "src",
|
|
112
|
+
"testRegex": ".*\\.spec\\.ts$",
|
|
113
|
+
"transform": {
|
|
114
|
+
"^.+\\.(t|j)s$": "ts-jest"
|
|
115
|
+
},
|
|
116
|
+
"collectCoverageFrom": [
|
|
117
|
+
"**/*.(t|j)s"
|
|
118
|
+
],
|
|
119
|
+
"coverageDirectory": "../coverage",
|
|
120
|
+
"testEnvironment": "node"
|
|
121
|
+
}
|
|
122
|
+
}
|
package/pkg/index.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as _nestjs_common from '@nestjs/common';
|
|
2
|
+
import { DynamicModule, CanActivate, ExecutionContext } from '@nestjs/common';
|
|
3
|
+
import { Reflector } from '@nestjs/core';
|
|
4
|
+
|
|
5
|
+
interface WrytesUserProfile {
|
|
6
|
+
firstName: string | null;
|
|
7
|
+
lastName: string | null;
|
|
8
|
+
businessName: string | null;
|
|
9
|
+
isVerified: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface WrytesUserWallet {
|
|
12
|
+
address: string;
|
|
13
|
+
label: string | null;
|
|
14
|
+
}
|
|
15
|
+
interface WrytesUser {
|
|
16
|
+
id: string;
|
|
17
|
+
telegramHandle: string | null;
|
|
18
|
+
notificationsEnabled: boolean;
|
|
19
|
+
scopes: string[];
|
|
20
|
+
wallets: WrytesUserWallet[];
|
|
21
|
+
profile: WrytesUserProfile | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
declare const IS_PUBLIC_KEY = "isPublic";
|
|
25
|
+
declare const SCOPES_KEY = "scopes";
|
|
26
|
+
declare const Public: () => _nestjs_common.CustomDecorator<string>;
|
|
27
|
+
declare const RequireScopes: (...scopes: string[]) => _nestjs_common.CustomDecorator<string>;
|
|
28
|
+
declare const CurrentUser: (...dataOrPipes: unknown[]) => ParameterDecorator;
|
|
29
|
+
|
|
30
|
+
interface WrytesAuthModuleOptions {
|
|
31
|
+
wrytesApiUrl: string;
|
|
32
|
+
global?: boolean;
|
|
33
|
+
}
|
|
34
|
+
declare class WrytesAuthModule {
|
|
35
|
+
static forRoot(options: WrytesAuthModuleOptions): DynamicModule;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
declare const WRYTES_API_URL = "WRYTES_API_URL";
|
|
39
|
+
declare class AuthProxyService {
|
|
40
|
+
private readonly wrytesApiUrl;
|
|
41
|
+
private readonly logger;
|
|
42
|
+
private readonly cache;
|
|
43
|
+
private readonly ttlMs;
|
|
44
|
+
constructor(wrytesApiUrl: string);
|
|
45
|
+
resolve(rawToken: string): Promise<WrytesUser>;
|
|
46
|
+
invalidate(rawToken: string): void;
|
|
47
|
+
private evict;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
declare class AuthProxyGuard implements CanActivate {
|
|
51
|
+
private readonly authProxy;
|
|
52
|
+
private readonly reflector;
|
|
53
|
+
constructor(authProxy: AuthProxyService, reflector: Reflector);
|
|
54
|
+
canActivate(ctx: ExecutionContext): Promise<boolean>;
|
|
55
|
+
private extractToken;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
declare class ScopesGuard implements CanActivate {
|
|
59
|
+
private readonly reflector;
|
|
60
|
+
constructor(reflector: Reflector);
|
|
61
|
+
canActivate(ctx: ExecutionContext): boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { AuthProxyGuard, AuthProxyService, CurrentUser, IS_PUBLIC_KEY, Public, RequireScopes, SCOPES_KEY, ScopesGuard, WRYTES_API_URL, WrytesAuthModule, type WrytesAuthModuleOptions, type WrytesUser, type WrytesUserProfile, type WrytesUserWallet };
|
package/pkg/index.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
20
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
21
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
22
|
+
if (decorator = decorators[i])
|
|
23
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
24
|
+
if (kind && result) __defProp(target, key, result);
|
|
25
|
+
return result;
|
|
26
|
+
};
|
|
27
|
+
var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
28
|
+
|
|
29
|
+
// exports/index.ts
|
|
30
|
+
var index_exports = {};
|
|
31
|
+
__export(index_exports, {
|
|
32
|
+
AuthProxyGuard: () => AuthProxyGuard,
|
|
33
|
+
AuthProxyService: () => AuthProxyService,
|
|
34
|
+
CurrentUser: () => CurrentUser,
|
|
35
|
+
IS_PUBLIC_KEY: () => IS_PUBLIC_KEY,
|
|
36
|
+
Public: () => Public,
|
|
37
|
+
RequireScopes: () => RequireScopes,
|
|
38
|
+
SCOPES_KEY: () => SCOPES_KEY,
|
|
39
|
+
ScopesGuard: () => ScopesGuard,
|
|
40
|
+
WRYTES_API_URL: () => WRYTES_API_URL,
|
|
41
|
+
WrytesAuthModule: () => WrytesAuthModule
|
|
42
|
+
});
|
|
43
|
+
module.exports = __toCommonJS(index_exports);
|
|
44
|
+
|
|
45
|
+
// exports/decorators.ts
|
|
46
|
+
var import_common = require("@nestjs/common");
|
|
47
|
+
var IS_PUBLIC_KEY = "isPublic";
|
|
48
|
+
var SCOPES_KEY = "scopes";
|
|
49
|
+
var Public = () => (0, import_common.SetMetadata)(IS_PUBLIC_KEY, true);
|
|
50
|
+
var RequireScopes = (...scopes) => (0, import_common.SetMetadata)(SCOPES_KEY, scopes);
|
|
51
|
+
var CurrentUser = (0, import_common.createParamDecorator)(
|
|
52
|
+
(_data, ctx) => ctx.switchToHttp().getRequest().user
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// exports/auth-proxy.module.ts
|
|
56
|
+
var import_common5 = require("@nestjs/common");
|
|
57
|
+
var import_core = require("@nestjs/core");
|
|
58
|
+
|
|
59
|
+
// exports/auth-proxy.service.ts
|
|
60
|
+
var import_common2 = require("@nestjs/common");
|
|
61
|
+
var import_crypto = require("crypto");
|
|
62
|
+
var WRYTES_API_URL = "WRYTES_API_URL";
|
|
63
|
+
var AuthProxyService = class {
|
|
64
|
+
constructor(wrytesApiUrl) {
|
|
65
|
+
this.wrytesApiUrl = wrytesApiUrl;
|
|
66
|
+
this.logger = new import_common2.Logger(AuthProxyService.name);
|
|
67
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
68
|
+
this.ttlMs = 5 * 60 * 1e3;
|
|
69
|
+
}
|
|
70
|
+
async resolve(rawToken) {
|
|
71
|
+
const key = (0, import_crypto.createHash)("sha256").update(rawToken).digest("hex");
|
|
72
|
+
const cached = this.cache.get(key);
|
|
73
|
+
if (cached && cached.expiresAt > Date.now()) return cached.user;
|
|
74
|
+
if (cached) this.cache.delete(key);
|
|
75
|
+
const isApiKey = rawToken.startsWith("rw_prod_");
|
|
76
|
+
const headers = isApiKey ? { "x-api-key": rawToken } : { authorization: `Bearer ${rawToken}` };
|
|
77
|
+
let res;
|
|
78
|
+
try {
|
|
79
|
+
res = await fetch(`${this.wrytesApiUrl}/auth/me`, {
|
|
80
|
+
headers,
|
|
81
|
+
signal: AbortSignal.timeout(5e3)
|
|
82
|
+
});
|
|
83
|
+
} catch (err) {
|
|
84
|
+
this.logger.error(`/auth/me unreachable: ${err?.message}`);
|
|
85
|
+
throw new import_common2.UnauthorizedException("Auth service unavailable");
|
|
86
|
+
}
|
|
87
|
+
if (!res.ok) {
|
|
88
|
+
this.logger.warn(`/auth/me \u2192 ${res.status}`);
|
|
89
|
+
throw new import_common2.UnauthorizedException();
|
|
90
|
+
}
|
|
91
|
+
const user = await res.json();
|
|
92
|
+
this.cache.set(key, { user, expiresAt: Date.now() + this.ttlMs });
|
|
93
|
+
if (this.cache.size > 2e3) this.evict();
|
|
94
|
+
return user;
|
|
95
|
+
}
|
|
96
|
+
/** Force-expire a token from the cache (e.g. on logout) */
|
|
97
|
+
invalidate(rawToken) {
|
|
98
|
+
this.cache.delete((0, import_crypto.createHash)("sha256").update(rawToken).digest("hex"));
|
|
99
|
+
}
|
|
100
|
+
evict() {
|
|
101
|
+
const now = Date.now();
|
|
102
|
+
for (const [k, v] of this.cache) {
|
|
103
|
+
if (v.expiresAt <= now) this.cache.delete(k);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
AuthProxyService = __decorateClass([
|
|
108
|
+
(0, import_common2.Injectable)(),
|
|
109
|
+
__decorateParam(0, (0, import_common2.Inject)(WRYTES_API_URL))
|
|
110
|
+
], AuthProxyService);
|
|
111
|
+
|
|
112
|
+
// exports/auth-proxy.guard.ts
|
|
113
|
+
var import_common3 = require("@nestjs/common");
|
|
114
|
+
var AuthProxyGuard = class {
|
|
115
|
+
constructor(authProxy, reflector) {
|
|
116
|
+
this.authProxy = authProxy;
|
|
117
|
+
this.reflector = reflector;
|
|
118
|
+
}
|
|
119
|
+
async canActivate(ctx) {
|
|
120
|
+
const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [
|
|
121
|
+
ctx.getHandler(),
|
|
122
|
+
ctx.getClass()
|
|
123
|
+
]);
|
|
124
|
+
if (isPublic) return true;
|
|
125
|
+
const req = ctx.switchToHttp().getRequest();
|
|
126
|
+
const token = this.extractToken(req);
|
|
127
|
+
if (!token) throw new import_common3.UnauthorizedException();
|
|
128
|
+
const user = await this.authProxy.resolve(token);
|
|
129
|
+
req["user"] = user;
|
|
130
|
+
req["scopes"] = user.scopes;
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
extractToken(req) {
|
|
134
|
+
const auth = req["headers"]?.["authorization"];
|
|
135
|
+
if (auth?.startsWith("Bearer ")) return auth.slice(7);
|
|
136
|
+
const key = req["headers"]?.["x-api-key"];
|
|
137
|
+
if (key) return key;
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
AuthProxyGuard = __decorateClass([
|
|
142
|
+
(0, import_common3.Injectable)()
|
|
143
|
+
], AuthProxyGuard);
|
|
144
|
+
|
|
145
|
+
// exports/scopes.guard.ts
|
|
146
|
+
var import_common4 = require("@nestjs/common");
|
|
147
|
+
var ScopesGuard = class {
|
|
148
|
+
constructor(reflector) {
|
|
149
|
+
this.reflector = reflector;
|
|
150
|
+
}
|
|
151
|
+
canActivate(ctx) {
|
|
152
|
+
const required = this.reflector.getAllAndOverride(SCOPES_KEY, [
|
|
153
|
+
ctx.getHandler(),
|
|
154
|
+
ctx.getClass()
|
|
155
|
+
]);
|
|
156
|
+
if (!required?.length) return true;
|
|
157
|
+
const scopes = ctx.switchToHttp().getRequest()["scopes"] ?? [];
|
|
158
|
+
if (scopes.includes("ADMIN")) return true;
|
|
159
|
+
return required.every((s) => scopes.includes(s));
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
ScopesGuard = __decorateClass([
|
|
163
|
+
(0, import_common4.Injectable)()
|
|
164
|
+
], ScopesGuard);
|
|
165
|
+
|
|
166
|
+
// exports/auth-proxy.module.ts
|
|
167
|
+
var WrytesAuthModule = class {
|
|
168
|
+
static forRoot(options) {
|
|
169
|
+
const applyGlobally = options.global !== false;
|
|
170
|
+
return {
|
|
171
|
+
module: WrytesAuthModule,
|
|
172
|
+
global: true,
|
|
173
|
+
providers: [
|
|
174
|
+
{ provide: WRYTES_API_URL, useValue: options.wrytesApiUrl },
|
|
175
|
+
AuthProxyService,
|
|
176
|
+
AuthProxyGuard,
|
|
177
|
+
ScopesGuard,
|
|
178
|
+
...applyGlobally ? [
|
|
179
|
+
{ provide: import_core.APP_GUARD, useClass: AuthProxyGuard },
|
|
180
|
+
{ provide: import_core.APP_GUARD, useClass: ScopesGuard }
|
|
181
|
+
] : []
|
|
182
|
+
],
|
|
183
|
+
exports: [AuthProxyService, AuthProxyGuard, ScopesGuard]
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
WrytesAuthModule = __decorateClass([
|
|
188
|
+
(0, import_common5.Module)({})
|
|
189
|
+
], WrytesAuthModule);
|
|
190
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
191
|
+
0 && (module.exports = {
|
|
192
|
+
AuthProxyGuard,
|
|
193
|
+
AuthProxyService,
|
|
194
|
+
CurrentUser,
|
|
195
|
+
IS_PUBLIC_KEY,
|
|
196
|
+
Public,
|
|
197
|
+
RequireScopes,
|
|
198
|
+
SCOPES_KEY,
|
|
199
|
+
ScopesGuard,
|
|
200
|
+
WRYTES_API_URL,
|
|
201
|
+
WrytesAuthModule
|
|
202
|
+
});
|