@shwfed/config 2.11.1 → 2.11.5

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 (139) hide show
  1. package/dist/mcp.mjs +1592 -1220
  2. package/dist/module.json +1 -1
  3. package/dist/preview/assets/{FieldGroup.vue_vue_type_script_setup_true_lang-CosmpPSu.js → FieldGroup.vue_vue_type_script_setup_true_lang-BK4nj6mF.js} +1 -1
  4. package/dist/preview/assets/{badge-BkYCxTFK.js → badge-Df9KgnrB.js} +1 -1
  5. package/dist/preview/assets/config-B3NwVBxT.js +1 -0
  6. package/dist/preview/assets/{config-Dt8k1gnT.js → config-BrtNnMlJ.js} +1 -1
  7. package/dist/preview/assets/{config-Cbp7aAAw.js → config-CUJNegvX.js} +1 -1
  8. package/dist/preview/assets/{config-C_Ia1CDq.js → config-ChrXUmKf.js} +1 -1
  9. package/dist/preview/assets/{config-B62b9dMF.js → config-CmEXMpIU.js} +1 -1
  10. package/dist/preview/assets/{config-Dk9OegYx.js → config-CrBoFiYB.js} +1 -1
  11. package/dist/preview/assets/{config-74YmXQsH.js → config-D-Hf0dls.js} +1 -1
  12. package/dist/preview/assets/{config-Bt6--diX.js → config-D4cXwy75.js} +1 -1
  13. package/dist/preview/assets/{config-BcZe-bR9.js → config-DCj5Qyiq.js} +1 -1
  14. package/dist/preview/assets/{config-sCP15_0f.js → config-DPfx03nM.js} +1 -1
  15. package/dist/preview/assets/{config-Bbbyd5lB.js → config-DWF0bcmF.js} +1 -1
  16. package/dist/preview/assets/{config-CPsd0ppi.js → config-Do4K9hI7.js} +1 -1
  17. package/dist/preview/assets/config-DwblM1r8.js +1 -0
  18. package/dist/preview/assets/{config-CYVafGLc.js → config-MW5Hs8yE.js} +1 -1
  19. package/dist/preview/assets/{config-COr2MFhN.js → config-uNoNEc-1.js} +1 -1
  20. package/dist/preview/assets/{definition.vue_vue_type_script_setup_true_lang-C3NiB99t.js → definition.vue_vue_type_script_setup_true_lang-CbtpddWK.js} +1 -1
  21. package/dist/preview/assets/index-Bm7I4Tr0.css +1 -0
  22. package/dist/preview/assets/{index-DjG-VVR4.js → index-CkyV576r.js} +217 -205
  23. package/dist/preview/assets/{index-BMOizF8g.js → index-CtW2E0ME.js} +1 -1
  24. package/dist/preview/assets/index-xDmBF3zO.js +1 -0
  25. package/dist/preview/assets/{item-C1efxuFt.js → item-D0e9Cx1Q.js} +1 -1
  26. package/dist/preview/assets/{runtime-Du0ghzR2.js → runtime-3tGIbclh.js} +1 -1
  27. package/dist/preview/assets/{runtime-7z9N9JGG.js → runtime-BCePD3XR.js} +1 -1
  28. package/dist/preview/assets/runtime-BMyFUaSM.js +1 -0
  29. package/dist/preview/assets/runtime-BXZU3EqA.js +1 -0
  30. package/dist/preview/assets/{runtime-LgZuN2Tf.js → runtime-BySNFNSO.js} +1 -1
  31. package/dist/preview/assets/{runtime-Dz7SCudL.js → runtime-CI02gDFj.js} +1 -1
  32. package/dist/preview/assets/{runtime-DoLpKFu-.js → runtime-DCo1Qp8a.js} +1 -1
  33. package/dist/preview/assets/runtime-DDSKV70N.js +1 -0
  34. package/dist/preview/assets/runtime-Dc7pytUy.js +1 -0
  35. package/dist/preview/assets/{runtime-S9eZ2nJS.js → runtime-ckLrkTMm.js} +1 -1
  36. package/dist/preview/assets/runtime-y4oJ8VkY.js +1 -0
  37. package/dist/preview/assets/{schema-meta-CYKPEnu9.js → schema-meta-D0y0sKal.js} +1 -1
  38. package/dist/preview/index.html +2 -2
  39. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/config.d.vue.ts +39 -0
  40. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/config.vue +127 -0
  41. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/config.vue.d.ts +39 -0
  42. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/runtime.d.vue.ts +8 -0
  43. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/runtime.vue +62 -0
  44. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/runtime.vue.d.ts +8 -0
  45. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/schema.d.ts +25 -0
  46. package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/schema.js +41 -0
  47. package/dist/runtime/components/config/blocks/2026-06-17/com.shwfed.block.tree.single/runtime.vue +5 -22
  48. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/config.d.vue.ts +70 -0
  49. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/config.vue +349 -0
  50. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/config.vue.d.ts +70 -0
  51. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/loop-item.d.vue.ts +33 -0
  52. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/loop-item.vue +37 -0
  53. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/loop-item.vue.d.ts +33 -0
  54. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/loop-scope-provider.d.vue.ts +13 -0
  55. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/loop-scope-provider.vue +22 -0
  56. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/loop-scope-provider.vue.d.ts +13 -0
  57. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/runtime.d.vue.ts +70 -0
  58. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/runtime.vue +62 -0
  59. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/runtime.vue.d.ts +70 -0
  60. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/schema.d.ts +85 -0
  61. package/dist/runtime/components/config/blocks/2026-06-25/com.shwfed.block.loop/schema.js +60 -0
  62. package/dist/runtime/components/form/fields/2026-04-22/com.shwfed.form.field.textarea/config.d.vue.ts +2 -2
  63. package/dist/runtime/components/form/fields/2026-04-22/com.shwfed.form.field.textarea/config.vue.d.ts +2 -2
  64. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.d.vue.ts +4 -4
  65. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue.d.ts +4 -4
  66. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.d.vue.ts +6 -6
  67. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue.d.ts +6 -6
  68. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.d.vue.ts +2 -2
  69. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.vue.d.ts +2 -2
  70. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.d.vue.ts +22 -22
  71. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.vue.d.ts +22 -22
  72. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.d.vue.ts +4 -4
  73. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.vue.d.ts +4 -4
  74. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/config.d.vue.ts +22 -22
  75. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/config.vue.d.ts +22 -22
  76. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/config.d.vue.ts +22 -22
  77. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/config.vue.d.ts +22 -22
  78. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/config.d.vue.ts +22 -22
  79. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/config.vue.d.ts +22 -22
  80. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/config.d.vue.ts +22 -22
  81. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/config.vue.d.ts +22 -22
  82. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/config.d.vue.ts +22 -22
  83. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/config.vue.d.ts +22 -22
  84. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/runtime.vue +2 -19
  85. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/config.d.vue.ts +22 -22
  86. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/config.vue.d.ts +22 -22
  87. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/runtime.vue +5 -22
  88. package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/config.d.vue.ts +2 -0
  89. package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/config.vue +49 -22
  90. package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/config.vue.d.ts +2 -0
  91. package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/runtime.js +17 -10
  92. package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/schema.d.ts +1 -0
  93. package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/schema.js +25 -3
  94. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.d.vue.ts +2 -2
  95. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.vue.d.ts +2 -2
  96. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-static/config.d.vue.ts +2 -2
  97. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-static/config.vue.d.ts +2 -2
  98. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.d.vue.ts +2 -2
  99. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.vue.d.ts +2 -2
  100. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-static/config.d.vue.ts +2 -2
  101. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-static/config.vue.d.ts +2 -2
  102. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/config.d.vue.ts +2 -2
  103. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/config.vue.d.ts +2 -2
  104. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/config.d.vue.ts +2 -2
  105. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/config.vue.d.ts +2 -2
  106. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-multi/runtime.vue +5 -1
  107. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-single/runtime.vue +5 -1
  108. package/dist/runtime/components/table/columns/2026-06-17/com.shwfed.table.column.date-input/config.vue +81 -2
  109. package/dist/runtime/components/table/columns/2026-06-17/com.shwfed.table.column.date-input/runtime.vue +35 -1
  110. package/dist/runtime/components/table/columns/2026-06-17/com.shwfed.table.column.date-input/schema.d.ts +132 -0
  111. package/dist/runtime/components/table/columns/2026-06-17/com.shwfed.table.column.date-input/schema.js +28 -2
  112. package/dist/runtime/components/ui/date-picker/DatePicker.d.vue.ts +11 -1
  113. package/dist/runtime/components/ui/date-picker/DatePicker.vue +8 -1
  114. package/dist/runtime/components/ui/date-picker/DatePicker.vue.d.ts +11 -1
  115. package/dist/runtime/components/ui/date-picker/DatePickerInput.d.vue.ts +12 -2
  116. package/dist/runtime/components/ui/date-picker/DatePickerInput.vue +4 -0
  117. package/dist/runtime/components/ui/date-picker/DatePickerInput.vue.d.ts +12 -2
  118. package/dist/runtime/components/ui/date-picker/DatePickerTimeInput.d.vue.ts +1 -1
  119. package/dist/runtime/components/ui/date-picker/DatePickerTimeInput.vue.d.ts +1 -1
  120. package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.d.vue.ts +1 -1
  121. package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.vue.d.ts +1 -1
  122. package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.d.vue.ts +2 -2
  123. package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.vue.d.ts +2 -2
  124. package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue +1 -1
  125. package/dist/runtime/share/loop-item-var.d.ts +21 -0
  126. package/dist/runtime/share/loop-item-var.js +13 -0
  127. package/dist/runtime/vendor/cel-js/CLAUDE.md +2 -2
  128. package/dist/runtime/vendor/cel-js/PROMPT.md +7 -0
  129. package/dist/runtime/vendor/cel-js/lib/functions.js +25 -1
  130. package/dist/runtime/vendor/cel-js/lib/http-builder.d.ts +38 -3
  131. package/dist/runtime/vendor/cel-js/lib/http-builder.js +33 -0
  132. package/package.json +1 -1
  133. package/dist/preview/assets/config-BHYlKhDX.js +0 -1
  134. package/dist/preview/assets/index-C9G8y6qZ.js +0 -1
  135. package/dist/preview/assets/index-DqRQ67sX.css +0 -1
  136. package/dist/preview/assets/runtime-Bpa1zRxG.js +0 -1
  137. package/dist/preview/assets/runtime-Csv04MYG.js +0 -1
  138. package/dist/preview/assets/runtime-D0bjM4NL.js +0 -1
  139. package/dist/preview/assets/runtime-Dz3ZQYdq.js +0 -1
