@alleyboss/micropay-solana-x402-paywall 3.0.6 → 3.1.1
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 +56 -1
- package/dist/next/index.cjs +147 -7
- package/dist/next/index.d.cts +2 -0
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +147 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -106,10 +106,65 @@ import { createSession, validateSession } from '@alleyboss/micropay-solana-x402-
|
|
|
106
106
|
import { createPaymentFlow } from '@alleyboss/micropay-solana-x402-paywall/client';
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
+
## 🛡️ Self-Sovereign Verification (New in v3.1)
|
|
110
|
+
|
|
111
|
+
By default, the library uses the `x402.org` hosted facilitator for convenience. However, you can opt for **Self-Sovereign Mode** to verify payments directly against your own Solana RPC node, removing reliance on any external API services.
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// app/api/articles/[id]/route.ts
|
|
115
|
+
const withMicropay = createX402Middleware({
|
|
116
|
+
walletAddress: 'YOUR_WALLET',
|
|
117
|
+
network: 'devnet',
|
|
118
|
+
price: '1000000',
|
|
119
|
+
// ⚡️ Enable Self-Sovereign Mode
|
|
120
|
+
// The library will verify transactions locally using this RPC connection.
|
|
121
|
+
rpcUrl: process.env.NEXT_PUBLIC_RPC_URL
|
|
122
|
+
});
|
|
123
|
+
### 🛡️ Verification Flow (Self-Sovereign Mode)
|
|
124
|
+
|
|
125
|
+
```mermaid
|
|
126
|
+
sequenceDiagram
|
|
127
|
+
participant User
|
|
128
|
+
participant App
|
|
129
|
+
participant Lib as x402 Lib
|
|
130
|
+
participant RPC as Solana RPC
|
|
131
|
+
|
|
132
|
+
User->>App: Request Premium Content
|
|
133
|
+
App->>Lib: Create Payment Options
|
|
134
|
+
Lib-->>User: Return 402 + Payment Link
|
|
135
|
+
User->>RPC: Submit Transaction
|
|
136
|
+
User->>App: Send Receipt/Signature
|
|
137
|
+
App->>Lib: Verify Transaction
|
|
138
|
+
Lib->>RPC: Get Transaction Status (Local)
|
|
139
|
+
RPC-->>Lib: Confirmed
|
|
140
|
+
Lib-->>App: Valid Session Token
|
|
141
|
+
App-->>User: Unlock Content
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 🆚 Hosted vs. Self-Sovereign Mode
|
|
145
|
+
|
|
146
|
+
| Feature | Hosted Mode (Default) | Self-Sovereign Mode |
|
|
147
|
+
|---------|----------------------|---------------------|
|
|
148
|
+
| **Verification** | Verified by x402.org | Verified by **You** (Local RPC) |
|
|
149
|
+
| **Trust** | Trust x402 Facilitator | Trustless / Trust Your Node |
|
|
150
|
+
| **Privacy** | Metadata sent to facilitator | No external data sharing |
|
|
151
|
+
| **Setup** | Zero-config | Requires RPC URL |
|
|
152
|
+
| **Best For** | Quick startups, MVPs | Production, High-Volume, Agents |
|
|
153
|
+
|
|
109
154
|
## 🤖 AI Agent Payments
|
|
110
155
|
|
|
111
156
|
Enable autonomous AI agents to pay for premium API access.
|
|
112
157
|
|
|
158
|
+
```mermaid
|
|
159
|
+
flowchart LR
|
|
160
|
+
A[AI Agent] -->|1. Detects Paywall| B(Check Wallet)
|
|
161
|
+
B -->|2. Sufficient Balance?| C{Pay?}
|
|
162
|
+
C -- Yes --> D[Sign & Send Tx]
|
|
163
|
+
D --> E[Wait for Confirmation]
|
|
164
|
+
E -->|3. Success| F[Retry Request + Proof]
|
|
165
|
+
F --> G((Unlock Data))
|
|
166
|
+
```
|
|
167
|
+
|
|
113
168
|
```typescript
|
|
114
169
|
import { executeAgentPayment } from '@alleyboss/micropay-solana-x402-paywall/agent';
|
|
115
170
|
import { Keypair, Connection } from '@solana/web3.js';
|
|
@@ -121,7 +176,7 @@ const result = await executeAgentPayment({
|
|
|
121
176
|
agentKeypair,
|
|
122
177
|
recipientAddress: 'CREATOR_WALLET',
|
|
123
178
|
amountLamports: 2_000_000n,
|
|
124
|
-
priorityFee: { enabled: true, microLamports: 10000 },
|
|
179
|
+
priorityFee: { enabled: true, microLamports: 10000 },
|
|
125
180
|
});
|
|
126
181
|
|
|
127
182
|
if (result.success) {
|
package/dist/next/index.cjs
CHANGED
|
@@ -4,21 +4,161 @@ var next = require('@x402/next');
|
|
|
4
4
|
var server = require('@x402/core/server');
|
|
5
5
|
var http = require('@x402/core/http');
|
|
6
6
|
var server$1 = require('@x402/svm/exact/server');
|
|
7
|
+
var web3_js = require('@solana/web3.js');
|
|
8
|
+
var types = require('@x402/core/types');
|
|
9
|
+
|
|
10
|
+
// src/next/index.ts
|
|
11
|
+
var LocalSvmFacilitator = class {
|
|
12
|
+
scheme = "exact";
|
|
13
|
+
caipFamily = "solana:*";
|
|
14
|
+
connection;
|
|
15
|
+
constructor(rpcUrl) {
|
|
16
|
+
this.connection = new web3_js.Connection(rpcUrl, "confirmed");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get supported payment kinds
|
|
20
|
+
* Mocking the response of the /supported endpoint
|
|
21
|
+
*/
|
|
22
|
+
async getSupported(extensionKeys = []) {
|
|
23
|
+
return {
|
|
24
|
+
kinds: [
|
|
25
|
+
{
|
|
26
|
+
x402Version: 1,
|
|
27
|
+
scheme: "exact",
|
|
28
|
+
network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
|
|
29
|
+
// Devnet
|
|
30
|
+
extra: {}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
x402Version: 1,
|
|
34
|
+
scheme: "exact",
|
|
35
|
+
network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
|
|
36
|
+
// Mainnet
|
|
37
|
+
extra: {}
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
extensions: [],
|
|
41
|
+
signers: {
|
|
42
|
+
"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": [],
|
|
43
|
+
"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": []
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get mechanism-specific extra data
|
|
49
|
+
*/
|
|
50
|
+
getExtra(network) {
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get default signers (not used for local verification usually, but required by interface)
|
|
55
|
+
*/
|
|
56
|
+
getSigners(network) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Verify a payment on-chain
|
|
61
|
+
*/
|
|
62
|
+
async verify(payload, requirements) {
|
|
63
|
+
try {
|
|
64
|
+
const signature = payload.payload.signature;
|
|
65
|
+
if (!signature) {
|
|
66
|
+
return { isValid: false, invalidReason: "Missing signature in payment payload" };
|
|
67
|
+
}
|
|
68
|
+
const payTo = requirements.payTo;
|
|
69
|
+
const amountVal = requirements.amount || requirements.maxAmountRequired || "0";
|
|
70
|
+
const requiredAmount = BigInt(amountVal);
|
|
71
|
+
console.log(`[LocalSvmFacilitator] Verifying signature: ${signature}`);
|
|
72
|
+
console.log(`[LocalSvmFacilitator] Required Amount: ${requiredAmount}, PayTo: ${payTo}`);
|
|
73
|
+
const tx = await this.connection.getParsedTransaction(signature, {
|
|
74
|
+
maxSupportedTransactionVersion: 0,
|
|
75
|
+
commitment: "confirmed"
|
|
76
|
+
});
|
|
77
|
+
if (!tx) {
|
|
78
|
+
console.error("[LocalSvmFacilitator] Transaction not found or not confirmed");
|
|
79
|
+
return { isValid: false, invalidReason: "Transaction not found or not confirmed" };
|
|
80
|
+
}
|
|
81
|
+
console.log("[LocalSvmFacilitator] Transaction found. Parsing instructions...");
|
|
82
|
+
const instructions = tx.transaction.message.instructions;
|
|
83
|
+
let paidAmount = 0n;
|
|
84
|
+
let payer = void 0;
|
|
85
|
+
for (const ix of instructions) {
|
|
86
|
+
if ("program" in ix && ix.program === "system") {
|
|
87
|
+
const parsed = ix.parsed;
|
|
88
|
+
if (parsed.type === "transfer") {
|
|
89
|
+
const info = parsed.info;
|
|
90
|
+
console.log(`[LocalSvmFacilitator] Found transfer: ${info.lamports} lamports to ${info.destination}`);
|
|
91
|
+
if (info.destination === payTo) {
|
|
92
|
+
paidAmount += BigInt(info.lamports);
|
|
93
|
+
if (!payer) payer = info.source;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
console.log(`[LocalSvmFacilitator] Total Paid Correctly: ${paidAmount}`);
|
|
99
|
+
if (paidAmount >= requiredAmount) {
|
|
100
|
+
console.log("[LocalSvmFacilitator] Verification SUCCESS");
|
|
101
|
+
return {
|
|
102
|
+
isValid: true,
|
|
103
|
+
payer: payer || tx.transaction.message.accountKeys[0].pubkey.toBase58()
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
console.error(`[LocalSvmFacilitator] Verification FAILED. Paid: ${paidAmount}, Required: ${requiredAmount}`);
|
|
107
|
+
return {
|
|
108
|
+
isValid: false,
|
|
109
|
+
invalidReason: `Insufficient payment. Required: ${requiredAmount}, Found: ${paidAmount}`,
|
|
110
|
+
payer
|
|
111
|
+
};
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error("[LocalSvmFacilitator] Verify error:", error);
|
|
114
|
+
throw new types.VerifyError(500, {
|
|
115
|
+
isValid: false,
|
|
116
|
+
invalidReason: error.message
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Settle a payment (not applicable for direct chain verification, usually)
|
|
122
|
+
* But we must implement it. For 'exact', settlement is just verification + finality.
|
|
123
|
+
*/
|
|
124
|
+
async settle(payload, requirements) {
|
|
125
|
+
const verifyResult = await this.verify(payload, requirements);
|
|
126
|
+
if (!verifyResult.isValid) {
|
|
127
|
+
throw new types.SettleError(400, {
|
|
128
|
+
success: false,
|
|
129
|
+
errorReason: verifyResult.invalidReason || "Verification failed",
|
|
130
|
+
transaction: payload.payload.signature,
|
|
131
|
+
network: requirements.network
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
success: true,
|
|
136
|
+
payer: verifyResult.payer,
|
|
137
|
+
transaction: payload.payload.signature,
|
|
138
|
+
network: requirements.network
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
};
|
|
7
142
|
|
|
8
143
|
// src/next/index.ts
|
|
9
144
|
function createX402Middleware(config) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
145
|
+
let facilitatorClient;
|
|
146
|
+
if (config.rpcUrl) {
|
|
147
|
+
facilitatorClient = new LocalSvmFacilitator(config.rpcUrl);
|
|
148
|
+
} else {
|
|
149
|
+
const facilitatorUrl = config.facilitatorUrl || "https://x402.org/facilitator";
|
|
150
|
+
facilitatorClient = new http.HTTPFacilitatorClient({
|
|
151
|
+
url: facilitatorUrl
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
const server$2 = new server.x402ResourceServer(facilitatorClient);
|
|
155
|
+
server$1.registerExactSvmScheme(server$2);
|
|
16
156
|
return function withMicropay(handler, routeConfig) {
|
|
17
157
|
const finalConfig = routeConfig || {
|
|
18
158
|
accepts: {
|
|
19
159
|
scheme: "exact",
|
|
20
160
|
payTo: config.walletAddress,
|
|
21
|
-
|
|
161
|
+
amount: config.price?.toString() || "0",
|
|
22
162
|
network: config.network === "mainnet-beta" ? "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" : "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
|
|
23
163
|
asset: "native"
|
|
24
164
|
}
|
package/dist/next/index.d.cts
CHANGED
|
@@ -14,6 +14,8 @@ interface X402Config {
|
|
|
14
14
|
price?: string | number;
|
|
15
15
|
/** Network (mainnet-beta or devnet) */
|
|
16
16
|
network?: 'mainnet-beta' | 'devnet';
|
|
17
|
+
/** RPC URL for local verification (optional, enables self-contained validation) */
|
|
18
|
+
rpcUrl?: string;
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* Create a specialized Next.js middleware with Solana support pre-configured
|
package/dist/next/index.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ interface X402Config {
|
|
|
14
14
|
price?: string | number;
|
|
15
15
|
/** Network (mainnet-beta or devnet) */
|
|
16
16
|
network?: 'mainnet-beta' | 'devnet';
|
|
17
|
+
/** RPC URL for local verification (optional, enables self-contained validation) */
|
|
18
|
+
rpcUrl?: string;
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* Create a specialized Next.js middleware with Solana support pre-configured
|
package/dist/next/index.js
CHANGED
|
@@ -3,21 +3,161 @@ import { x402ResourceServer } from '@x402/core/server';
|
|
|
3
3
|
export { x402ResourceServer } from '@x402/core/server';
|
|
4
4
|
import { HTTPFacilitatorClient } from '@x402/core/http';
|
|
5
5
|
import { registerExactSvmScheme } from '@x402/svm/exact/server';
|
|
6
|
+
import { Connection } from '@solana/web3.js';
|
|
7
|
+
import { VerifyError, SettleError } from '@x402/core/types';
|
|
8
|
+
|
|
9
|
+
// src/next/index.ts
|
|
10
|
+
var LocalSvmFacilitator = class {
|
|
11
|
+
scheme = "exact";
|
|
12
|
+
caipFamily = "solana:*";
|
|
13
|
+
connection;
|
|
14
|
+
constructor(rpcUrl) {
|
|
15
|
+
this.connection = new Connection(rpcUrl, "confirmed");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Get supported payment kinds
|
|
19
|
+
* Mocking the response of the /supported endpoint
|
|
20
|
+
*/
|
|
21
|
+
async getSupported(extensionKeys = []) {
|
|
22
|
+
return {
|
|
23
|
+
kinds: [
|
|
24
|
+
{
|
|
25
|
+
x402Version: 1,
|
|
26
|
+
scheme: "exact",
|
|
27
|
+
network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
|
|
28
|
+
// Devnet
|
|
29
|
+
extra: {}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
x402Version: 1,
|
|
33
|
+
scheme: "exact",
|
|
34
|
+
network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
|
|
35
|
+
// Mainnet
|
|
36
|
+
extra: {}
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
extensions: [],
|
|
40
|
+
signers: {
|
|
41
|
+
"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": [],
|
|
42
|
+
"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": []
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get mechanism-specific extra data
|
|
48
|
+
*/
|
|
49
|
+
getExtra(network) {
|
|
50
|
+
return void 0;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get default signers (not used for local verification usually, but required by interface)
|
|
54
|
+
*/
|
|
55
|
+
getSigners(network) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Verify a payment on-chain
|
|
60
|
+
*/
|
|
61
|
+
async verify(payload, requirements) {
|
|
62
|
+
try {
|
|
63
|
+
const signature = payload.payload.signature;
|
|
64
|
+
if (!signature) {
|
|
65
|
+
return { isValid: false, invalidReason: "Missing signature in payment payload" };
|
|
66
|
+
}
|
|
67
|
+
const payTo = requirements.payTo;
|
|
68
|
+
const amountVal = requirements.amount || requirements.maxAmountRequired || "0";
|
|
69
|
+
const requiredAmount = BigInt(amountVal);
|
|
70
|
+
console.log(`[LocalSvmFacilitator] Verifying signature: ${signature}`);
|
|
71
|
+
console.log(`[LocalSvmFacilitator] Required Amount: ${requiredAmount}, PayTo: ${payTo}`);
|
|
72
|
+
const tx = await this.connection.getParsedTransaction(signature, {
|
|
73
|
+
maxSupportedTransactionVersion: 0,
|
|
74
|
+
commitment: "confirmed"
|
|
75
|
+
});
|
|
76
|
+
if (!tx) {
|
|
77
|
+
console.error("[LocalSvmFacilitator] Transaction not found or not confirmed");
|
|
78
|
+
return { isValid: false, invalidReason: "Transaction not found or not confirmed" };
|
|
79
|
+
}
|
|
80
|
+
console.log("[LocalSvmFacilitator] Transaction found. Parsing instructions...");
|
|
81
|
+
const instructions = tx.transaction.message.instructions;
|
|
82
|
+
let paidAmount = 0n;
|
|
83
|
+
let payer = void 0;
|
|
84
|
+
for (const ix of instructions) {
|
|
85
|
+
if ("program" in ix && ix.program === "system") {
|
|
86
|
+
const parsed = ix.parsed;
|
|
87
|
+
if (parsed.type === "transfer") {
|
|
88
|
+
const info = parsed.info;
|
|
89
|
+
console.log(`[LocalSvmFacilitator] Found transfer: ${info.lamports} lamports to ${info.destination}`);
|
|
90
|
+
if (info.destination === payTo) {
|
|
91
|
+
paidAmount += BigInt(info.lamports);
|
|
92
|
+
if (!payer) payer = info.source;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
console.log(`[LocalSvmFacilitator] Total Paid Correctly: ${paidAmount}`);
|
|
98
|
+
if (paidAmount >= requiredAmount) {
|
|
99
|
+
console.log("[LocalSvmFacilitator] Verification SUCCESS");
|
|
100
|
+
return {
|
|
101
|
+
isValid: true,
|
|
102
|
+
payer: payer || tx.transaction.message.accountKeys[0].pubkey.toBase58()
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
console.error(`[LocalSvmFacilitator] Verification FAILED. Paid: ${paidAmount}, Required: ${requiredAmount}`);
|
|
106
|
+
return {
|
|
107
|
+
isValid: false,
|
|
108
|
+
invalidReason: `Insufficient payment. Required: ${requiredAmount}, Found: ${paidAmount}`,
|
|
109
|
+
payer
|
|
110
|
+
};
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error("[LocalSvmFacilitator] Verify error:", error);
|
|
113
|
+
throw new VerifyError(500, {
|
|
114
|
+
isValid: false,
|
|
115
|
+
invalidReason: error.message
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Settle a payment (not applicable for direct chain verification, usually)
|
|
121
|
+
* But we must implement it. For 'exact', settlement is just verification + finality.
|
|
122
|
+
*/
|
|
123
|
+
async settle(payload, requirements) {
|
|
124
|
+
const verifyResult = await this.verify(payload, requirements);
|
|
125
|
+
if (!verifyResult.isValid) {
|
|
126
|
+
throw new SettleError(400, {
|
|
127
|
+
success: false,
|
|
128
|
+
errorReason: verifyResult.invalidReason || "Verification failed",
|
|
129
|
+
transaction: payload.payload.signature,
|
|
130
|
+
network: requirements.network
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
success: true,
|
|
135
|
+
payer: verifyResult.payer,
|
|
136
|
+
transaction: payload.payload.signature,
|
|
137
|
+
network: requirements.network
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
};
|
|
6
141
|
|
|
7
142
|
// src/next/index.ts
|
|
8
143
|
function createX402Middleware(config) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
144
|
+
let facilitatorClient;
|
|
145
|
+
if (config.rpcUrl) {
|
|
146
|
+
facilitatorClient = new LocalSvmFacilitator(config.rpcUrl);
|
|
147
|
+
} else {
|
|
148
|
+
const facilitatorUrl = config.facilitatorUrl || "https://x402.org/facilitator";
|
|
149
|
+
facilitatorClient = new HTTPFacilitatorClient({
|
|
150
|
+
url: facilitatorUrl
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
const server = new x402ResourceServer(facilitatorClient);
|
|
154
|
+
registerExactSvmScheme(server);
|
|
15
155
|
return function withMicropay(handler, routeConfig) {
|
|
16
156
|
const finalConfig = routeConfig || {
|
|
17
157
|
accepts: {
|
|
18
158
|
scheme: "exact",
|
|
19
159
|
payTo: config.walletAddress,
|
|
20
|
-
|
|
160
|
+
amount: config.price?.toString() || "0",
|
|
21
161
|
network: config.network === "mainnet-beta" ? "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" : "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
|
|
22
162
|
asset: "native"
|
|
23
163
|
}
|
package/package.json
CHANGED