@yss123/cage-kernel 0.2.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 +70 -10
  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 +32 -0
  12. package/dist/db/ddl.js +36 -0
  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 +3 -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 +12 -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 +11 -2
  42. package/dist/index.js +11 -2
  43. package/dist/index.js.map +1 -1
  44. package/dist/kernel.d.ts +86 -0
  45. package/dist/kernel.js +65 -40
  46. package/dist/kernel.js.map +1 -1
  47. package/dist/mask.d.ts +6 -0
  48. package/dist/mask.js +6 -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 +13 -0
  64. package/dist/pipeline/load.js.map +1 -1
  65. package/dist/primitives/aggregate.d.ts +95 -2
  66. package/dist/primitives/aggregate.js +13 -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 +10 -1
  82. package/dist/primitives/event.js.map +1 -1
  83. package/dist/primitives/fields.d.ts +136 -16
  84. package/dist/primitives/fields.js +104 -13
  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 +31 -1
  93. package/dist/read.js +137 -39
  94. package/dist/read.js.map +1 -1
  95. package/dist/registry.d.ts +51 -1
  96. package/dist/registry.js +79 -5
  97. package/dist/registry.js.map +1 -1
  98. package/dist/relations.d.ts +7 -0
  99. package/dist/relations.js +7 -0
  100. package/dist/relations.js.map +1 -1
  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 +11 -0
  111. package/dist/transfer/csv.js +11 -0
  112. package/dist/transfer/csv.js.map +1 -1
  113. package/dist/transfer/index.d.ts +18 -0
  114. package/dist/transfer/index.js +34 -8
  115. package/dist/transfer/index.js.map +1 -1
  116. package/dist/transfer/schema.d.ts +5 -0
  117. package/dist/transfer/schema.js +5 -0
  118. package/dist/transfer/schema.js.map +1 -1
  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 +175 -38
  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
@@ -1,3 +1,7 @@
1
+ /**
2
+ * 声明唯一领域写入口及 handler 可使用的输入、草稿、读依赖和调用信息。
3
+ * command 构造冻结规格,注册表确定能力名称,内核流水线执行状态、权限、版本、约束、事务、审计和事件;本文件不发 HTTP、不连接数据库、不执行 handler。
4
+ */
1
5
  import { z } from 'zod';
2
6
  import { COMMAND } from '../brands.js';
3
7
  import { type DomainError } from '../errors.js';
@@ -7,31 +11,54 @@ import type { Constraint } from './constraints.js';
7
11
  import { type AnyEvent, type EmitSpec } from './event.js';
8
12
  /** reads 的形状:别名 → 聚合 */
9
13
  export type Reads = Record<string, AnyAggregate>;
14
+ /** handler 读依赖的有界查询选项;orderBy 使用业务字段名,底层负责映射与校验。 */
10
15
  export interface FindOptions {
16
+ /**
17
+ * 期望返回条数;实现默认 1000、最多 5000,不提供 offset 或全量保证,业务应选择合理正整数。
18
+ */
11
19
  limit?: number;
20
+ /**
21
+ * 排序业务字段或系统字段名;省略时按 createdAt 升序,未知字段及集合关系拒绝。
22
+ */
12
23
  orderBy?: string;
24
+ /**
25
+ * 提供 orderBy 时是否降序,省略/false 为升序;未指定排序字段时不改变默认创建时间顺序。
26
+ */
13
27
  desc?: boolean;
14
28
  }
15
- /** 注入给 handler 的只读仓储:自动附加数据范围,范围外等于不存在 */
29
+ /**
30
+ * 注入 handler 的只读仓储,绑定本次命令事务及当前数据范围,范围外对象按不存在处理。
31
+ * 返回供服务端业务计算使用的内部快照,不是浏览器安全呈现 DTO;不要直接把它作为公开响应或绕过掩码输出。
32
+ * 没有写方法,find/findOne 只接受声明列的等值条件;事务内读取本身不保证其他聚合的后续并发写已被锁定。
33
+ */
16
34
  export interface ReadRepo<A extends AnyAggregate> {
17
- /** 按 id 取一条,范围外返回 null */
35
+ /** 按 UUID 取一条内部快照,不存在、范围外或明显非法 ID 返回 null;不会取得业务更新行锁。 */
18
36
  get(id: string): Promise<SnapshotOf<A> | null>;
19
- /** 等值条件查询,自动附加范围 */
37
+ /** 按等值条件读取范围内列表,省略 where 不加额外业务筛选;undefined 条件忽略,null 使用 IS NULL,集合/JSON 不能作主表筛选。 */
20
38
  find(where?: Partial<SnapshotOf<A>>, opts?: FindOptions): Promise<SnapshotOf<A>[]>;
21
- /** 按条件取第一条 */
39
+ /** 按等值条件取默认创建时间升序的第一条,未命中为 null;不表示条件在数据库中具有唯一约束。 */
22
40
  findOne(where: Partial<SnapshotOf<A>>): Promise<SnapshotOf<A> | null>;
23
- /** 计数,同样自动附加范围 */
41
+ /** 统计相同租户/范围内的等值条件记录数,不使用 find 的返回数量上限;未知字段及 JSON/集合条件会拒绝。 */
24
42
  count(where?: Partial<SnapshotOf<A>>): Promise<number>;
25
43
  }
