@canton-network/core-splice-provider 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # splice-provider
@@ -0,0 +1,19 @@
1
+ import { RequestPayload } from '@canton-network/core-types';
2
+ export type EventListener<T> = (...args: T[]) => void;
3
+ export interface SpliceProvider {
4
+ request<T>(args: RequestPayload): Promise<T>;
5
+ on<T>(event: string, listener: EventListener<T>): SpliceProvider;
6
+ emit<T>(event: string, ...args: T[]): boolean;
7
+ removeListener<T>(event: string, listenerToRemove: EventListener<T>): SpliceProvider;
8
+ }
9
+ export declare abstract class SpliceProviderBase implements SpliceProvider {
10
+ listeners: {
11
+ [event: string]: EventListener<unknown>[];
12
+ };
13
+ constructor();
14
+ abstract request<T>(args: RequestPayload): Promise<T>;
15
+ on<T>(event: string, listener: EventListener<T>): SpliceProvider;
16
+ emit<T>(event: string, ...args: T[]): boolean;
17
+ removeListener<T>(event: string, listenerToRemove: EventListener<T>): SpliceProvider;
18
+ }
19
+ //# sourceMappingURL=SpliceProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpliceProvider.d.ts","sourceRoot":"","sources":["../src/SpliceProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAE3D,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,KAAK,IAAI,CAAA;AAErD,MAAM,WAAW,cAAc;IAC3B,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IAC5C,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,cAAc,CAAA;IAChE,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO,CAAA;IAC7C,cAAc,CAAC,CAAC,EACZ,KAAK,EAAE,MAAM,EACb,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,GACnC,cAAc,CAAA;CACpB;AAED,8BAAsB,kBAAmB,YAAW,cAAc;IAC9D,SAAS,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,EAAE,CAAA;KAAE,CAAA;;IAMxD,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;IAG9C,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,cAAc;IAUhE,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO;IAQ7C,cAAc,CAAC,CAAC,EACnB,KAAK,EAAE,MAAM,EACb,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,GACnC,cAAc;CASpB"}
@@ -0,0 +1,28 @@
1
+ export class SpliceProviderBase {
2
+ listeners;
3
+ constructor() {
4
+ this.listeners = {}; // Event listeners
5
+ }
6
+ // Event handling
7
+ on(event, listener) {
8
+ if (!this.listeners[event]) {
9
+ this.listeners[event] = [];
10
+ }
11
+ const listeners = this.listeners[event];
12
+ listeners.push(listener);
13
+ return this;
14
+ }
15
+ emit(event, ...args) {
16
+ if (this.listeners[event]) {
17
+ this.listeners[event].forEach((listener) => listener(...args));
18
+ return true;
19
+ }
20
+ return false;
21
+ }
22
+ removeListener(event, listenerToRemove) {
23
+ if (!this.listeners[event])
24
+ return this;
25
+ this.listeners[event] = this.listeners[event].filter((listener) => listener !== listenerToRemove);
26
+ return this;
27
+ }
28
+ }
@@ -0,0 +1,12 @@
1
+ import { RequestPayload } from '@canton-network/core-types';
2
+ import { SpliceProviderBase } from './SpliceProvider';
3
+ export declare class SpliceProviderHttp extends SpliceProviderBase {
4
+ private url;
5
+ private sessionToken?;
6
+ private socket;
7
+ private transport;
8
+ private openSocket;
9
+ constructor(url: URL, sessionToken?: string);
10
+ request<T>({ method, params }: RequestPayload): Promise<T>;
11
+ }
12
+ //# sourceMappingURL=SpliceProviderHttp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpliceProviderHttp.d.ts","sourceRoot":"","sources":["../src/SpliceProviderHttp.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,cAAc,EAEjB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAIrD,qBAAa,kBAAmB,SAAQ,kBAAkB;IA6BlD,OAAO,CAAC,GAAG;IA5Bf,OAAO,CAAC,YAAY,CAAC,CAAQ;IAC7B,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,SAAS,CAAe;IAEhC,OAAO,CAAC,UAAU;gBAwBN,GAAG,EAAE,GAAG,EAChB,YAAY,CAAC,EAAE,MAAM;IAyCZ,OAAO,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;CAa1E"}
@@ -0,0 +1,72 @@
1
+ import { HttpTransport, isSpliceMessageEvent, WalletEvent, } from '@canton-network/core-types';
2
+ import { SpliceProviderBase } from './SpliceProvider';
3
+ import { io } from 'socket.io-client';
4
+ import { popupHref } from '@canton-network/core-wallet-ui-components';
5
+ export class SpliceProviderHttp extends SpliceProviderBase {
6
+ url;
7
+ sessionToken;
8
+ socket;
9
+ transport;
10
+ openSocket(url) {
11
+ // Assumes the RPC URL is on /rpc, and the socket URL is the same but without the /rpc path.
12
+ const socketUrl = new URL(url.href);
13
+ socketUrl.pathname = '';
14
+ if (this.socket) {
15
+ this.socket.disconnect();
16
+ }
17
+ const socket = io(socketUrl.href, {
18
+ forceNew: true,
19
+ auth: {
20
+ token: `Bearer ${this.sessionToken}`,
21
+ },
22
+ });
23
+ socket.onAny((event, ...args) => {
24
+ this.emit(event, ...args);
25
+ });
26
+ return socket;
27
+ }
28
+ constructor(url, sessionToken) {
29
+ super();
30
+ this.url = url;
31
+ if (sessionToken)
32
+ this.sessionToken = sessionToken;
33
+ this.transport = new HttpTransport(url, sessionToken);
34
+ this.socket = this.openSocket(url);
35
+ // Listen for the auth success event sent from the WK UI popup to the SDK running in the parent window.
36
+ window.addEventListener('message', async (event) => {
37
+ if (!isSpliceMessageEvent(event))
38
+ return;
39
+ if (event.data.type === WalletEvent.SPLICE_WALLET_IDP_AUTH_SUCCESS) {
40
+ this.sessionToken = event.data.token;
41
+ this.transport = new HttpTransport(url, this.sessionToken);
42
+ console.log(`SpliceProviderHttp: setting sessionToken to ${this.sessionToken}`);
43
+ this.openSocket(this.url);
44
+ // We requery the status explicitly here, as it's not guaranteed that the socket will be open & authenticated
45
+ // before the `onConnected` event is fired from the `addSession` RPC call. The dappApi.StatusResult and
46
+ // dappApi.OnConnectedEvent are mapped manually to avoid dependency.
47
+ this.request({ method: 'status' }).then((status) => {
48
+ const statusResult = status;
49
+ this.emit('onConnected', {
50
+ kernel: statusResult.kernel,
51
+ chainId: statusResult.chainId,
52
+ sessionToken: this.sessionToken,
53
+ });
54
+ });
55
+ }
56
+ });
57
+ }
58
+ async request({ method, params }) {
59
+ const response = await this.transport.submit({ method, params });
60
+ if ('error' in response)
61
+ throw new Error(response.error.message);
62
+ const result = response.result;
63
+ if (method === 'prepareExecute') {
64
+ const { userUrl } = result;
65
+ if (!userUrl) {
66
+ throw new Error('No userUrl provided in response');
67
+ }
68
+ popupHref(userUrl);
69
+ }
70
+ return result;
71
+ }
72
+ }
@@ -0,0 +1,8 @@
1
+ import { RequestPayload } from '@canton-network/core-types';
2
+ import { SpliceProviderBase } from './SpliceProvider.js';
3
+ export declare class SpliceProviderWindow extends SpliceProviderBase {
4
+ private transport;
5
+ constructor();
6
+ request<T>({ method, params }: RequestPayload): Promise<T>;
7
+ }
8
+ //# sourceMappingURL=SpliceProviderWindow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpliceProviderWindow.d.ts","sourceRoot":"","sources":["../src/SpliceProviderWindow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAmB,MAAM,4BAA4B,CAAA;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAExD,qBAAa,oBAAqB,SAAQ,kBAAkB;IACxD,OAAO,CAAC,SAAS,CAAiB;;IAOrB,OAAO,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;CAI1E"}
@@ -0,0 +1,13 @@
1
+ import { WindowTransport } from '@canton-network/core-types';
2
+ import { SpliceProviderBase } from './SpliceProvider.js';
3
+ export class SpliceProviderWindow extends SpliceProviderBase {
4
+ transport;
5
+ constructor() {
6
+ super();
7
+ this.transport = new WindowTransport(window);
8
+ }
9
+ async request({ method, params }) {
10
+ const response = await this.transport.submit({ method, params });
11
+ return response.result;
12
+ }
13
+ }
@@ -0,0 +1,15 @@
1
+ import { SpliceProvider } from './SpliceProvider';
2
+ declare global {
3
+ interface Window {
4
+ splice?: SpliceProvider;
5
+ canton?: SpliceProvider;
6
+ ethereum?: SpliceProvider;
7
+ }
8
+ }
9
+ export declare enum ProviderType {
10
+ WINDOW = 0,
11
+ HTTP = 1
12
+ }
13
+ export declare function injectSpliceProvider(providerType: ProviderType, url?: URL, sessionToken?: string): SpliceProvider;
14
+ export * from './SpliceProvider';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAIjD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,MAAM;QACZ,MAAM,CAAC,EAAE,cAAc,CAAA;QACvB,MAAM,CAAC,EAAE,cAAc,CAAA;QACvB,QAAQ,CAAC,EAAE,cAAc,CAAA;KAC5B;CACJ;AAED,oBAAY,YAAY;IACpB,MAAM,IAAA;IACN,IAAI,IAAA;CACP;AAED,wBAAgB,oBAAoB,CAChC,YAAY,EAAE,YAAY,EAC1B,GAAG,CAAC,EAAE,GAAG,EACT,YAAY,CAAC,EAAE,MAAM,GACtB,cAAc,CA2BhB;AAED,cAAc,kBAAkB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,31 @@
1
+ import { SpliceProviderHttp } from './SpliceProviderHttp';
2
+ import { SpliceProviderWindow } from './SpliceProviderWindow';
3
+ export var ProviderType;
4
+ (function (ProviderType) {
5
+ ProviderType[ProviderType["WINDOW"] = 0] = "WINDOW";
6
+ ProviderType[ProviderType["HTTP"] = 1] = "HTTP";
7
+ })(ProviderType || (ProviderType = {}));
8
+ export function injectSpliceProvider(providerType, url, sessionToken) {
9
+ // Check if the provider is already injected
10
+ const existing = window.splice || window.canton || window.ethereum;
11
+ if (existing)
12
+ return existing;
13
+ // Inject the SpliceProvider instance
14
+ if (providerType === ProviderType.WINDOW) {
15
+ window.splice = new SpliceProviderWindow();
16
+ }
17
+ else if (providerType === ProviderType.HTTP) {
18
+ if (!url || !(url instanceof URL)) {
19
+ throw new Error('Invalid URL for HTTP provider. Please provide a valid URL instance.');
20
+ }
21
+ window.splice = new SpliceProviderHttp(url, sessionToken);
22
+ }
23
+ else {
24
+ throw new Error('Invalid provider type. Use ProviderType.WINDOW or ProviderType.HTTP.');
25
+ }
26
+ window.canton = window.splice; // For compatibility with Canton dApps
27
+ window.ethereum = window.splice; // For EIP-1193 compatibility
28
+ console.log('Splice provider injected successfully.');
29
+ return window.splice;
30
+ }
31
+ export * from './SpliceProvider';
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@canton-network/core-splice-provider",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "A JavaScript Splice Provider API (EIP-1193 compliant).",
6
+ "repository": "https://github.com/hyperledger-labs/splice-wallet-kernel",
7
+ "license": "Apache-2.0",
8
+ "author": "Marc Juchli <marc.juchli@digitalasset.com>",
9
+ "packageManager": "yarn@4.9.2",
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "scripts": {
13
+ "build": "tsc -b",
14
+ "dev": "tsc -b --watch",
15
+ "clean": "tsc -b --clean; rm -rf dist"
16
+ },
17
+ "devDependencies": {
18
+ "typescript": "^5.8.3"
19
+ },
20
+ "dependencies": {
21
+ "@canton-network/core-types": "^0.1.0",
22
+ "@canton-network/core-wallet-ui-components": "^0.1.0",
23
+ "socket.io-client": "^4.8.1"
24
+ },
25
+ "files": [
26
+ "dist/*"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ }
31
+ }