@coinflowlabs/angular 0.0.3 → 0.0.4

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 (40) hide show
  1. package/ng-package.json +7 -0
  2. package/package.json +9 -17
  3. package/src/lib/coinflow-iframe.component.ts +63 -0
  4. package/src/lib/coinflow-purchase-history.component.ts +9 -0
  5. package/src/lib/coinflow-purchase-protection.component.ts +9 -0
  6. package/src/lib/coinflow-purchase.component.ts +37 -0
  7. package/src/lib/coinflow-withdraw-history.component.ts +9 -0
  8. package/src/lib/coinflow-withdraw.component.ts +36 -0
  9. package/src/lib/common/CoinflowLibMessageHandlers.ts +188 -0
  10. package/src/lib/common/CoinflowTypes.ts +403 -0
  11. package/src/lib/common/CoinflowUtils.ts +269 -0
  12. package/{public-api.d.ts → src/public-api.ts} +4 -0
  13. package/tsconfig.lib.json +14 -0
  14. package/tsconfig.lib.prod.json +10 -0
  15. package/tsconfig.spec.json +14 -0
  16. package/esm2022/coinflowlabs-angular.mjs +0 -5
  17. package/esm2022/lib/coinflow-iframe.component.mjs +0 -67
  18. package/esm2022/lib/coinflow-purchase-history.component.mjs +0 -16
  19. package/esm2022/lib/coinflow-purchase-protection.component.mjs +0 -16
  20. package/esm2022/lib/coinflow-purchase.component.mjs +0 -32
  21. package/esm2022/lib/coinflow-withdraw-history.component.mjs +0 -16
  22. package/esm2022/lib/coinflow-withdraw.component.mjs +0 -32
  23. package/esm2022/lib/common/CoinflowLibMessageHandlers.mjs +0 -127
  24. package/esm2022/lib/common/CoinflowTypes.mjs +0 -13
  25. package/esm2022/lib/common/CoinflowUtils.mjs +0 -173
  26. package/esm2022/lib/common/index.mjs +0 -4
  27. package/esm2022/public-api.mjs +0 -10
  28. package/fesm2022/coinflowlabs-angular.mjs +0 -486
  29. package/fesm2022/coinflowlabs-angular.mjs.map +0 -1
  30. package/index.d.ts +0 -5
  31. package/lib/coinflow-iframe.component.d.ts +0 -17
  32. package/lib/coinflow-purchase-history.component.d.ts +0 -5
  33. package/lib/coinflow-purchase-protection.component.d.ts +0 -5
  34. package/lib/coinflow-purchase.component.d.ts +0 -10
  35. package/lib/coinflow-withdraw-history.component.d.ts +0 -5
  36. package/lib/coinflow-withdraw.component.d.ts +0 -10
  37. package/lib/common/CoinflowLibMessageHandlers.d.ts +0 -21
  38. package/lib/common/CoinflowTypes.d.ts +0 -287
  39. package/lib/common/CoinflowUtils.d.ts +0 -21
  40. /package/{lib/common/index.d.ts → src/lib/common/index.ts} +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3
