@getvouch/sdk 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 +46 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/vouch.d.ts +16 -0
- package/dist/lib/vouch.js +28 -0
- package/dist/lib/vouch.test.d.ts +1 -0
- package/dist/lib/vouch.test.js +79 -0
- package/dist/utils/validated-host.d.ts +1 -0
- package/dist/utils/validated-host.js +18 -0
- package/dist/utils/validated-host.test.d.ts +1 -0
- package/dist/utils/validated-host.test.js +28 -0
- package/dist/utils/validated-uuid.d.ts +1 -0
- package/dist/utils/validated-uuid.js +7 -0
- package/dist/utils/validated-uuid.test.d.ts +1 -0
- package/dist/utils/validated-uuid.test.js +31 -0
- package/package.json +36 -0
- package/tsconfig.json +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Vouch SDK
|
|
2
|
+
|
|
3
|
+
This is the Vouch SDK, a TypeScript library for interacting with vouch. Currently it allows you to generate a link to start the web proof flow.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
To install the Vouch SDK, you can use npm or other package managers.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @vouch/vouch-sdk
|
|
11
|
+
yarn add @vouch/vouch-sdk
|
|
12
|
+
pnpm add @vouch/vouch-sdk
|
|
13
|
+
bun add @vouch/vouch-sdk
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
Create vouch instance:
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { Vouch } from "@vouch/vouch-sdk";
|
|
22
|
+
const vouch = new Vouch();
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
You may provide a configuration object with a set of optional parameters:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { Vouch } from "@vouch/vouch-sdk";
|
|
29
|
+
const vouch = new Vouch({
|
|
30
|
+
vouchHost: "https://app.getvouch.io", // The base URL for the Vouch API. Can be a string or an URL object. Defaults to "https://app.getvouch.io".
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Get vouch start URL
|
|
35
|
+
|
|
36
|
+
[Generate a link to start the Vouch flow](https://docs.getvouch.io/getting-started/first-steps#redirect-user-to-vouch).
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const url = vouch.getStartUrl({
|
|
40
|
+
requestId, // Optional. If not provided, a new request ID will be generated.
|
|
41
|
+
datasourceId: "93826be6-6c7d-495a-9859-de5a1d17f30b", // Datasource ID. Here we use example.com data source. Must be a UUIDv4.
|
|
42
|
+
customerId: "1be03be8-5014-413c-835a-feddf4020da2", // Your unique customer ID.
|
|
43
|
+
redirectBackUrl: `https://docs.getvouch.io/getting-started/first-steps?requestId=${requestId}`, // Return destination.
|
|
44
|
+
webhookUrl: `https://docs.getvouch.io/api/web-proof/${requestId}`, // (Optional) Proof delivery endpoint.
|
|
45
|
+
});
|
|
46
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./lib/vouch";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./lib/vouch";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface Config {
|
|
2
|
+
vouchHost?: string | URL;
|
|
3
|
+
}
|
|
4
|
+
export interface VouchUrlParams {
|
|
5
|
+
datasourceId: string;
|
|
6
|
+
redirectBackUrl: string;
|
|
7
|
+
customerId?: string;
|
|
8
|
+
requestId?: string;
|
|
9
|
+
inputs?: string;
|
|
10
|
+
webhookUrl?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare class Vouch {
|
|
13
|
+
host: URL;
|
|
14
|
+
constructor({ vouchHost }?: Config);
|
|
15
|
+
getStartUrl({ customerId, datasourceId, requestId, redirectBackUrl, inputs, webhookUrl, }: VouchUrlParams): URL;
|
|
16
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { validatedHost } from "@/utils/validated-host";
|
|
2
|
+
import { validatedUuidV4 } from "@/utils/validated-uuid";
|
|
3
|
+
const DEFAULT_VOUCH_HOST = "https://app.getvouch.io";
|
|
4
|
+
const DEFAULT_CUSTOMER_ID = "1be03be8-5014-413c-835a-feddf4020da2";
|
|
5
|
+
export class Vouch {
|
|
6
|
+
constructor({ vouchHost = DEFAULT_VOUCH_HOST } = {}) {
|
|
7
|
+
this.host = validatedHost(vouchHost);
|
|
8
|
+
}
|
|
9
|
+
getStartUrl({ customerId, datasourceId, requestId, redirectBackUrl, inputs, webhookUrl, }) {
|
|
10
|
+
const params = new URLSearchParams({
|
|
11
|
+
requestId: requestId
|
|
12
|
+
? validatedUuidV4(requestId, "requestId")
|
|
13
|
+
: crypto.randomUUID(),
|
|
14
|
+
customerId: customerId
|
|
15
|
+
? validatedUuidV4(customerId, "customerId")
|
|
16
|
+
: DEFAULT_CUSTOMER_ID,
|
|
17
|
+
datasourceId: validatedUuidV4(datasourceId, "datasourceId"),
|
|
18
|
+
redirectBackUrl,
|
|
19
|
+
});
|
|
20
|
+
if (inputs) {
|
|
21
|
+
params.set("inputs", inputs);
|
|
22
|
+
}
|
|
23
|
+
if (webhookUrl) {
|
|
24
|
+
params.set("webhookUrl", webhookUrl);
|
|
25
|
+
}
|
|
26
|
+
return new URL(`/start?${params.toString()}`, this.host);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Vouch } from "./vouch";
|
|
2
|
+
import { beforeEach, expect } from "vitest";
|
|
3
|
+
import { validatedUuidV4 } from "@/utils/validated-uuid";
|
|
4
|
+
describe("Vouch SDK", () => {
|
|
5
|
+
it("correctly sets default vouch host", () => {
|
|
6
|
+
const vouch = new Vouch();
|
|
7
|
+
expect(vouch.host).toStrictEqual(new URL("https://app.getvouch.io"));
|
|
8
|
+
});
|
|
9
|
+
describe("getVouchUrl", () => {
|
|
10
|
+
let vouch;
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
vouch = new Vouch();
|
|
13
|
+
});
|
|
14
|
+
it("constructs correct URL", () => {
|
|
15
|
+
const params = {
|
|
16
|
+
requestId: crypto.randomUUID(),
|
|
17
|
+
datasourceId: crypto.randomUUID(),
|
|
18
|
+
customerId: crypto.randomUUID(),
|
|
19
|
+
redirectBackUrl: "https://example.com/redirect",
|
|
20
|
+
};
|
|
21
|
+
const url = vouch.getStartUrl(params);
|
|
22
|
+
expect(url.toString()).toBe(`https://app.getvouch.io/start?requestId=${params.requestId}&customerId=${params.customerId}&datasourceId=${params.datasourceId}&redirectBackUrl=${encodeURIComponent(params.redirectBackUrl)}`);
|
|
23
|
+
});
|
|
24
|
+
it("adds inputs", () => {
|
|
25
|
+
const params = {
|
|
26
|
+
requestId: crypto.randomUUID(),
|
|
27
|
+
datasourceId: crypto.randomUUID(),
|
|
28
|
+
customerId: crypto.randomUUID(),
|
|
29
|
+
redirectBackUrl: "https://example.com/redirect",
|
|
30
|
+
inputs: "eyJrZXkiOiAidmFsdWUifQ",
|
|
31
|
+
};
|
|
32
|
+
const url = vouch.getStartUrl(params);
|
|
33
|
+
expect(url.toString()).toBe(`https://app.getvouch.io/start?requestId=${params.requestId}&customerId=${params.customerId}&datasourceId=${params.datasourceId}&redirectBackUrl=${encodeURIComponent(params.redirectBackUrl)}&inputs=${params.inputs}`);
|
|
34
|
+
});
|
|
35
|
+
it("adds webhookUrl", () => {
|
|
36
|
+
const params = {
|
|
37
|
+
requestId: crypto.randomUUID(),
|
|
38
|
+
datasourceId: crypto.randomUUID(),
|
|
39
|
+
customerId: crypto.randomUUID(),
|
|
40
|
+
redirectBackUrl: "https://example.com/redirect",
|
|
41
|
+
webhookUrl: "https://example.com/webhook",
|
|
42
|
+
};
|
|
43
|
+
const url = vouch.getStartUrl(params);
|
|
44
|
+
expect(url.toString()).toBe(`https://app.getvouch.io/start?requestId=${params.requestId}&customerId=${params.customerId}&datasourceId=${params.datasourceId}&redirectBackUrl=${encodeURIComponent(params.redirectBackUrl)}&webhookUrl=${encodeURIComponent(params.webhookUrl)}`);
|
|
45
|
+
});
|
|
46
|
+
it("generates requestId", () => {
|
|
47
|
+
var _a;
|
|
48
|
+
const params = {
|
|
49
|
+
datasourceId: crypto.randomUUID(),
|
|
50
|
+
customerId: crypto.randomUUID(),
|
|
51
|
+
redirectBackUrl: "https://example.com/redirect",
|
|
52
|
+
};
|
|
53
|
+
const url = vouch.getStartUrl(params);
|
|
54
|
+
const generatedRequestId = (_a = url.searchParams.get("requestId")) !== null && _a !== void 0 ? _a : "";
|
|
55
|
+
expect(() => validatedUuidV4(generatedRequestId)).not.toThrow();
|
|
56
|
+
});
|
|
57
|
+
it("sets default customerId", () => {
|
|
58
|
+
const params = {
|
|
59
|
+
requestId: crypto.randomUUID(),
|
|
60
|
+
datasourceId: crypto.randomUUID(),
|
|
61
|
+
redirectBackUrl: "https://example.com/redirect",
|
|
62
|
+
};
|
|
63
|
+
const url = vouch.getStartUrl(params);
|
|
64
|
+
expect(url.searchParams.get("customerId")).toBe("1be03be8-5014-413c-835a-feddf4020da2");
|
|
65
|
+
});
|
|
66
|
+
it("validates UUIDs", () => {
|
|
67
|
+
const params = {
|
|
68
|
+
requestId: crypto.randomUUID(),
|
|
69
|
+
datasourceId: crypto.randomUUID(),
|
|
70
|
+
customerId: crypto.randomUUID(),
|
|
71
|
+
redirectBackUrl: "https://example.com/redirect",
|
|
72
|
+
};
|
|
73
|
+
const keys = ["requestId", "datasourceId", "customerId"];
|
|
74
|
+
keys.forEach((key) => {
|
|
75
|
+
expect(() => vouch.getStartUrl(Object.assign(Object.assign({}, params), { [key]: "invalid-uuid" }))).toThrow(`Invalid UUIDv4 for ${key}: invalid-uuid`);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function validatedHost(url: string | URL): URL;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function validatedHost(url) {
|
|
2
|
+
const parsedUrl = parseUrl(url);
|
|
3
|
+
if (!/^https?:$/.exec(parsedUrl.protocol)) {
|
|
4
|
+
throw new Error(`Invalid vouch host: ${url.toString()}. Only HTTP and HTTPS protocols are allowed.`);
|
|
5
|
+
}
|
|
6
|
+
if (parsedUrl.pathname !== "/" || parsedUrl.search || parsedUrl.hash) {
|
|
7
|
+
throw new Error(`Invalid vouch host: ${url.toString()}. Only root URLs are allowed as vouch host.`);
|
|
8
|
+
}
|
|
9
|
+
return parsedUrl;
|
|
10
|
+
}
|
|
11
|
+
function parseUrl(url) {
|
|
12
|
+
try {
|
|
13
|
+
return new URL(url);
|
|
14
|
+
}
|
|
15
|
+
catch (_a) {
|
|
16
|
+
throw new Error(`Invalid URL: ${url.toString()}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { validatedHost } from "./validated-host";
|
|
2
|
+
describe("Validate vouch host", () => {
|
|
3
|
+
it("should validate a valid vouch host URL", () => {
|
|
4
|
+
const validUrls = [
|
|
5
|
+
"https://vouch.example.com",
|
|
6
|
+
"https://vouch.example.com/",
|
|
7
|
+
"http://localhost:3000",
|
|
8
|
+
"http://127.0.0.1",
|
|
9
|
+
"http://127.0.0.1:3000",
|
|
10
|
+
];
|
|
11
|
+
validUrls.forEach((url) => {
|
|
12
|
+
expect(() => validatedHost(url)).not.toThrow();
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
it("should throw an error for invalid vouch host URLs", () => {
|
|
16
|
+
const invalidUrls = [
|
|
17
|
+
"https://vouch.example.com/some/path",
|
|
18
|
+
"https://vouch.example.com?query=param",
|
|
19
|
+
"https://vouch.example.com#fragment",
|
|
20
|
+
"https://vouch.example.com/some/path?query=param#fragment",
|
|
21
|
+
"invalid-url",
|
|
22
|
+
"localhost:3000",
|
|
23
|
+
];
|
|
24
|
+
invalidUrls.forEach((url) => {
|
|
25
|
+
expect(() => validatedHost(url)).toThrow();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function validatedUuidV4(uuid: string, tag?: string): string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function validatedUuidV4(uuid, tag) {
|
|
2
|
+
const uuidv4Regex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
3
|
+
if (!uuidv4Regex.test(uuid)) {
|
|
4
|
+
throw new Error(`Invalid UUIDv4${tag ? ` for ${tag}` : ""}: ${uuid}`);
|
|
5
|
+
}
|
|
6
|
+
return uuid.toLowerCase();
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { validatedUuidV4 } from "./validated-uuid";
|
|
2
|
+
describe("Validate UUIDv4", () => {
|
|
3
|
+
it("passes for correct UUIDs", () => {
|
|
4
|
+
const exampleUuids = [
|
|
5
|
+
"f1df320a-774e-4061-ac7c-a0941d34a4fc",
|
|
6
|
+
"618379a9-7331-4556-b289-8039d1066aee",
|
|
7
|
+
"304875b0-becc-4ad6-a958-13867b03928c",
|
|
8
|
+
"4248b872-79b6-4e0d-a315-36b9579cae8c",
|
|
9
|
+
];
|
|
10
|
+
exampleUuids.forEach((uuid) => {
|
|
11
|
+
expect(() => validatedUuidV4(uuid)).not.toThrow();
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
it("converts to lowercase", () => {
|
|
15
|
+
const uuid = crypto.randomUUID().toUpperCase();
|
|
16
|
+
expect(validatedUuidV4(uuid)).toBe(uuid.toLowerCase());
|
|
17
|
+
});
|
|
18
|
+
it("throws for incorrect UUIDs", () => {
|
|
19
|
+
const invalidUuids = [
|
|
20
|
+
"definitely not a uuid",
|
|
21
|
+
"12345678-1234-1234-1234-123456789012", // not a v4 UUID
|
|
22
|
+
"123e4567-e89b-12d3-a456-426614174000", // not a v4 UUID
|
|
23
|
+
"g23e4567-e89b-12d3-a456-426614174000", // invalid character
|
|
24
|
+
"123e4567-e89b-12d3-a456-42661417400", // too short
|
|
25
|
+
"123e4567-e89b-12d3-a456-4266141740000", // too long
|
|
26
|
+
];
|
|
27
|
+
invalidUuids.forEach((uuid) => {
|
|
28
|
+
expect(() => validatedUuidV4(uuid)).toThrow();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@getvouch/sdk",
|
|
3
|
+
"author": "Vouch",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/vlayer-xyz/vouch.git#main"
|
|
9
|
+
},
|
|
10
|
+
"private": false,
|
|
11
|
+
"version": "0.1.0",
|
|
12
|
+
"description": "Vouch SDK",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"webproof",
|
|
15
|
+
"sdk",
|
|
16
|
+
"vouch"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"lint": "eslint src && tsc --noEmit",
|
|
22
|
+
"lint:fix": "eslint src --fix && tsc --noEmit",
|
|
23
|
+
"format": "prettier --check .",
|
|
24
|
+
"format:fix": "prettier --write ."
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"eslint": "^9.24.0",
|
|
28
|
+
"eslint-config-prettier": "^10.1.1",
|
|
29
|
+
"eslint-plugin-prettier": "^5.2.6",
|
|
30
|
+
"prettier": "^3.5.3",
|
|
31
|
+
"typescript": "^5",
|
|
32
|
+
"typescript-eslint": "^8.30.1",
|
|
33
|
+
"vite-tsconfig-paths": "^5.1.4",
|
|
34
|
+
"vitest": "^3.2.3"
|
|
35
|
+
}
|
|
36
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": ["ESNext"],
|
|
4
|
+
"target": "ES2017",
|
|
5
|
+
"types": ["vitest/globals"],
|
|
6
|
+
"moduleDetection": "force",
|
|
7
|
+
"moduleResolution": "node",
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"rootDir": "./src",
|
|
11
|
+
"allowJs": true,
|
|
12
|
+
"strict": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"noFallthroughCasesInSwitch": true,
|
|
16
|
+
"noUncheckedIndexedAccess": true,
|
|
17
|
+
"noUnusedLocals": true,
|
|
18
|
+
"noUnusedParameters": true,
|
|
19
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
20
|
+
"paths": {
|
|
21
|
+
"@/*": ["./src/*"]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"include": ["src/**/*"],
|
|
25
|
+
"exclude": ["dist", "node_modules"]
|
|
26
|
+
}
|