@@ -49,6 +49,138 @@ export declare function schema(configure: (env: Environment) => void): Schema.St
49
49
  }>]>;
50
50
  value: Schema.Schema<string, string, never>;
51
51
  }>>>;
52
+ addon: Schema.optional<Schema.Struct<{
53
+ groups: Schema.optionalWith<Schema.Array$<Schema.Struct<{
54
+ id: Schema.refine<string, typeof Schema.String>;
55
+ variant: Schema.optional<Schema.Literal<["default", "primary", "destructive", "ghost", "link"]>>;
56
+ }>>, {
57
+ default: () => never[];
58
+ }>;
59
+ items: Schema.optionalWith<Schema.Array$<Schema.Schema<import("../../../../actions/schema.js").RegistryItemValue | {
60
+ readonly disabled?: string | undefined;
61
+ readonly id: string;
62
+ readonly title: readonly [{
63
+ readonly locale: "zh";
64
+ readonly message: string;
65
+ }, ...{
66
+ readonly locale: "en" | "ja" | "ko";
67
+ readonly message: string;
68
+ }[]];
69
+ readonly icon?: string | undefined;
70
+ readonly hidden?: string | undefined;
71
+ readonly tooltip?: readonly [{
72
+ readonly locale: "zh";
73
+ readonly message: string;
74
+ }, ...{
75
+ readonly locale: "en" | "ja" | "ko";
76
+ readonly message: string;
77
+ }[]] | undefined;
78
+ readonly variant?: "default" | "link" | "destructive" | "primary" | "ghost" | undefined;
79
+ readonly action?: any;
80
+ readonly groupId: string;
81
+ readonly hideTitle?: boolean | undefined;
82
+ } | {
83
+ readonly id: string;
84
+ readonly title: readonly [{
85
+ readonly locale: "zh";
86
+ readonly message: string;
87
+ }, ...{
88
+ readonly locale: "en" | "ja" | "ko";
89
+ readonly message: string;
90
+ }[]];
91
+ readonly icon?: string | undefined;
92
+ readonly items: readonly (import("../../../../actions/schema.js").RegistrySubItemValue | {
93
+ readonly disabled?: string | undefined;
94
+ readonly id: string;
95
+ readonly title: readonly [{
96
+ readonly locale: "zh";
97
+ readonly message: string;
98
+ }, ...{
99
+ readonly locale: "en" | "ja" | "ko";
100
+ readonly message: string;
101
+ }[]];
102
+ readonly icon?: string | undefined;
103
+ readonly hidden?: string | undefined;
104
+ readonly tooltip?: readonly [{
105
+ readonly locale: "zh";
106
+ readonly message: string;
107
+ }, ...{
108
+ readonly locale: "en" | "ja" | "ko";
109
+ readonly message: string;
110
+ }[]] | undefined;
111
+ readonly variant?: "default" | "link" | "destructive" | "primary" | "ghost" | undefined;
112
+ readonly action?: any;
113
+ })[];
114
+ readonly groupId: string;
115
+ readonly hideTitle?: boolean | undefined;
116
+ }, import("../../../../actions/schema.js").RegistryItemValue | {
117
+ readonly id: string;
118
+ readonly title: readonly [{
119
+ readonly locale: "zh";
120
+ readonly message: string;
121
+ }, ...{
122
+ readonly locale: "en" | "ja" | "ko";
123
+ readonly message: string;
124
+ }[]];
125
+ readonly groupId: string;
126
+ readonly disabled?: string | undefined;
127
+ readonly icon?: string | undefined;
128
+ readonly hidden?: string | undefined;
129
+ readonly tooltip?: readonly [{
130
+ readonly locale: "zh";
131
+ readonly message: string;
132
+ }, ...{
133
+ readonly locale: "en" | "ja" | "ko";
134
+ readonly message: string;
135
+ }[]] | undefined;
136
+ readonly variant?: "default" | "link" | "destructive" | "primary" | "ghost" | undefined;
137
+ readonly action?: any;
138
+ readonly hideTitle?: boolean | undefined;
139
+ } | {
140
+ readonly id: string;
141
+ readonly title: readonly [{
142
+ readonly locale: "zh";
143
+ readonly message: string;
144
+ }, ...{
145
+ readonly locale: "en" | "ja" | "ko";
146
+ readonly message: string;
147
+ }[]];
148
+ readonly items: readonly (import("../../../../actions/schema.js").RegistrySubItemValue | {
149
+ readonly id: string;
150
+ readonly title: readonly [{
151
+ readonly locale: "zh";
152
+ readonly message: string;
153
+ }, ...{
154
+ readonly locale: "en" | "ja" | "ko";
155
+ readonly message: string;
156
+ }[]];
157
+ readonly disabled?: string | undefined;
158
+ readonly icon?: string | undefined;
159
+ readonly hidden?: string | undefined;
160
+ readonly tooltip?: readonly [{
161
+ readonly locale: "zh";
162
+ readonly message: string;
163
+ }, ...{
164
+ readonly locale: "en" | "ja" | "ko";
165
+ readonly message: string;
166
+ }[]] | undefined;
167
+ readonly variant?: "default" | "link" | "destructive" | "primary" | "ghost" | undefined;
168
+ readonly action?: any;
169
+ })[];
170
+ readonly groupId: string;
171
+ readonly icon?: string | undefined;
172
+ readonly hideTitle?: boolean | undefined;
173
+ }, never>>, {
174
+ default: () => never[];
175
+ }>;
176
+ size: Schema.optionalWith<Schema.Literal<["default", "sm", "xs"]>, {
177
+ default: () => "default";
178
+ }>;
179
+ gap: Schema.optionalWith<Schema.filter<Schema.filter<typeof Schema.Number>>, {
180
+ default: () => number;
181
+ }>;
182
+ style: Schema.optional<typeof Schema.String>;
183
+ }>>;
52
184
  title: Schema.TupleType<readonly [Schema.Struct<{
53
185
  locale: Schema.Literal<["zh"]>;
54
186
  message: Schema.SchemaClass<string, string, never>;
@@ -1,13 +1,29 @@
1
1
  import { Schema } from "effect";
2
2
  import { getProperty } from "dot-prop";
3
3
  import { Locale } from "../../../../../share/locale.js";
4
- import { Align, CelRowAccess, derivedRowField, editableColumnFields, editableHeader } from "../../../utils/shared.js";
4
+ import { ActionSchemaFields } from "../../../../actions/schema.js";
5
+ import { Align, CelRowAccess, derivedRowField, editableColumnFields, editableHeader, registerRowVariablesIfAbsent } from "../../../utils/shared.js";
5
6
  export const type = "com.shwfed.table.column.date-input";
6
7
  export const compatibilityDate = "2026-06-17";
7
8
  export const metadata = {
8
9
  name: "\u65E5\u671F\u8F93\u5165",
9
10
  icon: "fluent:calendar-ltr-20-regular"
10
11
  };
12
+ function AddonActions(configure) {
13
+ const configureWithRow = (env) => {
14
+ configure(env);
15
+ registerRowVariablesIfAbsent(env);
16
+ };
17
+ const { groups, items, ...rest } = ActionSchemaFields(configureWithRow).fields;
18
+ return Schema.Struct({
19
+ ...rest,
20
+ groups: Schema.optionalWith(groups, { default: () => [] }),
21
+ items: Schema.optionalWith(items, { default: () => [] })
22
+ }).annotations({
23
+ title: "\u8F93\u5165\u6846\u5185\u6309\u94AE",
24
+ description: "\u5728\u8F93\u5165\u6846\u53F3\u4FA7\u5185\u5D4C\u4E00\u7EC4\u64CD\u4F5C\u6309\u94AE"
25
+ });
26
+ }
11
27
  export function presetSchema(configure) {
12
28
  const CelDate = CelRowAccess(configure, { resultType: "Date" });
13
29
  return Schema.Struct({
@@ -56,7 +72,17 @@ export function schema(configure) {
56
72
  presets: Schema.optional(Schema.Array(Preset).annotations({
57
73
  title: "\u5FEB\u6377\u9009\u9879",
58
74
  description: "\u5728\u9009\u62E9\u5668\u4FA7\u680F\u5C55\u793A\u7684\u5FEB\u6377\u9884\u8BBE\uFF1B\u7559\u7A7A\u5219\u4E0D\u6E32\u67D3\u4FA7\u680F"
59
- }))
75
+ })),
76
+ // `Schema.optional` rebuilds the struct's union member, and because the
77
+ // `optionalWith`-default fields make `AddonActions` a `Transformation`, the
78
+ // inner struct's `title`/`description` don't survive onto the rebuilt
79
+ // member. The config editor's `getStructFieldTitle('addon')` would then fall
80
+ // back to the raw key "addon". Re-state them on the property signature,
81
+ // which the meta reader checks before the field type.
82
+ addon: Schema.optional(AddonActions(configure)).annotations({
83
+ title: "\u8F93\u5165\u6846\u5185\u6309\u94AE",
84
+ description: "\u5728\u8F93\u5165\u6846\u53F3\u4FA7\u5185\u5D4C\u4E00\u7EC4\u64CD\u4F5C\u6309\u94AE"
85
+ })
60
86
  }).annotations({ title: "DateInputRenderer", description: "\u65E5\u671F\u8F93\u5165\u6E32\u67D3\u5668\uFF08\u53EF\u7F16\u8F91\uFF09" });
61
87
  }