44
+ /**
45
+ * 按 reads 的每个别名推导只读仓储类型;只读映射禁止替换依赖,不提供写接口。
46
+ * 运行时访问未声明别名仍会失败,类型擦除不能绕过 CAGE-READS-001 门禁。
47
+ */
26
48
  export type DepsOf<R extends Reads> = {
27
49
  readonly [K in keyof R]: ReadRepo<R[K]>;
28
50
  };
29
51
  /** handler 拿到的草稿:业务字段可改;状态、主键、版本号只读,handler 改不了 */
30
52
  export type Draft<A extends AnyAggregate> = FieldValuesOf<A> & {
53
+ /** 新建草稿或当前对象的 UUID,只读,handler 不得更换对象身份。 */
31
54
  readonly id: string;
55
+ /** 执行 handler 时的草稿/当前状态,只读;目标状态由命令 to 在合并后确定。 */
32
56
  readonly status: StateOf<A>;
57
+ /** handler 所见草稿版本或已加载版本,只读;内核提交时维护版本递增。 */
33
58
  readonly version: number;
59
+ /** 原始创建时间字符串,新建使用本次固定时间,handler 不改写。 */
34
60
  readonly createdAt: string;
61
+ /** 本次草稿或已加载记录的更新时间字符串,最终更新时间由流水线设定。 */
35
62
  readonly updatedAt: string;
36
63
  };
37
64
  /** handler 的第四个参数:只读的调用信息 */
@@ -41,24 +68,64 @@ export interface HandlerCtx {
41
68
  /** 真人操作者(系统身份时为它代表的人) */
42
69
  readonly actorUserId: string | null;
43
70
  }
71
+ /** 可直接修改草稿并返回 void,或返回字段补丁;DomainError 会终止整笔命令事务。 */
44
72
  export type HandlerResult<A extends AnyAggregate> = Draft<A> | Partial<FieldValuesOf<A>> | DomainError | void;
73
+ /**
74
+ * 命令声明可选择的调用入口种类。
75
+ * 用户/匿名入口必须包含 user;框架反应按 process 入口解释,内部系统身份有专用路径。声明入口不等于授权,能力、范围和调度器 calls 白名单仍分别检查。
76
+ */
45
77
  export type Invoker = 'user' | 'process' | 'job' | 'external';
78
+ /**
79
+ * 一次业务写入的完整规格。input 验证调用参数,reads 列明只读依赖,constraints 在 handler 前执行,
80
+ * emits 在业务写入成功后进入同事务 outbox;handler 不能代替权限、版本或状态检查。
81
+ */
46
82
  export interface Command<A extends AnyAggregate = AnyAggregate, R extends Reads = Reads, I extends z.ZodType = z.ZodType> {
83
+ /**
84
+ * 声明品牌标记,供注册表识别顶层导出,不表示命令已执行。
85
+ */
47
86
  readonly [COMMAND]: true;
87
+ /**
88
+ * 本命令唯一写入的聚合定义;跨聚合变化通过声明反应/其他命令组合。
89
+ */
48
90
  readonly agg: A;
91
+ /**
92
+ * new 表示创建;否则为规范化冻结的允许起始状态列表,实际当前状态不匹配返回 INVALID_TRANSITION。
93
+ */
49
94
  readonly from: readonly StateOf<A>[] | 'new';
50
95
  /** null 表示保持加锁读到的当前状态;仍检查 from、权限、版本并写审计。 */
51
96
  readonly to: StateOf<A> | null;
97
+ /**
98
+ * 命令输入 Zod schema,handler 接收 z.output 转换后的值;expectedVersion 由流水线单独处理。
99
+ */
52
100
  readonly input: I;
101
+ /**
102
+ * 别名到聚合的冻结声明,运行时在当前事务/范围内绑定只读仓储;不因声明获得任意数据库连接。
103
+ */
53
104
  readonly reads: R;
105
+ /**
106
+ * 规范化事件及可选载荷映射列表;最终状态通过校验后与业务写入共同进入事务/outbox。
107
+ */
54
108
  readonly emits: readonly EmitSpec[];
109
+ /**
110
+ * handler 前依次执行的硬约束,拒绝会回滚命令事务;与最终不变量检查职责不同。
111
+ */
55
112
  readonly constraints: readonly Constraint<A>[];
113
+ /**
114
+ * 规范化调用入口列表,默认 [user];仍需能力和数据范围检查,不能把被流程选中当作授权。
115
+ */
56
116
  readonly invokedBy: readonly Invoker[];
57
- /** 匿名用户也能调用(极少使用) */
117
+ /** 显式公开命令,默认 false;允许 anonymous 主体并跳过能力点检查,但不跳过调用身份、范围、状态、版本及业务约束。 */
58
118
  readonly public: boolean;
59
119
  /** 显式命令名;不写时取导出名 */
60
120
  readonly name?: string;
121
+ /**
122
+ * 可选命令用途说明,供目录、本体和生成文档展示,不改变能力名称或执行策略。
123
+ */
61
124
  readonly description?: string;
125
+ /**
126
+ * 在框架草稿、已解析输入和已声明只读依赖上描述业务字段变化。
127
+ * 可返回草稿、字段补丁、void 或 DomainError;状态/版本由流水线维护,外部 IO 应走连接器,不由此回调自行提交数据库事务。
128
+ */
62
129
  readonly handler: (o: Draft<A>, input: z.output<I>, deps: DepsOf<R>, ctx: HandlerCtx) => MaybePromise<HandlerResult<A>>;
63
130
  }
