@geoly-ai/social-hub-core 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/activity.d.ts +138 -0
- package/dist/activity.d.ts.map +1 -0
- package/dist/activity.js +577 -0
- package/dist/activity.js.map +1 -0
- package/dist/activity.test.d.ts +2 -0
- package/dist/activity.test.d.ts.map +1 -0
- package/dist/activity.test.js +430 -0
- package/dist/activity.test.js.map +1 -0
- package/dist/client-delivery-config.d.ts +26 -0
- package/dist/client-delivery-config.d.ts.map +1 -0
- package/dist/client-delivery-config.js +40 -0
- package/dist/client-delivery-config.js.map +1 -0
- package/dist/client-delivery-config.test.d.ts +2 -0
- package/dist/client-delivery-config.test.d.ts.map +1 -0
- package/dist/client-delivery-config.test.js +36 -0
- package/dist/client-delivery-config.test.js.map +1 -0
- package/dist/content-review-scoring.d.ts +67 -0
- package/dist/content-review-scoring.d.ts.map +1 -0
- package/dist/content-review-scoring.js +128 -0
- package/dist/content-review-scoring.js.map +1 -0
- package/dist/content-review-scoring.test.d.ts +2 -0
- package/dist/content-review-scoring.test.d.ts.map +1 -0
- package/dist/content-review-scoring.test.js +109 -0
- package/dist/content-review-scoring.test.js.map +1 -0
- package/dist/errors.d.ts +3 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +7 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/notification-sources/field-paths.d.ts +93 -0
- package/dist/notification-sources/field-paths.d.ts.map +1 -0
- package/dist/notification-sources/field-paths.js +86 -0
- package/dist/notification-sources/field-paths.js.map +1 -0
- package/dist/notification-sources/field-set.d.ts +46 -0
- package/dist/notification-sources/field-set.d.ts.map +1 -0
- package/dist/notification-sources/field-set.js +178 -0
- package/dist/notification-sources/field-set.js.map +1 -0
- package/dist/notification-sources/index.d.ts +13 -0
- package/dist/notification-sources/index.d.ts.map +1 -0
- package/dist/notification-sources/index.js +13 -0
- package/dist/notification-sources/index.js.map +1 -0
- package/dist/notification-sources/notification-sources.test.d.ts +2 -0
- package/dist/notification-sources/notification-sources.test.d.ts.map +1 -0
- package/dist/notification-sources/notification-sources.test.js +211 -0
- package/dist/notification-sources/notification-sources.test.js.map +1 -0
- package/dist/notification-sources/post-performance-node-runtime.d.ts +155 -0
- package/dist/notification-sources/post-performance-node-runtime.d.ts.map +1 -0
- package/dist/notification-sources/post-performance-node-runtime.js +158 -0
- package/dist/notification-sources/post-performance-node-runtime.js.map +1 -0
- package/dist/notification-sources/post-performance-node-runtime.test.d.ts +2 -0
- package/dist/notification-sources/post-performance-node-runtime.test.d.ts.map +1 -0
- package/dist/notification-sources/post-performance-node-runtime.test.js +182 -0
- package/dist/notification-sources/post-performance-node-runtime.test.js.map +1 -0
- package/dist/notification-sources/post-performance-node.d.ts +34 -0
- package/dist/notification-sources/post-performance-node.d.ts.map +1 -0
- package/dist/notification-sources/post-performance-node.js +437 -0
- package/dist/notification-sources/post-performance-node.js.map +1 -0
- package/dist/notification-sources/registry.d.ts +27 -0
- package/dist/notification-sources/registry.d.ts.map +1 -0
- package/dist/notification-sources/registry.js +222 -0
- package/dist/notification-sources/registry.js.map +1 -0
- package/dist/notification-sources/source-definition.d.ts +97 -0
- package/dist/notification-sources/source-definition.d.ts.map +1 -0
- package/dist/notification-sources/source-definition.js +30 -0
- package/dist/notification-sources/source-definition.js.map +1 -0
- package/dist/openclaw-config.d.ts +9 -0
- package/dist/openclaw-config.d.ts.map +1 -1
- package/dist/openclaw-config.js +17 -0
- package/dist/openclaw-config.js.map +1 -1
- package/dist/openclaw-config.test.d.ts +2 -0
- package/dist/openclaw-config.test.d.ts.map +1 -0
- package/dist/openclaw-config.test.js +49 -0
- package/dist/openclaw-config.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-review-scoring.d.ts","sourceRoot":"","sources":["../src/content-review-scoring.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,yBAAyB,GACjC,mBAAmB,GACnB,YAAY,GACZ,SAAS,GACT,eAAe,GACf,YAAY,GACZ,iBAAiB,CAAC;AAEtB,MAAM,MAAM,4BAA4B,GAAG,MAAM,CAC/C,yBAAyB,EACzB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CACpC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC,yBAAyB,EAAE,MAAM,CAAC,CAAC;IACnD,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,0BAA0B,EAAE,MAAM,CAAC;IACnC,0CAA0C;IAC1C,oBAAoB,EAAE,MAAM,CAAC;IAC7B,2BAA2B;IAC3B,wBAAwB,EAAE,MAAM,CAAC;CAClC,CAAC;AAEF,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAElD,eAAO,MAAM,6BAA6B,EAAE,mBAgB3C,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,UAAU,EAAE,4BAA4B,CAAC;IACzC,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,SAAS,EACL,sBAAsB,GACtB,6BAA6B,GAC7B,aAAa,GACb,cAAc,GACd,YAAY,CAAC;IACjB,iBAAiB,EAAE,8BAA8B,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,yBAAyB,EAAE,MAAM,CAAC,CAAC;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B,EAAE,MAAM,CAAC;IACnC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,sDAAsD;AACtD,wBAAgB,iCAAiC,CAC/C,MAAM,EAAE,mBAAmB,EAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACpB,8BAA8B,CAYhC;AAED,gDAAgD;AAChD,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,IAAI,GAAG,SAAS,GACxD,mBAAmB,CAUrB;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,uBAAuB,GAC7B,wBAAwB,CAiE1B;AAED;;;GAGG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,KAAK,GAAG,OAAO,GAAG,qBAAqB,CAAC;IAC9C,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAQF,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,MAAM,GACZ,0BAA0B,EAAE,CAS9B"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 内容复审的服务端计分与 verdict 判定(纯函数,权威口径)。
|
|
3
|
+
*
|
|
4
|
+
* LLM 只产出六维原始分与证据;综合分由这里按版本化权重计算,verdict 由
|
|
5
|
+
* precedence 规则判定——防止模型自报综合分漂移/越权(独立模型换代后分布
|
|
6
|
+
* 变化不影响阈值语义)。策略可整体替换(system_settings 覆盖默认),每次
|
|
7
|
+
* 复审记录 thresholdSnapshot 供金丝雀跨版本对比。
|
|
8
|
+
*/
|
|
9
|
+
export const CONTENT_REVIEW_RUBRIC_VERSION = "v1";
|
|
10
|
+
export const DEFAULT_CONTENT_REVIEW_POLICY = {
|
|
11
|
+
policyVersion: "v1",
|
|
12
|
+
weights: {
|
|
13
|
+
// 情境锚定权重最高(需求 §6):能原样贴到另外 50 个帖子下 = 不合格。
|
|
14
|
+
context_anchoring: 3,
|
|
15
|
+
burstiness: 1.5,
|
|
16
|
+
ai_tone: 2,
|
|
17
|
+
persona_voice: 1.5,
|
|
18
|
+
compliance: 1,
|
|
19
|
+
self_repetition: 1,
|
|
20
|
+
},
|
|
21
|
+
blockBelow: 55,
|
|
22
|
+
reviseBelow: 75,
|
|
23
|
+
contextAnchoringBlockBelow: 50,
|
|
24
|
+
complianceBlockBelow: 60,
|
|
25
|
+
quietStageThresholdBonus: 10,
|
|
26
|
+
};
|
|
27
|
+
/** 本次请求实际生效的策略快照(degraded/deterministic 分支也要完整留档)。 */
|
|
28
|
+
export function getContentReviewThresholdSnapshot(policy, stage) {
|
|
29
|
+
const stageBonus = stage === "静默期" ? policy.quietStageThresholdBonus : 0;
|
|
30
|
+
return {
|
|
31
|
+
policyVersion: policy.policyVersion,
|
|
32
|
+
weights: policy.weights,
|
|
33
|
+
blockBelow: policy.blockBelow + stageBonus,
|
|
34
|
+
reviseBelow: policy.reviseBelow + stageBonus,
|
|
35
|
+
contextAnchoringBlockBelow: policy.contextAnchoringBlockBelow + stageBonus,
|
|
36
|
+
complianceBlockBelow: policy.complianceBlockBelow + stageBonus,
|
|
37
|
+
stageBonusApplied: stageBonus,
|
|
38
|
+
stage: stage ?? null,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** system_settings 覆盖默认策略时的合并(部分覆盖,未给字段用默认)。 */
|
|
42
|
+
export function mergeContentReviewPolicy(override) {
|
|
43
|
+
if (!override)
|
|
44
|
+
return DEFAULT_CONTENT_REVIEW_POLICY;
|
|
45
|
+
return {
|
|
46
|
+
...DEFAULT_CONTENT_REVIEW_POLICY,
|
|
47
|
+
...override,
|
|
48
|
+
weights: {
|
|
49
|
+
...DEFAULT_CONTENT_REVIEW_POLICY.weights,
|
|
50
|
+
...(override.weights ?? {}),
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function scoreContentReview(input) {
|
|
55
|
+
const policy = input.policy ?? DEFAULT_CONTENT_REVIEW_POLICY;
|
|
56
|
+
const stageBonus = input.stage === "静默期" ? policy.quietStageThresholdBonus : 0;
|
|
57
|
+
const blockBelow = policy.blockBelow + stageBonus;
|
|
58
|
+
const reviseBelow = policy.reviseBelow + stageBonus;
|
|
59
|
+
const anchorBlockBelow = policy.contextAnchoringBlockBelow + stageBonus;
|
|
60
|
+
const complianceBlockBelow = policy.complianceBlockBelow + stageBonus;
|
|
61
|
+
const clamp = (n) => Math.max(0, Math.min(100, n));
|
|
62
|
+
let weightSum = 0;
|
|
63
|
+
let weighted = 0;
|
|
64
|
+
for (const [key, weight] of Object.entries(policy.weights)) {
|
|
65
|
+
weightSum += weight;
|
|
66
|
+
weighted += clamp(input.dimensions[key].score) * weight;
|
|
67
|
+
}
|
|
68
|
+
const computedScore = Math.round(weighted / (weightSum || 1));
|
|
69
|
+
// 与 deterministic/degraded 分支共用同一 snapshot 结构。
|
|
70
|
+
const thresholdSnapshot = getContentReviewThresholdSnapshot(policy, input.stage);
|
|
71
|
+
// Precedence: 合规红线 > 情境锚定一票否决 > 综合分阈值。
|
|
72
|
+
if (clamp(input.dimensions.compliance.score) < complianceBlockBelow) {
|
|
73
|
+
return {
|
|
74
|
+
verdict: "block",
|
|
75
|
+
computedScore,
|
|
76
|
+
decidedBy: "compliance_hard_fail",
|
|
77
|
+
thresholdSnapshot,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
if (clamp(input.dimensions.context_anchoring.score) < anchorBlockBelow) {
|
|
81
|
+
return {
|
|
82
|
+
verdict: "block",
|
|
83
|
+
computedScore,
|
|
84
|
+
decidedBy: "context_anchoring_hard_fail",
|
|
85
|
+
thresholdSnapshot,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (computedScore < blockBelow) {
|
|
89
|
+
return {
|
|
90
|
+
verdict: "block",
|
|
91
|
+
computedScore,
|
|
92
|
+
decidedBy: "score_block",
|
|
93
|
+
thresholdSnapshot,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (computedScore < reviseBelow) {
|
|
97
|
+
return {
|
|
98
|
+
verdict: "revise",
|
|
99
|
+
computedScore,
|
|
100
|
+
decidedBy: "score_revise",
|
|
101
|
+
thresholdSnapshot,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
verdict: "pass",
|
|
106
|
+
computedScore,
|
|
107
|
+
decidedBy: "score_pass",
|
|
108
|
+
thresholdSnapshot,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const URL_RE = /(https?:\/\/|www\.)[^\s)\]]+/i;
|
|
112
|
+
const EMAIL_RE = /[\w.+-]+@[\w-]+\.[a-z]{2,}/i;
|
|
113
|
+
// 站外联系引导:telegram/whatsapp/discord/dm me at 等
|
|
114
|
+
const SOLICITATION_RE = /\b(telegram|whatsapp|wechat|discord\.gg|dm me (?:at|on)|contact me (?:at|on))\b/i;
|
|
115
|
+
export function detectDeterministicComplianceHits(draft) {
|
|
116
|
+
const hits = [];
|
|
117
|
+
const url = draft.match(URL_RE);
|
|
118
|
+
if (url)
|
|
119
|
+
hits.push({ rule: "url", match: url[0] });
|
|
120
|
+
const email = draft.match(EMAIL_RE);
|
|
121
|
+
if (email)
|
|
122
|
+
hits.push({ rule: "email", match: email[0] });
|
|
123
|
+
const sol = draft.match(SOLICITATION_RE);
|
|
124
|
+
if (sol)
|
|
125
|
+
hits.push({ rule: "handle_solicitation", match: sol[0] });
|
|
126
|
+
return hits;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=content-review-scoring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-review-scoring.js","sourceRoot":"","sources":["../src/content-review-scoring.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-review-scoring.test.d.ts","sourceRoot":"","sources":["../src/content-review-scoring.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { DEFAULT_CONTENT_REVIEW_POLICY, detectDeterministicComplianceHits, scoreContentReview, } from "./content-review-scoring.js";
|
|
3
|
+
function dims(over = {}) {
|
|
4
|
+
const base = {
|
|
5
|
+
context_anchoring: 85,
|
|
6
|
+
burstiness: 85,
|
|
7
|
+
ai_tone: 85,
|
|
8
|
+
persona_voice: 85,
|
|
9
|
+
compliance: 95,
|
|
10
|
+
self_repetition: 90,
|
|
11
|
+
...over,
|
|
12
|
+
};
|
|
13
|
+
return Object.fromEntries(Object.entries(base).map(([k, score]) => [
|
|
14
|
+
k,
|
|
15
|
+
{ score, issues: [] },
|
|
16
|
+
]));
|
|
17
|
+
}
|
|
18
|
+
describe("scoreContentReview", () => {
|
|
19
|
+
it("passes a human-sounding contextual comment", () => {
|
|
20
|
+
const r = scoreContentReview({ dimensions: dims() });
|
|
21
|
+
expect(r.verdict).toBe("pass");
|
|
22
|
+
expect(r.decidedBy).toBe("score_pass");
|
|
23
|
+
expect(r.computedScore).toBeGreaterThanOrEqual(75);
|
|
24
|
+
});
|
|
25
|
+
it("blocks on compliance hard fail regardless of other scores", () => {
|
|
26
|
+
const r = scoreContentReview({ dimensions: dims({ compliance: 30 }) });
|
|
27
|
+
expect(r.verdict).toBe("block");
|
|
28
|
+
expect(r.decidedBy).toBe("compliance_hard_fail");
|
|
29
|
+
});
|
|
30
|
+
it("blocks on context anchoring hard fail (one-vote veto)", () => {
|
|
31
|
+
const r = scoreContentReview({
|
|
32
|
+
dimensions: dims({ context_anchoring: 40 }),
|
|
33
|
+
});
|
|
34
|
+
expect(r.verdict).toBe("block");
|
|
35
|
+
expect(r.decidedBy).toBe("context_anchoring_hard_fail");
|
|
36
|
+
});
|
|
37
|
+
it("revises mid-band scores", () => {
|
|
38
|
+
const r = scoreContentReview({
|
|
39
|
+
dimensions: dims({
|
|
40
|
+
ai_tone: 55,
|
|
41
|
+
burstiness: 60,
|
|
42
|
+
persona_voice: 60,
|
|
43
|
+
context_anchoring: 65,
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
expect(r.verdict).toBe("revise");
|
|
47
|
+
expect(r.decidedBy).toBe("score_revise");
|
|
48
|
+
});
|
|
49
|
+
it("blocks low overall scores", () => {
|
|
50
|
+
const r = scoreContentReview({
|
|
51
|
+
dimensions: dims({
|
|
52
|
+
ai_tone: 30,
|
|
53
|
+
burstiness: 30,
|
|
54
|
+
persona_voice: 30,
|
|
55
|
+
context_anchoring: 55,
|
|
56
|
+
self_repetition: 40,
|
|
57
|
+
}),
|
|
58
|
+
});
|
|
59
|
+
expect(r.verdict).toBe("block");
|
|
60
|
+
expect(r.decidedBy).toBe("score_block");
|
|
61
|
+
});
|
|
62
|
+
it("tightens thresholds for 静默期 accounts", () => {
|
|
63
|
+
const borderline = dims({
|
|
64
|
+
context_anchoring: 76,
|
|
65
|
+
ai_tone: 76,
|
|
66
|
+
burstiness: 76,
|
|
67
|
+
persona_voice: 76,
|
|
68
|
+
compliance: 80,
|
|
69
|
+
self_repetition: 76,
|
|
70
|
+
});
|
|
71
|
+
const normal = scoreContentReview({
|
|
72
|
+
dimensions: borderline,
|
|
73
|
+
stage: "互动期",
|
|
74
|
+
});
|
|
75
|
+
const quiet = scoreContentReview({
|
|
76
|
+
dimensions: borderline,
|
|
77
|
+
stage: "静默期",
|
|
78
|
+
});
|
|
79
|
+
expect(normal.verdict).toBe("pass");
|
|
80
|
+
expect(quiet.verdict).toBe("revise");
|
|
81
|
+
expect(quiet.thresholdSnapshot.stageBonusApplied).toBe(DEFAULT_CONTENT_REVIEW_POLICY.quietStageThresholdBonus);
|
|
82
|
+
});
|
|
83
|
+
it("records the effective policy snapshot", () => {
|
|
84
|
+
const r = scoreContentReview({ dimensions: dims() });
|
|
85
|
+
expect(r.thresholdSnapshot.policyVersion).toBe("v1");
|
|
86
|
+
expect(r.thresholdSnapshot.blockBelow).toBe(55);
|
|
87
|
+
});
|
|
88
|
+
it("weights context anchoring heaviest", () => {
|
|
89
|
+
const anchorLow = scoreContentReview({
|
|
90
|
+
dimensions: dims({ context_anchoring: 55 }),
|
|
91
|
+
}).computedScore;
|
|
92
|
+
const toneLow = scoreContentReview({
|
|
93
|
+
dimensions: dims({ burstiness: 55 }),
|
|
94
|
+
}).computedScore;
|
|
95
|
+
expect(anchorLow).toBeLessThan(toneLow);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe("detectDeterministicComplianceHits", () => {
|
|
99
|
+
it("flags urls, emails and off-platform solicitation", () => {
|
|
100
|
+
expect(detectDeterministicComplianceHits("check https://example.com/promo")).toEqual([{ rule: "url", match: "https://example.com/promo" }]);
|
|
101
|
+
expect(detectDeterministicComplianceHits("mail me sales@brand.com")).toEqual([{ rule: "email", match: "sales@brand.com" }]);
|
|
102
|
+
expect(detectDeterministicComplianceHits("dm me on telegram for a deal")[0]
|
|
103
|
+
?.rule).toBe("handle_solicitation");
|
|
104
|
+
});
|
|
105
|
+
it("does not flag plain human comments", () => {
|
|
106
|
+
expect(detectDeterministicComplianceHits("ran the 9700x on a b650 board for 6 months, zero whea errors after the agesa update")).toEqual([]);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
//# sourceMappingURL=content-review-scoring.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-review-scoring.test.js","sourceRoot":"","sources":["../src/content-review-scoring.test.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -11,5 +11,8 @@ export declare function tooManyRequests(message?: string): AppError;
|
|
|
11
11
|
export declare function unauthorized(message?: string): AppError;
|
|
12
12
|
export declare function forbidden(message?: string): AppError;
|
|
13
13
|
export declare function notFound(message?: string): AppError;
|
|
14
|
+
/** 语义上无法处理的请求(字段互相矛盾等),区别于 400 的"格式不对"。 */
|
|
15
|
+
export declare function unprocessable(message?: string): AppError;
|
|
16
|
+
export declare function conflict(message?: string, details?: unknown): AppError;
|
|
14
17
|
export declare function internalError(message?: string): AppError;
|
|
15
18
|
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,qBAAa,QAAS,SAAQ,KAAK;aAEf,IAAI,EAAE,MAAM;aACZ,UAAU,EAAE,MAAM;aAElB,OAAO,CAAC,EAAE,OAAO;gBAHjB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClC,OAAO,EAAE,MAAM,EACC,OAAO,CAAC,EAAE,OAAO,YAAA;CAKpC;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAE5E;AAED,wBAAgB,UAAU,CAAC,OAAO,SAAgB,GAAG,QAAQ,CAE5D;AAED,wBAAgB,eAAe,CAAC,OAAO,SAAsB,GAAG,QAAQ,CAEvE;AAED,wBAAgB,YAAY,CAAC,OAAO,SAAiB,GAAG,QAAQ,CAE/D;AAED,wBAAgB,SAAS,CAAC,OAAO,SAAc,GAAG,QAAQ,CAEzD;AAED,wBAAgB,QAAQ,CAAC,OAAO,SAAc,GAAG,QAAQ,CAExD;AAED,wBAAgB,aAAa,CAAC,OAAO,SAAmB,GAAG,QAAQ,CAElE"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,qBAAa,QAAS,SAAQ,KAAK;aAEf,IAAI,EAAE,MAAM;aACZ,UAAU,EAAE,MAAM;aAElB,OAAO,CAAC,EAAE,OAAO;gBAHjB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClC,OAAO,EAAE,MAAM,EACC,OAAO,CAAC,EAAE,OAAO,YAAA;CAKpC;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAE5E;AAED,wBAAgB,UAAU,CAAC,OAAO,SAAgB,GAAG,QAAQ,CAE5D;AAED,wBAAgB,eAAe,CAAC,OAAO,SAAsB,GAAG,QAAQ,CAEvE;AAED,wBAAgB,YAAY,CAAC,OAAO,SAAiB,GAAG,QAAQ,CAE/D;AAED,wBAAgB,SAAS,CAAC,OAAO,SAAc,GAAG,QAAQ,CAEzD;AAED,wBAAgB,QAAQ,CAAC,OAAO,SAAc,GAAG,QAAQ,CAExD;AAED,2CAA2C;AAC3C,wBAAgB,aAAa,CAAC,OAAO,SAAyB,GAAG,QAAQ,CAExE;AAED,wBAAgB,QAAQ,CAAC,OAAO,SAAa,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAE1E;AAED,wBAAgB,aAAa,CAAC,OAAO,SAAmB,GAAG,QAAQ,CAElE"}
|
package/dist/errors.js
CHANGED
|
@@ -29,6 +29,13 @@ export function forbidden(message = "Forbidden") {
|
|
|
29
29
|
export function notFound(message = "Not found") {
|
|
30
30
|
return new AppError("NOT_FOUND", 404, message);
|
|
31
31
|
}
|
|
32
|
+
/** 语义上无法处理的请求(字段互相矛盾等),区别于 400 的"格式不对"。 */
|
|
33
|
+
export function unprocessable(message = "Unprocessable entity") {
|
|
34
|
+
return new AppError("UNPROCESSABLE_ENTITY", 422, message);
|
|
35
|
+
}
|
|
36
|
+
export function conflict(message = "Conflict", details) {
|
|
37
|
+
return new AppError("CONFLICT", 409, message, details);
|
|
38
|
+
}
|
|
32
39
|
export function internalError(message = "Internal error") {
|
|
33
40
|
return new AppError("INTERNAL_ERROR", 500, message);
|
|
34
41
|
}
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEf;IACA;IAEA;IAJlB,YACkB,IAAY,EACZ,UAAkB,EAClC,OAAe,EACC,OAAiB;QAEjC,KAAK,CAAC,OAAO,CAAC,CAAC;QALC,SAAI,GAAJ,IAAI,CAAQ;QACZ,eAAU,GAAV,UAAU,CAAQ;QAElB,YAAO,GAAP,OAAO,CAAU;QAGjC,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,OAAiB;IAChE,OAAO,IAAI,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAO,GAAG,aAAa;IAChD,OAAO,IAAI,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAO,GAAG,mBAAmB;IAC3D,OAAO,IAAI,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAO,GAAG,cAAc;IACnD,OAAO,IAAI,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAO,GAAG,WAAW;IAC7C,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,OAAO,GAAG,WAAW;IAC5C,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAO,GAAG,gBAAgB;IACtD,OAAO,IAAI,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AACtD,CAAC"}
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEf;IACA;IAEA;IAJlB,YACkB,IAAY,EACZ,UAAkB,EAClC,OAAe,EACC,OAAiB;QAEjC,KAAK,CAAC,OAAO,CAAC,CAAC;QALC,SAAI,GAAJ,IAAI,CAAQ;QACZ,eAAU,GAAV,UAAU,CAAQ;QAElB,YAAO,GAAP,OAAO,CAAU;QAGjC,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,OAAiB;IAChE,OAAO,IAAI,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAO,GAAG,aAAa;IAChD,OAAO,IAAI,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAO,GAAG,mBAAmB;IAC3D,OAAO,IAAI,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAO,GAAG,cAAc;IACnD,OAAO,IAAI,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAO,GAAG,WAAW;IAC7C,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,OAAO,GAAG,WAAW;IAC5C,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AACjD,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,aAAa,CAAC,OAAO,GAAG,sBAAsB;IAC5D,OAAO,IAAI,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,OAAO,GAAG,UAAU,EAAE,OAAiB;IAC9D,OAAO,IAAI,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAO,GAAG,gBAAgB;IACtD,OAAO,IAAI,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AACtD,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,4 +3,8 @@ export * from "./graph-domain.js";
|
|
|
3
3
|
export * from "./errors.js";
|
|
4
4
|
export * from "./reddit-topic-taxonomy.js";
|
|
5
5
|
export * from "./openclaw-config.js";
|
|
6
|
+
export * from "./client-delivery-config.js";
|
|
7
|
+
export * from "./content-review-scoring.js";
|
|
8
|
+
export * from "./activity.js";
|
|
9
|
+
export * from "./notification-sources/index.js";
|
|
6
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,eAAe,CAAC;AAG9B,cAAc,iCAAiC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,4 +3,10 @@ export * from "./graph-domain.js";
|
|
|
3
3
|
export * from "./errors.js";
|
|
4
4
|
export * from "./reddit-topic-taxonomy.js";
|
|
5
5
|
export * from "./openclaw-config.js";
|
|
6
|
+
export * from "./client-delivery-config.js";
|
|
7
|
+
export * from "./content-review-scoring.js";
|
|
8
|
+
export * from "./activity.js";
|
|
9
|
+
// 事件订阅通知能力:registry 是 db/worker/api 的暴露面推导单点,必须能跨包 import。
|
|
10
|
+
// core 的 exports map 只有 ".",没有 subpath,故在此 re-export(零依赖纯 TS,不引 node:*)。
|
|
11
|
+
export * from "./notification-sources/index.js";
|
|
6
12
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,eAAe,CAAC;AAC9B,2DAA2D;AAC3D,yEAAyE;AACzE,cAAc,iCAAiC,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 事件订阅通知能力 —— Block 0:字段路径原语(代码侧 source registry 的地基)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么放 `packages/core` 而不是 contracts:
|
|
5
|
+
* - 本文件是**纯 TS、零依赖**(core 没有 zod、没有 node:crypto),registry 框架要能被
|
|
6
|
+
* db / worker / api 直接引用做「暴露面推导」,不该被 zod 绑架。
|
|
7
|
+
* - contracts 侧(`packages/contracts/src/notifications.ts`)只负责 **wire 形状**(zod)。
|
|
8
|
+
* 两边各自 pin 同一份叶子路径清单,跨包一致性检查留给集成块(见设计文档 §12 验收点 A-38)。
|
|
9
|
+
*
|
|
10
|
+
* 铁律:字段路径是**开发者声明的 schema identifier**,不是用户输入。因此不做 trim /
|
|
11
|
+
* lowercase / NFKC 归一化——任何大小写或空白差异一律视为「未知字段」直接拒绝,
|
|
12
|
+
* 避免「后台保存的是 A、实际 hash 的是 B」。
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* 受限字段路径语法:ASCII 点号叶子路径,segment 必须小写字母开头 + 字母数字。
|
|
16
|
+
* 明确**不**支持:转义、索引(`a.0.b`)、非 ASCII、空 segment。
|
|
17
|
+
* 数组整体即叶子(如 `trigger.supersededNodes`),永不产生索引路径。
|
|
18
|
+
*/
|
|
19
|
+
export declare const NOTIFICATION_FIELD_PATH_PATTERN: RegExp;
|
|
20
|
+
export declare function isNotificationFieldPath(value: unknown): value is string;
|
|
21
|
+
/**
|
|
22
|
+
* 字段路径排序 comparator。
|
|
23
|
+
*
|
|
24
|
+
* ⚠️ 规范冻结为「按 **ASCII 字节字典序** 升序」,而不是含糊的「JS 默认排序」——
|
|
25
|
+
* JS 的 `<` 比较严格说是 UTF-16 code unit 序,与 code point 序在 BMP 外不一致。
|
|
26
|
+
* 由于路径语法已限制为 ASCII,三者在本域内结果相同;显式写出来是为了让
|
|
27
|
+
* 其它语言/其它层(SQL、Go agent)能一字不差地复现 fieldSetVersion。
|
|
28
|
+
*/
|
|
29
|
+
export declare function compareNotificationFieldPaths(left: string, right: string): 0 | 1 | -1;
|
|
30
|
+
/** 排序(不去重、不校验;调用方负责先 assert)。返回新数组。 */
|
|
31
|
+
export declare function sortNotificationFieldPaths(paths: readonly string[]): readonly string[];
|
|
32
|
+
/**
|
|
33
|
+
* 单条事件的触发形态(定义在本文件是为了让 {@link NotificationFieldDefinition.variants}
|
|
34
|
+
* 能强类型引用而不与 source-definition.ts 形成循环 import)。
|
|
35
|
+
* - `scheduled_node`:正常到点。
|
|
36
|
+
* - `catchup`:一次 overdue 折叠(多个错过的节点塌缩成一条,见设计文档 §7)。
|
|
37
|
+
*/
|
|
38
|
+
export declare const NOTIFICATION_TRIGGER_MODES: readonly ["scheduled_node", "catchup"];
|
|
39
|
+
export type NotificationTriggerMode = (typeof NOTIFICATION_TRIGGER_MODES)[number];
|
|
40
|
+
/** 字段敏感度。后台**永远不能**改这个值——它是代码侧声明的暴露面等级。 */
|
|
41
|
+
export declare const NOTIFICATION_FIELD_SENSITIVITIES: readonly ["public", "internal", "restricted"];
|
|
42
|
+
export type NotificationFieldSensitivity = (typeof NOTIFICATION_FIELD_SENSITIVITIES)[number];
|
|
43
|
+
/**
|
|
44
|
+
* 字段值形态(供后台展示与 agent 解析用;不是 zod 类型,wire 校验在 contracts)。
|
|
45
|
+
* `stringArray` 是「数组整体作为叶子」的唯一合法形态。
|
|
46
|
+
*/
|
|
47
|
+
export declare const NOTIFICATION_FIELD_VALUE_KINDS: readonly ["string", "uuid", "url", "datetime", "integer", "ratio", "enum", "stringArray"];
|
|
48
|
+
export type NotificationFieldValueKind = (typeof NOTIFICATION_FIELD_VALUE_KINDS)[number];
|
|
49
|
+
/**
|
|
50
|
+
* 单条 authz 需求。语义**恒为 AND**(一个字段声明多条 = 全部满足才可选/可发)。
|
|
51
|
+
* 不允许 OR——OR 会让「谁能看到什么」在不同调用方被解释成不同结果。
|
|
52
|
+
*/
|
|
53
|
+
export interface NotificationFieldPermission {
|
|
54
|
+
readonly resource: string;
|
|
55
|
+
readonly action: "list" | "read";
|
|
56
|
+
}
|
|
57
|
+
/** 便于书写与日志展示的 `resource:action` 串。 */
|
|
58
|
+
export declare function formatNotificationFieldPermission(permission: NotificationFieldPermission): string;
|
|
59
|
+
/**
|
|
60
|
+
* 字段声明(代码侧唯一真源;改任何一项都必须 bump sourceDefinitionVersion,
|
|
61
|
+
* 改 `valueKind`/`nullable` 还必须 bump payloadSchemaVersion)。
|
|
62
|
+
*/
|
|
63
|
+
export interface NotificationFieldDefinition {
|
|
64
|
+
/** 叶子路径,必须匹配 {@link NOTIFICATION_FIELD_PATH_PATTERN}。 */
|
|
65
|
+
readonly path: string;
|
|
66
|
+
readonly sensitivity: NotificationFieldSensitivity;
|
|
67
|
+
readonly valueKind: NotificationFieldValueKind;
|
|
68
|
+
/**
|
|
69
|
+
* true = 字段被选中后即使数据不可得也**必定出现**、值为 `null`
|
|
70
|
+
*(区别于「未选中 → key 完全不出现」)。
|
|
71
|
+
* 这是「browserEnvironment 解析不到仍然发事件」的表达方式。
|
|
72
|
+
*/
|
|
73
|
+
readonly nullable: boolean;
|
|
74
|
+
/** AND 语义;空数组 = 只要能读该 subscription 即可见。 */
|
|
75
|
+
readonly requiredPermissions: readonly NotificationFieldPermission[];
|
|
76
|
+
/**
|
|
77
|
+
* 字段依赖:选中本字段则**自动补入**这些字段(依赖闭包),
|
|
78
|
+
* 保证「有值但无法判断值的观测时间/来源」这类不可解释的暴露不会发生。
|
|
79
|
+
*/
|
|
80
|
+
readonly requires?: readonly string[];
|
|
81
|
+
/**
|
|
82
|
+
* 仅对这些 trigger variant 有意义(省略 = **所有** variant)。
|
|
83
|
+
* catchup 专属字段(winnerScheduleId 等)用它标注,避免污染正常节点事件。
|
|
84
|
+
* 强类型 + registry 自检双重把关:拼错成 `"catcup"` 会让字段进了 configuredFields
|
|
85
|
+
* 却在所有 variant 事件里消失(静默丢字段),必须在声明期就炸掉。
|
|
86
|
+
*/
|
|
87
|
+
readonly variants?: readonly NotificationTriggerMode[];
|
|
88
|
+
/** 后台展示用中文说明。 */
|
|
89
|
+
readonly description: string;
|
|
90
|
+
}
|
|
91
|
+
/** 建索引,供 O(1) 查找与未知路径拒绝。 */
|
|
92
|
+
export declare function indexNotificationFields(fields: readonly NotificationFieldDefinition[]): ReadonlyMap<string, NotificationFieldDefinition>;
|
|
93
|
+
//# sourceMappingURL=field-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-paths.d.ts","sourceRoot":"","sources":["../../src/notification-sources/field-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,QACG,CAAC;AAEhD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAIvE;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,cAExE;AAED,uCAAuC;AACvC,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,SAAS,MAAM,EAAE,CAEnB;AAED;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,wCAG7B,CAAC;AACX,MAAM,MAAM,uBAAuB,GACjC,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9C,2CAA2C;AAC3C,eAAO,MAAM,gCAAgC,+CAInC,CAAC;AACX,MAAM,MAAM,4BAA4B,GACtC,CAAC,OAAO,gCAAgC,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpD;;;GAGG;AACH,eAAO,MAAM,8BAA8B,2FASjC,CAAC;AACX,MAAM,MAAM,0BAA0B,GACpC,CAAC,OAAO,8BAA8B,CAAC,CAAC,MAAM,CAAC,CAAC;AAElD;;;GAGG;AACH,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CAClC;AAED,sCAAsC;AACtC,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,2BAA2B,GACtC,MAAM,CAER;AAED;;;GAGG;AACH,MAAM,WAAW,2BAA2B;IAC1C,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,4BAA4B,CAAC;IACnD,QAAQ,CAAC,SAAS,EAAE,0BAA0B,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,2CAA2C;IAC3C,QAAQ,CAAC,mBAAmB,EAAE,SAAS,2BAA2B,EAAE,CAAC;IACrE;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACvD,iBAAiB;IACjB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,4BAA4B;AAC5B,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,2BAA2B,EAAE,GAC7C,WAAW,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAYlD"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 事件订阅通知能力 —— Block 0:字段路径原语(代码侧 source registry 的地基)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么放 `packages/core` 而不是 contracts:
|
|
5
|
+
* - 本文件是**纯 TS、零依赖**(core 没有 zod、没有 node:crypto),registry 框架要能被
|
|
6
|
+
* db / worker / api 直接引用做「暴露面推导」,不该被 zod 绑架。
|
|
7
|
+
* - contracts 侧(`packages/contracts/src/notifications.ts`)只负责 **wire 形状**(zod)。
|
|
8
|
+
* 两边各自 pin 同一份叶子路径清单,跨包一致性检查留给集成块(见设计文档 §12 验收点 A-38)。
|
|
9
|
+
*
|
|
10
|
+
* 铁律:字段路径是**开发者声明的 schema identifier**,不是用户输入。因此不做 trim /
|
|
11
|
+
* lowercase / NFKC 归一化——任何大小写或空白差异一律视为「未知字段」直接拒绝,
|
|
12
|
+
* 避免「后台保存的是 A、实际 hash 的是 B」。
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* 受限字段路径语法:ASCII 点号叶子路径,segment 必须小写字母开头 + 字母数字。
|
|
16
|
+
* 明确**不**支持:转义、索引(`a.0.b`)、非 ASCII、空 segment。
|
|
17
|
+
* 数组整体即叶子(如 `trigger.supersededNodes`),永不产生索引路径。
|
|
18
|
+
*/
|
|
19
|
+
export const NOTIFICATION_FIELD_PATH_PATTERN = /^[a-z][A-Za-z0-9]*(?:\.[a-z][A-Za-z0-9]*)*$/;
|
|
20
|
+
export function isNotificationFieldPath(value) {
|
|
21
|
+
return (typeof value === "string" && NOTIFICATION_FIELD_PATH_PATTERN.test(value));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 字段路径排序 comparator。
|
|
25
|
+
*
|
|
26
|
+
* ⚠️ 规范冻结为「按 **ASCII 字节字典序** 升序」,而不是含糊的「JS 默认排序」——
|
|
27
|
+
* JS 的 `<` 比较严格说是 UTF-16 code unit 序,与 code point 序在 BMP 外不一致。
|
|
28
|
+
* 由于路径语法已限制为 ASCII,三者在本域内结果相同;显式写出来是为了让
|
|
29
|
+
* 其它语言/其它层(SQL、Go agent)能一字不差地复现 fieldSetVersion。
|
|
30
|
+
*/
|
|
31
|
+
export function compareNotificationFieldPaths(left, right) {
|
|
32
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
33
|
+
}
|
|
34
|
+
/** 排序(不去重、不校验;调用方负责先 assert)。返回新数组。 */
|
|
35
|
+
export function sortNotificationFieldPaths(paths) {
|
|
36
|
+
return [...paths].sort(compareNotificationFieldPaths);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 单条事件的触发形态(定义在本文件是为了让 {@link NotificationFieldDefinition.variants}
|
|
40
|
+
* 能强类型引用而不与 source-definition.ts 形成循环 import)。
|
|
41
|
+
* - `scheduled_node`:正常到点。
|
|
42
|
+
* - `catchup`:一次 overdue 折叠(多个错过的节点塌缩成一条,见设计文档 §7)。
|
|
43
|
+
*/
|
|
44
|
+
export const NOTIFICATION_TRIGGER_MODES = [
|
|
45
|
+
"scheduled_node",
|
|
46
|
+
"catchup",
|
|
47
|
+
];
|
|
48
|
+
/** 字段敏感度。后台**永远不能**改这个值——它是代码侧声明的暴露面等级。 */
|
|
49
|
+
export const NOTIFICATION_FIELD_SENSITIVITIES = [
|
|
50
|
+
"public",
|
|
51
|
+
"internal",
|
|
52
|
+
"restricted",
|
|
53
|
+
];
|
|
54
|
+
/**
|
|
55
|
+
* 字段值形态(供后台展示与 agent 解析用;不是 zod 类型,wire 校验在 contracts)。
|
|
56
|
+
* `stringArray` 是「数组整体作为叶子」的唯一合法形态。
|
|
57
|
+
*/
|
|
58
|
+
export const NOTIFICATION_FIELD_VALUE_KINDS = [
|
|
59
|
+
"string",
|
|
60
|
+
"uuid",
|
|
61
|
+
"url",
|
|
62
|
+
"datetime",
|
|
63
|
+
"integer",
|
|
64
|
+
"ratio",
|
|
65
|
+
"enum",
|
|
66
|
+
"stringArray",
|
|
67
|
+
];
|
|
68
|
+
/** 便于书写与日志展示的 `resource:action` 串。 */
|
|
69
|
+
export function formatNotificationFieldPermission(permission) {
|
|
70
|
+
return `${permission.resource}:${permission.action}`;
|
|
71
|
+
}
|
|
72
|
+
/** 建索引,供 O(1) 查找与未知路径拒绝。 */
|
|
73
|
+
export function indexNotificationFields(fields) {
|
|
74
|
+
const map = new Map();
|
|
75
|
+
for (const field of fields) {
|
|
76
|
+
if (!isNotificationFieldPath(field.path)) {
|
|
77
|
+
throw new Error(`invalid notification field path: ${field.path}`);
|
|
78
|
+
}
|
|
79
|
+
if (map.has(field.path)) {
|
|
80
|
+
throw new Error(`duplicate notification field path: ${field.path}`);
|
|
81
|
+
}
|
|
82
|
+
map.set(field.path, field);
|
|
83
|
+
}
|
|
84
|
+
return map;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=field-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-paths.js","sourceRoot":"","sources":["../../src/notification-sources/field-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAC1C,6CAA6C,CAAC;AAEhD,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ,IAAI,+BAA+B,CAAC,IAAI,CAAC,KAAK,CAAC,CACzE,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,6BAA6B,CAAC,IAAY,EAAE,KAAa;IACvE,OAAO,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,0BAA0B,CACxC,KAAwB;IAExB,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,gBAAgB;IAChB,SAAS;CACD,CAAC;AAIX,2CAA2C;AAC3C,MAAM,CAAC,MAAM,gCAAgC,GAAG;IAC9C,QAAQ;IACR,UAAU;IACV,YAAY;CACJ,CAAC;AAIX;;;GAGG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC5C,QAAQ;IACR,MAAM;IACN,KAAK;IACL,UAAU;IACV,SAAS;IACT,OAAO;IACP,MAAM;IACN,aAAa;CACL,CAAC;AAaX,sCAAsC;AACtC,MAAM,UAAU,iCAAiC,CAC/C,UAAuC;IAEvC,OAAO,GAAG,UAAU,CAAC,QAAQ,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;AACvD,CAAC;AAmCD,4BAA4B;AAC5B,MAAM,UAAU,uBAAuB,CACrC,MAA8C;IAE9C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAuC,CAAC;IAC3D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,uBAAuB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,oCAAoC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,sCAAsC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACtE,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 事件订阅通知能力 —— Block 0:字段集推导(暴露面的唯一计算入口)。
|
|
3
|
+
*
|
|
4
|
+
* 三个身份必须分清(Codex 复审 P0-1,设计文档 §5):
|
|
5
|
+
*
|
|
6
|
+
* configuredFields = 该 config **允许输出**的字段全集
|
|
7
|
+
* = commonRequired ∪ 全部 variantRequired ∪ selectedOptional ∪ 依赖闭包
|
|
8
|
+
* fieldSetVersion = sha256(canonical(configuredFields)) ← **配置级暴露政策身份**
|
|
9
|
+
* includedFields = 某条**具体事件**实际含有的叶子字段集合(⊆ configuredFields)
|
|
10
|
+
*
|
|
11
|
+
* 为什么 fieldSetVersion 不等于每条事件的 includedFields hash:catchup 事件比正常节点
|
|
12
|
+
* 多带折叠身份字段,若强求相等,同一份 config 就要有两个 fieldSetVersion,
|
|
13
|
+
* DTO 与 DB 都得双份。分开后 catchup / 字段依赖 / 配置切换的语义才自洽。
|
|
14
|
+
*/
|
|
15
|
+
import { type NotificationFieldDefinition, type NotificationTriggerMode } from "./field-paths.js";
|
|
16
|
+
import type { NodeEventSourceDefinition } from "./source-definition.js";
|
|
17
|
+
export declare class NotificationFieldSetError extends Error {
|
|
18
|
+
readonly reason: "unknown_field" | "duplicate_field" | "required_field_selected" | "required_field_not_declared" | "empty_field_set" | "configured_set_not_closed";
|
|
19
|
+
constructor(reason: "unknown_field" | "duplicate_field" | "required_field_selected" | "required_field_not_declared" | "empty_field_set" | "configured_set_not_closed", message: string);
|
|
20
|
+
}
|
|
21
|
+
/** required + optional 合并索引(source 声明期一次性建好;重复路径直接抛)。 */
|
|
22
|
+
export declare function indexSourceFields(definition: NodeEventSourceDefinition): ReadonlyMap<string, NotificationFieldDefinition>;
|
|
23
|
+
/**
|
|
24
|
+
* 后台勾选校验 —— **早拒**,绝不静默去重/静默丢弃。
|
|
25
|
+
* 拒绝理由(Codex 复审明确冻结):未知路径、重复路径、把 required 当 optional 勾选。
|
|
26
|
+
*/
|
|
27
|
+
export declare function assertSelectableFields(definition: NodeEventSourceDefinition, selectedFields: readonly string[]): void;
|
|
28
|
+
/**
|
|
29
|
+
* 推导**配置级**字段全集(fieldSetVersion 的输入)。
|
|
30
|
+
* 空 selectedFields 合法(结果仍含 required);空结果集非法(registry 声明有误)。
|
|
31
|
+
*/
|
|
32
|
+
export declare function deriveConfiguredFields(definition: NodeEventSourceDefinition, selectedFields: readonly string[]): readonly string[];
|
|
33
|
+
/**
|
|
34
|
+
* 推导**某条事件**的 includedFields。
|
|
35
|
+
* = configuredFields 中「适用于本 variant」的部分 ∪ 本 variant 的必填(再闭包一次)。
|
|
36
|
+
*
|
|
37
|
+
* 调用方(payload builder / DB 写入)**必须**用本函数的返回值,不得自造 includedFields —
|
|
38
|
+
* 否则「payload 多一个 restricted 字段 + includedFields 也多写一行」即可一起通过精确集校验。
|
|
39
|
+
*/
|
|
40
|
+
export declare function deriveIncludedFields(definition: NodeEventSourceDefinition, configuredFields: readonly string[], triggerMode: NotificationTriggerMode): readonly string[];
|
|
41
|
+
/**
|
|
42
|
+
* 汇总一组字段所需的全部 authz 权限(AND 语义,去重后稳定排序)。
|
|
43
|
+
* 权限不足 → **整个 subscription 403**,不做字段级动态脱敏(设计文档 §9)。
|
|
44
|
+
*/
|
|
45
|
+
export declare function collectRequiredPermissions(definition: NodeEventSourceDefinition, fields: readonly string[]): readonly string[];
|
|
46
|
+
//# sourceMappingURL=field-set.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-set.d.ts","sourceRoot":"","sources":["../../src/notification-sources/field-set.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAIL,KAAK,2BAA2B,EAChC,KAAK,uBAAuB,EAC7B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAExE,qBAAa,yBAA0B,SAAQ,KAAK;IAEhD,QAAQ,CAAC,MAAM,EACX,eAAe,GACf,iBAAiB,GACjB,yBAAyB,GACzB,6BAA6B,GAC7B,iBAAiB,GACjB,2BAA2B;gBANtB,MAAM,EACX,eAAe,GACf,iBAAiB,GACjB,yBAAyB,GACzB,6BAA6B,GAC7B,iBAAiB,GACjB,2BAA2B,EAC/B,OAAO,EAAE,MAAM;CAKlB;AAED,yDAAyD;AACzD,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,yBAAyB,GACpC,WAAW,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAKlD;AAwBD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,yBAAyB,EACrC,cAAc,EAAE,SAAS,MAAM,EAAE,GAChC,IAAI,CAmCN;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,yBAAyB,EACrC,cAAc,EAAE,SAAS,MAAM,EAAE,GAChC,SAAS,MAAM,EAAE,CA0BnB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,yBAAyB,EACrC,gBAAgB,EAAE,SAAS,MAAM,EAAE,EACnC,WAAW,EAAE,uBAAuB,GACnC,SAAS,MAAM,EAAE,CAuEnB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,yBAAyB,EACrC,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB,SAAS,MAAM,EAAE,CAgBnB"}
|