feat: initial Pezkuwi Apps rebrand from polkadot-apps

Rebranded terminology:
- Polkadot → Pezkuwi
- Kusama → Dicle
- Westend → Zagros
- Rococo → PezkuwiChain
- Substrate → Bizinikiwi
- parachain → teyrchain

Custom logos with Kurdistan brand colors (#e6007a → #86e62a):
- bizinikiwi-hexagon.svg
- sora-bizinikiwi.svg
- hezscanner.svg
- heztreasury.svg
- pezkuwiscan.svg
- pezkuwistats.svg
- pezkuwiassembly.svg
- pezkuwiholic.svg
This commit is contained in:
2026-01-07 13:05:27 +03:00
commit d21bfb1320
5867 changed files with 329019 additions and 0 deletions
@@ -0,0 +1,72 @@
// Copyright 2017-2025 @pezkuwi/apps authors & contributors
// SPDX-License-Identifier: Apache-2.0
/// <reference types="@pezkuwi/dev-test/globals.d.ts" />
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore Warned on by nodenext resolution (while package does build in bundler mode)
import type { KeyringJson } from '@pezkuwi/ui-keyring/types';
import type { IpcMainHandler } from './ipc-main-handler.js';
import * as tmp from 'tmp';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore Warned on by nodenext resolution (while package does build in bundler mode)
import { FileStore } from '@pezkuwi/ui-keyring/stores';
import { accountStoreIpcHandler } from './account-store.js';
const exampleAccount = (address: string): KeyringJson => ({
address,
meta: {}
});
describe('Account store', () => {
let accountStore: IpcMainHandler;
let tmpDir: tmp.DirResult;
beforeEach(() => {
tmpDir = tmp.dirSync({ unsafeCleanup: true });
accountStore = accountStoreIpcHandler(new FileStore(tmpDir.name));
});
afterEach(() => {
tmpDir.removeCallback();
});
it('all returns empty array at first', () => {
expect(accountStore['account-store-all']()).toEqual([]);
});
it('after adding accounts, they become visible', async () => {
await accountStore['account-store-set']('1', exampleAccount('a'));
await accountStore['account-store-set']('2', exampleAccount('b'));
expect(accountStore['account-store-all']()).toEqual([{
key: '1', value: exampleAccount('a')
}, {
key: '2', value: exampleAccount('b')
}]);
});
it('get returns account if exists', async () => {
await accountStore['account-store-set']('1', exampleAccount('a'));
expect(await accountStore['account-store-get']('1')).toEqual(exampleAccount('a'));
});
it('get returns null if account does not exist', async () => {
// jest.spyOn(console, 'error').mockImplementationOnce(() => { /**/ });
expect(await accountStore['account-store-get']('1')).toEqual(null);
});
it('account disappears from list after it is removed', async () => {
// jest.spyOn(console, 'error').mockImplementationOnce(() => { /**/ });
await accountStore['account-store-set']('1', exampleAccount('a'));
await accountStore['account-store-remove']('1');
expect(await accountStore['account-store-get']('1')).toEqual(null);
expect(accountStore['account-store-all']()).toEqual([]);
});
});
@@ -0,0 +1,60 @@
// Copyright 2017-2025 @pezkuwi/apps authors & contributors
// SPDX-License-Identifier: Apache-2.0
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore Warned on by nodenext resolution (while package does build in bundler mode)
import type { KeyringJson } from '@pezkuwi/ui-keyring/types';
import type { IpcMainHandler } from './ipc-main-handler.js';
import electron from 'electron';
import path from 'path';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore Warned on by nodenext resolution (while package does build in bundler mode)
import { FileStore } from '@pezkuwi/ui-keyring/stores';
import { registerIpcHandler } from './register-ipc-handler.js';
const ACCOUNTS_SUBFOLDER = 'pezkuwi-accounts';
function safeWriteKey (key: string) {
return key.replace(/:/g, '-');
}
function safeReadKey (key: string) {
return key.replace(/-/g, ':');
}
export const accountStoreIpcHandler = (fileStore: FileStore): IpcMainHandler => ({
'account-store-all': () => {
let result: { key: string, value: KeyringJson }[] = [];
const collect = (key: string, value: KeyringJson) => {
result = [...result, { key: safeReadKey(key), value }];
};
fileStore.all(collect);
return result;
},
'account-store-get': async (key: string) => new Promise((resolve) => {
try {
fileStore.get(safeWriteKey(key), resolve);
} catch {
resolve(null);
}
}),
'account-store-remove': async (key: string) => new Promise((resolve) =>
fileStore.remove(safeWriteKey(key), () => resolve(undefined))
),
'account-store-set': async (key: string, value: KeyringJson) => new Promise((resolve) =>
fileStore.set(safeWriteKey(key), value, () => resolve(undefined))
)
});
export const registerAccountStoreHandlers = (): void => {
const defaultStorePath = path.join(electron.app.getPath('userData'), ACCOUNTS_SUBFOLDER);
const fileStore = new FileStore(defaultStorePath);
registerIpcHandler(accountStoreIpcHandler(fileStore));
};
@@ -0,0 +1,4 @@
// Copyright 2017-2025 @pezkuwi/apps authors & contributors
// SPDX-License-Identifier: Apache-2.0
export type IpcMainHandler = Record<string, (...args: any[]) => unknown>;
@@ -0,0 +1,14 @@
// Copyright 2017-2025 @pezkuwi/apps authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { IpcMainHandler } from './ipc-main-handler.js';
import electron from 'electron';
export const registerIpcHandler = (ipcHandler: IpcMainHandler): void => {
for (const [channel, listener] of Object.entries(ipcHandler)) {
electron.ipcMain.handle(channel, (_, ...args: unknown[]) => {
return listener(...args);
});
}
};