@sogni-ai/expo-client 1.0.0-alpha.2

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 (185) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +87 -0
  3. package/dist/cjs/Account/index.d.ts +39 -0
  4. package/dist/cjs/Account/index.d.ts.map +1 -0
  5. package/dist/cjs/Account/index.js +111 -0
  6. package/dist/cjs/Account/index.js.map +1 -0
  7. package/dist/cjs/Account/types.d.ts +25 -0
  8. package/dist/cjs/Account/types.d.ts.map +1 -0
  9. package/dist/cjs/Account/types.js +18 -0
  10. package/dist/cjs/Account/types.js.map +1 -0
  11. package/dist/cjs/ApiClient/WebSocketClient/events.d.ts +51 -0
  12. package/dist/cjs/ApiClient/WebSocketClient/events.d.ts.map +1 -0
  13. package/dist/cjs/ApiClient/WebSocketClient/events.js +3 -0
  14. package/dist/cjs/ApiClient/WebSocketClient/events.js.map +1 -0
  15. package/dist/cjs/ApiClient/WebSocketClient/index.d.ts +34 -0
  16. package/dist/cjs/ApiClient/WebSocketClient/index.d.ts.map +1 -0
  17. package/dist/cjs/ApiClient/WebSocketClient/index.js +183 -0
  18. package/dist/cjs/ApiClient/WebSocketClient/index.js.map +1 -0
  19. package/dist/cjs/ApiClient/WebSocketClient/normalize.d.ts +24 -0
  20. package/dist/cjs/ApiClient/WebSocketClient/normalize.d.ts.map +1 -0
  21. package/dist/cjs/ApiClient/WebSocketClient/normalize.js +87 -0
  22. package/dist/cjs/ApiClient/WebSocketClient/normalize.js.map +1 -0
  23. package/dist/cjs/ApiClient/WebSocketClient/types.d.ts +9 -0
  24. package/dist/cjs/ApiClient/WebSocketClient/types.d.ts.map +1 -0
  25. package/dist/cjs/ApiClient/WebSocketClient/types.js +3 -0
  26. package/dist/cjs/ApiClient/WebSocketClient/types.js.map +1 -0
  27. package/dist/cjs/ApiClient/WebSocketClient/wireTypes.d.ts +61 -0
  28. package/dist/cjs/ApiClient/WebSocketClient/wireTypes.d.ts.map +1 -0
  29. package/dist/cjs/ApiClient/WebSocketClient/wireTypes.js +11 -0
  30. package/dist/cjs/ApiClient/WebSocketClient/wireTypes.js.map +1 -0
  31. package/dist/cjs/ApiClient/index.d.ts +57 -0
  32. package/dist/cjs/ApiClient/index.d.ts.map +1 -0
  33. package/dist/cjs/ApiClient/index.js +75 -0
  34. package/dist/cjs/ApiClient/index.js.map +1 -0
  35. package/dist/cjs/index.d.ts +55 -0
  36. package/dist/cjs/index.d.ts.map +1 -0
  37. package/dist/cjs/index.js +108 -0
  38. package/dist/cjs/index.js.map +1 -0
  39. package/dist/cjs/lib/AuthManager/ApiKeyAuthManager.d.ts +15 -0
  40. package/dist/cjs/lib/AuthManager/ApiKeyAuthManager.d.ts.map +1 -0
  41. package/dist/cjs/lib/AuthManager/ApiKeyAuthManager.js +47 -0
  42. package/dist/cjs/lib/AuthManager/ApiKeyAuthManager.js.map +1 -0
  43. package/dist/cjs/lib/AuthManager/AuthManagerBase.d.ts +23 -0
  44. package/dist/cjs/lib/AuthManager/AuthManagerBase.d.ts.map +1 -0
  45. package/dist/cjs/lib/AuthManager/AuthManagerBase.js +14 -0
  46. package/dist/cjs/lib/AuthManager/AuthManagerBase.js.map +1 -0
  47. package/dist/cjs/lib/AuthManager/AuthStorage.d.ts +11 -0
  48. package/dist/cjs/lib/AuthManager/AuthStorage.d.ts.map +1 -0
  49. package/dist/cjs/lib/AuthManager/AuthStorage.js +50 -0
  50. package/dist/cjs/lib/AuthManager/AuthStorage.js.map +1 -0
  51. package/dist/cjs/lib/AuthManager/TokenAuthManager.d.ts +35 -0
  52. package/dist/cjs/lib/AuthManager/TokenAuthManager.d.ts.map +1 -0
  53. package/dist/cjs/lib/AuthManager/TokenAuthManager.js +164 -0
  54. package/dist/cjs/lib/AuthManager/TokenAuthManager.js.map +1 -0
  55. package/dist/cjs/lib/AuthManager/index.d.ts +7 -0
  56. package/dist/cjs/lib/AuthManager/index.d.ts.map +1 -0
  57. package/dist/cjs/lib/AuthManager/index.js +13 -0
  58. package/dist/cjs/lib/AuthManager/index.js.map +1 -0
  59. package/dist/cjs/lib/Cache.d.ts +12 -0
  60. package/dist/cjs/lib/Cache.d.ts.map +1 -0
  61. package/dist/cjs/lib/Cache.js +36 -0
  62. package/dist/cjs/lib/Cache.js.map +1 -0
  63. package/dist/cjs/lib/DefaultLogger.d.ts +17 -0
  64. package/dist/cjs/lib/DefaultLogger.d.ts.map +1 -0
  65. package/dist/cjs/lib/DefaultLogger.js +36 -0
  66. package/dist/cjs/lib/DefaultLogger.js.map +1 -0
  67. package/dist/cjs/lib/RestClient.d.ts +18 -0
  68. package/dist/cjs/lib/RestClient.d.ts.map +1 -0
  69. package/dist/cjs/lib/RestClient.js +67 -0
  70. package/dist/cjs/lib/RestClient.js.map +1 -0
  71. package/dist/cjs/lib/TypedEventEmitter.d.ts +16 -0
  72. package/dist/cjs/lib/TypedEventEmitter.d.ts.map +1 -0
  73. package/dist/cjs/lib/TypedEventEmitter.js +46 -0
  74. package/dist/cjs/lib/TypedEventEmitter.js.map +1 -0
  75. package/dist/cjs/lib/base64.d.ts +3 -0
  76. package/dist/cjs/lib/base64.d.ts.map +1 -0
  77. package/dist/cjs/lib/base64.js +21 -0
  78. package/dist/cjs/lib/base64.js.map +1 -0
  79. package/dist/cjs/lib/getUUID.d.ts +12 -0
  80. package/dist/cjs/lib/getUUID.d.ts.map +1 -0
  81. package/dist/cjs/lib/getUUID.js +29 -0
  82. package/dist/cjs/lib/getUUID.js.map +1 -0
  83. package/dist/cjs/lib/utils.d.ts +10 -0
  84. package/dist/cjs/lib/utils.d.ts.map +1 -0
  85. package/dist/cjs/lib/utils.js +24 -0
  86. package/dist/cjs/lib/utils.js.map +1 -0
  87. package/dist/cjs/types/ErrorData.d.ts +7 -0
  88. package/dist/cjs/types/ErrorData.d.ts.map +1 -0
  89. package/dist/cjs/types/ErrorData.js +3 -0
  90. package/dist/cjs/types/ErrorData.js.map +1 -0
  91. package/dist/cjs/types/json.d.ts +6 -0
  92. package/dist/cjs/types/json.d.ts.map +1 -0
  93. package/dist/cjs/types/json.js +3 -0
  94. package/dist/cjs/types/json.js.map +1 -0
  95. package/dist/cjs/types/token.d.ts +2 -0
  96. package/dist/cjs/types/token.d.ts.map +1 -0
  97. package/dist/cjs/types/token.js +3 -0
  98. package/dist/cjs/types/token.js.map +1 -0
  99. package/dist/cjs/version.d.ts +2 -0
  100. package/dist/cjs/version.d.ts.map +1 -0
  101. package/dist/cjs/version.js +5 -0
  102. package/dist/cjs/version.js.map +1 -0
  103. package/dist/cjs/wallet.d.ts +6 -0
  104. package/dist/cjs/wallet.d.ts.map +1 -0
  105. package/dist/cjs/wallet.js +6 -0
  106. package/dist/cjs/wallet.js.map +1 -0
  107. package/dist/esm/Account/index.js +106 -0
  108. package/dist/esm/Account/index.js.map +1 -0
  109. package/dist/esm/Account/types.js +15 -0
  110. package/dist/esm/Account/types.js.map +1 -0
  111. package/dist/esm/ApiClient/WebSocketClient/events.js +2 -0
  112. package/dist/esm/ApiClient/WebSocketClient/events.js.map +1 -0
  113. package/dist/esm/ApiClient/WebSocketClient/index.js +178 -0
  114. package/dist/esm/ApiClient/WebSocketClient/index.js.map +1 -0
  115. package/dist/esm/ApiClient/WebSocketClient/normalize.js +81 -0
  116. package/dist/esm/ApiClient/WebSocketClient/normalize.js.map +1 -0
  117. package/dist/esm/ApiClient/WebSocketClient/types.js +2 -0
  118. package/dist/esm/ApiClient/WebSocketClient/types.js.map +1 -0
  119. package/dist/esm/ApiClient/WebSocketClient/wireTypes.js +10 -0
  120. package/dist/esm/ApiClient/WebSocketClient/wireTypes.js.map +1 -0
  121. package/dist/esm/ApiClient/index.js +68 -0
  122. package/dist/esm/ApiClient/index.js.map +1 -0
  123. package/dist/esm/index.js +66 -0
  124. package/dist/esm/index.js.map +1 -0
  125. package/dist/esm/lib/AuthManager/ApiKeyAuthManager.js +42 -0
  126. package/dist/esm/lib/AuthManager/ApiKeyAuthManager.js.map +1 -0
  127. package/dist/esm/lib/AuthManager/AuthManagerBase.js +9 -0
  128. package/dist/esm/lib/AuthManager/AuthManagerBase.js.map +1 -0
  129. package/dist/esm/lib/AuthManager/AuthStorage.js +13 -0
  130. package/dist/esm/lib/AuthManager/AuthStorage.js.map +1 -0
  131. package/dist/esm/lib/AuthManager/TokenAuthManager.js +159 -0
  132. package/dist/esm/lib/AuthManager/TokenAuthManager.js.map +1 -0
  133. package/dist/esm/lib/AuthManager/index.js +5 -0
  134. package/dist/esm/lib/AuthManager/index.js.map +1 -0
  135. package/dist/esm/lib/Cache.js +33 -0
  136. package/dist/esm/lib/Cache.js.map +1 -0
  137. package/dist/esm/lib/DefaultLogger.js +32 -0
  138. package/dist/esm/lib/DefaultLogger.js.map +1 -0
  139. package/dist/esm/lib/RestClient.js +62 -0
  140. package/dist/esm/lib/RestClient.js.map +1 -0
  141. package/dist/esm/lib/TypedEventEmitter.js +44 -0
  142. package/dist/esm/lib/TypedEventEmitter.js.map +1 -0
  143. package/dist/esm/lib/base64.js +17 -0
  144. package/dist/esm/lib/base64.js.map +1 -0
  145. package/dist/esm/lib/getUUID.js +26 -0
  146. package/dist/esm/lib/getUUID.js.map +1 -0
  147. package/dist/esm/lib/utils.js +19 -0
  148. package/dist/esm/lib/utils.js.map +1 -0
  149. package/dist/esm/types/ErrorData.js +2 -0
  150. package/dist/esm/types/ErrorData.js.map +1 -0
  151. package/dist/esm/types/json.js +2 -0
  152. package/dist/esm/types/json.js.map +1 -0
  153. package/dist/esm/types/token.js +2 -0
  154. package/dist/esm/types/token.js.map +1 -0
  155. package/dist/esm/version.js +2 -0
  156. package/dist/esm/version.js.map +1 -0
  157. package/dist/esm/wallet.js +2 -0
  158. package/dist/esm/wallet.js.map +1 -0
  159. package/package.json +91 -0
  160. package/src/Account/index.ts +118 -0
  161. package/src/Account/types.ts +41 -0
  162. package/src/ApiClient/WebSocketClient/events.ts +60 -0
  163. package/src/ApiClient/WebSocketClient/index.ts +224 -0
  164. package/src/ApiClient/WebSocketClient/normalize.ts +104 -0
  165. package/src/ApiClient/WebSocketClient/types.ts +10 -0
  166. package/src/ApiClient/WebSocketClient/wireTypes.ts +63 -0
  167. package/src/ApiClient/index.ts +134 -0
  168. package/src/index.ts +141 -0
  169. package/src/lib/AuthManager/ApiKeyAuthManager.ts +52 -0
  170. package/src/lib/AuthManager/AuthManagerBase.ts +35 -0
  171. package/src/lib/AuthManager/AuthStorage.ts +21 -0
  172. package/src/lib/AuthManager/TokenAuthManager.ts +179 -0
  173. package/src/lib/AuthManager/index.ts +8 -0
  174. package/src/lib/Cache.ts +45 -0
  175. package/src/lib/DefaultLogger.ts +47 -0
  176. package/src/lib/RestClient.ts +77 -0
  177. package/src/lib/TypedEventEmitter.ts +52 -0
  178. package/src/lib/base64.ts +17 -0
  179. package/src/lib/getUUID.ts +27 -0
  180. package/src/lib/utils.ts +21 -0
  181. package/src/types/ErrorData.ts +7 -0
  182. package/src/types/json.ts +5 -0
  183. package/src/types/token.ts +1 -0
  184. package/src/version.ts +1 -0
  185. package/src/wallet.ts +6 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * The ONLY place where wire-level message shapes are translated into clean
