Token导航 LogoToken导航TokenDH.com
前端设计敏感数据github未标认证来源可访问许可证需确认审计通过

yn-be-developer-typescriptYN BE 开发者 TypeScript

Agent Skill

yn-be-developer-typescript 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

776

周安装

33

GitHub Stars

公开资料未说明

下载量

272
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:yn-be-developer-typescript(YN BE 开发者 TypeScript)
来源仓库:https://github.com/marco-meini/cursor
仓库路径:skills/yn-be-developer-typescript
安装命令:
npx skills add https://github.com/marco-meini/cursor --skill yn-be-developer-typescript
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/marco-meini/cursor --skill yn-be-developer-typescript

简介

yn-be-developer-typescript 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合围绕仓库状态和协作事项进行整理。

  • 适用于需要跟踪代码变更、管理 Issue 或审查 Pull Request 的场景。
  • 可结合项目现有流程,自动提取关键信息并生成报告。
  • 安装命令:npx skills add https://github.com/marco-meini/cursor --skill yn-be-developer-typescript。
  • 建议确认权限范围,避免触发不必要的命令执行或文件读写。

SKILL.md

Backend TypeScript – Best Practices & Skills

This skill provides guidance for working on TypeScript backend projects that follow this pattern: structure under src/, ESM, Express, PostgreSQL/MongoDB, and tests with Mocha + tsx. Align with refactor.md, test.md, doc.md, and create-project.md in commands/ when refactoring, testing, documenting, or creating new projects.

When to Use

  • Writing new controllers, models, or utilities in TypeScript
  • Creating or updating tests (.test.ts, Mocha + tsx/cjs)
  • Implementing features in a codebase that uses src/, env.pgConnection, env.pgModels
  • Reviewing or refactoring TypeScript backend code
  • Generating OpenAPI docs or new project scaffolds

Core Technologies

Runtime & Language

  • Node.js: ESM ("type": "module"), run with tsx (or compiled dist/ with node)
  • TypeScript: Strict mode, .ts only under src/ (and config/ if needed)
  • Imports: Use .js extension in import paths for ESM resolution (e.g. from "./app.js"); tsx/Node resolve to .ts when needed. No .mjs.
  • No dynamic imports in handlers: Do not use await import(...) inside controller/model method bodies for normal dependencies. Resolve imports at module scope (or in a dedicated adapter module) to keep types and behavior explicit.

Testing

  • Mocha: Test runner; scripts must use --require tsx/cjs (not tsx/register) so .test.ts files load
  • Chai: Assertions (expect, assert)
  • Sinon: Stubs/spies; stub real method names (e.g. sinon.stub(controller as any, 'login')), not __methodName
  • Structure: Top-level describe('<ClassName>'), nested describe('<methodName>') with the real method name (no __)

Web Framework

  • Express: Routing and middleware; read parsed values from res.locals (e.g. res.locals.id, res.locals.limit, res.locals.offset)

Architecture Patterns

Project Structure

src/
  controllers/   # HTTP layer (extend Abstract_Controller, bind this.methodName)
  lib/           # Utilities, express-middlewares (validIntegerPathParam, parsePaginationParams)
  model/
    postgres/    # PgModels, Abstract_PgModel; register in pg-models.ts
    mongo/       # MongoModels, Abstract_BaseCollection
  cronie/        # Batch jobs: one folder per batch with run.ts entrypoint
config/          # config.ts (or config.json)
docs/            # OpenAPI YAML fragments
test/            # .test.ts mirroring src (test/controllers/, test/lib/, test/lib/notifications/, test/model/...)

Source lives under src/; no app/.

