@cooperation/vc-storage 1.0.40 → 1.0.41
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 +61 -90
- package/dist/index.js +2 -0
- package/dist/models/CredentialEngine.js +5 -1
- package/dist/models/StorageContext.js +15 -50
- package/dist/models/WASZcapStorage.js +70 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/models/StorageContext.d.ts +16 -0
- package/dist/types/models/WASZcapStorage.d.ts +41 -0
- package/package.json +4 -1
package/README.md
CHANGED
@@ -1,109 +1,80 @@
|
|
1
1
|
# @cooperation/vc-storage
|
2
2
|
|
3
|
-
|
3
|
+
TypeScript utilities to work with storage backends used by Linked Claims: Google Drive and Wallet Aggregated Storage (WAS). Includes a simple factory to construct storage clients and helpers used by the authoring app.
|
4
4
|
|
5
|
-
##
|
5
|
+
## Installation
|
6
6
|
|
7
|
-
|
7
|
+
```bash
|
8
|
+
npm install @cooperation/vc-storage
|
9
|
+
```
|
8
10
|
|
9
|
-
##
|
11
|
+
## Exports (selected)
|
10
12
|
|
11
|
-
-
|
12
|
-
-
|
13
|
-
-
|
14
|
-
-
|
15
|
-
|
16
|
-
- **Dropbox Storage**: Integration for storing VCs in Dropbox (under development).
|
13
|
+
- GoogleDriveStorage
|
14
|
+
- LCWStorage (WAS via @wallet.storage/fetch-client)
|
15
|
+
- WASZcapStorage (WAS via zCap delegation)
|
16
|
+
- createStorage(kind, options)
|
17
|
+
- Misc models: CredentialEngine, Resume, ResumeVC, utils
|
17
18
|
|
18
|
-
##
|
19
|
+
## Storage factory
|
19
20
|
|
20
|
-
|
21
|
+
```ts
|
22
|
+
import { createStorage } from '@cooperation/vc-storage';
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
+
// Google Drive
|
25
|
+
const drive = createStorage('googleDrive', { accessToken });
|
26
|
+
|
27
|
+
// WAS (zCap-capability, delegated access)
|
28
|
+
const wasZ = createStorage('wasZcap', { appInstance, capability });
|
24
29
|
```
|
25
30
|
|
26
|
-
##
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
} else {
|
62
|
-
({ didDocument, keyPair } = await credentialEngine.createDID());
|
63
|
-
}
|
64
|
-
|
65
|
-
await saveToGoogleDrive(storage, { ...didDocument, keyPair }, 'DID');
|
66
|
-
|
67
|
-
const issuerDid = didDocument.id;
|
68
|
-
|
69
|
-
// Step 2: Create an Unsigned VC
|
70
|
-
const unsignedVC = await credentialEngine.createUnsignedVC(formData, issuerDid);
|
71
|
-
await saveToGoogleDrive(storage, unsignedVC, 'UnsignedVC');
|
72
|
-
console.log('Unsigned VC:', unsignedVC);
|
73
|
-
|
74
|
-
// Step 3: Sign the VC
|
75
|
-
try {
|
76
|
-
const signedVC = await credentialEngine.signVC(unsignedVC, keyPair);
|
77
|
-
await saveToGoogleDrive(storage, signedVC, 'VC');
|
78
|
-
console.log('Signed VC:', signedVC);
|
79
|
-
} catch (error) {
|
80
|
-
console.error('Error during VC signing:', error);
|
81
|
-
}
|
82
|
-
|
83
|
-
// Retrieve all stored claims
|
84
|
-
const claims = await storage.getAllClaims();
|
85
|
-
console.log('Stored Claims:', claims);
|
86
|
-
}
|
87
|
-
|
88
|
-
// Example usage:
|
89
|
-
// 1. For Google Drive storage with standard DID creation
|
90
|
-
main().catch(console.error);
|
91
|
-
|
92
|
-
// 2. For Google Drive storage with wallet-based DID creation
|
93
|
-
// main(true, 'your-wallet-address').catch(console.error);
|
31
|
+
## GoogleDriveStorage (highlights)
|
32
|
+
|
33
|
+
```ts
|
34
|
+
import { GoogleDriveStorage } from '@cooperation/vc-storage';
|
35
|
+
|
36
|
+
const drive = new GoogleDriveStorage(accessToken);
|
37
|
+
|
38
|
+
// Upload binary (images/videos/pdfs)
|
39
|
+
await drive.uploadBinaryFile({ file }); // -> { id }
|
40
|
+
|
41
|
+
// Save JSON file to a specific folder
|
42
|
+
await drive.saveFile({ data: { fileName: 'VC', mimeType: 'application/json', body: JSON.stringify(vc) }, folderId });
|
43
|
+
|
44
|
+
// Retrieve file content
|
45
|
+
await drive.retrieve(fileId); // -> { id, data }
|
46
|
+
|
47
|
+
// Delete
|
48
|
+
await drive.delete(fileId);
|
49
|
+
```
|
50
|
+
|
51
|
+
## WASZcapStorage (WAS, zCap delegation)
|
52
|
+
|
53
|
+
Use when uploading from the browser with delegated capability (zCap).
|
54
|
+
|
55
|
+
```ts
|
56
|
+
import { WASZcapStorage } from '@cooperation/vc-storage';
|
57
|
+
|
58
|
+
const was = new WASZcapStorage({ appInstance, capability });
|
59
|
+
|
60
|
+
// Blob upload (images, pdfs, or JSON-as-blob)
|
61
|
+
await was.upload({ key: file.name, file }); // -> id or url
|
62
|
+
|
63
|
+
// Optional read/delete
|
64
|
+
await was.read('key.json');
|
65
|
+
await was.delete('old-file.txt');
|
94
66
|
```
|
95
67
|
|
96
|
-
|
68
|
+
## Choosing a backend
|
97
69
|
|
98
|
-
|
99
|
-
|
100
|
-
3. **Wallet Storage**: (Under Development) Store your VCs directly in your digital wallet.
|
101
|
-
4. **Dropbox**: (Under Development) Store your VCs in Dropbox.
|
70
|
+
- Use WASZcapStorage when you have a zCap capability and an appInstance Ed25519 keypair (delegated, least-privilege).
|
71
|
+
- Use GoogleDriveStorage for Drive workflows (e.g., storing VC artifacts/files in Drive).
|
102
72
|
|
103
|
-
##
|
73
|
+
## Notes
|
104
74
|
|
105
|
-
|
75
|
+
- WAS zCap requests are signed with Ed25519Signature2020 and require a valid `invocationSigner.id`.
|
76
|
+
- There is no implicit fallback between backends; handle errors per backend explicitly in your app.
|
106
77
|
|
107
78
|
## License
|
108
79
|
|
109
|
-
|
80
|
+
ISC
|
package/dist/index.js
CHANGED
@@ -4,5 +4,7 @@ export * from './utils/google.js';
|
|
4
4
|
export * from './models/Resume.js';
|
5
5
|
export * from './models/ResumeVC.js';
|
6
6
|
export * from './models/WASStorage.js';
|
7
|
+
export * from './models/WASZcapStorage.js';
|
8
|
+
export * from './models/StorageContext.js';
|
7
9
|
export * from './utils/createWASSpace.js';
|
8
10
|
export * from './utils/getOrCreateAppDID.js';
|
@@ -143,7 +143,11 @@ export class CredentialEngine {
|
|
143
143
|
case 'RECOMMENDATION':
|
144
144
|
if (!vcFileId)
|
145
145
|
throw new Error('vcFileId is required for recommendation');
|
146
|
-
credential = generateUnsignedRecommendation({
|
146
|
+
credential = generateUnsignedRecommendation({
|
147
|
+
vcId: vcFileId,
|
148
|
+
recommendation: data,
|
149
|
+
issuerDid: issuerId,
|
150
|
+
});
|
147
151
|
break;
|
148
152
|
case 'EMPLOYMENT':
|
149
153
|
credential = generateUnsignedEmployment({ formData: data, issuerDid: issuerId });
|
@@ -1,50 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
// }
|
17
|
-
// async retrieve(id: string) {
|
18
|
-
// return this.strategy.retrieve(id);
|
19
|
-
// }
|
20
|
-
// async findFolders(id?: string) {
|
21
|
-
// return this.strategy.findFolders(id);
|
22
|
-
// }
|
23
|
-
// async findLastFile(folderId: string) {
|
24
|
-
// return this.strategy.findLastFile(folderId);
|
25
|
-
// }
|
26
|
-
// async getAllClaims() {
|
27
|
-
// return this.strategy.getAllClaims();
|
28
|
-
// }
|
29
|
-
// async getAllSessions() {
|
30
|
-
// return this.strategy.getAllSessions();
|
31
|
-
// }
|
32
|
-
// async getFileContent(fileId: string) {
|
33
|
-
// return this.strategy.getFileContent(fileId);
|
34
|
-
// }
|
35
|
-
// }
|
36
|
-
// class StorageFactory {
|
37
|
-
// static getStorageStrategy(type: StorageType, options: any): StorageStrategy {
|
38
|
-
// switch (type) {
|
39
|
-
// case 'googleDrive':
|
40
|
-
// const { accessToken } = options;
|
41
|
-
// if (!accessToken) {
|
42
|
-
// throw new Error('Missing required parameters');
|
43
|
-
// }
|
44
|
-
// return new GoogleDriveStorage(accessToken);
|
45
|
-
// default:
|
46
|
-
// throw new Error('Unsupported storage type');
|
47
|
-
// }
|
48
|
-
// }
|
49
|
-
// }
|
50
|
-
// export { StorageContext, StorageFactory };
|
1
|
+
import { GoogleDriveStorage } from './GoogleDriveStorage.js';
|
2
|
+
import { WASZcapStorage } from './WASZcapStorage.js';
|
3
|
+
export function createStorage(kind, options) {
|
4
|
+
if (kind === 'googleDrive') {
|
5
|
+
if (!options?.accessToken)
|
6
|
+
throw new Error('Missing accessToken for Google Drive');
|
7
|
+
return new GoogleDriveStorage(options.accessToken);
|
8
|
+
}
|
9
|
+
if (kind === 'wasZcap') {
|
10
|
+
if (!options?.appInstance || !options?.capability)
|
11
|
+
throw new Error('Missing appInstance or capability for WAS Zcap');
|
12
|
+
return new WASZcapStorage({ appInstance: options.appInstance, capability: options.capability });
|
13
|
+
}
|
14
|
+
throw new Error('Unsupported storage kind');
|
15
|
+
}
|
@@ -0,0 +1,70 @@
|
|
1
|
+
// @ts-nocheck
|
2
|
+
import { ZcapClient } from '@digitalcredentials/ezcap';
|
3
|
+
import { Ed25519VerificationKey2020 } from '@digitalcredentials/ed25519-verification-key-2020';
|
4
|
+
import { Ed25519Signature2020 } from '@digitalcredentials/ed25519-signature-2020';
|
5
|
+
export class WASZcapStorage {
|
6
|
+
zcapClient;
|
7
|
+
capability;
|
8
|
+
ready;
|
9
|
+
constructor(config) {
|
10
|
+
if (!config?.appInstance?.publicKeyMultibase || !config?.appInstance?.privateKeyMultibase) {
|
11
|
+
throw new Error('appInstance is missing key material');
|
12
|
+
}
|
13
|
+
if (!config?.capability) {
|
14
|
+
throw new Error('capability (zcap) is required');
|
15
|
+
}
|
16
|
+
this.capability = config.capability;
|
17
|
+
this.ready = this.initClient(config.appInstance);
|
18
|
+
}
|
19
|
+
async initClient(appInstance) {
|
20
|
+
const key = await Ed25519VerificationKey2020.from(appInstance);
|
21
|
+
const signer = key.signer();
|
22
|
+
// ezcap expects invocationSigner.id
|
23
|
+
this.zcapClient = new ZcapClient({
|
24
|
+
SuiteClass: Ed25519Signature2020,
|
25
|
+
invocationSigner: signer,
|
26
|
+
});
|
27
|
+
}
|
28
|
+
async request(method, url, body) {
|
29
|
+
await this.ready;
|
30
|
+
return this.zcapClient.request({
|
31
|
+
url,
|
32
|
+
capability: this.capability,
|
33
|
+
method,
|
34
|
+
action: method,
|
35
|
+
...(body ? { blob: body } : {}),
|
36
|
+
});
|
37
|
+
}
|
38
|
+
buildUrlForKey(key) {
|
39
|
+
const baseUrl = this.capability?.invocationTarget;
|
40
|
+
if (!baseUrl)
|
41
|
+
throw new Error('Capability invocationTarget is missing');
|
42
|
+
return `${baseUrl}/${encodeURIComponent(key)}`;
|
43
|
+
}
|
44
|
+
async upload({ key, file }) {
|
45
|
+
const url = this.buildUrlForKey(key);
|
46
|
+
const res = await this.request('PUT', url, file);
|
47
|
+
return this.extractId(res) ?? url;
|
48
|
+
}
|
49
|
+
async read(key) {
|
50
|
+
const url = this.buildUrlForKey(key);
|
51
|
+
const res = await this.request('GET', url);
|
52
|
+
if (res?.status === 404)
|
53
|
+
return null;
|
54
|
+
try {
|
55
|
+
return await res.json();
|
56
|
+
}
|
57
|
+
catch (err) {
|
58
|
+
console.error('Error reading file:', err);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
async delete(key) {
|
62
|
+
const url = this.buildUrlForKey(key);
|
63
|
+
const res = await this.request('DELETE', url);
|
64
|
+
return res?.ok || res?.status === 404;
|
65
|
+
}
|
66
|
+
// Updates can be performed by calling upload() with the same key
|
67
|
+
extractId(res) {
|
68
|
+
return res?.id || res?.result?.id || res?.url;
|
69
|
+
}
|
70
|
+
}
|
package/dist/types/index.d.ts
CHANGED
@@ -4,5 +4,7 @@ export * from './utils/google.js';
|
|
4
4
|
export * from './models/Resume.js';
|
5
5
|
export * from './models/ResumeVC.js';
|
6
6
|
export * from './models/WASStorage.js';
|
7
|
+
export * from './models/WASZcapStorage.js';
|
8
|
+
export * from './models/StorageContext.js';
|
7
9
|
export * from './utils/createWASSpace.js';
|
8
10
|
export * from './utils/getOrCreateAppDID.js';
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { GoogleDriveStorage } from './GoogleDriveStorage.js';
|
2
|
+
import { WASZcapStorage } from './WASZcapStorage.js';
|
3
|
+
export type StorageKind = 'googleDrive' | 'was' | 'wasZcap';
|
4
|
+
export type GoogleDriveOptions = {
|
5
|
+
accessToken: string;
|
6
|
+
};
|
7
|
+
export type WASOptions = {
|
8
|
+
signer: any;
|
9
|
+
spaceId: string;
|
10
|
+
};
|
11
|
+
export type WASZcapOptions = {
|
12
|
+
appInstance: any;
|
13
|
+
capability: any;
|
14
|
+
};
|
15
|
+
export declare function createStorage(kind: 'googleDrive', options: GoogleDriveOptions): GoogleDriveStorage;
|
16
|
+
export declare function createStorage(kind: 'wasZcap', options: WASZcapOptions): WASZcapStorage;
|
@@ -0,0 +1,41 @@
|
|
1
|
+
export interface WasZcapStorageConfig {
|
2
|
+
appInstance: {
|
3
|
+
publicKeyMultibase: string;
|
4
|
+
privateKeyMultibase: string;
|
5
|
+
controller: string;
|
6
|
+
id: string;
|
7
|
+
};
|
8
|
+
capability: {
|
9
|
+
'@context': string[];
|
10
|
+
allowedAction: string[];
|
11
|
+
controller: string;
|
12
|
+
expires: string;
|
13
|
+
id: string;
|
14
|
+
invocationTarget: string;
|
15
|
+
parentCapability: string;
|
16
|
+
proof: {
|
17
|
+
capabilityChain: string[];
|
18
|
+
type: string;
|
19
|
+
created: string;
|
20
|
+
proofPurpose: string;
|
21
|
+
proofValue: string;
|
22
|
+
verificationMethod: string;
|
23
|
+
};
|
24
|
+
};
|
25
|
+
}
|
26
|
+
export declare class WASZcapStorage {
|
27
|
+
private zcapClient;
|
28
|
+
private capability;
|
29
|
+
private ready;
|
30
|
+
constructor(config: WasZcapStorageConfig);
|
31
|
+
private initClient;
|
32
|
+
private request;
|
33
|
+
private buildUrlForKey;
|
34
|
+
upload({ key, file }: {
|
35
|
+
key: string;
|
36
|
+
file: File | Blob;
|
37
|
+
}): Promise<string>;
|
38
|
+
read(key: string): Promise<any | null>;
|
39
|
+
delete(key: string): Promise<boolean>;
|
40
|
+
private extractId;
|
41
|
+
}
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@cooperation/vc-storage",
|
3
3
|
"type": "module",
|
4
|
-
"version": "1.0.
|
4
|
+
"version": "1.0.41",
|
5
5
|
"description": "Sign and store your verifiable credentials.",
|
6
6
|
"main": "dist/index.js",
|
7
7
|
"types": "dist/types/index.d.ts",
|
@@ -23,6 +23,9 @@
|
|
23
23
|
"@digitalbazaar/ed25519-verification-key-2020": "^4.1.0",
|
24
24
|
"@digitalbazaar/vc": "^6.3.0",
|
25
25
|
"@wallet.storage/fetch-client": "^1.2.0",
|
26
|
+
"@digitalcredentials/ezcap": "^7.1.0",
|
27
|
+
"@digitalcredentials/ed25519-verification-key-2020": "^5.0.0-beta.2",
|
28
|
+
"@digitalcredentials/ed25519-signature-2020": "^5.0.0",
|
26
29
|
"add": "^2.0.6",
|
27
30
|
"bnid": "^3.0.0",
|
28
31
|
"crypto-js": "^4.2.0",
|