64
131
  /**
@@ -68,34 +135,66 @@ export interface Command<A extends AnyAggregate = AnyAggregate, R extends Reads
68
135
  * command() 的返回值仍保留 A/R/I,调用处的类型推导不受这个内部容器类型影响。
69
136
  */
70
137
  export type AnyCommand = Omit<Command<AnyAggregate, Reads, z.ZodType>, 'handler'> & {
138
+ /** 注册表内部擦除 handler 参数类型以容纳不同聚合/reads;业务 command 返回类型仍精确保留输入与依赖。 */
71
139
  readonly handler: (...args: any[]) => MaybePromise<any>;
72
140
  };
141
+ /**
142
+ * 已有对象命令省略 input 时使用的默认 schema,只接收 UUID id;expectedVersion 由流水线作为并发元数据单独拆分。
143
+ */
73
144
  export declare const idOnly: z.ZodObject<{
74
145
  id: z.ZodString;
75
146
  }, z.core.$strip>;
147
+ /**
148
+ * 新建命令省略 input 时使用的默认空对象 schema;需要业务参数时应显式声明,聚合字段不会自动成为命令输入。
149
+ */
76
150
  export declare const empty: z.ZodObject<{}, z.core.$strip>;
151
+ /**
152
+ * 根据 from 是否为 new 推导省略 input 时的 schema,新建为空对象、已有对象默认 idOnly。
153
+ */
77
154
  type DefaultInput<F> = F extends 'new' ? typeof empty : typeof idOnly;
155
+ /**
156
+ * 应用传给 command 的原始声明选项,保留 from 与输入/读依赖泛型推导。
157
+ * 构造时规范化默认值和冻结容器;后续注册与执行仍检查跨声明关系、输入、授权和业务状态,不能把成功构造当作可执行证明。
158
+ */
78
159
  export interface CommandDef<A extends AnyAggregate, R extends Reads, I extends z.ZodType, F> {
79
160
  /** 起始状态;'new' 表示新建 */
80
161
  from: F;
81
162
  /** 目标状态;非新建命令可显式写 null,只更新业务字段而不迁移状态。 */
82
163
  to: F extends 'new' ? StateOf<A> : StateOf<A> | null;
83
- /** 输入校验;非新建命令的输入必须包含 id */
164
+ /** 输入校验,handler 收到解析后的值;省略时新建为 {}、已有记录为 { id: uuid },已有记录显式 schema 必须提供 id。 */
84
165
  input?: I;
85
- /** 读依赖,决定 handler 能拿到什么 */
166
+ /** 别名到聚合的只读依赖,默认空;handler 只获得这些仓储,运行时访问未声明别名会报 CAGE-READS-001。 */
86
167
  reads?: R;
87
- /** 发出的事件 */
168
+ /** 默认空;可传事件声明或 emit 显式映射,载荷在最终快照形成后校验,并与命令写入同事务保存。 */
88
169
  emits?: (AnyEvent | EmitSpec)[];
89
- /** 硬约束组合子 */
170
+ /** 默认空;handler 前按声明顺序执行的硬约束,拒绝或异常中止整笔命令,不代替最终不变量。 */
90
171
  constraints?: NoInfer<Constraint<A>>[];
91
172
  /** 谁能调用,默认 user */
92
173
  invokedBy?: Invoker | Invoker[];
174
+ /**
175
+ * 默认 false;true 允许显式匿名主体且跳过该命令能力检查,仍受调用身份、状态、范围、版本及业务约束限制,不能用于普通业务提权。
176
+ */
93
177
  public?: boolean;
178
+ /**
179
+ * 可选小驼峰命令名;省略时由顶层导出名推导,能力最终为 Aggregate.commandName。
180
+ */
94
181
  name?: string;
182
+ /**
183
+ * 面向能力目录和本体的业务说明,应写操作意图及边界,不承担运行时约束。
184
+ */
95
185
  description?: string;
96
- /** AI 写的业务逻辑:纯函数,返回新草稿、字段变更或业务错误 */
186
+ /**
187
+ * 用可写业务草稿、解析后输入及受限读依赖描述业务变化,可同步或异步返回草稿、补丁、void 或 DomainError。
188
+ * 允许等待声明的只读依赖;状态/系统列由内核维护,外部副作用应声明连接器和事件,不在 handler 自行开连接或提交事务。
189
+ */
97
190
  handler: (o: Draft<A>, input: z.output<[I] extends [never] ? DefaultInput<F> : I>, deps: DepsOf<R>, ctx: HandlerCtx) => MaybePromise<HandlerResult<A>>;
98
191
  }