Controller Pattern

  • Extend Abstract_Controller; call super(env, "<scope>")
  • Register routes: this.router.get("/",..., this.methodName.bind(this))
  • Endpoint handler names: Methods that implement an HTTP endpoint must use the CRUD verb as prefix: get* (GET), post* (POST), patch* (PATCH), delete* (DELETE). Examples: getEvents, getUser, postTicket, patchSettings, deleteEvent. Avoid generic names like retrieveEvents for GET handlers — use getEvents instead.
  • Private methods without __: e.g. login, getNations, getAssociations. In tests call via (controller as any).methodName(...)
  • Flow: try/catch → validate (early return with HttpResponseStatus) → env.pgConnection / env.pgModels → shape response
  • Use ExpressMiddlewares: validIntegerPathParam('<param>'), parsePaginationParams(required), validIntegerQueryParam('<param>', required?). Middleware sets res.locals[param] (not always res.locals.id). Pagination offset = **(page - 1) * limit**.
  • Middleware-first rule (mandatory): For controller endpoints, parse/validate path and query params with middleware in route registration, then read normalized values from res.locals inside handlers. Do not parse numeric params manually in handler bodies (parseInt(request.query...), parseInt(request.params...)) except when no suitable middleware exists yet.
  • Path param IDs (integer): Always use validIntegerPathParam('<param>') (or validIntegerPathParam('<param>', HttpResponseStatus.NOT_FOUND) when invalid id should return 404). In the handler, read the value from response.locals[param] (e.g. response.locals.id). Do not parse request.params.id (or other param names) manually in the handler.

Data Layer

  • PostgreSQL: env.pgConnection (query, queryReturnFirst, queryPaged, insert, updateByKey, startTransaction, commit, rollback). Pass transactionClient: t (not transaction) when using a transaction.
  • Models: Prefer env.pgModels.<model>.<method>(); add new models in src/model/postgres/pg-models.ts (extend Abstract_PgModel). Lookups by code/name (e.g. get id by status code, get record by slug) belong in the model, not in the controller: expose methods like getStatusIdByCode(status), getBySlug(slug) and call them from the controller.
  • Read-only: Use isSlave: true for COUNT and read-only SELECT; never for INSERT/UPDATE/DELETE.
  • updateByKey: Keys are an array (e.g. ["id_us"], ['id_up']), not a string. Payload may include id_last_updater_up from request.session.idUser.
  • MongoDB: env.mongoClient, env.mongoModels; same patterns as in JS skill for parameterized access and sanitization.

Service / lib modules — prefer classes when methods share the same parameters

  • When several functions in a module repeatedly receive the same context (e.g. Environment, a DB connection, or a config object), refactor to a class that receives that context in the constructor and stores it on the instance (e.g. private env: Environment).
  • Expose the former "entry" functions as instance methods that take only the operation-specific arguments; internal steps can be private methods or closures that use this.env (or the stored context).
  • This avoids passing the same parameter through every call and keeps the API clearer (e.g. new CalendarSync(this.env).syncCalendar(row) instead of syncCalendar(env, row)).

TypeScript Conventions

Types and Interfaces

  • One model file per table (singular domain naming): Each table has exactly one model file named with the singular domain concept in kebab-case (e.g. users_ususer.model.ts, ticket_categories_tcticket-category.model.ts).
  • One model class per table (singular): Each table model class must use singular PascalCase + Model suffix (e.g. users_usUserModel, ticket_categories_tcTicketCategoryModel).
  • One interface per table (singular Record): Exactly one singular I<Domain>Record interface per table with all columns (e.g. users_usIUserRecord). No subset interfaces (no IRetryRow, IListItem, etc.).
  • Each field defined only once: Fields of the table belong only in the Record interface. Do not extend the Record and re-declare the same field names. Use **Partial<I*Record>** where you need a subset.
  • Partial + extra: add ONLY fields that are NOT in the Record. When you write a type like Partial<I*Record> & {...}, the & {...} part must contain only properties that do not exist in the Record. Never do: Partial<IRecord> & {start_ce: Date} (start_ce is already in IRecord). Never do: Omit<Partial<IRecord>, "start_ce" | "end_ce"> & {start_ce: Date; end_ce: Date} (removing fields to re-add them). Correct: Partial<ICalendarRecord> & {occurrence?: number} — occurrence is the only field not in the Record, so it is the only one you add. This avoids confusion and duplicate field definitions.
  • Prefer Partial at the variable site: Prefer typing variables/parameters as **Partial<I*Record> (and & {extra?: T} only for properties not** in the Record) instead of defining many Pick<> or dedicated subset interfaces. Define the type where the variable is used, or use a short type alias that does not re-list Record fields.
  • In models, define only: (1) Record interfaces (one per table, all columns), (2) transformation interfaces (data with renamed or restructured properties, e.g. for API output). If a transformation type is used in only one place, define it there to keep model files as clean as possible.
  • Single source of truth: Define interfaces in one model file; import elsewhere. Do not duplicate.
  • Use model interfaces: Always use the model interface. Do not define custom interfaces in controllers or lib for the same shape. Import the *Record interface from the model.
  • Record vs extended: Base interface = DB columns only (e.g. IUserRecord with _us fields). Extended interface = computed/joined (e.g. IUserExtended with fullname, departmentFullname, pbx, plan). Model methods return the extended type when the query includes joins.
  • **Object properties in *Record interfaces: Properties that are object types (e.g. JSONB columns) must be typed with | string** in the Record interface, because on insert/update they are passed to the database as serialized strings (e.g. JSON.stringify(...)). Example: automatic_data_pm?: IAutomaticDataPm | string.
  • Split model interfaces: e.g. IWorkingPlanRecord (table only) and IWorkingPlanExtended extends IWorkingPlanRecord (adds users?). In controllers use optional chaining: workingPlan.users?.map(...)?? [].
  • Callbacks: When mapping over arrays with mixed types, type the callback parameter to accept the source type; use Buffer | string when a value can be either.
  • No unknown cast chains: Do not use as unknown as... to silence type errors. Fix typing at the source (interfaces, function generics, or explicit runtime guards).
  • No broad Record<string, any> workarounds: Avoid generic catch-all types to bypass typing. Prefer concrete model interfaces and narrow, explicit types.
  • No typing-only object rebuilding: Do not rebuild DB entities field-by-field just to satisfy TypeScript. Prefer clean source typing first (e.g. insert<I*Record>(...)) and use the returned object directly when behavior is unchanged.

