prividium 1.3.1 → 1.4.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 +5 -3
- package/dist/cli/commands/doctor/probes/authentication/authentication.js +2 -4
- package/dist/cli/commands/doctor/probes/global/input-validation.js +3 -4
- package/dist/cli/commands/doctor/probes/global/well-known.d.ts +2 -0
- package/dist/cli/commands/doctor/probes/global/well-known.js +16 -0
- package/dist/cli/commands/doctor/probes/global.js +9 -1
- package/dist/cli/commands/doctor/report/build.js +3 -1
- package/dist/cli/commands/doctor/types.d.ts +2 -2
- package/dist/cli/commands/doctor/utils.d.ts +1 -1
- package/dist/cli/commands/doctor/utils.js +2 -7
- package/dist/cli/commands/doctor.js +7 -8
- package/dist/cli/commands/proxy.js +12 -74
- package/dist/cli/commands/utils/url-config.d.ts +1 -11
- package/dist/cli/commands/utils/url-config.js +17 -18
- package/dist/cli/server/config-file.d.ts +0 -6
- package/dist/cli/server/config-file.js +2 -9
- package/dist/sdk/admin-api/index.d.ts +1 -1
- package/dist/sdk/admin-api/types.d.ts +4 -9
- package/dist/sdk/admin-api/users.d.ts +2 -2
- package/dist/sdk/admin-api/users.js +18 -4
- package/dist/sdk/index.d.ts +1 -0
- package/dist/sdk/index.js +1 -0
- package/dist/sdk/siwe.d.ts +1 -1
- package/dist/sdk/well-known.d.ts +30 -0
- package/dist/sdk/well-known.js +58 -0
- package/dist/tsconfig.cli.tsbuildinfo +1 -1
- package/dist/tsconfig.sdk.tsbuildinfo +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Prividium™ SDK & CLI
|
|
2
2
|
|
|
3
|
-
A TypeScript SDK and CLI for integrating with the Prividium™ authorization system. The SDK
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
A TypeScript SDK and CLI for integrating with the Prividium™ authorization system. The SDK handles **authentication** —
|
|
4
|
+
signing in with OIDC or SIWE and attaching your identity to each request — while Prividium™ enforces **authorization**
|
|
5
|
+
server-side from your assigned roles, controlling which contract functions, events, and data you can access; the SDK
|
|
6
|
+
does not grant permissions. It provides popup OAuth, token management, and a viem transport for secure RPC; the CLI runs
|
|
7
|
+
a local authenticated JSON-RPC proxy to your Prividium™ RPC and manages basic configuration.
|
|
6
8
|
|
|
7
9
|
## Features
|
|
8
10
|
|
|
@@ -4,12 +4,10 @@ import { fetchAuthenticatedJson } from '../../clients/http.js';
|
|
|
4
4
|
import { DEFAULT_DOCTOR_CALLBACK_PORT } from '../../constants.js';
|
|
5
5
|
import { profileSchema } from '../../profile.js';
|
|
6
6
|
export async function runBrowserAuthProbe(context) {
|
|
7
|
-
|
|
8
|
-
context.pendingToken = token;
|
|
7
|
+
context.pendingToken = await authenticateInBrowser(context.targets.userPanelBaseUrl, DEFAULT_DOCTOR_CALLBACK_PORT);
|
|
9
8
|
}
|
|
10
9
|
export async function runSessionValidationProbe(context) {
|
|
11
|
-
|
|
12
|
-
context.pendingSession = session;
|
|
10
|
+
context.pendingSession = await fetchAuthenticatedJson(sessionSchema, new URL('/api/auth/current-session', context.targets.apiBaseUrl).href, context.pendingToken);
|
|
13
11
|
}
|
|
14
12
|
export async function runProfileFetchProbe(context) {
|
|
15
13
|
const profile = await fetchAuthenticatedJson(profileSchema, new URL('/api/profiles/me', context.targets.apiBaseUrl).href, context.pendingToken);
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { validateAndNormalizeUrls } from '../../utils.js';
|
|
2
2
|
export async function runInputValidationProbe(context) {
|
|
3
|
-
|
|
4
|
-
context.targets = targets;
|
|
3
|
+
context.targets = validateAndNormalizeUrls(context.rawRpcUrl);
|
|
5
4
|
}
|
|
6
5
|
export async function runHostMismatchProbe(context) {
|
|
7
6
|
const warnings = [];
|
|
8
|
-
if (context.targets.apiBaseUrl !== context.rawRpcUrl) {
|
|
7
|
+
if (new URL(context.targets.apiBaseUrl).origin !== new URL(context.rawRpcUrl).origin) {
|
|
9
8
|
warnings.push({ label: 'api', value: context.rawRpcUrl });
|
|
10
9
|
}
|
|
11
10
|
if (context.targets.userPanelBaseUrl !== context.rawUserPanelUrl) {
|
|
12
|
-
warnings.push({ label: 'user panel', value: context.rawUserPanelUrl });
|
|
11
|
+
warnings.push({ label: 'user panel', value: context.rawUserPanelUrl ?? '' });
|
|
13
12
|
}
|
|
14
13
|
if (warnings.length > 0) {
|
|
15
14
|
return {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { fetchPrividiumConfig } from '#sdk';
|
|
2
|
+
export async function runWellKnownProbe(context) {
|
|
3
|
+
const prividiumInfo = await fetchPrividiumConfig(new URL(context.targets.apiBaseUrl).origin);
|
|
4
|
+
context.targets = {
|
|
5
|
+
...context.targets,
|
|
6
|
+
userPanelBaseUrl: new URL(prividiumInfo.userPanelUrl).origin
|
|
7
|
+
};
|
|
8
|
+
context.apiVersion = prividiumInfo.version;
|
|
9
|
+
return {
|
|
10
|
+
values: [
|
|
11
|
+
{ label: 'User Panel', value: prividiumInfo.userPanelUrl, inline: true },
|
|
12
|
+
{ label: 'Chain', value: prividiumInfo.chainName, inline: true },
|
|
13
|
+
{ label: 'Version', value: prividiumInfo.version, inline: true }
|
|
14
|
+
]
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { passed } from '../utils.js';
|
|
2
2
|
import { runHostMismatchProbe, runInputValidationProbe } from './global/input-validation.js';
|
|
3
3
|
import { runApiHealthProbe, runCallbackPortProbe, runPublicRpcProbe, runUserPanelReachabilityProbe } from './global/reachability.js';
|
|
4
|
+
import { runWellKnownProbe } from './global/well-known.js';
|
|
4
5
|
export const globalStage = {
|
|
5
6
|
id: 'global',
|
|
6
7
|
title: 'Global',
|
|
@@ -22,11 +23,18 @@ export const globalStage = {
|
|
|
22
23
|
runIf: passed('input-validation', 'Input validation failed'),
|
|
23
24
|
run: runHostMismatchProbe
|
|
24
25
|
},
|
|
26
|
+
{
|
|
27
|
+
id: 'well-known',
|
|
28
|
+
label: 'Prividium configuration',
|
|
29
|
+
progressMessage: 'Fetching Prividium configuration',
|
|
30
|
+
runIf: passed('input-validation', 'Input validation failed'),
|
|
31
|
+
run: runWellKnownProbe
|
|
32
|
+
},
|
|
25
33
|
{
|
|
26
34
|
id: 'user-panel-reachable',
|
|
27
35
|
label: 'User Panel reachability',
|
|
28
36
|
progressMessage: 'Checking User Panel reachability',
|
|
29
|
-
runIf: passed('
|
|
37
|
+
runIf: passed('well-known', 'Could not discover User Panel url'),
|
|
30
38
|
run: runUserPanelReachabilityProbe
|
|
31
39
|
},
|
|
32
40
|
{
|
|
@@ -22,7 +22,9 @@ function buildSummaryBlock(context) {
|
|
|
22
22
|
{ label: 'Status', value: `${failCount} failed, ${skipCount} skipped, ${passCount} passed` },
|
|
23
23
|
{ label: 'API', value: context.targets?.apiBaseUrl ?? context.rawRpcUrl },
|
|
24
24
|
...(context.apiVersion ? [{ label: 'API Version', value: context.apiVersion }] : []),
|
|
25
|
-
|
|
25
|
+
...(context.targets?.userPanelBaseUrl
|
|
26
|
+
? [{ label: 'User Panel', value: context.targets.userPanelBaseUrl }]
|
|
27
|
+
: []),
|
|
26
28
|
{ label: 'Time', value: new Date().toISOString() }
|
|
27
29
|
]
|
|
28
30
|
};
|
|
@@ -8,7 +8,7 @@ export type Options = {
|
|
|
8
8
|
};
|
|
9
9
|
export type NormalizedTargets = {
|
|
10
10
|
apiBaseUrl: string;
|
|
11
|
-
userPanelBaseUrl
|
|
11
|
+
userPanelBaseUrl?: string;
|
|
12
12
|
};
|
|
13
13
|
export type ReportStatus = 'pass' | 'warn' | 'fail' | 'skip';
|
|
14
14
|
export type ReportValue = {
|
|
@@ -59,7 +59,7 @@ export type AuthenticatedDoctorState = {
|
|
|
59
59
|
};
|
|
60
60
|
export type DoctorContext = {
|
|
61
61
|
rawRpcUrl: string;
|
|
62
|
-
rawUserPanelUrl
|
|
62
|
+
rawUserPanelUrl?: string;
|
|
63
63
|
targets?: NormalizedTargets;
|
|
64
64
|
authState?: AuthenticatedDoctorState;
|
|
65
65
|
reportContext?: ReportContext;
|
|
@@ -15,4 +15,4 @@ export declare function formatHexQuantity(value: string): string;
|
|
|
15
15
|
export declare function shortenAddress(address: string): string;
|
|
16
16
|
export declare function getRawReason(status: number, body: string): string;
|
|
17
17
|
export declare function getThrownReason(error: unknown): string;
|
|
18
|
-
export declare function validateAndNormalizeUrls(prividiumRpcUrl: string
|
|
18
|
+
export declare function validateAndNormalizeUrls(prividiumRpcUrl: string): NormalizedTargets;
|
|
@@ -36,17 +36,12 @@ export function getRawReason(status, body) {
|
|
|
36
36
|
export function getThrownReason(error) {
|
|
37
37
|
return error instanceof Error ? error.message : String(error);
|
|
38
38
|
}
|
|
39
|
-
export function validateAndNormalizeUrls(prividiumRpcUrl
|
|
39
|
+
export function validateAndNormalizeUrls(prividiumRpcUrl) {
|
|
40
40
|
const apiParse = z.url().safeParse(prividiumRpcUrl);
|
|
41
41
|
if (!apiParse.success) {
|
|
42
42
|
throw new Error(`Invalid API url provided: ${prividiumRpcUrl}`);
|
|
43
43
|
}
|
|
44
|
-
const panelParse = z.url().safeParse(userPanelUrl);
|
|
45
|
-
if (!panelParse.success) {
|
|
46
|
-
throw new Error(`Invalid user panel url provided: ${userPanelUrl}`);
|
|
47
|
-
}
|
|
48
44
|
return {
|
|
49
|
-
apiBaseUrl: `${new URL(prividiumRpcUrl).origin}/rpc
|
|
50
|
-
userPanelBaseUrl: new URL(userPanelUrl).origin
|
|
45
|
+
apiBaseUrl: `${new URL(prividiumRpcUrl).origin}/rpc`
|
|
51
46
|
};
|
|
52
47
|
}
|
|
@@ -8,19 +8,16 @@ import { buildDoctorReport } from './doctor/report/build.js';
|
|
|
8
8
|
import { printReport } from './doctor/report/render.js';
|
|
9
9
|
import { executeDoctorStages } from './doctor/stages.js';
|
|
10
10
|
import { showPrividiumHeader } from './utils/show-prividium-header.js';
|
|
11
|
-
import {
|
|
11
|
+
import { gatherApiUrl } from './utils/url-config.js';
|
|
12
12
|
async function runDoctor(opts) {
|
|
13
13
|
showPrividiumHeader();
|
|
14
14
|
intro('Prividium™ Doctor');
|
|
15
|
-
const
|
|
15
|
+
const prividiumRpcUrl = await gatherApiUrl({
|
|
16
16
|
configPath: opts.configPath,
|
|
17
|
-
|
|
18
|
-
userPanelUrl: opts.userPanelUrl,
|
|
19
|
-
rpcUrlLabel: 'prividium api'
|
|
17
|
+
apiUrl: opts.rpcUrl
|
|
20
18
|
});
|
|
21
19
|
const executionContext = {
|
|
22
20
|
rawRpcUrl: prividiumRpcUrl,
|
|
23
|
-
rawUserPanelUrl: userPanelUrl,
|
|
24
21
|
walletAddresses: [],
|
|
25
22
|
walletApiAvailable: false,
|
|
26
23
|
results: []
|
|
@@ -52,13 +49,15 @@ export const addDoctor = (cli) => {
|
|
|
52
49
|
return cli.command('doctor', 'Runs Prividium Doctor checks', (yargs) => yargs
|
|
53
50
|
.option('rpcUrl', {
|
|
54
51
|
alias: ['prividium-api-url', 'rpc-url', 'r'],
|
|
55
|
-
description: 'Target Prividium™ API URL or /rpc URL.
|
|
52
|
+
description: 'Target Prividium™ API URL or /rpc URL. The User Panel url and chain config are fetched from /.well-known/prividium on this host.',
|
|
56
53
|
demandOption: false,
|
|
57
54
|
type: 'string'
|
|
58
55
|
})
|
|
59
56
|
.option('userPanelUrl', {
|
|
60
57
|
alias: ['user-panel-url', 'u'],
|
|
61
|
-
description: 'User
|
|
58
|
+
description: 'Specifies the User Panel url to check. When provided, this value takes priority and the User Panel url is not fetched from /.well-known/prividium.',
|
|
59
|
+
demandOption: false,
|
|
60
|
+
deprecated: 'fetched automatically from Prividium™ API.',
|
|
62
61
|
type: 'string'
|
|
63
62
|
}), async (args) => {
|
|
64
63
|
try {
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { intro, log
|
|
1
|
+
import { intro, log } from '@clack/prompts';
|
|
2
2
|
import color from 'kleur';
|
|
3
3
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
4
|
-
import { z } from 'zod';
|
|
5
4
|
import { MemoryStorage, SiweAuth, TokenManager } from '#sdk/siwe';
|
|
6
5
|
import { CreationWorkflow } from '../server/connection-workflow.js';
|
|
7
6
|
import { buildServer } from '../server/server.js';
|
|
8
7
|
import { showPrividiumHeader } from './utils/show-prividium-header.js';
|
|
9
|
-
import { gatherApiUrl } from './utils/url-config.js';
|
|
8
|
+
import { gatherApiUrl, getUserPanelUrl } from './utils/url-config.js';
|
|
10
9
|
const DEFAULT_PORT = 24101;
|
|
11
10
|
const PRIVATE_KEY_REGEX = /^0x[0-9a-fA-F]{64}$/;
|
|
12
11
|
function checkHostAndPortWarnings(host, port, allowExternalAccess) {
|
|
@@ -26,64 +25,6 @@ function checkHostAndPortWarnings(host, port, allowExternalAccess) {
|
|
|
26
25
|
}
|
|
27
26
|
}
|
|
28
27
|
}
|
|
29
|
-
const wellKnownMetadataSchema = z.object({
|
|
30
|
-
apiUrl: z.string().optional()
|
|
31
|
-
});
|
|
32
|
-
// Fetches /.well-known/prividium from the User Panel and returns its apiUrl.
|
|
33
|
-
async function discoverApiUrlFromUserPanel(userPanelUrl) {
|
|
34
|
-
const wellKnownUrl = new URL('/.well-known/prividium', userPanelUrl).toString();
|
|
35
|
-
let response;
|
|
36
|
-
try {
|
|
37
|
-
response = await fetch(wellKnownUrl, { signal: AbortSignal.timeout(5000) });
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
throw new Error(`Could not reach User Panel at ${userPanelUrl}.\n` +
|
|
41
|
-
` ${error instanceof Error ? error.message : String(error)}\n` +
|
|
42
|
-
' Please verify the URL is correct and the User Panel is running.');
|
|
43
|
-
}
|
|
44
|
-
if (!response.ok) {
|
|
45
|
-
throw new Error(`User Panel at ${userPanelUrl} did not return /.well-known/prividium (HTTP ${response.status}).\n` +
|
|
46
|
-
' Please verify the URL points to a Prividium™ User Panel, or pass --api-url directly.');
|
|
47
|
-
}
|
|
48
|
-
let json;
|
|
49
|
-
try {
|
|
50
|
-
json = await response.json();
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
throw new Error(`User Panel at ${userPanelUrl} returned non-JSON for /.well-known/prividium.\n` +
|
|
54
|
-
' Please verify the URL points to a Prividium™ User Panel, or pass --api-url directly.');
|
|
55
|
-
}
|
|
56
|
-
const parsed = wellKnownMetadataSchema.safeParse(json);
|
|
57
|
-
if (!parsed.success || !parsed.data.apiUrl) {
|
|
58
|
-
throw new Error(`User Panel at ${userPanelUrl} did not advertise an apiUrl in /.well-known/prividium.\n` +
|
|
59
|
-
' Please pass --api-url directly.');
|
|
60
|
-
}
|
|
61
|
-
return parsed.data.apiUrl;
|
|
62
|
-
}
|
|
63
|
-
async function resolveUserPanelUrl(opts) {
|
|
64
|
-
const explicit = opts.userPanelUrl ?? process.env.USER_PANEL_URL;
|
|
65
|
-
if (explicit) {
|
|
66
|
-
const res = z.url().safeParse(explicit);
|
|
67
|
-
if (!res.success) {
|
|
68
|
-
throw new Error(`Invalid user panel url provided: ${explicit}`);
|
|
69
|
-
}
|
|
70
|
-
log.info(`Using user panel url: ${explicit}`);
|
|
71
|
-
return explicit;
|
|
72
|
-
}
|
|
73
|
-
const prompted = await text({
|
|
74
|
-
message: 'Please insert your Prividium™ User Panel url',
|
|
75
|
-
validate(value) {
|
|
76
|
-
const parsed = z.url().safeParse(value);
|
|
77
|
-
if (!parsed.success) {
|
|
78
|
-
return 'Please provide a valid url';
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
if (typeof prompted === 'symbol') {
|
|
83
|
-
throw new Error('Canceled by the user');
|
|
84
|
-
}
|
|
85
|
-
return prompted;
|
|
86
|
-
}
|
|
87
28
|
async function startServerWithPrivateKey(opts) {
|
|
88
29
|
const privateKey = opts.privateKey;
|
|
89
30
|
if (!PRIVATE_KEY_REGEX.test(privateKey)) {
|
|
@@ -143,17 +84,12 @@ async function startServerWithPrivateKey(opts) {
|
|
|
143
84
|
async function startServer(opts) {
|
|
144
85
|
const workflow = new CreationWorkflow(opts.host, opts.port);
|
|
145
86
|
workflow.start();
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
else {
|
|
153
|
-
log.info('Discovering API URL from User Panel...');
|
|
154
|
-
apiUrl = await discoverApiUrlFromUserPanel(userPanelUrl);
|
|
155
|
-
log.info(`Using Prividium™ API url: ${apiUrl}`);
|
|
156
|
-
}
|
|
87
|
+
const apiUrl = await gatherApiUrl({
|
|
88
|
+
configPath: opts.configPath,
|
|
89
|
+
apiUrl: opts.apiUrl,
|
|
90
|
+
logProvidedUrls: true
|
|
91
|
+
});
|
|
92
|
+
const userPanelUrl = await getUserPanelUrl(opts.userPanelUrl, apiUrl);
|
|
157
93
|
checkHostAndPortWarnings(opts.host, opts.port, opts.allowExternalAccess);
|
|
158
94
|
const serverUrl = `http://${opts.host}:${opts.port}`;
|
|
159
95
|
const app = buildServer({
|
|
@@ -184,13 +120,15 @@ export const addProxy = (cli) => {
|
|
|
184
120
|
return cli.command('proxy', 'Starts authenticated rpc proxy server', (yargs) => yargs
|
|
185
121
|
.option('apiUrl', {
|
|
186
122
|
alias: ['api-url', 'rpc-url', 'r'],
|
|
187
|
-
description: 'Specifies target Prividium™ API url.
|
|
123
|
+
description: 'Specifies target Prividium™ API url. The User Panel url is fetched from /.well-known/prividium on this host.',
|
|
188
124
|
demandOption: false,
|
|
189
125
|
type: 'string'
|
|
190
126
|
})
|
|
191
127
|
.option('userPanelUrl', {
|
|
192
128
|
alias: ['user-panel-url', 'u'],
|
|
193
|
-
description: 'Specifies the User Panel url for browser-based login.
|
|
129
|
+
description: 'Specifies the User Panel url for browser-based login. When provided, this value takes priority and the User Panel url is not fetched from /.well-known/prividium.',
|
|
130
|
+
demandOption: false,
|
|
131
|
+
deprecated: 'fetched automatically from Prividium™ API.',
|
|
194
132
|
type: 'string'
|
|
195
133
|
})
|
|
196
134
|
.option('configPath', {
|
|
@@ -4,15 +4,5 @@ type GatherApiUrlOptions = {
|
|
|
4
4
|
logProvidedUrls?: boolean;
|
|
5
5
|
};
|
|
6
6
|
export declare function gatherApiUrl({ configPath, apiUrl, logProvidedUrls }: GatherApiUrlOptions): Promise<string>;
|
|
7
|
-
|
|
8
|
-
configPath?: string;
|
|
9
|
-
rpcUrl?: string;
|
|
10
|
-
rpcUrlLabel: string;
|
|
11
|
-
logProvidedUrls?: boolean;
|
|
12
|
-
userPanelUrl?: string;
|
|
13
|
-
};
|
|
14
|
-
export declare function gatherUrlConfig({ configPath, rpcUrl, userPanelUrl, rpcUrlLabel, logProvidedUrls }: GatherUrlConfigOptions): Promise<{
|
|
15
|
-
prividiumRpcUrl: string;
|
|
16
|
-
userPanelUrl: string;
|
|
17
|
-
}>;
|
|
7
|
+
export declare function getUserPanelUrl(userInput: string | undefined, apiUrl: string): Promise<string>;
|
|
18
8
|
export {};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { confirm, log, text } from '@clack/prompts';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
+
import { fetchPrividiumConfig } from '#sdk';
|
|
3
4
|
import { ConfigFile } from '../../server/config-file.js';
|
|
4
5
|
const envSchema = z.object({
|
|
5
6
|
PRIVIDIUM_API_URL: z.string().optional(),
|
|
6
|
-
PRIVIDIUM_RPC_URL: z.string().optional()
|
|
7
|
-
USER_PANEL_URL: z.string().optional()
|
|
7
|
+
PRIVIDIUM_RPC_URL: z.string().optional()
|
|
8
8
|
});
|
|
9
9
|
async function askForUrl(maybeUrl, name, logProvidedUrls) {
|
|
10
10
|
if (maybeUrl !== undefined) {
|
|
@@ -35,7 +35,7 @@ export async function gatherApiUrl({ configPath, apiUrl, logProvidedUrls = false
|
|
|
35
35
|
const config = new ConfigFile(configPath);
|
|
36
36
|
const configData = config.read();
|
|
37
37
|
const env = envSchema.parse(process.env);
|
|
38
|
-
const givenApiUrl = apiUrl ?? env.PRIVIDIUM_API_URL ?? configData.apiUrl;
|
|
38
|
+
const givenApiUrl = apiUrl ?? env.PRIVIDIUM_API_URL ?? env.PRIVIDIUM_RPC_URL ?? configData.apiUrl;
|
|
39
39
|
const { url: resolvedApiUrl, prompted } = await askForUrl(givenApiUrl, 'Prividium™ API', logProvidedUrls);
|
|
40
40
|
if (prompted) {
|
|
41
41
|
const confirmation = await confirm({
|
|
@@ -47,21 +47,20 @@ export async function gatherApiUrl({ configPath, apiUrl, logProvidedUrls = false
|
|
|
47
47
|
}
|
|
48
48
|
return resolvedApiUrl;
|
|
49
49
|
}
|
|
50
|
-
export async function
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const { url: prividiumRpcUrl, prompted: promptedRpc } = await askForUrl(givenRpcUrl, rpcUrlLabel, logProvidedUrls);
|
|
57
|
-
const { url: resolvedUserPanelUrl, prompted: promptedPanel } = await askForUrl(givenUserPanelUrl, 'user panel', logProvidedUrls);
|
|
58
|
-
if (promptedRpc || promptedPanel) {
|
|
59
|
-
const confirmation = await confirm({
|
|
60
|
-
message: 'Do you want to store this config for future usages?'
|
|
61
|
-
});
|
|
62
|
-
if (confirmation) {
|
|
63
|
-
config.write({ apiUrl: prividiumRpcUrl });
|
|
50
|
+
export async function getUserPanelUrl(userInput, apiUrl) {
|
|
51
|
+
let userPanelUrl;
|
|
52
|
+
if (userInput !== undefined) {
|
|
53
|
+
const parsed = z.url().safeParse(userInput);
|
|
54
|
+
if (!parsed.success) {
|
|
55
|
+
throw new Error(`Invalid User Panel url provided: ${userInput}`);
|
|
64
56
|
}
|
|
57
|
+
userPanelUrl = parsed.data;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
log.info('Fetching configuration from Prividium™ API...');
|
|
61
|
+
const prividiumInfo = await fetchPrividiumConfig(apiUrl);
|
|
62
|
+
userPanelUrl = prividiumInfo.userPanelUrl;
|
|
65
63
|
}
|
|
66
|
-
|
|
64
|
+
log.info(`Using User Panel url: ${userPanelUrl}`);
|
|
65
|
+
return userPanelUrl;
|
|
67
66
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
declare const schemas: {
|
|
3
3
|
readonly latest: z.ZodObject<{
|
|
4
|
-
userPanelUrl: z.ZodOptional<z.ZodString>;
|
|
5
4
|
apiUrl: z.ZodOptional<z.ZodString>;
|
|
6
5
|
l1RpcUrl: z.ZodOptional<z.ZodString>;
|
|
7
6
|
localZksyncOsRpcUrl: z.ZodOptional<z.ZodString>;
|
|
@@ -13,11 +12,6 @@ declare const schemas: {
|
|
|
13
12
|
}, z.core.$strip>;
|
|
14
13
|
};
|
|
15
14
|
declare const PROMPTS_FOR_CONFIGS: {
|
|
16
|
-
readonly userPanelUrl: {
|
|
17
|
-
readonly msg: "Please insert your Prividium™ User Panel url";
|
|
18
|
-
readonly retry: "Please provide a valid url";
|
|
19
|
-
readonly schema: z.ZodURL;
|
|
20
|
-
};
|
|
21
15
|
readonly apiUrl: {
|
|
22
16
|
readonly msg: "Please insert your Prividium™ api url";
|
|
23
17
|
readonly retry: "Please provide a valid url";
|
|
@@ -16,7 +16,6 @@ const dirs = appDirsFn({ appName: 'prividium-proxy' });
|
|
|
16
16
|
// key, then change `latest` to the new shape and add a branch in `migrate()`.
|
|
17
17
|
const schemas = {
|
|
18
18
|
latest: z.object({
|
|
19
|
-
userPanelUrl: z.string().optional(),
|
|
20
19
|
apiUrl: z.string().optional(),
|
|
21
20
|
l1RpcUrl: z.string().optional(),
|
|
22
21
|
localZksyncOsRpcUrl: z.string().optional(),
|
|
@@ -31,15 +30,9 @@ const ENV_VARS_FOR_CONFIG = {
|
|
|
31
30
|
apiUrl: 'PRIVIDIUM_API_URL',
|
|
32
31
|
l1RpcUrl: 'L1_RPC_URL',
|
|
33
32
|
diamondAddress: 'ZSYNCOS_L1_DIAMOND',
|
|
34
|
-
userPanelUrl: 'USER_PANEL_URL',
|
|
35
33
|
localZksyncOsRpcUrl: 'LOCAL_ZKSYNCOS_RPC_URL'
|
|
36
34
|
};
|
|
37
35
|
const PROMPTS_FOR_CONFIGS = {
|
|
38
|
-
userPanelUrl: {
|
|
39
|
-
msg: 'Please insert your Prividium™ User Panel url',
|
|
40
|
-
retry: 'Please provide a valid url',
|
|
41
|
-
schema: z.url()
|
|
42
|
-
},
|
|
43
36
|
apiUrl: {
|
|
44
37
|
msg: 'Please insert your Prividium™ api url',
|
|
45
38
|
retry: 'Please provide a valid url',
|
|
@@ -100,13 +93,13 @@ export class ConfigFile {
|
|
|
100
93
|
write(config) {
|
|
101
94
|
const dir = path.parse(this.filePath).dir;
|
|
102
95
|
mkdirSync(dir, { recursive: true });
|
|
103
|
-
writeFileSync(this.filePath, JSON.stringify(
|
|
96
|
+
writeFileSync(this.filePath, JSON.stringify(config));
|
|
104
97
|
}
|
|
105
98
|
partialWrite(newConfig) {
|
|
106
99
|
const old = this.read();
|
|
107
100
|
const dir = path.parse(this.filePath).dir;
|
|
108
101
|
mkdirSync(dir, { recursive: true });
|
|
109
|
-
writeFileSync(this.filePath, JSON.stringify({
|
|
102
|
+
writeFileSync(this.filePath, JSON.stringify({ ...old, ...newConfig }));
|
|
110
103
|
}
|
|
111
104
|
remove() {
|
|
112
105
|
if (existsSync(this.filePath)) {
|
|
@@ -10,5 +10,5 @@ export declare function createAdminMethods(deps: {
|
|
|
10
10
|
prividiumApiBaseUrl: string;
|
|
11
11
|
}): AdminMethods;
|
|
12
12
|
export type { ContractsAdminMethods } from './contracts.js';
|
|
13
|
-
export type { AdminContract, AdminContractCreate, AdminUser, AdminUserUpdate } from './types.js';
|
|
13
|
+
export type { AdminContract, AdminContractCreate, AdminUser, AdminUserUpdate, AdminUserUpdateInput } from './types.js';
|
|
14
14
|
export type { UsersAdminMethods } from './users.js';
|
|
@@ -33,16 +33,11 @@ export interface AdminUser {
|
|
|
33
33
|
wallets: Array<AdminUserWallet>;
|
|
34
34
|
}
|
|
35
35
|
export interface AdminUserUpdate {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
source?: AdminUserSource;
|
|
40
|
-
walletToken?: string | null;
|
|
41
|
-
createdAt?: unknown;
|
|
42
|
-
updatedAt?: unknown;
|
|
43
|
-
roles?: Array<string>;
|
|
44
|
-
wallets?: Array<string>;
|
|
36
|
+
displayName: string;
|
|
37
|
+
roles: Array<string>;
|
|
38
|
+
wallets: Array<string>;
|
|
45
39
|
}
|
|
40
|
+
export type AdminUserUpdateInput = Partial<AdminUserUpdate>;
|
|
46
41
|
export interface AdminDisclosedAddress {
|
|
47
42
|
address: string;
|
|
48
43
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ApiCaller } from '../chain-core.js';
|
|
2
|
-
import type { AdminUser,
|
|
2
|
+
import type { AdminUser, AdminUserUpdateInput } from './types.js';
|
|
3
3
|
export interface UsersAdminMethods {
|
|
4
4
|
getById(userId: string): Promise<AdminUser>;
|
|
5
|
-
update(userId: string, params:
|
|
5
|
+
update(userId: string, params: AdminUserUpdateInput): Promise<AdminUser>;
|
|
6
6
|
}
|
|
7
7
|
export declare function createUsersAdminMethods(deps: {
|
|
8
8
|
prividiumApiCall: ApiCaller;
|
|
@@ -2,12 +2,26 @@ import { adminUserSchema } from './schemas.js';
|
|
|
2
2
|
export function createUsersAdminMethods(deps) {
|
|
3
3
|
const { prividiumApiCall, prividiumApiBaseUrl } = deps;
|
|
4
4
|
const baseUrl = (id) => `${prividiumApiBaseUrl}/api/users/${encodeURIComponent(id)}`;
|
|
5
|
+
const getById = (userId) => prividiumApiCall(adminUserSchema, baseUrl(userId), 'GET');
|
|
5
6
|
return {
|
|
6
|
-
|
|
7
|
-
return prividiumApiCall(adminUserSchema, baseUrl(userId), 'GET');
|
|
8
|
-
},
|
|
7
|
+
getById,
|
|
9
8
|
async update(userId, params) {
|
|
10
|
-
|
|
9
|
+
// PUT /users/{id} is a full replacement. To keep partial updates working,
|
|
10
|
+
// fetch the current user and merge in any omitted fields before sending.
|
|
11
|
+
// When the caller already provides every field, skip the extra round-trip.
|
|
12
|
+
let body;
|
|
13
|
+
if (params.displayName !== undefined && params.roles !== undefined && params.wallets !== undefined) {
|
|
14
|
+
body = { displayName: params.displayName, roles: params.roles, wallets: params.wallets };
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
const current = await getById(userId);
|
|
18
|
+
body = {
|
|
19
|
+
displayName: params.displayName ?? current.displayName,
|
|
20
|
+
roles: params.roles ?? current.roles.map((role) => role.roleName),
|
|
21
|
+
wallets: params.wallets ?? current.wallets.map((wallet) => wallet.walletAddress)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return prividiumApiCall(adminUserSchema, baseUrl(userId), 'PUT', JSON.stringify(body));
|
|
11
25
|
}
|
|
12
26
|
};
|
|
13
27
|
}
|
package/dist/sdk/index.d.ts
CHANGED
|
@@ -9,3 +9,4 @@ export type { AddNetworkParams, ContractAbiResponse, PopupOptions, PrividiumChai
|
|
|
9
9
|
export { AUTH_ERRORS, STORAGE_KEYS } from './types.js';
|
|
10
10
|
export type { UserTokenVerifyError, UserTokenVerifyResult, VerifyUserAccessTokenOptions } from './verify-user-access-token.js';
|
|
11
11
|
export { verifyUserAccessToken } from './verify-user-access-token.js';
|
|
12
|
+
export { type FetchPrividiumConfigOptions, fetchPrividiumConfig, type PrividiumSystemInfo, PrividiumWellKnownError, type PrividiumWellKnownErrorKind, prividiumSystemInfoSchema } from './well-known.js';
|
package/dist/sdk/index.js
CHANGED
|
@@ -7,3 +7,4 @@ export { LocalStorage, TokenManager } from './storage.js';
|
|
|
7
7
|
export { generateRandomState } from './token-utils.js';
|
|
8
8
|
export { AUTH_ERRORS, STORAGE_KEYS } from './types.js';
|
|
9
9
|
export { verifyUserAccessToken } from './verify-user-access-token.js';
|
|
10
|
+
export { fetchPrividiumConfig, PrividiumWellKnownError, prividiumSystemInfoSchema } from './well-known.js';
|
package/dist/sdk/siwe.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { AdminContract, AdminContractCreate, AdminMethods, AdminUser, AdminUserUpdate, ContractsAdminMethods, UsersAdminMethods } from './admin-api/index.js';
|
|
1
|
+
export type { AdminContract, AdminContractCreate, AdminMethods, AdminUser, AdminUserUpdate, AdminUserUpdateInput, ContractsAdminMethods, UsersAdminMethods } from './admin-api/index.js';
|
|
2
2
|
export { createPrividiumClient } from './create-prividium-client.js';
|
|
3
3
|
export { MemoryStorage } from './memory-storage.js';
|
|
4
4
|
export { FORBIDDEN_ERROR_CODE, METHOD_NOT_FOUND_ERROR_CODE, UNAUTHORIZED_ERROR_CODE } from './rpc-error-codes.js';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const prividiumSystemInfoSchema: z.ZodObject<{
|
|
3
|
+
blockExplorerUrl: z.ZodURL;
|
|
4
|
+
chainId: z.ZodTemplateLiteral<`0x${string}`>;
|
|
5
|
+
chainName: z.ZodString;
|
|
6
|
+
baseToken: z.ZodObject<{
|
|
7
|
+
name: z.ZodString;
|
|
8
|
+
symbol: z.ZodString;
|
|
9
|
+
decimals: z.ZodNumber;
|
|
10
|
+
l1Address: z.ZodNullable<z.ZodTemplateLiteral<`0x${string}`>>;
|
|
11
|
+
}, z.core.$strip>;
|
|
12
|
+
rpcUrl: z.ZodURL;
|
|
13
|
+
userPanelUrl: z.ZodURL;
|
|
14
|
+
version: z.ZodString;
|
|
15
|
+
l1ChainId: z.ZodTemplateLiteral<`0x${string}`>;
|
|
16
|
+
l1ChainName: z.ZodString;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
export type PrividiumSystemInfo = z.infer<typeof prividiumSystemInfoSchema>;
|
|
19
|
+
export type PrividiumWellKnownErrorKind = 'network' | 'http' | 'schema';
|
|
20
|
+
export declare class PrividiumWellKnownError extends Error {
|
|
21
|
+
readonly kind: PrividiumWellKnownErrorKind;
|
|
22
|
+
constructor(kind: PrividiumWellKnownErrorKind, message: string, options?: {
|
|
23
|
+
cause?: unknown;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
export type FetchPrividiumConfigOptions = {
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
fetch?: typeof fetch;
|
|
29
|
+
};
|
|
30
|
+
export declare function fetchPrividiumConfig(apiUrl: string, opts?: FetchPrividiumConfigOptions): Promise<PrividiumSystemInfo>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const hexSchema = z.templateLiteral(['0x', z.string().regex(/^[0-9a-fA-F]+$/)]);
|
|
3
|
+
const addressSchema = z.templateLiteral(['0x', z.string().regex(/^[0-9a-fA-F]{40}$/)]);
|
|
4
|
+
export const prividiumSystemInfoSchema = z.object({
|
|
5
|
+
blockExplorerUrl: z.url(),
|
|
6
|
+
chainId: hexSchema,
|
|
7
|
+
chainName: z.string(),
|
|
8
|
+
baseToken: z.object({
|
|
9
|
+
name: z.string(),
|
|
10
|
+
symbol: z.string(),
|
|
11
|
+
decimals: z.number(),
|
|
12
|
+
l1Address: addressSchema.nullable()
|
|
13
|
+
}),
|
|
14
|
+
rpcUrl: z.url(),
|
|
15
|
+
userPanelUrl: z.url(),
|
|
16
|
+
version: z.string(),
|
|
17
|
+
l1ChainId: hexSchema,
|
|
18
|
+
l1ChainName: z.string()
|
|
19
|
+
});
|
|
20
|
+
const wellKnownSchema = z.object({
|
|
21
|
+
v1: prividiumSystemInfoSchema
|
|
22
|
+
});
|
|
23
|
+
export class PrividiumWellKnownError extends Error {
|
|
24
|
+
kind;
|
|
25
|
+
constructor(kind, message, options) {
|
|
26
|
+
super(message, options);
|
|
27
|
+
this.name = 'PrividiumWellKnownError';
|
|
28
|
+
this.kind = kind;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const DEFAULT_TIMEOUT_MS = 5000;
|
|
32
|
+
export async function fetchPrividiumConfig(apiUrl, opts) {
|
|
33
|
+
const url = new URL('/.well-known/prividium', apiUrl).toString();
|
|
34
|
+
const doFetch = opts?.fetch ?? fetch;
|
|
35
|
+
const signal = opts?.signal ?? AbortSignal.timeout(DEFAULT_TIMEOUT_MS);
|
|
36
|
+
let response;
|
|
37
|
+
try {
|
|
38
|
+
response = await doFetch(url, { signal });
|
|
39
|
+
}
|
|
40
|
+
catch (cause) {
|
|
41
|
+
throw new PrividiumWellKnownError('network', `Could not reach ${url}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
42
|
+
}
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
throw new PrividiumWellKnownError('http', `Unexpected HTTP ${response.status} from ${url}`);
|
|
45
|
+
}
|
|
46
|
+
let json;
|
|
47
|
+
try {
|
|
48
|
+
json = await response.json();
|
|
49
|
+
}
|
|
50
|
+
catch (cause) {
|
|
51
|
+
throw new PrividiumWellKnownError('schema', `Response from ${url} was not valid JSON`, { cause });
|
|
52
|
+
}
|
|
53
|
+
const parsed = wellKnownSchema.safeParse(json);
|
|
54
|
+
if (!parsed.success) {
|
|
55
|
+
throw new PrividiumWellKnownError('schema', `Response from ${url} did not match the Prividium well-known shape: ${parsed.error.message}`, { cause: parsed.error });
|
|
56
|
+
}
|
|
57
|
+
return parsed.data.v1;
|
|
58
|
+
}
|