192
+ /**
193
+ * 构造命令描述,不执行业务,也不注册全局状态。新建默认空输入,更新默认只要求 id。
194
+ * from/to 必须属于聚合状态;更新可用 to:null 保留当前状态,新建必须指定真实目标状态。
195
+ * 命令名称可显式给出,也可稍后从 domain 导出名推断,因此仅写文件还不足以注册能力。
196
+ */
99
197
  export declare function command<A extends AnyAggregate, const F extends StateOf<A> | readonly StateOf<A>[] | 'new', R extends Reads = {}, I extends z.ZodType = never>(agg: A, def: CommandDef<A, R, I, F>): Command<A, R, [I] extends [never] ? DefaultInput<F> : I>;
198
+ /** 注册表识别顶层导出时使用;具体结构和跨声明关系由后续注册校验负责。 */
100
199
  export declare function isCommand(v: unknown): v is AnyCommand;
101
200
  export {};
@@ -1,3 +1,7 @@
1
+ /**
2
+ * 声明唯一领域写入口及 handler 可使用的输入、草稿、读依赖和调用信息。
3
+ * command 构造冻结规格,注册表确定能力名称,内核流水线执行状态、权限、版本、约束、事务、审计和事件;本文件不发 HTTP、不连接数据库、不执行 handler。
4
+ */
1
5
  // command 原语:一次写操作。命令名由导出的变量名决定:export const approve = command(PurchaseOrder, …)
2
6
  // 的能力点就是 PurchaseOrder.approve。
3
7
  import { z } from 'zod';
@@ -5,8 +9,19 @@ import { COMMAND } from '../brands.js';
5
9
  import { declError } from '../errors.js';
6
10
  import { hasStates, } from './aggregate.js';
7
11
  import { toEmitSpec } from './event.js';
12
+ /**
13
+ * 已有对象命令省略 input 时使用的默认 schema,只接收 UUID id;expectedVersion 由流水线作为并发元数据单独拆分。
14
+ */
8
15
  export const idOnly = z.object({ id: z.string().uuid() });
16
+ /**
17
+ * 新建命令省略 input 时使用的默认空对象 schema;需要业务参数时应显式声明,聚合字段不会自动成为命令输入。
18
+ */
9
19
  export const empty = z.object({});
20
+ /**
21
+ * 构造命令描述,不执行业务,也不注册全局状态。新建默认空输入,更新默认只要求 id。
22
+ * from/to 必须属于聚合状态;更新可用 to:null 保留当前状态,新建必须指定真实目标状态。
23
+ * 命令名称可显式给出,也可稍后从 domain 导出名推断,因此仅写文件还不足以注册能力。
24
+ */
10
25
  export function command(agg, def) {
11
26
  const from = def.from;
12
27
  if (from !== 'new' && !hasStates(agg, from)) {
@@ -43,6 +58,7 @@ export function command(agg, def) {
43
58
  handler: def.handler,
44
59
  });
45
60
  }
61
+ /** 注册表识别顶层导出时使用;具体结构和跨声明关系由后续注册校验负责。 */
46
62
  export function isCommand(v) {
47
63
  return !!v && typeof v === 'object' && v[COMMAND] === true;
48
64
  }
