@mldong/jeeflow 1.8.12 → 1.8.13

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/engine.d.ts CHANGED
@@ -34,7 +34,9 @@ export declare class EngineImpl implements Engine {
34
34
  private interceptorCache;
35
35
  /** 定义级拦截器解析(issue 34,对齐 Java 模型级 postInterceptors):
36
36
  * 流程定义顶层 postInterceptors 声明 → 按名从 interceptorRegistry 取(未声明该流程不触发);
37
- * 未声明 → 回落引擎级列表(向后兼容)。结果按 defineId 缓存。 */
37
+ * 未声明 → 回落引擎级列表(向后兼容)。结果按 defineId 缓存。
38
+ * issues/60:解析与校验分离——定义读取/JSON 解析失败回落引擎级(现状语义),
39
+ * 声明中存在未注册名时抛错(不静默跳过),且错误不写缓存保证持续报错。 */
38
40
  private resolveInterceptors;
39
41
  private firePre;
40
42
  /** 表达式求值(v1.5.0,门面 highLight 决策分支过滤用) */
package/dist/engine.js CHANGED
@@ -36,7 +36,9 @@ export class EngineImpl {
36
36
  interceptorCache = new Map();
37
37
  /** 定义级拦截器解析(issue 34,对齐 Java 模型级 postInterceptors):
38
38
  * 流程定义顶层 postInterceptors 声明 → 按名从 interceptorRegistry 取(未声明该流程不触发);
39
- * 未声明 → 回落引擎级列表(向后兼容)。结果按 defineId 缓存。 */
39
+ * 未声明 → 回落引擎级列表(向后兼容)。结果按 defineId 缓存。
40
+ * issues/60:解析与校验分离——定义读取/JSON 解析失败回落引擎级(现状语义),
41
+ * 声明中存在未注册名时抛错(不静默跳过),且错误不写缓存保证持续报错。 */
40
42
  async resolveInterceptors(inst) {
41
43
  if (!this.ext)
42
44
  return [];
@@ -47,23 +49,27 @@ export class EngineImpl {
47
49
  if (cached)
48
50
  return cached;
49
51
  let list = this.ext.interceptors ?? [];
52
+ let declared = '';
50
53
  try {
51
54
  const def = await this.repo.findDefineById(defineId);
52
55
  if (def) {
53
56
  const content = typeof def.content === 'string' ? def.content : new TextDecoder().decode(def.content);
54
57
  const meta = JSON.parse(content);
55
- const declared = String(meta.postInterceptors ?? '').trim();
56
- if (declared) {
57
- list = [];
58
- for (const name of declared.split(',').map(n => n.trim())) {
59
- const ic = this.ext.interceptorRegistry?.[name];
60
- if (name && ic)
61
- list.push(ic);
62
- }
63
- }
58
+ declared = String(meta.postInterceptors ?? '').trim();
59
+ }
60
+ }
61
+ catch { /* 定义读取/JSON 解析失败回落引擎级 */ }
62
+ if (declared) {
63
+ list = [];
64
+ for (const name of declared.split(',').map(n => n.trim())) {
65
+ if (!name)
66
+ continue;
67
+ const ic = this.ext.interceptorRegistry?.[name];
68
+ if (!ic)
69
+ throw new Error(`postInterceptors 声明的拦截器未注册: ${name}`);
70
+ list.push(ic);
64
71
  }
65
72
  }
66
- catch { /* 解析失败回落引擎级 */ }
67
73
  this.interceptorCache.set(defineId, list);
68
74
  return list;
69
75
  }
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  export { EngineImpl, type Engine } from './engine.js';
2
2
  export { MemoryRepository } from './memory.js';
3
- export { HandlerRegistry, type IAssignmentHandler, type IDecisionHandler, type HandlerMeta } from './registry.js';
3
+ export { HandlerRegistry, type IAssignmentHandler, type IDecisionHandler, type HandlerMeta, type HandlerType } from './registry.js';
4
4
  export { enumDict, enumDictKeys, type DictItem } from './metadata.js';
5
5
  export * from './model.js';
6
6
  export type { ProcessRepository, UserProvider, OrgUserProvider, IDGenerator, ExpressionEvaluator } from './spi.js';
7
- export { SqliteDynamicTableWriter, PersistPostInterceptor, type DynamicTableWriter, type DefineLoader, } from './persist.js';
7
+ export { SqliteDynamicTableWriter, PersistPostInterceptor, registerPersistMeta, type DynamicTableWriter, type DefineLoader, } from './persist.js';
8
8
  export { registerBuiltinAssignments, OperatorAssignmentHandler, FormFieldAssigneeHandler, DeptLeaderAssignmentHandler, DeptMainLeaderAssignmentHandler, ApplicantDeptLeaderAssignmentHandler, ApplicantDeptMainLeaderAssignmentHandler, TaskRoleAssigneeHandler, HANDLER_OPERATOR_ASSIGNMENT, HANDLER_FORM_FIELD_ASSIGNEE, HANDLER_DEPT_LEADER, HANDLER_DEPT_MAIN_LEADER, HANDLER_APPLICANT_DEPT_LEADER, HANDLER_APPLICANT_DEPT_MAIN_LEADER, HANDLER_TASK_ROLE_ASSIGNEE, } from './builtin.js';
9
9
  export { JeeflowFacade } from './facade.js';
10
10
  export type { EngineExtensions, FlowInterceptor, ProcessEventListener, ProcessEvent, AssignmentHandler, DecisionHandler } from './extensions.js';
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ export { MemoryRepository } from './memory.js';
3
3
  export { HandlerRegistry } from './registry.js';
4
4
  export { enumDict, enumDictKeys } from './metadata.js';
5
5
  export * from './model.js';
6
- export { SqliteDynamicTableWriter, PersistPostInterceptor, } from './persist.js';
6
+ export { SqliteDynamicTableWriter, PersistPostInterceptor, registerPersistMeta, } from './persist.js';
7
7
  export { registerBuiltinAssignments, OperatorAssignmentHandler, FormFieldAssigneeHandler, DeptLeaderAssignmentHandler, DeptMainLeaderAssignmentHandler, ApplicantDeptLeaderAssignmentHandler, ApplicantDeptMainLeaderAssignmentHandler, TaskRoleAssigneeHandler, HANDLER_OPERATOR_ASSIGNMENT, HANDLER_FORM_FIELD_ASSIGNEE, HANDLER_DEPT_LEADER, HANDLER_DEPT_MAIN_LEADER, HANDLER_APPLICANT_DEPT_LEADER, HANDLER_APPLICANT_DEPT_MAIN_LEADER, HANDLER_TASK_ROLE_ASSIGNEE, } from './builtin.js';
8
8
  // issues/35:包导出面补齐——门面/扩展类型/扩展仓储(集成方组装完整引擎链)
9
9
  export { JeeflowFacade } from './facade.js';
package/dist/persist.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { DatabaseSync } from 'node:sqlite';
2
2
  import { type ProcessInstance, type ProcessDefine, type FlowNode } from './model.js';
3
3
  import type { FlowInterceptor } from './extensions.js';
4
+ import type { HandlerRegistry } from './registry.js';
4
5
  /**
5
6
  * 动态表写入组件接口——引擎无关,四语言契约一致(Java/Go/Python/Node)
6
7
  *
@@ -111,3 +112,6 @@ export declare class PersistPostInterceptor implements FlowInterceptor {
111
112
  /** 流程上下文字段(蛇形列名约定,与 writer 系统字段一致) */
112
113
  private fillContext;
113
114
  }
115
+ /** 将 PersistPostInterceptor 元数据注册进处理器注册中心(SPI 字典源),
116
+ * 集成方在实例组装处调用一次即可,保证"字典项 ⟺ 实例"同步(避免各端写死注册遗漏/名不一致)。 */
117
+ export declare function registerPersistMeta(registry: HandlerRegistry): void;
package/dist/persist.js CHANGED
@@ -362,3 +362,14 @@ export class PersistPostInterceptor {
362
362
  data['apply_dept_id'] ??= inst.variables[KeyDeptID] ?? null;
363
363
  }
364
364
  }
365
+ // ─── 注册助手(issues/60)──────────────────────────────────────────────────────
366
+ /** 将 PersistPostInterceptor 元数据注册进处理器注册中心(SPI 字典源),
367
+ * 集成方在实例组装处调用一次即可,保证"字典项 ⟺ 实例"同步(避免各端写死注册遗漏/名不一致)。 */
368
+ export function registerPersistMeta(registry) {
369
+ registry.registerMeta('FlowInterceptor', {
370
+ name: 'com.mldong.jeeflow.persist.interceptor.PersistPostInterceptor',
371
+ displayName: '业务数据自动入库',
372
+ order: 0,
373
+ group: 'post',
374
+ });
375
+ }
@@ -8,8 +8,12 @@ export interface IAssignmentHandler {
8
8
  export interface IDecisionHandler {
9
9
  decide(node: FlowNode, inst: ProcessInstance, vars: Record<string, any>): string | Promise<string>;
10
10
  }
11
+ /** 处理器类型名(对齐 Java/go/python HandlerMeta.type,四语言通用) */
12
+ export type HandlerType = 'AssignmentHandler' | 'CandidateHandler' | 'FlowInterceptor' | 'DecisionHandler';
11
13
  /** 处理器元数据(v1.4.0,SPI 实现清单字典源) */
12
14
  export interface HandlerMeta {
15
+ /** 处理器类型(内置 AssignmentHandler 元数据自动携带;老数据缺省按 AssignmentHandler 归类) */
16
+ type?: HandlerType;
13
17
  /** 处理器标识:节点配置的 handlerName(与字典 value 一致) */
14
18
  name: string;
15
19
  /** 显示名(字典 label) */
@@ -28,14 +32,18 @@ export declare class HandlerRegistry {
28
32
  private metas;
29
33
  /** 构造即内置 7 个通用 AssignmentHandler 元数据(v1.6.0 issues/16,注册名与 Java 类全限定名一致) */
30
34
  constructor();
31
- registerAssignment(name: string, handler: IAssignmentHandler, meta?: Omit<HandlerMeta, 'name'>): void;
32
- registerDecision(name: string, handler: IDecisionHandler, meta?: Omit<HandlerMeta, 'name'>): void;
35
+ registerAssignment(name: string, handler: IAssignmentHandler, meta?: Omit<HandlerMeta, 'name' | 'type'>): void;
36
+ registerDecision(name: string, handler: IDecisionHandler, meta?: Omit<HandlerMeta, 'name' | 'type'>): void;
37
+ /** 注册处理器元数据(不绑定运行时实现,对齐 Java HandlerRegistry.register;
38
+ * 拦截器/候选类清单等无运行时注册表的类型用) */
39
+ registerMeta(type: HandlerType, meta: Omit<HandlerMeta, 'type'>): void;
33
40
  resolveAssignment(name: string): IAssignmentHandler | undefined;
34
41
  resolveDecision(name: string): IDecisionHandler | undefined;
35
- /** 按处理器类型列出可用实现的元数据(typeName: AssignmentHandler / DecisionHandler,按 order 升序) */
36
- listHandlers(typeName: 'AssignmentHandler' | 'DecisionHandler'): HandlerMeta[];
42
+ /** 按处理器类型列出可用实现的元数据(按 order 升序;
43
+ * AssignmentHandler/DecisionHandler 并集运行时注册名,其余类型只列显式元数据) */
44
+ listHandlers(typeName: HandlerType): HandlerMeta[];
37
45
  /** 按处理器类型 + 分组列出(拦截器 pre/post) */
38
- listHandlersGroup(typeName: 'AssignmentHandler' | 'DecisionHandler', group: string): HandlerMeta[];
46
+ listHandlersGroup(typeName: HandlerType, group: string): HandlerMeta[];
39
47
  /** 已注册的处理器名称清单(含未带元数据的) */
40
48
  listHandlerNames(): string[];
41
49
  }
package/dist/registry.js CHANGED
@@ -1,12 +1,12 @@
1
1
  /** 内置通用 AssignmentHandler 元数据(v1.6.0 issues/16,注册名与 Java 类全限定名一致,四语言通用) */
2
2
  export const BUILTIN_ASSIGNMENT_METAS = [
3
- { name: 'com.mldong.jeeflow.interceptor.impl.OperatorAssignmentHandler', displayName: '流程发起人', order: -9999 },
4
- { name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$ApplicantDeptLeaderAssignmentHandler', displayName: '发起人所属部门经理', order: 10 },
5
- { name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$ApplicantDeptMainLeaderAssignmentHandler', displayName: '发起人所属部门分管领导', order: 20 },
6
- { name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$DeptLeaderAssignmentHandler', displayName: '当前用户所属部门经理', order: 30 },
7
- { name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$DeptMainLeaderAssignmentHandler', displayName: '当前用户所属部门分管领导', order: 40 },
8
- { name: 'com.mldong.jeeflow.interceptor.impl.FormFieldAssigneeHandler', displayName: '根据表单字段值分配参与者', order: 50 },
9
- { name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$TaskRoleAssigneeHandler', displayName: '根据任务节点唯一编码关联角色分配参与者', order: 60 },
3
+ { type: 'AssignmentHandler', name: 'com.mldong.jeeflow.interceptor.impl.OperatorAssignmentHandler', displayName: '流程发起人', order: -9999 },
4
+ { type: 'AssignmentHandler', name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$ApplicantDeptLeaderAssignmentHandler', displayName: '发起人所属部门经理', order: 10 },
5
+ { type: 'AssignmentHandler', name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$ApplicantDeptMainLeaderAssignmentHandler', displayName: '发起人所属部门分管领导', order: 20 },
6
+ { type: 'AssignmentHandler', name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$DeptLeaderAssignmentHandler', displayName: '当前用户所属部门经理', order: 30 },
7
+ { type: 'AssignmentHandler', name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$DeptMainLeaderAssignmentHandler', displayName: '当前用户所属部门分管领导', order: 40 },
8
+ { type: 'AssignmentHandler', name: 'com.mldong.jeeflow.interceptor.impl.FormFieldAssigneeHandler', displayName: '根据表单字段值分配参与者', order: 50 },
9
+ { type: 'AssignmentHandler', name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$TaskRoleAssigneeHandler', displayName: '根据任务节点唯一编码关联角色分配参与者', order: 60 },
10
10
  ];
11
11
  /** 处理器注册表——按名称注册/解析 + 元数据清单(对标 Spring IoC / Java HandlerRegistry) */
12
12
  export class HandlerRegistry {
@@ -22,12 +22,17 @@ export class HandlerRegistry {
22
22
  registerAssignment(name, handler, meta) {
23
23
  this.assignments.set(name, handler);
24
24
  if (meta)
25
- this.metas.set(name, { name, ...meta });
25
+ this.metas.set(name, { type: 'AssignmentHandler', name, ...meta });
26
26
  }
27
27
  registerDecision(name, handler, meta) {
28
28
  this.decisions.set(name, handler);
29
29
  if (meta)
30
- this.metas.set(name, { name, ...meta });
30
+ this.metas.set(name, { type: 'DecisionHandler', name, ...meta });
31
+ }
32
+ /** 注册处理器元数据(不绑定运行时实现,对齐 Java HandlerRegistry.register;
33
+ * 拦截器/候选类清单等无运行时注册表的类型用) */
34
+ registerMeta(type, meta) {
35
+ this.metas.set(meta.name, { type, ...meta });
31
36
  }
32
37
  resolveAssignment(name) {
33
38
  return this.assignments.get(name);
@@ -36,14 +41,24 @@ export class HandlerRegistry {
36
41
  return this.decisions.get(name);
37
42
  }
38
43
  // ── SPI 实现清单(v1.4.0)──
39
- /** 按处理器类型列出可用实现的元数据(typeName: AssignmentHandler / DecisionHandler,按 order 升序) */
44
+ /** 按处理器类型列出可用实现的元数据(按 order 升序;
45
+ * AssignmentHandler/DecisionHandler 并集运行时注册名,其余类型只列显式元数据) */
40
46
  listHandlers(typeName) {
41
- const names = typeName === 'AssignmentHandler'
42
- ? [...this.assignments.keys(), ...this.metas.keys()]
43
- : [...this.decisions.keys(), ...this.metas.keys()];
44
- // 内置 meta 属于 AssignmentHandler 类型——DecisionHandler 只列注册过的
45
- const unique = typeName === 'AssignmentHandler' ? names : this.decisions.keys();
46
- return [...new Set(unique)]
47
+ const names = new Set();
48
+ if (typeName === 'AssignmentHandler') {
49
+ for (const n of this.assignments.keys())
50
+ names.add(n);
51
+ }
52
+ else if (typeName === 'DecisionHandler') {
53
+ for (const n of this.decisions.keys())
54
+ names.add(n);
55
+ }
56
+ for (const [n, m] of this.metas) {
57
+ // 老数据无 type 时按 AssignmentHandler 归类(与历史 listHandlers 行为一致)
58
+ if ((m.type ?? 'AssignmentHandler') === typeName)
59
+ names.add(n);
60
+ }
61
+ return [...names]
47
62
  .map(n => this.metas.get(n) ?? { name: n })
48
63
  .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
49
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mldong/jeeflow",
3
- "version": "1.8.12",
3
+ "version": "1.8.13",
4
4
  "description": "jeeflow workflow engine — Node.js / TypeScript implementation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",