3
+ * public types. Every quirk in the sogni-socket protocol gets masked here so
4
+ * the rest of the SDK and downstream apps never see them.
5
+ *
6
+ * Authoritative wire source:
7
+ * ../sogni-socket/controllers/jobsController.js
8
+ * ../sogni-socket/controllers/websocketsController.js
9
+ *
10
+ * Known quirks masked (catalog grows as later phases add events):
11
+ * - `jobID` on the wire is actually the PROJECT id (Phase 3)
12
+ * - `imgID` on the wire is actually the JOB id (Phase 3)
13
+ * - `error_message` is snake_case in an otherwise camelCase API (Phase 3)
14
+ * - `balanceUpdate` arrives in two shapes (v1 flat, v2 nested) — always
15
+ * normalized to v2 here.
16
+ * - `authenticated.tokens` similarly v1/v2 — normalized to v2.
17
+ */
18
+
19
+ import {
20
+ AuthenticatedEvent,
21
+ BalanceUpdateEvent,
22
+ Balances,
23
+ ChangeNetworkEvent,
24
+ ToastMessageEvent
25
+ } from './events';
26
+ import {
27
+ RawAuthenticated,
28
+ RawBalanceUpdate,
29
+ RawBalanceV1Tokens,
30
+ RawBalanceV2Tokens,
31
+ RawChangeNetwork,
32
+ RawToastMessage
33
+ } from './wireTypes';
34
+
35
+ function isV2Tokens(t: RawBalanceUpdate): t is RawBalanceV2Tokens {
36
+ return (
37
+ typeof t === 'object' && t !== null && 'sogni' in t && 'spark' in (t as RawBalanceV2Tokens)
38
+ );
39
+ }
40
+
41
+ function normalizeBalanceTokens(raw: RawBalanceUpdate): Balances {
42
+ if (isV2Tokens(raw)) {
43
+ return {
44
+ sogni: {
45
+ settled: String(raw.sogni.settled ?? '0'),
46
+ credit: String(raw.sogni.credit ?? '0'),
47
+ debit: String(raw.sogni.debit ?? '0'),
48
+ net: String(raw.sogni.net ?? '0')
49
+ },
50
+ spark: {
51
+ settled: String(raw.spark.settled ?? '0'),
52
+ credit: String(raw.spark.credit ?? '0'),
53
+ debit: String(raw.spark.debit ?? '0'),
54
+ net: String(raw.spark.net ?? '0'),
55
+ premiumCredit: String(raw.spark.premiumCredit ?? '0')
56
+ }
57
+ };
58
+ }
59
+ // v1 → synthesize v2 wrapper with empty spark
60
+ const v1 = raw as RawBalanceV1Tokens;
61
+ return {
62
+ sogni: {
63
+ settled: String(v1.settled ?? '0'),
64
+ credit: String(v1.credit ?? '0'),
65
+ debit: String(v1.debit ?? '0'),
66
+ net: String(v1.net ?? '0')
67
+ },
68
+ spark: {
69
+ settled: '0',
70
+ credit: '0',
71
+ debit: '0',
72
+ net: '0',
73
+ premiumCredit: '0'
74
+ }
75
+ };
76
+ }
77
+
78
+ export function normalizeAuthenticated(raw: RawAuthenticated): AuthenticatedEvent {
79
+ return {
80
+ username: raw.username,
81
+ walletAddress: raw.address,
82
+ balance: normalizeBalanceTokens(raw.tokens),
83
+ isMainnet: !!raw.isMainnet,
84
+ accountWasMigrated: !!raw.accountWasMigrated,
85
+ hasUnclaimedAirdrop: !!raw.hasUnclaimedAirdrop,
86
+ firstLoginAfterMigration: !!raw.firstLoginAfterMigration
87
+ };
88
+ }
89
+
90
+ export function normalizeBalanceUpdate(raw: RawBalanceUpdate): BalanceUpdateEvent {
91
+ return { balance: normalizeBalanceTokens(raw) };
92
+ }
93
+
94
+ export function normalizeChangeNetwork(raw: RawChangeNetwork): ChangeNetworkEvent {
95
+ return { network: raw.network };
96
+ }
97
+
98
+ export function normalizeToastMessage(raw: RawToastMessage): ToastMessageEvent {
99
+ return {
100
+ level: raw.type,
101
+ message: raw.message,
102
+ ...(raw.stickyID ? { stickyID: raw.stickyID } : {})
103
+ };
104
+ }
@@ -0,0 +1,10 @@
1
+ export type SupernetType = 'fast' | 'relaxed';
2
+
3
+ export type ConnectionStatus = 'disconnected' | 'connecting' | 'connected';
4
+
5
+ export interface SocketAuthData {
6
+ /** Headers sent in the WebSocket upgrade request. */
7
+ headers?: Record<string, string>;
8
+ /** Query string parameters appended to the WebSocket URL. */
9
+ queryParams?: Record<string, string>;
10
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Wire-level message shapes as the sogni-socket server sends them.
3
+ * These are NOT exposed to consumers. They are translated into clean public
4
+ * types by `normalize.ts`.
5
+ *
6
+ * Authoritative source: ../sogni-socket/controllers/jobsController.js and
7
+ * ../sogni-socket/controllers/websocketsController.js.
8
+ */
9
+
10
+ /** Envelope wrapping all socket messages in both directions. */
11
+ export interface RawSocketEnvelope {
12
+ type: string;
13
+ /** base64-encoded JSON.stringify(payload) */
14
+ data: string;
15
+ }
16
+
17
+ /** `authenticated` event — sent right after the server upgrades a connection. */
18
+ export interface RawAuthenticated {
19
+ id: string;
20
+ clientType: string;
21
+ username: string;
22
+ address: string;
23
+ SID: number;
24
+ clientSID: number;
25
+ addressSID: number;
26
+ balanceVersion?: 1 | 2;
27
+ /** v1: BigNumber/string; v2: { sogni, spark } */
28
+ tokens: RawBalanceV1Tokens | RawBalanceV2Tokens;
29
+ activeProjects: string[];
30
+ unclaimedCompletedProjects: string[];
31
+ isMainnet: boolean;
32
+ accountWasMigrated: boolean;
33
+ hasUnclaimedAirdrop: boolean;
34
+ firstLoginAfterMigration: boolean;
35
+ }
36
+
37
+ export interface RawBalanceV1Tokens {
38
+ settled: string;
39
+ credit: string;
40
+ debit: string;
41
+ net: string;
42
+ }
43
+
44
+ export interface RawBalanceV2Tokens {
45
+ sogni: RawBalanceV1Tokens & { premiumCredit?: string };
46
+ spark: RawBalanceV1Tokens & { premiumCredit?: string };
47
+ }
48
+
49
+ /** `balanceUpdate` event — fired when the user's balance changes. */
50
+ export type RawBalanceUpdate = RawBalanceV1Tokens | RawBalanceV2Tokens;
51
+
52
+ /** `changeNetwork` event — confirms a network switch. */
53
+ export interface RawChangeNetwork {
54
+ network: 'fast' | 'relaxed';
55
+ }
56
+
57
+ /** `toastMessage` event — server-initiated UI message. */
58
+ export interface RawToastMessage {
59
+ type: 'info' | 'success' | 'warning' | 'error';
60
+ message: string;
61
+ autoClose?: number;
62
+ stickyID?: string;
63
+ }
@@ -0,0 +1,134 @@
1
+ import RestClient from '../lib/RestClient';
2
+ import TypedEventEmitter from '../lib/TypedEventEmitter';
3
+ import { JSONValue } from '../types/json';
4
+ import { Logger } from '../lib/DefaultLogger';
5
+ import { ApiKeyAuthManager, AuthManager, AuthStorage, TokenAuthManager } from '../lib/AuthManager';
6
+ import WebSocketClient from './WebSocketClient';
7
+ import { SupernetType } from './WebSocketClient/types';
8
+ import { ConnectedEvent, DisconnectedEvent } from './WebSocketClient/events';
9
+
10
+ export interface ApiResponse<D = JSONValue> {
11
+ status: 'success';
12
+ data: D;
13
+ }
14
+
15
+ export interface ApiErrorResponse {
16
+ status: 'error';
17
+ message: string;
18
+ errorCode: number;
19
+ }
20
+
21
+ export class ApiError extends Error {
22
+ status: number;
23
+ payload: ApiErrorResponse;
24
+ constructor(status: number, payload: ApiErrorResponse) {
25
+ super(payload.message);
26
+ this.status = status;
27
+ this.payload = payload;
28
+ }
29
+ }
30
+
31
+ interface ApiClientEvents {
32
+ authUpdated: boolean;
33
+ connected: ConnectedEvent;
34
+ disconnected: DisconnectedEvent;
35
+ }
36
+
37
+ export interface ApiClientOptions {
38
+ baseUrl: string;
39
+ socketUrl: string;
40
+ appId: string;
41
+ appSource?: string;
42
+ networkType: SupernetType;
43
+ logger: Logger;
44
+ authType: 'token' | 'apiKey';
45
+ authStorage?: AuthStorage;
46
+ disableSocket?: boolean;
47
+ }
48
+
49
+ class ApiClient extends TypedEventEmitter<ApiClientEvents> {
50
+ readonly appId: string;
51
+ readonly appSource?: string;
52
+ readonly logger: Logger;
53
+ private _rest: RestClient;
54
+ private _auth: AuthManager;
55
+ private _socket: WebSocketClient;
56
+ private _disableSocket: boolean;
57
+
58
+ constructor({
59
+ baseUrl,
60
+ socketUrl,
61
+ appId,
62
+ appSource,
63
+ networkType,
64
+ authType,
65
+ logger,
66
+ authStorage,
67
+ disableSocket = false
68
+ }: ApiClientOptions) {
69
+ super();
70
+ this.appId = appId;
71
+ this.appSource = appSource?.trim() || undefined;
72
+ this.logger = logger;
73
+ this._disableSocket = disableSocket;
74
+ if (authType === 'apiKey') {
75
+ this._auth = new ApiKeyAuthManager(logger);
76
+ } else {
77
+ this._auth = new TokenAuthManager(baseUrl, logger, authStorage);
78
+ }
79
+ this._rest = new RestClient(baseUrl, this._auth, logger);
80
+ this._socket = new WebSocketClient(
81
+ socketUrl,
82
+ this._auth,
83
+ appId,
84
+ networkType,
85
+ logger,
86
+ this.appSource
87
+ );
88
+ this._auth.on('updated', (isAuthenticated) => {
89
+ this.emit('authUpdated', isAuthenticated);
90
+ this._handleAuthUpdated(isAuthenticated);
91
+ });
92
+ this._socket.on('connected', (e) => this.emit('connected', e));
93
+ this._socket.on('disconnected', (e) => this.emit('disconnected', e));
94
+ }
95
+
96
+ get isAuthenticated(): boolean {
97
+ return this._auth.isAuthenticated;
98
+ }
99
+
100
+ get auth(): AuthManager {
101
+ return this._auth;
102
+ }
103
+
104
+ get rest(): RestClient {
105
+ return this._rest;
106
+ }
107
+
108
+ get socket(): WebSocketClient {
109
+ return this._socket;
110
+ }
111
+
112
+ get socketEnabled(): boolean {
113
+ return !this._disableSocket;
114
+ }
115
+
116
+ private _handleAuthUpdated(isAuthenticated: boolean) {
117
+ if (this._disableSocket) return;
118
+ if (isAuthenticated && !this._socket.isConnected) {
119
+ void this._socket.connect();
120
+ } else if (!isAuthenticated && this._socket.isConnected) {
121
+ this._socket.disconnect();
122
+ }
123
+ }
124
+
125
+ dispose() {
126
+ this._socket.disconnect();
127
+ this._socket.removeAllListeners();
128
+ this._auth.removeAllListeners();
129
+ this.removeAllListeners();
130
+ this._auth.clear();
131
+ }
132
+ }
133
+
134
+ export default ApiClient;
package/src/index.ts ADDED
@@ -0,0 +1,141 @@
1
+ import AccountApi from './Account';
2
+ import { AccountSnapshot, Balances, MeData } from './Account/types';
3
+ import ApiClient, { ApiError, ApiErrorResponse, ApiResponse } from './ApiClient';
4
+ import { SupernetType } from './ApiClient/WebSocketClient/types';
5
+ import {
6
+ AuthenticatedEvent,
7
+ BalanceUpdateEvent,
8
+ ChangeNetworkEvent,
9
+ ConnectedEvent,
10
+ DisconnectedEvent,
11
+ ToastMessageEvent
12
+ } from './ApiClient/WebSocketClient/events';
13
+ import { DefaultLogger, Logger, LogLevel } from './lib/DefaultLogger';
14
+ import { ApiKeyAuthManager, AuthStorage, TokenAuthData, TokenAuthManager } from './lib/AuthManager';
15
+ import ErrorData from './types/ErrorData';
16
+ import { TokenType } from './types/token';
17
+ import { LIB_VERSION } from './version';
18
+
19
+ export type {
20
+ AccountSnapshot,
21
+ ApiErrorResponse,
22
+ ApiResponse,
23
+ AuthenticatedEvent,
24
+ AuthStorage,
25
+ Balances,
26
+ BalanceUpdateEvent,
27
+ ChangeNetworkEvent,
28
+ ConnectedEvent,
29
+ DisconnectedEvent,
30
+ ErrorData,
31
+ Logger,
32
+ LogLevel,
33
+ MeData,
34
+ SupernetType,
35
+ ToastMessageEvent,
36
+ TokenAuthData,
37
+ TokenType
38
+ };
39
+ export { ApiError, ApiKeyAuthManager, LIB_VERSION };
40
+
41
+ export interface SogniClientConfig {
42
+ /** Unique application ID. Multiple connections with the same ID will be rejected by the server. */
43
+ appId: string;
44
+ /** Optional source label for server-side attribution. */
45
+ appSource?: string;
46
+ /** Override the default REST API endpoint. Internal use. */
47
+ restEndpoint?: string;
48
+ /** Override the default WebSocket endpoint. Internal use. */
49
+ socketEndpoint?: string;
50
+ /** Which Supernet to connect to. Defaults to 'fast'. */
51
+ network?: SupernetType;
52
+ /** Connect to testnet instead of mainnet. */
53
+ testnet?: boolean;
54
+ /** API key for authentication. When provided, the client uses API key auth. */
55
+ apiKey?: string;
56
+ /** Authentication type. Defaults to 'token'. Forced to 'apiKey' when apiKey is provided. */
57
+ authType?: 'token' | 'apiKey';
58
+ /** Logger instance. Defaults to a console-backed logger at logLevel. */
59
+ logger?: Logger;
60
+ /** Log level for the default logger. Ignored if a custom logger is provided. */
61
+ logLevel?: LogLevel;
62
+ /** Custom storage adapter for token persistence. Defaults to expo-secure-store. */
63
+ authStorage?: AuthStorage;
64
+ /** Disable the WebSocket connection. Most APIs will not work without it. */
65
+ disableSocket?: boolean;
66
+ }
67
+
68
+ function assertCryptoPolyfill(): void {
69
+ if (
70
+ typeof globalThis.crypto === 'undefined' ||
71
+ typeof globalThis.crypto.getRandomValues !== 'function'
72
+ ) {
73
+ throw new Error(
74
+ "@sogni-ai/expo-client requires crypto.getRandomValues. Add `import 'expo-standard-web-crypto/polyfill'` at your app entry point (e.g. app/_layout.tsx). See README for details."
75
+ );
76
+ }
77
+ }
78
+
79
+ export class SogniClient {
80
+ apiClient: ApiClient;
81
+ account: AccountApi;
82
+
83
+ private constructor(client: ApiClient) {
84
+ this.apiClient = client;
85
+ this.account = new AccountApi(client);
86
+ }
87
+
88
+ get isAuthenticated(): boolean {
89
+ return this.apiClient.isAuthenticated;
90
+ }
91
+
92
+ /**
93
+ * For token-based auth, restore a session from refresh+access tokens.
94
+ * Typically called once at app startup; the SDK also auto-restores from
95
+ * secure storage in `create()`, so this is only needed when migrating
96
+ * tokens from another source.
97
+ */
98
+ async setTokens(tokens: TokenAuthData): Promise<void> {
99
+ const auth = this.apiClient.auth;
100
+ if (!(auth instanceof TokenAuthManager)) {
101
+ throw new Error('setTokens can only be used with token authentication');
102
+ }
103
+ await auth.authenticate(tokens);
104
+ }
105
+
106
+ /** Disconnect and tear down resources. Instance should not be reused after dispose(). */
107
+ dispose() {
108
+ this.apiClient.dispose();
109
+ }
110
+
111
+ static async create(config: SogniClientConfig): Promise<SogniClient> {
112
+ assertCryptoPolyfill();
113
+
114
+ const restEndpoint = config.restEndpoint || 'https://api.sogni.ai';
115
+ const socketEndpoint = config.socketEndpoint || 'wss://socket.sogni.ai';
116
+ const network: SupernetType = config.network || 'fast';
117
+ const logger = config.logger || new DefaultLogger(config.logLevel || 'warn');
118
+ const authType: 'token' | 'apiKey' = config.apiKey ? 'apiKey' : config.authType || 'token';
119
+
120
+ const apiClient = new ApiClient({
121
+ baseUrl: restEndpoint,
122
+ socketUrl: socketEndpoint,
123
+ appId: config.appId,
124
+ appSource: config.appSource,
125
+ networkType: network,
126
+ authType,
127
+ logger,
128
+ authStorage: config.authStorage,
129
+ disableSocket: config.disableSocket
130
+ });
131
+
132
+ if (config.apiKey) {
133
+ const auth = apiClient.auth as ApiKeyAuthManager;
134
+ await auth.authenticate(config.apiKey);
135
+ } else if (apiClient.auth instanceof TokenAuthManager) {
136
+ await apiClient.auth.restore();
137
+ }
138
+
139
+ return new SogniClient(apiClient);
140
+ }
141
+ }
@@ -0,0 +1,52 @@
1
+ import AuthManagerBase from './AuthManagerBase';
2
+ import { Logger } from '../DefaultLogger';
3
+ import { SocketAuthData } from '../../ApiClient/WebSocketClient/types';
4
+
5
+ class ApiKeyAuthManager extends AuthManagerBase<string | null> {
6
+ private _apiKey?: string;
7
+
8
+ constructor(logger: Logger) {
9
+ super(logger);
10
+ }
11
+
12
+ get isAuthenticated() {
13
+ return !!this._apiKey;
14
+ }
15
+
16
+ async authenticate(apiKey: string): Promise<void> {
17
+ if (this._apiKey === apiKey) {
18
+ return;
19
+ }
20
+ this._apiKey = apiKey;
21
+ this.emit('updated', true);
22
+ }
23
+
24
+ clear() {
25
+ if (!this._apiKey) {
26
+ return;
27
+ }
28
+ this._apiKey = undefined;
29
+ this.emit('updated', false);
30
+ }
31
+
32
+ async backup(): Promise<string | null> {
33
+ return this._apiKey || null;
34
+ }
35
+
36
+ async authenticateRequest(options: RequestInit): Promise<RequestInit> {
37
+ if (!this._apiKey) {
38
+ return options;
39
+ }
40
+ return {
41
+ ...options,
42
+ headers: { ...options.headers, 'api-key': this._apiKey }
43
+ };
44
+ }
45
+
46
+ async socketAuth(): Promise<SocketAuthData> {
47
+ if (!this._apiKey) return {};
48
+ return { queryParams: { apiKey: this._apiKey } };
49
+ }
50
+ }
51
+
52
+ export default ApiKeyAuthManager;
@@ -0,0 +1,35 @@
1
+ import { Logger } from '../DefaultLogger';
2
+ import TypedEventEmitter from '../TypedEventEmitter';
3
+ import { SocketAuthData } from '../../ApiClient/WebSocketClient/types';
4
+
5
+ interface AuthManagerEvents {
6
+ updated: boolean;
7
+ }
8
+
9
+ abstract class AuthManagerBase<AuthData = never> extends TypedEventEmitter<AuthManagerEvents> {
10
+ protected _logger: Logger;
11
+
12
+ constructor(logger: Logger) {
13
+ super();
14
+ this._logger = logger;
15
+ }
16
+
17
+ abstract get isAuthenticated(): boolean;
18
+
19
+ abstract authenticateRequest(option: RequestInit): Promise<RequestInit>;
20
+
21
+ /**
22
+ * Describe how to authenticate the WebSocket upgrade request. May return
23
+ * headers (preferred for JWT tokens), query params (preferred for API keys),
24
+ * or both. Empty object means unauthenticated.
25
+ */
26
+ abstract socketAuth(): Promise<SocketAuthData>;
27
+
28
+ abstract backup(): Promise<AuthData>;
29
+
30
+ abstract authenticate(data: AuthData): Promise<void>;
31
+
32
+ abstract clear(): void;
33
+ }
34
+
35
+ export default AuthManagerBase;
@@ -0,0 +1,21 @@
1
+ import * as SecureStore from 'expo-secure-store';
2
+
3
+ export interface AuthStorage {
4
+ getItem(key: string): Promise<string | null>;
5
+ setItem(key: string, value: string): Promise<void>;
6
+ removeItem(key: string): Promise<void>;
7
+ }
8
+
9
+ export class ExpoSecureStorage implements AuthStorage {
10
+ async getItem(key: string): Promise<string | null> {
11
+ return SecureStore.getItemAsync(key);
12
+ }
13
+
14
+ async setItem(key: string, value: string): Promise<void> {
15
+ await SecureStore.setItemAsync(key, value);
16
+ }
17
+
18
+ async removeItem(key: string): Promise<void> {
19
+ await SecureStore.deleteItemAsync(key);
20
+ }
21
+ }