@@ -1 +1 @@
1
- {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/primitives/command.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/primitives/command.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,28 @@
1
+ /**
2
+ * 提供命令 handler 之前执行的硬约束协议与职责分离、额度、二次认证组合子。
3
+ * 流水线在读取当前对象后传入可信 ctx 和受限元数据,约束只判断是否允许继续;最终字段与不变量校验仍在 handler 后进行,约束通过不等于命令必然提交。
4
+ */
1
5
  import type { CapabilityParams, Ctx, MaybePromise } from '../types.js';
6
+ /** 预期拒绝用失败结果表达;内部故障可抛异常,不能被伪装成约束通过。 */
2
7
  export type ConstraintResult = {
3
8
  ok: true;
4
9
  } | {
5
- ok: false;
10
+ ok: false; /** 业务拒绝说明,可能进入诊断;不要拼入不应公开的敏感数据。 */
6
11
  message: string;
7
12
  };
13
+ /**
14
+ * 构造明确的约束通过结果;仅表示当前规则通过,不授予能力或跳过后续规则。
15
+ */
8
16
  export declare const ok: () => ConstraintResult;
17
+ /**
18
+ * 构造预期业务拒绝结果并保留说明,流水线据此抛约束失败、回滚命令。
19
+ * 说明可能进入业务诊断,避免拼入密钥或无权公开的明文。
20
+ */
9
21
  export declare const violation: (message: string) => ConstraintResult;
22
+ /**
23
+ * 框架为当前约束提供的命令能力名、当前租户能力查询和范围读取工具。
24
+ * 不暴露任意数据库写入;自定义约束应把所用业务字段记入 fields 以支持影响分析。
25
+ */
10
26
  export interface ConstraintMeta {
11
27
  /** 正在执行的命令的能力点,例如 PurchaseOrder.approve */
12
28
  capability: string;
@@ -17,11 +33,19 @@ export interface ConstraintMeta {
17
33
  /** 能力目录 */
18
34
  catalog(): string[];
19
35
  }
36
+ /**
37
+ * 命令加载记录后、handler 前执行的守卫;current 是当前记录,input 尚未成为持久状态。
38
+ * fields 为静态依赖证据,check 才是实际判断。约束通过不代表随后 handler 或不变量一定成功。
39
+ */
20
40
  export interface Constraint<_A = any> {
21
41
  /** 约束名,出现在本体图和报错里 */
22
42
  readonly name: string;
23
43
  /** 用到的字段,抽取器据此画 uses 边,影响分析能找到它 */
24
44
  readonly fields?: readonly string[];
45
+ /**
46
+ * 接收当前快照、可信身份、已解析输入和框架元数据,返回同步或异步 ConstraintResult。
47
+ * 返回 ok:false 表示业务拒绝,抛异常表示依赖/实现故障;不得把失败吞成 ok,也不在检查中提交业务副作用。
48
+ */
25
49
  readonly check: (current: any, ctx: Ctx, input: any, meta: ConstraintMeta) => MaybePromise<ConstraintResult>;
26
50
  }
27
51
  /** 职责分离:操作人(或系统身份代表的真人)不能是该字段记录的人,例如提单人不能审批 */
@@ -29,8 +53,13 @@ export declare const sod: {
29
53
  notSameAs(field: string): Constraint;
30
54
  };
31
55
  /** 额度:字段值不得超过操作人在该能力点上的 ceiling 参数;多角色取最大值 */
56
+ /**
57
+ * 审批等系统身份优先读取 onBehalfOf 真人当前能力参数,避免流程本身的能力集合绕过额度。
58
+ * 未配置参数即拒绝;金额字符串在此转成 Number 比较,业务仍需在字段/handler 中保证值合法。
59
+ */
32
60
  export declare function ceiling(field: string, param?: string): Constraint;
33
61
  /** 二次认证:最近 maxAgeSec 秒内完成过二次认证 */
62
+ /** maxAgeSec 单位为秒,ctx.stepUpAt 单位为毫秒;缺失认证证据时返回拒绝而非跳过。 */
34
63
  export declare function stepUp(maxAgeSec?: number): Constraint;
35
64
  /** 自定义约束(仍然是一个纯函数,必须写清楚用到哪些字段) */
36
65
  export declare function constraint(name: string, fields: string[], check: Constraint['check']): Constraint;
@@ -1,4 +1,11 @@
1
+ /**
2
+ * 构造明确的约束通过结果;仅表示当前规则通过,不授予能力或跳过后续规则。
3
+ */
1
4
  export const ok = () => ({ ok: true });
5
+ /**
6
+ * 构造预期业务拒绝结果并保留说明,流水线据此抛约束失败、回滚命令。
7
+ * 说明可能进入业务诊断,避免拼入密钥或无权公开的明文。
8
+ */
2
9
  export const violation = (message) => ({ ok: false, message });
3
10
  /** 职责分离:操作人(或系统身份代表的真人)不能是该字段记录的人,例如提单人不能审批 */
4
11
  export const sod = {
@@ -8,12 +15,18 @@ export const sod = {
8
15
  fields: [field],
9
16
  check: (cur, ctx) => {
10
17
  const who = ctx.onBehalfOf ?? ctx.userId;
18
+ if (!who)
19
+ return violation('职责分离需要可核验的操作人身份');
11
20
  return who && cur[field] === who ? violation(`操作人不能是 ${field} 记录的人(职责分离)`) : ok();
12
21
  },
13
22
  });
14
23
  },
15
24
  };
