fix: replace as any casts with proper TypeScript types, fix webhook retry query, replace console with logger, add webhook stats return type - #507
Merged
DeFiVC merged 5 commits intoSep 30, 2026
Annotations
11 errors, 1 warning, and 1 notice
|
Upload coverage report
No files were found with the provided path: coverage/. No artifacts will be uploaded.
|
|
Run tests with coverage:
tests/unit/services/sep10-auth.test.ts#L184
AssertionError: expected [Function] to throw error including 'Invalid transaction envelope' but got 'logger.debug is…'
Expected: "Invalid transaction envelope"
Received: "__vite_ssr_import_7__.logger.debug is not a function"
❯ tests/unit/services/sep10-auth.test.ts:184:7
|
|
Run tests with coverage:
tests/unit/services/sep10-auth.test.ts#L173
AssertionError: expected [Function] to throw error including 'Corrupt stored challenge' but got 'logger.debug is…'
Expected: "Corrupt stored challenge"
Received: "__vite_ssr_import_7__.logger.debug is not a function"
❯ tests/unit/services/sep10-auth.test.ts:173:7
|
|
Run tests with coverage:
tests/unit/services/sep10-auth.test.ts#L160
AssertionError: expected [Function] to throw error including 'Corrupt stored challenge' but got 'logger.debug is…'
Expected: "Corrupt stored challenge"
Received: "__vite_ssr_import_7__.logger.debug is not a function"
❯ tests/unit/services/sep10-auth.test.ts:160:7
|
|
Run tests with coverage:
src/jobs/reconcile-pending-rewards.ts#L15
Error: [vitest] There was an error when mocking a module. If you are using "vi.mock" factory, make sure there are no top level variables inside, since this call is hoisted to top of the file. Read more: https://vitest.dev/api/vi.html#vi-mock
❯ src/jobs/reconcile-pending-rewards.ts:15:1
Caused by: Caused by: ReferenceError: Cannot access 'mockUpdate' before initialization
❯ tests/unit/services/reconcile-pending-rewards.test.ts:17:13
❯ src/jobs/reconcile-pending-rewards.ts:15:1
|
|
Run tests with coverage:
tests/unit/middleware/rate-limit.test.ts#L87
AssertionError: expected '10.0.0.1:auth' to be '10.0.0.1' // Object.is equality
Expected: "10.0.0.1"
Received: "10.0.0.1:auth"
❯ tests/unit/middleware/rate-limit.test.ts:87:19
|
|
Run tests with coverage:
tests/unit/config/test-mode-required-vars.test.ts#L86
AssertionError: expected 'import { z } from "zod";\nimport "dot…' not to contain 'test-secret-key-that-is-at-least-sixt…'
- Expected
+ Received
- test-secret-key-that-is-at-least-sixty-four
+ import { z } from "zod";
+ import "dotenv/config";
+ import { logger } from "../utils/logger.js";
+ import dotenv from "dotenv";
+
+ // Test mode gets its own optional .env.test file (#475), gitignored like
+ // .env — see .env.test.example. dotenv never overwrites a value already set
+ // in process.env, so real CI-provided environment variables still win over
+ // anything in either file; this only fills in what's missing.
+ dotenv.config({ path: process.env.NODE_ENV === "test" ? ".env.test" : ".env" });
+
+ const envSchema = z.object({
+ NODE_ENV: z
+ .enum(["development", "production", "test"])
+ .default("development"),
+ PORT: z.coerce.number().default(3000),
+ HOST: z.string().default("0.0.0.0"),
+
+ // Database
+ DATABASE_URL: z
+ .string()
+ .url()
+ .refine(
+ (url) => url.startsWith("postgresql://") || url.startsWith("postgres://"),
+ { message: "DATABASE_URL must be a PostgreSQL connection string" }
+ ),
+
+ // Redis
+ REDIS_URL: z.string().default("redis://localhost:6379"),
+
+ // CORS — comma-separated allow-list of browser origins, e.g.
+ // "https://chainlearn.io,https://app.chainlearn.io". Optional: when unset,
+ // a per-environment default is used (see `corsOrigins` below). Parsed into
+ // an array of trimmed, non-empty origin strings.
+ CORS_ORIGINS: z
+ .string()
+ .optional()
+ .transform((val) =>
+ val
+ ? val
+ .split(",")
+ .map((origin) => origin.trim())
+ .filter(Boolean)
+ : undefined,
+ ),
+
+ // JWT — OWASP recommends 256 bits (>= 64 chars) and a non-placeholder value.
+ JWT_SECRET: z
+ .string()
+ .min(64, "JWT_SECRET must be at least 64 characters (256 bits)")
+ .refine(
+ (val) =>
+ val !== "your-secret-key" && !val.includes("change-in-production"),
+ "JWT_SECRET must be a real secret, not a placeholder"
+ ),
+
+ // Stellar
+ STELLAR_NETWORK: z.enum(["testnet", "mainnet"]).default("testnet"),
+ STELLAR_HORIZON_URL: z.string().url(),
+ STELLAR_SOROBAN_RPC_URL: z.string().url(),
+ STELLAR_PLATFORM_SECRET: z.string().regex(
+ /^S[A-Z2-7]{55}$/,
+ { message: "Invalid Stellar secret key format" }
+ ),
+ STELLAR_QUIZ_CONTRACT_ID: z.string().min(1),
+ STELLAR_REWARD_CONTRACT_ID: z.string().min(1),
+ STELLAR_CREDENTIAL_CONTRACT_ID: z.string().min(1),
+ // Optional: enables on-chain contentHash verification on enrollment
+ // (#294). Unset by default — the check is skipped (non-blocking) until a
+ // progress-tracker contract is deployed and configured.
+ STELLAR_PROGRESS_TRACKER_CONTRACT_ID: z.string().optional(),
+
+ // Rate limiting
+ RATE_LIMIT_MAX: z.coerce.number().default(100),
+ RATE_LIMIT_WINDOW_MS: z.coerce.number().default(60_000),
+
+ // Max number of courses a user can be actively enrolled in at once (#306).
+ // Completed enrollments (completedAt set) don't count toward this.
+ MAX_ENROLLMENTS: z.coerce.number().int().positive().default(10),
+
+ // Request timeout middleware (#305)
+ REQUEST_TIMEOUT_MS: z.coerce.number().int().positive().default(30_000),
+ QUIZ_GENERATION_TIMEOUT_MS: z.coerce.number().int().positive().default(60_000),
+ // Request body limits
+ REQUEST_BODY_LIMIT_BYTES: z.coerce.number().int().positive().default(1_048_576),
+ MULTIPART_BODY_LIMIT_BYTES: z.coerce.number().int().positive().default(5_242_880),
+ AVATAR_UPLOAD_MAX_BYTES: z.coerce.number().int().positive().default(2_097_152),
+ AVATAR_UPLOAD_DIR: z.string().default("uploads/avatars"),
+ PUBLIC_BASE_URL: z.string().url().optional(),
+
+ // AI service (chainlearn-ai) used for quiz generation
+ AI_SERVICE_URL: z.string().url().default("http://localhost:8000"),
+ AI_TIMEOUT_MS: z.coerce.number().default(30_000),
+ });
+
+ export type Env = z.infer<typeof envSchema>;
|
|
Run tests with coverage:
tests/unit/config/test-mode-required-vars.test.ts#L68
AssertionError: expected [Function] to throw error matching /DATABASE_URL.*JWT_SECRET|JWT_SECRET.*…/ but got 'Transform failed with 1 error:\n/home…'
- Expected:
/DATABASE_URL.*JWT_SECRET|JWT_SECRET.*DATABASE_URL/
+ Received:
"Transform failed with 1 error:
/home/runner/work/chainlearn-api/chainlearn-api/src/config/index.ts:181:6: ERROR: Expected \")\" but found \"console\""
❯ tests/unit/config/test-mode-required-vars.test.ts:68:5
|
|
Run tests with coverage:
tests/unit/config/test-mode-required-vars.test.ts#L60
AssertionError: expected [Function] to throw error matching /Missing required test environment var…/ but got 'Transform failed with 1 error:\n/home…'
- Expected:
/Missing required test environment variable.*STELLAR_PLATFORM_SECRET/
+ Received:
"Transform failed with 1 error:
/home/runner/work/chainlearn-api/chainlearn-api/src/config/index.ts:181:6: ERROR: Expected \")\" but found \"console\""
❯ tests/unit/config/test-mode-required-vars.test.ts:60:5
|
|
Run tests with coverage:
tests/unit/config/test-mode-required-vars.test.ts#L54
AssertionError: expected [Function] to throw error matching /Missing required test environment var…/ but got 'Transform failed with 1 error:\n/home…'
- Expected:
/Missing required test environment variable.*JWT_SECRET/
+ Received:
"Transform failed with 1 error:
/home/runner/work/chainlearn-api/chainlearn-api/src/config/index.ts:181:6: ERROR: Expected \")\" but found \"console\""
❯ tests/unit/config/test-mode-required-vars.test.ts:54:5
|
|
Run tests with coverage:
tests/unit/config/test-mode-required-vars.test.ts#L48
AssertionError: expected [Function] to throw error matching /Missing required test environment var…/ but got 'Transform failed with 1 error:\n/home…'
- Expected:
/Missing required test environment variable.*DATABASE_URL/
+ Received:
"Transform failed with 1 error:
/home/runner/work/chainlearn-api/chainlearn-api/src/config/index.ts:181:6: ERROR: Expected \")\" but found \"console\""
❯ tests/unit/config/test-mode-required-vars.test.ts:48:5
|
|
Complete job
Node.js 20 is deprecated. The following actions target Node.js 20 but are being forced to run on Node.js 24: actions/cache@v4, actions/checkout@v4, actions/setup-node@v4, actions/upload-artifact@v4. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
|
|
"The ubuntu-latest label will migrate to Ubuntu 26 beginning October 19, 2026. For more information, see https://github.com/actions/runner-images/issues/14748"
|
background
wait
wait-all
cancel
parallel
Loading