Validation (TypeScript)

  • Use _.isNil(variable) for null/undefined; _.isArray(x) when a value must be an array (e.g. if (_.isNil(numbers) ||!_.isArray(numbers) || numbers.length === 0)).
  • For IDs (path/query/body): Number.isInteger(id) && id > 0 so strings like 'invalid' return 400, not 404.
  • In model methods: same checks; return result?.rows?? [] or throw when query result is null/undefined where appropriate.

Code Style & Naming

  • Files: kebab-case (e.g. auth.controller.ts, express-middlewares.ts)
  • Classes: PascalCase (AuthController, ExpressMiddlewares)
  • Endpoint handlers: Name controller methods that map to routes with the CRUD verb as prefixget*, post*, patch*, delete* (e.g. getEvents, postTicket, patchUser, deleteEvent).
  • Private methods: Real names, no __ (e.g. login, getNations). Use TypeScript private when appropriate.
  • Constants: UPPER_SNAKE_CASE; HttpResponseStatus constants, never hardcoded numeric codes.
  • Indentation: 2 spaces; early returns; small, cohesive functions.
  • No one-liner helpers: Do not add a function or method that wraps a single line of code; keep the logic inline at the call site.

Error Handling & HTTP

  • Use HttpResponseStatus for all responses; propagate errors via next(error).
  • Validation errors (400): When returning 400 for missing or invalid parameters, send a JSON body {error, message} with response.status(HttpResponseStatus.MISSING_PARAMS).send({error: "CODE", message: "..."}). The error field must be a specific UPPER_SNAKE_CASE code that concisely describes the failure (e.g. URL_NAME_COLOR_REQUIRED, EVENT_NOT_RECURRING, SHARED_MANAGEMENT_REQUIRED), not a generic like MISSING_PARAMS; message is the human-readable description. Inline this call at each validation site — do not add a helper method for it. Example: response.status(HttpResponseStatus.MISSING_PARAMS).send({error: "EVENT_TITLE_START_END_REQUIRED", message: "title, start and end are required"});
  • Structured errors: error.status, optional error.errors array; never expose stack or raw DB errors in responses.
  • Cookies: When setting session cookie, pass an options object (e.g. {maxAge,...} or {}), never null.

SQL & PgFilter

  • Query formatting: Indent SQL strings so that lines are not overly long. Put major clauses on their own line (SELECT, FROM, JOIN, WHERE, GROUP BY, ORDER BY). Break long SELECT lists with one column or expression per line (indented). Break long subqueries and function arguments across lines with consistent indentation. This keeps queries readable and diff-friendly.
  • Use queryReturnFirst for single-row checks (e.g. folder count); query for multi-row or when expecting {rows}. Tests must stub and assert on the method actually used.
  • Mandatory SQL existence check before delivery: Validate every SQL statement against the target DB to ensure referenced tables and columns exist.

