@yss123/cage-kernel 0.1.0 → 0.3.0

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.
Files changed (140) hide show
  1. package/README.md +71 -9
  2. package/dist/authorization.d.ts +34 -0
  3. package/dist/authorization.js +89 -0
  4. package/dist/authorization.js.map +1 -0
  5. package/dist/brands.d.ts +10 -0
  6. package/dist/brands.js +11 -1
  7. package/dist/brands.js.map +1 -1
  8. package/dist/db/connect.d.ts +14 -0
  9. package/dist/db/connect.js +18 -2
  10. package/dist/db/connect.js.map +1 -1
  11. package/dist/db/ddl.d.ts +40 -1
  12. package/dist/db/ddl.js +111 -7
  13. package/dist/db/ddl.js.map +1 -1
  14. package/dist/db/event-version-schema.d.ts +9 -0
  15. package/dist/db/event-version-schema.js +10 -0
  16. package/dist/db/event-version-schema.js.map +1 -0
  17. package/dist/db/index.d.ts +4 -0
  18. package/dist/db/index.js +4 -0
  19. package/dist/db/index.js.map +1 -1
  20. package/dist/db/migrate.d.ts +10 -0
  21. package/dist/db/migrate.js +9 -1
  22. package/dist/db/migrate.js.map +1 -1
  23. package/dist/db/rows.d.ts +2 -0
  24. package/dist/db/rows.js +6 -0
  25. package/dist/db/rows.js.map +1 -1
  26. package/dist/db/runtime-schema.d.ts +9 -0
  27. package/dist/db/runtime-schema.js +41 -0
  28. package/dist/db/runtime-schema.js.map +1 -0
  29. package/dist/db/session.d.ts +6 -0
  30. package/dist/db/session.js +6 -0
  31. package/dist/db/session.js.map +1 -1
  32. package/dist/errors.d.ts +12 -0
  33. package/dist/errors.js +14 -0
  34. package/dist/errors.js.map +1 -1
  35. package/dist/files/links.d.ts +10 -0
  36. package/dist/files/links.js +50 -0
  37. package/dist/files/links.js.map +1 -0
  38. package/dist/files/schema.d.ts +9 -0
  39. package/dist/files/schema.js +51 -0
  40. package/dist/files/schema.js.map +1 -0
  41. package/dist/index.d.ts +12 -2
  42. package/dist/index.js +12 -2
  43. package/dist/index.js.map +1 -1
  44. package/dist/kernel.d.ts +88 -0
  45. package/dist/kernel.js +82 -41
  46. package/dist/kernel.js.map +1 -1
  47. package/dist/mask.d.ts +7 -1
  48. package/dist/mask.js +11 -0
  49. package/dist/mask.js.map +1 -1
  50. package/dist/org.d.ts +7 -0
  51. package/dist/org.js +5 -0
  52. package/dist/org.js.map +1 -1
  53. package/dist/pipeline/draft.d.ts +16 -0
  54. package/dist/pipeline/draft.js +39 -0
  55. package/dist/pipeline/draft.js.map +1 -0
  56. package/dist/pipeline/idempotency.d.ts +6 -0
  57. package/dist/pipeline/idempotency.js +6 -0
  58. package/dist/pipeline/idempotency.js.map +1 -1
  59. package/dist/pipeline/invoker.d.ts +9 -0
  60. package/dist/pipeline/invoker.js +22 -0
  61. package/dist/pipeline/invoker.js.map +1 -0
  62. package/dist/pipeline/load.d.ts +13 -0
  63. package/dist/pipeline/load.js +22 -6
  64. package/dist/pipeline/load.js.map +1 -1
  65. package/dist/primitives/aggregate.d.ts +95 -2
  66. package/dist/primitives/aggregate.js +15 -1
  67. package/dist/primitives/aggregate.js.map +1 -1
  68. package/dist/primitives/business-process.d.ts +128 -0
  69. package/dist/primitives/business-process.js +62 -0
  70. package/dist/primitives/business-process.js.map +1 -0
  71. package/dist/primitives/collection.d.ts +65 -0
  72. package/dist/primitives/collection.js +79 -0
  73. package/dist/primitives/collection.js.map +1 -0
  74. package/dist/primitives/command.d.ts +110 -11
  75. package/dist/primitives/command.js +16 -0
  76. package/dist/primitives/command.js.map +1 -1
  77. package/dist/primitives/constraints.d.ts +30 -1
  78. package/dist/primitives/constraints.js +14 -0
  79. package/dist/primitives/constraints.js.map +1 -1
  80. package/dist/primitives/event.d.ts +36 -0
  81. package/dist/primitives/event.js +12 -1
  82. package/dist/primitives/event.js.map +1 -1
  83. package/dist/primitives/fields.d.ts +176 -36
  84. package/dist/primitives/fields.js +134 -14
  85. package/dist/primitives/fields.js.map +1 -1
  86. package/dist/primitives/flow.d.ts +173 -8
  87. package/dist/primitives/flow.js +29 -2
  88. package/dist/primitives/flow.js.map +1 -1
  89. package/dist/primitives/states.d.ts +34 -2
  90. package/dist/primitives/states.js +15 -0
  91. package/dist/primitives/states.js.map +1 -1
  92. package/dist/read.d.ts +39 -3
  93. package/dist/read.js +193 -48
  94. package/dist/read.js.map +1 -1
  95. package/dist/registry.d.ts +51 -1
  96. package/dist/registry.js +105 -5
  97. package/dist/registry.js.map +1 -1
  98. package/dist/relations.d.ts +21 -0
  99. package/dist/relations.js +65 -0
  100. package/dist/relations.js.map +1 -0
  101. package/dist/runtime.d.ts +35 -0
  102. package/dist/runtime.js +9 -0
  103. package/dist/runtime.js.map +1 -0
  104. package/dist/scope/index.d.ts +5 -0
  105. package/dist/scope/index.js +5 -0
  106. package/dist/scope/index.js.map +1 -1
  107. package/dist/telemetry.d.ts +8 -0
  108. package/dist/telemetry.js +28 -3
  109. package/dist/telemetry.js.map +1 -1
  110. package/dist/transfer/csv.d.ts +19 -0
  111. package/dist/transfer/csv.js +125 -0
  112. package/dist/transfer/csv.js.map +1 -0
  113. package/dist/transfer/index.d.ts +67 -0
  114. package/dist/transfer/index.js +271 -0
  115. package/dist/transfer/index.js.map +1 -0
  116. package/dist/transfer/schema.d.ts +9 -0
  117. package/dist/transfer/schema.js +36 -0
  118. package/dist/transfer/schema.js.map +1 -0
  119. package/dist/types.d.ts +38 -2
  120. package/dist/types.js +8 -0
  121. package/dist/types.js.map +1 -1
  122. package/dist/util/names.d.ts +6 -0
  123. package/dist/util/names.js +6 -0
  124. package/dist/util/names.js.map +1 -1
  125. package/dist/worker/consumers.d.ts +7 -0
  126. package/dist/worker/consumers.js +21 -9
  127. package/dist/worker/consumers.js.map +1 -1
  128. package/dist/worker/health.d.ts +38 -0
  129. package/dist/worker/health.js +20 -0
  130. package/dist/worker/health.js.map +1 -0
  131. package/dist/worker/index.d.ts +34 -1
  132. package/dist/worker/index.js +176 -37
  133. package/dist/worker/index.js.map +1 -1
  134. package/dist/worker/outbox.d.ts +25 -2
  135. package/dist/worker/outbox.js +40 -2
  136. package/dist/worker/outbox.js.map +1 -1
  137. package/dist/worker/scheduler.d.ts +10 -1
  138. package/dist/worker/scheduler.js +34 -4
  139. package/dist/worker/scheduler.js.map +1 -1
  140. package/package.json +1 -1
