@keyringnetwork/keyring-connect-sdk 3.2.0 → 4.1.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 (68) hide show
  1. package/dist/core/VerificationSession.d.ts +62 -0
  2. package/dist/core/VerificationSession.js +404 -0
  3. package/dist/core/errors.d.ts +49 -0
  4. package/dist/core/errors.js +81 -0
  5. package/dist/core/htppClient.d.ts +17 -0
  6. package/dist/core/htppClient.js +160 -0
  7. package/dist/{main.d.ts → core/keyringConnectExtension.d.ts} +6 -4
  8. package/dist/{main.js → core/keyringConnectExtension.js} +33 -16
  9. package/dist/core/websocketClient.d.ts +23 -0
  10. package/dist/core/websocketClient.js +220 -0
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.js +3 -3
  13. package/dist/types/api.d.ts +24 -0
  14. package/dist/types/api.js +2 -0
  15. package/dist/types/core.d.ts +78 -0
  16. package/dist/types/core.js +2 -0
  17. package/dist/{types.d.ts → types/extension.d.ts} +2 -49
  18. package/dist/types/index.d.ts +4 -0
  19. package/dist/types/index.js +20 -0
  20. package/dist/types/websocket.d.ts +68 -0
  21. package/dist/types/websocket.js +3 -0
  22. package/dist/ui/UIManager.d.ts +52 -0
  23. package/dist/ui/UIManager.js +257 -0
  24. package/dist/ui/components/keyring-button.d.ts +12 -0
  25. package/dist/ui/components/keyring-button.js +140 -0
  26. package/dist/ui/components/keyring-text.d.ts +12 -0
  27. package/dist/ui/components/keyring-text.js +169 -0
  28. package/dist/ui/composites/keyring-complete-modal.d.ts +19 -0
  29. package/dist/ui/composites/keyring-complete-modal.js +200 -0
  30. package/dist/ui/composites/keyring-mobile-modal.d.ts +25 -0
  31. package/dist/ui/composites/keyring-mobile-modal.js +308 -0
  32. package/dist/ui/composites/keyring-qr-modal.d.ts +32 -0
  33. package/dist/ui/composites/keyring-qr-modal.js +464 -0
  34. package/dist/ui/composites/keyring-selection-modal.d.ts +25 -0
  35. package/dist/ui/composites/keyring-selection-modal.js +342 -0
  36. package/dist/ui/composites/keyring-terminated-modal.d.ts +14 -0
  37. package/dist/ui/composites/keyring-terminated-modal.js +121 -0
  38. package/dist/ui/icons/apple-icon.d.ts +4 -0
  39. package/dist/ui/icons/apple-icon.js +47 -0
  40. package/dist/ui/icons/check-circle.d.ts +4 -0
  41. package/dist/ui/icons/check-circle.js +35 -0
  42. package/dist/ui/icons/checkmark.d.ts +4 -0
  43. package/dist/ui/icons/checkmark.js +37 -0
  44. package/dist/ui/icons/close-circle.d.ts +4 -0
  45. package/dist/ui/icons/close-circle.js +35 -0
  46. package/dist/ui/icons/error-circle.d.ts +4 -0
  47. package/dist/ui/icons/error-circle.js +48 -0
  48. package/dist/ui/icons/extension-grid.d.ts +4 -0
  49. package/dist/ui/icons/extension-grid.js +79 -0
  50. package/dist/ui/icons/google-icon.d.ts +4 -0
  51. package/dist/ui/icons/google-icon.js +55 -0
  52. package/dist/ui/icons/gradient-donut.d.ts +8 -0
  53. package/dist/ui/icons/gradient-donut.js +85 -0
  54. package/dist/ui/icons/keyring.d.ts +4 -0
  55. package/dist/ui/icons/keyring.js +71 -0
  56. package/dist/ui/icons/mobile-grid.d.ts +4 -0
  57. package/dist/ui/icons/mobile-grid.js +68 -0
  58. package/dist/ui/icons/success.d.ts +4 -0
  59. package/dist/ui/icons/success.js +54 -0
  60. package/dist/utils/environment.d.ts +34 -0
  61. package/dist/utils/environment.js +67 -0
  62. package/dist/utils/logger.d.ts +7 -0
  63. package/dist/utils/logger.js +40 -0
  64. package/dist/utils/platformUtils.d.ts +24 -0
  65. package/dist/utils/platformUtils.js +64 -0
  66. package/package.json +29 -14
  67. package/readme.md +57 -105
  68. /package/dist/{types.js → types/extension.js} +0 -0
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.HttpClient = void 0;
16
+ const axios_1 = __importDefault(require("axios"));
17
+ const environment_1 = require("../utils/environment");
18
+ const logger_1 = require("../utils/logger");
19
+ const platformUtils_1 = require("../utils/platformUtils");
20
+ const errors_1 = require("./errors");
21
+ class HttpClient {
22
+ constructor(apiKey) {
23
+ this.logger = logger_1.KeyringLogger.init("HttpClient");
24
+ this.httpClient = axios_1.default.create({
25
+ baseURL: environment_1.Environment.getConfig().apiUrl,
26
+ timeout: environment_1.Environment.getConfig().timeout,
27
+ headers: {
28
+ "Content-Type": "application/json",
29
+ "X-API-KEY": apiKey,
30
+ },
31
+ });
32
+ this.setupAxiosInterceptors();
33
+ this.logger.debug({ apiUrl: environment_1.Environment.getConfig().apiUrl }, "HTTP client initialized");
34
+ HttpClient.instance = this;
35
+ }
36
+ setupAxiosInterceptors() {
37
+ this.httpClient.interceptors.request.use((config) => {
38
+ var _a;
39
+ this.logger.debug({ method: (_a = config.method) === null || _a === void 0 ? void 0 : _a.toUpperCase(), url: config.url }, "HTTP Request");
40
+ return config;
41
+ }, (error) => {
42
+ this.logger.error("HTTP Request failed", error);
43
+ return Promise.reject(errors_1.KeyringError.fromUnknown(error));
44
+ });
45
+ this.httpClient.interceptors.response.use((response) => {
46
+ this.logger.debug({ status: response.status, url: response.config.url }, "HTTP Response");
47
+ return response;
48
+ }, (error) => {
49
+ var _a, _b, _c;
50
+ this.logger.error({
51
+ status: (_a = error.response) === null || _a === void 0 ? void 0 : _a.status,
52
+ url: (_b = error.config) === null || _b === void 0 ? void 0 : _b.url,
53
+ message: error.message || ((_c = error.response) === null || _c === void 0 ? void 0 : _c.data),
54
+ }, "HTTP Response error");
55
+ return Promise.reject(errors_1.KeyringError.fromUnknown(error));
56
+ });
57
+ }
58
+ static initializeHttpClient(apiKey) {
59
+ if (!this.instance) {
60
+ this.instance = new HttpClient(apiKey);
61
+ }
62
+ return this.instance;
63
+ }
64
+ createSession(sessionConfig) {
65
+ return __awaiter(this, void 0, void 0, function* () {
66
+ this.logger.debug("Creating session on backend");
67
+ const response = yield this.httpClient.post("/api/v1/connect/sessions/create", {
68
+ config: sessionConfig,
69
+ origin_url: platformUtils_1.PlatformUtils.isBrowser() ? window.location.href : "server",
70
+ });
71
+ this.logger.debug({ sessionId: response.data.session_id, expiresAt: response.data.expires_at }, "Session creation response received");
72
+ return response.data;
73
+ });
74
+ }
75
+ closeSession(sessionId, sessionToken) {
76
+ return __awaiter(this, void 0, void 0, function* () {
77
+ yield this.httpClient.delete(`/api/v1/connect/sessions/${sessionId}`, {
78
+ headers: {
79
+ "X-SESSION-TOKEN": sessionToken,
80
+ },
81
+ });
82
+ });
83
+ }
84
+ getSession(sessionId, sessionToken) {
85
+ return __awaiter(this, void 0, void 0, function* () {
86
+ var _a, _b, _c;
87
+ this.logger.debug({ sessionId }, "Getting session from backend");
88
+ try {
89
+ const response = yield this.httpClient.get(`/api/v1/connect/sessions/${sessionId}`, {
90
+ headers: {
91
+ "x-session-token": sessionToken,
92
+ },
93
+ });
94
+ // Handle 204 No Content (session deleted/expired)
95
+ if (response.status === 204 || !response.data) {
96
+ this.logger.debug({ sessionId }, "Session not found (204 or empty response)");
97
+ return null;
98
+ }
99
+ this.logger.debug({ sessionId: response.data.session_id, status: response.data.status }, "Session retrieved");
100
+ return response.data;
101
+ }
102
+ catch (error) {
103
+ // Return null for 404 or 401 (session not found or expired)
104
+ if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404 || ((_b = error.response) === null || _b === void 0 ? void 0 : _b.status) === 401) {
105
+ this.logger.debug({ sessionId, status: (_c = error.response) === null || _c === void 0 ? void 0 : _c.status }, "Session not found");
106
+ return null;
107
+ }
108
+ // Re-throw other errors
109
+ throw error;
110
+ }
111
+ });
112
+ }
113
+ /**
114
+ * Start polling for session updates
115
+ * Returns a function to stop polling
116
+ */
117
+ startPolling(sessionId, sessionToken, onUpdate, onError, interval = 2000) {
118
+ this.logger.debug({ sessionId, interval }, "Starting session polling");
119
+ let isPolling = true;
120
+ let timeoutId = null;
121
+ const poll = () => __awaiter(this, void 0, void 0, function* () {
122
+ if (!isPolling)
123
+ return;
124
+ try {
125
+ const session = yield this.getSession(sessionId, sessionToken);
126
+ // Stop polling if session not found (expired or deleted)
127
+ if (!session) {
128
+ this.logger.debug({ sessionId }, "Session not found, stopping polling");
129
+ isPolling = false;
130
+ onError(new Error("Session not found or expired"));
131
+ return;
132
+ }
133
+ onUpdate(session);
134
+ // Continue polling if still active
135
+ if (isPolling) {
136
+ timeoutId = setTimeout(poll, interval);
137
+ }
138
+ }
139
+ catch (error) {
140
+ this.logger.error(error, "Polling error");
141
+ onError(error);
142
+ // Continue polling despite errors (network might be temporarily down)
143
+ if (isPolling) {
144
+ timeoutId = setTimeout(poll, interval);
145
+ }
146
+ }
147
+ });
148
+ // Start polling
149
+ poll();
150
+ // Return stop function
151
+ return () => {
152
+ this.logger.debug({ sessionId }, "Stopping session polling");
153
+ isPolling = false;
154
+ if (timeoutId) {
155
+ clearTimeout(timeoutId);
156
+ }
157
+ };
158
+ }
159
+ }
160
+ exports.HttpClient = HttpClient;
@@ -1,11 +1,14 @@
1
- import { ExtensionSDKConfig, ExtensionState } from "./types";
1
+ import { CredentialData, ExtensionState, SessionConfig } from "../types";
2
2
  /**
3
3
  * Class for interacting with the Keyring Connect browser extension
4
4
  */
