@merkl/api 0.20.104 → 0.20.106

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.
@@ -44,9 +44,7 @@ export declare const ProtocolController: Elysia<"/protocols", false, {
44
44
  };
45
45
  };
46
46
  };
47
- };
48
- } & {
49
- protocols: {
47
+ } & {
50
48
  count: {
51
49
  get: {
52
50
  body: unknown;
@@ -67,9 +65,7 @@ export declare const ProtocolController: Elysia<"/protocols", false, {
67
65
  };
68
66
  };
69
67
  };
70
- };
71
- } & {
72
- protocols: {
68
+ } & {
73
69
  ":id": {
74
70
  get: {
75
71
  body: unknown;
@@ -93,9 +89,7 @@ export declare const ProtocolController: Elysia<"/protocols", false, {
93
89
  };
94
90
  };
95
91
  };
96
- };
97
- } & {
98
- protocols: {
92
+ } & {
99
93
  ":id": {
100
94
  patch: {
101
95
  body: {
@@ -123,9 +117,7 @@ export declare const ProtocolController: Elysia<"/protocols", false, {
123
117
  };
124
118
  };
125
119
  };
126
- };
127
- } & {
128
- protocols: {
120
+ } & {
129
121
  index: {
130
122
  post: {
131
123
  body: {
@@ -153,6 +145,77 @@ export declare const ProtocolController: Elysia<"/protocols", false, {
153
145
  };
154
146
  };
155
147
  };
148
+ } & {
149
+ webhooks: {
150
+ notion: {
151
+ post: {
152
+ body: {
153
+ data: {
154
+ properties: {
155
+ id: {
156
+ title: {
157
+ text: {
158
+ content: string;
159
+ };
160
+ }[];
161
+ };
162
+ name: {
163
+ rich_text: {
164
+ text: {
165
+ content: string;
166
+ };
167
+ }[];
168
+ };
169
+ url: {
170
+ url: string;
171
+ };
172
+ description: {
173
+ rich_text: {
174
+ text: {
175
+ content: string;
176
+ };
177
+ }[];
178
+ };
179
+ tags: {
180
+ rich_text: {
181
+ text: {
182
+ content: string;
183
+ };
184
+ }[];
185
+ };
186
+ icon: {
187
+ files: ({
188
+ file: {
189
+ url: string;
190
+ };
191
+ name: string;
192
+ } | {
193
+ external: {
194
+ url: string;
195
+ };
196
+ })[];
197
+ };
198
+ };
199
+ };
200
+ };
201
+ params: {};
202
+ query: unknown;
203
+ headers: {
204
+ authorization: string;
205
+ };
206
+ response: {
207
+ 200: {
208
+ id: string;
209
+ name: string;
210
+ url: string;
211
+ description: string;
212
+ tags: string[];
213
+ icon: string;
214
+ };
215
+ };
216
+ };
217
+ };
218
+ };
156
219
  };
157
220
  }, {
158
221
  derive: {};
@@ -1,6 +1,6 @@
1
1
  import { AuthorizationHeadersDto, BackOfficeGuard } from "@/guards/BackOffice.guard";
2
2
  import Elysia, { t } from "elysia";
3
- import { CreateProtocolDto, GetProtocolsQueryDto, ProtocolIdDto, ProtocolResourceDto, UpdateProtocolDto, } from "./protocol.model";
3
+ import { CreateProtocolDto, GetProtocolsQueryDto, NotionWebhookAddProtocolDto, ProtocolIdDto, ProtocolResourceDto, UpdateProtocolDto, } from "./protocol.model";
4
4
  import { ProtocolService } from "./protocol.service";
5
5
  // ─── Protocols Controller ────────────────────────────────────────────────────
6
6
  export const ProtocolController = new Elysia({ prefix: "/protocols", detail: { tags: ["Protocols"] } })
@@ -36,4 +36,18 @@ export const ProtocolController = new Elysia({ prefix: "/protocols", detail: { t
36
36
  headers: AuthorizationHeadersDto,
37
37
  beforeHandle: BackOfficeGuard,
38
38
  detail: { hide: true },
39
- });
39
+ })
40
+ .group("/webhooks", app => app.post("/notion", async ({ body }) => ProtocolService.upsert({
41
+ id: body.data.properties.id.title[0].text.content,
42
+ description: body.data.properties.description.rich_text[0].text.content,
43
+ icon: "file" in body.data.properties.icon.files[0]
44
+ ? body.data.properties.icon.files[0].file.url
45
+ : body.data.properties.icon.files[0].external.url,
46
+ name: body.data.properties.name.rich_text[0].text.content,
47
+ tags: body.data.properties.tags.rich_text[0]?.text.content.split(","),
48
+ url: body.data.properties.url.url,
49
+ }), {
50
+ headers: AuthorizationHeadersDto,
51
+ beforeHandle: BackOfficeGuard,
52
+ body: NotionWebhookAddProtocolDto,
53
+ }));
@@ -49,6 +49,55 @@ export declare const CreateProtocolDto: import("@sinclair/typebox").TObject<{
49
49
  export declare const ProtocolIdDto: import("@sinclair/typebox").TObject<{
50
50
  id: import("@sinclair/typebox").TString;
51
51
  }>;
52
+ export declare const NotionWebhookAddProtocolDto: import("@sinclair/typebox").TObject<{
53
+ data: import("@sinclair/typebox").TObject<{
54
+ properties: import("@sinclair/typebox").TObject<{
55
+ id: import("@sinclair/typebox").TObject<{
56
+ title: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
57
+ text: import("@sinclair/typebox").TObject<{
58
+ content: import("@sinclair/typebox").TString;
59
+ }>;
60
+ }>>;
61
+ }>;
62
+ description: import("@sinclair/typebox").TObject<{
63
+ rich_text: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
64
+ text: import("@sinclair/typebox").TObject<{
65
+ content: import("@sinclair/typebox").TString;
66
+ }>;
67
+ }>>;
68
+ }>;
69
+ icon: import("@sinclair/typebox").TObject<{
70
+ files: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
71
+ name: import("@sinclair/typebox").TString;
72
+ file: import("@sinclair/typebox").TObject<{
73
+ url: import("@sinclair/typebox").TString;
74
+ }>;
75
+ }>, import("@sinclair/typebox").TObject<{
76
+ external: import("@sinclair/typebox").TObject<{
77
+ url: import("@sinclair/typebox").TString;
78
+ }>;
79
+ }>]>>;
80
+ }>;
81
+ name: import("@sinclair/typebox").TObject<{
82
+ rich_text: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
83
+ text: import("@sinclair/typebox").TObject<{
84
+ content: import("@sinclair/typebox").TString;
85
+ }>;
86
+ }>>;
87
+ }>;
88
+ tags: import("@sinclair/typebox").TObject<{
89
+ rich_text: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
90
+ text: import("@sinclair/typebox").TObject<{
91
+ content: import("@sinclair/typebox").TString;
92
+ }>;
93
+ }>>;
94
+ }>;
95
+ url: import("@sinclair/typebox").TObject<{
96
+ url: import("@sinclair/typebox").TString;
97
+ }>;
98
+ }>;
99
+ }>;
100
+ }>;
52
101
  export type GetProtocolsQueryModel = typeof GetProtocolsQueryDto.static;
53
102
  export type GetProtocolModel = typeof GetProtocolParamsDto.static;
54
103
  export type UpdateProtocolModel = typeof UpdateProtocolDto.static;
@@ -156,3 +156,22 @@ export const CreateProtocolDto = t.Object({
156
156
  tags: t.Array(t.String()),
157
157
  });
158
158
  export const ProtocolIdDto = t.Object({ id: t.String() });
159
+ export const NotionWebhookAddProtocolDto = t.Object({
160
+ data: t.Object({
161
+ properties: t.Object({
162
+ id: t.Object({
163
+ title: t.Array(t.Object({ text: t.Object({ content: t.String() }) })),
164
+ }),
165
+ description: t.Object({ rich_text: t.Array(t.Object({ text: t.Object({ content: t.String() }) })) }),
166
+ icon: t.Object({
167
+ files: t.Array(t.Union([
168
+ t.Object({ name: t.String(), file: t.Object({ url: t.String() }) }),
169
+ t.Object({ external: t.Object({ url: t.String() }) }),
170
+ ])),
171
+ }),
172
+ name: t.Object({ rich_text: t.Array(t.Object({ text: t.Object({ content: t.String() }) })) }),
173
+ tags: t.Object({ rich_text: t.Array(t.Object({ text: t.Object({ content: t.String() }) })) }),
174
+ url: t.Object({ url: t.String() }),
175
+ }),
176
+ }),
177
+ }, { additionalProperties: true });
@@ -9,6 +9,14 @@ export declare abstract class ProtocolRepository {
9
9
  tags: string[];
10
10
  icon: string;
11
11
  }>;
12
+ static upsert(data: CreateProtocolModel): Promise<{
13
+ id: string;
14
+ name: string;
15
+ url: string;
16
+ description: string;
17
+ tags: string[];
18
+ icon: string;
19
+ }>;
12
20
  static changeId(oldId: string, newId: string): Promise<void>;
13
21
  static findUnique(type: string): Promise<{
14
22
  id: string;
@@ -47,6 +47,26 @@ export class ProtocolRepository {
47
47
  },
48
48
  });
49
49
  }
50
+ static async upsert(data) {
51
+ return await apiDbClient.protocol.upsert({
52
+ where: { id: data.id },
53
+ create: {
54
+ id: data.id,
55
+ name: data.name,
56
+ icon: data.icon,
57
+ url: data.url,
58
+ description: data.description,
59
+ tags: data.tags,
60
+ },
61
+ update: {
62
+ name: data.name,
63
+ icon: data.icon,
64
+ url: data.url,
65
+ description: data.description,
66
+ tags: data.tags,
67
+ },
68
+ });
69
+ }
50
70
  static async changeId(oldId, newId) {
51
71
  if (!(await ProtocolRepository.findMany({ id: newId }))[0]) {
52
72
  await apiDbClient.protocol.create({
@@ -12,6 +12,14 @@ export declare abstract class ProtocolService {
12
12
  tags: string[];
13
13
  icon: string;
14
14
  }>;
15
+ static upsert(data: CreateProtocolModel): Promise<{
16
+ id: string;
17
+ name: string;
18
+ url: string;
19
+ description: string;
20
+ tags: string[];
21
+ icon: string;
22
+ }>;
15
23
  static update(id: string, data: UpdateProtocolModel): Promise<{
16
24
  id: string;
17
25
  name: string;
@@ -1,8 +1,10 @@
1
1
  import { ChainService } from "@/modules/v4/chain/chain.service";
2
2
  import { TokenService } from "@/modules/v4/token/token.service";
3
3
  import { log } from "@/utils/logger";
4
+ import { BucketService } from "../bucket/bucket.service";
4
5
  import { CacheService } from "../cache";
5
6
  import { TTLPresets } from "../cache/cache.model";
7
+ import { IconService } from "../icon/icon.service";
6
8
  import { ProtocolRepository } from "./protocol.repository";
7
9
  // ─── Protocols Services ──────────────────────────────────────────────────────
8
10
  export class ProtocolService {
@@ -30,6 +32,16 @@ export class ProtocolService {
30
32
  static async create(data) {
31
33
  return await ProtocolRepository.create(data);
32
34
  }
35
+ static async upsert(data) {
36
+ const env = process.env.ENV === "prod" ? "production" : process.env.ENV;
37
+ const iconUri = await IconService.pullPush(data.icon, new BucketService(`merkl-${env}-tokens`, `angle-${env}-1`), {
38
+ name: `protocols/${data.id}`,
39
+ });
40
+ return await ProtocolRepository.upsert({
41
+ ...data,
42
+ icon: `${iconUri}`,
43
+ });
44
+ }
33
45
  static async update(id, data) {
34
46
  return await ProtocolRepository.update(id, data);
35
47
  }
@@ -2023,9 +2023,7 @@ export declare const v4: Elysia<"/v4", false, {
2023
2023
  };
2024
2024
  };
2025
2025
  };
2026
- };
2027
- } & {
2028
- protocols: {
2026
+ } & {
2029
2027
  count: {
2030
2028
  get: {
2031
2029
  body: unknown;
@@ -2046,9 +2044,7 @@ export declare const v4: Elysia<"/v4", false, {
2046
2044
  };
2047
2045
  };
2048
2046
  };
2049
- };
2050
- } & {
2051
- protocols: {
2047
+ } & {
2052
2048
  ":id": {
2053
2049
  get: {
2054
2050
  body: unknown;
@@ -2072,9 +2068,7 @@ export declare const v4: Elysia<"/v4", false, {
2072
2068
  };
2073
2069
  };
2074
2070
  };
2075
- };
2076
- } & {
2077
- protocols: {
2071
+ } & {
2078
2072
  ":id": {
2079
2073
  patch: {
2080
2074
  body: {
@@ -2102,9 +2096,7 @@ export declare const v4: Elysia<"/v4", false, {
2102
2096
  };
2103
2097
  };
2104
2098
  };
2105
- };
2106
- } & {
2107
- protocols: {
2099
+ } & {
2108
2100
  index: {
2109
2101
  post: {
2110
2102
  body: {
@@ -2132,6 +2124,77 @@ export declare const v4: Elysia<"/v4", false, {
2132
2124
  };
2133
2125
  };
2134
2126
  };
2127
+ } & {
2128
+ webhooks: {
2129
+ notion: {
2130
+ post: {
2131
+ body: {
2132
+ data: {
2133
+ properties: {
2134
+ id: {
2135
+ title: {
2136
+ text: {
2137
+ content: string;
2138
+ };
2139
+ }[];
2140
+ };
2141
+ name: {
2142
+ rich_text: {
2143
+ text: {
2144
+ content: string;
2145
+ };
2146
+ }[];
2147
+ };
2148
+ url: {
2149
+ url: string;
2150
+ };
2151
+ description: {
2152
+ rich_text: {
2153
+ text: {
2154
+ content: string;
2155
+ };
2156
+ }[];
2157
+ };
2158
+ tags: {
2159
+ rich_text: {
2160
+ text: {
2161
+ content: string;
2162
+ };
2163
+ }[];
2164
+ };
2165
+ icon: {
2166
+ files: ({
2167
+ file: {
2168
+ url: string;
2169
+ };
2170
+ name: string;
2171
+ } | {
2172
+ external: {
2173
+ url: string;
2174
+ };
2175
+ })[];
2176
+ };
2177
+ };
2178
+ };
2179
+ };
2180
+ params: {};
2181
+ query: unknown;
2182
+ headers: {
2183
+ authorization: string;
2184
+ };
2185
+ response: {
2186
+ 200: {
2187
+ id: string;
2188
+ name: string;
2189
+ url: string;
2190
+ description: string;
2191
+ tags: string[];
2192
+ icon: string;
2193
+ };
2194
+ };
2195
+ };
2196
+ };
2197
+ };
2135
2198
  };
2136
2199
  };
2137
2200
  } & {
@@ -4,7 +4,7 @@ import { getUserAllowance } from "@/libs/tokens/allowances";
4
4
  import { throwOnInvalidRequiredAddress, throwOnUnsupportedChainId } from "@/utils/throw";
5
5
  import Elysia from "elysia";
6
6
  import { ChainDto } from "../accounting";
7
- import { CreateTokenDto, FindUniqueTokenAllowanceDto, FindUniqueTokenDto, GetTokenBalanceDto, GetTokenQueryDto, NotionWebhookDto, TokenIdDto, UpdateTokenDto, } from "./token.model";
7
+ import { CreateTokenDto, FindUniqueTokenAllowanceDto, FindUniqueTokenDto, GetTokenBalanceDto, GetTokenQueryDto, NotionWebhookAddTokenDto, TokenIdDto, UpdateTokenDto, } from "./token.model";
8
8
  import { TokenService } from "./token.service";
9
9
  // ─── Tokens Controller ───────────────────────────────────────────────────────
10
10
  export const TokenController = new Elysia({ prefix: "/tokens", detail: { tags: ["Tokens"] } })
@@ -95,7 +95,7 @@ export const TokenController = new Elysia({ prefix: "/tokens", detail: { tags: [
95
95
  })
96
96
  .group("/webhooks", app => {
97
97
  return app.post("/notion", async ({ body }) => TokenService.notionWebhook(body), {
98
- body: NotionWebhookDto,
98
+ body: NotionWebhookAddTokenDto,
99
99
  headers: AuthorizationHeadersDto,
100
100
  beforeHandle: BackOfficeGuard,
101
101
  detail: { hide: true },
@@ -76,7 +76,7 @@ export declare const CreateTokenDto: import("@sinclair/typebox").TObject<{
76
76
  verified: import("@sinclair/typebox").TBoolean;
77
77
  isTest: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
78
78
  }>;
79
- export declare const NotionWebhookDto: import("@sinclair/typebox").TObject<{
79
+ export declare const NotionWebhookAddTokenDto: import("@sinclair/typebox").TObject<{
80
80
  data: import("@sinclair/typebox").TObject<{
81
81
  properties: import("@sinclair/typebox").TObject<{
82
82
  "Icon (Required)": import("@sinclair/typebox").TObject<{
@@ -115,4 +115,4 @@ export type TokenModel = typeof TokenDto.static;
115
115
  export type GetTokenQueryModel = typeof GetTokenQueryDto.static;
116
116
  export type UpdateTokenModel = typeof UpdateTokenDto.static;
117
117
  export type CreateTokenModel = typeof CreateTokenDto.static;
118
- export type NotionWebhookModel = typeof NotionWebhookDto.static;
118
+ export type NotionWebhookModel = typeof NotionWebhookAddTokenDto.static;
@@ -64,7 +64,7 @@ export const CreateTokenDto = t.Object({
64
64
  verified: t.Boolean(),
65
65
  isTest: t.Optional(t.Boolean()),
66
66
  });
67
- export const NotionWebhookDto = t.Object({
67
+ export const NotionWebhookAddTokenDto = t.Object({
68
68
  data: t.Object({
69
69
  properties: t.Object({
70
70
  "Icon (Required)": t.Object({