This commit is contained in:
Mark S. Lewis 2026-02-25 17:22:13 +00:00 committed by GitHub
commit 1e786f9b5b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
82 changed files with 17143 additions and 4521 deletions

View file

@ -6,16 +6,16 @@ inputs:
default: "lts/*"
just-version:
description: Just Version
default: "1.43.0"
default: "1.46.0"
k9s-version:
description: k9s Version
default: v0.50.15
default: v0.50.18
fabric-version:
description: Version of Hyperledger Fabric
default: "2.5.14"
ca-version:
description: Version of Hyperledger Fabric CA
default: "1.5.15"
default: "1.5.17"
runs:
using: "composite"

View file

@ -15,7 +15,7 @@ inputs:
default: 2.5.14
ca-version:
description: Version of Hyperledger Fabric CA
default: 1.5.15
default: 1.5.17
runs:
using: "composite"

1
.gitignore vendored
View file

@ -13,7 +13,6 @@ vendor/
.idea
# Dependency directories
node_modules/
package-lock.json
# Ignore Gradle build output directory
build
# Ignore Maven build output directory

View file

@ -1,7 +1,8 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
export default defineConfig(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',

File diff suppressed because it is too large Load diff

View file

@ -23,11 +23,11 @@
"@hyperledger/fabric-gateway": "^1.10.0"
},
"devDependencies": {
"@eslint/js": "^9.3.0",
"@tsconfig/node18": "^18.2.2",
"@types/node": "^18.18.6",
"eslint": "^8.57.0",
"typescript": "~5.4",
"typescript-eslint": "^7.13.0"
"@eslint/js": "^10.0.1",
"@tsconfig/node20": "^20.1.9",
"@types/node": "^20.19.33",
"eslint": "^10.0.2",
"typescript": "~5.8",
"typescript-eslint": "^8.56.1"
}
}

View file

@ -1,5 +1,5 @@
{
"extends": "@tsconfig/node18/tsconfig.json",
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"declaration": true,
@ -10,6 +10,6 @@
"noUncheckedIndexedAccess": true,
"forceConsistentCasingInFileNames": true
},
"include": ["./src/**/*"],
"exclude": ["./src/**/*.spec.ts"]
"include": ["src/"],
"exclude": ["**/*.spec.*"]
}

View file

@ -1,7 +1,8 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
export default defineConfig(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',

File diff suppressed because it is too large Load diff

View file

@ -31,11 +31,11 @@
"sort-keys-recursive": "^2.1.0"
},
"devDependencies": {
"@types/node": "^18.19.33",
"@eslint/js": "^9.3.0",
"@tsconfig/node18": "^18.2.4",
"eslint": "^8.57.0",
"typescript": "~5.4.5",
"typescript-eslint": "^7.11.0"
"@eslint/js": "^10.0.1",
"@tsconfig/node20": "^20.1.9",
"@types/node": "^20.19.33",
"eslint": "^10.0.2",
"typescript": "~5.8",
"typescript-eslint": "^8.56.1"
}
}

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@tsconfig/node18/tsconfig.json",
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,

View file

@ -1,7 +1,8 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
export default defineConfig(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',

File diff suppressed because it is too large Load diff

View file

@ -23,11 +23,11 @@
"@hyperledger/fabric-gateway": "^1.10.0"
},
"devDependencies": {
"@eslint/js": "^9.3.0",
"@tsconfig/node18": "^18.2.2",
"@types/node": "^18.18.6",
"eslint": "^8.57.0",
"typescript": "~5.4",
"typescript-eslint": "^7.13.0"
"@eslint/js": "^10.0.1",
"@tsconfig/node20": "^20.1.9",
"@types/node": "^20.19.33",
"eslint": "^10.0.2",
"typescript": "~5.8",
"typescript-eslint": "^8.56.1"
}
}

View file

@ -1,5 +1,5 @@
{
"extends": "@tsconfig/node18/tsconfig.json",
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"declaration": true,
@ -10,6 +10,6 @@
"noUncheckedIndexedAccess": true,
"forceConsistentCasingInFileNames": true
},
"include": ["./src/**/*"],
"exclude": ["./src/**/*.spec.ts"]
"include": ["src/"],
"exclude": ["**/*.spec.*"]
}

View file

@ -1,7 +1,8 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
export default defineConfig(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,9 @@
"version": "0.0.1",
"description": "Hyperledger Fabric Asset Transfer Chaincode written in TypeScript",
"main": "dist/index.js",
"engines": {
"node": ">=20"
},
"scripts": {
"build": "tsc",
"lint": "eslint src",
@ -17,11 +20,11 @@
"sort-keys-recursive": "^2.1.0"
},
"devDependencies": {
"@types/node": "^18.19.33",
"@eslint/js": "^9.3.0",
"@tsconfig/node18": "^18.2.4",
"eslint": "^8.57.0",
"typescript": "~5.4.5",
"typescript-eslint": "^7.11.0"
"@eslint/js": "^10.0.1",
"@tsconfig/node20": "^20.1.9",
"@types/node": "^20.19.33",
"eslint": "^10.0.2",
"typescript": "~5.8",
"typescript-eslint": "^8.56.1"
}
}