- SELECT: Execute the query as-is (same SQL text, with valid parameters) and verify it runs without relation/column errors. - INSERT / UPDATE: Do not execute the write during validation. Execute a read-only probe SELECT on the target table that references the same columns used by the write, to confirm table/column existence.

  • Query result shape — flat row, no wrapper: Type the query result as the exact row shape returned by the SELECT. Do not wrap the whole row in an outer SELECT row_to_json(q) AS question FROM (...) q. Return columns directly so each row has a flat structure. Example: query<{id_tq: number; mandatory: boolean; type: string; choices: ITicketQuestionChoiceRecord[]; tree: ITicketCustomizedTreesRecord}>.
  • Single query with array_agg for parent + aggregated child data: When loading parent rows with per-parent arrays of child values (e.g. categories with user/group visibility ids), use one query with LEFT JOIN + GROUP BY and array_agg(...) FILTER (WHERE...) (and COALESCE(..., '{}')::integer[] for empty arrays) instead of two round-trips (one SELECT parents, one SELECT children by parent ids then merge in code). Example: SELECT tc.id_tc, tc.name_tc, COALESCE(array_agg(tcv.id_user_tcv) FILTER (WHERE tcv.id_user_tcv IS NOT NULL), '{}')::integer[] AS user_ids,... FROM ticket_categories_tc tc LEFT JOIN ticket_category_visibilities_tcv tcv ON... WHERE tc.id_customer_tc = $1 GROUP BY tc.id_tc, tc.name_tc ORDER BY tc.name_tc.
  • row_to_json for joined/related data:

- Single related record: Use row_to_json(alias) AS column_name (e.g. row_to_json(tct) AS tree) so the row has one column with the full record. Type it with the model interface (e.g. tree: ITicketCustomizedTreesRecord). - Array of related records: Use COALESCE((SELECT json_agg(row_to_json(alias)) FROM table alias WHERE...), '[]'::json) AS column_name so the row has one column with an array of full records. Type it (e.g. choices: ITicketQuestionChoiceRecord[]). Do not return only IDs when you need full records; use json_agg(row_to_json(...)) for arrays. - Define and use I*Record interfaces for each table involved.

  • No unnecessary variables: Do not introduce intermediate variables when the value is used only once (e.g. use ${filterTree.getWhere(false)} directly in the SQL template, not const treeWhere =...).
  • Insert/update typing must match table interface: For pgConnection.insert<T> / updateByKey, use the table I*Record interface as generic T. If a property used by code is missing from I*Record, add it to the interface (the interface is the source of truth for table columns), do not bypass with casts.
  • PgFilter (common-mjs) — use one filter per query and build the WHERE via the filter API:

- One filter per query: Use a single PgFilter per query. Add all conditions (status, visibility, custom clauses) to that filter with addEqual, addNotEqual, addCondition, etc. Use one getWhere(...) in the SQL and one replacements. Do not combine two filters with AND in the SQL (e.g. WHERE ${filterA.getWhere(false)} AND ${filterB.getWhere(false)}). Using two (or more) filters only makes sense when you have complex conditions combined with OR; otherwise fold every condition into the same filter. - WHERE in the filter (preferred): When the only conditions come from the filter, put the WHERE in the filter: write FROM table ${filter.getWhere()} (no WHERE in the template). The filter then outputs WHERE cond and the SQL is valid. Avoid writing WHERE ${filter.getWhere()} — that produces WHERE WHERE cond and a syntax error. - getWhere(false) when concatenating: Use getWhere(false) only when the template already contains WHERE or AND before the filter (e.g. WHERE id = $1 AND ${filter.getWhere(false)}, or inside a subquery like AND ${filter.getWhere(false)}). Then the filter must output only the condition, not WHERE cond. - Placeholders: Use getParameterPlaceHolder(value) for any value in custom conditions; never use manual $1, $2 in the SQL string. When the same value is used multiple times in the same condition (e.g. idCustomer in a visibility clause), use one placeholder and reuse it (e.g. const ph = filter.getParameterPlaceHolder(idCustomer); filter.addCondition(\... = ${ph} OR... = ${ph})), not separate placeholders for the same value. - Methods: addEqual(col, val), addNotEqual(col, val), addCondition(sqlFragment), addIn(col, values); for ranges: addGreaterThan(col, val, true) = >=, addLessThan(col, val, true) = <= (third param = orEqual). - Pagination: addPagination(limit, offset) and getPagination() in the SQL (do not build LIMIT $n OFFSET $m by hand). Ordering: addOrderByCondition(field, direction) and getOrderBy() (do not build ORDER BY... by hand when the filter supports it). - Replacements: Prefer new PgFilter(0) and have the filter own all placeholders. Use replacements: filter.replacements only — no concatenation of multiple filters' replacements.

