@energica-city/shared-amplify-utils

中文文档
0.21.0发布于 2026/10/29UNLICENSEDTypeScriptES Module近 30 天下载 4314

Shared utilities for AWS Amplify projects

此软件包已被标记为弃用

Moved to the private CodeArtifact registry; this public copy is no longer maintained.

原始使用文档
文档目录11 节
  1. Installation
  2. Developing
  3. Publishing
  4. Modules
  5. Error — error/
  6. Logging — log/
  7. Query Factory — queries/
  8. Middleware — middleware/
  9. Configuration
  10. Requirements
  11. Exports

@energica-city/shared-amplify-utils

TypeScript utilities every backend handler in this platform is built from: error handling, structured logging, type-safe database operations with in-memory caching, and Lambda middleware chains.

Three repositories depend on this one — Eve-Backend-v2, cdk-test-proyect and eve_adminwebv3. energica_payments does not. A change here reaches production in three places, so it is the highest-leverage repository in the workspace and the easiest to break something distant from.

Installation

npm install @energica-city/shared-amplify-utils

⚠ Everything is imported from the package root. package.json declares a single "." export, so subpath imports do not resolve:

import { logger, throwError, QueryFactory } from "@energica-city/shared-amplify-utils"; // ✅
import { logger } from "@energica-city/shared-amplify-utils/log"; // ❌ no such export

The section headings below name the source directory a utility lives in, not an import path.

Developing

Source lives at the repository root, not under src/.

npm install
npm run build          # tsc → dist/
npm test               # vitest, once
npm run test:watch     # watching
npm run lint && npm run format:check
npm run gate           # the repo's whole gate — what the pre-commit hook runs
npm run fix            # prettier --write, then eslint --fix
npm run build:verify   # = npm run build; what the pre-push hook runs

The workspace gate (../tools/run-all-tests.sh shared) runs the repo's gate script: the typecheck, lint, format and test passes together.

Publishing

npm run release:patch   # a fix that changes no behaviour
npm run release:minor   # anything a consumer must act on — see CHANGELOG.md
npm run release:major

Every release states in CHANGELOG.md what a consumer must change to adopt it.

prepublishOnly builds, tests, lints and format-checks first, so a broken publish fails before it leaves the machine. Publishing is a separate step from pushing — unlike three of the five repositories here, git push ships nothing.

⚠ Publishing is only half the job. The three consumers pin a ^ range, so a new version reaches them only when their package.json is updated and they are redeployed. Bumping this library means updating all three and saying so.

Modules

Error — error/

Standardized error handling with structured logging and context preservation.

Core Functions:

  • throwError(message, context) - Throw with structured context and automatic logging
  • extractErrorMessage(error) - Extract consistent messages from any error type
  • createErrorContext(data) - Create filtered context objects

WebSocket Errors:

  • throwWebSocketError(statusCode, code, message, context) - WebSocket-specific errors
  • isWebSocketError(error) - Type guard for WebSocket errors
  • WebSocketErrorCodes - Predefined error codes (VALIDATION_ERROR, AUTHENTICATION_ERROR, etc.)
import { throwError, createErrorContext } from "@energica-city/shared-amplify-utils";

throwError("Operation failed", createErrorContext({ userId: "123", operation: "create" }));

Logging — log/

One logger API with two engines, chosen by the package's exports conditions:

  • Node (Lambda) — AWS Lambda Powertools. Lean JSON lines: timestamp, level, message, requestId, the trace keys (buyOrder, stationId, eveId, connectorId, residenceId, stage), then data; at most 16 KB per line.
  • Browser (browser condition) — the console engine: same API, same redaction, no trail.

Every line is redacted: emails, phones, RUTs and names masked; card, bank, token, address and free-text fields redacted; free strings scrubbed. The trace keys stay readable — they are how a line is found.

The trail holds detail — database reads, raw requests, GraphQL arguments — and writes it only when the invocation fails (an ERROR line, an uncaught throw, a pending timeout, trail.flush()), or directly when the function's level is DEBUG.

import { logger, trail, withInvocation, configureTrail } from "@energica-city/shared-amplify-utils";

configureTrail({ maxBytes: 256 * 1024 }); // once, at module load

export const handler = (event, context) =>
    withInvocation(context, async () => {
        logger.setContext({ buyOrder: event.buyOrder });
        trail.info("charge read", { charge }); // only if this invocation fails
        logger.info("charge settled", { amountUsedAccounting });
    });

