commit 54b4d8f8c5812845edd6b1704a88deccecdf1911 Author: tiga.ye Date: Mon Oct 12 02:10:43 2026 +0000 上传文件至「/」 diff --git a/COMMIT_EDITMSG b/COMMIT_EDITMSG new file mode 100644 index 0000000..5a93c4e --- /dev/null +++ b/COMMIT_EDITMSG @@ -0,0 +1,6 @@ +feat(ewallet): 支持会员 card_num 场景 (Task 15171) 并新增 msgw contentSend 路由 + +- member.profile 与 createMockContext 增加 card_num 字段及 MOCK_TASK_15171_ENABLED 开关 +- 新增 memberProfileCardNum 路由与对应测试 +- 新增 ewl/msgw/contentSend 路由并在 registerRoutes 注册 +- 包管理从 npm 迁移到 yarn diff --git a/README.md b/README.md new file mode 100644 index 0000000..d252ec2 --- /dev/null +++ b/README.md @@ -0,0 +1,481 @@ +# Mock Gateway + +本项目是 **独立 Git 仓库** 的本地 Mock 网关,用于模拟 eWallet 后端依赖的 Bally/EDIP 接口,避免在 `Backend` 主代码中持续保留绕过逻辑。 + +## 已内置的 Mock 接口 + +- `POST /edip/v1/token/get` +- `POST /edip/v1/token/refresh` +- `POST /ewl/bal/v1/cardpin/validate` +- `POST /ewl/promotion/v1/promotion/all` +- `POST /ewl/bal/v1/promotion/all` (兼容旧地址) +- `POST /ewl/promotion/v1/promotion/backdate/all` +- `POST /ewl/bal/v1/promotion/backdate/all` (兼容旧地址) +- `POST /ewl/mkt-rm/v1/team/hierarchy` +- `POST /ewl/bal/v1/prize/redeem` +- `POST /ewl/bal/v1/point/void` +- `POST /ewl/promotion/v1/redeemedpromotion/detail` +- `POST /ewl/bal/v1/redeemedpromotion/detail` (兼容旧地址) +- `POST /ewl/promotion/v1/playerpromotion/redeem` +- `POST /ewl/bal/v1/playerpromotion/redeem` (兼容旧地址) +- `POST /ewl/promotion/v1/redeemedpromotion/void` +- `POST /ewl/bal/v1/redeemedpromotion/void` (兼容旧地址) +- `POST /ewl/edip/v1/member/profile` +- `POST /ewl/bal/v1/player/image` +- `POST /ewl/bal/v1/player/earn` +- `POST /api/v1/prize-redemptions/sync` +- `GET /healthz` + +## 已内置的 LDAP Mock(新增) + +- 协议:LDAPv3 +- 默认监听:`ldap://0.0.0.0:1389` +- 支持能力:`Simple Bind` + `Search` + +固定行为(与对接约定一致): + +1. manager bind DN:`cn=s-cicd-app,OU=ServiceAccount,dc=macausjm-glp,dc=com` +2. 用户搜索:base `dc=macausjm-glp,dc=com` + filter `(sAMAccountName={username})` +3. 组搜索:base `OU=SecurityGroups,OU=GLPUsers,dc=macausjm-glp,dc=com` + filter `(member={userDn})` +4. 用户条目属性:`sAMAccountName` / `cn` / `mail` / `memberOf` +5. 组条目属性:`cn` / `member` + +并且支持用户 DN + 密码直接 bind 成功(基于内置默认用户或 `MOCK_LDAP_USERS_JSON` 配置用户)。 + +另外默认开启“任意用户名/密码放行”联调模式(`MOCK_LDAP_ALLOW_ANY_USER_MODE=true`): + +- 前端输入任意账号密码都可通过后端 LDAP 认证 +- `(sAMAccountName={username})` 会按 `{username}` 动态返回用户条目 +- `(member={userDn})` 会返回组条目(默认 `SG-APP-EWALLET-SUPER-ADMIN`) + +推荐做法:通过 `MOCK_LDAP_USERS_JSON` / `MOCK_LDAP_GROUPS_JSON` 在 `Mock_Gateway` 侧配置用户与用户组,不要再在 `Backend` 代码里硬编码开发账号或组别。 + +## 本地启动 + +```bash +cd Mock_Gateway +npm install +cp .env.example .env +npm run start +``` + +开发联调建议使用自动重启模式(监听 `src/` 与 `.env` 变更): + +```bash +npm run dev +``` + +默认监听:`http://127.0.0.1:19090` + +LDAP 默认监听:`ldap://0.0.0.0:1389` + +## Promotion 完整链路 mock + +默认的 `playerpromotion/redeem` 仍然只是静态回包。 + +如果你要在本地继续联调 promotion 首打、redeemed history、reprint 这一整条链路,可以开启下面这组桥接配置,让 `Mock_Gateway` 在 promotion redeem 成功后继续: + +1. 登录本地 `Backend` +2. 调用真实 `POST /api/v1/prize-redemptions` +3. 把同一笔 `redemptionId` 记录进 mock 的 `redeemedpromotion/detail` + +建议同时满足以下前提: + +- 本地 `Backend` 已启动 +- 本地 `Backend` 已接到当前 `Mock_Gateway` 的 LDAP mock +- 测试会员在本地 wallet 里对 `MOCK_PROMOTION_REDEMPTION_SOURCE_BUCKET` 有足够余额 + +推荐配置: + +```bash +MOCK_PROMOTION_REDEMPTION_BRIDGE_ENABLED=true +MOCK_PROMOTION_REDEMPTION_BRIDGE_BASE_URL=http://127.0.0.1:8080 +MOCK_PROMOTION_REDEMPTION_BRIDGE_LOGIN_PASSWORD=mock-password +MOCK_PROMOTION_REDEMPTION_BRIDGE_TIMEOUT_MS=30000 +MOCK_PROMOTION_REDEMPTION_INITIATE_SOURCE=PROMOTION_MODULE +MOCK_PROMOTION_REDEMPTION_SOURCE_BUCKET=m-comp +``` + +说明: + +- `MOCK_PROMOTION_REDEMPTION_BRIDGE_LOGIN_USERNAME` 留空时,默认复用本次 redeem 请求里的 `loginId` +- `MOCK_PROMOTION_REDEMPTION_SOURCE_BUCKET` 默认用 `m-comp` 作为 source wallet bucket +- 桥接成功后,`/ewl/bal/v1/redeemedpromotion/detail` 会优先返回本次实际生成的 mock redeemed record + +### Promotion issue-to-wallet 控制 + +当前 `Mock_Gateway` 已支持两层控制 promotion redeem -> 本地 `prize-redemptions` 的 `issueTargetToWallet`: + +1. 显式覆盖,优先级最高 +2. 现有推断,作为兜底 + +显式覆盖支持两种写法: + +- 请求级: + - `data.issueTargetToWallet: [true, false, ...]`,按 `outcomeId` 顺序逐项覆盖;同一个 `outcomeId` 重复出现且每次选择不同 `Open Item / Auto Settle` 时,必须走这个数组 + - `data.issueTargetToWalletByOutcomeId: { "11330011": true, "11330012": false }`,按 outcomeId 精确覆盖 +- fixture 级: + - `outcomeList[].mockIssueTargetToWallet` + - `outcomeList[].prize.mockIssueTargetToWallet` + +当以上显式覆盖都没有提供时,才回退到现有推断规则: + +- `gisPrizeIdentifier[index]` 非空 -> `issueTargetToWallet=false` +- 否则 `deliveryMode=EXTERNAL_ONLY` -> `false` +- 其他情况 -> `true` + +这意味着: + +- 对 `USER_CHOICE` prize,如需稳定复现同一个 outcome 在 openitem / autosettle 之间切换,推荐直接在 mock 请求或 fixture 中提供显式覆盖,不要只依赖 `deliveryMode` +- 如果一个请求里允许同一个 `outcomeId` 重复出现且每次选择不同,优先使用 `issueTargetToWallet` 数组;`issueTargetToWalletByOutcomeId` 只适合一个 outcomeId 对应一个固定值的场景 +- 如果调用方需要,也可以通过 body 的 `issueTargetToWalletByOutcomeId` / `issueTargetToWallet`,或自定义 header `X-Ewallet-Mock-Issue-Target-To-Wallet-By-Outcome-Id` 给 mock 传入显式覆盖;未提供时仍按当前默认推断执行 +- 旧链路不受影响;未提供覆盖时仍保持当前默认行为 + +### UI 点测同一个 outcome 的本地预设 + +如果不改 Backend,但希望在 UI 上对同一个 outcome 反复点测 `Open Item / Auto Settle`,可以先写入 mock runtime override: + +```bash +curl -s -X POST http://127.0.0.1:19090/mock-api/promotion-redeem/fulfillment-overrides \ + -H 'Content-Type: application/json' \ + -d '{ + "accountNum": "80010991", + "promotionId": 11330, + "promotionRuleId": 1133001, + "outcomeId": 11330011, + "issueTargetToWallet": false + }' +``` + +说明: + +- `issueTargetToWallet=true` 表示本次同一个 outcome 走 `Open Item` +- `issueTargetToWallet=false` 表示本次同一个 outcome 走 `Auto Settle` +- 写入后,直接在 UI 点同一个 outcome 即可;mock 会优先使用这份 runtime override +- override 默认会持久化到 `./runtime/promotion-redeem-fulfillment-overrides.json`,重启 `Mock_Gateway` 后仍会保留 +- 可通过 `GET /mock-api/promotion-redeem/fulfillment-overrides` 查看当前预设 +- 可通过 `DELETE /mock-api/promotion-redeem/fulfillment-overrides?accountNum=80010991&promotionId=11330&promotionRuleId=1133001&outcomeId=11330011` 清除单条预设 + +## 与 Backend 集成 + +在 Backend 启动环境中设置: + +```bash +MOCK_GATEWAY_BASE_URL=http://127.0.0.1:19090 +BALLY_BASE_URL=${MOCK_GATEWAY_BASE_URL} +EDIP_BASE_URL=${MOCK_GATEWAY_BASE_URL} +BALLY_REDEEM_BASE_URL=${MOCK_GATEWAY_BASE_URL} +BALLY_PROMOTION_BASE_URL=${MOCK_GATEWAY_BASE_URL} + +# 建议关闭旧的本地 member 直返 mock,改走网关 +BALLY_MEMBER_QUERY_LOCAL_MOCK_ENABLED=false +``` + +## Task12085 本地故障注入 + +当前 `Mock_Gateway` 已支持直接注入 Member Profile 两类关键故障: + +1. `503` / 服务不可用 + +```bash +MOCK_MEMBER_PROFILE_FORCE_STATUS_CODE=503 +MOCK_MEMBER_PROFILE_FORCE_ERROR_CODE=MOCK_503 +MOCK_MEMBER_PROFILE_FORCE_ERROR_MSG='Mock member profile unavailable' +``` + +2. 响应超时 + +```bash +MOCK_MEMBER_PROFILE_DELAY_MS=15000 +``` + +建议: + +- `MOCK_MEMBER_PROFILE_DELAY_MS` 需要大于 Backend 当前 member profile 调用的阻塞超时,才能稳定触发超时 +- 如果你只想打 member profile 故障,保持 `MOCK_EDIP_FORCE_ERROR_CODE` 为空,让 token 继续正常返回 +- 测完后把这些变量清空并重启 `Mock_Gateway` + +## 快速验证 + +```bash +curl -s http://127.0.0.1:19090/healthz + +curl -s -X POST http://127.0.0.1:19090/edip/v1/token/get \ + -H 'Content-Type: application/json' \ + -d '{"schema":{},"data":{"account":"a","password":"b","key":"k","secret":"s"}}' + +curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/cardpin/validate \ + -H 'Content-Type: application/json' \ + -d '{"schema":{},"data":{"accountNum":"810006843","pin":"1234"}}' + +curl -s -X POST http://127.0.0.1:19090/ewl/promotion/v1/promotion/all \ + -H 'Content-Type: application/json' \ + -d '{"schema":{},"data":{"accountNum":"800048718"}}' + +curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/promotion/all \ + -H 'Content-Type: application/json' \ + -d '{"schema":{},"data":{"accountNum":"800048718"}}' + +curl -s -X POST http://127.0.0.1:19090/ewl/mkt-rm/v1/team/hierarchy \ + -H 'Content-Type: application/json' \ + -d '{"schema":{"terminalCode":"MOCK-PC"},"data":{"userName":"mock.user","staffId":"M000001"}}' + +curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/prize/redeem \ + -H 'Content-Type: application/json' \ + -d '{"schema":{},"data":{"accountNum":"800048718","prizeCode":"MOCK"}}' + +curl -s -X POST http://127.0.0.1:19090/api/v1/prize-redemptions/sync \ + -H 'Content-Type: application/json' \ + -d '{"schema":{},"data":{"correlationId":"mock-correlation-id"}}' + +curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/point/void \ + -H 'Content-Type: application/json' \ + -d '{"schema":{},"data":{"transId":"mock-redeem-id"}}' + +curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/redeemedpromotion/detail \ + -H 'Content-Type: application/json' \ + -d '{"schema":{},"data":{"accountNum":"800048718"}}' + +curl -s -X POST http://127.0.0.1:19090/ewl/promotion/v1/playerpromotion/redeem \ + -H 'Content-Type: application/json' \ + -d '{"schema":{},"data":{"accountNum":"800048718","promotionId":100002}}' + +curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/playerpromotion/redeem \ + -H 'Content-Type: application/json' \ + -d '{ + "schema": {}, + "data": { + "accountNum": "80010991", + "promotionId": 11330, + "promotionRuleId": 1133001, + "outcomeId": [11330011, 11330012, 11330013], + "issueTargetToWalletByOutcomeId": { + "11330011": true, + "11330012": false, + "11330013": false + } + } + }' + +curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/playerpromotion/redeem \ + -H 'Content-Type: application/json' \ + -d '{"schema":{},"data":{"accountNum":"800048718","promotionId":100002}}' + +curl -s -X POST http://127.0.0.1:19090/ewl/promotion/v1/redeemedpromotion/void \ + -H 'Content-Type: application/json' \ + -d '{"schema":{},"data":{"redeemedId":<上一步 detail 响应里的 redemptionId>}}' + +curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/redeemedpromotion/void \ + -H 'Content-Type: application/json' \ + -d '{"schema":{},"data":{"redeemedId":<上一步 detail 响应里的 redemptionId>}}' + +# LDAP manager bind(默认 manager 密码可留空,便于 Backend 只改 LDAP_URL) +ldapsearch -x -H ldap://127.0.0.1:1389 \ + -D "cn=s-cicd-app,OU=ServiceAccount,dc=macausjm-glp,dc=com" \ + -w "any-password" \ + -b "dc=macausjm-glp,dc=com" \ + "(sAMAccountName=mock.user)" sAMAccountName cn mail memberOf + +# LDAP user bind(DN + 密码) +ldapsearch -x -H ldap://127.0.0.1:1389 \ + -D "cn=mock.user,OU=GLPUsers,dc=macausjm-glp,dc=com" \ + -w "mock-user-password" \ + -b "OU=SecurityGroups,OU=GLPUsers,dc=macausjm-glp,dc=com" \ + "(member=cn=mock.user,OU=GLPUsers,dc=macausjm-glp,dc=com)" cn member + +# 建议把默认组名设置成 Backend 角色表已有 code(如 `SG-APP-EWALLET-SUPER-ADMIN`),更容易看到非空 permissions +``` + +## 页面数据模板(JSON) + +- `fixtures/token.get.json`:`/edip/v1/token/get` 成功响应模板 +- `fixtures/member.profile.json`:`/ewl/edip/v1/member/profile` 成功响应模板 +- `fixtures/promotions.capture.800048718.json`:`/ewl/promotion/v1/promotion/all` 抓包模板 +- `fixtures/promotions.capture..json`:按会员号隔离的 promotion fixture;存在同名文件时,mock 会优先对该会员返回该文件内容 +- promotion fixture 可额外带 `outcomeList[].mockIssueTargetToWallet` 或 `outcomeList[].prize.mockIssueTargetToWallet`,用于稳定指定某个 outcome 走 openitem / autosettle + +当前已补一条专用于完整链路测试的会员: + +- `80010991` +- promotionId:`10991` +- promotion:`LP-MOCK-REPRINT-CHAIN` +- ruleId:`1099101` +- outcomeId:`10991011` +- targetPrizeCode:`lp-ee-nsuwr-5pts-20-fb` +- 另有 3-outcome 的 `USER_CHOICE` 测试 promotion: +- promotionId:`11330` +- promotion:`LP-MOCK-USER-CHOICE-3-OUTCOMES` +- ruleId:`1133001` +- outcomeId:`11330011` -> `it-test-fb-$1` +- outcomeId:`11330012` -> `it-test-nnpc-$1` +- outcomeId:`11330013` -> `it-test-ebo-$1` +- 这 3 个 outcome 都可在 UI 上分别切 `Open Item / Auto Settle`,用于本地验证 promotion redeem -> prize-redemptions -> redeemed detail 整条链路 + +说明: + +- 以上模板用于维护响应“静态骨架” +- 动态字段仍由网关运行时覆盖(如 `accessToken`、`refreshToken`、`accountNum`、`playerId`、以及 LDAP 用户相关字段) + +## 代码结构(已拆分) + +- `src/server.js`:仅保留启动、路由装配、404 与 LDAP 启动 +- `src/ldap/createMockLdapService.js`:LDAP 相关逻辑独立维护 +- `src/context/createMockContext.js`:共享配置、fixture 加载、通用工具函数 +- `src/routes/**`:每个接口路径一个独立文件(便于新增与变更) + +## 常用环境变量 + +- `MOCK_PROMOTION_CAPTURE_FILE`:promotion 抓包文件路径(默认读取仓库内 `./fixtures/promotions.capture.800048718.json`) +- `MOCK_PROMOTION_MAX_ITEMS`:promotion 返回上限(eligible/entitled 各自限制,默认 `30`) +- `MOCK_TASK_10766_ENABLED`:开启 Task 10766 复现场景(默认 `false`) +- `MOCK_TASK_10766_ACCOUNT_NUM`:Task 10766 固定 mock 会员号(默认 `80010766`) +- `MOCK_TASK_10766_PROMOTION_CAPTURE_FILE`:Task 10766 promotion fixture(默认 `./fixtures/promotions.capture.10766.json`) +- `MOCK_TASK_10766_MEMBER_EBONUS`:Task 10766 会员资料接口返回的 eBonus 数值(默认 `8888`) +- `MOCK_TASK_10766_REDEEM_ERROR_CODE` / `MOCK_TASK_10766_REDEEM_ERROR_MSG` / `MOCK_TASK_10766_REDEEM_RESULT`:Task 10766 的 `playerpromotion/redeem` 定向失败控制 +- `MOCK_TASK_10852_ENABLED`:开启 Task 10852 多 outcome promotion 复现场景(默认 `false`) +- `MOCK_TASK_10852_ACCOUNT_NUM`:Task 10852 固定 mock 会员号(默认 `80010852`) +- `MOCK_TASK_10852_PROMOTION_CAPTURE_FILE`:Task 10852 promotion fixture,默认使用隔离的 entitled 双 outcome 抓包 `./fixtures/promotions.capture.10852.json` +- `MOCK_TASK_10852_MEMBER_EBONUS`:Task 10852 会员资料接口返回的 eBonus 数值(默认 `188`) +- `MOCK_TOKEN_GET_FIXTURE_FILE`:`/edip/v1/token/get` JSON 模板文件路径(默认 `./fixtures/token.get.json`) +- `MOCK_MEMBER_PROFILE_FIXTURE_FILE`:`/ewl/edip/v1/member/profile` JSON 模板文件路径(默认 `./fixtures/member.profile.json`) +- `MOCK_MEMBER_PROFILE_FORCE_STATUS_CODE`:`/ewl/edip/v1/member/profile` 强制返回指定 HTTP 状态码,例如 `503` +- `MOCK_MEMBER_PROFILE_FORCE_ERROR_CODE`:配合 `MOCK_MEMBER_PROFILE_FORCE_STATUS_CODE` 返回错误码 +- `MOCK_MEMBER_PROFILE_FORCE_ERROR_MSG`:配合 `MOCK_MEMBER_PROFILE_FORCE_STATUS_CODE` 返回错误信息 +- `MOCK_MEMBER_PROFILE_DELAY_MS`:`/ewl/edip/v1/member/profile` 延迟响应毫秒数,可用于本地模拟超时 +- `MOCK_TEAM_HIERARCHY_STATUS`:`team/hierarchy` 的 `status`(默认 `true`) +- `MOCK_TEAM_HIERARCHY_ERROR_CODE` / `MOCK_TEAM_HIERARCHY_MESSAGE`:`team/hierarchy` 错误模拟 +- `MOCK_TEAM_HIERARCHY_ROLE` / `MOCK_TEAM_HIERARCHY_DEPARTMENT` / `MOCK_TEAM_HIERARCHY_TAGS`:`team/hierarchy` 返回字段 +- `MOCK_PRIZE_REDEEM_ERROR_CODE` / `MOCK_PRIZE_REDEEM_ERROR_MSG` / `MOCK_PRIZE_REDEEM_VALUE`:`prize/redeem` 返回控制(`MOCK_PRIZE_REDEEM_VALUE` 留空时自动生成交易号) +- `MOCK_POINT_VOID_ERROR_CODE` / `MOCK_POINT_VOID_ERROR_MSG` / `MOCK_POINT_VOID_RESULT`:`point/void` 返回控制 +- `MOCK_REDEEMED_PROMOTION_DETAIL_ERROR_CODE` / `MOCK_REDEEMED_PROMOTION_DETAIL_ERROR_MSG`:`redeemedpromotion/detail` 返回控制 +- `MOCK_REDEEMED_PROMOTION_DETAIL_INCLUDE_DEFAULT_RECORD`:是否返回默认一条 `outcomeList`(默认 `true`) +- `MOCK_REDEEMED_PROMOTION_DETAIL_VOIDED`:默认记录是否标记已作废(默认 `false`) +- `MOCK_PLAYERPROMOTION_REDEEM_ERROR_CODE` / `MOCK_PLAYERPROMOTION_REDEEM_ERROR_MSG` / `MOCK_PLAYERPROMOTION_REDEEM_RESULT`:`playerpromotion/redeem` 返回控制 +- `MOCK_PROMOTION_REDEMPTION_BRIDGE_ENABLED`:开启 promotion redeem -> 本地 `prize-redemptions` 桥接(默认 `false`) +- `MOCK_PROMOTION_REDEMPTION_BRIDGE_BASE_URL`:本地 Backend 基地址(默认 `http://127.0.0.1:8080`) +- `MOCK_PROMOTION_REDEMPTION_BRIDGE_LOGIN_USERNAME` / `MOCK_PROMOTION_REDEMPTION_BRIDGE_LOGIN_PASSWORD`:桥接调用 Backend 登录用账号;用户名留空时默认复用本次 redeem 的 `loginId` +- `MOCK_PROMOTION_REDEMPTION_BRIDGE_TIMEOUT_MS`:桥接调用超时毫秒数(默认 `30000`);本地完整链路联调建议至少保留 `30000` +- `MOCK_PROMOTION_REDEMPTION_INITIATE_SOURCE`:桥接到 `prize-redemptions` 时写入的 `initiateSource`(默认 `PROMOTION_MODULE`) +- `MOCK_PROMOTION_REDEMPTION_SOURCE_BUCKET`:桥接到 `prize-redemptions` 时使用的 source wallet bucket(默认 `m-comp`) +- `MOCK_PROMOTION_REDEMPTION_ID_START`:mock redeemed history 的起始 `redemptionId`;留空时默认用进程启动时的 Unix 秒级时间戳作为 seed,且会限制在 Backend `int` 可解析范围内,避免 Mock_Gateway 重启后重复复用旧 `redemptionId` +- `MOCK_REDEEMEDPROMOTION_VOID_ERROR_CODE` / `MOCK_REDEEMEDPROMOTION_VOID_ERROR_MSG` / `MOCK_REDEEMEDPROMOTION_VOID_RESULT`:`redeemedpromotion/void` 返回控制 +- `MOCK_PRIZE_REDEMPTIONS_SYNC_SUCCESS` / `MOCK_PRIZE_REDEMPTIONS_SYNC_MESSAGE`:`/api/v1/prize-redemptions/sync` 返回控制 +- `MOCK_LDAP_ENABLED`:是否启用 LDAP mock(默认 `true`) +- `MOCK_LDAP_HOST`:LDAP 监听地址(默认 `0.0.0.0`) +- `MOCK_LDAP_PORT`:LDAP 监听端口(默认 `1389`) +- `MOCK_LDAP_BASE_DN`:LDAP 基础 DN(默认 `dc=macausjm-glp,dc=com`) +- `MOCK_LDAP_MANAGER_DN`:manager bind DN(默认 `cn=s-cicd-app,OU=ServiceAccount,dc=macausjm-glp,dc=com`) +- `MOCK_LDAP_GROUP_BASE_DN`:组搜索 base(默认 `OU=SecurityGroups,OU=GLPUsers,dc=macausjm-glp,dc=com`) +- `MOCK_LDAP_ALLOW_ANY_USER_MODE`:任意用户名/密码放行模式(默认 `true`) +- `MOCK_LDAP_ALLOW_ANY_USER_OU`:动态用户 DN 的 OU 段(默认 `OU=GLPUsers`) +- `MOCK_LDAP_ALLOW_ANY_USER_GROUP_CN`:动态用户默认组名(默认 `SG-APP-EWALLET-SUPER-ADMIN`) +- `MOCK_LDAP_ALLOW_ANY_USER_MAIL_DOMAIN`:动态用户邮箱域名(默认 `macausjm-glp.com`) +- `MOCK_LDAP_MANAGER_PASSWORD`:manager bind 密码;留空时允许任意密码(便于仅改 `LDAP_URL` 联调) +- `MOCK_LDAP_DEFAULT_USER_*`:默认单用户 mock 配置 +- `MOCK_LDAP_USERS_JSON`:JSON 数组,多用户覆盖配置 + +## Task 10766 复现场景 + +打开 `.env`,加入或覆盖以下配置: + +```bash +MOCK_TASK_10766_ENABLED=true +MOCK_TASK_10766_ACCOUNT_NUM=80010766 +MOCK_TASK_10766_PROMOTION_CAPTURE_FILE=./fixtures/promotions.capture.10766.json +MOCK_TASK_10766_MEMBER_EBONUS=8888 +MOCK_TASK_10766_REDEEM_ERROR_CODE=EWALLET_HTTP_ERROR +MOCK_TASK_10766_REDEEM_ERROR_MSG=ewallet connection failed: 404 NOT_FOUND, {"success":false,"message":"Prize definition not found"} +MOCK_TASK_10766_REDEEM_RESULT=false +``` + +复现方式: + +1. 启动 `Mock_Gateway` +2. 前后端联调继续指向本地 mock 网关 +3. 在 `Wallet` 页面搜索会员 `80010766` +4. 切到 `Promotion` +5. 搜索 `cny` +6. 选择 `CNY Gift Set Earn & Get-2026 / GS-8pts-LCH Gift Set Abalone + Scallop` +7. 点击 `Redeem` 并完成确认 + +预期: + +- 会员资料接口返回 `eBonus=8888` + +- promotion 列表固定返回 Task 10766 专用 fixture +- `POST /ewl/promotion/v1/playerpromotion/redeem` 固定返回 `Prize definition not found` 场景 +- 可稳定复现 10766 对应的 promotion redeem 失败明细展示问题 + +## Task 10852 复现场景 + +打开 `.env`,加入或覆盖以下配置: + +```bash +MOCK_TASK_10852_ENABLED=true +MOCK_TASK_10852_ACCOUNT_NUM=80010852 +MOCK_TASK_10852_PROMOTION_CAPTURE_FILE=./fixtures/promotions.capture.10852.json +MOCK_TASK_10852_MEMBER_EBONUS=188 +``` + +复现方式: + +1. 启动 `Mock_Gateway` +2. 前后端联调继续指向本地 mock 网关 +3. 在 `Wallet` 页面搜索会员 `80010852` +4. 切到 `Promotion` +5. 搜索 `cny` +6. 选择 `CNY Gift Set Earn & Get-2026` +7. 勾选两个 outcome 后继续兑换流程 + +预期: + +- 会员资料接口返回 `eBonus=188` +- `POST /ewl/promotion/v1/promotion/all` 固定返回可点击的 entitled 双 outcome promotion +- 前端会稳定走到 `targetPrizes` 多项场景,便于验证 10852 的最小修复 + +## 按会员号自动注入 Promotion Fixture + +除了现有的 Task 10766 / 10852 专用开关外,`Mock_Gateway` 现在还支持按会员号自动加载 fixture: + +- 文件命名:`fixtures/promotions.capture..json` +- 命中规则:当 `/ewl/promotion/v1/promotion/all` 的 `accountNum` 与文件名中的会员号一致时,自动返回该 fixture +- backdate 文件命名:`fixtures/promotions.backdate..json` +- backdate 命中规则:当 `/ewl/promotion/v1/promotion/backdate/all` 的 `accountNum` 与文件名中的会员号一致时,自动返回该 fixture +- 优先级:Task 10766 / 10852 专用场景优先,其次才是按会员号自动加载的 fixture + +示例: + +- `fixtures/promotions.capture.800038008.json` +- `fixtures/promotions.capture.80010852.json` +- `fixtures/promotions.backdate.800038008.json` + +适用场景: + +- 需要保留某个会员的真实采样 promotion 规则 +- 想快速补充新的 `minOutcome / maxOutcome / outcomeList / prize` 组合 +- 不希望影响默认共享 mock 数据 + + + +## 使用本地测试开发网关的时候可以使用以下会员号 +按 `Mock_Gateway` 当前代码中的“定向逻辑 / 定向 fixture / 固定路由”统计,特别会员号共有 `5` 个(不含默认模板/示例号): + +1. `800038008` - backdate 固定会员号。 + `/ewl/promotion/v1/promotion/entitledBackDate` 和 `/ewl/promotion/v1/promotion/entitledBackDate/all` 会固定返回这个会员号的 backdate promotion;仓库里也有它的普通 promotion fixture 和 backdate fixture。 +2. `80010766` - Task 10766 专用复现号。 + 开启 `MOCK_TASK_10766_ENABLED=true` 后,会员资料固定返回 `eBonus=8888`,promotion 列表走专用 fixture,`playerpromotion/redeem` 固定复现 `Prize definition not found` 失败场景。 +3. `80010852` - Task 10852 专用复现号。 + 开启 `MOCK_TASK_10852_ENABLED=true` 后,会员资料固定返回 `eBonus=188`,promotion 列表走专用 fixture,并强制提供可点击的 entitled 双 outcome 场景,用于验证多 outcome redeem。 +4. `80010991` - 完整链路 / 同 outcome 切换场景号。 + 命中专用 `promotions.capture.80010991.json`,内含单 outcome reprint chain 和 3-outcome `USER_CHOICE` promotion;也用于 runtime fulfillment override,方便在 UI 上反复验证同一个 outcome 的 `Open Item / Auto Settle` 切换。 +5. `100000059` - redeemed promotion detail 专用号。 + 命中 `award.promotions.100000059.json`,用于 `redeemedpromotion/detail` 返回账户级已兑 promotion 明细。 + +以下号码也出现在 `Mock_Gateway` 中,但更适合视为默认模板 / 示例数据,不计入上面的“特别会员号”: + +1. `800048718` - 默认 promotion 抓包模板来源。 + 没有专属定向逻辑,未命中其他专用场景时,普通账号会回落到这份默认 promotion fixture。 +2. `800049052` - 默认 redeemed promotions 示例号。 + 只在 `redeemedpromotion/detail` 没传账号且没有账户级记录时,作为默认示例数据中的 `customerId` 出现。 + + 800048718 老会员----换新账号----910700001 \ No newline at end of file diff --git a/mock_gateway.log b/mock_gateway.log new file mode 100644 index 0000000..06d7405 Binary files /dev/null and b/mock_gateway.log differ diff --git a/package.json b/package.json new file mode 100644 index 0000000..49e8473 --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "ewallet-mock-gateway", + "version": "0.1.0", + "private": true, + "description": "Local mock gateway for eWallet external Bally/EDIP APIs", + "main": "src/server.js", + "engines": { + "node": ">=18" + }, + "scripts": { + "start": "node src/server.js", + "dev": "node --watch --watch-preserve-output --watch-path=src --watch-path=.env src/server.js", + "test": "node --test tests/*.test.js" + }, + "dependencies": { + "dotenv": "^16.4.7", + "express": "^4.21.2", + "ldapjs": "^3.0.7" + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..6e27750 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,665 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ldapjs/asn1@^1.2.0": + "integrity" "sha512-KX/qQJ2xxzvO2/WOvr1UdQ+8P5dVvuOLk/C9b1bIkXxZss8BaR28njXdPgFCpj5aHaf1t8PmuVnea+N9YG9YMw==" + "resolved" "https://registry.npmmirror.com/@ldapjs/asn1/-/asn1-1.2.0.tgz" + "version" "1.2.0" + +"@ldapjs/asn1@^2.0.0", "@ldapjs/asn1@2.0.0": + "integrity" "sha512-G9+DkEOirNgdPmD0I8nu57ygQJKOOgFEMKknEuQvIHbGLwP3ny1mY+OTUYLCbCaGJP4sox5eYgBJRuSUpnAddA==" + "resolved" "https://registry.npmmirror.com/@ldapjs/asn1/-/asn1-2.0.0.tgz" + "version" "2.0.0" + +"@ldapjs/attribute@^1.0.0", "@ldapjs/attribute@1.0.0": + "integrity" "sha512-ptMl2d/5xJ0q+RgmnqOi3Zgwk/TMJYG7dYMC0Keko+yZU6n+oFM59MjQOUht5pxJeS4FWrImhu/LebX24vJNRQ==" + "resolved" "https://registry.npmmirror.com/@ldapjs/attribute/-/attribute-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "@ldapjs/asn1" "2.0.0" + "@ldapjs/protocol" "^1.2.1" + "process-warning" "^2.1.0" + +"@ldapjs/change@^1.0.0": + "integrity" "sha512-EOQNFH1RIku3M1s0OAJOzGfAohuFYXFY4s73wOhRm4KFGhmQQ7MChOh2YtYu9Kwgvuq1B0xKciXVzHCGkB5V+Q==" + "resolved" "https://registry.npmmirror.com/@ldapjs/change/-/change-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "@ldapjs/asn1" "2.0.0" + "@ldapjs/attribute" "1.0.0" + +"@ldapjs/controls@^2.1.0": + "integrity" "sha512-2pFdD1yRC9V9hXfAWvCCO2RRWK9OdIEcJIos/9cCVP9O4k72BY1bLDQQ4KpUoJnl4y/JoD4iFgM+YWT3IfITWw==" + "resolved" "https://registry.npmmirror.com/@ldapjs/controls/-/controls-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "@ldapjs/asn1" "^1.2.0" + "@ldapjs/protocol" "^1.2.1" + +"@ldapjs/dn@^1.1.0": + "integrity" "sha512-R72zH5ZeBj/Fujf/yBu78YzpJjJXG46YHFo5E4W1EqfNpo1UsVPqdLrRMXeKIsJT3x9dJVIfR6OpzgINlKpi0A==" + "resolved" "https://registry.npmmirror.com/@ldapjs/dn/-/dn-1.1.0.tgz" + "version" "1.1.0" + dependencies: + "@ldapjs/asn1" "2.0.0" + "process-warning" "^2.1.0" + +"@ldapjs/filter@^2.1.1": + "integrity" "sha512-TwPK5eEgNdUO1ABPBUQabcZ+h9heDORE4V9WNZqCtYLKc06+6+UAJ3IAbr0L0bYTnkkWC/JEQD2F+zAFsuikNw==" + "resolved" "https://registry.npmmirror.com/@ldapjs/filter/-/filter-2.1.1.tgz" + "version" "2.1.1" + dependencies: + "@ldapjs/asn1" "2.0.0" + "@ldapjs/protocol" "^1.2.1" + "process-warning" "^2.1.0" + +"@ldapjs/messages@^1.3.0": + "integrity" "sha512-K7xZpXJ21bj92jS35wtRbdcNrwmxAtPwy4myeh9duy/eR3xQKvikVycbdWVzkYEAVE5Ce520VXNOwCHjomjCZw==" + "resolved" "https://registry.npmmirror.com/@ldapjs/messages/-/messages-1.3.0.tgz" + "version" "1.3.0" + dependencies: + "@ldapjs/asn1" "^2.0.0" + "@ldapjs/attribute" "^1.0.0" + "@ldapjs/change" "^1.0.0" + "@ldapjs/controls" "^2.1.0" + "@ldapjs/dn" "^1.1.0" + "@ldapjs/filter" "^2.1.1" + "@ldapjs/protocol" "^1.2.1" + "process-warning" "^2.2.0" + +"@ldapjs/protocol@^1.2.1": + "integrity" "sha512-O89xFDLW2gBoZWNXuXpBSM32/KealKCTb3JGtJdtUQc7RjAk8XzrRgyz02cPAwGKwKPxy0ivuC7UP9bmN87egQ==" + "resolved" "https://registry.npmmirror.com/@ldapjs/protocol/-/protocol-1.2.1.tgz" + "version" "1.2.1" + +"abstract-logging@^2.0.1": + "integrity" "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==" + "resolved" "https://registry.npmmirror.com/abstract-logging/-/abstract-logging-2.0.1.tgz" + "version" "2.0.1" + +"accepts@~1.3.8": + "integrity" "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==" + "resolved" "https://registry.npmmirror.com/accepts/-/accepts-1.3.8.tgz" + "version" "1.3.8" + dependencies: + "mime-types" "~2.1.34" + "negotiator" "0.6.3" + +"array-flatten@1.1.1": + "integrity" "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + "resolved" "https://registry.npmmirror.com/array-flatten/-/array-flatten-1.1.1.tgz" + "version" "1.1.1" + +"assert-plus@^1.0.0": + "integrity" "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" + "resolved" "https://registry.npmmirror.com/assert-plus/-/assert-plus-1.0.0.tgz" + "version" "1.0.0" + +"backoff@^2.5.0": + "integrity" "sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA==" + "resolved" "https://registry.npmmirror.com/backoff/-/backoff-2.5.0.tgz" + "version" "2.5.0" + dependencies: + "precond" "0.2" + +"body-parser@~1.20.3": + "integrity" "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==" + "resolved" "https://registry.npmmirror.com/body-parser/-/body-parser-1.20.4.tgz" + "version" "1.20.4" + dependencies: + "bytes" "~3.1.2" + "content-type" "~1.0.5" + "debug" "2.6.9" + "depd" "2.0.0" + "destroy" "~1.2.0" + "http-errors" "~2.0.1" + "iconv-lite" "~0.4.24" + "on-finished" "~2.4.1" + "qs" "~6.14.0" + "raw-body" "~2.5.3" + "type-is" "~1.6.18" + "unpipe" "~1.0.0" + +"bytes@~3.1.2": + "integrity" "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + "resolved" "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz" + "version" "3.1.2" + +"call-bind-apply-helpers@^1.0.1", "call-bind-apply-helpers@^1.0.2": + "integrity" "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==" + "resolved" "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "es-errors" "^1.3.0" + "function-bind" "^1.1.2" + +"call-bound@^1.0.2": + "integrity" "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==" + "resolved" "https://registry.npmmirror.com/call-bound/-/call-bound-1.0.4.tgz" + "version" "1.0.4" + dependencies: + "call-bind-apply-helpers" "^1.0.2" + "get-intrinsic" "^1.3.0" + +"content-disposition@~0.5.4": + "integrity" "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==" + "resolved" "https://registry.npmmirror.com/content-disposition/-/content-disposition-0.5.4.tgz" + "version" "0.5.4" + dependencies: + "safe-buffer" "5.2.1" + +"content-type@~1.0.4", "content-type@~1.0.5": + "integrity" "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + "resolved" "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz" + "version" "1.0.5" + +"cookie-signature@~1.0.6": + "integrity" "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==" + "resolved" "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.0.7.tgz" + "version" "1.0.7" + +"cookie@~0.7.1": + "integrity" "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==" + "resolved" "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz" + "version" "0.7.2" + +"core-util-is@1.0.2": + "integrity" "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + "resolved" "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz" + "version" "1.0.2" + +"debug@2.6.9": + "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==" + "resolved" "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz" + "version" "2.6.9" + dependencies: + "ms" "2.0.0" + +"depd@~2.0.0", "depd@2.0.0": + "integrity" "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + "resolved" "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz" + "version" "2.0.0" + +"destroy@~1.2.0", "destroy@1.2.0": + "integrity" "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + "resolved" "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz" + "version" "1.2.0" + +"dotenv@^16.4.7": + "integrity" "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==" + "resolved" "https://registry.npmmirror.com/dotenv/-/dotenv-16.6.1.tgz" + "version" "16.6.1" + +"dunder-proto@^1.0.1": + "integrity" "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==" + "resolved" "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "call-bind-apply-helpers" "^1.0.1" + "es-errors" "^1.3.0" + "gopd" "^1.2.0" + +"ee-first@1.1.1": + "integrity" "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "resolved" "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz" + "version" "1.1.1" + +"encodeurl@~2.0.0": + "integrity" "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" + "resolved" "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz" + "version" "2.0.0" + +"es-define-property@^1.0.1": + "integrity" "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" + "resolved" "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz" + "version" "1.0.1" + +"es-errors@^1.3.0": + "integrity" "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + "resolved" "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz" + "version" "1.3.0" + +"es-object-atoms@^1.0.0", "es-object-atoms@^1.1.1": + "integrity" "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==" + "resolved" "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz" + "version" "1.1.1" + dependencies: + "es-errors" "^1.3.0" + +"escape-html@~1.0.3": + "integrity" "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "resolved" "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz" + "version" "1.0.3" + +"etag@~1.8.1": + "integrity" "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + "resolved" "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz" + "version" "1.8.1" + +"express@^4.21.2": + "integrity" "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==" + "resolved" "https://registry.npmmirror.com/express/-/express-4.22.1.tgz" + "version" "4.22.1" + dependencies: + "accepts" "~1.3.8" + "array-flatten" "1.1.1" + "body-parser" "~1.20.3" + "content-disposition" "~0.5.4" + "content-type" "~1.0.4" + "cookie" "~0.7.1" + "cookie-signature" "~1.0.6" + "debug" "2.6.9" + "depd" "2.0.0" + "encodeurl" "~2.0.0" + "escape-html" "~1.0.3" + "etag" "~1.8.1" + "finalhandler" "~1.3.1" + "fresh" "~0.5.2" + "http-errors" "~2.0.0" + "merge-descriptors" "1.0.3" + "methods" "~1.1.2" + "on-finished" "~2.4.1" + "parseurl" "~1.3.3" + "path-to-regexp" "~0.1.12" + "proxy-addr" "~2.0.7" + "qs" "~6.14.0" + "range-parser" "~1.2.1" + "safe-buffer" "5.2.1" + "send" "~0.19.0" + "serve-static" "~1.16.2" + "setprototypeof" "1.2.0" + "statuses" "~2.0.1" + "type-is" "~1.6.18" + "utils-merge" "1.0.1" + "vary" "~1.1.2" + +"extsprintf@^1.2.0": + "integrity" "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==" + "resolved" "https://registry.npmmirror.com/extsprintf/-/extsprintf-1.4.1.tgz" + "version" "1.4.1" + +"finalhandler@~1.3.1": + "integrity" "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==" + "resolved" "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.3.2.tgz" + "version" "1.3.2" + dependencies: + "debug" "2.6.9" + "encodeurl" "~2.0.0" + "escape-html" "~1.0.3" + "on-finished" "~2.4.1" + "parseurl" "~1.3.3" + "statuses" "~2.0.2" + "unpipe" "~1.0.0" + +"forwarded@0.2.0": + "integrity" "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + "resolved" "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz" + "version" "0.2.0" + +"fresh@~0.5.2": + "integrity" "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + "resolved" "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz" + "version" "0.5.2" + +"function-bind@^1.1.2": + "integrity" "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + "resolved" "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz" + "version" "1.1.2" + +"get-intrinsic@^1.2.5", "get-intrinsic@^1.3.0": + "integrity" "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==" + "resolved" "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz" + "version" "1.3.0" + dependencies: + "call-bind-apply-helpers" "^1.0.2" + "es-define-property" "^1.0.1" + "es-errors" "^1.3.0" + "es-object-atoms" "^1.1.1" + "function-bind" "^1.1.2" + "get-proto" "^1.0.1" + "gopd" "^1.2.0" + "has-symbols" "^1.1.0" + "hasown" "^2.0.2" + "math-intrinsics" "^1.1.0" + +"get-proto@^1.0.1": + "integrity" "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==" + "resolved" "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "dunder-proto" "^1.0.1" + "es-object-atoms" "^1.0.0" + +"gopd@^1.2.0": + "integrity" "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" + "resolved" "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz" + "version" "1.2.0" + +"has-symbols@^1.1.0": + "integrity" "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + "resolved" "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz" + "version" "1.1.0" + +"hasown@^2.0.2": + "integrity" "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==" + "resolved" "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "function-bind" "^1.1.2" + +"http-errors@~2.0.0", "http-errors@~2.0.1": + "integrity" "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==" + "resolved" "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "depd" "~2.0.0" + "inherits" "~2.0.4" + "setprototypeof" "~1.2.0" + "statuses" "~2.0.2" + "toidentifier" "~1.0.1" + +"iconv-lite@~0.4.24": + "integrity" "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==" + "resolved" "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz" + "version" "0.4.24" + dependencies: + "safer-buffer" ">= 2.1.2 < 3" + +"inherits@~2.0.4": + "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "resolved" "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz" + "version" "2.0.4" + +"ipaddr.js@1.9.1": + "integrity" "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + "resolved" "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz" + "version" "1.9.1" + +"ldapjs@^3.0.7": + "integrity" "sha512-1ky+WrN+4CFMuoekUOv7Y1037XWdjKpu0xAPwSP+9KdvmV9PG+qOKlssDV6a+U32apwxdD3is/BZcWOYzN30cg==" + "resolved" "https://registry.npmmirror.com/ldapjs/-/ldapjs-3.0.7.tgz" + "version" "3.0.7" + dependencies: + "@ldapjs/asn1" "^2.0.0" + "@ldapjs/attribute" "^1.0.0" + "@ldapjs/change" "^1.0.0" + "@ldapjs/controls" "^2.1.0" + "@ldapjs/dn" "^1.1.0" + "@ldapjs/filter" "^2.1.1" + "@ldapjs/messages" "^1.3.0" + "@ldapjs/protocol" "^1.2.1" + "abstract-logging" "^2.0.1" + "assert-plus" "^1.0.0" + "backoff" "^2.5.0" + "once" "^1.4.0" + "vasync" "^2.2.1" + "verror" "^1.10.1" + +"math-intrinsics@^1.1.0": + "integrity" "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + "resolved" "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz" + "version" "1.1.0" + +"media-typer@0.3.0": + "integrity" "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + "resolved" "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz" + "version" "0.3.0" + +"merge-descriptors@1.0.3": + "integrity" "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" + "resolved" "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz" + "version" "1.0.3" + +"methods@~1.1.2": + "integrity" "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + "resolved" "https://registry.npmmirror.com/methods/-/methods-1.1.2.tgz" + "version" "1.1.2" + +"mime-db@1.52.0": + "integrity" "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + "resolved" "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz" + "version" "1.52.0" + +"mime-types@~2.1.24", "mime-types@~2.1.34": + "integrity" "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==" + "resolved" "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz" + "version" "2.1.35" + dependencies: + "mime-db" "1.52.0" + +"mime@1.6.0": + "integrity" "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + "resolved" "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz" + "version" "1.6.0" + +"ms@2.0.0": + "integrity" "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "resolved" "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz" + "version" "2.0.0" + +"ms@2.1.3": + "integrity" "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "resolved" "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz" + "version" "2.1.3" + +"negotiator@0.6.3": + "integrity" "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + "resolved" "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz" + "version" "0.6.3" + +"object-inspect@^1.13.3": + "integrity" "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==" + "resolved" "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.4.tgz" + "version" "1.13.4" + +"on-finished@~2.4.1": + "integrity" "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==" + "resolved" "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz" + "version" "2.4.1" + dependencies: + "ee-first" "1.1.1" + +"once@^1.4.0": + "integrity" "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==" + "resolved" "https://registry.npmmirror.com/once/-/once-1.4.0.tgz" + "version" "1.4.0" + dependencies: + "wrappy" "1" + +"parseurl@~1.3.3": + "integrity" "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + "resolved" "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz" + "version" "1.3.3" + +"path-to-regexp@~0.1.12": + "integrity" "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" + "resolved" "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz" + "version" "0.1.12" + +"precond@0.2": + "integrity" "sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ==" + "resolved" "https://registry.npmmirror.com/precond/-/precond-0.2.3.tgz" + "version" "0.2.3" + +"process-warning@^2.1.0", "process-warning@^2.2.0": + "integrity" "sha512-n9wh8tvBe5sFmsqlg+XQhaQLumwpqoAUruLwjCopgTmUBjJ/fjtBsJzKleCaIGBOMXYEhp1YfKl4d7rJ5ZKJGA==" + "resolved" "https://registry.npmmirror.com/process-warning/-/process-warning-2.3.2.tgz" + "version" "2.3.2" + +"proxy-addr@~2.0.7": + "integrity" "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==" + "resolved" "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz" + "version" "2.0.7" + dependencies: + "forwarded" "0.2.0" + "ipaddr.js" "1.9.1" + +"qs@~6.14.0": + "integrity" "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==" + "resolved" "https://registry.npmmirror.com/qs/-/qs-6.14.1.tgz" + "version" "6.14.1" + dependencies: + "side-channel" "^1.1.0" + +"range-parser@~1.2.1": + "integrity" "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + "resolved" "https://registry.npmmirror.com/range-parser/-/range-parser-1.2.1.tgz" + "version" "1.2.1" + +"raw-body@~2.5.3": + "integrity" "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==" + "resolved" "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.3.tgz" + "version" "2.5.3" + dependencies: + "bytes" "~3.1.2" + "http-errors" "~2.0.1" + "iconv-lite" "~0.4.24" + "unpipe" "~1.0.0" + +"safe-buffer@5.2.1": + "integrity" "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "resolved" "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz" + "version" "5.2.1" + +"safer-buffer@>= 2.1.2 < 3": + "integrity" "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "resolved" "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz" + "version" "2.1.2" + +"send@~0.19.0", "send@~0.19.1": + "integrity" "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==" + "resolved" "https://registry.npmmirror.com/send/-/send-0.19.2.tgz" + "version" "0.19.2" + dependencies: + "debug" "2.6.9" + "depd" "2.0.0" + "destroy" "1.2.0" + "encodeurl" "~2.0.0" + "escape-html" "~1.0.3" + "etag" "~1.8.1" + "fresh" "~0.5.2" + "http-errors" "~2.0.1" + "mime" "1.6.0" + "ms" "2.1.3" + "on-finished" "~2.4.1" + "range-parser" "~1.2.1" + "statuses" "~2.0.2" + +"serve-static@~1.16.2": + "integrity" "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==" + "resolved" "https://registry.npmmirror.com/serve-static/-/serve-static-1.16.3.tgz" + "version" "1.16.3" + dependencies: + "encodeurl" "~2.0.0" + "escape-html" "~1.0.3" + "parseurl" "~1.3.3" + "send" "~0.19.1" + +"setprototypeof@~1.2.0", "setprototypeof@1.2.0": + "integrity" "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "resolved" "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz" + "version" "1.2.0" + +"side-channel-list@^1.0.0": + "integrity" "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==" + "resolved" "https://registry.npmmirror.com/side-channel-list/-/side-channel-list-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "es-errors" "^1.3.0" + "object-inspect" "^1.13.3" + +"side-channel-map@^1.0.1": + "integrity" "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==" + "resolved" "https://registry.npmmirror.com/side-channel-map/-/side-channel-map-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "call-bound" "^1.0.2" + "es-errors" "^1.3.0" + "get-intrinsic" "^1.2.5" + "object-inspect" "^1.13.3" + +"side-channel-weakmap@^1.0.2": + "integrity" "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==" + "resolved" "https://registry.npmmirror.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "call-bound" "^1.0.2" + "es-errors" "^1.3.0" + "get-intrinsic" "^1.2.5" + "object-inspect" "^1.13.3" + "side-channel-map" "^1.0.1" + +"side-channel@^1.1.0": + "integrity" "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==" + "resolved" "https://registry.npmmirror.com/side-channel/-/side-channel-1.1.0.tgz" + "version" "1.1.0" + dependencies: + "es-errors" "^1.3.0" + "object-inspect" "^1.13.3" + "side-channel-list" "^1.0.0" + "side-channel-map" "^1.0.1" + "side-channel-weakmap" "^1.0.2" + +"statuses@~2.0.1", "statuses@~2.0.2": + "integrity" "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==" + "resolved" "https://registry.npmmirror.com/statuses/-/statuses-2.0.2.tgz" + "version" "2.0.2" + +"toidentifier@~1.0.1": + "integrity" "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + "resolved" "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz" + "version" "1.0.1" + +"type-is@~1.6.18": + "integrity" "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==" + "resolved" "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz" + "version" "1.6.18" + dependencies: + "media-typer" "0.3.0" + "mime-types" "~2.1.24" + +"unpipe@~1.0.0": + "integrity" "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + "resolved" "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz" + "version" "1.0.0" + +"utils-merge@1.0.1": + "integrity" "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + "resolved" "https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz" + "version" "1.0.1" + +"vary@~1.1.2": + "integrity" "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + "resolved" "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz" + "version" "1.1.2" + +"vasync@^2.2.1": + "integrity" "sha512-Hq72JaTpcTFdWiNA4Y22Amej2GH3BFmBaKPPlDZ4/oC8HNn2ISHLkFrJU4Ds8R3jcUi7oo5Y9jcMHKjES+N9wQ==" + "resolved" "https://registry.npmmirror.com/vasync/-/vasync-2.2.1.tgz" + "version" "2.2.1" + dependencies: + "verror" "1.10.0" + +"verror@^1.10.1": + "integrity" "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==" + "resolved" "https://registry.npmmirror.com/verror/-/verror-1.10.1.tgz" + "version" "1.10.1" + dependencies: + "assert-plus" "^1.0.0" + "core-util-is" "1.0.2" + "extsprintf" "^1.2.0" + +"verror@1.10.0": + "integrity" "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==" + "resolved" "https://registry.npmmirror.com/verror/-/verror-1.10.0.tgz" + "version" "1.10.0" + dependencies: + "assert-plus" "^1.0.0" + "core-util-is" "1.0.2" + "extsprintf" "^1.2.0" + +"wrappy@1": + "integrity" "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "resolved" "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz" + "version" "1.0.2"