Files
iot-dc3/dc3-web/package.json
Henry ZhangandClaude Fable 5 7c643a8e80 fix(api): dc3-api contract overhaul (auth JWT, history, presence, decision enum) (#193)
* fix(api): correct inverted enable_flag comment and document time unit

- tenant.proto enable_flag comment said "1 enabled, 0 disabled" but the
  actual EnableFlagEnum is ENABLE=0, DISABLE=1 — callers reading the
  comment would invert the flag. Correct it.
- base.proto create_time/operate_time are epoch milliseconds
  (LocalDateTimeUtil/Instant.toEpochMilli); document the unit so callers
  don't guess seconds vs millis.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(api): carry timestamp in point-value history; explicit bool presence

#5 Point-value history: the whole chain (proto -> gRPC server ->
PointValueService -> repository -> facades -> controller -> agentic tool)
returned List<String> and dropped create_time even though the DB row
already carried it. Switch to PointValueBO / FacadePointValueBO end to
end so callers receive each value with its timestamp.

#6 Field presence: GrpcR.ok and McpIntrospectDTO.active are now optional
bool, so "unset" is distinguishable from false on the wire.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(auth): unify JWT signing key, drop salt/password from token contract

The JWT signing key was per-principal — securityKey + ":" + salt, where
salt was the credential salt also carried through the gateway and the
token RPC. That makes the JWT key weak and widens salt exposure to every
gateway hop. Sign with the single configured securityKey (HS256) instead
and remove salt from the JWT path entirely:

- KeyUtil.generateToken/parserToken drop the salt parameter; the HMAC
  key is now just securityKey (must be >= 32 bytes for HS256).
- TokenService.generateToken/checkValid drop the salt parameter.
- token.proto GrpcLoginQuery drops salt and password — CheckValid only
  ever needed tenant, name and token.
- gateway FilterService, TokenGrpcFacade, TokenController adapted; the
  request header no longer feeds salt into validation.

The login-handshake salt (POST /token/salt, used to salt the password
client-side before verifyPassword) is unchanged — only the JWT signing
salt is removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(api): type MCP authorize decision as proto enum

The authorize-tool-call decision was a free-form string, so callers
could only compare it against literals with no compile-time check.
Introduce GrpcMcpDecision (MCP_DECISION_UNSPECIFIED / AUTHORIZED /
CONFIRM_REQUIRED / REJECTED) and type GrpcMcpToolAuthorizeDTO.decision
with it. Enum names match the existing auth-side literals, so the
mapping is a direct valueOf / name().

- McpRuntimeServer builds the enum via toGrpcDecision (unknown -> UNSPECIFIED).
- McpRuntimeGrpcFacade maps enum -> BO string via name().
- gateway unchanged: it receives the BO (string decision) through the facade.

The other string MCP fields (risk_level, status, grant_type,
principal_type) stay strings for now — their value sets are wider and
partly lowercase (OAuth grant_type), so they are a follow-up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(facade): align TokenLocalFacade with 3-arg checkValid (CI compile fix)

TokenLocalFacade (local impl) was missed when TokenFacade.checkValid
dropped salt; CI compiles facade-local-auth independently and caught
it. Align it + its test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 16:36:35 +08:00

112 lines
3.4 KiB
JSON

{
"name": "iot-dc3-web",
"version": "2026.5.22",
"private": true,
"author": "pnoker",
"description": "IoT DC3 platform frontend — Vue 3 + TypeScript + Element Plus",
"license": "Apache-2.0",
"homepage": "https://github.com/pnoker/iot-dc3",
"repository": {
"type": "git",
"url": "https://github.com/pnoker/iot-dc3.git"
},
"keywords": [
"iot",
"dc3",
"web",
"vue3",
"typescript",
"element-plus"
],
"engines": {
"node": ">=22.0.0"
},
"packageManager": "pnpm@11.15.0",
"type": "module",
"scripts": {
"dev": "vite --host --mode dev",
"dev:prod": "vite --host --mode production",
"serve:e2e": "vite build --mode dev && node scripts/testing/e2e-server.mjs",
"build": "vite build",
"build:mock": "vite build --mode mock",
"preview": "vite preview",
"check": "vue-tsc --noEmit --skipLibCheck",
"type-check": "pnpm run check",
"lint": "eslint . --fix",
"lint:check": "eslint .",
"test": "vitest run",
"test:unit": "vitest run tests/unit",
"test:api": "vitest run tests/api",
"test:component": "vitest run tests/component",
"test:views": "vitest run tests/views",
"test:guard": "vitest run tests/guardrails",
"test:impact": "node scripts/testing/changed-test-plan.mjs",
"test:ci": "vitest run --coverage",
"test:coverage": "vitest run --coverage",
"test:e2e": "playwright test",
"test:e2e:headed": "E2E_HEADLESS=false playwright test",
"test:e2e:ui": "playwright test --ui",
"test:e2e:sweep": "node tests/e2e/browser-sweep.mjs",
"test:e2e:sweep:headed": "E2E_HEADLESS=false node tests/e2e/browser-sweep.mjs",
"test:all": "pnpm run test && pnpm run test:e2e",
"prepare": "cd .. && git config core.hooksPath .husky/_",
"clean": "rimraf dist"
},
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@antv/g2": "^5.4.8",
"@antv/g6": "^5.1.1",
"@element-plus/icons-vue": "^2.3.2",
"axios": "^1.18.1",
"dayjs": "^1.11.21",
"dompurify": "^3.4.12",
"element-plus": "^2.14.3",
"highlight.js": "^11.11.1",
"js-base64": "^3.9.1",
"js-cookie": "^3.0.8",
"json-bigint": "^1.0.0",
"marked": "^18.0.6",
"mitt": "^3.0.1",
"nprogress": "^0.2.0",
"pinia": "^4.0.2",
"vue": "^3.5.40",
"vue-element-plus-x": "^2.0.3",
"vue-i18n": "^11.4.6",
"vue-router": "^5.2.0"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@playwright/test": "^1.62.0",
"@types/js-cookie": "^3.0.6",
"@types/json-bigint": "^1.0.4",
"@types/node": "^26.1.1",
"@types/nprogress": "^0.2.3",
"@typescript-eslint/eslint-plugin": "^8.64.0",
"@typescript-eslint/parser": "^8.64.0",
"@vitejs/plugin-vue": "^6.0.8",
"@vitest/coverage-v8": "^4.1.10",
"@vue/eslint-config-typescript": "^14.9.0",
"@vue/test-utils": "^2.4.11",
"eslint": "^10.7.0",
"eslint-plugin-vue": "^10.10.0",
"globals": "^17.8.0",
"happy-dom": "^20.11.0",
"jsdom": "^30.0.1",
"lint-staged": "^17.1.0",
"playwright": "^1.61.1",
"sass": "^1.102.0",
"typescript": "~6.0.3",
"unplugin-auto-import": "^21.0.0",
"unplugin-vue-components": "^32.1.0",
"vite": "^8.1.5",
"vitest": "^4.1.10",
"vue-eslint-parser": "^10.4.1",
"vue-tsc": "^3.3.7"
},
"lint-staged": {
"*.{vue,js,mjs,cjs,ts,jsx,tsx}": [
"eslint --fix --config eslint.config.mjs"
]
}
}