5
- export declare class KeyringConnect {
5
+ export declare class KeyringConnectExtension {
6
6
  private static readonly EXTENSION_TIMEOUT;
7
7
  private static readonly EXTENSION_ID;
8
8
  private static keyringConnectUrl;
9
+ private static resultPromise?;
10
+ private static resolveResult?;
11
+ private static rejectResult?;
9
12
  /**
10
13
  * Tries to launch the Keyring Connect Extension with the provided configuration.
11
14
  * If the extension is not installed, it will redirect to the Keyring Connect page.
@@ -14,7 +17,7 @@ export declare class KeyringConnect {
14
17
  * if extension communication times out, or if the extension returns an error.
15
18
  * @param data - The configuration for the extension
16
19
  */
17
- static launchExtension(data: ExtensionSDKConfig): Promise<void>;
20
+ static launchExtension(data: SessionConfig): Promise<CredentialData | null>;
18
21
  /**
19
22
  * Check if Keyring Connect Extension is installed and ready to use
20
23
  * @returns Promise that resolves with true if extension is installed and ready to use, false otherwise
@@ -38,6 +41,5 @@ export declare class KeyringConnect {
38
41
  private static validateCredentialConfig;
39
42
  private static validateConfigData;
40
43
  private static convertToLaunchConfig;
41
- private static isChromeRuntimeAvailable;
42
44
  private static sendChromeMessage;
43
45
  }
@@ -9,12 +9,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.KeyringConnect = void 0;
13
- const types_1 = require("./types");
12
+ exports.KeyringConnectExtension = void 0;
13
+ const types_1 = require("../types");
14
+ const platformUtils_1 = require("../utils/platformUtils");
14
15
  /**
15
16
  * Class for interacting with the Keyring Connect browser extension
16
17
  */
17
- class KeyringConnect {
18
+ class KeyringConnectExtension {
18
19
  /**
19
20
  * Tries to launch the Keyring Connect Extension with the provided configuration.
20
21
  * If the extension is not installed, it will redirect to the Keyring Connect page.
@@ -35,14 +36,36 @@ class KeyringConnect {
35
36
  else {
36
37
  throw new Error("Keyring Connect is not installed");
37
38
  }
38
- return;
39
+ return null;
39
40
  }
41
+ // Create result promise that will be resolved when verification completes
42
+ this.resultPromise = new Promise((resolve, reject) => {
43
+ this.resolveResult = resolve;
44
+ this.rejectResult = reject;
45
+ });
40
46
  const validatedConfig = this.validateConfigData(data);
41
47
  const launchConfig = this.convertToLaunchConfig(validatedConfig);
42
48
  yield this.sendChromeMessage({
43
49
  type: types_1.EVENT_ACTIONS.LAUNCH_KEYRING_CONNECT,
44
50
  data: launchConfig,
45
51
  });
52
+ const unsubscribe = this.subscribeToExtensionState((state) => {
53
+ var _a, _b, _c;
54
+ if ((state === null || state === void 0 ? void 0 : state.status) === "credential_success") {
55
+ if (!state.credentialData) {
56
+ (_a = this.rejectResult) === null || _a === void 0 ? void 0 : _a.call(this, new Error("No credential data found"));
57
+ }
58
+ else {
59
+ (_b = this.resolveResult) === null || _b === void 0 ? void 0 : _b.call(this, state.credentialData);
60
+ }
61
+ unsubscribe();
62
+ }
63
+ else if (state === null || state === void 0 ? void 0 : state.error) {
64
+ (_c = this.rejectResult) === null || _c === void 0 ? void 0 : _c.call(this, new Error(state.error));
65
+ unsubscribe();
66
+ }
67
+ });
68
+ return this.resultPromise;
46
69
  });
47
70
  }
48
71
  /**
@@ -66,7 +89,7 @@ class KeyringConnect {
66
89
  setTimeout(() => resolve(null), this.EXTENSION_TIMEOUT);
67
90
  });
68
91
  // Check if Chrome is available first
69
- if (!this.isChromeRuntimeAvailable()) {
92
+ if (!platformUtils_1.PlatformUtils.isChromeRuntimeAvailable()) {
70
93
  return null;
71
94
  }
72
95
  let extensionResponse;
@@ -153,14 +176,12 @@ class KeyringConnect {
153
176
  return config;
154
177
  }
155
178
  static convertToLaunchConfig(config) {
156
- var _a;
157
179
  const launchConfig = {
158
180
  client: {
159
181
  client_name: config.name,
160
182
  client_app_url: config.app_url,
161
183
  client_logo_url: config.logo_url,
162
184
  client_policy_id: config.policy_id,
163
- client_entity_id: (_a = config.krn_config) === null || _a === void 0 ? void 0 : _a.entity_id,
164
185
  credential_config: config.credential_config,
165
186
  },
166
187
  krn_config: config.krn_config
@@ -175,14 +196,10 @@ class KeyringConnect {
175
196
  };
176
197
  return launchConfig;
177
198
  }
178
- static isChromeRuntimeAvailable() {
179
- var _a;
180
- return typeof ((_a = chrome === null || chrome === void 0 ? void 0 : chrome.runtime) === null || _a === void 0 ? void 0 : _a.sendMessage) === "function";
181
- }
182
199
  static sendChromeMessage(message) {
183
200
  return __awaiter(this, void 0, void 0, function* () {
184
201
  return new Promise((resolve, reject) => {
185
- if (!this.isChromeRuntimeAvailable()) {
202
+ if (!platformUtils_1.PlatformUtils.isChromeRuntimeAvailable()) {
186
203
  reject(new Error("Chrome runtime not available"));
187
204
  return;
188
205
  }
@@ -218,7 +235,7 @@ class KeyringConnect {
218
235
  });
219
236
  }
220
237
  }
221
- exports.KeyringConnect = KeyringConnect;
222
- KeyringConnect.EXTENSION_TIMEOUT = 2000;
223
- KeyringConnect.EXTENSION_ID = "jgogeidclfccfoedhfjjaclnaojcllpi";
224
- KeyringConnect.keyringConnectUrl = "https://app.keyring.network/connect";
238
+ exports.KeyringConnectExtension = KeyringConnectExtension;
239
+ KeyringConnectExtension.EXTENSION_TIMEOUT = 2000;
240
+ KeyringConnectExtension.EXTENSION_ID = "jgogeidclfccfoedhfjjaclnaojcllpi";
241
+ KeyringConnectExtension.keyringConnectUrl = "https://app.keyring.network/connect";
@@ -0,0 +1,23 @@
1
+ import { SDKCallbacks, WebSocketMessage } from "../types";
2
+ export declare class KeyringWebSocketClient {
3
+ private logger;
4
+ private socket;
5
+ private sessionId;
6
+ private sessionToken;
7
+ private wsUrl;
8
+ private callbacks;
9
+ private reconnectAttempts;
10
+ private maxReconnectAttempts;
11
+ private heartbeatInterval;
12
+ private isConnected;
13
+ constructor(sessionId: string, sessionToken: string, callbacks: SDKCallbacks);
14
+ connect(): Promise<void>;
15
+ private handleMessage;
16
+ sendMessage(message: Partial<WebSocketMessage>): void;
17
+ private startHeartbeat;
18
+ private scheduleReconnect;
19
+ private cleanup;
20
+ disconnect(): void;
21
+ getConnectionState(): string;
22
+ private createError;
23
+ }
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.KeyringWebSocketClient = void 0;
13
+ const environment_1 = require("../utils/environment");
14
+ const logger_1 = require("../utils/logger");
15
+ class KeyringWebSocketClient {
16
+ constructor(sessionId, sessionToken, callbacks) {
17
+ this.socket = null;
18
+ this.wsUrl = environment_1.Environment.getConfig().apiUrl;
19
+ this.reconnectAttempts = 0;
20
+ this.maxReconnectAttempts = 5;
21
+ this.heartbeatInterval = null;
22
+ this.isConnected = false;
23
+ this.sessionId = sessionId;
24
+ this.sessionToken = sessionToken;
25
+ this.callbacks = callbacks;
26
+ this.logger = logger_1.KeyringLogger.init("KeyringWebSocketClient").child({
27
+ sessionId,
28
+ wsUrl: this.wsUrl,
29
+ });
30
+ }
31
+ connect() {
32
+ return __awaiter(this, void 0, void 0, function* () {
33
+ return new Promise((resolve, reject) => {
34
+ try {
35
+ // Convert HTTP/HTTPS URL to WS/WSS for native WebSocket
36
+ const wsUrl = this.wsUrl.replace("http://", "ws://").replace("https://", "wss://");
37
+ // Build WebSocket URL with sessionId and sessionToken
38
+ const url = `${wsUrl}/ws/connect/session?sessionId=${encodeURIComponent(this.sessionId)}&sessionToken=${encodeURIComponent(this.sessionToken)}`;
39
+ this.logger.debug({
40
+ wsUrl,
41
+ sessionId: this.sessionId,
42
+ hasSessionToken: !!this.sessionToken,
43
+ }, "Connecting to WebSocket");
44
+ this.socket = new WebSocket(url);
45
+ this.socket.onopen = () => {
46
+ var _a, _b;
47
+ this.logger.info("WebSocket connected successfully");
48
+ this.isConnected = true;
49
+ this.reconnectAttempts = 0;
50
+ this.startHeartbeat();
51
+ (_b = (_a = this.callbacks).onConnectionStatusChanged) === null || _b === void 0 ? void 0 : _b.call(_a, true);
52
+ resolve();
53
+ };
54
+ this.socket.onmessage = (event) => {
55
+ try {
56
+ const message = JSON.parse(event.data);
57
+ this.handleMessage(message);
58
+ }
59
+ catch (error) {
60
+ this.logger.error({ error, data: event.data }, "Failed to parse WebSocket message");
61
+ }
62
+ };
63
+ this.socket.onclose = (event) => {
64
+ var _a, _b;
65
+ if (!this.isConnected)
66
+ return;
67
+ this.logger.info({ code: event.code, reason: event.reason }, "WebSocket disconnected");
68
+ this.isConnected = false;
69
+ this.cleanup();
70
+ if (event.code !== 1000) {
71
+ if (this.reconnectAttempts < this.maxReconnectAttempts) {
72
+ this.scheduleReconnect();
73
+ }
74
+ }
75
+ else {
76
+ (_b = (_a = this.callbacks).onConnectionStatusChanged) === null || _b === void 0 ? void 0 : _b.call(_a, false);
77
+ }
78
+ };
79
+ this.socket.onerror = (error) => {
80
+ var _a, _b;
81
+ this.logger.error({ error, sessionId: this.sessionId }, "WebSocket error");
82
+ (_b = (_a = this.callbacks).onConnectionStatusChanged) === null || _b === void 0 ? void 0 : _b.call(_a, false);
83
+ reject(error);
84
+ };
85
+ // Set connection timeout
86
+ setTimeout(() => {
87
+ if (this.socket && !this.isConnected) {
88
+ this.socket.close();
89
+ reject(new Error("WebSocket connection timeout"));
90
+ }
91
+ }, 10000); // 10 second timeout
92
+ }
93
+ catch (error) {
94
+ reject(error);
95
+ }
96
+ });
97
+ });
98
+ }
99
+ handleMessage(message) {
100
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
101
+ try {
102
+ this.logger.debug({ message }, "Received message");
103
+ switch (message.type) {
104
+ case "connected":
105
+ this.logger.info("Connection confirmed by server");
106
+ break;
107
+ case "mobile_connected":
108
+ (_b = (_a = this.callbacks).onMobileConnected) === null || _b === void 0 ? void 0 : _b.call(_a, message.data);
109
+ break;
110
+ case "processing_started":
111
+ (_d = (_c = this.callbacks).onProcessingStarted) === null || _d === void 0 ? void 0 : _d.call(_c, message.data);
112
+ break;
113
+ case "processing_completed":
114
+ (_f = (_e = this.callbacks).onProcessingCompleted) === null || _f === void 0 ? void 0 : _f.call(_e, message.data);
115
+ break;
116
+ case "processing_failed":
117
+ (_h = (_g = this.callbacks).onProcessingFailed) === null || _h === void 0 ? void 0 : _h.call(_g, message.data);
118
+ break;
119
+ case "session_expired":
120
+ (_k = (_j = this.callbacks).onSessionExpired) === null || _k === void 0 ? void 0 : _k.call(_j, message.data);
121
+ this.disconnect();
122
+ break;
123
+ case "error":
124
+ (_m = (_l = this.callbacks).onError) === null || _m === void 0 ? void 0 : _m.call(_l, this.createError("MOBILE_PROCESSING_FAILED", message.data.message || "Mobile processing error", message.data));
125
+ break;
126
+ case "heartbeat_response":
127
+ this.logger.debug("Heartbeat response received");
128
+ break;
129
+ default:
130
+ this.logger.warn({ messageType: message.type }, "Unknown message type");
131
+ }
132
+ }
133
+ catch (error) {
134
+ this.logger.error({ error }, "Error handling WebSocket message");
135
+ (_p = (_o = this.callbacks).onError) === null || _p === void 0 ? void 0 : _p.call(_o, this.createError("NETWORK_ERROR", "Failed to handle WebSocket message", error));
136
+ }
137
+ }
138
+ sendMessage(message) {
139
+ var _a, _b;
140
+ if (!this.socket || !this.isConnected || this.socket.readyState !== WebSocket.OPEN) {
141
+ this.logger.warn("Cannot send message - WebSocket not connected");
142
+ return;
143
+ }
144
+ const fullMessage = Object.assign({ session_id: this.sessionId, timestamp: Date.now() }, message);
145
+ try {
146
+ this.socket.send(JSON.stringify(fullMessage));
147
+ this.logger.debug({ message: fullMessage }, "Sent message");
148
+ }
149
+ catch (error) {
150
+ this.logger.error({ error }, "Error sending message");
151
+ (_b = (_a = this.callbacks).onError) === null || _b === void 0 ? void 0 : _b.call(_a, this.createError("WEBSOCKET_CONNECTION_FAILED", "Failed to send WebSocket message", error));
152
+ }
153
+ }
154
+ startHeartbeat() {
155
+ this.heartbeatInterval = setInterval(() => {
156
+ this.sendMessage({
157
+ type: "heartbeat",
158
+ });
159
+ }, 30000); // 30 second heartbeat
160
+ }
161
+ scheduleReconnect() {
162
+ this.reconnectAttempts++;
163
+ const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000); // Exponential backoff, max 30s
164
+ this.logger.info({
165
+ attempt: this.reconnectAttempts,
166
+ maxAttempts: this.maxReconnectAttempts,
167
+ delay,
168
+ }, "Scheduling reconnection attempt");
169
+ setTimeout(() => __awaiter(this, void 0, void 0, function* () {
170
+ try {
171
+ yield this.connect();
172
+ this.logger.info("Reconnection successful");
173
+ }
174
+ catch (error) {
175
+ this.logger.error({ error }, "Reconnection failed");
176
+ }
177
+ }), delay);
178
+ }
179
+ cleanup() {
180
+ if (this.heartbeatInterval) {
181
+ clearInterval(this.heartbeatInterval);
182
+ this.heartbeatInterval = null;
183
+ }
184
+ }
185
+ disconnect() {
186
+ var _a, _b;
187
+ this.logger.info("Disconnecting WebSocket");
188
+ this.cleanup();
189
+ this.isConnected = false;
190
+ if (this.socket) {
191
+ this.socket.close(1000, "Normal closure");
192
+ this.socket = null;
193
+ }
194
+ (_b = (_a = this.callbacks).onConnectionStatusChanged) === null || _b === void 0 ? void 0 : _b.call(_a, false);
195
+ }
196
+ getConnectionState() {
197
+ if (!this.socket)
198
+ return "CLOSED";
199
+ switch (this.socket.readyState) {
200
+ case WebSocket.CONNECTING:
201
+ return "CONNECTING";
202
+ case WebSocket.OPEN:
203
+ return "CONNECTED";
204
+ case WebSocket.CLOSING:
205
+ return "CLOSING";
206
+ case WebSocket.CLOSED:
207
+ return "CLOSED";
208
+ default:
209
+ return "UNKNOWN";
210
+ }
211
+ }
212
+ createError(code, message, details) {
213
+ return {
214
+ code,
215
+ message,
216
+ details,
217
+ };
218
+ }
219
+ }
220
+ exports.KeyringWebSocketClient = KeyringWebSocketClient;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export * from "@keyringnetwork/contracts-abi";
2
- export { KeyringConnect } from "./main";
2
+ export { VerificationSession } from "./core/VerificationSession";
3
3
  export * from "./types";
package/dist/index.js CHANGED
@@ -14,8 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.KeyringConnect = void 0;
17
+ exports.VerificationSession = void 0;
18
18
  __exportStar(require("@keyringnetwork/contracts-abi"), exports);
19
- var main_1 = require("./main");
20
- Object.defineProperty(exports, "KeyringConnect", { enumerable: true, get: function () { return main_1.KeyringConnect; } });
19
+ var VerificationSession_1 = require("./core/VerificationSession");
20
+ Object.defineProperty(exports, "VerificationSession", { enumerable: true, get: function () { return VerificationSession_1.VerificationSession; } });
21
21
  __exportStar(require("./types"), exports);
@@ -0,0 +1,24 @@
1
+ import { DatasourceTypes } from "@keyringnetwork/keyring-dtos";
2
+ import { CredentialData, SessionConfig } from "./core";
3
+ export type SessionStatus = "session_created" | "mobile_connected" | "processing_started" | "processing_completed" | "processing_failed" | "session_expired";
4
+ export interface CrossDeviceSession {
5
+ session_id: string;
6
+ session_token: string;
7
+ config: SessionConfig;
8
+ origin_url: string;
9
+ status: SessionStatus;
10
+ created_at: number | string;
11
+ expires_at: number | string;
12
+ result?: {
13
+ credential_data?: CredentialData;
14
+ entity_type?: string;
15
+ datasourceObject?: DatasourceTypes.DatasourceObject;
16
+ };
17
+ error?: string;
18
+ platform: "web" | "mobile";
19
+ qr_code_data: string;
20
+ connected_clients: {
21
+ web?: string;
22
+ mobile?: string;
23
+ };
24
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,78 @@
1
+ import { MobileConnectedMessage, ProcessingCompletedMessage, ProcessingFailedMessage, ProcessingStartedMessage, SessionCreatedMessage, SessionExpiredMessage } from "./websocket";
2
+ export interface SessionConfig {
3
+ /**
4
+ * The name of the client.
5
+ */
6
+ name: string;
7
+ /**
8
+ * The URL of the client app which the chrome extension will communicate with.
9
+ */
10
+ app_url: string;
11
+ /**
12
+ * The URL of the client logo.
13
+ */
14
+ logo_url: string;
15
+ /**
16
+ * The onchain policy ID of the client.
17
+ */
18
+ policy_id: number;
19
+ /**
20
+ * The wallet address and chain ID of the user.
21
+ */
22
+ credential_config: {
23
+ chain_id: number;
24
+ wallet_address: string;
25
+ };
26
+ /**
27
+ * The API key of the client.
28
+ */
29
+ api_key: string;
30
+ /**
31
+ * Keyring Network configuration for the extension.
32
+ * @note this is meant to be used for internal testing and development purposes.
33
+ */
34
+ krn_config?: {
35
+ keyring_api_url?: string;
36
+ keyring_user_app_url?: string;
37
+ analytics_api_url?: string;
38
+ notaryUrl?: string;
39
+ websocketProxyUrl?: string;
40
+ };
41
+ }
42
+ export interface CredentialData {
43
+ trader: `0x${string}`;
44
+ policyId: number;
45
+ chainId: number;
46
+ validUntil: number;
47
+ cost: number;
48
+ key: string;
49
+ signature: string;
50
+ backdoor: string;
51
+ }
52
+ export interface SDKError {
53
+ code: string;
54
+ message: string;
55
+ details?: any;
56
+ }
57
+ export type SDKErrorCode = "BACKEND_UNAVAILABLE" | "SESSION_CREATION_FAILED" | "SESSION_NOT_FOUND" | "SESSION_EXPIRED" | "WEBSOCKET_CONNECTION_FAILED" | "WEBSOCKET_DISCONNECTED" | "MOBILE_PROCESSING_FAILED" | "NETWORK_ERROR" | "VALIDATION_ERROR" | "TIMEOUT_ERROR" | "QR_DISPLAY_NOT_SUPPORTED";
58
+ export interface SDKCallbacks {
59
+ onSessionCreated?: (data: SessionCreatedMessage["data"]) => void;
60
+ onMobileConnected?: (data: MobileConnectedMessage["data"]) => void;
61
+ onProcessingStarted?: (data: ProcessingStartedMessage["data"]) => void;
62
+ onProcessingCompleted?: (data: ProcessingCompletedMessage["data"]) => void;
63
+ onProcessingFailed?: (data: ProcessingFailedMessage["data"]) => void;
64
+ onSessionExpired?: (data: SessionExpiredMessage["data"]) => void;
65
+ onError?: (error: SDKError) => void;
66
+ onConnectionStatusChanged?: (connected: boolean) => void;
67
+ }
68
+ export type SDKEventTypes = "sessionCreated" | "mobileConnected" | "processingStarted" | "processingCompleted" | "processingFailed" | "sessionExpired" | "error" | "connectionStatusChanged";
69
+ export type SDKEventData = {
70
+ sessionCreated: SessionCreatedMessage["data"];
71
+ mobileConnected: MobileConnectedMessage["data"];
72
+ processingStarted: ProcessingStartedMessage["data"];
73
+ processingCompleted: ProcessingCompletedMessage["data"];
74
+ processingFailed: ProcessingFailedMessage["data"];
75
+ sessionExpired: SessionExpiredMessage["data"];
76
+ error: SDKError;
77
+ connectionStatusChanged: boolean;
78
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });