add readme, add unit test for backend app, reconfigure IP on pc 1
This commit is contained in:
parent
aa47a38c7a
commit
278ff47ad9
157
README.md
Normal file
157
README.md
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
# Pengembangan Sistem Audit Rekam Medis Menggunakan Teknologi Blockchain
|
||||||
|
|
||||||
|
Repositori ini berisi <i>source code</i> untuk pengembangan sistem audit rekam medis berbasis blockchain.
|
||||||
|
|
||||||
|
## Gambaran Proyek
|
||||||
|
|
||||||
|
Dalam proyek ini terdapat 3 node peer dan 1 node orderer. Keempat peer tersebut dijalankan pada 3 pc desktop menggunakan docker swarm dengan detail sebagai berikut:
|
||||||
|
|
||||||
|
- PC 1 (Ubuntu 24.04.3): PC 1 ini sebagai host docker swarm dan menjalankan peer serta orderer.
|
||||||
|
- PC 2 (Ubuntu 24.04.3): PC 2 ini sebagai worker docker swarm pertama dan menjalankan peer.
|
||||||
|
- PC 3 (Windows WSL dengan distro Ubuntu 24.04.1): PC 3 ini sebagai worker docker swarm keuda dan menjalankan peer.
|
||||||
|
|
||||||
|
Proyek ini mengimplementasikan sistem rekam medis menggunakan teknologi blockchain dengan rincian sebagai berikut:
|
||||||
|
|
||||||
|
- Hyperledger Fabric sebagai framework blockchain dengan chaincode dibangun menggunakan bahasa pemrograman javascript.
|
||||||
|
- Mekanisme konsensus RAFT untuk <i>ordering service</i>.
|
||||||
|
- PostgreSQL sebagai basis data dan penyimpanan rekam medis offchain.
|
||||||
|
- REST API Gateway sebagai penghubung antara pengguna dan jaringan blockchain, dibangun menggunakan javascript.
|
||||||
|
|
||||||
|
## Struktur Repositori
|
||||||
|
|
||||||
|
- `/backend` - Folder backend yang di dalamnya terdapat kode program backend api dan blockchain.
|
||||||
|
- `/frontend` - Folder frontend yang di dalamnya terdapat kode program frontend.
|
||||||
|
|
||||||
|
## Prasyarat
|
||||||
|
|
||||||
|
- Docker & Docker Compose
|
||||||
|
- Node.js (v20 atau lebih tinggi)
|
||||||
|
- Instalasi Hyperledger Fabric (v2.5.13)
|
||||||
|
- Jika menggunakan Windows, pastikan WSL2 telah diinstal dan diaktifkan serta jalankan proyek ini di dalam WSL2.
|
||||||
|
- PostgreSQL (PostgreSQL 16.11 atau lebih tinggi)
|
||||||
|
- **Pastikan semua pc/vm yang digunakan memiliki IP Statis**
|
||||||
|
- **Pastikan port berikut tersedia karena diperlukan untuk koneksi docker swarm: 2377 (TCP), 7946 (TCP/UDP), 4789 (UDP)**
|
||||||
|
|
||||||
|
## Instalasi
|
||||||
|
|
||||||
|
1. Clone repositori
|
||||||
|
2. Masuk ke direktori [network](/backend/blockchain/network/), ikuti instruksi di file `README.md` untuk konfigurasi jaringan Hyperledger Fabric.
|
||||||
|
3. Masuk ke direktori [chaincode](/chaincode), ikuti instruksi di file `README.md` jika ingin mengubah logika bisnis dalam smartcontract, jika tidak, lanjut pada langkah ke-4.
|
||||||
|
4. Jalankan command berikut di pc/vm yang akan menjadi gateway utama/docker swarm leader:
|
||||||
|
```bash
|
||||||
|
docker swarm init --advertise-addr [IP_PC_UTAMA]
|
||||||
|
```
|
||||||
|
5. Kemudian jalankan command berikut untuk mendapatkan token docker swarm yang akan digunakan pc/vm lain untuk bergabung ke dalam docker swarm:
|
||||||
|
```bash
|
||||||
|
docker swarm join-token worker
|
||||||
|
```
|
||||||
|
Setelah itu, salin output dari command tersebut.
|
||||||
|
<br>
|
||||||
|
\*Output command tersebut kurang lebih adalah seperti berikut
|
||||||
|
```bash
|
||||||
|
docker swarm join --token SWMTKN-1-2ig... 192.168.11.74:2377
|
||||||
|
```
|
||||||
|
6. Selanjutnya, jalankan output command yang telah disalin tadi pada masing-masing pc/vm yang akan bergabung dalam jaringan menjadi docker swarm worker.
|
||||||
|
7. Pada pc/vm docker swarm leader, jalankan command berikut untuk mengidentifikasi pc/vm yang bergabung ke dalam docker swarm:
|
||||||
|
```bash
|
||||||
|
docker node ls
|
||||||
|
```
|
||||||
|
8. Setelah list node yang bergabung ke dalam docker swarm susah sesuai, maka selanjutnya adalah memberi nama masing-masing node yang bergabung ke dalam docker swarm. Untuk pemberian nama ini, pastikan sesuai dengan nama label yang ada dalam [docker-compose-swarm.yaml](/backend/blockchain/network/docker/docker-compose-swarm.yaml). (Contohnya dalam file docker compose, peer 1 ada constraint placement yang bernilai label lokasi pc-tengah, maka pelabelan lokasi pc/vm yang harus jadi peer 1 haruslah pc-tengah). Untuk memberi label jalankan command berikut:
|
||||||
|
```bash
|
||||||
|
docker node update --label-add lokasi=[LABEL] <ID_NODE>
|
||||||
|
```
|
||||||
|
9. Kemudian, jalankan command berikut untuk membuat jaringan overlay yang berfungsi untuk membuat jalur komunikasi virtual agar container di pc/vm berbeda bisa saling bicara.
|
||||||
|
```bash
|
||||||
|
docker network create --driver overlay --attachable hospital-net
|
||||||
|
```
|
||||||
|
10. Selanjutnya jalankan command berikut pada pc/vm yang berperan sebagai docker swarm leader di dalam folder yang ada [docker-compose-swarm.yaml](/backend/blockchain/network/docker/docker-compose-swarm.yaml), kalau dalam repositori ini berada dalam folder [docker](/backend/blockchain/network/docker/).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker stack deploy -c docker-compose.yaml hospital
|
||||||
|
```
|
||||||
|
|
||||||
|
11. Verifikasi status docker swarm dengan menjalankan command berikut pada pc/vm yang berperan sebagai docker swarm leader.
|
||||||
|
```bash
|
||||||
|
docker service ls
|
||||||
|
```
|
||||||
|
12. Setelah jaringan berjalan, langkah selanjutnya adalah membuat channel, membuat peer dan orderer bergabung ke channel, dan melakukan deploy chaincode.
|
||||||
|
13. Untuk membuat channel dan membuat peer dan orderer bergabung ke channel, jalankan command berikut:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -it cli bash
|
||||||
|
```
|
||||||
|
|
||||||
|
Setelah masuk ke dalam CLI fabric, lanjutkan dengan menjalankan command berikut:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem
|
||||||
|
|
||||||
|
# Buat channel
|
||||||
|
peer channel create -o [ip_orderer_atau_domain_orderer_sesuai_konfigurasi]:[port_orderer] -c mychannel \
|
||||||
|
-f ./channel-artifacts/mychannel.tx \
|
||||||
|
--outputBlock ./channel-artifacts/mychannel.block \
|
||||||
|
--tls --cafile "$ORDERER_CA"
|
||||||
|
|
||||||
|
# Export peer address
|
||||||
|
export CORE_PEER_ADDRESS=[ip_peer_atau_domain_peer_sesuai_konfigurasi]:[port_peer]
|
||||||
|
# Gabung ke dalam channel
|
||||||
|
peer channel join -b ./channel-artifacts/mychannel.block
|
||||||
|
|
||||||
|
# !PENTING! Jika memiliki lebih dari satu peer, peer tersebut juga
|
||||||
|
# harus bergabung ke dalam channel
|
||||||
|
export CORE_PEER_ADDRESS=[ip_peer_atau_domain_peer_sesuai_konfigurasi]:[port_peer]
|
||||||
|
peer channel join -b ./channel-artifacts/mychannel.block
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setelah berhasil, jangan keluar dari CLI terlebih dahulu.
|
||||||
|
|
||||||
|
14. Masih dalam CLI fabric, untuk melakukan deploy chaincode modifikasi dan jalankan command berikut sesuai konfigurasi jaringan anda:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Sesuaikan domain dengan peer yang digunakan, file ini dapat dilihat dalam
|
||||||
|
# folder organizations
|
||||||
|
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/medorg.example.com/peers/peer0.medorg.example.com/tls/server.crt
|
||||||
|
export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/medorg.example.com/peers/peer0.medorg.example.com/tls/server.key
|
||||||
|
|
||||||
|
peer lifecycle chaincode package logVerification.tar.gz \
|
||||||
|
--path /opt/gopath/src/github.com/hyperledger/fabric/peer/chaincode/logVerification \
|
||||||
|
--lang golang \
|
||||||
|
--label logVerification_1.0
|
||||||
|
# Jika anda mengembangkan dan ingin mengubah versi chaincode supaya
|
||||||
|
# dapat mempermudah dalam hal version control, anda dapat mengubah labelnya
|
||||||
|
# Contoh, untuk pengembangan selanjutnya dapat menggunakan label berikut:
|
||||||
|
# --label logVerification_1.1
|
||||||
|
|
||||||
|
export CORE_PEER_ADDRESS=[ip_peer_atau_domain_peer_sesuai_konfigurasi]:[port_peer]
|
||||||
|
peer lifecycle chaincode install logVerification.tar.gz
|
||||||
|
|
||||||
|
# Install chaincode pada semua peer yang ada.
|
||||||
|
# Contoh, jika terdapat dua peer, maka jalankan export CORE_PEER_ADDRESS
|
||||||
|
# lagi dengan ip_peer untuk peer kedua.
|
||||||
|
export CORE_PEER_ADDRESS=[ip_peer_atau_domain_peer_kedua_sesuai_konfigurasi]:[port_peer]
|
||||||
|
peer lifecycle chaincode install logVerification.tar.gz
|
||||||
|
|
||||||
|
# Setelah anda menjalankan command peer lifecycle chaincode queryinstalled berikut
|
||||||
|
# maka akan muncul package_id chaincode anda, simpan id tersebut.
|
||||||
|
peer lifecycle chaincode queryinstalled
|
||||||
|
|
||||||
|
export NEW_CC_PACKAGE_ID=[isi_dari_output_command_peer_lifecycle_chaincode_queryinstalled]
|
||||||
|
|
||||||
|
peer lifecycle chaincode approveformyorg -o [ip_orderer_atau_domain_orderer_sesuai_konfigurasi]:[port_orderer] --channelID mychannel \
|
||||||
|
--name test-med --version [isi_dengan_versi_contoh_1.0] --package-id $CC_PACKAGE_ID --sequence [isi_dengan_sequence_ke_berapa_dan_sequence_harus_selalu_bertambah_sehingga_catat_selalu_sequence_ke_berapa] \
|
||||||
|
--tls --cafile "$ORDERER_CA"
|
||||||
|
|
||||||
|
# Command berikut berfungsi untuk melakukan commit chaincode.
|
||||||
|
# Perhatikan pada --peerAddressess, jika memiliki lebih dari satu peer
|
||||||
|
# sertakan juga dengan flag --peerAdressess dan format yang sesuai.
|
||||||
|
peer lifecycle chaincode commit -o [ip_orderer_atau_domain_orderer_sesuai_konfigurasi]:[port_orderer] --channelID mychannel \
|
||||||
|
--name test-med --version [isi_dengan_versi_contoh_1.0] --sequence [isi_dengan_sequence_ke_berapa_dan_sequence_harus_selalu_bertambah_sehingga_catat_selalu_sequence_ke_berapa]\
|
||||||
|
--collections-config /opt/gopath/src/github.com/hyperledger/fabric/peer/config/collections_config.json \
|
||||||
|
--tls --cafile "$ORDERER_CA" \
|
||||||
|
--peerAddresses [ip_peer_atau_domain_peer_sesuai_konfigurasi]:[port_peer] --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/medorg.example.com/peers/peer0.medorg.example.com/tls/ca.crt \
|
||||||
|
--peerAddresses [ip_peer_atau_domain_peer_sesuai_konfigurasi]:[port_peer] --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/medorg.example.com/peers/peer1.medorg.example.com/tls/ca.crt
|
||||||
|
```
|
||||||
|
|
||||||
|
15. Setelah blockchain berhasil di deploy, anda dapat menjalankan backend dan frontend. Panduan menjalankan backend dan front end dapat diakses pada masing-masing folder:
|
||||||
|
- [/backend](/backend/api/README.md)
|
||||||
|
- [/frontend](/frontend/hospital-log/README.md)
|
||||||
|
|
@ -1,22 +1,157 @@
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
|
import { AuthGuard } from './modules/auth/guard/auth.guard';
|
||||||
|
|
||||||
describe('AppController', () => {
|
describe('AppController', () => {
|
||||||
let appController: AppController;
|
let controller: AppController;
|
||||||
|
let mockAppService: {
|
||||||
|
getDashboard: jest.Mock;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockDashboardData = {
|
||||||
|
countRekamMedis: 100,
|
||||||
|
countTindakanDokter: 50,
|
||||||
|
countObat: 75,
|
||||||
|
auditTrailData: { tampered: 2, total: 100 },
|
||||||
|
validasiData: [{ id: 1, status: 'PENDING' }],
|
||||||
|
last7DaysRekamMedis: [
|
||||||
|
{ date: '2025-12-10', count: 10 },
|
||||||
|
{ date: '2025-12-09', count: 8 },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const app: TestingModule = await Test.createTestingModule({
|
mockAppService = {
|
||||||
controllers: [AppController],
|
getDashboard: jest.fn(),
|
||||||
providers: [AppService],
|
};
|
||||||
}).compile();
|
|
||||||
|
|
||||||
appController = app.get<AppController>(AppController);
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [AppController],
|
||||||
|
providers: [{ provide: AppService, useValue: mockAppService }],
|
||||||
|
})
|
||||||
|
.overrideGuard(AuthGuard)
|
||||||
|
.useValue({ canActivate: () => true })
|
||||||
|
.compile();
|
||||||
|
|
||||||
|
controller = module.get<AppController>(AppController);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('root', () => {
|
afterEach(() => {
|
||||||
it('should return "Hello World!"', () => {
|
jest.clearAllMocks();
|
||||||
expect(appController.getHello()).toBe('Hello World!');
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// getDashboard (GET /dashboard)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
describe('getDashboard', () => {
|
||||||
|
it('should return dashboard data from service', async () => {
|
||||||
|
mockAppService.getDashboard.mockResolvedValue(mockDashboardData);
|
||||||
|
|
||||||
|
const result = await controller.getDashboard();
|
||||||
|
|
||||||
|
expect(mockAppService.getDashboard).toHaveBeenCalledTimes(1);
|
||||||
|
expect(result).toEqual(mockDashboardData);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return all expected dashboard properties', async () => {
|
||||||
|
mockAppService.getDashboard.mockResolvedValue(mockDashboardData);
|
||||||
|
|
||||||
|
const result = await controller.getDashboard();
|
||||||
|
|
||||||
|
expect(result).toHaveProperty('countRekamMedis');
|
||||||
|
expect(result).toHaveProperty('countTindakanDokter');
|
||||||
|
expect(result).toHaveProperty('countObat');
|
||||||
|
expect(result).toHaveProperty('auditTrailData');
|
||||||
|
expect(result).toHaveProperty('validasiData');
|
||||||
|
expect(result).toHaveProperty('last7DaysRekamMedis');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle empty dashboard data', async () => {
|
||||||
|
const emptyData = {
|
||||||
|
countRekamMedis: 0,
|
||||||
|
countTindakanDokter: 0,
|
||||||
|
countObat: 0,
|
||||||
|
auditTrailData: { tampered: 0, total: 0 },
|
||||||
|
validasiData: [],
|
||||||
|
last7DaysRekamMedis: [],
|
||||||
|
};
|
||||||
|
mockAppService.getDashboard.mockResolvedValue(emptyData);
|
||||||
|
|
||||||
|
const result = await controller.getDashboard();
|
||||||
|
|
||||||
|
expect(result.countRekamMedis).toBe(0);
|
||||||
|
expect(result.validasiData).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should propagate service errors', async () => {
|
||||||
|
mockAppService.getDashboard.mockRejectedValue(
|
||||||
|
new Error('Database error'),
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(controller.getDashboard()).rejects.toThrow('Database error');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle service timeout', async () => {
|
||||||
|
mockAppService.getDashboard.mockRejectedValue(
|
||||||
|
new Error('Request timeout'),
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(controller.getDashboard()).rejects.toThrow(
|
||||||
|
'Request timeout',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Security Tests
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
describe('Security', () => {
|
||||||
|
it('getDashboard should have AuthGuard protection', () => {
|
||||||
|
const guards = Reflect.getMetadata(
|
||||||
|
'__guards__',
|
||||||
|
AppController.prototype.getDashboard,
|
||||||
|
);
|
||||||
|
expect(guards).toBeDefined();
|
||||||
|
expect(guards.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ISSUE: No RolesGuard - any authenticated user can access dashboard
|
||||||
|
it('ISSUE: getDashboard has no role restriction', () => {
|
||||||
|
// Any authenticated user can access dashboard data
|
||||||
|
// Consider if this should be restricted to Admin only
|
||||||
|
const roles = Reflect.getMetadata(
|
||||||
|
'roles',
|
||||||
|
AppController.prototype.getDashboard,
|
||||||
|
);
|
||||||
|
expect(roles).toBeUndefined(); // Documents missing role restriction
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* CODE ISSUES DOCUMENTATION
|
||||||
|
* ============================================================
|
||||||
|
*
|
||||||
|
* 1. ISSUE - No role-based access control:
|
||||||
|
* - getDashboard only uses AuthGuard
|
||||||
|
* - Any authenticated user can access sensitive dashboard data
|
||||||
|
* - Consider: Should regular users see tampered audit data counts?
|
||||||
|
* - Fix: Add @UseGuards(RolesGuard) and @Roles(UserRole.Admin) if needed
|
||||||
|
*
|
||||||
|
* 2. ISSUE - No error handling in controller:
|
||||||
|
* - Service errors propagate directly to client
|
||||||
|
* - No custom error messages or status codes
|
||||||
|
* - Consider: Wrap in try-catch for better error responses
|
||||||
|
*
|
||||||
|
* 3. SUGGESTION - Add caching:
|
||||||
|
* - Dashboard data is likely expensive to compute
|
||||||
|
* - Consider adding @CacheKey() and @CacheTTL() decorators
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,6 @@ import { AuthGuard } from './modules/auth/guard/auth.guard';
|
||||||
export class AppController {
|
export class AppController {
|
||||||
constructor(private readonly appService: AppService) {}
|
constructor(private readonly appService: AppService) {}
|
||||||
|
|
||||||
@Get()
|
|
||||||
getHello(): string {
|
|
||||||
return this.appService.getHello();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get('/dashboard')
|
@Get('/dashboard')
|
||||||
@UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
getDashboard() {
|
getDashboard() {
|
||||||
|
|
|
||||||
471
backend/api/src/app.service.spec.ts
Normal file
471
backend/api/src/app.service.spec.ts
Normal file
|
|
@ -0,0 +1,471 @@
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { AppService } from './app.service';
|
||||||
|
import { RekammedisService } from './modules/rekammedis/rekammedis.service';
|
||||||
|
import { TindakanDokterService } from './modules/tindakandokter/tindakandokter.service';
|
||||||
|
import { ObatService } from './modules/obat/obat.service';
|
||||||
|
import { AuditService } from './modules/audit/audit.service';
|
||||||
|
import { ValidationService } from './modules/validation/validation.service';
|
||||||
|
|
||||||
|
describe('AppService', () => {
|
||||||
|
let service: AppService;
|
||||||
|
let mockRekamMedisService: {
|
||||||
|
countRekamMedis: jest.Mock;
|
||||||
|
getLast7DaysCount: jest.Mock;
|
||||||
|
};
|
||||||
|
let mockTindakanDokterService: {
|
||||||
|
countTindakanDokter: jest.Mock;
|
||||||
|
};
|
||||||
|
let mockObatService: {
|
||||||
|
countObat: jest.Mock;
|
||||||
|
};
|
||||||
|
let mockAuditService: {
|
||||||
|
getCountAuditTamperedData: jest.Mock;
|
||||||
|
};
|
||||||
|
let mockValidationService: {
|
||||||
|
getAllValidationQueueDashboard: jest.Mock;
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
mockRekamMedisService = {
|
||||||
|
countRekamMedis: jest.fn(),
|
||||||
|
getLast7DaysCount: jest.fn(),
|
||||||
|
};
|
||||||
|
mockTindakanDokterService = {
|
||||||
|
countTindakanDokter: jest.fn(),
|
||||||
|
};
|
||||||
|
mockObatService = {
|
||||||
|
countObat: jest.fn(),
|
||||||
|
};
|
||||||
|
mockAuditService = {
|
||||||
|
getCountAuditTamperedData: jest.fn(),
|
||||||
|
};
|
||||||
|
mockValidationService = {
|
||||||
|
getAllValidationQueueDashboard: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
AppService,
|
||||||
|
{ provide: RekammedisService, useValue: mockRekamMedisService },
|
||||||
|
{ provide: TindakanDokterService, useValue: mockTindakanDokterService },
|
||||||
|
{ provide: ObatService, useValue: mockObatService },
|
||||||
|
{ provide: AuditService, useValue: mockAuditService },
|
||||||
|
{ provide: ValidationService, useValue: mockValidationService },
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<AppService>(AppService);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// getDashboard
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
describe('getDashboard', () => {
|
||||||
|
const mockCountRekamMedis = 100;
|
||||||
|
const mockCountTindakanDokter = 50;
|
||||||
|
const mockCountObat = 75;
|
||||||
|
const mockAuditTrailData = { tampered: 2, total: 100 };
|
||||||
|
const mockValidasiData = [
|
||||||
|
{ id: 1, status: 'PENDING', table_name: 'rekam_medis' },
|
||||||
|
{ id: 2, status: 'PENDING', table_name: 'pemberian_obat' },
|
||||||
|
];
|
||||||
|
const mockLast7DaysRekamMedis = [
|
||||||
|
{ date: '2025-12-10', count: 10 },
|
||||||
|
{ date: '2025-12-09', count: 8 },
|
||||||
|
{ date: '2025-12-08', count: 12 },
|
||||||
|
];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockRekamMedisService.countRekamMedis.mockResolvedValue(
|
||||||
|
mockCountRekamMedis,
|
||||||
|
);
|
||||||
|
mockTindakanDokterService.countTindakanDokter.mockResolvedValue(
|
||||||
|
mockCountTindakanDokter,
|
||||||
|
);
|
||||||
|
mockObatService.countObat.mockResolvedValue(mockCountObat);
|
||||||
|
mockAuditService.getCountAuditTamperedData.mockResolvedValue(
|
||||||
|
mockAuditTrailData,
|
||||||
|
);
|
||||||
|
mockValidationService.getAllValidationQueueDashboard.mockResolvedValue(
|
||||||
|
mockValidasiData,
|
||||||
|
);
|
||||||
|
mockRekamMedisService.getLast7DaysCount.mockResolvedValue(
|
||||||
|
mockLast7DaysRekamMedis,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call all required services', async () => {
|
||||||
|
await service.getDashboard();
|
||||||
|
|
||||||
|
expect(mockRekamMedisService.countRekamMedis).toHaveBeenCalledTimes(1);
|
||||||
|
expect(
|
||||||
|
mockTindakanDokterService.countTindakanDokter,
|
||||||
|
).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockObatService.countObat).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockAuditService.getCountAuditTamperedData).toHaveBeenCalledTimes(
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
mockValidationService.getAllValidationQueueDashboard,
|
||||||
|
).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockRekamMedisService.getLast7DaysCount).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return complete dashboard data structure', async () => {
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
countRekamMedis: mockCountRekamMedis,
|
||||||
|
countTindakanDokter: mockCountTindakanDokter,
|
||||||
|
countObat: mockCountObat,
|
||||||
|
auditTrailData: mockAuditTrailData,
|
||||||
|
validasiData: mockValidasiData,
|
||||||
|
last7DaysRekamMedis: mockLast7DaysRekamMedis,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return countRekamMedis from rekamMedisService', async () => {
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
expect(result.countRekamMedis).toBe(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return countTindakanDokter from tindakanDokterService', async () => {
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
expect(result.countTindakanDokter).toBe(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return countObat from obatService', async () => {
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
expect(result.countObat).toBe(75);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return auditTrailData from auditService', async () => {
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
expect(result.auditTrailData).toEqual({ tampered: 2, total: 100 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return validasiData from validationService', async () => {
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
expect(result.validasiData).toEqual(mockValidasiData);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return last7DaysRekamMedis from rekamMedisService', async () => {
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
expect(result.last7DaysRekamMedis).toEqual(mockLast7DaysRekamMedis);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Zero/Empty Values
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
describe('Zero/Empty Values', () => {
|
||||||
|
it('should handle zero counts', async () => {
|
||||||
|
mockRekamMedisService.countRekamMedis.mockResolvedValue(0);
|
||||||
|
mockTindakanDokterService.countTindakanDokter.mockResolvedValue(0);
|
||||||
|
mockObatService.countObat.mockResolvedValue(0);
|
||||||
|
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
expect(result.countRekamMedis).toBe(0);
|
||||||
|
expect(result.countTindakanDokter).toBe(0);
|
||||||
|
expect(result.countObat).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle empty validasiData array', async () => {
|
||||||
|
mockValidationService.getAllValidationQueueDashboard.mockResolvedValue(
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
expect(result.validasiData).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle empty last7DaysRekamMedis array', async () => {
|
||||||
|
mockRekamMedisService.getLast7DaysCount.mockResolvedValue([]);
|
||||||
|
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
expect(result.last7DaysRekamMedis).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle zero tampered data', async () => {
|
||||||
|
mockAuditService.getCountAuditTamperedData.mockResolvedValue({
|
||||||
|
tampered: 0,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
expect(result.auditTrailData).toEqual({ tampered: 0, total: 0 });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Large Values
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
describe('Large Values', () => {
|
||||||
|
it('should handle large counts', async () => {
|
||||||
|
mockRekamMedisService.countRekamMedis.mockResolvedValue(1000000);
|
||||||
|
mockTindakanDokterService.countTindakanDokter.mockResolvedValue(500000);
|
||||||
|
mockObatService.countObat.mockResolvedValue(750000);
|
||||||
|
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
expect(result.countRekamMedis).toBe(1000000);
|
||||||
|
expect(result.countTindakanDokter).toBe(500000);
|
||||||
|
expect(result.countObat).toBe(750000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle many validation items', async () => {
|
||||||
|
const manyItems = Array.from({ length: 100 }, (_, i) => ({
|
||||||
|
id: i + 1,
|
||||||
|
status: 'PENDING',
|
||||||
|
}));
|
||||||
|
mockValidationService.getAllValidationQueueDashboard.mockResolvedValue({
|
||||||
|
data: manyItems,
|
||||||
|
totalCount: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
expect(result.validasiData.totalCount).toBe(100);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Error Handling - ISSUES DOCUMENTED
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
describe('Error Handling', () => {
|
||||||
|
// ISSUE: No error handling - any service error propagates directly
|
||||||
|
it('ISSUE: rekamMedisService.countRekamMedis error propagates unhandled', async () => {
|
||||||
|
mockRekamMedisService.countRekamMedis.mockRejectedValue(
|
||||||
|
new Error('Database connection failed'),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Error propagates directly - no graceful handling
|
||||||
|
await expect(service.getDashboard()).rejects.toThrow(
|
||||||
|
'Database connection failed',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ISSUE: tindakanDokterService.countTindakanDokter error propagates unhandled', async () => {
|
||||||
|
mockTindakanDokterService.countTindakanDokter.mockRejectedValue(
|
||||||
|
new Error('Query timeout'),
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(service.getDashboard()).rejects.toThrow('Query timeout');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ISSUE: obatService.countObat error propagates unhandled', async () => {
|
||||||
|
mockObatService.countObat.mockRejectedValue(
|
||||||
|
new Error('Service unavailable'),
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(service.getDashboard()).rejects.toThrow(
|
||||||
|
'Service unavailable',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ISSUE: auditService.getCountAuditTamperedData error propagates unhandled', async () => {
|
||||||
|
mockAuditService.getCountAuditTamperedData.mockRejectedValue(
|
||||||
|
new Error('Audit service error'),
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(service.getDashboard()).rejects.toThrow(
|
||||||
|
'Audit service error',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ISSUE: validationService.getAllValidationQueueDashboard error propagates unhandled', async () => {
|
||||||
|
mockValidationService.getAllValidationQueueDashboard.mockRejectedValue(
|
||||||
|
new Error('Validation service error'),
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(service.getDashboard()).rejects.toThrow(
|
||||||
|
'Validation service error',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ISSUE: rekamMedisService.getLast7DaysCount error propagates unhandled', async () => {
|
||||||
|
mockRekamMedisService.getLast7DaysCount.mockRejectedValue(
|
||||||
|
new Error('Date range query failed'),
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(service.getDashboard()).rejects.toThrow(
|
||||||
|
'Date range query failed',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Null/Undefined Values - ISSUES DOCUMENTED
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
describe('Null/Undefined Values', () => {
|
||||||
|
// ISSUE: No null checks - service returns whatever dependencies return
|
||||||
|
it('ISSUE: returns null countRekamMedis without validation', async () => {
|
||||||
|
mockRekamMedisService.countRekamMedis.mockResolvedValue(null);
|
||||||
|
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
// No validation - null is returned directly
|
||||||
|
expect(result.countRekamMedis).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ISSUE: returns undefined countTindakanDokter without validation', async () => {
|
||||||
|
mockTindakanDokterService.countTindakanDokter.mockResolvedValue(
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
// No validation - undefined is returned directly
|
||||||
|
expect(result.countTindakanDokter).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ISSUE: returns null validasiData without validation', async () => {
|
||||||
|
mockValidationService.getAllValidationQueueDashboard.mockResolvedValue(
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
// No validation - null is returned directly
|
||||||
|
expect(result.validasiData).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ISSUE: returns null auditTrailData without validation', async () => {
|
||||||
|
mockAuditService.getCountAuditTamperedData.mockResolvedValue(null);
|
||||||
|
|
||||||
|
const result = await service.getDashboard();
|
||||||
|
|
||||||
|
// No validation - null is returned directly
|
||||||
|
expect(result.auditTrailData).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Performance - Sequential vs Parallel
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
describe('Performance', () => {
|
||||||
|
// ISSUE: All service calls are sequential (await one by one)
|
||||||
|
// This is inefficient - they could run in parallel with Promise.all
|
||||||
|
it('ISSUE: service calls are sequential instead of parallel', async () => {
|
||||||
|
const callOrder: string[] = [];
|
||||||
|
|
||||||
|
mockRekamMedisService.countRekamMedis.mockImplementation(async () => {
|
||||||
|
callOrder.push('countRekamMedis');
|
||||||
|
return 100;
|
||||||
|
});
|
||||||
|
mockTindakanDokterService.countTindakanDokter.mockImplementation(
|
||||||
|
async () => {
|
||||||
|
callOrder.push('countTindakanDokter');
|
||||||
|
return 50;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
mockObatService.countObat.mockImplementation(async () => {
|
||||||
|
callOrder.push('countObat');
|
||||||
|
return 75;
|
||||||
|
});
|
||||||
|
mockAuditService.getCountAuditTamperedData.mockImplementation(
|
||||||
|
async () => {
|
||||||
|
callOrder.push('auditTrailData');
|
||||||
|
return { tampered: 0, total: 0 };
|
||||||
|
},
|
||||||
|
);
|
||||||
|
mockValidationService.getAllValidationQueueDashboard.mockImplementation(
|
||||||
|
async () => {
|
||||||
|
callOrder.push('validasiData');
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
);
|
||||||
|
mockRekamMedisService.getLast7DaysCount.mockImplementation(async () => {
|
||||||
|
callOrder.push('last7DaysRekamMedis');
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
await service.getDashboard();
|
||||||
|
|
||||||
|
// Documents that calls happen sequentially in specific order
|
||||||
|
expect(callOrder).toEqual([
|
||||||
|
'countRekamMedis',
|
||||||
|
'countTindakanDokter',
|
||||||
|
'countObat',
|
||||||
|
'auditTrailData',
|
||||||
|
'validasiData',
|
||||||
|
'last7DaysRekamMedis',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============================================================
|
||||||
|
* CODE ISSUES DOCUMENTATION
|
||||||
|
* ============================================================
|
||||||
|
*
|
||||||
|
* 1. ISSUE - No error handling:
|
||||||
|
* - Any service error propagates directly to the controller
|
||||||
|
* - No try-catch, no graceful degradation
|
||||||
|
* - Fix: Wrap in try-catch, return partial data or default values
|
||||||
|
*
|
||||||
|
* 2. ISSUE - No null/undefined validation:
|
||||||
|
* - Service returns whatever dependencies return
|
||||||
|
* - If any dependency returns null, dashboard has null values
|
||||||
|
* - Fix: Add null coalescing (value ?? defaultValue)
|
||||||
|
*
|
||||||
|
* 3. PERFORMANCE - Sequential service calls:
|
||||||
|
* - All 6 service calls are awaited sequentially
|
||||||
|
* - If each takes 100ms, total = 600ms
|
||||||
|
* - Fix: Use Promise.all() for parallel execution
|
||||||
|
*
|
||||||
|
* Example fix:
|
||||||
|
* ```typescript
|
||||||
|
* async getDashboard() {
|
||||||
|
* const [
|
||||||
|
* countRekamMedis,
|
||||||
|
* countTindakanDokter,
|
||||||
|
* countObat,
|
||||||
|
* auditTrailData,
|
||||||
|
* validasiData,
|
||||||
|
* last7DaysRekamMedis,
|
||||||
|
* ] = await Promise.all([
|
||||||
|
* this.rekamMedisService.countRekamMedis(),
|
||||||
|
* this.tindakanDokterService.countTindakanDokter(),
|
||||||
|
* this.obatService.countObat(),
|
||||||
|
* this.auditService.getCountAuditTamperedData(),
|
||||||
|
* this.validationService.getAllValidationQueueDashboard(),
|
||||||
|
* this.rekamMedisService.getLast7DaysCount(),
|
||||||
|
* ]);
|
||||||
|
* return { ... };
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* 4. SUGGESTION - Add response DTO:
|
||||||
|
* - No type safety on return value
|
||||||
|
* - Consider creating DashboardResponseDto
|
||||||
|
*
|
||||||
|
* 5. SUGGESTION - Add caching:
|
||||||
|
* - Dashboard data is expensive to compute
|
||||||
|
* - Consider caching with a short TTL (e.g., 30 seconds)
|
||||||
|
*/
|
||||||
|
|
@ -1,28 +1,20 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { PrismaService } from './modules/prisma/prisma.service';
|
|
||||||
import { TindakanDokterService } from './modules/tindakandokter/tindakandokter.service';
|
import { TindakanDokterService } from './modules/tindakandokter/tindakandokter.service';
|
||||||
import { RekammedisService } from './modules/rekammedis/rekammedis.service';
|
import { RekammedisService } from './modules/rekammedis/rekammedis.service';
|
||||||
import { ObatService } from './modules/obat/obat.service';
|
import { ObatService } from './modules/obat/obat.service';
|
||||||
import { LogService } from './modules/log/log.service';
|
|
||||||
import { AuditService } from './modules/audit/audit.service';
|
import { AuditService } from './modules/audit/audit.service';
|
||||||
import { ValidationService } from './modules/validation/validation.service';
|
import { ValidationService } from './modules/validation/validation.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AppService {
|
export class AppService {
|
||||||
constructor(
|
constructor(
|
||||||
private prisma: PrismaService,
|
|
||||||
private rekamMedisService: RekammedisService,
|
private rekamMedisService: RekammedisService,
|
||||||
private tindakanDokterService: TindakanDokterService,
|
private tindakanDokterService: TindakanDokterService,
|
||||||
private obatService: ObatService,
|
private obatService: ObatService,
|
||||||
private logService: LogService,
|
|
||||||
private auditService: AuditService,
|
private auditService: AuditService,
|
||||||
private validationService: ValidationService,
|
private validationService: ValidationService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getHello(): string {
|
|
||||||
return 'Hello World!';
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDashboard() {
|
async getDashboard() {
|
||||||
const countRekamMedis = await this.rekamMedisService.countRekamMedis();
|
const countRekamMedis = await this.rekamMedisService.countRekamMedis();
|
||||||
const countTindakanDokter =
|
const countTindakanDokter =
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ async function bootstrap() {
|
||||||
'http://localhost:5173',
|
'http://localhost:5173',
|
||||||
'http://localhost:5174',
|
'http://localhost:5174',
|
||||||
'http://localhost:5175',
|
'http://localhost:5175',
|
||||||
|
'http://localhost:5176',
|
||||||
],
|
],
|
||||||
credentials: true,
|
credentials: true,
|
||||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
|
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
|
||||||
|
|
|
||||||
1
backend/blockchain/.gitignore
vendored
1
backend/blockchain/.gitignore
vendored
|
|
@ -2,3 +2,4 @@ node_modules/*
|
||||||
network/channel-artifacts/
|
network/channel-artifacts/
|
||||||
network/organizations/
|
network/organizations/
|
||||||
backup/*
|
backup/*
|
||||||
|
.env
|
||||||
23
backend/blockchain/chaincode/README.md
Normal file
23
backend/blockchain/chaincode/README.md
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Dokumentasi mengenai Smartcontract.
|
||||||
|
|
||||||
|
Smartcontract, atau dalam Fabric disebut chaincode ini dikembangkan menggunakan bahasa pemrograman Javascript. Dalam folder [logVerification](/backend/blockchain/chaincode/logVerification/), <i>source file</i> mengenai smartcontract dapat dilihat pada folder [logVerification](logVerification/). File [index.js](logVerification/index.js) berisi smartcontract yang memuat logika bisnis dalam sistem yang dikembangkan.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pengembangan pada smartcontract
|
||||||
|
|
||||||
|
### Prasyarat
|
||||||
|
|
||||||
|
- NodeJs (v20 atau lebih tinggi)
|
||||||
|
- Hyperledger Fabric samples dan binary (v2.5.13)
|
||||||
|
|
||||||
|
### Langkah pengembangan
|
||||||
|
|
||||||
|
1. Pastikan NodeJs dan Fabric samples dan binary sudah terinstall.
|
||||||
|
2. Jalankan command berikut:
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
3. Lakukan pengembangan
|
||||||
|
4. Untuk menjalankan hasil pengembangan, pastikan anda sudah melakukan mulai dari langkah ke-4 hingga ke-8 dalam [README.md](/README.md) pada root project.
|
||||||
|
5. Kemudian lakukan deploy chaincode ke dalam channel seperti pada langkah ke-9 dalam [README.md](/README.md) pada root project.
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
"fabric-contract-api": "^2.5.8",
|
"fabric-contract-api": "^2.5.8",
|
||||||
"fabric-shim": "^2.5.8",
|
"fabric-shim": "^2.5.8",
|
||||||
"json-stringify-deterministic": "^1.0.0",
|
"json-stringify-deterministic": "^1.0.0",
|
||||||
|
"snarkjs": "^0.7.5",
|
||||||
"sort-keys-recursive": "^2.1.0"
|
"sort-keys-recursive": "^2.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
@ -515,6 +516,22 @@
|
||||||
"node": ">=16.13.0"
|
"node": ">=16.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@iden3/bigarray": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iden3/bigarray/-/bigarray-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-Xzdyxqm1bOFF6pdIsiHLLl3HkSLjbhqJHVyqaTxXt3RqXBEnmsUmEW47H7VOi/ak7TdkRpNkxjyK5Zbkm+y52g==",
|
||||||
|
"license": "GPL-3.0"
|
||||||
|
},
|
||||||
|
"node_modules/@iden3/binfileutils": {
|
||||||
|
"version": "0.0.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iden3/binfileutils/-/binfileutils-0.0.12.tgz",
|
||||||
|
"integrity": "sha512-naAmzuDufRIcoNfQ1d99d7hGHufLA3wZSibtr4dMe6ZeiOPV1KwOZWTJ1YVz4HbaWlpDuzVU72dS4ATQS4PXBQ==",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"dependencies": {
|
||||||
|
"fastfile": "0.0.20",
|
||||||
|
"ffjavascript": "^0.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@istanbuljs/load-nyc-config": {
|
"node_modules/@istanbuljs/load-nyc-config": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
|
||||||
|
|
@ -969,15 +986,45 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/async": {
|
"node_modules/async": {
|
||||||
"version": "3.2.5",
|
"version": "3.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
|
||||||
"integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg=="
|
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/b4a": {
|
||||||
|
"version": "1.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz",
|
||||||
|
"integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-native-b4a": "*"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"react-native-b4a": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||||
"dev": true
|
},
|
||||||
|
"node_modules/bfj": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bfj/-/bfj-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-I6MMLkn+anzNdCUp9hMRyui1HaNEUCco50lxbvNS4+EyXg8lN3nJ48PjPWtbH8UVS9CuMoaKE9U2V3l29DaRQw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"bluebird": "^3.7.2",
|
||||||
|
"check-types": "^11.2.3",
|
||||||
|
"hoopy": "^0.1.4",
|
||||||
|
"jsonpath": "^1.1.1",
|
||||||
|
"tryer": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/binary-extensions": {
|
"node_modules/binary-extensions": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
|
|
@ -991,6 +1038,22 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/blake2b-wasm": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"b4a": "^1.0.1",
|
||||||
|
"nanoassert": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bluebird": {
|
||||||
|
"version": "3.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
||||||
|
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.12",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||||
|
|
@ -1151,6 +1214,12 @@
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/check-types": {
|
||||||
|
"version": "11.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz",
|
||||||
|
"integrity": "sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/chokidar": {
|
"node_modules/chokidar": {
|
||||||
"version": "3.5.3",
|
"version": "3.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||||
|
|
@ -1190,6 +1259,18 @@
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/circom_runtime": {
|
||||||
|
"version": "0.1.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.1.28.tgz",
|
||||||
|
"integrity": "sha512-ACagpQ7zBRLKDl5xRZ4KpmYIcZDUjOiNRuxvXLqhnnlLSVY1Dbvh73TI853nqoR0oEbihtWmMSjgc5f+pXf/jQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"ffjavascript": "0.3.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"calcwit": "calcwit.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/class-transformer": {
|
"node_modules/class-transformer": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz",
|
||||||
|
|
@ -1348,8 +1429,7 @@
|
||||||
"node_modules/deep-is": {
|
"node_modules/deep-is": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||||
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
|
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/default-require-extensions": {
|
"node_modules/default-require-extensions": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
|
|
@ -1388,6 +1468,21 @@
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ejs": {
|
||||||
|
"version": "3.1.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
|
||||||
|
"integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"jake": "^10.8.5"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"ejs": "bin/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.802",
|
"version": "1.4.802",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.802.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.802.tgz",
|
||||||
|
|
@ -1430,6 +1525,87 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/escodegen": {
|
||||||
|
"version": "1.14.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
|
||||||
|
"integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"esprima": "^4.0.1",
|
||||||
|
"estraverse": "^4.2.0",
|
||||||
|
"esutils": "^2.0.2",
|
||||||
|
"optionator": "^0.8.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"escodegen": "bin/escodegen.js",
|
||||||
|
"esgenerate": "bin/esgenerate.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"source-map": "~0.6.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/escodegen/node_modules/estraverse": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/escodegen/node_modules/levn": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
|
||||||
|
"integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"prelude-ls": "~1.1.2",
|
||||||
|
"type-check": "~0.3.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/escodegen/node_modules/optionator": {
|
||||||
|
"version": "0.8.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
|
||||||
|
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"deep-is": "~0.1.3",
|
||||||
|
"fast-levenshtein": "~2.0.6",
|
||||||
|
"levn": "~0.3.0",
|
||||||
|
"prelude-ls": "~1.1.2",
|
||||||
|
"type-check": "~0.3.2",
|
||||||
|
"word-wrap": "~1.2.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/escodegen/node_modules/prelude-ls": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/escodegen/node_modules/type-check": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"prelude-ls": "~1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "8.57.0",
|
"version": "8.57.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
|
||||||
|
|
@ -1534,7 +1710,6 @@
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||||
"dev": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"esparse": "bin/esparse.js",
|
"esparse": "bin/esparse.js",
|
||||||
"esvalidate": "bin/esvalidate.js"
|
"esvalidate": "bin/esvalidate.js"
|
||||||
|
|
@ -1580,7 +1755,6 @@
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
|
|
@ -1652,14 +1826,19 @@
|
||||||
"node_modules/fast-levenshtein": {
|
"node_modules/fast-levenshtein": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
||||||
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
|
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/fast-safe-stringify": {
|
"node_modules/fast-safe-stringify": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
|
||||||
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
|
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/fastfile": {
|
||||||
|
"version": "0.0.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.20.tgz",
|
||||||
|
"integrity": "sha512-r5ZDbgImvVWCP0lA/cGNgQcZqR+aYdFx3u+CtJqUE510pBUVGMn4ulL/iRTI4tACTYsNJ736uzFxEBXesPAktA==",
|
||||||
|
"license": "GPL-3.0"
|
||||||
|
},
|
||||||
"node_modules/fastq": {
|
"node_modules/fastq": {
|
||||||
"version": "1.17.1",
|
"version": "1.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
|
||||||
|
|
@ -1674,6 +1853,17 @@
|
||||||
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
|
||||||
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
|
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/ffjavascript": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.3.1.tgz",
|
||||||
|
"integrity": "sha512-4PbK1WYodQtuF47D4pRI5KUg3Q392vuP5WjE1THSnceHdXwU3ijaoS0OqxTzLknCtz4Z2TtABzkBdBdMn3B/Aw==",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"dependencies": {
|
||||||
|
"wasmbuilder": "0.0.16",
|
||||||
|
"wasmcurves": "0.2.2",
|
||||||
|
"web-worker": "1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/file-entry-cache": {
|
"node_modules/file-entry-cache": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||||
|
|
@ -1686,6 +1876,36 @@
|
||||||
"node": "^10.12.0 || >=12.0.0"
|
"node": "^10.12.0 || >=12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/filelist": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"minimatch": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/filelist/node_modules/brace-expansion": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"balanced-match": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/filelist/node_modules/minimatch": {
|
||||||
|
"version": "5.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||||
|
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"brace-expansion": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
|
|
@ -1988,6 +2208,15 @@
|
||||||
"he": "bin/he"
|
"he": "bin/he"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/hoopy": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/html-escaper": {
|
"node_modules/html-escaper": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
|
||||||
|
|
@ -2290,6 +2519,29 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jake": {
|
||||||
|
"version": "10.9.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz",
|
||||||
|
"integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"async": "^3.2.6",
|
||||||
|
"filelist": "^1.0.4",
|
||||||
|
"picocolors": "^1.1.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"jake": "bin/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/js-sha3": {
|
||||||
|
"version": "0.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
|
||||||
|
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/js-tokens": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
|
@ -2358,6 +2610,29 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jsonpath": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"esprima": "1.2.2",
|
||||||
|
"static-eval": "2.0.2",
|
||||||
|
"underscore": "1.12.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jsonpath/node_modules/esprima": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==",
|
||||||
|
"bin": {
|
||||||
|
"esparse": "bin/esparse.js",
|
||||||
|
"esvalidate": "bin/esvalidate.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/just-extend": {
|
"node_modules/just-extend": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz",
|
||||||
|
|
@ -2470,6 +2745,12 @@
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/logplease": {
|
||||||
|
"version": "1.2.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/logplease/-/logplease-1.2.15.tgz",
|
||||||
|
"integrity": "sha512-jLlHnlsPSJjpwUfcNyUxXCl33AYg2cHhIf9QhGL2T4iPT0XPB+xP1LRKFPgIg1M/sg9kAJvy94w9CzBNrfnstA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/long": {
|
"node_modules/long": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
||||||
|
|
@ -2645,6 +2926,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
},
|
},
|
||||||
|
"node_modules/nanoassert": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/natural-compare": {
|
"node_modules/natural-compare": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||||
|
|
@ -3039,7 +3326,6 @@
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||||
"dev": true,
|
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
|
|
@ -3191,6 +3477,29 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/r1csfile": {
|
||||||
|
"version": "0.0.48",
|
||||||
|
"resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.48.tgz",
|
||||||
|
"integrity": "sha512-kHRkKUJNaor31l05f2+RFzvcH5XSa7OfEfd/l4hzjte6NL6fjRkSMfZ4BjySW9wmfdwPOtq3mXurzPvPGEf5Tw==",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@iden3/bigarray": "0.0.2",
|
||||||
|
"@iden3/binfileutils": "0.0.12",
|
||||||
|
"fastfile": "0.0.20",
|
||||||
|
"ffjavascript": "0.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/r1csfile/node_modules/ffjavascript": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.3.0.tgz",
|
||||||
|
"integrity": "sha512-l7sR5kmU3gRwDy8g0Z2tYBXy5ttmafRPFOqY7S6af5cq51JqJWt5eQ/lSR/rs2wQNbDYaYlQr5O+OSUf/oMLoQ==",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"dependencies": {
|
||||||
|
"wasmbuilder": "0.0.16",
|
||||||
|
"wasmcurves": "0.2.2",
|
||||||
|
"web-worker": "1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/randombytes": {
|
"node_modules/randombytes": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
|
|
@ -3451,6 +3760,27 @@
|
||||||
"sinon": ">=4.0.0"
|
"sinon": ">=4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/snarkjs": {
|
||||||
|
"version": "0.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.7.5.tgz",
|
||||||
|
"integrity": "sha512-h+3c4rXZKLhLuHk4LHydZCk/h5GcNvk5GjVKRRkHmfb6Ntf8gHOA9zea3g656iclRuhqQ3iKDWFgiD9ypLrKiA==",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@iden3/binfileutils": "0.0.12",
|
||||||
|
"bfj": "^7.0.2",
|
||||||
|
"blake2b-wasm": "^2.4.0",
|
||||||
|
"circom_runtime": "0.1.28",
|
||||||
|
"ejs": "^3.1.6",
|
||||||
|
"fastfile": "0.0.20",
|
||||||
|
"ffjavascript": "0.3.1",
|
||||||
|
"js-sha3": "^0.8.0",
|
||||||
|
"logplease": "^1.2.15",
|
||||||
|
"r1csfile": "0.0.48"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"snarkjs": "build/cli.cjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sort-keys": {
|
"node_modules/sort-keys": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz",
|
||||||
|
|
@ -3481,7 +3811,7 @@
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
|
|
@ -3517,6 +3847,15 @@
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/static-eval": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"escodegen": "^1.8.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/string_decoder": {
|
"node_modules/string_decoder": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
|
@ -3648,6 +3987,12 @@
|
||||||
"node": ">= 14.0.0"
|
"node": ">= 14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tryer": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/tweetnacl": {
|
"node_modules/tweetnacl": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||||
|
|
@ -3695,6 +4040,12 @@
|
||||||
"is-typedarray": "^1.0.0"
|
"is-typedarray": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/underscore": {
|
||||||
|
"version": "1.12.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz",
|
||||||
|
"integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.0.16",
|
"version": "1.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz",
|
||||||
|
|
@ -3747,6 +4098,27 @@
|
||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/wasmbuilder": {
|
||||||
|
"version": "0.0.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.16.tgz",
|
||||||
|
"integrity": "sha512-Qx3lEFqaVvp1cEYW7Bfi+ebRJrOiwz2Ieu7ZG2l7YyeSJIok/reEQCQCuicj/Y32ITIJuGIM9xZQppGx5LrQdA==",
|
||||||
|
"license": "GPL-3.0"
|
||||||
|
},
|
||||||
|
"node_modules/wasmcurves": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-JRY908NkmKjFl4ytnTu5ED6AwPD+8VJ9oc94kdq7h5bIwbj0L4TDJ69mG+2aLs2SoCmGfqIesMWTEJjtYsoQXQ==",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"dependencies": {
|
||||||
|
"wasmbuilder": "0.0.16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/web-worker": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
@ -3806,7 +4178,6 @@
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
||||||
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
|
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
"fabric-contract-api": "^2.5.8",
|
"fabric-contract-api": "^2.5.8",
|
||||||
"fabric-shim": "^2.5.8",
|
"fabric-shim": "^2.5.8",
|
||||||
"json-stringify-deterministic": "^1.0.0",
|
"json-stringify-deterministic": "^1.0.0",
|
||||||
|
"snarkjs": "^0.7.5",
|
||||||
"sort-keys-recursive": "^2.1.0"
|
"sort-keys-recursive": "^2.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
43
backend/blockchain/network/README.md
Normal file
43
backend/blockchain/network/README.md
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
# Konfigurasi Jaringan untuk Blockchain Rekam Medis
|
||||||
|
|
||||||
|
Direktori ini berisi file konfigurasi jaringan untuk jaringan blockchain Hyperledger Fabric yang digunakan dalam sistem rekam medis.
|
||||||
|
|
||||||
|
## Struktur Direktori
|
||||||
|
|
||||||
|
- \*`organizations/` - Berisi material kripto dan sertifikat untuk organisasi dalam jaringan
|
||||||
|
- \*`channel-artifacts/` - Berisi artefak channel seperti genesis block dan transaksi
|
||||||
|
- `docker/` - File Docker compose untuk konfigurasi deployment jaringan
|
||||||
|
- `config/` - File konfigurasi jaringan
|
||||||
|
|
||||||
|
**\*Jika sudah menjalankan generate artifact**
|
||||||
|
|
||||||
|
## Prasyarat
|
||||||
|
|
||||||
|
- Git
|
||||||
|
- WSL2 (jika menjalankan melalui sistem operasi Windows)
|
||||||
|
- Docker dan Docker Compose
|
||||||
|
- Hyperledger Fabric samples dan binary (v2.5.13)
|
||||||
|
|
||||||
|
## Petunjuk Instalasi dan Konfigurasi
|
||||||
|
|
||||||
|
1. Pastikan anda telah menginstal Docker, Docker Compose, dan [Hyperledger Fabric](https://hyperledger-fabric.readthedocs.io/en/release-2.5/install.html).
|
||||||
|
2. Sebelum membuat artefak jaringan, sesuaikan topologi jaringan dengan kebutuhan. Hal ini terkait dengan:
|
||||||
|
- Jumlah Peer dan Orderer: edit file [network/config/crypto-config.yaml](config/crypto-config.yaml) untuk mengubah jumlah Peer atau Orderer yang akan dibuat.
|
||||||
|
- Channel: edit file [network/config/configtx.yaml](config/configtx.yaml) untuk menyesuaikan profil channel atau menambahkan organisasi baru.
|
||||||
|
3. Jalankan skrip `generate-artifacts.sh` pada folder [blockchain](/backend/blockchain/) untuk menghasilkan artefak jaringan:
|
||||||
|
```bash
|
||||||
|
./generate-artifacts.sh
|
||||||
|
```
|
||||||
|
4. Skrip di atas akan menghasilkan artefak jaringan yang diperlukan, termasuk material kripto dan sertifikat untuk organisasi. Hasilnya adalah dua folder sebagai berikut:
|
||||||
|
- `organizations/` - Berisi material kripto untuk organisasi
|
||||||
|
- `channel-artifacts/` - Berisi artefak channel seperti genesis block dan transaksi
|
||||||
|
5. Jika menjalankan node pada beberapa VM yang berbeda, distribusikan artefak jaringan yang telah dibuat.
|
||||||
|
- Arsipkan artefak jaringan dengan menjalankan command
|
||||||
|
```bash
|
||||||
|
tar -czvf artifacts.tar.gz ./network/organizations ./network/channel-artifacts
|
||||||
|
```
|
||||||
|
- Setelah didistribusikan pada VM yang lain, ekstrak arsip tersebut.
|
||||||
|
6. Selanjutnya adalah melakukan konfigurasi environment yang akan digunakan oleh sistem ini. Anda dapat menduplikat file `.env.example` yang berada dalam directory [docker](docker/) menjadi `.env` dan mengedit sesuai dengan petunjuk yang ada dalam file .env tersebut.
|
||||||
|
7. Sesuaikan isi dari [docker-compose-swarm.yaml](docker/docker-compose-swarm.yaml) dengan konfigurasi node milik anda.
|
||||||
|
8. Ubah isi dari masing-masing file konfigurasi kontainer docker sesuai petunjuk dalam file tersebut.
|
||||||
|
9. Setelah selesai, lanjut menuju direktori [chaincode](/backend/blockchain/chaincode/) jika ingin melakukan pengembangan terkait dengan chaincode/smartcontract.
|
||||||
3
backend/blockchain/network/docker/.env.example
Normal file
3
backend/blockchain/network/docker/.env.example
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# POSTGRES_PASSWORD=password
|
||||||
|
# JWT_SECRET_KEY=masukkan_jwt_secret_dengan_format_SHA256
|
||||||
|
# ENCRYPTION_KEY=masukkan_key_32byte
|
||||||
|
|
@ -42,6 +42,7 @@ services:
|
||||||
deploy:
|
deploy:
|
||||||
placement:
|
placement:
|
||||||
constraints:
|
constraints:
|
||||||
|
# Pastikan label sesuai dengan yang ada dalam node swarm
|
||||||
- node.labels.lokasi == pc-kiri
|
- node.labels.lokasi == pc-kiri
|
||||||
|
|
||||||
peer0:
|
peer0:
|
||||||
|
|
@ -75,6 +76,7 @@ services:
|
||||||
deploy:
|
deploy:
|
||||||
placement:
|
placement:
|
||||||
constraints:
|
constraints:
|
||||||
|
# Pastikan label sesuai dengan yang ada dalam node swarm
|
||||||
- node.labels.lokasi == pc-kiri
|
- node.labels.lokasi == pc-kiri
|
||||||
|
|
||||||
cli:
|
cli:
|
||||||
|
|
@ -98,6 +100,7 @@ services:
|
||||||
- /home/labai1/josafat/hospital-log/backend/blockchain/network/organizations:/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations
|
- /home/labai1/josafat/hospital-log/backend/blockchain/network/organizations:/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations
|
||||||
- /home/labai1/josafat/hospital-log/backend/blockchain/network/channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
|
- /home/labai1/josafat/hospital-log/backend/blockchain/network/channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
|
# Pastikan IP sesuai dengan node swarm
|
||||||
- "peer1.hospital.com:192.168.11.94"
|
- "peer1.hospital.com:192.168.11.94"
|
||||||
- "peer2.hospital.com:192.168.11.63"
|
- "peer2.hospital.com:192.168.11.63"
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|
@ -108,6 +111,7 @@ services:
|
||||||
deploy:
|
deploy:
|
||||||
placement:
|
placement:
|
||||||
constraints:
|
constraints:
|
||||||
|
# Pastikan label sesuai dengan yang ada dalam node swarm
|
||||||
- node.labels.lokasi == pc-kiri
|
- node.labels.lokasi == pc-kiri
|
||||||
|
|
||||||
peer1:
|
peer1:
|
||||||
|
|
@ -132,8 +136,9 @@ services:
|
||||||
- /home/labai2/josafat/hospital-log/backend/blockchain/network/organizations/peerOrganizations/hospital.com/peers/peer1.hospital.com/msp:/etc/hyperledger/fabric/msp
|
- /home/labai2/josafat/hospital-log/backend/blockchain/network/organizations/peerOrganizations/hospital.com/peers/peer1.hospital.com/msp:/etc/hyperledger/fabric/msp
|
||||||
- /home/labai2/josafat/hospital-log/backend/blockchain/network/organizations/peerOrganizations/hospital.com/peers/peer1.hospital.com/tls:/etc/hyperledger/fabric/tls
|
- /home/labai2/josafat/hospital-log/backend/blockchain/network/organizations/peerOrganizations/hospital.com/peers/peer1.hospital.com/tls:/etc/hyperledger/fabric/tls
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
- "peer0.hospital.com:192.168.11.211"
|
# Pastikan IP sesuai dengan node swarm
|
||||||
- "orderer.hospital.com:192.168.11.211"
|
- "peer0.hospital.com:192.168.11.74"
|
||||||
|
- "orderer.hospital.com:192.168.11.74"
|
||||||
- "peer2.hospital.com:192.168.11.63"
|
- "peer2.hospital.com:192.168.11.63"
|
||||||
ports:
|
ports:
|
||||||
- target: 8051
|
- target: 8051
|
||||||
|
|
@ -145,6 +150,7 @@ services:
|
||||||
deploy:
|
deploy:
|
||||||
placement:
|
placement:
|
||||||
constraints:
|
constraints:
|
||||||
|
# Pastikan label sesuai dengan yang ada dalam node swarm
|
||||||
- node.labels.lokasi == pc-tengah
|
- node.labels.lokasi == pc-tengah
|
||||||
|
|
||||||
peer2:
|
peer2:
|
||||||
|
|
@ -170,8 +176,9 @@ services:
|
||||||
- /home/my_device/josafat/hospital-log/backend/blockchain/network/organizations/peerOrganizations/hospital.com/peers/peer2.hospital.com/tls:/etc/hyperledger/fabric/tls
|
- /home/my_device/josafat/hospital-log/backend/blockchain/network/organizations/peerOrganizations/hospital.com/peers/peer2.hospital.com/tls:/etc/hyperledger/fabric/tls
|
||||||
- /home/my_device/josafat/hospital-log/backend/blockchain/data:/var/hyperledger/production
|
- /home/my_device/josafat/hospital-log/backend/blockchain/data:/var/hyperledger/production
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
- "peer0.hospital.com:192.168.11.211"
|
# Pastikan IP sesuai dengan node swarm
|
||||||
- "orderer.hospital.com:192.168.11.211"
|
- "peer0.hospital.com:192.168.11.74"
|
||||||
|
- "orderer.hospital.com:192.168.11.74"
|
||||||
- "peer1.hospital.com:192.168.11.94"
|
- "peer1.hospital.com:192.168.11.94"
|
||||||
ports:
|
ports:
|
||||||
- target: 9051
|
- target: 9051
|
||||||
|
|
@ -183,4 +190,5 @@ services:
|
||||||
deploy:
|
deploy:
|
||||||
placement:
|
placement:
|
||||||
constraints:
|
constraints:
|
||||||
|
# Pastikan label sesuai dengan yang ada dalam node swarm
|
||||||
- node.labels.lokasi == pc-kanan
|
- node.labels.lokasi == pc-kanan
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
# Vue 3 + TypeScript + Vite
|
# How to start
|
||||||
|
|
||||||
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
1. npm install
|
||||||
|
2. npm run dev / bun run dev
|
||||||
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user