A Lambda killed at its timeout runs no catch. configureInvocation makes withInvocation call a hook shortly before the kill, after flushing the trail, so the repo can raise an incident:

import { configureInvocation } from "@energica-city/shared-amplify-utils";

configureInvocation({
    timeoutMarginMs: 3000, // default
    onTimeout: async ({ requestId, functionName, logGroup, remainingMs }) => {
        await reportIncident({ requestId, functionName, logGroup, remainingMs });
    },
}); // once, at module load; a later call replaces the settings

A hook that throws or rejects is logged and swallowed; a no-op in the browser.

Levels by name or number, from AWS_LAMBDA_LOG_LEVEL (the function's logging config), then POWERTOOLS_LOG_LEVEL, then LOG_LEVEL; INFO otherwise.

Query Factory — queries/

Type-safe CRUD operations for Amplify Data models with automatic client management, connection pooling, and optional in-memory caching with LRU eviction.

Core Features:

  • Type-safe database operations
  • Automatic client management and connection pooling
  • Schema-driven identifier extraction
  • Optional per-factory read cache, off unless enabled: true
  • Every write clears what it outdates; invalidate(id) for other writers
  • Conditional writes (condition), authMode on every operation
  • Truncated pagination throws unless allowTruncation: true
  • Composite key support for complex identifiers

Basic Usage:

import { QueryFactory, initializeQueries } from "@energica-city/shared-amplify-utils";

await initializeQueries<MainTypes>(outputs);
const UserQueries = await QueryFactory<"User", MainTypes>({ name: "User" });

const user = await UserQueries.create({
    input: { username: "john", email: "[email protected]" },
});
const foundUser = await UserQueries.get({ input: { userId: user.id } });
await UserQueries.update({ input: { userId: user.id, validated: true } });
await UserQueries.delete({ input: { userId: user.id } });

With Caching:

const UserQueries = await QueryFactory<"User", MainTypes>({
    name: "User",
    cache: { enabled: true, ttl: 60_000 }, // off unless enabled: true
});

await UserQueries.get({ input: { userId: "123" } }); // database
await UserQueries.get({ input: { userId: "123" } }); // cache
await UserQueries.update({ input: { userId: "123", validated: true } }); // clears it
UserQueries.invalidate({ userId: "123" }); // after a write by anyone else

⚠ A cache lives in a warm Lambda container across invocations. A handler that decides money from a read — settlement, refunds, a duplicate check — should not cache that model at all.

As the Lambda's own role:

await initializeQueries({ amplifyOutputs, schema, credentials: "lambdaRole" }); // iam, signed as the role

Middleware — middleware/

Universal composable middleware chains for AWS Lambda with REST, WebSocket, and GraphQL support.

Core Middleware Chain

import { MiddlewareChain } from "@energica-city/shared-amplify-utils";

const chain = new MiddlewareChain<MyInput, MyOutput>();
chain.use("auth", authMiddleware).use("validation", validationMiddleware);
const result = await chain.execute(input, finalHandler);

REST Middleware

Complete REST API middleware system for AWS API Gateway with HTTP-specific error handling.

import {
    createRestChain,
    wrapRestHandler,
    createRestErrorHandler,
    createRestRequestLogger,
    createRestRequestValidator,
    createRestModelInitializer,
    getValidatedBody,
    getModelsFromInput,
} from "@energica-city/shared-amplify-utils";

const chain = createRestChain<MainTypes>()
    .use("errorHandler", createRestErrorHandler())
    .use("logger", createRestRequestLogger())
    .use("modelInitializer", createRestModelInitializer({ entities: ["User"] }))
    .use("validator", createRestRequestValidator({ bodySchema: userSchema }));

export const handler = wrapRestHandler(chain, async input => {
    const { User } = getModelsFromInput(input);
    const body = getValidatedBody(input);
    return createSuccessResponse(await User.create({ input: body }));
});

WebSocket Middleware

WebSocket-specific middleware for AWS API Gateway WebSocket APIs with real-time connection management.

import {
    createWebSocketChain,
    wrapWebSocketHandler,
    createWebSocketErrorHandler,
    createWebSocketModelInitializer,
    getModelFromInput,
} from "@energica-city/shared-amplify-utils";

const chain = createWebSocketChain<MainTypes>()
    .use("errorHandler", createWebSocketErrorHandler())
    .use("modelInitializer", createWebSocketModelInitializer({ entities: ["Message"] }));

export const handler = wrapWebSocketHandler(chain, async input => {
    const MessageModel = getModelFromInput(input, "Message");
    // WebSocket handler logic
});

GraphQL Middleware

GraphQL resolver middleware for AWS AppSync with Amplify Data integration and structured error handling.

import {
    createGraphQLChain,
    wrapGraphQLResolver,
    createGraphQLErrorHandler,
    createGraphQLRequestLogger,
    createGraphQLModelInitializer,
    getModelsFromInput,
    extractArguments,
} from "@energica-city/shared-amplify-utils";

const chain = createGraphQLChain<MainTypes>()
    .use("modelInitializer", createGraphQLModelInitializer({ entities: ["User", "Post"] }))
    .use("logger", createGraphQLRequestLogger())
    .use("errorHandler", createGraphQLErrorHandler());

export const handler = wrapGraphQLResolver(chain, async input => {
    const { User } = getModelsFromInput(input);
    const { userId } = extractArguments(input);
    return await User.get({ input: { userId } });
});

Validation Utils

Universal validation patterns and data sanitization utilities.

import { ValidationPatterns, sanitizeObject } from "@energica-city/shared-amplify-utils";

// Pre-built patterns
ValidationPatterns.uuid(); // UUID validation
ValidationPatterns.email(); // Email format validation
ValidationPatterns.pagination(); // Page/limit parameters

// Data sanitization
const clean = sanitizeObject(data, { excludeFields: ["secret"], maxDepth: 3 });

Configuration

Environment Variables:

  • AWS_LAMBDA_LOG_LEVEL / POWERTOOLS_LOG_LEVEL / LOG_LEVEL: log level, by name or 0–4
  • EVE_TRAIL_MAX_BYTES: the trail buffer size, if configureTrail is not called
  • STRUCTURED_LOGGING: force the console engine's JSON output ('true'/'false')
  • NODE_ENV: development is the only value that shows stacks and internal messages

AWS Lambda Auto-Detection:

  • The Node entry writes through Powertools; withInvocation adds the request id to every line
  • A read cache, when enabled, persists across warm invocations

Requirements

  • Node.js 20+
  • TypeScript 5.6+
  • AWS Amplify 6.0+
  • Yup 1.6+ (for validation)
  • lru-cache 11.0+ (for in-memory caching)

Exports

// Root exports only
export * from "./error";
export * from "./log";
export * from "./queries";
export * from "./middleware";

// All imports from root package
import { throwError } from "@energica-city/shared-amplify-utils";
import { logger } from "@energica-city/shared-amplify-utils";
import { QueryFactory, AppError } from "@energica-city/shared-amplify-utils";

One "." export, with a browser condition that swaps the logging engine; there are no subpath exports.

版本与发布记录

@energica-city/shared-amplify-utils 共发布 135 个版本,首次发布于 2025/07/31;过去 12 个月发布了 34 个版本。

版本发布日期距今
0.21.0latest2026/10/2915 天前
0.19.02026/10/2915 天前
0.17.12026/10/2915 天前
0.17.02026/10/2916 天前
0.16.02026/10/2816 天前
0.15.12026/10/2816 天前

关于 @energica-city/shared-amplify-utils 的常见问题

@energica-city/shared-amplify-utils 是什么?

Shared utilities for AWS Amplify projects注意:该包已被作者标记为弃用——Moved to the private CodeArtifact registry; this public copy is no longer maintained.

如何安装 @energica-city/shared-amplify-utils?

在项目目录运行 npm install @energica-city/shared-amplify-utils,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:aws-amplify(^6.16.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@energica-city/shared-amplify-utils 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@energica-city/shared-amplify-utils 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@energica-city/shared-amplify-utils 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@energica-city/shared-amplify-utils 可以商用吗?

@energica-city/shared-amplify-utils 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@energica-city/shared-amplify-utils 的下载量有多少?

根据 npm 官方下载统计,@energica-city/shared-amplify-utils 在 2026/10/14 – 2026/11/12 这 30 天内被下载 4,314 次,日均约 144 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@energica-city/shared-amplify-utils 还在维护吗?

最新版本 0.21.0 发布于 2026/10/29(15 天前);至今共发布 135 个版本,其中过去 12 个月发布了 34 个;首次发布于 2025/07/31。作者已将其标记为弃用,新项目建议寻找替代方案。