Transactions

  • const t = await env.pgConnection.startTransaction(); then commit(t) / rollback(t).
  • Pass transactionClient: t to query / insert / updateByKey.
  • In tests: stub startTransaction with .resolves(t) (not .returns(t)). If the controller does not wrap rollback in try/catch, when rollback rejects, next is called with the rollback error; tests should assert next(rollbackError) and not expect logger.error for rollback.

Testing (Mocha + tsx)

  • Run: npm test or npm run test:all; scripts use --require tsx/cjs.
  • Controller methods: Call (controller as any).methodName(...); describe('methodName',...) (not __methodName).
  • Stubs: sinon.stub(controller as any, 'methodName') (and same for lib/helpers: e.g. sendRequest, parsePaddingTemplate).
  • Assertions: Use transactionClient in calledWith/calledOnceWith; updateByKey keys = array; response.cookie third arg = options object.
  • Mock env: Do not change production to satisfy tests. Provide config.pubSubOptions (topicId, authentication) when code builds NotificationsManager/PubSubV2; config.getstream, config.sms (e.g. fakeSms) when used. Use documentsConnection (not ynDbConnection) when the controller uses it. For helpers that need env but not full config, use a minimal fake env instead of new Environment().
  • Import paths: From test/ use ../../src/...; from test/lib/notifications/ use ../../../src/... and ../../../config/... (three levels).
  • Logger: If the controller uses this.env.logger.warning, the mock must provide logger.warning (not only logger.warn).

Configuration & Environment

  • Do not read process.env directly in controllers; use Environment/config layer.
  • Document defaults in config/config.ts (or project equivalent).

Security, Logging, Batch, Git

  • Same as in the Node.js backend skill: no secrets in code/logs; parameterized queries only; hash passwords in model layer; validate/sanitize input; use env.session.checkAuthentication() / checkPermission().
  • Logging: env.logger with appropriate levels; never log sensitive data.
  • Batch/cron: under src/cronie/ with one folder per batch (src/cronie/<batch>/), executable always named run.ts, and batch logic in <batch>-batch.ts. Do not use aggregated multi-flag runners. Keep jobs idempotent with clear logging.
  • Git: branch names feature/, fix/, chore/, refactor/; commits imperative present tense; PRs small and tested.

Commands Reference

  • refactor.md: Port legacy controller to TypeScript (src/, no __, transactionClient, types, tests).
  • test.md: Write/update tests (.test.ts, tsx/cjs, (controller as any).methodName, mock env, no production changes).
  • doc.md: OpenAPI YAML from controller method name without __ and route registration.
  • create-project.md: New TypeScript project (src/,.ts, tsconfig, tsx, private methods without __).

Instructions Summary

  1. TypeScript only under src/ –.ts, ESM, real method names (no __).
  2. Test with Mocha + tsx/cjs – (controller as any).methodName, transactionClient, correct mock config.
  3. Validate early – _.isNil, _.isArray, Number.isInteger(id) && id > 0 where needed.
  4. Handle errors – next(error), HttpResponseStatus constants; for validation (400) use .send({error: "SPECIFIC_CODE", message: "..."}) with a specific code that describes the message, inline (no helper).
  5. Types – Single source (each field only in the Record); Partial<I*Record> at the variable site; when adding with & {...} add ONLY properties not in the Record (never Omit/re-add or Partial + re-declare Record fields); in models only Record + transformation interfaces.
  6. SQL – queryReturnFirst vs query; isSlave: true for read-only; getParameterPlaceHolder; transactionClient; validate table/column existence before delivery (SELECT as-is, INSERT/UPDATE via probe SELECT).
  7. No production changes for tests – complete mock config (pubSubOptions, getstream, sms, etc.) and minimal fake env when appropriate.

When in doubt, prefer the patterns described in refactor.md and test.md for controllers, handlers, types, and tests.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

35.92%
按下载量换算98

Claude

30.56%
按下载量换算83

Cursor

20.09%
按下载量换算55

Gemini CLI

9.73%
按下载量换算26

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills