odin-connect 1.3.2 → 1.3.3

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.
Files changed (70) hide show
  1. package/dist/index.d.ts +406 -10
  2. package/dist/index.js +2 -2
  3. package/package.json +20 -4
  4. package/.claude/settings.local.json +0 -7
  5. package/.github/workflows/pr.yml +0 -24
  6. package/demo/README.md +0 -69
  7. package/demo/eslint.config.js +0 -23
  8. package/demo/index.html +0 -13
  9. package/demo/package-lock.json +0 -3495
  10. package/demo/package.json +0 -32
  11. package/demo/public/icon.svg +0 -6
  12. package/demo/tsconfig.app.json +0 -27
  13. package/demo/tsconfig.node.json +0 -25
  14. package/demo/vite.config.ts +0 -7
  15. package/dist/index.d.ts.map +0 -1
  16. package/dist/models/achievement.d.ts +0 -20
  17. package/dist/models/achievement.d.ts.map +0 -1
  18. package/dist/models/achievement.js +0 -1
  19. package/dist/models/activity.d.ts +0 -11
  20. package/dist/models/activity.d.ts.map +0 -1
  21. package/dist/models/activity.js +0 -1
  22. package/dist/models/balance.d.ts +0 -6
  23. package/dist/models/balance.d.ts.map +0 -1
  24. package/dist/models/balance.js +0 -1
  25. package/dist/models/environment.d.ts +0 -8
  26. package/dist/models/environment.d.ts.map +0 -1
  27. package/dist/models/environment.js +0 -6
  28. package/dist/models/token.d.ts +0 -78
  29. package/dist/models/token.d.ts.map +0 -1
  30. package/dist/models/token.js +0 -1
  31. package/dist/models/transactions.d.ts +0 -13
  32. package/dist/models/transactions.d.ts.map +0 -1
  33. package/dist/models/transactions.js +0 -11
  34. package/dist/models/user.d.ts +0 -13
  35. package/dist/models/user.d.ts.map +0 -1
  36. package/dist/models/user.js +0 -1
  37. package/dist/services/api.d.ts +0 -66
  38. package/dist/services/api.d.ts.map +0 -1
  39. package/dist/services/api.js +0 -169
  40. package/dist/services/api.test.d.ts +0 -2
  41. package/dist/services/api.test.d.ts.map +0 -1
  42. package/dist/services/api.test.js +0 -86
  43. package/dist/services/canister.d.ts +0 -72
  44. package/dist/services/canister.d.ts.map +0 -1
  45. package/dist/services/canister.js +0 -208
  46. package/dist/services/connect.d.ts +0 -41
  47. package/dist/services/connect.d.ts.map +0 -1
  48. package/dist/services/connect.js +0 -105
  49. package/dist/services/connected-user.d.ts +0 -74
  50. package/dist/services/connected-user.d.ts.map +0 -1
  51. package/dist/services/connected-user.js +0 -100
  52. package/dist/services/http.d.ts +0 -10
  53. package/dist/services/http.d.ts.map +0 -1
  54. package/dist/services/http.js +0 -43
  55. package/dist/services/http.test.d.ts +0 -2
  56. package/dist/services/http.test.d.ts.map +0 -1
  57. package/dist/services/http.test.js +0 -37
  58. package/dist/services/window.d.ts +0 -12
  59. package/dist/services/window.d.ts.map +0 -1
  60. package/dist/services/window.js +0 -21
  61. package/dist/utils/conver-to-odin-amount.test.d.ts +0 -2
  62. package/dist/utils/conver-to-odin-amount.test.d.ts.map +0 -1
  63. package/dist/utils/conver-to-odin-amount.test.js +0 -36
  64. package/dist/utils/index.d.ts +0 -6
  65. package/dist/utils/index.d.ts.map +0 -1
  66. package/dist/utils/index.js +0 -134
  67. package/dist/utils/token-field-validators.test.d.ts +0 -2
  68. package/dist/utils/token-field-validators.test.d.ts.map +0 -1
  69. package/dist/utils/token-field-validators.test.js +0 -31
  70. package/vitest.config.ts +0 -7
package/dist/index.d.ts CHANGED
@@ -1,10 +1,406 @@
1
- export { Connect as OdinConnect } from "./services/connect";
2
- export type { User as OdinUser } from "./models/user";
3
- export type { Balance as OdinBalance } from "./models/balance";
4
- export type { BaseToken as OdinBaseToken, Token as OdinToken, TokenWithBalance as OdinTokenWithBalance, } from "./models/token";
5
- export type { Activity as OdinActivity } from "./models/activity";
6
- export type { Transaction as OdinTransaction } from "./models/transactions";
7
- export type { Achievement as OdinAchievement, AchievementCategory as OdinAchievementCategory, } from "./models/achievement";
8
- export * as OdinUtils from "./utils";
9
- export type { ConnectedUser as OdinConnectedUser } from "./services/connected-user";
10
- //# sourceMappingURL=index.d.ts.map
1
+ import { DelegationIdentity } from '@dfinity/identity';
2
+
3
+ interface BaseToken {
4
+ id: string;
5
+ name: string;
6
+ ticker: string;
7
+ divisibility: number;
8
+ decimals: number;
9
+ withdrawals: boolean;
10
+ deposits: boolean;
11
+ }
12
+ interface Token extends BaseToken {
13
+ image: string | null;
14
+ description: string | null;
15
+ creator: string;
16
+ created_time: Date;
17
+ marketcap: bigint;
18
+ volume: bigint;
19
+ volume_24: number;
20
+ holder_count: number;
21
+ power_holder_count: number;
22
+ sell_count: number;
23
+ buy_count: number;
24
+ comment_count: number;
25
+ featured: boolean;
26
+ bonded: boolean;
27
+ external: boolean;
28
+ trading: boolean;
29
+ icrc_ledger: string | null;
30
+ sold: bigint;
31
+ total_supply: bigint;
32
+ threshold: bigint;
33
+ swap_volume: bigint | null;
34
+ swap_volume_24: bigint | null;
35
+ holding_value: number | null;
36
+ price: number;
37
+ twitter: string | null;
38
+ twitter_verified: boolean | null;
39
+ website: string | null;
40
+ telegram: string | null;
41
+ btc_liquidity: bigint;
42
+ token_liquidity: bigint;
43
+ liquidity_threshold: bigint;
44
+ last_comment_time: string | null;
45
+ last_action_time: Date | null;
46
+ user_lp_tokens: bigint;
47
+ user_btc_liquidity: bigint;
48
+ user_token_liquidity: bigint;
49
+ verified: boolean;
50
+ progress: number | null;
51
+ price_5m: number | null;
52
+ price_1h: number | null;
53
+ price_6h: number | null;
54
+ price_1d: number | null;
55
+ }
56
+ interface TokenWithBalance {
57
+ token: Token;
58
+ balance: bigint;
59
+ }
60
+ type TokenFilterFields = {
61
+ ascended: boolean;
62
+ etched: boolean;
63
+ /** External: true - Launched on BitCoin; false - Launched on Odin */
64
+ external: boolean;
65
+ verified: boolean;
66
+ has_website: boolean;
67
+ has_twitter: boolean;
68
+ has_telegram: boolean;
69
+ marketcap_max: bigint;
70
+ marketcap_min: bigint;
71
+ volume_max: bigint;
72
+ volume_min: bigint;
73
+ holders_max: number;
74
+ holders_min: number;
75
+ price_max: number;
76
+ price_min: number;
77
+ search: string;
78
+ };
79
+ type TokenSortableFields = "created_time" | "marketcap" | "volume" | "power_holder_count" | "price" | "holders_count" | "price_delta_5m" | "price_delta_1h" | "price_delta_6h" | "price_delta_1d" | "volume_24" | "txn_count" | "ascension" | "last_action_time";
80
+
81
+ interface Activity {
82
+ id: number;
83
+ token: BaseToken;
84
+ time: Date;
85
+ action: string;
86
+ amount_token?: bigint;
87
+ amount_btc?: bigint;
88
+ description?: string;
89
+ }
90
+
91
+ interface Balance extends Token {
92
+ principal: string;
93
+ balance: bigint;
94
+ }
95
+
96
+ interface User {
97
+ principal: string;
98
+ username: string;
99
+ image: string;
100
+ btc_wallet_address: string | null;
101
+ created_at: Date;
102
+ btc_deposit_address: string | null;
103
+ rune_deposit_address: string | null;
104
+ ref_code: string | null;
105
+ referrer: string | null;
106
+ admin: number;
107
+ }
108
+
109
+ interface Achievement {
110
+ id: number;
111
+ name: string | null;
112
+ image: string | null;
113
+ description: string | null;
114
+ prereq_display: string | null;
115
+ prereq_active: number[] | null;
116
+ default: number;
117
+ category: number;
118
+ category_order: number | null;
119
+ fn: string;
120
+ status: number;
121
+ status_text: "EARNED" | "VISIBLE_EARNABLE" | "VISIBLE_NOT_EARNABLE";
122
+ }
123
+ interface AchievementCategory {
124
+ category_id: number;
125
+ category_name: string;
126
+ achievements: ReadonlyArray<Achievement>;
127
+ }
128
+
129
+ declare const transactionStatuses: readonly ["pending", "processing", "complete", "too small", "error", "unsupported", "unknown", "delayed"];
130
+ interface Transaction {
131
+ id: string;
132
+ status: typeof transactionStatuses[number];
133
+ address: string;
134
+ index_time: Date;
135
+ created_time: Date;
136
+ canister: string;
137
+ token: string;
138
+ amount: bigint;
139
+ }
140
+
141
+ type Pagination = {
142
+ page: number;
143
+ limit: number;
144
+ };
145
+ type Sort<T = string> = {
146
+ field: T;
147
+ direction: "asc" | "desc";
148
+ };
149
+ type PaginatedResponse<T> = {
150
+ data: ReadonlyArray<T>;
151
+ count: number;
152
+ page: number;
153
+ limit: number;
154
+ };
155
+ declare class OdinApiClient {
156
+ private _apiKey;
157
+ private _httpClient;
158
+ readonly BASE_URL: string;
159
+ constructor(env?: "prod" | "dev");
160
+ getUser(id: string): Promise<User>;
161
+ getBalances(principal: string, pagination: Pagination): Promise<readonly Balance[]>;
162
+ getBalance(principal: string, tokenId: string): Promise<Balance | null>;
163
+ getTokens(pagination: Pagination, sort?: Sort<TokenSortableFields>, filters?: Partial<TokenFilterFields>): Promise<PaginatedResponse<Token>>;
164
+ getToken(id: string): Promise<Token>;
165
+ uploadImage(image: File): Promise<string>;
166
+ updateTokenImage(tokenId: string, image: File): Promise<{
167
+ data: Token;
168
+ }>;
169
+ getUserActivity(principal: string, pagination: Pagination): Promise<PaginatedResponse<Activity>>;
170
+ getUserTokens(principal: string, pagination: Pagination): Promise<{
171
+ data: {
172
+ balance: bigint;
173
+ token: Token;
174
+ unrealized_pnl?: number;
175
+ unrealized_pnl_percent?: number;
176
+ }[];
177
+ count: number;
178
+ page: number;
179
+ limit: number;
180
+ }>;
181
+ getUserLiquidity(principal: string, pagination: Pagination): Promise<{
182
+ data: {
183
+ balance: bigint;
184
+ token: Token;
185
+ }[];
186
+ count: number;
187
+ page: number;
188
+ limit: number;
189
+ }>;
190
+ getUserAchievements(principal: string, pagination: Pagination): Promise<readonly AchievementCategory[]>;
191
+ getUserTransactions(principal: string, pagination: Pagination): Promise<PaginatedResponse<Transaction>>;
192
+ getUserCreatedTokens(principal: string, pagination: Pagination): Promise<PaginatedResponse<Token>>;
193
+ getUserStats(principal: string): Promise<{
194
+ followers: number;
195
+ following: number;
196
+ }>;
197
+ set apiKey(key: string);
198
+ get apiKey(): string | null;
199
+ }
200
+
201
+ interface WindowClientSettings {
202
+ target: string;
203
+ settings: string;
204
+ }
205
+ declare class WindowClient {
206
+ private _settings;
207
+ constructor(options?: Partial<WindowClientSettings>);
208
+ get settings(): Partial<WindowClientSettings>;
209
+ set settings(settings: Partial<WindowClientSettings>);
210
+ open(url: URL): Window | null;
211
+ }
212
+
213
+ interface SellOptions {
214
+ principal: string;
215
+ token: string;
216
+ tokenAmount: bigint;
217
+ }
218
+ interface BuyOptions {
219
+ principal: string;
220
+ token: string;
221
+ btcAmount: bigint;
222
+ }
223
+ interface TransferOptions {
224
+ principal: string;
225
+ token: string;
226
+ amount: bigint;
227
+ destination: string;
228
+ }
229
+ interface AddLiquidityOptions {
230
+ principal: string;
231
+ btcAmount: bigint;
232
+ token: string;
233
+ }
234
+ interface RemoveLiquidityOptions {
235
+ principal: string;
236
+ lpAmount: bigint;
237
+ token: string;
238
+ }
239
+ interface SwapOptions {
240
+ principal: string;
241
+ fromToken: string;
242
+ toToken: string;
243
+ fromAmount: bigint;
244
+ }
245
+ interface IcrcApproveOptions {
246
+ principal: string;
247
+ token: string;
248
+ spender: string;
249
+ amount: bigint;
250
+ }
251
+ interface CreateTokenParams {
252
+ principal: string;
253
+ name: string;
254
+ ticker: string;
255
+ image: File;
256
+ description?: string;
257
+ website?: string;
258
+ twitter?: string;
259
+ telegram?: string;
260
+ buy?: bigint;
261
+ discount?: string;
262
+ }
263
+ declare class OdinCanisterClient {
264
+ private _window;
265
+ private _appInfo;
266
+ private _api;
267
+ origin: string;
268
+ constructor(windowClient: WindowClient, apiClient: OdinApiClient, appInfo: AppInitOptions, origin: string);
269
+ get appInfo(): AppInitOptions;
270
+ private createUrl;
271
+ private baseAction;
272
+ sell({ token, tokenAmount, principal }: SellOptions): Promise<boolean>;
273
+ buy({ principal, token, btcAmount }: BuyOptions): Promise<boolean>;
274
+ transfer({ principal, token, amount, destination }: TransferOptions): Promise<boolean>;
275
+ addLiquidity({ principal, btcAmount, token }: AddLiquidityOptions): Promise<boolean>;
276
+ removeLiquidity({ principal, lpAmount, token }: RemoveLiquidityOptions): Promise<boolean>;
277
+ swap({ principal, fromToken: from, toToken: to, fromAmount }: SwapOptions): Promise<boolean>;
278
+ icrcApprove({ principal, token, spender, amount }: IcrcApproveOptions): Promise<boolean>;
279
+ createToken({ image, ...params }: CreateTokenParams): Promise<boolean>;
280
+ }
281
+
282
+ declare class ConnectedUser {
283
+ private _identity;
284
+ private _api;
285
+ private _principal;
286
+ private _odin;
287
+ constructor(principal: string, identity: DelegationIdentity | null, api: OdinApiClient, odin: OdinCanisterClient);
288
+ get principal(): string;
289
+ set principal(principal: string);
290
+ getIdentity(): DelegationIdentity | null;
291
+ getUser(): Promise<User>;
292
+ getBalances(pagination: {
293
+ page: number;
294
+ limit: number;
295
+ }): Promise<readonly Balance[]>;
296
+ getBalance(tokenId: string): Promise<Balance | null>;
297
+ getTokens(pagination: {
298
+ page: number;
299
+ limit: number;
300
+ }): Promise<{
301
+ data: {
302
+ balance: bigint;
303
+ token: Token;
304
+ unrealized_pnl?: number;
305
+ unrealized_pnl_percent?: number;
306
+ }[];
307
+ count: number;
308
+ page: number;
309
+ limit: number;
310
+ }>;
311
+ getCreatedTokens(pagination: {
312
+ page: number;
313
+ limit: number;
314
+ }): Promise<PaginatedResponse<Token>>;
315
+ getActivity(pagination: {
316
+ page: number;
317
+ limit: number;
318
+ }): Promise<PaginatedResponse<Activity>>;
319
+ getLiquidity(pagination: {
320
+ page: number;
321
+ limit: number;
322
+ }): Promise<{
323
+ data: {
324
+ balance: bigint;
325
+ token: Token;
326
+ }[];
327
+ count: number;
328
+ page: number;
329
+ limit: number;
330
+ }>;
331
+ getAchievements(pagination: {
332
+ page: number;
333
+ limit: number;
334
+ }): Promise<readonly AchievementCategory[]>;
335
+ getTransactions(pagination: {
336
+ page: number;
337
+ limit: number;
338
+ }): Promise<PaginatedResponse<Transaction>>;
339
+ getStats(): Promise<{
340
+ followers: number;
341
+ following: number;
342
+ }>;
343
+ sell(params: Omit<SellOptions, "principal">): Promise<boolean>;
344
+ buy(params: Omit<BuyOptions, "principal">): Promise<boolean>;
345
+ addLiquidity(params: Omit<AddLiquidityOptions, "principal">): Promise<boolean>;
346
+ removeLiquidity(params: Omit<RemoveLiquidityOptions, "principal">): Promise<boolean>;
347
+ transfer(params: Omit<TransferOptions, "principal">): Promise<boolean>;
348
+ createToken(params: Omit<CreateTokenParams, "principal">): Promise<boolean>;
349
+ icrcApprove(params: Omit<IcrcApproveOptions, "principal">): Promise<boolean>;
350
+ swap(params: Omit<SwapOptions, "principal">): Promise<boolean>;
351
+ }
352
+
353
+ declare const ORIGINS: {
354
+ local: string;
355
+ prod: string;
356
+ dev: string;
357
+ _preview: string;
358
+ };
359
+ type Environment = keyof typeof ORIGINS;
360
+
361
+ interface AppInitOptions {
362
+ name: string;
363
+ icon?: string;
364
+ env?: Environment;
365
+ }
366
+ interface BaseConnectOptions {
367
+ open?: WindowClientSettings;
368
+ requires_api?: boolean;
369
+ }
370
+ interface ConnectOptionsWithDelegation extends BaseConnectOptions {
371
+ requires_delegation: true;
372
+ targets: string[];
373
+ }
374
+ interface ConnectOptionsWithoutDelegation extends BaseConnectOptions {
375
+ requires_delegation?: false;
376
+ targets?: never;
377
+ session_key?: never;
378
+ }
379
+ type ConnectOptions = ConnectOptionsWithDelegation | ConnectOptionsWithoutDelegation;
380
+ declare class Connect {
381
+ private _appInfo;
382
+ private _api;
383
+ private _window;
384
+ private _odin;
385
+ constructor(appInfo?: Partial<AppInitOptions>);
386
+ private createUrl;
387
+ get origin(): string;
388
+ get appInfo(): AppInitOptions | null;
389
+ connect({ open, requires_api, requires_delegation, targets, }?: ConnectOptions | undefined): Promise<ConnectedUser>;
390
+ get api(): OdinApiClient;
391
+ get odin(): OdinCanisterClient;
392
+ get currentEnv(): "prod" | "dev" | "local" | "_preview";
393
+ hello(): void;
394
+ }
395
+
396
+ declare function convertToOdinAmount(numberStr: string | number, token?: Pick<BaseToken, "decimals" | "divisibility">): bigint;
397
+ type TokenValue = string | File | null | bigint;
398
+ declare const createTokenValidators: Partial<Record<keyof Token, (value: TokenValue) => string | undefined>>;
399
+
400
+ declare const index_convertToOdinAmount: typeof convertToOdinAmount;
401
+ declare const index_createTokenValidators: typeof createTokenValidators;
402
+ declare namespace index {
403
+ export { index_convertToOdinAmount as convertToOdinAmount, index_createTokenValidators as createTokenValidators };
404
+ }
405
+
406
+ export { type Achievement as OdinAchievement, type AchievementCategory as OdinAchievementCategory, type Activity as OdinActivity, type Balance as OdinBalance, type BaseToken as OdinBaseToken, Connect as OdinConnect, ConnectedUser as OdinConnectedUser, type Token as OdinToken, type TokenWithBalance as OdinTokenWithBalance, type Transaction as OdinTransaction, type User as OdinUser, index as OdinUtils };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { Connect as OdinConnect } from "./services/connect";
2
- export * as OdinUtils from "./utils";
1
+ import U from'axios';import E from'@apimatic/json-bigint';import {Ed25519KeyIdentity,DelegationIdentity,DelegationChain}from'@dfinity/identity';var C=Object.defineProperty;var R=(n,e)=>{for(var t in e)C(n,t,{get:e[t],enumerable:true});};var x=n=>{try{return E.parse(n)}catch(e){return console.error("Error parsing response:",e),n}},u=class{async get(e,t){return this.fetch(e,{method:"GET",...t})}async fetch(e,t){let i={transformResponse:[x],...t};return (await U(e,i)).data}async post(e,t,i){return this.fetch(e,{method:"POST",data:t,...i})}async put(e,t,i){return this.fetch(e,{method:"PUT",data:t,...i})}async delete(e,t){return this.fetch(e,{method:"DELETE",...t})}};var b={};R(b,{convertToOdinAmount:()=>I,createTokenValidators:()=>c});function I(n,e={decimals:3,divisibility:8}){let t=e.decimals+e.divisibility;if(n=typeof n=="string"?n.trim():String(n),isNaN(+n))return 0n;let[i,r=""]=n.split(".");return r=r.slice(0,t),r=r.padEnd(t,"0"),i=i.replace(/^0+(?=\d)/,""),i===""&&(i="0"),BigInt(i+r)}var c={name:P,image:L,ticker:B,description:S,twitter:$,website:q,telegram:D};function P(n){if(typeof n!="string")return "Name must be a string.";if(!n||n.trim()==="")return "Name is required.";if(n.length<3||n.length>30)return "Name must be between 3 and 30 characters."}function S(n){if(n){if(typeof n!="string")return "Description must be a string.";if(n&&n.length>100)return "Description must not exceed 100 characters."}}function B(n){if(typeof n!="string")return "Ticker must be a string.";if(!n||n.trim()==="")return "Ticker is required.";if(n.length<3||n.length>10)return "Ticker must be between 3 and 10 characters.";if(!/^[A-Z0-9]+$/.test(n))return "Ticker must be alphanumeric characters in uppercase only.";if(!/(?=(.*[A-Z].*[A-Z]))/.test(n))return "Ticker must have at least 2 alpha characters."}function L(n){if(!(n instanceof File))return "Image must be a file.";let e=["image/png","image/jpeg","image/webp","image/svg","image/gif","image/avif"],t=200*1024;if(!n)return "Image file is required.";if(!e.includes(n.type))return `Invalid file type. Allowed types are: ${e.join(", ")}`;if(n.size>t)return `File size exceeds the maximum limit of ${t/1024}KB.`}function $(n){if(n){if(typeof n!="string")return "Twitter handle must be a string.";if(n&&!/^https?:\/\/(www\.)?(twitter\.com|x\.com)\/[A-Za-z0-9_]{1,15}\/?$/.test(n))return "Twitter must be a valid twitter URL."}}function q(n){if(n){if(typeof n!="string")return "Website must be a string.";if(n&&!/^(https?:\/\/)?([\w-]+(\.[\w-]+)+)(\/[\w-./?%&=]*)?$/.test(n))return "Website must be a valid URL."}}function D(n){if(n){if(typeof n!="string")return "Telegram must be a string.";if(n&&!/^(https?:\/\/)?(t\.me|telegram\.me|telegram\.org)\/[A-Za-z0-9_]{5,32}\/?$/.test(n))return "Telegram must be a valid telegram URL."}}var F={dev:"https://api.odin.fun/dev",prod:"https://api.odin.fun/v1",local:"https://api.odin.fun/dev"},m=class{_apiKey=null;_httpClient;BASE_URL;constructor(e="prod"){this._httpClient=new u,this.BASE_URL=F[e];}getUser(e){return this._httpClient.get(`${this.BASE_URL}/user/${e}`)}async getBalances(e,t){return (await this._httpClient.get(`${this.BASE_URL}/user/${e}/balances`,{params:{...t}})).data}async getBalance(e,t){return (await this._httpClient.get(`${this.BASE_URL}/user/${e}/balances`,{params:{token_in:t}})).data.find(r=>r.id===t)??null}getTokens(e,t={field:"marketcap",direction:"desc"},i={}){return this._httpClient.get(`${this.BASE_URL}/tokens`,{params:{...e,sort:`${t.field}:${t.direction}`,...i}})}getToken(e){return this._httpClient.get(`${this.BASE_URL}/token/${e}`)}async uploadImage(e){if(!this._apiKey)throw new Error("API key is not set");try{let t=c.image?.(e);if(t)throw new Error(t);let i=new FormData;return i.append("file",e),(await this._httpClient.post(`${this.BASE_URL}/upload`,i,{headers:{"Content-Type":"multipart/form-data",Authorization:`Bearer ${this._apiKey}`}})).data.upload}catch(t){if(t instanceof Error)if(t.name==="AxiosError"){let i=t;throw new Error(i.response?.data?.message||i.message)}else throw new Error(t.message);else throw new Error("Image upload failed")}}updateTokenImage(e,t){if(!this._apiKey)throw new Error("API key is not set");try{return this._httpClient.post(`${this.BASE_URL}/token/${e}/image`,{image:t},{headers:{"Content-Type":"multipart/form-data",Authorization:`Bearer ${this._apiKey}`}})}catch(i){if(i instanceof Error&&i.name==="AxiosError"){let r=i;throw new Error(r.response?.data?.message||r.message)}else throw new Error("Image update failed")}}getUserActivity(e,t){return this._httpClient.get(`${this.BASE_URL}/user/${e}/activity`,{params:{...t}})}async getUserTokens(e,t){let i=await this._httpClient.get(`${this.BASE_URL}/user/${e}/tokens`,{params:{...t}});return {...i,data:i.data.map(r=>({...r,balance:BigInt(r.balance)}))}}async getUserLiquidity(e,t){let i=await this._httpClient.get(`${this.BASE_URL}/user/${e}/liquidity`,{params:{...t}});return {...i,data:i.data.map(r=>({...r,balance:BigInt(r.balance)}))}}async getUserAchievements(e,t){return (await this._httpClient.get(`${this.BASE_URL}/user/${e}/achievements`,{params:{...t}})).data}getUserTransactions(e,t){return this._httpClient.get(`${this.BASE_URL}/user/${e}/transactions`,{params:{...t}})}getUserCreatedTokens(e,t){return this._httpClient.get(`${this.BASE_URL}/user/${e}/created`,{params:{...t}})}getUserStats(e){return this._httpClient.get(`${this.BASE_URL}/user/${e}/stats`)}set apiKey(e){this._apiKey=e;}get apiKey(){return this._apiKey}};var g=class{_identity;_api;_principal;_odin;constructor(e,t,i,r){this._principal=e,this._identity=t,this._api=i,this._odin=r;}get principal(){return this._principal}set principal(e){this._principal=e;}getIdentity(){return this._identity}getUser(){return this._api.getUser(this.principal)}getBalances(e){return this._api.getBalances(this.principal,e)}getBalance(e){return this._api.getBalance(this.principal,e)}getTokens(e){return this._api.getUserTokens(this.principal,e)}getCreatedTokens(e){return this._api.getUserCreatedTokens(this.principal,e)}getActivity(e){return this._api.getUserActivity(this.principal,e)}getLiquidity(e){return this._api.getUserLiquidity(this.principal,e)}getAchievements(e){return this._api.getUserAchievements(this.principal,e)}getTransactions(e){return this._api.getUserTransactions(this.principal,e)}getStats(){return this._api.getUserStats(this.principal)}sell(e){return this._odin.sell({...e,principal:this.principal})}buy(e){return this._odin.buy({...e,principal:this.principal})}addLiquidity(e){return this._odin.addLiquidity({...e,principal:this.principal})}removeLiquidity(e){return this._odin.removeLiquidity({...e,principal:this.principal})}transfer(e){return this._odin.transfer({...e,principal:this.principal})}createToken(e){return this._odin.createToken({...e,principal:this.principal})}icrcApprove(e){return this._odin.icrcApprove({...e,principal:this.principal})}swap(e){return this._odin.swap({...e,principal:this.principal})}};var w={local:"http://localhost:5173",prod:"https://odin.fun",dev:"https://dev.odin.fun",_preview:"https://deploy-preview-1368--dev-odin-toniq.netlify.app"};var h=class{_settings;constructor(e){this._settings={target:e?.target||"_blank",settings:e?.settings||""};}get settings(){return this._settings}set settings(e){this._settings={...this._settings,...e};}open(e){return window.open(e,this._settings?.target||"_blank",this._settings?.settings)}};var f=class{_window;_appInfo;_api;origin;constructor(e,t,i,r){this._window=e,this._api=t,this._appInfo=i,this.origin=r;}get appInfo(){return this._appInfo}createUrl(e){let t=new URL(`${this.origin}/${e}`);return this._appInfo?.name&&t.searchParams.append("app_name",this._appInfo.name),t.searchParams.append("referrer",window.location.origin),t}baseAction({params:e,odinPath:t,receivedMessageFromOrigin:i,resolve:r}){return new Promise((o,l)=>{let p=async s=>{s.origin===this.origin&&s.data.path==="/"+t&&(window.removeEventListener("message",p),(typeof i=="function"?i(s.data.message):i===s.data.message)?o(r.success(s.data.message)):l(new Error(r.failure)));},d=this.createUrl(t);for(let s in e)e[s]&&d.searchParams.append(s,e[s]);let a=this._window.open(d);if(!a||a.closed||typeof a.closed>"u"){l(new Error(r.didnotopen??`Failed to open ${t} window, please always allow popups and try again`));return}window.addEventListener("message",p);})}sell({token:e,tokenAmount:t,principal:i}){return this.baseAction({params:{principal:i,token:e,amount:t.toString()},odinPath:"authorize/sell",receivedMessageFromOrigin:"sold",resolve:{success:()=>true,failure:"Sell failed or was cancelled",close:"User closed the window"}})}buy({principal:e,token:t,btcAmount:i}){return this.baseAction({params:{principal:e,token:t,amount:i.toString()},odinPath:"authorize/buy",receivedMessageFromOrigin:"purchased",resolve:{success:()=>true,failure:"Purchase failed or was cancelled",close:"User closed the window"}})}transfer({principal:e,token:t,amount:i,destination:r}){return this.baseAction({params:{principal:e,token:t,amount:i.toString(),destination:r},odinPath:"authorize/transfer",receivedMessageFromOrigin:"transferred",resolve:{success:()=>true,failure:"Transfer failed or was cancelled",close:"User closed the window"}})}addLiquidity({principal:e,btcAmount:t,token:i}){return this.baseAction({params:{principal:e,amount:t.toString(),token:i},odinPath:"authorize/add_liquidity",receivedMessageFromOrigin:"addedLiquidity",resolve:{success:()=>true,failure:"Add liquidity failed or was cancelled",close:"User closed the window"}})}removeLiquidity({principal:e,lpAmount:t,token:i}){return this.baseAction({params:{principal:e,amount:t.toString(),token:i},odinPath:"authorize/remove_liquidity",receivedMessageFromOrigin:"removedLiquidity",resolve:{success:()=>true,failure:"Remove liquidity failed or was cancelled",close:"User closed the window"}})}swap({principal:e,fromToken:t,toToken:i,fromAmount:r}){return this.baseAction({params:{principal:e,from:t,to:i,amount:r.toString()},odinPath:"authorize/swap",receivedMessageFromOrigin:"swapped",resolve:{success:()=>true,failure:"Swap failed or was cancelled",close:"User closed the window"}})}icrcApprove({principal:e,token:t,spender:i,amount:r}){return this.baseAction({params:{principal:e,token:t,spender:i,amount:r.toString()},odinPath:"authorize/icrc_approve",receivedMessageFromOrigin:"approved",resolve:{success:()=>true,failure:"ICRC approve failed or was cancelled",close:"User closed the window"}})}async createToken({image:e,...t}){for(let o in c)if(o in t){let p=c[o]?.(t[o]||null);if(p)throw new Error(p)}if(t.discount&&!/^[A-Za-z0-9]{10}$/.test(t.discount))throw new Error("Discount code must be alphanumeric and exactly 10 characters long.");let i=await this._api.uploadImage(e);if(!await this.baseAction({params:{...t,image:i,buy:t.buy?.toString()},odinPath:"authorize/create_token",receivedMessageFromOrigin:"tokenCreated",resolve:{success:()=>true,failure:"Token creation failed or was cancelled",close:"User closed the window"}}))throw new Error("Token creation failed. Please try again.");return true}};var _=class{_appInfo=null;_api;_window;_odin;constructor(e){this._appInfo={env:"prod",name:"app_name",...e},this._api=new m(this._appInfo.env==="prod"?"prod":"dev"),this._window=new h,this._odin=new f(this._window,this._api,this._appInfo,w[this._appInfo.env||"prod"]);}createUrl(e){let t=new URL(`${this.origin}/${e}`);return this._appInfo?.name&&t.searchParams.append("app_name",this._appInfo.name),t.searchParams.append("referrer",window.location.origin),t}get origin(){return w[this._appInfo?.env||"prod"]}get appInfo(){return this._appInfo}connect({open:e,requires_api:t,requires_delegation:i,targets:r}={requires_delegation:false,requires_api:false}){return new Promise((o,l)=>{e&&(this._window.settings=e);let p=Ed25519KeyIdentity.generate(),d=async s=>{if(s.origin===this.origin&&s.data.path==="/authorize/connect")if(window.removeEventListener("message",d),s.data.message!="rejected"){let y;try{let T=s.data.message,{principal:v,jwt:O,delegationChain:A}=T;if(t&&(this._api.apiKey=O),i){if(!A)throw new Error("Delegation chain is missing");let k=DelegationIdentity.fromDelegation(p,DelegationChain.fromJSON(A));y=new g(v,k,this.api,this._odin);}else y=new g(v,null,this.api,this._odin);o(y);}catch{l(new Error("Failed to fetch user data"));}}else l(new Error("User rejected the connection"));},a=this.createUrl("authorize/connect");if(a.searchParams.append("requires_api",t?"1":"0"),i){a.searchParams.append("requires_delegation","1");let s=btoa(JSON.stringify(p.toJSON()));a.searchParams.append("session_key",s),a.searchParams.append("targets",r?.join(",")||"");}this._window.open(a),window.addEventListener("message",d);})}get api(){return this._api}get odin(){return this._odin}get currentEnv(){return this._appInfo?.env||"prod"}hello(){console.log("Hello from Odin Connect!");}};
2
+ export{_ as OdinConnect,b as OdinUtils};
package/package.json CHANGED
@@ -1,11 +1,24 @@
1
1
  {
2
2
  "name": "odin-connect",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
4
4
  "description": "",
5
+ "type": "module",
5
6
  "main": "dist/index.js",
7
+ "module": "dist/index.js",
6
8
  "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ }
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
7
20
  "scripts": {
8
- "build": "tsc",
21
+ "build": "tsup",
9
22
  "prepublishOnly": "npm run build",
10
23
  "test": "vitest",
11
24
  "demo:update": "npm run build && cd demo && npm install ../ && cd ..",
@@ -21,7 +34,6 @@
21
34
  "keywords": [],
22
35
  "author": "",
23
36
  "license": "ISC",
24
- "type": "module",
25
37
  "bugs": {
26
38
  "url": "https://github.com/Toniq-Labs/odin-connect/issues"
27
39
  },
@@ -31,14 +43,18 @@
31
43
  "@vitest/ui": "^3.2.4",
32
44
  "jsdom": "^27.0.0",
33
45
  "release-it": "^19.0.5",
46
+ "tsup": "^8.5.1",
34
47
  "typescript": "^5.9.2",
35
48
  "vitest": "^3.2.4"
36
49
  },
37
50
  "dependencies": {
38
51
  "@apimatic/json-bigint": "^1.2.0",
39
- "@dfinity/identity": "^3.3.0",
52
+ "@dfinity/identity": "^3.4.3",
40
53
  "axios": "^1.12.0"
41
54
  },
55
+ "overrides": {
56
+ "undici": "6.24.1"
57
+ },
42
58
  "release-it": {
43
59
  "npm": {
44
60
  "publish": true
@@ -1,7 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(gh pr:*)"
5
- ]
6
- }
7
- }
@@ -1,24 +0,0 @@
1
- name: Run Unit Tests on Pull Request
2
-
3
- on:
4
- pull_request:
5
- branches:
6
- - "**"
7
-
8
- jobs:
9
- run-npm-script-test:
10
- runs-on: ubuntu-latest
11
- steps:
12
- - name: Checkout code
13
- uses: actions/checkout@v4
14
-
15
- - name: Set up Node.js
16
- uses: actions/setup-node@v4
17
- with:
18
- node-version: "20.18"
19
-
20
- - name: Install dependencies
21
- run: npm install
22
-
23
- - name: Run Tests
24
- run: npm run test
package/demo/README.md DELETED
@@ -1,69 +0,0 @@
1
- # React + TypeScript + Vite
2
-
3
- This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4
-
5
- Currently, two official plugins are available:
6
-
7
- - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
8
- - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9
-
10
- ## Expanding the ESLint configuration
11
-
12
- If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
13
-
14
- ```js
15
- export default tseslint.config([
16
- globalIgnores(['dist']),
17
- {
18
- files: ['**/*.{ts,tsx}'],
19
- extends: [
20
- // Other configs...
21
-
22
- // Remove tseslint.configs.recommended and replace with this
23
- ...tseslint.configs.recommendedTypeChecked,
24
- // Alternatively, use this for stricter rules
25
- ...tseslint.configs.strictTypeChecked,
26
- // Optionally, add this for stylistic rules
27
- ...tseslint.configs.stylisticTypeChecked,
28
-
29
- // Other configs...
30
- ],
31
- languageOptions: {
32
- parserOptions: {
33
- project: ['./tsconfig.node.json', './tsconfig.app.json'],
34
- tsconfigRootDir: import.meta.dirname,
35
- },
36
- // other options...
37
- },
38
- },
39
- ])
40
- ```
41
-
42
- You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
43
-
44
- ```js
45
- // eslint.config.js
46
- import reactX from 'eslint-plugin-react-x'
47
- import reactDom from 'eslint-plugin-react-dom'
48
-
49
- export default tseslint.config([
50
- globalIgnores(['dist']),
51
- {
52
- files: ['**/*.{ts,tsx}'],
53
- extends: [
54
- // Other configs...
55
- // Enable lint rules for React
56
- reactX.configs['recommended-typescript'],
57
- // Enable lint rules for React DOM
58
- reactDom.configs.recommended,
59
- ],
60
- languageOptions: {
61
- parserOptions: {
62
- project: ['./tsconfig.node.json', './tsconfig.app.json'],
63
- tsconfigRootDir: import.meta.dirname,
64
- },
65
- // other options...
66
- },
67
- },
68
- ])
69
- ```
@@ -1,23 +0,0 @@
1
- import js from '@eslint/js'
2
- import globals from 'globals'
3
- import reactHooks from 'eslint-plugin-react-hooks'
4
- import reactRefresh from 'eslint-plugin-react-refresh'
5
- import tseslint from 'typescript-eslint'
6
- import { globalIgnores } from 'eslint/config'
7
-
8
- export default tseslint.config([
9
- globalIgnores(['dist']),
10
- {
11
- files: ['**/*.{ts,tsx}'],
12
- extends: [
13
- js.configs.recommended,
14
- tseslint.configs.recommended,
15
- reactHooks.configs['recommended-latest'],
16
- reactRefresh.configs.vite,
17
- ],
18
- languageOptions: {
19
- ecmaVersion: 2020,
20
- globals: globals.browser,
21
- },
22
- },
23
- ])
package/demo/index.html DELETED
@@ -1,13 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/icon.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Demo</title>
8
- </head>
9
- <body>
10
- <div id="root"></div>
11
- <script type="module" src="/src/main.tsx"></script>
12
- </body>
13
- </html>