package/dist/types.d.ts CHANGED
@@ -1,6 +1,14 @@
1
+ /**
2
+ * 定义内核授权上下文、调用主体、来源和数据范围的公共类型。
3
+ * 认证、审批、任务与反应在服务端组装这些值,写流水线、安全读和审计共同消费;业务输入不能自行指定可信身份,类型描述也不等于已经验证或授予权限。
4
+ */
1
5
  /** 主体种类。系统身份(process/job/external/reaction)只能调用声明了对应 invokedBy 的命令,或自己声明过的命令。 */
2
6
  export type ActorKind = 'user' | 'process' | 'job' | 'external' | 'reaction' | 'system' | 'anonymous';
7
+ /** 审计主体;id 的解释依赖 kind,系统主体名称不能当作真人用户 ID 使用。 */
3
8
  export interface Actor {
9
+ /**
10
+ * 真实调用身份类型,决定调用入口边界;真人委托信息放在 Ctx.onBehalfOf,不伪装为 user。
11
+ */
4
12
  kind: ActorKind;
5
13
  /** 用户 id,或系统身份名,例如 job:expireStaleOrders */
6
14
  id: string;
@@ -9,11 +17,18 @@ export interface Actor {
9
17
  export type Source = 'api' | 'process' | 'job' | 'import' | 'external' | 'reaction' | 'system';
10
18
  /** 范围组合子:封闭集合,每个都同时有内存语义和 SQL 语义 */
11
19
  export type Combinator = 'all' | 'self' | 'dept' | 'deptSubtree' | 'deptSet';
20
+ /**
21
+ * 内核支持的数据范围组合子白名单,供配置校验与目录发现使用。
22
+ * 具体数据判定由 scope 的 SQL 和内存实现承担,数组顺序不等于范围授权的包含关系。
23
+ */
12
24
  export declare const COMBINATORS: readonly Combinator[];
13
25
  /** 组合子由窄到宽的顺序,用于「不能授出比自己更宽的范围」 */
14
26
  export declare const COMBINATOR_WIDTH: Record<Combinator, number>;
15
27
  /** 角色在某个聚合上的数据范围授权 */
16
28
  export interface ScopeGrant {
29
+ /**
30
+ * 此条授权采用的范围规则,多条授权按 OR 合并;all 仍受租户边界限制。
31
+ */
17
32
  combinator: Combinator;
18
33
  /** deptSet 用:角色配置的部门集合 */
19
34
  deptIds?: string[];
@@ -21,32 +36,53 @@ export interface ScopeGrant {
21
36
  /** 能力点参数,例如 { ceiling: 50000 } */
22
37
  export type CapabilityParams = Record<string, unknown>;
23
38
  /** 当前主体的上下文。HTTP 认证、审批桥接、调度器、反应各自构造它,交给内核。 */
39
+ /**
40
+ * ctx 是可信服务端组装的授权快照,不是客户端可直接提交的请求体。
41
+ * capabilities 决定能做什么,scopes 决定可操作哪些记录,invokedBy 另由命令声明检查;
42
+ * 三者不可互相替代。异步处理派生上下文时要保留租户、真人委托和追踪信息。
43
+ */
24
44
  export interface Ctx {
45
+ /**
46
+ * 可信服务端主体;null 表示尚无身份,匿名公共调用也需显式 anonymous 主体。
47
+ */
25
48
  actor: Actor | null;
26
49
  /** 当前真人用户;系统身份时为 null(真人在 onBehalfOf) */
27
50
  userId: string | null;
28
51
  /** 系统身份代表的真人,用于职责分离和审计 */
29
52
  onBehalfOf?: string | null;
53
+ /** 所有数据库读写和异步事件的租户边界,不允许通过业务输入覆盖。 */
30
54
  tenantId: string;
55
+ /**
56
+ * 当前主体关联部门 ID;无部门时为 null,不能据空值自动扩展到全租户。
57
+ */
31
58
  deptId: string | null;
32
59
  /** 当前部门的祖先路径(含自己),例如 /root/purchase/ */
33
60
  deptPath: string | null;
34
61
  /** 能力集合及参数;多角色取并集,额度取最大值 */
35
62
  capabilities: Map<string, CapabilityParams>;
36
- /** 各聚合上的范围授权,多角色取并集(OR);未配置的聚合按「仅本人」 */
63
+ /** 各聚合上的范围授权,多角色取并集(OR);具体聚合缺省时可使用 * 通配授权,仍未配置则按仅本人处理。 */
37
64
  scopes: Record<string, ScopeGrant[]>;
38
65
  /** 可以看明文的「聚合.种类」,例如 PurchaseOrder.phone */
39
66
  unmask: string[];
67
+ /**
68
+ * 本次业务入口来源,写入审计和异步关联,不独立授予对应调用身份或能力。
69
+ */
40
70
  source: Source;
71
+ /** 跨 HTTP、命令审计和 outbox 关联同一次请求;不承担业务去重。 */
41
72
  requestId?: string;
73
+ /** 同一次逻辑提交重试时复用;未提供时不会自动合并两次独立业务操作。 */
42
74
  idempotencyKey?: string;
43
75
  /** 二次认证时间(毫秒时间戳) */
44
76
  stepUpAt?: number | null;
77
+ /**
78
+ * 可选客户端来源信息,包含 IP 和 User-Agent,仅作审计上下文,不作为业务授权依据。
79
+ */
45
80
  client?: {
46
- ip?: string;
81
+ ip?: string; /** 可选浏览器/客户端标识,属于不可信展示文本,不参与能力判断。 */
47
82
  userAgent?: string;
48
83
  };
49
84
  /** onBehalfOf 那个人的能力(额度类约束按他判断);内核会按需加载 */
50
85
  onBehalfOfCapabilities?: Map<string, CapabilityParams>;
51
86
  }
87
+ /** 声明回调既可同步计算,也可等待框架允许的读依赖;调用侧始终可以 await。 */
52
88
  export type MaybePromise<T> = T | Promise<T>;
package/dist/types.js CHANGED
@@ -1,4 +1,12 @@
1
+ /**
2
+ * 定义内核授权上下文、调用主体、来源和数据范围的公共类型。
3
+ * 认证、审批、任务与反应在服务端组装这些值,写流水线、安全读和审计共同消费;业务输入不能自行指定可信身份,类型描述也不等于已经验证或授予权限。
4
+ */
1
5
  // 内核公共类型:上下文 ctx、主体、范围授权。
6
+ /**
7
+ * 内核支持的数据范围组合子白名单,供配置校验与目录发现使用。
8
+ * 具体数据判定由 scope 的 SQL 和内存实现承担,数组顺序不等于范围授权的包含关系。
9
+ */
2
10
  export const COMBINATORS = ['all', 'self', 'dept', 'deptSubtree', 'deptSet'];
3
11
  /** 组合子由窄到宽的顺序,用于「不能授出比自己更宽的范围」 */
4
12
  export const COMBINATOR_WIDTH = { self: 0, dept: 1, deptSet: 2, deptSubtree: 2, all: 3 };
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAgB1B,MAAM,CAAC,MAAM,WAAW,GAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;AACpG,kCAAkC;AAClC,MAAM,CAAC,MAAM,gBAAgB,GAA+B,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,0BAA0B;AAoB1B;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;AACpG,kCAAkC;AAClC,MAAM,CAAC,MAAM,gBAAgB,GAA+B,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC"}
@@ -1,9 +1,15 @@
1
+ /** 兼顾连续大写缩写和普通驼峰边界;输出用作数据库名字,调用前由声明层约束合法标识。 */
1
2
  export declare function snake(s: string): string;
3
+ /** 与表名转换共享分词规则,使自动 HTTP 路径和领域命名保持可推导关系。 */
2
4
  export declare function kebab(s: string): string;
5
+ /** 将数据库下划线列名转换为业务字段名;不改变已经是驼峰的字段。 */
3
6
  export declare function camel(s: string): string;
7
+ /** 只改变首字符,供生成器保留后续缩写/驼峰;空字符串仍返回空字符串。 */
4
8
  export declare function lowerFirst(s: string): string;
9
+ /** 只改变首字符,适合从字段名构造公开类型名,不承担标识符合法性检查。 */
5
10
  export declare function upperFirst(s: string): string;
6
11
  /** 32 位哈希(FNV-1a),用于咨询锁编号 */
7
12
  export declare function hash32(s: string): number;
8
13
  /** 稳定的 JSON 序列化(键排序),用于本体图比较 */
14
+ /** 对对象键排序但保持数组顺序;仅用于可 JSON 化的声明资料,不作为密码学签名规范。 */
9
15
  export declare function stableStringify(v: unknown): string;
@@ -1,19 +1,24 @@
1
1
  // 命名转换:聚合名大驼峰 → 表名 snake_case、路由 kebab-case;字段名 camelCase ↔ 列名 snake_case。
2
+ /** 兼顾连续大写缩写和普通驼峰边界;输出用作数据库名字,调用前由声明层约束合法标识。 */
2
3
  export function snake(s) {
3
4
  return s
4
5
  .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
5
6
  .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
6
7
  .toLowerCase();
7
8
  }
9
+ /** 与表名转换共享分词规则,使自动 HTTP 路径和领域命名保持可推导关系。 */
8
10
  export function kebab(s) {
9
11
  return snake(s).replace(/_/g, '-');
10
12
  }
13
+ /** 将数据库下划线列名转换为业务字段名;不改变已经是驼峰的字段。 */
11
14
  export function camel(s) {
12
15
  return s.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
13
16
  }
17
+ /** 只改变首字符,供生成器保留后续缩写/驼峰;空字符串仍返回空字符串。 */
14
18
  export function lowerFirst(s) {
15
19
  return s.charAt(0).toLowerCase() + s.slice(1);
16
20
  }
21
+ /** 只改变首字符,适合从字段名构造公开类型名,不承担标识符合法性检查。 */
17
22
  export function upperFirst(s) {
18
23
  return s.charAt(0).toUpperCase() + s.slice(1);
19
24
  }
@@ -27,6 +32,7 @@ export function hash32(s) {
27
32
  return h | 0;
28
33
  }
29
34
  /** 稳定的 JSON 序列化(键排序),用于本体图比较 */
35
+ /** 对对象键排序但保持数组顺序;仅用于可 JSON 化的声明资料,不作为密码学签名规范。 */
30
36
  export function stableStringify(v) {
31
37
  if (v === null || typeof v !== 'object')
32
38
  return JSON.stringify(v);
@@ -1 +1 @@
1
- {"version":3,"file":"names.js","sourceRoot":"","sources":["../../src/util/names.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAE3E,MAAM,UAAU,KAAK,CAAC,CAAS;IAC7B,OAAO,CAAC;SACL,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,OAAO,CAAC,uBAAuB,EAAE,OAAO,CAAC;SACzC,WAAW,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,CAAS;IAC7B,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,CAAS;IAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,6BAA6B;AAC7B,MAAM,UAAU,MAAM,CAAC,CAAS;IAC9B,IAAI,CAAC,GAAG,UAAU,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,gCAAgC;AAChC,MAAM,UAAU,eAAe,CAAC,CAAU;IACxC,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAClE,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IACrE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAAS,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC;IACxF,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,eAAe,CAAE,CAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AACpG,CAAC"}
1
+ {"version":3,"file":"names.js","sourceRoot":"","sources":["../../src/util/names.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAE3E,+CAA+C;AAC/C,MAAM,UAAU,KAAK,CAAC,CAAS;IAC7B,OAAO,CAAC;SACL,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,OAAO,CAAC,uBAAuB,EAAE,OAAO,CAAC;SACzC,WAAW,EAAE,CAAC;AACnB,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,KAAK,CAAC,CAAS;IAC7B,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACrC,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,KAAK,CAAC,CAAS;IAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AACtE,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,6BAA6B;AAC7B,MAAM,UAAU,MAAM,CAAC,CAAS;IAC9B,IAAI,CAAC,GAAG,UAAU,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,gCAAgC;AAChC,iDAAiD;AACjD,MAAM,UAAU,eAAe,CAAC,CAAU;IACxC,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAClE,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IACrE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAAS,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC;IACxF,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,eAAe,CAAE,CAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AACpG,CAAC"}
@@ -9,6 +9,8 @@ export interface ApprovalEngine {
9
9
  tenantId: string;
10
10
  /** 只包含声明过的 routable 字段 */
11
11
  vars: Record<string, unknown>;
12
+ subjectVersion?: number;
13
+ eventId?: number;
12
14
  tx: Transaction<any>;
13
15
  }): Promise<{
14
16
  instanceId: string;
@@ -20,8 +22,13 @@ export interface ApprovalEngine {
20
22
  tx: Transaction<any>;
21
23
  }): Promise<void>;
22
24
  }
25
+ /**
26
+ * 只装配 tx:outbox 的反应,same 反应已由主命令事务执行。消费名称稳定,供持久去重使用。
27
+ * 每个反应只获得目标命令能力;集合按声明顺序串行执行,失败带原始条目坐标并回滚消费事务。
28
+ */
23
29
  export declare function reactionConsumers(k: Kernel): EventConsumer[];
24
30
  /** 审批启动:只把 routable 字段作为流程变量传给引擎 */
31
+ /** 启动时要求每个流程存在引擎,避免事件已标 done 却没有产生待办;启动/取消随消费事务提交。 */
25
32
  export declare function approvalConsumers(k: Kernel, engines: Record<string, ApprovalEngine>): EventConsumer[];
26
33
  /** 声明对象通过 CONSUMERS 扩展点提供的消费者(例如 @yss123/cage-connectors 的出站映射) */
27
34
  export declare function extensionConsumers(k: Kernel): EventConsumer[];
@@ -1,19 +1,22 @@
1
1
  import { CONSUMERS } from '../brands.js';
2
2
  import { systemCtx } from '../org.js';
3
3
  import { loadScoped } from '../pipeline/load.js';
4
+ import { reactionEntries, reactionEntryError } from '../primitives/collection.js';
5
+ /** 事件可来自真人或代表真人的系统身份,后续反应继续携带同一委托用于审计和职责分离。 */
4
6
  function actorUser(row) {
5
7
  return row.actor?.userId ?? row.actor?.onBehalfOf ?? null;
6
8
  }
9
+ /**
10
+ * 只装配 tx:outbox 的反应,same 反应已由主命令事务执行。消费名称稳定,供持久去重使用。
11
+ * 每个反应只获得目标命令能力;集合按声明顺序串行执行,失败带原始条目坐标并回滚消费事务。
12
+ */
7
13
  export function reactionConsumers(k) {
8
- return k.registry.reactions
9
- .filter(({ r }) => r.tx === 'outbox')
14
+ const events = new Set(k.registry.reactions.map(({ r }) => r.event.name));
15
+ return [...events].flatMap((event) => k.registry.reactionsFor(event).filter(({ r }) => r.tx === 'outbox'))
10
16
  .map(({ r, name }) => ({
11
17
  name: `reaction:${name}`,
12
18
  event: r.event.name,
13
19
  async handle(row, tx) {
14
- const input = r.map(row.payload);
15
- if (input === null || input === undefined)
16
- return;
17
20
  const ctx = systemCtx({
18
21
  kind: 'reaction',
19
22
  name,
@@ -22,25 +25,33 @@ export function reactionConsumers(k) {
22
25
  onBehalfOf: actorUser(row),
23
26
  requestId: row.request_id ?? undefined,
24
27
  });
25
- await k.executeIn(tx, r.command, input, ctx, 0);
28
+ // 集合调用和去重登记共享同一事务;串行执行保留声明的锁顺序。
29
+ for (const entry of reactionEntries(r, row.payload)) {
30
+ try {
31
+ await k.executeIn(tx, r.command, entry.input, ctx, 0);
32
+ }
33
+ catch (error) {
34
+ throw reactionEntryError(error, r, name, entry);
35
+ }
36
+ }
26
37
  },
27
38
  }));
28
39
  }
29
40
  /** 审批启动:只把 routable 字段作为流程变量传给引擎 */
41
+ /** 启动时要求每个流程存在引擎,避免事件已标 done 却没有产生待办;启动/取消随消费事务提交。 */
30
42
  export function approvalConsumers(k, engines) {
31
43
  const out = [];
32
44
  for (const { a, name } of k.registry.approvals) {
33
45
  const engine = engines[a.process];
34
46
  if (!engine) {
35
- k.log.warn({ process: a.process }, `审批绑定 ${name} 没有可用的审批引擎,流程不会启动`);
36
- continue;
47
+ throw new Error(`[CAGE-WORKER-001] 审批绑定 ${name} 缺少流程 ${a.process} 的审批引擎;补齐路由或装配引擎后再启动 worker`);
37
48
  }
38
49
  out.push({
39
50
  name: `approval:${name}:start`,
40
51
  event: a.start.name,
41
52
  async handle(row, tx) {
42
53
  const vars = await routableVars(k, a, row, tx);
43
- await engine.start({ process: a.process, businessKey: row.aggregate_id, tenantId: row.tenant_id, vars, tx });
54
+ await engine.start({ process: a.process, businessKey: row.aggregate_id, tenantId: row.tenant_id, vars, tx, subjectVersion: row.aggregate_version ?? undefined, eventId: row.id });
44
55
  },
45
56
  });
46
57
  for (const ev of a.cancelOn) {
@@ -55,6 +66,7 @@ export function approvalConsumers(k, engines) {
55
66
  }
56
67
  return out;
57
68
  }
69
+ /** 只提取 routable 白名单,优先当前对象快照、再事件载荷;不把整个聚合或任意输入传给流程。 */
58
70
  async function routableVars(k, a, row, tx) {
59
71
  const ctx = systemCtx({ kind: 'process', name: a.process, tenantId: row.tenant_id, capabilities: [] });
60
72
  const snap = await loadScoped(tx, a.agg, row.aggregate_id, ctx, false);
@@ -1 +1 @@
1
- {"version":3,"file":"consumers.js","sourceRoot":"","sources":["../../src/worker/consumers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAiBjD,SAAS,SAAS,CAAC,GAAc;IAC/B,OAAO,GAAG,CAAC,KAAK,EAAE,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,UAAU,IAAI,IAAI,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,CAAS;IACzC,OAAO,CAAC,CAAC,QAAQ,CAAC,SAAS;SACxB,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC;SACpC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACrB,IAAI,EAAE,YAAY,IAAI,EAAE;QACxB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI;QACnB,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE;YAClB,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAc,CAAC,CAAC;YACxC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO;YAClD,MAAM,GAAG,GAAG,SAAS,CAAC;gBACpB,IAAI,EAAE,UAAU;gBAChB,IAAI;gBACJ,QAAQ,EAAE,GAAG,CAAC,SAAS;gBACvB,YAAY,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;gBAClD,UAAU,EAAE,SAAS,CAAC,GAAG,CAAC;gBAC1B,SAAS,EAAE,GAAG,CAAC,UAAU,IAAI,SAAS;aACvC,CAAC,CAAC;YACH,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QAClD,CAAC;KACF,CAAC,CAAC,CAAC;AACR,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,iBAAiB,CAAC,CAAS,EAAE,OAAuC;IAClF,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;QAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,QAAQ,IAAI,mBAAmB,CAAC,CAAC;YACpE,SAAS;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,YAAY,IAAI,QAAQ;YAC9B,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI;YACnB,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE;gBAClB,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;gBAC/C,MAAM,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YAC/G,CAAC;SACF,CAAC,CAAC;QACH,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC5B,GAAG,CAAC,IAAI,CAAC;gBACP,IAAI,EAAE,YAAY,IAAI,WAAW,EAAE,CAAC,IAAI,EAAE;gBAC1C,KAAK,EAAE,EAAE,CAAC,IAAI;gBACd,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE;oBAClB,MAAM,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,GAAG,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC1G,CAAC;aACF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,CAAS,EAAE,CAAW,EAAE,GAAc,EAAE,EAAoB;IACtF,MAAM,GAAG,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,SAAS,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;IACvG,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,YAAY,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACvE,MAAM,IAAI,GAA4B,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ;QAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,IAAK,GAAG,CAAC,OAAe,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACrF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,kBAAkB,CAAC,CAAS;IAC1C,OAAO,CAAC,CAAC,QAAQ,CAAC,iBAAiB,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAqB,IAAI,EAAE,CAAC,CAAC;AACnG,CAAC;AAED,gCAAgC;AAChC,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,MAAM,GAAG,GAAmC,EAAE,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;QACtC,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,UAAU;YAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC5G,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"consumers.js","sourceRoot":"","sources":["../../src/worker/consumers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { Kernel } from '../kernel.js';
2
+ import type { EventConsumer } from './outbox.js';
3
+ /** 进程实际装载的版本/协议/注册指纹及消费者清单,不能用磁盘源码代替这份运行证据。 */
4
+ export interface WorkerManifest {
5
+ version: string;
6
+ protocolVersion: number;
7
+ registryFingerprint: string;
8
+ loadedAt: string;
9
+ consumers: {
10
+ name: string;
11
+ event: string;
12
+ ready: boolean;
13
+ }[];
14
+ events: {
15
+ name: string;
16
+ consumers: string[];
17
+ recordOnly: boolean;
18
+ }[];
19
+ jobs: string[];
20
+ }
21
+ /** 可观测运行状态;heartbeatAt 为 ISO 时间,null 表示尚无成功心跳,inFlight 是正在执行的任务标识。 */
22
+ export interface WorkerSnapshot {
23
+ id: string;
24
+ pid: number;
25
+ status: 'starting' | 'running' | 'stopping' | 'stopped' | 'error';
26
+ listenerHealthy: boolean;
27
+ schedulerHealthy: boolean;
28
+ heartbeatAt: string | null;
29
+ inFlight: string[];
30
+ lastError: string | null;
31
+ manifest: WorkerManifest;
32
+ }
33
+ /** 清单按名称稳定排序;recordOnly 事件允许没有消费者,未知事件则由投递校验拒绝静默完成。 */
34
+ export declare function describeConsumers(k: Kernel, consumers: EventConsumer[]): WorkerManifest;
35
+ /** 保存实时快照提供器而非冻结结果,HTTP 同进程诊断可观察到最新状态;WeakMap 不延长 kernel 生命周期。 */
36
+ export declare function registerWorkerSnapshot(k: Kernel, snapshot: () => WorkerSnapshot): void;
37
+ /** 未在此进程装配 worker 时返回 null;跨进程状态应查询数据库心跳记录。 */
38
+ export declare function workerSnapshot(k: Kernel): WorkerSnapshot | null;
@@ -0,0 +1,20 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { registryFingerprint } from '../registry.js';
3
+ const { version } = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8'));
4
+ /** 清单按名称稳定排序;recordOnly 事件允许没有消费者,未知事件则由投递校验拒绝静默完成。 */
5
+ export function describeConsumers(k, consumers) {
6
+ const entries = consumers.map((c) => ({ name: c.name, event: c.event, ready: true })).sort((a, b) => a.name.localeCompare(b.name));
7
+ const events = [...new Set([...k.registry.events.map((event) => event.name), ...entries.map((c) => c.event)])].sort();
8
+ return {
9
+ version, protocolVersion: 2, registryFingerprint: registryFingerprint(k.registry), loadedAt: new Date().toISOString(),
10
+ consumers: entries,
11
+ events: events.map((name) => { const names = entries.filter((c) => c.event === name).map((c) => c.name); return { name, consumers: names, recordOnly: names.length === 0 }; }),
12
+ jobs: k.registry.jobs.map((j) => j.name).sort(),
13
+ };
14
+ }
15
+ const snapshots = new WeakMap();
16
+ /** 保存实时快照提供器而非冻结结果,HTTP 同进程诊断可观察到最新状态;WeakMap 不延长 kernel 生命周期。 */
17
+ export function registerWorkerSnapshot(k, snapshot) { snapshots.set(k, snapshot); }
18
+ /** 未在此进程装配 worker 时返回 null;跨进程状态应查询数据库心跳记录。 */
19
+ export function workerSnapshot(k) { return snapshots.get(k)?.() ?? null; }
20
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/worker/health.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAGrD,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAwB,CAAC;AA0B5H,uDAAuD;AACvD,MAAM,UAAU,iBAAiB,CAAC,CAAS,EAAE,SAA0B;IACrE,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACnI,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACtH,OAAO;QACL,OAAO,EAAE,eAAe,EAAE,CAAC,EAAE,mBAAmB,EAAE,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrH,SAAS,EAAE,OAAO;QAClB,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9K,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE;KAChD,CAAC;AACJ,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,OAAO,EAAgC,CAAC;AAC9D,kEAAkE;AAClE,MAAM,UAAU,sBAAsB,CAAC,CAAS,EAAE,QAA8B,IAAU,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvH,+CAA+C;AAC/C,MAAM,UAAU,cAAc,CAAC,CAAS,IAA2B,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC"}
@@ -3,17 +3,24 @@ import { type Kernel } from '../kernel.js';
3
3
  import { type Logger } from '../telemetry.js';
4
4
  import { type ApprovalEngine } from './consumers.js';
5
5
  import { type EventConsumer } from './outbox.js';
6
+ import { type WorkerManifest, type WorkerSnapshot } from './health.js';
6
7
  export * from './outbox.js';
7
8
  export * from './consumers.js';
8
9
  export * from './scheduler.js';
10
+ export * from './health.js';
11
+ /** 生命周期装配选项;注入 kernel 时 worker 不拥有其关闭权,所有带 Ms 后缀的时限均为毫秒。 */
9
12
  export interface WorkerOptions {
13
+ /** 未注入 kernel 时用于创建内核的领域导出;必须与 API 使用同一业务版本。 */
10
14
  domain?: object | object[];
15
+ /** 可选现有内核,提供时由宿主负责关闭;worker 仍拥有自己创建的监听及锁连接。 */
11
16
  kernel?: Kernel;
17
+ /** 数据库账号连接;未注入内核时缺省从环境读取,专用监听连接也需要 app URL。 */
12
18
  urls?: DatabaseUrls;
13
19
  /** 同时处理的事件数 */
14
20
  concurrency?: number;
15
21
  /** 没收到 NOTIFY 时的轮询间隔 */
16
22
  pollIntervalMs?: number;
23
+ /** 单个 outbox 事件的最大投递尝试次数,缺省使用 MAX_ATTEMPTS;失败终结后需人工诊断。 */
17
24
  maxAttempts?: number;
18
25
  /** 外部审批引擎(按流程名);不传时使用代码内封闭路由 */
19
26
  approvalEngines?: Record<string, ApprovalEngine>;
@@ -21,16 +28,42 @@ export interface WorkerOptions {
21
28
  consumers?: EventConsumer[];
22
29
  /** 是否运行定时任务,默认 true */
23
30
  jobs?: boolean;
31
+ /** 停止后等待所有在途任务的时限;超时不会提前释放仍在执行的任务锁。 */
32
+ shutdownTimeoutMs?: number;
33
+ /** 调度扫描间隔,默认 5 秒;错过周期跳过,不积压补跑。 */
34
+ schedulerIntervalMs?: number;
35
+ /** 后台循环日志出口;省略使用默认日志器,不应在日志中输出完整连接、载荷或凭据。 */
24
36
  logger?: Logger;
25
37
  }
38
+ /** stop 可重复调用并复用同一停机 Promise;snapshot 是观测证据,不可用于绕过数据库互斥。 */
26
39
  export interface WorkerHandle {
40
+ /** 供消费者复用的执行内核;是否由 stop 关闭取决于是否由 worker 创建。 */
27
41
  kernel: Kernel;
42
+ /** 当前装配的全部消费者,包含框架、扩展及宿主补充项。 */
28
43
  consumers: EventConsumer[];
29
- /** 处理到 outbox 为空为止(测试和 cage dev 用) */
44
+ /** 注册指纹与消费者清单,用于判断实际装载版本;不证明某事件已经消费成功。 */
45
+ manifest: WorkerManifest;
46
+ /** 读取此进程最新内存状态、在途任务及心跳证据;人工驱动实例返回 manual/stopped 摘要。 */
47
+ snapshot(): WorkerSnapshot;
48
+ /** 手动处理当前可领取事件及扩展工作,默认最多 50 轮;返回处理数量,不代表未来重试或死信已清空。 */
30
49
  drain(maxRounds?: number): Promise<number>;
50
+ /** 停止新工作并等待在途任务;超时会拒绝等待,但不会提前释放仍执行中的任务锁。 */
31
51
  stop(): Promise<void>;
32
52
  }
53
+ /** 合并内置、扩展和额外消费者,显式审批引擎覆盖同名代码路由;缺失引擎或名称冲突在启动前失败。 */
33
54
  export declare function buildConsumers(k: Kernel, opts?: Pick<WorkerOptions, 'approvalEngines' | 'consumers'>): EventConsumer[];
55
+ /** 构建并验证消费者后描述装载清单;这不启动轮询、建立心跳或证明 worker 正在运行。 */
56
+ export declare function workerManifest(k: Kernel, opts?: Pick<WorkerOptions, 'approvalEngines' | 'consumers'>): WorkerManifest;
34
57
  /** 不启动循环,只创建可手动驱动的 worker(测试用) */
58
+ /**
59
+ * 手动驱动当前可领取任务,drain 默认最多 50 轮;无到期事件且扩展无进展即返回处理数量。
60
+ * 未来重试、死信及被前序阻塞的事件仍可能存在,因此 drain 返回并不证明完整业务链已经成功。
61
+ */
35
62
  export declare function createWorker(k: Kernel, opts?: WorkerOptions): Omit<WorkerHandle, 'stop'>;
63
+ /**
64
+ * 装配服务和消费者后,建立独立 LISTEN/调度锁连接,写首个心跳,再启动投递、定时任务和维护循环。
65
+ * 所有后台 Promise 统一登记,停机先停止新工作、取消可取消 IO,再等待在途工作后释放连接与锁。
66
+ * 停机超时只向调用方报错,不提前关闭仍持有任务锁的连接;后台清理继续等待真实任务结束。
67
+ * LISTEN 失效可由轮询继续发现 outbox;调度连接异常会停止新调度,健康状态如实反映该区别。
68
+ */
36
69
  export declare function startWorker(opts?: WorkerOptions): Promise<WorkerHandle>;