+ "dest": "../../dist/coinflowlabs",
4
+ "lib": {
5
+ "entryFile": "src/public-api.ts"
6
+ }
7
+ }
package/package.json CHANGED
@@ -1,6 +1,11 @@
1
1
  {
2
2
  "name": "@coinflowlabs/angular",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
+ "scripts": {
5
+ "clean": "rimraf ../../dist && rimraf ./src/lib/common",
6
+ "build": "npm run codegen && ng build coinflowlabs",
7
+ "codegen": "cp -r ../../../lib-common/src/ ./src/lib/common/"
8
+ },
4
9
  "peerDependencies": {
5
10
  "@angular/common": "^17.3.0",
6
11
  "@angular/core": "^17.3.0",
@@ -9,7 +14,7 @@
9
14
  "bs58": "~5.0.0"
10
15
  },
11
16
  "dependencies": {
12
- "tslib": "^2.3.0"
17
+ "tslib": "^2.6.2"
13
18
  },
14
19
  "peerDependenciesMeta": {
15
20
  "@coinflowlabs/lib-common": {
@@ -22,18 +27,5 @@
22
27
  "optional": true
23
28
  }
24
29
  },
25
- "sideEffects": false,
26
- "module": "fesm2022/coinflowlabs-angular.mjs",
27
- "typings": "index.d.ts",
28
- "exports": {
29
- "./package.json": {
30
- "default": "./package.json"
31
- },
32
- ".": {
33
- "types": "./index.d.ts",
34
- "esm2022": "./esm2022/coinflowlabs-angular.mjs",
35
- "esm": "./esm2022/coinflowlabs-angular.mjs",
36
- "default": "./fesm2022/coinflowlabs-angular.mjs"
37
- }
38
- }
39
- }
30
+ "sideEffects": false
31
+ }
@@ -0,0 +1,63 @@
1
+ import {
2
+ Component,
3
+ ElementRef,
4
+ HostListener,
5
+ Input,
6
+ ViewChild,
7
+ } from '@angular/core';
8
+ import {
9
+ CoinflowIFrameProps,
10
+ CoinflowUtils,
11
+ IFrameMessageHandlers,
12
+ handleIFrameMessage,
13
+ } from './common';
14
+ import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser';
15
+
16
+ @Component({
17
+ selector: 'lib-coinflow-iframe',
18
+ standalone: true,
19
+ imports: [],
20
+ template: ` <iframe
21
+ width="100%"
22
+ height="100%"
23
+ #iframe
24
+ scrolling="{{ iframeProps?.handleHeightChange ? 'no' : 'yes' }}"
25
+ allow="payment;camera"
26
+ title="withdraw"
27
+ frameBorder="0"
28
+ [src]="dynamicUrl"
29
+ ></iframe>`,
30
+ })
31
+ export class CoinflowIFrameComponent {
32
+ @Input() iframeProps!: CoinflowIFrameProps;
33
+ @Input() messageHandlers!: IFrameMessageHandlers;
34
+
35
+ dynamicUrl?: SafeResourceUrl;
36
+ @ViewChild('iframe') iframe?: ElementRef<HTMLIFrameElement>;
37
+
38
+ constructor(private sanitizer: DomSanitizer) {}
39
+
40
+ ngOnInit() {
41
+ const coinflowUrl = CoinflowUtils.getCoinflowUrl(this.iframeProps);
42
+ this.dynamicUrl =
43
+ this.sanitizer.bypassSecurityTrustResourceUrl(coinflowUrl);
44
+ }
45
+
46
+ @HostListener('window:message', ['$event']) onPostMessage(event: any) {
47
+ if (
48
+ !event.origin.includes(
49
+ CoinflowUtils.getCoinflowBaseUrl(this.iframeProps.env)
50
+ )
51
+ )
52
+ return;
53
+
54
+ const promise = handleIFrameMessage(event.data, this.messageHandlers);
55
+ if (!promise) return;
56
+ promise.then(this.sendMessage.bind(this));
57
+ }
58
+
59
+ sendMessage(message: string) {
60
+ if (!this.iframe || !this.iframe.nativeElement) return;
61
+ this.iframe.nativeElement.contentWindow!.postMessage(message, '*');
62
+ }
63
+ }
@@ -0,0 +1,9 @@
1
+ import {Component} from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'lib-coinflow-purchase-history',
5
+ standalone: true,
6
+ imports: [],
7
+ template: ' <p>coinflow-purchase-history works!</p> ',
8
+ })
9
+ export class CoinflowPurchaseHistoryComponent {}
@@ -0,0 +1,9 @@
1
+ import {Component} from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'lib-coinflow-purchase-protection',
5
+ standalone: true,
6
+ imports: [],
7
+ template: ' <p>coinflow-purchase-protection works!</p> ',
8
+ })
9
+ export class CoinflowPurchaseProtectionComponent {}
@@ -0,0 +1,37 @@
1
+ import {Component, Input} from '@angular/core';
2
+ import {CoinflowIFrameComponent} from './coinflow-iframe.component';
3
+ import {
4
+ CoinflowIFrameProps,
5
+ CoinflowPurchaseProps,
6
+ IFrameMessageHandlers,
7
+ getHandlers,
8
+ getWalletPubkey,
9
+ CoinflowUtils,
10
+ } from './common';
11
+
12
+ @Component({
13
+ selector: 'lib-coinflow-purchase',
14
+ standalone: true,
15
+ imports: [CoinflowIFrameComponent],
16
+ template:
17
+ ' <lib-coinflow-iframe ng-if="iframeProps && messageHandlers" [iframeProps]="iframeProps!" [messageHandlers]="messageHandlers!"></lib-coinflow-iframe> ',
18
+ })
19
+ export class CoinflowPurchaseComponent {
20
+ @Input() purchaseProps!: CoinflowPurchaseProps;
21
+ iframeProps?: CoinflowIFrameProps;
22
+ messageHandlers?: IFrameMessageHandlers;
23
+
24
+ ngOnInit() {
25
+ const walletPubkey = getWalletPubkey(this.purchaseProps);
26
+ this.messageHandlers = getHandlers(this.purchaseProps);
27
+ this.messageHandlers.handleHeightChange =
28
+ this.purchaseProps.handleHeightChange;
29
+
30
+ this.iframeProps = {
31
+ ...this.purchaseProps,
32
+ walletPubkey,
33
+ route: `/purchase/${this.purchaseProps?.merchantId}`,
34
+ transaction: CoinflowUtils.getTransaction(this.purchaseProps),
35
+ };
36
+ }
37
+ }
@@ -0,0 +1,9 @@
1
+ import {Component} from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'lib-coinflow-withdraw-history',
5
+ standalone: true,
6
+ imports: [],
7
+ template: ' <p>coinflow-withdraw-history works!</p> ',
8
+ })
9
+ export class CoinflowWithdrawHistoryComponent {}
@@ -0,0 +1,36 @@
1
+ import {Component, Input} from '@angular/core';
2
+ import {
3
+ CoinflowIFrameProps,
4
+ CoinflowWithdrawProps,
5
+ IFrameMessageHandlers,
6
+ getHandlers,
7
+ getWalletPubkey,
8
+ } from './common';
9
+ import {CoinflowIFrameComponent} from './coinflow-iframe.component';
10
+
11
+ @Component({
12
+ selector: 'lib-coinflow-withdraw',
13
+ standalone: true,
14
+ imports: [CoinflowIFrameComponent],
15
+ template:
16
+ ' <lib-coinflow-iframe ng-if="iframeProps && messageHandlers" [iframeProps]="iframeProps!" [messageHandlers]="messageHandlers!"></lib-coinflow-iframe> ',
17
+ })
18
+ export class CoinflowWithdrawComponent {
19
+ @Input() withdrawProps!: CoinflowWithdrawProps;
20
+ iframeProps?: CoinflowIFrameProps;
21
+ messageHandlers?: IFrameMessageHandlers;
22
+
23
+ ngOnInit() {
24
+ const walletPubkey = getWalletPubkey(this.withdrawProps);
25
+ this.messageHandlers = getHandlers(this.withdrawProps);
26
+ this.messageHandlers.handleHeightChange =
27
+ this.withdrawProps.handleHeightChange;
28
+
29
+ this.iframeProps = {
30
+ ...this.withdrawProps,
31
+ walletPubkey,
32
+ route: `/withdraw/${this.withdrawProps?.merchantId}`,
33
+ transaction: undefined,
34
+ };
35
+ }
36
+ }
@@ -0,0 +1,188 @@
1
+ import {
2
+ CoinflowPurchaseProps,
3
+ EthWallet,
4
+ NearWallet,
5
+ SolanaWallet,
6
+ } from './CoinflowTypes';
7
+ import {CoinflowUtils} from './CoinflowUtils';
8
+ import {Transaction, VersionedTransaction} from '@solana/web3.js';
9
+ import * as web3 from '@solana/web3.js';
10
+ import base58 from 'bs58';
11
+
12
+ export type WalletCall = {method: IFrameMessageMethods; data: string};
13
+
14
+ export interface IFrameMessageHandlers {
15
+ handleSendTransaction: (transaction: string) => Promise<string>;
16
+ handleSignMessage?: (message: string) => Promise<string>;
17
+ handleSignTransaction?: (transaction: string) => Promise<string>;
18
+ handleHeightChange?: (height: string) => void;
19
+ }
20
+
21
+ enum IFrameMessageMethods {
22
+ SignMessage = 'signMessage',
23
+ SignTransaction = 'signTransaction',
24
+ SendTransaction = 'sendTransaction',
25
+ HeightChange = 'heightChange',
26
+ }
27
+
28
+ export function getWalletPubkey({
29
+ wallet,
30
+ }: Pick<CoinflowPurchaseProps, 'wallet'>): string | null | undefined {
31
+ if ('publicKey' in wallet) {
32
+ return wallet.publicKey!.toString();
33
+ }
34
+
35
+ if ('address' in wallet) {
36
+ return wallet.address;
37
+ }
38
+
39
+ if ('accountId' in wallet) {
40
+ return wallet.accountId;
41
+ }
42
+
43
+ return null;
44
+ }
45
+
46
+ export function handleIFrameMessage(
47
+ rawMessage: string,
48
+ handlers: IFrameMessageHandlers
49
+ ): Promise<string> | void {
50
+ let walletCall: WalletCall;
51
+ try {
52
+ walletCall = JSON.parse(rawMessage);
53
+ if (!('method' in walletCall) || !('data' in walletCall)) return;
54
+ } catch (e) {
55
+ console.error('handleIFrameMessage JSON parse', e);
56
+ return;
57
+ }
58
+
59
+ const {data, method} = walletCall;
60
+ switch (method) {
61
+ case IFrameMessageMethods.SignMessage:
62
+ if (!handlers.handleSignMessage) return;
63
+ return handlers.handleSignMessage(data);
64
+ case IFrameMessageMethods.SignTransaction:
65
+ if (!handlers.handleSignTransaction) return;
66
+ return handlers.handleSignTransaction(data);
67
+ case IFrameMessageMethods.SendTransaction:
68
+ return handlers.handleSendTransaction(data);
69
+ case IFrameMessageMethods.HeightChange:
70
+ if (!handlers.handleHeightChange) return;
71
+ return handlers.handleHeightChange(data);
72
+ }
73
+
74
+ console.warn(
75
+ `Didn't expect to get here, handleIFrameMessage method:${method} is not one of ${Object.values(IFrameMessageMethods)}`
76
+ );
77
+ }
78
+
79
+ export function getHandlers({
80
+ wallet,
81
+ blockchain,
82
+ }: Pick<CoinflowPurchaseProps, 'wallet' | 'blockchain'>): Omit<
83
+ IFrameMessageHandlers,
84
+ 'handleHeightChange'
85
+ > {
86
+ return CoinflowUtils.byBlockchain(blockchain, {
87
+ solana: () => getSolanaWalletHandlers({wallet}),
88
+ near: () => getNearWalletHandlers({wallet}),
89
+ eth: () => getEvmWalletHandlers({wallet}),
90
+ polygon: () => getEvmWalletHandlers({wallet}),
91
+ base: () => getEvmWalletHandlers({wallet}),
92
+ })();
93
+ }
94
+
95
+ function getSolanaWalletHandlers({
96
+ wallet,
97
+ }: Pick<CoinflowPurchaseProps, 'wallet'>): Omit<
98
+ IFrameMessageHandlers,
99
+ 'handleHeightChange'
100
+ > {
101
+ return {
102
+ handleSendTransaction: async (transaction: string) => {
103
+ const tx = getSolanaTransaction(transaction);
104
+ return (wallet as SolanaWallet).sendTransaction(tx);
105
+ },
106
+ handleSignMessage: async (message: string) => {
107
+ const signMessage = (wallet as SolanaWallet).signMessage;
108
+ if (!signMessage) {
109
+ throw new Error('signMessage is not supported by this wallet');
110
+ }
111
+
112
+ const signedMessage = await signMessage(
113
+ new TextEncoder().encode(message)
114
+ );
115
+ return base58.encode(signedMessage);
116
+ },
117
+ handleSignTransaction: async (transaction: string) => {
118
+ const signTransaction = (wallet as SolanaWallet).signTransaction;
119
+ if (!signTransaction) {
120
+ throw new Error('signTransaction is not supported by this wallet');
121
+ }
122
+ const tx = getSolanaTransaction(transaction);
123
+ const signedTransaction = await signTransaction(tx);
124
+ return base58.encode(
125
+ signedTransaction.serialize({
126
+ requireAllSignatures: false,
127
+ verifySignatures: false,
128
+ })
129
+ );
130
+ },
131
+ };
132
+ }
133
+
134
+ function getSolanaTransaction(
135
+ data: string
136
+ ): Transaction | VersionedTransaction {
137
+ if (!web3)
138
+ throw new Error(
139
+ '@solana/web3.js is not defined. Please install @solana/web3.js into your project'
140
+ );
141
+
142
+ if (!base58)
143
+ throw new Error(
144
+ 'bs58 is not defined. Please install bs58 into your project'
145
+ );
146
+
147
+ const parsedUInt8Array = base58.decode(data);
148
+ const vtx = web3.VersionedTransaction.deserialize(parsedUInt8Array);
149
+ if (vtx.version === 'legacy') return web3.Transaction.from(parsedUInt8Array);
150
+ return vtx;
151
+ }
152
+
153
+ function getNearWalletHandlers({
154
+ wallet,
155
+ }: Pick<CoinflowPurchaseProps, 'wallet'>): Omit<
156
+ IFrameMessageHandlers,
157
+ 'handleHeightChange'
158
+ > {
159
+ const nearWallet = wallet as NearWallet;
160
+ return {
161
+ handleSendTransaction: async (transaction: string) => {
162
+ const action = JSON.parse(Buffer.from(transaction, 'base64').toString());
163
+ const executionOutcome = await nearWallet.signAndSendTransaction(action);
164
+ if (!executionOutcome) throw new Error('Transaction did not send');
165
+ const {transaction: transactionResult} = executionOutcome;
166
+ return transactionResult.hash;
167
+ },
168
+ };
169
+ }
170
+
171
+ function getEvmWalletHandlers({
172
+ wallet,
173
+ }: Pick<CoinflowPurchaseProps, 'wallet'>): Omit<
174
+ IFrameMessageHandlers,
175
+ 'handleHeightChange'
176
+ > {
177
+ const evmWallet = wallet as EthWallet;
178
+ return {
179
+ handleSendTransaction: async (transaction: string) => {
180
+ const tx = JSON.parse(Buffer.from(transaction, 'base64').toString());
181
+ const {hash} = await evmWallet.sendTransaction(tx);
182
+ return hash;
183
+ },
184
+ handleSignMessage: async (message: string) => {
185
+ return evmWallet.signMessage(message);
186
+ },
187
+ };
188
+ }