@hashgraph/hedera-identify-snap
Version:
A snap for managing Decentralized Identifiers(DIDs)
241 lines (211 loc) • 6.3 kB
text/typescript
/*-
*
* Hedera Identify Snap
*
* Copyright (C) 2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import { IAgentPlugin } from '@veramo/core';
import { AbstractDataStore } from '../data-store/abstractDataStore';
import {
IDataManager,
IDataManagerClearArgs,
IDataManagerClearResult,
IDataManagerDeleteArgs,
IDataManagerDeleteResult,
IDataManagerQueryArgs,
IDataManagerQueryResult,
IDataManagerSaveArgs,
IDataManagerSaveResult,
} from '../types/IDataManager';
export class DataManager implements IAgentPlugin {
readonly methods: IDataManager = {
saveVC: this.saveVC.bind(this),
queryVC: this.queryVC.bind(this),
deleteVC: this.deleteVC.bind(this),
clearVCs: this.clearVCs.bind(this),
};
private stores: Record<string, AbstractDataStore>;
constructor(options: { store: Record<string, AbstractDataStore> }) {
this.stores = options.store;
}
/**
* Check if any stores require token configuration.
*
* @param store - Input stores.
* @param accessToken - Access token.
* @returns The result to check token configuration.
*/
private async checkTokenConfiguration(
store: string[],
accessToken: string | undefined,
) {
for (const storeName of store) {
const storePlugin = this.stores[storeName];
if (!storePlugin) {
throw new Error(`Store plugin ${storeName} not found`);
}
if (storePlugin.configure) {
if (!accessToken) {
throw new Error('You need to configure google account.');
}
await storePlugin.configure({ accessToken });
}
}
return true;
}
public async saveVC(
args: IDataManagerSaveArgs,
): Promise<IDataManagerSaveResult[]> {
const { data, options, accessToken } = args;
let store;
if (options === undefined) {
store = Object.keys(this.stores);
} else if (options.store === undefined) {
store = Object.keys(this.stores);
} else {
store = options.store;
}
if (typeof store === 'string') {
store = [store];
}
await this.checkTokenConfiguration(store, accessToken);
// Save VC for all stores
let res: IDataManagerSaveResult[] = [];
for (const storeName of store) {
const storePlugin = this.stores[storeName];
try {
const result = await storePlugin.saveVC({ data });
const mappedResult = result.map((savedId) => {
return { id: savedId, store: storeName };
});
res = [...res, ...mappedResult];
} catch (e) {
console.log(e);
}
}
return res;
}
public async queryVC(
args: IDataManagerQueryArgs,
): Promise<IDataManagerQueryResult[]> {
const {
filter = { type: 'none', filter: {} },
options,
accessToken,
} = args;
let store;
let returnStore = true;
if (options === undefined) {
store = Object.keys(this.stores);
} else {
if (options.store === undefined) {
store = Object.keys(this.stores);
} else {
store = options.store;
}
if (options.returnStore !== undefined) {
returnStore = options.returnStore;
}
}
if (typeof store === 'string') {
store = [store];
}
await this.checkTokenConfiguration(store, accessToken);
let res: IDataManagerQueryResult[] = [];
for (const storeName of store) {
const storePlugin = this.stores[storeName];
try {
const result = await storePlugin.queryVC({ filter });
const mappedResult = result.map((r) => {
if (returnStore) {
return {
data: r.data,
metadata: { id: r.metadata.id, store: storeName },
};
}
return { data: r.data, metadata: { id: r.metadata.id } };
});
res = [...res, ...mappedResult];
} catch (e) {
console.log(e);
}
}
return res;
}
public async deleteVC(
args: IDataManagerDeleteArgs,
): Promise<IDataManagerDeleteResult[]> {
const { id, options, accessToken } = args;
let store;
if (options === undefined) {
store = Object.keys(this.stores);
} else if (options.store === undefined) {
store = Object.keys(this.stores);
} else {
store = options.store;
}
if (typeof store === 'string') {
store = [store];
}
await this.checkTokenConfiguration(store, accessToken);
const res: IDataManagerDeleteResult[] = [];
for (const storeName of store) {
const storePlugin = this.stores[storeName];
try {
let ids = Array.isArray(id) ? id : [id];
for (const id of ids) {
const result = await storePlugin.deleteVC({ id });
res.push({ id, removed: result, store: storeName });
}
} catch (e) {
console.log(e);
}
}
return res;
}
public async clearVCs(
args: IDataManagerClearArgs,
): Promise<IDataManagerClearResult[]> {
const {
filter = { type: 'none', filter: {} },
options,
accessToken,
} = args;
let store;
if (options === undefined) {
store = Object.keys(this.stores);
} else if (options.store === undefined) {
store = Object.keys(this.stores);
} else {
store = options.store;
}
if (typeof store === 'string') {
store = [store];
}
await this.checkTokenConfiguration(store, accessToken);
const res: IDataManagerClearResult[] = [];
for (const storeName of store) {
const storePlugin = this.stores[storeName];
try {
const result = await storePlugin.clearVCs({ filter });
res.push({ removed: result, store: storeName });
} catch (e) {
console.log(e);
}
}
return res;
}
}