@cooperation/vc-storage 1.0.34 → 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/app.config.js +1 -0
- package/dist/index.js +5 -1
- package/dist/models/CredentialEngine.js +7 -3
- package/dist/models/GoogleDriveStorage.js +121 -273
- package/dist/models/Resume.js +16 -4
- package/dist/models/StorageContext.js +15 -50
- package/dist/models/WASStorage.js +71 -0
- package/dist/models/WASZcapStorage.js +70 -0
- package/dist/scripts/test-was.js +61 -0
- package/dist/types/index.d.ts +5 -1
- package/dist/types/models/CredentialEngine.d.ts +1 -1
- package/dist/types/models/GoogleDriveStorage.d.ts +31 -55
- package/dist/types/models/Resume.d.ts +3 -2
- package/dist/types/models/StorageContext.d.ts +16 -0
- package/dist/types/models/WASStorage.d.ts +30 -0
- package/dist/types/models/WASZcapStorage.d.ts +41 -0
- package/dist/types/scripts/test-was.d.ts +1 -0
- package/dist/types/utils/createWASSpace.d.ts +9 -0
- package/dist/types/utils/credential.d.ts +1 -1
- package/dist/types/utils/getOrCreateAppDID.d.ts +11 -0
- package/dist/types/utils/google.d.ts +1 -1
- package/dist/utils/createWASSpace.js +27 -0
- package/dist/utils/credential.js +7 -16
- package/dist/utils/getOrCreateAppDID.js +22 -0
- package/dist/utils/google.js +1 -1
- package/package.json +9 -3
- package/dist/types/utils/presentation.d.ts +0 -10
- package/dist/utils/presentation.js +0 -45
@@ -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,71 @@
|
|
1
|
+
import { StorageClient } from '@wallet.storage/fetch-client';
|
2
|
+
import { WAS_BASE_URL } from '../../app.config.js';
|
3
|
+
export class LCWStorage {
|
4
|
+
static storageClient;
|
5
|
+
signer;
|
6
|
+
zcap;
|
7
|
+
spaceId;
|
8
|
+
constructor({ signer, zcap, spaceId }) {
|
9
|
+
this.signer = signer;
|
10
|
+
this.zcap = zcap;
|
11
|
+
this.spaceId = spaceId;
|
12
|
+
}
|
13
|
+
getStorageClient() {
|
14
|
+
if (!LCWStorage.storageClient) {
|
15
|
+
LCWStorage.storageClient = new StorageClient(new URL(WAS_BASE_URL));
|
16
|
+
}
|
17
|
+
return LCWStorage.storageClient;
|
18
|
+
}
|
19
|
+
getResource(key) {
|
20
|
+
const space = this.getStorageClient().space({
|
21
|
+
signer: this.signer,
|
22
|
+
id: this.spaceId,
|
23
|
+
});
|
24
|
+
return space.resource(key);
|
25
|
+
}
|
26
|
+
async add(key, value) {
|
27
|
+
const resource = this.getResource(key);
|
28
|
+
const blob = new Blob([JSON.stringify(value)], {
|
29
|
+
type: 'application/json',
|
30
|
+
});
|
31
|
+
const res = await resource.put(blob, {
|
32
|
+
signer: this.signer,
|
33
|
+
});
|
34
|
+
if (!res.ok) {
|
35
|
+
throw new Error(`Failed to add resource. Status: ${res.status}`);
|
36
|
+
}
|
37
|
+
return res;
|
38
|
+
}
|
39
|
+
async read(key) {
|
40
|
+
const resource = this.getResource(key);
|
41
|
+
const res = await resource.get({ signer: this.signer });
|
42
|
+
if (!res.ok) {
|
43
|
+
if (res.status === 404)
|
44
|
+
return null;
|
45
|
+
throw new Error(`Failed to read resource. Status: ${res.status}`);
|
46
|
+
}
|
47
|
+
return await res.json();
|
48
|
+
}
|
49
|
+
async update(key, value) {
|
50
|
+
return this.add(key, value); // Overwrite = update
|
51
|
+
}
|
52
|
+
async delete(key) {
|
53
|
+
const resource = this.getResource(key);
|
54
|
+
const res = await resource.delete({ signer: this.signer });
|
55
|
+
if (!res.ok && res.status !== 404) {
|
56
|
+
throw new Error(`Failed to delete resource. Status: ${res.status}`);
|
57
|
+
}
|
58
|
+
return true;
|
59
|
+
}
|
60
|
+
async list() {
|
61
|
+
// const space = this.getStorageClient().space({
|
62
|
+
// signer: this.signer,
|
63
|
+
// id: this.spaceId as `urn:uuid:${string}`,
|
64
|
+
// });
|
65
|
+
// const res = await space.resources().list({ signer: this.signer });
|
66
|
+
// if (!res.ok) {
|
67
|
+
// throw new Error(`Failed to list resources. Status: ${res.status}`);
|
68
|
+
// }
|
69
|
+
// return await res.json(); // Should contain list of resource IDs or summaries
|
70
|
+
}
|
71
|
+
}
|
@@ -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
|
+
}
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import { Ed25519Signer } from '@did.coop/did-key-ed25519';
|
2
|
+
import { v4 as uuidv4 } from 'uuid';
|
3
|
+
import { LCWStorage } from '../models/WASStorage.js';
|
4
|
+
import { StorageClient } from '@wallet.storage/fetch-client';
|
5
|
+
import { WAS_BASE_URL } from '../../app.config.js';
|
6
|
+
async function main() {
|
7
|
+
const appDidSigner = await Ed25519Signer.generate();
|
8
|
+
console.log('Signer:', appDidSigner);
|
9
|
+
const spaceUUID = uuidv4();
|
10
|
+
const spaceId = `urn:uuid:${spaceUUID}`;
|
11
|
+
console.log('Space ID:', spaceId);
|
12
|
+
const storage = new StorageClient(new URL(WAS_BASE_URL));
|
13
|
+
const space = storage.space({
|
14
|
+
signer: appDidSigner,
|
15
|
+
id: spaceId,
|
16
|
+
});
|
17
|
+
const spaceObject = {
|
18
|
+
id: spaceId,
|
19
|
+
controller: appDidSigner.id.split('#')[0],
|
20
|
+
};
|
21
|
+
console.log('Creating space with object:', spaceObject);
|
22
|
+
const spaceObjectBlob = new Blob([JSON.stringify(spaceObject)], { type: 'application/json' });
|
23
|
+
// Create the space
|
24
|
+
const response = await space.put(spaceObjectBlob, {
|
25
|
+
signer: appDidSigner,
|
26
|
+
});
|
27
|
+
console.log('🚀 ~ main ~ response:', response);
|
28
|
+
console.log('Space PUT response:', {
|
29
|
+
status: response.status,
|
30
|
+
ok: response.ok,
|
31
|
+
});
|
32
|
+
if (!response.ok) {
|
33
|
+
throw new Error(`Failed to initialize space. Status: ${response.status}`);
|
34
|
+
}
|
35
|
+
// Store the signer for future connections
|
36
|
+
const signerJson = await appDidSigner.toJSON();
|
37
|
+
console.log('Signer JSON:', signerJson);
|
38
|
+
const lcwStorage = new LCWStorage({ signer: appDidSigner, zcap: {}, spaceId });
|
39
|
+
const res = await lcwStorage.add('test', { test: 'test' });
|
40
|
+
if (res.ok) {
|
41
|
+
console.log('Record added successfully');
|
42
|
+
}
|
43
|
+
else {
|
44
|
+
console.error('Failed to add record');
|
45
|
+
}
|
46
|
+
const res2 = await lcwStorage.read('test');
|
47
|
+
if (res2) {
|
48
|
+
console.log('Record read successfully');
|
49
|
+
}
|
50
|
+
else {
|
51
|
+
console.error('Failed to read record');
|
52
|
+
}
|
53
|
+
const res3 = await lcwStorage.update('test', { test: 'test2' });
|
54
|
+
if (res3.ok) {
|
55
|
+
console.log('Record updated successfully');
|
56
|
+
}
|
57
|
+
else {
|
58
|
+
console.error('Failed to update record');
|
59
|
+
}
|
60
|
+
}
|
61
|
+
main();
|
package/dist/types/index.d.ts
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
export * from './models/GoogleDriveStorage.js';
|
2
2
|
export * from './models/CredentialEngine.js';
|
3
3
|
export * from './utils/google.js';
|
4
|
-
export * from './utils/presentation.js';
|
5
4
|
export * from './models/Resume.js';
|
6
5
|
export * from './models/ResumeVC.js';
|
6
|
+
export * from './models/WASStorage.js';
|
7
|
+
export * from './models/WASZcapStorage.js';
|
8
|
+
export * from './models/StorageContext.js';
|
9
|
+
export * from './utils/createWASSpace.js';
|
10
|
+
export * from './utils/getOrCreateAppDID.js';
|
@@ -50,7 +50,7 @@ export declare class CredentialEngine {
|
|
50
50
|
}>;
|
51
51
|
/**
|
52
52
|
* Sign a Verifiable Credential (VC)
|
53
|
-
* @param {'VC' | 'RECOMMENDATION'} type - The signature type.
|
53
|
+
* @param {'VC' | 'RECOMMENDATION' | 'EMPLOYMENT' | 'VOLUNTEERING' | 'PERFORMANCE_REVIEW'} type - The signature type.
|
54
54
|
* @param {string} issuerId - The ID of the issuer [currently we put it as the did id]
|
55
55
|
* @param {KeyPair} keyPair - The key pair to use for signing.
|
56
56
|
* @param {FormDataI | RecommendationFormDataI} formData - The form data to include in the VC.
|
@@ -3,70 +3,64 @@ type FileType = 'KEYPAIRs' | 'VCs' | 'SESSIONs' | 'DIDs' | 'RECOMMENDATIONs' | '
|
|
3
3
|
* @class GoogleDriveStorage
|
4
4
|
* @description Class to interact with Google Drive API
|
5
5
|
* @param accessToken - Access token to authenticate with Google Drive API
|
6
|
-
* @method
|
7
|
-
* @method save - Save data to Google Drive
|
8
|
-
* @method addCommentToFile - Add a comment to a file in Google Drive
|
9
|
-
* @method addCommenterRoleToFile - Add commenter role to a file in Google Drive
|
6
|
+
* @method saveFile - Save a file to Google Drive
|
10
7
|
* @method retrieve - Retrieve a file from Google Drive
|
11
|
-
* @method
|
12
|
-
* @method
|
13
|
-
* @method
|
14
|
-
* @method
|
8
|
+
* @method createFolder - Create a new folder in Google Drive
|
9
|
+
* @method getOrCreateMediaFolder - Get the ID of the MEDIAs folder
|
10
|
+
* @method uploadBinaryFile - Upload a binary file to Google Drive
|
11
|
+
* @method updateFileData - Update the data of a file
|
12
|
+
* @method updateRelationsFile - Update the relations file
|
15
13
|
* @method delete - Delete a file from Google Drive
|
14
|
+
* @method checkEmailExists - Check if an email VC exists and return its content
|
15
|
+
* @method findFolders - Find folders in Google Drive
|
16
|
+
* @method findFolderFiles - Find files in a folder
|
16
17
|
*/
|
17
18
|
export declare class GoogleDriveStorage {
|
18
19
|
private accessToken;
|
19
|
-
folderCache: any;
|
20
|
-
private fileIdsCache;
|
21
|
-
private updateFileIdsJson;
|
20
|
+
static folderCache: any;
|
21
|
+
private static fileIdsCache;
|
22
22
|
constructor(accessToken: string);
|
23
|
+
private updateFileIdsJson;
|
23
24
|
private fetcher;
|
24
25
|
private getFileContent;
|
25
26
|
private searchFiles;
|
27
|
+
private getOrCreateMediaFolder;
|
28
|
+
findFolderFiles(folderId: string): Promise<any[]>;
|
26
29
|
createFolder({ folderName, parentFolderId }: {
|
27
30
|
folderName: string;
|
28
31
|
parentFolderId: string;
|
29
32
|
}): Promise<any>;
|
30
|
-
|
33
|
+
/**
|
34
|
+
* Get the ID of the MEDIAs folder (public wrapper for getOrCreateMediaFolder)
|
35
|
+
* @returns The folder ID for the MEDIAs folder
|
36
|
+
*/
|
37
|
+
getMediaFolderId(): Promise<string>;
|
31
38
|
uploadBinaryFile({ file }: {
|
32
39
|
file: File;
|
33
40
|
}): Promise<any>;
|
34
|
-
saveFile({ data, folderId }: {
|
41
|
+
saveFile({ data, folderId, fileId }: {
|
35
42
|
data: any;
|
36
|
-
folderId
|
43
|
+
folderId?: string;
|
44
|
+
fileId?: string;
|
37
45
|
}): Promise<any>;
|
38
|
-
/**
|
39
|
-
* Get file from google drive by id
|
40
|
-
* @param id
|
41
|
-
* @returns file content
|
42
|
-
*/
|
43
46
|
retrieve(id: string): Promise<{
|
44
47
|
data: any;
|
45
48
|
id: string;
|
46
49
|
} | null>;
|
47
|
-
/**
|
48
|
-
* Get folder by folderId, if folderId == null you will have them all
|
49
|
-
* @param folderId [Optional]
|
50
|
-
* @returns
|
51
|
-
*/
|
52
50
|
findFolders(folderId?: string): Promise<any[]>;
|
53
|
-
/**
|
54
|
-
* Get all files content for the specified type ('KEYPAIRs' | 'VCs' | 'SESSIONs' | 'DIDs' | 'RECOMMENDATIONs')
|
55
|
-
* @param type
|
56
|
-
* @returns
|
57
|
-
*/
|
58
51
|
getAllFilesByType(type: FileType): Promise<any[]>;
|
52
|
+
updateFileData(fileId: string, data: {
|
53
|
+
fileName: string;
|
54
|
+
}): Promise<any>;
|
59
55
|
/**
|
60
|
-
* Update the
|
56
|
+
* Update the content of an existing file in Google Drive
|
61
57
|
* @param fileId - The ID of the file to update
|
62
|
-
* @param
|
63
|
-
* @returns The updated file metadata
|
58
|
+
* @param data - The new content for the file
|
59
|
+
* @returns The updated file metadata
|
64
60
|
*/
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
updateFileData(fileId: string, data: {
|
69
|
-
fileName: string;
|
61
|
+
updateFileContent({ fileId, data }: {
|
62
|
+
fileId: string;
|
63
|
+
data: any;
|
70
64
|
}): Promise<any>;
|
71
65
|
getFileParents(fileId: string): Promise<any>;
|
72
66
|
updateRelationsFile({ relationsFileId, recommendationFileId }: {
|
@@ -76,25 +70,7 @@ export declare class GoogleDriveStorage {
|
|
76
70
|
createRelationsFile({ vcFolderId }: {
|
77
71
|
vcFolderId: string;
|
78
72
|
}): Promise<any>;
|
79
|
-
updateResumeRelation({ authorFolderId, draftFileId, signedFileId, }: {
|
80
|
-
authorFolderId: string;
|
81
|
-
draftFileId: string;
|
82
|
-
signedFileId: string;
|
83
|
-
}): Promise<any>;
|
84
|
-
/**
|
85
|
-
* Delete file by id
|
86
|
-
* @param id
|
87
|
-
* @returns
|
88
|
-
*/
|
89
73
|
delete(id: string): Promise<any>;
|
90
|
-
update(fileId: string, data: any): Promise<any>;
|
91
|
-
getFileIdsFromAppDataFolder(): Promise<any>;
|
92
|
-
getAllFilesData(): Promise<any>;
|
93
|
-
/**
|
94
|
-
* Check if an email VC exists and return its content
|
95
|
-
* @param email - The email address to check
|
96
|
-
* @returns {Promise<{data: any, id: string} | null>} - The email VC content and ID if exists, null otherwise
|
97
|
-
*/
|
98
74
|
checkEmailExists(email: string): Promise<{
|
99
75
|
data: any;
|
100
76
|
id: string;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { GoogleDriveStorage } from './GoogleDriveStorage
|
1
|
+
import { GoogleDriveStorage } from './GoogleDriveStorage';
|
2
2
|
export declare const resumeFolderTypes: {
|
3
3
|
root: string;
|
4
4
|
nonSigned: string;
|
@@ -14,9 +14,10 @@ export declare class StorageHandler {
|
|
14
14
|
}
|
15
15
|
export declare class Resume extends StorageHandler {
|
16
16
|
constructor(storage: GoogleDriveStorage);
|
17
|
-
saveResume({ resume, type }: {
|
17
|
+
saveResume({ resume, type, id }: {
|
18
18
|
resume: any;
|
19
19
|
type: 'sign' | 'unsigned';
|
20
|
+
id?: string;
|
20
21
|
}): Promise<any>;
|
21
22
|
find(): Promise<{
|
22
23
|
signed: any[];
|
@@ -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,30 @@
|
|
1
|
+
export declare class LCWStorage {
|
2
|
+
private static storageClient;
|
3
|
+
private signer;
|
4
|
+
private zcap;
|
5
|
+
private spaceId;
|
6
|
+
constructor({ signer, zcap, spaceId }: {
|
7
|
+
signer: any;
|
8
|
+
zcap: any;
|
9
|
+
spaceId: string;
|
10
|
+
});
|
11
|
+
private getStorageClient;
|
12
|
+
private getResource;
|
13
|
+
add(key: string, value: any): Promise<{
|
14
|
+
ok: boolean;
|
15
|
+
headers: [string, string][];
|
16
|
+
status: number;
|
17
|
+
blob(): Promise<import("buffer").Blob>;
|
18
|
+
json(): Promise<unknown>;
|
19
|
+
}>;
|
20
|
+
read(key: string): Promise<unknown>;
|
21
|
+
update(key: string, value: any): Promise<{
|
22
|
+
ok: boolean;
|
23
|
+
headers: [string, string][];
|
24
|
+
status: number;
|
25
|
+
blob(): Promise<import("buffer").Blob>;
|
26
|
+
json(): Promise<unknown>;
|
27
|
+
}>;
|
28
|
+
delete(key: string): Promise<boolean>;
|
29
|
+
list(): Promise<void>;
|
30
|
+
}
|
@@ -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
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { Ed25519Signer } from '@did.coop/did-key-ed25519';
|
2
|
+
/**
|
3
|
+
* Create a new WAS space
|
4
|
+
* @returns {Promise<{ signer: InstanceType<typeof Ed25519Signer>; spaceId: `urn:uuid:${string}` }>}
|
5
|
+
*/
|
6
|
+
export declare function createSpace(): Promise<{
|
7
|
+
signer: InstanceType<typeof Ed25519Signer>;
|
8
|
+
spaceId: `urn:uuid:${string}`;
|
9
|
+
}>;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { KeyPair, DidDocument, FormDataI, RecommendationCredential, Credential, RecommendationFormDataI, VerifiableCredential, EmploymentFormDataI, VolunteeringFormDataI, PerformanceReviewFormDataI } from '../../types
|
1
|
+
import { KeyPair, DidDocument, FormDataI, RecommendationCredential, Credential, RecommendationFormDataI, VerifiableCredential, EmploymentFormDataI, VolunteeringFormDataI, PerformanceReviewFormDataI } from '../../types';
|
2
2
|
/**
|
3
3
|
* Create a DID document using the provided key pair.
|
4
4
|
* @param {KeyPair} keyPair - The key pair used to create the DID document.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { Ed25519VerificationKey2020 } from '@digitalbazaar/ed25519-verification-key-2020';
|
2
|
+
export interface AppInstanceKeyPair {
|
3
|
+
controller: string;
|
4
|
+
id: string;
|
5
|
+
publicKeyMultibase: string;
|
6
|
+
privateKeyMultibase: string;
|
7
|
+
}
|
8
|
+
export declare function getOrCreateAppInstanceDid(): Promise<{
|
9
|
+
did: string;
|
10
|
+
keyPair: Ed25519VerificationKey2020;
|
11
|
+
}>;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { GoogleDriveStorage } from '../models/GoogleDriveStorage
|
1
|
+
import { GoogleDriveStorage } from '../models/GoogleDriveStorage';
|
2
2
|
export type FileType = 'VC' | 'DID' | 'SESSION' | 'RECOMMENDATION' | 'KEYPAIR';
|
3
3
|
interface SaveToGooglePropsI {
|
4
4
|
storage: GoogleDriveStorage;
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { StorageClient } from '@wallet.storage/fetch-client';
|
2
|
+
import { Ed25519Signer } from '@did.coop/did-key-ed25519';
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
4
|
+
import { WAS_BASE_URL } from '../../app.config.js';
|
5
|
+
/**
|
6
|
+
* Create a new WAS space
|
7
|
+
* @returns {Promise<{ signer: InstanceType<typeof Ed25519Signer>; spaceId: `urn:uuid:${string}` }>}
|
8
|
+
*/
|
9
|
+
export async function createSpace() {
|
10
|
+
const signer = await Ed25519Signer.generate();
|
11
|
+
const controller = signer.id.split('#')[0];
|
12
|
+
const spaceUUID = uuidv4();
|
13
|
+
const spaceId = `urn:uuid:${spaceUUID}`;
|
14
|
+
const client = new StorageClient(new URL(WAS_BASE_URL));
|
15
|
+
const space = client.space({ signer, id: spaceId });
|
16
|
+
const spaceObject = {
|
17
|
+
id: spaceId,
|
18
|
+
controller,
|
19
|
+
};
|
20
|
+
const blob = new Blob([JSON.stringify(spaceObject)], { type: 'application/json' });
|
21
|
+
const res = await space.put(blob, { signer });
|
22
|
+
if (!res.ok) {
|
23
|
+
throw new Error(`Failed to initialize WAS space. Status: ${res.status}`);
|
24
|
+
}
|
25
|
+
console.log('✅ Provisioned and saved new WAS space');
|
26
|
+
return { signer, spaceId };
|
27
|
+
}
|
package/dist/utils/credential.js
CHANGED
@@ -177,10 +177,7 @@ export function generateUnsignedRecommendation({ vcId, recommendation, issuerDid
|
|
177
177
|
export function generateUnsignedEmployment({ formData, issuerDid }) {
|
178
178
|
const issuanceDate = new Date().toISOString();
|
179
179
|
const unsignedCredential = {
|
180
|
-
'@context': [
|
181
|
-
'https://www.w3.org/2018/credentials/v1',
|
182
|
-
employmentCredentialContext['@context'],
|
183
|
-
],
|
180
|
+
'@context': ['https://www.w3.org/2018/credentials/v1', employmentCredentialContext['@context']],
|
184
181
|
id: '',
|
185
182
|
type: ['VerifiableCredential', 'EmploymentCredential'],
|
186
183
|
issuer: { id: issuerDid, type: ['Profile'] },
|
@@ -192,7 +189,7 @@ export function generateUnsignedEmployment({ formData, issuerDid }) {
|
|
192
189
|
credentialName: formData.credentialName,
|
193
190
|
credentialDuration: formData.credentialDuration,
|
194
191
|
credentialDescription: formData.credentialDescription,
|
195
|
-
portfolio: formData.portfolio.map(item => ({ name: item.name, url: item.url })),
|
192
|
+
portfolio: formData.portfolio.map((item) => ({ name: item.name, url: item.url })),
|
196
193
|
evidenceLink: formData.evidenceLink,
|
197
194
|
evidenceDescription: formData.evidenceDescription,
|
198
195
|
company: formData.company,
|
@@ -208,10 +205,7 @@ export function generateUnsignedEmployment({ formData, issuerDid }) {
|
|
208
205
|
export function generateUnsignedVolunteering({ formData, issuerDid }) {
|
209
206
|
const issuanceDate = new Date().toISOString();
|
210
207
|
const unsignedCredential = {
|
211
|
-
'@context': [
|
212
|
-
'https://www.w3.org/2018/credentials/v1',
|
213
|
-
volunteeringCredentialContext['@context'],
|
214
|
-
],
|
208
|
+
'@context': ['https://www.w3.org/2018/credentials/v1', volunteeringCredentialContext['@context']],
|
215
209
|
id: '',
|
216
210
|
type: ['VerifiableCredential', 'VolunteeringCredential'],
|
217
211
|
issuer: { id: issuerDid, type: ['Profile'] },
|
@@ -223,10 +217,10 @@ export function generateUnsignedVolunteering({ formData, issuerDid }) {
|
|
223
217
|
volunteerWork: formData.volunteerWork,
|
224
218
|
volunteerOrg: formData.volunteerOrg,
|
225
219
|
volunteerDescription: formData.volunteerDescription,
|
226
|
-
skillsGained: formData.skillsGained ? formData.skillsGained.split(',').map(s => s.trim()) : undefined,
|
220
|
+
skillsGained: formData.skillsGained ? formData.skillsGained.split(',').map((s) => s.trim()) : undefined,
|
227
221
|
duration: formData.duration,
|
228
222
|
volunteerDates: formData.volunteerDates,
|
229
|
-
portfolio: formData.portfolio.map(item => ({ name: item.name, url: item.url })),
|
223
|
+
portfolio: formData.portfolio.map((item) => ({ name: item.name, url: item.url })),
|
230
224
|
evidenceLink: formData.evidenceLink,
|
231
225
|
evidenceDescription: formData.evidenceDescription,
|
232
226
|
},
|
@@ -240,10 +234,7 @@ export function generateUnsignedVolunteering({ formData, issuerDid }) {
|
|
240
234
|
export function generateUnsignedPerformanceReview({ formData, issuerDid }) {
|
241
235
|
const issuanceDate = new Date().toISOString();
|
242
236
|
const unsignedCredential = {
|
243
|
-
'@context': [
|
244
|
-
'https://www.w3.org/2018/credentials/v1',
|
245
|
-
performanceReviewCredentialContext['@context'],
|
246
|
-
],
|
237
|
+
'@context': ['https://www.w3.org/2018/credentials/v1', performanceReviewCredentialContext['@context']],
|
247
238
|
id: '',
|
248
239
|
type: ['VerifiableCredential', 'PerformanceReviewCredential'],
|
249
240
|
issuer: { id: issuerDid, type: ['Profile'] },
|
@@ -266,7 +257,7 @@ export function generateUnsignedPerformanceReview({ formData, issuerDid }) {
|
|
266
257
|
overallRating: formData.overallRating,
|
267
258
|
reviewComments: formData.reviewComments,
|
268
259
|
goalsNext: formData.goalsNext,
|
269
|
-
portfolio: formData.portfolio.map(item => ({ name: item.name, url: item.url })),
|
260
|
+
portfolio: formData.portfolio.map((item) => ({ name: item.name, url: item.url })),
|
270
261
|
evidenceLink: formData.evidenceLink,
|
271
262
|
evidenceDescription: formData.evidenceDescription,
|
272
263
|
},
|