Compare commits
No commits in common. "72d20c646ec891313b8c1a67243a68fe63791bfa" and "a7e9043ae47fcb66f07d09bb4394a204ca723894" have entirely different histories.
72d20c646e
...
a7e9043ae4
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "sdk_client",
|
"name": "sdk_client",
|
||||||
"version": "1.1.0",
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "sdk_client",
|
"name": "sdk_client",
|
||||||
"version": "1.1.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/elements": "^19.0.1",
|
"@angular/elements": "^19.0.1",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { INotification } from '~/models/notification.model';
|
import { INotification } from '~/models/notification.model';
|
||||||
import { IProcess } from '~/models/process.model';
|
import { IProcess } from '~/models/process.model';
|
||||||
import { initWebsocket, sendMessage } from '../websockets';
|
import { initWebsocket, sendMessage } from '../websockets';
|
||||||
import { ApiReturn, Device, HandshakeMessage, Member, MerkleProofResult, NewTxMessage, OutPointProcessMap, Process, ProcessState, RoleDefinition, SecretsStore, UserDiff } from '../../pkg/sdk_client';
|
import type { ApiReturn, Device, HandshakeMessage, Member, MerkleProofResult, NewTxMessage, OutPointProcessMap, Process, ProcessState, RoleDefinition, SecretsStore, UserDiff } from '../../pkg/sdk_client';
|
||||||
import ModalService from './modal.service';
|
import ModalService from './modal.service';
|
||||||
import Database from './database.service';
|
import Database from './database.service';
|
||||||
import { navigate } from '../router';
|
import { navigate } from '../router';
|
||||||
@ -12,8 +12,8 @@ export const U32_MAX = 4294967295;
|
|||||||
|
|
||||||
const BASEURL = `http://localhost`;
|
const BASEURL = `http://localhost`;
|
||||||
const BOOTSTRAPURL = [`${BASEURL}:8090`];
|
const BOOTSTRAPURL = [`${BASEURL}:8090`];
|
||||||
const STORAGEURL = `${BASEURL}:8081`
|
const STORAGEURL = `${BASEURL}:8081`;
|
||||||
const BLINDBITURL = `${BASEURL}:8000`
|
const BLINDBITURL = `${BASEURL}:8000`;
|
||||||
const DEFAULTAMOUNT = 1000n;
|
const DEFAULTAMOUNT = 1000n;
|
||||||
const EMPTY32BYTES = String('').padStart(64, '0');
|
const EMPTY32BYTES = String('').padStart(64, '0');
|
||||||
|
|
||||||
@ -60,6 +60,14 @@ export default class Services {
|
|||||||
this.notifications = this.getNotifications();
|
this.notifications = this.getNotifications();
|
||||||
this.sdkClient = await import('../../pkg/sdk_client');
|
this.sdkClient = await import('../../pkg/sdk_client');
|
||||||
this.sdkClient.setup();
|
this.sdkClient.setup();
|
||||||
|
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const isE2E = params.has('e2e');
|
||||||
|
if (isE2E) {
|
||||||
|
// Mode E2E: ne pas tenter de connexion aux relays
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (const wsurl of Object.values(BOOTSTRAPURL)) {
|
for (const wsurl of Object.values(BOOTSTRAPURL)) {
|
||||||
this.updateRelay(wsurl, '');
|
this.updateRelay(wsurl, '');
|
||||||
}
|
}
|
||||||
@ -86,24 +94,24 @@ export default class Services {
|
|||||||
* Waits for at least one handshake message before returning.
|
* Waits for at least one handshake message before returning.
|
||||||
*/
|
*/
|
||||||
public async connectAllRelays(): Promise<void> {
|
public async connectAllRelays(): Promise<void> {
|
||||||
const connectedUrls: string[] = [];
|
const connectedUrls: string[] = [];
|
||||||
|
|
||||||
// Connect to all relays
|
// Connect to all relays
|
||||||
for (const wsurl of Object.keys(this.relayAddresses)) {
|
for (const wsurl of Object.keys(this.relayAddresses)) {
|
||||||
try {
|
try {
|
||||||
console.log(`Connecting to: ${wsurl}`);
|
console.log(`Connecting to: ${wsurl}`);
|
||||||
await this.addWebsocketConnection(wsurl);
|
await this.addWebsocketConnection(wsurl);
|
||||||
connectedUrls.push(wsurl);
|
connectedUrls.push(wsurl);
|
||||||
console.log(`Successfully connected to: ${wsurl}`);
|
console.log(`Successfully connected to: ${wsurl}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to connect to ${wsurl}:`, error);
|
console.error(`Failed to connect to ${wsurl}:`, error);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for at least one handshake message if we have connections
|
// Wait for at least one handshake message if we have connections
|
||||||
if (connectedUrls.length > 0) {
|
if (connectedUrls.length > 0) {
|
||||||
await this.waitForHandshakeMessage();
|
await this.waitForHandshakeMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async addWebsocketConnection(url: string): Promise<void> {
|
public async addWebsocketConnection(url: string): Promise<void> {
|
||||||
@ -117,8 +125,8 @@ export default class Services {
|
|||||||
* @param spAddress - The SP Address (value).
|
* @param spAddress - The SP Address (value).
|
||||||
*/
|
*/
|
||||||
public updateRelay(wsurl: string, spAddress: string): void {
|
public updateRelay(wsurl: string, spAddress: string): void {
|
||||||
this.relayAddresses[wsurl] = spAddress;
|
this.relayAddresses[wsurl] = spAddress;
|
||||||
console.log(`Updated: ${wsurl} -> ${spAddress}`);
|
console.log(`Updated: ${wsurl} -> ${spAddress}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -127,7 +135,7 @@ export default class Services {
|
|||||||
* @returns The SP Address if found, or undefined if not.
|
* @returns The SP Address if found, or undefined if not.
|
||||||
*/
|
*/
|
||||||
public getSpAddress(wsurl: string): string | undefined {
|
public getSpAddress(wsurl: string): string | undefined {
|
||||||
return this.relayAddresses[wsurl];
|
return this.relayAddresses[wsurl];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,20 +143,20 @@ export default class Services {
|
|||||||
* @returns An array of objects containing wsurl and spAddress.
|
* @returns An array of objects containing wsurl and spAddress.
|
||||||
*/
|
*/
|
||||||
public getAllRelays(): { wsurl: string; spAddress: string }[] {
|
public getAllRelays(): { wsurl: string; spAddress: string }[] {
|
||||||
return Object.entries(this.relayAddresses).map(([wsurl, spAddress]) => ({
|
return Object.entries(this.relayAddresses).map(([wsurl, spAddress]) => ({
|
||||||
wsurl,
|
wsurl,
|
||||||
spAddress,
|
spAddress,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print all key/value pairs for debugging.
|
* Print all key/value pairs for debugging.
|
||||||
*/
|
*/
|
||||||
public printAllRelays(): void {
|
public printAllRelays(): void {
|
||||||
console.log("Current relay addresses:");
|
console.log('Current relay addresses:');
|
||||||
for (const [wsurl, spAddress] of Object.entries(this.relayAddresses)) {
|
for (const [wsurl, spAddress] of Object.entries(this.relayAddresses)) {
|
||||||
console.log(`${wsurl} -> ${spAddress}`);
|
console.log(`${wsurl} -> ${spAddress}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public isPaired(): boolean {
|
public isPaired(): boolean {
|
||||||
@ -299,27 +307,18 @@ export default class Services {
|
|||||||
min_sig_member: 1.0,
|
min_sig_member: 1.0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
storages: [STORAGEURL]
|
storages: [STORAGEURL],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
return this.createProcess(
|
return this.createProcess(privateData, publicData, roles);
|
||||||
privateData,
|
|
||||||
publicData,
|
|
||||||
roles
|
|
||||||
);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`Creating process failed:, ${e}`);
|
throw new Error(`Creating process failed:, ${e}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private isFileBlob(value: any): value is { type: string, data: Uint8Array } {
|
private isFileBlob(value: any): value is { type: string; data: Uint8Array } {
|
||||||
return (
|
return typeof value === 'object' && value !== null && typeof value.type === 'string' && value.data instanceof Uint8Array;
|
||||||
typeof value === 'object' &&
|
|
||||||
value !== null &&
|
|
||||||
typeof value.type === 'string' &&
|
|
||||||
value.data instanceof Uint8Array
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private splitData(obj: Record<string, any>) {
|
private splitData(obj: Record<string, any>) {
|
||||||
@ -337,11 +336,7 @@ export default class Services {
|
|||||||
return { jsonCompatibleData, binaryData };
|
return { jsonCompatibleData, binaryData };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createProcess(
|
public async createProcess(privateData: Record<string, any>, publicData: Record<string, any>, roles: Record<string, RoleDefinition>): Promise<ApiReturn> {
|
||||||
privateData: Record<string, any>,
|
|
||||||
publicData: Record<string, any>,
|
|
||||||
roles: Record<string, RoleDefinition>,
|
|
||||||
): Promise<ApiReturn> {
|
|
||||||
let relayAddress = this.getAllRelays()[0]?.spAddress;
|
let relayAddress = this.getAllRelays()[0]?.spAddress;
|
||||||
|
|
||||||
if (!relayAddress || relayAddress === '') {
|
if (!relayAddress || relayAddress === '') {
|
||||||
@ -364,11 +359,11 @@ export default class Services {
|
|||||||
const publicSplitData = this.splitData(publicData);
|
const publicSplitData = this.splitData(publicData);
|
||||||
const encodedPrivateData = {
|
const encodedPrivateData = {
|
||||||
...this.sdkClient.encode_json(privateSplitData.jsonCompatibleData),
|
...this.sdkClient.encode_json(privateSplitData.jsonCompatibleData),
|
||||||
...this.sdkClient.encode_binary(privateSplitData.binaryData)
|
...this.sdkClient.encode_binary(privateSplitData.binaryData),
|
||||||
};
|
};
|
||||||
const encodedPublicData = {
|
const encodedPublicData = {
|
||||||
...this.sdkClient.encode_json(publicSplitData.jsonCompatibleData),
|
...this.sdkClient.encode_json(publicSplitData.jsonCompatibleData),
|
||||||
...this.sdkClient.encode_binary(publicSplitData.binaryData)
|
...this.sdkClient.encode_binary(publicSplitData.binaryData),
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('encoded data:', encodedPrivateData);
|
console.log('encoded data:', encodedPrivateData);
|
||||||
@ -387,16 +382,9 @@ export default class Services {
|
|||||||
console.log('members:', members);
|
console.log('members:', members);
|
||||||
await this.checkConnections([...members]);
|
await this.checkConnections([...members]);
|
||||||
|
|
||||||
const result = this.sdkClient.create_new_process (
|
const result = this.sdkClient.create_new_process(encodedPrivateData, roles, encodedPublicData, relayAddress, feeRate, this.getAllMembers());
|
||||||
encodedPrivateData,
|
|
||||||
roles,
|
|
||||||
encodedPublicData,
|
|
||||||
relayAddress,
|
|
||||||
feeRate,
|
|
||||||
this.getAllMembers()
|
|
||||||
);
|
|
||||||
|
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateProcess(process: Process, privateData: Record<string, any>, publicData: Record<string, any>, roles: Record<string, RoleDefinition> | null): Promise<ApiReturn> {
|
public async updateProcess(process: Process, privateData: Record<string, any>, publicData: Record<string, any>, roles: Record<string, RoleDefinition> | null): Promise<ApiReturn> {
|
||||||
@ -410,7 +398,7 @@ export default class Services {
|
|||||||
let members: Set<Member> = new Set();
|
let members: Set<Member> = new Set();
|
||||||
for (const role of Object.values(roles!)) {
|
for (const role of Object.values(roles!)) {
|
||||||
for (const member of role.members) {
|
for (const member of role.members) {
|
||||||
members.add(member)
|
members.add(member);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (members.size === 0) {
|
if (members.size === 0) {
|
||||||
@ -431,11 +419,11 @@ export default class Services {
|
|||||||
const publicSplitData = this.splitData(publicData);
|
const publicSplitData = this.splitData(publicData);
|
||||||
const encodedPrivateData = {
|
const encodedPrivateData = {
|
||||||
...this.sdkClient.encode_json(privateSplitData.jsonCompatibleData),
|
...this.sdkClient.encode_json(privateSplitData.jsonCompatibleData),
|
||||||
...this.sdkClient.encode_binary(privateSplitData.binaryData)
|
...this.sdkClient.encode_binary(privateSplitData.binaryData),
|
||||||
};
|
};
|
||||||
const encodedPublicData = {
|
const encodedPublicData = {
|
||||||
...this.sdkClient.encode_json(publicSplitData.jsonCompatibleData),
|
...this.sdkClient.encode_json(publicSplitData.jsonCompatibleData),
|
||||||
...this.sdkClient.encode_binary(publicSplitData.binaryData)
|
...this.sdkClient.encode_binary(publicSplitData.binaryData),
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
return this.sdkClient.update_process(process, encodedPrivateData, roles, encodedPublicData, this.getAllMembers());
|
return this.sdkClient.update_process(process, encodedPrivateData, roles, encodedPublicData, this.getAllMembers());
|
||||||
@ -536,7 +524,6 @@ export default class Services {
|
|||||||
if (waitingModal) {
|
if (waitingModal) {
|
||||||
this.device2Ready = true;
|
this.device2Ready = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`Parsed cipher with error: ${e}`);
|
console.error(`Parsed cipher with error: ${e}`);
|
||||||
}
|
}
|
||||||
@ -604,7 +591,7 @@ export default class Services {
|
|||||||
|
|
||||||
if (apiReturn.new_tx_to_send && apiReturn.new_tx_to_send.transaction.length != 0) {
|
if (apiReturn.new_tx_to_send && apiReturn.new_tx_to_send.transaction.length != 0) {
|
||||||
this.sendNewTxMessage(JSON.stringify(apiReturn.new_tx_to_send));
|
this.sendNewTxMessage(JSON.stringify(apiReturn.new_tx_to_send));
|
||||||
await new Promise(r => setTimeout(r, 500));
|
await new Promise((r) => setTimeout(r, 500));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (apiReturn.secrets) {
|
if (apiReturn.secrets) {
|
||||||
@ -781,7 +768,7 @@ export default class Services {
|
|||||||
try {
|
try {
|
||||||
let encodedSpAddressList: number[] = [];
|
let encodedSpAddressList: number[] = [];
|
||||||
if (this.stateId) {
|
if (this.stateId) {
|
||||||
const state = process.states.find(state => state.state_id === this.stateId);
|
const state = process.states.find((state) => state.state_id === this.stateId);
|
||||||
if (state) {
|
if (state) {
|
||||||
encodedSpAddressList = state.public_data['pairedAddresses'];
|
encodedSpAddressList = state.public_data['pairedAddresses'];
|
||||||
}
|
}
|
||||||
@ -850,7 +837,7 @@ export default class Services {
|
|||||||
try {
|
try {
|
||||||
const prevDevice = await this.getDeviceFromDatabase();
|
const prevDevice = await this.getDeviceFromDatabase();
|
||||||
if (prevDevice) {
|
if (prevDevice) {
|
||||||
await db.deleteObject(walletStore, "1");
|
await db.deleteObject(walletStore, '1');
|
||||||
}
|
}
|
||||||
await db.addObject({
|
await db.addObject({
|
||||||
storeName: walletStore,
|
storeName: walletStore,
|
||||||
@ -1227,7 +1214,7 @@ export default class Services {
|
|||||||
let hasAccess = false;
|
let hasAccess = false;
|
||||||
// If we're not supposed to have access to this attribute, ignore
|
// If we're not supposed to have access to this attribute, ignore
|
||||||
for (const role of Object.values(roles)) {
|
for (const role of Object.values(roles)) {
|
||||||
for (const rule of Object.values(role.validation_rules)) {
|
for (const rule of Object.values(role.validation_rules) as any[]) {
|
||||||
if (rule.fields.includes(attribute)) {
|
if (rule.fields.includes(attribute)) {
|
||||||
if (role.members.includes(pairingProcessId)) {
|
if (role.members.includes(pairingProcessId)) {
|
||||||
// We have access to this attribute
|
// We have access to this attribute
|
||||||
@ -1248,7 +1235,7 @@ export default class Services {
|
|||||||
let retries = 0;
|
let retries = 0;
|
||||||
|
|
||||||
while ((!hash || !key) && retries < maxRetries) {
|
while ((!hash || !key) && retries < maxRetries) {
|
||||||
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
||||||
// Re-read hash and key after waiting
|
// Re-read hash and key after waiting
|
||||||
hash = state.pcd_commitment[attribute];
|
hash = state.pcd_commitment[attribute];
|
||||||
key = state.keys[attribute];
|
key = state.keys[attribute];
|
||||||
@ -1365,7 +1352,6 @@ export default class Services {
|
|||||||
this.device2Ready = false;
|
this.device2Ready = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Handle the handshake message
|
// Handle the handshake message
|
||||||
public async handleHandshakeMsg(url: string, parsedMsg: any) {
|
public async handleHandshakeMsg(url: string, parsedMsg: any) {
|
||||||
try {
|
try {
|
||||||
@ -1403,10 +1389,12 @@ export default class Services {
|
|||||||
const existing = await this.getProcess(processId);
|
const existing = await this.getProcess(processId);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
// Look for state id we don't know yet
|
// Look for state id we don't know yet
|
||||||
let new_states = [];
|
let new_states: string[] = [];
|
||||||
let roles = [];
|
let roles: Record<string, RoleDefinition>[] = [];
|
||||||
for (const state of process.states) {
|
for (const state of process.states) {
|
||||||
if (!state.state_id || state.state_id === EMPTY32BYTES) { continue; }
|
if (!state.state_id || state.state_id === EMPTY32BYTES) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!this.lookForStateId(existing, state.state_id)) {
|
if (!this.lookForStateId(existing, state.state_id)) {
|
||||||
if (this.rolesContainsUs(state.roles)) {
|
if (this.rolesContainsUs(state.roles)) {
|
||||||
new_states.push(state.state_id);
|
new_states.push(state.state_id);
|
||||||
@ -1454,7 +1442,7 @@ export default class Services {
|
|||||||
|
|
||||||
await this.batchSaveProcessesToDb(toSave);
|
await this.batchSaveProcessesToDb(toSave);
|
||||||
}
|
}
|
||||||
}, 500)
|
}, 500);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to parse init message:', e);
|
console.error('Failed to parse init message:', e);
|
||||||
}
|
}
|
||||||
@ -1507,9 +1495,7 @@ export default class Services {
|
|||||||
* @returns Un tableau contenant tous les membres
|
* @returns Un tableau contenant tous les membres
|
||||||
*/
|
*/
|
||||||
public getAllMembersSorted(): Record<string, Member> {
|
public getAllMembersSorted(): Record<string, Member> {
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(Object.entries(this.membersList).sort(([keyA], [keyB]) => keyA.localeCompare(keyB)));
|
||||||
Object.entries(this.membersList).sort(([keyA], [keyB]) => keyA.localeCompare(keyB))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAllMembers(): Record<string, Member> {
|
public getAllMembers(): Record<string, Member> {
|
||||||
@ -1525,10 +1511,14 @@ export default class Services {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public compareMembers(memberA: string[], memberB: string[]): boolean {
|
public compareMembers(memberA: string[], memberB: string[]): boolean {
|
||||||
if (!memberA || !memberB) { return false }
|
if (!memberA || !memberB) {
|
||||||
if (memberA.length !== memberB.length) { return false }
|
return false;
|
||||||
|
}
|
||||||
|
if (memberA.length !== memberB.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const res = memberA.every(item => memberB.includes(item)) && memberB.every(item => memberA.includes(item));
|
const res = memberA.every((item) => memberB.includes(item)) && memberB.every((item) => memberA.includes(item));
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -1537,16 +1527,14 @@ export default class Services {
|
|||||||
const content = JSON.parse(response);
|
const content = JSON.parse(response);
|
||||||
const error = content.error;
|
const error = content.error;
|
||||||
const errorMsg = error['GenericError'];
|
const errorMsg = error['GenericError'];
|
||||||
const dontRetry = [
|
const dontRetry = ['State is identical to the previous state', 'Not enough valid proofs', 'Not enough members to validate'];
|
||||||
'State is identical to the previous state',
|
if (dontRetry.includes(errorMsg)) {
|
||||||
'Not enough valid proofs',
|
return;
|
||||||
'Not enough members to validate',
|
}
|
||||||
];
|
|
||||||
if (dontRetry.includes(errorMsg)) { return; }
|
|
||||||
// Wait and retry
|
// Wait and retry
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
this.sendCommitMessage(JSON.stringify(content));
|
this.sendCommitMessage(JSON.stringify(content));
|
||||||
}, 1000)
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRoles(process: Process): Record<string, RoleDefinition> | null {
|
public getRoles(process: Process): Record<string, RoleDefinition> | null {
|
||||||
@ -1579,8 +1567,11 @@ export default class Services {
|
|||||||
const lastCommitedState = this.getLastCommitedState(process);
|
const lastCommitedState = this.getLastCommitedState(process);
|
||||||
if (lastCommitedState && lastCommitedState.public_data) {
|
if (lastCommitedState && lastCommitedState.public_data) {
|
||||||
const processName = lastCommitedState!.public_data['processName'];
|
const processName = lastCommitedState!.public_data['processName'];
|
||||||
if (processName) { return this.decodeValue(processName) }
|
if (processName) {
|
||||||
else { return null }
|
return this.decodeValue(processName);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -1622,7 +1613,7 @@ export default class Services {
|
|||||||
this.myProcesses = newMyProcesses; // atomic update
|
this.myProcesses = newMyProcesses; // atomic update
|
||||||
return Array.from(this.myProcesses);
|
return Array.from(this.myProcesses);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to get processes:", e);
|
console.error('Failed to get processes:', e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1640,13 +1631,16 @@ export default class Services {
|
|||||||
|
|
||||||
public hexToBlob(hexString: string): Blob {
|
public hexToBlob(hexString: string): Blob {
|
||||||
const uint8Array = this.hexToUInt8Array(hexString);
|
const uint8Array = this.hexToUInt8Array(hexString);
|
||||||
|
// Crée un ArrayBuffer standard et copie les données pour éviter ArrayBufferLike/SharedArrayBuffer
|
||||||
return new Blob([uint8Array], { type: "application/octet-stream" });
|
const ab = new ArrayBuffer(uint8Array.length);
|
||||||
|
const view = new Uint8Array(ab);
|
||||||
|
view.set(uint8Array);
|
||||||
|
return new Blob([ab], { type: 'application/octet-stream' });
|
||||||
}
|
}
|
||||||
|
|
||||||
public hexToUInt8Array(hexString: string): Uint8Array {
|
public hexToUInt8Array(hexString: string): Uint8Array {
|
||||||
if (hexString.length % 2 !== 0) {
|
if (hexString.length % 2 !== 0) {
|
||||||
throw new Error("Invalid hex string: length must be even");
|
throw new Error('Invalid hex string: length must be even');
|
||||||
}
|
}
|
||||||
const uint8Array = new Uint8Array(hexString.length / 2);
|
const uint8Array = new Uint8Array(hexString.length / 2);
|
||||||
for (let i = 0; i < hexString.length; i += 2) {
|
for (let i = 0; i < hexString.length; i += 2) {
|
||||||
@ -1660,7 +1654,7 @@ export default class Services {
|
|||||||
const buffer = await blob.arrayBuffer();
|
const buffer = await blob.arrayBuffer();
|
||||||
const bytes = new Uint8Array(buffer);
|
const bytes = new Uint8Array(buffer);
|
||||||
return Array.from(bytes)
|
return Array.from(bytes)
|
||||||
.map(byte => byte.toString(16).padStart(2, '0'))
|
.map((byte) => byte.toString(16).padStart(2, '0'))
|
||||||
.join('');
|
.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1683,7 +1677,7 @@ export default class Services {
|
|||||||
public getLastCommitedState(process: Process): ProcessState | null {
|
public getLastCommitedState(process: Process): ProcessState | null {
|
||||||
if (process.states.length === 0) return null;
|
if (process.states.length === 0) return null;
|
||||||
const processTip = process.states[process.states.length - 1].commited_in;
|
const processTip = process.states[process.states.length - 1].commited_in;
|
||||||
const lastCommitedState = process.states.findLast(state => state.commited_in !== processTip);
|
const lastCommitedState = process.states.findLast((state: ProcessState) => state.commited_in !== processTip);
|
||||||
if (lastCommitedState) {
|
if (lastCommitedState) {
|
||||||
return lastCommitedState;
|
return lastCommitedState;
|
||||||
} else {
|
} else {
|
||||||
@ -1705,13 +1699,13 @@ export default class Services {
|
|||||||
public getUncommitedStates(process: Process): ProcessState[] {
|
public getUncommitedStates(process: Process): ProcessState[] {
|
||||||
if (process.states.length === 0) return [];
|
if (process.states.length === 0) return [];
|
||||||
const processTip = process.states[process.states.length - 1].commited_in;
|
const processTip = process.states[process.states.length - 1].commited_in;
|
||||||
const res = process.states.filter(state => state.commited_in === processTip);
|
const res = process.states.filter((state: ProcessState) => state.commited_in === processTip);
|
||||||
return res.filter(state => state.state_id !== EMPTY32BYTES);
|
return res.filter((state: ProcessState) => state.state_id !== EMPTY32BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getStateFromId(process: Process, stateId: string): ProcessState | null {
|
public getStateFromId(process: Process, stateId: string): ProcessState | null {
|
||||||
if (process.states.length === 0) return null;
|
if (process.states.length === 0) return null;
|
||||||
const state = process.states.find(state => state.state_id === stateId);
|
const state = process.states.find((state: ProcessState) => state.state_id === stateId);
|
||||||
if (state) {
|
if (state) {
|
||||||
return state;
|
return state;
|
||||||
} else {
|
} else {
|
||||||
@ -1722,7 +1716,7 @@ export default class Services {
|
|||||||
public getNextStateAfterId(process: Process, stateId: string): ProcessState | null {
|
public getNextStateAfterId(process: Process, stateId: string): ProcessState | null {
|
||||||
if (process.states.length === 0) return null;
|
if (process.states.length === 0) return null;
|
||||||
|
|
||||||
const index = process.states.findIndex(state => state.state_id === stateId);
|
const index = process.states.findIndex((state: ProcessState) => state.state_id === stateId);
|
||||||
|
|
||||||
if (index !== -1 && index < process.states.length - 1) {
|
if (index !== -1 && index < process.states.length - 1) {
|
||||||
return process.states[index + 1];
|
return process.states[index + 1];
|
||||||
@ -1732,7 +1726,9 @@ export default class Services {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public isPairingProcess(roles: Record<string, RoleDefinition>): boolean {
|
public isPairingProcess(roles: Record<string, RoleDefinition>): boolean {
|
||||||
if (Object.keys(roles).length != 1) { return false }
|
if (Object.keys(roles).length != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const pairingRole = roles['pairing'];
|
const pairingRole = roles['pairing'];
|
||||||
if (pairingRole) {
|
if (pairingRole) {
|
||||||
// For now that's enough, we should probably test more things
|
// For now that's enough, we should probably test more things
|
||||||
@ -1744,7 +1740,7 @@ export default class Services {
|
|||||||
|
|
||||||
public async updateMemberPublicName(process: Process, newName: string): Promise<ApiReturn> {
|
public async updateMemberPublicName(process: Process, newName: string): Promise<ApiReturn> {
|
||||||
const publicData = {
|
const publicData = {
|
||||||
'memberPublicName': newName
|
memberPublicName: newName,
|
||||||
};
|
};
|
||||||
|
|
||||||
return await this.updateProcess(process, {}, publicData, null);
|
return await this.updateProcess(process, {}, publicData, null);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user