prividium 0.1.4 → 0.1.6

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 CHANGED
@@ -62,16 +62,22 @@ const prividium = createPrividiumChain({
62
62
  });
63
63
  ```
64
64
 
65
- ### 2. Create Viem Client
65
+ ### 2. Create Prividium™ Viem Client
66
66
 
67
67
  ```typescript
68
+ import { createPrividiumClient } from 'prividium';
69
+
68
70
  // The SDK provides a pre-configured transport with automatic auth headers
69
- const client = createPublicClient({
71
+ const client = createPrividiumClient({
70
72
  chain: prividium.chain,
71
- transport: prividium.transport // ✨ Auth headers are automatically included!
73
+ transport: prividium.transport, // ✨ Auth headers are automatically included!
74
+ account: '0x...' // 🔐 Provide user account to make `eth_call`s from that address
72
75
  });
73
76
  ```
74
77
 
78
+ **Note:** Providing the account is required only for read operations that use `eth_call`. Prividium™ needs to know the
79
+ caller address to enforce permissions correctly.
80
+
75
81
  ### 3. Authenticate and Use
76
82
 
77
83
  ```typescript
@@ -87,7 +93,35 @@ const balance = await client.getBalance({
87
93
  });
88
94
  ```
89
95
 
90
- ### 4. Sending Transactions with Injected Wallets (MetaMask)
96
+ ### 4. Reading contract data
97
+
98
+ ```typescript
99
+ import { createContract } from 'viem';
100
+ // Define contract
101
+ const greeterContract = createContract({
102
+ address: '0x...',
103
+ abi: [
104
+ {
105
+ name: 'getGreeting',
106
+ type: 'function',
107
+ inputs: [],
108
+ outputs: [{ name: '', type: 'string' }],
109
+ stateMutability: 'view'
110
+ }
111
+ ],
112
+ client: client
113
+ });
114
+
115
+ // Read data
116
+ if (!client.account) {
117
+ console.warn('Client account is not set. Connect wallet.');
118
+ } else {
119
+ const greeting = await greeterContract.read.getGreeting();
120
+ console.log('Greeting:', greeting);
121
+ }
122
+ ```
123
+
124
+ ### 5. Sending Transactions with Injected Wallets (MetaMask)
91
125
 
92
126
  Before sending transactions through injected wallets, you need to add the Prividium™ network and enable wallet RPC for
93
127
  each transaction.
@@ -121,26 +155,28 @@ const request = await walletClient.prepareTransactionRequest({
121
155
  }
122
156
  ],
123
157
  functionName: 'setGreeting',
124
- args: ['Hello, Prividium!']
158
+ args: ['Hello, Prividium!'],
159
+ value: 0n // Optional ETH value to send
125
160
  })
126
161
  });
127
162
 
128
- // Enable wallet token for this transaction
129
- await prividium.enableWalletToken({
163
+ // Authorize transaction
164
+ await prividium.authorizeTransaction({
130
165
  walletAddress: address,
131
166
  contractAddress: greeterContract,
132
167
  nonce: Number(request.nonce),
133
- calldata: request.data
168
+ calldata: request.data,
169
+ value: request.value
134
170
  });
135
171
 
136
172
  // Send transaction through MetaMask
137
173
  const hash = await walletClient.sendTransaction(request);
138
174
  ```
139
175
 
140
- **Note:** Call `enableWalletToken(...)` before each transaction. Permission is transaction-specific and expires after 1
141
- hour.
176
+ **Note:** Call `authorizeTransaction(...)` before each transaction. Permission is transaction-specific and expires after
177
+ 1 hour.
142
178
 
143
- ### 5. Setup OAuth Callback Page
179
+ ### 6. Setup OAuth Callback Page
144
180
 
145
181
  The SDK requires a callback page to complete the authentication flow securely using `postMessage`. Create a callback
146
182
  page at the `redirectUrl` you configured:
@@ -246,8 +282,8 @@ Opens authentication popup and handles OAuth flow.
246
282
 
247
283
  ```typescript
248
284
  await prividium.authorize({
249
- popupSize: { w: 600, h: 700 } // Optional custom popup dimensions
250
- scopes: ['wallet:required', 'network:required'], // Optional scope requests
285
+ popupSize: { w: 600, h: 700 }, // Optional custom popup dimensions
286
+ scopes: ['wallet:required', 'network:required'] // Optional scope requests
251
287
  });
252
288
  ```
253
289
 
@@ -307,6 +343,23 @@ handleAuthCallback((error) => {
307
343
  - Automatically closes popup window on success
308
344
  - Calls `onError` if any errors occur
309
345
 
346
+ ### `createPrividiumClient(config)`
347
+
348
+ Creates a viem client.
349
+
350
+ **Parameters:**
351
+
352
+ ```typescript
353
+ interface PrividiumClientConfig {
354
+ chain: Chain; // Viem chain configuration
355
+ transport: Transport; // Viem transport with Prividium™ auth headers
356
+ account?: Address; // Optional user account for eth_call operations
357
+ // Other viem client config options...
358
+ }
359
+ ```
360
+
361
+ **Returns:** `PublicClient` - Viem client instance.
362
+
310
363
  ## Advanced Usage
311
364
 
312
365
  ### Custom Storage
@@ -446,6 +499,7 @@ Flags:
446
499
  - `--host, -h` (string, default `127.0.0.1`): host binded to server. By default only connections comming from local
447
500
  device will be accepted. WARNING: Using 0.0.0.0 implies allowing anyone in the local network to use your credentials.
448
501
  - `--config-path, -c` (string): Path to the CLI config file.
502
+ - `--unsecure-allow-outside-access`: Needed to expose the proxy to any network (including local network).
449
503
 
450
504
  Environment variables (optional):
451
505
 
@@ -1,4 +1,6 @@
1
1
  import { buildServer } from '../server/server.js';
2
+ import { log } from '@clack/prompts';
3
+ import color from 'kleur';
2
4
  import { CreationWorkflow } from '../server/connection-workflow.js';
3
5
  import { ConfigFile } from '../server/config-file.js';
4
6
  import { z } from 'zod';
@@ -6,6 +8,24 @@ const envSchema = z.object({
6
8
  PRIVIDIUM_RPC_URL: z.string().optional(),
7
9
  USER_PANEL_URL: z.string().optional()
8
10
  });
11
+ const DEFAULT_PORT = 24101;
12
+ function checkHostAndPortWarnings(host, port, allowExternalAccess) {
13
+ if (port !== DEFAULT_PORT) {
14
+ log.warn(`Non standard port detected: ${port}. Redirect from prividium auth might not work.`);
15
+ }
16
+ if (host !== '127.0.0.1' && host !== 'localhost') {
17
+ if (!allowExternalAccess) {
18
+ log.error(`${color.bold('ERROR')}: In order to use a host different than local host you need to set --unsecureAllowOutsideAccess flag.`);
19
+ process.exit(1);
20
+ }
21
+ if (host === '0.0.0.0') {
22
+ log.warn(`${color.bold('WARNING')}: Your local proxy will be exposed outside your current device.`);
23
+ }
24
+ else {
25
+ log.warn(`${color.bold('WARNING')}: Non standard host: ${host}. Your proxy might be open for other devices. Redirect from prividium auth might not work.`);
26
+ }
27
+ }
28
+ }
9
29
  async function startServer(opts) {
10
30
  const config = new ConfigFile(opts.configPath);
11
31
  const workflow = new CreationWorkflow(config);
@@ -18,6 +38,8 @@ async function startServer(opts) {
18
38
  const app = buildServer({
19
39
  prividiumRpcUrl,
20
40
  userPanelUrl,
41
+ host: opts.host,
42
+ port: opts.port,
21
43
  async onSubmit() {
22
44
  await workflow.onSubmit();
23
45
  },
@@ -25,9 +47,10 @@ async function startServer(opts) {
25
47
  workflow.onMessage(methodName);
26
48
  }
27
49
  });
50
+ checkHostAndPortWarnings(opts.host, opts.port, opts.allowExternalAccess);
28
51
  const serverUrl = await app.listen({
29
- port: 24101,
30
- host: '127.0.0.1'
52
+ port: opts.port,
53
+ host: opts.host
31
54
  });
32
55
  await workflow.waitForAuthentication(serverUrl);
33
56
  }
@@ -53,19 +76,26 @@ export const addProxy = (cli) => {
53
76
  .option('port', {
54
77
  alias: ['p'],
55
78
  description: 'Port used for local proxy. This has to match with the port configured in your Prividium™ network.',
56
- default: 24101,
79
+ default: DEFAULT_PORT,
57
80
  type: 'number'
58
81
  })
59
82
  .option('host', {
60
83
  alias: 'h',
61
84
  description: 'Host used for local server. By default traffic from outside localhost is disabled.',
62
- default: '127.0.0.1',
85
+ default: 'localhost',
63
86
  type: 'string'
87
+ })
88
+ .option('unsecureAllowOutsideAccess', {
89
+ alias: ['unsecure-allow-outside-access'],
90
+ description: 'Allow server to be exposed to the network (accessible by other devices)',
91
+ default: false,
92
+ type: 'boolean'
64
93
  }), (args) => startServer({
65
94
  rpcUrl: args.rpcUrl,
66
95
  userPanelUrl: args.userPanelUrl,
67
96
  configPath: args.configPath,
68
97
  port: args.port,
69
- host: args.host
98
+ host: args.host,
99
+ allowExternalAccess: args.unsecureAllowOutsideAccess
70
100
  }));
71
101
  };
@@ -5,6 +5,7 @@ import path from 'node:path';
5
5
  import { z } from 'zod';
6
6
  import { fastifyHttpProxy } from '@fastify/http-proxy';
7
7
  import { randomBytes } from 'node:crypto';
8
+ import { log } from '@clack/prompts';
8
9
  function fastifyApp() {
9
10
  return Fastify().withTypeProvider();
10
11
  }
@@ -17,7 +18,7 @@ export function buildServer(config) {
17
18
  const app = fastifyApp();
18
19
  app.setValidatorCompiler(validatorCompiler);
19
20
  const state = randomStateString();
20
- let jwt = '';
21
+ let accessToken = '';
21
22
  app.register(fastifyStatic, { root: path.join(import.meta.dirname, '..', 'static') });
22
23
  app.get('/health', async (_req, reply) => {
23
24
  return reply.send('ok');
@@ -49,7 +50,7 @@ export function buildServer(config) {
49
50
  if (req.body.state !== state) {
50
51
  throw new Error('invalid state received');
51
52
  }
52
- jwt = req.body.token;
53
+ accessToken = req.body.token;
53
54
  await config.onSubmit();
54
55
  return reply.send('ok');
55
56
  });
@@ -57,6 +58,7 @@ export function buildServer(config) {
57
58
  upstream: config.prividiumRpcUrl,
58
59
  prefix: '/rpc',
59
60
  rewritePrefix: '/rpc',
61
+ httpMethods: ['POST'],
60
62
  routes: ['/'],
61
63
  preValidation: (request, _reply, done) => {
62
64
  const method = rpcReqSchema.safeParse(request.body);
@@ -71,17 +73,24 @@ export function buildServer(config) {
71
73
  }
72
74
  done();
73
75
  },
74
- preHandler: (_req, reply, done) => {
75
- if (jwt === '') {
76
+ preHandler: (req, reply, done) => {
77
+ if (accessToken === '') {
76
78
  reply.status(500).send('please authenticate first.');
77
79
  return;
78
80
  }
81
+ const portStr = config.port !== 80 ? `:${config.port}` : '';
82
+ const fullHost = `${config.host}${portStr}`;
83
+ if (req.headers.host && req.headers.host !== fullHost) {
84
+ log.error(`Expected host ${fullHost} but got ${req.headers.host}`);
85
+ reply.status(403).send("host doesn't match");
86
+ return;
87
+ }
79
88
  return done();
80
89
  },
81
90
  replyOptions: {
82
91
  rewriteRequestHeaders: (_originalReq, headers) => ({
83
92
  ...headers,
84
- authorization: `Bearer ${jwt}`
93
+ authorization: `Bearer ${accessToken}`
85
94
  })
86
95
  }
87
96
  });
@@ -0,0 +1,8 @@
1
+ import { type Account, type Chain, type ClientConfig, type PublicClient, type PublicClientConfig, type RpcSchema, type Transport } from 'viem';
2
+ type PrividiumClientConfig<transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined, accountOrAddress extends Account | undefined = undefined, rpcSchema extends RpcSchema | undefined = undefined> = PublicClientConfig<transport, chain, accountOrAddress, rpcSchema> & Pick<ClientConfig<transport, chain, accountOrAddress, rpcSchema>, 'account'>;
3
+ /**
4
+ * Creates a Prividium specific Public Client. This client extends the standard Viem Public Client
5
+ * with additional checks required for Prividium operations.
6
+ */
7
+ export declare function createPrividiumClient<transport extends Transport = Transport, chain extends Chain | undefined = Chain | undefined, accountOrAddress extends Account | undefined = undefined, rpcSchema extends RpcSchema | undefined = undefined>(config: PrividiumClientConfig<transport, chain, accountOrAddress, rpcSchema>): PublicClient<transport, chain, accountOrAddress, rpcSchema>;
8
+ export {};
@@ -0,0 +1,25 @@
1
+ import { createClient, publicActions } from 'viem';
2
+ function prividiumActions(client) {
3
+ return {
4
+ call: (args) => {
5
+ if (!client.account || !client.account.address) {
6
+ throw new Error('RPC method eth_call requires an account to be provided for the client');
7
+ }
8
+ return client.call(args);
9
+ }
10
+ };
11
+ }
12
+ /**
13
+ * Creates a Prividium specific Public Client. This client extends the standard Viem Public Client
14
+ * with additional checks required for Prividium operations.
15
+ */
16
+ export function createPrividiumClient(config) {
17
+ const { key = 'prividium', name = 'Prividium™ Public Client' } = config;
18
+ const client = createClient({
19
+ ...config,
20
+ key,
21
+ name,
22
+ type: 'publicClient'
23
+ });
24
+ return client.extend(publicActions).extend(prividiumActions);
25
+ }
@@ -5,3 +5,4 @@ export { LocalStorage, TokenManager } from './storage.js';
5
5
  export { generateRandomState } from './token-utils.js';
6
6
  export { PopupAuth, handleAuthCallback, type AuthCallbackMessage, type OauthScope } from './popup-auth.js';
7
7
  export { UNAUTHORIZED_ERROR_CODE, FORBIDDEN_ERROR_CODE } from './rpc-error-codes.js';
8
+ export { createPrividiumClient } from './create-prividium-client.js';
package/dist/sdk/index.js CHANGED
@@ -4,3 +4,4 @@ export { LocalStorage, TokenManager } from './storage.js';
4
4
  export { generateRandomState } from './token-utils.js';
5
5
  export { PopupAuth, handleAuthCallback } from './popup-auth.js';
6
6
  export { UNAUTHORIZED_ERROR_CODE, FORBIDDEN_ERROR_CODE } from './rpc-error-codes.js';
7
+ export { createPrividiumClient } from './create-prividium-client.js';
@@ -1,4 +1,4 @@
1
- import { type PrividiumConfig, type PrividiumChain } from './types.js';
1
+ import { type PrividiumChain, type PrividiumConfig } from './types.js';
2
2
  declare global {
3
3
  interface Window {
4
4
  ethereum?: {
@@ -142,18 +142,23 @@ export function createPrividiumChain(config) {
142
142
  const result = (await response.json());
143
143
  return result.newWalletToken;
144
144
  },
145
- async enableWalletToken(params) {
145
+ async authorizeTransaction(params) {
146
146
  const headers = getAuthHeaders();
147
147
  if (!headers) {
148
148
  throw new Error('Authentication required. Please call authorize() first.');
149
149
  }
150
- const response = await fetch(`${config.permissionsApiBaseUrl}/api/wallet/enable`, {
150
+ const response = await fetch(`${config.permissionsApiBaseUrl}/api/wallet/transaction-authorization`, {
151
151
  method: 'POST',
152
152
  headers: {
153
153
  'Content-Type': 'application/json',
154
154
  ...headers
155
155
  },
156
- body: JSON.stringify(params)
156
+ body: JSON.stringify({
157
+ ...params,
158
+ // Always pass calldata and value, even if undefined
159
+ calldata: params?.calldata ?? '0x',
160
+ value: params.value?.toString() ?? '0'
161
+ })
157
162
  });
158
163
  if (response.status === 403) {
159
164
  tokenManager.clearToken();
@@ -161,7 +166,7 @@ export function createPrividiumChain(config) {
161
166
  throw new Error('Authentication required. Please call authorize() first.');
162
167
  }
163
168
  if (!response.ok) {
164
- throw new Error(`Failed to enable wallet token: ${response.status} ${response.statusText}`);
169
+ throw new Error(`Failed to authorize transaction: ${response.status} ${response.statusText}`);
165
170
  }
166
171
  const result = (await response.json());
167
172
  return result;
@@ -1,4 +1,4 @@
1
- import { type Chain, type Transport, type Address, type Hex } from 'viem';
1
+ import { type Address, type Chain, type Hex, type Transport } from 'viem';
2
2
  import { type OauthScope } from './popup-auth.js';
3
3
  export interface Storage {
4
4
  getItem(key: string): string | null;
@@ -36,13 +36,26 @@ export interface AddNetworkParams {
36
36
  };
37
37
  blockExplorerUrls?: string[];
38
38
  }
39
- export interface EnableWalletTokenParams {
39
+ export type AuthorizeTransactionParams = {
40
40
  walletAddress: Address;
41
- contractAddress: Address;
41
+ toAddress: Address;
42
42
  nonce: number;
43
43
  calldata: Hex;
44
- }
45
- export interface EnableWalletTokenResponse {
44
+ value: bigint;
45
+ } | {
46
+ walletAddress: Address;
47
+ toAddress: Address;
48
+ nonce: number;
49
+ calldata: Hex;
50
+ value?: never;
51
+ } | {
52
+ walletAddress: Address;
53
+ toAddress: Address;
54
+ nonce: number;
55
+ calldata?: never;
56
+ value: bigint;
57
+ };
58
+ export interface AuthorizeTransactionResponse {
46
59
  message: string;
47
60
  activeUntil: string;
48
61
  }
@@ -57,7 +70,7 @@ export interface PrividiumChain {
57
70
  getWalletToken(): Promise<string>;
58
71
  getWalletRpcUrl(): Promise<string>;
59
72
  invalidateWalletToken(): Promise<string>;
60
- enableWalletToken(params: EnableWalletTokenParams): Promise<EnableWalletTokenResponse>;
73
+ authorizeTransaction(params: AuthorizeTransactionParams): Promise<AuthorizeTransactionResponse>;
61
74
  addNetworkToWallet(params?: AddNetworkParams): Promise<void>;
62
75
  }
63
76
  export interface TokenData {
@@ -1 +1 @@
1
- {"root":["../src/error-utils.ts","../src/index.ts","../src/popup-auth.ts","../src/prividium-chain.ts","../src/rpc-error-codes.ts","../src/storage.ts","../src/token-utils.ts","../src/types.ts"],"version":"5.8.3"}
1
+ {"root":["../src/create-prividium-client.ts","../src/error-utils.ts","../src/index.ts","../src/popup-auth.ts","../src/prividium-chain.ts","../src/rpc-error-codes.ts","../src/storage.ts","../src/token-utils.ts","../src/types.ts"],"version":"5.8.3"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prividium",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "bin": {
5
5
  "prividium": "./bin/cli.js"
6
6
  },