View file

@ -335,7 +335,7 @@ export class AssetTransferContract extends Contract {
const nanos = historyRecord.timestamp.nanos;
const secondsNumber =
typeof seconds === 'number' ? seconds : Number(seconds.low);
typeof seconds === 'number' ? seconds : seconds.low;
const timestamp = new Date(secondsNumber * 1000 + nanos / 1e6);
results.push({
txId: historyRecord.txId,
@ -355,7 +355,7 @@ export class AssetTransferContract extends Contract {
@Returns('boolean')
public async AssetExists(ctx: Context, assetID: string): Promise<boolean> {
const assetBytes = await ctx.stub.getState(assetID);
return !!(assetBytes.length > 0);
return assetBytes.length > 0;
}
// InitLedger creates the initial set of assets in the ledger.
@ -436,6 +436,7 @@ export class AssetTransferContract extends Contract {
let record: Asset;
try {
record = JSON.parse(strValue) as Asset;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (err) {
record = {} as Asset;
}

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@tsconfig/node18/tsconfig.json",
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,

View file

@ -1,7 +1,8 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
export default defineConfig(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',

File diff suppressed because it is too large Load diff

View file

@ -23,11 +23,11 @@
"@hyperledger/fabric-gateway": "^1.10.0"
},
"devDependencies": {
"@eslint/js": "^9.3.0",
"@tsconfig/node18": "^18.2.2",
"@types/node": "^18.18.6",
"eslint": "^8.57.0",
"typescript": "~5.4",
"typescript-eslint": "^7.13.0"
"@eslint/js": "^10.0.1",
"@tsconfig/node20": "^20.1.9",
"@types/node": "^20.19.33",
"eslint": "^10.0.2",
"typescript": "~5.8",
"typescript-eslint": "^8.56.1"
}
}

View file

@ -1,5 +1,5 @@
{
"extends": "@tsconfig/node18/tsconfig.json",
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"declaration": true,

View file

@ -1,7 +1,8 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
export default defineConfig(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',

File diff suppressed because it is too large Load diff

View file

@ -31,11 +31,11 @@
"sort-keys-recursive": "^2.1.10"
},
"devDependencies": {
"@types/node": "^18.19.33",
"@eslint/js": "^9.3.0",
"@tsconfig/node18": "^18.2.4",
"eslint": "^8.57.0",
"typescript": "~5.4.5",
"typescript-eslint": "^7.11.0"
"@eslint/js": "^10.0.1",
"@tsconfig/node20": "^20.1.9",
"@types/node": "^20.19.33",
"eslint": "^10.0.2",
"typescript": "~5.8",
"typescript-eslint": "^8.56.1"
}
}

View file

@ -465,9 +465,7 @@ export class AssetTransfer extends Contract {
const b64ID = ctx.clientIdentity.getID();
// base64.StdEncoding.DecodeString(b64ID);
const decodeID = Buffer.from(b64ID, 'base64').toString('binary');
return String(decodeID);
return Buffer.from(b64ID, 'base64').toString('binary');
}
// verifyClientOrgMatchesPeerOrg is an internal function used verify client org id and matches peer org id.
public verifyClientOrgMatchesPeerOrg(ctx: Context): void {

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@tsconfig/node18/tsconfig.json",
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,

View file

@ -1,7 +1,8 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
export default defineConfig(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',

File diff suppressed because it is too large Load diff

View file

@ -25,11 +25,11 @@
"fabric-shim": "~2.5"
},
"devDependencies": {
"@types/node": "^18.19.33",
"@eslint/js": "^9.3.0",
"@tsconfig/node18": "^18.2.4",
"eslint": "^8.57.0",
"typescript": "~5.4.5",
"typescript-eslint": "^7.11.0"
"@eslint/js": "^10.0.1",
"@tsconfig/node20": "^20.1.9",
"@types/node": "^20.19.33",
"eslint": "^10.0.2",
"typescript": "~5.8",
"typescript-eslint": "^8.56.1"
}
}

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@tsconfig/node18/tsconfig.json",
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,

View file

@ -1,4 +1,5 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {

File diff suppressed because it is too large Load diff

View file

@ -23,11 +23,11 @@
"@hyperledger/fabric-gateway": "^1.10.0"
},
"devDependencies": {
"@eslint/js": "^9.3.0",
"@tsconfig/node18": "^18.2.2",
"@types/node": "^18.18.6",
"eslint": "^8.57.0",
"typescript": "~5.4",
"typescript-eslint": "^7.13.0"
"@eslint/js": "^10.0.1",
"@tsconfig/node20": "^20.1.9",
"@types/node": "^20.19.33",
"eslint": "^10.0.2",
"typescript": "~5.8",
"typescript-eslint": "^8.56.1"
}
}

View file

@ -5,7 +5,7 @@
*/
import { Contract } from '@hyperledger/fabric-gateway';
import { TextDecoder } from 'util';
import { GREEN, parse, RED, RESET } from './utils';
import { GREEN, RED, RESET } from './utils';
import crypto from 'crypto';
import { mspIdOrg2 } from './connect';
@ -92,16 +92,16 @@ export class ContractWrapper {
const resultBytes = await this.#contract.evaluateTransaction('ReadAsset', assetKey);
const result = this.#utf8Decoder.decode(resultBytes);
if (result.length !== 0) {
const json = parse<AssetJSON>(result);
if (!result) {
throw new Error('No Asset Found');
}
const json = JSON.parse(result) as AssetJSON;
if (json.ownerOrg === ownerOrg) {
console.log(`*** Result from ${this.#org} - asset ${json.assetID} owned by ${json.ownerOrg} DESC: ${json.publicDescription}`);
} else {
console.log(`${RED}*** Failed owner check from ${this.#org} - asset ${json.assetID} owned by ${json.ownerOrg} DESC:${json.publicDescription}.${RESET}`);
}
} else {
throw new Error('No Asset Found');
}
}
public async getAssetPrivateProperties(assetKey: string, ownerOrg: string): Promise<void> {
@ -113,7 +113,7 @@ export class ContractWrapper {
const resultBytes = await this.#contract.evaluateTransaction('GetAssetPrivateProperties', assetKey);
const resultString = this.#utf8Decoder.decode(resultBytes);
const json = parse<AssetPropertiesJSON>(resultString);
const json = JSON.parse(resultString) as AssetPropertiesJSON;
const result: AssetProperties = {
color: json.color,
size: json.size,
@ -167,16 +167,16 @@ export class ContractWrapper {
});
const resultString = this.#utf8Decoder.decode(resultBytes);
if (resultString.length !== 0) {
const json = parse<AssetPropertiesJSON>(resultString);
if (!resultString) {
throw new Error(`Private information about asset ${assetId} has not been verified by ${this.#org}`);
}
const json = JSON.parse(resultString) as AssetPropertiesJSON;
if (typeof json === 'object') {
console.log(`*** Success VerifyAssetProperties, private information about asset ${assetId} has been verified by ${this.#org}`);
} else {
console.log(`*** Failed: VerifyAssetProperties, private information about asset ${assetId} has not been verified by ${this.#org}`);
}
} else {
throw new Error(`Private information about asset ${assetId} has not been verified by ${this.#org}`);
}
}
public async agreeToBuy(assetPrice: AssetPrice, privateData: AssetPrivateData): Promise<void> {
@ -217,7 +217,7 @@ export class ContractWrapper {
const resultBytes = await this.#contract.evaluateTransaction('GetAssetSalesPrice', assetKey);
const resultString = this.#utf8Decoder.decode(resultBytes);
const json = parse<AssetPriceJSON>(resultString);
const json = JSON.parse(resultString) as AssetPriceJSON;
const result: AssetPrice = {
assetId: json.assetID,
@ -238,7 +238,7 @@ export class ContractWrapper {
const resultBytes = await this.#contract.evaluateTransaction('GetAssetBidPrice', assetKey);
const resultString = this.#utf8Decoder.decode(resultBytes);
const json = parse<AssetPriceJSON>(resultString);
const json = JSON.parse(resultString) as AssetPriceJSON;
const result: AssetPrice = {
assetId: json.assetID,
price: json.price,

View file

@ -7,7 +7,3 @@
export const RED = '\x1b[31m\n';
export const GREEN = '\x1b[32m\n';
export const RESET = '\x1b[0m';
export function parse<T>(data: string): T {
return JSON.parse(data) as T;
}

View file

@ -1,5 +1,5 @@
{
"extends": "@tsconfig/node18/tsconfig.json",
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"declaration": true,

View file

@ -8,7 +8,7 @@ function print() {
echo -e "${GREEN}${1}${NC}"
}
dirs=("$(find . -name "*-typescript" -type d -not -path '*/.*')")
dirs=("$(find . \( -name '.?*' -o -name 'node_modules' \) -prune -o -type d -name '*-typescript' -print)")
for dir in $dirs; do
print "Linting $dir"
pushd $dir

View file

@ -8,7 +8,6 @@ coverage
# Dependencies
node_modules/
jspm_packages/
package-lock.json
# Compiled TypeScript files
dist

View file

@ -10,7 +10,7 @@ This project is based on the [trader-typescript](../trader-typescript) sample Ga
## Prerequisites
The client application requires Node.js 16 or later.
The client application requires Node.js 20 or later.
## Set up

View file

@ -0,0 +1,14 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default defineConfig(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: import.meta.dirname,
},
},
});

File diff suppressed because it is too large Load diff

View file

@ -10,7 +10,7 @@
"scripts": {
"build": "tsc",
"build:watch": "tsc -w",
"lint": "eslint ./src",
"lint": "eslint src",
"prepare": "npm run build",
"pretest": "npm run lint",
"start": "node ./dist/app",
@ -21,16 +21,16 @@
"dependencies": {
"@grpc/grpc-js": "^1.14.0",
"@hyperledger/fabric-gateway": "^1.10.0",
"axios": "^1.7.7",
"axios": "^1.13.5",
"source-map-support": "^0.5.21"
},
"devDependencies": {
"@tsconfig/node18": "^18.2.2",
"@types/node": "^18.18.6",
"@eslint/js": "^10.0.1",
"@tsconfig/node20": "^20.1.9",
"@types/node": "^20.19.33",
"@types/source-map-support": "^0.5.6",
"@typescript-eslint/eslint-plugin": "^6.9.0",
"@typescript-eslint/parser": "^6.9.0",
"eslint": "^8.52.0",
"typescript": "~5.2.2"
"eslint": "^10.0.2",
"typescript": "~5.8",
"typescript-eslint": "^8.56.1"
}
}

View file

@ -13,6 +13,11 @@ import { ExpectedError } from './expectedError';
async function main(): Promise<void> {
const commandName = process.argv[2];
if (!commandName) {
printUsage();
throw new Error('No command specified');
}
const args = process.argv.slice(3);
const command = commands[commandName];
@ -44,7 +49,7 @@ function printUsage(): void {
console.log(`\t${Object.keys(commands).sort().join('\n\t')}`);
}
main().catch(error => {
main().catch((error: unknown) => {
if (error instanceof ExpectedError) {
console.log(error);
} else {

View file

@ -7,10 +7,14 @@
import { Gateway } from '@hyperledger/fabric-gateway';
import { CHAINCODE_NAME, CHANNEL_NAME } from '../config';
import { AssetTransfer } from '../contract';
import { assertAllDefined } from '../utils';
import { assertDefined } from '../utils';
const usage = 'Arguments: <assetId> <ownerName> <color>';
export default async function main(gateway: Gateway, args: string[]): Promise<void> {
const [assetId, owner, color] = assertAllDefined([args[0], args[1], args[2]], 'Arguments: <assetId> <ownerName> <color>');
const assetId = assertDefined(args[0], usage);
const owner = assertDefined(args[1], usage);
const color = assertDefined(args[2], usage);
const network = gateway.getNetwork(CHANNEL_NAME);
const contract = network.getContract(CHAINCODE_NAME);

View file

@ -7,10 +7,10 @@ import { ChaincodeEvent, checkpointers, Gateway } from '@hyperledger/fabric-gate
import * as path from 'path';
import { CHAINCODE_NAME, CHANNEL_NAME } from '../config';
import { Asset } from '../contract';
import { assertDefined } from '../utils';
import { assertDefined, randomElement } from '../utils';
import { TextDecoder } from 'util';
import axios from 'axios'
const axios = require('axios');
const utf8Decoder = new TextDecoder();
const checkpointFile = path.resolve(process.env.CHECKPOINT_FILE ?? 'checkpoint.json');
@ -33,7 +33,7 @@ export default async function main(gateway: Gateway): Promise<void> {
const checkpointer = await checkpointers.file(checkpointFile);
console.log(`Connecting to #discord webhook ${webhookURL}`);
console.log(`Starting event discording from block ${checkpointer.getBlockNumber() ?? startBlock}`);
console.log(`Starting event discording from block ${String(checkpointer.getBlockNumber() ?? startBlock)}`);
console.log('Last processed transaction ID within block:', checkpointer.getTransactionId());
const events = await network.getChaincodeEvents(CHAINCODE_NAME, {
@ -58,7 +58,7 @@ export default async function main(gateway: Gateway): Promise<void> {
}
// Relay a quick message to the discord webhook to indicate the transaction has been processed.
async function discord(webhookURL: string, event: ChaincodeEvent): Promise<void> {
function discord(webhookURL: string, event: ChaincodeEvent): Promise<void> {
const asset = parseJson(event.payload);
console.log(`\n<-- Chaincode event received: ${event.eventName}: `, asset);
@ -66,11 +66,11 @@ async function discord(webhookURL: string, event: ChaincodeEvent): Promise<void>
// const message = boringLogMessage(event, asset);
const message = splashyShoutMessage(event, asset);
deliverMessage(webhookURL, message);
return deliverMessage(webhookURL, message);
}
// Send an event to a discord webhook.
async function deliverMessage(webhookURL: string, message: any): Promise<void> {
async function deliverMessage(webhookURL: string, message: object): Promise<void> {
console.log('--> Sending to discord webhook: ' + webhookURL);
console.log(JSON.stringify(message));
@ -82,7 +82,8 @@ async function deliverMessage(webhookURL: string, message: any): Promise<void> {
}
}
function boringLogMessage(event: ChaincodeEvent, asset: Asset): any {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function boringLogMessage(event: ChaincodeEvent, asset: Asset): object {
const owner = ownerNickname(asset);
const text = format(event, asset, owner);
@ -93,9 +94,9 @@ function boringLogMessage(event: ChaincodeEvent, asset: Asset): any {
}
}
function splashyShoutMessage(event: ChaincodeEvent, asset: Asset): any {
function splashyShoutMessage(event: ChaincodeEvent, asset: Asset): object {
const owner:any = JSON.parse(asset.Owner);
const owner = JSON.parse(asset.Owner) as Owner;
if (event.eventName == 'CreateAsset') {
return {
@ -104,7 +105,7 @@ function splashyShoutMessage(event: ChaincodeEvent, asset: Asset): any {
content: `${bold(owner.user)} has caught a wild ${bold(asset.ID)}!` + getRandomEmoji(),
embeds: [
{
title: `${owner.org}`,
title: owner.org,
image: {
// an actual conga comic (sometimes png and sometimes jpg)
// url: `https://congacomic.github.io/assets/img/blockheight-${offset}.png`
@ -140,7 +141,7 @@ function format(event: ChaincodeEvent, asset: Asset, owner: string): string {
function parseJson(jsonBytes: Uint8Array): Asset {
const json = utf8Decoder.decode(jsonBytes);
return JSON.parse(json);
return JSON.parse(json) as Asset;
}
function quote(s: string): string {
@ -160,7 +161,7 @@ function snippet(s: string) {
}
function ownerNickname(asset: Asset): string {
const owner:any = JSON.parse(asset.Owner);
const owner = JSON.parse(asset.Owner) as Owner;
return `${owner.org}, ${owner.user}`;
}
@ -169,7 +170,10 @@ function ownerNickname(asset: Asset): string {
// Simple method that returns a random emoji from list
function getRandomEmoji(): string {
const emojiList = ['😭','😄','😌','🤓','😎','😤','🤖','😶‍🌫', '🌏','📸','💿','👋','🌊','✨'];
return emojiList[Math.floor(Math.random() * emojiList.length)];
return randomElement(emojiList)
}
interface Owner {
user: string;
org: string;
}

View file

@ -16,5 +16,7 @@ export default async function main(gateway: Gateway): Promise<void> {
const assets = await smartContract.getAllAssets();
const assetsJson = JSON.stringify(assets, undefined, 2);
assetsJson.split('\n').forEach(line => console.log(line)); // Write line-by-line to avoid truncation
assetsJson.split('\n').forEach(line => {
console.log(line);
}); // Write line-by-line to avoid truncation
}

View file

@ -7,10 +7,14 @@
import { Gateway } from '@hyperledger/fabric-gateway';
import { CHAINCODE_NAME, CHANNEL_NAME } from '../config';
import { AssetTransfer } from '../contract';
import { assertAllDefined } from '../utils';
import { assertDefined } from '../utils';
const usage = 'Arguments: <assetId> <newOwner> <newOwnerOrg>';
export default async function main(gateway: Gateway, args: string[]): Promise<void> {
const [assetId, newOwner, newOwnerOrg] = assertAllDefined([args[0], args[1], args[2]], 'Arguments: <assetId> <ownerName> <ownerMspId>');
const assetId = assertDefined(args[0], usage);
const newOwner = assertDefined(args[1], usage);
const newOwnerOrg = assertDefined(args[2], usage);
const network = gateway.getNetwork(CHANNEL_NAME);
const contract = network.getContract(CHAINCODE_NAME);

View file

@ -83,7 +83,7 @@ export class AssetTransfer {
}
async function submitWithRetry<T>(submit: () => Promise<T>): Promise<T> {
let lastError: unknown | undefined;
let lastError: unknown;
for (let retryCount = 0; retryCount < RETRIES; retryCount++) {
try {

View file

@ -13,7 +13,8 @@ const utf8Decoder = new TextDecoder();
* @param values Candidate elements.
*/
export function randomElement<T>(values: T[]): T {
return values[randomInt(values.length)];
const result = values[randomInt(values.length)];
return assertDefined(result, `Missing element in ${String(values)}`);
}
/**
@ -47,7 +48,7 @@ export async function allFulfilled(promises: Promise<unknown>[]): Promise<void>
if (failures.length > 0) {
const failMessages = '- ' + failures.join('\n- ');
throw new Error(`${failures.length} failures:\n${failMessages}\n`);
throw new Error(`${String(failures.length)} failures:\n${failMessages}\n`);
}
}
@ -61,11 +62,6 @@ export function printable<T extends object>(event: T): PrintView<T> {
) as PrintView<T>;
}
export function assertAllDefined<T>(values: (T | undefined)[], message: string | (() => string)): T[] {
values.forEach(value => assertDefined(value, message));
return values as T[];
}
export function assertDefined<T>(value: T | undefined, message: string | (() => string)): T {
if (value == undefined) {
throw new Error(typeof message === 'string' ? message : message());

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@tsconfig/node18/tsconfig.json",
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"declaration": true,
"declarationMap": true,
@ -8,12 +8,13 @@
"outDir": "dist",
"rootDir": "src",
"noUnusedLocals": false,
"noImplicitReturns": true
"noImplicitReturns": true,
"noUncheckedIndexedAccess": true
},
"include": [
"src/"
],
"exclude": [
"src/**/*.spec.ts"
"**/*.spec.*"
]
}

View file

@ -8,7 +8,6 @@ coverage
# Dependencies
node_modules/
jspm_packages/
package-lock.json
# Compiled TypeScript files
dist

View file

@ -1,7 +1,8 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
export default defineConfig(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',

File diff suppressed because it is too large Load diff

View file

@ -23,11 +23,11 @@
"@hyperledger/fabric-gateway": "^1.10.0"
},
"devDependencies": {
"@eslint/js": "^9.3.0",
"@tsconfig/node18": "^18.2.4",
"@types/node": "^18.19.33",
"eslint": "^8.57.0",
"typescript": "~5.4.5",
"typescript-eslint": "^7.11.0"
"@eslint/js": "^10.0.1",
"@tsconfig/node20": "^20.1.9",
"@types/node": "^20.19.33",
"eslint": "^10.0.2",
"typescript": "~5.8",
"typescript-eslint": "^8.56.1"
}
}

View file

@ -48,7 +48,7 @@ function getSimulatedFailureCount(): number {
const value = process.env.SIMULATED_FAILURE_COUNT ?? '0';
const count = Math.floor(Number(value));
if (isNaN(count) || count < 0) {
throw new Error(`Invalid SIMULATED_FAILURE_COUNT value: ${String(value)}`);
throw new Error(`Invalid SIMULATED_FAILURE_COUNT value: ${value}`);
}
return count;

View file

@ -14,7 +14,7 @@ const utf8Decoder = new TextDecoder();
*/
export function randomElement<T>(values: T[]): T {
const result = values[randomInt(values.length)];
return assertDefined(result, `Missing element in {String(values)}`);
return assertDefined(result, `Missing element in ${String(values)}`);
}
/**

View file

@ -1,5 +1,5 @@
{
"extends": "@tsconfig/node18/tsconfig.json",
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"declaration": true,

View file

@ -12,7 +12,7 @@ RUN npm install
RUN npm run build && npm shrinkwrap
FROM node:lts as prod-builder
FROM node:lts AS prod-builder
WORKDIR /usr/src/app
COPY --chown=node:node --from=builder /usr/src/app/dist ./dist
COPY --chown=node:node --from=builder /usr/src/app/package.json ./

View file

@ -1,7 +1,8 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
export default defineConfig(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',

View file

@ -31,14 +31,6 @@
"json-stringify-deterministic": "^1.0.7",
"sort-keys-recursive": "^2.1.7"
},
"devDependencies": {
"@types/node": "^18.19.33",
"@eslint/js": "^9.3.0",
"@tsconfig/node18": "^18.2.4",
"eslint": "^8.57.0",
"typescript": "~5.4.5",
"typescript-eslint": "^7.11.0"
},
"nyc": {
"extension": [
".ts",
@ -58,5 +50,13 @@
"branches": 100,
"functions": 100,
"lines": 100
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@tsconfig/node20": "^20.1.9",
"@types/node": "^20.19.33",
"eslint": "^10.0.2",
"typescript": "~5.8",
"typescript-eslint": "^8.56.1"
}
}

View file

@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@tsconfig/node18/tsconfig.json",
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
@ -8,10 +8,10 @@
"declarationMap": true,
"sourceMap": true,
"outDir": "dist",
"strict": true,
"noUnusedLocals": true,
"noImplicitReturns": true,
"forceConsistentCasingInFileNames": true
"forceConsistentCasingInFileNames": true,
"isolatedModules": true
},
"include": ["src/"]
}

View file

@ -21,7 +21,7 @@ set -eo pipefail
set -x
KIND_CLUSTER_NAME=kind
KIND_CLUSTER_IMAGE=${KIND_CLUSTER_IMAGE:-kindest/node:v1.28.0} # Important! k8s v1.25.0 brings breaking changes.
KIND_CLUSTER_IMAGE=${KIND_CLUSTER_IMAGE:-kindest/node:v1.35.1} # Important! k8s v1.25.0 brings breaking changes.
KIND_API_SERVER_ADDRESS=${KIND_API_SERVER_ADDRESS:-127.0.0.1}
KIND_API_SERVER_PORT=${KIND_API_SERVER_PORT:-8888}
CONTAINER_REGISTRY_NAME=${CONTAINER_REGISTRY_NAME:-kind-registry}
@ -78,14 +78,27 @@ networking:
# create a cluster with the local registry enabled in containerd
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:${CONTAINER_REGISTRY_PORT}"]
endpoint = ["http://${CONTAINER_REGISTRY_NAME}:${CONTAINER_REGISTRY_PORT}"]
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
EOF
# Configure registry for containerd 2.x using config_path mode
for node in $(kind get nodes --name $KIND_CLUSTER_NAME);
do
docker exec "$node" mkdir -p "/etc/containerd/certs.d/localhost:${CONTAINER_REGISTRY_PORT}"
docker exec "$node" sh -c "cat > /etc/containerd/certs.d/localhost:${CONTAINER_REGISTRY_PORT}/hosts.toml <<EOT
server = \"http://localhost:${CONTAINER_REGISTRY_PORT}\"
[host.\"http://${CONTAINER_REGISTRY_NAME}:${CONTAINER_REGISTRY_PORT}\"]
capabilities = [\"pull\", \"resolve\", \"push\"]
EOT"
done
#
# Work around a bug in KIND where DNS is not always resolved correctly on machines with IPv6
#
for node in $(kind get nodes);
for node in $(kind get nodes --name $KIND_CLUSTER_NAME);
do
docker exec "$node" sysctl net.ipv4.conf.all.route_localnet=1;
done

View file

@ -34,7 +34,7 @@ function context() {
}
context FABRIC_VERSION 2.5.14
context FABRIC_CA_VERSION 1.5.15
context FABRIC_CA_VERSION 1.5.17
context CLUSTER_RUNTIME kind # or k3s for Rancher
context CONTAINER_CLI docker # or nerdctl for containerd
@ -78,7 +78,7 @@ context CA_IMAGE_LABEL ${FABRIC_CA_VERSION}
#context PEER_IMAGE ${FABRIC_CONTAINER_REGISTRY}/fabric-peer
#context PEER_IMAGE_LABEL ${FABRIC_VERSION}
context PEER_IMAGE ghcr.io/hyperledger-labs/fabric-builder-k8s/k8s-fabric-peer
context PEER_IMAGE_LABEL 0.11.0 # When using k8s-fabric-peer in Fabric v2.5+, 0.11.0+ should be specified
context PEER_IMAGE_LABEL 0.15.1 # When using k8s-fabric-peer in Fabric v2.5+, 0.11.0+ should be specified
context ORDERER_IMAGE ${FABRIC_CONTAINER_REGISTRY}/fabric-orderer
context ORDERER_IMAGE_LABEL ${FABRIC_VERSION}
context OPERATOR_IMAGE ghcr.io/hyperledger-labs/fabric-operator
@ -91,7 +91,7 @@ context COUCHDB_IMAGE couchdb
context COUCHDB_IMAGE_LABEL 3.4.2
context CONSOLE_IMAGE ghcr.io/hyperledger-labs/fabric-console
context CONSOLE_IMAGE_LABEL latest
context DEPLOYER_IMAGE ghcr.io/ibm-blockchain/fabric-deployer
context DEPLOYER_IMAGE ghcr.io/hyperledger-labs/fabric-deployer
context DEPLOYER_IMAGE_LABEL latest-amd64
export FABRIC_OPERATOR_IMAGE=${OPERATOR_IMAGE}:${OPERATOR_IMAGE_LABEL}

View file

@ -332,12 +332,12 @@ fabric-ca-client register \
--id.name $USERNAME \
--id.secret $PASSWORD \
--id.type client \
--url https://$WORKSHOP_NAMESPACE-$ORG-ca-ca.$WORKSHOP_INGRESS_DOMAIN \
--url https://$WORKSHOP_NAMESPACE-$ORG-ca-ca.$WORKSHOP_INGRESS_DOMAIN:443 \
--tls.certfiles $WORKSHOP_CRYPTO/cas/$ORG-ca/tls-cert.pem \
--mspdir $WORKSHOP_CRYPTO/enrollments/$ORG/users/rcaadmin/msp
fabric-ca-client enroll \
--url https://$USERNAME:$PASSWORD@$WORKSHOP_NAMESPACE-$ORG-ca-ca.$WORKSHOP_INGRESS_DOMAIN \
--url https://$USERNAME:$PASSWORD@$WORKSHOP_NAMESPACE-$ORG-ca-ca.$WORKSHOP_INGRESS_DOMAIN:443 \
--tls.certfiles $WORKSHOP_CRYPTO/cas/$ORG-ca/tls-cert.pem \
--mspdir $WORKSHOP_CRYPTO/enrollments/$ORG/users/$USERNAME/msp

View file

@ -1,3 +1,2 @@
dist/
node_modules/
package-lock.json

View file

@ -1,7 +1,8 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
export default defineConfig(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',

File diff suppressed because it is too large Load diff

View file

@ -21,13 +21,12 @@
"@hyperledger/fabric-gateway": "^1.10.0"
},
"devDependencies": {
"@eslint/js": "^9.3.0",
"@tsconfig/node18": "^18.2.4",
"@types/node": "^18.19.33",
"eslint": "^8.57.0",
"npm-run-all": "^4.1.5",
"@eslint/js": "^10.0.1",
"@tsconfig/node20": "^20.1.9",
"@types/node": "^20.19.33",
"eslint": "^10.0.2",
"rimraf": "^5.0.1",
"typescript": "~5.4.5",
"typescript-eslint": "^7.11.0"
"typescript": "~5.8",
"typescript-eslint": "^8.56.1"
}
}

View file

@ -1,5 +1,5 @@
{
"extends": "@tsconfig/node18/tsconfig.json",
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"declaration": true,

View file

@ -1,7 +1,8 @@
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
export default defineConfig(js.configs.recommended, ...tseslint.configs.strictTypeChecked, {
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',

File diff suppressed because it is too large Load diff

View file

@ -23,11 +23,11 @@
"@hyperledger/fabric-protos": "^0.3.4"
},
"devDependencies": {
"@eslint/js": "^9.3.0",
"@tsconfig/node18": "^18.2.4",
"@types/node": "^18.19.33",
"eslint": "^8.57.0",
"typescript": "~5.4.5",
"typescript-eslint": "^7.11.0"
"@eslint/js": "^10.0.1",
"@tsconfig/node20": "^20.1.9",
"@types/node": "^20.19.33",
"eslint": "^10.0.2",
"typescript": "~5.8",
"typescript-eslint": "^8.56.1"
}
}

View file

@ -240,7 +240,7 @@ function getSimulatedFailureCount(): number {
const value = process.env.SIMULATED_FAILURE_COUNT ?? '0';
const count = Math.floor(Number(value));
if (isNaN(count) || count < 0) {
throw new Error(`Invalid SIMULATED_FAILURE_COUNT value: ${String(value)}`);
throw new Error(`Invalid SIMULATED_FAILURE_COUNT value: ${value}`);
}
return count;

View file

@ -1,5 +1,5 @@
{
"extends": "@tsconfig/node18/tsconfig.json",
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"declaration": true,
@ -10,6 +10,6 @@
"noUncheckedIndexedAccess": true,
"forceConsistentCasingInFileNames": true
},
"include": ["./src/**/*"],
"exclude": ["./src/**/*.spec.ts"]
"include": ["src/"],
"exclude": ["**/*.spec.*"]
}

View file

@ -39,8 +39,8 @@ First, run the following command to verify that the environment variables are co
```shell
$ ./network
Fabric image versions: Peer (3.1.1), CA (1.5.15)
Fabric binary versions: Peer (3.1.1), CA (1.5.15)
Fabric image versions: Peer (3.1.1), CA (1.5.17)
Fabric binary versions: Peer (3.1.1), CA (1.5.17)
--- Fabric Information
Fabric Version : 3.1

View file

@ -1,7 +1,7 @@
# default image tag, example: "2.5.13". "default" will download the latest. (-i)
IMAGETAG="default"
# default ca image tag, example: "1.5.15". "default" will download the latest. (-cai)
# default ca image tag, example: "1.5.17". "default" will download the latest. (-cai)
CA_IMAGETAG="default"
# Using crpto vs CA. default is cryptogen

View file

@ -18,7 +18,7 @@ function printHelp() {
println " Flags:"
println " Used with \033[0;32mnetwork.sh prereq\033[0m:"
println " -i FabricVersion (default: '2.5.14')"
println " -cai Fabric CA Version (default: '1.5.15')"
println " -cai Fabric CA Version (default: '1.5.17')"
println
elif [ "$USAGE" == "up" ]; then
println "Usage: "
@ -160,7 +160,7 @@ function printHelp() {
println " Flags:"
println " Used with \033[0;32mnetwork.sh prereq\033[0m"
println " -i FabricVersion (default: '2.5.14')"
println " -cai Fabric CA Version (default: '1.5.15')"
println " -cai Fabric CA Version (default: '1.5.17')"
println
println " Used with \033[0;32mnetwork.sh up\033[0m, \033[0;32mnetwork.sh createChannel\033[0m:"
println " -ca - Use Certificate Authorities to generate network crypto material"