62
88
  export function defaults() {
@@ -28,7 +28,11 @@ type __VLS_Props = {
28
28
  shortcuts?: ReadonlyArray<DatePickerShortcut>;
29
29
  size?: 'sm' | 'md' | 'lg';
30
30
  };
31
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
+ declare var __VLS_33: {};
32
+ type __VLS_Slots = {} & {
33
+ trailing?: (props: typeof __VLS_33) => any;
34
+ };
35
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
32
36
  clear: () => any;
33
37
  blur: (args_0: FocusEvent) => any;
34
38
  change: (args_0: string | undefined) => any;
@@ -47,5 +51,11 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
47
51
  clearable: boolean;
48
52
  timeGranularity: "hour" | "minute" | "second";
49
53
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
54
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
50
55
  declare const _default: typeof __VLS_export;
51
56
  export default _default;
57
+ type __VLS_WithSlots<T, S> = T & {
58
+ new (): {
59
+ $slots: S;
60
+ };
61
+ };
@@ -212,7 +212,14 @@ function applyShortcut(index) {
212
212
  @focus="onInputFocus"
213
213
  @blur="onInputBlur"
214
214
  @clear="onInputClear"
215
- />
215
+ >
216
+ <template
217
+ v-if="$slots.trailing"
218
+ #trailing
219
+ >
220
+ <slot name="trailing" />
221
+ </template>
222
+ </DatePickerInput>
216
223
  </PopoverAnchor>
217
224
  <PopoverContent
218
225
  align="start"
@@ -28,7 +28,11 @@ type __VLS_Props = {
28
28
  shortcuts?: ReadonlyArray<DatePickerShortcut>;
29
29
  size?: 'sm' | 'md' | 'lg';
30
30
  };
31
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
+ declare var __VLS_33: {};
32
+ type __VLS_Slots = {} & {
33
+ trailing?: (props: typeof __VLS_33) => any;
34
+ };
35
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
32
36
  clear: () => any;
33
37
  blur: (args_0: FocusEvent) => any;
34
38
  change: (args_0: string | undefined) => any;
@@ -47,5 +51,11 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
47
51
  clearable: boolean;
48
52
  timeGranularity: "hour" | "minute" | "second";
49
53
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
54
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
50
55
  declare const _default: typeof __VLS_export;
51
56
  export default _default;
57
+ type __VLS_WithSlots<T, S> = T & {
58
+ new (): {
59
+ $slots: S;
60
+ };
61
+ };
@@ -12,7 +12,11 @@ type __VLS_Props = {
12
12
  size?: 'sm' | 'md' | 'lg';
13
13
  class?: HTMLAttributes['class'];
14
14
  };
15
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
15
+ declare var __VLS_49: {};
16
+ type __VLS_Slots = {} & {
17
+ trailing?: (props: typeof __VLS_49) => any;
18
+ };
19
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
16
20
  clear: () => any;
17
21
  blur: (args_0: FocusEvent) => any;
18
22
  focus: (args_0: FocusEvent) => any;
@@ -24,8 +28,14 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
24
28
  "onUpdate:modelValue"?: ((args_0: Date | undefined) => any) | undefined;
25
29
  }>, {
26
30
  size: "sm" | "md" | "lg";
27
- clearIcon: string;
28
31
  clearable: boolean;
32
+ clearIcon: string;
29
33
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
34
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
30
35
  declare const _default: typeof __VLS_export;
31
36
  export default _default;
37
+ type __VLS_WithSlots<T, S> = T & {
38
+ new (): {
39
+ $slots: S;
40
+ };
41
+ };
@@ -120,5 +120,9 @@ const showClear = computed(
120
120
  />
121
121
  </InputGroupButton>
122
122
  </InputGroupAddon>
123
+ <!-- A trailing slot for consumer-supplied addons (e.g. the table date-input
124
+ column's embedded action buttons). Rendered inside the `InputGroup` so
125
+ the consumer can drop its own `InputGroupAddon`. -->
126
+ <slot name="trailing" />
123
127
  </InputGroup>
124
128
  </template>
@@ -12,7 +12,11 @@ type __VLS_Props = {
12
12
  size?: 'sm' | 'md' | 'lg';
13
13
  class?: HTMLAttributes['class'];
14
14
  };
15
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
15
+ declare var __VLS_49: {};
16
+ type __VLS_Slots = {} & {
17
+ trailing?: (props: typeof __VLS_49) => any;
18
+ };
19
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
16
20
  clear: () => any;
17
21
  blur: (args_0: FocusEvent) => any;
18
22
  focus: (args_0: FocusEvent) => any;
@@ -24,8 +28,14 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
24
28
  "onUpdate:modelValue"?: ((args_0: Date | undefined) => any) | undefined;
25
29
  }>, {
26
30
  size: "sm" | "md" | "lg";
27
- clearIcon: string;
28
31
  clearable: boolean;
32
+ clearIcon: string;
29
33
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
34
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
30
35
  declare const _default: typeof __VLS_export;
31
36
  export default _default;
37
+ type __VLS_WithSlots<T, S> = T & {
38
+ new (): {
39
+ $slots: S;
40
+ };
41
+ };
@@ -22,8 +22,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
22
22
  size: "sm" | "md" | "lg";
23
23
  granularity: "hour" | "minute" | "second";
24
24
  hourCycle: 12 | 24;
25
- clearIcon: string;
26
25
  clearable: boolean;
26
+ clearIcon: string;
27
27
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
28
  declare const _default: typeof __VLS_export;
29
29
  export default _default;
@@ -22,8 +22,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
22
22
  size: "sm" | "md" | "lg";
23
23
  granularity: "hour" | "minute" | "second";
24
24
  hourCycle: 12 | 24;
25
- clearIcon: string;
26
25
  clearable: boolean;
26
+ clearIcon: string;
27
27
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
28
  declare const _default: typeof __VLS_export;
29
29
  export default _default;
@@ -29,8 +29,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
29
29
  "onUpdate:endValue"?: ((args_0: Date | undefined) => any) | undefined;
30
30
  }>, {
31
31
  size: "sm" | "md" | "lg";
32
- clearIcon: string;
33
32
  clearable: boolean;
33
+ clearIcon: string;
34
34
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
35
35
  declare const _default: typeof __VLS_export;
36
36
  export default _default;
@@ -29,8 +29,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
29
29
  "onUpdate:endValue"?: ((args_0: Date | undefined) => any) | undefined;
30
30
  }>, {
31
31
  size: "sm" | "md" | "lg";
32
- clearIcon: string;
33
32
  clearable: boolean;
33
+ clearIcon: string;
34
34
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
35
35
  declare const _default: typeof __VLS_export;
36
36
  export default _default;
@@ -26,9 +26,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
26
26
  size: "sm" | "md" | "lg";
27
27
  granularity: "hour" | "minute" | "second";
28
28
  hourCycle: 12 | 24;
29
- rangeSeparatorIcon: string;
30
- clearIcon: string;
31
29
  clearable: boolean;
30
+ clearIcon: string;
31
+ rangeSeparatorIcon: string;
32
32
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
33
33
  declare const _default: typeof __VLS_export;
34
34
  export default _default;
@@ -26,9 +26,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
26
26
  size: "sm" | "md" | "lg";
27
27
  granularity: "hour" | "minute" | "second";
28
28
  hourCycle: 12 | 24;
29
- rangeSeparatorIcon: string;
30
- clearIcon: string;
31
29
  clearable: boolean;
30
+ clearIcon: string;
31
+ rangeSeparatorIcon: string;
32
32
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
33
33
  declare const _default: typeof __VLS_export;
34
34
  export default _default;
@@ -86,7 +86,7 @@ const addonAlign = computed(
86
86
  </script>
87
87
 
88
88
  <template>
89
- <div class="flex flex-col gap-1.5">
89
+ <div class="flex w-full min-w-0 flex-col gap-1.5">
90
90
  <InputGroup>
91
91
  <InputGroupAddon
92
92
  v-if="$slots.leading"
@@ -0,0 +1,21 @@
1
+ import type { Environment } from '../vendor/cel-js/lib/index.js';
2
+ /**
3
+ * The per-iteration CEL variables a `loop` block exposes to the blocks inside
4
+ * its slot: `item` (the current list element) and `index` (its 0-based
5
+ * position). Mirrors the form list field's row scope and the table row's
6
+ * `row`/`index`. `item` is always `dyn` — the element shape is backend-defined
7
+ * and unknowable at design time.
8
+ */
9
+ export declare const ITEM_VAR_TYPE = "dyn";
10
+ export declare const ITEM_VAR_DESCRIPTION = "\u5F53\u524D\u5FAA\u73AF\u9879\uFF1B\u7531 `\u5217\u8868` \u8868\u8FBE\u5F0F\u8FD4\u56DE\u7684\u6BCF\u4E00\u9879";
11
+ export declare const INDEX_VAR_TYPE = "number";
12
+ export declare const INDEX_VAR_DESCRIPTION = "\u5F53\u524D\u5FAA\u73AF\u9879\u7D22\u5F15\uFF0C\u4ECE `0` \u5F00\u59CB";
13
+ /**
14
+ * Register the per-iteration `item` (dyn) and `index` (number) CEL variables,
15
+ * skipping each when an enclosing `configure` already declared it. Idempotent
16
+ * so a loop nested inside another loop (or any host that already exposes these
17
+ * names) doesn't re-register — the CEL registry throws `'item' is already
18
+ * registered` on a second declaration. Mirrors `registerNodeVariableIfAbsent`
19
+ * (share/tree-node-var.ts).
20
+ */
21
+ export declare function registerLoopVariablesIfAbsent(env: Environment): void;
@@ -0,0 +1,13 @@
1
+ export const ITEM_VAR_TYPE = "dyn";
2
+ export const ITEM_VAR_DESCRIPTION = "\u5F53\u524D\u5FAA\u73AF\u9879\uFF1B\u7531 `\u5217\u8868` \u8868\u8FBE\u5F0F\u8FD4\u56DE\u7684\u6BCF\u4E00\u9879";
3
+ export const INDEX_VAR_TYPE = "number";
4
+ export const INDEX_VAR_DESCRIPTION = "\u5F53\u524D\u5FAA\u73AF\u9879\u7D22\u5F15\uFF0C\u4ECE `0` \u5F00\u59CB";
5
+ export function registerLoopVariablesIfAbsent(env) {
6
+ const declared = new Set(env.getDefinitions().variables.map((v) => v.name));
7
+ if (!declared.has("item")) {
8
+ env.registerVariable("item", ITEM_VAR_TYPE, { description: ITEM_VAR_DESCRIPTION });
9
+ }
10
+ if (!declared.has("index")) {
11
+ env.registerVariable("index", INDEX_VAR_TYPE, { description: INDEX_VAR_DESCRIPTION });
12
+ }
13
+ }
@@ -10,7 +10,7 @@ When modifying this library, keep both `CLAUDE.md` and `PROMPT.md` in sync with
10
10
 
11
11
  `int` and `uint` types have been removed in favor of a unified `number` type backed by `Decimal` (arbitrary-precision arithmetic via BigInt). All numeric literals, arithmetic results, and size/index returns are `Decimal` instances. The `int()`, `uint()`, and `double()` conversion functions still exist as aliases but all return `number`.
12
12
 
13
- `google.protobuf.Timestamp` and `google.protobuf.Duration` have been removed. Replaced with a `Date` type backed by `TZDate` from `@date-fns/tz`, constructed via `date(string)` or `date(number)` (a Unix timestamp — the seconds-vs-milliseconds unit is auto-detected by magnitude: values `< 1e11` are read as seconds, the rest as milliseconds). Date manipulation uses date-fns functions (`startOf`, `endOf`, `offset`, `set`, `format`).
13
+ `google.protobuf.Timestamp` and `google.protobuf.Duration` have been removed. Replaced with a `Date` type backed by `TZDate` from `@date-fns/tz`, constructed via `date(string)` or `date(number)` (a Unix timestamp — the seconds-vs-milliseconds unit is auto-detected by magnitude: values `< 1e11` are read as seconds, the rest as milliseconds). Date manipulation uses date-fns functions (`startOf`, `endOf`, `offset`, `set`, `format`). `Date.diff(Date, string): number` returns the signed, truncated-toward-zero distance between two dates in a given unit (`millisecond` / `second` / `minute` / `hour` / `day` / `week` / `month` / `year`, plural tolerated) — the receiver is the minuend (`a.diff(b, unit)` = `a − b`, mirroring date-fns `differenceInX(left, right)`); there is no `Date − Date` operator and no duration type, so this is the way to measure elapsed time.
14
14
 
15
15
  A `range()` built-in has been added (not from upstream) — `range(number, number)`, `range(number, number, number)` and `range(Date, Date, string)`. It builds an end-exclusive list; the direction follows the operands (counts down when `start > end`); `step` is a positive magnitude; the date unit is `year` / `month` / `day` / `hour` / `minute`. Output length is capped at 100000.
16
16
 
@@ -24,7 +24,7 @@ The `homogeneousAggregateLiterals` and `enableOptionalTypes` environment options
24
24
 
25
25
  The custom `Optional` class has been replaced with Effect's `Option` type (`import { Option } from 'effect'`). Internal helpers `optionalOf(value)` and `optionalValue(opt)` in `optional.js` handle the CEL-specific semantics (treating `undefined` as `None`, throwing `EvaluationError` on missing value access). The optional surface is `optional.of(A): optional<A>` (the lift / `pure`), `optional.none()`, `optional.hasValue()`, `optional.value()`, `optional.or(optional)`, `optional.orValue(value)`, plus `optional<A>.flatMap(var, body): optional<B>` (monadic bind) and `optional<A>.map(var, body): optional<B>` (the Functor `fmap`) — all local additions (not from upstream). Both are variable-binding macros (registered with `(ast, ast)` arg types so the body stays unevaluated): on `Some` they bind the value and evaluate `body`; on `None` they short-circuit without touching `body`. `flatMap`'s body must itself yield an `optional`; `map`'s body is a plain value that gets re-wrapped in `Some`. `map` is the derived `o.flatMap(v, optional.of(body))` promoted to a first-class macro. NOTE: `map` is **registered in `macros.ts`**, not here — the parser resolves a macro by name before types are known, so the optional `map` and the list-comprehension `map` must share one expander that dispatches on the receiver type at type-check (an `optional` receiver → fmap; `list`/`map` → comprehension; a `dyn` receiver is deferred to a runtime `Option.isOption` check).
26
26
 
27
- An `http` built-in has been added (`http-builtins.ts`, `http-builder.ts`) — not from upstream. It registers the `http` constant and the `http` / `HttpRequest` types on `globalRegistry`, so `http.get(url).header(...).body(...)` expressions type-check and evaluate in every `Environment`. A CEL expression only builds an `HttpRequestBuilder` — a pure description of a request; it never issues one. Both terminal methods, `.json()` and `.file()`, are dispatched by the host on the returned builder (neither is a CEL method), so expression evaluation stays free of IO. Endpoints must be absolute URLs — there is no base-URL resolution. Depends on `fx-fetch`. The host can register process-wide default headers via `HttpRequestBuilder.setDefaultHeader(name, valueOrGetter)` / `clearDefaultHeader(name)`; they are merged in at `#buildRequest()` time, with case-insensitive precedence to an explicit `.header(...)` on the builder. A getter that returns `null` / `undefined` / `''` skips the header for that request, so the host can source values from live refs (e.g. the active i18n locale for `Accept-Language`) without baking in stale snapshots. `.query` accepts `(string, string)` / `(string, number)`, the optional-valued `(string, optional<string>)` / `(string, optional<number>)` (a `None`, e.g. an absent `.?` field, drops the param rather than emitting `key=`; `Some` appends it via the string/number coercion), and the record-splat `(dyn)`.
27
+ An `http` built-in has been added (`http-builtins.ts`, `http-builder.ts`) — not from upstream. It registers the `http` constant and the `http` / `HttpRequest` types on `globalRegistry`, so `http.get(url).header(...).body(...)` expressions type-check and evaluate in every `Environment`. A CEL expression only builds an `HttpRequestBuilder` — a pure description of a request; it never issues one. The terminal methods `.json()`, `.file()`, and `.fileOrJson()` are dispatched by the host on the returned builder (none is a CEL method), so expression evaluation stays free of IO. `.fileOrJson()` branches on the response `Content-Type`: a JSON media type (`application/json` or a `+json` suffix) is parsed and returned as `{ _tag: 'json', json }`; anything else is returned as `{ _tag: 'file', file }`. Note the `Fetch` service itself `ensureOk`s (both `FetchLive` and the mock layer), so a non-2xx fails at `Fetch.fetch` before the branch and this only ever distinguishes 2xx bodies — i.e. the HTTP-200-with-error-envelope case. The download operation uses it so a backend that answers a download with a JSON error envelope (commonly `{ code: -1 }` on a 200) is classified rather than saved as the file. Endpoints must be absolute URLs — there is no base-URL resolution. Depends on `fx-fetch`. The host can register process-wide default headers via `HttpRequestBuilder.setDefaultHeader(name, valueOrGetter)` / `clearDefaultHeader(name)`; they are merged in at `#buildRequest()` time, with case-insensitive precedence to an explicit `.header(...)` on the builder. A getter that returns `null` / `undefined` / `''` skips the header for that request, so the host can source values from live refs (e.g. the active i18n locale for `Accept-Language`) without baking in stale snapshots. `.query` accepts `(string, string)` / `(string, number)`, the optional-valued `(string, optional<string>)` / `(string, optional<number>)` (a `None`, e.g. an absent `.?` field, drops the param rather than emitting `key=`; `Some` appends it via the string/number coercion), and the record-splat `(dyn)`.
28
28
 
29
29
  A `form(dyn): FormData` built-in has been added (`form-builtins.ts`) — not from upstream. It registers the `FormData` type on `globalRegistry` and a global `form` function that turns a CEL map into a native `FormData`, so authors can write `http.post(url).body(form({"file": myFile, "name": "Alice"}))` (`.body()` passes `FormData` through verbatim; `#buildRequest()` serializes it). NOTE: `#buildRequest()` must serialize a `FormData` body itself rather than hand it to fx-fetch — fx-fetch clones bodies via `new Response(body).blob()`, and the File API ASCII-lowercases `Blob#type`, so in Chrome the multipart boundary in the derived `Content-Type` loses its case while the body bytes keep it (boundaries are case-sensitive → every parser sees zero parts). The builder lifts the case-preserved `Content-Type` off the `Response` *header* (header values are never case-normalized), adds it as an explicit header (unless the author set their own `Content-Type`), and passes the bytes as a `Promise<Blob>` (fx-fetch resolves promises verbatim). Value coercion mirrors `.query()`'s flat-record semantics: `null` / `undefined` / `Option.None` skip the key; `Option.Some(x)` recurses on `x`; `File` / `Blob` pass through (preserves the `File` filename); `Decimal` → `.toString()` (preserves precision past safe-integer); `Date` (`TZDate`) → `.toISOString()`; `bool` → `'true'` / `'false'`; arrays append one entry per element; nested objects throw (`multipart/form-data` is flat — same rule as `.query(dyn)`). Top-level input must be a map literal / record (Map or plain object); passing an array or scalar throws.
30
30
  The `__proto__` / `constructor` / `prototype` keys are skipped on the top-level record, mirroring `safeFromEntries`.
@@ -234,6 +234,13 @@ d.offset(-1, "month") // 1 month earlier
234
234
  d.offset(2, "weeks") // 2 weeks later
235
235
  d.offset(1, "year") // 1 year later
236
236
 
237
+ // Difference between two dates (signed, truncated toward zero):
238
+ // receiver is the minuend, so `a.diff(b, unit)` == a − b
239
+ d.diff(other, "day") // whole days from other to d (negative if d is earlier)
240
+ d.diff(other, "hour") // whole hours
241
+ d.diff(other, "minute") // whole minutes
242
+ // units: millisecond / second / minute / hour / day / week / month / year (plural ok)
243
+
237
244
  // Set specific fields:
238
245
  d.set("day", 15) // set day of month to 15
239
246
  d.set("month", 6) // set to June (1-based)
@@ -4,7 +4,7 @@ import { TYPES, Type } from "./registry.js";
4
4
  import { register as registerOptional, optionalOf } from "./optional.js";
5
5
  import { objKeys, arrayFrom } from "./globals.js";
6
6
  import { TZDate } from "@date-fns/tz";
7
- import { startOfDay, startOfWeek, startOfMonth, startOfYear, endOfDay, endOfWeek, endOfMonth, endOfYear, addDays, addWeeks, addMonths, addYears, addHours, addMinutes, setDate as setDayOfMonth, setMonth, setYear, format as formatDate } from "date-fns";
7
+ import { startOfDay, startOfWeek, startOfMonth, startOfYear, endOfDay, endOfWeek, endOfMonth, endOfYear, addDays, addWeeks, addMonths, addYears, addHours, addMinutes, setDate as setDayOfMonth, setMonth, setYear, format as formatDate, differenceInMilliseconds, differenceInSeconds, differenceInMinutes, differenceInHours, differenceInDays, differenceInWeeks, differenceInMonths, differenceInYears } from "date-fns";
8
8
  function toNum(v) {
9
9
  if (v instanceof Decimal) return v.toNumber();
10
10
  if (typeof v === "bigint") return Number(v);
@@ -387,6 +387,30 @@ export function registerFunctions(registry) {
387
387
  throw evaluationError("invalid_unit", `offset(): unknown unit "${unit}"`);
388
388
  }
389
389
  });
390
+ functionOverload("Date.diff(Date, string): number", (d, other, unit) => {
391
+ const left = d;
392
+ const right = other;
393
+ switch (unit.replace(/s$/, "")) {
394
+ case "millisecond":
395
+ return Decimal.from(differenceInMilliseconds(left, right));
396
+ case "second":
397
+ return Decimal.from(differenceInSeconds(left, right));
398
+ case "minute":
399
+ return Decimal.from(differenceInMinutes(left, right));
400
+ case "hour":
401
+ return Decimal.from(differenceInHours(left, right));
402
+ case "day":
403
+ return Decimal.from(differenceInDays(left, right));
404
+ case "week":
405
+ return Decimal.from(differenceInWeeks(left, right));
406
+ case "month":
407
+ return Decimal.from(differenceInMonths(left, right));
408
+ case "year":
409
+ return Decimal.from(differenceInYears(left, right));
410
+ default:
411
+ throw evaluationError("invalid_unit", `diff(): unknown unit "${unit}"`);
412
+ }
413
+ });
390
414
  functionOverload("Date.set(string, number): Date", (d, field, value) => {
391
415
  const date = d;
392
416
  const val = toNum(value);
@@ -2,15 +2,26 @@
2
2
  * `HttpRequestBuilder` — the value an `http.*` CEL expression evaluates to.
3
3
  *
4
4
  * A local (non-upstream) extension. A CEL expression only *describes* a
5
- * request — it never issues one. Both terminal methods, `.json()` and
6
- * `.file()`, are dispatched by the host on the returned builder, keeping
7
- * expression evaluation free of IO.
5
+ * request — it never issues one. The terminal methods `.json()`, `.file()`,
6
+ * and `.fileOrJson()` are dispatched by the host on the returned builder,
7
+ * keeping expression evaluation free of IO.
8
8
  *
9
9
  * Endpoints are used verbatim — there is no base-URL resolution, so callers
10
10
  * must pass absolute URLs.
11
11
  */
12
12
  import { Effect } from 'effect';
13
13
  import { Fetch } from 'fx-fetch';
14
+ /**
15
+ * The outcome of `.fileOrJson()` — discriminated on what the server actually
16
+ * returned, so the host can save a binary body but classify a JSON envelope.
17
+ */
18
+ export type FileOrJson = {
19
+ readonly _tag: 'file';
20
+ readonly file: File;
21
+ } | {
22
+ readonly _tag: 'json';
23
+ readonly json: unknown;
24
+ };
14
25
  export declare class HttpRequestBuilder {
15
26
  #private;
16
27
  static setDefaultHeader(name: string, value: string | (() => string | null | undefined)): void;
@@ -42,4 +53,28 @@ export declare class HttpRequestBuilder {
42
53
  };
43
54
  json(): Effect.Effect<unknown, import("fx-fetch/Cause").MalformedJsonError | Fetch.Fetch.ErrorType, Fetch.Fetch>;
44
55
  file(): Effect.Effect<File, Fetch.Fetch.ErrorType | import("fx-fetch/Cause").MalformedBlobError, Fetch.Fetch>;
56
+ /**
57
+ * A download that branches on the response Content-Type:
58
+ * - JSON (`application/json` / a `+json` type) → parse the body and return
59
+ * `{ _tag: 'json', json }`. A download endpoint that answers with JSON has
60
+ * almost always returned an error envelope (e.g. `{ code: -1 }` on a 200)
61
+ * rather than the file — the host classifies it instead of saving the
62
+ * bytes. This branch deliberately does not `ensureOk`, but the `Fetch`
63
+ * service already does (both `FetchLive` and the mock layer), so under the
64
+ * standard layer a non-2xx has already failed at `Fetch.fetch` above and
65
+ * this branch sees only 2xx — the HTTP-200-with-error-envelope case.
66
+ * - anything else → the bytes are the file. `ensureOk` is kept for parity
67
+ * with `.file()` (redundant under the standard `Fetch` service, defensive
68
+ * against a layer that doesn't), then return `{ _tag: 'file', file }` with
69
+ * the filename from `Content-Disposition`.
70
+ */
71
+ fileOrJson(): Effect.Effect<{
72
+ _tag: "json";
73
+ json: unknown;
74
+ file?: undefined;
75
+ } | {
76
+ _tag: "file";
77
+ file: File;
78
+ json?: undefined;
79
+ }, import("fx-fetch/Cause").MalformedJsonError | Fetch.Fetch.ErrorType | import("fx-fetch/Cause").MalformedBlobError, Fetch.Fetch>;
45
80
  }
@@ -23,6 +23,9 @@ function normalizeBody(value) {
23
23
  }
24
24
  return value;
25
25
  }
26
+ function isJsonContentType(contentType) {
27
+ return /application\/(?:[\w.+-]+\+)?json\b/i.test(contentType);
28
+ }
26
29
  function extractFilename(response, url) {
27
30
  const disposition = FxResponse.getHeader(response, "content-disposition");
28
31
  if (disposition) {
@@ -126,6 +129,36 @@ export class HttpRequestBuilder {
126
129
  return new File([blob], extractFilename(response, url));
127
130
  });
128
131
  }
132
+ /**
133
+ * A download that branches on the response Content-Type:
134
+ * - JSON (`application/json` / a `+json` type) → parse the body and return
135
+ * `{ _tag: 'json', json }`. A download endpoint that answers with JSON has
136
+ * almost always returned an error envelope (e.g. `{ code: -1 }` on a 200)
137
+ * rather than the file — the host classifies it instead of saving the
138
+ * bytes. This branch deliberately does not `ensureOk`, but the `Fetch`
139
+ * service already does (both `FetchLive` and the mock layer), so under the
140
+ * standard layer a non-2xx has already failed at `Fetch.fetch` above and
141
+ * this branch sees only 2xx — the HTTP-200-with-error-envelope case.
142
+ * - anything else → the bytes are the file. `ensureOk` is kept for parity
143
+ * with `.file()` (redundant under the standard `Fetch` service, defensive
144
+ * against a layer that doesn't), then return `{ _tag: 'file', file }` with
145
+ * the filename from `Content-Disposition`.
146
+ */
147
+ fileOrJson() {
148
+ const url = this.#url;
149
+ const request = this.#buildRequest();
150
+ return Effect.gen(function* () {
151
+ const response = yield* Fetch.fetch(request);
152
+ const contentType = FxResponse.getHeader(response, "content-type")?.[0] ?? "";
153
+ if (isJsonContentType(contentType)) {
154
+ const json = yield* FxResponse.readJson(response);
155
+ return { _tag: "json", json };
156
+ }
157
+ yield* FxResponse.ensureOk(response);
158
+ const blob = yield* FxResponse.readBlob(response);
159
+ return { _tag: "file", file: new File([blob], extractFilename(response, url)) };
160
+ });
161
+ }
129
162
  #buildRequest() {
130
163
  const parts = {
131
164
  url: this.#url,