16
25
  /** 额度:字段值不得超过操作人在该能力点上的 ceiling 参数;多角色取最大值 */
26
+ /**
27
+ * 审批等系统身份优先读取 onBehalfOf 真人当前能力参数,避免流程本身的能力集合绕过额度。
28
+ * 未配置参数即拒绝;金额字符串在此转成 Number 比较,业务仍需在字段/handler 中保证值合法。
29
+ */
17
30
  export function ceiling(field, param = 'ceiling') {
18
31
  return Object.freeze({
19
32
  name: `ceiling(${field})`,
@@ -28,6 +41,7 @@ export function ceiling(field, param = 'ceiling') {
28
41
  });
29
42
  }
30
43
  /** 二次认证:最近 maxAgeSec 秒内完成过二次认证 */
44
+ /** maxAgeSec 单位为秒,ctx.stepUpAt 单位为毫秒;缺失认证证据时返回拒绝而非跳过。 */
31
45
  export function stepUp(maxAgeSec = 300) {
32
46
  return Object.freeze({
33
47
  name: 'stepUp',
@@ -1 +1 @@
1
- {"version":3,"file":"constraints.js","sourceRoot":"","sources":["../../src/primitives/constraints.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,EAAE,GAAG,GAAqB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;AACzD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,OAAe,EAAoB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;AAqBzF,+CAA+C;AAC/C,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,SAAS,CAAC,KAAa;QACrB,OAAO,MAAM,CAAC,MAAM,CAAC;YACnB,IAAI,EAAE,iBAAiB,KAAK,GAAG;YAC/B,MAAM,EAAE,CAAC,KAAK,CAAC;YACf,KAAK,EAAE,CAAC,GAAQ,EAAE,GAAQ,EAAE,EAAE;gBAC5B,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,MAAM,CAAC;gBACzC,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,KAAK,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACpF,CAAC;SACF,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,8CAA8C;AAC9C,MAAM,UAAU,OAAO,CAAC,KAAa,EAAE,KAAK,GAAG,SAAS;IACtD,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,IAAI,EAAE,WAAW,KAAK,GAAG;QACzB,MAAM,EAAE,CAAC,KAAK,CAAC;QACf,KAAK,EAAE,KAAK,EAAE,GAAQ,EAAE,GAAQ,EAAE,MAAW,EAAE,IAAoB,EAAE,EAAE;YACrE,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;YAC3F,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;YACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,SAAS,CAAC,OAAO,IAAI,CAAC,UAAU,SAAS,KAAK,EAAE,CAAC,CAAC;YACpG,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;QACxG,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,MAAM,CAAC,SAAS,GAAG,GAAG;IACpC,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,CAAC,IAAS,EAAE,GAAQ,EAAE,EAAE,CAC7B,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,QAAQ,IAAI,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC;KAC7F,CAAC,CAAC;AACL,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,MAAgB,EAAE,KAA0B;IACnF,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AAChD,CAAC"}
1
+ {"version":3,"file":"constraints.js","sourceRoot":"","sources":["../../src/primitives/constraints.ts"],"names":[],"mappings":"AAUA;;GAEG;AACH,MAAM,CAAC,MAAM,EAAE,GAAG,GAAqB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;AACzD;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,OAAe,EAAoB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;AAiCzF,+CAA+C;AAC/C,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,SAAS,CAAC,KAAa;QACrB,OAAO,MAAM,CAAC,MAAM,CAAC;YACnB,IAAI,EAAE,iBAAiB,KAAK,GAAG;YAC/B,MAAM,EAAE,CAAC,KAAK,CAAC;YACf,KAAK,EAAE,CAAC,GAAQ,EAAE,GAAQ,EAAE,EAAE;gBAC5B,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,MAAM,CAAC;gBACzC,IAAI,CAAC,GAAG;oBAAE,OAAO,SAAS,CAAC,iBAAiB,CAAC,CAAC;gBAC9C,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,KAAK,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACpF,CAAC;SACF,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,8CAA8C;AAC9C;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,KAAa,EAAE,KAAK,GAAG,SAAS;IACtD,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,IAAI,EAAE,WAAW,KAAK,GAAG;QACzB,MAAM,EAAE,CAAC,KAAK,CAAC;QACf,KAAK,EAAE,KAAK,EAAE,GAAQ,EAAE,GAAQ,EAAE,MAAW,EAAE,IAAoB,EAAE,EAAE;YACrE,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;YAC3F,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;YACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,SAAS,CAAC,OAAO,IAAI,CAAC,UAAU,SAAS,KAAK,EAAE,CAAC,CAAC;YACpG,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;QACxG,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,kCAAkC;AAClC,yDAAyD;AACzD,MAAM,UAAU,MAAM,CAAC,SAAS,GAAG,GAAG;IACpC,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,CAAC,IAAS,EAAE,GAAQ,EAAE,EAAE,CAC7B,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,QAAQ,IAAI,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC;KAC7F,CAAC,CAAC;AACL,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,MAAgB,EAAE,KAA0B;IACnF,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AAChD,CAAC"}
@@ -1,26 +1,62 @@
1
+ /**
2
+ * 定义领域事件及从命令前后快照构造载荷的映射规格。
3
+ * 命令流水线校验载荷并与业务写入同事务保存 outbox,再交给同事务反应或异步消费者;声明函数本身不会投递消息,也不保证第三方恰好一次收到。
4
+ */
1
5
  import { z } from 'zod';
2
6
  import { EVENT } from '../brands.js';
3
7
  import { type FieldValues, type Fields } from './fields.js';
8
+ /** 事件描述已发生的事实;字段是稳定传输载荷,不是聚合表结构或关联集合声明。 */
4
9
  export interface Event<N extends string = string, F extends Fields = Fields> {
10
+ /**
11
+ * 事件品牌标记,供注册表与 emits 归一化识别。
12
+ */
5
13
  readonly [EVENT]: true;
14
+ /**
15
+ * 稳定大驼峰事件名,作为持久 outbox 和消费者协议标识,已部署后修改含义需考虑兼容。
16
+ */
6
17
  readonly name: N;
18
+ /**
19
+ * 冻结载荷字段映射,不是持久聚合表;禁止集合关系和文件生命周期原语,关联使用 ID 值传递。
20
+ */
7
21
  readonly fields: F;
22
+ /**
23
+ * 由字段生成的载荷校验器,在事件持久化前验证必填、类型和可空规则。
24
+ */
8
25
  readonly schema: z.ZodObject<any>;
26
+ /**
27
+ * 可选事实含义说明,供目录和本体展示,不改变投递或事务行为。
28
+ */
9
29
  readonly description?: string;
10
30
  }
31
+ /**
32
+ * 不同事件名称/字段的异构容器类型,用于命令 emits、反应和注册表;事件声明返回值仍保留载荷字段类型。
33
+ */
11
34
  export type AnyEvent = Event<string, any>;
35
+ /**
36
+ * 从事件 Field 映射推导载荷业务值,不添加对象系统列;需要对象 ID 或旧状态时必须在事件 fields 中显式声明。
37
+ */
12
38
  export type PayloadOf<E> = E extends Event<any, infer F> ? FieldValues<F> : never;
39
+ /**
40
+ * 声明事件名称与严格字段规格;拒绝关系/文件生命周期原语,引用对象时应发送 ID。
41
+ * 此函数不投递事件;只有命令流水线完成载荷映射、校验并写入 outbox 后才形成事件事实。
42
+ */
13
43
  export declare function event<const N extends string, F extends Fields>(name: N, fields: F, opts?: {
14
44
  description?: string;
15
45
  }): Event<N, F>;
46
+ /** 区分裸事件声明与 emit 映射对象,避免构造命令时丢失显式载荷映射。 */
16
47
  export declare function isEvent(v: unknown): v is AnyEvent;
17
48
  /** 显式指定载荷怎么从快照得到:emits: [emit(OrderApproved, (o) => ({ orderId: o.id, items: o.items }))] */
18
49
  export interface EmitSpec<E extends AnyEvent = AnyEvent> {
50
+ /**
51
+ * 待发出的事件声明,决定载荷 schema 和后续反应订阅。
52
+ */
19
53
  readonly event: E;
20
54
  /** snapshot:写入后的快照;input:命令输入;previous:写入前的快照(新建时为 null) */
21
55
  readonly map?: (snapshot: any, input: any, previous: any) => PayloadOf<E>;
22
56
  }
57
+ /** 保存纯映射回调;previous 对新建为 null,可用于取消等需要旧状态决定资源释放的事件。 */
23
58
  export declare function emit<E extends AnyEvent>(ev: E, map: (snapshot: any, input: any, previous: any) => PayloadOf<E>): EmitSpec<E>;
59
+ /** 将两种 emits 写法归一化;裸事件留空 map,在执行时使用 defaultPayload。 */
24
60
  export declare function toEmitSpec(e: AnyEvent | EmitSpec): EmitSpec;
25
61
  /**
26
62
  * 默认载荷映射规则(没有写 emit(...) 时):
@@ -1,11 +1,17 @@
1
1
  import { EVENT } from '../brands.js';
2
2
  import { declError } from '../errors.js';
3
- import { isRelation, objectSchema } from './fields.js';
3
+ import { isRelation, isFile, objectSchema } from './fields.js';
4
+ /**
5
+ * 声明事件名称与严格字段规格;拒绝关系/文件生命周期原语,引用对象时应发送 ID。
6
+ * 此函数不投递事件;只有命令流水线完成载荷映射、校验并写入 outbox 后才形成事件事实。
7
+ */
4
8
  export function event(name, fields, opts) {
5
9
  if (!/^[A-Z][A-Za-z0-9]*$/.test(name))
6
10
  throw declError('CAGE-NAME-003', `事件名 ${name} 必须是大驼峰`);
7
11
  if (Object.values(fields).some(isRelation))
8
12
  throw declError('CAGE-REL-001', '事件载荷不声明持久化关系;传递 ID 数组请使用 list(id())');
13
+ if (Object.values(fields).some(isFile))
14
+ throw declError('CAGE-FILE-001', '事件传递文件 ID 请使用 id/list(id()),不声明文件生命周期');
9
15
  return Object.freeze({
10
16
  [EVENT]: true,
11
17
  name,
@@ -14,12 +20,15 @@ export function event(name, fields, opts) {
14
20
  description: opts?.description,
15
21
  });
16
22
  }
23
+ /** 区分裸事件声明与 emit 映射对象,避免构造命令时丢失显式载荷映射。 */
17
24
  export function isEvent(v) {
18
25
  return !!v && typeof v === 'object' && v[EVENT] === true;
19
26
  }
27
+ /** 保存纯映射回调;previous 对新建为 null,可用于取消等需要旧状态决定资源释放的事件。 */
20
28
  export function emit(ev, map) {
21
29
  return Object.freeze({ event: ev, map });
22
30
  }
31
+ /** 将两种 emits 写法归一化;裸事件留空 map,在执行时使用 defaultPayload。 */
23
32
  export function toEmitSpec(e) {
24
33
  return isEvent(e) ? { event: e } : e;
25
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"event.js","sourceRoot":"","sources":["../../src/primitives/event.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAiC,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAatF,MAAM,UAAU,KAAK,CAA2C,IAAO,EAAE,MAAS,EAAE,IAA+B;IACjH,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,SAAS,CAAC,eAAe,EAAE,OAAO,IAAI,SAAS,CAAC,CAAC;IAC9F,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;QAAE,MAAM,SAAS,CAAC,cAAc,EAAE,qCAAqC,CAAC,CAAC;IACnH,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,CAAC,KAAK,CAAC,EAAE,IAAa;QACtB,IAAI;QACJ,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC;QACpC,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC;QAC5B,WAAW,EAAE,IAAI,EAAE,WAAW;KAC/B,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,CAAU;IAChC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAK,CAAS,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;AACpE,CAAC;AASD,MAAM,UAAU,IAAI,CAAqB,EAAK,EAAE,GAA+D;IAC7G,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAsB;IAC/C,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,EAAY,EAAE,QAAiC,EAAE,KAA8B;IAC5G,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,QAAQ;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;aACnC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;aAC3C,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"event.js","sourceRoot":"","sources":["../../src/primitives/event.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAiC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAmC9F;;;GAGG;AACH,MAAM,UAAU,KAAK,CAA2C,IAAO,EAAE,MAAS,EAAE,IAAwE;IAC1J,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,SAAS,CAAC,eAAe,EAAE,OAAO,IAAI,SAAS,CAAC,CAAC;IAC9F,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;QAAE,MAAM,SAAS,CAAC,cAAc,EAAE,qCAAqC,CAAC,CAAC;IACnH,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,MAAM,SAAS,CAAC,eAAe,EAAE,uCAAuC,CAAC,CAAC;IAClH,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,CAAC,KAAK,CAAC,EAAE,IAAa;QACtB,IAAI;QACJ,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC;QACpC,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC;QAC5B,WAAW,EAAE,IAAI,EAAE,WAAW;KAC/B,CAAC,CAAC;AACL,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,OAAO,CAAC,CAAU;IAChC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAK,CAAS,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;AACpE,CAAC;AAYD,uDAAuD;AACvD,MAAM,UAAU,IAAI,CAAqB,EAAK,EAAE,GAA+D;IAC7G,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,UAAU,CAAC,CAAsB;IAC/C,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,EAAY,EAAE,QAAiC,EAAE,KAA8B;IAC5G,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,QAAQ;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;aACnC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;aAC3C,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}