From 116880af9c973b0ab5d6fb51dd5cf37988586df3 Mon Sep 17 00:00:00 2001 From: Blake Byrnes Date: Fri, 1 Mar 2024 09:50:23 -0500 Subject: [PATCH] chore: move schema/crypto/spec to platform --- commons/lib/asyncUtils.ts | 22 +- commons/lib/objectUtils.ts | 15 ++ crypto/CHANGELOG.md | 191 -------------- crypto/bin/cli.ts | 6 - crypto/cli.ts | 191 -------------- crypto/index.ts | 0 crypto/interfaces/IAddressSettings.ts | 13 - crypto/lib/Address.ts | 205 --------------- crypto/lib/AddressOwnersTree.ts | 116 --------- crypto/lib/AddressSignature.ts | 163 ------------ crypto/lib/Ed25519.ts | 71 ------ crypto/lib/Identity.ts | 156 ------------ crypto/lib/MerkleTree.ts | 213 ---------------- crypto/lib/errors.ts | 20 -- crypto/package.json | 14 -- crypto/test/Address.test.ts | 53 ---- crypto/test/Ed25519.test.ts | 18 -- crypto/test/Identity.test.ts | 30 --- crypto/test/Merkle.model.test.ts | 234 ------------------ package.json | 5 +- schema/CHANGELOG.md | 143 ----------- schema/index.ts | 130 ---------- schema/interfaces/ISchemaJson.ts | 58 ----- schema/interfaces/IValidationResult.ts | 10 - schema/lib/ArraySchema.ts | 35 --- schema/lib/BaseSchema.ts | 163 ------------ schema/lib/BigintSchema.ts | 39 --- schema/lib/BooleanSchema.ts | 18 -- schema/lib/BufferSchema.ts | 43 ---- schema/lib/DateSchema.ts | 43 ---- schema/lib/DateUtilities.ts | 39 --- schema/lib/NumberSchema.ts | 65 ----- schema/lib/ObjectSchema.ts | 64 ----- schema/lib/RecordSchema.ts | 57 ----- schema/lib/StringSchema.ts | 166 ------------- schema/lib/jsonToSchemaCode.ts | 122 --------- schema/lib/schemaFromJson.ts | 59 ----- schema/lib/schemaToInterface.ts | 140 ----------- schema/package.dist.json | 5 - schema/package.json | 12 - schema/test/Number.test.ts | 36 --- schema/test/Object.test.ts | 122 --------- schema/test/String.test.ts | 51 ---- schema/test/jsonToSchemaCode.test.ts | 53 ---- schema/test/schemaToInterface.test.ts | 25 -- schema/yarn.lock | 8 - specification/.eslintrc.js | 8 - specification/CHANGELOG.md | 208 ---------------- specification/common.ts | 41 --- specification/index.ts | 45 ---- specification/mainchain/BlockApis.ts | 66 ----- specification/mainchain/BlockHeaderApis.ts | 28 --- specification/mainchain/CoinageApis.ts | 35 --- .../mainchain/SidechainGovernanceApis.ts | 33 --- specification/mainchain/TransactionApis.ts | 69 ------ specification/mainchain/index.ts | 20 -- specification/package.json | 10 - specification/sidechain/AddressApis.ts | 25 -- .../sidechain/FundingTransferApis.ts | 41 --- specification/sidechain/MicronoteApis.ts | 89 ------- specification/sidechain/MicronoteBatchApis.ts | 64 ----- specification/sidechain/NoteApis.ts | 23 -- specification/sidechain/RampApis.ts | 45 ---- specification/sidechain/SidechainInfoApis.ts | 49 ---- .../sidechain/SidechainSnapshot.proto | 67 ----- specification/sidechain/StakeApis.ts | 46 ---- specification/sidechain/index.ts | 26 -- specification/tsconfig.dist.json | 8 - specification/tsconfig.json | 8 - specification/types/BlockError.ts | 41 --- specification/types/CoinageType.ts | 6 - specification/types/IAddressOwnershipProof.ts | 13 - specification/types/IAddressSignature.ts | 16 -- specification/types/IArithmeticEncoding.ts | 9 - specification/types/IAuthorizedSidechain.ts | 21 -- specification/types/IBitDatumHistory.ts | 17 -- specification/types/IBlock.ts | 27 -- specification/types/IBlockHeader.ts | 28 --- specification/types/IBlockSettings.ts | 30 --- specification/types/ICoinage.ts | 25 -- specification/types/ICoordinator.ts | 15 -- specification/types/IDatum.ts | 16 -- specification/types/IDatumSummary.ts | 17 -- specification/types/IGrantTransfer.ts | 12 - specification/types/IMerkleProof.ts | 16 -- specification/types/IMicronote.ts | 27 -- specification/types/IMicronoteBatch.ts | 21 -- specification/types/IMicronoteBatchDatums.ts | 13 - specification/types/INote.ts | 19 -- specification/types/IProofOfKnowedge.ts | 33 --- specification/types/IStakeSettings.ts | 23 -- specification/types/IStakeSignature.ts | 12 - specification/types/ITransaction.ts | 19 -- specification/types/ITransactionOutput.ts | 15 -- specification/types/ITransactionSource.ts | 18 -- .../types/ITransactionSourceSignatureData.ts | 24 -- specification/types/IWebhitsClaimAddress.ts | 16 -- specification/types/IXoredCandidate.ts | 38 --- specification/types/IXoredCandidateSummary.ts | 16 -- specification/types/LedgerType.ts | 5 - specification/types/NoteType.ts | 14 -- specification/types/TransactionError.ts | 26 -- specification/types/TransactionType.ts | 8 - specification/utils/IZodApi.ts | 22 -- specification/utils/ValidatingApiHandler.ts | 49 ---- specification/utils/ValidationError.ts | 29 --- tsconfig.json | 11 +- yarn.lock | 20 -- 108 files changed, 35 insertions(+), 5248 deletions(-) delete mode 100644 crypto/CHANGELOG.md delete mode 100644 crypto/bin/cli.ts delete mode 100644 crypto/cli.ts delete mode 100644 crypto/index.ts delete mode 100644 crypto/interfaces/IAddressSettings.ts delete mode 100644 crypto/lib/Address.ts delete mode 100644 crypto/lib/AddressOwnersTree.ts delete mode 100644 crypto/lib/AddressSignature.ts delete mode 100644 crypto/lib/Ed25519.ts delete mode 100644 crypto/lib/Identity.ts delete mode 100644 crypto/lib/MerkleTree.ts delete mode 100644 crypto/lib/errors.ts delete mode 100644 crypto/package.json delete mode 100644 crypto/test/Address.test.ts delete mode 100644 crypto/test/Ed25519.test.ts delete mode 100644 crypto/test/Identity.test.ts delete mode 100644 crypto/test/Merkle.model.test.ts delete mode 100644 schema/CHANGELOG.md delete mode 100644 schema/index.ts delete mode 100644 schema/interfaces/ISchemaJson.ts delete mode 100644 schema/interfaces/IValidationResult.ts delete mode 100644 schema/lib/ArraySchema.ts delete mode 100644 schema/lib/BaseSchema.ts delete mode 100644 schema/lib/BigintSchema.ts delete mode 100644 schema/lib/BooleanSchema.ts delete mode 100644 schema/lib/BufferSchema.ts delete mode 100644 schema/lib/DateSchema.ts delete mode 100644 schema/lib/DateUtilities.ts delete mode 100644 schema/lib/NumberSchema.ts delete mode 100644 schema/lib/ObjectSchema.ts delete mode 100644 schema/lib/RecordSchema.ts delete mode 100644 schema/lib/StringSchema.ts delete mode 100644 schema/lib/jsonToSchemaCode.ts delete mode 100644 schema/lib/schemaFromJson.ts delete mode 100644 schema/lib/schemaToInterface.ts delete mode 100644 schema/package.dist.json delete mode 100644 schema/package.json delete mode 100644 schema/test/Number.test.ts delete mode 100644 schema/test/Object.test.ts delete mode 100644 schema/test/String.test.ts delete mode 100644 schema/test/jsonToSchemaCode.test.ts delete mode 100644 schema/test/schemaToInterface.test.ts delete mode 100644 schema/yarn.lock delete mode 100644 specification/.eslintrc.js delete mode 100644 specification/CHANGELOG.md delete mode 100644 specification/common.ts delete mode 100644 specification/index.ts delete mode 100644 specification/mainchain/BlockApis.ts delete mode 100644 specification/mainchain/BlockHeaderApis.ts delete mode 100644 specification/mainchain/CoinageApis.ts delete mode 100644 specification/mainchain/SidechainGovernanceApis.ts delete mode 100644 specification/mainchain/TransactionApis.ts delete mode 100644 specification/mainchain/index.ts delete mode 100644 specification/package.json delete mode 100644 specification/sidechain/AddressApis.ts delete mode 100644 specification/sidechain/FundingTransferApis.ts delete mode 100644 specification/sidechain/MicronoteApis.ts delete mode 100644 specification/sidechain/MicronoteBatchApis.ts delete mode 100644 specification/sidechain/NoteApis.ts delete mode 100644 specification/sidechain/RampApis.ts delete mode 100644 specification/sidechain/SidechainInfoApis.ts delete mode 100644 specification/sidechain/SidechainSnapshot.proto delete mode 100644 specification/sidechain/StakeApis.ts delete mode 100644 specification/sidechain/index.ts delete mode 100644 specification/tsconfig.dist.json delete mode 100644 specification/tsconfig.json delete mode 100644 specification/types/BlockError.ts delete mode 100644 specification/types/CoinageType.ts delete mode 100644 specification/types/IAddressOwnershipProof.ts delete mode 100644 specification/types/IAddressSignature.ts delete mode 100644 specification/types/IArithmeticEncoding.ts delete mode 100644 specification/types/IAuthorizedSidechain.ts delete mode 100644 specification/types/IBitDatumHistory.ts delete mode 100644 specification/types/IBlock.ts delete mode 100644 specification/types/IBlockHeader.ts delete mode 100644 specification/types/IBlockSettings.ts delete mode 100644 specification/types/ICoinage.ts delete mode 100644 specification/types/ICoordinator.ts delete mode 100644 specification/types/IDatum.ts delete mode 100644 specification/types/IDatumSummary.ts delete mode 100644 specification/types/IGrantTransfer.ts delete mode 100644 specification/types/IMerkleProof.ts delete mode 100644 specification/types/IMicronote.ts delete mode 100644 specification/types/IMicronoteBatch.ts delete mode 100644 specification/types/IMicronoteBatchDatums.ts delete mode 100644 specification/types/INote.ts delete mode 100644 specification/types/IProofOfKnowedge.ts delete mode 100644 specification/types/IStakeSettings.ts delete mode 100644 specification/types/IStakeSignature.ts delete mode 100644 specification/types/ITransaction.ts delete mode 100644 specification/types/ITransactionOutput.ts delete mode 100644 specification/types/ITransactionSource.ts delete mode 100644 specification/types/ITransactionSourceSignatureData.ts delete mode 100644 specification/types/IWebhitsClaimAddress.ts delete mode 100644 specification/types/IXoredCandidate.ts delete mode 100644 specification/types/IXoredCandidateSummary.ts delete mode 100644 specification/types/LedgerType.ts delete mode 100644 specification/types/NoteType.ts delete mode 100644 specification/types/TransactionError.ts delete mode 100644 specification/types/TransactionType.ts delete mode 100644 specification/utils/IZodApi.ts delete mode 100644 specification/utils/ValidatingApiHandler.ts delete mode 100644 specification/utils/ValidationError.ts diff --git a/commons/lib/asyncUtils.ts b/commons/lib/asyncUtils.ts index ea6ba54..05b59df 100644 --- a/commons/lib/asyncUtils.ts +++ b/commons/lib/asyncUtils.ts @@ -1,15 +1,25 @@ -export function debounce(func: () => any, wait: number): () => void { +export function debounce void | Promise>( + func: T, + wait: number, + maxWait?: number, +): T { let timeout: NodeJS.Timeout; + let lastRun: number; - return function runLater() { + return function runLater(...args: any[]) { function later(): void { timeout = undefined; - func(); + void func(...args); } - clearTimeout(timeout); - timeout = setTimeout(later, wait).unref(); - }; + + if (maxWait && Date.now() - lastRun > maxWait) { + void func(...args); + } else { + timeout = setTimeout(later, wait).unref(); + } + lastRun = Date.now(); + } as T; } export function length(source: AsyncIterable): Promise { diff --git a/commons/lib/objectUtils.ts b/commons/lib/objectUtils.ts index f7dc8de..eddc29c 100644 --- a/commons/lib/objectUtils.ts +++ b/commons/lib/objectUtils.ts @@ -22,3 +22,18 @@ export function omit( } return result; } + +export function pick( + object: T, + keys: Keys[], +): Pick> { + object = Object(object); + const result = {} as any; + + for (const [key, value] of Object.entries(object)) { + if (keys.includes(key as any)) { + result[key] = value; + } + } + return result; +} diff --git a/crypto/CHANGELOG.md b/crypto/CHANGELOG.md deleted file mode 100644 index ee06be6..0000000 --- a/crypto/CHANGELOG.md +++ /dev/null @@ -1,191 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -# [2.0.0-alpha.27](https://github.com/ulixee/shared/compare/v2.0.0-alpha.26...v2.0.0-alpha.27) (2024-03-01) - -**Note:** Version bump only for package @ulixee/crypto - - - - - -# [2.0.0-alpha.26](https://github.com/ulixee/shared/compare/v2.0.0-alpha.25...v2.0.0-alpha.26) (2024-02-02) - -**Note:** Version bump only for package @ulixee/crypto - - - - - -# [2.0.0-alpha.25](https://github.com/ulixee/shared/compare/v2.0.0-alpha.24...v2.0.0-alpha.25) (2023-09-28) - -**Note:** Version bump only for package @ulixee/crypto - - - - - -# [2.0.0-alpha.24](https://github.com/ulixee/shared/compare/v2.0.0-alpha.23...v2.0.0-alpha.24) (2023-08-09) - -**Note:** Version bump only for package @ulixee/crypto - - - - - -# [2.0.0-alpha.23](https://github.com/ulixee/shared/compare/v2.0.0-alpha.22...v2.0.0-alpha.23) (2023-07-07) - - -### Features - -* **commons:** add async iterator last function ([f4dd911](https://github.com/ulixee/shared/commit/f4dd9113341e37ce193455e5a55b30f99436daa9)) - - - - - -# [2.0.0-alpha.22](https://github.com/ulixee/shared/compare/v2.0.0-alpha.21...v2.0.0-alpha.22) (2023-06-12) - - -### Bug Fixes - -* **commons:** change default settings to data dir ([c6d5a34](https://github.com/ulixee/shared/commit/c6d5a3412e6876448e17734013ee76222d4c4e43)) -* **commons:** handle relative source map content ([2fa4cbc](https://github.com/ulixee/shared/commit/2fa4cbc6304c7547f98d0d64c68d62c827ddc921)) - - -### Features - -* **commons:** add priority to queue; lru cache ([f25caad](https://github.com/ulixee/shared/commit/f25caad300260aee6724f6daecc3dec110c28cce)) -* **commons:** buffer xor, toBigInt ([3d3c18a](https://github.com/ulixee/shared/commit/3d3c18af6cdb0dffa413b15c440a588b768f1ff2)) - - - - - -# [2.0.0-alpha.21](https://github.com/ulixee/shared/compare/v2.0.0-alpha.20...v2.0.0-alpha.21) (2023-04-24) - -**Note:** Version bump only for package @ulixee/crypto - - - - - -# [2.0.0-alpha.20](https://github.com/ulixee/shared/compare/v2.0.0-alpha.19...v2.0.0-alpha.20) (2023-04-19) - - -### Bug Fixes - -* **commons:** always handle emitter errors ([1c5f60f](https://github.com/ulixee/shared/commit/1c5f60f21c4c174c99c10e9e9d2edb07b06c28a0)) -* **commons:** global instance bug ([b895c0e](https://github.com/ulixee/shared/commit/b895c0e14602d92f42c559c6130d8a66b9b0770e)) -* **crypto:** disallow overwriting identity/address ([c14a185](https://github.com/ulixee/shared/commit/c14a1857c80ca800198d231236d5fcb6223026c9)) - - - - - -# [2.0.0-alpha.19](https://github.com/ulixee/shared/compare/v2.0.0-alpha.18...v2.0.0-alpha.19) (2023-02-25) - -**Note:** Version bump only for package @ulixee/crypto - - - - - -# [2.0.0-alpha.18](https://github.com/ulixee/shared/compare/v2.0.0-alpha.17...v2.0.0-alpha.18) (2023-01-17) - - -### Bug Fixes - -* **crypt:** don’t read pem if not provided ([cb825d1](https://github.com/ulixee/shared/commit/cb825d11712215c3a157f433e6b77dcd23230019)) - - -### Features - -* **specification:** credits api in datastore ([0dfab62](https://github.com/ulixee/shared/commit/0dfab6269e14c2d8cba99e860110732c58365a2e)) - - - - - -# [2.0.0-alpha.17](https://github.com/ulixee/shared/compare/v2.0.0-alpha.16...v2.0.0-alpha.17) (2022-12-15) - - -### Features - -* micronote apis conversion to hold/settle ([c03c6fd](https://github.com/ulixee/shared/commit/c03c6fd8c7d17c29a8347aaba7413920e859c556)) - - - - - -# [2.0.0-alpha.16](https://github.com/ulixee/shared/compare/v2.0.0-alpha.15...v2.0.0-alpha.16) (2022-12-05) - -**Note:** Version bump only for package @ulixee/crypto - - - - - -# [2.0.0-alpha.15](https://github.com/ulixee/shared/compare/v2.0.0-alpha.14...v2.0.0-alpha.15) (2022-11-17) - - -### Features - -* gift card api v2 to support redemption key ([b2f11f4](https://github.com/ulixee/shared/commit/b2f11f44a784adf8dd208db9683c99369f33f98c)) - - - - - -# [2.0.0-alpha.14](https://github.com/ulixee/shared/compare/v2.0.0-alpha.13...v2.0.0-alpha.14) (2022-11-02) - -**Note:** Version bump only for package @ulixee/crypto - - - - - -# [2.0.0-alpha.13](https://github.com/ulixee/shared/compare/v2.0.0-alpha.12...v2.0.0-alpha.13) (2022-10-31) - -**Note:** Version bump only for package @ulixee/crypto - - - - - -# [2.0.0-alpha.12](https://github.com/ulixee/shared/compare/v2.0.0-alpha.11...v2.0.0-alpha.12) (2022-10-03) - -**Note:** Version bump only for package @ulixee/crypto - - - - - -# [2.0.0-alpha.11](https://github.com/ulixee/shared/compare/v2.0.0-alpha.10...v2.0.0-alpha.11) (2022-08-31) - - -### Features - -* **commons:** env utils + timed cache ([8583846](https://github.com/ulixee/shared/commit/8583846f891cc1f93c079c8f6e3b1868ba7fcb5e)) - - - - - -# [2.0.0-alpha.10](https://github.com/ulixee/shared/compare/v2.0.0-alpha.9...v2.0.0-alpha.10) (2022-08-16) - -**Note:** Version bump only for package @ulixee/crypto - - - - - -# [2.0.0-alpha.9](https://github.com/ulixee/shared/compare/v2.0.0-alpha.8...v2.0.0-alpha.9) (2022-08-16) - - -### Features - -* add port in use fn ([b8c1a10](https://github.com/ulixee/shared/commit/b8c1a10c6da91a303d284e0e4c0723bc9f5dcf17)) -* specification, crypto projects ([fa61e3d](https://github.com/ulixee/shared/commit/fa61e3d221dacc3c1509309ebbfc7a05cf43923c)) diff --git a/crypto/bin/cli.ts b/crypto/bin/cli.ts deleted file mode 100644 index 501e5e2..0000000 --- a/crypto/bin/cli.ts +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env node - -import '@ulixee/commons/lib/SourceMapSupport'; -import cli from '../cli'; - -cli().name('@ulixee/crypto').parseAsync().catch(console.error); diff --git a/crypto/cli.ts b/crypto/cli.ts deleted file mode 100644 index 66370cb..0000000 --- a/crypto/cli.ts +++ /dev/null @@ -1,191 +0,0 @@ -import UlixeeConfig from '@ulixee/commons/config/index'; -import TypeSerializer from '@ulixee/commons/lib/TypeSerializer'; -import { assert } from '@ulixee/commons/lib/utils'; -import Identity from '@ulixee/crypto/lib/Identity'; -import { Command } from 'commander'; -import { randomBytes } from 'crypto'; -import * as Path from 'path'; -import IAddressSettings, { ISignerType } from './interfaces/IAddressSettings'; -import Address from './lib/Address'; -import Ed25519 from './lib/Ed25519'; - -const logError = (err: Error): void => { - console.log(`\nIDENTITIES ERROR: ${err.message}\n`); // eslint-disable-line no-console -}; - -const { version } = require('./package.json'); - -export default function cliCommands(): Command { - const cryptoCommands = new Command().version(version); - - cryptoCommands - .command('address') - .description('Create a new address.') - .argument( - '[signerPattern]', - 'The pattern of signing Identities you wish to create. Specify which actions each identity should be used for. T=Transfer, C=Claim, U=Universal. eg, TTC = 3 key ring with 2 transfer identities and 1 claim key', - 'U', - ) - .argument('[filename]', 'Where do you want to save this Address?', 'UlixeeAddress.json') - .option( - '-t, --transfer-signatures ', - 'How many signatures should be required for transfers?', - parseInt, - 1, - ) - .option( - '-s, --transfer-salt ', - 'Add salt (noise) to your transfer signatures', - randomBytes(32).toString('base64'), - ) - .option( - '-c, --claim-signatures ', - 'How many signatures should be required for claims (coinage claims, voting)?', - parseInt, - 1, - ) - .option( - '-d, --claim-salt ', - 'Add salt (noise) to your claims signatures', - randomBytes(32).toString('base64'), - ) - .option('-q, --quiet', "Don't log any details to the console.", false) - .action(async (signerPattern: string, filename: string, args): Promise => { - try { - const { transferSignatures, claimSignatures, transferSalt, claimSalt, quiet } = args; - const signersCount = signerPattern.length; - assert( - signerPattern.length <= 6, - 'A max of 6 signing Identities is allowed in an Address.', - ); - assert(signerPattern.length > 0, 'You must specify at least one key'); - assert( - signerPattern.match(/^[TCU]{1,6}$/i), - 'Valid signer options are T=Transfer, C=Claim, U=Universal', - ); - assert( - transferSignatures > 0, - 'You must require at least one transfer signature (-t, --transfer-signatures).', - ); - assert( - claimSignatures > 0, - 'You must require at least one claim signature (-c, --claim-signatures)', - ); - assert( - transferSignatures <= signersCount, - 'You cannot have more transfer signatures required than total identities', - ); - assert( - claimSignatures <= signersCount, - 'You cannot have more claim signatures required than total identities', - ); - - const signerTypes = [...signerPattern] as ISignerType[]; - const identities = await Promise.all(signerTypes.map(Identity.create)); - const addressSettings: IAddressSettings = { - signerTypes, - transferSignatureSettings: transferSignatures, - transferSignatureSalt: transferSalt ? Buffer.from(transferSalt) : null, - claimSignatureSettings: claimSignatures, - claimSignatureSalt: claimSalt ? Buffer.from(claimSalt) : null, - }; - - const address = Address.createFromSigningIdentities(identities, addressSettings); - - if (filename.endsWith('.json')) { - filename = filename.replace(Path.extname(filename), ''); - } - const filepath = await address.save(true, Path.basename(filename), Path.dirname(filename)); - if (!quiet) { - console.log('Wrote address: %s to %s', address.bech32, filepath); // eslint-disable-line no-console - console.log(TypeSerializer.stringify(address.toJSON(), { format: true })); // eslint-disable-line no-console - } - } catch (err) { - logError(err); - } - }); - - cryptoCommands - .command('identity') - .description( - 'Create an Identity (ed25519 key). It will be used to anonymously secure your network requests.', - ) - .option('-p, --passphrase ', 'Save the private key with a passphrase (pkcs8 format).') - .option( - '-c, --passphrase-cipher ', - 'Encrypt the internal key with a cipher (pkcs8 format).', - Identity.defaultPkcsCipher, - ) - .option( - '-f, --filename ', - 'Save this Identity to a filepath. If not specified, will be console logged.', - ) - .enablePositionalOptions(true) - .action(async ({ filename, passphraseCipher, passphrase }) => { - const identity = await Identity.create(); - - if (filename) { - await identity.save(filename, { passphrase, cipher: passphraseCipher }); - console.log('Saved to %s', filename); // eslint-disable-line no-console - } else { - console.log(identity.export(passphrase, passphraseCipher)); // eslint-disable-line no-console - } - }); - - cryptoCommands - .command('save-identity') - .description('Save an Identity PEM to a local file.') - .option('-k, --privateKey ', 'The private key bytes') - .option( - '-f, --filename ', - 'Save this Identity to a filepath. If not specified, will be placed in /identities.', - ) - .option('-p, --passphrase ', 'Save identity to a file with a passphrase.') - .option( - '-c, --passphrase-cipher ', - 'Encrypt the internal key with a cipher (pkcs8 format).', - Identity.defaultPkcsCipher, - ) - .action(async ({ privateKey, filename, passphraseCipher, passphrase }) => { - const ed25519 = Ed25519.createPrivateKeyFromBytes(Buffer.from(privateKey, 'base64')); - - const identity = new Identity(ed25519); - identity.verifyKeys(); - - filename ||= Path.join( - UlixeeConfig.global.directoryPath, - 'identities', - `${identity.bech32}.pem`, - ); - - await identity.save(filename, { passphrase, cipher: passphraseCipher }); - console.log('Saved %s to %s', identity.bech32, filename); // eslint-disable-line no-console - }); - - cryptoCommands - .command('read-identity') - .description('Output the bech32 value of an identity.') - .option('--pem ', 'The raw bytes of the PEM.') - .option( - '-f, --filename ', - 'Save this Identity to a filepath. If not specified, will be console logged.', - ) - .option('-p, --passphrase ', 'Save identity to a file with a passphrase.') - .enablePositionalOptions(true) - .action(({ pem, filename, passphrase }) => { - if (filename) { - const identity = Identity.loadFromFile(Path.resolve(process.cwd(), filename), { - keyPassphrase: passphrase, - }); - - console.log(identity.bech32); // eslint-disable-line no-console - } else { - pem = pem?.replaceAll('\\n', '\n'); - const identity = Identity.loadFromPem(pem, { keyPassphrase: passphrase }); - - console.log(identity.bech32); // eslint-disable-line no-console - } - }); - - return cryptoCommands; -} diff --git a/crypto/index.ts b/crypto/index.ts deleted file mode 100644 index e69de29..0000000 diff --git a/crypto/interfaces/IAddressSettings.ts b/crypto/interfaces/IAddressSettings.ts deleted file mode 100644 index 7960f20..0000000 --- a/crypto/interfaces/IAddressSettings.ts +++ /dev/null @@ -1,13 +0,0 @@ -export default interface IAddressSettings { - signerTypes: ISignerType[]; - transferSignatureSettings?: number; // default is all public keys - transferSignatureSalt?: Buffer; - claimSignatureSettings?: number; // default is only 1 key for claims - claimSignatureSalt?: Buffer; -} - -const UniversalSigner = 'U'; -const ClaimsSigner = 'C'; -const TransferSigner = 'T'; -type ISignerType = typeof UniversalSigner | typeof ClaimsSigner | typeof TransferSigner; -export { UniversalSigner, ClaimsSigner, ISignerType, TransferSigner }; diff --git a/crypto/lib/Address.ts b/crypto/lib/Address.ts deleted file mode 100644 index 5b7b757..0000000 --- a/crypto/lib/Address.ts +++ /dev/null @@ -1,205 +0,0 @@ -import MerkleTree from '@ulixee/crypto/lib/MerkleTree'; -import * as path from 'path'; -import * as fs from 'fs'; -import Identity from '@ulixee/crypto/lib/Identity'; -import TypeSerializer from '@ulixee/commons/lib/TypeSerializer'; -import IAddressSignature from '@ulixee/specification/types/IAddressSignature'; -import { encodeBuffer, decodeBuffer } from '@ulixee/commons/lib/bufferUtils'; -import IAddressSettings, { - ClaimsSigner, - TransferSigner, - UniversalSigner, -} from '../interfaces/IAddressSettings'; -import AddressOwnersTree from './AddressOwnersTree'; -import AddressSignature from './AddressSignature'; - -let isFilepathInitialized = false; - -export default class Address { - public static defaultDirname = 'addresses'; - - public readonly bech32: string; - public addressSettings: IAddressSettings; - public ownersMerkleTree: MerkleTree; - - public readonly transferSigners: Identity[] = []; - public readonly claimSigners: Identity[] = []; - - private readonly loadedIdentitiesAtIndexes: Identity[] = []; - - constructor( - merkleTreeLeaves: Buffer[], - settings: IAddressSettings, - loadedIdentitiesAtIndexes: (Identity | undefined)[], - ) { - this.loadedIdentitiesAtIndexes = loadedIdentitiesAtIndexes; - - this.addressSettings = settings ?? ({} as any); - this.addressSettings.signerTypes ??= loadedIdentitiesAtIndexes.map(() => UniversalSigner); - for (let i = 0; i <= loadedIdentitiesAtIndexes.length; i += 1) { - if (loadedIdentitiesAtIndexes[i]) { - const keyType = this.addressSettings.signerTypes[i]; - - if (keyType === UniversalSigner || keyType === TransferSigner) { - this.transferSigners.push(loadedIdentitiesAtIndexes[i]); - } - if (keyType === UniversalSigner || keyType === ClaimsSigner) { - this.claimSigners.push(loadedIdentitiesAtIndexes[i]); - } - } - } - this.addressSettings.transferSignatureSettings ||= this.transferSigners.length; - this.addressSettings.claimSignatureSettings ||= 1; - this.ownersMerkleTree = new MerkleTree(merkleTreeLeaves); - this.bech32 = Address.encodeAddress(this.ownersMerkleTree.getRoot()); - } - - public async save(format = false, filename?: string, relativeTo?: string): Promise { - const basePath = relativeTo || path.join(process.cwd(), Address.defaultDirname); - if (!isFilepathInitialized) { - if (!fs.existsSync(basePath)) fs.mkdirSync(basePath, { recursive: true }); - isFilepathInitialized = true; - } - - const json = TypeSerializer.stringify(this.toJSON(), { format }); - const filepath = path.resolve(basePath, `${filename || this.bech32}.json`); - if (fs.existsSync(filepath)) { - throw new Error('You attempted to overwrite an existing address!!'); - } - await fs.promises.writeFile(filepath, json, { encoding: 'utf8' }); - return filepath; - } - - public sign(hash: Buffer, identityIndexes: number[], isClaim = false): IAddressSignature { - const identities: Identity[] = []; - - for (let i = 0; i < this.loadedIdentitiesAtIndexes.length; i += 1) { - if (!identityIndexes.includes(i)) continue; - this.verifyKeyType(i, isClaim); - const key = this.loadedIdentitiesAtIndexes[i]; - if (key) identities.push(key); - } - - return AddressSignature.create( - hash, - identities, - this.ownersMerkleTree, - this.addressSettings, - isClaim, - ); - } - - public verifyKeyType(index: number, isClaim: boolean): void { - const keyType = this.addressSettings.signerTypes[index]; - const isUniversalKey = keyType === UniversalSigner; - - if (!isUniversalKey) { - if (isClaim && keyType !== ClaimsSigner) - throw new Error( - `Invalid key index provided (${index}). Index not valid for claim transactions.`, - ); - if (!isClaim && keyType !== TransferSigner) - throw new Error( - `Invalid key index provided (${index}). Index not valid for transfer transactions.`, - ); - } - } - - public equals(addressBech32: string): boolean { - return this.bech32 === addressBech32; - } - - public toJSON(): IAddressJson { - return { - settings: this.addressSettings, - bech32: this.bech32, - merkleLeaves: this.ownersMerkleTree.leaves, - loadedKeysAtIndexes: this.loadedIdentitiesAtIndexes.map(x => (x ? x.export() : null)), - }; - } - - public static verify( - addressBech32: string, - hashedMessage: Buffer, - signature: IAddressSignature, - isClaim = false, - ): boolean { - const treeRoot = this.decodeAddress(addressBech32); - const addressSignature = new AddressSignature(treeRoot, signature); - return !addressSignature.isInvalid(hashedMessage, isClaim); - } - - public static createFromSigningIdentities( - signingIdentities: Identity[], - settings?: IAddressSettings, - ): Address { - settings ??= { signerTypes: signingIdentities.map(() => UniversalSigner) }; - - settings.transferSignatureSettings ??= settings.signerTypes.filter( - x => x === UniversalSigner || x === TransferSigner, - ).length; - settings.claimSignatureSettings ??= 1; - - const merkleTree = AddressOwnersTree.create( - signingIdentities.map(x => x.bech32), - settings, - ); - settings.signerTypes ??= signingIdentities.map(() => UniversalSigner); - - return new Address(merkleTree.leaves, settings, signingIdentities); - } - - public static fromStored(stored: IAddressJson): Address { - const { merkleLeaves, loadedKeysAtIndexes, bech32, settings } = stored; - - const address = new Address( - merkleLeaves, - settings, - loadedKeysAtIndexes.map(x => (x ? Identity.loadFromPem(x) : null)), - ); - if (address.bech32 !== bech32) - throw new Error( - `Failed to load Address. Different key calculated. (calculated: ${address.bech32}, stored: ${bech32})`, - ); - return address; - } - - public static readFromPath(filepath: string, relativeToDir = process.cwd()): Address { - if (!path.isAbsolute(filepath)) filepath = path.resolve(relativeToDir, filepath); - const data = fs.readFileSync(filepath, { encoding: 'utf8' }); - const address = TypeSerializer.parse(data); - return Address.fromStored(address); - } - - public static readFromFile(addressBech32: string, relativeToDir = process.cwd()): Address { - const filepath = path.resolve(relativeToDir, Address.defaultDirname, `${addressBech32}.json`); - return Address.readFromPath(filepath); - } - - public static getIdentityIndices(settings: IAddressSettings, isClaim: boolean): number[] { - const identityIndices: number[] = []; - for (let i = 0; i < settings.signerTypes.length; i += 1) { - const type = settings.signerTypes[i]; - - if (type === UniversalSigner) identityIndices.push(i); - else if (isClaim && type === ClaimsSigner) identityIndices.push(i); - else if (!isClaim && type === TransferSigner) identityIndices.push(i); - } - return identityIndices; - } - - public static encodeAddress(treeRoot: Buffer): string { - return encodeBuffer(treeRoot, 'ar'); - } - - public static decodeAddress(addressBech32: string): Buffer { - return decodeBuffer(addressBech32, 'ar'); - } -} - -interface IAddressJson { - bech32: string; - merkleLeaves: Buffer[]; - settings: IAddressSettings; - loadedKeysAtIndexes: (string | null)[]; -} diff --git a/crypto/lib/AddressOwnersTree.ts b/crypto/lib/AddressOwnersTree.ts deleted file mode 100644 index 2599458..0000000 --- a/crypto/lib/AddressOwnersTree.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { sha256 } from '@ulixee/commons/lib/hashUtils'; -import assert = require('assert'); -import MerkleTree from '@ulixee/crypto/lib/MerkleTree'; -import { IMerkleProof } from '@ulixee/specification'; -import IAddressSettings, { - ClaimsSigner, - TransferSigner, - UniversalSigner, -} from '../interfaces/IAddressSettings'; - -export default class AddressOwnersTree { - public static getProof( - identity: string, - isClaim: boolean, - merkleTree: MerkleTree, - ): { - signatureSettings: IMerkleProof[]; - ownerIdentityProof: IMerkleProof[]; - } { - const signatureSettings = AddressOwnersTree.getSignatureSettingsProof(merkleTree, isClaim); - const ownerIdentityProof = AddressOwnersTree.getIdentityIsOwnerProof(merkleTree, identity); - return { - signatureSettings, - ownerIdentityProof, - }; - } - - public static getIdentityIsOwnerProof(merkleTree: MerkleTree, identity: string): IMerkleProof[] { - return merkleTree.getProof(sha256(identity)); - } - - public static getSignatureSettingsProof( - merkleTree: MerkleTree, - isClaim: boolean, - ): IMerkleProof[] { - return merkleTree.getProofForIndex(isClaim ? -1 : -2); - } - - public static create(identities: string[], details: IAddressSettings): MerkleTree { - const { claimSignatureSettings } = details; - - let signatureSettings = details.transferSignatureSettings; - - assert(identities.length > 0 && identities.length <= 6, 'Must provide 1-6 valid public key(s)'); - assert( - signatureSettings ? signatureSettings < 7 : true, - 'Must require 6 or less signatures in a multisig', - ); - if (!signatureSettings) { - signatureSettings = identities.length; - } - - const claimKeyIndices: number[] = []; - const transferKeyIndices: number[] = []; - for (let i = 0; i < details.signerTypes.length; i += 1) { - const type = details.signerTypes[i]; - if (type === UniversalSigner || type === ClaimsSigner) claimKeyIndices.push(i); - if (type === UniversalSigner || type === TransferSigner) transferKeyIndices.push(i); - } - - if (claimKeyIndices && claimKeyIndices.length) { - assert( - claimKeyIndices.length >= details.claimSignatureSettings, - 'Must provide enough valid public key indices to make claims', - ); - for (const index of claimKeyIndices) { - assert(index < identities.length, 'Claim index must be within range of public keys'); - } - } - - if (transferKeyIndices && transferKeyIndices.length) { - assert( - transferKeyIndices.length >= signatureSettings, - 'Must provide enough valid public key indices to make transfers', - ); - for (const index of transferKeyIndices) { - assert(index < identities.length, 'Transfer index must be within range of public keys'); - } - } - - const leaves = identities.map(sha256); - let fillLeaves = 2; - if (leaves.length > 2) { - fillLeaves = 6; - } - // fill up to 4 or 8 leaves so tree is balanced - while (leaves.length < fillLeaves) { - leaves.push( - // empty string hashed - Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), - ); - } - - leaves.push( - this.createLeaf(signatureSettings, details.transferSignatureSalt, transferKeyIndices), - ); - leaves.push( - this.createLeaf(claimSignatureSettings ?? 1, details.claimSignatureSalt, claimKeyIndices), - ); - - return new MerkleTree(leaves); - } - - public static createLeaf( - signatureSettings: number, - salt: Buffer, - publicKeyIndices: number[], - ): Buffer { - const parts = [ - signatureSettings ?? '', - salt?.toString('hex') ?? '', - publicKeyIndices?.join(',') ?? '', - ]; - return sha256(parts.join('')); - } -} diff --git a/crypto/lib/AddressSignature.ts b/crypto/lib/AddressSignature.ts deleted file mode 100644 index 2e221d8..0000000 --- a/crypto/lib/AddressSignature.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { IAddressOwnershipProof, IAddressSignature } from '@ulixee/specification'; -import Identity from '@ulixee/crypto/lib/Identity'; -import MerkleTree from '@ulixee/crypto/lib/MerkleTree'; -import { sha256 } from '@ulixee/commons/lib/hashUtils'; -import { MerklePosition } from '@ulixee/specification/types/IMerkleProof'; -import IAddressSettings from '../interfaces/IAddressSettings'; -import AddressOwnersTree from './AddressOwnersTree'; -import Address from './Address'; - -export default class AddressSignature { - public get signatureSettings(): IAddressSignature['signatureSettings'] { - return this.signature.signatureSettings; - } - - constructor(readonly treeRoot: Buffer, readonly signature: IAddressSignature) {} - - public isValidSignaturePosition(isClaim: boolean): boolean { - const proofsToRight = this.signatureSettings.settingsMerkleProofs.filter( - x => x.position === MerklePosition.Right, - ).length; - - // if this is a claim, must have no proofs to the right - if (isClaim && proofsToRight > 0) { - return false; - } - // if this is a transfer, there must be 1 proof to the right - if ( - isClaim === false && - (proofsToRight !== 1 || - this.signatureSettings.settingsMerkleProofs[0].position !== MerklePosition.Right) - ) { - return false; - } - return true; - } - - public isValidWalletOwnershipProof(owner: IAddressOwnershipProof): boolean { - const isValidProof = MerkleTree.verify( - owner.ownershipMerkleProofs, - sha256(owner.identity), - this.treeRoot, - ); - if (!isValidProof) return false; - - const identityIndices = this.signature.signatureSettings.identityIndices; - if (identityIndices && identityIndices.length) { - const index = MerkleTree.getLeafIndex(owner.ownershipMerkleProofs); - if (identityIndices.includes(index) === false) { - return false; - } - } - return true; - } - - public isValidSignatureSettingsProof(): boolean { - // verify the signature count location - return MerkleTree.verify( - this.signatureSettings.settingsMerkleProofs, - AddressOwnersTree.createLeaf( - this.signatureSettings.countRequired, - this.signatureSettings.salt, - this.signatureSettings.identityIndices, - ), - this.treeRoot, - ); - } - - public isInvalid(messageHash: Buffer, isClaim: boolean): string { - const isValidSignatureSettings = - this.isValidSignatureSettingsProof() && this.isValidSignaturePosition(isClaim); - if (!isValidSignatureSettings) { - return 'Invalid RequiredSignatureSettings proof provided'; - } - - const signatures: Buffer[] = []; - const seenIdentities = new Set(); - for (const signer of this.signature.signers) { - const identity = signer.identity; - if (seenIdentities.has(identity)) { - continue; - } - seenIdentities.add(identity); - const isValidIdentity = this.isValidWalletOwnershipProof(signer); - if (isValidIdentity === false) { - return 'Invalid public key provided'; - } - - /** - * verify signatures of each public key - */ - const isMatch = Identity.verify( - signer.identity, - sha256(Buffer.concat([messageHash, ...signatures])), - signer.signature, - ); - if (isMatch === false) { - return 'Invalid signature provided'; - } - signatures.push(signer.signature); - } - - // ensure signatures are unique - if (seenIdentities.size < this.signatureSettings.countRequired) { - return `Insufficient public key signatures provided ${seenIdentities.size} vs ${this.signatureSettings.countRequired} required`; - } - return null; - } - - public static buildSignatureSettings( - addressTree: MerkleTree, - addressSettings: IAddressSettings, - isClaim = false, - ): IAddressSignature['signatureSettings'] { - return { - countRequired: isClaim - ? addressSettings.claimSignatureSettings - : addressSettings.transferSignatureSettings, - settingsMerkleProofs: addressTree.getProofForIndex(isClaim ? -1 : -2), // notes are all transfers - salt: isClaim ? addressSettings.claimSignatureSalt : addressSettings.transferSignatureSalt, - identityIndices: Address.getIdentityIndices(addressSettings, isClaim), - }; - } - - public static create( - hash: Buffer, - identities: Identity[], - addressOwnersTree: MerkleTree, - addressSettings: IAddressSettings, - isClaim = false, - ): IAddressSignature { - const signatures: Buffer[] = []; - return { - signers: identities.map(identity => { - const identityProof = AddressOwnersTree.getIdentityIsOwnerProof( - addressOwnersTree, - identity.bech32, - ); - const ownerProof: IAddressOwnershipProof = { - ownershipMerkleProofs: identityProof, - identity: identity.bech32, - signature: identity.sign(sha256(Buffer.concat([hash, ...signatures]))), - }; - signatures.push(ownerProof.signature); - return ownerProof; - }), - signatureSettings: AddressSignature.buildSignatureSettings( - addressOwnersTree, - addressSettings, - isClaim, - ), - }; - } - - public static verify( - address: string, - signature: IAddressSignature, - messageHash: Buffer, - isClaim: boolean, - ): string | null { - const root = Address.decodeAddress(address); - return new AddressSignature(root, signature).isInvalid(messageHash, isClaim); - } -} diff --git a/crypto/lib/Ed25519.ts b/crypto/lib/Ed25519.ts deleted file mode 100644 index 3c7320e..0000000 --- a/crypto/lib/Ed25519.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { - createPrivateKey, - createPublicKey, - generateKeyPair, - KeyObject, - KeyPairKeyObjectResult, - sign, - verify, -} from 'crypto'; -import { promisify } from 'util'; - -const ed25519DerPrefix = Buffer.from('302a300506032b6570032100', 'hex'); -const ed25519PrivateDerPrefix = Buffer.from('302e020100300506032b657004220420', 'hex'); -const generateKeyPairAsync = promisify(generateKeyPair); - -export default class Ed25519 { - static getPublicKeyBytes(privateKey: KeyObject): Buffer { - return createPublicKey(privateKey) - .export({ type: 'spki', format: 'der' }) - .slice(ed25519DerPrefix.length); - } - - static getPrivateKeyBytes(key: KeyObject): Buffer { - return key.export({ type: 'pkcs8', format: 'der' }).slice(ed25519PrivateDerPrefix.length); - } - - static createPublicKeyFromBytes(bytes: Buffer): KeyObject { - if (bytes.length !== 32) { - throw new Error( - `Wrong key length (${bytes.length}) provided to createPublicKeyFromBytes. Must be 32 bytes (20 hex chars)`, - ); - } - const keyDer = Buffer.concat([ed25519DerPrefix, bytes]); - - return createPublicKey({ key: keyDer, format: 'der', type: 'spki' }); - } - - static createPrivateKeyFromBytes(bytes: Buffer): KeyObject { - if (bytes.length !== 32) { - throw new Error( - `Wrong key length (${bytes.length}) provided to importPublicKey. Must be 32 bytes (20 hex chars)`, - ); - } - const keyDer = Buffer.concat([ed25519PrivateDerPrefix, bytes]); - - return createPrivateKey({ key: keyDer, format: 'der', type: 'pkcs8' }); - } - - static async create(): Promise { - return await generateKeyPairAsync('ed25519'); - } - - static verify(publicKey: KeyObject, hashedMessage: Buffer, signature: Buffer): Error | boolean { - if (!signature || !signature.length || !hashedMessage || !hashedMessage.length || !publicKey) - return false; - - try { - return verify(null, hashedMessage, publicKey, signature); - } catch (e) { - return e; - } - } - - static sign(keyObject: KeyObject, hashedMessage: Buffer): Buffer { - if (hashedMessage.byteLength !== 32) - throw new Error( - 'Attempting to sign a non 256 bit value. Only provide hashed values to sign!!', - ); - return sign(null, hashedMessage, keyObject); - } -} diff --git a/crypto/lib/Identity.ts b/crypto/lib/Identity.ts deleted file mode 100644 index 35484eb..0000000 --- a/crypto/lib/Identity.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { promises as fs, readFileSync, existsSync } from 'fs'; -import * as path from 'path'; -import { createPrivateKey, generateKeyPairSync, KeyExportOptions, KeyObject } from 'crypto'; -import { sha256 } from '@ulixee/commons/lib/hashUtils'; -import { existsAsync } from '@ulixee/commons/lib/fileUtils'; -import Log from '@ulixee/commons/lib/Logger'; -import { decodeBuffer, encodeBuffer } from '@ulixee/commons/lib/bufferUtils'; -import Ed25519 from './Ed25519'; -import { UnreadableIdentityError } from './errors'; - -const { log } = Log(module); - -export default class Identity { - public static defaultPkcsCipher = 'aes-256-cbc'; - public static encodingPrefix = 'id' as const; - public readonly privateKey: KeyObject; - - public get bech32(): string { - this.#bech32 ??= encodeBuffer(this.publicKey, Identity.encodingPrefix); - return this.#bech32; - } - - public get publicKey(): Buffer { - this.#publicKeyBytes ??= Ed25519.getPublicKeyBytes(this.privateKey); - return this.#publicKeyBytes; - } - - #bech32: string; - #publicKeyBytes: Buffer; - - constructor(privateKey: KeyObject) { - if (!privateKey) { - throw new UnreadableIdentityError(`Cannot read private key`); - } - this.privateKey = privateKey; - } - - public sign(hashedMessage: Buffer): Buffer { - return Ed25519.sign(this.privateKey, hashedMessage); - } - - public equals(identityBech32: string): boolean { - return this.bech32 === identityBech32; - } - - public verifyKeys(): void { - const hashedMessage = sha256(Buffer.from('signed_test_message')); - const signature = this.sign(hashedMessage); - const isValid = Identity.verify(this.bech32, hashedMessage, signature); - if (!isValid) { - throw new UnreadableIdentityError( - 'This Identity private key does not match the ED25519 spec', - ); - } - } - - public export(passphrase?: string, cipher?: string): string { - const options: KeyExportOptions<'pem'> = { - type: 'pkcs8', - format: 'pem', - }; - if (passphrase) { - options.passphrase = passphrase; - options.cipher = cipher ?? Identity.defaultPkcsCipher; - } - return this.privateKey.export(options) as string; - } - - public toJSON(): string { - return this.bech32; - } - - public toString(): string { - return this.bech32; - } - - public async save( - filepath: string, - options?: { passphrase?: string; cipher?: string }, - ): Promise { - if (filepath) { - if (!path.isAbsolute(filepath)) { - filepath = path.join(process.cwd(), filepath); - } - if (!(await existsAsync(path.dirname(filepath)))) { - await fs.mkdir(path.dirname(filepath), { recursive: true }); - } - } - if (!filepath) throw new Error('No valid filepath was provided'); - if (existsSync(filepath)) { - throw new Error('You attempted to overwrite an existing Identity!! Please remove it first.'); - } - - await fs.writeFile(filepath, this.export(options?.passphrase, options?.cipher)); - return filepath; - } - - // CLASS METHODS //////////////////////// - - public static loadFromFile( - filepath: string, - options?: { relativeToPath?: string; keyPassphrase?: string }, - ): Identity { - if (!path.isAbsolute(filepath)) { - filepath = path.join(options?.relativeToPath ?? process.cwd(), filepath); - } - const data = readFileSync(filepath, 'utf8'); - return Identity.loadFromPem(data, options); - } - - public static loadFromPem(data: string, options?: { keyPassphrase?: string }): Identity { - const privateKey = createPrivateKey({ - key: data, - format: 'pem', - type: 'pkcs8', - passphrase: options?.keyPassphrase, - }); - const identity = new Identity(privateKey); - identity.verifyKeys(); - return identity; - } - - public static createSync(): Identity { - const key = generateKeyPairSync('ed25519'); - const identity = new Identity(key.privateKey); - identity.verifyKeys(); - return identity; - } - - public static getBytes(encoded: string): Buffer { - return decodeBuffer(encoded, Identity.encodingPrefix); - } - - public static async create(): Promise { - const key = await Ed25519.create(); - const pair = new Identity(key.privateKey); - pair.verifyKeys(); - return pair; - } - - public static verify(identityBech32: string, hashedMessage: Buffer, signature: Buffer): boolean { - if (!identityBech32) return false; - const publicKeyBytes = Identity.getBytes(identityBech32); - - const publicKey = Ed25519.createPublicKeyFromBytes(publicKeyBytes); - const isValid = Ed25519.verify(publicKey, hashedMessage, signature); - if (isValid === true) return true; - - if (isValid instanceof Error) { - log.error('Error validating signature', { - error: isValid, - }); - } - return false; - } -} diff --git a/crypto/lib/MerkleTree.ts b/crypto/lib/MerkleTree.ts deleted file mode 100644 index b80845b..0000000 --- a/crypto/lib/MerkleTree.ts +++ /dev/null @@ -1,213 +0,0 @@ -import { sha256 } from '@ulixee/commons/lib/hashUtils'; -import IMerkleProof, { MerklePosition } from '@ulixee/specification/types/IMerkleProof'; - -/** - * Use sha256 instead of default keccak used in the network. - * This ensures the leaves have a different (albeit slight) encoding - * - * Keccak has different padding than sha256 - * @param content - */ -function createHash(content: Buffer | string): Buffer { - return sha256(content); -} - -interface Layer { - nodes: Buffer[]; -} - -/** - * Class reprensenting a Merkle Tree - converted to typescript from: - * https://github.com/miguelmota/merkletreejs - * - * @namespace MerkleTree - */ -export default class MerkleTree { - public readonly leaves: Buffer[]; - public layers: Layer[]; - // NOTE: should be different than leaf algorithm to block second pre-image attacks - public nodeHashAlgorithm: (data: Buffer | string) => Buffer = createHash; - - /** - * @desc Constructs a Merkle Tree. - * All nodes and leaves are stored as Buffers. - * Lonely leaf nodes are promoted to the next level up without being hashed again. - * @param {Buffer[]} leaves - Array of hashed leaves. Each leaf must be a Buffer. - * @param nodeHashAlgorithm? {(data: Buffer | string) => Buffer}: Buffer) - if you need to override the algorithm for creating nodes - * - * const leaves = ['a', 'b', 'c'].map(x => createHash(x)) - * - * const tree = new MerkleTree(leaves) - */ - constructor(leaves: Buffer[], nodeHashAlgorithm?: (data: Buffer | string) => Buffer) { - this.leaves = leaves; - this.layers = [{ nodes: this.leaves }]; - if (nodeHashAlgorithm) { - this.nodeHashAlgorithm = nodeHashAlgorithm; - } - - this.createPyramid(this.leaves); - } - - /** - * getRoot - * @desc Returns the Merkle root hash as a Buffer. - * @return {Buffer} - * @example - * const root = tree.getRoot() - */ - public getRoot(): Buffer { - return this.layers[this.layers.length - 1].nodes[0] || Buffer.from([]); - } - - /** - * getProof - * @desc Returns the proof for a target leaf. - * @param {Buffer} leaf - Target leaf - * @param {Number} [index] - Target leaf index in leaves array. - * Use if there are leaves containing duplicate data in order to distinguish it. - * @return {IMerkleProof[]} - Array of objects containing a position property of type string - * with values of 'left' or 'right' and a data property of type Buffer. - * @example - * const proof = tree.getProof(leaves[2]) - * - * @example - * const leaves = ['a', 'b', 'a'].map(x => sha256(x)) - * const tree = new MerkleTree(leaves, sha256) - * const proof = tree.getProof(leaves[2], 2) - */ - public getProof(leaf: Buffer, index?: number): IMerkleProof[] { - let finalIndex = index; - if (typeof index !== 'number') { - finalIndex = this.leaves.findIndex(x => Buffer.compare(x, leaf) === 0); - } - - if (finalIndex <= -1) { - return []; - } - - return this.getProofForIndex(finalIndex); - } - - public getProofForIndex(index: number): IMerkleProof[] { - const proof: IMerkleProof[] = []; - - let finalIndex = index; - if (finalIndex < 0) { - finalIndex = this.leaves.length + finalIndex; - } - - for (const layer of this.layers) { - const isRightNode = finalIndex % 2; - const pairIndex = isRightNode ? finalIndex - 1 : finalIndex + 1; - - if (pairIndex < layer.nodes.length) { - const position = isRightNode ? MerklePosition.Left : MerklePosition.Right; - const thisProof = { hash: layer.nodes[pairIndex], position }; - proof.push(thisProof); - } - - // set finalIndex to parent finalIndex - finalIndex = (finalIndex / 2) | 0; - } - - return proof; - } - - private buildLayer(nodes: Buffer[]): Layer { - const layer: Layer = { nodes: [] }; - /** - * Go bottom up creating layers in a pyramid - */ - for (let i = 0; i < nodes.length - 1; i += 2) { - const left = nodes[i]; - const right = nodes[i + 1]; - const data = Buffer.concat([left, right]); - const hash = this.nodeHashAlgorithm(data); - - layer.nodes.push(hash); - } - - // is odd number of nodeTraversal - if (nodes.length % 2 === 1) { - // don't double hash - just push - const alreadyHashed = nodes[nodes.length - 1]; - layer.nodes.push(alreadyHashed); - } - return layer; - } - - private createPyramid(nodes: Buffer[]): void { - let nodeTraversal = nodes; - while (nodeTraversal.length > 1) { - /** - * create layer of the pyramid - */ - this.layers.push(this.buildLayer(nodeTraversal)); - - /** - * now combine entries from top layer (we keep going until there's only 1 entry) - */ - nodeTraversal = this.layers[this.layers.length - 1].nodes; - } - } - - /** - * verify - * @desc Returns true if the proof path (array of hashes) can connect the target node - * to the Merkle root. - * @param {IMerkleProof[]} proof - Array of proof objects that should connect - * target node to Merkle root. - * @param {Buffer} targetNode - Target node Buffer - * @param {Buffer} root - Merkle root Buffer - * @param {function} nodeHashAlgorithm - Function to hash nodes - * @return {Boolean} - * @example - * const root = tree.getRoot() - * const proof = tree.getProof(leaves[2]) - * const verified = tree.verify(proof, leaves[2], root) - * - */ - public static verify( - proof: IMerkleProof[], - targetNode: Buffer, - root: Buffer, - nodeHashAlgorithm: (data: Buffer | string) => Buffer = createHash, - ): boolean { - let hash = targetNode; - - if (!proof.length || !targetNode || !root) { - return false; - } - - for (const node of proof) { - const buffers = [hash]; - const nodeBuffer = node.hash; - if (node.position === MerklePosition.Left) { - buffers.unshift(nodeBuffer); - } else { - buffers.push(nodeBuffer); - } - - hash = nodeHashAlgorithm(Buffer.concat(buffers)); - } - - return Buffer.compare(hash, root) === 0; - } - - /** - * Get the index that the given proof correlates to. NOTE: only works in a balanced tree - * @param proof {IMerkleProof[]} - */ - public static getLeafIndex(proof: IMerkleProof[]): number { - let position = 0; - let layer = 0; - for (const p of proof) { - if (p.position === MerklePosition.Left) { - position += 2 ** layer; - } - layer += 1; - } - return position; - } -} diff --git a/crypto/lib/errors.ts b/crypto/lib/errors.ts deleted file mode 100644 index 623b32b..0000000 --- a/crypto/lib/errors.ts +++ /dev/null @@ -1,20 +0,0 @@ -// eslint-disable-next-line max-classes-per-file -import { UlixeeError } from '@ulixee/commons/lib/errors'; - -export class InvalidSignatureError extends UlixeeError { - constructor(message, readonly details = {}) { - super(message, 'ERR_SIGNATURE_INVALID', { details }); - } -} - -export class UnreadableIdentityError extends UlixeeError { - constructor(message) { - super(message, 'ERR_IDENTITY_UNREADABLE'); - } -} - -export class InvalidIdentityError extends UlixeeError { - constructor(message) { - super(message, 'ERR_IDENTITY_INVALID'); - } -} diff --git a/crypto/package.json b/crypto/package.json deleted file mode 100644 index 6fc2450..0000000 --- a/crypto/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "@ulixee/crypto", - "version": "2.0.0-alpha.27", - "description": "Common crypto tools for Ulixee", - "license": "MIT", - "bin": "./bin/cli.js", - "dependencies": { - "@ulixee/commons": "2.0.0-alpha.27", - "@ulixee/crypto": "2.0.0-alpha.27", - "@ulixee/specification": "2.0.0-alpha.27", - "bignumber.js": "^9.0.2", - "commander": "^9.5.0" - } -} diff --git a/crypto/test/Address.test.ts b/crypto/test/Address.test.ts deleted file mode 100644 index a285f4c..0000000 --- a/crypto/test/Address.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import Identity from '@ulixee/crypto/lib/Identity'; -import Address from '../lib/Address'; -import AddressSignature from '../lib/AddressSignature'; -import { ClaimsSigner, UniversalSigner } from '../interfaces/IAddressSettings'; - -let address: Address; -let identity1: Identity; -let identity2: Identity; - -beforeAll(async () => { - [identity1, identity2] = await Promise.all([Identity.create(), Identity.create()]); - address = Address.createFromSigningIdentities([identity1, identity2], { - claimSignatureSettings: 1, - transferSignatureSettings: 1, - signerTypes: [UniversalSigner, ClaimsSigner], - }); -}); - -test('should validate the keys match the allowed keys', async () => { - expect(address.bech32).toBeTruthy(); - expect(address.transferSigners).toHaveLength(1); - expect(address.claimSigners).toHaveLength(2); - const hash = Buffer.from('hash'); - jest.spyOn(address, 'verifyKeyType').mockImplementationOnce(() => null); - const signature = address.sign(hash, [1]); - - expect(AddressSignature.verify(address.bech32, signature, hash, false)).toBe( - 'Invalid public key provided', - ); -}); - -test('should allow the proper keys if provided', async () => { - const signature = address.sign(Buffer.from('hash'), [0]); - - expect( - AddressSignature.verify(address.bech32, signature, Buffer.from('hash'), false), - ).toBeNull(); -}); - -test('should be able to save to a file and recreate', async () => { - const filePath = await address.save(); - expect(filePath.endsWith(`${address.bech32}.json`)).toBe(true); - - const wallet2 = Address.readFromFile(address.bech32); - - expect(wallet2.ownersMerkleTree).toBeTruthy(); - expect(wallet2.transferSigners.map(x => x.publicKey.toString('hex'))).toEqual( - address.transferSigners.map(x => x.publicKey.toString('hex')), - ); - const signature = wallet2.sign(Buffer.from('claim'), [0], true); - - expect(Address.verify(wallet2.bech32, Buffer.from('claim'), signature, true)).toBe(true); -}); diff --git a/crypto/test/Ed25519.test.ts b/crypto/test/Ed25519.test.ts deleted file mode 100644 index aad90c6..0000000 --- a/crypto/test/Ed25519.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import Ed25519 from '../lib/Ed25519'; - -test('can create and restore public ed25519 key bytes', async () => { - const keys = await Ed25519.create(); - const publicKeyBytes = Ed25519.getPublicKeyBytes(keys.privateKey); - expect(keys.publicKey).toEqual(Ed25519.createPublicKeyFromBytes(publicKeyBytes)); -}); - -test('can create and restore private ed25519 key bytes', async () => { - const keys = await Ed25519.create(); - const privateKeyBytes = Ed25519.getPrivateKeyBytes(keys.privateKey); - const privateKeyString = keys.privateKey.export({ format: 'der', type: 'pkcs8' }).toString('hex'); - const recreatedPk = Ed25519.createPrivateKeyFromBytes(privateKeyBytes); - expect(recreatedPk.export({ format: 'der', type: 'pkcs8' }).toString('hex')).toBe( - privateKeyString, - ); - expect(Ed25519.getPrivateKeyBytes(recreatedPk)).toEqual(privateKeyBytes); -}); diff --git a/crypto/test/Identity.test.ts b/crypto/test/Identity.test.ts deleted file mode 100644 index 3f62cb5..0000000 --- a/crypto/test/Identity.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import Identity from '../lib/Identity'; - -test('can create an identity', async () => { - await expect(Identity.create()).resolves.toBeTruthy(); -}); - -test('can reload an identity', async () => { - const identity = await Identity.create(); - const pem = identity.export(); - - const identity2 = Identity.loadFromPem(pem); - expect(identity2.publicKey).toEqual(identity.publicKey); - expect(identity2.bech32).toEqual(identity.bech32); - expect(identity2.publicKey).toHaveLength(32); - expect(identity2.privateKey.type).toBe(identity.privateKey.type); - expect(identity2.privateKey.asymmetricKeyType).toBe(identity.privateKey.asymmetricKeyType); - expect(identity2.privateKey.asymmetricKeySize).toBe(identity.privateKey.asymmetricKeySize); -}); - -test('can create a passphrase protected private key', async () => { - const identity = await Identity.create(); - const pem = identity.export('password1'); - - expect(() => { - Identity.loadFromPem(pem, { keyPassphrase: 'p' }); - }).toThrow(); - - const identity2 = Identity.loadFromPem(pem, { keyPassphrase: 'password1' }); - expect(identity2.bech32).toEqual(identity.bech32); -}); diff --git a/crypto/test/Merkle.model.test.ts b/crypto/test/Merkle.model.test.ts deleted file mode 100644 index c88c8f0..0000000 --- a/crypto/test/Merkle.model.test.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { createHash } from 'crypto'; -import { MerklePosition } from '@ulixee/specification/types/IMerkleProof'; -import MerkleTree from '../lib/MerkleTree'; - -function sha256(data: string): Buffer { - return createHash('sha256').update(Buffer.from(data, 'hex')).digest(); -} - -function sha3(data: string | Buffer): Buffer { - return createHash('sha3-256').update(data).digest(); -} - -test('sha256 nodes with sha3 leaves', () => { - const leaves = ['a', 'b', 'c'].map(sha3); - - const tree = new MerkleTree(leaves, sha256); - - const root = '49d2d1a14929a8f556bd6f4a698d90a48c9d1ca5a562773010dfdc93f8340ab9'; - expect(tree.getRoot().toString('hex')).toBe(root); -}); - -test('sha3', () => { - expect.assertions(20); - - const leaves = ['a', 'b', 'c'].map(sha3); - - const aHash = Buffer.from( - '80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b', - 'hex', - ); - const bHash = Buffer.from( - 'b039179a8a4ce2c252aa6f2f25798251c19b75fc1508d9d511a191e0487d64a7', - 'hex', - ); - const cHash = Buffer.from( - '263ab762270d3b73d3e2cddf9acc893bb6bd41110347e5d5e4bd1d3c128ea90a', - 'hex', - ); - - expect(leaves).toEqual([aHash, bHash, cHash]); - - const tree = new MerkleTree(leaves, sha3); - - const layers = tree.layers.slice(1); // no leaves - - const layer1 = sha3(Buffer.concat([leaves[0], leaves[1]])); - expect(layers[0].nodes[0]).toEqual(layer1); - expect(layers[0].nodes[1]).toEqual(cHash); - - const root = Buffer.from( - 'b940dc53d707e4d9dfe9300664c6bbc4ab0c9f045d74441bfeda030cedbdbcba', - 'hex', - ); - expect(tree.getRoot().toString('hex')).toEqual(root.toString('hex')); - - const proof0 = tree.getProof(leaves[0]); - expect(proof0.length).toBe(2); - expect(proof0[0].position).toBe(MerklePosition.Right); - expect(proof0[0].hash).toEqual(bHash); - expect(proof0[1].position).toBe(MerklePosition.Right); - expect(proof0[1].hash).toEqual(cHash); - - expect(MerkleTree.verify(proof0, leaves[0], root, sha3)).toBe(true); - - const proof1 = tree.getProof(leaves[1]); - expect(proof1.length).toBe(2); - expect(proof1[0].position).toBe(MerklePosition.Left); - expect(proof1[0].hash).toEqual(aHash); - expect(proof1[1].position).toBe(MerklePosition.Right); - expect(proof1[1].hash).toEqual(cHash); - - expect(MerkleTree.verify(proof1, leaves[1], root, sha3)).toBe(true); - - const proof2 = tree.getProof(leaves[2]); - expect(proof2.length).toBe(1); - expect(proof2[0].position).toBe(MerklePosition.Left); - expect(proof2[0].hash).toEqual(layer1); - - expect(MerkleTree.verify(proof2, leaves[2], root, sha3)).toBe(true); -}); - -test('sha3 [keccak-256] with duplicate leaves', () => { - const leaves = ['a', 'b', 'a'].map(sha3); - - const aHash = '80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b'; - const bHash = 'b039179a8a4ce2c252aa6f2f25798251c19b75fc1508d9d511a191e0487d64a7'; - - const tree = new MerkleTree(leaves, sha3); - - expect(leaves.map(x => x.toString('hex'))).toEqual([aHash, bHash, aHash]); - - expect(tree.getRoot().toString('hex')).toEqual('e0c866810cf325979eca6987adb9bc627720a3b9502d620b1d6608ee765f07dd'); - - const layer1 = sha3(Buffer.concat([leaves[0], leaves[1]])); - - const proof0 = tree.getProof(leaves[2], 2); - expect(proof0.length).toBe(1); - expect(proof0[0].position).toBe(MerklePosition.Left); - expect(proof0[0].hash).toEqual(layer1); -}); - -test('sha256 - no leaves', () => { - const leaves = []; - const tree = new MerkleTree(leaves, sha256); - - const root = ''; - expect(tree.getRoot().toString('hex')).toBe(root); -}); - -test('should be able to find indices by proof (balanced trees only)', () => { - const leaves2x = ['a', 'b', 'c', 'd'].map(sha3); - const tree2x = new MerkleTree(leaves2x, sha256); - { - // proof 0 - const proof = tree2x.getProofForIndex(0); - expect(proof).toHaveLength(2); - expect(proof[0].position).toBe(MerklePosition.Right); - expect(proof[1].position).toBe(MerklePosition.Right); - expect(MerkleTree.getLeafIndex(proof)).toBe(0); - } - { - // proof 1 - const proof = tree2x.getProofForIndex(1); - expect(proof).toHaveLength(2); - expect(proof[0].position).toBe(MerklePosition.Left); // 1 - expect(proof[1].position).toBe(MerklePosition.Right); // 0 - expect(MerkleTree.getLeafIndex(proof)).toBe(1); - } - { - // proof 2 - const proof = tree2x.getProofForIndex(2); - expect(proof).toHaveLength(2); - expect(proof[0].position).toBe(MerklePosition.Right); // 0 - expect(proof[1].position).toBe(MerklePosition.Left); // 2 - expect(MerkleTree.getLeafIndex(proof)).toBe(2); - } - { - // proof 3 - const proof = tree2x.getProofForIndex(3); - expect(proof).toHaveLength(2); - expect(proof[0].position).toBe(MerklePosition.Left); // 1 - expect(proof[1].position).toBe(MerklePosition.Left); // 2 - expect(MerkleTree.getLeafIndex(proof)).toBe(3); - } - - const leaves = ['a', 'b', 'c', 'd', '0', '0', '1', '2'].map(sha3); - const tree = new MerkleTree(leaves, sha256); - { - // proof 0 - const proof = tree.getProofForIndex(0); - expect(proof).toHaveLength(3); - expect(proof[0].position).toBe(MerklePosition.Right); - expect(proof[1].position).toBe(MerklePosition.Right); - expect(proof[2].position).toBe(MerklePosition.Right); - expect(MerkleTree.getLeafIndex(proof)).toBe(0); - } - { - // proof 1 - const proof = tree.getProofForIndex(1); - expect(proof).toHaveLength(3); - expect(proof[0].position).toBe(MerklePosition.Left); // 1 - expect(proof[1].position).toBe(MerklePosition.Right); // 0 - expect(proof[2].position).toBe(MerklePosition.Right); // 0 - expect(MerkleTree.getLeafIndex(proof)).toBe(1); - } - { - // proof 2 - const proof = tree.getProofForIndex(2); - expect(proof).toHaveLength(3); - expect(proof[0].position).toBe(MerklePosition.Right); // 0 - expect(proof[1].position).toBe(MerklePosition.Left); // 2 - expect(proof[2].position).toBe(MerklePosition.Right); // 0 - expect(MerkleTree.getLeafIndex(proof)).toBe(2); - } - { - // proof 3 - const proof = tree.getProofForIndex(3); - expect(proof).toHaveLength(3); - expect(proof[0].position).toBe(MerklePosition.Left); // 1 - expect(proof[1].position).toBe(MerklePosition.Left); // 2 - expect(proof[2].position).toBe(MerklePosition.Right); // 0 - expect(MerkleTree.getLeafIndex(proof)).toBe(3); - } - { - // proof 4 - const proof = tree.getProofForIndex(4); - expect(proof).toHaveLength(3); - expect(proof[0].position).toBe(MerklePosition.Right); // 0 - expect(proof[1].position).toBe(MerklePosition.Right); // 0 - expect(proof[2].position).toBe(MerklePosition.Left); // 4 - expect(MerkleTree.getLeafIndex(proof)).toBe(4); - } - { - // proof 5 - const proof = tree.getProofForIndex(5); - expect(proof).toHaveLength(3); - expect(proof[0].position).toBe(MerklePosition.Left); // 1 - expect(proof[1].position).toBe(MerklePosition.Right); // 0 - expect(proof[2].position).toBe(MerklePosition.Left); // 4 - expect(MerkleTree.getLeafIndex(proof)).toBe(5); - } - { - // proof 6 - const proof = tree.getProofForIndex(6); - expect(proof).toHaveLength(3); - expect(proof[0].position).toBe(MerklePosition.Right); // 0 - expect(proof[1].position).toBe(MerklePosition.Left); // 2 - expect(proof[2].position).toBe(MerklePosition.Left); // 4 - expect(MerkleTree.getLeafIndex(proof)).toBe(6); - } - { - // proof 7 - const proof = tree.getProofForIndex(7); - expect(proof).toHaveLength(3); - expect(proof[0].position).toBe(MerklePosition.Left); - expect(proof[1].position).toBe(MerklePosition.Left); - expect(proof[2].position).toBe(MerklePosition.Left); - expect(MerkleTree.getLeafIndex(proof)).toBe(7); - } -}); - -test('sha3 - 100,000 leaves', () => { - const values = []; - for (let i = 0; i < 1e5; i += 1) { - values.push(`${i}`); - } - - const leaves = values.map(x => sha3(x)); - - const tree = new MerkleTree(leaves, sha3); - - const root = '9ae5005173e8c0f54cebb774855398cc1613c5b8237e42b944b2c6a8f4483efc'; - expect(tree.getRoot().toString('hex')).toBe(root); -}); diff --git a/package.json b/package.json index 3567e9e..026ea7d 100644 --- a/package.json +++ b/package.json @@ -43,10 +43,7 @@ }, "workspaces": [ "net", - "crypto", - "commons", - "specification", - "schema" + "commons" ], "packageManager": "yarn@1.22.21+sha256.dbed5b7e10c552ba0e1a545c948d5473bc6c5a28ce22a8fd27e493e3e5eb6370" } diff --git a/schema/CHANGELOG.md b/schema/CHANGELOG.md deleted file mode 100644 index 8585f0c..0000000 --- a/schema/CHANGELOG.md +++ /dev/null @@ -1,143 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -# [2.0.0-alpha.27](https://github.com/ulixee/shared/compare/v2.0.0-alpha.26...v2.0.0-alpha.27) (2024-03-01) - -**Note:** Version bump only for package @ulixee/schema - - - - - -# [2.0.0-alpha.26](https://github.com/ulixee/shared/compare/v2.0.0-alpha.25...v2.0.0-alpha.26) (2024-02-02) - - -### Features - -* update typescript defs ([24b6b62](https://github.com/ulixee/shared/commit/24b6b6296b55302ad7b59fffda3ce64846e13a0d)) - - - - - -# [2.0.0-alpha.25](https://github.com/ulixee/shared/compare/v2.0.0-alpha.24...v2.0.0-alpha.25) (2023-09-28) - -**Note:** Version bump only for package @ulixee/schema - - - - - -# [2.0.0-alpha.24](https://github.com/ulixee/shared/compare/v2.0.0-alpha.23...v2.0.0-alpha.24) (2023-08-09) - -**Note:** Version bump only for package @ulixee/schema - - - - - -# [2.0.0-alpha.23](https://github.com/ulixee/shared/compare/v2.0.0-alpha.22...v2.0.0-alpha.23) (2023-07-07) - -**Note:** Version bump only for package @ulixee/schema - - - - - -# [2.0.0-alpha.22](https://github.com/ulixee/shared/compare/v2.0.0-alpha.21...v2.0.0-alpha.22) (2023-06-12) - - -### Bug Fixes - -* **commons:** handle relative source map content ([2fa4cbc](https://github.com/ulixee/shared/commit/2fa4cbc6304c7547f98d0d64c68d62c827ddc921)) - - - - - -# [2.0.0-alpha.21](https://github.com/ulixee/shared/compare/v2.0.0-alpha.20...v2.0.0-alpha.21) (2023-04-24) - -**Note:** Version bump only for package @ulixee/schema - - - - - -# [2.0.0-alpha.20](https://github.com/ulixee/shared/compare/v2.0.0-alpha.19...v2.0.0-alpha.20) (2023-04-19) - - -### Bug Fixes - -* **crypto:** disallow overwriting identity/address ([c14a185](https://github.com/ulixee/shared/commit/c14a1857c80ca800198d231236d5fcb6223026c9)) - - - - - -# [2.0.0-alpha.19](https://github.com/ulixee/shared/compare/v2.0.0-alpha.18...v2.0.0-alpha.19) (2023-02-25) - - -### Bug Fixes - -* **commons:** allow clearing sourcemap paths ([4d14167](https://github.com/ulixee/shared/commit/4d141673bd34e22d556539e6eb7bf8e63d9c9c3e)) -* **schema:** serialization fixes for schema object ([24ce6cc](https://github.com/ulixee/shared/commit/24ce6cc5605aaff5b1b306755f34e431c8f70cf3)) - - - - - -# [2.0.0-alpha.18](https://github.com/ulixee/shared/compare/v2.0.0-alpha.17...v2.0.0-alpha.18) (2023-01-17) - - -### Features - -* allow optional schema types at compile time ([188ccfd](https://github.com/ulixee/shared/commit/188ccfdca5aeb7f391a4063d8e9af805ae82bc60)) -* databox stream and output apis ([1901482](https://github.com/ulixee/shared/commit/1901482b58d8e8d82497841d7a781efa5ee520cb)) -* **schema:** ability to convert json to code ([1bd0281](https://github.com/ulixee/shared/commit/1bd028171be4751e342e500e44fee0db9306e435)) -* **schema:** add tables to Manifest and Apis ([545bbb0](https://github.com/ulixee/shared/commit/545bbb0412058f3271e4d5796344e270457f4af0)) - - - - - -# [2.0.0-alpha.17](https://github.com/ulixee/shared/compare/v2.0.0-alpha.16...v2.0.0-alpha.17) (2022-12-15) - -**Note:** Version bump only for package @ulixee/schema - - - - - -# [2.0.0-alpha.16](https://github.com/ulixee/shared/compare/v2.0.0-alpha.15...v2.0.0-alpha.16) (2022-12-05) - -**Note:** Version bump only for package @ulixee/schema - - - - - -# [2.0.0-alpha.15](https://github.com/ulixee/shared/compare/v2.0.0-alpha.14...v2.0.0-alpha.15) (2022-11-17) - -**Note:** Version bump only for package @ulixee/schema - - - - - -# [2.0.0-alpha.14](https://github.com/ulixee/shared/compare/v2.0.0-alpha.13...v2.0.0-alpha.14) (2022-11-02) - -**Note:** Version bump only for package @ulixee/schema - - - - - -# [2.0.0-alpha.13](https://github.com/ulixee/shared/compare/v2.0.0-alpha.12...v2.0.0-alpha.13) (2022-10-31) - - -### Features - -* ability to generate schema interface strings ([b1be5c5](https://github.com/ulixee/shared/commit/b1be5c585c19a2d8c101812d8ae5d7b08be9dc0e)) -* schemas ([a3efe35](https://github.com/ulixee/shared/commit/a3efe35cc18319557434bef4239eff52978cb4a1)) diff --git a/schema/index.ts b/schema/index.ts deleted file mode 100644 index c2b559d..0000000 --- a/schema/index.ts +++ /dev/null @@ -1,130 +0,0 @@ -import BaseSchema, { IBaseConfig } from './lib/BaseSchema'; -import NumberSchema, { INumberSchemaConfig } from './lib/NumberSchema'; -import StringSchema, { IStringSchemaConfig } from './lib/StringSchema'; -import BigintSchema, { IBigintSchemaConfig } from './lib/BigintSchema'; -import ObjectSchema, { IObjectSchemaConfig } from './lib/ObjectSchema'; -import ArraySchema, { IArraySchemaConfig } from './lib/ArraySchema'; -import BooleanSchema, { IBooleanSchemaConfig } from './lib/BooleanSchema'; -import BufferSchema, { IBufferSchemaConfig } from './lib/BufferSchema'; -import DateSchema, { IDateSchemaConfig } from './lib/DateSchema'; -import RecordSchema, { IRecordSchemaConfig } from './lib/RecordSchema'; -import { DateUtilities, IUnits } from './lib/DateUtilities'; - -type ISchemaAny = - | StringSchema - | BooleanSchema - | NumberSchema - | BigintSchema - | BufferSchema - | DateSchema - | RecordSchema - | ObjectSchema - | ArraySchema; - -export { ArraySchema, ObjectSchema, ISchemaAny, DateUtilities }; - -export type FilterOptionalKeys = { - [K in keyof T]: T[K] extends { optional: true } ? K : never; -}[keyof T]; - -export type FilterRequiredKeys = { - [K in keyof T]: T[K] extends { optional: true } ? never : K; -}[keyof T]; - -export type IRecordSchemaType>> = { - [K in FilterRequiredKeys]: T[K]['$type']; -} & { - [K in FilterOptionalKeys]?: T[K]['$type']; -} extends infer P - ? { [K in keyof P]: P[K] } - : never; - -export type ExtractSchemaType = T extends BaseSchema - ? U - : T extends Record> - ? IRecordSchemaType - : unknown; - -export function boolean( - config: IBooleanSchemaConfig = {}, -): BooleanSchema { - return new BooleanSchema(config); -} - -export function number( - config: INumberSchemaConfig = {}, -): NumberSchema { - return new NumberSchema(config); -} - -export function string( - config: IStringSchemaConfig = {}, -): StringSchema { - return new StringSchema(config); -} - -export function bigint( - config: IBigintSchemaConfig = {}, -): BigintSchema { - return new BigintSchema(config); -} - -export function buffer( - config: IBufferSchemaConfig = {}, -): BufferSchema { - return new BufferSchema(config); -} - -export function date( - config: IDateSchemaConfig = {}, -): DateSchema { - return new DateSchema(config); -} - -export function dateAdd(quantity: number, units: IUnits): DateUtilities { - return new DateUtilities({ func: 'add', units, quantity }); -} - -export function dateSubtract(quantity: number, units: IUnits): DateUtilities { - return new DateUtilities({ func: 'subtract', units, quantity }); -} - -export function record, TOptional extends boolean = false>( - config: IRecordSchemaConfig, -): RecordSchema { - return new RecordSchema(config); -} - -export function object< - TOptional extends boolean = boolean, - S extends BaseSchema & IBaseConfig = BaseSchema & IBaseConfig, - O extends Record = Record, ->(fields: O): ObjectSchema; -export function object< - S extends BaseSchema = BaseSchema, - O extends Record = Record, - TOptional extends boolean = false, ->(config: IObjectSchemaConfig): ObjectSchema; -export function object(fieldsOrConfig): ObjectSchema { - if ( - !fieldsOrConfig.fields || - typeof fieldsOrConfig.fields !== 'object' || - !(Object.values(fieldsOrConfig.fields)[0] instanceof BaseSchema) - ) { - fieldsOrConfig = { fields: fieldsOrConfig } as IObjectSchemaConfig; - } - return new ObjectSchema(fieldsOrConfig as any); -} - -export function array>(element: E): ArraySchema; -export function array, TOptional extends boolean = false>( - config: IArraySchemaConfig, -): ArraySchema; -export function array, TOptional extends boolean = false>( - elementOrConfig: IArraySchemaConfig | E, -): ArraySchema { - if (elementOrConfig instanceof BaseSchema) { - elementOrConfig = { element: elementOrConfig }; - } - return new ArraySchema(elementOrConfig); -} diff --git a/schema/interfaces/ISchemaJson.ts b/schema/interfaces/ISchemaJson.ts deleted file mode 100644 index 6683aa3..0000000 --- a/schema/interfaces/ISchemaJson.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { IBaseConfig } from '../lib/BaseSchema'; -import { IBigintSchemaConfig } from '../lib/BigintSchema'; -import { IBooleanSchemaConfig } from '../lib/BooleanSchema'; -import { IBufferSchemaConfig } from '../lib/BufferSchema'; -import { IDateSchemaConfig } from '../lib/DateSchema'; -import { INumberSchemaConfig } from '../lib/NumberSchema'; -import { IStringSchemaConfig } from '../lib/StringSchema'; - -export type IAnySchemaJson = - | IArraySchemaJson - | IObjectSchemaJson - | IBigintSchemaJson - | IBooleanSchemaJson - | IBufferSchemaJson - | IDateSchemaJson - | IStringSchemaJson - | INumberSchemaJson - | IRecordSchemaJson; - -export interface IArraySchemaJson extends IBaseConfig { - typeName: 'array'; - element: IObjectSchemaJson; -} - -export interface IObjectSchemaJson extends IBaseConfig { - typeName: 'object'; - fields: Record; -} - -export interface IBigintSchemaJson extends IBigintSchemaConfig { - typeName: 'bigint'; -} - -export interface IBooleanSchemaJson extends IBooleanSchemaConfig { - typeName: 'boolean'; -} - -export interface IBufferSchemaJson extends IBufferSchemaConfig { - typeName: 'buffer'; -} - -export interface IDateSchemaJson extends IDateSchemaConfig { - typeName: 'date'; -} - -export interface INumberSchemaJson extends INumberSchemaConfig { - typeName: 'number'; -} - -export interface IStringSchemaJson extends IStringSchemaConfig { - typeName: 'string'; -} - -export interface IRecordSchemaJson extends IBaseConfig { - typeName: 'record'; - values: IAnySchemaJson; - keys?: IStringSchemaJson; -} diff --git a/schema/interfaces/IValidationResult.ts b/schema/interfaces/IValidationResult.ts deleted file mode 100644 index 11f7f31..0000000 --- a/schema/interfaces/IValidationResult.ts +++ /dev/null @@ -1,10 +0,0 @@ -export type IValidationError = { - path: string; - code: 'invalidType' | 'constraintFailed' | 'missing'; - message: string; -}; - -export default interface IValidationResult { - success: boolean; - errors: IValidationError[]; -} diff --git a/schema/lib/ArraySchema.ts b/schema/lib/ArraySchema.ts deleted file mode 100644 index f18c802..0000000 --- a/schema/lib/ArraySchema.ts +++ /dev/null @@ -1,35 +0,0 @@ -import assert = require('assert'); -import BaseSchema, { IBaseConfig } from './BaseSchema'; - -export interface IArraySchemaConfig, TOptional extends boolean = boolean> - extends IBaseConfig { - element: E; -} - -export default class ArraySchema, TOptional extends boolean = boolean> extends BaseSchema< - Array, - TOptional, - IArraySchemaConfig -> { - readonly typeName = 'array'; - element: E; - - constructor(config: IArraySchemaConfig) { - super(config); - assert( - !!config.element, - 'You must provide a definition for the types of elements in this array', - ); - assert(config.element instanceof BaseSchema, 'Element must be an instance of a type of Schema'); - } - - protected validationLogic(value, path, tracker): void { - if (!Array.isArray(value)) { - return this.incorrectType(value, path, tracker); - } - - for (let i = 0; i < value.length; i += 1) { - this.element.validate(value[i], `${path}.${i}`, tracker); - } - } -} diff --git a/schema/lib/BaseSchema.ts b/schema/lib/BaseSchema.ts deleted file mode 100644 index cc23439..0000000 --- a/schema/lib/BaseSchema.ts +++ /dev/null @@ -1,163 +0,0 @@ -import assert = require('assert'); -import IValidationResult, { IValidationError } from '../interfaces/IValidationResult'; - -export interface IBaseConfig { - optional?: TOptional; - description?: string; -} - -export default abstract class BaseSchema< - Type, - TOptional extends boolean = boolean, - Config extends IBaseConfig = IBaseConfig, -> { - readonly $type: Type; - optional: TOptional; - description?: string; - - abstract readonly typeName: string; - - constructor(config?: Config) { - if (config) { - if (isDefined(config.description)) { - assert(typeof config.description === 'string', 'description must be a string'); - } - if (isDefined(config.optional)) { - assert(typeof config.optional === 'boolean', 'optional must be a boolean'); - } - for (const [key, value] of Object.entries(config)) { - if (key === 'optional' && value === false) continue; - this[key] = value; - } - } - } - - validate(value: any, path = '', validationTracker = ValidationTracker()): IValidationResult { - if (!validationTracker.has(value, this)) { - this.validationLogic(value, path, validationTracker); - } - return { - success: !validationTracker.errors.length, - errors: validationTracker.errors, - }; - } - - protected abstract validationLogic( - value: any, - path: string, - validationTracker: IValidationTracker, - ): void; - - protected incorrectType(value: unknown, path: string, tracker: IValidationTracker): void { - let actualType: string = typeof value; - if (actualType === 'object') { - if (value === null) actualType = 'null'; - if (Array.isArray(value)) actualType = 'array'; - if (value.constructor?.name !== 'Object') actualType = value.constructor?.name; - } - tracker.errors.push({ - path, - code: 'invalidType', - message: `Expected ${BaseSchema.inspect(this)}, but was ${actualType}`, - }); - } - - protected failedConstraint( - value: unknown, - message: string, - path: string, - tracker: IValidationTracker, - ): void { - const info = message ? `: ${message}` : ''; - tracker.errors.push({ - path, - code: 'constraintFailed', - message: `Failed constraint check for ${BaseSchema.inspect(this)}${info}`, - }); - } - - protected propertyMissing( - property: BaseSchema, - path: string, - tracker: IValidationTracker, - ): void { - tracker.errors.push({ - path, - code: 'missing', - message: `Expected ${BaseSchema.inspect(property, undefined)}, but was missing`, - }); - } - - static inspect(schema: any, needsParens = false, circular = new Set>()): string { - if (circular.has(schema)) { - let s = `CIRCULAR ${schema.typeName}`; - if (needsParens) s = `(${s})`; - return s; - } - circular.add(schema); - - try { - switch (schema.typeName) { - case 'boolean': - case 'number': - case 'bigint': - case 'buffer': - case 'date': - case 'string': { - return schema.typeName; - } - case 'array': - return `Array<${BaseSchema.inspect(schema.element, true, circular)}>`; - case 'record': - return `{ keys: ${BaseSchema.inspect( - schema.keys, - true, - circular, - )}, values: ${BaseSchema.inspect(schema.values, true, circular)} }`; - case 'object': { - let returnType = '{'; - let isFirst = true; - for (const [key, field] of Object.entries(schema.fields)) { - if (!isFirst) returnType += ','; - const optional = (field as BaseSchema).optional; - const nested = BaseSchema.inspect(field, false, circular); - returnType += ` ${key}${optional ? '?' : ''}: ${nested}`; - isFirst = false; - } - return `${returnType} }`; - } - } - } finally { - circular.delete(schema); - } - } -} - -export function isDefined(value: any): boolean { - return !(value === null || value === undefined); -} - -export type IValidationTracker = { - errors: IValidationError[]; - has(candidate: object, type: BaseSchema): boolean; -}; - -function ValidationTracker(): IValidationTracker { - const members: WeakMap, true>> = new WeakMap(); - - return { - errors: [], - has(candidate: object, type: BaseSchema): boolean { - let typeSet = members.get(candidate); - const value = typeSet?.get(type) ?? false; - if (candidate !== null && typeof candidate === 'object') { - if (!typeSet) { - typeSet = new WeakMap(); - members.set(candidate, typeSet); - } - typeSet.set(type, true); - } - return value; - }, - }; -} diff --git a/schema/lib/BigintSchema.ts b/schema/lib/BigintSchema.ts deleted file mode 100644 index 68ac0e3..0000000 --- a/schema/lib/BigintSchema.ts +++ /dev/null @@ -1,39 +0,0 @@ -import assert = require('assert'); -import BaseSchema, { IBaseConfig, isDefined } from './BaseSchema'; - -export interface IBigintSchemaConfig - extends IBaseConfig { - min?: bigint; - max?: bigint; -} - -export default class BigintSchema extends BaseSchema< - bigint, - TOptional, - IBigintSchemaConfig -> { - readonly typeName = 'bigint'; - min?: bigint; - max?: bigint; - - constructor(config: IBigintSchemaConfig = {}) { - super(config); - if (isDefined(config.min)) assert(typeof config.min === 'bigint', 'Min value must be a bigint'); - if (isDefined(config.max)) assert(typeof config.max === 'bigint', 'Max value must be a bigint'); - } - - protected validationLogic(value: any, path, tracker): void { - if (typeof value !== this.typeName) { - return this.incorrectType(value, path, tracker); - } - - const config = this as IBigintSchemaConfig; - if (config.max !== undefined && config.min !== null && value < config.min) { - return this.failedConstraint(value, ' This value is smaller than the min.', path, tracker); - } - - if (config.max !== undefined && config.max !== null && value > config.max) { - return this.failedConstraint(value, ' This value is larger than the max.', path, tracker); - } - } -} diff --git a/schema/lib/BooleanSchema.ts b/schema/lib/BooleanSchema.ts deleted file mode 100644 index ebb50d1..0000000 --- a/schema/lib/BooleanSchema.ts +++ /dev/null @@ -1,18 +0,0 @@ -import BaseSchema, { IBaseConfig } from './BaseSchema'; - -export interface IBooleanSchemaConfig - extends IBaseConfig {} - -export default class BooleanSchema extends BaseSchema< - boolean, - TOptional, - IBooleanSchemaConfig -> { - readonly typeName = 'boolean'; - - protected validationLogic(value: any, path, tracker): void { - if (typeof value !== this.typeName) { - return this.incorrectType(value, path, tracker); - } - } -} diff --git a/schema/lib/BufferSchema.ts b/schema/lib/BufferSchema.ts deleted file mode 100644 index 01d7780..0000000 --- a/schema/lib/BufferSchema.ts +++ /dev/null @@ -1,43 +0,0 @@ -import assert = require('assert'); -import BaseSchema, { IBaseConfig, isDefined } from './BaseSchema'; - -const IBufferEncodingTypes = [ - 'ascii', - 'utf8', - 'utf16le', - 'ucs2', - 'base64', - 'latin1', - 'binary', - 'hex', -] as const; - -export interface IBufferSchemaConfig - extends IBaseConfig { - encoding?: keyof typeof IBufferEncodingTypes; -} - -export default class BufferSchema extends BaseSchema< - Buffer, - TOptional, - IBufferSchemaConfig -> { - readonly typeName = 'buffer'; - encoding?: keyof typeof IBufferEncodingTypes; - - constructor(config?: IBufferSchemaConfig) { - super(config); - - if (isDefined(config.encoding)) - assert( - !IBufferEncodingTypes.includes(config.encoding as any), - `encoding must be one of ${IBufferEncodingTypes.join(', ')}`, - ); - } - - protected validationLogic(value: any, path, tracker): void { - if (!Buffer.isBuffer(value)) { - return this.incorrectType(value, path, tracker); - } - } -} diff --git a/schema/lib/DateSchema.ts b/schema/lib/DateSchema.ts deleted file mode 100644 index 3da5a7d..0000000 --- a/schema/lib/DateSchema.ts +++ /dev/null @@ -1,43 +0,0 @@ -import moment = require('moment'); -import assert = require('assert'); -import BaseSchema, { IBaseConfig, isDefined } from './BaseSchema'; - -export interface IDateSchemaConfig - extends IBaseConfig { - future?: boolean; - past?: boolean; -} - -export default class DateSchema extends BaseSchema< - Date, - TOptional, - IDateSchemaConfig -> { - readonly typeName = 'date'; - future?: boolean; - past?: boolean; - - constructor(config: IDateSchemaConfig = {}) { - super(config); - if (isDefined(config.future)) - assert(typeof config.future === 'boolean', 'future must be a boolean'); - if (isDefined(config.past)) assert(typeof config.past === 'boolean', 'past must be a boolean'); - assert(!(config.past && config.future), "can't be both past and future"); - } - - protected validationLogic(value: any, path, tracker): void { - const mDate = moment(value); - if (!mDate.isValid()) { - return this.incorrectType(value, path, tracker); - } - - const config = this as IDateSchemaConfig; - if (config.future && !mDate.isAfter(new Date())) { - return this.failedConstraint(value, ' Value is not a date in the future.', path, tracker); - } - - if (config.past && !mDate.isBefore(new Date())) { - return this.failedConstraint(value, ' Value is not a date in the past.', path, tracker); - } - } -} diff --git a/schema/lib/DateUtilities.ts b/schema/lib/DateUtilities.ts deleted file mode 100644 index 8e74370..0000000 --- a/schema/lib/DateUtilities.ts +++ /dev/null @@ -1,39 +0,0 @@ -import assert = require('assert'); -import moment = require('moment'); - -const Units = ['seconds', 'minutes', 'hours', 'days', 'months', 'years'] as const; -export type IUnits = 'seconds' | 'minutes' | 'hours' | 'days' | 'months' | 'years'; - -interface IDateFunction { - func: 'add' | 'subtract'; - quantity: number; - units: IUnits; -} - -export class DateUtilities implements IDateFunction { - func: 'add' | 'subtract'; - quantity: number; - units: IUnits; - - constructor(config: IDateFunction) { - Object.assign(this, config); - assert(config.func === 'add' || config.func === 'subtract', 'func must be add or subtract'); - assert(typeof config.quantity === 'number', 'quantity must be a number'); - assert(Units.includes(config.units as any), `units must be one of ${Units.join(',')}`); - } - - public evaluate(format: 'date' | 'time'): string; - public evaluate(): Date; - public evaluate(format?: 'date' | 'time'): Date | string { - let result: moment.Moment; - if (this.func === 'add') { - result = moment().add(this.quantity, this.units as any); - } - if (this.func === 'subtract') { - result = moment().subtract(this.quantity, this.units as any); - } - if (format === 'date') return result.format('YYYY-MM-DD'); - if (format === 'time') return result.format('HH:mm'); - return result.toDate(); - } -} diff --git a/schema/lib/NumberSchema.ts b/schema/lib/NumberSchema.ts deleted file mode 100644 index b2b3dc1..0000000 --- a/schema/lib/NumberSchema.ts +++ /dev/null @@ -1,65 +0,0 @@ -import assert = require('assert'); -import BaseSchema, { IBaseConfig, isDefined } from './BaseSchema'; - -export interface INumberSchemaConfig - extends IBaseConfig { - min?: number; - max?: number; - decimals?: number; - integer?: boolean; -} - -export default class NumberSchema extends BaseSchema< - number, - TOptional, - INumberSchemaConfig -> { - readonly typeName = 'number'; - min?: number; - max?: number; - decimals?: number; - integer?: boolean; - - constructor(config: INumberSchemaConfig = {}) { - super(config); - if (isDefined(config.min)) assert(typeof config.min === 'number', 'Min value must be a number'); - if (isDefined(config.max)) assert(typeof config.max === 'number', 'Max value must be a number'); - if (isDefined(config.decimals)) { - assert(typeof config.decimals === 'number', 'number of required decimals must be a number'); - } - if (isDefined(config.integer)) { - assert(typeof config.integer === 'boolean', 'integer must be a boolean'); - } - } - - protected validationLogic(value: any, path, tracker): void { - if (typeof value !== this.typeName) { - return this.incorrectType(value, path, tracker); - } - - const config = this as INumberSchemaConfig; - if (config.min !== undefined && config.min !== null && value < config.min) { - return this.failedConstraint(value, ' This value is smaller than the min.', path, tracker); - } - - if (config.max !== undefined && config.max !== null && value > config.max) { - return this.failedConstraint(value, ' This value is larger than the max.', path, tracker); - } - - if (config.integer === true && !Number.isInteger(value)) { - return this.failedConstraint(value, ' This value is not an integer.', path, tracker); - } - - if (config.decimals !== undefined && Number.isInteger(config.decimals)) { - const decimals = String(value).split('.')[1]?.length ?? 0; - if (decimals !== config.decimals) { - return this.failedConstraint( - value, - ` This value has an invalid number of decimal places (${decimals})`, - path, - tracker, - ); - } - } - } -} diff --git a/schema/lib/ObjectSchema.ts b/schema/lib/ObjectSchema.ts deleted file mode 100644 index 6535937..0000000 --- a/schema/lib/ObjectSchema.ts +++ /dev/null @@ -1,64 +0,0 @@ -import assert = require('assert'); -import { ExtractSchemaType } from '../index'; -import BaseSchema, { IBaseConfig } from './BaseSchema'; - -type ISchemaRecord>> = { - [T in keyof O]: O[T]; -}; - -export interface IObjectSchemaConfig< - O extends Record, - S extends BaseSchema = BaseSchema, - TOptional extends boolean = boolean, -> extends IBaseConfig { - fields: ISchemaRecord; -} - -export default class ObjectSchema< - O extends Record, - TOptional extends boolean = boolean, - S extends BaseSchema = BaseSchema, -> extends BaseSchema, TOptional, IObjectSchemaConfig> { - readonly typeName = 'object'; - fields: O; - - constructor(config: IObjectSchemaConfig) { - super(config); - assert(config.fields, 'You must configure the fields for this object'); - assert( - Object.keys(config.fields).length, - 'You must configure one or more fields for this object', - ); - assert( - Object.values(config.fields).every(x => x && x instanceof BaseSchema), - 'Each value of fields must be a type of Schema', - ); - } - - protected validationLogic(value, path, tracker): void { - if (value === null || value === undefined) { - return this.incorrectType(value, path, tracker); - } - - const fields = this.fields; - const keysOfFields = Object.keys(fields); - if (keysOfFields.length && typeof value !== 'object') { - return this.incorrectType(value, path, tracker); - } - - const keys = [...new Set([...keysOfFields, ...Object.keys(value)])]; - for (const key of keys) { - const childPath = `${path}.${key}`; - if (key in fields) { - const schema: BaseSchema = fields[key]; - if (!schema || !(schema instanceof BaseSchema)) continue; - const keyValue = value[key]; - if (keyValue !== null && keyValue !== undefined) { - schema.validate(keyValue, childPath, tracker); - } else if (!schema.optional) { - this.propertyMissing(schema, childPath, tracker); - } - } - } - } -} diff --git a/schema/lib/RecordSchema.ts b/schema/lib/RecordSchema.ts deleted file mode 100644 index aee1254..0000000 --- a/schema/lib/RecordSchema.ts +++ /dev/null @@ -1,57 +0,0 @@ -import assert = require('assert'); -import BaseSchema, { IBaseConfig } from './BaseSchema'; -import StringSchema from './StringSchema'; -import { ExtractSchemaType } from '../index'; - -export interface IRecordSchemaConfig< - Value extends BaseSchema, - TOptional extends boolean = false, -> extends IBaseConfig { - values: Value; - keys?: StringSchema; -} - -export default class RecordSchema< - Value extends BaseSchema, - TOptional extends boolean = boolean, -> extends BaseSchema< - Record>, - TOptional, - IRecordSchemaConfig -> { - readonly typeName = 'record'; - values: BaseSchema; - keys?: StringSchema; - - constructor(config: IRecordSchemaConfig) { - super(config); - assert(config.values, 'You must configure the types of values for this record'); - assert( - config.values instanceof BaseSchema, - 'The values definition for this record must be a type of Schema', - ); - if (config.keys) { - assert( - config.keys instanceof StringSchema, - 'The definition for keys of this record must be a StringSchema', - ); - } - } - - protected validationLogic(value, path, tracker): void { - if (value === null || value === undefined) { - return this.incorrectType(value, path, tracker); - } - - if (typeof value !== 'object') { - return this.incorrectType(value, path, tracker); - } - - for (const key of Object.keys(value)) { - const childPath = `${path}.${key}`; - if (this.keys) this.keys.validate(key, childPath, tracker); - const schema = this.values; - schema.validate(value[key], childPath, tracker); - } - } -} diff --git a/schema/lib/StringSchema.ts b/schema/lib/StringSchema.ts deleted file mode 100644 index 1228ca6..0000000 --- a/schema/lib/StringSchema.ts +++ /dev/null @@ -1,166 +0,0 @@ -import moment = require('moment'); -import { URL } from 'url'; -import assert = require('assert'); -import BaseSchema, { IBaseConfig, isDefined } from './BaseSchema'; - -export interface IStringSchemaConfig - extends IBaseConfig { - format?: 'email' | 'url' | 'date' | 'time'; - regexp?: RegExp; - enum?: string[]; - minLength?: number; - maxLength?: number; - length?: number; -} - -export default class StringSchema extends BaseSchema< - string, - TOptional, - IStringSchemaConfig -> { - public static DateFormat = 'YYYY-MM-DD'; - public static TimeFormat = 'HH:mm'; - - readonly typeName = 'string'; - format?: 'email' | 'url' | 'date' | 'time'; - regexp?: RegExp; - enum?: string[]; - minLength?: number; - maxLength?: number; - length?: number; - - constructor(config: IStringSchemaConfig = {}) { - super(config); - if (isDefined(this.format)) - assert( - ['email', 'url', 'date', 'time'].includes(this.format), - 'format must be one of email, url, date, time', - ); - if (isDefined(this.regexp)) - assert(this.regexp instanceof RegExp, 'regexp must be an instance of a regex'); - if (isDefined(this.enum)) { - assert(Array.isArray(this.enum), 'enum must be an array of values'); - assert( - this.enum.every(x => typeof x === 'string'), - 'enum must contain only strings', - ); - } - if (isDefined(config.minLength)) - assert(typeof config.minLength === 'number', 'minLength value must be a number'); - if (isDefined(config.maxLength)) - assert(typeof config.maxLength === 'number', 'maxLength value must be a number'); - if (isDefined(config.length)) - assert(typeof config.length === 'number', 'length value must be a number'); - } - - public toMoment(value: string): moment.Moment { - if (this.format === 'date') return moment(value, StringSchema.DateFormat); - if (this.format === 'time') return moment(value, StringSchema.TimeFormat); - throw new Error('This StringSchema does not have a format of date or time.'); - } - - public toDate(value: string): Date { - return this.toMoment(value).toDate(); - } - - public toFormat(date: Date | moment.Moment): string { - if (date instanceof Date) { - date = moment(date); - } - if (this.format === 'time') return date.format(StringSchema.TimeFormat); - if (this.format === 'date') return date.format(StringSchema.DateFormat); - throw new Error('This StringSchema does not have a format of date or time.'); - } - - protected validationLogic(value: any, path, tracker): void { - if (typeof value !== this.typeName) { - return this.incorrectType(value, path, tracker); - } - - const config = this as IStringSchemaConfig; - if (config.format) { - switch (config.format) { - case 'date': { - if (!moment(value, StringSchema.DateFormat, true).isValid()) { - return this.failedConstraint( - value, - ` This value does not follow the YYYY-MM-DD date pattern`, - path, - tracker, - ); - } - break; - } - case 'email': { - if (!regexpEmail.test(value)) { - return this.failedConstraint(value, ' This value is not a valid email', path, tracker); - } - break; - } - case 'time': { - if (!moment(value, StringSchema.TimeFormat, true).isValid()) { - return this.failedConstraint( - value, - ` This value does not follow the HH:mm time pattern`, - path, - tracker, - ); - } - break; - } - case 'url': { - try { - new URL(value); - } catch (err) { - return this.failedConstraint(value, ' This value is not a valid url', path, tracker); - } - break; - } - } - } - - if (config.regexp && config.regexp instanceof RegExp && !config.regexp.test(value)) { - return this.failedConstraint( - value, - ` This value does not match the field RegExp: /${config.regexp.source}/${config.regexp.flags}`, - path, - tracker, - ); - } - - if (config.minLength !== undefined && value.length < config.minLength) { - return this.failedConstraint( - value, - ' This value is shorter than the minLength', - path, - tracker, - ); - } - - if (config.maxLength !== undefined && value.length > config.maxLength) { - return this.failedConstraint( - value, - ' This value is shorter than the maxLength', - path, - tracker, - ); - } - - if (config.length !== undefined && value.length !== config.length) { - return this.failedConstraint(value, ' This value is not the required length', path, tracker); - } - - if (config.enum?.length && !config.enum.includes(value)) { - return this.failedConstraint( - value, - ' This value does not match the allowed enum values', - path, - tracker, - ); - } - } -} - -// Taken from HTML spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address -const regexpEmail = - /^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; diff --git a/schema/lib/jsonToSchemaCode.ts b/schema/lib/jsonToSchemaCode.ts deleted file mode 100644 index 75e2f25..0000000 --- a/schema/lib/jsonToSchemaCode.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { IAnySchemaJson, IObjectSchemaJson } from '../interfaces/ISchemaJson'; - -export default function jsonToSchemaCode( - json: Record | IAnySchemaJson, - schemaImports: Set, -): string { - if (!json) return undefined; - - if (json.typeName) { - return parseField(json as IAnySchemaJson, schemaImports); - } - - let js = `{\n`; - for (const [field, schemaJson] of Object.entries(json)) { - js += ` ${getFieldName(field)}: ${parseField(schemaJson, schemaImports, 2)},\n`; - } - return `${js}}`; -} - -function parseField(json: IAnySchemaJson, schemaImports: Set, leadingSpaces = 0): string { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { typeName, element, fields, values, keys, ...config } = json as any; - if (config.optional !== true) delete config.optional; - schemaImports.add(typeName); - - if (typeName === 'object') { - return parseObjectSchema(json as IObjectSchemaJson, schemaImports, leadingSpaces); - } - - if (typeName === 'array') { - // use shortcut by default - if (Object.keys(config).length === 0) { - const field = parseField(element, schemaImports, leadingSpaces); - return `array(${field})`; - } - config.element = element; - } - - if (typeName === 'record') { - config.values = values; - if (keys) config.keys = keys; - } - - let js = `${typeName}(`; - - const configEntries = Object.keys(config).length; - if (configEntries > 0) { - js += '{'; - if (configEntries > 1) js += '\n'; - - for (const [key, value] of Object.entries(config)) { - if (configEntries > 1) { - js += spaces(leadingSpaces + 2); - } else { - js += ' '; - } - js += `${getFieldName(key)}: `; - if (key === 'element' || key === 'values' || key === 'keys') { - js += `${parseField(value as any, schemaImports, leadingSpaces + 2)},\n`; - } else { - js += JSON.stringify(value); - } - if (configEntries > 1) js += ',\n'; - } - if (configEntries === 1) js += ' '; - else js += spaces(leadingSpaces); - js += '}'; - } - return `${js})`; -} - -function parseObjectSchema( - json: IObjectSchemaJson, - schemaImports: Set, - leadingSpaces = 0, -): string { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { typeName, fields, ...config } = json; - if (config.optional !== true) delete config.optional; - - schemaImports.add('object'); - let js = `object({\n`; - - const configEntries = Object.keys(config).length; - const indented = spaces(leadingSpaces + 2); - - if (configEntries > 0) { - js += `${indented}fields: {\n`; - } - for (const [field, schemaJson] of Object.entries(fields)) { - js += `${indented}${getFieldName(field)}: ${parseField( - schemaJson, - schemaImports, - leadingSpaces + 2, - )},\n`; - } - if (configEntries > 0) { - // close fields - js += '},\n'; - for (const [key, value] of Object.entries(config)) { - js += `${indented}${getFieldName(key)}: ${JSON.stringify(value)},\n`; - } - } - js += spaces(leadingSpaces); - return `${js}})`; -} - -const identifierRE = /^[A-Za-z_$][A-Za-z0-9_$]*$/; - -export function getFieldName(str: string): string { - if (identifierRE.test(str)) { - return str; - } - - return JSON.stringify(str); -} - -function spaces(count: number): string { - let spacesStr = ''; - for (let i = 0; i < count; i += 1) spacesStr += ' '; - return spacesStr; -} diff --git a/schema/lib/schemaFromJson.ts b/schema/lib/schemaFromJson.ts deleted file mode 100644 index 2d862d1..0000000 --- a/schema/lib/schemaFromJson.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { IAnySchemaJson } from '../interfaces/ISchemaJson'; -import NumberSchema from './NumberSchema'; -import BigintSchema from './BigintSchema'; -import BooleanSchema from './BooleanSchema'; -import BufferSchema from './BufferSchema'; -import DateSchema from './DateSchema'; -import StringSchema from './StringSchema'; -import RecordSchema, { IRecordSchemaConfig } from './RecordSchema'; -import ArraySchema from './ArraySchema'; -import ObjectSchema from './ObjectSchema'; -import { ISchemaAny } from '../index'; -import { IBaseConfig } from './BaseSchema'; - -export default function schemaFromJson( - json: Record | IAnySchemaJson, -): ISchemaAny { - if (!json) return undefined; - - if (json?.typeName && typeof json.typeName === 'string') { - return parseField(json as IAnySchemaJson); - } - return parseObjectSchema(json as Record); -} - -function parseField(json: IAnySchemaJson): ISchemaAny { - const { typeName, element, fields, values, keys, ...config } = json as any; - if (typeName === 'number') return new NumberSchema(config); - if (typeName === 'bigint') return new BigintSchema(config); - if (typeName === 'boolean') return new BooleanSchema(config); - if (typeName === 'buffer') return new BufferSchema(config); - if (typeName === 'date') return new DateSchema(config); - if (typeName === 'string') return new StringSchema(config); - if (typeName === 'record') { - const recordConfig: IRecordSchemaConfig = { - values: parseField(values), - ...config, - }; - if (keys) recordConfig.keys = new StringSchema(keys); - return new RecordSchema(recordConfig); - } - if (typeName === 'array') { - const elementConfig = parseField(element); - return new ArraySchema({ element: elementConfig, ...config }); - } - if (typeName === 'object') { - return parseObjectSchema(fields, config); - } -} - -function parseObjectSchema( - json: Record, - options: IBaseConfig = {}, -): ObjectSchema { - const fields: Record = {}; - for (const [field, schemaJson] of Object.entries(json)) { - fields[field] = parseField(schemaJson); - } - return new ObjectSchema({ fields, ...options }); -} diff --git a/schema/lib/schemaToInterface.ts b/schema/lib/schemaToInterface.ts deleted file mode 100644 index b6e27d8..0000000 --- a/schema/lib/schemaToInterface.ts +++ /dev/null @@ -1,140 +0,0 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import * as ts from 'typescript'; -import { ISchemaAny } from '../index'; -import BaseSchema from './BaseSchema'; - -const { factory: f } = ts; - -export default function schemaToInterface( - schema: ISchemaAny | Record | Record>, -): ts.TypeNode { - if (schema !== null && !(schema instanceof BaseSchema) && typeof schema === 'object') { - const members = Object.entries(schema).map(([key, value]) => { - const propName = getIdentifierOrStringLiteral(key); - const type = schemaToInterface(value); - return f.createPropertySignature(undefined, propName, undefined, type); - }); - return f.createTypeLiteralNode(members); - } - - switch (schema.typeName) { - case 'string': { - if (schema.enum) { - const types = schema.enum.map(x => f.createLiteralTypeNode(f.createStringLiteral(x))); - return f.createUnionTypeNode(types); - } - return f.createKeywordTypeNode(ts.SyntaxKind.StringKeyword); - } - case 'number': - return f.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword); - case 'bigint': - return f.createKeywordTypeNode(ts.SyntaxKind.BigIntKeyword); - case 'boolean': - return f.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword); - case 'date': - return f.createTypeReferenceNode(f.createIdentifier('Date')); - case 'buffer': - return f.createTypeReferenceNode(f.createIdentifier('Buffer')); - case 'object': { - const properties = Object.entries(schema.fields) as [string, ISchemaAny][]; - - const members: ts.TypeElement[] = properties.map(([key, childSchema]) => { - const type = schemaToInterface(childSchema); - const optional = childSchema.optional - ? f.createToken(ts.SyntaxKind.QuestionToken) - : undefined; - const propName = getIdentifierOrStringLiteral(key); - - const propertySignature = f.createPropertySignature(undefined, propName, optional, type); - const comments: string[] = []; - - if (childSchema.description) { - comments.push(childSchema.description); - } - const constraints: string[] = []; - if ('decimals' in childSchema) constraints.push(`@decimals ${childSchema.decimals}`); - if ('integer' in childSchema && childSchema.integer) constraints.push(`@integer`); - if ('min' in childSchema) constraints.push(`@min ${childSchema.min}`); - if ('max' in childSchema) constraints.push(`@max ${childSchema.min}`); - if ('encoding' in childSchema) - constraints.push(`@encoding ${String(childSchema.encoding)}`); - if ('format' in childSchema) constraints.push(`@format ${childSchema.format}`); - if ('minLength' in childSchema) constraints.push(`@minLength ${childSchema.minLength}`); - if ('maxLength' in childSchema) constraints.push(`@maxLength ${childSchema.maxLength}`); - if ('length' in childSchema) constraints.push(`@length ${childSchema.length}`); - if ('regexp' in childSchema) constraints.push(`@regex /${childSchema.regexp.source}/`); - if ('future' in childSchema && childSchema.future) constraints.push(`@future`); - if ('past' in childSchema && childSchema.past) constraints.push(`@past`); - - if (constraints.length) comments.push(...constraints); - - if (comments.length) { - ts.addSyntheticLeadingComment( - propertySignature, - ts.SyntaxKind.MultiLineCommentTrivia, - `*\n * ${comments.join('\n * ')}\n `, - true, - ); - } - - return propertySignature; - }); - return f.createTypeLiteralNode(members); - } - - case 'array': { - const type = schemaToInterface(schema.element); - return f.createArrayTypeNode(type); - } - - case 'record': { - const valueType = schemaToInterface(schema.values as ISchemaAny); - - return f.createTypeLiteralNode([ - f.createIndexSignature( - undefined, - [ - f.createParameterDeclaration( - undefined, - undefined, - f.createIdentifier('x'), - undefined, - f.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), - undefined, - ), - ], - valueType, - ), - ]); - } - } - - return f.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); -} - -const identifierRE = /^[A-Za-z_$][A-Za-z0-9_$]*$/; - -export function getIdentifierOrStringLiteral(str: string): ts.PropertyName { - if (identifierRE.test(str)) { - return f.createIdentifier(str); - } - - return f.createStringLiteral(str); -} - -export function printNode(node: ts.Node, printerOptions?: ts.PrinterOptions): string { - const sourceFile = ts.createSourceFile( - 'print.ts', - '', - ts.ScriptTarget.Latest, - false, - ts.ScriptKind.TS, - ); - const printer = ts.createPrinter(printerOptions ?? { newLine: ts.NewLineKind.LineFeed }); - return ( - printer - .printNode(ts.EmitHint.Unspecified, node, sourceFile) - // change to 2 spaces - .replace(/^(\s{4})+/gm, match => new Array(match.length / 4 + 1).join(' ')) - ); -} diff --git a/schema/package.dist.json b/schema/package.dist.json deleted file mode 100644 index 0a47e39..0000000 --- a/schema/package.dist.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "devDependencies": { - "typescript": "^5.3.3" - } -} diff --git a/schema/package.json b/schema/package.json deleted file mode 100644 index f7676ed..0000000 --- a/schema/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "@ulixee/schema", - "version": "2.0.0-alpha.27", - "description": "A basic schema utility with static constraints to support secure type checking.", - "license": "MIT", - "dependencies": { - "moment": "^2.29.4" - }, - "devDependencies": { - "typescript": "^5.3.3" - } -} diff --git a/schema/test/Number.test.ts b/schema/test/Number.test.ts deleted file mode 100644 index 8c9e248..0000000 --- a/schema/test/Number.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { bigint, number } from '../index'; - -test('should be able to create an int schema', () => { - const schema = number({ integer: true }); - expect(schema.validate(1).success).toBe(true); - expect(schema.validate('test').success).toBe(false); - expect(schema.validate(1.2).success).toBe(false); -}); - -test('should be able to create an decimal schema', () => { - const schema = number({ decimals: 1 }); - expect(schema.validate(1.1).success).toBe(true); - expect(schema.validate('test').success).toBe(false); - expect(schema.validate(1).success).toBe(false); -}); - -test('should be able to create an bigint schema', () => { - const schema = bigint(); - expect(schema.validate(1n).success).toBe(true); - expect(schema.validate('test').success).toBe(false); - expect(schema.validate(1).success).toBe(false); -}); - -test('should be able to validate a number has a max range', () => { - const schema = number({ max: 10 }); - expect(schema.validate(0).success).toBe(true); - expect(schema.validate(-190).success).toBe(true); - expect(schema.validate(11).success).toBe(false); -}); - -test('should be able to validate a number has a min range', () => { - const schema = number({ min: 0 }); - expect(schema.validate(1).success).toBe(true); - expect(schema.validate(-190).success).toBe(false); - expect(schema.validate(1).success).toBe(true); -}); diff --git a/schema/test/Object.test.ts b/schema/test/Object.test.ts deleted file mode 100644 index 1734b88..0000000 --- a/schema/test/Object.test.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { - array, - bigint, - boolean, - buffer, - date, - ExtractSchemaType, - number, - object, - string, -} from '../index'; -import ObjectSchema from '../lib/ObjectSchema'; - -test('should be able to create an object schema', () => { - const schema = object({ - one: boolean(), - two: string(), - three: number({ optional: true }), - }); - const testOptional: ExtractSchemaType = { - one: true, - two: 'two', - }; - expect(testOptional).toBeTruthy(); - expect(schema.validate({ one: true, two: '' }).success).toBe(true); - expect(schema.validate({ one: true, two: '', three: 1 }).success).toBe(true); - expect(schema.validate({ one: true, two: '', three: '' }).success).toBe(false); - expect(schema.validate({ one: true, two: '', three: '' }).errors).toHaveLength(1); - expect(schema.validate({ one: true, two: '', three: '' }).errors[0]).toEqual( - expect.objectContaining({ - code: 'invalidType', - path: '.three', - }), - ); -}); - -test('should be able to create an object schema with nested objects', () => { - const nested = object({ - one: string(), - two: string({ format: 'email' }), - }); - - const record = { - one: string({ optional: true }), - two: string({ format: 'email' }), - nested: object({ - three: buffer({ optional: true }), - four: number({ optional: false }), - }), - nestedWithFields: object({ - optional: true, - fields: { - five: number({ optional: true }), - six: date(), - seven: bigint({ optional: false }), - }, - }), - }; - - // test out some nested optionals (just in typescript) - const nestedOptionalSchema: ExtractSchemaType = { - two: 'two', - nested: { - four: 1, - }, - }; - expect(nestedOptionalSchema).toBeTruthy(); - - const nestedBadTypeField: ExtractSchemaType = { - two: 'two', - nested: { - four: 1, - }, - // @ts-expect-error - nestedWithFields: { bad: true, seven: 2n, six: new Date() }, - }; - expect(nestedBadTypeField).toBeTruthy(); - - const nestedOptionalField: ExtractSchemaType = { - two: 'two', - nested: { - four: 1, - }, - nestedWithFields: { seven: 2n, six: new Date() }, - }; - expect(nestedOptionalField).toBeTruthy(); - - const schema = object({ - fields: { - one: boolean(), - twoArray: array(nested), - }, - }); - expect(schema.validate({ one: true, two: '' }).success).toBe(false); - expect(schema.validate({ one: true, twoArray: '' }).errors[0]).toEqual( - expect.objectContaining({ - code: 'invalidType', - path: '.twoArray', - }), - ); - - const jsonExample: ExtractSchemaType = { - one: false, - twoArray: [ - { - one: 'one', - two: 'email@gmail.com', - }, - { - one: 'two', - two: 'notAnEmail', - }, - ], - }; - - expect(schema.validate(jsonExample).errors[0]).toEqual( - expect.objectContaining({ - code: 'constraintFailed', - path: '.twoArray.1.two', - }), - ); -}); diff --git a/schema/test/String.test.ts b/schema/test/String.test.ts deleted file mode 100644 index 4406348..0000000 --- a/schema/test/String.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { string } from '../index'; - -test('should be able to create a string schema', () => { - const schema = string(); - expect(schema.validate('test').success).toBe(true); - expect(schema.validate(1).success).toBe(false); -}); - -test('should be able to test an email format', () => { - const schema = string({ format: 'email' }); - expect(schema.validate('test@test.com').success).toBe(true); - expect(schema.validate('tes').success).toBe(false); - expect(schema.validate(1).success).toBe(false); -}); - -test('should be able to specify a url format', () => { - const schema = string({ format: 'url' }); - expect(schema.validate('https://url.com').success).toBe(true); - expect(schema.validate('test@test.com').success).toBe(false); - expect(schema.validate('tes').success).toBe(false); - expect(schema.validate(1).success).toBe(false); -}); - -test('should be able to specify a date format', () => { - const schema = string({ format: 'date' }); - expect(schema.validate('2022-01-01').success).toBe(true); - expect(schema.validate('2022-12-31').success).toBe(true); - expect(schema.validate('2022-12-32').success).toBe(false); -}); - -test('should be able to specify a time format', () => { - const schema = string({ format: 'time' }); - expect(schema.validate('01:01').success).toBe(true); - expect(schema.validate('23:59').success).toBe(true); - expect(schema.validate('24:01').success).toBe(false); -}); - -test('should be able to validate a string length', () => { - expect(string({ length: 5 }).validate('12345').success).toBe(true); - expect(string({ length: 5 }).validate('1234').success).toBe(false); - expect(string({ maxLength: 5 }).validate('125').success).toBe(true); - expect(string({ maxLength: 5 }).validate('123456').success).toBe(false); - expect(string({ minLength: 5 }).validate('12345').success).toBe(true); - expect(string({ minLength: 5 }).validate('1234').success).toBe(false); -}); - -test('should be able to validate a regex', () => { - const schema = string({ regexp: /[ABC]{3,5}/ }); - expect(schema.validate('AAA').success).toBe(true); - expect(schema.validate('acb').success).toBe(false); -}); diff --git a/schema/test/jsonToSchemaCode.test.ts b/schema/test/jsonToSchemaCode.test.ts deleted file mode 100644 index 3a99e85..0000000 --- a/schema/test/jsonToSchemaCode.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { array, bigint, number, object, string } from '../index'; -import jsonToSchemaCode from '../lib/jsonToSchemaCode'; - -test('should be able to generate a schema from json', () => { - const schema = object({ - field1: string({ description: 'This is a test', format: 'email' }), - field2: string({ length: 4 }), - field3: string({ optional: true }), - 'field-4': number(), - }); - const json = JSON.parse(JSON.stringify(schema)); - - const schema2 = jsonToSchemaCode(json, new Set()); - - expect(schema2).toBe(`object({ - field1: string({ - description: "This is a test", - format: "email", - }), - field2: string({ length: 4 }), - field3: string({ optional: true }), - "field-4": number(), -})`); -}); - -test('should be able to generate a nested object structure from json', () => { - const schema = { - test: object({ - optional: false, - fields: { - field1: string({ description: 'This is a test', format: 'email' }), - field3: array(object({ 'tester-2': number({ optional: true }) })), - }, - }), - test2: bigint(), - }; - const json = JSON.parse(JSON.stringify(schema)); - - const schema2 = jsonToSchemaCode(json, new Set()); - - expect(schema2).toBe(`{ - test: object({ - field1: string({ - description: "This is a test", - format: "email", - }), - field3: array(object({ - "tester-2": number({ optional: true }), - })), - }), - test2: bigint(), -}`); -}); diff --git a/schema/test/schemaToInterface.test.ts b/schema/test/schemaToInterface.test.ts deleted file mode 100644 index e7577bf..0000000 --- a/schema/test/schemaToInterface.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { number, object, string } from '../index'; -import schemaToInterface, { printNode } from '../lib/schemaToInterface'; - -test('should be able to generate a type', () => { - const schema = object({ - field1: string({ description: 'This is a test', format: 'email' }), - field2: string({ length: 4 }), - field3: string({ optional: true }), - 'field-4': number(), - }); - const ts = schemaToInterface(schema); - expect(printNode(ts)).toBe(`{ - /** - * This is a test - * @format email - */ - field1: string; - /** - * @length 4 - */ - field2: string; - field3?: string; - "field-4": number; -}`); -}); diff --git a/schema/yarn.lock b/schema/yarn.lock deleted file mode 100644 index 847bb49..0000000 --- a/schema/yarn.lock +++ /dev/null @@ -1,8 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -moment@^2.29.4: - version "2.29.4" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" - integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== diff --git a/specification/.eslintrc.js b/specification/.eslintrc.js deleted file mode 100644 index ff0effc..0000000 --- a/specification/.eslintrc.js +++ /dev/null @@ -1,8 +0,0 @@ -const Path = require('path'); - -module.exports = { - parserOptions: { - project: Path.join(__dirname, 'tsconfig.json'), - }, - extends: '../.eslintrc.js', -}; diff --git a/specification/CHANGELOG.md b/specification/CHANGELOG.md deleted file mode 100644 index 59df097..0000000 --- a/specification/CHANGELOG.md +++ /dev/null @@ -1,208 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -# [2.0.0-alpha.27](https://github.com/ulixee/shared/compare/v2.0.0-alpha.26...v2.0.0-alpha.27) (2024-03-01) - -**Note:** Version bump only for package @ulixee/specification - - - - - -# [2.0.0-alpha.26](https://github.com/ulixee/shared/compare/v2.0.0-alpha.25...v2.0.0-alpha.26) (2024-02-02) - -**Note:** Version bump only for package @ulixee/specification - - - - - -# [2.0.0-alpha.25](https://github.com/ulixee/shared/compare/v2.0.0-alpha.24...v2.0.0-alpha.25) (2023-09-28) - -**Note:** Version bump only for package @ulixee/specification - - - - - -# [2.0.0-alpha.24](https://github.com/ulixee/shared/compare/v2.0.0-alpha.23...v2.0.0-alpha.24) (2023-08-09) - -**Note:** Version bump only for package @ulixee/specification - - - - - -# [2.0.0-alpha.23](https://github.com/ulixee/shared/compare/v2.0.0-alpha.22...v2.0.0-alpha.23) (2023-07-07) - - -### Features - -* **commons:** add async iterator last function ([f4dd911](https://github.com/ulixee/shared/commit/f4dd9113341e37ce193455e5a55b30f99436daa9)) - - - - - -# [2.0.0-alpha.22](https://github.com/ulixee/shared/compare/v2.0.0-alpha.21...v2.0.0-alpha.22) (2023-06-12) - - -### Features - -* **specification:** allow configuring api context ([e41e409](https://github.com/ulixee/shared/commit/e41e40991db595abf75bd80635ae4e958965a425)) - - - - - -# [2.0.0-alpha.21](https://github.com/ulixee/shared/compare/v2.0.0-alpha.20...v2.0.0-alpha.21) (2023-04-24) - -**Note:** Version bump only for package @ulixee/specification - - - - - -# [2.0.0-alpha.20](https://github.com/ulixee/shared/compare/v2.0.0-alpha.19...v2.0.0-alpha.20) (2023-04-19) - -**Note:** Version bump only for package @ulixee/specification - - - - - -# [2.0.0-alpha.19](https://github.com/ulixee/shared/compare/v2.0.0-alpha.18...v2.0.0-alpha.19) (2023-02-25) - - -### Features - -* added Datastore.fetchInternalTable + tweaked Datastore.stream ([5525bb4](https://github.com/ulixee/shared/commit/5525bb4cf0021ac933cfe4fb8e23b631e6aa0f8d)) -* **specification:** add dns domains to datastores ([c36e3d7](https://github.com/ulixee/shared/commit/c36e3d7bbc40aef1f9323178556d59a7d8b203e5)) - - - - - -# [2.0.0-alpha.18](https://github.com/ulixee/shared/compare/v2.0.0-alpha.17...v2.0.0-alpha.18) (2023-01-17) - - -### Bug Fixes - -* **crypt:** don’t read pem if not provided ([cb825d1](https://github.com/ulixee/shared/commit/cb825d11712215c3a157f433e6b77dcd23230019)) - - -### Features - -* databox stream and output apis ([1901482](https://github.com/ulixee/shared/commit/1901482b58d8e8d82497841d7a781efa5ee520cb)) -* **schema:** ability to convert json to code ([1bd0281](https://github.com/ulixee/shared/commit/1bd028171be4751e342e500e44fee0db9306e435)) -* **schema:** add tables to Manifest and Apis ([545bbb0](https://github.com/ulixee/shared/commit/545bbb0412058f3271e4d5796344e270457f4af0)) -* **specification:** credits api in datastore ([0dfab62](https://github.com/ulixee/shared/commit/0dfab6269e14c2d8cba99e860110732c58365a2e)) - - - - - -# [2.0.0-alpha.17](https://github.com/ulixee/shared/compare/v2.0.0-alpha.16...v2.0.0-alpha.17) (2022-12-15) - - -### Features - -* added table endpoints ([62fe366](https://github.com/ulixee/shared/commit/62fe366a967d2ff8f1ae0f100cf8d8adb52d2e98)) -* converted Databox.exec into Databox.query + cleaned up other Databox endpoints ([a483c3d](https://github.com/ulixee/shared/commit/a483c3d061ad2a7a94fc3effb3ab3fb99ad2f26c)) -* micronote apis conversion to hold/settle ([c03c6fd](https://github.com/ulixee/shared/commit/c03c6fd8c7d17c29a8347aaba7413920e859c556)) - - - - - -# [2.0.0-alpha.16](https://github.com/ulixee/shared/compare/v2.0.0-alpha.15...v2.0.0-alpha.16) (2022-12-05) - - -### Features - -* add databox functions ([4577be8](https://github.com/ulixee/shared/commit/4577be8ca3d1adf887659bf57cbf8a48c5d39b14)) - - - - - -# [2.0.0-alpha.15](https://github.com/ulixee/shared/compare/v2.0.0-alpha.14...v2.0.0-alpha.15) (2022-11-17) - - -### Features - -* gift card api v2 to support redemption key ([b2f11f4](https://github.com/ulixee/shared/commit/b2f11f44a784adf8dd208db9683c99369f33f98c)) - - - - - -# [2.0.0-alpha.14](https://github.com/ulixee/shared/compare/v2.0.0-alpha.13...v2.0.0-alpha.14) (2022-11-02) - -**Note:** Version bump only for package @ulixee/specification - - - - - -# [2.0.0-alpha.13](https://github.com/ulixee/shared/compare/v2.0.0-alpha.12...v2.0.0-alpha.13) (2022-10-31) - - -### Bug Fixes - -* rename server config to hosts ([70d4e66](https://github.com/ulixee/shared/commit/70d4e661c1c2a964ffe72b79635cfa40bf12b2c6)) - - -### Features - -* ability to generate schema interface strings ([b1be5c5](https://github.com/ulixee/shared/commit/b1be5c585c19a2d8c101812d8ae5d7b08be9dc0e)) -* schemas ([a3efe35](https://github.com/ulixee/shared/commit/a3efe35cc18319557434bef4239eff52978cb4a1)) -* updated Databox specifications to match changes in ulixee ([869bf9b](https://github.com/ulixee/shared/commit/869bf9baa28c6bb6c55afc30390e52dd74a8dfcc)) - - - - - -# [2.0.0-alpha.12](https://github.com/ulixee/shared/compare/v2.0.0-alpha.11...v2.0.0-alpha.12) (2022-10-03) - - -### Bug Fixes - -* **commons:** typeserializer not deep on map ([1f01a5c](https://github.com/ulixee/shared/commit/1f01a5c04d3c8318f44b0a5ac8509247313c7153)) - - - - - -# [2.0.0-alpha.11](https://github.com/ulixee/shared/compare/v2.0.0-alpha.10...v2.0.0-alpha.11) (2022-08-31) - - -### Features - -* **commons:** env utils + timed cache ([8583846](https://github.com/ulixee/shared/commit/8583846f891cc1f93c079c8f6e3b1868ba7fcb5e)) - - - - - -# [2.0.0-alpha.10](https://github.com/ulixee/shared/compare/v2.0.0-alpha.9...v2.0.0-alpha.10) (2022-08-16) - - -### Bug Fixes - -* **specification:** publishing broken ([88539ee](https://github.com/ulixee/shared/commit/88539ee5b8663d0c19b0518fb3b4ed218dd6dbbe)) - - - - - -# [2.0.0-alpha.9](https://github.com/ulixee/shared/compare/v2.0.0-alpha.8...v2.0.0-alpha.9) (2022-08-16) - - -### Features - -* api function extractor ([b96c7c1](https://github.com/ulixee/shared/commit/b96c7c1bf68c65cdba9278591507b4a3405c8ab9)) -* **net:** add remoteId to transports for logs ([1cbc117](https://github.com/ulixee/shared/commit/1cbc117230644fd1e8dc3ba14b7bf01cfdb3142d)) -* specification, crypto projects ([fa61e3d](https://github.com/ulixee/shared/commit/fa61e3d221dacc3c1509309ebbfc7a05cf43923c)) diff --git a/specification/common.ts b/specification/common.ts deleted file mode 100644 index 920c560..0000000 --- a/specification/common.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { z } from 'zod'; - -export const addressValidation = z - .string() - .length(61) - .regex( - /^ar1[ac-hj-np-z02-9]{58}/, - 'This is not an Argon address (Bech32 encoded, starting with "ar1").', - ); - -export const identityValidation = z - .string() - .length(61) - .regex( - /^id1[ac-hj-np-z02-9]{58}/, - 'This is not a Ulixee identity (Bech32 encoded public key starting with "id1").', - ); - -export const hashValidation = z - .instanceof(Buffer) - .refine(x => x.length === 32, { message: 'Hashes must be 32 bytes' }); - -export const isHex = /^(0x|0h)?[0-9A-F]+$/i; - -export const signatureValidation = z - .instanceof(Buffer) - .refine(x => x.length === 64, { message: 'Signatures must be 64 bytes' }); - -export const blockHeightValidation = z.number().int().nonnegative(); - -export const micronoteIdValidation = z - .string() - .length(62) - .regex( - /^mcr1[ac-hj-np-z02-9]{58}/, - 'This is not a Micronote id (Bech32 encoded, starting with "mcr").', - ); - -export const centagonTokenValidation = z.bigint().refine(x => x > 0n); - -export const micronoteTokenValidation = z.number().int().positive(); diff --git a/specification/index.ts b/specification/index.ts deleted file mode 100644 index edd5d8c..0000000 --- a/specification/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { z } from 'zod'; -import INote from './types/INote'; -import IMerkleProof from './types/IMerkleProof'; -import IAddressOwnershipProof from './types/IAddressOwnershipProof'; -import IAddressSignature from './types/IAddressSignature'; -import IStakeSettings from './types/IStakeSettings'; -import IStakeSignature from './types/IStakeSignature'; -import ICoinage from './types/ICoinage'; -import CoinageType from './types/CoinageType'; -import NoteType from './types/NoteType'; -import ITransaction from './types/ITransaction'; -import ITransactionOutput from './types/ITransactionOutput'; -import ITransactionSource from './types/ITransactionSource'; -import ITransactionSourceSignatureData from './types/ITransactionSourceSignatureData'; -import TransactionType from './types/TransactionType'; -import IBlock from './types/IBlock'; -import LedgerType from './types/LedgerType'; -import IBlockHeader from './types/IBlockHeader'; -import IBlockSettings from './types/IBlockSettings'; -import IMicronote from './types/IMicronote'; -import TransactionError from './types/TransactionError'; - -export { - z, - IBlock, - IBlockHeader, - IBlockSettings, - INote, - ICoinage, - CoinageType, - NoteType, - LedgerType, - IMerkleProof, - IMicronote, - IStakeSettings, - ITransaction, - ITransactionSource, - ITransactionOutput, - ITransactionSourceSignatureData, - TransactionType, - IStakeSignature, - IAddressSignature, - IAddressOwnershipProof, - TransactionError -}; diff --git a/specification/mainchain/BlockApis.ts b/specification/mainchain/BlockApis.ts deleted file mode 100644 index fd2493a..0000000 --- a/specification/mainchain/BlockApis.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { z } from 'zod'; -import { addressValidation, blockHeightValidation, hashValidation } from '../common'; -import { IZodSchemaToApiTypes } from '../utils/IZodApi'; -import { DatumSummarySchema } from '../types/IDatumSummary'; -import { BlockSchema } from '../types/IBlock'; -import BlockError from '../types/BlockError'; -import { BitDatumHistorySchema } from '../types/IBitDatumHistory'; -import { BlockSettingsSchema } from '../types/IBlockSettings'; -import { LedgerType } from '../index'; - -export const BlockApiSchemas = { - 'Block.create': { - args: z.object({ - prevBlockHash: hashValidation, - payoutAddress: addressValidation, - linkNonce: hashValidation, // since already calculated, send it through - datumSummary: DatumSummarySchema, - bitSampling: z.object({ - bitDatumHistories: BitDatumHistorySchema.array(), - }), // sampling of node datums created - }), - result: z.object({ - success: z.boolean(), - }), - }, - 'Block.created': { - args: z.object({ - block: BlockSchema, - nodeIdsAlreadySent: z.string().array(), - }), - result: z.object({ - accept: z.boolean(), - error: z.nativeEnum(BlockError), - message: z.string(), - }), - }, - 'Block.findWithTransaction': { - args: z.object({ - transactionHash: hashValidation, - ledgerType: z.nativeEnum(LedgerType), - }), - result: z.object({ - blockHeight: blockHeightValidation, - merkleRoot: hashValidation, - blockHash: hashValidation, - }), - }, - 'Block.getMany': { - args: z.object({ - blockHeights: blockHeightValidation.array(), - blockHashes: hashValidation.array(), - }), - result: z.object({ - blocks: BlockSchema.array(), - }), - }, - 'Block.settings': { - args: z.object({ - blockHeight: blockHeightValidation.optional(), - }), - result: BlockSettingsSchema, - }, -}; - -type IBlockApis = IZodSchemaToApiTypes; -export default IBlockApis; diff --git a/specification/mainchain/BlockHeaderApis.ts b/specification/mainchain/BlockHeaderApis.ts deleted file mode 100644 index a12e0e5..0000000 --- a/specification/mainchain/BlockHeaderApis.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { z } from 'zod'; -import { blockHeightValidation, hashValidation } from '../common'; -import { IZodSchemaToApiTypes } from '../utils/IZodApi'; -import { BlockHeaderSchema } from '../types/IBlockHeader'; - -export const BlockHeaderApiSchemas = { - 'BlockHeader.getMany': { - args: z.object({ - heights: blockHeightValidation.array(), - }), - result: z.object({ - headers: BlockHeaderSchema.array(), - }), - }, - 'BlockHeader.get': { - args: z.object({ - hash: hashValidation, - includeFork: z.boolean(), - }), - result: z.object({ - header: BlockHeaderSchema, - isOnFork: z.boolean(), - }), - }, -}; - -type IBlockHeaderApis = IZodSchemaToApiTypes; -export default IBlockHeaderApis; diff --git a/specification/mainchain/CoinageApis.ts b/specification/mainchain/CoinageApis.ts deleted file mode 100644 index 9e5c9a5..0000000 --- a/specification/mainchain/CoinageApis.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { z } from 'zod'; -import { IZodSchemaToApiTypes } from '../utils/IZodApi'; -import { CoinageSchema } from '../types/ICoinage'; - -export enum CoinageError { - BAD_SIGNATURE = 0, - NO_PERMISSIONS = 1, - INVALID_PARAMETER = 2, - INVALID_TYPE = 3, -} - -export const CoinageApiSchemas = { - 'Coinage.create': { - args: z.object({ - coinage: CoinageSchema, - }), - result: z.object({ - accept: z.boolean(), - error: z.nativeEnum(CoinageError), - }), - }, - 'Coinage.created': { - args: z.object({ - coinage: CoinageSchema, - nodeIdsAlreadySent: z.string().array(), - }), - result: z.object({ - accept: z.boolean(), - error: z.nativeEnum(CoinageError), - }), - }, -}; - -type ICoinageApis = IZodSchemaToApiTypes; -export default ICoinageApis; diff --git a/specification/mainchain/SidechainGovernanceApis.ts b/specification/mainchain/SidechainGovernanceApis.ts deleted file mode 100644 index b33bceb..0000000 --- a/specification/mainchain/SidechainGovernanceApis.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { z } from 'zod'; -import { IZodSchemaToApiTypes } from '../utils/IZodApi'; -import { AuthorizedSidechainSchema } from '../types/IAuthorizedSidechain'; - -export enum SidechainGovernanceError { - BAD_SIGNATURE = 0, - NO_PERMISSIONS = 1, -} - -export const SidechainGovernanceSchemas = { - 'Sidechain.authorize': { - args: z.object({ - sidechain: AuthorizedSidechainSchema, - }), - result: z.object({ - accept: z.boolean(), - error: z.nativeEnum(SidechainGovernanceError), - }), - }, - 'Sidechain.authorized': { - args: z.object({ - sidechain: AuthorizedSidechainSchema, - nodeIdsAlreadySent: z.string().array(), - }), - result: z.object({ - accept: z.boolean(), - error: z.nativeEnum(SidechainGovernanceError), - }), - }, -}; - -type ISidechainGovernanceApis = IZodSchemaToApiTypes; -export default ISidechainGovernanceApis; diff --git a/specification/mainchain/TransactionApis.ts b/specification/mainchain/TransactionApis.ts deleted file mode 100644 index 0da74c3..0000000 --- a/specification/mainchain/TransactionApis.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { z } from 'zod'; -import { IZodSchemaToApiTypes } from '../utils/IZodApi'; -import { TransactionSchema } from '../types/ITransaction'; -import { LedgerType, TransactionError } from '../index'; -import { blockHeightValidation, hashValidation } from '../common'; -import { MerkleProofSchema } from '../types/IMerkleProof'; - -const TransactionResponseSchema = z.object({ - preliminaryBlockHeight: blockHeightValidation, - error: z.nativeEnum(TransactionError), - message: z.string().optional(), -}); - -export const TransactionApiSchemas = { - 'Transaction.created': { - args: z.object({ - transaction: TransactionSchema, - ledger: z.nativeEnum(LedgerType), - nodeIdsAlreadySent: z.string().array(), - }), - result: z.object({ - accept: z.boolean(), - error: z.nativeEnum(TransactionError), - message: z.string().optional(), - }), - }, - 'Transaction.transfer': { - args: z.object({ - transaction: TransactionSchema, - ledger: z.nativeEnum(LedgerType), - }), - result: TransactionResponseSchema, - }, - 'Transaction.claim': { - args: z.object({ - transaction: TransactionSchema, - }), - result: TransactionResponseSchema, - }, - 'Transaction.purchase': { - args: z.object({ - transaction: TransactionSchema, - }), - result: TransactionResponseSchema, - }, - 'Transaction.verifyInBlock': { - args: z.object({ - transactionHash: hashValidation, - transactionIndex: z.number().int().nonnegative(), - blockHeight: blockHeightValidation, - ledger: z.nativeEnum(LedgerType), - }), - result: z.object({ - proofs: MerkleProofSchema.array(), - }), - }, - 'Transaction.checkForBondRedemption': { - args: z.object({ - transactionHash: hashValidation, - }), - result: z.object({ - transaction: TransactionSchema, - blockHeight: blockHeightValidation, - }), - }, -}; - -type ITransactionApis = IZodSchemaToApiTypes; -export default ITransactionApis; diff --git a/specification/mainchain/index.ts b/specification/mainchain/index.ts deleted file mode 100644 index faf7c72..0000000 --- a/specification/mainchain/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { BlockApiSchemas } from './BlockApis'; -import { BlockHeaderApiSchemas } from './BlockHeaderApis'; -import { SidechainGovernanceSchemas } from './SidechainGovernanceApis'; -import { CoinageApiSchemas } from './CoinageApis'; -import { TransactionApiSchemas } from './TransactionApis'; -import { IZodHandlers, IZodSchemaToApiTypes } from '../utils/IZodApi'; - -const MainchainApiSchema = { - ...BlockApiSchemas, - ...BlockHeaderApiSchemas, - ...CoinageApiSchemas, - ...SidechainGovernanceSchemas, - ...TransactionApiSchemas, -}; - -export type IMainchainApiTypes = IZodSchemaToApiTypes; - -export type IMainchainApis = IZodHandlers; - -export default MainchainApiSchema; diff --git a/specification/package.json b/specification/package.json deleted file mode 100644 index 3b4a17b..0000000 --- a/specification/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "@ulixee/specification", - "version": "2.0.0-alpha.27", - "description": "", - "main": "./index.js", - "license": "MIT", - "dependencies": { - "zod": "^3.20.2" - } -} diff --git a/specification/sidechain/AddressApis.ts b/specification/sidechain/AddressApis.ts deleted file mode 100644 index c0c445f..0000000 --- a/specification/sidechain/AddressApis.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { z } from 'zod'; -import { addressValidation } from '../common'; -import { IZodSchemaToApiTypes } from '../utils/IZodApi'; - -export const AddressApiSchemas = { - 'Address.getBalance': { - args: z.object({ - address: addressValidation, - }), - result: z.object({ - balance: z.bigint(), - }), - }, - 'Address.register': { - args: z.object({ - address: addressValidation, - }), - result: z.object({ - success: z.boolean(), - }), - }, -}; - -type IAddressApis = IZodSchemaToApiTypes; -export default IAddressApis; diff --git a/specification/sidechain/FundingTransferApis.ts b/specification/sidechain/FundingTransferApis.ts deleted file mode 100644 index 1c18c85..0000000 --- a/specification/sidechain/FundingTransferApis.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { z } from 'zod'; -import { addressValidation, blockHeightValidation, hashValidation } from '../common'; -import { IZodSchemaToApiTypes } from '../utils/IZodApi'; -import { NoteSchema } from '../types/INote'; - -export const FundingTransferApiSchemas = { - 'FundingTransfer.status': { - args: z.object({ - noteHash: hashValidation, - }), - result: z.object({ - transactionHash: hashValidation, - currentBlockHeight: blockHeightValidation, - blocks: z - .object({ - blockHash: hashValidation, - blockHeight: blockHeightValidation, - }) - .array(), - }), - }, - 'FundingTransfer.keys': { - args: z.object({}), - result: z.object({ - transferOutKey: addressValidation, - transferInKeys: addressValidation.array(), - }), - }, - 'FundingTransfer.out': { - args: z.object({ - note: NoteSchema, - }), - result: z.object({ - noteHash: hashValidation, - currentBlockHash: hashValidation, - }), - }, -}; - -type IFundingTransferApis = IZodSchemaToApiTypes; -export default IFundingTransferApis; diff --git a/specification/sidechain/MicronoteApis.ts b/specification/sidechain/MicronoteApis.ts deleted file mode 100644 index cb24075..0000000 --- a/specification/sidechain/MicronoteApis.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { z } from 'zod'; -import { - addressValidation, - blockHeightValidation, - hashValidation, - identityValidation, - micronoteIdValidation, - micronoteTokenValidation, - signatureValidation, -} from '../common'; -import { IZodSchemaToApiTypes } from '../utils/IZodApi'; -import { AddressSignatureSchema } from '../types/IAddressSignature'; -import { MicronoteBatchSchema } from '../types/IMicronoteBatch'; - -export const MicronoteApiSchemas = { - 'Micronote.create': { - args: z.object({ - batchSlug: MicronoteBatchSchema.shape.batchSlug, - address: addressValidation, - microgons: micronoteTokenValidation.lte(1000e6), // $1000 max = 1000*1M microgon max - fundsId: z.string().length(30).optional(), - signature: AddressSignatureSchema, - isAuditable: z.boolean().optional(), - }), - result: z.object({ - id: micronoteIdValidation, - micronoteSignature: signatureValidation, - blockHeight: blockHeightValidation, - fundsId: z.string().length(30), - guaranteeBlockHeight: blockHeightValidation, - fundMicrogonsRemaining: micronoteTokenValidation, - }), - }, - 'Micronote.hold': { - args: z.object({ - batchSlug: MicronoteBatchSchema.shape.batchSlug, - id: micronoteIdValidation, - identity: identityValidation, - signature: signatureValidation, - microgons: micronoteTokenValidation.describe('Number of microgons to put on hold.'), - holdAuthorizationCode: z - .string() - .length(16) - .optional() - .describe('Authorization code provided to hold funds.'), - }), - result: z.object({ - holdAuthorizationCode: z - .string() - .length(16) - .optional() - .describe( - 'An authorization code that can be used to claim funds against a Micronote. Only returned to the first claimer.', - ), - holdId: z - .string() - .length(30) - .optional() - .describe('A holdId to settle. If insufficient funds, this value will not be returned.'), - accepted: z.boolean(), - remainingBalance: micronoteTokenValidation.describe( - 'Number of microgons remaining on this miconote.', - ), - currentBlockHeight: blockHeightValidation, - currentBlockHash: hashValidation, - }), - }, - 'Micronote.settle': { - args: z.object({ - batchSlug: MicronoteBatchSchema.shape.batchSlug, - id: micronoteIdValidation, - identity: identityValidation, - tokenAllocation: z.record(addressValidation, micronoteTokenValidation), - signature: signatureValidation, - holdId: z - .string() - .length(30) - .optional() - .describe('A hold id that will settle funds allocated in a hold.'), - isFinal: z.boolean().describe('Should this call finalize the Micronote and return change.'), - }), - result: z.object({ - finalCost: z.number().nonnegative().int().optional(), - }), - }, -}; - -type IMicronoteApis = IZodSchemaToApiTypes; -export default IMicronoteApis; diff --git a/specification/sidechain/MicronoteBatchApis.ts b/specification/sidechain/MicronoteBatchApis.ts deleted file mode 100644 index 6602790..0000000 --- a/specification/sidechain/MicronoteBatchApis.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { z } from 'zod'; -import { MicronoteBatchSchema } from '../types/IMicronoteBatch'; -import { NoteSchema } from '../types/INote'; -import { addressValidation, micronoteTokenValidation } from '../common'; -import { IZodSchemaToApiTypes } from '../utils/IZodApi'; - -const fundsIdValidation = z.string().length(30); - -export const MicronoteBatchApiSchemas = { - 'MicronoteBatch.fund': { - args: z.object({ - note: NoteSchema, - batchSlug: MicronoteBatchSchema.shape.batchSlug, - }), - result: z.object({ - fundsId: fundsIdValidation, - }), - }, - 'MicronoteBatch.activeFunds': { - args: z.object({ - batchSlug: MicronoteBatchSchema.shape.batchSlug, - address: addressValidation, - }), - result: z - .object({ - fundsId: fundsIdValidation, - microgonsRemaining: micronoteTokenValidation, - allowedRecipientAddresses: addressValidation.array(), - }) - .array(), - }, - 'MicronoteBatch.findFund': { - args: z.object({ - batchSlug: MicronoteBatchSchema.shape.batchSlug, - microgons: micronoteTokenValidation, - address: addressValidation, - }), - result: z.object({ - fundsId: fundsIdValidation, - microgonsRemaining: micronoteTokenValidation, - allowedRecipientAddresses: addressValidation.array().optional(), - }), - }, - 'MicronoteBatch.getFundSettlement': { - args: z.object({ - fundIds: fundsIdValidation.array(), - batchSlug: MicronoteBatchSchema.shape.batchSlug, - }), - result: z.object({ - isBatchSettled: z.boolean(), - settledTime: z.date(), - settlements: z - .object({ - fundsId: fundsIdValidation, - fundedCentagons: z.bigint().refine(x => x >= 0), - settledCentagons: z.bigint().refine(x => x >= 0), - }) - .array(), - }), - }, -}; - -type IMicronoteBatchApis = IZodSchemaToApiTypes; -export default IMicronoteBatchApis; diff --git a/specification/sidechain/NoteApis.ts b/specification/sidechain/NoteApis.ts deleted file mode 100644 index d6a3389..0000000 --- a/specification/sidechain/NoteApis.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { z } from 'zod'; -import { NoteSchema } from '../types/INote'; -import { IZodSchemaToApiTypes } from '../utils/IZodApi'; - -export const NoteApiSchemas = { - 'Note.get': { - args: z.object({ - noteHash: NoteSchema.shape.noteHash, - }), - result: z.object({ note: NoteSchema }), - }, - 'Note.create': { - args: z.object({ - note: NoteSchema, - }), - result: z.object({ - accepted: z.boolean(), - }), - }, -}; - -type INoteApis = IZodSchemaToApiTypes; -export default INoteApis; diff --git a/specification/sidechain/RampApis.ts b/specification/sidechain/RampApis.ts deleted file mode 100644 index 658facb..0000000 --- a/specification/sidechain/RampApis.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { z } from 'zod'; -import { IZodSchemaToApiTypes } from '../utils/IZodApi'; -import { addressValidation } from '../common'; - -export const RampApiSchemas = { - 'Ramp.audit': { - args: z.undefined().nullish(), - result: z.object({ - auditDate: z.date(), - usdcToArgonConversionRate: z.number(), - argonsInCirculation_e6: z - .bigint() - .describe( - 'Argons converted to 6 decimals to match USDC reserves. Amount should NOT exceed USDC reserves adjusted by conversion rate.', - ), - usdcReserves_e6: z.bigint().describe('Total reserves balance in USDC raw value.'), - usdcReserveAddresses: z - .object({ - blockchain: z.string().describe('Blockchain where USDC is held (eg, ethereum, polygon, etc).'), - blockchainNetwork: z.string().describe('Blockchain network for the given chain (eg, homestead, ropsten, etc).'), - address: z.string().describe('USDC address of reserves.'), - ownershipProof: z - .string() - .describe('Signature proving ownership of holdings as of Audit Date.'), - }) - .array(), - }), - }, - 'Ramp.createTransferInAddress': { - args: z.object({ - blockchain: z.enum(['ethereum', 'polygon']), - address: addressValidation, - }), - result: z.object({ - blockchainNetwork: z.string(), - address: z.string().describe('Address on the given network.'), - expirationDate: z - .date() - .describe('Valid through date. Funds sent after this date will be lost.'), - }), - }, -}; - -type IRampApis = IZodSchemaToApiTypes; -export default IRampApis; diff --git a/specification/sidechain/SidechainInfoApis.ts b/specification/sidechain/SidechainInfoApis.ts deleted file mode 100644 index 3926a67..0000000 --- a/specification/sidechain/SidechainInfoApis.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { z } from 'zod'; -import { IZodSchemaToApiTypes } from '../utils/IZodApi'; -import { identityValidation, micronoteTokenValidation, signatureValidation } from '../common'; -import { BlockSettingsSchema } from '../types/IBlockSettings'; -import { MicronoteBatchSchema } from '../types/IMicronoteBatch'; - -export const SidechainInfoApiSchemas = { - 'Sidechain.settings': { - args: z.object({ - identity: identityValidation - .nullish() - .describe( - 'Provide an identity to get proof back that the Sidechain owns the rootIdentity.', - ), - }), - result: z.object({ - version: z.string(), - rootIdentities: identityValidation.array(), - identityProofSignatures: signatureValidation.array().optional(), - latestBlockSettings: BlockSettingsSchema, - settlementFeeMicrogons: micronoteTokenValidation, - batchDurationMinutes: z.number().int(), - }), - }, - 'Sidechain.audit': { - args: z.undefined().nullish(), - result: z.object({ - auditDate: z.date(), - argonsInCirculation_e2: z - .bigint() - .describe('Argons with centagon precision as a whole number (e-2).'), - argonsBurnedYesterday_e2: z - .bigint() - .describe('Argons burned in the previous day (starting UTC 0:00 to UTC 23:59).'), - argonsBurnedRolling30DayAverage_e2: z - .bigint() - .describe('Average daily Argons burned over the previous 30 days.'), - }), - }, - 'Sidechain.openBatches': { - args: z.undefined().nullish(), - result: z.object({ - micronote: MicronoteBatchSchema.array(), - }), - }, -}; - -type ISidechainInfoApis = IZodSchemaToApiTypes; -export default ISidechainInfoApis; diff --git a/specification/sidechain/SidechainSnapshot.proto b/specification/sidechain/SidechainSnapshot.proto deleted file mode 100644 index 34a98a8..0000000 --- a/specification/sidechain/SidechainSnapshot.proto +++ /dev/null @@ -1,67 +0,0 @@ -syntax = "proto3"; - -import "../protos/Transaction.json"; -import "../protos/DatumSummary.json"; - -service SidechainSnapshotService { - rpc get (GetSidechainSnapshotRequest) returns (GetSidechainSnapshotResponse) {} -} - -message GetSidechainSnapshotRequest { - bytes prevBlockHash = 1; - bytes linkNonce = 2; - DatumSummary datumSummary = 3; - bytes signature = 4; -} - -message ClosedMicronoteBatch { - bytes batchPublicKey = 1; - uint32 newNotesCount = 2; - bytes newNotesHash = 3; - string fundingMicrogons = 4; - string allocatedMicrogons = 5; - string revenueMicrogons = 6; - uint32 settledCentagons = 7; - uint32 settlementFeeCentagons = 8; - uint32 burnedCentagons = 9; - bytes burnNoteHash = 10; - uint32 micronotesCount = 11; - uint32 startBlockHeight = 12; - uint32 endBlockHeight = 13; - uint32 guaranteeBlockHeight = 14; - bytes burnSecurityTransactionHash = 15; -} - -message Security { - bytes transactionHash = 1; - uint32 outputIndex = 2; - uint32 centagons = 3; -} - -message AddressOwnershipProof { - bytes address = 1; - SignatureSettingsProof signatureSettings = 2; - repeated OwnershipProof owners = 3; -} - -message AccountBalance { - bytes address = 1; - string centagons = 2; - uint32 guaranteeBlockHeight = 3; -} - -message SidechainSnapshot { - bytes rootPublicKey = 1; - repeated Transaction burnTransactions = 2; - repeated Transaction transfersOut = 3; - repeated AccountBalance accounts = 4; - repeated ClosedMicronoteBatch closedMicronoteBatches = 5; - repeated Security securities = 6; - repeated AddressOwnershipProof securityAddressProofs = 7; - bytes snapshotHash = 8; - bytes signature = 9; -} - -message GetSidechainSnapshotResponse { - SidechainSnapshot snapshot = 1; -} diff --git a/specification/sidechain/StakeApis.ts b/specification/sidechain/StakeApis.ts deleted file mode 100644 index 251ea05..0000000 --- a/specification/sidechain/StakeApis.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { z } from 'zod'; -import { NoteSchema } from '../types/INote'; -import { IZodSchemaToApiTypes } from '../utils/IZodApi'; -import { StakeSettingsSchema } from '../types/IStakeSettings'; -import { - addressValidation, - blockHeightValidation, - hashValidation, - identityValidation, - signatureValidation, -} from '../common'; -import { StakeSignatureSchema } from '../types/IStakeSignature'; -import { AddressSignatureSchema } from '../types/IAddressSignature'; - -export const StakeApiSchemas = { - 'Stake.settings': { args: z.undefined().nullish(), result: StakeSettingsSchema }, - 'Stake.create': { - args: z.object({ - note: NoteSchema, - stakedIdentity: identityValidation, - }), - result: StakeSignatureSchema, - }, - 'Stake.refund': { - args: z.object({ - address: addressValidation, - stakedIdentity: identityValidation, - signature: AddressSignatureSchema, - }), - result: z.object({ - blockEndHeight: blockHeightValidation, - refundNoteHash: hashValidation, - refundEffectiveHeight: blockHeightValidation, - }), - }, - 'Stake.signature': { - args: z.object({ - stakedIdentity: identityValidation, - signature: signatureValidation, - }), - result: StakeSignatureSchema, - }, -}; - -type IStakeApis = IZodSchemaToApiTypes; -export default IStakeApis; diff --git a/specification/sidechain/index.ts b/specification/sidechain/index.ts deleted file mode 100644 index 30c1536..0000000 --- a/specification/sidechain/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { MicronoteBatchApiSchemas } from './MicronoteBatchApis'; -import { NoteApiSchemas } from './NoteApis'; -import { MicronoteApiSchemas } from './MicronoteApis'; -import { FundingTransferApiSchemas } from './FundingTransferApis'; -import { AddressApiSchemas } from './AddressApis'; -import { StakeApiSchemas } from './StakeApis'; -import { SidechainInfoApiSchemas } from './SidechainInfoApis'; -import { RampApiSchemas } from './RampApis'; -import { IZodHandlers, IZodSchemaToApiTypes } from '../utils/IZodApi'; - -const SidechainApiSchema = { - ...SidechainInfoApiSchemas, - ...AddressApiSchemas, - ...FundingTransferApiSchemas, - ...MicronoteApiSchemas, - ...MicronoteBatchApiSchemas, - ...NoteApiSchemas, - ...StakeApiSchemas, - ...RampApiSchemas, -}; - -export type ISidechainApiTypes = IZodSchemaToApiTypes; - -export type ISidechainApis = IZodHandlers; - -export default SidechainApiSchema; diff --git a/specification/tsconfig.dist.json b/specification/tsconfig.dist.json deleted file mode 100644 index 5a3db5d..0000000 --- a/specification/tsconfig.dist.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../tsconfig.dist.json", - "compilerOptions": { - "strict": true - }, - "include": ["**/*.ts", "*.ts", "package.json", ".eslintrc.js"], - "exclude": ["**/tsconfig*.json", "**/node_modules", "**/build"] -} diff --git a/specification/tsconfig.json b/specification/tsconfig.json deleted file mode 100644 index d883d01..0000000 --- a/specification/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "strictNullChecks": true - }, - "include": ["**/*.ts", "*.ts", "package.json", ".eslintrc.js"], - "exclude": ["**/tsconfig*.json", "**/node_modules", "**/build"] -} diff --git a/specification/types/BlockError.ts b/specification/types/BlockError.ts deleted file mode 100644 index 7acd4df..0000000 --- a/specification/types/BlockError.ts +++ /dev/null @@ -1,41 +0,0 @@ -enum BlockError { - SYSTEM_ERROR = 0, - INVALID_HEIGHT = 1, - INVALID_LINK_TARGET = 2, - INVALID_BOND_REDEMPTION = 3, - TOO_MANY_BOND_PURCHASES = 4, - STABLE_TRANSACTION_REJECTED = 5, - SHARES_LEDGER_REJECTED = 6, - INVALID_CALCULATION = 7, - INVALID_HASH = 8, - NOT_SOLVED = 9, - INVALID_COINBASE_PARAM = 10, - INVALID_COINBASE_AMOUNT = 11, - DUPLICATE_COINBASE = 12, - INVALID_LINK_NONCE = 13, - MISSING_BIT_SAMPLING = 14, - INSUFFICIENT_BIT_SAMPLING_SIZE = 15, - INVALID_BIT_SAMPLED = 16, - INVALID_STAKE = 17, - INVALID_BIT_SAMPLE_SIGNATURE = 18, - INVALID_DATUM_AUDIT_SIGNATURE = 19, - INVALID_MICRONOTE_ID_SIGNATURE = 20, - INVALID_MICRONOTE_ID = 22, - INVALID_DATUM_AUDITOR = 21, - INVALID_DATUM_XORED_CANDIDATE_SIGNATURE = 23, - INSUFFICIENT_XORED_CANDIDATES_FOUND = 24, - DUPLICATE_DATUM_AUDITOR = 25, - INSUFFICIENT_DATUM_SECOND_PINGS = 26, - INSUFFICIENT_DATUM_AUDITORS = 27, - INVALID_PARAM = 28, - INVALID_SIDECHAIN_TRANSFER = 29, - INVALID_MICRONOTE_SIDECHAIN = 30, - INVALID_DATUM_COORDINATOR_SIGNATURE = 31, - INVALID_SIDECHAIN_ROOT_IDENTITY = 32, - INVALID_SIDECHAIN_SNAPSHOT_BURN = 33, - SIDECHAIN_OUT_OF_BALANCE = 34, - INVALID_SIDECHAIN_FEES_COLLECTED = 35, - INVALID_SIDECHAIN_FUNDS = 36, - INVALID_SIDECHAIN_ADDRESS_PROOF = 37, -} -export default BlockError; diff --git a/specification/types/CoinageType.ts b/specification/types/CoinageType.ts deleted file mode 100644 index 863d248..0000000 --- a/specification/types/CoinageType.ts +++ /dev/null @@ -1,6 +0,0 @@ -enum CoinageType { - GRANT = 0, - SHAREHOLDERS = 1, - WEBHITS = 2, -} -export default CoinageType; diff --git a/specification/types/IAddressOwnershipProof.ts b/specification/types/IAddressOwnershipProof.ts deleted file mode 100644 index 9f48b0f..0000000 --- a/specification/types/IAddressOwnershipProof.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { z } from 'zod'; -import { identityValidation, signatureValidation } from '../common'; -import { MerkleProofSchema } from './IMerkleProof'; - -export const AddressOwnershipProofSchema = z.object({ - signature: signatureValidation, - identity: identityValidation, - ownershipMerkleProofs: MerkleProofSchema.array(), -}); - -type IAddressOwnershipProof = z.infer; - -export default IAddressOwnershipProof; diff --git a/specification/types/IAddressSignature.ts b/specification/types/IAddressSignature.ts deleted file mode 100644 index 2e336a1..0000000 --- a/specification/types/IAddressSignature.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { z } from 'zod'; -import { MerkleProofSchema } from './IMerkleProof'; -import { AddressOwnershipProofSchema } from './IAddressOwnershipProof'; - -export const AddressSignatureSchema = z.object({ - signers: AddressOwnershipProofSchema.array(), - signatureSettings: z.object({ - countRequired: z.number(), - settingsMerkleProofs: MerkleProofSchema.array(), - salt: z.instanceof(Buffer).optional(), - identityIndices: z.number().array().optional(), - }), -}); - -type IAddressSignature = z.infer; -export default IAddressSignature; diff --git a/specification/types/IArithmeticEncoding.ts b/specification/types/IArithmeticEncoding.ts deleted file mode 100644 index 95afd03..0000000 --- a/specification/types/IArithmeticEncoding.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { z } from 'zod'; - -export const ArithmeticEncodingSchema = z.object({ - powerOf2: z.number().nonnegative(), - multiplierE6: z.number().nonnegative().optional(), -}); - -type IArithmeticEncoding = z.infer; -export default IArithmeticEncoding; diff --git a/specification/types/IAuthorizedSidechain.ts b/specification/types/IAuthorizedSidechain.ts deleted file mode 100644 index 5655ee2..0000000 --- a/specification/types/IAuthorizedSidechain.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { z } from 'zod'; -import { hashValidation, identityValidation } from '../common'; - -export const AuthorizedSidechainTransferSchema = z.object({ - sidechainHash: hashValidation, - transferSignature: hashValidation, -}); - -export const AuthorizedSidechainSchema = z.object({ - sidechainHash: hashValidation, - rootIdentity: identityValidation, - url: z.string().url(), - transfer: AuthorizedSidechainTransferSchema.array().optional(), // optional - if rotating key/address -}); - -type IAuthorizedSidechain = z.infer; -type IAuthorizedSidechainTransfer = z.infer; - -export { IAuthorizedSidechainTransfer }; - -export default IAuthorizedSidechain; diff --git a/specification/types/IBitDatumHistory.ts b/specification/types/IBitDatumHistory.ts deleted file mode 100644 index b938532..0000000 --- a/specification/types/IBitDatumHistory.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { z } from 'zod'; -import { blockHeightValidation, identityValidation, signatureValidation } from '../common'; -import { MicronoteBatchDatumsSchema } from './IMicronoteBatchDatums'; -import { WebhitsClaimAddressSchema } from './IWebhitsClaimAddress'; - -export const BitDatumHistorySchema = z.object({ - identity: identityValidation, - blockHeight: blockHeightValidation, - averageXoredCandidates: z.number().int().nonnegative(), - datumsPerMicronoteBatch: MicronoteBatchDatumsSchema.array(), - webhitsClaimAddresses: WebhitsClaimAddressSchema.array(), - signature: signatureValidation, // need signature from original user to make sure hash that gets put into network is truly from you (should include block height) -}); - -type IBitDatumHistory = z.infer; - -export default IBitDatumHistory; diff --git a/specification/types/IBlock.ts b/specification/types/IBlock.ts deleted file mode 100644 index 988bd80..0000000 --- a/specification/types/IBlock.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { z } from 'zod'; -import { BlockHeaderSchema } from './IBlockHeader'; -import { AuthorizedSidechainSchema } from './IAuthorizedSidechain'; -import { TransactionSchema } from './ITransaction'; -import { CoinageSchema } from './ICoinage'; -import { DatumSummarySchema } from './IDatumSummary'; -import { BitDatumHistorySchema } from './IBitDatumHistory'; - -export const BlockSchema = z.object({ - header: BlockHeaderSchema, - stableLedger: TransactionSchema.array(), - sharesLedger: TransactionSchema.array(), // all share trades must happen in the sharesLedger - // these fields can be rolled off - coinages: CoinageSchema.array(), - datumSummary: DatumSummarySchema, - bitSampling: z.object({ - bitDatumHistories: BitDatumHistorySchema.array(), - }), - sidechainGovernance: z.object({ - authorizedSidechains: AuthorizedSidechainSchema.array(), - }), - // repeated SidechainSnapshot sidechainSnapshots = 8; -}); - -type IBlock = z.infer; - -export default IBlock; diff --git a/specification/types/IBlockHeader.ts b/specification/types/IBlockHeader.ts deleted file mode 100644 index 0661a7d..0000000 --- a/specification/types/IBlockHeader.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { z } from 'zod'; -import { blockHeightValidation, hashValidation } from '../common'; -import { ArithmeticEncodingSchema } from './IArithmeticEncoding'; - -export const BlockHeaderSchema = z.object({ - hash: hashValidation, - version: z.string(), - height: blockHeightValidation, - linkNonce: hashValidation, - prevBlockHash: hashValidation, - nextLinkTarget: ArithmeticEncodingSchema, // the max value of the hash that is allowed for the next linked block - time: z.date(), - stableMerkleRoot: hashValidation, - sharesMerkleRoot: hashValidation, - coinagesHash: hashValidation, - bondCentagonsCreated: z.bigint().refine(x => x >= 0n, 'Cannot be negative'), - stableCoinUSDCents: z.number().int().nonnegative(), // figure out bond price from stable price. - stableCoinVolume: z.number().int().nonnegative(), // figure out bond price from stable price. NOTE: not in centagons - datumSummaryHash: hashValidation, - sampledBitsHash: hashValidation, - xoredCandidateDistance: ArithmeticEncodingSchema, // minimum xor distance for future candidates - xoredCandidateAverage: z.number().int().nonnegative(), - sidechainChangesHash: hashValidation, - sidechainSnapshotsHash: hashValidation, -}); - -type IBlockHeader = z.infer; -export default IBlockHeader; diff --git a/specification/types/IBlockSettings.ts b/specification/types/IBlockSettings.ts deleted file mode 100644 index fb1f592..0000000 --- a/specification/types/IBlockSettings.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { z } from 'zod'; -import { hashValidation, identityValidation } from '../common'; -import { ArithmeticEncodingSchema } from './IArithmeticEncoding'; - -export const DatumSettingsSchema = z.object({ - xoredCandidatesMinimum: z.number().int().nonnegative(), - secondPingPercent: z.number().int().nonnegative(), - auditorsCount: z.number().int().nonnegative(), -}); - -export const ApprovedSidechainSchema = z.object({ - url: z.string(), - rootIdentity: identityValidation, -}); - -export const BlockSettingsSchema = z.object({ - xoredCandidateDistance: ArithmeticEncodingSchema, - datum: DatumSettingsSchema, - networkNodes: z.number().int().nonnegative(), - bitSamplingsInBlock: z.number().int().nonnegative(), - bitSamplingBlockAge: z.number().int().nonnegative(), - blockHash: hashValidation, - nextLinkTarget: ArithmeticEncodingSchema, - height: z.number().int().nonnegative(), - sidechains: ApprovedSidechainSchema.array(), - minimumMicronoteBurnPercent: z.number().int().nonnegative(), -}); - -type IBlockSettings = z.infer; -export default IBlockSettings; diff --git a/specification/types/ICoinage.ts b/specification/types/ICoinage.ts deleted file mode 100644 index d6553be..0000000 --- a/specification/types/ICoinage.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { z } from 'zod'; -import CoinageType from './CoinageType'; -import { - addressValidation, - blockHeightValidation, - centagonTokenValidation, - hashValidation, -} from '../common'; -import { GrantTransferSchema } from './IGrantTransfer'; - -export const CoinageSchema = z.object({ - type: z.nativeEnum(CoinageType), - hash: hashValidation, - centagons: centagonTokenValidation, - minimumClaimCentagons: centagonTokenValidation, - blockHeight: blockHeightValidation, - expirationBlockHeight: blockHeightValidation, - oldestClaimHeight: blockHeightValidation, - grantAddress: addressValidation, - transfer: GrantTransferSchema, // optional - if rotating key/address -}); - -type ICoinage = z.infer; - -export default ICoinage; diff --git a/specification/types/ICoordinator.ts b/specification/types/ICoordinator.ts deleted file mode 100644 index d6b7e2c..0000000 --- a/specification/types/ICoordinator.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { z } from 'zod'; -import { addressValidation, identityValidation, signatureValidation } from '../common'; -import { StakeSignatureSchema } from './IStakeSignature'; - -export const CoordinatorSchema = z.object({ - identity: identityValidation, - reputation: z.number().int().nonnegative(), - proofSignature: signatureValidation, - stakeSignature: StakeSignatureSchema, - paymentAddress: addressValidation, -}); - -type ICoordinator = z.infer; - -export default ICoordinator; diff --git a/specification/types/IDatum.ts b/specification/types/IDatum.ts deleted file mode 100644 index 082bdba..0000000 --- a/specification/types/IDatum.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { z } from 'zod'; -import { identityValidation, signatureValidation } from '../common'; -import { ProofOfKnowledgeSchema } from './IProofOfKnowedge'; - -export const DatumSchema = z.object({ - finalResult: z.any(), - proof: ProofOfKnowledgeSchema.array(), - signature: signatureValidation, - identity: identityValidation, - lastUpdated: z.string(), - isError: z.boolean(), -}); - -type IDatum = z.infer; - -export default IDatum; diff --git a/specification/types/IDatumSummary.ts b/specification/types/IDatumSummary.ts deleted file mode 100644 index 2ef1c80..0000000 --- a/specification/types/IDatumSummary.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { z } from 'zod'; -import { blockHeightValidation, identityValidation, signatureValidation } from '../common'; -import { WebhitsClaimAddressSchema } from './IWebhitsClaimAddress'; -import { MicronoteBatchDatumsSchema } from './IMicronoteBatchDatums'; - -export const DatumSummarySchema = z.object({ - identity: identityValidation, - blockHeight: blockHeightValidation, - averageXoredCandidates: z.number().int().nonnegative(), - datumsPerMicronoteBatch: MicronoteBatchDatumsSchema.array(), - webhitsClaimAddresses: WebhitsClaimAddressSchema.array(), - signature: signatureValidation, // need signature from original user to make sure hash that gets put into network is truly from you (should include block height) -}); - -type IDatumSummary = z.infer; - -export default IDatumSummary; diff --git a/specification/types/IGrantTransfer.ts b/specification/types/IGrantTransfer.ts deleted file mode 100644 index c21c46a..0000000 --- a/specification/types/IGrantTransfer.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { z } from 'zod'; -import { hashValidation } from '../common'; -import { AddressSignatureSchema } from './IAddressSignature'; - -export const GrantTransferSchema = z.object({ - coinageHash: hashValidation, - signature: AddressSignatureSchema, -}); - -type IGrantTransfer = z.infer; - -export default IGrantTransfer; diff --git a/specification/types/IMerkleProof.ts b/specification/types/IMerkleProof.ts deleted file mode 100644 index a97298a..0000000 --- a/specification/types/IMerkleProof.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { z } from 'zod'; -import { hashValidation } from '../common'; - -enum MerklePosition { - Left = 0, - Right = 1, -} - -export const MerkleProofSchema = z.object({ - position: z.nativeEnum(MerklePosition), - hash: hashValidation, -}); - -type IMerkleProof = z.infer; -export { MerklePosition }; -export default IMerkleProof; diff --git a/specification/types/IMicronote.ts b/specification/types/IMicronote.ts deleted file mode 100644 index c764b03..0000000 --- a/specification/types/IMicronote.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { z } from 'zod'; -import { - blockHeightValidation, - identityValidation, - micronoteIdValidation, - micronoteTokenValidation, - signatureValidation, -} from '../common'; -import { MicronoteBatchSchema } from './IMicronoteBatch'; - -export const MicronoteSchema = z.object({ - microgons: micronoteTokenValidation, - micronoteId: micronoteIdValidation, - blockHeight: blockHeightValidation, - batchSlug: MicronoteBatchSchema.shape.batchSlug, - micronoteBatchUrl: z.string().url(), - micronoteBatchIdentity: identityValidation, - micronoteSignature: signatureValidation, - sidechainIdentity: identityValidation, - sidechainValidationSignature: signatureValidation, - // guaranteeBlockHash: hashValidation.describe('TODO: Add back in. This should tell a server what block hash they can choose to trust or not'), - guaranteeBlockHeight: blockHeightValidation, -}); - -type IMicronote = z.infer; - -export default IMicronote; diff --git a/specification/types/IMicronoteBatch.ts b/specification/types/IMicronoteBatch.ts deleted file mode 100644 index cd50d16..0000000 --- a/specification/types/IMicronoteBatch.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { z } from 'zod'; -import { addressValidation, identityValidation, signatureValidation } from '../common'; - -export const MicronoteBatchSchema = z.object({ - batchHost: z.string().url(), - batchSlug: z - .string() - .regex(/^[0-9A-Fa-f]+$/) - .length(14), - plannedClosingTime: z.date(), - stopNewNotesTime: z.date(), - minimumFundingCentagons: z.bigint().refine(x => x >= 1n), - micronoteBatchIdentity: identityValidation, - micronoteBatchAddress: addressValidation, - sidechainIdentity: identityValidation, - sidechainValidationSignature: signatureValidation, -}); - -type IMicronoteBatch = z.infer; - -export default IMicronoteBatch; diff --git a/specification/types/IMicronoteBatchDatums.ts b/specification/types/IMicronoteBatchDatums.ts deleted file mode 100644 index c89310b..0000000 --- a/specification/types/IMicronoteBatchDatums.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { z } from 'zod'; -import { hashValidation, identityValidation } from '../common'; - -export const MicronoteBatchDatumsSchema = z.object({ - micronoteBatchUrl: z.string().url(), - micronoteBatchIdentity: identityValidation, - micronoteIdsHash: hashValidation, - micronotesCount: z.number().nonnegative(), -}); - -type IMicronoteBatchDatums = z.infer; - -export default IMicronoteBatchDatums; diff --git a/specification/types/INote.ts b/specification/types/INote.ts deleted file mode 100644 index 1e07841..0000000 --- a/specification/types/INote.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { z } from 'zod'; -import { AddressSignatureSchema } from './IAddressSignature'; -import { addressValidation, blockHeightValidation, hashValidation } from '../common'; -import NoteType from './NoteType'; - -export const NoteSchema = z.object({ - toAddress: addressValidation, - fromAddress: addressValidation, - centagons: z.bigint().refine(x => x > 0), - noteHash: hashValidation, - type: z.nativeEnum(NoteType), - effectiveBlockHeight: blockHeightValidation.optional(), - guaranteeBlockHeight: blockHeightValidation.optional(), - timestamp: z.date(), - signature: AddressSignatureSchema, -}); - -type INote = z.infer; -export default INote; diff --git a/specification/types/IProofOfKnowedge.ts b/specification/types/IProofOfKnowedge.ts deleted file mode 100644 index 356cc85..0000000 --- a/specification/types/IProofOfKnowedge.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { z } from 'zod'; -import { - addressValidation, - blockHeightValidation, - hashValidation, - identityValidation, - micronoteIdValidation, - micronoteTokenValidation, -} from '../common'; -import { XoredCandidateSchema } from './IXoredCandidate'; -import { CoordinatorSchema } from './ICoordinator'; - -export const ProofOfKnowledgeSchema = z.object({ - hash: hashValidation, - micronoteId: micronoteIdValidation, - micronoteBlockHeight: blockHeightValidation, - blockHeight: blockHeightValidation, - xoredCandidates: XoredCandidateSchema.array(), - coordinator: CoordinatorSchema, - decoderHash: hashValidation, - decoderReputation: z.number().int().nonnegative(), - identityReputationChanges: z.record(identityValidation, z.number().int()), - isBlockEligible: z.boolean(), - resultHash: hashValidation, - webhitsClaimAddress: addressValidation, - viewOfTruthHash: hashValidation, - maxBasePricePerKb: micronoteTokenValidation, - maxBasePricePerQuery: micronoteTokenValidation, -}); - -type IProofOfKnowledge = z.infer; - -export default IProofOfKnowledge; diff --git a/specification/types/IStakeSettings.ts b/specification/types/IStakeSettings.ts deleted file mode 100644 index 1bf30c9..0000000 --- a/specification/types/IStakeSettings.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { z } from 'zod'; -import { - addressValidation, - blockHeightValidation, - centagonTokenValidation, - hashValidation, - identityValidation, -} from '../common'; - -export const StakeSettingsSchema = z.object({ - centagons: centagonTokenValidation, - rootIdentity: identityValidation, - stakeAddress: addressValidation, - stableBlockHeight: blockHeightValidation, - stableBlockHash: hashValidation, - currentBlockHash: hashValidation, - currentBlockHeight: blockHeightValidation, - refundBlockWindow: z.number().int().nonnegative(), -}); - -type IStateSettings = z.infer; - -export default IStateSettings; diff --git a/specification/types/IStakeSignature.ts b/specification/types/IStakeSignature.ts deleted file mode 100644 index cd9856f..0000000 --- a/specification/types/IStakeSignature.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { z } from 'zod'; -import { blockHeightValidation, identityValidation, signatureValidation } from '../common'; - -export const StakeSignatureSchema = z.object({ - signature: signatureValidation, - blockHeight: blockHeightValidation, - rootIdentity: identityValidation, -}); - -type IStakeSignature = z.infer; - -export default IStakeSignature; diff --git a/specification/types/ITransaction.ts b/specification/types/ITransaction.ts deleted file mode 100644 index 215f0c8..0000000 --- a/specification/types/ITransaction.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { z } from 'zod'; -import { blockHeightValidation, hashValidation } from '../common'; -import { TransactionSourceSchema } from './ITransactionSource'; -import { TransactionOutputSchema } from './ITransactionOutput'; -import TransactionType from './TransactionType'; - -export const TransactionSchema = z.object({ - transactionHash: hashValidation, // transaction hash - version: z.string(), - time: z.date(), - type: z.nativeEnum(TransactionType), - expiresAtBlockHeight: blockHeightValidation, - sources: TransactionSourceSchema.array(), // empty means coinbase (ie, printed) - outputs: TransactionOutputSchema.array(), -}); - -type ITransaction = z.infer; - -export default ITransaction; diff --git a/specification/types/ITransactionOutput.ts b/specification/types/ITransactionOutput.ts deleted file mode 100644 index dfa2ee7..0000000 --- a/specification/types/ITransactionOutput.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { z } from 'zod'; -import { addressValidation, centagonTokenValidation } from '../common'; - -export const TransactionOutputSchema = z.object({ - address: addressValidation, // signatureSettings + hashed alpha sorted public keys - centagons: centagonTokenValidation, - isBond: z.boolean().optional(), - isBurned: z.boolean().optional(), // if the coins are burned up as part of the transaction - addressOnSidechain: addressValidation.optional(), - isSidechained: z.boolean().optional(), -}); - -type ITransactionOutput = z.infer; - -export default ITransactionOutput; diff --git a/specification/types/ITransactionSource.ts b/specification/types/ITransactionSource.ts deleted file mode 100644 index 9ed12ce..0000000 --- a/specification/types/ITransactionSource.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { z } from 'zod'; -import { blockHeightValidation, hashValidation } from '../common'; -import { AddressSignatureSchema } from './IAddressSignature'; -import LedgerType from './LedgerType'; - -export const TransactionSourceSchema = z.object({ - sourceTransactionHash: hashValidation.optional(), - sourceOutputIndex: z.number().int().nonnegative().optional(), - sourceAddressSignatureSettings: AddressSignatureSchema.shape.signatureSettings, - sourceAddressSigners: AddressSignatureSchema.shape.signers, - sourceLedger: z.nativeEnum(LedgerType), // if coinage or bond, need to specify where we're trying to grab from - blockClaimHeight: blockHeightValidation.optional(), // required if the transaction source is a coinage claim - coinageHash: hashValidation.optional(), // required for coinage claims -}); - -type ITransactionSource = z.infer; - -export default ITransactionSource; diff --git a/specification/types/ITransactionSourceSignatureData.ts b/specification/types/ITransactionSourceSignatureData.ts deleted file mode 100644 index 2069664..0000000 --- a/specification/types/ITransactionSourceSignatureData.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { z } from 'zod'; -import { addressValidation, centagonTokenValidation, hashValidation } from '../common'; -import LedgerType from './LedgerType'; -import TransactionType from './TransactionType'; -import { TransactionOutputSchema } from './ITransactionOutput'; -import { AddressSignatureSchema } from './IAddressSignature'; - -export const TransactionSourceSignatureDataSchema = z.object({ - version: z.string(), - ledger: z.nativeEnum(LedgerType), - type: z.nativeEnum(TransactionType), - sourceTransactionHash: hashValidation, // transaction hash - sourceTransactionOutputIndex: z.number().int().nonnegative(), - sourceLedger: z.nativeEnum(LedgerType), - address: addressValidation, - addressSignatureSettings: AddressSignatureSchema.shape.signatureSettings, // signatures by other multisig authors - centagons: centagonTokenValidation, - coinageHash: hashValidation.optional(), - outputs: TransactionOutputSchema.array(), -}); - -type ITransactionSourceSignatureData = z.infer; - -export default ITransactionSourceSignatureData; diff --git a/specification/types/IWebhitsClaimAddress.ts b/specification/types/IWebhitsClaimAddress.ts deleted file mode 100644 index f93ddbf..0000000 --- a/specification/types/IWebhitsClaimAddress.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { z } from 'zod'; -import { addressValidation, hashValidation } from '../common'; - -export const AddressCountsSchema = z.object({ - claimAddress: addressValidation, - count: z.number().int().nonnegative(), -}); - -export const WebhitsClaimAddressSchema = z.object({ - viewOfTruthHash: hashValidation, - addressCounts: AddressCountsSchema.array(), -}); - -type IWebhitsClaimAddress = z.infer; - -export default IWebhitsClaimAddress; diff --git a/specification/types/IXoredCandidate.ts b/specification/types/IXoredCandidate.ts deleted file mode 100644 index 00dbe53..0000000 --- a/specification/types/IXoredCandidate.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { z } from 'zod'; -import { - addressValidation, - hashValidation, - identityValidation, - micronoteTokenValidation, - signatureValidation, -} from '../common'; -import { StakeSignatureSchema } from './IStakeSignature'; - -export const XoredCandidateSchema = z.object({ - nodeId: z.string(), - identity: identityValidation, - publicIp: z.string(), - publicPort: z.number().int().positive(), - reputation: z.number().int().nonnegative(), - signature: signatureValidation, - available: z.boolean(), - stakeSignature: StakeSignatureSchema, - pricePerKb: micronoteTokenValidation, - pricePerQuery: micronoteTokenValidation, - firstPingSignature: signatureValidation, - secondPingSignature: signatureValidation, - result: z.any(), - resultHash: hashValidation, - webhitsClaimAddress: addressValidation, - resultSignature: signatureValidation, - resultError: z.object({ - name: z.string(), - description: z.string(), - }), - isConsensusResult: z.boolean(), - isHighReputationRunner: z.boolean(), - paymentAddress: addressValidation, -}); - -type IXoredCandidate = z.infer; -export default IXoredCandidate; diff --git a/specification/types/IXoredCandidateSummary.ts b/specification/types/IXoredCandidateSummary.ts deleted file mode 100644 index 21382b2..0000000 --- a/specification/types/IXoredCandidateSummary.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { z } from 'zod'; -import { addressValidation, identityValidation, signatureValidation } from '../common'; -import { StakeSignatureSchema } from './IStakeSignature'; - -export const XoredCandidateSummarySchema = z.object({ - identity: identityValidation, - reputation: z.number().nonnegative(), - firstPingSignature: signatureValidation, - secondPingSignature: signatureValidation, - auditSignature: signatureValidation, - stakeSignature: StakeSignatureSchema, - paymentAddress: addressValidation, -}); - -type IXoredCandidateSummary = z.infer; -export default IXoredCandidateSummary; diff --git a/specification/types/LedgerType.ts b/specification/types/LedgerType.ts deleted file mode 100644 index db124c8..0000000 --- a/specification/types/LedgerType.ts +++ /dev/null @@ -1,5 +0,0 @@ -enum LedgerType { - STABLE = 0, - SHARES = 1, -} -export default LedgerType; diff --git a/specification/types/NoteType.ts b/specification/types/NoteType.ts deleted file mode 100644 index af09923..0000000 --- a/specification/types/NoteType.ts +++ /dev/null @@ -1,14 +0,0 @@ -enum NoteType { - transferIn = 0, - transferOut = 1, - transfer = 2, - revenue = 3, - settlementFees = 4, - interest = 5, - micronoteFunds = 6, - micronoteBatchRefund = 7, - burn = 8, - stakeCreate = 9, - stakeRefund = 10 -} -export default NoteType; diff --git a/specification/types/TransactionError.ts b/specification/types/TransactionError.ts deleted file mode 100644 index 740f1b1..0000000 --- a/specification/types/TransactionError.ts +++ /dev/null @@ -1,26 +0,0 @@ -enum TransactionError { - INVALID_LEDGER_USED = 0, - INVALID_SOURCES = 1, - SOURCE_NOT_FOUND = 2, - FIRST_OUTPUT_MUST_BE_BOND = 3, - INVALID_OUTPUTS = 4, - INVALID_HASH = 5, - SPENT = 7, - INSUFFICIENT_CENTAGONS = 8, - INSUFFICIENT_BURN = 9, - SINGLE_BOND_OUTPUT_REQUIRED = 10, - SOURCES_FROZEN_AS_BONDS = 11, - SOURCE_IS_BURNED = 12, - TX_NOT_FOUND = 13, - INVALID_VARIABLE = 14, - INVALID_SIGNATURE = 15, - NEEDS_COOLDOWN_BEFORE_SPEND = 16, - ALREADY_CLAIMED = 17, - INVALID_COINBASE_TX = 18, - EXPIRED = 19, - SYSTEM_ERROR = 20, - SOURCE_NOT_COMMITTED_TO_A_BLOCK = 21, - COINAGE_CLAIM_MINIMUM_NOT_REACHED = 22, - SOURCE_IS_SIDECHAINED = 23, -} -export default TransactionError; diff --git a/specification/types/TransactionType.ts b/specification/types/TransactionType.ts deleted file mode 100644 index e747735..0000000 --- a/specification/types/TransactionType.ts +++ /dev/null @@ -1,8 +0,0 @@ -enum TransactionType { - COINBASE = 0, - TRANSFER = 1, - COINAGE_CLAIM = 2, - BOND_PURCHASE = 3, - BOND_REDEMPTION = 4, // only allowed in stable ledger. must have corresponding transaction in bondTransactions -} -export default TransactionType; diff --git a/specification/utils/IZodApi.ts b/specification/utils/IZodApi.ts deleted file mode 100644 index 1b6295f..0000000 --- a/specification/utils/IZodApi.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { z } from 'zod'; - -export type IZodSchemaToApiTypes = { - [T in keyof Z & string]: IZodCommandSchema; -}; - -export type IZodCommandSchema = { - command: T; - args: z.infer; - result: z.infer; -}; - -export type IZodApiTypes = { args: z.Schema; result: z.Schema }; - -export type IZodApiSpec = { [command: string]: IZodApiTypes }; - -export type IZodHandlers = { - [Api in keyof Spec]: ( - args: z.infer, - context?: TContext, - ) => Promise>; -}; diff --git a/specification/utils/ValidatingApiHandler.ts b/specification/utils/ValidatingApiHandler.ts deleted file mode 100644 index 550dfad..0000000 --- a/specification/utils/ValidatingApiHandler.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { IZodApiSpec, IZodApiTypes, IZodSchemaToApiTypes } from './IZodApi'; -import ValidationError from './ValidationError'; - -export default class ValidatingApiHandler< - APIs extends IZodApiSpec, - Command extends keyof APIs & string, - APISpec extends IZodSchemaToApiTypes, - IHandlerOptions = any, -> { - protected apiHandler: ( - this: ValidatingApiHandler, - args: APISpec[Command]['args'], - options?: IHandlerOptions, - ) => Promise; - - protected validationSchema: IZodApiTypes | undefined; - - constructor( - public readonly command: Command, - protected apiSchema: APIs, - args: { - handler: ValidatingApiHandler['apiHandler']; - }, - ) { - this.apiHandler = args.handler.bind(this); - this.validationSchema = apiSchema[command]; - } - - public async handler( - rawArgs: unknown, - options?: IHandlerOptions, - ): Promise { - const args = this.validatePayload(rawArgs); - return await this.apiHandler(args, options); - } - - public validatePayload(data: unknown): APISpec[Command]['args'] { - if (!this.validationSchema) return data; - // NOTE: mutates `errors` - const result = this.validationSchema.args.safeParse(data); - if (result.success) return result.data; - - - throw ValidationError.fromZodValidation( - `The parameters for this command (${this.command}) are invalid.`, - result.error, - ); - } -} diff --git a/specification/utils/ValidationError.ts b/specification/utils/ValidationError.ts deleted file mode 100644 index a0c3cde..0000000 --- a/specification/utils/ValidationError.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ZodError } from 'zod'; - -export default class ValidationError extends Error { - public readonly code = 'ERR_VALIDATION'; - constructor(message: string, readonly errors: string[]) { - super(message ?? 'Invalid request'); - // Capturing stack trace, excluding constructor call from it. - Error.captureStackTrace(this, this.constructor); - } - - public toJSON(): unknown { - return { - errors: this.errors, - message: this.message, - code: this.code, - stack: this.stack, - }; - } - - public override toString(): string { - const errors = this.errors ? `\n${this.errors.join('\n - ')}` : ''; - return `${this.message}${errors}`; - } - - static fromZodValidation(message: string, error: ZodError): ValidationError { - const errorList = error.issues.map(x => `"${x.path.join('.')}": ${x.message}`); - throw new ValidationError(message, errorList); - } -} diff --git a/tsconfig.json b/tsconfig.json index 677ab01..bb91b4f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,13 +2,8 @@ "extends": "./node_modules/@ulixee/repo-tools/tsconfig.json", "compilerOptions": { "rootDir": ".", - "outDir": "./build" + "outDir": "./build", }, - "references": [ - { - "path": "specification/tsconfig.json" - } - ], "include": ["./**/*.ts", "**/*.js", "**/*.json", ".eslintrc.js"], "exclude": [ "**/tsconfig*.json", @@ -17,6 +12,6 @@ "specification", "node_modules", "**/node_modules", - "**/*.d.ts" - ] + "**/*.d.ts", + ], } diff --git a/yarn.lock b/yarn.lock index 860464e..2c5cce7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2384,11 +2384,6 @@ before-after-hook@^2.2.0: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== -bignumber.js@^9.0.2: - version "9.1.2" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" - integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -2707,11 +2702,6 @@ commander@11.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== -commander@^9.5.0: - version "9.5.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" - integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== - compare-func@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" @@ -5730,11 +5720,6 @@ modify-values@^1.0.0: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== -moment@^2.29.4: - version "2.30.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" - integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== - mri@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" @@ -8075,8 +8060,3 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -zod@^3.20.2: - version "3.22.4" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" - integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==